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