blob: 889194931b4ed0388b719eb0fc7781db4210475a [file] [log] [blame]
Zhu Yibb9f8692009-05-21 21:20:45 +08001/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/netdevice.h>
26#include <linux/wireless.h>
27#include <linux/if_arp.h>
28#include <linux/etherdevice.h>
29#include <net/cfg80211.h>
30#include <net/iw_handler.h>
31
32#include "iwm.h"
33#include "umac.h"
34#include "commands.h"
35#include "debug.h"
36
37static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
38{
39 struct iwm_priv *iwm = ndev_to_iwm(dev);
40 struct iw_statistics *wstats = &iwm->wstats;
41
42 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
43 memset(wstats, 0, sizeof(struct iw_statistics));
44 wstats->qual.updated = IW_QUAL_ALL_INVALID;
45 }
46
47 return wstats;
48}
49
50static int iwm_wext_siwfreq(struct net_device *dev,
51 struct iw_request_info *info,
52 struct iw_freq *freq, char *extra)
53{
54 struct iwm_priv *iwm = ndev_to_iwm(dev);
55
56 if (freq->flags == IW_FREQ_AUTO)
57 return 0;
58
59 /* frequency/channel can only be set in IBSS mode */
60 if (iwm->conf.mode != UMAC_MODE_IBSS)
61 return -EOPNOTSUPP;
62
63 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
64}
65
66static int iwm_wext_giwfreq(struct net_device *dev,
67 struct iw_request_info *info,
68 struct iw_freq *freq, char *extra)
69{
70 struct iwm_priv *iwm = ndev_to_iwm(dev);
71
72 if (iwm->conf.mode == UMAC_MODE_IBSS)
73 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
74
75 freq->e = 0;
76 freq->m = iwm->channel;
77
78 return 0;
79}
80
81static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
82 struct sockaddr *ap_addr, char *extra)
83{
84 struct iwm_priv *iwm = ndev_to_iwm(dev);
Samuel Ortiz0c5553b2009-06-15 21:59:50 +020085 int ret;
Zhu Yibb9f8692009-05-21 21:20:45 +080086
87 if (iwm->conf.mode == UMAC_MODE_IBSS)
88 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
89
90 if (!test_bit(IWM_STATUS_READY, &iwm->status))
91 return -EIO;
92
93 if (is_zero_ether_addr(ap_addr->sa_data) ||
94 is_broadcast_ether_addr(ap_addr->sa_data)) {
95 IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
96 iwm->umac_profile->bssid[0]);
97 memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
98 iwm->umac_profile->bss_num = 0;
99 } else {
100 IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
101 ap_addr->sa_data);
102 memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
103 ETH_ALEN);
104 iwm->umac_profile->bss_num = 1;
105 }
106
107 if (iwm->umac_profile_active) {
Samuel Ortiz0c5553b2009-06-15 21:59:50 +0200108 int i;
109
Zhu Yibb9f8692009-05-21 21:20:45 +0800110 if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
111 return 0;
112
Samuel Ortiz0c5553b2009-06-15 21:59:50 +0200113 /*
114 * If we're clearing the BSSID, and we're associated,
115 * we have to clear the keys as they're no longer valid.
116 */
117 if (is_zero_ether_addr(ap_addr->sa_data)) {
118 for (i = 0; i < IWM_NUM_KEYS; i++)
119 iwm->keys[i].in_use = 0;
120
121 }
122
123 ret = iwm_invalidate_mlme_profile(iwm);
124 if (ret < 0) {
125 IWM_ERR(iwm, "Couldn't invalidate profile\n");
126 return ret;
127 }
Zhu Yibb9f8692009-05-21 21:20:45 +0800128 }
129
130 if (iwm->umac_profile->ssid.ssid_len)
131 return iwm_send_mlme_profile(iwm);
132
133 return 0;
134}
135
136static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
137 struct sockaddr *ap_addr, char *extra)
138{
139 struct iwm_priv *iwm = ndev_to_iwm(dev);
140
141 switch (iwm->conf.mode) {
142 case UMAC_MODE_IBSS:
143 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
144 case UMAC_MODE_BSS:
145 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
146 ap_addr->sa_family = ARPHRD_ETHER;
147 memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
148 } else
149 memset(&ap_addr->sa_data, 0, ETH_ALEN);
150 break;
151 default:
152 return -EOPNOTSUPP;
153 }
154
155 return 0;
156}
157
158static int iwm_wext_siwessid(struct net_device *dev,
159 struct iw_request_info *info,
160 struct iw_point *data, char *ssid)
161{
162 struct iwm_priv *iwm = ndev_to_iwm(dev);
163 size_t len = data->length;
164 int ret;
165
166 if (iwm->conf.mode == UMAC_MODE_IBSS)
167 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
168
169 if (!test_bit(IWM_STATUS_READY, &iwm->status))
170 return -EIO;
171
172 if (len > 0 && ssid[len - 1] == '\0')
173 len--;
174
175 if (iwm->umac_profile_active) {
176 if (iwm->umac_profile->ssid.ssid_len == len &&
177 !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
178 return 0;
179
180 ret = iwm_invalidate_mlme_profile(iwm);
181 if (ret < 0) {
182 IWM_ERR(iwm, "Couldn't invalidate profile\n");
183 return ret;
184 }
185 }
186
187 iwm->umac_profile->ssid.ssid_len = len;
188 memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
189
190 return iwm_send_mlme_profile(iwm);
191}
192
193static int iwm_wext_giwessid(struct net_device *dev,
194 struct iw_request_info *info,
195 struct iw_point *data, char *ssid)
196{
197 struct iwm_priv *iwm = ndev_to_iwm(dev);
198
199 if (iwm->conf.mode == UMAC_MODE_IBSS)
200 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
201
202 if (!test_bit(IWM_STATUS_READY, &iwm->status))
203 return -EIO;
204
205 data->length = iwm->umac_profile->ssid.ssid_len;
206 if (data->length) {
207 memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
208 data->flags = 1;
209 } else
210 data->flags = 0;
211
212 return 0;
213}
214
215static struct iwm_key *
216iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
217 struct iw_encode_ext *ext, u8 alg)
218{
219 struct iwm_key *key = &iwm->keys[key_idx];
220
221 memset(key, 0, sizeof(struct iwm_key));
222 memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
223 key->hdr.key_idx = key_idx;
224 if (is_broadcast_ether_addr(ext->addr.sa_data))
225 key->hdr.multicast = 1;
226
227 key->in_use = in_use;
228 key->flags = ext->ext_flags;
229 key->alg = alg;
230 key->key_len = ext->key_len;
231 memcpy(key->key, ext->key, ext->key_len);
232
233 return key;
234}
235
236static int iwm_wext_giwrate(struct net_device *dev,
237 struct iw_request_info *info,
238 struct iw_param *rate, char *extra)
239{
240 struct iwm_priv *iwm = ndev_to_iwm(dev);
241
242 rate->value = iwm->rate * 1000000;
243
244 return 0;
245}
246
247static int iwm_wext_siwencode(struct net_device *dev,
248 struct iw_request_info *info,
249 struct iw_point *erq, char *key_buf)
250{
251 struct iwm_priv *iwm = ndev_to_iwm(dev);
252 struct iwm_key *uninitialized_var(key);
253 int idx, i, uninitialized_var(alg), remove = 0, ret;
254
255 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
256 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
257
258 if (!iwm->umac_profile) {
259 IWM_ERR(iwm, "UMAC profile not allocated yet\n");
260 return -ENODEV;
261 }
262
263 if (erq->length == WLAN_KEY_LEN_WEP40) {
264 alg = UMAC_CIPHER_TYPE_WEP_40;
265 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
266 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
267 } else if (erq->length == WLAN_KEY_LEN_WEP104) {
268 alg = UMAC_CIPHER_TYPE_WEP_104;
269 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
270 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
271 }
272
273 if (erq->flags & IW_ENCODE_RESTRICTED)
274 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
275 else
276 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
277
278 idx = erq->flags & IW_ENCODE_INDEX;
279 if (idx == 0) {
280 if (iwm->default_key)
281 for (i = 0; i < IWM_NUM_KEYS; i++) {
282 if (iwm->default_key == &iwm->keys[i]) {
283 idx = i;
284 break;
285 }
286 }
287 else
288 iwm->default_key = &iwm->keys[idx];
289 } else if (idx < 1 || idx > 4) {
290 return -EINVAL;
291 } else
292 idx--;
293
294 if (erq->flags & IW_ENCODE_DISABLED)
295 remove = 1;
296 else if (erq->length == 0) {
297 if (!iwm->keys[idx].in_use)
298 return -EINVAL;
299 iwm->default_key = &iwm->keys[idx];
300 }
301
302 if (erq->length) {
303 key = &iwm->keys[idx];
304 memset(key, 0, sizeof(struct iwm_key));
305 memset(key->hdr.mac, 0xff, ETH_ALEN);
306 key->hdr.key_idx = idx;
307 key->hdr.multicast = 1;
308 key->in_use = !remove;
309 key->alg = alg;
310 key->key_len = erq->length;
311 memcpy(key->key, key_buf, erq->length);
312
313 IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
314 idx, !!iwm->default_key);
315 }
316
317 if (remove) {
318 if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
319 int j;
320 for (j = 0; j < IWM_NUM_KEYS; j++)
321 if (iwm->keys[j].in_use) {
322 struct iwm_key *k = &iwm->keys[j];
323
324 k->in_use = 0;
325 ret = iwm_set_key(iwm, remove, 0, k);
326 if (ret < 0)
327 return ret;
328 }
329
330 iwm->umac_profile->sec.ucast_cipher =
331 UMAC_CIPHER_TYPE_NONE;
332 iwm->umac_profile->sec.mcast_cipher =
333 UMAC_CIPHER_TYPE_NONE;
334 iwm->umac_profile->sec.auth_type =
335 UMAC_AUTH_TYPE_OPEN;
336
337 return 0;
338 } else {
339 key->in_use = 0;
340 return iwm_set_key(iwm, remove, 0, key);
341 }
342 }
343
344 /*
345 * If we havent set a profile yet, we cant set keys.
346 * Keys will be pushed after we're associated.
347 */
348 if (!iwm->umac_profile_active)
349 return 0;
350
351 /*
352 * If there is a current active profile, but no
353 * default key, it's not worth trying to associate again.
354 */
355 if (!iwm->default_key)
356 return 0;
357
358 /*
359 * Here we have an active profile, but a key setting changed.
360 * We thus have to invalidate the current profile, and push the
361 * new one. Keys will be pushed when association takes place.
362 */
363 ret = iwm_invalidate_mlme_profile(iwm);
364 if (ret < 0) {
365 IWM_ERR(iwm, "Couldn't invalidate profile\n");
366 return ret;
367 }
368
369 return iwm_send_mlme_profile(iwm);
370}
371
372static int iwm_wext_giwencode(struct net_device *dev,
373 struct iw_request_info *info,
374 struct iw_point *erq, char *key)
375{
376 struct iwm_priv *iwm = ndev_to_iwm(dev);
377 int idx, i;
378
379 idx = erq->flags & IW_ENCODE_INDEX;
380 if (idx < 1 || idx > 4) {
381 idx = -1;
382 if (!iwm->default_key) {
383 erq->length = 0;
384 erq->flags |= IW_ENCODE_NOKEY;
385 return 0;
386 } else
387 for (i = 0; i < IWM_NUM_KEYS; i++) {
388 if (iwm->default_key == &iwm->keys[i]) {
389 idx = i;
390 break;
391 }
392 }
393 if (idx < 0)
394 return -EINVAL;
395 } else
396 idx--;
397
398 erq->flags = idx + 1;
399
400 if (!iwm->keys[idx].in_use) {
401 erq->length = 0;
402 erq->flags |= IW_ENCODE_DISABLED;
403 return 0;
404 }
405
406 memcpy(key, iwm->keys[idx].key,
407 min_t(int, erq->length, iwm->keys[idx].key_len));
408 erq->length = iwm->keys[idx].key_len;
409 erq->flags |= IW_ENCODE_ENABLED;
410
411 if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
412 switch (iwm->umac_profile->sec.auth_type) {
413 case UMAC_AUTH_TYPE_OPEN:
414 erq->flags |= IW_ENCODE_OPEN;
415 break;
416 default:
417 erq->flags |= IW_ENCODE_RESTRICTED;
418 break;
419 }
420 }
421
422 return 0;
423}
424
425static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
426{
427 if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
428 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
429 else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
430 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
431 else
432 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
433
434 return 0;
435}
436
437static int iwm_wext_siwpower(struct net_device *dev,
438 struct iw_request_info *info,
439 struct iw_param *wrq, char *extra)
440{
441 struct iwm_priv *iwm = ndev_to_iwm(dev);
442 u32 power_index;
443
444 if (wrq->disabled) {
445 power_index = IWM_POWER_INDEX_MIN;
446 goto set;
447 } else
448 power_index = IWM_POWER_INDEX_DEFAULT;
449
450 switch (wrq->flags & IW_POWER_MODE) {
451 case IW_POWER_ON:
452 case IW_POWER_MODE:
453 case IW_POWER_ALL_R:
454 break;
455 default:
456 return -EINVAL;
457 }
458
459 set:
460 if (power_index == iwm->conf.power_index)
461 return 0;
462
463 iwm->conf.power_index = power_index;
464
465 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
466 CFG_POWER_INDEX, iwm->conf.power_index);
467}
468
469static int iwm_wext_giwpower(struct net_device *dev,
470 struct iw_request_info *info,
471 union iwreq_data *wrqu, char *extra)
472{
473 struct iwm_priv *iwm = ndev_to_iwm(dev);
474
475 wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
476
477 return 0;
478}
479
480static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
481{
482 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
483
484 if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
485 *auth_type = UMAC_AUTH_TYPE_8021X;
486 else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
487 if (iwm->umac_profile->sec.flags &
488 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
489 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
490 else
491 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
492 } else {
493 IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
494 return -EINVAL;
495 }
496
497 return 0;
498}
499
500static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
501{
502 u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
503 &iwm->umac_profile->sec.mcast_cipher;
504
505 switch (cipher) {
506 case IW_AUTH_CIPHER_NONE:
507 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
508 break;
509 case IW_AUTH_CIPHER_WEP40:
510 *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
511 break;
512 case IW_AUTH_CIPHER_TKIP:
513 *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
514 break;
515 case IW_AUTH_CIPHER_CCMP:
516 *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
517 break;
518 case IW_AUTH_CIPHER_WEP104:
519 *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
520 break;
521 default:
522 IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
523 return -ENOTSUPP;
524 }
525
526 return 0;
527}
528
529static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
530{
531 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
532
533 switch (auth_alg) {
534 case IW_AUTH_ALG_OPEN_SYSTEM:
535 *auth_type = UMAC_AUTH_TYPE_OPEN;
536 break;
537 case IW_AUTH_ALG_SHARED_KEY:
538 if (iwm->umac_profile->sec.flags &
539 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
540 if (*auth_type == UMAC_AUTH_TYPE_8021X)
541 return -EINVAL;
542 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
543 } else {
544 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
545 }
546 break;
547 case IW_AUTH_ALG_LEAP:
548 default:
549 IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
550 return -ENOTSUPP;
551 }
552
553 return 0;
554}
555
556static int iwm_wext_siwauth(struct net_device *dev,
557 struct iw_request_info *info,
558 struct iw_param *data, char *extra)
559{
560 struct iwm_priv *iwm = ndev_to_iwm(dev);
561 int ret;
562
563 if ((data->flags) &
564 (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
565 IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
566 /* We need to invalidate the current profile */
567 if (iwm->umac_profile_active) {
568 ret = iwm_invalidate_mlme_profile(iwm);
569 if (ret < 0) {
570 IWM_ERR(iwm, "Couldn't invalidate profile\n");
571 return ret;
572 }
573 }
574 }
575
576 switch (data->flags & IW_AUTH_INDEX) {
577 case IW_AUTH_WPA_VERSION:
578 return iwm_set_wpa_version(iwm, data->value);
579 break;
580 case IW_AUTH_CIPHER_PAIRWISE:
581 return iwm_set_cipher(iwm, data->value, 1);
582 break;
583 case IW_AUTH_CIPHER_GROUP:
584 return iwm_set_cipher(iwm, data->value, 0);
585 break;
586 case IW_AUTH_KEY_MGMT:
587 return iwm_set_key_mgt(iwm, data->value);
588 break;
589 case IW_AUTH_80211_AUTH_ALG:
590 return iwm_set_auth_alg(iwm, data->value);
591 break;
592 default:
593 return -ENOTSUPP;
594 }
595
596 return 0;
597}
598
599static int iwm_wext_giwauth(struct net_device *dev,
600 struct iw_request_info *info,
601 struct iw_param *data, char *extra)
602{
603 return 0;
604}
605
606static int iwm_wext_siwencodeext(struct net_device *dev,
607 struct iw_request_info *info,
608 struct iw_point *erq, char *extra)
609{
610 struct iwm_priv *iwm = ndev_to_iwm(dev);
611 struct iwm_key *key;
612 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
613 int uninitialized_var(alg), idx, i, remove = 0;
614
615 IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
616 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
617 IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
618 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
619 IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
620
621 switch (ext->alg) {
622 case IW_ENCODE_ALG_NONE:
623 remove = 1;
624 break;
625 case IW_ENCODE_ALG_WEP:
626 if (ext->key_len == WLAN_KEY_LEN_WEP40)
627 alg = UMAC_CIPHER_TYPE_WEP_40;
628 else if (ext->key_len == WLAN_KEY_LEN_WEP104)
629 alg = UMAC_CIPHER_TYPE_WEP_104;
630 else {
631 IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
632 return -EINVAL;
633 }
634
635 break;
636 case IW_ENCODE_ALG_TKIP:
637 alg = UMAC_CIPHER_TYPE_TKIP;
638 break;
639 case IW_ENCODE_ALG_CCMP:
640 alg = UMAC_CIPHER_TYPE_CCMP;
641 break;
642 default:
643 return -EOPNOTSUPP;
644 }
645
646 idx = erq->flags & IW_ENCODE_INDEX;
647
648 if (idx == 0) {
649 if (iwm->default_key)
650 for (i = 0; i < IWM_NUM_KEYS; i++) {
651 if (iwm->default_key == &iwm->keys[i]) {
652 idx = i;
653 break;
654 }
655 }
656 } else if (idx < 1 || idx > 4) {
657 return -EINVAL;
658 } else
659 idx--;
660
661 if (erq->flags & IW_ENCODE_DISABLED)
662 remove = 1;
663 else if ((erq->length == 0) ||
664 (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
665 iwm->default_key = &iwm->keys[idx];
666 if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
667 return iwm_set_tx_key(iwm, idx);
668 }
669
670 key = iwm_key_init(iwm, idx, !remove, ext, alg);
671
672 return iwm_set_key(iwm, remove, !iwm->default_key, key);
673}
674
675static const iw_handler iwm_handlers[] =
676{
677 (iw_handler) NULL, /* SIOCSIWCOMMIT */
678 (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
679 (iw_handler) NULL, /* SIOCSIWNWID */
680 (iw_handler) NULL, /* SIOCGIWNWID */
681 (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
682 (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
683 (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
684 (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
685 (iw_handler) NULL, /* SIOCSIWSENS */
686 (iw_handler) NULL, /* SIOCGIWSENS */
687 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
688 (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
689 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
690 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
691 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
692 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
693 (iw_handler) NULL, /* SIOCSIWSPY */
694 (iw_handler) NULL, /* SIOCGIWSPY */
695 (iw_handler) NULL, /* SIOCSIWTHRSPY */
696 (iw_handler) NULL, /* SIOCGIWTHRSPY */
697 (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
698 (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
699 (iw_handler) NULL, /* SIOCSIWMLME */
700 (iw_handler) NULL, /* SIOCGIWAPLIST */
701 (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
702 (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
703 (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
704 (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
705 (iw_handler) NULL, /* SIOCSIWNICKN */
706 (iw_handler) NULL, /* SIOCGIWNICKN */
707 (iw_handler) NULL, /* -- hole -- */
708 (iw_handler) NULL, /* -- hole -- */
709 (iw_handler) NULL, /* SIOCSIWRATE */
710 (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
711 (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
712 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
713 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
714 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
715 (iw_handler) NULL, /* SIOCSIWTXPOW */
716 (iw_handler) NULL, /* SIOCGIWTXPOW */
717 (iw_handler) NULL, /* SIOCSIWRETRY */
718 (iw_handler) NULL, /* SIOCGIWRETRY */
719 (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
720 (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
721 (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
722 (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
723 (iw_handler) NULL, /* -- hole -- */
724 (iw_handler) NULL, /* -- hole -- */
725 (iw_handler) NULL, /* SIOCSIWGENIE */
726 (iw_handler) NULL, /* SIOCGIWGENIE */
727 (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
728 (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
729 (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
730 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
731 (iw_handler) NULL, /* SIOCSIWPMKSA */
732 (iw_handler) NULL, /* -- hole -- */
733};
734
735const struct iw_handler_def iwm_iw_handler_def = {
736 .num_standard = ARRAY_SIZE(iwm_handlers),
737 .standard = (iw_handler *) iwm_handlers,
738 .get_wireless_stats = iwm_get_wireless_stats,
739};
740