diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-08-04 16:37:44 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-22 16:29:58 -0400 |
commit | 2bb057d07a0bc17475a7bf897fc41667ab08b73f (patch) | |
tree | 55461e52caa34a45a67aaf9e3f1c608f96c77d59 /drivers/net/wireless/rt2x00/rt2x00mac.c | |
parent | 8e7cdbb6333ef7654e708bd60e50a123688dcd7b (diff) | |
download | linux-2bb057d07a0bc17475a7bf897fc41667ab08b73f.tar.gz |
rt2x00: Implement HW encryption
Various rt2x00 devices support hardware encryption.
Most of them require the IV/EIV to be generated by mac80211,
but require it to be provided seperately instead of within
the frame itself. This means that rt2x00lib should extract
the data from the frame and place it in the frame descriptor.
During RX the IV/EIV is provided in the descriptor by the
hardware which means that it should be inserted into the
frame by rt2x00lib.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00mac.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 110 |
1 files changed, 102 insertions, 8 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4b9fde903cd6..3af427339417 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -36,22 +36,22 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); struct ieee80211_tx_info *rts_info; struct sk_buff *skb; - int size; + unsigned int data_length; int retval = 0; if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) - size = sizeof(struct ieee80211_cts); + data_length = sizeof(struct ieee80211_cts); else - size = sizeof(struct ieee80211_rts); + data_length = sizeof(struct ieee80211_rts); - skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); + skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom); if (unlikely(!skb)) { WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); return -ENOMEM; } skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); - skb_put(skb, size); + skb_put(skb, data_length); /* * Copy TX information over from original frame to @@ -64,7 +64,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->control.hw_key = NULL; rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; @@ -74,13 +73,24 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + skb->do_not_encrypt = 1; + + /* + * RTS/CTS frame should use the length of the frame plus any + * encryption overhead that will be added by the hardware. + */ +#ifdef CONFIG_RT2X00_LIB_CRYPTO + if (!frag_skb->do_not_encrypt) + data_length += rt2x00crypto_tx_overhead(tx_info); +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); else ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, - frag_skb->data, size, tx_info, + frag_skb->data, data_length, tx_info, (struct ieee80211_rts *)(skb->data)); retval = rt2x00queue_write_tx_frame(queue, skb); @@ -464,6 +474,90 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); +#ifdef CONFIG_RT2X00_LIB_CRYPTO +int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int (*set_key) (struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); + struct rt2x00lib_crypto crypto; + + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + return -EOPNOTSUPP; + else if (key->keylen > 32) + return -ENOSPC; + + memset(&crypto, 0, sizeof(crypto)); + + /* + * When in STA mode, bssidx is always 0 otherwise local_address[5] + * contains the bss number, see BSS_ID_MASK comments for details. + */ + if (rt2x00dev->intf_sta_count) + crypto.bssidx = 0; + else + crypto.bssidx = + local_address[5] & (rt2x00dev->ops->max_ap_intf - 1); + + crypto.cipher = rt2x00crypto_key_to_cipher(key); + if (crypto.cipher == CIPHER_NONE) + return -EOPNOTSUPP; + + crypto.cmd = cmd; + crypto.address = address; + + if (crypto.cipher == CIPHER_TKIP) { + if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY) + memcpy(&crypto.key, + &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY], + sizeof(crypto.key)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(&crypto.tx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + sizeof(crypto.tx_mic)); + + if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY) + memcpy(&crypto.rx_mic, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + sizeof(crypto.rx_mic)); + } else + memcpy(&crypto.key, &key->key[0], key->keylen); + + /* + * Each BSS has a maximum of 4 shared keys. + * Shared key index values: + * 0) BSS0 key0 + * 1) BSS0 key1 + * ... + * 4) BSS1 key0 + * ... + * 8) BSS2 key0 + * ... + * Both pairwise as shared key indeces are determined by + * driver. This is required because the hardware requires + * keys to be assigned in correct order (When key 1 is + * provided but key 0 is not, then the key is not found + * by the hardware during RX). + */ + key->hw_key_idx = 0; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + set_key = rt2x00dev->ops->lib->config_pairwise_key; + else + set_key = rt2x00dev->ops->lib->config_shared_key; + + if (!set_key) + return -EOPNOTSUPP; + + return set_key(rt2x00dev, &crypto, key); +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_key); +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ + int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { |