diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-04-15 00:16:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-16 15:59:58 -0400 |
commit | 6974e36356524fa856435cb1be40aaffbac9601a (patch) | |
tree | c5a98e784ce1d5c20ce99dec5ffcc7b1bca46efa | |
parent | 0a0bed1d10105a9f58cd14ebe216e8479dd31fda (diff) |
iwlwifi: default WEP HW encryption
This patch adds HW encryption support in default WEP mode.
When no key mapping key/pairwise key is used. The key is broadcast key
is used as default/global/static key.
This code assumes that group cast key is added after pairwise key.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 119 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.h | 46 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 90 |
5 files changed, 220 insertions, 40 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 2751e8aa97d7..741ea346a295 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -22,5 +22,5 @@ endif | |||
22 | 22 | ||
23 | 23 | ||
24 | obj-$(CONFIG_IWL4965) += iwl4965.o | 24 | obj-$(CONFIG_IWL4965) += iwl4965.o |
25 | iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o | 25 | iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o |
26 | 26 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 65e536782706..93df29e4689a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h | |||
@@ -1112,6 +1112,9 @@ struct iwl_priv { | |||
1112 | spinlock_t sta_lock; | 1112 | spinlock_t sta_lock; |
1113 | int num_stations; | 1113 | int num_stations; |
1114 | struct iwl4965_station_entry stations[IWL_STATION_COUNT]; | 1114 | struct iwl4965_station_entry stations[IWL_STATION_COUNT]; |
1115 | struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; | ||
1116 | u8 default_wep_key; | ||
1117 | u8 key_mapping_key; | ||
1115 | 1118 | ||
1116 | /* Indication if ieee80211_ops->open has been called */ | 1119 | /* Indication if ieee80211_ops->open has been called */ |
1117 | u8 is_open; | 1120 | u8 is_open; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c new file mode 100644 index 000000000000..a48e228e2ffd --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * Portions of this file are derived from the ipw3945 project, as well | ||
6 | * as portions of the ieee80211 subsystem header files. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution in the | ||
22 | * file called LICENSE. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | * | ||
28 | *****************************************************************************/ | ||
29 | |||
30 | #include <net/mac80211.h> | ||
31 | |||
32 | #include "iwl-eeprom.h" | ||
33 | #include "iwl-4965.h" | ||
34 | #include "iwl-core.h" | ||
35 | #include "iwl-sta.h" | ||
36 | #include "iwl-io.h" | ||
37 | #include "iwl-helpers.h" | ||
38 | |||
39 | int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) | ||
40 | { | ||
41 | int i, not_empty = 0; | ||
42 | u8 buff[sizeof(struct iwl_wep_cmd) + | ||
43 | sizeof(struct iwl_wep_key) * WEP_KEYS_MAX]; | ||
44 | struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff; | ||
45 | size_t cmd_size = sizeof(struct iwl_wep_cmd); | ||
46 | struct iwl_host_cmd cmd = { | ||
47 | .id = REPLY_WEPKEY, | ||
48 | .data = wep_cmd, | ||
49 | .meta.flags = CMD_ASYNC, | ||
50 | }; | ||
51 | |||
52 | memset(wep_cmd, 0, cmd_size + | ||
53 | (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); | ||
54 | |||
55 | for (i = 0; i < WEP_KEYS_MAX ; i++) { | ||
56 | wep_cmd->key[i].key_index = i; | ||
57 | if (priv->wep_keys[i].key_size) { | ||
58 | wep_cmd->key[i].key_offset = i; | ||
59 | not_empty = 1; | ||
60 | } else { | ||
61 | wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET; | ||
62 | } | ||
63 | |||
64 | wep_cmd->key[i].key_size = priv->wep_keys[i].key_size; | ||
65 | memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key, | ||
66 | priv->wep_keys[i].key_size); | ||
67 | } | ||
68 | |||
69 | wep_cmd->global_key_type = WEP_KEY_WEP_TYPE; | ||
70 | wep_cmd->num_keys = WEP_KEYS_MAX; | ||
71 | |||
72 | cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX; | ||
73 | |||
74 | cmd.len = cmd_size; | ||
75 | |||
76 | if (not_empty || send_if_empty) | ||
77 | return iwl_send_cmd(priv, &cmd); | ||
78 | else | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int iwl_remove_default_wep_key(struct iwl_priv *priv, | ||
83 | struct ieee80211_key_conf *key) | ||
84 | { | ||
85 | int ret; | ||
86 | unsigned long flags; | ||
87 | |||
88 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
89 | priv->default_wep_key--; | ||
90 | memset(&priv->wep_keys[key->keyidx], 0, sizeof(priv->wep_keys[0])); | ||
91 | ret = iwl_send_static_wepkey_cmd(priv, 1); | ||
92 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | int iwl_set_default_wep_key(struct iwl_priv *priv, | ||
98 | struct ieee80211_key_conf *keyconf) | ||
99 | { | ||
100 | int ret; | ||
101 | unsigned long flags; | ||
102 | |||
103 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | ||
104 | keyconf->hw_key_idx = keyconf->keyidx; | ||
105 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; | ||
106 | |||
107 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
108 | priv->default_wep_key++; | ||
109 | |||
110 | priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; | ||
111 | memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key, | ||
112 | keyconf->keylen); | ||
113 | |||
114 | ret = iwl_send_static_wepkey_cmd(priv, 0); | ||
115 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h new file mode 100644 index 000000000000..50e9f1470d8d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * Portions of this file are derived from the ipw3945 project, as well | ||
6 | * as portions of the ieee80211 subsystem header files. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution in the | ||
22 | * file called LICENSE. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | * | ||
28 | *****************************************************************************/ | ||
29 | #ifndef __iwl_sta_h__ | ||
30 | #define __iwl_sta_h__ | ||
31 | |||
32 | #include <net/mac80211.h> | ||
33 | |||
34 | #include "iwl-eeprom.h" | ||
35 | #include "iwl-core.h" | ||
36 | #include "iwl-4965.h" | ||
37 | #include "iwl-io.h" | ||
38 | #include "iwl-helpers.h" | ||
39 | |||
40 | int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); | ||
41 | int iwl_remove_default_wep_key(struct iwl_priv *priv, | ||
42 | struct ieee80211_key_conf *key); | ||
43 | int iwl_set_default_wep_key(struct iwl_priv *priv, | ||
44 | struct ieee80211_key_conf *key); | ||
45 | |||
46 | #endif /* __iwl_sta_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ecc9cba62bf9..dfd2b75492e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include "iwl-core.h" | 50 | #include "iwl-core.h" |
51 | #include "iwl-io.h" | 51 | #include "iwl-io.h" |
52 | #include "iwl-helpers.h" | 52 | #include "iwl-helpers.h" |
53 | #include "iwl-sta.h" | ||
53 | 54 | ||
54 | static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, | 55 | static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, |
55 | struct iwl4965_tx_queue *txq); | 56 | struct iwl4965_tx_queue *txq); |
@@ -941,6 +942,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) | |||
941 | return -EIO; | 942 | return -EIO; |
942 | } | 943 | } |
943 | priv->assoc_station_added = 1; | 944 | priv->assoc_station_added = 1; |
945 | if (priv->default_wep_key && | ||
946 | iwl_send_static_wepkey_cmd(priv, 0)) | ||
947 | IWL_ERROR("Could not send WEP static key.\n"); | ||
944 | } | 948 | } |
945 | 949 | ||
946 | return 0; | 950 | return 0; |
@@ -1180,6 +1184,8 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) | |||
1180 | { | 1184 | { |
1181 | unsigned long flags; | 1185 | unsigned long flags; |
1182 | 1186 | ||
1187 | priv->key_mapping_key = 0; | ||
1188 | |||
1183 | spin_lock_irqsave(&priv->sta_lock, flags); | 1189 | spin_lock_irqsave(&priv->sta_lock, flags); |
1184 | memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key)); | 1190 | memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key)); |
1185 | memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); | 1191 | memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); |
@@ -1198,6 +1204,8 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv, | |||
1198 | { | 1204 | { |
1199 | int ret; | 1205 | int ret; |
1200 | 1206 | ||
1207 | priv->key_mapping_key = 1; | ||
1208 | |||
1201 | switch (key->alg) { | 1209 | switch (key->alg) { |
1202 | case ALG_CCMP: | 1210 | case ALG_CCMP: |
1203 | ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id); | 1211 | ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id); |
@@ -1216,23 +1224,6 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv, | |||
1216 | return ret; | 1224 | return ret; |
1217 | } | 1225 | } |
1218 | 1226 | ||
1219 | static int iwl4965_remove_static_key(struct iwl_priv *priv) | ||
1220 | { | ||
1221 | int ret = -EOPNOTSUPP; | ||
1222 | |||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int iwl4965_set_static_key(struct iwl_priv *priv, | ||
1227 | struct ieee80211_key_conf *key) | ||
1228 | { | ||
1229 | if (key->alg == ALG_WEP) | ||
1230 | return -EOPNOTSUPP; | ||
1231 | |||
1232 | IWL_ERROR("Static key invalid: alg %d\n", key->alg); | ||
1233 | return -EINVAL; | ||
1234 | } | ||
1235 | |||
1236 | static void iwl4965_clear_free_frames(struct iwl_priv *priv) | 1227 | static void iwl4965_clear_free_frames(struct iwl_priv *priv) |
1237 | { | 1228 | { |
1238 | struct list_head *element; | 1229 | struct list_head *element; |
@@ -2115,6 +2106,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, | |||
2115 | int sta_id) | 2106 | int sta_id) |
2116 | { | 2107 | { |
2117 | struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; | 2108 | struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; |
2109 | struct iwl_wep_key *wepkey; | ||
2110 | int keyidx = 0; | ||
2111 | |||
2112 | BUG_ON(ctl->key_idx > 3); | ||
2118 | 2113 | ||
2119 | switch (keyinfo->alg) { | 2114 | switch (keyinfo->alg) { |
2120 | case ALG_CCMP: | 2115 | case ALG_CCMP: |
@@ -2133,16 +2128,24 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, | |||
2133 | break; | 2128 | break; |
2134 | 2129 | ||
2135 | case ALG_WEP: | 2130 | case ALG_WEP: |
2136 | cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | | 2131 | wepkey = &priv->wep_keys[ctl->key_idx]; |
2137 | (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; | 2132 | cmd->cmd.tx.sec_ctl = 0; |
2138 | 2133 | if (priv->default_wep_key) { | |
2139 | if (keyinfo->keylen == 13) | 2134 | /* the WEP key was sent as static */ |
2140 | cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; | 2135 | keyidx = ctl->key_idx; |
2136 | memcpy(&cmd->cmd.tx.key[3], wepkey->key, | ||
2137 | wepkey->key_size); | ||
2138 | if (wepkey->key_size == WEP_KEY_LEN_128) | ||
2139 | cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; | ||
2140 | } else { | ||
2141 | IWL_ERROR("No support for WEP key mappings key\n"); | ||
2142 | } | ||
2141 | 2143 | ||
2142 | memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); | 2144 | cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP | |
2145 | (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); | ||
2143 | 2146 | ||
2144 | IWL_DEBUG_TX("Configuring packet for WEP encryption " | 2147 | IWL_DEBUG_TX("Configuring packet for WEP encryption " |
2145 | "with key %d\n", ctl->key_idx); | 2148 | "with key %d\n", keyidx); |
2146 | break; | 2149 | break; |
2147 | 2150 | ||
2148 | default: | 2151 | default: |
@@ -6989,7 +6992,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
6989 | DECLARE_MAC_BUF(mac); | 6992 | DECLARE_MAC_BUF(mac); |
6990 | int ret = 0; | 6993 | int ret = 0; |
6991 | u8 sta_id = IWL_INVALID_STATION; | 6994 | u8 sta_id = IWL_INVALID_STATION; |
6992 | u8 static_key; | 6995 | u8 is_default_wep_key = 0; |
6993 | 6996 | ||
6994 | IWL_DEBUG_MAC80211("enter\n"); | 6997 | IWL_DEBUG_MAC80211("enter\n"); |
6995 | 6998 | ||
@@ -7002,33 +7005,42 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
7002 | /* only support pairwise keys */ | 7005 | /* only support pairwise keys */ |
7003 | return -EOPNOTSUPP; | 7006 | return -EOPNOTSUPP; |
7004 | 7007 | ||
7005 | /* FIXME: need to differenciate between static and dynamic key | 7008 | sta_id = iwl4965_hw_find_station(priv, addr); |
7006 | * in the level of mac80211 */ | 7009 | if (sta_id == IWL_INVALID_STATION) { |
7007 | static_key = !iwl_is_associated(priv); | 7010 | IWL_DEBUG_MAC80211("leave - %s not in station map.\n", |
7011 | print_mac(mac, addr)); | ||
7012 | return -EINVAL; | ||
7008 | 7013 | ||
7009 | if (!static_key) { | ||
7010 | sta_id = iwl4965_hw_find_station(priv, addr); | ||
7011 | if (sta_id == IWL_INVALID_STATION) { | ||
7012 | IWL_DEBUG_MAC80211("leave - %s not in station map.\n", | ||
7013 | print_mac(mac, addr)); | ||
7014 | return -EINVAL; | ||
7015 | } | ||
7016 | } | 7014 | } |
7017 | 7015 | ||
7016 | mutex_lock(&priv->mutex); | ||
7018 | iwl4965_scan_cancel_timeout(priv, 100); | 7017 | iwl4965_scan_cancel_timeout(priv, 100); |
7018 | mutex_unlock(&priv->mutex); | ||
7019 | |||
7020 | /* If we are getting WEP group key and we didn't receive any key mapping | ||
7021 | * so far, we are in legacy wep mode (group key only), otherwise we are | ||
7022 | * in 1X mode. | ||
7023 | * In legacy wep mode, we use another host command to the uCode */ | ||
7024 | if (key->alg == ALG_WEP && sta_id == priv->hw_setting.bcast_sta_id && | ||
7025 | priv->iw_mode != IEEE80211_IF_TYPE_AP) { | ||
7026 | if (cmd == SET_KEY) | ||
7027 | is_default_wep_key = !priv->key_mapping_key; | ||
7028 | else | ||
7029 | is_default_wep_key = priv->default_wep_key; | ||
7030 | } | ||
7019 | 7031 | ||
7020 | switch (cmd) { | 7032 | switch (cmd) { |
7021 | case SET_KEY: | 7033 | case SET_KEY: |
7022 | if (static_key) | 7034 | if (is_default_wep_key) |
7023 | ret = iwl4965_set_static_key(priv, key); | 7035 | ret = iwl_set_default_wep_key(priv, key); |
7024 | else | 7036 | else |
7025 | ret = iwl4965_set_dynamic_key(priv, key, sta_id); | 7037 | ret = iwl4965_set_dynamic_key(priv, key, sta_id); |
7026 | 7038 | ||
7027 | IWL_DEBUG_MAC80211("enable hwcrypto key\n"); | 7039 | IWL_DEBUG_MAC80211("enable hwcrypto key\n"); |
7028 | break; | 7040 | break; |
7029 | case DISABLE_KEY: | 7041 | case DISABLE_KEY: |
7030 | if (static_key) | 7042 | if (is_default_wep_key) |
7031 | ret = iwl4965_remove_static_key(priv); | 7043 | ret = iwl_remove_default_wep_key(priv, key); |
7032 | else | 7044 | else |
7033 | ret = iwl4965_clear_sta_key_info(priv, sta_id); | 7045 | ret = iwl4965_clear_sta_key_info(priv, sta_id); |
7034 | 7046 | ||