]> err.no Git - linux-2.6/blob - drivers/net/wireless/iwlwifi/iwl-sta.c
iwlwifi: rename iwl-4965.h to iwl-dev.h
[linux-2.6] / drivers / net / wireless / iwlwifi / iwl-sta.c
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 #include <linux/etherdevice.h>
32
33 #include "iwl-eeprom.h"
34 #include "iwl-dev.h"
35 #include "iwl-core.h"
36 #include "iwl-sta.h"
37 #include "iwl-io.h"
38 #include "iwl-helpers.h"
39
40 u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
41 {
42         int i;
43         int start = 0;
44         int ret = IWL_INVALID_STATION;
45         unsigned long flags;
46         DECLARE_MAC_BUF(mac);
47
48         if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
49             (priv->iw_mode == IEEE80211_IF_TYPE_AP))
50                 start = IWL_STA_ID;
51
52         if (is_broadcast_ether_addr(addr))
53                 return priv->hw_params.bcast_sta_id;
54
55         spin_lock_irqsave(&priv->sta_lock, flags);
56         for (i = start; i < priv->hw_params.max_stations; i++)
57                 if (priv->stations[i].used &&
58                     (!compare_ether_addr(priv->stations[i].sta.sta.addr,
59                                          addr))) {
60                         ret = i;
61                         goto out;
62                 }
63
64         IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
65                               print_mac(mac, addr), priv->num_stations);
66
67  out:
68         spin_unlock_irqrestore(&priv->sta_lock, flags);
69         return ret;
70 }
71 EXPORT_SYMBOL(iwl_find_station);
72
73
74 int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
75 {
76         int i;
77
78         for (i = 0; i < STA_KEY_MAX_NUM; i++)
79                 if (!test_and_set_bit(i, &priv->ucode_key_table))
80                         return i;
81
82         return -1;
83 }
84
85 int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
86 {
87         int i, not_empty = 0;
88         u8 buff[sizeof(struct iwl_wep_cmd) +
89                 sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
90         struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
91         size_t cmd_size  = sizeof(struct iwl_wep_cmd);
92         struct iwl_host_cmd cmd = {
93                 .id = REPLY_WEPKEY,
94                 .data = wep_cmd,
95                 .meta.flags = CMD_ASYNC,
96         };
97
98         memset(wep_cmd, 0, cmd_size +
99                         (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
100
101         for (i = 0; i < WEP_KEYS_MAX ; i++) {
102                 wep_cmd->key[i].key_index = i;
103                 if (priv->wep_keys[i].key_size) {
104                         wep_cmd->key[i].key_offset = i;
105                         not_empty = 1;
106                 } else {
107                         wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
108                 }
109
110                 wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
111                 memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
112                                 priv->wep_keys[i].key_size);
113         }
114
115         wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
116         wep_cmd->num_keys = WEP_KEYS_MAX;
117
118         cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
119
120         cmd.len = cmd_size;
121
122         if (not_empty || send_if_empty)
123                 return iwl_send_cmd(priv, &cmd);
124         else
125                 return 0;
126 }
127
128 int iwl_remove_default_wep_key(struct iwl_priv *priv,
129                                struct ieee80211_key_conf *keyconf)
130 {
131         int ret;
132         unsigned long flags;
133
134         spin_lock_irqsave(&priv->sta_lock, flags);
135
136         if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
137                 IWL_ERROR("index %d not used in uCode key table.\n",
138                           keyconf->keyidx);
139
140         priv->default_wep_key--;
141         memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
142         ret = iwl_send_static_wepkey_cmd(priv, 1);
143         spin_unlock_irqrestore(&priv->sta_lock, flags);
144
145         return ret;
146 }
147
148 int iwl_set_default_wep_key(struct iwl_priv *priv,
149                             struct ieee80211_key_conf *keyconf)
150 {
151         int ret;
152         unsigned long flags;
153
154         keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
155         keyconf->hw_key_idx = keyconf->keyidx;
156         priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
157
158         spin_lock_irqsave(&priv->sta_lock, flags);
159         priv->default_wep_key++;
160
161         if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
162                 IWL_ERROR("index %d already used in uCode key table.\n",
163                         keyconf->keyidx);
164
165         priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
166         memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
167                                                         keyconf->keylen);
168
169         ret = iwl_send_static_wepkey_cmd(priv, 0);
170         spin_unlock_irqrestore(&priv->sta_lock, flags);
171
172         return ret;
173 }
174
175 static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
176                                 struct ieee80211_key_conf *keyconf,
177                                 u8 sta_id)
178 {
179         unsigned long flags;
180         __le16 key_flags = 0;
181         int ret;
182
183         keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
184         keyconf->hw_key_idx = keyconf->keyidx;
185
186         key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
187         key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
188         key_flags &= ~STA_KEY_FLG_INVALID;
189
190         if (keyconf->keylen == WEP_KEY_LEN_128)
191                 key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
192
193         if (sta_id == priv->hw_params.bcast_sta_id)
194                 key_flags |= STA_KEY_MULTICAST_MSK;
195
196         spin_lock_irqsave(&priv->sta_lock, flags);
197
198         priv->stations[sta_id].keyinfo.alg = keyconf->alg;
199         priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
200         priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
201
202         memcpy(priv->stations[sta_id].keyinfo.key,
203                                 keyconf->key, keyconf->keylen);
204
205         memcpy(&priv->stations[sta_id].sta.key.key[3],
206                                 keyconf->key, keyconf->keylen);
207
208         if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
209                         == STA_KEY_FLG_NO_ENC)
210                 priv->stations[sta_id].sta.key.key_offset =
211                                  iwl_get_free_ucode_key_index(priv);
212         /* else, we are overriding an existing key => no need to allocated room
213          * in uCode. */
214
215         priv->stations[sta_id].sta.key.key_flags = key_flags;
216         priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
217         priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
218
219         ret = iwl4965_send_add_station(priv,
220                 &priv->stations[sta_id].sta, CMD_ASYNC);
221
222         spin_unlock_irqrestore(&priv->sta_lock, flags);
223
224         return ret;
225 }
226
227 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
228                                    struct ieee80211_key_conf *keyconf,
229                                    u8 sta_id)
230 {
231         unsigned long flags;
232         __le16 key_flags = 0;
233
234         key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
235         key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
236         key_flags &= ~STA_KEY_FLG_INVALID;
237
238         if (sta_id == priv->hw_params.bcast_sta_id)
239                 key_flags |= STA_KEY_MULTICAST_MSK;
240
241         keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
242         keyconf->hw_key_idx = keyconf->keyidx;
243
244         spin_lock_irqsave(&priv->sta_lock, flags);
245         priv->stations[sta_id].keyinfo.alg = keyconf->alg;
246         priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
247
248         memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
249                keyconf->keylen);
250
251         memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
252                keyconf->keylen);
253
254         if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
255                         == STA_KEY_FLG_NO_ENC)
256                 priv->stations[sta_id].sta.key.key_offset =
257                                  iwl_get_free_ucode_key_index(priv);
258         /* else, we are overriding an existing key => no need to allocated room
259          * in uCode. */
260
261         priv->stations[sta_id].sta.key.key_flags = key_flags;
262         priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
263         priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
264
265         spin_unlock_irqrestore(&priv->sta_lock, flags);
266
267         IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
268         return iwl4965_send_add_station(priv,
269                                 &priv->stations[sta_id].sta, CMD_ASYNC);
270 }
271
272 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
273                                    struct ieee80211_key_conf *keyconf,
274                                    u8 sta_id)
275 {
276         unsigned long flags;
277         int ret = 0;
278
279         keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
280         keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
281         keyconf->hw_key_idx = keyconf->keyidx;
282
283         spin_lock_irqsave(&priv->sta_lock, flags);
284
285         priv->stations[sta_id].keyinfo.alg = keyconf->alg;
286         priv->stations[sta_id].keyinfo.conf = keyconf;
287         priv->stations[sta_id].keyinfo.keylen = 16;
288
289         if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
290                         == STA_KEY_FLG_NO_ENC)
291                 priv->stations[sta_id].sta.key.key_offset =
292                                  iwl_get_free_ucode_key_index(priv);
293         /* else, we are overriding an existing key => no need to allocated room
294          * in uCode. */
295
296         /* This copy is acutally not needed: we get the key with each TX */
297         memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
298
299         memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
300
301         spin_unlock_irqrestore(&priv->sta_lock, flags);
302
303         return ret;
304 }
305
306 int iwl_remove_dynamic_key(struct iwl_priv *priv,
307                                 struct ieee80211_key_conf *keyconf,
308                                 u8 sta_id)
309 {
310         unsigned long flags;
311         int ret = 0;
312         u16 key_flags;
313         u8 keyidx;
314
315         priv->key_mapping_key = 0;
316
317         spin_lock_irqsave(&priv->sta_lock, flags);
318         key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
319         keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
320
321         if (keyconf->keyidx != keyidx) {
322                 /* We need to remove a key with index different that the one
323                  * in the uCode. This means that the key we need to remove has
324                  * been replaced by another one with different index.
325                  * Don't do anything and return ok
326                  */
327                 spin_unlock_irqrestore(&priv->sta_lock, flags);
328                 return 0;
329         }
330
331         if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
332                 &priv->ucode_key_table))
333                 IWL_ERROR("index %d not used in uCode key table.\n",
334                         priv->stations[sta_id].sta.key.key_offset);
335         memset(&priv->stations[sta_id].keyinfo, 0,
336                                         sizeof(struct iwl4965_hw_key));
337         memset(&priv->stations[sta_id].sta.key, 0,
338                                         sizeof(struct iwl4965_keyinfo));
339         priv->stations[sta_id].sta.key.key_flags =
340                         STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
341         priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
342         priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
343         priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
344
345         IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
346         ret =  iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
347         spin_unlock_irqrestore(&priv->sta_lock, flags);
348         return ret;
349 }
350
351 int iwl_set_dynamic_key(struct iwl_priv *priv,
352                                 struct ieee80211_key_conf *key, u8 sta_id)
353 {
354         int ret;
355
356         priv->key_mapping_key = 1;
357
358         switch (key->alg) {
359         case ALG_CCMP:
360                 ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
361                 break;
362         case ALG_TKIP:
363                 ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
364                 break;
365         case ALG_WEP:
366                 ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
367                 break;
368         default:
369                 IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
370                 ret = -EINVAL;
371         }
372
373         return ret;
374 }
375
376 #ifdef CONFIG_IWLWIFI_DEBUG
377 static void iwl_dump_lq_cmd(struct iwl_priv *priv,
378                            struct iwl_link_quality_cmd *lq)
379 {
380         int i;
381         IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
382         IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
383                        lq->general_params.single_stream_ant_msk,
384                        lq->general_params.dual_stream_ant_msk);
385
386         for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
387                 IWL_DEBUG_RATE("lq index %d 0x%X\n",
388                                i, lq->rs_table[i].rate_n_flags);
389 }
390 #else
391 static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
392                                    struct iwl_link_quality_cmd *lq)
393 {
394 }
395 #endif
396
397 int iwl_send_lq_cmd(struct iwl_priv *priv,
398                     struct iwl_link_quality_cmd *lq, u8 flags)
399 {
400         struct iwl_host_cmd cmd = {
401                 .id = REPLY_TX_LINK_QUALITY_CMD,
402                 .len = sizeof(struct iwl_link_quality_cmd),
403                 .meta.flags = flags,
404                 .data = lq,
405         };
406
407         if ((lq->sta_id == 0xFF) &&
408             (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
409                 return -EINVAL;
410
411         if (lq->sta_id == 0xFF)
412                 lq->sta_id = IWL_AP_ID;
413
414         iwl_dump_lq_cmd(priv,lq);
415
416         if (iwl_is_associated(priv) && priv->assoc_station_added &&
417             priv->lq_mngr.lq_ready)
418                 return  iwl_send_cmd(priv, &cmd);
419
420         return 0;
421 }
422 EXPORT_SYMBOL(iwl_send_lq_cmd);
423