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