kernel.org linux-2.6.10
[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
1528         wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
1529         if (!wrqu.data.pointer)
1530                 return;
1531         wrqu.data.length = 0;
1532         format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
1533                      error);
1534         wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
1535         kfree(wrqu.data.pointer);
1536 }
1537
1538 static void
1539 send_simple_event(islpci_private *priv, const char *str)
1540 {
1541         union iwreq_data wrqu;
1542         int n = strlen(str);
1543
1544         wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
1545         if (!wrqu.data.pointer)
1546                 return;
1547         BUG_ON(n > IW_CUSTOM_MAX);
1548         wrqu.data.length = n;
1549         strcpy(wrqu.data.pointer, str);
1550         wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
1551         kfree(wrqu.data.pointer);
1552 }
1553
1554 static void
1555 link_changed(struct net_device *ndev, u32 bitrate)
1556 {
1557         islpci_private *priv = netdev_priv(ndev);
1558
1559         if (bitrate) {
1560                 if (priv->iw_mode == IW_MODE_INFRA) {
1561                         union iwreq_data uwrq;
1562                         prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
1563                                         NULL);
1564                         wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
1565                 } else
1566                         send_simple_event(netdev_priv(ndev),
1567                                           "Link established");
1568         } else
1569                 send_simple_event(netdev_priv(ndev), "Link lost");
1570 }
1571
1572 /* Beacon/ProbeResp payload header */
1573 struct ieee80211_beacon_phdr {
1574         u8 timestamp[8];
1575         u16 beacon_int;
1576         u16 capab_info;
1577 } __attribute__ ((packed));
1578
1579 #define WLAN_EID_GENERIC 0xdd
1580 static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
1581
1582 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
1583 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
1584
1585 void
1586 prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
1587                    u8 *wpa_ie, size_t wpa_ie_len)
1588 {
1589         struct list_head *ptr;
1590         struct islpci_bss_wpa_ie *bss = NULL;
1591
1592         if (wpa_ie_len > MAX_WPA_IE_LEN)
1593                 wpa_ie_len = MAX_WPA_IE_LEN;
1594
1595         if (down_interruptible(&priv->wpa_sem))
1596                 return;
1597
1598         /* try to use existing entry */
1599         list_for_each(ptr, &priv->bss_wpa_list) {
1600                 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1601                 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
1602                         list_move(&bss->list, &priv->bss_wpa_list);
1603                         break;
1604                 }
1605                 bss = NULL;
1606         }
1607
1608         if (bss == NULL) {
1609                 /* add a new BSS entry; if max number of entries is already
1610                  * reached, replace the least recently updated */
1611                 if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
1612                         bss = list_entry(priv->bss_wpa_list.prev,
1613                                          struct islpci_bss_wpa_ie, list);
1614                         list_del(&bss->list);
1615                 } else {
1616                         bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
1617                         if (bss != NULL) {
1618                                 priv->num_bss_wpa++;
1619                                 memset(bss, 0, sizeof (*bss));
1620                         }
1621                 }
1622                 if (bss != NULL) {
1623                         memcpy(bss->bssid, bssid, ETH_ALEN);
1624                         list_add(&bss->list, &priv->bss_wpa_list);
1625                 }
1626         }
1627
1628         if (bss != NULL) {
1629                 memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
1630                 bss->wpa_ie_len = wpa_ie_len;
1631                 bss->last_update = jiffies;
1632         } else {
1633                 printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
1634                        "\n", MAC2STR(bssid));
1635         }
1636
1637         /* expire old entries from WPA list */
1638         while (priv->num_bss_wpa > 0) {
1639                 bss = list_entry(priv->bss_wpa_list.prev,
1640                                  struct islpci_bss_wpa_ie, list);
1641                 if (!time_after(jiffies, bss->last_update + 60 * HZ))
1642                         break;
1643
1644                 list_del(&bss->list);
1645                 priv->num_bss_wpa--;
1646                 kfree(bss);
1647         }
1648
1649         up(&priv->wpa_sem);
1650 }
1651
1652 size_t
1653 prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
1654 {
1655         struct list_head *ptr;
1656         struct islpci_bss_wpa_ie *bss = NULL;
1657         size_t len = 0;
1658
1659         if (down_interruptible(&priv->wpa_sem))
1660                 return 0;
1661
1662         list_for_each(ptr, &priv->bss_wpa_list) {
1663                 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1664                 if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
1665                         break;
1666                 bss = NULL;
1667         }
1668         if (bss) {
1669                 len = bss->wpa_ie_len;
1670                 memcpy(wpa_ie, bss->wpa_ie, len);
1671         }
1672         up(&priv->wpa_sem);
1673
1674         return len;
1675 }
1676
1677 void
1678 prism54_wpa_ie_init(islpci_private *priv)
1679 {
1680         INIT_LIST_HEAD(&priv->bss_wpa_list);
1681         sema_init(&priv->wpa_sem, 1);
1682 }
1683
1684 void
1685 prism54_wpa_ie_clean(islpci_private *priv)
1686 {
1687         struct list_head *ptr, *n;
1688
1689         list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
1690                 struct islpci_bss_wpa_ie *bss;
1691                 bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
1692                 kfree(bss);
1693         }
1694 }
1695
1696 static void
1697 prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
1698                          u8 *payload, size_t len)
1699 {
1700         struct ieee80211_beacon_phdr *hdr;
1701         u8 *pos, *end;
1702
1703         if (!priv->wpa)
1704                 return;
1705
1706         hdr = (struct ieee80211_beacon_phdr *) payload;
1707         pos = (u8 *) (hdr + 1);
1708         end = payload + len;
1709         while (pos < end) {
1710                 if (pos + 2 + pos[1] > end) {
1711                         printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
1712                                "for " MACSTR "\n", MAC2STR(addr));
1713                         return;
1714                 }
1715                 if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
1716                     memcmp(pos + 2, wpa_oid, 4) == 0) {
1717                         prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
1718                         return;
1719                 }
1720                 pos += 2 + pos[1];
1721         }
1722 }
1723
1724 static void
1725 handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
1726 {
1727         if (((mlme->state == DOT11_STATE_AUTHING) ||
1728              (mlme->state == DOT11_STATE_ASSOCING))
1729             && mgt_mlme_answer(priv)) {
1730                 /* Someone is requesting auth and we must respond. Just send back
1731                  * the trap with error code set accordingly.
1732                  */
1733                 mlme->code = prism54_mac_accept(&priv->acl,
1734                                                 mlme->address) ? 0 : 1;
1735                 mgt_set_request(priv, oid, 0, mlme);
1736         }
1737 }
1738
1739 int
1740 prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
1741                             char *data)
1742 {
1743         struct obj_mlme *mlme = (struct obj_mlme *) data;
1744         struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
1745         struct obj_mlmeex *confirm;
1746         u8 wpa_ie[MAX_WPA_IE_LEN];
1747         int wpa_ie_len;
1748         size_t len = 0; /* u16, better? */
1749         u8 *payload = 0, *pos = 0;
1750         int ret;
1751
1752         /* I think all trapable objects are listed here.
1753          * Some oids have a EX version. The difference is that they are emitted
1754          * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
1755          * with more info.
1756          * The few events already defined by the wireless tools are not really
1757          * suited. We use the more flexible custom event facility.
1758          */
1759
1760         if (oid >= DOT11_OID_BEACON) {
1761                 len = mlmeex->size;
1762                 payload = pos = mlmeex->data;
1763         }
1764
1765         /* I fear prism54_process_bss_data won't work with big endian data */
1766         if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
1767                 prism54_process_bss_data(priv, oid, mlmeex->address,
1768                                          payload, len);
1769
1770         mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
1771
1772         switch (oid) {
1773
1774         case GEN_OID_LINKSTATE:
1775                 link_changed(priv->ndev, (u32) *data);
1776                 break;
1777
1778         case DOT11_OID_MICFAILURE:
1779                 send_simple_event(priv, "Mic failure");
1780                 break;
1781
1782         case DOT11_OID_DEAUTHENTICATE:
1783                 send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
1784                 break;
1785
1786         case DOT11_OID_AUTHENTICATE:
1787                 handle_request(priv, mlme, oid);
1788                 send_formatted_event(priv, "Authenticate request", mlme, 1);
1789                 break;
1790
1791         case DOT11_OID_DISASSOCIATE:
1792                 send_formatted_event(priv, "Disassociate request", mlme, 0);
1793                 break;
1794
1795         case DOT11_OID_ASSOCIATE:
1796                 handle_request(priv, mlme, oid);
1797                 send_formatted_event(priv, "Associate request", mlme, 1);
1798                 break;
1799
1800         case DOT11_OID_REASSOCIATE:
1801                 handle_request(priv, mlme, oid);
1802                 send_formatted_event(priv, "ReAssociate request", mlme, 1);
1803                 break;
1804
1805         case DOT11_OID_BEACON:
1806                 send_formatted_event(priv,
1807                                      "Received a beacon from an unkown AP",
1808                                      mlme, 0);
1809                 break;
1810
1811         case DOT11_OID_PROBE:
1812                 /* we received a probe from a client. */
1813                 send_formatted_event(priv, "Received a probe from client", mlme,
1814                                      0);
1815                 break;
1816
1817                 /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
1818                  * is backward compatible layout-wise with "struct obj_mlme".
1819                  */
1820
1821         case DOT11_OID_DEAUTHENTICATEEX:
1822                 send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
1823                 break;
1824
1825         case DOT11_OID_AUTHENTICATEEX:
1826                 handle_request(priv, mlme, oid);
1827                 send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
1828
1829                 if (priv->iw_mode != IW_MODE_MASTER 
1830                                 && mlmeex->state != DOT11_STATE_AUTHING)
1831                         break;
1832
1833                 confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
1834
1835                 if (!confirm) 
1836                         break;
1837
1838                 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1839                 printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
1840                                 mlmeex->address[0],
1841                                 mlmeex->address[1],
1842                                 mlmeex->address[2],
1843                                 mlmeex->address[3],
1844                                 mlmeex->address[4],
1845                                 mlmeex->address[5]
1846                                 );
1847                 confirm->id = -1; /* or mlmeex->id ? */
1848                 confirm->state = 0; /* not used */
1849                 confirm->code = 0;
1850                 confirm->size = 6;
1851                 confirm->data[0] = 0x00;
1852                 confirm->data[1] = 0x00;
1853                 confirm->data[2] = 0x02;
1854                 confirm->data[3] = 0x00;
1855                 confirm->data[4] = 0x00;
1856                 confirm->data[5] = 0x00;
1857
1858                 ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
1859
1860                 kfree(confirm);
1861                 if (ret)
1862                         return ret;
1863                 break;
1864
1865         case DOT11_OID_DISASSOCIATEEX:
1866                 send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
1867                 break;
1868
1869         case DOT11_OID_ASSOCIATEEX:
1870                 handle_request(priv, mlme, oid);
1871                 send_formatted_event(priv, "Associate request (ex)", mlme, 1);
1872
1873                 if (priv->iw_mode != IW_MODE_MASTER 
1874                                 && mlmeex->state != DOT11_STATE_AUTHING)
1875                         break;
1876                 
1877                 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
1878
1879                 if (!confirm)
1880                         break;
1881
1882                 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1883
1884                 confirm->id = ((struct obj_mlmeex *)mlme)->id;
1885                 confirm->state = 0; /* not used */
1886                 confirm->code = 0;
1887
1888                 wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
1889
1890                 if (!wpa_ie_len) {
1891                         printk(KERN_DEBUG "No WPA IE found from "
1892                                         "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
1893                                 mlmeex->address[0],
1894                                 mlmeex->address[1],
1895                                 mlmeex->address[2],
1896                                 mlmeex->address[3],
1897                                 mlmeex->address[4],
1898                                 mlmeex->address[5]
1899                                 );
1900                         kfree(confirm);
1901                         break;
1902                 }
1903
1904                 confirm->size = wpa_ie_len;
1905                 memcpy(&confirm->data, wpa_ie, wpa_ie_len);
1906
1907                 mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
1908
1909                 kfree(confirm);
1910                 
1911                 break;
1912
1913         case DOT11_OID_REASSOCIATEEX:
1914                 handle_request(priv, mlme, oid);
1915                 send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
1916
1917                 if (priv->iw_mode != IW_MODE_MASTER 
1918                                 && mlmeex->state != DOT11_STATE_ASSOCING)
1919                         break;
1920
1921                 confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
1922
1923                 if (!confirm)
1924                         break;
1925
1926                 memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
1927
1928                 confirm->id = mlmeex->id;
1929                 confirm->state = 0; /* not used */
1930                 confirm->code = 0;
1931
1932                 wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
1933
1934                 if (!wpa_ie_len) {
1935                         printk(KERN_DEBUG "No WPA IE found from "
1936                                         "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
1937                                 mlmeex->address[0],
1938                                 mlmeex->address[1],
1939                                 mlmeex->address[2],
1940                                 mlmeex->address[3],
1941                                 mlmeex->address[4],
1942                                 mlmeex->address[5]
1943                                 );
1944                         kfree(confirm);
1945                         break;
1946                 }
1947
1948                 confirm->size = wpa_ie_len; 
1949                 memcpy(&confirm->data, wpa_ie, wpa_ie_len);
1950
1951                 mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
1952
1953                 kfree(confirm);
1954                 
1955                 break;
1956
1957         default:
1958                 return -EINVAL;
1959         }
1960
1961         return 0;
1962 }
1963
1964 /*
1965  * Process a device trap.  This is called via schedule_work(), outside of
1966  * interrupt context, no locks held.
1967  */
1968 void
1969 prism54_process_trap(void *data)
1970 {
1971         struct islpci_mgmtframe *frame = data;
1972         struct net_device *ndev = frame->ndev;
1973         enum oid_num_t n = mgt_oidtonum(frame->header->oid);
1974
1975         if (n != OID_NUM_LAST)
1976                 prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
1977         islpci_mgt_release(frame);
1978 }
1979
1980 int
1981 prism54_set_mac_address(struct net_device *ndev, void *addr)
1982 {
1983         islpci_private *priv = netdev_priv(ndev);
1984         int ret;
1985
1986         if (ndev->addr_len != 6)
1987                 return -EINVAL;
1988         ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
1989                               &((struct sockaddr *) addr)->sa_data);
1990         if (!ret)
1991                 memcpy(priv->ndev->dev_addr,
1992                        &((struct sockaddr *) addr)->sa_data, 6);
1993
1994         return ret;
1995 }
1996
1997 /* Note: currently, use hostapd ioctl from the Host AP driver for WPA
1998  * support. This is to be replaced with Linux wireless extensions once they
1999  * get WPA support. */
2000
2001 /* Note II: please leave all this together as it will be easier to remove later,
2002  * once wireless extensions add WPA support -mcgrof */
2003
2004 /* PRISM54_HOSTAPD ioctl() cmd: */
2005 enum {
2006         PRISM2_SET_ENCRYPTION = 6,
2007         PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
2008         PRISM2_HOSTAPD_MLME = 13,
2009         PRISM2_HOSTAPD_SCAN_REQ = 14,
2010 };
2011
2012 #define PRISM54_SET_WPA                 SIOCIWFIRSTPRIV+12
2013 #define PRISM54_HOSTAPD                 SIOCIWFIRSTPRIV+25
2014 #define PRISM54_DROP_UNENCRYPTED        SIOCIWFIRSTPRIV+26
2015
2016 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
2017 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
2018 ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
2019
2020 /* Maximum length for algorithm names (-1 for nul termination) 
2021  * used in ioctl() */
2022 #define HOSTAP_CRYPT_ALG_NAME_LEN 16
2023         
2024 struct prism2_hostapd_param {
2025         u32 cmd;
2026         u8 sta_addr[ETH_ALEN];
2027         union {
2028                struct {
2029                        u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
2030                        u32 flags;
2031                        u32 err;
2032                        u8 idx;
2033                        u8 seq[8]; /* sequence counter (set: RX, get: TX) */
2034                        u16 key_len;
2035                        u8 key[0];
2036                        } crypt;
2037                struct {
2038                        u8 len;
2039                        u8 data[0];
2040                } generic_elem;
2041                struct {
2042 #define MLME_STA_DEAUTH 0
2043 #define MLME_STA_DISASSOC 1
2044                        u16 cmd;
2045                        u16 reason_code;
2046                } mlme;
2047                struct {
2048                        u8 ssid_len;
2049                        u8 ssid[32];
2050                } scan_req;
2051        } u;
2052 };
2053
2054
2055 static int
2056 prism2_ioctl_set_encryption(struct net_device *dev,
2057         struct prism2_hostapd_param *param,
2058         int param_len)
2059 {
2060         islpci_private *priv = netdev_priv(dev);
2061         int rvalue = 0, force = 0;
2062         int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
2063         union oid_res_t r;
2064
2065         /* with the new API, it's impossible to get a NULL pointer.
2066          * New version of iwconfig set the IW_ENCODE_NOKEY flag
2067          * when no key is given, but older versions don't. */
2068
2069         if (param->u.crypt.key_len > 0) {
2070                 /* we have a key to set */
2071                 int index = param->u.crypt.idx;
2072                 int current_index;
2073                 struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
2074
2075                 /* get the current key index */
2076                 rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
2077                 current_index = r.u;
2078                 /* Verify that the key is not marked as invalid */
2079                 if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
2080                         key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
2081                             sizeof (param->u.crypt.key) : param->u.crypt.key_len;
2082                         memcpy(key.key, param->u.crypt.key, key.length);
2083                         if (key.length == 32)
2084                                 /* we want WPA-PSK */
2085                                 key.type = DOT11_PRIV_TKIP;
2086                         if ((index < 0) || (index > 3))
2087                                 /* no index provided use the current one */
2088                                 index = current_index;
2089
2090                         /* now send the key to the card  */
2091                         rvalue |=
2092                             mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
2093                                             &key);
2094                 }
2095                 /*
2096                  * If a valid key is set, encryption should be enabled 
2097                  * (user may turn it off later).
2098                  * This is also how "iwconfig ethX key on" works
2099                  */
2100                 if ((index == current_index) && (key.length > 0))
2101                         force = 1;
2102         } else {
2103                 int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
2104                 if ((index >= 0) && (index <= 3)) {
2105                         /* we want to set the key index */
2106                         rvalue |=
2107                             mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
2108                                             &index);
2109                 } else {
2110                         if (!param->u.crypt.flags & IW_ENCODE_MODE) {
2111                                 /* we cannot do anything. Complain. */
2112                                 return -EINVAL;
2113                         }
2114                 }
2115         }
2116         /* now read the flags */
2117         if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
2118                 /* Encoding disabled, 
2119                  * authen = DOT11_AUTH_OS;
2120                  * invoke = 0;
2121                  * exunencrypt = 0; */
2122         }
2123         if (param->u.crypt.flags & IW_ENCODE_OPEN)
2124                 /* Encode but accept non-encoded packets. No auth */
2125                 invoke = 1;
2126         if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
2127                 /* Refuse non-encoded packets. Auth */
2128                 authen = DOT11_AUTH_BOTH;
2129                 invoke = 1;
2130                 exunencrypt = 1;
2131         }
2132         /* do the change if requested  */
2133         if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
2134                 rvalue |=
2135                     mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2136                 rvalue |=
2137                     mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
2138                 rvalue |=
2139                     mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
2140                                     &exunencrypt);
2141         }
2142         return rvalue;
2143 }
2144
2145 static int
2146 prism2_ioctl_set_generic_element(struct net_device *ndev,
2147         struct prism2_hostapd_param *param,
2148         int param_len)
2149 {
2150        islpci_private *priv = netdev_priv(ndev);
2151        int max_len, len, alen, ret=0;
2152        struct obj_attachment *attach;
2153
2154        len = param->u.generic_elem.len;
2155        max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
2156        if (max_len < 0 || max_len < len)
2157                return -EINVAL;
2158
2159        alen = sizeof(*attach) + len;
2160        attach = kmalloc(alen, GFP_KERNEL);
2161        if (attach == NULL)
2162                return -ENOMEM;
2163
2164        memset(attach, 0, alen);
2165 #define WLAN_FC_TYPE_MGMT 0
2166 #define WLAN_FC_STYPE_ASSOC_REQ 0
2167 #define WLAN_FC_STYPE_REASSOC_REQ 2
2168
2169        /* Note: endianness is covered by mgt_set_varlen */
2170
2171        attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2172                (WLAN_FC_STYPE_ASSOC_REQ << 4);
2173        attach->id = -1;
2174        attach->size = len;
2175        memcpy(attach->data, param->u.generic_elem.data, len);
2176
2177        ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2178
2179        if (ret == 0) {
2180                attach->type = (WLAN_FC_TYPE_MGMT << 2) |
2181                        (WLAN_FC_STYPE_REASSOC_REQ << 4);
2182
2183                ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
2184
2185                if (ret == 0) 
2186                        printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
2187                                        ndev->name);
2188        }
2189
2190        kfree(attach);
2191        return ret;
2192
2193 }
2194
2195 static int
2196 prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
2197 {
2198         return -EOPNOTSUPP;
2199 }
2200
2201 static int
2202 prism2_ioctl_scan_req(struct net_device *ndev,
2203                      struct prism2_hostapd_param *param)
2204 {
2205         islpci_private *priv = netdev_priv(ndev);
2206         int i, rvalue;
2207         struct obj_bsslist *bsslist;
2208         u32 noise = 0;
2209         char *extra = "";
2210         char *current_ev = "foo";
2211         union oid_res_t r;
2212
2213         if (islpci_get_state(priv) < PRV_STATE_INIT) {
2214                 /* device is not ready, fail gently */
2215                 return 0;
2216         }
2217
2218         /* first get the noise value. We will use it to report the link quality */
2219         rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
2220         noise = r.u;
2221
2222         /* Ask the device for a list of known bss. We can report at most
2223          * IW_MAX_AP=64 to the range struct. But the device won't repport anything
2224          * if you change the value of IWMAX_BSS=24.
2225          */
2226         rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
2227         bsslist = r.ptr;
2228
2229         /* ok now, scan the list and translate its info */
2230         for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
2231                 current_ev = prism54_translate_bss(ndev, current_ev,
2232                                                    extra + IW_SCAN_MAX_DATA,
2233                                                    &(bsslist->bsslist[i]),
2234                                                    noise);
2235         kfree(bsslist);
2236
2237         return rvalue;
2238 }
2239
2240 static int
2241 prism54_hostapd(struct net_device *ndev, struct iw_point *p)
2242 {
2243        struct prism2_hostapd_param *param;
2244        int ret = 0;
2245        u32 uwrq;
2246
2247        printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
2248        if (p->length < sizeof(struct prism2_hostapd_param) ||
2249            p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
2250                return -EINVAL;
2251
2252        param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
2253        if (param == NULL)
2254                return -ENOMEM;
2255
2256        if (copy_from_user(param, p->pointer, p->length)) {
2257                kfree(param);
2258                return -EFAULT;
2259        }
2260
2261        switch (param->cmd) {
2262        case PRISM2_SET_ENCRYPTION:
2263                printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
2264                                ndev->name);
2265                ret = prism2_ioctl_set_encryption(ndev, param, p->length);
2266                break;
2267        case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
2268                printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
2269                                ndev->name);
2270                ret = prism2_ioctl_set_generic_element(ndev, param,
2271                                                       p->length);
2272                break;
2273        case PRISM2_HOSTAPD_MLME:
2274                printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
2275                                ndev->name);
2276                ret = prism2_ioctl_mlme(ndev, param);
2277                break;
2278        case PRISM2_HOSTAPD_SCAN_REQ:
2279                printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
2280                                ndev->name);
2281                ret = prism2_ioctl_scan_req(ndev, param);
2282                break;
2283         case PRISM54_SET_WPA:
2284                printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
2285                                ndev->name);
2286                uwrq = 1;
2287                ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
2288                break;
2289         case PRISM54_DROP_UNENCRYPTED:
2290                printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
2291                                ndev->name);
2292 #if 0
2293                uwrq = 0x01;
2294                mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
2295                down_write(&priv->mib_sem);
2296                mgt_commit(priv);
2297                up_write(&priv->mib_sem);
2298 #endif
2299                /* Not necessary, as set_wpa does it, should we just do it here though? */
2300                ret = 0;
2301                break;
2302        default:
2303                printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
2304                                ndev->name);
2305                ret = -EOPNOTSUPP;
2306                break;
2307        }
2308
2309        if (ret == 0 && copy_to_user(p->pointer, param, p->length))
2310                ret = -EFAULT;
2311
2312        kfree(param);
2313
2314        return ret;
2315 }
2316
2317 int
2318 prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
2319                 __u32 * uwrq, char *extra)
2320 {
2321         islpci_private *priv = netdev_priv(ndev);
2322         u32 mlme, authen, dot1x, filter, wep;
2323
2324         if (islpci_get_state(priv) < PRV_STATE_INIT)
2325                 return 0;
2326
2327         wep = 1; /* For privacy invoked */
2328         filter = 1; /* Filter out all unencrypted frames */
2329         dot1x = 0x01; /* To enable eap filter */
2330         mlme = DOT11_MLME_EXTENDED;
2331         authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
2332
2333         down_write(&priv->mib_sem);
2334         priv->wpa = *uwrq;
2335
2336         switch (priv->wpa) {
2337                 default:
2338                 case 0: /* Clears/disables WPA and friends */
2339                         wep = 0;
2340                         filter = 0; /* Do not filter un-encrypted data */
2341                         dot1x = 0;
2342                         mlme = DOT11_MLME_AUTO;
2343                         printk("%s: Disabling WPA\n", ndev->name);
2344                         break;
2345                 case 2: 
2346                 case 1: /* WPA */
2347                         printk("%s: Enabling WPA\n", ndev->name);
2348                         break;
2349         }
2350         up_write(&priv->mib_sem);
2351
2352         mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2353         mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
2354         mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
2355         mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
2356         mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
2357
2358         return 0;
2359 }
2360
2361 int
2362 prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
2363                 __u32 * uwrq, char *extra)
2364 {
2365         islpci_private *priv = netdev_priv(ndev);
2366         *uwrq = priv->wpa;
2367         return 0;
2368 }
2369
2370 int
2371 prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2372                      __u32 * uwrq, char *extra)
2373 {
2374         islpci_private *priv = netdev_priv(ndev);
2375         priv->monitor_type =
2376             (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
2377         if (priv->iw_mode == IW_MODE_MONITOR)
2378                 priv->ndev->type = priv->monitor_type;
2379
2380         return 0;
2381 }
2382
2383 int
2384 prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2385                      __u32 * uwrq, char *extra)
2386 {
2387         islpci_private *priv = netdev_priv(ndev);
2388         *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
2389         return 0;
2390 }
2391
2392 int
2393 prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
2394                   __u32 * uwrq, char *extra)
2395 {
2396         islpci_private *priv = netdev_priv(ndev);
2397
2398         priv->priv_oid = *uwrq;
2399         printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
2400
2401         return 0;
2402 }
2403
2404 int
2405 prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
2406                       struct iw_point *data, char *extra)
2407 {
2408         islpci_private *priv = netdev_priv(ndev);
2409         struct islpci_mgmtframe *response;
2410         int ret = -EIO;
2411
2412         printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
2413         data->length = 0;
2414
2415         if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2416                 ret =
2417                     islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
2418                                            priv->priv_oid, extra, 256,
2419                                            &response);
2420                 printk("%s: ret: %i\n", ndev->name, ret);
2421                 if (ret || !response
2422                     || response->header->operation == PIMFOR_OP_ERROR) {
2423                         if (response) {
2424                                 islpci_mgt_release(response);
2425                         }
2426                         printk("%s: EIO\n", ndev->name);
2427                         ret = -EIO;
2428                 }
2429                 if (!ret) {
2430                         data->length = response->header->length;
2431                         memcpy(extra, response->data, data->length);
2432                         islpci_mgt_release(response);
2433                         printk("%s: len: %i\n", ndev->name, data->length);
2434                 }
2435         }
2436
2437         return ret;
2438 }
2439
2440 int
2441 prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
2442                       struct iw_point *data, char *extra)
2443 {
2444         islpci_private *priv = netdev_priv(ndev);
2445         struct islpci_mgmtframe *response;
2446         int ret = 0, response_op = PIMFOR_OP_ERROR;
2447
2448         printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
2449                data->length);
2450
2451         if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2452                 ret =
2453                     islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
2454                                            priv->priv_oid, extra, data->length,
2455                                            &response);
2456                 printk("%s: ret: %i\n", ndev->name, ret);
2457                 if (ret || !response
2458                     || response->header->operation == PIMFOR_OP_ERROR) {
2459                         if (response) {
2460                                 islpci_mgt_release(response);
2461                         }
2462                         printk("%s: EIO\n", ndev->name);
2463                         ret = -EIO;
2464                 }
2465                 if (!ret) {
2466                         response_op = response->header->operation;
2467                         printk("%s: response_op: %i\n", ndev->name,
2468                                response_op);
2469                         islpci_mgt_release(response);
2470                 }
2471         }
2472
2473         return (ret ? ret : -EINPROGRESS);
2474 }
2475
2476 static int
2477 prism54_set_spy(struct net_device *ndev,
2478                 struct iw_request_info *info,
2479                 union iwreq_data *uwrq, char *extra)
2480 {
2481         islpci_private *priv = netdev_priv(ndev);
2482         u32 u, oid = OID_INL_CONFIG;
2483
2484         down_write(&priv->mib_sem);
2485         mgt_get(priv, OID_INL_CONFIG, &u);
2486
2487         if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
2488                 /* disable spy */
2489                 u &= ~INL_CONFIG_RXANNEX;
2490         else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
2491                 /* enable spy */
2492                 u |= INL_CONFIG_RXANNEX;
2493
2494         mgt_set(priv, OID_INL_CONFIG, &u);
2495         mgt_commit_list(priv, &oid, 1);
2496         up_write(&priv->mib_sem);
2497
2498         return iw_handler_set_spy(ndev, info, uwrq, extra);
2499 }
2500
2501 static const iw_handler prism54_handler[] = {
2502         (iw_handler) prism54_commit,    /* SIOCSIWCOMMIT */
2503         (iw_handler) prism54_get_name,  /* SIOCGIWNAME */
2504         (iw_handler) NULL,      /* SIOCSIWNWID */
2505         (iw_handler) NULL,      /* SIOCGIWNWID */
2506         (iw_handler) prism54_set_freq,  /* SIOCSIWFREQ */
2507         (iw_handler) prism54_get_freq,  /* SIOCGIWFREQ */
2508         (iw_handler) prism54_set_mode,  /* SIOCSIWMODE */
2509         (iw_handler) prism54_get_mode,  /* SIOCGIWMODE */
2510         (iw_handler) prism54_set_sens,  /* SIOCSIWSENS */
2511         (iw_handler) prism54_get_sens,  /* SIOCGIWSENS */
2512         (iw_handler) NULL,      /* SIOCSIWRANGE */
2513         (iw_handler) prism54_get_range, /* SIOCGIWRANGE */
2514         (iw_handler) NULL,      /* SIOCSIWPRIV */
2515         (iw_handler) NULL,      /* SIOCGIWPRIV */
2516         (iw_handler) NULL,      /* SIOCSIWSTATS */
2517         (iw_handler) NULL,      /* SIOCGIWSTATS */
2518         prism54_set_spy,        /* SIOCSIWSPY */
2519         iw_handler_get_spy,     /* SIOCGIWSPY */
2520         iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
2521         iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
2522         (iw_handler) prism54_set_wap,   /* SIOCSIWAP */
2523         (iw_handler) prism54_get_wap,   /* SIOCGIWAP */
2524         (iw_handler) NULL,      /* -- hole -- */
2525         (iw_handler) NULL,      /* SIOCGIWAPLIST depreciated */
2526         (iw_handler) prism54_set_scan,  /* SIOCSIWSCAN */
2527         (iw_handler) prism54_get_scan,  /* SIOCGIWSCAN */
2528         (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
2529         (iw_handler) prism54_get_essid, /* SIOCGIWESSID */
2530         (iw_handler) prism54_set_nick,  /* SIOCSIWNICKN */
2531         (iw_handler) prism54_get_nick,  /* SIOCGIWNICKN */
2532         (iw_handler) NULL,      /* -- hole -- */
2533         (iw_handler) NULL,      /* -- hole -- */
2534         (iw_handler) prism54_set_rate,  /* SIOCSIWRATE */
2535         (iw_handler) prism54_get_rate,  /* SIOCGIWRATE */
2536         (iw_handler) prism54_set_rts,   /* SIOCSIWRTS */
2537         (iw_handler) prism54_get_rts,   /* SIOCGIWRTS */
2538         (iw_handler) prism54_set_frag,  /* SIOCSIWFRAG */
2539         (iw_handler) prism54_get_frag,  /* SIOCGIWFRAG */
2540         (iw_handler) prism54_set_txpower,       /* SIOCSIWTXPOW */
2541         (iw_handler) prism54_get_txpower,       /* SIOCGIWTXPOW */
2542         (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
2543         (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
2544         (iw_handler) prism54_set_encode,        /* SIOCSIWENCODE */
2545         (iw_handler) prism54_get_encode,        /* SIOCGIWENCODE */
2546         (iw_handler) NULL,      /* SIOCSIWPOWER */
2547         (iw_handler) NULL,      /* SIOCGIWPOWER */
2548 };
2549
2550 /* The low order bit identify a SET (0) or a GET (1) ioctl.  */
2551
2552 #define PRISM54_RESET           SIOCIWFIRSTPRIV
2553 #define PRISM54_GET_POLICY      SIOCIWFIRSTPRIV+1
2554 #define PRISM54_SET_POLICY      SIOCIWFIRSTPRIV+2
2555 #define PRISM54_GET_MAC         SIOCIWFIRSTPRIV+3
2556 #define PRISM54_ADD_MAC         SIOCIWFIRSTPRIV+4
2557
2558 #define PRISM54_DEL_MAC         SIOCIWFIRSTPRIV+6
2559
2560 #define PRISM54_KICK_MAC        SIOCIWFIRSTPRIV+8
2561
2562 #define PRISM54_KICK_ALL        SIOCIWFIRSTPRIV+10
2563
2564 #define PRISM54_GET_WPA         SIOCIWFIRSTPRIV+11
2565 #define PRISM54_SET_WPA         SIOCIWFIRSTPRIV+12
2566
2567 #define PRISM54_DBG_OID         SIOCIWFIRSTPRIV+14
2568 #define PRISM54_DBG_GET_OID     SIOCIWFIRSTPRIV+15
2569 #define PRISM54_DBG_SET_OID     SIOCIWFIRSTPRIV+16
2570
2571 #define PRISM54_GET_OID         SIOCIWFIRSTPRIV+17
2572 #define PRISM54_SET_OID_U32     SIOCIWFIRSTPRIV+18
2573 #define PRISM54_SET_OID_STR     SIOCIWFIRSTPRIV+20
2574 #define PRISM54_SET_OID_ADDR    SIOCIWFIRSTPRIV+22
2575
2576 #define PRISM54_GET_PRISMHDR    SIOCIWFIRSTPRIV+23
2577 #define PRISM54_SET_PRISMHDR    SIOCIWFIRSTPRIV+24
2578
2579 #define IWPRIV_SET_U32(n,x)     { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2580 #define IWPRIV_SET_SSID(n,x)    { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2581 #define IWPRIV_SET_ADDR(n,x)    { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2582 #define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
2583
2584 #define IWPRIV_U32(n,x)         IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
2585 #define IWPRIV_SSID(n,x)        IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
2586 #define IWPRIV_ADDR(n,x)        IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
2587
2588 /* Note : limited to 128 private ioctls (wireless tools 26) */
2589
2590 static const struct iw_priv_args prism54_private_args[] = {
2591 /*{ cmd, set_args, get_args, name } */
2592         {PRISM54_RESET, 0, 0, "reset"},
2593         {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2594          "get_prismhdr"},
2595         {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2596          "set_prismhdr"},
2597         {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2598          "getPolicy"},
2599         {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2600          "setPolicy"},
2601         {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
2602         {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2603          "addMac"},
2604         {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2605          "delMac"},
2606         {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2607          "kickMac"},
2608         {PRISM54_KICK_ALL, 0, 0, "kickAll"},
2609         {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2610          "get_wpa"},
2611         {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2612          "set_wpa"},
2613         {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2614          "dbg_oid"},
2615         {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
2616         {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
2617         /* --- sub-ioctls handlers --- */
2618         {PRISM54_GET_OID,
2619          0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
2620         {PRISM54_SET_OID_U32,
2621          IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2622         {PRISM54_SET_OID_STR,
2623          IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2624         {PRISM54_SET_OID_ADDR,
2625          IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2626         /* --- sub-ioctls definitions --- */
2627         IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
2628         IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
2629         IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
2630         IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
2631         IWPRIV_U32(DOT11_OID_STATE, "state"),
2632         IWPRIV_U32(DOT11_OID_AID, "aid"),
2633
2634         IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
2635
2636         IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
2637         IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
2638         IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
2639
2640         IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
2641         IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
2642         IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
2643
2644         IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
2645
2646         IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
2647         IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
2648         IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
2649         IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
2650         IWPRIV_U32(DOT11_OID_PSM, "psm"),
2651
2652         IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
2653         IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
2654         IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
2655         IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
2656         IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
2657         IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
2658         IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
2659         IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
2660         IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
2661         IWPRIV_GET(DOT11_OID_RATES, "rates"),
2662         IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
2663         IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
2664         IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
2665
2666         IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
2667         IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
2668         IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
2669         IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
2670         IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
2671         IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
2672
2673         IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
2674         IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
2675         IWPRIV_U32(OID_INL_MODE, "mode"),
2676         IWPRIV_U32(OID_INL_CONFIG, "config"),
2677         IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
2678         IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
2679         IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
2680 };
2681
2682 static const iw_handler prism54_private_handler[] = {
2683         (iw_handler) prism54_reset,
2684         (iw_handler) prism54_get_policy,
2685         (iw_handler) prism54_set_policy,
2686         (iw_handler) prism54_get_mac,
2687         (iw_handler) prism54_add_mac,
2688         (iw_handler) NULL,
2689         (iw_handler) prism54_del_mac,
2690         (iw_handler) NULL,
2691         (iw_handler) prism54_kick_mac,
2692         (iw_handler) NULL,
2693         (iw_handler) prism54_kick_all,
2694         (iw_handler) prism54_get_wpa,
2695         (iw_handler) prism54_set_wpa,
2696         (iw_handler) NULL,
2697         (iw_handler) prism54_debug_oid,
2698         (iw_handler) prism54_debug_get_oid,
2699         (iw_handler) prism54_debug_set_oid,
2700         (iw_handler) prism54_get_oid,
2701         (iw_handler) prism54_set_u32,
2702         (iw_handler) NULL,
2703         (iw_handler) prism54_set_raw,
2704         (iw_handler) NULL,
2705         (iw_handler) prism54_set_raw,
2706         (iw_handler) prism54_get_prismhdr,
2707         (iw_handler) prism54_set_prismhdr,
2708 };
2709
2710 const struct iw_handler_def prism54_handler_def = {
2711         .num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
2712         .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
2713         .num_private_args =
2714             sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
2715         .standard = (iw_handler *) prism54_handler,
2716         .private = (iw_handler *) prism54_private_handler,
2717         .private_args = (struct iw_priv_args *) prism54_private_args,
2718 #if WIRELESS_EXT == 16
2719         .spy_offset = offsetof(islpci_private, spy_data),
2720 #endif /* WIRELESS_EXT == 16 */
2721 };
2722
2723 /* For wpa_supplicant */
2724
2725 int
2726 prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
2727 {
2728         struct iwreq *wrq = (struct iwreq *) rq;
2729         int ret = -1;
2730         switch (cmd) {
2731                 case PRISM54_HOSTAPD:
2732                 if (!capable(CAP_NET_ADMIN))
2733                 return -EPERM;
2734                 ret = prism54_hostapd(ndev, &wrq->u.data);
2735                 return ret;
2736         }
2737         return -EOPNOTSUPP;
2738 }