OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [wireless/] [prism54/] [isl_ioctl.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  Copyright (C) 2002 Intersil Americas Inc.
3
 *            (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
4
 *            (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5
 *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 *
20
 */
21
 
22
#include <linux/module.h>
23
#include <linux/kernel.h>
24
#include <linux/if_arp.h>
25
#include <linux/pci.h>
26
 
27
#include <asm/uaccess.h>
28
 
29
#include "prismcompat.h"
30
#include "isl_ioctl.h"
31
#include "islpci_mgt.h"
32
#include "isl_oid.h"            /* additional types and defs for isl38xx fw */
33
#include "oid_mgt.h"
34
 
35
#include <net/iw_handler.h>     /* New driver API */
36
 
37
#define KEY_SIZE_WEP104 13      /* 104/128-bit WEP keys */
38
#define KEY_SIZE_WEP40  5       /* 40/64-bit WEP keys */
39
/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
40
#define KEY_SIZE_TKIP   32      /* TKIP keys */
41
 
42
static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
43
                                u8 *wpa_ie, size_t wpa_ie_len);
44
static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
45
static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
46
                                __u32 *, char *);
47
 
48
/* In 500 kbps */
49
static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
50
                                                12, 18, 24, 36,
51
                                                48, 72, 96, 108 };
52
 
53
/**
54
 * prism54_mib_mode_helper - MIB change mode helper function
55
 * @mib: the &struct islpci_mib object to modify
56
 * @iw_mode: new mode (%IW_MODE_*)
57
 *
58
 *  This is a helper function, hence it does not lock. Make sure
59
 *  caller deals with locking *if* necessary. This function sets the
60
 *  mode-dependent mib values and does the mapping of the Linux
61
 *  Wireless API modes to Device firmware modes. It also checks for
62
 *  correct valid Linux wireless modes.
63
 */
64
static int
65
prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
66
{
67
        u32 config = INL_CONFIG_MANUALRUN;
68
        u32 mode, bsstype;
69
 
70
        /* For now, just catch early the Repeater and Secondary modes here */
71
        if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
72
                printk(KERN_DEBUG
73
                       "%s(): Sorry, Repeater mode and Secondary mode "
74
                       "are not yet supported by this driver.\n", __FUNCTION__);
75
                return -EINVAL;
76
        }
77
 
78
        priv->iw_mode = iw_mode;
79
 
80
        switch (iw_mode) {
81
        case IW_MODE_AUTO:
82
                mode = INL_MODE_CLIENT;
83
                bsstype = DOT11_BSSTYPE_ANY;
84
                break;
85
        case IW_MODE_ADHOC:
86
                mode = INL_MODE_CLIENT;
87
                bsstype = DOT11_BSSTYPE_IBSS;
88
                break;
89
        case IW_MODE_INFRA:
90
                mode = INL_MODE_CLIENT;
91
                bsstype = DOT11_BSSTYPE_INFRA;
92
                break;
93
        case IW_MODE_MASTER:
94
                mode = INL_MODE_AP;
95
                bsstype = DOT11_BSSTYPE_INFRA;
96
                break;
97
        case IW_MODE_MONITOR:
98
                mode = INL_MODE_PROMISCUOUS;
99
                bsstype = DOT11_BSSTYPE_ANY;
100
                config |= INL_CONFIG_RXANNEX;
101
                break;
102
        default:
103
                return -EINVAL;
104
        }
105
 
106
        if (init_wds)
107
                config |= INL_CONFIG_WDS;
108
        mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
109
        mgt_set(priv, OID_INL_CONFIG, &config);
110
        mgt_set(priv, OID_INL_MODE, &mode);
111
 
112
        return 0;
113
}
114
 
115
/**
116
 * prism54_mib_init - fill MIB cache with defaults
117
 *
118
 *  this function initializes the struct given as @mib with defaults,
119
 *  of which many are retrieved from the global module parameter
120
 *  variables.
121
 */
122
 
123
void
124
prism54_mib_init(islpci_private *priv)
125
{
126
        u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
127
        struct obj_buffer psm_buffer = {
128
                .size = PSM_BUFFER_SIZE,
129
                .addr = priv->device_psm_buffer
130
        };
131
 
132
        channel = CARD_DEFAULT_CHANNEL;
133
        authen = CARD_DEFAULT_AUTHEN;
134
        wep = CARD_DEFAULT_WEP;
135
        filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
136
        dot1x = CARD_DEFAULT_DOT1X;
137
        mlme = CARD_DEFAULT_MLME_MODE;
138
        conformance = CARD_DEFAULT_CONFORMANCE;
139
        power = 127;
140
        mode = CARD_DEFAULT_IW_MODE;
141
 
142
        mgt_set(priv, DOT11_OID_CHANNEL, &channel);
143
        mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
144
        mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
145
        mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
146
        mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
147
        mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
148
        mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
149
        mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
150
        mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
151
 
152
        /* This sets all of the mode-dependent values */
153
        prism54_mib_mode_helper(priv, mode);
154
}
155
 
156
/* this will be executed outside of atomic context thanks to
157
 * schedule_work(), thus we can as well use sleeping semaphore
158
 * locking */
159
void
160
prism54_update_stats(struct work_struct *work)
161
{
162
        islpci_private *priv = container_of(work, islpci_private, stats_work);
163
        char *data;
164
        int j;
165
        struct obj_bss bss, *bss2;
166
        union oid_res_t r;
167
 
168
        if (down_interruptible(&priv->stats_sem))
169
                return;
170
 
171
/* Noise floor.
172
 * I'm not sure if the unit is dBm.
173
 * Note : If we are not connected, this value seems to be irrelevant. */
174
 
175
        mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
176
        priv->local_iwstatistics.qual.noise = r.u;
177
 
178
/* Get the rssi of the link. To do this we need to retrieve a bss. */
179
 
180
        /* First get the MAC address of the AP we are associated with. */
181
        mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
182
        data = r.ptr;
183
 
184
        /* copy this MAC to the bss */
185
        memcpy(bss.address, data, 6);
186
        kfree(data);
187
 
188
        /* now ask for the corresponding bss */
189
        j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
190
        bss2 = r.ptr;
191
        /* report the rssi and use it to calculate
192
         *  link quality through a signal-noise
193
         *  ratio */
194
        priv->local_iwstatistics.qual.level = bss2->rssi;
195
        priv->local_iwstatistics.qual.qual =
196
            bss2->rssi - priv->iwstatistics.qual.noise;
197
 
198
        kfree(bss2);
199
 
200
        /* report that the stats are new */
201
        priv->local_iwstatistics.qual.updated = 0x7;
202
 
203
/* Rx : unable to decrypt the MPDU */
204
        mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
205
        priv->local_iwstatistics.discard.code = r.u;
206
 
207
/* Tx : Max MAC retries num reached */
208
        mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
209
        priv->local_iwstatistics.discard.retries = r.u;
210
 
211
        up(&priv->stats_sem);
212
 
213
        return;
214
}
215
 
216
struct iw_statistics *
217
prism54_get_wireless_stats(struct net_device *ndev)
218
{
219
        islpci_private *priv = netdev_priv(ndev);
220
 
221
        /* If the stats are being updated return old data */
222
        if (down_trylock(&priv->stats_sem) == 0) {
223
                memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
224
                       sizeof (struct iw_statistics));
225
                /* They won't be marked updated for the next time */
226
                priv->local_iwstatistics.qual.updated = 0;
227
                up(&priv->stats_sem);
228
        } else
229
                priv->iwstatistics.qual.updated = 0;
230
 
231
        /* Update our wireless stats, but do not schedule to often
232
         * (max 1 HZ) */
233
        if ((priv->stats_timestamp == 0) ||
234
            time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
235
                schedule_work(&priv->stats_work);
236
                priv->stats_timestamp = jiffies;
237
        }
238
 
239
        return &priv->iwstatistics;
240
}
241
 
242
static int
243
prism54_commit(struct net_device *ndev, struct iw_request_info *info,
244
               char *cwrq, char *extra)
245
{
246
        islpci_private *priv = netdev_priv(ndev);
247
 
248
        /* simply re-set the last set SSID, this should commit most stuff */
249
 
250
        /* Commit in Monitor mode is not necessary, also setting essid
251
         * in Monitor mode does not make sense and isn't allowed for this
252
         * device's firmware */
253
        if (priv->iw_mode != IW_MODE_MONITOR)
254
                return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
255
        return 0;
256
}
257
 
258
static int
259
prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
260
                 char *cwrq, char *extra)
261
{
262
        islpci_private *priv = netdev_priv(ndev);
263
        char *capabilities;
264
        union oid_res_t r;
265
        int rvalue;
266
 
267
        if (islpci_get_state(priv) < PRV_STATE_INIT) {
268
                strncpy(cwrq, "NOT READY!", IFNAMSIZ);
269
                return 0;
270
        }
271
        rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
272
 
273
        switch (r.u) {
274
        case INL_PHYCAP_5000MHZ:
275
                capabilities = "IEEE 802.11a/b/g";
276
                break;
277
        case INL_PHYCAP_FAA:
278
                capabilities = "IEEE 802.11b/g - FAA Support";
279
                break;
280
        case INL_PHYCAP_2400MHZ:
281
        default:
282
                capabilities = "IEEE 802.11b/g";        /* Default */
283
                break;
284
        }
285
        strncpy(cwrq, capabilities, IFNAMSIZ);
286
        return rvalue;
287
}
288
 
289
static int
290
prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
291
                 struct iw_freq *fwrq, char *extra)
292
{
293
        islpci_private *priv = netdev_priv(ndev);
294
        int rvalue;
295
        u32 c;
296
 
297
        if (fwrq->m < 1000)
298
                /* we have a channel number */
299
                c = fwrq->m;
300
        else
301
                c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
302
 
303
        rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
304
 
305
        /* Call commit handler */
306
        return (rvalue ? rvalue : -EINPROGRESS);
307
}
308
 
309
static int
310
prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
311
                 struct iw_freq *fwrq, char *extra)
312
{
313
        islpci_private *priv = netdev_priv(ndev);
314
        union oid_res_t r;
315
        int rvalue;
316
 
317
        rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
318
        fwrq->i = r.u;
319
        rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r);
320
        fwrq->m = r.u;
321
        fwrq->e = 3;
322
 
323
        return rvalue;
324
}
325
 
326
static int
327
prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
328
                 __u32 * uwrq, char *extra)
329
{
330
        islpci_private *priv = netdev_priv(ndev);
331
        u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
332
 
333
        /* Let's see if the user passed a valid Linux Wireless mode */
334
        if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
335
                printk(KERN_DEBUG
336
                       "%s: %s() You passed a non-valid init_mode.\n",
337
                       priv->ndev->name, __FUNCTION__);
338
                return -EINVAL;
339
        }
340
 
341
        down_write(&priv->mib_sem);
342
 
343
        if (prism54_mib_mode_helper(priv, *uwrq)) {
344
                up_write(&priv->mib_sem);
345
                return -EOPNOTSUPP;
346
        }
347
 
348
        /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
349
         * extended one.
350
         */
351
        if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
352
                mlmeautolevel = DOT11_MLME_INTERMEDIATE;
353
        if (priv->wpa)
354
                mlmeautolevel = DOT11_MLME_EXTENDED;
355
 
356
        mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
357
 
358
        if (mgt_commit(priv)) {
359
                up_write(&priv->mib_sem);
360
                return -EIO;
361
        }
362
        priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
363
            ? priv->monitor_type : ARPHRD_ETHER;
364
        up_write(&priv->mib_sem);
365
 
366
        return 0;
367
}
368
 
369
/* Use mib cache */
370
static int
371
prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
372
                 __u32 * uwrq, char *extra)
373
{
374
        islpci_private *priv = netdev_priv(ndev);
375
 
376
        BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
377
                                                  IW_MODE_MONITOR));
378
        *uwrq = priv->iw_mode;
379
 
380
        return 0;
381
}
382
 
383
/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
384
 * emit data if (sensitivity > rssi - noise) (in dBm).
385
 * prism54_set_sens does not seem to work.
386
 */
387
 
388
static int
389
prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
390
                 struct iw_param *vwrq, char *extra)
391
{
392
        islpci_private *priv = netdev_priv(ndev);
393
        u32 sens;
394
 
395
        /* by default  the card sets this to 20. */
396
        sens = vwrq->disabled ? 20 : vwrq->value;
397
 
398
        return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
399
}
400
 
401
static int
402
prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
403
                 struct iw_param *vwrq, char *extra)
404
{
405
        islpci_private *priv = netdev_priv(ndev);
406
        union oid_res_t r;
407
        int rvalue;
408
 
409
        rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
410
 
411
        vwrq->value = r.u;
412
        vwrq->disabled = (vwrq->value == 0);
413
        vwrq->fixed = 1;
414
 
415
        return rvalue;
416
}
417
 
418
static int
419
prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
420
                  struct iw_point *dwrq, char *extra)
421
{
422
        struct iw_range *range = (struct iw_range *) extra;
423
        islpci_private *priv = netdev_priv(ndev);
424
        u8 *data;
425
        int i, m, rvalue;
426
        struct obj_frequencies *freq;
427
        union oid_res_t r;
428
 
429
        memset(range, 0, sizeof (struct iw_range));
430
        dwrq->length = sizeof (struct iw_range);
431
 
432
        /* set the wireless extension version number */
433
        range->we_version_source = SUPPORTED_WIRELESS_EXT;
434
        range->we_version_compiled = WIRELESS_EXT;
435
 
436
        /* Now the encoding capabilities */
437
        range->num_encoding_sizes = 3;
438
        /* 64(40) bits WEP */
439
        range->encoding_size[0] = 5;
440
        /* 128(104) bits WEP */
441
        range->encoding_size[1] = 13;
442
        /* 256 bits for WPA-PSK */
443
        range->encoding_size[2] = 32;
444
        /* 4 keys are allowed */
445
        range->max_encoding_tokens = 4;
446
 
447
        /* we don't know the quality range... */
448
        range->max_qual.level = 0;
449
        range->max_qual.noise = 0;
450
        range->max_qual.qual = 0;
451
        /* these value describe an average quality. Needs more tweaking... */
452
        range->avg_qual.level = -80;    /* -80 dBm */
453
        range->avg_qual.noise = 0;       /* don't know what to put here */
454
        range->avg_qual.qual = 0;
455
 
456
        range->sensitivity = 200;
457
 
458
        /* retry limit capabilities */
459
        range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
460
        range->retry_flags = IW_RETRY_LIMIT;
461
        range->r_time_flags = IW_RETRY_LIFETIME;
462
 
463
        /* I don't know the range. Put stupid things here */
464
        range->min_retry = 1;
465
        range->max_retry = 65535;
466
        range->min_r_time = 1024;
467
        range->max_r_time = 65535 * 1024;
468
 
469
        /* txpower is supported in dBm's */
470
        range->txpower_capa = IW_TXPOW_DBM;
471
 
472
        /* Event capability (kernel + driver) */
473
        range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
474
        IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
475
        IW_EVENT_CAPA_MASK(SIOCGIWAP));
476
        range->event_capa[1] = IW_EVENT_CAPA_K_1;
477
        range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
478
 
479
        range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
480
                IW_ENC_CAPA_CIPHER_TKIP;
481
 
482
        if (islpci_get_state(priv) < PRV_STATE_INIT)
483
                return 0;
484
 
485
        /* Request the device for the supported frequencies
486
         * not really relevant since some devices will report the 5 GHz band
487
         * frequencies even if they don't support them.
488
         */
489
        rvalue =
490
            mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
491
        freq = r.ptr;
492
 
493
        range->num_channels = freq->nr;
494
        range->num_frequency = freq->nr;
495
 
496
        m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
497
        for (i = 0; i < m; i++) {
498
                range->freq[i].m = freq->mhz[i];
499
                range->freq[i].e = 6;
500
                range->freq[i].i = channel_of_freq(freq->mhz[i]);
501
        }
502
        kfree(freq);
503
 
504
        rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
505
        data = r.ptr;
506
 
507
        /* We got an array of char. It is NULL terminated. */
508
        i = 0;
509
        while ((i < IW_MAX_BITRATES) && (*data != 0)) {
510
                /*       the result must be in bps. The card gives us 500Kbps */
511
                range->bitrate[i] = *data * 500000;
512
                i++;
513
                data++;
514
        }
515
        range->num_bitrates = i;
516
        kfree(r.ptr);
517
 
518
        return rvalue;
519
}
520
 
521
/* Set AP address*/
522
 
523
static int
524
prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
525
                struct sockaddr *awrq, char *extra)
526
{
527
        islpci_private *priv = netdev_priv(ndev);
528
        char bssid[6];
529
        int rvalue;
530
 
531
        if (awrq->sa_family != ARPHRD_ETHER)
532
                return -EINVAL;
533
 
534
        /* prepare the structure for the set object */
535
        memcpy(&bssid[0], awrq->sa_data, 6);
536
 
537
        /* set the bssid -- does this make sense when in AP mode? */
538
        rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
539
 
540
        return (rvalue ? rvalue : -EINPROGRESS);        /* Call commit handler */
541
}
542
 
543
/* get AP address*/
544
 
545
static int
546
prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
547
                struct sockaddr *awrq, char *extra)
548
{
549
        islpci_private *priv = netdev_priv(ndev);
550
        union oid_res_t r;
551
        int rvalue;
552
 
553
        rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
554
        memcpy(awrq->sa_data, r.ptr, 6);
555
        awrq->sa_family = ARPHRD_ETHER;
556
        kfree(r.ptr);
557
 
558
        return rvalue;
559
}
560
 
561
static int
562
prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
563
                 struct iw_param *vwrq, char *extra)
564
{
565
        /* hehe the device does this automagicaly */
566
        return 0;
567
}
568
 
569
/* a little helper that will translate our data into a card independent
570
 * format that the Wireless Tools will understand. This was inspired by
571
 * the "Aironet driver for 4500 and 4800 series cards" (GPL)
572
 */
573
 
574
static char *
575
prism54_translate_bss(struct net_device *ndev, char *current_ev,
576
                      char *end_buf, struct obj_bss *bss, char noise)
577
{
578
        struct iw_event iwe;    /* Temporary buffer */
579
        short cap;
580
        islpci_private *priv = netdev_priv(ndev);
581
        u8 wpa_ie[MAX_WPA_IE_LEN];
582
        size_t wpa_ie_len;
583
 
584
        /* The first entry must be the MAC address */
585
        memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
586
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
587
        iwe.cmd = SIOCGIWAP;
588
        current_ev =
589
            iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
590
 
591
        /* The following entries will be displayed in the same order we give them */
592
 
593
        /* The ESSID. */
594
        iwe.u.data.length = bss->ssid.length;
595
        iwe.u.data.flags = 1;
596
        iwe.cmd = SIOCGIWESSID;
597
        current_ev = iwe_stream_add_point(current_ev, end_buf,
598
                                          &iwe, bss->ssid.octets);
599
 
600
        /* Capabilities */
601
#define CAP_ESS 0x01
602
#define CAP_IBSS 0x02
603
#define CAP_CRYPT 0x10
604
 
605
        /* Mode */
606
        cap = bss->capinfo;
607
        iwe.u.mode = 0;
608
        if (cap & CAP_ESS)
609
                iwe.u.mode = IW_MODE_MASTER;
610
        else if (cap & CAP_IBSS)
611
                iwe.u.mode = IW_MODE_ADHOC;
612
        iwe.cmd = SIOCGIWMODE;
613
        if (iwe.u.mode)
614
                current_ev =
615
                    iwe_stream_add_event(current_ev, end_buf, &iwe,
616
                                         IW_EV_UINT_LEN);
617
 
618
        /* Encryption capability */
619
        if (cap & CAP_CRYPT)
620
                iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
621
        else
622
                iwe.u.data.flags = IW_ENCODE_DISABLED;
623
        iwe.u.data.length = 0;
624
        iwe.cmd = SIOCGIWENCODE;
625
        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
626
 
627
        /* Add frequency. (short) bss->channel is the frequency in MHz */
628
        iwe.u.freq.m = bss->channel;
629
        iwe.u.freq.e = 6;
630
        iwe.cmd = SIOCGIWFREQ;
631
        current_ev =
632
            iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
633
 
634
        /* Add quality statistics */
635
        iwe.u.qual.level = bss->rssi;
636
        iwe.u.qual.noise = noise;
637
        /* do a simple SNR for quality */
638
        iwe.u.qual.qual = bss->rssi - noise;
639
        iwe.cmd = IWEVQUAL;
640
        current_ev =
641
            iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
642
 
643
        /* Add WPA/RSN Information Element, if any */
644
        wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
645
        if (wpa_ie_len > 0) {
646
                iwe.cmd = IWEVGENIE;
647
                iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
648
                current_ev = iwe_stream_add_point(current_ev, end_buf,
649
                                &iwe, wpa_ie);
650
        }
651
        /* Do the bitrates */
652
        {
653
                char *  current_val = current_ev + IW_EV_LCP_LEN;
654
                int i;
655
                int mask;
656
 
657
                iwe.cmd = SIOCGIWRATE;
658
                /* Those two flags are ignored... */
659
                iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
660
 
661
                /* Parse the bitmask */
662
                mask = 0x1;
663
                for(i = 0; i < sizeof(scan_rate_list); i++) {
664
                        if(bss->rates & mask) {
665
                                iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
666
                                current_val = iwe_stream_add_value(current_ev, current_val,
667
                                                                   end_buf, &iwe,
668
                                                                   IW_EV_PARAM_LEN);
669
                        }
670
                        mask <<= 1;
671
                }
672
                /* Check if we added any event */
673
                if ((current_val - current_ev) > IW_EV_LCP_LEN)
674
                        current_ev = current_val;
675
        }
676
 
677
        return current_ev;
678
}
679
 
680
static int
681
prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
682
                 struct iw_point *dwrq, char *extra)
683
{
684
        islpci_private *priv = netdev_priv(ndev);
685
        int i, rvalue;
686
        struct obj_bsslist *bsslist;
687
        u32 noise = 0;
688
        char *current_ev = extra;
689
        union oid_res_t r;
690
 
691
        if (islpci_get_state(priv) < PRV_STATE_INIT) {
692
                /* device is not ready, fail gently */
693
                dwrq->length = 0;
694
                return 0;
695
        }
696
 
697
        /* first get the noise value. We will use it to report the link quality */
698
        rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
699
        noise = r.u;
700
 
701
        /* Ask the device for a list of known bss.
702
        * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
703
        * The new API, using SIOCGIWSCAN, is only limited by the buffer size.
704
        * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
705
        * Starting with WE-17, the buffer can be as big as needed.
706
        * But the device won't repport anything if you change the value
707
        * of IWMAX_BSS=24. */
708
 
709
        rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
710
        bsslist = r.ptr;
711
 
712
        /* ok now, scan the list and translate its info */
713
        for (i = 0; i < (int) bsslist->nr; i++) {
714
                current_ev = prism54_translate_bss(ndev, current_ev,
715
                                                   extra + dwrq->length,
716
                                                   &(bsslist->bsslist[i]),
717
                                                   noise);
718
 
719
                /* Check if there is space for one more entry */
720
                if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
721
                        /* Ask user space to try again with a bigger buffer */
722
                        rvalue = -E2BIG;
723
                        break;
724
                }
725
        }
726
 
727
        kfree(bsslist);
728
        dwrq->length = (current_ev - extra);
729
        dwrq->flags = 0; /* todo */
730
 
731
        return rvalue;
732
}
733
 
734
static int
735
prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
736
                  struct iw_point *dwrq, char *extra)
737
{
738
        islpci_private *priv = netdev_priv(ndev);
739
        struct obj_ssid essid;
740
 
741
        memset(essid.octets, 0, 33);
742
 
743
        /* Check if we were asked for `any' */
744
        if (dwrq->flags && dwrq->length) {
745
                if (dwrq->length > 32)
746
                        return -E2BIG;
747
                essid.length = dwrq->length;
748
                memcpy(essid.octets, extra, dwrq->length);
749
        } else
750
                essid.length = 0;
751
 
752
        if (priv->iw_mode != IW_MODE_MONITOR)
753
                return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
754
 
755
        /* If in monitor mode, just save to mib */
756
        mgt_set(priv, DOT11_OID_SSID, &essid);
757
        return 0;
758
 
759
}
760
 
761
static int
762
prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
763
                  struct iw_point *dwrq, char *extra)
764
{
765
        islpci_private *priv = netdev_priv(ndev);
766
        struct obj_ssid *essid;
767
        union oid_res_t r;
768
        int rvalue;
769
 
770
        rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
771
        essid = r.ptr;
772
 
773
        if (essid->length) {
774
                dwrq->flags = 1;        /* set ESSID to ON for Wireless Extensions */
775
                /* if it is too big, trunk it */
776
                dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length);
777
        } else {
778
                dwrq->flags = 0;
779
                dwrq->length = 0;
780
        }
781
        essid->octets[essid->length] = '\0';
782
        memcpy(extra, essid->octets, dwrq->length);
783
        kfree(essid);
784
 
785
        return rvalue;
786
}
787
 
788
/* Provides no functionality, just completes the ioctl. In essence this is a
789
 * just a cosmetic ioctl.
790
 */
791
static int
792
prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
793
                 struct iw_point *dwrq, char *extra)
794
{
795
        islpci_private *priv = netdev_priv(ndev);
796
 
797
        if (dwrq->length > IW_ESSID_MAX_SIZE)
798
                return -E2BIG;
799
 
800
        down_write(&priv->mib_sem);
801
        memset(priv->nickname, 0, sizeof (priv->nickname));
802
        memcpy(priv->nickname, extra, dwrq->length);
803
        up_write(&priv->mib_sem);
804
 
805
        return 0;
806
}
807
 
808
static int
809
prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
810
                 struct iw_point *dwrq, char *extra)
811
{
812
        islpci_private *priv = netdev_priv(ndev);
813
 
814
        dwrq->length = 0;
815
 
816
        down_read(&priv->mib_sem);
817
        dwrq->length = strlen(priv->nickname);
818
        memcpy(extra, priv->nickname, dwrq->length);
819
        up_read(&priv->mib_sem);
820
 
821
        return 0;
822
}
823
 
824
/* Set the allowed Bitrates */
825
 
826
static int
827
prism54_set_rate(struct net_device *ndev,
828
                 struct iw_request_info *info,
829
                 struct iw_param *vwrq, char *extra)
830
{
831
 
832
        islpci_private *priv = netdev_priv(ndev);
833
        u32 rate, profile;
834
        char *data;
835
        int ret, i;
836
        union oid_res_t r;
837
 
838
        if (vwrq->value == -1) {
839
                /* auto mode. No limit. */
840
                profile = 1;
841
                return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
842
        }
843
 
844
        ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
845
        if (ret) {
846
                kfree(r.ptr);
847
                return ret;
848
        }
849
 
850
        rate = (u32) (vwrq->value / 500000);
851
        data = r.ptr;
852
        i = 0;
853
 
854
        while (data[i]) {
855
                if (rate && (data[i] == rate)) {
856
                        break;
857
                }
858
                if (vwrq->value == i) {
859
                        break;
860
                }
861
                data[i] |= 0x80;
862
                i++;
863
        }
864
 
865
        if (!data[i]) {
866
                kfree(r.ptr);
867
                return -EINVAL;
868
        }
869
 
870
        data[i] |= 0x80;
871
        data[i + 1] = 0;
872
 
873
        /* Now, check if we want a fixed or auto value */
874
        if (vwrq->fixed) {
875
                data[0] = data[i];
876
                data[1] = 0;
877
        }
878
 
879
/*
880
        i = 0;
881
        printk("prism54 rate: ");
882
        while(data[i]) {
883
                printk("%u ", data[i]);
884
                i++;
885
        }
886
        printk("0\n");
887
*/
888
        profile = -1;
889
        ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
890
        ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
891
        ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
892
 
893
        kfree(r.ptr);
894
 
895
        return ret;
896
}
897
 
898
/* Get the current bit rate */
899
static int
900
prism54_get_rate(struct net_device *ndev,
901
                 struct iw_request_info *info,
902
                 struct iw_param *vwrq, char *extra)
903
{
904
        islpci_private *priv = netdev_priv(ndev);
905
        int rvalue;
906
        char *data;
907
        union oid_res_t r;
908
 
909
        /* Get the current bit rate */
910
        if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
911
                return rvalue;
912
        vwrq->value = r.u * 500000;
913
 
914
        /* request the device for the enabled rates */
915
        rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r);
916
        if (rvalue) {
917
                kfree(r.ptr);
918
                return rvalue;
919
        }
920
        data = r.ptr;
921
        vwrq->fixed = (data[0] != 0) && (data[1] == 0);
922
        kfree(r.ptr);
923
 
924
        return 0;
925
}
926
 
927
static int
928
prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
929
                struct iw_param *vwrq, char *extra)
930
{
931
        islpci_private *priv = netdev_priv(ndev);
932
 
933
        return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
934
}
935
 
936
static int
937
prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
938
                struct iw_param *vwrq, char *extra)
939
{
940
        islpci_private *priv = netdev_priv(ndev);
941
        union oid_res_t r;
942
        int rvalue;
943
 
944
        /* get the rts threshold */
945
        rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
946
        vwrq->value = r.u;
947
 
948
        return rvalue;
949
}
950
 
951
static int
952
prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
953
                 struct iw_param *vwrq, char *extra)
954
{
955
        islpci_private *priv = netdev_priv(ndev);
956
 
957
        return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
958
}
959
 
960
static int
961
prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
962
                 struct iw_param *vwrq, char *extra)
963
{
964
        islpci_private *priv = netdev_priv(ndev);
965
        union oid_res_t r;
966
        int rvalue;
967
 
968
        rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
969
        vwrq->value = r.u;
970
 
971
        return rvalue;
972
}
973
 
974
/* Here we have (min,max) = max retries for (small frames, big frames). Where
975
 * big frame <=>  bigger than the rts threshold
976
 * small frame <=>  smaller than the rts threshold
977
 * This is not really the behavior expected by the wireless tool but it seems
978
 * to be a common behavior in other drivers.
979
 */
980
 
981
static int
982
prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
983
                  struct iw_param *vwrq, char *extra)
984
{
985
        islpci_private *priv = netdev_priv(ndev);
986
        u32 slimit = 0, llimit = 0;       /* short and long limit */
987
        u32 lifetime = 0;
988
        int rvalue = 0;
989
 
990
        if (vwrq->disabled)
991
                /* we cannot disable this feature */
992
                return -EINVAL;
993
 
994
        if (vwrq->flags & IW_RETRY_LIMIT) {
995
                if (vwrq->flags & IW_RETRY_SHORT)
996
                        slimit = vwrq->value;
997
                else if (vwrq->flags & IW_RETRY_LONG)
998
                        llimit = vwrq->value;
999
                else {
1000
                        /* we are asked to set both */
1001
                        slimit = vwrq->value;
1002
                        llimit = vwrq->value;
1003
                }
1004
        }
1005
        if (vwrq->flags & IW_RETRY_LIFETIME)
1006
                /* Wireless tools use us unit while the device uses 1024 us unit */
1007
                lifetime = vwrq->value / 1024;
1008
 
1009
        /* now set what is requested */
1010
        if (slimit)
1011
                rvalue =
1012
                    mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
1013
        if (llimit)
1014
                rvalue |=
1015
                    mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
1016
        if (lifetime)
1017
                rvalue |=
1018
                    mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
1019
                                    &lifetime);
1020
        return rvalue;
1021
}
1022
 
1023
static int
1024
prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
1025
                  struct iw_param *vwrq, char *extra)
1026
{
1027
        islpci_private *priv = netdev_priv(ndev);
1028
        union oid_res_t r;
1029
        int rvalue = 0;
1030
        vwrq->disabled = 0;      /* It cannot be disabled */
1031
 
1032
        if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1033
                /* we are asked for the life time */
1034
                rvalue =
1035
                    mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
1036
                vwrq->value = r.u * 1024;
1037
                vwrq->flags = IW_RETRY_LIFETIME;
1038
        } else if ((vwrq->flags & IW_RETRY_LONG)) {
1039
                /* we are asked for the long retry limit */
1040
                rvalue |=
1041
                    mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
1042
                vwrq->value = r.u;
1043
                vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1044
        } else {
1045
                /* default. get the  short retry limit */
1046
                rvalue |=
1047
                    mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
1048
                vwrq->value = r.u;
1049
                vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
1050
        }
1051
 
1052
        return rvalue;
1053
}
1054
 
1055
static int
1056
prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
1057
                   struct iw_point *dwrq, char *extra)
1058
{
1059
        islpci_private *priv = netdev_priv(ndev);
1060
        int rvalue = 0, force = 0;
1061
        int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
1062
        union oid_res_t r;
1063
 
1064
        /* with the new API, it's impossible to get a NULL pointer.
1065
         * New version of iwconfig set the IW_ENCODE_NOKEY flag
1066
         * when no key is given, but older versions don't. */
1067
 
1068
        if (dwrq->length > 0) {
1069
                /* we have a key to set */
1070
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1071
                int current_index;
1072
                struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
1073
 
1074
                /* get the current key index */
1075
                rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1076
                current_index = r.u;
1077
                /* Verify that the key is not marked as invalid */
1078
                if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
1079
                        if (dwrq->length > KEY_SIZE_TKIP) {
1080
                                /* User-provided key data too big */
1081
                                return -EINVAL;
1082
                        }
1083
                        if (dwrq->length > KEY_SIZE_WEP104) {
1084
                                /* WPA-PSK TKIP */
1085
                                key.type = DOT11_PRIV_TKIP;
1086
                                key.length = KEY_SIZE_TKIP;
1087
                        } else if (dwrq->length > KEY_SIZE_WEP40) {
1088
                                /* WEP 104/128 */
1089
                                key.length = KEY_SIZE_WEP104;
1090
                        } else {
1091
                                /* WEP 40/64 */
1092
                                key.length = KEY_SIZE_WEP40;
1093
                        }
1094
                        memset(key.key, 0, sizeof (key.key));
1095
                        memcpy(key.key, extra, dwrq->length);
1096
 
1097
                        if ((index < 0) || (index > 3))
1098
                                /* no index provided use the current one */
1099
                                index = current_index;
1100
 
1101
                        /* now send the key to the card  */
1102
                        rvalue |=
1103
                            mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
1104
                                            &key);
1105
                }
1106
                /*
1107
                 * If a valid key is set, encryption should be enabled
1108
                 * (user may turn it off later).
1109
                 * This is also how "iwconfig ethX key on" works
1110
                 */
1111
                if ((index == current_index) && (key.length > 0))
1112
                        force = 1;
1113
        } else {
1114
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1115
                if ((index >= 0) && (index <= 3)) {
1116
                        /* we want to set the key index */
1117
                        rvalue |=
1118
                            mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
1119
                                            &index);
1120
                } else {
1121
                        if (!dwrq->flags & IW_ENCODE_MODE) {
1122
                                /* we cannot do anything. Complain. */
1123
                                return -EINVAL;
1124
                        }
1125
                }
1126
        }
1127
        /* now read the flags */
1128
        if (dwrq->flags & IW_ENCODE_DISABLED) {
1129
                /* Encoding disabled,
1130
                 * authen = DOT11_AUTH_OS;
1131
                 * invoke = 0;
1132
                 * exunencrypt = 0; */
1133
        }
1134
        if (dwrq->flags & IW_ENCODE_OPEN)
1135
                /* Encode but accept non-encoded packets. No auth */
1136
                invoke = 1;
1137
        if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
1138
                /* Refuse non-encoded packets. Auth */
1139
                authen = DOT11_AUTH_BOTH;
1140
                invoke = 1;
1141
                exunencrypt = 1;
1142
        }
1143
        /* do the change if requested  */
1144
        if ((dwrq->flags & IW_ENCODE_MODE) || force) {
1145
                rvalue |=
1146
                    mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
1147
                rvalue |=
1148
                    mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
1149
                rvalue |=
1150
                    mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
1151
                                    &exunencrypt);
1152
        }
1153
        return rvalue;
1154
}
1155
 
1156
static int
1157
prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
1158
                   struct iw_point *dwrq, char *extra)
1159
{
1160
        islpci_private *priv = netdev_priv(ndev);
1161
        struct obj_key *key;
1162
        u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1163
        u32 authen = 0, invoke = 0, exunencrypt = 0;
1164
        int rvalue;
1165
        union oid_res_t r;
1166
 
1167
        /* first get the flags */
1168
        rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1169
        authen = r.u;
1170
        rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1171
        invoke = r.u;
1172
        rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1173
        exunencrypt = r.u;
1174
 
1175
        if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
1176
                dwrq->flags = IW_ENCODE_RESTRICTED;
1177
        else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
1178
                if (invoke)
1179
                        dwrq->flags = IW_ENCODE_OPEN;
1180
                else
1181
                        dwrq->flags = IW_ENCODE_DISABLED;
1182
        } else
1183
                /* The card should not work in this state */
1184
                dwrq->flags = 0;
1185
 
1186
        /* get the current device key index */
1187
        rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1188
        devindex = r.u;
1189
        /* Now get the key, return it */
1190
        if ((index < 0) || (index > 3))
1191
                /* no index provided, use the current one */
1192
                index = devindex;
1193
        rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
1194
        key = r.ptr;
1195
        dwrq->length = key->length;
1196
        memcpy(extra, key->key, dwrq->length);
1197
        kfree(key);
1198
        /* return the used key index */
1199
        dwrq->flags |= devindex + 1;
1200
 
1201
        return rvalue;
1202
}
1203
 
1204
static int
1205
prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
1206
                    struct iw_param *vwrq, char *extra)
1207
{
1208
        islpci_private *priv = netdev_priv(ndev);
1209
        union oid_res_t r;
1210
        int rvalue;
1211
 
1212
        rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
1213
        /* intersil firmware operates in 0.25 dBm (1/4 dBm) */
1214
        vwrq->value = (s32) r.u / 4;
1215
        vwrq->fixed = 1;
1216
        /* radio is not turned of
1217
         * btw: how is possible to turn off only the radio
1218
         */
1219
        vwrq->disabled = 0;
1220
 
1221
        return rvalue;
1222
}
1223
 
1224
static int
1225
prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
1226
                    struct iw_param *vwrq, char *extra)
1227
{
1228
        islpci_private *priv = netdev_priv(ndev);
1229
        s32 u = vwrq->value;
1230
 
1231
        /* intersil firmware operates in 0.25 dBm (1/4) */
1232
        u *= 4;
1233
        if (vwrq->disabled) {
1234
                /* don't know how to disable radio */
1235
                printk(KERN_DEBUG
1236
                       "%s: %s() disabling radio is not yet supported.\n",
1237
                       priv->ndev->name, __FUNCTION__);
1238
                return -ENOTSUPP;
1239
        } else if (vwrq->fixed)
1240
                /* currently only fixed value is supported */
1241
                return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
1242
        else {
1243
                printk(KERN_DEBUG
1244
                       "%s: %s() auto power will be implemented later.\n",
1245
                       priv->ndev->name, __FUNCTION__);
1246
                return -ENOTSUPP;
1247
        }
1248
}
1249
 
1250
static int prism54_set_genie(struct net_device *ndev,
1251
                             struct iw_request_info *info,
1252
                             struct iw_point *data, char *extra)
1253
{
1254
        islpci_private *priv = netdev_priv(ndev);
1255
        int alen, ret = 0;
1256
        struct obj_attachment *attach;
1257
 
1258
        if (data->length > MAX_WPA_IE_LEN ||
1259
            (data->length && extra == NULL))
1260
                return -EINVAL;
1261
 
1262
        memcpy(priv->wpa_ie, extra, data->length);
1263
        priv->wpa_ie_len = data->length;
1264
 
1265
        alen = sizeof(*attach) + priv->wpa_ie_len;
1266
        attach = kzalloc(alen, GFP_KERNEL);
1267
        if (attach == NULL)
1268
                return -ENOMEM;
1269
 
1270
#define WLAN_FC_TYPE_MGMT 0
1271
#define WLAN_FC_STYPE_ASSOC_REQ 0
1272
#define WLAN_FC_STYPE_REASSOC_REQ 2
1273
 
1274
        /* Note: endianness is covered by mgt_set_varlen */
1275
        attach->type = (WLAN_FC_TYPE_MGMT << 2) |
1276
               (WLAN_FC_STYPE_ASSOC_REQ << 4);
1277
        attach->id = -1;
1278
        attach->size = priv->wpa_ie_len;
1279
        memcpy(attach->data, extra, priv->wpa_ie_len);
1280
 
1281
        ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
1282
                priv->wpa_ie_len);
1283
        if (ret == 0) {
1284
                attach->type = (WLAN_FC_TYPE_MGMT << 2) |
1285
                        (WLAN_FC_STYPE_REASSOC_REQ << 4);
1286
 
1287
                ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
1288
                        priv->wpa_ie_len);
1289
                if (ret == 0)
1290
                        printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
1291
                                ndev->name);
1292
        }
1293
 
1294
        kfree(attach);
1295
        return ret;
1296
}
1297
 
1298
 
1299
static int prism54_get_genie(struct net_device *ndev,
1300
                             struct iw_request_info *info,
1301
                             struct iw_point *data, char *extra)
1302
{
1303
        islpci_private *priv = netdev_priv(ndev);
1304
        int len = priv->wpa_ie_len;
1305
 
1306
        if (len <= 0) {
1307
                data->length = 0;
1308
                return 0;
1309
        }
1310
 
1311
        if (data->length < len)
1312
                return -E2BIG;
1313
 
1314
        data->length = len;
1315
        memcpy(extra, priv->wpa_ie, len);
1316
 
1317
        return 0;
1318
}
1319
 
1320
static int prism54_set_auth(struct net_device *ndev,
1321
                               struct iw_request_info *info,
1322
                               union iwreq_data *wrqu, char *extra)
1323
{
1324
        islpci_private *priv = netdev_priv(ndev);
1325
        struct iw_param *param = &wrqu->param;
1326
        u32 mlmelevel = 0, authen = 0, dot1x = 0;
1327
        u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
1328
        u32 old_wpa;
1329
        int ret = 0;
1330
        union oid_res_t r;
1331
 
1332
        if (islpci_get_state(priv) < PRV_STATE_INIT)
1333
                return 0;
1334
 
1335
        /* first get the flags */
1336
        down_write(&priv->mib_sem);
1337
        wpa = old_wpa = priv->wpa;
1338
        up_write(&priv->mib_sem);
1339
        ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1340
        authen = r.u;
1341
        ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1342
        privinvoked = r.u;
1343
        ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1344
        exunencrypt = r.u;
1345
        ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
1346
        dot1x = r.u;
1347
        ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
1348
        mlmelevel = r.u;
1349
 
1350
        if (ret < 0)
1351
                goto out;
1352
 
1353
        switch (param->flags & IW_AUTH_INDEX) {
1354
        case IW_AUTH_CIPHER_PAIRWISE:
1355
        case IW_AUTH_CIPHER_GROUP:
1356
        case IW_AUTH_KEY_MGMT:
1357
                break;
1358
 
1359
        case IW_AUTH_WPA_ENABLED:
1360
                /* Do the same thing as IW_AUTH_WPA_VERSION */
1361
                if (param->value) {
1362
                        wpa = 1;
1363
                        privinvoked = 1; /* For privacy invoked */
1364
                        exunencrypt = 1; /* Filter out all unencrypted frames */
1365
                        dot1x = 0x01; /* To enable eap filter */
1366
                        mlmelevel = DOT11_MLME_EXTENDED;
1367
                        authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
1368
                } else {
1369
                        wpa = 0;
1370
                        privinvoked = 0;
1371
                        exunencrypt = 0; /* Do not filter un-encrypted data */
1372
                        dot1x = 0;
1373
                        mlmelevel = DOT11_MLME_AUTO;
1374
                }
1375
                break;
1376
 
1377
        case IW_AUTH_WPA_VERSION:
1378
                if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
1379
                        wpa = 0;
1380
                        privinvoked = 0;
1381
                        exunencrypt = 0; /* Do not filter un-encrypted data */
1382
                        dot1x = 0;
1383
                        mlmelevel = DOT11_MLME_AUTO;
1384
                } else {
1385
                        if (param->value & IW_AUTH_WPA_VERSION_WPA)
1386
                                wpa = 1;
1387
                        else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
1388
                                wpa = 2;
1389
                        privinvoked = 1; /* For privacy invoked */
1390
                        exunencrypt = 1; /* Filter out all unencrypted frames */
1391
                        dot1x = 0x01; /* To enable eap filter */
1392
                        mlmelevel = DOT11_MLME_EXTENDED;
1393
                        authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
1394
                }
1395
                break;
1396
 
1397
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1398
                /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL;
1399
                 * turn off dot1x when allowing receipt of unencrypted EAPOL
1400
                 * frames, turn on dot1x when receipt should be disallowed
1401
                 */
1402
                dot1x = param->value ? 0 : 0x01;
1403
                break;
1404
 
1405
        case IW_AUTH_PRIVACY_INVOKED:
1406
                privinvoked = param->value ? 1 : 0;
1407
                break;
1408
 
1409
        case IW_AUTH_DROP_UNENCRYPTED:
1410
                exunencrypt = param->value ? 1 : 0;
1411
                break;
1412
 
1413
        case IW_AUTH_80211_AUTH_ALG:
1414
                if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1415
                        /* Only WEP uses _SK and _BOTH */
1416
                        if (wpa > 0) {
1417
                                ret = -EINVAL;
1418
                                goto out;
1419
                        }
1420
                        authen = DOT11_AUTH_SK;
1421
                } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1422
                        authen = DOT11_AUTH_OS;
1423
                } else {
1424
                        ret = -EINVAL;
1425
                        goto out;
1426
                }
1427
                break;
1428
 
1429
        default:
1430
                return -EOPNOTSUPP;
1431
        }
1432
 
1433
        /* Set all the values */
1434
        down_write(&priv->mib_sem);
1435
        priv->wpa = wpa;
1436
        up_write(&priv->mib_sem);
1437
        mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
1438
        mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
1439
        mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
1440
        mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
1441
        mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
1442
 
1443
out:
1444
        return ret;
1445
}
1446
 
1447
static int prism54_get_auth(struct net_device *ndev,
1448
                            struct iw_request_info *info,
1449
                            union iwreq_data *wrqu, char *extra)
1450
{
1451
        islpci_private *priv = netdev_priv(ndev);
1452
        struct iw_param *param = &wrqu->param;
1453
        u32 wpa = 0;
1454
        int ret = 0;
1455
        union oid_res_t r;
1456
 
1457
        if (islpci_get_state(priv) < PRV_STATE_INIT)
1458
                return 0;
1459
 
1460
        /* first get the flags */
1461
        down_write(&priv->mib_sem);
1462
        wpa = priv->wpa;
1463
        up_write(&priv->mib_sem);
1464
 
1465
        switch (param->flags & IW_AUTH_INDEX) {
1466
        case IW_AUTH_CIPHER_PAIRWISE:
1467
        case IW_AUTH_CIPHER_GROUP:
1468
        case IW_AUTH_KEY_MGMT:
1469
                /*
1470
                 * wpa_supplicant will control these internally
1471
                 */
1472
                ret = -EOPNOTSUPP;
1473
                break;
1474
 
1475
        case IW_AUTH_WPA_VERSION:
1476
                switch (wpa) {
1477
                case 1:
1478
                        param->value = IW_AUTH_WPA_VERSION_WPA;
1479
                        break;
1480
                case 2:
1481
                        param->value = IW_AUTH_WPA_VERSION_WPA2;
1482
                        break;
1483
                case 0:
1484
                default:
1485
                        param->value = IW_AUTH_WPA_VERSION_DISABLED;
1486
                        break;
1487
                }
1488
                break;
1489
 
1490
        case IW_AUTH_DROP_UNENCRYPTED:
1491
                ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1492
                if (ret >= 0)
1493
                        param->value = r.u > 0 ? 1 : 0;
1494
                break;
1495
 
1496
        case IW_AUTH_80211_AUTH_ALG:
1497
                ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1498
                if (ret >= 0) {
1499
                        switch (r.u) {
1500
                        case DOT11_AUTH_OS:
1501
                                param->value = IW_AUTH_ALG_OPEN_SYSTEM;
1502
                                break;
1503
                        case DOT11_AUTH_BOTH:
1504
                        case DOT11_AUTH_SK:
1505
                                param->value = IW_AUTH_ALG_SHARED_KEY;
1506
                        case DOT11_AUTH_NONE:
1507
                        default:
1508
                                param->value = 0;
1509
                                break;
1510
                        }
1511
                }
1512
                break;
1513
 
1514
        case IW_AUTH_WPA_ENABLED:
1515
                param->value = wpa > 0 ? 1 : 0;
1516
                break;
1517
 
1518
        case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1519
                ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
1520
                if (ret >= 0)
1521
                        param->value = r.u > 0 ? 1 : 0;
1522
                break;
1523
 
1524
        case IW_AUTH_PRIVACY_INVOKED:
1525
                ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1526
                if (ret >= 0)
1527
                        param->value = r.u > 0 ? 1 : 0;
1528
                break;
1529
 
1530
        default:
1531
                return -EOPNOTSUPP;
1532
        }
1533
        return ret;
1534
}
1535
 
1536
static int prism54_set_encodeext(struct net_device *ndev,
1537
                                 struct iw_request_info *info,
1538
                                 union iwreq_data *wrqu,
1539
                                 char *extra)
1540
{
1541
        islpci_private *priv = netdev_priv(ndev);
1542
        struct iw_point *encoding = &wrqu->encoding;
1543
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1544
        int idx, alg = ext->alg, set_key = 1;
1545
        union oid_res_t r;
1546
        int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
1547
        int ret = 0;
1548
 
1549
        if (islpci_get_state(priv) < PRV_STATE_INIT)
1550
                return 0;
1551
 
1552
        /* Determine and validate the key index */
1553
        idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
1554
        if (idx) {
1555
                if (idx < 0 || idx > 3)
1556
                        return -EINVAL;
1557
        } else {
1558
                ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1559
                if (ret < 0)
1560
                        goto out;
1561
                idx = r.u;
1562
        }
1563
 
1564
        if (encoding->flags & IW_ENCODE_DISABLED)
1565
                alg = IW_ENCODE_ALG_NONE;
1566
 
1567
        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1568
                /* Only set transmit key index here, actual
1569
                 * key is set below if needed.
1570
                 */
1571
                ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
1572
                set_key = ext->key_len > 0 ? 1 : 0;
1573
        }
1574
 
1575
        if (set_key) {
1576
                struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
1577
                switch (alg) {
1578
                case IW_ENCODE_ALG_NONE:
1579
                        break;
1580
                case IW_ENCODE_ALG_WEP:
1581
                        if (ext->key_len > KEY_SIZE_WEP104) {
1582
                                ret = -EINVAL;
1583
                                goto out;
1584
                        }
1585
                        if (ext->key_len > KEY_SIZE_WEP40)
1586
                                key.length = KEY_SIZE_WEP104;
1587
                        else
1588
                                key.length = KEY_SIZE_WEP40;
1589
                        break;
1590
                case IW_ENCODE_ALG_TKIP:
1591
                        if (ext->key_len > KEY_SIZE_TKIP) {
1592
                                ret = -EINVAL;
1593
                                goto out;
1594
                        }
1595
                        key.type = DOT11_PRIV_TKIP;
1596
                        key.length = KEY_SIZE_TKIP;
1597
                        break;
1598
                default:
1599
                        return -EINVAL;
1600
                }
1601
 
1602
                if (key.length) {
1603
                        memset(key.key, 0, sizeof(key.key));
1604
                        memcpy(key.key, ext->key, ext->key_len);
1605
                        ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
1606
                                            &key);
1607
                        if (ret < 0)
1608
                                goto out;
1609
                }
1610
        }
1611
 
1612
        /* Read the flags */
1613
        if (encoding->flags & IW_ENCODE_DISABLED) {
1614
                /* Encoding disabled,
1615
                 * authen = DOT11_AUTH_OS;
1616
                 * invoke = 0;
1617
                 * exunencrypt = 0; */
1618
        }
1619
        if (encoding->flags & IW_ENCODE_OPEN) {
1620
                /* Encode but accept non-encoded packets. No auth */
1621
                invoke = 1;
1622
        }
1623
        if (encoding->flags & IW_ENCODE_RESTRICTED) {
1624
                /* Refuse non-encoded packets. Auth */
1625
                authen = DOT11_AUTH_BOTH;
1626
                invoke = 1;
1627
                exunencrypt = 1;
1628
        }
1629
 
1630
        /* do the change if requested  */
1631
        if (encoding->flags & IW_ENCODE_MODE) {
1632
                ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
1633
                                      &authen);
1634
                ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
1635
                                      &invoke);
1636
                ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
1637
                                      &exunencrypt);
1638
        }
1639
 
1640
out:
1641
        return ret;
1642
}
1643
 
1644
 
1645
static int prism54_get_encodeext(struct net_device *ndev,
1646
                                 struct iw_request_info *info,
1647
                                 union iwreq_data *wrqu,
1648
                                 char *extra)
1649
{
1650
        islpci_private *priv = netdev_priv(ndev);
1651
        struct iw_point *encoding = &wrqu->encoding;
1652
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1653
        int idx, max_key_len;
1654
        union oid_res_t r;
1655
        int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
1656
        int ret = 0;
1657
 
1658
        if (islpci_get_state(priv) < PRV_STATE_INIT)
1659
                return 0;
1660
 
1661
        /* first get the flags */
1662
        ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1663
        authen = r.u;
1664
        ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1665
        invoke = r.u;
1666
        ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1667
        exunencrypt = r.u;
1668
        if (ret < 0)
1669
                goto out;
1670
 
1671
        max_key_len = encoding->length - sizeof(*ext);
1672
        if (max_key_len < 0)
1673
                return -EINVAL;
1674
 
1675
        idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
1676
        if (idx) {
1677
                if (idx < 0 || idx > 3)
1678
                        return -EINVAL;
1679
        } else {
1680
                ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1681
                if (ret < 0)
1682
                        goto out;
1683
                idx = r.u;
1684
        }
1685
 
1686
        encoding->flags = idx + 1;
1687
        memset(ext, 0, sizeof(*ext));
1688
 
1689
        switch (authen) {
1690
        case DOT11_AUTH_BOTH:
1691
        case DOT11_AUTH_SK:
1692
                wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
1693
        case DOT11_AUTH_OS:
1694
        default:
1695
                wrqu->encoding.flags |= IW_ENCODE_OPEN;
1696
                break;
1697
        }
1698
 
1699
        down_write(&priv->mib_sem);
1700
        wpa = priv->wpa;
1701
        up_write(&priv->mib_sem);
1702
 
1703
        if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
1704
                /* No encryption */
1705
                ext->alg = IW_ENCODE_ALG_NONE;
1706
                ext->key_len = 0;
1707
                wrqu->encoding.flags |= IW_ENCODE_DISABLED;
1708
        } else {
1709
                struct obj_key *key;
1710
 
1711
                ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
1712
                if (ret < 0)
1713
                        goto out;
1714
                key = r.ptr;
1715
                if (max_key_len < key->length) {
1716
                        ret = -E2BIG;
1717
                        goto out;
1718
                }
1719
                memcpy(ext->key, key->key, key->length);
1720
                ext->key_len = key->length;
1721
 
1722
                switch (key->type) {
1723
                case DOT11_PRIV_TKIP:
1724
                        ext->alg = IW_ENCODE_ALG_TKIP;
1725
                        break;
1726
                default:
1727
                case DOT11_PRIV_WEP:
1728
                        ext->alg = IW_ENCODE_ALG_WEP;
1729
                        break;
1730
                }
1731
                wrqu->encoding.flags |= IW_ENCODE_ENABLED;
1732
        }
1733
 
1734
out:
1735
        return ret;
1736
}
1737
 
1738
 
1739
static int
1740
prism54_reset(struct net_device *ndev, struct iw_request_info *info,
1741
              __u32 * uwrq, char *extra)
1742
{
1743
        islpci_reset(netdev_priv(ndev), 0);
1744
 
1745
        return 0;
1746
}
1747
 
1748
static int
1749
prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
1750
                struct iw_point *dwrq, char *extra)
1751
{
1752
        union oid_res_t r;
1753
        int rvalue;
1754
        enum oid_num_t n = dwrq->flags;
1755
 
1756
        rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r);
1757
        dwrq->length = mgt_response_to_str(n, &r, extra);
1758
        if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
1759
                kfree(r.ptr);
1760
        return rvalue;
1761
}
1762
 
1763
static int
1764
prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
1765
                __u32 * uwrq, char *extra)
1766
{
1767
        u32 oid = uwrq[0], u = uwrq[1];
1768
 
1769
        return mgt_set_request(netdev_priv(ndev), oid, 0, &u);
1770
}
1771
 
1772
static int
1773
prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
1774
                struct iw_point *dwrq, char *extra)
1775
{
1776
        u32 oid = dwrq->flags;
1777
 
1778
        return mgt_set_request(netdev_priv(ndev), oid, 0, extra);
1779
}
1780
 
1781
void
1782
prism54_acl_init(struct islpci_acl *acl)
1783
{
1784
        sema_init(&acl->sem, 1);
1785
        INIT_LIST_HEAD(&acl->mac_list);
1786
        acl->size = 0;
1787
        acl->policy = MAC_POLICY_OPEN;
1788
}
1789
 
1790
static void
1791
prism54_clear_mac(struct islpci_acl *acl)
1792
{
1793
        struct list_head *ptr, *next;
1794
        struct mac_entry *entry;
1795
 
1796
        if (down_interruptible(&acl->sem))
1797
                return;
1798
 
1799
        if (acl->size == 0) {
1800
                up(&acl->sem);
1801
                return;
1802
        }
1803
 
1804
        for (ptr = acl->mac_list.next, next = ptr->next;
1805
             ptr != &acl->mac_list; ptr = next, next = ptr->next) {
1806
                entry = list_entry(ptr, struct mac_entry, _list);
1807
                list_del(ptr);
1808
                kfree(entry);
1809
        }
1810
        acl->size = 0;
1811
        up(&acl->sem);
1812
}
1813
 
1814
void
1815
prism54_acl_clean(struct islpci_acl *acl)
1816
{
1817
        prism54_clear_mac(acl);
1818
}
1819
 
1820
static int
1821
prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
1822
                struct sockaddr *awrq, char *extra)
1823
{
1824
        islpci_private *priv = netdev_priv(ndev);
1825
        struct islpci_acl *acl = &priv->acl;
1826
        struct mac_entry *entry;
1827
        struct sockaddr *addr = (struct sockaddr *) extra;
1828
 
1829
        if (addr->sa_family != ARPHRD_ETHER)
1830
                return -EOPNOTSUPP;
1831
 
1832
        entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
1833
        if (entry == NULL)
1834
                return -ENOMEM;
1835
 
1836
        memcpy(entry->addr, addr->sa_data, ETH_ALEN);
1837
 
1838
        if (down_interruptible(&acl->sem)) {
1839
                kfree(entry);
1840
                return -ERESTARTSYS;
1841
        }
1842
        list_add_tail(&entry->_list, &acl->mac_list);
1843
        acl->size++;
1844
        up(&acl->sem);
1845
 
1846
        return 0;
1847
}
1848
 
1849
static int
1850
prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
1851
                struct sockaddr *awrq, char *extra)
1852
{
1853
        islpci_private *priv = netdev_priv(ndev);
1854
        struct islpci_acl *acl = &priv->acl;
1855
        struct mac_entry *entry;
1856
        struct sockaddr *addr = (struct sockaddr *) extra;
1857
 
1858
        if (addr->sa_family != ARPHRD_ETHER)
1859
                return -EOPNOTSUPP;
1860
 
1861
        if (down_interruptible(&acl->sem))
1862
                return -ERESTARTSYS;
1863
        list_for_each_entry(entry, &acl->mac_list, _list) {
1864
                if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
1865
                        list_del(&entry->_list);
1866
                        acl->size--;
1867
                        kfree(entry);
1868
                        up(&acl->sem);
1869
                        return 0;
1870
                }
1871
        }
1872
        up(&acl->sem);
1873
        return -EINVAL;
1874
}
1875
 
1876
static int
1877
prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
1878
                struct iw_point *dwrq, char *extra)
1879
{
1880
        islpci_private *priv = netdev_priv(ndev);
1881
        struct islpci_acl *acl = &priv->acl;
1882
        struct mac_entry *entry;
1883
        struct sockaddr *dst = (struct sockaddr *) extra;
1884
 
1885
        dwrq->length = 0;
1886
 
1887
        if (down_interruptible(&acl->sem))
1888
                return -ERESTARTSYS;
1889
 
1890
        list_for_each_entry(entry, &acl->mac_list, _list) {
1891
                memcpy(dst->sa_data, entry->addr, ETH_ALEN);
1892
                dst->sa_family = ARPHRD_ETHER;
1893
                dwrq->length++;
1894
                dst++;
1895
        }
1896
        up(&acl->sem);
1897
        return 0;
1898
}
1899
 
1900
/* Setting policy also clears the MAC acl, even if we don't change the defaut
1901
 * policy
1902
 */
1903
 
1904
static int
1905
prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
1906
                   __u32 * uwrq, char *extra)
1907
{
1908
        islpci_private *priv = netdev_priv(ndev);
1909
        struct islpci_acl *acl = &priv->acl;
1910
        u32 mlmeautolevel;
1911
 
1912
        prism54_clear_mac(acl);
1913
 
1914
        if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
1915
                return -EINVAL;
1916
 
1917
        down_write(&priv->mib_sem);
1918
 
1919
        acl->policy = *uwrq;
1920
 
1921
        /* the ACL code needs an intermediate mlmeautolevel */
1922
        if ((priv->iw_mode == IW_MODE_MASTER) &&
1923
            (acl->policy != MAC_POLICY_OPEN))
1924
                mlmeautolevel = DOT11_MLME_INTERMEDIATE;
1925
        else
1926
                mlmeautolevel = CARD_DEFAULT_MLME_MODE;
1927
        if (priv->wpa)
1928
                mlmeautolevel = DOT11_MLME_EXTENDED;
1929
        mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
1930
        /* restart the card with our new policy */
1931
        if (mgt_commit(priv)) {
1932
                up_write(&priv->mib_sem);
1933
                return -EIO;
1934
        }
1935
        up_write(&priv->mib_sem);
1936
 
1937
        return 0;
1938
}
1939
 
1940
static int
1941
prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
1942
                   __u32 * uwrq, char *extra)
1943
{
1944
        islpci_private *priv = netdev_priv(ndev);
1945
        struct islpci_acl *acl = &priv->acl;
1946
 
1947
        *uwrq = acl->policy;
1948
 
1949
        return 0;
1950
}
1951
 
1952
/* Return 1 only if client should be accepted. */
1953
 
1954
static int
1955
prism54_mac_accept(struct islpci_acl *acl, char *mac)
1956
{
1957
        struct mac_entry *entry;
1958
        int res = 0;
1959
 
1960
        if (down_interruptible(&acl->sem))
1961
                return -ERESTARTSYS;
1962
 
1963
        if (acl->policy == MAC_POLICY_OPEN) {
1964
                up(&acl->sem);
1965
                return 1;
1966
        }
1967
 
1968
        list_for_each_entry(entry, &acl->mac_list, _list) {
1969
                if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
1970
                        res = 1;
1971
                        break;
1972
                }
1973
        }
1974
        res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
1975
        up(&acl->sem);
1976
 
1977
        return res;
1978
}
1979
 
1980
static int
1981
prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
1982
                 struct iw_point *dwrq, char *extra)
1983
{
1984
        struct obj_mlme *mlme;
1985
        int rvalue;
1986
 
1987
        mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
1988
        if (mlme == NULL)
1989
                return -ENOMEM;
1990
 
1991
        /* Tell the card to kick every client */
1992
        mlme->id = 0;
1993
        rvalue =
1994
            mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
1995
        kfree(mlme);
1996
 
1997
        return rvalue;
1998
}
1999
 
2000
static int
2001
prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
2002
                 struct sockaddr *awrq, char *extra)
2003
{
2004
        struct obj_mlme *mlme;
2005
        struct sockaddr *addr = (struct sockaddr *) extra;
2006
        int rvalue;
2007
 
2008
        if (addr->sa_family != ARPHRD_ETHER)
2009
                return -EOPNOTSUPP;
2010
 
2011
        mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
2012
        if (mlme == NULL)
2013
                return -ENOMEM;
2014
 
2015
        /* Tell the card to only kick the corresponding bastard */
2016
        memcpy(mlme->address, addr->sa_data, ETH_ALEN);
2017
        mlme->id = -1;
2018
        rvalue =
2019
            mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
2020
 
2021
        kfree(mlme);
2022
 
2023
        return rvalue;
2024
}
2025
 
2026
/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
2027
 
2028
static void
2029
format_event(islpci_private *priv, char *dest, const char *str,
2030
             const struct obj_mlme *mlme, u16 *length, int error)
2031
{
2032
        DECLARE_MAC_BUF(mac);
2033
        int n = snprintf(dest, IW_CUSTOM_MAX,
2034
                         "%s %s %s %s (%2.2X)",
2035
                         str,
2036
                         ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
2037
                         print_mac(mac, mlme->address),
2038
                         (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
2039
                          : ""), mlme->code);
2040
        BUG_ON(n > IW_CUSTOM_MAX);
2041
        *length = n;
2042
}
2043
 
2044
static void
2045
send_formatted_event(islpci_private *priv, const char *str,
2046
                     const struct obj_mlme *mlme, int error)
2047
{
2048
        union iwreq_data wrqu;
2049
        char *memptr;
2050
 
2051
        memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
2052
        if (!memptr)
2053
                return;
2054
        wrqu.data.pointer = memptr;
2055
        wrqu.data.length = 0;
2056
        format_event(priv, memptr, str, mlme, &wrqu.data.length,
2057
                     error);
2058
        wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
2059
        kfree(memptr);
2060
}
2061
 
2062
static void
2063
send_simple_event(islpci_private *priv, const char *str)
2064
{
2065
        union iwreq_data wrqu;
2066
        char *memptr;
2067
        int n = strlen(str);
2068
 
2069
        memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
2070
        if (!memptr)
2071
                return;
2072
        BUG_ON(n > IW_CUSTOM_MAX);
2073
        wrqu.data.pointer = memptr;
2074
        wrqu.data.length = n;
2075
        strcpy(memptr, str);
2076
        wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
2077
        kfree(memptr);
2078
}
2079
 
2080
static void
2081
link_changed(struct net_device *ndev, u32 bitrate)
2082
{
2083
        islpci_private *priv = netdev_priv(ndev);
2084
 
2085
        if (bitrate) {
2086
                if (priv->iw_mode == IW_MODE_INFRA) {
2087
                        union iwreq_data uwrq;
2088
                        prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
2089
                                        NULL);
2090
                        wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
2091
                } else
2092
                        send_simple_event(netdev_priv(ndev),
2093
                                          "Link established");
2094
        } else
2095
                send_simple_event(netdev_priv(ndev), "Link lost");
2096
}
2097
 
2098
/* Beacon/ProbeResp payload header */
2099
struct ieee80211_beacon_phdr {
2100
        u8 timestamp[8];
2101
        u16 beacon_int;
2102
        u16 capab_info;
2103
} __attribute__ ((packed));
2104
 
