Commit 035d0243 authored by gregor kowski's avatar gregor kowski Committed by John W. Linville

b43: add hardware tkip

This add hardware tkip for b43.
Signed-off-by: default avatarGregor Kowski <gregor.kowski@gmail.com>
Acked-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 11ba964d
...@@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]);
cookie = generate_cookie(ring, slot); cookie = generate_cookie(ring, slot);
err = b43_generate_txhdr(ring->dev, header, err = b43_generate_txhdr(ring->dev, header,
skb->data, skb->len, info, cookie); skb, info, cookie);
if (unlikely(err)) { if (unlikely(err)) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots; ring->used_slots = old_used_slots;
......
...@@ -80,6 +80,10 @@ static int modparam_nohwcrypt; ...@@ -80,6 +80,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static int modparam_hwtkip;
module_param_named(hwtkip, modparam_hwtkip, int, 0444);
MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");
static int modparam_qos = 1; static int modparam_qos = 1;
module_param_named(qos, modparam_qos, int, 0444); module_param_named(qos, modparam_qos, int, 0444);
MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
...@@ -834,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) ...@@ -834,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
(index * 2) + 1, addrtmp[1]); (index * 2) + 1, addrtmp[1]);
} }
/* The ucode will use phase1 key with TEK key to decrypt rx packets.
* When a packet is received, the iv32 is checked.
* - if it doesn't the packet is returned without modification (and software
* decryption can be done). That's what happen when iv16 wrap.
* - if it does, the rc4 key is computed, and decryption is tried.
* 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 (it got modified by the ucode).
* 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 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
if (!modparam_hwtkip)
return;
if (b43_new_kidx_api(dev))
pairwise_keys_start = B43_NR_GROUP_KEYS;
B43_WARN_ON(index < pairwise_keys_start);
/* We have four default TX keys and possibly four 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 -= pairwise_keys_start;
B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);
if (b43_debug(dev, B43_DBG_KEYS)) {
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 ? phase1key[i / 2] : 0);
}
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_op_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;
int index = keyconf->hw_key_idx;
if (B43_WARN_ON(!modparam_hwtkip))
return;
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock;
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);
out_unlock:
mutex_unlock(&wl->mutex);
}
static void do_key_write(struct b43_wldev *dev, static void do_key_write(struct b43_wldev *dev,
u8 index, u8 algorithm, u8 index, u8 algorithm,
const u8 *key, size_t key_len, const u8 *mac_addr) const u8 *key, size_t key_len, const u8 *mac_addr)
...@@ -849,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev, ...@@ -849,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev,
if (index >= pairwise_keys_start) if (index >= pairwise_keys_start)
keymac_write(dev, index, NULL); /* First zero out mac. */ keymac_write(dev, index, NULL); /* First zero out mac. */
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 means 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
* 0xffffffff and let's b43_op_update_tkip_key provide a
* correct pair.
*/
rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
} else if (index >= pairwise_keys_start) /* clear it */
rx_tkip_phase1_write(dev, index, 0, NULL);
if (key) if (key)
memcpy(buf, key, key_len); memcpy(buf, key, key_len);
key_write(dev, index, algorithm, buf); key_write(dev, index, algorithm, buf);
...@@ -867,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev, ...@@ -867,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev,
int i; int i;
int pairwise_keys_start; int pairwise_keys_start;
/* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
* - Temporal Encryption Key (128 bits)
* - Temporal Authenticator Tx MIC Key (64 bits)
* - Temporal Authenticator Rx MIC Key (64 bits)
*
* Hardware only store TEK
*/
if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
key_len = 16;
if (key_len > B43_SEC_KEYSIZE) if (key_len > B43_SEC_KEYSIZE)
return -EINVAL; return -EINVAL;
for (i = 0; i < ARRAY_SIZE(dev->key); i++) { for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
...@@ -973,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) ...@@ -973,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
printk(" Algo: %04X/%02X", algo, key->algorithm); printk(" Algo: %04X/%02X", algo, key->algorithm);
if (index >= pairwise_keys_start) { if (index >= pairwise_keys_start) {
if (key->algorithm == B43_SEC_ALGO_TKIP) {
printk(" TKIP: ");
offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
for (i = 0; i < 14; i += 2) {
u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
}
}
rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
((index - pairwise_keys_start) * 2) + 0); ((index - pairwise_keys_start) * 2) + 0);
rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
...@@ -3620,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -3620,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (algorithm == B43_SEC_ALGO_TKIP) { if (algorithm == B43_SEC_ALGO_TKIP &&
/* FIXME: No TKIP hardware encryption for now. */ (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
!modparam_hwtkip)) {
/* We support only pairwise key */
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out_unlock; goto out_unlock;
} }
...@@ -3651,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -3651,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
} }
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (algorithm == B43_SEC_ALGO_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
break; break;
case DISABLE_KEY: { case DISABLE_KEY: {
err = b43_key_clear(dev, key->hw_key_idx); err = b43_key_clear(dev, key->hw_key_idx);
...@@ -4378,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = { ...@@ -4378,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = {
.bss_info_changed = b43_op_bss_info_changed, .bss_info_changed = b43_op_bss_info_changed,
.configure_filter = b43_op_configure_filter, .configure_filter = b43_op_configure_filter,
.set_key = b43_op_set_key, .set_key = b43_op_set_key,
.update_tkip_key = b43_op_update_tkip_key,
.get_stats = b43_op_get_stats, .get_stats = b43_op_get_stats,
.get_tx_stats = b43_op_get_tx_stats, .get_tx_stats = b43_op_get_tx_stats,
.get_tsf = b43_op_get_tsf, .get_tsf = b43_op_get_tsf,
......
...@@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, ...@@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
cookie = generate_cookie(q, pack); cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(q->dev); hdrlen = b43_txhdr_size(q->dev);
err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb,
skb->len, info, cookie); info, cookie);
if (err) if (err)
return err; return err;
......
...@@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate) ...@@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
/* Generate a TX data header. */ /* Generate a TX data header. */
int b43_generate_txhdr(struct b43_wldev *dev, int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr, u8 *_txhdr,
const unsigned char *fragment_data, struct sk_buff *skb_frag,
unsigned int fragment_len,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
u16 cookie) 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; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy; const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr = const struct ieee80211_hdr *wlhdr =
...@@ -258,10 +259,27 @@ int b43_generate_txhdr(struct b43_wldev *dev, ...@@ -258,10 +259,27 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TXH_MAC_KEYALG; B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_hdrlen(fctl); wlhdr_len = ieee80211_hdrlen(fctl);
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, iv_len = min((size_t) info->control.hw_key->iv_len,
ARRAY_SIZE(txhdr->iv)); ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
} }
}
if (b43_is_old_txhdr_format(dev)) { if (b43_is_old_txhdr_format(dev)) {
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
plcp_fragment_len, rate); plcp_fragment_len, rate);
......
...@@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev) ...@@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev)
int b43_generate_txhdr(struct b43_wldev *dev, int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr, u8 * txhdr,
const unsigned char *fragment_data, struct sk_buff *skb_frag,
unsigned int fragment_len,
struct ieee80211_tx_info *txctl, u16 cookie); struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */ /* Transmit Status */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment