~ubuntu-branches/ubuntu/saucy/bcmwl/saucy

« back to all changes in this revision

Viewing changes to src/src/wl/sys/wl_iw.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner
  • Date: 2009-05-11 16:04:29 UTC
  • Revision ID: james.westby@ubuntu.com-20090511160429-lciigiqnpp0fpu2k
Tags: 5.10.91.9-2
Add src/lib/LICENSE.txt to copyright notice. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Linux Wireless Extensions support
 
3
 *
 
4
 * Copyright 2008, Broadcom Corporation
 
5
 * All Rights Reserved.
 
6
 * 
 
7
 *      Unless you and Broadcom execute a separate written software license
 
8
 * agreement governing use of this software, this software is licensed to you
 
9
 * under the terms of the GNU General Public License version 2, available at
 
10
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"), with the
 
11
 * following added to such license:
 
12
 *      As a special exception, the copyright holders of this software give you
 
13
 * permission to link this software with independent modules, regardless of the
 
14
 * license terms of these independent modules, and to copy and distribute the
 
15
 * resulting executable under terms of your choice, provided that you also meet,
 
16
 * for each linked independent module, the terms and conditions of the license
 
17
 * of that module. An independent module is a module which is not derived from
 
18
 * this software.
 
19
 *
 
20
 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
 
21
 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
 
22
 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 
23
 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
 
24
 *
 
25
 * $Id: wl_iw.c,v 1.63.2.25.4.4 2009/04/20 19:22:00 Exp $
 
26
 */
 
27
 
 
28
#define LINUX_PORT
 
29
 
 
30
#include <typedefs.h>
 
31
#include <linuxver.h>
 
32
#include <osl.h>
 
33
 
 
34
#include <bcmutils.h>
 
35
#include <bcmendian.h>
 
36
#include <proto/ethernet.h>
 
37
 
 
38
#include <linux/if_arp.h>
 
39
#include <asm/uaccess.h>
 
40
 
 
41
typedef void wlc_info_t;
 
42
typedef void wl_info_t;
 
43
typedef const struct si_pub     si_t;
 
44
#include <wlioctl.h>
 
45
 
 
46
#include <wl_dbg.h>
 
47
#include <wl_iw.h>
 
48
 
 
49
extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
 
50
        uint32 reason, char* stringBuf, uint buflen);
 
51
 
 
52
#define MAX_IOCTL_LEN 600
 
53
 
 
54
#define htod32(i) i
 
55
#define htod16(i) i
 
56
#define dtoh32(i) i
 
57
#define dtoh16(i) i
 
58
#define htodchanspec(i) i
 
59
#define dtohchanspec(i) i
 
60
 
 
61
#ifdef CONFIG_WIRELESS_EXT
 
62
extern struct iw_statistics *wl_get_wireless_stats(struct net_device *dev);
 
63
#endif 
 
64
 
 
65
#if WIRELESS_EXT < 19
 
66
#define IW_IOCTL_IDX(cmd)       ((cmd) - SIOCIWFIRST)
 
67
#define IW_EVENT_IDX(cmd)       ((cmd) - IWEVFIRST)
 
68
#endif 
 
69
 
 
70
static void swap_key_from_BE(
 
71
                wl_wsec_key_t *key
 
72
)
 
73
{
 
74
        key->index = htod32(key->index);
 
75
        key->len = htod32(key->len);
 
76
        key->algo = htod32(key->algo);
 
77
        key->flags = htod32(key->flags);
 
78
        key->rxiv.hi = htod32(key->rxiv.hi);
 
79
        key->rxiv.lo = htod16(key->rxiv.lo);
 
80
        key->iv_initialized = htod32(key->iv_initialized);
 
81
}
 
82
 
 
83
static void swap_key_to_BE(
 
84
                wl_wsec_key_t *key
 
85
)
 
86
{
 
87
        key->index = dtoh32(key->index);
 
88
        key->len = dtoh32(key->len);
 
89
        key->algo = dtoh32(key->algo);
 
90
        key->flags = dtoh32(key->flags);
 
91
        key->rxiv.hi = dtoh32(key->rxiv.hi);
 
92
        key->rxiv.lo = dtoh16(key->rxiv.lo);
 
93
        key->iv_initialized = dtoh32(key->iv_initialized);
 
94
}
 
95
 
 
96
static int
 
97
dev_wlc_ioctl(
 
98
        struct net_device *dev,
 
99
        int cmd,
 
100
        void *arg,
 
101
        int len
 
102
)
 
103
{
 
104
        struct ifreq ifr;
 
105
        wl_ioctl_t ioc;
 
106
        mm_segment_t fs;
 
107
        int ret;
 
108
 
 
109
        memset(&ioc, 0, sizeof(ioc));
 
110
        ioc.cmd = cmd;
 
111
        ioc.buf = arg;
 
112
        ioc.len = len;
 
113
 
 
114
        strcpy(ifr.ifr_name, dev->name);
 
115
        ifr.ifr_data = (caddr_t) &ioc;
 
116
 
 
117
        dev_open(dev);
 
118
 
 
119
        fs = get_fs();
 
120
        set_fs(get_ds());
 
121
        ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
 
122
        set_fs(fs);
 
123
 
 
124
        return ret;
 
125
}
 
126
 
 
127
static int
 
128
dev_wlc_intvar_set(
 
129
        struct net_device *dev,
 
130
        char *name,
 
131
        int val)
 
132
{
 
133
        char buf[WLC_IOCTL_SMLEN];
 
134
        uint len;
 
135
 
 
136
        val = htod32(val);
 
137
        len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
 
138
        ASSERT(len);
 
139
 
 
140
        return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
 
141
}
 
142
 
 
143
#if WIRELESS_EXT > 17
 
144
static int
 
145
dev_wlc_bufvar_set(
 
146
        struct net_device *dev,
 
147
        char *name,
 
148
        char *buf, int len)
 
149
{
 
150
        char ioctlbuf[WLC_IOCTL_SMLEN];
 
151
        uint buflen;
 
152
 
 
153
        buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
 
154
        ASSERT(buflen);
 
155
 
 
156
        return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
 
157
}
 
158
#endif
 
159
 
 
160
static int
 
161
dev_wlc_bufvar_get(
 
162
        struct net_device *dev,
 
163
        char *name,
 
164
        char *buf, int buflen)
 
165
{
 
166
        char ioctlbuf[MAX_IOCTL_LEN];
 
167
        int error;
 
168
 
 
169
        uint len;
 
170
 
 
171
        len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
 
172
        ASSERT(len);
 
173
        error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_IOCTL_LEN);
 
174
        if (!error)
 
175
                bcopy(ioctlbuf, buf, buflen);
 
176
 
 
177
        return (error);
 
178
}
 
179
 
 
180
static int
 
181
dev_wlc_intvar_get(
 
182
        struct net_device *dev,
 
183
        char *name,
 
184
        int *retval)
 
185
{
 
186
        union {
 
187
                char buf[WLC_IOCTL_SMLEN];
 
188
                int val;
 
189
        } var;
 
190
        int error;
 
191
 
 
192
        uint len;
 
193
        uint data_null;
 
194
 
 
195
        len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
 
196
        ASSERT(len);
 
197
        error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
 
198
 
 
199
        *retval = dtoh32(var.val);
 
200
 
 
201
        return (error);
 
202
}
 
203
 
 
204
#if WIRELESS_EXT < 13
 
205
struct iw_request_info
 
206
{
 
207
        __u16           cmd;            
 
208
        __u16           flags;          
 
209
};
 
210
 
 
211
typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
 
212
        void *wrqu, char *extra);
 
213
#endif 
 
214
 
 
215
#if WIRELESS_EXT > 12
 
216
static int
 
217
wl_iw_set_leddc(
 
218
        struct net_device *dev,
 
219
        struct iw_request_info *info,
 
220
        union iwreq_data *wrqu,
 
221
        char *extra
 
222
)
 
223
{
 
224
        int dc = *(int *)extra;
 
225
        int error;
 
226
 
 
227
        error = dev_wlc_intvar_set(dev, "leddc", dc);
 
228
        return error;
 
229
}
 
230
 
 
231
static int
 
232
wl_iw_set_vlanmode(
 
233
        struct net_device *dev,
 
234
        struct iw_request_info *info,
 
235
        union iwreq_data *wrqu,
 
236
        char *extra
 
237
)
 
238
{
 
239
        int mode = *(int *)extra;
 
240
        int error;
 
241
 
 
242
        mode = htod32(mode);
 
243
        error = dev_wlc_intvar_set(dev, "vlan_mode", mode);
 
244
        return error;
 
245
}
 
246
 
 
247
static int
 
248
wl_iw_set_pm(
 
249
        struct net_device *dev,
 
250
        struct iw_request_info *info,
 
251
        union iwreq_data *wrqu,
 
252
        char *extra
 
253
)
 
254
{
 
255
        int pm = *(int *)extra;
 
256
        int error;
 
257
 
 
258
        pm = htod32(pm);
 
259
        error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
 
260
        return error;
 
261
}
 
262
#endif 
 
263
 
 
264
static int
 
265
wl_iw_config_commit(
 
266
        struct net_device *dev,
 
267
        struct iw_request_info *info,
 
268
        void *zwrq,
 
269
        char *extra
 
270
)
 
271
{
 
272
        wlc_ssid_t ssid;
 
273
        int error;
 
274
        struct sockaddr bssid;
 
275
 
 
276
        WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
 
277
 
 
278
        if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
 
279
                return error;
 
280
 
 
281
        ssid.SSID_len = dtoh32(ssid.SSID_len);
 
282
 
 
283
        if (!ssid.SSID_len)
 
284
                return 0;
 
285
 
 
286
        bzero(&bssid, sizeof(struct sockaddr));
 
287
        if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
 
288
                WL_ERROR(("Invalid ioctl data.\n"));
 
289
                return error;
 
290
        }
 
291
 
 
292
        return 0;
 
293
}
 
294
 
 
295
static int
 
296
wl_iw_get_name(
 
297
        struct net_device *dev,
 
298
        struct iw_request_info *info,
 
299
        union iwreq_data *cwrq,
 
300
        char *extra
 
301
)
 
302
{
 
303
        int phytype, err;
 
304
        uint band[3];
 
305
        char cap[5];
 
306
 
 
307
        WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
 
308
 
 
309
        cap[0] = 0;
 
310
        if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0)
 
311
                goto done;
 
312
        if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0)
 
313
                goto done;
 
314
 
 
315
        band[0] = dtoh32(band[0]);
 
316
        switch (phytype) {
 
317
                case WLC_PHY_TYPE_A:
 
318
                        strcpy(cap, "a");
 
319
                        break;
 
320
                case WLC_PHY_TYPE_B:
 
321
                        strcpy(cap, "b");
 
322
                        break;
 
323
                case WLC_PHY_TYPE_LP:
 
324
                case WLC_PHY_TYPE_G:
 
325
                        if (band[0] >= 2)
 
326
                                strcpy(cap, "abg");
 
327
                        else
 
328
                                strcpy(cap, "bg");
 
329
                        break;
 
330
                case WLC_PHY_TYPE_N:
 
331
                        if (band[0] >= 2)
 
332
                                strcpy(cap, "abgn");
 
333
                        else
 
334
                                strcpy(cap, "bgn");
 
335
                        break;
 
336
        }
 
337
done:
 
338
        snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap);
 
339
        return 0;
 
340
}
 
341
 
 
342
static int
 
343
wl_iw_set_freq(
 
344
        struct net_device *dev,
 
345
        struct iw_request_info *info,
 
346
        struct iw_freq *fwrq,
 
347
        char *extra
 
348
)
 
349
{
 
350
        int error, chan;
 
351
        uint sf = 0;
 
352
 
 
353
        WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name));
 
354
 
 
355
        if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
 
356
                chan = fwrq->m;
 
357
        }
 
358
 
 
359
        else {
 
360
 
 
361
                if (fwrq->e >= 6) {
 
362
                        fwrq->e -= 6;
 
363
                        while (fwrq->e--)
 
364
                                fwrq->m *= 10;
 
365
                } else if (fwrq->e < 6) {
 
366
                        while (fwrq->e++ < 6)
 
367
                                fwrq->m /= 10;
 
368
                }
 
369
 
 
370
        if (fwrq->m > 4000 && fwrq->m < 5000)
 
371
                sf = WF_CHAN_FACTOR_4_G; 
 
372
 
 
373
                chan = wf_mhz2channel(fwrq->m, sf);
 
374
        }
 
375
        chan = htod32(chan);
 
376
        if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
 
377
                return error;
 
378
 
 
379
        return -EINPROGRESS;
 
380
}
 
381
 
 
382
static int
 
383
wl_iw_get_freq(
 
384
        struct net_device *dev,
 
385
        struct iw_request_info *info,
 
386
        struct iw_freq *fwrq,
 
387
        char *extra
 
388
)
 
389
{
 
390
        channel_info_t ci;
 
391
        int error;
 
392
 
 
393
        WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
 
394
 
 
395
        if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
 
396
                return error;
 
397
 
 
398
        fwrq->m = dtoh32(ci.hw_channel);
 
399
        fwrq->e = dtoh32(0);
 
400
        return 0;
 
401
}
 
402
 
 
403
static int
 
404
wl_iw_set_mode(
 
405
        struct net_device *dev,
 
406
        struct iw_request_info *info,
 
407
        __u32 *uwrq,
 
408
        char *extra
 
409
)
 
410
{
 
411
        int infra = 0, ap = 0, error = 0;
 
412
 
 
413
        WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
 
414
 
 
415
        switch (*uwrq) {
 
416
        case IW_MODE_MASTER:
 
417
                infra = ap = 1;
 
418
                break;
 
419
        case IW_MODE_ADHOC:
 
420
        case IW_MODE_AUTO:
 
421
                break;
 
422
        case IW_MODE_INFRA:
 
423
                infra = 1;
 
424
                break;
 
425
        default:
 
426
                return -EINVAL;
 
427
        }
 
428
        infra = htod32(infra);
 
429
        ap = htod32(ap);
 
430
 
 
431
        if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
 
432
            (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
 
433
                return error;
 
434
 
 
435
        return -EINPROGRESS;
 
436
}
 
437
 
 
438
static int
 
439
wl_iw_get_mode(
 
440
        struct net_device *dev,
 
441
        struct iw_request_info *info,
 
442
        __u32 *uwrq,
 
443
        char *extra
 
444
)
 
445
{
 
446
        int error, infra = 0, ap = 0;
 
447
 
 
448
        WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
 
449
 
 
450
        if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
 
451
            (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
 
452
                return error;
 
453
 
 
454
        infra = dtoh32(infra);
 
455
        ap = dtoh32(ap);
 
456
        *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
 
457
 
 
458
        return 0;
 
459
}
 
460
 
 
461
static int
 
462
wl_iw_get_range(
 
463
        struct net_device *dev,
 
464
        struct iw_request_info *info,
 
465
        struct iw_point *dwrq,
 
466
        char *extra
 
467
)
 
468
{
 
469
        struct iw_range *range = (struct iw_range *) extra;
 
470
        int channels[MAXCHANNEL+1];
 
471
        wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
 
472
        wl_rateset_t rateset;
 
473
        int error, i;
 
474
        uint sf, ch;
 
475
 
 
476
        WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
 
477
 
 
478
        if (!extra)
 
479
                return -EINVAL;
 
480
 
 
481
        dwrq->length = sizeof(struct iw_range);
 
482
        memset(range, 0, sizeof(range));
 
483
 
 
484
        range->min_nwid = range->max_nwid = 0;
 
485
 
 
486
        list->count = htod32(MAXCHANNEL);
 
487
        if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels))))
 
488
                return error;
 
489
        for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
 
490
                range->freq[i].i = dtoh32(list->element[i]);
 
491
 
 
492
                ch = dtoh32(list->element[i]);
 
493
                if (ch <= CH_MAX_2G_CHANNEL)
 
494
                        sf = WF_CHAN_FACTOR_2_4_G;
 
495
                else
 
496
                        sf = WF_CHAN_FACTOR_5_G;
 
497
 
 
498
                range->freq[i].m = wf_channel2mhz(ch, sf);
 
499
                range->freq[i].e = 6;
 
500
        }
 
501
        range->num_frequency = range->num_channels = i;
 
502
 
 
503
        range->max_qual.qual = 5;
 
504
 
 
505
        range->max_qual.level = 0x100 - 200;    
 
506
 
 
507
        range->max_qual.noise = 0x100 - 200;    
 
508
 
 
509
        range->sensitivity = 65535;
 
510
 
 
511
#if WIRELESS_EXT > 11
 
512
 
 
513
        range->avg_qual.qual = 3;
 
514
 
 
515
        range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
 
516
 
 
517
        range->avg_qual.noise = 0x100 - 75;     
 
518
#endif 
 
519
 
 
520
        if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
 
521
                return error;
 
522
        rateset.count = dtoh32(rateset.count);
 
523
        range->num_bitrates = rateset.count;
 
524
        for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
 
525
                range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; 
 
526
 
 
527
        if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i))))
 
528
                return error;
 
529
        i = dtoh32(i);
 
530
        if (i == WLC_PHY_TYPE_A)
 
531
                range->throughput = 24000000;   
 
532
        else
 
533
                range->throughput = 1500000;    
 
534
 
 
535
        range->min_rts = 0;
 
536
        range->max_rts = 2347;
 
537
        range->min_frag = 256;
 
538
        range->max_frag = 2346;
 
539
 
 
540
        range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
 
541
        range->num_encoding_sizes = 4;
 
542
        range->encoding_size[0] = WEP1_KEY_SIZE;
 
543
        range->encoding_size[1] = WEP128_KEY_SIZE;
 
544
#if WIRELESS_EXT > 17
 
545
        range->encoding_size[2] = TKIP_KEY_SIZE;
 
546
#else
 
547
        range->encoding_size[2] = 0;
 
548
#endif
 
549
        range->encoding_size[3] = AES_KEY_SIZE;
 
550
 
 
551
        range->min_pmp = 0;
 
552
        range->max_pmp = 0;
 
553
        range->min_pmt = 0;
 
554
        range->max_pmt = 0;
 
555
        range->pmp_flags = 0;
 
556
        range->pm_capa = 0;
 
557
 
 
558
        range->num_txpower = 2;
 
559
        range->txpower[0] = 1;
 
560
        range->txpower[1] = 255;
 
561
        range->txpower_capa = IW_TXPOW_MWATT;
 
562
 
 
563
#if WIRELESS_EXT > 10
 
564
        range->we_version_compiled = WIRELESS_EXT;
 
565
        range->we_version_source = 19;
 
566
 
 
567
        range->retry_capa = IW_RETRY_LIMIT;
 
568
        range->retry_flags = IW_RETRY_LIMIT;
 
569
        range->r_time_flags = 0;
 
570
 
 
571
        range->min_retry = 1;
 
572
        range->max_retry = 255;
 
573
 
 
574
        range->min_r_time = 0;
 
575
        range->max_r_time = 0;
 
576
#endif 
 
577
 
 
578
#if WIRELESS_EXT > 17
 
579
        range->enc_capa = IW_ENC_CAPA_WPA;
 
580
        range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
 
581
        range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
 
582
        range->enc_capa |= IW_ENC_CAPA_WPA2;
 
583
#endif 
 
584
 
 
585
        return 0;
 
586
}
 
587
 
 
588
static int
 
589
rssi_to_qual(int rssi)
 
590
{
 
591
        if (rssi <= WL_IW_RSSI_NO_SIGNAL)
 
592
                return 0;
 
593
        else if (rssi <= WL_IW_RSSI_VERY_LOW)
 
594
                return 1;
 
595
        else if (rssi <= WL_IW_RSSI_LOW)
 
596
                return 2;
 
597
        else if (rssi <= WL_IW_RSSI_GOOD)
 
598
                return 3;
 
599
        else if (rssi <= WL_IW_RSSI_VERY_GOOD)
 
600
                return 4;
 
601
        else
 
602
                return 5;
 
603
}
 
604
 
 
605
static int
 
606
wl_iw_set_spy(
 
607
        struct net_device *dev,
 
608
        struct iw_request_info *info,
 
609
        struct iw_point *dwrq,
 
610
        char *extra
 
611
)
 
612
{
 
613
        wl_iw_t *iw = dev->priv;
 
614
        struct sockaddr *addr = (struct sockaddr *) extra;
 
615
        int i;
 
616
 
 
617
        WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
 
618
 
 
619
        if (!extra)
 
620
                return -EINVAL;
 
621
 
 
622
        iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
 
623
        for (i = 0; i < iw->spy_num; i++)
 
624
                memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
 
625
        memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
 
626
 
 
627
        return 0;
 
628
}
 
629
 
 
630
static int
 
631
wl_iw_get_spy(
 
632
        struct net_device *dev,
 
633
        struct iw_request_info *info,
 
634
        struct iw_point *dwrq,
 
635
        char *extra
 
636
)
 
637
{
 
638
        wl_iw_t *iw = dev->priv;
 
639
        struct sockaddr *addr = (struct sockaddr *) extra;
 
640
        struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
 
641
        int i;
 
642
 
 
643
        WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
 
644
 
 
645
        if (!extra)
 
646
                return -EINVAL;
 
647
 
 
648
        dwrq->length = iw->spy_num;
 
649
        for (i = 0; i < iw->spy_num; i++) {
 
650
                memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
 
651
                addr[i].sa_family = AF_UNIX;
 
652
                memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
 
653
                iw->spy_qual[i].updated = 0;
 
654
        }
 
655
 
 
656
        return 0;
 
657
}
 
658
 
 
659
static int
 
660
wl_iw_set_wap(
 
661
        struct net_device *dev,
 
662
        struct iw_request_info *info,
 
663
        struct sockaddr *awrq,
 
664
        char *extra
 
665
)
 
666
{
 
667
        int error = -EINVAL;
 
668
#ifdef BCMDBG
 
669
 
 
670
#endif
 
671
 
 
672
        WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
 
673
 
 
674
        if (awrq->sa_family != ARPHRD_ETHER) {
 
675
                WL_ERROR(("Invalid Header...sa_family\n"));
 
676
                return -EINVAL;
 
677
        }
 
678
 
 
679
        if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
 
680
                scb_val_t scbval;
 
681
 
 
682
                bzero(&scbval, sizeof(scb_val_t));
 
683
                dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
 
684
                return 0;
 
685
        }
 
686
 
 
687
        if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) {
 
688
                WL_ERROR(("Invalid ioctl data.\n"));
 
689
                return error;
 
690
        }
 
691
 
 
692
        return 0;
 
693
}
 
694
 
 
695
static int
 
696
wl_iw_get_wap(
 
697
        struct net_device *dev,
 
698
        struct iw_request_info *info,
 
699
        struct sockaddr *awrq,
 
700
        char *extra
 
701
)
 
702
{
 
703
        WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
 
704
 
 
705
        awrq->sa_family = ARPHRD_ETHER;
 
706
        memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
 
707
 
 
708
        (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
 
709
 
 
710
        return 0;
 
711
}
 
712
 
 
713
#if WIRELESS_EXT > 17
 
714
static int
 
715
wl_iw_mlme(
 
716
        struct net_device *dev,
 
717
        struct iw_request_info *info,
 
718
        struct sockaddr *awrq,
 
719
        char *extra
 
720
)
 
721
{
 
722
        struct iw_mlme *mlme;
 
723
        scb_val_t scbval;
 
724
        int error  = -EINVAL;
 
725
 
 
726
        WL_TRACE(("%s: SIOCSIWMLME\n", dev->name));
 
727
 
 
728
        mlme = (struct iw_mlme *)extra;
 
729
        if (mlme == NULL) {
 
730
                WL_ERROR(("Invalid ioctl data.\n"));
 
731
                return error;
 
732
        }
 
733
 
 
734
        scbval.val = mlme->reason_code;
 
735
        bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
 
736
 
 
737
        if (mlme->cmd == IW_MLME_DISASSOC) {
 
738
                scbval.val = htod32(scbval.val);
 
739
                error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
 
740
        }
 
741
        else if (mlme->cmd == IW_MLME_DEAUTH) {
 
742
                scbval.val = htod32(scbval.val);
 
743
                error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
 
744
                        sizeof(scb_val_t));
 
745
        }
 
746
        else {
 
747
                WL_ERROR(("Invalid ioctl data.\n"));
 
748
                return error;
 
749
        }
 
750
 
 
751
        return error;
 
752
}
 
753
#endif 
 
754
 
 
755
static int
 
756
wl_iw_get_aplist(
 
757
        struct net_device *dev,
 
758
        struct iw_request_info *info,
 
759
        struct iw_point *dwrq,
 
760
        char *extra
 
761
)
 
762
{
 
763
        wl_scan_results_t *list;
 
764
        struct sockaddr *addr = (struct sockaddr *) extra;
 
765
        struct iw_quality qual[IW_MAX_AP];
 
766
        wl_bss_info_t *bi = NULL;
 
767
        int error, i;
 
768
        uint buflen = dwrq->length;
 
769
 
 
770
        WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
 
771
 
 
772
        if (!extra)
 
773
                return -EINVAL;
 
774
 
 
775
        list = kmalloc(buflen, GFP_KERNEL);
 
776
        if (!list)
 
777
                return -ENOMEM;
 
778
        memset(list, 0, buflen);
 
779
        list->buflen = htod32(buflen);
 
780
        if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
 
781
                WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
 
782
                kfree(list);
 
783
                return error;
 
784
        }
 
785
        list->buflen = dtoh32(list->buflen);
 
786
        list->version = dtoh32(list->version);
 
787
        list->count = dtoh32(list->count);
 
788
        ASSERT(list->version == WL_BSS_INFO_VERSION);
 
789
 
 
790
        for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
 
791
                bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
 
792
                ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
 
793
                        buflen));
 
794
 
 
795
                if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
 
796
                        continue;
 
797
 
 
798
                memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
 
799
                addr[dwrq->length].sa_family = ARPHRD_ETHER;
 
800
                qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
 
801
                qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
 
802
                qual[dwrq->length].noise = 0x100 + bi->phy_noise;
 
803
 
 
804
#if WIRELESS_EXT > 18
 
805
                qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 
806
#else
 
807
                qual[dwrq->length].updated = 7;
 
808
#endif 
 
809
 
 
810
                dwrq->length++;
 
811
        }
 
812
 
 
813
        kfree(list);
 
814
 
 
815
        if (dwrq->length) {
 
816
                memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
 
817
 
 
818
                dwrq->flags = 1;
 
819
        }
 
820
 
 
821
        return 0;
 
822
}
 
823
 
 
824
#if WIRELESS_EXT > 13
 
825
static int
 
826
wl_iw_set_scan(
 
827
        struct net_device *dev,
 
828
        struct iw_request_info *info,
 
829
        union iwreq_data *wrqu,
 
830
        char *extra
 
831
)
 
832
{
 
833
        wlc_ssid_t ssid;
 
834
 
 
835
        WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name));
 
836
 
 
837
        memset(&ssid, 0, sizeof(ssid));
 
838
 
 
839
#if WIRELESS_EXT > 17
 
840
 
 
841
        if (wrqu->data.length == sizeof(struct iw_scan_req)) {
 
842
                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
 
843
                        struct iw_scan_req *req = (struct iw_scan_req *)extra;
 
844
                        ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
 
845
                        memcpy(ssid.SSID, req->essid, ssid.SSID_len);
 
846
                        ssid.SSID_len = htod32(ssid.SSID_len);
 
847
                }
 
848
        }
 
849
#endif
 
850
 
 
851
        (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid));
 
852
 
 
853
        return 0;
 
854
}
 
855
 
 
856
#if WIRELESS_EXT > 17
 
857
static bool
 
858
ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
 
859
{
 
860
 
 
861
        uint8 *ie = *wpaie;
 
862
 
 
863
        if ((ie[1] >= 6) &&
 
864
                !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
 
865
                return TRUE;
 
866
        }
 
867
 
 
868
        ie += ie[1] + 2;
 
869
 
 
870
        *tlvs_len -= (int)(ie - *tlvs);
 
871
 
 
872
        *tlvs = ie;
 
873
        return FALSE;
 
874
}
 
875
 
 
876
static bool
 
877
ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
 
878
{
 
879
 
 
880
        uint8 *ie = *wpsie;
 
881
 
 
882
        if ((ie[1] >= 4) &&
 
883
                !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
 
884
                return TRUE;
 
885
        }
 
886
 
 
887
        ie += ie[1] + 2;
 
888
 
 
889
        *tlvs_len -= (int)(ie - *tlvs);
 
890
 
 
891
        *tlvs = ie;
 
892
        return FALSE;
 
893
}
 
894
#endif 
 
895
 
 
896
static int
 
897
wl_iw_get_scan(
 
898
        struct net_device *dev,
 
899
        struct iw_request_info *info,
 
900
        struct iw_point *dwrq,
 
901
        char *extra
 
902
)
 
903
{
 
904
        channel_info_t ci;
 
905
        wl_scan_results_t *list;
 
906
        struct iw_event iwe;
 
907
        wl_bss_info_t *bi = NULL;
 
908
        int error, i, j;
 
909
        char *event = extra, *end = extra + IW_SCAN_MAX_DATA, *value;
 
910
        uint buflen = dwrq->length;
 
911
 
 
912
        WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name));
 
913
 
 
914
        if (!extra)
 
915
                return -EINVAL;
 
916
 
 
917
        if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
 
918
                return error;
 
919
        ci.scan_channel = dtoh32(ci.scan_channel);
 
920
        if (ci.scan_channel)
 
921
                return -EAGAIN;
 
922
 
 
923
        list = kmalloc(buflen, GFP_KERNEL);
 
924
        if (!list)
 
925
                return -ENOMEM;
 
926
        memset(list, 0, buflen);
 
927
        list->buflen = htod32(buflen);
 
928
        if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
 
929
                kfree(list);
 
930
                return error;
 
931
        }
 
932
        list->buflen = dtoh32(list->buflen);
 
933
        list->version = dtoh32(list->version);
 
934
        list->count = dtoh32(list->count);
 
935
 
 
936
        ASSERT(list->version == WL_BSS_INFO_VERSION);
 
937
 
 
938
        for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
 
939
                bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
 
940
                ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
 
941
                        buflen));
 
942
 
 
943
                iwe.cmd = SIOCGIWAP;
 
944
                iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 
945
                memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
 
946
                event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
 
947
 
 
948
                iwe.u.data.length = dtoh32(bi->SSID_len);
 
949
                iwe.cmd = SIOCGIWESSID;
 
950
                iwe.u.data.flags = 1;
 
951
                event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
 
952
 
 
953
                if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
 
954
                        iwe.cmd = SIOCGIWMODE;
 
955
                        if (dtoh16(bi->capability) & DOT11_CAP_ESS)
 
956
                                iwe.u.mode = IW_MODE_INFRA;
 
957
                        else
 
958
                                iwe.u.mode = IW_MODE_ADHOC;
 
959
                        event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
 
960
                }
 
961
 
 
962
                iwe.cmd = SIOCGIWFREQ;
 
963
                iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
 
964
                        CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
 
965
                        WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
 
966
                iwe.u.freq.e = 6;
 
967
                event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
 
968
 
 
969
                iwe.cmd = IWEVQUAL;
 
970
                iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
 
971
                iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
 
972
                iwe.u.qual.noise = 0x100 + bi->phy_noise;
 
973
                event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
 
974
 
 
975
#if WIRELESS_EXT > 17
 
976
 
 
977
                if (bi->ie_length) {
 
978
 
 
979
                        bcm_tlv_t *ie;
 
980
                        uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 
981
                        int ptr_len = bi->ie_length;
 
982
                        if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
 
983
                                iwe.cmd = IWEVGENIE;
 
984
                                iwe.u.data.length = ie->len + 2;
 
985
                                event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
 
986
                        }
 
987
                        ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 
988
                        while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
 
989
 
 
990
                            if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
 
991
                                iwe.cmd = IWEVGENIE;
 
992
                                iwe.u.data.length = ie->len + 2;
 
993
                                event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
 
994
                                break;
 
995
                            }
 
996
                        }
 
997
 
 
998
                        ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 
999
                        ptr_len = bi->ie_length;
 
1000
                        while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
 
1001
                                if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
 
1002
                                        iwe.cmd = IWEVGENIE;
 
1003
                                        iwe.u.data.length = ie->len + 2;
 
1004
                                        event = IWE_STREAM_ADD_POINT(info, event,
 
1005
                                                end, &iwe, (char *)ie);
 
1006
                                        goto done;
 
1007
                                }
 
1008
                        }
 
1009
                }
 
1010
done:
 
1011
#endif 
 
1012
 
 
1013
                iwe.cmd = SIOCGIWENCODE;
 
1014
                if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
 
1015
                        iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 
1016
                else
 
1017
                        iwe.u.data.flags = IW_ENCODE_DISABLED;
 
1018
                iwe.u.data.length = 0;
 
1019
                event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
 
1020
 
 
1021
                if (bi->rateset.count) {
 
1022
                        value = event + IW_EV_LCP_LEN;
 
1023
                        iwe.cmd = SIOCGIWRATE;
 
1024
 
 
1025
                        iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
 
1026
                        for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
 
1027
                                iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
 
1028
                                value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
 
1029
                                        IW_EV_PARAM_LEN);
 
1030
                        }
 
1031
                        event = value;
 
1032
                }
 
1033
        }
 
1034
 
 
1035
        kfree(list);
 
1036
 
 
1037
        dwrq->length = event - extra;
 
1038
        dwrq->flags = 0;        
 
1039
 
 
1040
        return 0;
 
1041
}
 
1042
#endif 
 
1043
 
 
1044
static int
 
1045
wl_iw_set_essid(
 
1046
        struct net_device *dev,
 
1047
        struct iw_request_info *info,
 
1048
        struct iw_point *dwrq,
 
1049
        char *extra
 
1050
)
 
1051
{
 
1052
        wlc_ssid_t ssid;
 
1053
        int error;
 
1054
 
 
1055
        WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
 
1056
 
 
1057
        memset(&ssid, 0, sizeof(ssid));
 
1058
        if (dwrq->length && extra) {
 
1059
#if WIRELESS_EXT > 20
 
1060
                ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length);
 
1061
#else
 
1062
                ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1);
 
1063
#endif
 
1064
                memcpy(ssid.SSID, extra, ssid.SSID_len);
 
1065
                ssid.SSID_len = htod32(ssid.SSID_len);
 
1066
        }
 
1067
        if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid))))
 
1068
                return error;
 
1069
 
 
1070
        return 0;
 
1071
}
 
1072
 
 
1073
static int
 
1074
wl_iw_get_essid(
 
1075
        struct net_device *dev,
 
1076
        struct iw_request_info *info,
 
1077
        struct iw_point *dwrq,
 
1078
        char *extra
 
1079
)
 
1080
{
 
1081
        wlc_ssid_t ssid;
 
1082
        int error;
 
1083
 
 
1084
        WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
 
1085
 
 
1086
        if (!extra)
 
1087
                return -EINVAL;
 
1088
 
 
1089
        if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
 
1090
                WL_ERROR(("Error getting the SSID\n"));
 
1091
                return error;
 
1092
        }
 
1093
 
 
1094
        ssid.SSID_len = dtoh32(ssid.SSID_len);
 
1095
 
 
1096
        memcpy(extra, ssid.SSID, ssid.SSID_len);
 
1097
 
 
1098
        dwrq->length = ssid.SSID_len;
 
1099
 
 
1100
        dwrq->flags = 1; 
 
1101
 
 
1102
        return 0;
 
1103
}
 
1104
 
 
1105
static int
 
1106
wl_iw_set_nick(
 
1107
        struct net_device *dev,
 
1108
        struct iw_request_info *info,
 
1109
        struct iw_point *dwrq,
 
1110
        char *extra
 
1111
)
 
1112
{
 
1113
        wl_iw_t *iw = dev->priv;
 
1114
 
 
1115
        WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
 
1116
 
 
1117
        if (!extra)
 
1118
                return -EINVAL;
 
1119
 
 
1120
        if (dwrq->length > sizeof(iw->nickname))
 
1121
                return -E2BIG;
 
1122
 
 
1123
        memcpy(iw->nickname, extra, dwrq->length);
 
1124
        iw->nickname[dwrq->length - 1] = '\0';
 
1125
 
 
1126
        return 0;
 
1127
}
 
1128
 
 
1129
static int
 
1130
wl_iw_get_nick(
 
1131
        struct net_device *dev,
 
1132
        struct iw_request_info *info,
 
1133
        struct iw_point *dwrq,
 
1134
        char *extra
 
1135
)
 
1136
{
 
1137
        wl_iw_t *iw = dev->priv;
 
1138
 
 
1139
        WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
 
1140
 
 
1141
        if (!extra)
 
1142
                return -EINVAL;
 
1143
 
 
1144
        strcpy(extra, iw->nickname);
 
1145
        dwrq->length = strlen(extra) + 1;
 
1146
 
 
1147
        return 0;
 
1148
}
 
1149
 
 
1150
static int wl_iw_set_rate(
 
1151
        struct net_device *dev,
 
1152
        struct iw_request_info *info,
 
1153
        struct iw_param *vwrq,
 
1154
        char *extra
 
1155
)
 
1156
{
 
1157
        wl_rateset_t rateset;
 
1158
        int error, rate, i, error_bg, error_a;
 
1159
 
 
1160
        WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
 
1161
 
 
1162
        if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
 
1163
                return error;
 
1164
 
 
1165
        rateset.count = dtoh32(rateset.count);
 
1166
 
 
1167
        if (vwrq->value < 0) {
 
1168
 
 
1169
                rate = rateset.rates[rateset.count - 1] & 0x7f;
 
1170
        } else if (vwrq->value < rateset.count) {
 
1171
 
 
1172
                rate = rateset.rates[vwrq->value] & 0x7f;
 
1173
        } else {
 
1174
 
 
1175
                rate = vwrq->value / 500000;
 
1176
        }
 
1177
 
 
1178
        if (vwrq->fixed) {
 
1179
 
 
1180
                error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
 
1181
                error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
 
1182
 
 
1183
                if (error_bg && error_a)
 
1184
                        return (error_bg | error_a);
 
1185
        } else {
 
1186
 
 
1187
                error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
 
1188
 
 
1189
                error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
 
1190
 
 
1191
                if (error_bg && error_a)
 
1192
                        return (error_bg | error_a);
 
1193
 
 
1194
                for (i = 0; i < rateset.count; i++)
 
1195
                        if ((rateset.rates[i] & 0x7f) > rate)
 
1196
                                break;
 
1197
                rateset.count = htod32(i);
 
1198
 
 
1199
                if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
 
1200
                        return error;
 
1201
        }
 
1202
 
 
1203
        return 0;
 
1204
}
 
1205
 
 
1206
static int wl_iw_get_rate(
 
1207
        struct net_device *dev,
 
1208
        struct iw_request_info *info,
 
1209
        struct iw_param *vwrq,
 
1210
        char *extra
 
1211
)
 
1212
{
 
1213
        int error, rate;
 
1214
 
 
1215
        WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
 
1216
 
 
1217
        if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
 
1218
                return error;
 
1219
        rate = dtoh32(rate);
 
1220
        vwrq->value = (rate & 0x7f) * 500000;
 
1221
 
 
1222
        return 0;
 
1223
}
 
1224
 
 
1225
static int
 
1226
wl_iw_set_rts(
 
1227
        struct net_device *dev,
 
1228
        struct iw_request_info *info,
 
1229
        struct iw_param *vwrq,
 
1230
        char *extra
 
1231
)
 
1232
{
 
1233
        int error, rts;
 
1234
 
 
1235
        WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
 
1236
 
 
1237
        if (vwrq->disabled)
 
1238
                rts = DOT11_DEFAULT_RTS_LEN;
 
1239
        else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
 
1240
                return -EINVAL;
 
1241
        else
 
1242
                rts = vwrq->value;
 
1243
 
 
1244
        if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
 
1245
                return error;
 
1246
 
 
1247
        return 0;
 
1248
}
 
1249
 
 
1250
static int
 
1251
wl_iw_get_rts(
 
1252
        struct net_device *dev,
 
1253
        struct iw_request_info *info,
 
1254
        struct iw_param *vwrq,
 
1255
        char *extra
 
1256
)
 
1257
{
 
1258
        int error, rts;
 
1259
 
 
1260
        WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
 
1261
 
 
1262
        if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
 
1263
                return error;
 
1264
 
 
1265
        vwrq->value = rts;
 
1266
        vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
 
1267
        vwrq->fixed = 1;
 
1268
 
 
1269
        return 0;
 
1270
}
 
1271
 
 
1272
static int
 
1273
wl_iw_set_frag(
 
1274
        struct net_device *dev,
 
1275
        struct iw_request_info *info,
 
1276
        struct iw_param *vwrq,
 
1277
        char *extra
 
1278
)
 
1279
{
 
1280
        int error, frag;
 
1281
 
 
1282
        WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
 
1283
 
 
1284
        if (vwrq->disabled)
 
1285
                frag = DOT11_DEFAULT_FRAG_LEN;
 
1286
        else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
 
1287
                return -EINVAL;
 
1288
        else
 
1289
                frag = vwrq->value;
 
1290
 
 
1291
        if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
 
1292
                return error;
 
1293
 
 
1294
        return 0;
 
1295
}
 
1296
 
 
1297
static int
 
1298
wl_iw_get_frag(
 
1299
        struct net_device *dev,
 
1300
        struct iw_request_info *info,
 
1301
        struct iw_param *vwrq,
 
1302
        char *extra
 
1303
)
 
1304
{
 
1305
        int error, fragthreshold;
 
1306
 
 
1307
        WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
 
1308
 
 
1309
        if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
 
1310
                return error;
 
1311
 
 
1312
        vwrq->value = fragthreshold;
 
1313
        vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
 
1314
        vwrq->fixed = 1;
 
1315
 
 
1316
        return 0;
 
1317
}
 
1318
 
 
1319
static int
 
1320
wl_iw_set_txpow(
 
1321
        struct net_device *dev,
 
1322
        struct iw_request_info *info,
 
1323
        struct iw_param *vwrq,
 
1324
        char *extra
 
1325
)
 
1326
{
 
1327
        int error, disable;
 
1328
        uint16 txpwrmw;
 
1329
        WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
 
1330
 
 
1331
        disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
 
1332
        disable += WL_RADIO_SW_DISABLE << 16;
 
1333
 
 
1334
        disable = htod32(disable);
 
1335
        if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
 
1336
                return error;
 
1337
 
 
1338
        if (disable & WL_RADIO_SW_DISABLE)
 
1339
                return 0;
 
1340
 
 
1341
        if (!(vwrq->flags & IW_TXPOW_MWATT))
 
1342
                return -EINVAL;
 
1343
 
 
1344
        if (vwrq->value < 0)
 
1345
                return 0;
 
1346
 
 
1347
        if (vwrq->value > 0xffff) txpwrmw = 0xffff;
 
1348
        else txpwrmw = (uint16)vwrq->value;
 
1349
 
 
1350
        error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
 
1351
        return error;
 
1352
}
 
1353
 
 
1354
static int
 
1355
wl_iw_get_txpow(
 
1356
        struct net_device *dev,
 
1357
        struct iw_request_info *info,
 
1358
        struct iw_param *vwrq,
 
1359
        char *extra
 
1360
)
 
1361
{
 
1362
        int error, disable, txpwrdbm;
 
1363
        uint8 result;
 
1364
 
 
1365
        WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
 
1366
 
 
1367
        if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
 
1368
            (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
 
1369
                return error;
 
1370
 
 
1371
        disable = dtoh32(disable);
 
1372
        result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
 
1373
        vwrq->value = (int32)bcm_qdbm_to_mw(result);
 
1374
        vwrq->fixed = 0;
 
1375
        vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
 
1376
        vwrq->flags = IW_TXPOW_MWATT;
 
1377
 
 
1378
        return 0;
 
1379
}
 
1380
 
 
1381
#if WIRELESS_EXT > 10
 
1382
static int
 
1383
wl_iw_set_retry(
 
1384
        struct net_device *dev,
 
1385
        struct iw_request_info *info,
 
1386
        struct iw_param *vwrq,
 
1387
        char *extra
 
1388
)
 
1389
{
 
1390
        int error, lrl, srl;
 
1391
 
 
1392
        WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
 
1393
 
 
1394
        if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
 
1395
                return -EINVAL;
 
1396
 
 
1397
        if (vwrq->flags & IW_RETRY_LIMIT) {
 
1398
 
 
1399
                if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
 
1400
                        lrl = htod32(vwrq->value);
 
1401
                        if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
 
1402
                                return error;
 
1403
                }
 
1404
 
 
1405
                if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
 
1406
                        srl = htod32(vwrq->value);
 
1407
                        if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
 
1408
                                return error;
 
1409
                }
 
1410
        }
 
1411
 
 
1412
        return 0;
 
1413
}
 
1414
 
 
1415
static int
 
1416
wl_iw_get_retry(
 
1417
        struct net_device *dev,
 
1418
        struct iw_request_info *info,
 
1419
        struct iw_param *vwrq,
 
1420
        char *extra
 
1421
)
 
1422
{
 
1423
        int error, lrl, srl;
 
1424
 
 
1425
        WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
 
1426
 
 
1427
        vwrq->disabled = 0;      
 
1428
 
 
1429
        if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
 
1430
                return -EINVAL;
 
1431
 
 
1432
        if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
 
1433
            (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
 
1434
                return error;
 
1435
 
 
1436
        lrl = dtoh32(lrl);
 
1437
        srl = dtoh32(srl);
 
1438
 
 
1439
        if (vwrq->flags & IW_RETRY_MAX) {
 
1440
                vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
 
1441
                vwrq->value = lrl;
 
1442
        } else {
 
1443
                vwrq->flags = IW_RETRY_LIMIT;
 
1444
                vwrq->value = srl;
 
1445
                if (srl != lrl)
 
1446
                        vwrq->flags |= IW_RETRY_MIN;
 
1447
        }
 
1448
 
 
1449
        return 0;
 
1450
}
 
1451
#endif 
 
1452
 
 
1453
static int
 
1454
wl_iw_set_encode(
 
1455
        struct net_device *dev,
 
1456
        struct iw_request_info *info,
 
1457
        struct iw_point *dwrq,
 
1458
        char *extra
 
1459
)
 
1460
{
 
1461
        wl_wsec_key_t key;
 
1462
        int error, val, wsec;
 
1463
 
 
1464
        WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
 
1465
 
 
1466
        memset(&key, 0, sizeof(key));
 
1467
 
 
1468
        if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
 
1469
 
 
1470
                for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
 
1471
                        val = htod32(key.index);
 
1472
                        if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
 
1473
                                return error;
 
1474
                        val = dtoh32(val);
 
1475
                        if (val)
 
1476
                                break;
 
1477
                }
 
1478
 
 
1479
                if (key.index == DOT11_MAX_DEFAULT_KEYS)
 
1480
                        key.index = 0;
 
1481
        } else {
 
1482
                key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
1483
                if (key.index >= DOT11_MAX_DEFAULT_KEYS)
 
1484
                        return -EINVAL;
 
1485
        }
 
1486
 
 
1487
        wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
 
1488
 
 
1489
        if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
 
1490
                return error;
 
1491
 
 
1492
        if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
 
1493
 
 
1494
                val = htod32(key.index);
 
1495
                if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
 
1496
                        return error;
 
1497
        } else {
 
1498
                key.len = dwrq->length;
 
1499
 
 
1500
                if (dwrq->length > sizeof(key.data))
 
1501
                        return -EINVAL;
 
1502
 
 
1503
                memcpy(key.data, extra, dwrq->length);
 
1504
 
 
1505
                key.flags = WL_PRIMARY_KEY;
 
1506
                switch (key.len) {
 
1507
                case WEP1_KEY_SIZE:
 
1508
                        key.algo = CRYPTO_ALGO_WEP1;
 
1509
                        break;
 
1510
                case WEP128_KEY_SIZE:
 
1511
                        key.algo = CRYPTO_ALGO_WEP128;
 
1512
                        break;
 
1513
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
 
1514
                case TKIP_KEY_SIZE:
 
1515
                        key.algo = CRYPTO_ALGO_TKIP;
 
1516
                        break;
 
1517
#endif
 
1518
                case AES_KEY_SIZE:
 
1519
                        key.algo = CRYPTO_ALGO_AES_CCM;
 
1520
                        break;
 
1521
                default:
 
1522
                        return -EINVAL;
 
1523
                }
 
1524
 
 
1525
                swap_key_from_BE(&key);
 
1526
                if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
 
1527
                        return error;
 
1528
        }
 
1529
 
 
1530
        val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
 
1531
        val = htod32(val);
 
1532
        if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
 
1533
                return error;
 
1534
 
 
1535
        return 0;
 
1536
}
 
1537
 
 
1538
static int
 
1539
wl_iw_get_encode(
 
1540
        struct net_device *dev,
 
1541
        struct iw_request_info *info,
 
1542
        struct iw_point *dwrq,
 
1543
        char *extra
 
1544
)
 
1545
{
 
1546
        wl_wsec_key_t key;
 
1547
        int error, val, wsec, auth;
 
1548
 
 
1549
        WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
 
1550
 
 
1551
        bzero(&key, sizeof(wl_wsec_key_t));
 
1552
 
 
1553
        if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
 
1554
 
 
1555
                for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
 
1556
                        val = key.index;
 
1557
                        if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
 
1558
                                return error;
 
1559
                        val = dtoh32(val);
 
1560
                        if (val)
 
1561
                                break;
 
1562
                }
 
1563
        } else
 
1564
                key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
1565
 
 
1566
        if (key.index >= DOT11_MAX_DEFAULT_KEYS)
 
1567
                key.index = 0;
 
1568
 
 
1569
        if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY, &key, sizeof(key))) ||
 
1570
            (error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
 
1571
            (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
 
1572
                return error;
 
1573
 
 
1574
        swap_key_to_BE(&key);
 
1575
 
 
1576
        wsec = dtoh32(wsec);
 
1577
        auth = dtoh32(auth);
 
1578
 
 
1579
        dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len);
 
1580
 
 
1581
        dwrq->flags = key.index + 1;
 
1582
        if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
 
1583
 
 
1584
                dwrq->flags |= IW_ENCODE_DISABLED;
 
1585
        }
 
1586
        if (auth) {
 
1587
 
 
1588
                dwrq->flags |= IW_ENCODE_RESTRICTED;
 
1589
        }
 
1590
 
 
1591
        if (dwrq->length && extra)
 
1592
                memcpy(extra, key.data, dwrq->length);
 
1593
 
 
1594
        return 0;
 
1595
}
 
1596
 
 
1597
static int
 
1598
wl_iw_set_power(
 
1599
        struct net_device *dev,
 
1600
        struct iw_request_info *info,
 
1601
        struct iw_param *vwrq,
 
1602
        char *extra
 
1603
)
 
1604
{
 
1605
        int error, pm;
 
1606
 
 
1607
        WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
 
1608
 
 
1609
        pm = vwrq->disabled ? PM_OFF : PM_MAX;
 
1610
 
 
1611
        pm = htod32(pm);
 
1612
        if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
 
1613
                return error;
 
1614
 
 
1615
        return 0;
 
1616
}
 
1617
 
 
1618
static int
 
1619
wl_iw_get_power(
 
1620
        struct net_device *dev,
 
1621
        struct iw_request_info *info,
 
1622
        struct iw_param *vwrq,
 
1623
        char *extra
 
1624
)
 
1625
{
 
1626
        int error, pm;
 
1627
 
 
1628
        WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
 
1629
 
 
1630
        if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
 
1631
                return error;
 
1632
 
 
1633
        pm = dtoh32(pm);
 
1634
        vwrq->disabled = pm ? 0 : 1;
 
1635
        vwrq->flags = IW_POWER_ALL_R;
 
1636
 
 
1637
        return 0;
 
1638
}
 
1639
 
 
1640
#if WIRELESS_EXT > 17
 
1641
static int
 
1642
wl_iw_set_wpaie(
 
1643
        struct net_device *dev,
 
1644
        struct iw_request_info *info,
 
1645
        struct iw_point *iwp,
 
1646
        char *extra
 
1647
)
 
1648
{
 
1649
        WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
 
1650
        dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
 
1651
        return 0;
 
1652
}
 
1653
 
 
1654
static int
 
1655
wl_iw_get_wpaie(
 
1656
        struct net_device *dev,
 
1657
        struct iw_request_info *info,
 
1658
        struct iw_point *iwp,
 
1659
        char *extra
 
1660
)
 
1661
{
 
1662
        WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
 
1663
        iwp->length = 64;
 
1664
        dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
 
1665
        return 0;
 
1666
}
 
1667
 
 
1668
static int
 
1669
wl_iw_set_encodeext(
 
1670
        struct net_device *dev,
 
1671
        struct iw_request_info *info,
 
1672
        struct iw_point *dwrq,
 
1673
        char *extra
 
1674
)
 
1675
{
 
1676
        wl_wsec_key_t key;
 
1677
        int error;
 
1678
        struct iw_encode_ext *iwe;
 
1679
 
 
1680
        WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
 
1681
 
 
1682
        memset(&key, 0, sizeof(key));
 
1683
        iwe = (struct iw_encode_ext *)extra;
 
1684
 
 
1685
        if (dwrq->flags & IW_ENCODE_DISABLED) {
 
1686
 
 
1687
        }
 
1688
 
 
1689
        key.index = 0;
 
1690
        if (dwrq->flags & IW_ENCODE_INDEX)
 
1691
                key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
1692
 
 
1693
        key.len = iwe->key_len;
 
1694
 
 
1695
        if (!ETHER_ISMULTI(iwe->addr.sa_data))
 
1696
                bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
 
1697
 
 
1698
        if (key.len == 0) {
 
1699
                if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 
1700
                        WL_WSEC(("Changing the the primary Key to %d\n", key.index));
 
1701
 
 
1702
                        key.index = htod32(key.index);
 
1703
                        error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
 
1704
                                &key.index, sizeof(key.index));
 
1705
                        if (error)
 
1706
                                return error;
 
1707
                }
 
1708
 
 
1709
                else {
 
1710
                        swap_key_from_BE(&key);
 
1711
                        dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
 
1712
                }
 
1713
        }
 
1714
        else {
 
1715
                if (iwe->key_len > sizeof(key.data))
 
1716
                        return -EINVAL;
 
1717
 
 
1718
                WL_WSEC(("Setting the key index %d\n", key.index));
 
1719
                if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
 
1720
                        WL_WSEC(("key is a Primary Key\n"));
 
1721
                        key.flags = WL_PRIMARY_KEY;
 
1722
                }
 
1723
 
 
1724
                bcopy((void *)iwe->key, key.data, iwe->key_len);
 
1725
 
 
1726
                if (iwe->alg == IW_ENCODE_ALG_TKIP) {
 
1727
                        uint8 keybuf[8];
 
1728
                        bcopy(&key.data[24], keybuf, sizeof(keybuf));
 
1729
                        bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
 
1730
                        bcopy(keybuf, &key.data[16], sizeof(keybuf));
 
1731
                }
 
1732
 
 
1733
                if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
 
1734
                        uchar *ivptr;
 
1735
                        ivptr = (uchar *)iwe->rx_seq;
 
1736
                        key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
 
1737
                                (ivptr[3] << 8) | ivptr[2];
 
1738
                        key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
 
1739
                        key.iv_initialized = TRUE;
 
1740
                }
 
1741
 
 
1742
                switch (iwe->alg) {
 
1743
                        case IW_ENCODE_ALG_NONE:
 
1744
                                key.algo = CRYPTO_ALGO_OFF;
 
1745
                                break;
 
1746
                        case IW_ENCODE_ALG_WEP:
 
1747
                                if (iwe->key_len == WEP1_KEY_SIZE)
 
1748
                                        key.algo = CRYPTO_ALGO_WEP1;
 
1749
                                else
 
1750
                                        key.algo = CRYPTO_ALGO_WEP128;
 
1751
                                break;
 
1752
                        case IW_ENCODE_ALG_TKIP:
 
1753
                                key.algo = CRYPTO_ALGO_TKIP;
 
1754
                                break;
 
1755
                        case IW_ENCODE_ALG_CCMP:
 
1756
                                key.algo = CRYPTO_ALGO_AES_CCM;
 
1757
                                break;
 
1758
                        default:
 
1759
                                break;
 
1760
                }
 
1761
                swap_key_from_BE(&key);
 
1762
                error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
 
1763
                if (error)
 
1764
                        return error;
 
1765
        }
 
1766
        return 0;
 
1767
}
 
1768
 
 
1769
static int
 
1770
wl_iw_get_encodeext(
 
1771
        struct net_device *dev,
 
1772
        struct iw_request_info *info,
 
1773
        struct iw_param *vwrq,
 
1774
        char *extra
 
1775
)
 
1776
{
 
1777
        WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
 
1778
        return 0;
 
1779
}
 
1780
 
 
1781
static int
 
1782
wl_iw_set_wpaauth(
 
1783
        struct net_device *dev,
 
1784
        struct iw_request_info *info,
 
1785
        struct iw_param *vwrq,
 
1786
        char *extra
 
1787
)
 
1788
{
 
1789
        int error = 0;
 
1790
        int paramid;
 
1791
        int paramval;
 
1792
        int val = 0;
 
1793
        wl_iw_t *iw = dev->priv;
 
1794
 
 
1795
        WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name));
 
1796
 
 
1797
        paramid = vwrq->flags & IW_AUTH_INDEX;
 
1798
        paramval = vwrq->value;
 
1799
 
 
1800
        switch (paramid) {
 
1801
        case IW_AUTH_WPA_VERSION:
 
1802
 
 
1803
                if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
 
1804
                        val = WPA_AUTH_DISABLED;
 
1805
                else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
 
1806
                        val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
 
1807
                else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
 
1808
                        val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
 
1809
                WL_ERROR(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
 
1810
                if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
 
1811
                        return error;
 
1812
                break;
 
1813
        case IW_AUTH_CIPHER_PAIRWISE:
 
1814
        case IW_AUTH_CIPHER_GROUP:
 
1815
                if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
 
1816
                        return error;
 
1817
 
 
1818
                if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
 
1819
                        val |=  WEP_ENABLED;
 
1820
                if (paramval & IW_AUTH_CIPHER_TKIP)
 
1821
                        val |= TKIP_ENABLED;
 
1822
                if (paramval & IW_AUTH_CIPHER_CCMP)
 
1823
                        val |= AES_ENABLED;
 
1824
 
 
1825
                if (paramid == IW_AUTH_CIPHER_PAIRWISE)
 
1826
                        val |= iw->pwsec;
 
1827
                else
 
1828
                        val |= iw->gwsec;
 
1829
 
 
1830
                if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
 
1831
                        return error;
 
1832
 
 
1833
                break;
 
1834
 
 
1835
        case IW_AUTH_KEY_MGMT:
 
1836
                if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
 
1837
                        return error;
 
1838
 
 
1839
                if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
 
1840
                        if (paramval & IW_AUTH_KEY_MGMT_PSK)
 
1841
                                val = WPA_AUTH_PSK;
 
1842
                        else
 
1843
                                val = WPA_AUTH_UNSPECIFIED;
 
1844
                }
 
1845
                else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
 
1846
                        if (paramval & IW_AUTH_KEY_MGMT_PSK)
 
1847
                                val = WPA2_AUTH_PSK;
 
1848
                        else
 
1849
                                val = WPA2_AUTH_UNSPECIFIED;
 
1850
                }
 
1851
                WL_ERROR(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
 
1852
                if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
 
1853
                        return error;
 
1854
                break;
 
1855
        case IW_AUTH_TKIP_COUNTERMEASURES:
 
1856
                dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
 
1857
                break;
 
1858
 
 
1859
        case IW_AUTH_80211_AUTH_ALG:
 
1860
 
 
1861
                WL_ERROR(("Setting the D11auth %d\n", paramval));
 
1862
                if (paramval & IW_AUTH_ALG_OPEN_SYSTEM)
 
1863
                        val = 0;
 
1864
                else if (paramval & IW_AUTH_ALG_SHARED_KEY)
 
1865
                        val = 1;
 
1866
                else
 
1867
                        error = 1;
 
1868
                if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
 
1869
                        return error;
 
1870
                break;
 
1871
 
 
1872
        case IW_AUTH_WPA_ENABLED:
 
1873
                if (paramval == 0) {
 
1874
                        if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
 
1875
                                return error;
 
1876
                        if (val & (TKIP_ENABLED | AES_ENABLED)) {
 
1877
                                val &= ~(TKIP_ENABLED | AES_ENABLED);
 
1878
                                dev_wlc_intvar_set(dev, "wsec", val);
 
1879
                        }
 
1880
                        val = 0;
 
1881
                        WL_ERROR(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
 
1882
                        dev_wlc_intvar_set(dev, "wpa_auth", val);
 
1883
                        return error;
 
1884
                }
 
1885
 
 
1886
                break;
 
1887
 
 
1888
        case IW_AUTH_DROP_UNENCRYPTED:
 
1889
                dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
 
1890
                break;
 
1891
 
 
1892
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 
1893
                dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
 
1894
                break;
 
1895
 
 
1896
#if WIRELESS_EXT > 17
 
1897
        case IW_AUTH_ROAMING_CONTROL:
 
1898
                WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
 
1899
 
 
1900
                break;
 
1901
        case IW_AUTH_PRIVACY_INVOKED:
 
1902
                WL_ERROR(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__));
 
1903
                break;
 
1904
#endif 
 
1905
        default:
 
1906
                break;
 
1907
        }
 
1908
        return 0;
 
1909
}
 
1910
#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
 
1911
 
 
1912
static int
 
1913
wl_iw_get_wpaauth(
 
1914
        struct net_device *dev,
 
1915
        struct iw_request_info *info,
 
1916
        struct iw_param *vwrq,
 
1917
        char *extra
 
1918
)
 
1919
{
 
1920
        int error;
 
1921
        int paramid;
 
1922
        int paramval = 0;
 
1923
        int val;
 
1924
        wl_iw_t *iw = dev->priv;
 
1925
 
 
1926
        WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
 
1927
 
 
1928
        paramid = vwrq->flags & IW_AUTH_INDEX;
 
1929
 
 
1930
        switch (paramid) {
 
1931
        case IW_AUTH_WPA_VERSION:
 
1932
 
 
1933
                if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
 
1934
                        return error;
 
1935
                if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
 
1936
                        paramval = IW_AUTH_WPA_VERSION_DISABLED;
 
1937
                else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
 
1938
                        paramval = IW_AUTH_WPA_VERSION_WPA;
 
1939
                else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
 
1940
                        paramval = IW_AUTH_WPA_VERSION_WPA2;
 
1941
                break;
 
1942
        case IW_AUTH_CIPHER_PAIRWISE:
 
1943
        case IW_AUTH_CIPHER_GROUP:
 
1944
                if (paramid == IW_AUTH_CIPHER_PAIRWISE)
 
1945
                        val = iw->pwsec;
 
1946
                else
 
1947
                        val = iw->gwsec;
 
1948
 
 
1949
                paramval = 0;
 
1950
                if (val) {
 
1951
                        if (val & WEP_ENABLED)
 
1952
                                paramval |= (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104);
 
1953
                        if (val & TKIP_ENABLED)
 
1954
                                paramval |= (IW_AUTH_CIPHER_TKIP);
 
1955
                        if (val & AES_ENABLED)
 
1956
                                paramval |= (IW_AUTH_CIPHER_CCMP);
 
1957
                }
 
1958
                else
 
1959
                        paramval = IW_AUTH_CIPHER_NONE;
 
1960
                break;
 
1961
        case IW_AUTH_KEY_MGMT:
 
1962
 
 
1963
                if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
 
1964
                        return error;
 
1965
                if (VAL_PSK(val))
 
1966
                        paramval = IW_AUTH_KEY_MGMT_PSK;
 
1967
                else
 
1968
                        paramval = IW_AUTH_KEY_MGMT_802_1X;
 
1969
 
 
1970
                break;
 
1971
        case IW_AUTH_TKIP_COUNTERMEASURES:
 
1972
                dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
 
1973
                break;
 
1974
 
 
1975
        case IW_AUTH_DROP_UNENCRYPTED:
 
1976
                dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
 
1977
                break;
 
1978
 
 
1979
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
 
1980
                dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
 
1981
                break;
 
1982
 
 
1983
        case IW_AUTH_80211_AUTH_ALG:
 
1984
 
 
1985
                if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
 
1986
                        return error;
 
1987
                if (!val)
 
1988
                        paramval = IW_AUTH_ALG_OPEN_SYSTEM;
 
1989
                else
 
1990
                        paramval = IW_AUTH_ALG_SHARED_KEY;
 
1991
                break;
 
1992
        case IW_AUTH_WPA_ENABLED:
 
1993
                if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
 
1994
                        return error;
 
1995
                if (val)
 
1996
                        paramval = TRUE;
 
1997
                else
 
1998
                        paramval = FALSE;
 
1999
                break;
 
2000
#if WIRELESS_EXT > 17
 
2001
        case IW_AUTH_ROAMING_CONTROL:
 
2002
                WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
 
2003
 
 
2004
                break;
 
2005
        case IW_AUTH_PRIVACY_INVOKED:
 
2006
                WL_ERROR(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__));
 
2007
                break;
 
2008
#endif 
 
2009
        }
 
2010
        vwrq->value = paramval;
 
2011
        return 0;
 
2012
}
 
2013
#endif 
 
2014
 
 
2015
static const iw_handler wl_iw_handler[] =
 
2016
{
 
2017
        (iw_handler) wl_iw_config_commit,       
 
2018
        (iw_handler) wl_iw_get_name,            
 
2019
        (iw_handler) NULL,                      
 
2020
        (iw_handler) NULL,                      
 
2021
        (iw_handler) wl_iw_set_freq,            
 
2022
        (iw_handler) wl_iw_get_freq,            
 
2023
        (iw_handler) wl_iw_set_mode,            
 
2024
        (iw_handler) wl_iw_get_mode,            
 
2025
        (iw_handler) NULL,                      
 
2026
        (iw_handler) NULL,                      
 
2027
        (iw_handler) NULL,                      
 
2028
        (iw_handler) wl_iw_get_range,           
 
2029
        (iw_handler) NULL,                      
 
2030
        (iw_handler) NULL,                      
 
2031
        (iw_handler) NULL,                      
 
2032
        (iw_handler) NULL,                      
 
2033
        (iw_handler) wl_iw_set_spy,             
 
2034
        (iw_handler) wl_iw_get_spy,             
 
2035
        (iw_handler) NULL,                      
 
2036
        (iw_handler) NULL,                      
 
2037
        (iw_handler) wl_iw_set_wap,             
 
2038
        (iw_handler) wl_iw_get_wap,             
 
2039
#if WIRELESS_EXT > 17
 
2040
        (iw_handler) wl_iw_mlme,                
 
2041
#else
 
2042
        (iw_handler) NULL,                      
 
2043
#endif
 
2044
        (iw_handler) wl_iw_get_aplist,          
 
2045
#if WIRELESS_EXT > 13
 
2046
        (iw_handler) wl_iw_set_scan,            
 
2047
        (iw_handler) wl_iw_get_scan,            
 
2048
#else   
 
2049
        (iw_handler) NULL,                      
 
2050
        (iw_handler) NULL,                      
 
2051
#endif  
 
2052
        (iw_handler) wl_iw_set_essid,           
 
2053
        (iw_handler) wl_iw_get_essid,           
 
2054
        (iw_handler) wl_iw_set_nick,            
 
2055
        (iw_handler) wl_iw_get_nick,            
 
2056
        (iw_handler) NULL,                      
 
2057
        (iw_handler) NULL,                      
 
2058
        (iw_handler) wl_iw_set_rate,            
 
2059
        (iw_handler) wl_iw_get_rate,            
 
2060
        (iw_handler) wl_iw_set_rts,             
 
2061
        (iw_handler) wl_iw_get_rts,             
 
2062
        (iw_handler) wl_iw_set_frag,            
 
2063
        (iw_handler) wl_iw_get_frag,            
 
2064
        (iw_handler) wl_iw_set_txpow,           
 
2065
        (iw_handler) wl_iw_get_txpow,           
 
2066
#if WIRELESS_EXT > 10
 
2067
        (iw_handler) wl_iw_set_retry,           
 
2068
        (iw_handler) wl_iw_get_retry,           
 
2069
#endif 
 
2070
        (iw_handler) wl_iw_set_encode,          
 
2071
        (iw_handler) wl_iw_get_encode,          
 
2072
        (iw_handler) wl_iw_set_power,           
 
2073
        (iw_handler) wl_iw_get_power,           
 
2074
#if WIRELESS_EXT > 17
 
2075
        (iw_handler) NULL,                      
 
2076
        (iw_handler) NULL,                      
 
2077
        (iw_handler) wl_iw_set_wpaie,           
 
2078
        (iw_handler) wl_iw_get_wpaie,           
 
2079
        (iw_handler) wl_iw_set_wpaauth,         
 
2080
        (iw_handler) wl_iw_get_wpaauth,         
 
2081
        (iw_handler) wl_iw_set_encodeext,       
 
2082
        (iw_handler) wl_iw_get_encodeext,       
 
2083
        (iw_handler) NULL,                      
 
2084
#endif 
 
2085
};
 
2086
 
 
2087
#if WIRELESS_EXT > 12
 
2088
enum {
 
2089
        WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV,
 
2090
        WL_IW_SET_VLANMODE,
 
2091
        WL_IW_SET_PM
 
2092
};
 
2093
 
 
2094
static iw_handler wl_iw_priv_handler[] = {
 
2095
        wl_iw_set_leddc,
 
2096
        wl_iw_set_vlanmode,
 
2097
        wl_iw_set_pm
 
2098
};
 
2099
 
 
2100
static struct iw_priv_args wl_iw_priv_args[] = {
 
2101
        {
 
2102
                WL_IW_SET_LEDDC,
 
2103
                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
2104
                0,
 
2105
                "set_leddc"
 
2106
        },
 
2107
        {
 
2108
                WL_IW_SET_VLANMODE,
 
2109
                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
2110
                0,
 
2111
                "set_vlanmode"
 
2112
        },
 
2113
        {
 
2114
                WL_IW_SET_PM,
 
2115
                IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
2116
                0,
 
2117
                "set_pm"
 
2118
        }
 
2119
};
 
2120
 
 
2121
const struct iw_handler_def wl_iw_handler_def =
 
2122
{
 
2123
        .num_standard = ARRAYSIZE(wl_iw_handler),
 
2124
        .num_private = ARRAY_SIZE(wl_iw_priv_handler),
 
2125
        .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
 
2126
        .standard = (iw_handler *) wl_iw_handler,
 
2127
        .private = wl_iw_priv_handler,
 
2128
        .private_args = wl_iw_priv_args,
 
2129
#if WIRELESS_EXT >= 19
 
2130
        get_wireless_stats: wl_get_wireless_stats,
 
2131
#endif
 
2132
        };
 
2133
#endif 
 
2134
 
 
2135
int
 
2136
wl_iw_ioctl(
 
2137
        struct net_device *dev,
 
2138
        struct ifreq *rq,
 
2139
        int cmd
 
2140
)
 
2141
{
 
2142
        struct iwreq *wrq = (struct iwreq *) rq;
 
2143
        struct iw_request_info info;
 
2144
        iw_handler handler;
 
2145
        char *extra = NULL;
 
2146
        int token_size = 1, max_tokens = 0, ret = 0;
 
2147
 
 
2148
        if (cmd < SIOCIWFIRST ||
 
2149
                IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
 
2150
                !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)]))
 
2151
                return -EOPNOTSUPP;
 
2152
 
 
2153
        switch (cmd) {
 
2154
 
 
2155
        case SIOCSIWESSID:
 
2156
        case SIOCGIWESSID:
 
2157
        case SIOCSIWNICKN:
 
2158
        case SIOCGIWNICKN:
 
2159
                max_tokens = IW_ESSID_MAX_SIZE + 1;
 
2160
                break;
 
2161
 
 
2162
        case SIOCSIWENCODE:
 
2163
        case SIOCGIWENCODE:
 
2164
#if WIRELESS_EXT > 17
 
2165
        case SIOCSIWENCODEEXT:
 
2166
        case SIOCGIWENCODEEXT:
 
2167
#endif
 
2168
                max_tokens = IW_ENCODING_TOKEN_MAX;
 
2169
                break;
 
2170
 
 
2171
        case SIOCGIWRANGE:
 
2172
                max_tokens = sizeof(struct iw_range);
 
2173
                break;
 
2174
 
 
2175
        case SIOCGIWAPLIST:
 
2176
                token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
 
2177
                max_tokens = IW_MAX_AP;
 
2178
                break;
 
2179
 
 
2180
#if WIRELESS_EXT > 13
 
2181
        case SIOCGIWSCAN:
 
2182
                max_tokens = IW_SCAN_MAX_DATA;
 
2183
                break;
 
2184
#endif 
 
2185
 
 
2186
        case SIOCSIWSPY:
 
2187
                token_size = sizeof(struct sockaddr);
 
2188
                max_tokens = IW_MAX_SPY;
 
2189
                break;
 
2190
 
 
2191
        case SIOCGIWSPY:
 
2192
                token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
 
2193
                max_tokens = IW_MAX_SPY;
 
2194
                break;
 
2195
 
 
2196
        }
 
2197
 
 
2198
        if (max_tokens && wrq->u.data.pointer) {
 
2199
                if (wrq->u.data.length > max_tokens)
 
2200
                        return -E2BIG;
 
2201
 
 
2202
                if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL)))
 
2203
                        return -ENOMEM;
 
2204
 
 
2205
                if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
 
2206
                        kfree(extra);
 
2207
                        return -EFAULT;
 
2208
                }
 
2209
        }
 
2210
 
 
2211
        info.cmd = cmd;
 
2212
        info.flags = 0;
 
2213
 
 
2214
        ret = handler(dev, &info, &wrq->u, extra);
 
2215
 
 
2216
        if (extra) {
 
2217
                if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
 
2218
                        kfree(extra);
 
2219
                        return -EFAULT;
 
2220
                }
 
2221
 
 
2222
                kfree(extra);
 
2223
        }
 
2224
 
 
2225
        return ret;
 
2226
}
 
2227
 
 
2228
bool
 
2229
wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
 
2230
        char* stringBuf, uint buflen)
 
2231
{
 
2232
        typedef struct conn_fail_event_map_t {
 
2233
                uint32 inEvent;                 
 
2234
                uint32 inStatus;                
 
2235
                uint32 inReason;                
 
2236
                const char* outName;    
 
2237
                const char* outCause;   
 
2238
        } conn_fail_event_map_t;
 
2239
 
 
2240
#       define WL_IW_DONT_CARE  9999
 
2241
        const conn_fail_event_map_t event_map [] = {
 
2242
 
 
2243
                {WLC_E_SET_SSID,     WLC_E_STATUS_SUCCESS,   WL_IW_DONT_CARE,
 
2244
                "Conn", "Success"},
 
2245
                {WLC_E_SET_SSID,     WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
 
2246
                "Conn", "NoNetworks"},
 
2247
                {WLC_E_SET_SSID,     WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
 
2248
                "Conn", "ConfigMismatch"},
 
2249
                {WLC_E_PRUNE,        WL_IW_DONT_CARE,        WLC_E_PRUNE_ENCR_MISMATCH,
 
2250
                "Conn", "EncrypMismatch"},
 
2251
                {WLC_E_PRUNE,        WL_IW_DONT_CARE,        WLC_E_RSN_MISMATCH,
 
2252
                "Conn", "RsnMismatch"},
 
2253
                {WLC_E_AUTH,         WLC_E_STATUS_TIMEOUT,   WL_IW_DONT_CARE,
 
2254
                "Conn", "AuthTimeout"},
 
2255
                {WLC_E_AUTH,         WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
 
2256
                "Conn", "AuthFail"},
 
2257
                {WLC_E_AUTH,         WLC_E_STATUS_NO_ACK,    WL_IW_DONT_CARE,
 
2258
                "Conn", "AuthNoAck"},
 
2259
                {WLC_E_REASSOC,      WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
 
2260
                "Conn", "ReassocFail"},
 
2261
                {WLC_E_REASSOC,      WLC_E_STATUS_TIMEOUT,   WL_IW_DONT_CARE,
 
2262
                "Conn", "ReassocTimeout"},
 
2263
                {WLC_E_REASSOC,      WLC_E_STATUS_ABORT,     WL_IW_DONT_CARE,
 
2264
                "Conn", "ReassocAbort"},
 
2265
                {WLC_E_DEAUTH_IND,   WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
 
2266
                "Conn", "Deauth"},
 
2267
                {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
 
2268
                "Conn", "DisassocInd"},
 
2269
                {WLC_E_DISASSOC,     WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
 
2270
                "Conn", "Disassoc"}
 
2271
        };
 
2272
 
 
2273
        const char* name = "";
 
2274
        const char* cause = NULL;
 
2275
        int i;
 
2276
 
 
2277
        for (i = 0;  i < sizeof(event_map)/sizeof(event_map[0]);  i++) {
 
2278
                const conn_fail_event_map_t* row = &event_map[i];
 
2279
                if (row->inEvent == event_type &&
 
2280
                    (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
 
2281
                    (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
 
2282
                        name = row->outName;
 
2283
                        cause = row->outCause;
 
2284
                        break;
 
2285
                }
 
2286
        }
 
2287
 
 
2288
        if (cause) {
 
2289
                memset(stringBuf, 0, buflen);
 
2290
                snprintf(stringBuf, buflen, "%s %s %02d %02d",
 
2291
                        name, cause, status, reason);
 
2292
                WL_INFORM(("Connection status: %s\n", stringBuf));
 
2293
                return TRUE;
 
2294
        } else {
 
2295
                return FALSE;
 
2296
        }
 
2297
}
 
2298
 
 
2299
#if (WIRELESS_EXT > 14)
 
2300
 
 
2301
static bool
 
2302
wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
 
2303
{
 
2304
        uint32 event = e->event_type;
 
2305
        uint32 status =  e->status;
 
2306
        uint32 reason =  e->reason;
 
2307
 
 
2308
        if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
 
2309
                return TRUE;
 
2310
        } else
 
2311
        {
 
2312
                return FALSE;
 
2313
        }
 
2314
}
 
2315
#endif 
 
2316
 
 
2317
#ifndef IW_CUSTOM_MAX
 
2318
#define IW_CUSTOM_MAX 256 
 
2319
#endif 
 
2320
 
 
2321
void
 
2322
wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
 
2323
{
 
2324
#if WIRELESS_EXT > 13
 
2325
        union iwreq_data wrqu;
 
2326
        char extra[IW_CUSTOM_MAX + 1];
 
2327
        int cmd = 0;
 
2328
        uint32 event_type = e->event_type;
 
2329
        uint16 flags =  e->flags;
 
2330
 
 
2331
        memset(&wrqu, 0, sizeof(wrqu));
 
2332
        memset(extra, 0, sizeof(extra));
 
2333
 
 
2334
        memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
 
2335
        wrqu.addr.sa_family = ARPHRD_ETHER;
 
2336
 
 
2337
        switch (event_type) {
 
2338
        case WLC_E_TXFAIL:
 
2339
                cmd = IWEVTXDROP;
 
2340
                break;
 
2341
#if WIRELESS_EXT > 14
 
2342
        case WLC_E_JOIN:
 
2343
        case WLC_E_ASSOC_IND:
 
2344
        case WLC_E_REASSOC_IND:
 
2345
                cmd = IWEVREGISTERED;
 
2346
                break;
 
2347
        case WLC_E_DEAUTH_IND:
 
2348
        case WLC_E_DISASSOC_IND:
 
2349
                cmd = SIOCGIWAP;
 
2350
                wrqu.data.length = strlen(extra);
 
2351
                bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
 
2352
                bzero(&extra, ETHER_ADDR_LEN);
 
2353
                break;
 
2354
        case WLC_E_LINK:
 
2355
        case WLC_E_NDIS_LINK:
 
2356
                cmd = SIOCGIWAP;
 
2357
                wrqu.data.length = strlen(extra);
 
2358
                if (!(flags & WLC_EVENT_MSG_LINK)) {
 
2359
                        bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
 
2360
                        bzero(&extra, ETHER_ADDR_LEN);
 
2361
                }
 
2362
                break;
 
2363
#endif 
 
2364
#if WIRELESS_EXT > 17
 
2365
        case WLC_E_MIC_ERROR: {
 
2366
                struct  iw_michaelmicfailure  *micerrevt = (struct  iw_michaelmicfailure  *)&extra;
 
2367
                cmd = IWEVMICHAELMICFAILURE;
 
2368
                wrqu.data.length = sizeof(struct iw_michaelmicfailure);
 
2369
                if (flags & WLC_EVENT_MSG_GROUP)
 
2370
                        micerrevt->flags |= IW_MICFAILURE_GROUP;
 
2371
                else
 
2372
                        micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
 
2373
                memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
 
2374
                micerrevt->src_addr.sa_family = ARPHRD_ETHER;
 
2375
 
 
2376
                break;
 
2377
        }
 
2378
        case WLC_E_PMKID_CACHE: {
 
2379
                if (data)
 
2380
                {
 
2381
                        struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
 
2382
                        pmkid_cand_list_t *pmkcandlist;
 
2383
                        pmkid_cand_t    *pmkidcand;
 
2384
                        int count;
 
2385
 
 
2386
                        cmd = IWEVPMKIDCAND;
 
2387
                        pmkcandlist = data;
 
2388
                        count = ntoh32(pmkcandlist->npmkid_cand);
 
2389
                        wrqu.data.length = sizeof(struct iw_pmkid_cand);
 
2390
                        pmkidcand = pmkcandlist->pmkid_cand;
 
2391
                        while (count) {
 
2392
                                bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
 
2393
                                if (pmkidcand->preauth)
 
2394
                                        iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
 
2395
                                bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
 
2396
                                        ETHER_ADDR_LEN);
 
2397
                                wireless_send_event(dev, cmd, &wrqu, extra);
 
2398
                                pmkidcand++;
 
2399
                                count--;
 
2400
                        }
 
2401
                }
 
2402
                return;
 
2403
        }
 
2404
#endif 
 
2405
        default:
 
2406
 
 
2407
                break;
 
2408
        }
 
2409
                if (cmd)
 
2410
                        wireless_send_event(dev, cmd, &wrqu, extra);
 
2411
 
 
2412
#if WIRELESS_EXT > 14
 
2413
 
 
2414
        memset(extra, 0, sizeof(extra));
 
2415
        if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
 
2416
                cmd = IWEVCUSTOM;
 
2417
                wrqu.data.length = strlen(extra);
 
2418
                wireless_send_event(dev, cmd, &wrqu, extra);
 
2419
        }
 
2420
#endif 
 
2421
 
 
2422
#endif 
 
2423
}
 
2424
 
 
2425
int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
 
2426
{
 
2427
        int res = 0;
 
2428
        wl_cnt_t cnt;
 
2429
        int phy_noise;
 
2430
        int rssi;
 
2431
        scb_val_t scb_val;
 
2432
 
 
2433
        phy_noise = 0;
 
2434
        if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
 
2435
                goto done;
 
2436
 
 
2437
        phy_noise = dtoh32(phy_noise);
 
2438
        WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise));
 
2439
 
 
2440
        scb_val.val = 0;
 
2441
        if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
 
2442
                goto done;
 
2443
 
 
2444
        rssi = dtoh32(scb_val.val);
 
2445
        WL_TRACE(("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi));
 
2446
        if (rssi <= WL_IW_RSSI_NO_SIGNAL)
 
2447
                wstats->qual.qual = 0;
 
2448
        else if (rssi <= WL_IW_RSSI_VERY_LOW)
 
2449
                wstats->qual.qual = 1;
 
2450
        else if (rssi <= WL_IW_RSSI_LOW)
 
2451
                wstats->qual.qual = 2;
 
2452
        else if (rssi <= WL_IW_RSSI_GOOD)
 
2453
                wstats->qual.qual = 3;
 
2454
        else if (rssi <= WL_IW_RSSI_VERY_GOOD)
 
2455
                wstats->qual.qual = 4;
 
2456
        else
 
2457
                wstats->qual.qual = 5;
 
2458
 
 
2459
        wstats->qual.level = 0x100 + rssi;
 
2460
        wstats->qual.noise = 0x100 + phy_noise;
 
2461
#if WIRELESS_EXT > 18
 
2462
        wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
 
2463
#else
 
2464
        wstats->qual.updated |= 7;
 
2465
#endif 
 
2466
 
 
2467
#if WIRELESS_EXT > 11
 
2468
        WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t)));
 
2469
 
 
2470
        memset(&cnt, 0, sizeof(wl_cnt_t));
 
2471
        res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
 
2472
        if (res)
 
2473
        {
 
2474
                WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res));
 
2475
                goto done;
 
2476
        }
 
2477
 
 
2478
        cnt.version = dtoh16(cnt.version);
 
2479
        if (cnt.version != WL_CNT_T_VERSION) {
 
2480
                WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
 
2481
                        WL_CNT_T_VERSION, cnt.version));
 
2482
                goto done;
 
2483
        }
 
2484
 
 
2485
        wstats->discard.nwid = 0;
 
2486
        wstats->discard.code = dtoh32(cnt.rxundec);
 
2487
        wstats->discard.fragment = dtoh32(cnt.rxfragerr);
 
2488
        wstats->discard.retries = dtoh32(cnt.txfail);
 
2489
        wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
 
2490
        wstats->miss.beacon = 0;
 
2491
 
 
2492
        WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
 
2493
                dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
 
2494
        WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
 
2495
        WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
 
2496
        WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
 
2497
        WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
 
2498
        WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
 
2499
        WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
 
2500
        WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
 
2501
 
 
2502
#endif 
 
2503
 
 
2504
done:
 
2505
        return res;
 
2506
}