Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / net / wireless / bcm43xx / bcm43xx_wx.c
1 /*
2
3   Broadcom BCM43xx wireless driver
4
5   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6                      Stefano Brivio <st3@riseup.net>
7                      Michael Buesch <mbuesch@freenet.de>
8                      Danny van Dyk <kugelfang@gentoo.org>
9                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11   Some parts of the code in this file are derived from the ipw2200
12   driver  Copyright(c) 2003 - 2004 Intel Corporation.
13
14   This program is free software; you can redistribute it and/or modify
15   it under the terms of the GNU General Public License as published by
16   the Free Software Foundation; either version 2 of the License, or
17   (at your option) any later version.
18
19   This program is distributed in the hope that it will be useful,
20   but WITHOUT ANY WARRANTY; without even the implied warranty of
21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22   GNU General Public License for more details.
23
24   You should have received a copy of the GNU General Public License
25   along with this program; see the file COPYING.  If not, write to
26   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27   Boston, MA 02110-1301, USA.
28
29 */
30
31 #include <linux/wireless.h>
32 #include <net/iw_handler.h>
33 #include <net/ieee80211softmac.h>
34 #include <net/ieee80211softmac_wx.h>
35 #include <linux/capability.h>
36 #include <linux/sched.h> /* for capable() */
37 #include <linux/delay.h>
38
39 #include "bcm43xx.h"
40 #include "bcm43xx_wx.h"
41 #include "bcm43xx_main.h"
42 #include "bcm43xx_radio.h"
43 #include "bcm43xx_phy.h"
44
45
46 /* The WIRELESS_EXT version, which is implemented by this driver. */
47 #define BCM43xx_WX_VERSION      18
48
49 #define MAX_WX_STRING           80
50
51
52 static int bcm43xx_wx_get_name(struct net_device *net_dev,
53                                struct iw_request_info *info,
54                                union iwreq_data *data,
55                                char *extra)
56 {
57         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
58         int i;
59         struct bcm43xx_phyinfo *phy;
60         char suffix[7] = { 0 };
61         int have_a = 0, have_b = 0, have_g = 0;
62
63         mutex_lock(&bcm->mutex);
64         for (i = 0; i < bcm->nr_80211_available; i++) {
65                 phy = &(bcm->core_80211_ext[i].phy);
66                 switch (phy->type) {
67                 case BCM43xx_PHYTYPE_A:
68                         have_a = 1;
69                         break;
70                 case BCM43xx_PHYTYPE_G:
71                         have_g = 1;
72                 case BCM43xx_PHYTYPE_B:
73                         have_b = 1;
74                         break;
75                 default:
76                         assert(0);
77                 }
78         }
79         mutex_unlock(&bcm->mutex);
80
81         i = 0;
82         if (have_a) {
83                 suffix[i++] = 'a';
84                 suffix[i++] = '/';
85         }
86         if (have_b) {
87                 suffix[i++] = 'b';
88                 suffix[i++] = '/';
89         }
90         if (have_g) {
91                 suffix[i++] = 'g';
92                 suffix[i++] = '/';
93         }
94         if (i != 0) 
95                 suffix[i - 1] = '\0';
96
97         snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
98
99         return 0;
100 }
101
102 static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
103                                       struct iw_request_info *info,
104                                       union iwreq_data *data,
105                                       char *extra)
106 {
107         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
108         unsigned long flags;
109         u8 channel;
110         int freq;
111         int err = -EINVAL;
112
113         mutex_lock(&bcm->mutex);
114         spin_lock_irqsave(&bcm->irq_lock, flags);
115
116         if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
117                 channel = data->freq.m;
118                 freq = bcm43xx_channel_to_freq(bcm, channel);
119         } else {
120                 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
121                 freq = data->freq.m;
122         }
123         if (!ieee80211_is_valid_channel(bcm->ieee, channel))
124                 goto out_unlock;
125         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
126                 //ieee80211softmac_disassoc(softmac, $REASON);
127                 bcm43xx_mac_suspend(bcm);
128                 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
129                 bcm43xx_mac_enable(bcm);
130         } else {
131                 bcm43xx_current_radio(bcm)->initial_channel = channel;
132                 err = 0;
133         }
134 out_unlock:
135         spin_unlock_irqrestore(&bcm->irq_lock, flags);
136         mutex_unlock(&bcm->mutex);
137
138         return err;
139 }
140
141 static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
142                                       struct iw_request_info *info,
143                                       union iwreq_data *data,
144                                       char *extra)
145 {
146         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
147         struct bcm43xx_radioinfo *radio;
148         int err = -ENODEV;
149         u16 channel;
150
151         mutex_lock(&bcm->mutex);
152         radio = bcm43xx_current_radio(bcm);
153         channel = radio->channel;
154         if (channel == 0xFF) {
155                 channel = radio->initial_channel;
156                 if (channel == 0xFF)
157                         goto out_unlock;
158         }
159         assert(channel > 0 && channel <= 1000);
160         data->freq.e = 1;
161         data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
162         data->freq.flags = 1;
163
164         err = 0;
165 out_unlock:
166         mutex_unlock(&bcm->mutex);
167
168         return err;
169 }
170
171 static int bcm43xx_wx_set_mode(struct net_device *net_dev,
172                                struct iw_request_info *info,
173                                union iwreq_data *data,
174                                char *extra)
175 {
176         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
177         unsigned long flags;
178         int mode;
179
180         mode = data->mode;
181         if (mode == IW_MODE_AUTO)
182                 mode = BCM43xx_INITIAL_IWMODE;
183
184         mutex_lock(&bcm->mutex);
185         spin_lock_irqsave(&bcm->irq_lock, flags);
186         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
187                 if (bcm->ieee->iw_mode != mode)
188                         bcm43xx_set_iwmode(bcm, mode);
189         } else
190                 bcm->ieee->iw_mode = mode;
191         spin_unlock_irqrestore(&bcm->irq_lock, flags);
192         mutex_unlock(&bcm->mutex);
193
194         return 0;
195 }
196
197 static int bcm43xx_wx_get_mode(struct net_device *net_dev,
198                                struct iw_request_info *info,
199                                union iwreq_data *data,
200                                char *extra)
201 {
202         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
203
204         mutex_lock(&bcm->mutex);
205         data->mode = bcm->ieee->iw_mode;
206         mutex_unlock(&bcm->mutex);
207
208         return 0;
209 }
210
211 static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
212                                       struct iw_request_info *info,
213                                       union iwreq_data *data,
214                                       char *extra)
215 {
216         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
217         struct iw_range *range = (struct iw_range *)extra;
218         const struct ieee80211_geo *geo;
219         int i, j;
220         struct bcm43xx_phyinfo *phy;
221
222         data->data.length = sizeof(*range);
223         memset(range, 0, sizeof(*range));
224
225         //TODO: What about 802.11b?
226         /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
227         range->throughput = 27 * 1000 * 1000;
228
229         range->max_qual.qual = 100;
230         /* TODO: Real max RSSI */
231         range->max_qual.level = 3;
232         range->max_qual.noise = 100;
233         range->max_qual.updated = 7;
234
235         range->avg_qual.qual = 70;
236         range->avg_qual.level = 2;
237         range->avg_qual.noise = 40;
238         range->avg_qual.updated = 7;
239
240         range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
241         range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
242         range->min_frag = MIN_FRAG_THRESHOLD;
243         range->max_frag = MAX_FRAG_THRESHOLD;
244
245         range->encoding_size[0] = 5;
246         range->encoding_size[1] = 13;
247         range->num_encoding_sizes = 2;
248         range->max_encoding_tokens = WEP_KEYS;
249
250         range->we_version_compiled = WIRELESS_EXT;
251         range->we_version_source = BCM43xx_WX_VERSION;
252
253         range->enc_capa = IW_ENC_CAPA_WPA |
254                           IW_ENC_CAPA_WPA2 |
255                           IW_ENC_CAPA_CIPHER_TKIP |
256                           IW_ENC_CAPA_CIPHER_CCMP;
257
258         mutex_lock(&bcm->mutex);
259         phy = bcm43xx_current_phy(bcm);
260
261         range->num_bitrates = 0;
262         i = 0;
263         if (phy->type == BCM43xx_PHYTYPE_A ||
264             phy->type == BCM43xx_PHYTYPE_G) {
265                 range->num_bitrates = 8;
266                 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
267                 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
268                 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
269                 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
270                 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
271                 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
272                 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
273                 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
274         }
275         if (phy->type == BCM43xx_PHYTYPE_B ||
276             phy->type == BCM43xx_PHYTYPE_G) {
277                 range->num_bitrates += 4;
278                 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
279                 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
280                 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
281                 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
282         }
283
284         geo = ieee80211_get_geo(bcm->ieee);
285         range->num_channels = geo->a_channels + geo->bg_channels;
286         j = 0;
287         for (i = 0; i < geo->a_channels; i++) {
288                 if (j == IW_MAX_FREQUENCIES)
289                         break;
290                 range->freq[j].i = j + 1;
291                 range->freq[j].m = geo->a[i].freq;//FIXME?
292                 range->freq[j].e = 1;
293                 j++;
294         }
295         for (i = 0; i < geo->bg_channels; i++) {
296                 if (j == IW_MAX_FREQUENCIES)
297                         break;
298                 range->freq[j].i = j + 1;
299                 range->freq[j].m = geo->bg[i].freq;//FIXME?
300                 range->freq[j].e = 1;
301                 j++;
302         }
303         range->num_frequency = j;
304
305         mutex_unlock(&bcm->mutex);
306
307         return 0;
308 }
309
310 static int bcm43xx_wx_set_nick(struct net_device *net_dev,
311                                struct iw_request_info *info,
312                                union iwreq_data *data,
313                                char *extra)
314 {
315         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
316         size_t len;
317
318         mutex_lock(&bcm->mutex);
319         len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
320         memcpy(bcm->nick, extra, len);
321         bcm->nick[len] = '\0';
322         mutex_unlock(&bcm->mutex);
323
324         return 0;
325 }
326
327 static int bcm43xx_wx_get_nick(struct net_device *net_dev,
328                                struct iw_request_info *info,
329                                union iwreq_data *data,
330                                char *extra)
331 {
332         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
333         size_t len;
334
335         mutex_lock(&bcm->mutex);
336         len = strlen(bcm->nick) + 1;
337         memcpy(extra, bcm->nick, len);
338         data->data.length = (__u16)len;
339         data->data.flags = 1;
340         mutex_unlock(&bcm->mutex);
341
342         return 0;
343 }
344
345 static int bcm43xx_wx_set_rts(struct net_device *net_dev,
346                               struct iw_request_info *info,
347                               union iwreq_data *data,
348                               char *extra)
349 {
350         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
351         unsigned long flags;
352         int err = -EINVAL;
353
354         mutex_lock(&bcm->mutex);
355         spin_lock_irqsave(&bcm->irq_lock, flags);
356         if (data->rts.disabled) {
357                 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
358                 err = 0;
359         } else {
360                 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
361                     data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
362                         bcm->rts_threshold = data->rts.value;
363                         err = 0;
364                 }
365         }
366         spin_unlock_irqrestore(&bcm->irq_lock, flags);
367         mutex_unlock(&bcm->mutex);
368
369         return err;
370 }
371
372 static int bcm43xx_wx_get_rts(struct net_device *net_dev,
373                               struct iw_request_info *info,
374                               union iwreq_data *data,
375                               char *extra)
376 {
377         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
378
379         mutex_lock(&bcm->mutex);
380         data->rts.value = bcm->rts_threshold;
381         data->rts.fixed = 0;
382         data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
383         mutex_unlock(&bcm->mutex);
384
385         return 0;
386 }
387
388 static int bcm43xx_wx_set_frag(struct net_device *net_dev,
389                                struct iw_request_info *info,
390                                union iwreq_data *data,
391                                char *extra)
392 {
393         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
394         unsigned long flags;
395         int err = -EINVAL;
396
397         mutex_lock(&bcm->mutex);
398         spin_lock_irqsave(&bcm->irq_lock, flags);
399         if (data->frag.disabled) {
400                 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
401                 err = 0;
402         } else {
403                 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
404                     data->frag.value <= MAX_FRAG_THRESHOLD) {
405                         bcm->ieee->fts = data->frag.value & ~0x1;
406                         err = 0;
407                 }
408         }
409         spin_unlock_irqrestore(&bcm->irq_lock, flags);
410         mutex_unlock(&bcm->mutex);
411
412         return err;
413 }
414
415 static int bcm43xx_wx_get_frag(struct net_device *net_dev,
416                                struct iw_request_info *info,
417                                union iwreq_data *data,
418                                char *extra)
419 {
420         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
421
422         mutex_lock(&bcm->mutex);
423         data->frag.value = bcm->ieee->fts;
424         data->frag.fixed = 0;
425         data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
426         mutex_unlock(&bcm->mutex);
427
428         return 0;
429 }
430
431 static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
432                                     struct iw_request_info *info,
433                                     union iwreq_data *data,
434                                     char *extra)
435 {
436         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
437         struct bcm43xx_radioinfo *radio;
438         struct bcm43xx_phyinfo *phy;
439         unsigned long flags;
440         int err = -ENODEV;
441         u16 maxpower;
442
443         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
444                 printk(PFX KERN_ERR "TX power not in dBm.\n");
445                 return -EOPNOTSUPP;
446         }
447
448         mutex_lock(&bcm->mutex);
449         spin_lock_irqsave(&bcm->irq_lock, flags);
450         if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
451                 goto out_unlock;
452         radio = bcm43xx_current_radio(bcm);
453         phy = bcm43xx_current_phy(bcm);
454         if (data->txpower.disabled != (!(radio->enabled))) {
455                 if (data->txpower.disabled)
456                         bcm43xx_radio_turn_off(bcm);
457                 else
458                         bcm43xx_radio_turn_on(bcm);
459         }
460         if (data->txpower.value > 0) {
461                 /* desired and maxpower dBm values are in Q5.2 */
462                 if (phy->type == BCM43xx_PHYTYPE_A)
463                         maxpower = bcm->sprom.maxpower_aphy;
464                 else
465                         maxpower = bcm->sprom.maxpower_bgphy;
466                 radio->txpower_desired = limit_value(data->txpower.value << 2,
467                                                      0, maxpower);
468                 bcm43xx_phy_xmitpower(bcm);
469         }
470         err = 0;
471
472 out_unlock:
473         spin_unlock_irqrestore(&bcm->irq_lock, flags);
474         mutex_unlock(&bcm->mutex);
475
476         return err;
477 }
478
479 static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
480                                     struct iw_request_info *info,
481                                     union iwreq_data *data,
482                                     char *extra)
483 {
484         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
485         struct bcm43xx_radioinfo *radio;
486         int err = -ENODEV;
487
488         mutex_lock(&bcm->mutex);
489         if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
490                 goto out_unlock;
491         radio = bcm43xx_current_radio(bcm);
492         /* desired dBm value is in Q5.2 */
493         data->txpower.value = radio->txpower_desired >> 2;
494         data->txpower.fixed = 1;
495         data->txpower.flags = IW_TXPOW_DBM;
496         data->txpower.disabled = !(radio->enabled);
497
498         err = 0;
499 out_unlock:
500         mutex_unlock(&bcm->mutex);
501
502         return err;
503 }
504
505 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
506                                    struct iw_request_info *info,
507                                    union iwreq_data *data,
508                                    char *extra)
509 {
510         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
511         int err;
512
513         err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
514
515         return err;
516 }
517
518 static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
519                                    struct iw_request_info *info,
520                                    union iwreq_data *data,
521                                    char *extra)
522 {
523         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
524         int err;
525
526         err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
527
528         return err;
529 }
530
531 static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
532                                    struct iw_request_info *info,
533                                    union iwreq_data *data,
534                                    char *extra)
535 {
536         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
537         int err;
538
539         err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
540
541         return err;
542 }
543
544 static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
545                                    struct iw_request_info *info,
546                                    union iwreq_data *data,
547                                    char *extra)
548 {
549         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
550         int err;
551
552         err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
553
554         return err;
555 }
556
557 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
558                                      struct iw_request_info *info,
559                                      union iwreq_data *data,
560                                      char *extra)
561 {
562         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
563         unsigned long flags;
564         int mode, err = 0;
565
566         mode = *((int *)extra);
567         switch (mode) {
568         case 0:
569                 mode = BCM43xx_RADIO_INTERFMODE_NONE;
570                 break;
571         case 1:
572                 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
573                 break;
574         case 2:
575                 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
576                 break;
577         case 3:
578                 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
579                 break;
580         default:
581                 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
582                                     "0 => None,  1 => Non-WLAN,  2 => WLAN,  "
583                                     "3 => Auto-WLAN\n");
584                 return -EINVAL;
585         }
586
587         mutex_lock(&bcm->mutex);
588         spin_lock_irqsave(&bcm->irq_lock, flags);
589         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
590                 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
591                 if (err) {
592                         printk(KERN_ERR PFX "Interference Mitigation not "
593                                             "supported by device\n");
594                 }
595         } else {
596                 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
597                         printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
598                                             "not supported while the interface is down.\n");
599                         err = -ENODEV;
600                 } else
601                         bcm43xx_current_radio(bcm)->interfmode = mode;
602         }
603         spin_unlock_irqrestore(&bcm->irq_lock, flags);
604         mutex_unlock(&bcm->mutex);
605
606         return err;
607 }
608
609 static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
610                                      struct iw_request_info *info,
611                                      union iwreq_data *data,
612                                      char *extra)
613 {
614         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
615         int mode;
616
617         mutex_lock(&bcm->mutex);
618         mode = bcm43xx_current_radio(bcm)->interfmode;
619         mutex_unlock(&bcm->mutex);
620
621         switch (mode) {
622         case BCM43xx_RADIO_INTERFMODE_NONE:
623                 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
624                 break;
625         case BCM43xx_RADIO_INTERFMODE_NONWLAN:
626                 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
627                 break;
628         case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
629                 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
630                 break;
631         default:
632                 assert(0);
633         }
634         data->data.length = strlen(extra) + 1;
635
636         return 0;
637 }
638
639 static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
640                                         struct iw_request_info *info,
641                                         union iwreq_data *data,
642                                         char *extra)
643 {
644         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
645         unsigned long flags;
646         int on;
647
648         on = *((int *)extra);
649         mutex_lock(&bcm->mutex);
650         spin_lock_irqsave(&bcm->irq_lock, flags);
651         bcm->short_preamble = !!on;
652         spin_unlock_irqrestore(&bcm->irq_lock, flags);
653         mutex_unlock(&bcm->mutex);
654
655         return 0;
656 }
657
658 static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
659                                         struct iw_request_info *info,
660                                         union iwreq_data *data,
661                                         char *extra)
662 {
663         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
664         int on;
665
666         mutex_lock(&bcm->mutex);
667         on = bcm->short_preamble;
668         mutex_unlock(&bcm->mutex);
669
670         if (on)
671                 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
672         else
673                 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
674         data->data.length = strlen(extra) + 1;
675
676         return 0;
677 }
678
679 static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
680                                        struct iw_request_info *info,
681                                        union iwreq_data *data,
682                                        char *extra)
683 {
684         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
685         unsigned long flags;
686         int on;
687         
688         on = *((int *)extra);
689
690         mutex_lock(&bcm->mutex);
691         spin_lock_irqsave(&bcm->irq_lock, flags);
692         bcm->ieee->host_encrypt = !!on;
693         bcm->ieee->host_decrypt = !!on;
694         bcm->ieee->host_build_iv = !on;
695         spin_unlock_irqrestore(&bcm->irq_lock, flags);
696         mutex_unlock(&bcm->mutex);
697
698         return 0;
699 }
700
701 static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
702                                        struct iw_request_info *info,
703                                        union iwreq_data *data,
704                                        char *extra)
705 {
706         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
707         int on;
708
709         mutex_lock(&bcm->mutex);
710         on = bcm->ieee->host_encrypt;
711         mutex_unlock(&bcm->mutex);
712
713         if (on)
714                 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
715         else
716                 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
717         data->data.length = strlen(extra + 1);
718
719         return 0;
720 }
721
722 /* Enough buffer to hold a hexdump of the sprom data. */
723 #define SPROM_BUFFERSIZE        512
724
725 static int sprom2hex(const u16 *sprom, char *dump)
726 {
727         int i, pos = 0;
728
729         for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
730                 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
731                                 "%04X", swab16(sprom[i]) & 0xFFFF);
732         }
733
734         return pos + 1;
735 }
736
737 static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
738 {
739         char tmp[5] = { 0 };
740         int cnt = 0;
741         unsigned long parsed;
742
743         if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
744                 return -EINVAL;
745         while (cnt < BCM43xx_SPROM_SIZE) {
746                 memcpy(tmp, dump, 4);
747                 dump += 4;
748                 parsed = simple_strtoul(tmp, NULL, 16);
749                 sprom[cnt++] = swab16((u16)parsed);
750         }
751
752         return 0;
753 }
754
755 static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
756                                  struct iw_request_info *info,
757                                  union iwreq_data *data,
758                                  char *extra)
759 {
760         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
761         int err = -EPERM;
762         u16 *sprom;
763         unsigned long flags;
764
765         if (!capable(CAP_SYS_RAWIO))
766                 goto out;
767
768         err = -ENOMEM;
769         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
770                         GFP_KERNEL);
771         if (!sprom)
772                 goto out;
773
774         mutex_lock(&bcm->mutex);
775         spin_lock_irqsave(&bcm->irq_lock, flags);
776         err = -ENODEV;
777         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
778                 err = bcm43xx_sprom_read(bcm, sprom);
779         spin_unlock_irqrestore(&bcm->irq_lock, flags);
780         mutex_unlock(&bcm->mutex);
781         if (!err)
782                 data->data.length = sprom2hex(sprom, extra);
783         kfree(sprom);
784 out:
785         return err;
786 }
787
788 static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
789                                   struct iw_request_info *info,
790                                   union iwreq_data *data,
791                                   char *extra)
792 {
793         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
794         int err = -EPERM;
795         u16 *sprom;
796         unsigned long flags;
797         char *input;
798         unsigned int len;
799
800         if (!capable(CAP_SYS_RAWIO))
801                 goto out;
802
803         err = -ENOMEM;
804         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
805                         GFP_KERNEL);
806         if (!sprom)
807                 goto out;
808
809         len = data->data.length;
810         extra[len - 1] = '\0';
811         input = strchr(extra, ':');
812         if (input) {
813                 input++;
814                 len -= input - extra;
815         } else
816                 input = extra;
817         err = hex2sprom(sprom, input, len);
818         if (err)
819                 goto out_kfree;
820
821         mutex_lock(&bcm->mutex);
822         spin_lock_irqsave(&bcm->irq_lock, flags);
823         spin_lock(&bcm->leds_lock);
824         err = -ENODEV;
825         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
826                 err = bcm43xx_sprom_write(bcm, sprom);
827         spin_unlock(&bcm->leds_lock);
828         spin_unlock_irqrestore(&bcm->irq_lock, flags);
829         mutex_unlock(&bcm->mutex);
830 out_kfree:
831         kfree(sprom);
832 out:
833         return err;
834 }
835
836 /* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
837
838 static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
839 {
840         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
841         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
842         struct iw_statistics *wstats;
843
844         wstats = &bcm->stats.wstats;
845         if (!mac->associated) {
846                 wstats->miss.beacon = 0;
847 //              bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
848                 wstats->discard.retries = 0;
849 //              bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
850                 wstats->discard.nwid = 0;
851 //              bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
852                 wstats->discard.code = 0;
853 //              bcm->ieee->ieee_stats.rx_fragments = 0;  // FIXME: same here
854                 wstats->discard.fragment = 0;
855                 wstats->discard.misc = 0;
856                 wstats->qual.qual = 0;
857                 wstats->qual.level = 0;
858                 wstats->qual.noise = 0;
859                 wstats->qual.updated = 7;
860                 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
861                         IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
862                 return wstats;
863         }
864         /* fill in the real statistics when iface associated */
865         wstats->qual.qual = 100;     // TODO: get the real signal quality
866         wstats->qual.level = 3 - bcm->stats.link_quality;
867         wstats->qual.noise = bcm->stats.noise;
868         wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
869                         IW_QUAL_NOISE_UPDATED;
870         wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
871         wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
872         wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
873         wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
874         wstats->discard.misc = 0;       // FIXME
875         wstats->miss.beacon = 0;        // FIXME
876         return wstats;
877 }
878
879
880 #ifdef WX
881 # undef WX
882 #endif
883 #define WX(ioctl)  [(ioctl) - SIOCSIWCOMMIT]
884 static const iw_handler bcm43xx_wx_handlers[] = {
885         /* Wireless Identification */
886         WX(SIOCGIWNAME)         = bcm43xx_wx_get_name,
887         /* Basic operations */
888         WX(SIOCSIWFREQ)         = bcm43xx_wx_set_channelfreq,
889         WX(SIOCGIWFREQ)         = bcm43xx_wx_get_channelfreq,
890         WX(SIOCSIWMODE)         = bcm43xx_wx_set_mode,
891         WX(SIOCGIWMODE)         = bcm43xx_wx_get_mode,
892         /* Informative stuff */
893         WX(SIOCGIWRANGE)        = bcm43xx_wx_get_rangeparams,
894         /* Access Point manipulation */
895         WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
896         WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
897         WX(SIOCSIWSCAN)         = ieee80211softmac_wx_trigger_scan,
898         WX(SIOCGIWSCAN)         = ieee80211softmac_wx_get_scan_results,
899         /* 802.11 specific support */
900         WX(SIOCSIWESSID)        = ieee80211softmac_wx_set_essid,
901         WX(SIOCGIWESSID)        = ieee80211softmac_wx_get_essid,
902         WX(SIOCSIWNICKN)        = bcm43xx_wx_set_nick,
903         WX(SIOCGIWNICKN)        = bcm43xx_wx_get_nick,
904         /* Other parameters */
905         WX(SIOCSIWRATE)         = ieee80211softmac_wx_set_rate,
906         WX(SIOCGIWRATE)         = ieee80211softmac_wx_get_rate,
907         WX(SIOCSIWRTS)          = bcm43xx_wx_set_rts,
908         WX(SIOCGIWRTS)          = bcm43xx_wx_get_rts,
909         WX(SIOCSIWFRAG)         = bcm43xx_wx_set_frag,
910         WX(SIOCGIWFRAG)         = bcm43xx_wx_get_frag,
911         WX(SIOCSIWTXPOW)        = bcm43xx_wx_set_xmitpower,
912         WX(SIOCGIWTXPOW)        = bcm43xx_wx_get_xmitpower,
913 //TODO  WX(SIOCSIWRETRY)        = bcm43xx_wx_set_retry,
914 //TODO  WX(SIOCGIWRETRY)        = bcm43xx_wx_get_retry,
915         /* Encoding */
916         WX(SIOCSIWENCODE)       = bcm43xx_wx_set_encoding,
917         WX(SIOCGIWENCODE)       = bcm43xx_wx_get_encoding,
918         WX(SIOCSIWENCODEEXT)    = bcm43xx_wx_set_encodingext,
919         WX(SIOCGIWENCODEEXT)    = bcm43xx_wx_get_encodingext,
920         /* Power saving */
921 //TODO  WX(SIOCSIWPOWER)        = bcm43xx_wx_set_power,
922 //TODO  WX(SIOCGIWPOWER)        = bcm43xx_wx_get_power,
923         WX(SIOCSIWGENIE)        = ieee80211softmac_wx_set_genie,
924         WX(SIOCGIWGENIE)        = ieee80211softmac_wx_get_genie,
925         WX(SIOCSIWAUTH)         = ieee80211_wx_set_auth,
926         WX(SIOCGIWAUTH)         = ieee80211_wx_get_auth,
927 };
928 #undef WX
929
930 static const iw_handler bcm43xx_priv_wx_handlers[] = {
931         /* Set Interference Mitigation Mode. */
932         bcm43xx_wx_set_interfmode,
933         /* Get Interference Mitigation Mode. */
934         bcm43xx_wx_get_interfmode,
935         /* Enable/Disable Short Preamble mode. */
936         bcm43xx_wx_set_shortpreamble,
937         /* Get Short Preamble mode. */
938         bcm43xx_wx_get_shortpreamble,
939         /* Enable/Disable Software Encryption mode */
940         bcm43xx_wx_set_swencryption,
941         /* Get Software Encryption mode */
942         bcm43xx_wx_get_swencryption,
943         /* Write SRPROM data. */
944         bcm43xx_wx_sprom_write,
945         /* Read SPROM data. */
946         bcm43xx_wx_sprom_read,
947 };
948
949 #define PRIV_WX_SET_INTERFMODE          (SIOCIWFIRSTPRIV + 0)
950 #define PRIV_WX_GET_INTERFMODE          (SIOCIWFIRSTPRIV + 1)
951 #define PRIV_WX_SET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 2)
952 #define PRIV_WX_GET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 3)
953 #define PRIV_WX_SET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 4)
954 #define PRIV_WX_GET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 5)
955 #define PRIV_WX_SPROM_WRITE             (SIOCIWFIRSTPRIV + 6)
956 #define PRIV_WX_SPROM_READ              (SIOCIWFIRSTPRIV + 7)
957
958 #define PRIV_WX_DUMMY(ioctl)    \
959         {                                       \
960                 .cmd            = (ioctl),      \
961                 .name           = "__unused"    \
962         }
963
964 static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
965         {
966                 .cmd            = PRIV_WX_SET_INTERFMODE,
967                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
968                 .name           = "set_interfmode",
969         },
970         {
971                 .cmd            = PRIV_WX_GET_INTERFMODE,
972                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
973                 .name           = "get_interfmode",
974         },
975         {
976                 .cmd            = PRIV_WX_SET_SHORTPREAMBLE,
977                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
978                 .name           = "set_shortpreamb",
979         },
980         {
981                 .cmd            = PRIV_WX_GET_SHORTPREAMBLE,
982                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
983                 .name           = "get_shortpreamb",
984         },
985         {
986                 .cmd            = PRIV_WX_SET_SWENCRYPTION,
987                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
988                 .name           = "set_swencrypt",
989         },
990         {
991                 .cmd            = PRIV_WX_GET_SWENCRYPTION,
992                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
993                 .name           = "get_swencrypt",
994         },
995         {
996                 .cmd            = PRIV_WX_SPROM_WRITE,
997                 .set_args       = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
998                 .name           = "write_sprom",
999         },
1000         {
1001                 .cmd            = PRIV_WX_SPROM_READ,
1002                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1003                 .name           = "read_sprom",
1004         },
1005 };
1006
1007 const struct iw_handler_def bcm43xx_wx_handlers_def = {
1008         .standard               = bcm43xx_wx_handlers,
1009         .num_standard           = ARRAY_SIZE(bcm43xx_wx_handlers),
1010         .num_private            = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1011         .num_private_args       = ARRAY_SIZE(bcm43xx_priv_wx_args),
1012         .private                = bcm43xx_priv_wx_handlers,
1013         .private_args           = bcm43xx_priv_wx_args,
1014         .get_wireless_stats     = bcm43xx_get_wireless_stats,
1015 };