29eb41695a82f1745898c94b4356a0bb742a4092
[firefly-linux-kernel-4.4.55.git] / net / ieee80211 / ieee80211_wx.c
1 /******************************************************************************
2
3   Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
4
5   Portions of this file are based on the WEP enablement code provided by the
6   Host AP project hostap-drivers v0.1.3
7   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8   <j@w1.fi>
9   Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
10
11   This program is free software; you can redistribute it and/or modify it
12   under the terms of version 2 of the GNU General Public License as
13   published by the Free Software Foundation.
14
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18   more details.
19
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 59
22   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24   The full GNU General Public License is included in this distribution in the
25   file called LICENSE.
26
27   Contact Information:
28   James P. Ketrenos <ipw2100-admin@linux.intel.com>
29   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31 ******************************************************************************/
32
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
36
37 #include <net/lib80211.h>
38 #include <net/ieee80211.h>
39 #include <linux/wireless.h>
40
41 static const char *ieee80211_modes[] = {
42         "?", "a", "b", "ab", "g", "ag", "bg", "abg"
43 };
44
45 #define MAX_CUSTOM_LEN 64
46 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
47                                       char *start, char *stop,
48                                       struct ieee80211_network *network,
49                                       struct iw_request_info *info)
50 {
51         char custom[MAX_CUSTOM_LEN];
52         char *p;
53         struct iw_event iwe;
54         int i, j;
55         char *current_val;      /* For rates */
56         u8 rate;
57
58         /* First entry *MUST* be the AP MAC address */
59         iwe.cmd = SIOCGIWAP;
60         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
61         memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
62         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
63
64         /* Remaining entries will be displayed in the order we provide them */
65
66         /* Add the ESSID */
67         iwe.cmd = SIOCGIWESSID;
68         iwe.u.data.flags = 1;
69         iwe.u.data.length = min(network->ssid_len, (u8) 32);
70         start = iwe_stream_add_point(info, start, stop,
71                                      &iwe, network->ssid);
72
73         /* Add the protocol name */
74         iwe.cmd = SIOCGIWNAME;
75         snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
76                  ieee80211_modes[network->mode]);
77         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
78
79         /* Add mode */
80         iwe.cmd = SIOCGIWMODE;
81         if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
82                 if (network->capability & WLAN_CAPABILITY_ESS)
83                         iwe.u.mode = IW_MODE_MASTER;
84                 else
85                         iwe.u.mode = IW_MODE_ADHOC;
86
87                 start = iwe_stream_add_event(info, start, stop,
88                                              &iwe, IW_EV_UINT_LEN);
89         }
90
91         /* Add channel and frequency */
92         /* Note : userspace automatically computes channel using iwrange */
93         iwe.cmd = SIOCGIWFREQ;
94         iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
95         iwe.u.freq.e = 6;
96         iwe.u.freq.i = 0;
97         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
98
99         /* Add encryption capability */
100         iwe.cmd = SIOCGIWENCODE;
101         if (network->capability & WLAN_CAPABILITY_PRIVACY)
102                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
103         else
104                 iwe.u.data.flags = IW_ENCODE_DISABLED;
105         iwe.u.data.length = 0;
106         start = iwe_stream_add_point(info, start, stop,
107                                      &iwe, network->ssid);
108
109         /* Add basic and extended rates */
110         /* Rate : stuffing multiple values in a single event require a bit
111          * more of magic - Jean II */
112         current_val = start + iwe_stream_lcp_len(info);
113         iwe.cmd = SIOCGIWRATE;
114         /* Those two flags are ignored... */
115         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
116
117         for (i = 0, j = 0; i < network->rates_len;) {
118                 if (j < network->rates_ex_len &&
119                     ((network->rates_ex[j] & 0x7F) <
120                      (network->rates[i] & 0x7F)))
121                         rate = network->rates_ex[j++] & 0x7F;
122                 else
123                         rate = network->rates[i++] & 0x7F;
124                 /* Bit rate given in 500 kb/s units (+ 0x80) */
125                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126                 /* Add new value to event */
127                 current_val = iwe_stream_add_value(info, start, current_val,
128                                                    stop, &iwe, IW_EV_PARAM_LEN);
129         }
130         for (; j < network->rates_ex_len; j++) {
131                 rate = network->rates_ex[j] & 0x7F;
132                 /* Bit rate given in 500 kb/s units (+ 0x80) */
133                 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
134                 /* Add new value to event */
135                 current_val = iwe_stream_add_value(info, start, current_val,
136                                                    stop, &iwe, IW_EV_PARAM_LEN);
137         }
138         /* Check if we added any rate */
139         if ((current_val - start) > iwe_stream_lcp_len(info))
140                 start = current_val;
141
142         /* Add quality statistics */
143         iwe.cmd = IWEVQUAL;
144         iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
145             IW_QUAL_NOISE_UPDATED;
146
147         if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
148                 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
149                     IW_QUAL_LEVEL_INVALID;
150                 iwe.u.qual.qual = 0;
151         } else {
152                 if (ieee->perfect_rssi == ieee->worst_rssi)
153                         iwe.u.qual.qual = 100;
154                 else
155                         iwe.u.qual.qual =
156                             (100 *
157                              (ieee->perfect_rssi - ieee->worst_rssi) *
158                              (ieee->perfect_rssi - ieee->worst_rssi) -
159                              (ieee->perfect_rssi - network->stats.rssi) *
160                              (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
161                               62 * (ieee->perfect_rssi -
162                                     network->stats.rssi))) /
163                             ((ieee->perfect_rssi -
164                               ieee->worst_rssi) * (ieee->perfect_rssi -
165                                                    ieee->worst_rssi));
166                 if (iwe.u.qual.qual > 100)
167                         iwe.u.qual.qual = 100;
168                 else if (iwe.u.qual.qual < 1)
169                         iwe.u.qual.qual = 0;
170         }
171
172         if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
173                 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
174                 iwe.u.qual.noise = 0;
175         } else {
176                 iwe.u.qual.noise = network->stats.noise;
177         }
178
179         if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
180                 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
181                 iwe.u.qual.level = 0;
182         } else {
183                 iwe.u.qual.level = network->stats.signal;
184         }
185
186         start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
187
188         iwe.cmd = IWEVCUSTOM;
189         p = custom;
190
191         iwe.u.data.length = p - custom;
192         if (iwe.u.data.length)
193                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
194
195         memset(&iwe, 0, sizeof(iwe));
196         if (network->wpa_ie_len) {
197                 char buf[MAX_WPA_IE_LEN];
198                 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
199                 iwe.cmd = IWEVGENIE;
200                 iwe.u.data.length = network->wpa_ie_len;
201                 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
202         }
203
204         memset(&iwe, 0, sizeof(iwe));
205         if (network->rsn_ie_len) {
206                 char buf[MAX_WPA_IE_LEN];
207                 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
208                 iwe.cmd = IWEVGENIE;
209                 iwe.u.data.length = network->rsn_ie_len;
210                 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
211         }
212
213         /* Add EXTRA: Age to display seconds since last beacon/probe response
214          * for given network. */
215         iwe.cmd = IWEVCUSTOM;
216         p = custom;
217         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
218                       " Last beacon: %dms ago",
219                       jiffies_to_msecs(jiffies - network->last_scanned));
220         iwe.u.data.length = p - custom;
221         if (iwe.u.data.length)
222                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
223
224         /* Add spectrum management information */
225         iwe.cmd = -1;
226         p = custom;
227         p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
228
229         if (ieee80211_get_channel_flags(ieee, network->channel) &
230             IEEE80211_CH_INVALID) {
231                 iwe.cmd = IWEVCUSTOM;
232                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
233         }
234
235         if (ieee80211_get_channel_flags(ieee, network->channel) &
236             IEEE80211_CH_RADAR_DETECT) {
237                 iwe.cmd = IWEVCUSTOM;
238                 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
239         }
240
241         if (iwe.cmd == IWEVCUSTOM) {
242                 iwe.u.data.length = p - custom;
243                 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
244         }
245
246         return start;
247 }
248
249 #define SCAN_ITEM_SIZE 128
250
251 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
252                           struct iw_request_info *info,
253                           union iwreq_data *wrqu, char *extra)
254 {
255         struct ieee80211_network *network;
256         unsigned long flags;
257         int err = 0;
258
259         char *ev = extra;
260         char *stop = ev + wrqu->data.length;
261         int i = 0;
262         DECLARE_SSID_BUF(ssid);
263
264         IEEE80211_DEBUG_WX("Getting scan\n");
265
266         spin_lock_irqsave(&ieee->lock, flags);
267
268         list_for_each_entry(network, &ieee->network_list, list) {
269                 i++;
270                 if (stop - ev < SCAN_ITEM_SIZE) {
271                         err = -E2BIG;
272                         break;
273                 }
274
275                 if (ieee->scan_age == 0 ||
276                     time_after(network->last_scanned + ieee->scan_age, jiffies))
277                         ev = ieee80211_translate_scan(ieee, ev, stop, network,
278                                                       info);
279                 else
280                         IEEE80211_DEBUG_SCAN("Not showing network '%s ("
281                                              "%pM)' due to age (%dms).\n",
282                                              print_ssid(ssid, network->ssid,
283                                                          network->ssid_len),
284                                              network->bssid,
285                                              jiffies_to_msecs(jiffies -
286                                                               network->
287                                                               last_scanned));
288         }
289
290         spin_unlock_irqrestore(&ieee->lock, flags);
291
292         wrqu->data.length = ev - extra;
293         wrqu->data.flags = 0;
294
295         IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
296
297         return err;
298 }
299
300 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
301                             struct iw_request_info *info,
302                             union iwreq_data *wrqu, char *keybuf)
303 {
304         struct iw_point *erq = &(wrqu->encoding);
305         struct net_device *dev = ieee->dev;
306         struct ieee80211_security sec = {
307                 .flags = 0
308         };
309         int i, key, key_provided, len;
310         struct ieee80211_crypt_data **crypt;
311         int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
312         DECLARE_SSID_BUF(ssid);
313
314         IEEE80211_DEBUG_WX("SET_ENCODE\n");
315
316         key = erq->flags & IW_ENCODE_INDEX;
317         if (key) {
318                 if (key > WEP_KEYS)
319                         return -EINVAL;
320                 key--;
321                 key_provided = 1;
322         } else {
323                 key_provided = 0;
324                 key = ieee->tx_keyidx;
325         }
326
327         IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
328                            "provided" : "default");
329
330         crypt = &ieee->crypt[key];
331
332         if (erq->flags & IW_ENCODE_DISABLED) {
333                 if (key_provided && *crypt) {
334                         IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
335                                            key);
336                         ieee80211_crypt_delayed_deinit(ieee, crypt);
337                 } else
338                         IEEE80211_DEBUG_WX("Disabling encryption.\n");
339
340                 /* Check all the keys to see if any are still configured,
341                  * and if no key index was provided, de-init them all */
342                 for (i = 0; i < WEP_KEYS; i++) {
343                         if (ieee->crypt[i] != NULL) {
344                                 if (key_provided)
345                                         break;
346                                 ieee80211_crypt_delayed_deinit(ieee,
347                                                                &ieee->crypt[i]);
348                         }
349                 }
350
351                 if (i == WEP_KEYS) {
352                         sec.enabled = 0;
353                         sec.encrypt = 0;
354                         sec.level = SEC_LEVEL_0;
355                         sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
356                 }
357
358                 goto done;
359         }
360
361         sec.enabled = 1;
362         sec.encrypt = 1;
363         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
364
365         if (*crypt != NULL && (*crypt)->ops != NULL &&
366             strcmp((*crypt)->ops->name, "WEP") != 0) {
367                 /* changing to use WEP; deinit previously used algorithm
368                  * on this key */
369                 ieee80211_crypt_delayed_deinit(ieee, crypt);
370         }
371
372         if (*crypt == NULL && host_crypto) {
373                 struct ieee80211_crypt_data *new_crypt;
374
375                 /* take WEP into use */
376                 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
377                                     GFP_KERNEL);
378                 if (new_crypt == NULL)
379                         return -ENOMEM;
380                 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
381                 if (!new_crypt->ops) {
382                         request_module("ieee80211_crypt_wep");
383                         new_crypt->ops = ieee80211_get_crypto_ops("WEP");
384                 }
385
386                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
387                         new_crypt->priv = new_crypt->ops->init(key);
388
389                 if (!new_crypt->ops || !new_crypt->priv) {
390                         kfree(new_crypt);
391                         new_crypt = NULL;
392
393                         printk(KERN_WARNING "%s: could not initialize WEP: "
394                                "load module ieee80211_crypt_wep\n", dev->name);
395                         return -EOPNOTSUPP;
396                 }
397                 *crypt = new_crypt;
398         }
399
400         /* If a new key was provided, set it up */
401         if (erq->length > 0) {
402                 len = erq->length <= 5 ? 5 : 13;
403                 memcpy(sec.keys[key], keybuf, erq->length);
404                 if (len > erq->length)
405                         memset(sec.keys[key] + erq->length, 0,
406                                len - erq->length);
407                 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
408                                    key, print_ssid(ssid, sec.keys[key], len),
409                                    erq->length, len);
410                 sec.key_sizes[key] = len;
411                 if (*crypt)
412                         (*crypt)->ops->set_key(sec.keys[key], len, NULL,
413                                                (*crypt)->priv);
414                 sec.flags |= (1 << key);
415                 /* This ensures a key will be activated if no key is
416                  * explicitly set */
417                 if (key == sec.active_key)
418                         sec.flags |= SEC_ACTIVE_KEY;
419
420         } else {
421                 if (host_crypto) {
422                         len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
423                                                      NULL, (*crypt)->priv);
424                         if (len == 0) {
425                                 /* Set a default key of all 0 */
426                                 IEEE80211_DEBUG_WX("Setting key %d to all "
427                                                    "zero.\n", key);
428                                 memset(sec.keys[key], 0, 13);
429                                 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
430                                                        (*crypt)->priv);
431                                 sec.key_sizes[key] = 13;
432                                 sec.flags |= (1 << key);
433                         }
434                 }
435                 /* No key data - just set the default TX key index */
436                 if (key_provided) {
437                         IEEE80211_DEBUG_WX("Setting key %d to default Tx "
438                                            "key.\n", key);
439                         ieee->tx_keyidx = key;
440                         sec.active_key = key;
441                         sec.flags |= SEC_ACTIVE_KEY;
442                 }
443         }
444         if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
445                 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
446                 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
447                     WLAN_AUTH_SHARED_KEY;
448                 sec.flags |= SEC_AUTH_MODE;
449                 IEEE80211_DEBUG_WX("Auth: %s\n",
450                                    sec.auth_mode == WLAN_AUTH_OPEN ?
451                                    "OPEN" : "SHARED KEY");
452         }
453
454         /* For now we just support WEP, so only set that security level...
455          * TODO: When WPA is added this is one place that needs to change */
456         sec.flags |= SEC_LEVEL;
457         sec.level = SEC_LEVEL_1;        /* 40 and 104 bit WEP */
458         sec.encode_alg[key] = SEC_ALG_WEP;
459
460       done:
461         if (ieee->set_security)
462                 ieee->set_security(dev, &sec);
463
464         /* Do not reset port if card is in Managed mode since resetting will
465          * generate new IEEE 802.11 authentication which may end up in looping
466          * with IEEE 802.1X.  If your hardware requires a reset after WEP
467          * configuration (for example... Prism2), implement the reset_port in
468          * the callbacks structures used to initialize the 802.11 stack. */
469         if (ieee->reset_on_keychange &&
470             ieee->iw_mode != IW_MODE_INFRA &&
471             ieee->reset_port && ieee->reset_port(dev)) {
472                 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
473                 return -EINVAL;
474         }
475         return 0;
476 }
477
478 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
479                             struct iw_request_info *info,
480                             union iwreq_data *wrqu, char *keybuf)
481 {
482         struct iw_point *erq = &(wrqu->encoding);
483         int len, key;
484         struct ieee80211_crypt_data *crypt;
485         struct ieee80211_security *sec = &ieee->sec;
486
487         IEEE80211_DEBUG_WX("GET_ENCODE\n");
488
489         key = erq->flags & IW_ENCODE_INDEX;
490         if (key) {
491                 if (key > WEP_KEYS)
492                         return -EINVAL;
493                 key--;
494         } else
495                 key = ieee->tx_keyidx;
496
497         crypt = ieee->crypt[key];
498         erq->flags = key + 1;
499
500         if (!sec->enabled) {
501                 erq->length = 0;
502                 erq->flags |= IW_ENCODE_DISABLED;
503                 return 0;
504         }
505
506         len = sec->key_sizes[key];
507         memcpy(keybuf, sec->keys[key], len);
508
509         erq->length = len;
510         erq->flags |= IW_ENCODE_ENABLED;
511
512         if (ieee->open_wep)
513                 erq->flags |= IW_ENCODE_OPEN;
514         else
515                 erq->flags |= IW_ENCODE_RESTRICTED;
516
517         return 0;
518 }
519
520 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
521                                struct iw_request_info *info,
522                                union iwreq_data *wrqu, char *extra)
523 {
524         struct net_device *dev = ieee->dev;
525         struct iw_point *encoding = &wrqu->encoding;
526         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
527         int i, idx, ret = 0;
528         int group_key = 0;
529         const char *alg, *module;
530         struct ieee80211_crypto_ops *ops;
531         struct ieee80211_crypt_data **crypt;
532
533         struct ieee80211_security sec = {
534                 .flags = 0,
535         };
536
537         idx = encoding->flags & IW_ENCODE_INDEX;
538         if (idx) {
539                 if (idx < 1 || idx > WEP_KEYS)
540                         return -EINVAL;
541                 idx--;
542         } else
543                 idx = ieee->tx_keyidx;
544
545         if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
546                 crypt = &ieee->crypt[idx];
547                 group_key = 1;
548         } else {
549                 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
550                 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
551                         return -EINVAL;
552                 if (ieee->iw_mode == IW_MODE_INFRA)
553                         crypt = &ieee->crypt[idx];
554                 else
555                         return -EINVAL;
556         }
557
558         sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
559         if ((encoding->flags & IW_ENCODE_DISABLED) ||
560             ext->alg == IW_ENCODE_ALG_NONE) {
561                 if (*crypt)
562                         ieee80211_crypt_delayed_deinit(ieee, crypt);
563
564                 for (i = 0; i < WEP_KEYS; i++)
565                         if (ieee->crypt[i] != NULL)
566                                 break;
567
568                 if (i == WEP_KEYS) {
569                         sec.enabled = 0;
570                         sec.encrypt = 0;
571                         sec.level = SEC_LEVEL_0;
572                         sec.flags |= SEC_LEVEL;
573                 }
574                 goto done;
575         }
576
577         sec.enabled = 1;
578         sec.encrypt = 1;
579
580         if (group_key ? !ieee->host_mc_decrypt :
581             !(ieee->host_encrypt || ieee->host_decrypt ||
582               ieee->host_encrypt_msdu))
583                 goto skip_host_crypt;
584
585         switch (ext->alg) {
586         case IW_ENCODE_ALG_WEP:
587                 alg = "WEP";
588                 module = "ieee80211_crypt_wep";
589                 break;
590         case IW_ENCODE_ALG_TKIP:
591                 alg = "TKIP";
592                 module = "ieee80211_crypt_tkip";
593                 break;
594         case IW_ENCODE_ALG_CCMP:
595                 alg = "CCMP";
596                 module = "ieee80211_crypt_ccmp";
597                 break;
598         default:
599                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
600                                    dev->name, ext->alg);
601                 ret = -EINVAL;
602                 goto done;
603         }
604
605         ops = ieee80211_get_crypto_ops(alg);
606         if (ops == NULL) {
607                 request_module(module);
608                 ops = ieee80211_get_crypto_ops(alg);
609         }
610         if (ops == NULL) {
611                 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
612                                    dev->name, ext->alg);
613                 ret = -EINVAL;
614                 goto done;
615         }
616
617         if (*crypt == NULL || (*crypt)->ops != ops) {
618                 struct ieee80211_crypt_data *new_crypt;
619
620                 ieee80211_crypt_delayed_deinit(ieee, crypt);
621
622                 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
623                 if (new_crypt == NULL) {
624                         ret = -ENOMEM;
625                         goto done;
626                 }
627                 new_crypt->ops = ops;
628                 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
629                         new_crypt->priv = new_crypt->ops->init(idx);
630                 if (new_crypt->priv == NULL) {
631                         kfree(new_crypt);
632                         ret = -EINVAL;
633                         goto done;
634                 }
635                 *crypt = new_crypt;
636         }
637
638         if (ext->key_len > 0 && (*crypt)->ops->set_key &&
639             (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
640                                    (*crypt)->priv) < 0) {
641                 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
642                 ret = -EINVAL;
643                 goto done;
644         }
645
646       skip_host_crypt:
647         if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
648                 ieee->tx_keyidx = idx;
649                 sec.active_key = idx;
650                 sec.flags |= SEC_ACTIVE_KEY;
651         }
652
653         if (ext->alg != IW_ENCODE_ALG_NONE) {
654                 memcpy(sec.keys[idx], ext->key, ext->key_len);
655                 sec.key_sizes[idx] = ext->key_len;
656                 sec.flags |= (1 << idx);
657                 if (ext->alg == IW_ENCODE_ALG_WEP) {
658                         sec.encode_alg[idx] = SEC_ALG_WEP;
659                         sec.flags |= SEC_LEVEL;
660                         sec.level = SEC_LEVEL_1;
661                 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
662                         sec.encode_alg[idx] = SEC_ALG_TKIP;
663                         sec.flags |= SEC_LEVEL;
664                         sec.level = SEC_LEVEL_2;
665                 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
666                         sec.encode_alg[idx] = SEC_ALG_CCMP;
667                         sec.flags |= SEC_LEVEL;
668                         sec.level = SEC_LEVEL_3;
669                 }
670                 /* Don't set sec level for group keys. */
671                 if (group_key)
672                         sec.flags &= ~SEC_LEVEL;
673         }
674       done:
675         if (ieee->set_security)
676                 ieee->set_security(ieee->dev, &sec);
677
678         /*
679          * Do not reset port if card is in Managed mode since resetting will
680          * generate new IEEE 802.11 authentication which may end up in looping
681          * with IEEE 802.1X. If your hardware requires a reset after WEP
682          * configuration (for example... Prism2), implement the reset_port in
683          * the callbacks structures used to initialize the 802.11 stack.
684          */
685         if (ieee->reset_on_keychange &&
686             ieee->iw_mode != IW_MODE_INFRA &&
687             ieee->reset_port && ieee->reset_port(dev)) {
688                 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
689                 return -EINVAL;
690         }
691
692         return ret;
693 }
694
695 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
696                                struct iw_request_info *info,
697                                union iwreq_data *wrqu, char *extra)
698 {
699         struct iw_point *encoding = &wrqu->encoding;
700         struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
701         struct ieee80211_security *sec = &ieee->sec;
702         int idx, max_key_len;
703
704         max_key_len = encoding->length - sizeof(*ext);
705         if (max_key_len < 0)
706                 return -EINVAL;
707
708         idx = encoding->flags & IW_ENCODE_INDEX;
709         if (idx) {
710                 if (idx < 1 || idx > WEP_KEYS)
711                         return -EINVAL;
712                 idx--;
713         } else
714                 idx = ieee->tx_keyidx;
715
716         if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
717             ext->alg != IW_ENCODE_ALG_WEP)
718                 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
719                         return -EINVAL;
720
721         encoding->flags = idx + 1;
722         memset(ext, 0, sizeof(*ext));
723
724         if (!sec->enabled) {
725                 ext->alg = IW_ENCODE_ALG_NONE;
726                 ext->key_len = 0;
727                 encoding->flags |= IW_ENCODE_DISABLED;
728         } else {
729                 if (sec->encode_alg[idx] == SEC_ALG_WEP)
730                         ext->alg = IW_ENCODE_ALG_WEP;
731                 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
732                         ext->alg = IW_ENCODE_ALG_TKIP;
733                 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
734                         ext->alg = IW_ENCODE_ALG_CCMP;
735                 else
736                         return -EINVAL;
737
738                 ext->key_len = sec->key_sizes[idx];
739                 memcpy(ext->key, sec->keys[idx], ext->key_len);
740                 encoding->flags |= IW_ENCODE_ENABLED;
741                 if (ext->key_len &&
742                     (ext->alg == IW_ENCODE_ALG_TKIP ||
743                      ext->alg == IW_ENCODE_ALG_CCMP))
744                         ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
745
746         }
747
748         return 0;
749 }
750
751 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
752 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
753
754 EXPORT_SYMBOL(ieee80211_wx_get_scan);
755 EXPORT_SYMBOL(ieee80211_wx_set_encode);
756 EXPORT_SYMBOL(ieee80211_wx_get_encode);