This add hardware tkip for b43. It uncovered a bug in b43_write_probe_resp_template : it is writing at the wrong shm offset, it is in the B43_SHM_SH_TKIPTSCTTAK zone. This patch comments these writes. There is another problem with b43_new_kidx_api, that allow 54 pairwise key (max key is 58), but there is only 50 entry in TKIPTSCTTAK (and may be RCMTA). Finally there is an issue in the mac80211 tkip code that won't always call update_tkip_key. A patch to workaround that is also provided. Signed-off-by: Gregor Kowski <gregor.kowski@xxxxxxxxx> Index: linux-2.6/drivers/net/wireless/b43/dma.c =================================================================== --- linux-2.6.orig/drivers/net/wireless/b43/dma.c 2009-06-07 21:33:42.000000000 +0000 +++ linux-2.6/drivers/net/wireless/b43/dma.c 2009-06-07 21:41:58.000000000 +0000 @@ -1188,7 +1188,7 @@ header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, info, cookie); + skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; Index: linux-2.6/drivers/net/wireless/b43/main.c =================================================================== --- linux-2.6.orig/drivers/net/wireless/b43/main.c 2009-06-07 21:33:42.000000000 +0000 +++ linux-2.6/drivers/net/wireless/b43/main.c 2009-06-07 21:41:58.000000000 +0000 @@ -860,6 +860,66 @@ } } +/* The ucode will use this with key to decrypt rx packets. + * It will first check if the iv32 match, + * - if they don't it returns the packet without decryption (and software + * decryption can be done). That's what happen when iv16 wrap. + * - if they do, the rc4 key is computed with tkip phase2, and + * the wep decryption is tried on the packet. Either it will + * success and B43_RX_MAC_DEC is returned, either it fails + * and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned and the packet + * is not usable (wrong key used on it). + * So in order to never have B43_RX_MAC_DECERR, we should provide + * a iv32 and phase1key that match. Because we drop packets in case of + * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all + * packets will be lost without higher layer knowing (ie no resync possible + * until next wrap). + * + * NOTE : this should support 50 key like RCMTA because + * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50 + */ +static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, + u16 *phase1key) +{ + unsigned int i; + u32 offset; + u8 per_sta_keys_start = 8; + + if (b43_new_kidx_api(dev)) + per_sta_keys_start = 4; + + B43_WARN_ON(index < per_sta_keys_start); + /* We have two default TX keys and possibly two default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8, depending + * on the firmware version. + * So we must adjust the index here. + */ + index -= per_sta_keys_start; + + b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n", + index, iv32); + /* Write the key to the RX tkip shared mem */ + offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4); + for (i = 0; i < 10; i += 2) { + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, phase1key[i/2]); + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32); + b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32>>16); +} + +static void b43_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int index = keyconf->hw_key_idx; + keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ + + rx_tkip_phase1_write(dev, index, iv32, phase1key); + keymac_write(dev, index, addr); +} + static void do_key_write(struct b43_wldev *dev, u8 index, u8 algorithm, const u8 *key, size_t key_len, const u8 *mac_addr) @@ -878,6 +938,19 @@ if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); + if (algorithm == B43_SEC_ALGO_TKIP) { + /* + * We should provide an initial iv32, phase1key pair. + * We could start with iv32=0 and compute the corresponding + * phase1key, but this mean calling ieee80211_get_tkip_key + * with a fake skb (or export other tkip function). + * Because we are lazy we hope iv32 won't start with + * 0xffff and let's b43_mac_update_tkip_key provide a + * correct pair. + */ + rx_tkip_phase1_write(dev, index, 0xffff, (u16*)buf); + } else /* clear it */ + rx_tkip_phase1_write(dev, index, 0, (u16*)buf); if (index >= per_sta_keys_start) keymac_write(dev, index, mac_addr); @@ -893,6 +966,11 @@ int i; int sta_keys_start; + if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32) { + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + key_len = 16; + } if (key_len > B43_SEC_KEYSIZE) return -EINVAL; for (i = 0; i < dev->max_nr_keys; i++) { @@ -954,6 +1032,7 @@ b43_key_clear(dev, i); } +/* XXX add tkip dump */ static void b43_dump_keymemory(struct b43_wldev *dev) { unsigned int i, index, offset; @@ -1545,10 +1624,13 @@ /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ + /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ +#if 0 b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); +#endif size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, @@ -2966,6 +3048,9 @@ static void b43_security_init(struct b43_wldev *dev) { + /* FIXME : for b43_new_kidx_api, there can be 54 key + * instead of 50 in RCMTA and TKIPTSCTTAK. + */ dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); @@ -3651,8 +3736,10 @@ switch (cmd) { case SET_KEY: - if (algorithm == B43_SEC_ALGO_TKIP) { - /* FIXME: No TKIP hardware encryption for now. */ + if (algorithm == B43_SEC_ALGO_TKIP && + (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) || + key->flags & IEEE80211_KEY_FLAG_WMM_STA )) { + /* We support only one rx queue (no QOS) and pairwise key */ err = -EOPNOTSUPP; goto out_unlock; } @@ -4452,6 +4539,7 @@ .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, + .update_tkip_key = b43_mac_update_tkip_key, .get_stats = b43_op_get_stats, .get_tx_stats = b43_op_get_tx_stats, .get_tsf = b43_op_get_tsf, Index: linux-2.6/drivers/net/wireless/b43/pio.c =================================================================== --- linux-2.6.orig/drivers/net/wireless/b43/pio.c 2009-06-07 21:33:42.000000000 +0000 +++ linux-2.6/drivers/net/wireless/b43/pio.c 2009-06-07 21:41:58.000000000 +0000 @@ -461,8 +461,8 @@ cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); - err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, info, cookie); + err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb, + info, cookie); if (err) return err; Index: linux-2.6/drivers/net/wireless/b43/xmit.c =================================================================== --- linux-2.6.orig/drivers/net/wireless/b43/xmit.c 2009-06-07 21:33:42.000000000 +0000 +++ linux-2.6/drivers/net/wireless/b43/xmit.c 2009-06-07 21:42:38.000000000 +0000 @@ -181,11 +181,12 @@ /* Generate a TX data header. */ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *info, u16 cookie) { + const unsigned char *fragment_data = skb_frag->data; + unsigned int fragment_len = skb_frag->len; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = @@ -259,9 +260,25 @@ mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.hw_key->iv_len, - ARRAY_SIZE(txhdr->iv)); - memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + if (key->algorithm == B43_SEC_ALGO_TKIP) { + u16 phase1key[5]; + int i; + /* we give the phase1key and iv16 here, the key is stored in + * shm. With that the hardware can do phase 2 and encryption. + */ + ieee80211_get_tkip_key(info->control.hw_key, skb_frag, IEEE80211_TKIP_P1_KEY, (u8*)phase1key); + /* phase1key is in host endian */ + for (i = 0; i < 5; i++) + phase1key[i] = cpu_to_le16(phase1key[i]); + + memcpy(txhdr->iv, phase1key, 10); + /* iv16 */ + memcpy(txhdr->iv+10, ((u8 *) wlhdr) + wlhdr_len, 3); + } else { + iv_len = min((size_t) info->control.hw_key->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } } if (b43_is_old_txhdr_format(dev)) { b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), Index: linux-2.6/drivers/net/wireless/b43/xmit.h =================================================================== --- linux-2.6.orig/drivers/net/wireless/b43/xmit.h 2009-06-07 21:33:42.000000000 +0000 +++ linux-2.6/drivers/net/wireless/b43/xmit.h 2009-06-07 21:41:58.000000000 +0000 @@ -176,8 +176,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */