1 /******************************************************************************
3 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
5 * Portions of this file are derived from the ipw3945 project, as well
6 * as portions of the ieee80211 subsystem header files.
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.
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
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
21 * The full GNU General Public License is included in this distribution in the
22 * file called LICENSE.
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
28 *****************************************************************************/
30 #include <net/mac80211.h>
32 #include "iwl-eeprom.h"
37 #include "iwl-helpers.h"
41 int iwl_get_free_ucode_key_index(struct iwl_priv
*priv
)
45 for (i
= 0; i
< STA_KEY_MAX_NUM
; i
++)
46 if (!test_and_set_bit(i
, &priv
->ucode_key_table
))
52 int iwl_send_static_wepkey_cmd(struct iwl_priv
*priv
, u8 send_if_empty
)
55 u8 buff
[sizeof(struct iwl_wep_cmd
) +
56 sizeof(struct iwl_wep_key
) * WEP_KEYS_MAX
];
57 struct iwl_wep_cmd
*wep_cmd
= (struct iwl_wep_cmd
*)buff
;
58 size_t cmd_size
= sizeof(struct iwl_wep_cmd
);
59 struct iwl_host_cmd cmd
= {
62 .meta
.flags
= CMD_ASYNC
,
65 memset(wep_cmd
, 0, cmd_size
+
66 (sizeof(struct iwl_wep_key
) * WEP_KEYS_MAX
));
68 for (i
= 0; i
< WEP_KEYS_MAX
; i
++) {
69 wep_cmd
->key
[i
].key_index
= i
;
70 if (priv
->wep_keys
[i
].key_size
) {
71 wep_cmd
->key
[i
].key_offset
= i
;
74 wep_cmd
->key
[i
].key_offset
= WEP_INVALID_OFFSET
;
77 wep_cmd
->key
[i
].key_size
= priv
->wep_keys
[i
].key_size
;
78 memcpy(&wep_cmd
->key
[i
].key
[3], priv
->wep_keys
[i
].key
,
79 priv
->wep_keys
[i
].key_size
);
82 wep_cmd
->global_key_type
= WEP_KEY_WEP_TYPE
;
83 wep_cmd
->num_keys
= WEP_KEYS_MAX
;
85 cmd_size
+= sizeof(struct iwl_wep_key
) * WEP_KEYS_MAX
;
89 if (not_empty
|| send_if_empty
)
90 return iwl_send_cmd(priv
, &cmd
);
95 int iwl_remove_default_wep_key(struct iwl_priv
*priv
,
96 struct ieee80211_key_conf
*keyconf
)
101 spin_lock_irqsave(&priv
->sta_lock
, flags
);
103 if (!test_and_clear_bit(keyconf
->keyidx
, &priv
->ucode_key_table
))
104 IWL_ERROR("index %d not used in uCode key table.\n",
107 priv
->default_wep_key
--;
108 memset(&priv
->wep_keys
[keyconf
->keyidx
], 0, sizeof(priv
->wep_keys
[0]));
109 ret
= iwl_send_static_wepkey_cmd(priv
, 1);
110 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
115 int iwl_set_default_wep_key(struct iwl_priv
*priv
,
116 struct ieee80211_key_conf
*keyconf
)
121 keyconf
->flags
&= ~IEEE80211_KEY_FLAG_GENERATE_IV
;
122 keyconf
->hw_key_idx
= keyconf
->keyidx
;
123 priv
->stations
[IWL_AP_ID
].keyinfo
.alg
= ALG_WEP
;
125 spin_lock_irqsave(&priv
->sta_lock
, flags
);
126 priv
->default_wep_key
++;
128 if (test_and_set_bit(keyconf
->keyidx
, &priv
->ucode_key_table
))
129 IWL_ERROR("index %d already used in uCode key table.\n",
132 priv
->wep_keys
[keyconf
->keyidx
].key_size
= keyconf
->keylen
;
133 memcpy(&priv
->wep_keys
[keyconf
->keyidx
].key
, &keyconf
->key
,
136 ret
= iwl_send_static_wepkey_cmd(priv
, 0);
137 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
142 static int iwl_set_wep_dynamic_key_info(struct iwl_priv
*priv
,
143 struct ieee80211_key_conf
*keyconf
,
147 __le16 key_flags
= 0;
150 keyconf
->flags
&= ~IEEE80211_KEY_FLAG_GENERATE_IV
;
151 keyconf
->hw_key_idx
= keyconf
->keyidx
;
153 key_flags
|= (STA_KEY_FLG_WEP
| STA_KEY_FLG_MAP_KEY_MSK
);
154 key_flags
|= cpu_to_le16(keyconf
->keyidx
<< STA_KEY_FLG_KEYID_POS
);
155 key_flags
&= ~STA_KEY_FLG_INVALID
;
157 if (keyconf
->keylen
== WEP_KEY_LEN_128
)
158 key_flags
|= STA_KEY_FLG_KEY_SIZE_MSK
;
160 if (sta_id
== priv
->hw_params
.bcast_sta_id
)
161 key_flags
|= STA_KEY_MULTICAST_MSK
;
163 spin_lock_irqsave(&priv
->sta_lock
, flags
);
165 priv
->stations
[sta_id
].keyinfo
.alg
= keyconf
->alg
;
166 priv
->stations
[sta_id
].keyinfo
.keylen
= keyconf
->keylen
;
167 priv
->stations
[sta_id
].keyinfo
.keyidx
= keyconf
->keyidx
;
169 memcpy(priv
->stations
[sta_id
].keyinfo
.key
,
170 keyconf
->key
, keyconf
->keylen
);
172 memcpy(&priv
->stations
[sta_id
].sta
.key
.key
[3],
173 keyconf
->key
, keyconf
->keylen
);
175 priv
->stations
[sta_id
].sta
.key
.key_offset
=
176 iwl_get_free_ucode_key_index(priv
);
177 priv
->stations
[sta_id
].sta
.key
.key_flags
= key_flags
;
179 priv
->stations
[sta_id
].sta
.sta
.modify_mask
= STA_MODIFY_KEY_MASK
;
180 priv
->stations
[sta_id
].sta
.mode
= STA_CONTROL_MODIFY_MSK
;
182 ret
= iwl4965_send_add_station(priv
,
183 &priv
->stations
[sta_id
].sta
, CMD_ASYNC
);
185 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
190 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv
*priv
,
191 struct ieee80211_key_conf
*keyconf
,
195 __le16 key_flags
= 0;
197 key_flags
|= (STA_KEY_FLG_CCMP
| STA_KEY_FLG_MAP_KEY_MSK
);
198 key_flags
|= cpu_to_le16(keyconf
->keyidx
<< STA_KEY_FLG_KEYID_POS
);
199 key_flags
&= ~STA_KEY_FLG_INVALID
;
201 if (sta_id
== priv
->hw_params
.bcast_sta_id
)
202 key_flags
|= STA_KEY_MULTICAST_MSK
;
204 keyconf
->flags
|= IEEE80211_KEY_FLAG_GENERATE_IV
;
205 keyconf
->hw_key_idx
= keyconf
->keyidx
;
207 spin_lock_irqsave(&priv
->sta_lock
, flags
);
208 priv
->stations
[sta_id
].keyinfo
.alg
= keyconf
->alg
;
209 priv
->stations
[sta_id
].keyinfo
.keylen
= keyconf
->keylen
;
211 memcpy(priv
->stations
[sta_id
].keyinfo
.key
, keyconf
->key
,
214 memcpy(priv
->stations
[sta_id
].sta
.key
.key
, keyconf
->key
,
217 priv
->stations
[sta_id
].sta
.key
.key_offset
=
218 iwl_get_free_ucode_key_index(priv
);
219 priv
->stations
[sta_id
].sta
.key
.key_flags
= key_flags
;
220 priv
->stations
[sta_id
].sta
.sta
.modify_mask
= STA_MODIFY_KEY_MASK
;
221 priv
->stations
[sta_id
].sta
.mode
= STA_CONTROL_MODIFY_MSK
;
223 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
225 IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
226 return iwl4965_send_add_station(priv
,
227 &priv
->stations
[sta_id
].sta
, CMD_ASYNC
);
230 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv
*priv
,
231 struct ieee80211_key_conf
*keyconf
,
237 keyconf
->flags
|= IEEE80211_KEY_FLAG_GENERATE_IV
;
238 keyconf
->flags
|= IEEE80211_KEY_FLAG_GENERATE_MMIC
;
239 keyconf
->hw_key_idx
= keyconf
->keyidx
;
241 spin_lock_irqsave(&priv
->sta_lock
, flags
);
243 priv
->stations
[sta_id
].keyinfo
.alg
= keyconf
->alg
;
244 priv
->stations
[sta_id
].keyinfo
.conf
= keyconf
;
245 priv
->stations
[sta_id
].keyinfo
.keylen
= 16;
246 priv
->stations
[sta_id
].sta
.key
.key_offset
=
247 iwl_get_free_ucode_key_index(priv
);
249 /* This copy is acutally not needed: we get the key with each TX */
250 memcpy(priv
->stations
[sta_id
].keyinfo
.key
, keyconf
->key
, 16);
252 memcpy(priv
->stations
[sta_id
].sta
.key
.key
, keyconf
->key
, 16);
254 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
259 int iwl_remove_dynamic_key(struct iwl_priv
*priv
, u8 sta_id
)
263 priv
->key_mapping_key
= 0;
265 spin_lock_irqsave(&priv
->sta_lock
, flags
);
266 if (!test_and_clear_bit(priv
->stations
[sta_id
].sta
.key
.key_offset
,
267 &priv
->ucode_key_table
))
268 IWL_ERROR("index %d not used in uCode key table.\n",
269 priv
->stations
[sta_id
].sta
.key
.key_offset
);
270 memset(&priv
->stations
[sta_id
].keyinfo
, 0,
271 sizeof(struct iwl4965_hw_key
));
272 memset(&priv
->stations
[sta_id
].sta
.key
, 0,
273 sizeof(struct iwl4965_keyinfo
));
274 priv
->stations
[sta_id
].sta
.key
.key_flags
= STA_KEY_FLG_NO_ENC
;
275 priv
->stations
[sta_id
].sta
.sta
.modify_mask
= STA_MODIFY_KEY_MASK
;
276 priv
->stations
[sta_id
].sta
.mode
= STA_CONTROL_MODIFY_MSK
;
277 spin_unlock_irqrestore(&priv
->sta_lock
, flags
);
279 IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
280 return iwl4965_send_add_station(priv
, &priv
->stations
[sta_id
].sta
, 0);
283 int iwl_set_dynamic_key(struct iwl_priv
*priv
,
284 struct ieee80211_key_conf
*key
, u8 sta_id
)
288 priv
->key_mapping_key
= 1;
292 ret
= iwl_set_ccmp_dynamic_key_info(priv
, key
, sta_id
);
295 ret
= iwl_set_tkip_dynamic_key_info(priv
, key
, sta_id
);
298 ret
= iwl_set_wep_dynamic_key_info(priv
, key
, sta_id
);
301 IWL_ERROR("Unknown alg: %s alg = %d\n", __func__
, key
->alg
);
308 #ifdef CONFIG_IWLWIFI_DEBUG
309 static void iwl_dump_lq_cmd(struct iwl_priv
*priv
,
310 struct iwl_link_quality_cmd
*lq
)
313 IWL_DEBUG_RATE("lq station id 0x%x\n", lq
->sta_id
);
314 IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
315 lq
->general_params
.single_stream_ant_msk
,
316 lq
->general_params
.dual_stream_ant_msk
);
318 for (i
= 0; i
< LINK_QUAL_MAX_RETRY_NUM
; i
++)
319 IWL_DEBUG_RATE("lq index %d 0x%X\n",
320 i
, lq
->rs_table
[i
].rate_n_flags
);
323 static inline void iwl_dump_lq_cmd(struct iwl_priv
*priv
,
324 struct iwl_link_quality_cmd
*lq
)
329 int iwl_send_lq_cmd(struct iwl_priv
*priv
,
330 struct iwl_link_quality_cmd
*lq
, u8 flags
)
332 struct iwl_host_cmd cmd
= {
333 .id
= REPLY_TX_LINK_QUALITY_CMD
,
334 .len
= sizeof(struct iwl_link_quality_cmd
),
339 if ((lq
->sta_id
== 0xFF) &&
340 (priv
->iw_mode
== IEEE80211_IF_TYPE_IBSS
))
343 if (lq
->sta_id
== 0xFF)
344 lq
->sta_id
= IWL_AP_ID
;
346 iwl_dump_lq_cmd(priv
,lq
);
348 if (iwl_is_associated(priv
) && priv
->assoc_station_added
&&
349 priv
->lq_mngr
.lq_ready
)
350 return iwl_send_cmd(priv
, &cmd
);
354 EXPORT_SYMBOL(iwl_send_lq_cmd
);