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