diff options
author | gregor kowski <gregor.kowski@gmail.com> | 2009-08-19 16:35:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 11:36:08 -0400 |
commit | 035d0243ebbdbd5f8f07d6ce378c9a9b36415bc9 (patch) | |
tree | be26939b0411ed337c583927e2f8866113e12f5d /drivers/net/wireless/b43/main.c | |
parent | 11ba964d4f936609a04e8b9f2051f6027ef761ae (diff) |
b43: add hardware tkip
This add hardware tkip for b43.
Signed-off-by: Gregor Kowski <gregor.kowski@gmail.com>
Acked-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 78ddbc7f836b..f5bdf1cae1d1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -80,6 +80,10 @@ static int modparam_nohwcrypt; | |||
80 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 80 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); |
81 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 81 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
82 | 82 | ||
83 | static int modparam_hwtkip; | ||
84 | module_param_named(hwtkip, modparam_hwtkip, int, 0444); | ||
85 | MODULE_PARM_DESC(hwtkip, "Enable hardware tkip."); | ||
86 | |||
83 | static int modparam_qos = 1; | 87 | static int modparam_qos = 1; |
84 | module_param_named(qos, modparam_qos, int, 0444); | 88 | module_param_named(qos, modparam_qos, int, 0444); |
85 | MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); | 89 | 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 | (index * 2) + 1, addrtmp[1]); | 838 | (index * 2) + 1, addrtmp[1]); |
835 | } | 839 | } |
836 | 840 | ||
841 | /* The ucode will use phase1 key with TEK key to decrypt rx packets. | ||
842 | * When a packet is received, the iv32 is checked. | ||
843 | * - if it doesn't the packet is returned without modification (and software | ||
844 | * decryption can be done). That's what happen when iv16 wrap. | ||
845 | * - if it does, the rc4 key is computed, and decryption is tried. | ||
846 | * Either it will success and B43_RX_MAC_DEC is returned, | ||
847 | * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned | ||
848 | * and the packet is not usable (it got modified by the ucode). | ||
849 | * So in order to never have B43_RX_MAC_DECERR, we should provide | ||
850 | * a iv32 and phase1key that match. Because we drop packets in case of | ||
851 | * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all | ||
852 | * packets will be lost without higher layer knowing (ie no resync possible | ||
853 | * until next wrap). | ||
854 | * | ||
855 | * NOTE : this should support 50 key like RCMTA because | ||
856 | * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50 | ||
857 | */ | ||
858 | static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, | ||
859 | u16 *phase1key) | ||
860 | { | ||
861 | unsigned int i; | ||
862 | u32 offset; | ||
863 | u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; | ||
864 | |||
865 | if (!modparam_hwtkip) | ||
866 | return; | ||
867 | |||
868 | if (b43_new_kidx_api(dev)) | ||
869 | pairwise_keys_start = B43_NR_GROUP_KEYS; | ||
870 | |||
871 | B43_WARN_ON(index < pairwise_keys_start); | ||
872 | /* We have four default TX keys and possibly four default RX keys. | ||
873 | * Physical mac 0 is mapped to physical key 4 or 8, depending | ||
874 | * on the firmware version. | ||
875 | * So we must adjust the index here. | ||
876 | */ | ||
877 | index -= pairwise_keys_start; | ||
878 | B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); | ||
879 | |||
880 | if (b43_debug(dev, B43_DBG_KEYS)) { | ||
881 | b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n", | ||
882 | index, iv32); | ||
883 | } | ||
884 | /* Write the key to the RX tkip shared mem */ | ||
885 | offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4); | ||
886 | for (i = 0; i < 10; i += 2) { | ||
887 | b43_shm_write16(dev, B43_SHM_SHARED, offset + i, | ||
888 | phase1key ? phase1key[i / 2] : 0); | ||
889 | } | ||
890 | b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32); | ||
891 | b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16); | ||
892 | } | ||
893 | |||
894 | static void b43_op_update_tkip_key(struct ieee80211_hw *hw, | ||
895 | struct ieee80211_key_conf *keyconf, const u8 *addr, | ||
896 | u32 iv32, u16 *phase1key) | ||
897 | { | ||
898 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
899 | struct b43_wldev *dev; | ||
900 | int index = keyconf->hw_key_idx; | ||
901 | |||
902 | if (B43_WARN_ON(!modparam_hwtkip)) | ||
903 | return; | ||
904 | |||
905 | mutex_lock(&wl->mutex); | ||
906 | |||
907 | dev = wl->current_dev; | ||
908 | if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) | ||
909 | goto out_unlock; | ||
910 | |||
911 | keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ | ||
912 | |||
913 | rx_tkip_phase1_write(dev, index, iv32, phase1key); | ||
914 | keymac_write(dev, index, addr); | ||
915 | |||
916 | out_unlock: | ||
917 | mutex_unlock(&wl->mutex); | ||
918 | } | ||
919 | |||
837 | static void do_key_write(struct b43_wldev *dev, | 920 | static void do_key_write(struct b43_wldev *dev, |
838 | u8 index, u8 algorithm, | 921 | u8 index, u8 algorithm, |
839 | const u8 *key, size_t key_len, const u8 *mac_addr) | 922 | 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 | 932 | ||
850 | if (index >= pairwise_keys_start) | 933 | if (index >= pairwise_keys_start) |
851 | keymac_write(dev, index, NULL); /* First zero out mac. */ | 934 | keymac_write(dev, index, NULL); /* First zero out mac. */ |
935 | if (algorithm == B43_SEC_ALGO_TKIP) { | ||
936 | /* | ||
937 | * We should provide an initial iv32, phase1key pair. | ||
938 | * We could start with iv32=0 and compute the corresponding | ||
939 | * phase1key, but this means calling ieee80211_get_tkip_key | ||
940 | * with a fake skb (or export other tkip function). | ||
941 | * Because we are lazy we hope iv32 won't start with | ||
942 | * 0xffffffff and let's b43_op_update_tkip_key provide a | ||
943 | * correct pair. | ||
944 | */ | ||
945 | rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf); | ||
946 | } else if (index >= pairwise_keys_start) /* clear it */ | ||
947 | rx_tkip_phase1_write(dev, index, 0, NULL); | ||
852 | if (key) | 948 | if (key) |
853 | memcpy(buf, key, key_len); | 949 | memcpy(buf, key, key_len); |
854 | key_write(dev, index, algorithm, buf); | 950 | key_write(dev, index, algorithm, buf); |
@@ -867,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev, | |||
867 | int i; | 963 | int i; |
868 | int pairwise_keys_start; | 964 | int pairwise_keys_start; |
869 | 965 | ||
966 | /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block: | ||
967 | * - Temporal Encryption Key (128 bits) | ||
968 | * - Temporal Authenticator Tx MIC Key (64 bits) | ||
969 | * - Temporal Authenticator Rx MIC Key (64 bits) | ||
970 | * | ||
971 | * Hardware only store TEK | ||
972 | */ | ||
973 | if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32) | ||
974 | key_len = 16; | ||
870 | if (key_len > B43_SEC_KEYSIZE) | 975 | if (key_len > B43_SEC_KEYSIZE) |
871 | return -EINVAL; | 976 | return -EINVAL; |
872 | for (i = 0; i < ARRAY_SIZE(dev->key); i++) { | 977 | for (i = 0; i < ARRAY_SIZE(dev->key); i++) { |
@@ -973,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) | |||
973 | printk(" Algo: %04X/%02X", algo, key->algorithm); | 1078 | printk(" Algo: %04X/%02X", algo, key->algorithm); |
974 | 1079 | ||
975 | if (index >= pairwise_keys_start) { | 1080 | if (index >= pairwise_keys_start) { |
1081 | if (key->algorithm == B43_SEC_ALGO_TKIP) { | ||
1082 | printk(" TKIP: "); | ||
1083 | offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4); | ||
1084 | for (i = 0; i < 14; i += 2) { | ||
1085 | u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); | ||
1086 | printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); | ||
1087 | } | ||
1088 | } | ||
976 | rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, | 1089 | rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, |
977 | ((index - pairwise_keys_start) * 2) + 0); | 1090 | ((index - pairwise_keys_start) * 2) + 0); |
978 | rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, | 1091 | 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 | 3733 | ||
3621 | switch (cmd) { | 3734 | switch (cmd) { |
3622 | case SET_KEY: | 3735 | case SET_KEY: |
3623 | if (algorithm == B43_SEC_ALGO_TKIP) { | 3736 | if (algorithm == B43_SEC_ALGO_TKIP && |
3624 | /* FIXME: No TKIP hardware encryption for now. */ | 3737 | (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) || |
3738 | !modparam_hwtkip)) { | ||
3739 | /* We support only pairwise key */ | ||
3625 | err = -EOPNOTSUPP; | 3740 | err = -EOPNOTSUPP; |
3626 | goto out_unlock; | 3741 | goto out_unlock; |
3627 | } | 3742 | } |
@@ -3651,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3651 | b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); | 3766 | b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); |
3652 | } | 3767 | } |
3653 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 3768 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
3769 | if (algorithm == B43_SEC_ALGO_TKIP) | ||
3770 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
3654 | break; | 3771 | break; |
3655 | case DISABLE_KEY: { | 3772 | case DISABLE_KEY: { |
3656 | err = b43_key_clear(dev, key->hw_key_idx); | 3773 | err = b43_key_clear(dev, key->hw_key_idx); |
@@ -4378,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
4378 | .bss_info_changed = b43_op_bss_info_changed, | 4495 | .bss_info_changed = b43_op_bss_info_changed, |
4379 | .configure_filter = b43_op_configure_filter, | 4496 | .configure_filter = b43_op_configure_filter, |
4380 | .set_key = b43_op_set_key, | 4497 | .set_key = b43_op_set_key, |
4498 | .update_tkip_key = b43_op_update_tkip_key, | ||
4381 | .get_stats = b43_op_get_stats, | 4499 | .get_stats = b43_op_get_stats, |
4382 | .get_tx_stats = b43_op_get_tx_stats, | 4500 | .get_tx_stats = b43_op_get_tx_stats, |
4383 | .get_tsf = b43_op_get_tsf, | 4501 | .get_tsf = b43_op_get_tsf, |