aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2008-04-15 00:16:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-16 15:59:58 -0400
commit6974e36356524fa856435cb1be40aaffbac9601a (patch)
treec5a98e784ce1d5c20ce99dec5ffcc7b1bca46efa
parent0a0bed1d10105a9f58cd14ebe216e8479dd31fda (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/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c119
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c90
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
24obj-$(CONFIG_IWL4965) += iwl4965.o 24obj-$(CONFIG_IWL4965) += iwl4965.o
25iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o 25iwl4965-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
39int 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
82int 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
97int 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
40int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
41int iwl_remove_default_wep_key(struct iwl_priv *priv,
42 struct ieee80211_key_conf *key);
43int 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
54static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, 55static 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
1219static int iwl4965_remove_static_key(struct iwl_priv *priv)
1220{
1221 int ret = -EOPNOTSUPP;
1222
1223 return ret;
1224}
1225
1226static 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
1236static void iwl4965_clear_free_frames(struct iwl_priv *priv) 1227static 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