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