Root/drivers/staging/rtl8192e/rtllib_wx.c

1/******************************************************************************
2
3  Copyright(c) 2004 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  <jkmaline@cc.hut.fi>
9  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.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#include <linux/wireless.h>
33#include <linux/kmod.h>
34#include <linux/module.h>
35
36#include "rtllib.h"
37struct modes_unit {
38    char *mode_string;
39    int mode_size;
40};
41static struct modes_unit rtllib_modes[] = {
42    {"a", 1},
43    {"b", 1},
44    {"g", 1},
45    {"?", 1},
46    {"N-24G", 5},
47    {"N-5G", 4},
48};
49
50#define MAX_CUSTOM_LEN 64
51static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
52                       char *start, char *stop,
53                       struct rtllib_network *network,
54                       struct iw_request_info *info)
55{
56    char custom[MAX_CUSTOM_LEN];
57    char proto_name[IFNAMSIZ];
58    char *pname = proto_name;
59    char *p;
60    struct iw_event iwe;
61    int i, j;
62    u16 max_rate, rate;
63    static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
64
65    /* First entry *MUST* be the AP MAC address */
66    iwe.cmd = SIOCGIWAP;
67    iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
68    memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
69    start = iwe_stream_add_event_rsl(info, start, stop,
70                     &iwe, IW_EV_ADDR_LEN);
71    /* Remaining entries will be displayed in the order we provide them */
72
73    /* Add the ESSID */
74    iwe.cmd = SIOCGIWESSID;
75    iwe.u.data.flags = 1;
76    if (network->ssid_len > 0) {
77        iwe.u.data.length = min(network->ssid_len, (u8)32);
78        start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
79                         network->ssid);
80    } else if (network->hidden_ssid_len == 0) {
81        iwe.u.data.length = sizeof("<hidden>");
82        start = iwe_stream_add_point_rsl(info, start, stop,
83                         &iwe, "<hidden>");
84    } else {
85        iwe.u.data.length = min(network->hidden_ssid_len, (u8)32);
86        start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
87                         network->hidden_ssid);
88    }
89    /* Add the protocol name */
90    iwe.cmd = SIOCGIWNAME;
91    for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
92        if (network->mode&(1<<i)) {
93            sprintf(pname, rtllib_modes[i].mode_string,
94                rtllib_modes[i].mode_size);
95            pname += rtllib_modes[i].mode_size;
96        }
97    }
98    *pname = '\0';
99    snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
100    start = iwe_stream_add_event_rsl(info, start, stop,
101                     &iwe, IW_EV_CHAR_LEN);
102    /* Add mode */
103    iwe.cmd = SIOCGIWMODE;
104    if (network->capability &
105        (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
106        if (network->capability & WLAN_CAPABILITY_ESS)
107            iwe.u.mode = IW_MODE_MASTER;
108        else
109            iwe.u.mode = IW_MODE_ADHOC;
110        start = iwe_stream_add_event_rsl(info, start, stop,
111                         &iwe, IW_EV_UINT_LEN);
112    }
113
114    /* Add frequency/channel */
115    iwe.cmd = SIOCGIWFREQ;
116/* iwe.u.freq.m = rtllib_frequency(network->channel, network->mode);
117    iwe.u.freq.e = 3; */
118    iwe.u.freq.m = network->channel;
119    iwe.u.freq.e = 0;
120    iwe.u.freq.i = 0;
121    start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
122                     IW_EV_FREQ_LEN);
123
124    /* Add encryption capability */
125    iwe.cmd = SIOCGIWENCODE;
126    if (network->capability & WLAN_CAPABILITY_PRIVACY)
127        iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
128    else
129        iwe.u.data.flags = IW_ENCODE_DISABLED;
130    iwe.u.data.length = 0;
131    start = iwe_stream_add_point_rsl(info, start, stop,
132                     &iwe, network->ssid);
133    /* Add basic and extended rates */
134    max_rate = 0;
135    p = custom;
136    p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
137    for (i = 0, j = 0; i < network->rates_len;) {
138        if (j < network->rates_ex_len &&
139            ((network->rates_ex[j] & 0x7F) <
140             (network->rates[i] & 0x7F)))
141            rate = network->rates_ex[j++] & 0x7F;
142        else
143            rate = network->rates[i++] & 0x7F;
144        if (rate > max_rate)
145            max_rate = rate;
146        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
147                  "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
148    }
149    for (; j < network->rates_ex_len; j++) {
150        rate = network->rates_ex[j] & 0x7F;
151        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
152                  "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
153        if (rate > max_rate)
154            max_rate = rate;
155    }
156
157    if (network->mode >= IEEE_N_24G) {
158        struct ht_capab_ele *ht_cap = NULL;
159        bool is40M = false, isShortGI = false;
160        u8 max_mcs = 0;
161        if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
162            ht_cap = (struct ht_capab_ele *)
163                 &network->bssht.bdHTCapBuf[4];
164        else
165            ht_cap = (struct ht_capab_ele *)
166                 &network->bssht.bdHTCapBuf[0];
167        is40M = (ht_cap->ChlWidth) ? 1 : 0;
168        isShortGI = (ht_cap->ChlWidth) ?
169                ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
170                ((ht_cap->ShortGI20Mhz) ? 1 : 0);
171
172        max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
173                          MCS_FILTER_ALL);
174        rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
175        if (rate > max_rate)
176            max_rate = rate;
177    }
178    iwe.cmd = SIOCGIWRATE;
179    iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
180    iwe.u.bitrate.value = max_rate * 500000;
181    start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
182                     IW_EV_PARAM_LEN);
183    iwe.cmd = IWEVCUSTOM;
184    iwe.u.data.length = p - custom;
185    if (iwe.u.data.length)
186        start = iwe_stream_add_point_rsl(info, start, stop,
187                         &iwe, custom);
188    /* Add quality statistics */
189    /* TODO: Fix these values... */
190    iwe.cmd = IWEVQUAL;
191    iwe.u.qual.qual = network->stats.signal;
192    iwe.u.qual.level = network->stats.rssi;
193    iwe.u.qual.noise = network->stats.noise;
194    iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
195    if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
196        iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
197    if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
198        iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
199    if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
200        iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
201    iwe.u.qual.updated = 7;
202    start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
203                     IW_EV_QUAL_LEN);
204
205    iwe.cmd = IWEVCUSTOM;
206    p = custom;
207    iwe.u.data.length = p - custom;
208    if (iwe.u.data.length)
209        start = iwe_stream_add_point_rsl(info, start, stop,
210                         &iwe, custom);
211
212    memset(&iwe, 0, sizeof(iwe));
213    if (network->wpa_ie_len) {
214        char buf[MAX_WPA_IE_LEN];
215        memcpy(buf, network->wpa_ie, network->wpa_ie_len);
216        iwe.cmd = IWEVGENIE;
217        iwe.u.data.length = network->wpa_ie_len;
218        start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
219    }
220    memset(&iwe, 0, sizeof(iwe));
221    if (network->rsn_ie_len) {
222        char buf[MAX_WPA_IE_LEN];
223        memcpy(buf, network->rsn_ie, network->rsn_ie_len);
224        iwe.cmd = IWEVGENIE;
225        iwe.u.data.length = network->rsn_ie_len;
226        start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
227    }
228
229    /* add info for WZC */
230    memset(&iwe, 0, sizeof(iwe));
231    if (network->wzc_ie_len) {
232        char buf[MAX_WZC_IE_LEN];
233        memcpy(buf, network->wzc_ie, network->wzc_ie_len);
234        iwe.cmd = IWEVGENIE;
235        iwe.u.data.length = network->wzc_ie_len;
236        start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
237    }
238
239    /* Add EXTRA: Age to display seconds since last beacon/probe response
240     * for given network. */
241    iwe.cmd = IWEVCUSTOM;
242    p = custom;
243    p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
244              " Last beacon: %lums ago",
245              (jiffies - network->last_scanned) / (HZ / 100));
246    iwe.u.data.length = p - custom;
247    if (iwe.u.data.length)
248        start = iwe_stream_add_point_rsl(info, start, stop,
249                         &iwe, custom);
250
251    return start;
252}
253
254int rtllib_wx_get_scan(struct rtllib_device *ieee,
255              struct iw_request_info *info,
256              union iwreq_data *wrqu, char *extra)
257{
258    struct rtllib_network *network;
259    unsigned long flags;
260
261    char *ev = extra;
262    char *stop = ev + wrqu->data.length;
263    int i = 0;
264    int err = 0;
265    RTLLIB_DEBUG_WX("Getting scan\n");
266    down(&ieee->wx_sem);
267    spin_lock_irqsave(&ieee->lock, flags);
268
269    list_for_each_entry(network, &ieee->network_list, list) {
270        i++;
271        if ((stop - ev) < 200) {
272            err = -E2BIG;
273            break;
274        }
275        if (ieee->scan_age == 0 ||
276            time_after(network->last_scanned + ieee->scan_age, jiffies))
277            ev = rtl819x_translate_scan(ieee, ev, stop, network,
278                            info);
279        else
280            RTLLIB_DEBUG_SCAN("Not showing network '%s ("
281                " %pM)' due to age (%lums).\n",
282                escape_essid(network->ssid,
283                         network->ssid_len),
284                network->bssid,
285                (jiffies - network->last_scanned) / (HZ / 100));
286    }
287
288    spin_unlock_irqrestore(&ieee->lock, flags);
289    up(&ieee->wx_sem);
290    wrqu->data.length = ev - extra;
291    wrqu->data.flags = 0;
292
293    RTLLIB_DEBUG_WX("exit: %d networks returned.\n", i);
294
295    return err;
296}
297EXPORT_SYMBOL(rtllib_wx_get_scan);
298
299int rtllib_wx_set_encode(struct rtllib_device *ieee,
300                struct iw_request_info *info,
301                union iwreq_data *wrqu, char *keybuf)
302{
303    struct iw_point *erq = &(wrqu->encoding);
304    struct net_device *dev = ieee->dev;
305    struct rtllib_security sec = {
306        .flags = 0
307    };
308    int i, key, key_provided, len;
309    struct lib80211_crypt_data **crypt;
310
311    RTLLIB_DEBUG_WX("SET_ENCODE\n");
312
313    key = erq->flags & IW_ENCODE_INDEX;
314    if (key) {
315        if (key > NUM_WEP_KEYS)
316            return -EINVAL;
317        key--;
318        key_provided = 1;
319    } else {
320        key_provided = 0;
321        key = ieee->crypt_info.tx_keyidx;
322    }
323
324    RTLLIB_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
325               "provided" : "default");
326    crypt = &ieee->crypt_info.crypt[key];
327    if (erq->flags & IW_ENCODE_DISABLED) {
328        if (key_provided && *crypt) {
329            RTLLIB_DEBUG_WX("Disabling encryption on key %d.\n",
330                       key);
331            lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
332        } else
333            RTLLIB_DEBUG_WX("Disabling encryption.\n");
334
335        /* Check all the keys to see if any are still configured,
336         * and if no key index was provided, de-init them all */
337        for (i = 0; i < NUM_WEP_KEYS; i++) {
338            if (ieee->crypt_info.crypt[i] != NULL) {
339                if (key_provided)
340                    break;
341                lib80211_crypt_delayed_deinit(&ieee->crypt_info,
342                                &ieee->crypt_info.crypt[i]);
343            }
344        }
345
346        if (i == NUM_WEP_KEYS) {
347            sec.enabled = 0;
348            sec.level = SEC_LEVEL_0;
349            sec.flags |= SEC_ENABLED | SEC_LEVEL;
350        }
351
352        goto done;
353    }
354
355
356
357    sec.enabled = 1;
358    sec.flags |= SEC_ENABLED;
359
360    if (*crypt != NULL && (*crypt)->ops != NULL &&
361        strcmp((*crypt)->ops->name, "R-WEP") != 0) {
362        /* changing to use WEP; deinit previously used algorithm
363         * on this key */
364        lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
365    }
366
367    if (*crypt == NULL) {
368        struct lib80211_crypt_data *new_crypt;
369
370        /* take WEP into use */
371        new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
372                    GFP_KERNEL);
373        if (new_crypt == NULL)
374            return -ENOMEM;
375        new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
376        if (!new_crypt->ops) {
377            request_module("rtllib_crypt_wep");
378            new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
379        }
380
381        if (new_crypt->ops)
382            new_crypt->priv = new_crypt->ops->init(key);
383
384        if (!new_crypt->ops || !new_crypt->priv) {
385            kfree(new_crypt);
386            new_crypt = NULL;
387
388            printk(KERN_WARNING "%s: could not initialize WEP: "
389                   "load module rtllib_crypt_wep\n",
390                   dev->name);
391            return -EOPNOTSUPP;
392        }
393        *crypt = new_crypt;
394    }
395
396    /* If a new key was provided, set it up */
397    if (erq->length > 0) {
398        len = erq->length <= 5 ? 5 : 13;
399        memcpy(sec.keys[key], keybuf, erq->length);
400        if (len > erq->length)
401            memset(sec.keys[key] + erq->length, 0,
402                   len - erq->length);
403        RTLLIB_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
404                   key, escape_essid(sec.keys[key], len),
405                   erq->length, len);
406        sec.key_sizes[key] = len;
407        (*crypt)->ops->set_key(sec.keys[key], len, NULL,
408                       (*crypt)->priv);
409        sec.flags |= (1 << key);
410        /* This ensures a key will be activated if no key is
411         * explicitly set */
412        if (key == sec.active_key)
413            sec.flags |= SEC_ACTIVE_KEY;
414        ieee->crypt_info.tx_keyidx = key;
415
416    } else {
417        len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
418                         NULL, (*crypt)->priv);
419        if (len == 0) {
420            /* Set a default key of all 0 */
421            printk(KERN_INFO "Setting key %d to all zero.\n",
422                       key);
423
424            RTLLIB_DEBUG_WX("Setting key %d to all zero.\n",
425                       key);
426            memset(sec.keys[key], 0, 13);
427            (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
428                           (*crypt)->priv);
429            sec.key_sizes[key] = 13;
430            sec.flags |= (1 << key);
431        }
432
433        /* No key data - just set the default TX key index */
434        if (key_provided) {
435            RTLLIB_DEBUG_WX(
436                "Setting key %d to default Tx key.\n", key);
437            ieee->crypt_info.tx_keyidx = key;
438            sec.active_key = key;
439            sec.flags |= SEC_ACTIVE_KEY;
440        }
441    }
442 done:
443    ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
444    ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
445              WLAN_AUTH_SHARED_KEY;
446    sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
447    sec.flags |= SEC_AUTH_MODE;
448    RTLLIB_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
449               "OPEN" : "SHARED KEY");
450
451    /* For now we just support WEP, so only set that security level...
452     * TODO: When WPA is added this is one place that needs to change */
453    sec.flags |= SEC_LEVEL;
454    sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
455
456    if (ieee->set_security)
457        ieee->set_security(dev, &sec);
458
459    /* Do not reset port if card is in Managed mode since resetting will
460     * generate new IEEE 802.11 authentication which may end up in looping
461     * with IEEE 802.1X. If your hardware requires a reset after WEP
462     * configuration (for example... Prism2), implement the reset_port in
463     * the callbacks structures used to initialize the 802.11 stack. */
464    if (ieee->reset_on_keychange &&
465        ieee->iw_mode != IW_MODE_INFRA &&
466        ieee->reset_port && ieee->reset_port(dev)) {
467        printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
468        return -EINVAL;
469    }
470    return 0;
471}
472EXPORT_SYMBOL(rtllib_wx_set_encode);
473
474int rtllib_wx_get_encode(struct rtllib_device *ieee,
475                struct iw_request_info *info,
476                union iwreq_data *wrqu, char *keybuf)
477{
478    struct iw_point *erq = &(wrqu->encoding);
479    int len, key;
480    struct lib80211_crypt_data *crypt;
481
482    RTLLIB_DEBUG_WX("GET_ENCODE\n");
483
484    if (ieee->iw_mode == IW_MODE_MONITOR)
485        return -1;
486
487    key = erq->flags & IW_ENCODE_INDEX;
488    if (key) {
489        if (key > NUM_WEP_KEYS)
490            return -EINVAL;
491        key--;
492    } else {
493        key = ieee->crypt_info.tx_keyidx;
494    }
495    crypt = ieee->crypt_info.crypt[key];
496
497    erq->flags = key + 1;
498
499    if (crypt == NULL || crypt->ops == NULL) {
500        erq->length = 0;
501        erq->flags |= IW_ENCODE_DISABLED;
502        return 0;
503    }
504    len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
505    erq->length = (len >= 0 ? len : 0);
506
507    erq->flags |= IW_ENCODE_ENABLED;
508
509    if (ieee->open_wep)
510        erq->flags |= IW_ENCODE_OPEN;
511    else
512        erq->flags |= IW_ENCODE_RESTRICTED;
513
514    return 0;
515}
516EXPORT_SYMBOL(rtllib_wx_get_encode);
517
518int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
519                   struct iw_request_info *info,
520                   union iwreq_data *wrqu, char *extra)
521{
522    int ret = 0;
523    struct net_device *dev = ieee->dev;
524    struct iw_point *encoding = &wrqu->encoding;
525    struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
526    int i, idx;
527    int group_key = 0;
528    const char *alg, *module;
529    struct lib80211_crypto_ops *ops;
530    struct lib80211_crypt_data **crypt;
531
532    struct rtllib_security sec = {
533        .flags = 0,
534    };
535    idx = encoding->flags & IW_ENCODE_INDEX;
536    if (idx) {
537        if (idx < 1 || idx > NUM_WEP_KEYS)
538            return -EINVAL;
539        idx--;
540    } else{
541            idx = ieee->crypt_info.tx_keyidx;
542    }
543    if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
544        crypt = &ieee->crypt_info.crypt[idx];
545        group_key = 1;
546    } else {
547        /* some Cisco APs use idx>0 for unicast in dynamic WEP */
548        if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
549            return -EINVAL;
550        if (ieee->iw_mode == IW_MODE_INFRA)
551            crypt = &ieee->crypt_info.crypt[idx];
552        else
553            return -EINVAL;
554    }
555
556    sec.flags |= SEC_ENABLED;
557    if ((encoding->flags & IW_ENCODE_DISABLED) ||
558        ext->alg == IW_ENCODE_ALG_NONE) {
559        if (*crypt)
560            lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
561
562        for (i = 0; i < NUM_WEP_KEYS; i++) {
563            if (ieee->crypt_info.crypt[i] != NULL)
564                break;
565        }
566        if (i == NUM_WEP_KEYS) {
567            sec.enabled = 0;
568            sec.level = SEC_LEVEL_0;
569            sec.flags |= SEC_LEVEL;
570        }
571        goto done;
572    }
573
574    sec.enabled = 1;
575    switch (ext->alg) {
576    case IW_ENCODE_ALG_WEP:
577        alg = "R-WEP";
578        module = "rtllib_crypt_wep";
579        break;
580    case IW_ENCODE_ALG_TKIP:
581        alg = "R-TKIP";
582        module = "rtllib_crypt_tkip";
583        break;
584    case IW_ENCODE_ALG_CCMP:
585        alg = "R-CCMP";
586        module = "rtllib_crypt_ccmp";
587        break;
588    default:
589        RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
590                   dev->name, ext->alg);
591        ret = -EINVAL;
592        goto done;
593    }
594    printk(KERN_INFO "alg name:%s\n", alg);
595
596    ops = lib80211_get_crypto_ops(alg);
597    if (ops == NULL) {
598        char tempbuf[100];
599
600        memset(tempbuf, 0x00, 100);
601        sprintf(tempbuf, "%s", module);
602        request_module("%s", tempbuf);
603        ops = lib80211_get_crypto_ops(alg);
604    }
605    if (ops == NULL) {
606        RTLLIB_DEBUG_WX("%s: unknown crypto alg %d\n",
607                   dev->name, ext->alg);
608        printk(KERN_INFO "========>unknown crypto alg %d\n", ext->alg);
609        ret = -EINVAL;
610        goto done;
611    }
612
613    if (*crypt == NULL || (*crypt)->ops != ops) {
614        struct lib80211_crypt_data *new_crypt;
615
616        lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
617
618        new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
619        if (new_crypt == NULL) {
620            ret = -ENOMEM;
621            goto done;
622        }
623        new_crypt->ops = ops;
624        if (new_crypt->ops)
625            new_crypt->priv = new_crypt->ops->init(idx);
626
627        if (new_crypt->priv == NULL) {
628            kfree(new_crypt);
629            ret = -EINVAL;
630            goto done;
631        }
632        *crypt = new_crypt;
633
634    }
635
636    if (ext->key_len > 0 && (*crypt)->ops->set_key &&
637        (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
638                   (*crypt)->priv) < 0) {
639        RTLLIB_DEBUG_WX("%s: key setting failed\n", dev->name);
640        printk(KERN_INFO "key setting failed\n");
641        ret = -EINVAL;
642        goto done;
643    }
644    if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
645        ieee->crypt_info.tx_keyidx = idx;
646        sec.active_key = idx;
647        sec.flags |= SEC_ACTIVE_KEY;
648    }
649    if (ext->alg != IW_ENCODE_ALG_NONE) {
650        sec.key_sizes[idx] = ext->key_len;
651        sec.flags |= (1 << idx);
652        if (ext->alg == IW_ENCODE_ALG_WEP) {
653            sec.flags |= SEC_LEVEL;
654            sec.level = SEC_LEVEL_1;
655        } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
656            sec.flags |= SEC_LEVEL;
657            sec.level = SEC_LEVEL_2;
658        } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
659            sec.flags |= SEC_LEVEL;
660            sec.level = SEC_LEVEL_3;
661        }
662        /* Don't set sec level for group keys. */
663        if (group_key)
664            sec.flags &= ~SEC_LEVEL;
665    }
666done:
667    if (ieee->set_security)
668        ieee->set_security(ieee->dev, &sec);
669
670     if (ieee->reset_on_keychange &&
671        ieee->iw_mode != IW_MODE_INFRA &&
672        ieee->reset_port && ieee->reset_port(dev)) {
673        RTLLIB_DEBUG_WX("%s: reset_port failed\n", dev->name);
674        return -EINVAL;
675    }
676    return ret;
677}
678EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
679
680int rtllib_wx_get_encode_ext(struct rtllib_device *ieee,
681                   struct iw_request_info *info,
682                   union iwreq_data *wrqu, char *extra)
683{
684    struct iw_point *encoding = &wrqu->encoding;
685    struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
686    struct lib80211_crypt_data *crypt;
687    int idx, max_key_len;
688
689    max_key_len = encoding->length - sizeof(*ext);
690    if (max_key_len < 0)
691        return -EINVAL;
692
693    idx = encoding->flags & IW_ENCODE_INDEX;
694    if (idx) {
695        if (idx < 1 || idx > NUM_WEP_KEYS)
696            return -EINVAL;
697        idx--;
698    } else {
699        idx = ieee->crypt_info.tx_keyidx;
700    }
701    if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
702        (ext->alg != IW_ENCODE_ALG_WEP))
703        if (idx != 0 || (ieee->iw_mode != IW_MODE_INFRA))
704            return -EINVAL;
705
706    crypt = ieee->crypt_info.crypt[idx];
707
708    encoding->flags = idx + 1;
709    memset(ext, 0, sizeof(*ext));
710
711    if (crypt == NULL || crypt->ops == NULL) {
712        ext->alg = IW_ENCODE_ALG_NONE;
713        ext->key_len = 0;
714        encoding->flags |= IW_ENCODE_DISABLED;
715    } else {
716        if (strcmp(crypt->ops->name, "R-WEP") == 0)
717            ext->alg = IW_ENCODE_ALG_WEP;
718        else if (strcmp(crypt->ops->name, "R-TKIP"))
719            ext->alg = IW_ENCODE_ALG_TKIP;
720        else if (strcmp(crypt->ops->name, "R-CCMP"))
721            ext->alg = IW_ENCODE_ALG_CCMP;
722        else
723            return -EINVAL;
724        ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN,
725                           NULL, crypt->priv);
726        encoding->flags |= IW_ENCODE_ENABLED;
727        if (ext->key_len &&
728            (ext->alg == IW_ENCODE_ALG_TKIP ||
729             ext->alg == IW_ENCODE_ALG_CCMP))
730            ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
731
732    }
733
734    return 0;
735}
736
737int rtllib_wx_set_mlme(struct rtllib_device *ieee,
738                   struct iw_request_info *info,
739                   union iwreq_data *wrqu, char *extra)
740{
741    u8 i = 0;
742    bool deauth = false;
743    struct iw_mlme *mlme = (struct iw_mlme *) extra;
744
745    if (ieee->state != RTLLIB_LINKED)
746        return -ENOLINK;
747
748    down(&ieee->wx_sem);
749
750    switch (mlme->cmd) {
751    case IW_MLME_DEAUTH:
752        deauth = true;
753        /* leave break out intentionly */
754
755    case IW_MLME_DISASSOC:
756        if (deauth == true)
757            printk(KERN_INFO "disauth packet !\n");
758        else
759            printk(KERN_INFO "dis associate packet!\n");
760
761        ieee->cannot_notify = true;
762
763        SendDisassociation(ieee, deauth, mlme->reason_code);
764        rtllib_disassociate(ieee);
765
766        ieee->wap_set = 0;
767        for (i = 0; i < 6; i++)
768            ieee->current_network.bssid[i] = 0x55;
769
770        ieee->ssid_set = 0;
771        ieee->current_network.ssid[0] = '\0';
772        ieee->current_network.ssid_len = 0;
773        break;
774    default:
775        up(&ieee->wx_sem);
776        return -EOPNOTSUPP;
777    }
778
779    up(&ieee->wx_sem);
780
781    return 0;
782}
783EXPORT_SYMBOL(rtllib_wx_set_mlme);
784
785int rtllib_wx_set_auth(struct rtllib_device *ieee,
786                   struct iw_request_info *info,
787                   struct iw_param *data, char *extra)
788{
789    switch (data->flags & IW_AUTH_INDEX) {
790    case IW_AUTH_WPA_VERSION:
791        break;
792    case IW_AUTH_CIPHER_PAIRWISE:
793    case IW_AUTH_CIPHER_GROUP:
794    case IW_AUTH_KEY_MGMT:
795        /*
796         * Host AP driver does not use these parameters and allows
797         * wpa_supplicant to control them internally.
798         */
799        break;
800    case IW_AUTH_TKIP_COUNTERMEASURES:
801        ieee->tkip_countermeasures = data->value;
802        break;
803    case IW_AUTH_DROP_UNENCRYPTED:
804        ieee->drop_unencrypted = data->value;
805        break;
806
807    case IW_AUTH_80211_AUTH_ALG:
808        if (data->value & IW_AUTH_ALG_SHARED_KEY) {
809            ieee->open_wep = 0;
810            ieee->auth_mode = 1;
811        } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
812            ieee->open_wep = 1;
813            ieee->auth_mode = 0;
814        } else if (data->value & IW_AUTH_ALG_LEAP) {
815            ieee->open_wep = 1;
816            ieee->auth_mode = 2;
817        } else
818            return -EINVAL;
819        break;
820
821    case IW_AUTH_WPA_ENABLED:
822        ieee->wpa_enabled = (data->value) ? 1 : 0;
823        break;
824
825    case IW_AUTH_RX_UNENCRYPTED_EAPOL:
826        ieee->ieee802_1x = data->value;
827        break;
828    case IW_AUTH_PRIVACY_INVOKED:
829        ieee->privacy_invoked = data->value;
830        break;
831    default:
832        return -EOPNOTSUPP;
833    }
834    return 0;
835}
836EXPORT_SYMBOL(rtllib_wx_set_auth);
837
838int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
839{
840    u8 *buf;
841    u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
842
843    if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
844        return -EINVAL;
845
846    if (len) {
847        eid = ie[0];
848        if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
849             wps_oui, 4))) {
850
851            ieee->wps_ie_len = (len < MAX_WZC_IE_LEN) ? (len) :
852                       (MAX_WZC_IE_LEN);
853            buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
854            if (buf == NULL)
855                return -ENOMEM;
856            ieee->wps_ie = buf;
857            return 0;
858        }
859    }
860    ieee->wps_ie_len = 0;
861    kfree(ieee->wps_ie);
862    ieee->wps_ie = NULL;
863    if (len) {
864        if (len != ie[1]+2)
865            return -EINVAL;
866        buf = kmemdup(ie, len, GFP_KERNEL);
867        if (buf == NULL)
868            return -ENOMEM;
869        kfree(ieee->wpa_ie);
870        ieee->wpa_ie = buf;
871        ieee->wpa_ie_len = len;
872    } else {
873        kfree(ieee->wpa_ie);
874        ieee->wpa_ie = NULL;
875        ieee->wpa_ie_len = 0;
876    }
877    return 0;
878}
879EXPORT_SYMBOL(rtllib_wx_set_gen_ie);
880

Archive Download this file



interactive