Showing error 1886

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: net/ieee80211/ieee80211_wx.c
Line in file: 416
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

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