1f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc/* 2f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * Copyright 2002-2004, Instant802 Networks, Inc. 3765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen * Copyright 2008, Jouni Malinen <j@w1.fi> 4f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * 5f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * This program is free software; you can redistribute it and/or modify 6f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * it under the terms of the GNU General Public License version 2 as 7f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * published by the Free Software Foundation. 8f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc */ 9f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 10f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/netdevice.h> 11f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/types.h> 12f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/skbuff.h> 13f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <linux/compiler.h> 14f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison#include <linux/ieee80211.h> 155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 16f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison#include <asm/unaligned.h> 17f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include <net/mac80211.h> 18aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg#include <crypto/aes.h> 19eb063c1702a84d58eb4c05a032bbff6f1c29049dJohannes Berg 20f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "ieee80211_i.h" 21f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "michael.h" 22f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "tkip.h" 23f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "aes_ccm.h" 24765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen#include "aes_cmac.h" 25f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc#include "wpa.h" 26f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 279ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result 285cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) 29f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 30747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen u8 *data, *key, *mic; 31f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc size_t data_len; 328e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison unsigned int hdrlen; 338e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison struct ieee80211_hdr *hdr; 34f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct sk_buff *skb = tx->skb; 35813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 3623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg int tail; 37f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 38c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison hdr = (struct ieee80211_hdr *)skb->data; 3997359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || 4097359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control)) 419ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_CONTINUE; 42f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 438e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 448e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison if (skb->len < hdrlen) 459ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_DROP; 46f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 478e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison data = skb->data + hdrlen; 488e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison data_len = skb->len - hdrlen; 498e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison 50681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) { 51681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen /* Need to use software crypto for the test */ 52681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen info->control.hw_key = NULL; 53681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen } 54681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen 55813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key && 56a26eb27ab430147a82e4a9f2f1ebfadf03d99550Johannes Berg (info->flags & IEEE80211_TX_CTL_DONTFRAG || 57a26eb27ab430147a82e4a9f2f1ebfadf03d99550Johannes Berg tx->local->ops->set_frag_threshold) && 58813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { 59813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg /* hwaccel - with no need for SW-generated MMIC */ 609ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_CONTINUE; 61f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc } 62f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 6323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg tail = MICHAEL_MIC_LEN; 64813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (!info->control.hw_key) 654325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg tail += IEEE80211_TKIP_ICV_LEN; 6623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg 67b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg if (WARN(skb_tailroom(skb) < tail || 68b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg skb_headroom(skb) < IEEE80211_TKIP_IV_LEN, 69b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg "mmic: not enough head/tail (%d/%d,%d/%d)\n", 70b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg skb_headroom(skb), IEEE80211_TKIP_IV_LEN, 71b1e9be8775b85d761cdb91386200a04d741f6a0dJohannes Berg skb_tailroom(skb), tail)) 7223c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg return TX_DROP; 73f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 74747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; 75f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc mic = skb_put(skb, MICHAEL_MIC_LEN); 768e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison michael_mic(key, hdr, data, data_len, mic); 77681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) 78681d119047761cc59a15c0bb86891f3a878997cfJouni Malinen mic[0]++; 79f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 809ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_CONTINUE; 81f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 82f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 83f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 849ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result 855cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) 86f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 87747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen u8 *data, *key = NULL; 88f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc size_t data_len; 898e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison unsigned int hdrlen; 90f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc u8 mic[MICHAEL_MIC_LEN]; 91f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct sk_buff *skb = rx->skb; 92eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 93eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 94f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 95816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter /* 96816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * it makes no sense to check for MIC errors on anything other 97816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * than data frames. 98816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter */ 99816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (!ieee80211_is_data_present(hdr->frame_control)) 1009ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 101f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 102816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter /* 103816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * No way to verify the MIC if the hardware stripped it or 104816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * the IV with the key index. In this case we have solely rely 105816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * on the driver to set RX_FLAG_MMIC_ERROR in the event of a 106816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * MIC failure report. 107816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter */ 108816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { 109816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (status->flag & RX_FLAG_MMIC_ERROR) 110b98ea05861d76f458029096e8b2939fcb58e9530Saravana goto mic_fail_no_key; 111816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 1124045f72bcf3c293c7c5932ef001742d8bb5ded76Stanislaw Gruszka if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && 1134045f72bcf3c293c7c5932ef001742d8bb5ded76Stanislaw Gruszka rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) 114816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter goto update_iv; 115816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 116816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter return RX_CONTINUE; 117816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter } 118816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 119816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter /* 120816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * Some hardware seems to generate Michael MIC failure reports; even 121816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * though, the frame was not encrypted with TKIP and therefore has no 122816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * MIC. Ignore the flag them to avoid triggering countermeasures. 123816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter */ 12497359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || 125816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter !(status->flag & RX_FLAG_DECRYPTED)) 1269ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 127f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 128816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { 129816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter /* 130816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * APs with pairwise keys should never receive Michael MIC 131816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * errors for non-zero keyidx because these are reserved for 132816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter * group keys and only the AP is sending real multicast 13387ee475ef62504609368a767f6ad2e903a442078Emmanuel Grumbach * frames in the BSS. 134816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter */ 135816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter return RX_DROP_UNUSABLE; 136816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter } 137816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 138816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (status->flag & RX_FLAG_MMIC_ERROR) 139816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter goto mic_fail; 140816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 1418e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 1428e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison if (skb->len < hdrlen + MICHAEL_MIC_LEN) 143e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 144f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 145a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg if (skb_linearize(rx->skb)) 146a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg return RX_DROP_UNUSABLE; 147a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg hdr = (void *)skb->data; 148a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg 1498e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison data = skb->data + hdrlen; 1508e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; 151747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; 1528e8862b79d2ce9177bfddd85b8328a86a25c69b2Harvey Harrison michael_mic(key, hdr, data, data_len, mic); 153816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) 154816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter goto mic_fail; 155f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 156f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* remove Michael MIC from payload */ 157f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc skb_trim(skb, skb->len - MICHAEL_MIC_LEN); 158f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 159816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparterupdate_iv: 16050741ae05a4742cae99361f57d84b5f8d33822a4Johannes Berg /* update IV in key information to be able to detect replays */ 1619e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; 1629e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; 16350741ae05a4742cae99361f57d84b5f8d33822a4Johannes Berg 1649ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 165816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter 166816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lampartermic_fail: 167b98ea05861d76f458029096e8b2939fcb58e9530Saravana rx->key->u.tkip.mic_failures++; 168b98ea05861d76f458029096e8b2939fcb58e9530Saravana 169b98ea05861d76f458029096e8b2939fcb58e9530Saravanamic_fail_no_key: 170a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov /* 171a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov * In some cases the key can be unset - e.g. a multicast packet, in 172a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov * a driver that supports HW encryption. Send up the key idx only if 173a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov * the key is set. 174a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov */ 175a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov mac80211_ev_michael_mic_failure(rx->sdata, 176a66b98db570a638afd909459e1e6bfa272344bd3Arik Nemtsov rx->key ? rx->key->conf.keyidx : -1, 177816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter (void *) skb->data, NULL, GFP_ATOMIC); 178816c04fe7ef01dd9649f5ccfe796474db8708be5Christian Lamparter return RX_DROP_UNUSABLE; 179f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 180f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 181f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 182e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Bergstatic int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) 183f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 184f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 185f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_key *key = tx->key; 186e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 187d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison unsigned int hdrlen; 188d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison int len, tail; 189f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc u8 *pos; 190f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 191813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key && 192ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && 193ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { 194813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg /* hwaccel - with no need for software-generated IV */ 19523c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg return 0; 196e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg } 197e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg 198d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 199f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc len = skb->len - hdrlen; 200f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 201813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key) 20223c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg tail = 0; 20311a843b7e16062389c53ba393c7913956e034eb2Johannes Berg else 2044325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg tail = IEEE80211_TKIP_ICV_LEN; 20523c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg 20623c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg if (WARN_ON(skb_tailroom(skb) < tail || 2074325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_headroom(skb) < IEEE80211_TKIP_IV_LEN)) 20823c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg return -1; 209f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2104325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); 2114325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); 2124325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_set_network_header(skb, skb_network_offset(skb) + 2134325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg IEEE80211_TKIP_IV_LEN); 214f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pos += hdrlen; 215f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 216ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com /* the HW only needs room for the IV, but not the actual IV */ 217ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com if (info->control.hw_key && 218ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) 219ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com return 0; 220ee70108fa2a7688dc67bfedaeb0c8c46a221effbJanusz.Dziedzic@tieto.com 221f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Increase IV for the frame */ 22203395003bf8ac813b1a0ac9299b3496484caf228Johannes Berg spin_lock(&key->u.tkip.txlock); 223b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison key->u.tkip.tx.iv16++; 224b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison if (key->u.tkip.tx.iv16 == 0) 225b0f76b335f8b1c324b4b2be06369d391b26a7cc9Harvey Harrison key->u.tkip.tx.iv32++; 226523b02ea23b175dd3e46e3daf1bc9354376640a3Johannes Berg pos = ieee80211_tkip_add_iv(pos, key); 22703395003bf8ac813b1a0ac9299b3496484caf228Johannes Berg spin_unlock(&key->u.tkip.txlock); 228f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 229813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg /* hwaccel - with software IV */ 230813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key) 231f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc return 0; 232f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 233f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Add room for ICV */ 2344325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_put(skb, IEEE80211_TKIP_ICV_LEN); 235f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2363473187d2459a078e00e5fac8aafc30af69c57faJohn W. Linville return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm, 237523b02ea23b175dd3e46e3daf1bc9354376640a3Johannes Berg key, skb, pos, len); 238f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 239f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 240f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2419ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result 2425cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) 243f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 244252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg struct sk_buff *skb; 245f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2465cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg ieee80211_tx_set_protected(tx); 247f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 248252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg skb_queue_walk(&tx->skbs, skb) { 2492de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg if (tkip_encrypt_skb(tx, skb) < 0) 2502de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg return TX_DROP; 251252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg } 252f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2539ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_CONTINUE; 254f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 255f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 256f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 2579ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result 2585cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) 259f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 260f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; 261747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen int hdrlen, res, hwaccel = 0; 262f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_key *key = rx->key; 263f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct sk_buff *skb = rx->skb; 264eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 265f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 266d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 267f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 268c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison if (!ieee80211_is_data(hdr->frame_control)) 2699ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 270f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 271f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc if (!rx->sta || skb->len - hdrlen < 12) 272e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 273f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 274a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg /* it may be possible to optimize this a bit more */ 275a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg if (skb_linearize(rx->skb)) 276a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg return RX_DROP_UNUSABLE; 277a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg hdr = (void *)skb->data; 278a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg 279dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg /* 280dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg * Let TKIP code verify IV, but skip decryption. 281dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg * In the case where hardware checks the IV as well, 282dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg * we don't even get here, see ieee80211_rx_h_decrypt() 283dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg */ 284dc1580ddfc1f70636f6ef80a385902f7e8278debJohannes Berg if (status->flag & RX_FLAG_DECRYPTED) 285f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hwaccel = 1; 286f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 287f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, 288f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc key, skb->data + hdrlen, 28917741cdc264e4d768167766a252210e201c1519aJohannes Berg skb->len - hdrlen, rx->sta->sta.addr, 2909e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg hdr->addr1, hwaccel, rx->security_idx, 2915cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg &rx->tkip_iv32, 2925cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg &rx->tkip_iv16); 293747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6Jouni Malinen if (res != TKIP_DECRYPT_OK) 294e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 295f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 296f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Trim ICV */ 2974325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN); 298f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 299f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Remove IV */ 3004325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen); 3014325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_pull(skb, IEEE80211_TKIP_IV_LEN); 302f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 3039ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 304f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 305f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 306f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 30730ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvelstatic void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) 308f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 309f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison __le16 mask_fc; 310fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen int a4_included, mgmt; 311f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison u8 qos_tid; 3127ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel u16 len_a; 313f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison unsigned int hdrlen; 314f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 315f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 316f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison /* 317fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen * Mask FC: zero subtype b4 b5 b6 (if not mgmt) 318f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison * Retry, PwrMgt, MoreData; set Protected 319f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison */ 320fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen mgmt = ieee80211_is_mgmt(hdr->frame_control); 321f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison mask_fc = hdr->frame_control; 322fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | 323f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); 324fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen if (!mgmt) 325fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen mask_fc &= ~cpu_to_le16(0x0070); 326f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 327f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison 328f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 329f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison len_a = hdrlen - 2; 330f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison a4_included = ieee80211_has_a4(hdr->frame_control); 331f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 332f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison if (ieee80211_is_data_qos(hdr->frame_control)) 333f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 334f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison else 335f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison qos_tid = 0; 336f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison 3377ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC 3387ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel * mode authentication are not allowed to collide, yet both are derived 3397ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel * from this vector b_0. We only set L := 1 here to indicate that the 3407ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel * data size can be represented in (L+1) bytes. The CCM layer will take 3417ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel * care of storing the data length in the top (L+1) bytes and setting 3427ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel * and clearing the other bits as is required to derive the two IVs. 3437ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel */ 3447ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel b_0[0] = 0x1; 345f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison 346fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen /* Nonce: Nonce Flags | A2 | PN 347fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) 348fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen */ 349fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen b_0[1] = qos_tid | (mgmt << 4); 35073e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison memcpy(&b_0[2], hdr->addr2, ETH_ALEN); 3514325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); 352f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 353f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* AAD (extra authenticate-only data) / masked 802.11 header 354f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ 355f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison put_unaligned_be16(len_a, &aad[0]); 356f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison put_unaligned(mask_fc, (__le16 *)&aad[2]); 35773e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); 358f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 359f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Mask Seq#, leave Frag# */ 360f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f; 361f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc aad[23] = 0; 362f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison 363f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc if (a4_included) { 36473e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison memcpy(&aad[24], hdr->addr4, ETH_ALEN); 365f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison aad[30] = qos_tid; 366f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc aad[31] = 0; 367f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison } else { 36873e1f7c823252d671361cddde0b498bf2c0fe4e1Harvey Harrison memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); 369f14df8049f9c9f34164dd598772fecea83a394a2Harvey Harrison aad[24] = qos_tid; 370f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc } 371f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 372f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 373f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 374f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Bencstatic inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id) 375f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 376f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[0] = pn[5]; 377f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[1] = pn[4]; 378f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[2] = 0; 379f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[3] = 0x20 | (key_id << 6); 380f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[4] = pn[3]; 381f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[5] = pn[2]; 382f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[6] = pn[1]; 383f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr[7] = pn[0]; 384f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 385f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 386f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 387c6a1fa12d206882757264869f8e32d606b930e2aJohannes Bergstatic inline void ccmp_hdr2pn(u8 *pn, u8 *hdr) 388f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 389f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[0] = hdr[7]; 390f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[1] = hdr[6]; 391f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[2] = hdr[5]; 392f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[3] = hdr[4]; 393f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[4] = hdr[1]; 394f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pn[5] = hdr[0]; 395f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 396f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 397f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 398e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Bergstatic int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) 399f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 400f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 401f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_key *key = tx->key; 402e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 40323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg int hdrlen, len, tail; 404aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg u8 *pos; 405aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg u8 pn[6]; 406aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg u64 pn64; 4077ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel u8 aad[2 * AES_BLOCK_SIZE]; 4087ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel u8 b_0[AES_BLOCK_SIZE]; 409f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 410813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key && 411077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && 41217d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && 41317d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski !((info->control.hw_key->flags & 41417d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) && 41517d38fa8c20a9c3ec76943da46264ce657ac56d0Marek Kwaczynski ieee80211_is_mgmt(hdr->frame_control))) { 416813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg /* 417813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg * hwaccel has no need for preallocated room for CCMP 418813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg * header or MIC fields 419813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg */ 42023c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg return 0; 421e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg } 422e039fa4a4195ac4ee895e6f3d1334beed63256feJohannes Berg 423d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 424f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc len = skb->len - hdrlen; 425f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 426813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key) 42723c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg tail = 0; 42811a843b7e16062389c53ba393c7913956e034eb2Johannes Berg else 4294325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg tail = IEEE80211_CCMP_MIC_LEN; 43023c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg 43123c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg if (WARN_ON(skb_tailroom(skb) < tail || 4324325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_headroom(skb) < IEEE80211_CCMP_HDR_LEN)) 43323c0752a25d73ccc4547700e8a57d5ae2f2edf56Johannes Berg return -1; 434f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4354325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); 4364325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); 4374325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_set_network_header(skb, skb_network_offset(skb) + 4384325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg IEEE80211_CCMP_HDR_LEN); 439077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov 440077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov /* the HW only needs room for the IV, but not the actual IV */ 441e0830f71e7b8c2c58031c9692384819943162e9bArik Nemtsov if (info->control.hw_key && 442e0830f71e7b8c2c58031c9692384819943162e9bArik Nemtsov (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) 443077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov return 0; 444077a9154898b374f20555adc3f620cccd02581d6Arik Nemtsov 445f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc hdr = (struct ieee80211_hdr *) pos; 446f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc pos += hdrlen; 447f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 448aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn64 = atomic64_inc_return(&key->u.ccmp.tx_pn); 449f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 450aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[5] = pn64; 451aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[4] = pn64 >> 8; 452aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[3] = pn64 >> 16; 453aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[2] = pn64 >> 24; 454aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[1] = pn64 >> 32; 455aba83a0b301c32dbb91c017f33307611e1a1d384Johannes Berg pn[0] = pn64 >> 40; 456f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4578f20fc24986a083228823d9b68adca20714b254eJohannes Berg ccmp_pn2hdr(pos, pn, key->conf.keyidx); 458f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 459813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg /* hwaccel - with software CCMP header */ 460813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key) 461f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc return 0; 462f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4634325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg pos += IEEE80211_CCMP_HDR_LEN; 46430ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvel ccmp_special_blocks(skb, pn, b_0, aad); 4657ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, 4667ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel skb_put(skb, IEEE80211_CCMP_MIC_LEN)); 467f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 468f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc return 0; 469f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 470f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 471f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4729ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_tx_result 4735cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) 474f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 475252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg struct sk_buff *skb; 476f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4775cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Berg ieee80211_tx_set_protected(tx); 478f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 479252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg skb_queue_walk(&tx->skbs, skb) { 4802de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg if (ccmp_encrypt_skb(tx, skb) < 0) 4812de8e0d999b8790861cd3749bec2236ccc1c8110Johannes Berg return TX_DROP; 482252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg } 483f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4849ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return TX_CONTINUE; 485f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 486f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 487f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 4889ae54c8463691b64ca6e6d8680787a6527810984Johannes Bergieee80211_rx_result 4895cf121c3cdb955583bf0c5d28c992b7968a4aa1aJohannes Bergieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) 490f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc{ 491c34498b9e633baa3266af98106502633b6bc371bHarvey Harrison struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 492f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc int hdrlen; 493f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct ieee80211_key *key = rx->key; 494f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc struct sk_buff *skb = rx->skb; 495eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 4964325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg u8 pn[IEEE80211_CCMP_PN_LEN]; 497f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc int data_len; 4989190252c952a33efa1ceff4ef35188f8a27b81cbJouni Malinen int queue; 499f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 500d5184cacf3eeaeb6ae0c7a02aa44fe589beeda23Harvey Harrison hdrlen = ieee80211_hdrlen(hdr->frame_control); 501f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 502fb7333367632c67d8b6b06fb8d906cdabb11b02aJouni Malinen if (!ieee80211_is_data(hdr->frame_control) && 503d8ca16db6bb23d03fcb794df44bae64ae976f27cJohannes Berg !ieee80211_is_robust_mgmt_frame(skb)) 5049ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 505f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 5064325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - 5074325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg IEEE80211_CCMP_MIC_LEN; 508f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc if (!rx->sta || data_len < 0) 509e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 510f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 511a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg if (status->flag & RX_FLAG_DECRYPTED) { 5124325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN)) 513a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg return RX_DROP_UNUSABLE; 514a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg } else { 515a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg if (skb_linearize(rx->skb)) 516a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg return RX_DROP_UNUSABLE; 517a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg } 518a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg 519c6a1fa12d206882757264869f8e32d606b930e2aJohannes Berg ccmp_hdr2pn(pn, skb->data + hdrlen); 520f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 5219e26297a56453315ae6829aec609b5a6309af7b4Johannes Berg queue = rx->security_idx; 5229190252c952a33efa1ceff4ef35188f8a27b81cbJouni Malinen 5234325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg if (memcmp(pn, key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN) <= 0) { 524f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc key->u.ccmp.replays++; 525e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 526f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc } 527f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 528eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg if (!(status->flag & RX_FLAG_DECRYPTED)) { 5297ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel u8 aad[2 * AES_BLOCK_SIZE]; 5307ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel u8 b_0[AES_BLOCK_SIZE]; 5317848ba7d7a010ccb265617fc2bc053e2bdf06f48Johannes Berg /* hardware didn't decrypt/verify MIC */ 53230ef7ef9672d92ab2cac37f60a31955c118321e7Ard Biesheuvel ccmp_special_blocks(skb, pn, b_0, aad); 533f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 534f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc if (ieee80211_aes_ccm_decrypt( 5357ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel key->u.ccmp.tfm, b_0, aad, 5364325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, 5374325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg data_len, 5387ec7c4a9a686c608315739ab6a2b0527a240883cArd Biesheuvel skb->data + skb->len - IEEE80211_CCMP_MIC_LEN)) 539e4c26add8893e40e6e809b8c1ebc81e37762af2bJohannes Berg return RX_DROP_UNUSABLE; 540f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc } 541f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 5424325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); 543f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 544f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc /* Remove CCMP header and MIC */ 5454325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg if (pskb_trim(skb, skb->len - IEEE80211_CCMP_MIC_LEN)) 546a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg return RX_DROP_UNUSABLE; 5474325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg memmove(skb->data + IEEE80211_CCMP_HDR_LEN, skb->data, hdrlen); 5484325f6caad98c075b39f0eaaac6693a0dd43f646Johannes Berg skb_pull(skb, IEEE80211_CCMP_HDR_LEN); 549f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc 5509ae54c8463691b64ca6e6d8680787a6527810984Johannes Berg return RX_CONTINUE; 551f0706e828e96d0fa4e80c0d25aa98523f6d589a0Jiri Benc} 552765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 5532475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic ieee80211_tx_result 5542475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, 5552475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct sk_buff *skb) 5562475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{ 5572475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 5582475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_key *key = tx->key; 5592475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 5602475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; 5612475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov int hdrlen; 5622475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov u8 *pos; 5632475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5642475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (info->control.hw_key && 5652475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { 5662475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov /* hwaccel has no need for preallocated head room */ 5672475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return TX_CONTINUE; 5682475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov } 5692475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5702475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (unlikely(skb_headroom(skb) < cs->hdr_len && 5712475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) 5722475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return TX_DROP; 5732475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5742475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov hdrlen = ieee80211_hdrlen(hdr->frame_control); 5752475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5762475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov pos = skb_push(skb, cs->hdr_len); 5772475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov memmove(pos, pos + cs->hdr_len, hdrlen); 5782475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); 5792475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5802475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return TX_CONTINUE; 5812475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov} 5822475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5832475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) 5842475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{ 5852475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov int i; 5862475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5872475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov /* pn is little endian */ 5882475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov for (i = len - 1; i >= 0; i--) { 5892475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (pn1[i] < pn2[i]) 5902475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return -1; 5912475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov else if (pn1[i] > pn2[i]) 5922475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return 1; 5932475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov } 5942475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5952475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return 0; 5962475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov} 5972475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 5982475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovstatic ieee80211_rx_result 5992475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) 6002475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{ 6012475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_key *key = rx->key; 6022475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 6032475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov const struct ieee80211_cipher_scheme *cs = NULL; 6042475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov int hdrlen = ieee80211_hdrlen(hdr->frame_control); 6052475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); 6062475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov int data_len; 6072475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov u8 *rx_pn; 6082475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov u8 *skb_pn; 6092475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov u8 qos_tid; 6102475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6112475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (!rx->sta || !rx->sta->cipher_scheme || 6122475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov !(status->flag & RX_FLAG_DECRYPTED)) 6132475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 6142475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6152475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (!ieee80211_is_data(hdr->frame_control)) 6162475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_CONTINUE; 6172475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6182475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov cs = rx->sta->cipher_scheme; 6192475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6202475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov data_len = rx->skb->len - hdrlen - cs->hdr_len; 6212475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6222475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (data_len < 0) 6232475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 6242475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6252475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (ieee80211_is_data_qos(hdr->frame_control)) 6262475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov qos_tid = *ieee80211_get_qos_ctl(hdr) & 6272475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov IEEE80211_QOS_CTL_TID_MASK; 6282475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov else 6292475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov qos_tid = 0; 6302475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6312475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (skb_linearize(rx->skb)) 6322475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 6332475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6342475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov hdr = (struct ieee80211_hdr *)rx->skb->data; 6352475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6362475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov rx_pn = key->u.gen.rx_pn[qos_tid]; 6372475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov skb_pn = rx->skb->data + hdrlen + cs->pn_off; 6382475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6392475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) 6402475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 6412475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6422475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov memcpy(rx_pn, skb_pn, cs->pn_len); 6432475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6442475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov /* remove security header and MIC */ 6452475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) 6462475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 6472475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6482475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); 6492475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov skb_pull(rx->skb, cs->hdr_len); 6502475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 6512475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_CONTINUE; 6522475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov} 653765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 654765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenstatic void bip_aad(struct sk_buff *skb, u8 *aad) 655765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{ 65633766368f6532313571534f9112b1796d6651bbeJouni Malinen __le16 mask_fc; 65733766368f6532313571534f9112b1796d6651bbeJouni Malinen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 65833766368f6532313571534f9112b1796d6651bbeJouni Malinen 659765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* BIP AAD: FC(masked) || A1 || A2 || A3 */ 660765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 661765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* FC type/subtype */ 662765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* Mask FC Retry, PwrMgt, MoreData flags to zero */ 66333766368f6532313571534f9112b1796d6651bbeJouni Malinen mask_fc = hdr->frame_control; 66433766368f6532313571534f9112b1796d6651bbeJouni Malinen mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | 66533766368f6532313571534f9112b1796d6651bbeJouni Malinen IEEE80211_FCTL_MOREDATA); 66633766368f6532313571534f9112b1796d6651bbeJouni Malinen put_unaligned(mask_fc, (__le16 *) &aad[0]); 667765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* A1 || A2 || A3 */ 66833766368f6532313571534f9112b1796d6651bbeJouni Malinen memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN); 669765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen} 670765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 671765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 67275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Bergstatic inline void bip_ipn_set64(u8 *d, u64 pn) 67375396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg{ 67475396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d++ = pn; 67575396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d++ = pn >> 8; 67675396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d++ = pn >> 16; 67775396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d++ = pn >> 24; 67875396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d++ = pn >> 32; 67975396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg *d = pn >> 40; 68075396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg} 68175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg 682765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenstatic inline void bip_ipn_swap(u8 *d, const u8 *s) 683765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{ 684765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d++ = s[5]; 685765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d++ = s[4]; 686765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d++ = s[3]; 687765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d++ = s[2]; 688765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d++ = s[1]; 689765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen *d = s[0]; 690765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen} 691765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 692765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 693765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_tx_result 694765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) 695765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{ 696252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg struct sk_buff *skb; 697252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg struct ieee80211_tx_info *info; 698765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct ieee80211_key *key = tx->key; 699765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct ieee80211_mmie *mmie; 70075396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg u8 aad[20]; 70175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg u64 pn64; 702765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 703252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) 704252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg return TX_DROP; 705252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg 706252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg skb = skb_peek(&tx->skbs); 707252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg 708252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg info = IEEE80211_SKB_CB(skb); 709252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg 710813d76694043d00b59475baa1fbfaf54a2eb7fadJohannes Berg if (info->control.hw_key) 711252b86c43225d067468dd182e9ae616ad2532bc8Johannes Berg return TX_CONTINUE; 712765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 713765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) 714765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return TX_DROP; 715765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 716765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie)); 717765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie->element_id = WLAN_EID_MMIE; 718765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie->length = sizeof(*mmie) - 2; 719765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie->key_id = cpu_to_le16(key->conf.keyidx); 720765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 721765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* PN = PN + 1 */ 72275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn); 723765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 72475396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg bip_ipn_set64(mmie->sequence_number, pn64); 725765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 726765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen bip_aad(skb, aad); 727765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 728765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* 729765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) 730765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen */ 73175396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, 73275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg skb->data + 24, skb->len - 24, mmie->mic); 733765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 734765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return TX_CONTINUE; 735765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen} 736765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 737765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 738765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_rx_result 739765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinenieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) 740765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen{ 741765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct sk_buff *skb = rx->skb; 742eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 743765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct ieee80211_key *key = rx->key; 744765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct ieee80211_mmie *mmie; 745765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen u8 aad[20], mic[8], ipn[6]; 746765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 747765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 748765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (!ieee80211_is_mgmt(hdr->frame_control)) 749765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_CONTINUE; 750765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 751a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg /* management frames are already linear */ 752a8286911881948c7a2ecc63ee4224c258cce2da3Johannes Berg 753765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (skb->len < 24 + sizeof(*mmie)) 754765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_DROP_UNUSABLE; 755765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 756765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie = (struct ieee80211_mmie *) 757765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen (skb->data + skb->len - sizeof(*mmie)); 758765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (mmie->element_id != WLAN_EID_MMIE || 759765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen mmie->length != sizeof(*mmie) - 2) 760765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_DROP_UNUSABLE; /* Invalid MMIE */ 761765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 762765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen bip_ipn_swap(ipn, mmie->sequence_number); 763765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 764765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { 765765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen key->u.aes_cmac.replays++; 766765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_DROP_UNUSABLE; 767765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen } 768765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 769eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18Johannes Berg if (!(status->flag & RX_FLAG_DECRYPTED)) { 770765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* hardware didn't decrypt/verify MIC */ 771765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen bip_aad(skb, aad); 77275396ae6d433b49482e377e6f8dbf1f42ad53f3aJohannes Berg ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, 773765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen skb->data + 24, skb->len - 24, mic); 774765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { 775765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen key->u.aes_cmac.icverrors++; 776765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_DROP_UNUSABLE; 777765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen } 778765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen } 779765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 780765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen memcpy(key->u.aes_cmac.rx_pn, ipn, 6); 781765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 782765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen /* Remove MMIE */ 783765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen skb_trim(skb, skb->len - sizeof(*mmie)); 784765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen 785765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen return RX_CONTINUE; 786765cb46a3fc856245ea68a7c961ac87c77e4ae2dJouni Malinen} 787d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky 788d32a102819eef99d4d87019266bea208447be0a0Yoni Divinskyieee80211_tx_result 789d32a102819eef99d4d87019266bea208447be0a0Yoni Divinskyieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) 790d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky{ 791d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky struct sk_buff *skb; 792d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky struct ieee80211_tx_info *info = NULL; 7932475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov ieee80211_tx_result res; 794d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky 795d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky skb_queue_walk(&tx->skbs, skb) { 796d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky info = IEEE80211_SKB_CB(skb); 797d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky 798d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky /* handle hw-only algorithm */ 799d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky if (!info->control.hw_key) 800d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky return TX_DROP; 8012475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 8022475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (tx->key->sta->cipher_scheme) { 8032475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov res = ieee80211_crypto_cs_encrypt(tx, skb); 8042475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov if (res != TX_CONTINUE) 8052475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return res; 8062475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov } 807d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky } 808d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky 809d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky ieee80211_tx_set_protected(tx); 810d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky 811d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky return TX_CONTINUE; 812d32a102819eef99d4d87019266bea208447be0a0Yoni Divinsky} 8132475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 8142475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_rx_result 8152475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanovieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) 8162475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov{ 817aeb136c5b433377324f030b1a50b96eb7a99193bMax Stepanov if (rx->sta && rx->sta->cipher_scheme) 8182475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return ieee80211_crypto_cs_decrypt(rx); 8192475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov 8202475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov return RX_DROP_UNUSABLE; 8212475b1cc0d5283a33144b79f3eba6d401d873962Max Stepanov} 822