This patch reworks the various hardware crypto related flags to make them more local, i.e. put them with each key or each packet instead of into the hw struct. Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx> --- drivers/net/wireless/adm8211.c | 3 - drivers/net/wireless/b43/main.c | 24 +++++++---- drivers/net/wireless/b43/xmit.c | 28 ------------- drivers/net/wireless/iwl-base.c | 5 +- drivers/net/wireless/p54common.c | 3 - drivers/net/wireless/rtl8187_dev.c | 3 - drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 1 include/net/mac80211.h | 49 +++++++----------------- net/mac80211/rx.c | 24 ++++------- net/mac80211/tx.c | 5 -- net/mac80211/wpa.c | 43 ++++++--------------- 11 files changed, 63 insertions(+), 125 deletions(-) --- wireless-dev.orig/include/net/mac80211.h 2007-08-21 22:27:14.459502183 +0200 +++ wireless-dev/include/net/mac80211.h 2007-08-22 10:19:21.789500061 +0200 @@ -245,6 +245,8 @@ struct ieee80211_rx_status { #define RX_FLAG_RADIOTAP (1<<2) #define RX_FLAG_FAILED_FCS_CRC (1<<3) #define RX_FLAG_FAILED_PLCP_CRC (1<<4) +#define RX_FLAG_MMIC_STRIPPED (1<<5) +#define RX_FLAG_IV_STRIPPED (1<<6) int flag; }; @@ -407,6 +409,16 @@ typedef enum { * that situation it should reject that key. */ #define IEEE80211_KEY_FLAG_WMM_STA (1<<0) +/* + * This flag should be set by the driver if it requires + * IV generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_IV (1<<1) +/* + * This flag should be set by the driver if it requires + * MMIC generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1<<2) struct ieee80211_key_conf { /* @@ -476,17 +488,7 @@ struct ieee80211_hw { */ #define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) - /* - * Some devices handle decryption internally and do not - * indicate whether the frame was encrypted (unencrypted frames - * will be dropped by the hardware, unless specifically allowed - * through.) - * It is permissible to not handle all encrypted frames and fall - * back to software encryption; however, if this flag is set - * unencrypted frames must be dropped unless the driver is told - * otherwise via the set_ieee8021x() callback. - */ -#define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2) +/* hole at 2 */ /* Whether RX frames passed to ieee80211_rx() include FCS in the end */ #define IEEE80211_HW_RX_INCLUDES_FCS (1<<3) @@ -499,32 +501,13 @@ struct ieee80211_hw { * can fetch them with ieee80211_get_buffered_bc(). */ #define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4) - /* - * This flag is only relevant if hardware encryption is used. - * If set, it has two meanings: - * 1) the IV and ICV are present in received frames that have - * been decrypted (unless IEEE80211_HW_DEVICE_HIDES_WEP is - * also set) - * 2) on transmission, the IV should be generated in software. - * - * Please let us know if you *don't* use this flag, the stack would - * really like to be able to get the IV to keep key statistics - * accurate. - */ -#define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) +/* hole at 5 */ /* hole at 6 */ /* hole at 7 */ - /* - * Some devices handle Michael MIC internally and do not include MIC in - * the received packets passed up. This flag must be set for such - * devices. The 'encryption' frame control bit is expected to be still - * set in the IEEE 802.11 header with this option unlike with the - * IEEE80211_HW_DEVICE_HIDES_WEP flag. - */ -#define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8) +/* hole at 8 */ /* * Device has multicast filters. @@ -537,8 +520,6 @@ struct ieee80211_hw { * specified in the device's EEPROM */ #define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11) - /* calculate Michael MIC for an MSDU when doing hwcrypto */ -#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12) /* Do TKIP phase1 key mixing in stack to support cards only do * phase2 key mixing when doing hwcrypto */ #define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13) --- wireless-dev.orig/net/mac80211/wpa.c 2007-08-21 22:29:21.399502183 +0200 +++ wireless-dev/net/mac80211/wpa.c 2007-08-22 10:25:17.689500061 +0200 @@ -103,7 +103,7 @@ ieee80211_tx_h_michael_mic_add(struct ie if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !tx->fragmented && - !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ @@ -170,7 +170,7 @@ ieee80211_rx_h_michael_mic_verify(struct /* * No way to verify the MIC if the hardware stripped it */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC) + if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) return TXRX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || @@ -183,19 +183,6 @@ ieee80211_rx_h_michael_mic_verify(struct } #endif /* CONFIG_HOSTAPD_WPA_TESTING */ - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (skb->len < MICHAEL_MIC_LEN) - return TXRX_DROP; - } - /* Need to verify Michael MIC sometimes in software even when - * hwaccel is used. Atheros ar5212: fragmented frames and QoS - * frames. */ - if (!rx->fragmented && !wpa_test) - goto remove_mic; - } - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -249,7 +236,6 @@ ieee80211_rx_h_michael_mic_verify(struct return TXRX_DROP; } - remove_mic: /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); @@ -401,7 +387,7 @@ ieee80211_tx_h_tkip_encrypt(struct ieee8 #endif /* CONFIG_HOSTAPD_WPA_TESTING */ if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -478,11 +464,13 @@ ieee80211_rx_h_tkip_decrypt(struct ieee8 } #endif /* CONFIG_HOSTAPD_WPA_TESTING */ - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { - /* Hardware takes care of all processing, including - * replay protection, so no need to continue here. */ + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { + if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { + /* + * Hardware took care of all processing, including + * replay protection, and stripped the ICV/IV so + * we cannot do any checks here. + */ return TXRX_CONTINUE; } @@ -721,7 +709,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee8 ieee80211_tx_set_iswep(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -772,8 +760,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee8 return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -792,10 +779,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee8 return TXRX_DROP; } - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - /* hwaccel has already decrypted frame and verified MIC */ - } else { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + /* hardware didn't decrypt/verify MIC */ u8 *scratch, *b_0, *aad; scratch = key->u.ccmp.rx_crypto_buf; --- wireless-dev.orig/net/mac80211/rx.c 2007-08-21 22:32:39.489502183 +0200 +++ wireless-dev/net/mac80211/rx.c 2007-08-22 10:20:23.119500061 +0200 @@ -379,7 +379,8 @@ ieee80211_rx_h_load_key(struct ieee80211 * we somehow allow the driver to tell us which key * the hardware used if this flag is set? */ - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); @@ -555,8 +556,8 @@ ieee80211_rx_h_wep_weak_iv_detection(str return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -580,15 +581,14 @@ ieee80211_rx_h_wep_decrypt(struct ieee80 return TXRX_DROP; } - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); return TXRX_DROP; } - } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { + } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - 4); @@ -918,13 +918,10 @@ static ieee80211_txrx_result ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) { /* - * Pass through unencrypted frames if the hardware might have - * decrypted them already without telling us, but that can only - * be true if we either didn't find a key or the found key is - * uploaded to the hardware. + * Pass through unencrypted frames if the hardware has + * decrypted them already. */ - if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && - (!rx->key || (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))) + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ @@ -1368,8 +1365,7 @@ static void ieee80211_rx_michael_mic_rep goto ignore; } - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { + if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { /* AP with Pairwise keys support should never receive Michael * MIC errors for non-zero keyidx because these are reserved * for group keys and only the AP is sending real multicast --- wireless-dev.orig/net/mac80211/tx.c 2007-08-21 22:37:34.039502183 +0200 +++ wireless-dev/net/mac80211/tx.c 2007-08-21 22:38:16.709502183 +0200 @@ -540,9 +540,8 @@ static int wep_encrypt_skb(struct ieee80 return -1; } else { tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == - NULL) + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; } } --- wireless-dev.orig/drivers/net/wireless/iwl-base.c 2007-08-21 22:40:18.729502183 +0200 +++ wireless-dev/drivers/net/wireless/iwl-base.c 2007-08-21 22:40:52.119502183 +0200 @@ -7928,6 +7928,8 @@ static int iwl_mac_set_key(struct ieee80 * conf->sw_decrypt = 0; */ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); + + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; } IWL_DEBUG_MAC80211("leave\n"); @@ -9157,8 +9159,7 @@ static int iwl_pci_probe(struct pci_dev hw->max_signal = 100; /* link quality indication (%) */ /* Tell mac80211 our Tx characteristics */ - hw->flags = IEEE80211_HW_WEP_INCLUDE_IV | - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->queues = 4; #if IWL == 4965 --- wireless-dev.orig/drivers/net/wireless/rtl8187_dev.c 2007-08-21 22:41:47.219502183 +0200 +++ wireless-dev/drivers/net/wireless/rtl8187_dev.c 2007-08-22 01:00:18.989502183 +0200 @@ -620,8 +620,7 @@ static int __devinit rtl8187_probe(struc priv->modes[1].channels = priv->channels; priv->mode = IEEE80211_IF_TYPE_MGMT; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV; + IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; dev->max_rssi = 65; --- wireless-dev.orig/drivers/net/wireless/adm8211.c 2007-08-21 22:42:38.949502183 +0200 +++ wireless-dev/drivers/net/wireless/adm8211.c 2007-08-22 01:00:18.959502183 +0200 @@ -1975,8 +1975,7 @@ static int __devinit adm8211_probe(struc SET_IEEE80211_PERM_ADDR(dev, perm_addr); dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); - dev->flags = IEEE80211_HW_WEP_INCLUDE_IV | - IEEE80211_HW_MULTICAST_FILTER; + dev->flags = IEEE80211_HW_MULTICAST_FILTER; // however, IEEE80211_HW_RX_INCLUDES_FCS in promisc mode dev->channel_change_time = 1000; --- wireless-dev.orig/drivers/net/wireless/b43/main.c 2007-08-21 22:43:25.559502183 +0200 +++ wireless-dev/drivers/net/wireless/b43/main.c 2007-08-22 10:19:20.529500061 +0200 @@ -720,13 +720,17 @@ static void key_write(struct b43_wldev * static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr) { u32 addrtmp[2]; + u8 start = 8; - B43_WARN_ON(index < 4 + 4); - /* We have two default TX keys and two default RX keys. - * Physical mac 0 is mapped to physical key 8. + if (b43_new_kidx_api(dev)) + start = 4; + + B43_WARN_ON(index < start); + /* We have two default TX keys and possibly two default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8. * So we must adjust the index here. */ - index -= 8; + index -= start; addrtmp[0] = addr[0]; addrtmp[0] |= ((u32) (addr[1]) << 8); @@ -764,16 +768,20 @@ static void do_key_write(struct b43_wlde const u8 * key, size_t key_len, const u8 * mac_addr) { u8 buf[B43_SEC_KEYSIZE]; + u8 start = 8; + + if (b43_new_kidx_api(dev)) + start = 4; B43_WARN_ON(index >= dev->max_nr_keys); B43_WARN_ON(key_len > B43_SEC_KEYSIZE); memset(buf, 0, sizeof(buf)); - if (index >= 8) + if (index >= start) keymac_write(dev, index, buf); /* First zero out mac. */ memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); - if (index >= 8) + if (index >= start) keymac_write(dev, index, mac_addr); dev->key[index].algorithm = algorithm; @@ -2923,6 +2931,7 @@ static int b43_dev_set_key(struct ieee80 b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; case DISABLE_KEY: { static const u8 zero[B43_SEC_KEYSIZE] = { 0 }; @@ -3915,8 +3924,7 @@ static int b43_wireless_init(struct ssb_ } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_DEVICE_HIDES_WEP | IEEE80211_HW_WEP_INCLUDE_IV; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; --- wireless-dev.orig/drivers/net/wireless/b43/xmit.c 2007-08-21 22:44:17.799502183 +0200 +++ wireless-dev/drivers/net/wireless/b43/xmit.c 2007-08-22 10:19:20.669500061 +0200 @@ -489,8 +489,6 @@ void b43_rx(struct b43_wldev *dev, struc if ((macstat & B43_RX_MAC_DEC) && !(macstat & B43_RX_MAC_DECERR)) { unsigned int keyidx; int wlhdr_len; - int iv_len; - int icv_len; keyidx = ((macstat & B43_RX_MAC_KEYIDX) >> B43_RX_MAC_KEYIDX_SHIFT); @@ -501,38 +499,12 @@ void b43_rx(struct b43_wldev *dev, struc B43_WARN_ON(keyidx >= dev->max_nr_keys); if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { - /* Remove PROTECTED flag to mark it as decrypted. */ - B43_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED)); - fctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_control = cpu_to_le16(fctl); - wlhdr_len = ieee80211_get_hdrlen(fctl); if (unlikely(skb->len < (wlhdr_len + 3))) { b43dbg(dev->wl, "RX: Packet size underrun (3)\n"); goto drop; } - if (skb->data[wlhdr_len + 3] & (1 << 5)) { - /* The Ext-IV Bit is set in the "KeyID" - * octet of the IV. - */ - iv_len = 8; - icv_len = 8; - } else { - iv_len = 4; - icv_len = 4; - } - if (unlikely(skb->len < (wlhdr_len + iv_len + icv_len))) { - b43dbg(dev->wl, - "RX: Packet size underrun (4)\n"); - goto drop; - } - /* Remove the IV */ - memmove(skb->data + iv_len, skb->data, wlhdr_len); - skb_pull(skb, iv_len); - /* Remove the ICV */ - skb_trim(skb, skb->len - icv_len); - status.flag |= RX_FLAG_DECRYPTED; } } --- wireless-dev.orig/drivers/net/wireless/p54common.c 2007-08-21 22:42:59.489502183 +0200 +++ wireless-dev/drivers/net/wireless/p54common.c 2007-08-22 01:00:19.019502183 +0200 @@ -892,8 +892,7 @@ struct ieee80211_hw *p54_init_common(siz priv->modes[0].num_channels = ARRAY_SIZE(p54_channels); priv->modes[0].channels = priv->channels; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV; + IEEE80211_HW_RX_INCLUDES_FCS; dev->channel_change_time = 1000; /* TODO: find actual value */ dev->max_rssi = 100; --- wireless-dev.orig/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-08-21 22:46:32.209502183 +0200 +++ wireless-dev/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-08-22 01:00:19.059502183 +0200 @@ -874,7 +874,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(str mac->modes[1].channels = mac->channels; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV | IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED | IEEE80211_HW_MULTICAST_FILTER; hw->max_rssi = 100; -- - To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html