Please test if this fixes hwcrypto. Note that we will require v4 firmware with this patch. I will remove v3 firmware support, because it's _really_ a huge pain to support both firmware versions. If someone wants to have v3 support, please fork my tree. Or alternatively simply install v4 firmware, which is a lot easier. ;)
Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h 2006-11-14 16:03:00.000000000 +0100 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h 2006-11-14 18:34:14.000000000 +0100 @@ -620,7 +620,6 @@ struct bcm43xx_stats { struct bcm43xx_key { u8 enabled; - u8 used; u8 algorithm; u8 address[6]; }; Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c 2006-11-14 16:03:00.000000000 +0100 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c 2006-11-15 18:58:51.000000000 +0100 @@ -874,11 +874,12 @@ static void keymac_write(struct bcm43xx_ { u32 addrtmp[2]; + assert(index >= 4 + 4); + memcpy(bcm->key[index].address, addr, 6); /* We have two default TX keys and two default RX keys. * Physical mac 0 is mapped to physical key 8. * So we must adjust the index here. */ - assert(index >= 4 + 4); index -= 8; addrtmp[0] = addr[0]; @@ -912,97 +913,88 @@ static void keymac_write(struct bcm43xx_ } } -static int key_write_common(struct bcm43xx_private *bcm, - u8 index, u8 algorithm, - struct ieee80211_key_conf *keyconf, - const u8 *mac_addr) +static void do_key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, + const u8 *key, size_t key_len, + const u8 *mac_addr) { u8 buf[BCM43xx_SEC_KEYSIZE]; - /* The "index" passed to this function is the - * absolute key table index. - */ - - if ((index >= bcm->max_nr_keys) || - (keyconf && (keyconf->keylen > BCM43xx_SEC_KEYSIZE))) - return -EINVAL; + assert(index < bcm->max_nr_keys); + assert(key_len <= BCM43xx_SEC_KEYSIZE); memset(buf, 0, sizeof(buf)); - if (mac_addr) + if (index >= 8) keymac_write(bcm, index, buf); /* First zero out mac. */ - if (keyconf) - memcpy(buf, keyconf->key, keyconf->keylen); + memcpy(buf, key, key_len); key_write(bcm, index, algorithm, buf); - if (mac_addr) + if (index >= 8) keymac_write(bcm, index, mac_addr); - bcm->key[index].algorithm = algorithm; - bcm->key[index].used = 1; - bcm->key[index].enabled = 1; - if (mac_addr) - memcpy(bcm->key[index].address, mac_addr, 6); - else - memset(bcm->key[index].address, 0, 6); - return 0; + bcm->key[index].algorithm = algorithm; } -static int bcm43xx_default_key_write(struct bcm43xx_private *bcm, - u8 index, u8 algorithm, - struct ieee80211_key_conf *key) +static int bcm43xx_key_write(struct bcm43xx_private *bcm, + int index, u8 algorithm, + const u8 *key, size_t key_len, + const u8 *mac_addr, + struct ieee80211_key_conf *keyconf) { - int err; + int i; - if (index > 3) + if (key_len > BCM43xx_SEC_KEYSIZE) return -EINVAL; + if (index < 0) { + /* Per station key with associated MAC address. + * Look if it already exists, if yes update, otherwise + * allocate a new key. + */ + for (i = 8; i < bcm->max_nr_keys; i++) { + if (compare_ether_addr(bcm->key[i].address, mac_addr) == 0) { + /* found existing */ + index = i; + break; + } + } + if (index < 0) { + for (i = 8; i < bcm->max_nr_keys; i++) { + if (!bcm->key[i].enabled) { + /* found empty */ + index = i; + break; + } + } + } + if (index < 0) { + dprintk(KERN_ERR PFX "Out of hw key memory\n"); + return -ENOBUFS; + } + } else + assert(index <= 3); - /* Write default TX key */ - err = key_write_common(bcm, index, algorithm, - key, NULL); - if (err) - return err; - /* Write default RX key */ - err = key_write_common(bcm, index + 4, algorithm, - key, NULL); - key->hw_key_idx = index; - - return err; -} - -static int bcm43xx_key_write(struct bcm43xx_private *bcm, - u8 algorithm, - struct ieee80211_key_conf *key, - const u8 *mac_addr) -{ - int err; - u8 index; - - for (index = 4 + 4; index < bcm->max_nr_keys; index++) { - if (!bcm->key[index].used) - break; + do_key_write(bcm, index, algorithm, key, key_len, mac_addr); + if (index <= 3) { + /* Default RX key */ + assert(mac_addr == NULL); + do_key_write(bcm, index + 4, algorithm, key, key_len, NULL); } - if (index >= bcm->max_nr_keys) - return -ENOBUFS; + keyconf->hw_key_idx = index; - err = key_write_common(bcm, index, algorithm, - key, mac_addr); - key->hw_key_idx = index; - - return err; + return 0; } static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) { - static const u8 zero[6] = { 0 }; + static const u8 zero[BCM43xx_SEC_KEYSIZE] = { 0 }; unsigned int i; + BUILD_BUG_ON(BCM43xx_SEC_KEYSIZE < ETH_ALEN); for (i = 0; i < bcm->max_nr_keys; i++) { - key_write_common(bcm, i, 0, NULL, - (i >= 4 + 4) ? zero : NULL); - bcm->key[i].used = 0; + do_key_write(bcm, i, BCM43xx_SEC_ALGO_NONE, + zero, BCM43xx_SEC_KEYSIZE, + zero); bcm->key[i].enabled = 0; - bcm->key[i].algorithm = 0; } - dprintk(KERN_INFO PFX "Keys cleared\n"); } /* http://bcm-specs.sipsolutions.net/80211CoreReset */ @@ -1928,9 +1920,15 @@ static int bcm43xx_upload_microcode(stru fwtime = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, BCM43xx_SHM_SH_UCODETIME); - phy->fw = BCM43xx_FW_3; - if (fwrev > 0x128) - phy->fw = BCM43xx_FW_4; + phy->fw = BCM43xx_FW_4; + if (fwrev <= 0x128) { + printk(KERN_ERR PFX "YOUR FIRMWARE IS TOO OLD. Firmware from " + "binary drivers older than version 4.x is unsupported. " + "You must upgrade your firmware files.\n"); + bcm43xx_write32(bcm->wlcore, BCM43xx_MMIO_STATUS_BITFIELD, 0); + err = -EOPNOTSUPP; + goto out; + } printk(KERN_DEBUG PFX "firmware revision %X, patchlevel %X, " "date 20%.2i-%.2i-%.2i %.2i:%.2i:%.2i\n", fwrev, fwpatch, @@ -3630,7 +3628,6 @@ static int bcm43xx_net_set_key(struct ne u8 algorithm; u8 index; int err = -EINVAL; - int i; switch (key->alg) { case ALG_NONE: @@ -3665,33 +3662,33 @@ static int bcm43xx_net_set_key(struct ne err = -ENODEV; goto out_unlock; } - if (bcm43xx_current_phy(bcm)->fw == BCM43xx_FW_3) { - /* No support for HW-crypto with v3 firmware. */ - key->force_sw_encrypt = 1; - err = 0; - goto out_unlock; - } switch (cmd) { case SET_KEY: + key->force_sw_encrypt = 0; if (algorithm == BCM43xx_SEC_ALGO_TKIP) { /* FIXME: No TKIP hardware encryption for now. */ - err = 0; key->force_sw_encrypt = 1; - goto out_unlock; + algorithm = BCM43xx_SEC_ALGO_NONE; } if (is_broadcast_ether_addr(addr)) { /* addr is FF:FF:FF:FF:FF:FF for default keys */ - err = bcm43xx_default_key_write(bcm, index, - algorithm, key); + err = bcm43xx_key_write(bcm, index, algorithm, + key->key, key->keylen, + NULL, key); } else { - err = bcm43xx_key_write(bcm, algorithm, key, - addr); + err = bcm43xx_key_write(bcm, -1, algorithm, + key->key, key->keylen, + addr, key); } - if (err) + if (err) { + key->force_sw_encrypt = 1; goto out_unlock; + } + bcm->key[key->hw_key_idx].enabled = 1; + if (algorithm == BCM43xx_SEC_ALGO_WEP40 || algorithm == BCM43xx_SEC_ALGO_WEP104) { bcm43xx_hf_write(bcm, @@ -3702,21 +3699,23 @@ static int bcm43xx_net_set_key(struct ne bcm43xx_hf_read(bcm) & ~BCM43xx_HF_USEDEFKEYS); } - key->force_sw_encrypt = 0; break; - case DISABLE_KEY: + case DISABLE_KEY: { + static const u8 zero[BCM43xx_SEC_KEYSIZE] = { 0 }; + + algorithm = BCM43xx_SEC_ALGO_NONE; if (is_broadcast_ether_addr(addr)) { - err = key_write_common(bcm, index, 0, NULL, NULL); + err = bcm43xx_key_write(bcm, index, algorithm, + zero, BCM43xx_SEC_KEYSIZE, + NULL, key); } else { - static const u8 zero[6] = { 0 }; - - for (i = 8; i < bcm->max_nr_keys; i++) { - if (compare_ether_addr(bcm->key[i].address, addr) != 0) - continue; - err = key_write_common(bcm, i, 0, NULL, zero); - } + err = bcm43xx_key_write(bcm, -1, algorithm, + zero, BCM43xx_SEC_KEYSIZE, + addr, key); } + bcm->key[key->hw_key_idx].enabled = 0; break; + } case REMOVE_ALL_KEYS: bcm43xx_clear_keys(bcm); err = 0; Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c 2006-11-14 16:03:00.000000000 +0100 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c 2006-11-15 18:16:18.000000000 +0100 @@ -405,7 +405,6 @@ static void generate_txhdr_fw4(struct bc assert(key_idx < bcm->max_nr_keys); key = &(bcm->key[key_idx]); - assert(key->used); if (key->enabled) { /* Hardware appends ICV. */ @@ -648,34 +647,45 @@ void bcm43xx_rx(struct bcm43xx_private * if ((macstat & BCM43xx_RX_MAC_DEC) && !(macstat & BCM43xx_RX_MAC_DECERR)) { + unsigned int keyidx; int wlhdr_len; int iv_len; int icv_len; - /* Remove PROTECTED flag to mark it as decrypted. */ - assert(fctl & IEEE80211_FCTL_PROTECTED); - fctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_control = cpu_to_le16(fctl); - - wlhdr_len = ieee80211_get_hdrlen(fctl); - 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; - } + keyidx = ((macstat & BCM43xx_RX_MAC_KEYIDX) + >> BCM43xx_RX_MAC_KEYIDX_SHIFT); + /* We must adjust the key index here. We want the "physical" + * key index, but the ucode passed it slightly different. + */ + keyidx += 4; + assert((keyidx >= 4) && (keyidx < bcm->max_nr_keys)); + + if (bcm->key[keyidx].algorithm != BCM43xx_SEC_ALGO_NONE) { + /* Remove PROTECTED flag to mark it as decrypted. */ + assert(fctl & IEEE80211_FCTL_PROTECTED); + fctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_control = cpu_to_le16(fctl); + + wlhdr_len = ieee80211_get_hdrlen(fctl); + 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; + } - /* 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); + /* 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; + status.flag |= RX_FLAG_DECRYPTED; + } } status.signal = bcm43xx_rssi_postprocess(bcm, jssi, -- Greetings Michael. - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html