2105
#define WLAN_EID_GENERIC 0xdd
2106
static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
2107
 
2108
static void
2109
prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
2110
                       u8 *wpa_ie, size_t wpa_ie_len)
2111
{
2112
        struct list_head *ptr;
2113
        struct islpci_bss_wpa_ie *bss = NULL;
2114
        DECLARE_MAC_BUF(mac);
2115
 
2116
        if (wpa_ie_len > MAX_WPA_IE_LEN)
2117
                wpa_ie_len = MAX_WPA_IE_LEN;
2118
 
2119
        if (down_interruptible(&priv->wpa_sem))
2120
                return;
2121
 
2122
        /* try to use existing entry */
2123
        list_for_each(ptr, &priv->bss_wpa_list) {
2124
                bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
2125
                if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
2126
                        list_move(&bss->list, &priv->bss_wpa_list);
2127
                        break;
2128
                }
2129
                bss = NULL;
2130
        }
2131
 
2132
        if (bss == NULL) {
2133
                /* add a new BSS entry; if max number of entries is already
2134
                 * reached, replace the least recently updated */
2135
                if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
2136
                        bss = list_entry(priv->bss_wpa_list.prev,
2137
                                         struct islpci_bss_wpa_ie, list);
2138
                        list_del(&bss->list);
2139
                } else {
2140
                        bss = kzalloc(sizeof (*bss), GFP_ATOMIC);
2141
                        if (bss != NULL)
2142
                                priv->num_bss_wpa++;
2143
                }
2144
                if (bss != NULL) {
2145
                        memcpy(bss->bssid, bssid, ETH_ALEN);
2146
                        list_add(&bss->list, &priv->bss_wpa_list);
2147
                }
2148
        }
2149
 
2150
        if (bss != NULL) {
2151
                memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
2152
                bss->wpa_ie_len = wpa_ie_len;
2153
                bss->last_update = jiffies;
2154
        } else {
2155
                printk(KERN_DEBUG "Failed to add BSS WPA entry for "
2156
                       "%s\n", print_mac(mac, bssid));
2157
        }
2158
 
2159
        /* expire old entries from WPA list */
2160
        while (priv->num_bss_wpa > 0) {
2161
                bss = list_entry(priv->bss_wpa_list.prev,
2162
                                 struct islpci_bss_wpa_ie, list);
2163
                if (!time_after(jiffies, bss->last_update + 60 * HZ))
2164
                        break;
2165
 
2166
                list_del(&bss->list);
2167
                priv->num_bss_wpa--;
2168
                kfree(bss);
2169
        }
2170
 
2171
        up(&priv->wpa_sem);
2172
}
2173
 
2174
static size_t
2175
prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
2176
{
2177
        struct list_head *ptr;
2178
        struct islpci_bss_wpa_ie *bss = NULL;
2179
        size_t len = 0;
2180
 
2181
        if (down_interruptible(&priv->wpa_sem))
2182
                return 0;
2183
 
2184
        list_for_each(ptr, &priv->bss_wpa_list) {
2185
                bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
2186
                if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
2187
                        break;
2188
                bss = NULL;
2189
        }
2190
        if (bss) {
2191
                len = bss->wpa_ie_len;
2192
                memcpy(wpa_ie, bss->wpa_ie, len);
2193
        }
2194
        up(&priv->wpa_sem);
2195
 
2196
        return len;
2197
}
2198
 
2199
void
2200
prism54_wpa_bss_ie_init(islpci_private *priv)
2201
{
2202
        INIT_LIST_HEAD(&priv->bss_wpa_list);
2203
        sema_init(&priv->wpa_sem, 1);
2204
}
2205
 
2206
void
2207
prism54_wpa_bss_ie_clean(islpci_private *priv)
2208
{
2209
        struct islpci_bss_wpa_ie *bss, *n;
2210
 
2211
        list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) {
2212
                kfree(bss);
2213
        }
2214
}
2215
 
2216
static void
2217
prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
2218
                         u8 *payload, size_t len)
2219
{
2220
        struct ieee80211_beacon_phdr *hdr;
2221
        u8 *pos, *end;
2222
        DECLARE_MAC_BUF(mac);
2223
 
2224
        if (!priv->wpa)
2225
                return;
2226
 
2227
        hdr = (struct ieee80211_beacon_phdr *) payload;
2228
        pos = (u8 *) (hdr + 1);
2229
        end = payload + len;
2230
        while (pos < end) {
2231
                if (pos + 2 + pos[1] > end) {
2232
                        printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
2233
                               "for %s\n", print_mac(mac, addr));
2234
                        return;
2235
                }
2236
                if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
2237
                    memcmp(pos + 2, wpa_oid, 4) == 0) {
2238
                        prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
2239
                        return;
2240
                }
2241
                pos += 2 + pos[1];
2242
        }
2243
}
2244
 
2245
static void
2246
handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
2247
{
2248
        if (((mlme->state == DOT11_STATE_AUTHING) ||
2249
             (mlme->state == DOT11_STATE_ASSOCING))
2250
            && mgt_mlme_answer(priv)) {
2251
                /* Someone is requesting auth and we must respond. Just send back
2252
                 * the trap with error code set accordingly.
2253
                 */
2254
                mlme->code = prism54_mac_accept(&priv->acl,
2255
                                                mlme->address) ? 0 : 1;
2256
                mgt_set_request(priv, oid, 0, mlme);
2257
        }
2258
}
2259
 
2260
static int
2261
prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
2262
                            char *data)
2263
{
2264
        struct obj_mlme *mlme = (struct obj_mlme *) data;
2265
        struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
2266
        struct obj_mlmeex *confirm;
2267
        u8 wpa_ie[MAX_WPA_IE_LEN];
2268
        int wpa_ie_len;
2269
        size_t len = 0; /* u16, better? */
2270
        u8 *payload = NULL, *pos = NULL;
2271
        int ret;
2272
        DECLARE_MAC_BUF(mac);
2273
 
2274
        /* I think all trapable objects are listed here.
2275
         * Some oids have a EX version. The difference is that they are emitted
2276
         * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
2277
         * with more info.
2278
         * The few events already defined by the wireless tools are not really
2279
         * suited. We use the more flexible custom event facility.
2280
         */
2281
 
2282
        if (oid >= DOT11_OID_BEACON) {
2283
                len = mlmeex->size;
2284
                payload = pos = mlmeex->data;
2285
        }
2286
 
2287
        /* I fear prism54_process_bss_data won't work with big endian data */
2288
        if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
2289
                prism54_process_bss_data(priv, oid, mlmeex->address,
2290
                                         payload, len);
2291
 
2292
        mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
2293
 
2294
        switch (oid) {
2295
 
2296
        case GEN_OID_LINKSTATE:
2297
                link_changed(priv->ndev, (u32) *data);
2298
                break;
2299
 
2300
        case DOT11_OID_MICFAILURE:
2301
                send_simple_event(priv, "Mic failure");
2302
                break;
2303
 
2304
        case DOT11_OID_DEAUTHENTICATE:
2305
                send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
2306
                break;
2307
 
2308
        case DOT11_OID_AUTHENTICATE:
2309
                handle_request(priv, mlme, oid);
2310
                send_formatted_event(priv, "Authenticate request", mlme, 1);
2311
                break;
2312
 
2313
        case DOT11_OID_DISASSOCIATE:
2314
                send_formatted_event(priv, "Disassociate request", mlme, 0);
2315
                break;
2316
 
2317
        case DOT11_OID_ASSOCIATE:
2318
                handle_request(priv, mlme, oid);
2319
                send_formatted_event(priv, "Associate request", mlme, 1);
2320
                break;
2321
 
2322
        case DOT11_OID_REASSOCIATE:
2323
                handle_request(priv, mlme, oid);
2324
                send_formatted_event(priv, "ReAssociate request", mlme, 1);
2325
                break;
2326
 
2327
        case DOT11_OID_BEACON:
2328
                send_formatted_event(priv,
2329
                                     "Received a beacon from an unkown AP",
2330
                                     mlme, 0);
2331
                break;
2332
 
2333
        case DOT11_OID_PROBE:
2334
                /* we received a probe from a client. */
2335
                send_formatted_event(priv, "Received a probe from client", mlme,
2336
                                     0);
2337
                break;
2338
 
2339
                /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
2340
                 * is backward compatible layout-wise with "struct obj_mlme".
2341
                 */
2342
 
2343
        case DOT11_OID_DEAUTHENTICATEEX:
2344
                send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
2345
                break;
2346
 
2347
        case DOT11_OID_AUTHENTICATEEX:
2348
                handle_request(priv, mlme, oid);
2349
                send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
2350
 
2351
                if (priv->iw_mode != IW_MODE_MASTER
2352
                                && mlmeex->state != DOT11_STATE_AUTHING)
2353
                        break;
2354
 
2355
                confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
2356
 
2357
                if (!confirm)
2358
                        break;
2359
 
2360
                memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2361
                printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
2362
                       print_mac(mac, mlmeex->address));
2363
                confirm->id = -1; /* or mlmeex->id ? */
2364
                confirm->state = 0; /* not used */
2365
                confirm->code = 0;
2366
                confirm->size = 6;
2367
                confirm->data[0] = 0x00;
2368
                confirm->data[1] = 0x00;
2369
                confirm->data[2] = 0x02;
2370
                confirm->data[3] = 0x00;
2371
                confirm->data[4] = 0x00;
2372
                confirm->data[5] = 0x00;
2373
 
2374
                ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
2375
 
2376
                kfree(confirm);
2377
                if (ret)
2378
                        return ret;
2379
                break;
2380
 
2381
        case DOT11_OID_DISASSOCIATEEX:
2382
                send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
2383
                break;
2384
 
2385
        case DOT11_OID_ASSOCIATEEX:
2386
                handle_request(priv, mlme, oid);
2387
                send_formatted_event(priv, "Associate request (ex)", mlme, 1);
2388
 
2389
                if (priv->iw_mode != IW_MODE_MASTER
2390
                                && mlmeex->state != DOT11_STATE_ASSOCING)
2391
                        break;
2392
 
2393
                confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
2394
 
2395
                if (!confirm)
2396
                        break;
2397
 
2398
                memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2399
 
2400
                confirm->id = ((struct obj_mlmeex *)mlme)->id;
2401
                confirm->state = 0; /* not used */
2402
                confirm->code = 0;
2403
 
2404
                wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
2405
 
2406
                if (!wpa_ie_len) {
2407
                        printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
2408
                               print_mac(mac, mlmeex->address));
2409
                        kfree(confirm);
2410
                        break;
2411
                }
2412
 
2413
                confirm->size = wpa_ie_len;
2414
                memcpy(&confirm->data, wpa_ie, wpa_ie_len);
2415
 
2416
                mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
2417
 
2418
                kfree(confirm);
2419
 
2420
                break;
2421
 
2422
        case DOT11_OID_REASSOCIATEEX:
2423
                handle_request(priv, mlme, oid);
2424
                send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
2425
 
2426
                if (priv->iw_mode != IW_MODE_MASTER
2427
                                && mlmeex->state != DOT11_STATE_ASSOCING)
2428
                        break;
2429
 
2430
                confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
2431
 
2432
                if (!confirm)
2433
                        break;
2434
 
2435
                memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2436
 
2437
                confirm->id = mlmeex->id;
2438
                confirm->state = 0; /* not used */
2439
                confirm->code = 0;
2440
 
2441
                wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
2442
 
2443
                if (!wpa_ie_len) {
2444
                        printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
2445
                               print_mac(mac, mlmeex->address));
2446
                        kfree(confirm);
2447
                        break;
2448
                }
2449
 
2450
                confirm->size = wpa_ie_len;
2451
                memcpy(&confirm->data, wpa_ie, wpa_ie_len);
2452
 
2453
                mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
2454
 
2455
                kfree(confirm);
2456
 
2457
                break;
2458
 
2459
        default:
2460
                return -EINVAL;
2461
        }
2462
 
2463
        return 0;
2464
}
2465
 
2466
/*
2467
 * Process a device trap.  This is called via schedule_work(), outside of
2468
 * interrupt context, no locks held.
2469
 */
2470
void
2471
prism54_process_trap(struct work_struct *work)
2472
{
2473
        struct islpci_mgmtframe *frame =
2474
                container_of(work, struct islpci_mgmtframe, ws);
2475
        struct net_device *ndev = frame->ndev;
2476
        enum oid_num_t n = mgt_oidtonum(frame->header->oid);
2477
 
2478
        if (n != OID_NUM_LAST)
2479
                prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
2480
        islpci_mgt_release(frame);
2481
}
2482
 
2483
int
2484
prism54_set_mac_address(struct net_device *ndev, void *addr)
2485
{
2486
        islpci_private *priv = netdev_priv(ndev);
2487
        int ret;
2488
 
2489
        if (ndev->addr_len != 6)
2490
                return -EINVAL;
2491
        ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
2492
                              &((struct sockaddr *) addr)->sa_data);
2493
        if (!ret)
2494
                memcpy(priv->ndev->dev_addr,
2495
                       &((struct sockaddr *) addr)->sa_data, 6);
2496
 
2497
        return ret;
2498
}
2499
 
2500
/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
2501
 * support. This is to be replaced with Linux wireless extensions once they
2502
 * get WPA support. */
2503
 
2504
/* Note II: please leave all this together as it will be easier to remove later,
2505
 * once wireless extensions add WPA support -mcgrof */
2506
 
2507
/* PRISM54_HOSTAPD ioctl() cmd: */
2508
enum {
2509
        PRISM2_SET_ENCRYPTION = 6,
2510
        PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
2511
        PRISM2_HOSTAPD_MLME = 13,
2512
        PRISM2_HOSTAPD_SCAN_REQ = 14,
2513
};
2514
 
2515
#define PRISM54_SET_WPA                 SIOCIWFIRSTPRIV+12
2516
#define PRISM54_HOSTAPD                 SIOCIWFIRSTPRIV+25
2517
#define PRISM54_DROP_UNENCRYPTED        SIOCIWFIRSTPRIV+26
2518
 
2519
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
2520
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
2521
((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
2522
 
2523
/* Maximum length for algorithm names (-1 for nul termination)
2524
 * used in ioctl() */
2525
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
2526
 
2527
struct prism2_hostapd_param {
2528
        u32 cmd;
2529
        u8 sta_addr[ETH_ALEN];
2530
        union {
2531
               struct {
2532
                       u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
2533
                       u32 flags;
2534
                       u32 err;
2535
                       u8 idx;
2536
                       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
2537
                       u16 key_len;
2538
                       u8 key[0];
2539
                       } crypt;
2540
               struct {
2541
                       u8 len;
2542
                       u8 data[0];
2543
               } generic_elem;
2544
               struct {
2545
#define MLME_STA_DEAUTH 0
2546
#define MLME_STA_DISASSOC 1
2547
                       u16 cmd;
2548
                       u16 reason_code;
2549
               } mlme;
2550
               struct {
2551
                       u8 ssid_len;
2552
                       u8 ssid[32];
2553
               } scan_req;
2554
       } u;
2555
};
2556
 
2557
 
2558
static int
2559
prism2_ioctl_set_encryption(struct net_device *dev,
2560
        struct prism2_hostapd_param *param,
2561
        int param_len)
2562
{
2563
        islpci_private *priv = netdev_priv(dev);
2564
        int rvalue = 0, force = 0;
2565
        int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
2566
        union oid_res_t r;
2567
 
2568
        /* with the new API, it's impossible to get a NULL pointer.
2569
         * New version of iwconfig set the IW_ENCODE_NOKEY flag
2570
         * when no key is given, but older versions don't. */
2571
 
2572
        if (param->u.crypt.key_len > 0) {
2573
                /* we have a key to set */
2574
                int index = param->u.crypt.idx;
2575
                int current_index;
2576
                struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
2577
 
2578
                /* get the current key index */
2579
                rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
2580
                current_index = r.u;
2581
                /* Verify that the key is not marked as invalid */
2582
                if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
2583
                        key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
2584
                            sizeof (param->u.crypt.key) : param->u.crypt.key_len;
2585
                        memcpy(key.key, param->u.crypt.key, key.length);
2586
                        if (key.length == 32)
2587
                                /* we want WPA-PSK */
2588
                                key.type = DOT11_PRIV_TKIP;
2589
                        if ((index < 0) || (index > 3))
2590
                                /* no index provided use the current one */
2591
                                index = current_index;
2592
 
2593
                        /* now send the key to the card  */
2594
                        rvalue |=
2595
                            mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
2596
                                            &key);
2597
                }
2598
                /*
2599
                 * If a valid key is set, encryption should be enabled
2600
                 * (user may turn it off later).
2601
                 * This is also how "iwconfig ethX key on" works
2602
                 */
2603
                if ((index == current_index) && (key.length > 0))
2604
                        force = 1;
2605
        } else {
2606
                int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
2607
                if ((index >= 0) && (index <= 3)) {
2608
                        /* we want to set the key index */
2609
                        rvalue |=
2610
                            mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
2611
                                            &index);
2612
                } else {
2613
                        if (!param->u.crypt.flags & IW_ENCODE_MODE) {
2614
                                /* we cannot do anything. Complain. */
2615
                                return -EINVAL;
2616
                        }
2617
                }
2618
        }
2619
        /* now read the flags */
2620
        if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
2621
                /* Encoding disabled,
2622
                 * authen = DOT11_AUTH_OS;
2623
                 * invoke = 0;
2624
                 * exunencrypt = 0; */
2625
        }
2626
        if (param->u.crypt.flags & IW_ENCODE_OPEN)
2627
                /* Encode but accept non-encoded packets. No auth */
2628
                invoke = 1;
2629
        if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
2630
                /* Refuse non-encoded packets. Auth */
2631
                authen = DOT11_AUTH_BOTH;
2632
                invoke = 1;
2633
                exunencrypt = 1;
2634
        }
2635
        /* do the change if requested  */
2636
        if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
2637
                rvalue |=
2638
                    mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2639
                rvalue |=
2640
                    mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
2641
                rvalue |=
2642
                    mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
2643
                                    &exunencrypt);
2644
        }
2645
        return rvalue;
2646
}
2647
 
2648
static int
2649
prism2_ioctl_set_generic_element(struct net_device *ndev,
2650
        struct prism2_hostapd_param *param,
2651
        int param_len)
2652
{
2653
       islpci_private *priv = netdev_priv(ndev);
2654
       int max_len, len, alen, ret=0;
2655
       struct obj_attachment *attach;
2656
 
2657
       len = param->u.generic_elem.len;
2658
       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
2659
       if (max_len < 0 || max_len < len)
2660
               return -EINVAL;
2661
 
2662
       alen = sizeof(*attach) + len;
2663
       attach = kzalloc(alen, GFP_KERNEL);
2664
       if (attach == NULL)
2665
               return -ENOMEM;
2666
 
2667
#define WLAN_FC_TYPE_MGMT 0
2668
#define WLAN_FC_STYPE_ASSOC_REQ 0
2669
#define WLAN_FC_STYPE_REASSOC_REQ 2
2670
 
2671
       /* Note: endianness is covered by mgt_set_varlen */
2672
 
2673
       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2674
               (WLAN_FC_STYPE_ASSOC_REQ << 4);
2675
       attach->id = -1;
2676
       attach->size = len;
2677
       memcpy(attach->data, param->u.generic_elem.data, len);
2678
 
2679
       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2680
 
2681
       if (ret == 0) {
2682
               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2683
                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
2684
 
2685
               ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2686
 
2687
               if (ret == 0)
2688
                       printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
2689
                                       ndev->name);
2690
       }
2691
 
2692
       kfree(attach);
2693
       return ret;
2694
 
2695
}
2696
 
2697
static int
2698
prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
2699
{
2700
        return -EOPNOTSUPP;
2701
}
2702
 
2703
static int
2704
prism2_ioctl_scan_req(struct net_device *ndev,
2705
                     struct prism2_hostapd_param *param)
2706
{
2707
        islpci_private *priv = netdev_priv(ndev);
2708
        int i, rvalue;
2709
        struct obj_bsslist *bsslist;
2710
        u32 noise = 0;
2711
        char *extra = "";
2712
        char *current_ev = "foo";
2713
        union oid_res_t r;
2714
 
2715
        if (islpci_get_state(priv) < PRV_STATE_INIT) {
2716
                /* device is not ready, fail gently */
2717
                return 0;
2718
        }
2719
 
2720
        /* first get the noise value. We will use it to report the link quality */
2721
        rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
2722
        noise = r.u;
2723
 
2724
        /* Ask the device for a list of known bss. We can report at most
2725
         * IW_MAX_AP=64 to the range struct. But the device won't repport anything
2726
         * if you change the value of IWMAX_BSS=24.
2727
         */
2728
        rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
2729
        bsslist = r.ptr;
2730
 
2731
        /* ok now, scan the list and translate its info */
2732
        for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
2733
                current_ev = prism54_translate_bss(ndev, current_ev,
2734
                                                   extra + IW_SCAN_MAX_DATA,
2735
                                                   &(bsslist->bsslist[i]),
2736
                                                   noise);
2737
        kfree(bsslist);
2738
 
2739
        return rvalue;
2740
}
2741
 
2742
static int
2743
prism54_hostapd(struct net_device *ndev, struct iw_point *p)
2744
{
2745
       struct prism2_hostapd_param *param;
2746
       int ret = 0;
2747
       u32 uwrq;
2748
 
2749
       printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
2750
       if (p->length < sizeof(struct prism2_hostapd_param) ||
2751
           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
2752
               return -EINVAL;
2753
 
2754
       param = kmalloc(p->length, GFP_KERNEL);
2755
       if (param == NULL)
2756
               return -ENOMEM;
2757
 
2758
       if (copy_from_user(param, p->pointer, p->length)) {
2759
               kfree(param);
2760
               return -EFAULT;
2761
       }
2762
 
2763
       switch (param->cmd) {
2764
       case PRISM2_SET_ENCRYPTION:
2765
               printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
2766
                               ndev->name);
2767
               ret = prism2_ioctl_set_encryption(ndev, param, p->length);
2768
               break;
2769
       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
2770
               printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
2771
                               ndev->name);
2772
               ret = prism2_ioctl_set_generic_element(ndev, param,
2773
                                                      p->length);
2774
               break;
2775
       case PRISM2_HOSTAPD_MLME:
2776
               printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
2777
                               ndev->name);
2778
               ret = prism2_ioctl_mlme(ndev, param);
2779
               break;
2780
       case PRISM2_HOSTAPD_SCAN_REQ:
2781
               printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
2782
                               ndev->name);
2783
               ret = prism2_ioctl_scan_req(ndev, param);
2784
               break;
2785
        case PRISM54_SET_WPA:
2786
               printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
2787
                               ndev->name);
2788
               uwrq = 1;
2789
               ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
2790
               break;
2791
        case PRISM54_DROP_UNENCRYPTED:
2792
               printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
2793
                               ndev->name);
2794
#if 0
2795
               uwrq = 0x01;
2796
               mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
2797
               down_write(&priv->mib_sem);
2798
               mgt_commit(priv);
2799
               up_write(&priv->mib_sem);
2800
#endif
2801
               /* Not necessary, as set_wpa does it, should we just do it here though? */
2802
               ret = 0;
2803
               break;
2804
       default:
2805
               printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
2806
                               ndev->name);
2807
               ret = -EOPNOTSUPP;
2808
               break;
2809
       }
2810
 
2811
       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2812
               ret = -EFAULT;
2813
 
2814
       kfree(param);
2815
 
2816
       return ret;
2817
}
2818
 
2819
static int
2820
prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
2821
                __u32 * uwrq, char *extra)
2822
{
2823
        islpci_private *priv = netdev_priv(ndev);
2824
        u32 mlme, authen, dot1x, filter, wep;
2825
 
2826
        if (islpci_get_state(priv) < PRV_STATE_INIT)
2827
                return 0;
2828
 
2829
        wep = 1; /* For privacy invoked */
2830
        filter = 1; /* Filter out all unencrypted frames */
2831
        dot1x = 0x01; /* To enable eap filter */
2832
        mlme = DOT11_MLME_EXTENDED;
2833
        authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
2834
 
2835
        down_write(&priv->mib_sem);
2836
        priv->wpa = *uwrq;
2837
 
2838
        switch (priv->wpa) {
2839
                default:
2840
                case 0: /* Clears/disables WPA and friends */
2841
                        wep = 0;
2842
                        filter = 0; /* Do not filter un-encrypted data */
2843
                        dot1x = 0;
2844
                        mlme = DOT11_MLME_AUTO;
2845
                        printk("%s: Disabling WPA\n", ndev->name);
2846
                        break;
2847
                case 2:
2848
                case 1: /* WPA */
2849
                        printk("%s: Enabling WPA\n", ndev->name);
2850
                        break;
2851
        }
2852
        up_write(&priv->mib_sem);
2853
 
2854
        mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2855
        mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
2856
        mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
2857
        mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
2858
        mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
2859
 
2860
        return 0;
2861
}
2862
 
2863
static int
2864
prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
2865
                __u32 * uwrq, char *extra)
2866
{
2867
        islpci_private *priv = netdev_priv(ndev);
2868
        *uwrq = priv->wpa;
2869
        return 0;
2870
}
2871
 
2872
static int
2873
prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2874
                     __u32 * uwrq, char *extra)
2875
{
2876
        islpci_private *priv = netdev_priv(ndev);
2877
        priv->monitor_type =
2878
            (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
2879
        if (priv->iw_mode == IW_MODE_MONITOR)
2880
                priv->ndev->type = priv->monitor_type;
2881
 
2882
        return 0;
2883
}
2884
 
2885
static int
2886
prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2887
                     __u32 * uwrq, char *extra)
2888
{
2889
        islpci_private *priv = netdev_priv(ndev);
2890
        *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
2891
        return 0;
2892
}
2893
 
2894
static int
2895
prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
2896
                  __u32 * uwrq, char *extra)
2897
{
2898
        islpci_private *priv = netdev_priv(ndev);
2899
 
2900
        priv->priv_oid = *uwrq;
2901
        printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
2902
 
2903
        return 0;
2904
}
2905
 
2906
static int
2907
prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
2908
                      struct iw_point *data, char *extra)
2909
{
2910
        islpci_private *priv = netdev_priv(ndev);
2911
        struct islpci_mgmtframe *response;
2912
        int ret = -EIO;
2913
 
2914
        printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
2915
        data->length = 0;
2916
 
2917
        if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2918
                ret =
2919
                    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
2920
                                           priv->priv_oid, extra, 256,
2921
                                           &response);
2922
                printk("%s: ret: %i\n", ndev->name, ret);
2923
                if (ret || !response
2924
                    || response->header->operation == PIMFOR_OP_ERROR) {
2925
                        if (response) {
2926
                                islpci_mgt_release(response);
2927
                        }
2928
                        printk("%s: EIO\n", ndev->name);
2929
                        ret = -EIO;
2930
                }
2931
                if (!ret) {
2932
                        data->length = response->header->length;
2933
                        memcpy(extra, response->data, data->length);
2934
                        islpci_mgt_release(response);
2935
                        printk("%s: len: %i\n", ndev->name, data->length);
2936
                }
2937
        }
2938
 
2939
        return ret;
2940
}
2941
 
2942
static int
2943
prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
2944
                      struct iw_point *data, char *extra)
2945
{
2946
        islpci_private *priv = netdev_priv(ndev);
2947
        struct islpci_mgmtframe *response;
2948
        int ret = 0, response_op = PIMFOR_OP_ERROR;
2949
 
2950
        printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
2951
               data->length);
2952
 
2953
        if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2954
                ret =
2955
                    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
2956
                                           priv->priv_oid, extra, data->length,
2957
                                           &response);
2958
                printk("%s: ret: %i\n", ndev->name, ret);
2959
                if (ret || !response
2960
                    || response->header->operation == PIMFOR_OP_ERROR) {
2961
                        if (response) {
2962
                                islpci_mgt_release(response);
2963
                        }
2964
                        printk("%s: EIO\n", ndev->name);
2965
                        ret = -EIO;
2966
                }
2967
                if (!ret) {
2968
                        response_op = response->header->operation;
2969
                        printk("%s: response_op: %i\n", ndev->name,
2970
                               response_op);
2971
                        islpci_mgt_release(response);
2972
                }
2973
        }
2974
 
2975
        return (ret ? ret : -EINPROGRESS);
2976
}
2977
 
2978
static int
2979
prism54_set_spy(struct net_device *ndev,
2980
                struct iw_request_info *info,
2981
                union iwreq_data *uwrq, char *extra)
2982
{
2983
        islpci_private *priv = netdev_priv(ndev);
2984
        u32 u, oid = OID_INL_CONFIG;
2985
 
2986
        down_write(&priv->mib_sem);
2987
        mgt_get(priv, OID_INL_CONFIG, &u);
2988
 
2989
        if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
2990
                /* disable spy */
2991
                u &= ~INL_CONFIG_RXANNEX;
2992
        else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
2993
                /* enable spy */
2994
                u |= INL_CONFIG_RXANNEX;
2995
 
2996
        mgt_set(priv, OID_INL_CONFIG, &u);
2997
        mgt_commit_list(priv, &oid, 1);
2998
        up_write(&priv->mib_sem);
2999
 
3000
        return iw_handler_set_spy(ndev, info, uwrq, extra);
3001
}
3002
 
3003
static const iw_handler prism54_handler[] = {
3004
        (iw_handler) prism54_commit,    /* SIOCSIWCOMMIT */
3005
        (iw_handler) prism54_get_name,  /* SIOCGIWNAME */
3006
        (iw_handler) NULL,      /* SIOCSIWNWID */
3007
        (iw_handler) NULL,      /* SIOCGIWNWID */
3008
        (iw_handler) prism54_set_freq,  /* SIOCSIWFREQ */
3009
        (iw_handler) prism54_get_freq,  /* SIOCGIWFREQ */
3010
        (iw_handler) prism54_set_mode,  /* SIOCSIWMODE */
3011
        (iw_handler) prism54_get_mode,  /* SIOCGIWMODE */
3012
        (iw_handler) prism54_set_sens,  /* SIOCSIWSENS */
3013
        (iw_handler) prism54_get_sens,  /* SIOCGIWSENS */
3014
        (iw_handler) NULL,      /* SIOCSIWRANGE */
3015
        (iw_handler) prism54_get_range, /* SIOCGIWRANGE */
3016
        (iw_handler) NULL,      /* SIOCSIWPRIV */
3017
        (iw_handler) NULL,      /* SIOCGIWPRIV */
3018
        (iw_handler) NULL,      /* SIOCSIWSTATS */
3019
        (iw_handler) NULL,      /* SIOCGIWSTATS */
3020
        prism54_set_spy,        /* SIOCSIWSPY */
3021
        iw_handler_get_spy,     /* SIOCGIWSPY */
3022
        iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
3023
        iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
3024
        (iw_handler) prism54_set_wap,   /* SIOCSIWAP */
3025
        (iw_handler) prism54_get_wap,   /* SIOCGIWAP */
3026
        (iw_handler) NULL,      /* -- hole -- */
3027
        (iw_handler) NULL,      /* SIOCGIWAPLIST deprecated */
3028
        (iw_handler) prism54_set_scan,  /* SIOCSIWSCAN */
3029
        (iw_handler) prism54_get_scan,  /* SIOCGIWSCAN */
3030
        (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
3031
        (iw_handler) prism54_get_essid, /* SIOCGIWESSID */
3032
        (iw_handler) prism54_set_nick,  /* SIOCSIWNICKN */
3033
        (iw_handler) prism54_get_nick,  /* SIOCGIWNICKN */
3034
        (iw_handler) NULL,      /* -- hole -- */
3035
        (iw_handler) NULL,      /* -- hole -- */
3036
        (iw_handler) prism54_set_rate,  /* SIOCSIWRATE */
3037
        (iw_handler) prism54_get_rate,  /* SIOCGIWRATE */
3038
        (iw_handler) prism54_set_rts,   /* SIOCSIWRTS */
3039
        (iw_handler) prism54_get_rts,   /* SIOCGIWRTS */
3040
        (iw_handler) prism54_set_frag,  /* SIOCSIWFRAG */
3041
        (iw_handler) prism54_get_frag,  /* SIOCGIWFRAG */
3042
        (iw_handler) prism54_set_txpower,       /* SIOCSIWTXPOW */
3043
        (iw_handler) prism54_get_txpower,       /* SIOCGIWTXPOW */
3044
        (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
3045
        (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
3046
        (iw_handler) prism54_set_encode,        /* SIOCSIWENCODE */
3047
        (iw_handler) prism54_get_encode,        /* SIOCGIWENCODE */
3048
        (iw_handler) NULL,      /* SIOCSIWPOWER */
3049
        (iw_handler) NULL,      /* SIOCGIWPOWER */
3050
        NULL,                   /* -- hole -- */
3051
        NULL,                   /* -- hole -- */
3052
        (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
3053
        (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
3054
        (iw_handler) prism54_set_auth,  /* SIOCSIWAUTH */
3055
        (iw_handler) prism54_get_auth,  /* SIOCGIWAUTH */
3056
        (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
3057
        (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
3058
        NULL,                   /* SIOCSIWPMKSA */
3059
};
3060
 
3061
/* The low order bit identify a SET (0) or a GET (1) ioctl.  */
3062
 
3063
#define PRISM54_RESET           SIOCIWFIRSTPRIV
3064
#define PRISM54_GET_POLICY      SIOCIWFIRSTPRIV+1
3065
#define PRISM54_SET_POLICY      SIOCIWFIRSTPRIV+2
3066
#define PRISM54_GET_MAC         SIOCIWFIRSTPRIV+3
3067
#define PRISM54_ADD_MAC         SIOCIWFIRSTPRIV+4
3068
 
3069
#define PRISM54_DEL_MAC         SIOCIWFIRSTPRIV+6
3070
 
3071
#define PRISM54_KICK_MAC        SIOCIWFIRSTPRIV+8
3072
 
3073
#define PRISM54_KICK_ALL        SIOCIWFIRSTPRIV+10
3074
 
3075
#define PRISM54_GET_WPA         SIOCIWFIRSTPRIV+11
3076
#define PRISM54_SET_WPA         SIOCIWFIRSTPRIV+12
3077
 
3078
#define PRISM54_DBG_OID         SIOCIWFIRSTPRIV+14
3079
#define PRISM54_DBG_GET_OID     SIOCIWFIRSTPRIV+15
3080
#define PRISM54_DBG_SET_OID     SIOCIWFIRSTPRIV+16
3081
 
3082
#define PRISM54_GET_OID         SIOCIWFIRSTPRIV+17
3083
#define PRISM54_SET_OID_U32     SIOCIWFIRSTPRIV+18
3084
#define PRISM54_SET_OID_STR     SIOCIWFIRSTPRIV+20
3085
#define PRISM54_SET_OID_ADDR    SIOCIWFIRSTPRIV+22
3086
 
3087
#define PRISM54_GET_PRISMHDR    SIOCIWFIRSTPRIV+23
3088
#define PRISM54_SET_PRISMHDR    SIOCIWFIRSTPRIV+24
3089
 
3090
#define IWPRIV_SET_U32(n,x)     { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
3091
#define IWPRIV_SET_SSID(n,x)    { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
3092
#define IWPRIV_SET_ADDR(n,x)    { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
3093
#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
3094
 
3095
#define IWPRIV_U32(n,x)         IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
3096
#define IWPRIV_SSID(n,x)        IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
3097
#define IWPRIV_ADDR(n,x)        IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
3098
 
3099
/* Note : limited to 128 private ioctls (wireless tools 26) */
3100
 
3101
static const struct iw_priv_args prism54_private_args[] = {
3102
/*{ cmd, set_args, get_args, name } */
3103
        {PRISM54_RESET, 0, 0, "reset"},
3104
        {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
3105
         "get_prismhdr"},
3106
        {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
3107
         "set_prismhdr"},
3108
        {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
3109
         "getPolicy"},
3110
        {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
3111
         "setPolicy"},
3112
        {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
3113
        {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
3114
         "addMac"},
3115
        {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
3116
         "delMac"},
3117
        {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
3118
         "kickMac"},
3119
        {PRISM54_KICK_ALL, 0, 0, "kickAll"},
3120
        {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
3121
         "get_wpa"},
3122
        {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
3123
         "set_wpa"},
3124
        {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
3125
         "dbg_oid"},
3126
        {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
3127
        {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
3128
        /* --- sub-ioctls handlers --- */
3129
        {PRISM54_GET_OID,
3130
         0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
3131
        {PRISM54_SET_OID_U32,
3132
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
3133
        {PRISM54_SET_OID_STR,
3134
         IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
3135
        {PRISM54_SET_OID_ADDR,
3136
         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
3137
        /* --- sub-ioctls definitions --- */
3138
        IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
3139
        IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
3140
        IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
3141
        IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
3142
        IWPRIV_U32(DOT11_OID_STATE, "state"),
3143
        IWPRIV_U32(DOT11_OID_AID, "aid"),
3144
 
3145
        IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
3146
 
3147
        IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
3148
        IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
3149
        IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
3150
 
3151
        IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
3152
        IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
3153
        IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
3154
 
3155
        IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
3156
 
3157
        IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
3158
        IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
3159
        IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
3160
        IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
3161
        IWPRIV_U32(DOT11_OID_PSM, "psm"),
3162
 
3163
        IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
3164
        IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
3165
        IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
3166
        IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
3167
        IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
3168
        IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
3169
        IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
3170
        IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
3171
        IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
3172
        IWPRIV_GET(DOT11_OID_RATES, "rates"),
3173
        IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
3174
        IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
3175
        IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
3176
 
3177
        IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
3178
        IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
3179
        IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
3180
        IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
3181
        IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
3182
        IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
3183
 
3184
        IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
3185
        IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
3186
        IWPRIV_U32(OID_INL_MODE, "mode"),
3187
        IWPRIV_U32(OID_INL_CONFIG, "config"),
3188
        IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
3189
        IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
3190
        IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
3191
};
3192
 
3193
static const iw_handler prism54_private_handler[] = {
3194
        (iw_handler) prism54_reset,
3195
        (iw_handler) prism54_get_policy,
3196
        (iw_handler) prism54_set_policy,
3197
        (iw_handler) prism54_get_mac,
3198
        (iw_handler) prism54_add_mac,
3199
        (iw_handler) NULL,
3200
        (iw_handler) prism54_del_mac,
3201
        (iw_handler) NULL,
3202
        (iw_handler) prism54_kick_mac,
3203
        (iw_handler) NULL,
3204
        (iw_handler) prism54_kick_all,
3205
        (iw_handler) prism54_get_wpa,
3206
        (iw_handler) prism54_set_wpa,
3207
        (iw_handler) NULL,
3208
        (iw_handler) prism54_debug_oid,
3209
        (iw_handler) prism54_debug_get_oid,
3210
        (iw_handler) prism54_debug_set_oid,
3211
        (iw_handler) prism54_get_oid,
3212
        (iw_handler) prism54_set_u32,
3213
        (iw_handler) NULL,
3214
        (iw_handler) prism54_set_raw,
3215
        (iw_handler) NULL,
3216
        (iw_handler) prism54_set_raw,
3217
        (iw_handler) prism54_get_prismhdr,
3218
        (iw_handler) prism54_set_prismhdr,
3219
};
3220
 
3221
const struct iw_handler_def prism54_handler_def = {
3222
        .num_standard = ARRAY_SIZE(prism54_handler),
3223
        .num_private = ARRAY_SIZE(prism54_private_handler),
3224
        .num_private_args = ARRAY_SIZE(prism54_private_args),
3225
        .standard = (iw_handler *) prism54_handler,
3226
        .private = (iw_handler *) prism54_private_handler,
3227
        .private_args = (struct iw_priv_args *) prism54_private_args,
3228
        .get_wireless_stats = prism54_get_wireless_stats,
3229
};
3230
 
3231
/* For wpa_supplicant */
3232
 
3233
int
3234
prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
3235
{
3236
        struct iwreq *wrq = (struct iwreq *) rq;
3237
        int ret = -1;
3238
        switch (cmd) {
3239
                case PRISM54_HOSTAPD:
3240
                if (!capable(CAP_NET_ADMIN))
3241
                return -EPERM;
3242
                ret = prism54_hostapd(ndev, &wrq->u.data);
3243
                return ret;
3244
        }
3245
        return -EOPNOTSUPP;
3246
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.