• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/drivers/net/wireless/libertas/
1/**
2  * This file contains ioctl functions
3  */
4#include <linux/ctype.h>
5#include <linux/delay.h>
6#include <linux/if.h>
7#include <linux/if_arp.h>
8#include <linux/wireless.h>
9#include <linux/bitops.h>
10
11#include <net/ieee80211.h>
12#include <net/iw_handler.h>
13
14#include "host.h"
15#include "radiotap.h"
16#include "decl.h"
17#include "defs.h"
18#include "dev.h"
19#include "join.h"
20#include "wext.h"
21#include "assoc.h"
22
23
24/**
25 * the rates supported by the card
26 */
27static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
28    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
29      0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
30};
31
32/**
33 *  @brief Convert mw value to dbm value
34 *
35 *  @param mw	   the value of mw
36 *  @return 	   the value of dbm
37 */
38static int mw_to_dbm(int mw)
39{
40	if (mw < 2)
41		return 0;
42	else if (mw < 3)
43		return 3;
44	else if (mw < 4)
45		return 5;
46	else if (mw < 6)
47		return 7;
48	else if (mw < 7)
49		return 8;
50	else if (mw < 8)
51		return 9;
52	else if (mw < 10)
53		return 10;
54	else if (mw < 13)
55		return 11;
56	else if (mw < 16)
57		return 12;
58	else if (mw < 20)
59		return 13;
60	else if (mw < 25)
61		return 14;
62	else if (mw < 32)
63		return 15;
64	else if (mw < 40)
65		return 16;
66	else if (mw < 50)
67		return 17;
68	else if (mw < 63)
69		return 18;
70	else if (mw < 79)
71		return 19;
72	else if (mw < 100)
73		return 20;
74	else
75		return 21;
76}
77
78/**
79 *  @brief Find the channel frequency power info with specific channel
80 *
81 *  @param adapter 	A pointer to wlan_adapter structure
82 *  @param band		it can be BAND_A, BAND_G or BAND_B
83 *  @param channel      the channel for looking
84 *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
85 */
86struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
87						 u8 band, u16 channel)
88{
89	struct chan_freq_power *cfp = NULL;
90	struct region_channel *rc;
91	int count = sizeof(adapter->region_channel) /
92	    sizeof(adapter->region_channel[0]);
93	int i, j;
94
95	for (j = 0; !cfp && (j < count); j++) {
96		rc = &adapter->region_channel[j];
97
98		if (adapter->enable11d)
99			rc = &adapter->universal_channel[j];
100		if (!rc->valid || !rc->CFP)
101			continue;
102		if (rc->band != band)
103			continue;
104		for (i = 0; i < rc->nrcfp; i++) {
105			if (rc->CFP[i].channel == channel) {
106				cfp = &rc->CFP[i];
107				break;
108			}
109		}
110	}
111
112	if (!cfp && channel)
113		lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
114		       "cfp by band %d / channel %d\n", band, channel);
115
116	return cfp;
117}
118
119/**
120 *  @brief Find the channel frequency power info with specific frequency
121 *
122 *  @param adapter 	A pointer to wlan_adapter structure
123 *  @param band		it can be BAND_A, BAND_G or BAND_B
124 *  @param freq	        the frequency for looking
125 *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
126 */
127static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
128						     u8 band, u32 freq)
129{
130	struct chan_freq_power *cfp = NULL;
131	struct region_channel *rc;
132	int count = sizeof(adapter->region_channel) /
133	    sizeof(adapter->region_channel[0]);
134	int i, j;
135
136	for (j = 0; !cfp && (j < count); j++) {
137		rc = &adapter->region_channel[j];
138
139		if (adapter->enable11d)
140			rc = &adapter->universal_channel[j];
141		if (!rc->valid || !rc->CFP)
142			continue;
143		if (rc->band != band)
144			continue;
145		for (i = 0; i < rc->nrcfp; i++) {
146			if (rc->CFP[i].freq == freq) {
147				cfp = &rc->CFP[i];
148				break;
149			}
150		}
151	}
152
153	if (!cfp && freq)
154		lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
155		       "band %d / freq %d\n", band, freq);
156
157	return cfp;
158}
159
160
161/**
162 *  @brief Set Radio On/OFF
163 *
164 *  @param priv                 A pointer to wlan_private structure
165 *  @option 			Radio Option
166 *  @return 	   		0 --success, otherwise fail
167 */
168int wlan_radio_ioctl(wlan_private * priv, u8 option)
169{
170	int ret = 0;
171	wlan_adapter *adapter = priv->adapter;
172
173	lbs_deb_enter(LBS_DEB_WEXT);
174
175	if (adapter->radioon != option) {
176		lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
177		adapter->radioon = option;
178
179		ret = libertas_prepare_and_send_command(priv,
180					    cmd_802_11_radio_control,
181					    cmd_act_set,
182					    cmd_option_waitforrsp, 0, NULL);
183	}
184
185	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
186	return ret;
187}
188
189/**
190 *  @brief Copy rates
191 *
192 *  @param dest                 A pointer to Dest Buf
193 *  @param src		        A pointer to Src Buf
194 *  @param len                  The len of Src Buf
195 *  @return 	   	        Number of rates copyed
196 */
197static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
198{
199	int i;
200
201	for (i = 0; i < len && src[i]; i++, pos++) {
202		if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
203			break;
204		dest[pos] = src[i];
205	}
206
207	return pos;
208}
209
210/**
211 *  @brief Get active data rates
212 *
213 *  @param adapter              A pointer to wlan_adapter structure
214 *  @param rate		        The buf to return the active rates
215 *  @return 	   	        The number of rates
216 */
217static int get_active_data_rates(wlan_adapter * adapter,
218				 u8* rates)
219{
220	int k = 0;
221
222	lbs_deb_enter(LBS_DEB_WEXT);
223
224	if (adapter->connect_status != libertas_connected) {
225		if (adapter->mode == IW_MODE_INFRA) {
226			lbs_deb_wext("infra\n");
227			k = copyrates(rates, k, libertas_supported_rates,
228				      sizeof(libertas_supported_rates));
229		} else {
230			lbs_deb_wext("Adhoc G\n");
231			k = copyrates(rates, k, libertas_adhoc_rates_g,
232				      sizeof(libertas_adhoc_rates_g));
233		}
234	} else {
235		k = copyrates(rates, 0, adapter->curbssparams.datarates,
236			      adapter->curbssparams.numofrates);
237	}
238
239	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
240	return k;
241}
242
243static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
244			 char *cwrq, char *extra)
245{
246	const char *cp;
247	char comm[6] = { "COMM-" };
248	char mrvl[6] = { "MRVL-" };
249	int cnt;
250
251	lbs_deb_enter(LBS_DEB_WEXT);
252
253	strcpy(cwrq, mrvl);
254
255	cp = strstr(libertas_driver_version, comm);
256	if (cp == libertas_driver_version)	//skip leading "COMM-"
257		cp = libertas_driver_version + strlen(comm);
258	else
259		cp = libertas_driver_version;
260
261	cnt = strlen(mrvl);
262	cwrq += cnt;
263	while (cnt < 16 && (*cp != '-')) {
264		*cwrq++ = toupper(*cp++);
265		cnt++;
266	}
267	*cwrq = '\0';
268
269	lbs_deb_leave(LBS_DEB_WEXT);
270	return 0;
271}
272
273static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
274			 struct iw_freq *fwrq, char *extra)
275{
276	wlan_private *priv = dev->priv;
277	wlan_adapter *adapter = priv->adapter;
278	struct chan_freq_power *cfp;
279
280	lbs_deb_enter(LBS_DEB_WEXT);
281
282	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
283					   adapter->curbssparams.channel);
284
285	if (!cfp) {
286		if (adapter->curbssparams.channel)
287			lbs_deb_wext("invalid channel %d\n",
288			       adapter->curbssparams.channel);
289		return -EINVAL;
290	}
291
292	fwrq->m = (long)cfp->freq * 100000;
293	fwrq->e = 1;
294
295	lbs_deb_wext("freq %u\n", fwrq->m);
296	lbs_deb_leave(LBS_DEB_WEXT);
297	return 0;
298}
299
300static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
301			struct sockaddr *awrq, char *extra)
302{
303	wlan_private *priv = dev->priv;
304	wlan_adapter *adapter = priv->adapter;
305
306	lbs_deb_enter(LBS_DEB_WEXT);
307
308	if (adapter->connect_status == libertas_connected) {
309		memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
310	} else {
311		memset(awrq->sa_data, 0, ETH_ALEN);
312	}
313	awrq->sa_family = ARPHRD_ETHER;
314
315	lbs_deb_leave(LBS_DEB_WEXT);
316	return 0;
317}
318
319static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
320			 struct iw_point *dwrq, char *extra)
321{
322	wlan_private *priv = dev->priv;
323	wlan_adapter *adapter = priv->adapter;
324
325	lbs_deb_enter(LBS_DEB_WEXT);
326
327	/*
328	 * Check the size of the string
329	 */
330
331	if (dwrq->length > 16) {
332		return -E2BIG;
333	}
334
335	mutex_lock(&adapter->lock);
336	memset(adapter->nodename, 0, sizeof(adapter->nodename));
337	memcpy(adapter->nodename, extra, dwrq->length);
338	mutex_unlock(&adapter->lock);
339
340	lbs_deb_leave(LBS_DEB_WEXT);
341	return 0;
342}
343
344static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
345			 struct iw_point *dwrq, char *extra)
346{
347	wlan_private *priv = dev->priv;
348	wlan_adapter *adapter = priv->adapter;
349
350	lbs_deb_enter(LBS_DEB_WEXT);
351
352	/*
353	 * Get the Nick Name saved
354	 */
355
356	mutex_lock(&adapter->lock);
357	strncpy(extra, adapter->nodename, 16);
358	mutex_unlock(&adapter->lock);
359
360	extra[16] = '\0';
361
362	/*
363	 * If none, we may want to get the one that was set
364	 */
365
366	/*
367	 * Push it out !
368	 */
369	dwrq->length = strlen(extra) + 1;
370
371	lbs_deb_leave(LBS_DEB_WEXT);
372	return 0;
373}
374
375static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
376			 struct iw_point *dwrq, char *extra)
377{
378	wlan_private *priv = dev->priv;
379	wlan_adapter *adapter = priv->adapter;
380
381	lbs_deb_enter(LBS_DEB_WEXT);
382
383	/* Use nickname to indicate that mesh is on */
384
385	if (adapter->connect_status == libertas_connected) {
386		strncpy(extra, "Mesh", 12);
387		extra[12] = '\0';
388		dwrq->length = strlen(extra) + 1;
389	}
390
391	else {
392		extra[0] = '\0';
393		dwrq->length = 1 ;
394	}
395
396	lbs_deb_leave(LBS_DEB_WEXT);
397	return 0;
398}
399static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
400			struct iw_param *vwrq, char *extra)
401{
402	int ret = 0;
403	wlan_private *priv = dev->priv;
404	wlan_adapter *adapter = priv->adapter;
405	u32 rthr = vwrq->value;
406
407	lbs_deb_enter(LBS_DEB_WEXT);
408
409	if (vwrq->disabled) {
410		adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
411	} else {
412		if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
413			return -EINVAL;
414		adapter->rtsthsd = rthr;
415	}
416
417	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
418				    cmd_act_set, cmd_option_waitforrsp,
419				    OID_802_11_RTS_THRESHOLD, &rthr);
420
421	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
422	return ret;
423}
424
425static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
426			struct iw_param *vwrq, char *extra)
427{
428	int ret = 0;
429	wlan_private *priv = dev->priv;
430	wlan_adapter *adapter = priv->adapter;
431
432	lbs_deb_enter(LBS_DEB_WEXT);
433
434	adapter->rtsthsd = 0;
435	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
436				    cmd_act_get, cmd_option_waitforrsp,
437				    OID_802_11_RTS_THRESHOLD, NULL);
438	if (ret)
439		goto out;
440
441	vwrq->value = adapter->rtsthsd;
442	vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
443			  || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
444	vwrq->fixed = 1;
445
446out:
447	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
448	return ret;
449}
450
451static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
452			 struct iw_param *vwrq, char *extra)
453{
454	int ret = 0;
455	u32 fthr = vwrq->value;
456	wlan_private *priv = dev->priv;
457	wlan_adapter *adapter = priv->adapter;
458
459	lbs_deb_enter(LBS_DEB_WEXT);
460
461	if (vwrq->disabled) {
462		adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
463	} else {
464		if (fthr < MRVDRV_FRAG_MIN_VALUE
465		    || fthr > MRVDRV_FRAG_MAX_VALUE)
466			return -EINVAL;
467		adapter->fragthsd = fthr;
468	}
469
470	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
471				    cmd_act_set, cmd_option_waitforrsp,
472				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
473
474	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
475	return ret;
476}
477
478static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
479			 struct iw_param *vwrq, char *extra)
480{
481	int ret = 0;
482	wlan_private *priv = dev->priv;
483	wlan_adapter *adapter = priv->adapter;
484
485	lbs_deb_enter(LBS_DEB_WEXT);
486
487	adapter->fragthsd = 0;
488	ret = libertas_prepare_and_send_command(priv,
489				    cmd_802_11_snmp_mib,
490				    cmd_act_get, cmd_option_waitforrsp,
491				    OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
492	if (ret)
493		goto out;
494
495	vwrq->value = adapter->fragthsd;
496	vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
497			  || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
498	vwrq->fixed = 1;
499
500out:
501	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
502	return ret;
503}
504
505static int wlan_get_mode(struct net_device *dev,
506			 struct iw_request_info *info, u32 * uwrq, char *extra)
507{
508	wlan_private *priv = dev->priv;
509	wlan_adapter *adapter = priv->adapter;
510
511	lbs_deb_enter(LBS_DEB_WEXT);
512
513	*uwrq = adapter->mode;
514
515	lbs_deb_leave(LBS_DEB_WEXT);
516	return 0;
517}
518
519static int mesh_wlan_get_mode(struct net_device *dev,
520		              struct iw_request_info *info, u32 * uwrq,
521			      char *extra)
522{
523	lbs_deb_enter(LBS_DEB_WEXT);
524
525	*uwrq = IW_MODE_REPEAT ;
526
527	lbs_deb_leave(LBS_DEB_WEXT);
528	return 0;
529}
530
531static int wlan_get_txpow(struct net_device *dev,
532			  struct iw_request_info *info,
533			  struct iw_param *vwrq, char *extra)
534{
535	int ret = 0;
536	wlan_private *priv = dev->priv;
537	wlan_adapter *adapter = priv->adapter;
538
539	lbs_deb_enter(LBS_DEB_WEXT);
540
541	ret = libertas_prepare_and_send_command(priv,
542				    cmd_802_11_rf_tx_power,
543				    cmd_act_tx_power_opt_get,
544				    cmd_option_waitforrsp, 0, NULL);
545
546	if (ret)
547		goto out;
548
549	lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
550	vwrq->value = adapter->txpowerlevel;
551	vwrq->fixed = 1;
552	if (adapter->radioon) {
553		vwrq->disabled = 0;
554		vwrq->flags = IW_TXPOW_DBM;
555	} else {
556		vwrq->disabled = 1;
557	}
558
559out:
560	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
561	return ret;
562}
563
564static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
565			  struct iw_param *vwrq, char *extra)
566{
567	int ret = 0;
568	wlan_private *priv = dev->priv;
569	wlan_adapter *adapter = priv->adapter;
570
571	lbs_deb_enter(LBS_DEB_WEXT);
572
573	if (vwrq->flags == IW_RETRY_LIMIT) {
574		/* The MAC has a 4-bit Total_Tx_Count register
575		   Total_Tx_Count = 1 + Tx_Retry_Count */
576#define TX_RETRY_MIN 0
577#define TX_RETRY_MAX 14
578		if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
579			return -EINVAL;
580
581		/* Adding 1 to convert retry count to try count */
582		adapter->txretrycount = vwrq->value + 1;
583
584		ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
585					    cmd_act_set,
586					    cmd_option_waitforrsp,
587					    OID_802_11_TX_RETRYCOUNT, NULL);
588
589		if (ret)
590			goto out;
591	} else {
592		return -EOPNOTSUPP;
593	}
594
595out:
596	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
597	return ret;
598}
599
600static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
601			  struct iw_param *vwrq, char *extra)
602{
603	wlan_private *priv = dev->priv;
604	wlan_adapter *adapter = priv->adapter;
605	int ret = 0;
606
607	lbs_deb_enter(LBS_DEB_WEXT);
608
609	adapter->txretrycount = 0;
610	ret = libertas_prepare_and_send_command(priv,
611				    cmd_802_11_snmp_mib,
612				    cmd_act_get, cmd_option_waitforrsp,
613				    OID_802_11_TX_RETRYCOUNT, NULL);
614	if (ret)
615		goto out;
616
617	vwrq->disabled = 0;
618	if (!vwrq->flags) {
619		vwrq->flags = IW_RETRY_LIMIT;
620		/* Subtract 1 to convert try count to retry count */
621		vwrq->value = adapter->txretrycount - 1;
622	}
623
624out:
625	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
626	return ret;
627}
628
629static inline void sort_channels(struct iw_freq *freq, int num)
630{
631	int i, j;
632	struct iw_freq temp;
633
634	for (i = 0; i < num; i++)
635		for (j = i + 1; j < num; j++)
636			if (freq[i].i > freq[j].i) {
637				temp.i = freq[i].i;
638				temp.m = freq[i].m;
639
640				freq[i].i = freq[j].i;
641				freq[i].m = freq[j].m;
642
643				freq[j].i = temp.i;
644				freq[j].m = temp.m;
645			}
646}
647
648/* data rate listing
649	MULTI_BANDS:
650		abg		a	b	b/g
651   Infra 	G(12)		A(8)	B(4)	G(12)
652   Adhoc 	A+B(12)		A(8)	B(4)	B(4)
653
654	non-MULTI_BANDS:
655					b	b/g
656   Infra 	     		    	B(4)	G(12)
657   Adhoc 	      		    	B(4)	B(4)
658 */
659/**
660 *  @brief Get Range Info
661 *
662 *  @param dev                  A pointer to net_device structure
663 *  @param info			A pointer to iw_request_info structure
664 *  @param vwrq 		A pointer to iw_param structure
665 *  @param extra		A pointer to extra data buf
666 *  @return 	   		0 --success, otherwise fail
667 */
668static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
669			  struct iw_point *dwrq, char *extra)
670{
671	int i, j;
672	wlan_private *priv = dev->priv;
673	wlan_adapter *adapter = priv->adapter;
674	struct iw_range *range = (struct iw_range *)extra;
675	struct chan_freq_power *cfp;
676	u8 rates[WLAN_SUPPORTED_RATES];
677
678	u8 flag = 0;
679
680	lbs_deb_enter(LBS_DEB_WEXT);
681
682	dwrq->length = sizeof(struct iw_range);
683	memset(range, 0, sizeof(struct iw_range));
684
685	range->min_nwid = 0;
686	range->max_nwid = 0;
687
688	memset(rates, 0, sizeof(rates));
689	range->num_bitrates = get_active_data_rates(adapter, rates);
690
691	for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
692	     i++) {
693		range->bitrate[i] = (rates[i] & 0x7f) * 500000;
694	}
695	range->num_bitrates = i;
696	lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
697	       range->num_bitrates);
698
699	range->num_frequency = 0;
700	if (priv->adapter->enable11d &&
701	    adapter->connect_status == libertas_connected) {
702		u8 chan_no;
703		u8 band;
704
705		struct parsed_region_chan_11d *parsed_region_chan =
706		    &adapter->parsed_region_chan;
707
708		if (parsed_region_chan == NULL) {
709			lbs_deb_wext("11d: parsed_region_chan is NULL\n");
710			goto out;
711		}
712		band = parsed_region_chan->band;
713		lbs_deb_wext("band %d, nr_char %d\n", band,
714		       parsed_region_chan->nr_chan);
715
716		for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
717		     && (i < parsed_region_chan->nr_chan); i++) {
718			chan_no = parsed_region_chan->chanpwr[i].chan;
719			lbs_deb_wext("chan_no %d\n", chan_no);
720			range->freq[range->num_frequency].i = (long)chan_no;
721			range->freq[range->num_frequency].m =
722			    (long)libertas_chan_2_freq(chan_no, band) * 100000;
723			range->freq[range->num_frequency].e = 1;
724			range->num_frequency++;
725		}
726		flag = 1;
727	}
728	if (!flag) {
729		for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
730		     && (j < sizeof(adapter->region_channel)
731			 / sizeof(adapter->region_channel[0])); j++) {
732			cfp = adapter->region_channel[j].CFP;
733			for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
734			     && adapter->region_channel[j].valid
735			     && cfp
736			     && (i < adapter->region_channel[j].nrcfp); i++) {
737				range->freq[range->num_frequency].i =
738				    (long)cfp->channel;
739				range->freq[range->num_frequency].m =
740				    (long)cfp->freq * 100000;
741				range->freq[range->num_frequency].e = 1;
742				cfp++;
743				range->num_frequency++;
744			}
745		}
746	}
747
748	lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
749	       IW_MAX_FREQUENCIES, range->num_frequency);
750
751	range->num_channels = range->num_frequency;
752
753	sort_channels(&range->freq[0], range->num_frequency);
754
755	/*
756	 * Set an indication of the max TCP throughput in bit/s that we can
757	 * expect using this interface
758	 */
759	if (i > 2)
760		range->throughput = 5000 * 1000;
761	else
762		range->throughput = 1500 * 1000;
763
764	range->min_rts = MRVDRV_RTS_MIN_VALUE;
765	range->max_rts = MRVDRV_RTS_MAX_VALUE;
766	range->min_frag = MRVDRV_FRAG_MIN_VALUE;
767	range->max_frag = MRVDRV_FRAG_MAX_VALUE;
768
769	range->encoding_size[0] = 5;
770	range->encoding_size[1] = 13;
771	range->num_encoding_sizes = 2;
772	range->max_encoding_tokens = 4;
773
774	range->min_pmp = 1000000;
775	range->max_pmp = 120000000;
776	range->min_pmt = 1000;
777	range->max_pmt = 1000000;
778	range->pmp_flags = IW_POWER_PERIOD;
779	range->pmt_flags = IW_POWER_TIMEOUT;
780	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
781
782	/*
783	 * Minimum version we recommend
784	 */
785	range->we_version_source = 15;
786
787	/*
788	 * Version we are compiled with
789	 */
790	range->we_version_compiled = WIRELESS_EXT;
791
792	range->retry_capa = IW_RETRY_LIMIT;
793	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
794
795	range->min_retry = TX_RETRY_MIN;
796	range->max_retry = TX_RETRY_MAX;
797
798	/*
799	 * Set the qual, level and noise range values
800	 */
801	range->max_qual.qual = 100;
802	range->max_qual.level = 0;
803	range->max_qual.noise = 0;
804	range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
805
806	range->avg_qual.qual = 70;
807	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
808	range->avg_qual.level = 0;
809	range->avg_qual.noise = 0;
810	range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
811
812	range->sensitivity = 0;
813
814	/*
815	 * Setup the supported power level ranges
816	 */
817	memset(range->txpower, 0, sizeof(range->txpower));
818	range->txpower[0] = 5;
819	range->txpower[1] = 7;
820	range->txpower[2] = 9;
821	range->txpower[3] = 11;
822	range->txpower[4] = 13;
823	range->txpower[5] = 15;
824	range->txpower[6] = 17;
825	range->txpower[7] = 19;
826
827	range->num_txpower = 8;
828	range->txpower_capa = IW_TXPOW_DBM;
829	range->txpower_capa |= IW_TXPOW_RANGE;
830
831	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
832				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
833				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
834	range->event_capa[1] = IW_EVENT_CAPA_K_1;
835
836	if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
837		range->enc_capa =   IW_ENC_CAPA_WPA
838		                  | IW_ENC_CAPA_WPA2
839		                  | IW_ENC_CAPA_CIPHER_TKIP
840		                  | IW_ENC_CAPA_CIPHER_CCMP;
841	}
842
843out:
844	lbs_deb_leave(LBS_DEB_WEXT);
845	return 0;
846}
847
848static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
849			  struct iw_param *vwrq, char *extra)
850{
851	wlan_private *priv = dev->priv;
852	wlan_adapter *adapter = priv->adapter;
853
854	lbs_deb_enter(LBS_DEB_WEXT);
855
856	/* PS is currently supported only in Infrastructure mode
857	 * Remove this check if it is to be supported in IBSS mode also
858	 */
859
860	if (vwrq->disabled) {
861		adapter->psmode = wlan802_11powermodecam;
862		if (adapter->psstate != PS_STATE_FULL_POWER) {
863			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
864		}
865
866		return 0;
867	}
868
869	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
870		lbs_deb_wext(
871		       "setting power timeout is not supported\n");
872		return -EINVAL;
873	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
874		lbs_deb_wext("setting power period not supported\n");
875		return -EINVAL;
876	}
877
878	if (adapter->psmode != wlan802_11powermodecam) {
879		return 0;
880	}
881
882	adapter->psmode = wlan802_11powermodemax_psp;
883
884	if (adapter->connect_status == libertas_connected) {
885		libertas_ps_sleep(priv, cmd_option_waitforrsp);
886	}
887
888	lbs_deb_leave(LBS_DEB_WEXT);
889	return 0;
890}
891
892static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
893			  struct iw_param *vwrq, char *extra)
894{
895	wlan_private *priv = dev->priv;
896	wlan_adapter *adapter = priv->adapter;
897	int mode;
898
899	lbs_deb_enter(LBS_DEB_WEXT);
900
901	mode = adapter->psmode;
902
903	if ((vwrq->disabled = (mode == wlan802_11powermodecam))
904	    || adapter->connect_status == libertas_disconnected)
905	{
906		goto out;
907	}
908
909	vwrq->value = 0;
910
911out:
912	lbs_deb_leave(LBS_DEB_WEXT);
913	return 0;
914}
915
916static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
917{
918	enum {
919		POOR = 30,
920		FAIR = 60,
921		GOOD = 80,
922		VERY_GOOD = 90,
923		EXCELLENT = 95,
924		PERFECT = 100
925	};
926	wlan_private *priv = dev->priv;
927	wlan_adapter *adapter = priv->adapter;
928	u32 rssi_qual;
929	u32 tx_qual;
930	u32 quality = 0;
931	int stats_valid = 0;
932	u8 rssi;
933	u32 tx_retries;
934
935	lbs_deb_enter(LBS_DEB_WEXT);
936
937	priv->wstats.status = adapter->mode;
938
939	/* If we're not associated, all quality values are meaningless */
940	if (adapter->connect_status != libertas_connected)
941		goto out;
942
943	/* Quality by RSSI */
944	priv->wstats.qual.level =
945	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
946	     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
947
948	if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
949		priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
950	} else {
951		priv->wstats.qual.noise =
952		    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
953	}
954
955	lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
956	lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
957
958	rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
959	if (rssi < 15)
960		rssi_qual = rssi * POOR / 10;
961	else if (rssi < 20)
962		rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
963	else if (rssi < 30)
964		rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
965	else if (rssi < 40)
966		rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
967		    10 + GOOD;
968	else
969		rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
970		    10 + VERY_GOOD;
971	quality = rssi_qual;
972
973	/* Quality by TX errors */
974	priv->wstats.discard.retries = priv->stats.tx_errors;
975
976	tx_retries = le16_to_cpu(adapter->logmsg.retry);
977
978	if (tx_retries > 75)
979		tx_qual = (90 - tx_retries) * POOR / 15;
980	else if (tx_retries > 70)
981		tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
982	else if (tx_retries > 65)
983		tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
984	else if (tx_retries > 50)
985		tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
986		    15 + GOOD;
987	else
988		tx_qual = (50 - tx_retries) *
989		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
990	quality = min(quality, tx_qual);
991
992	priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable);
993	priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag);
994	priv->wstats.discard.retries = tx_retries;
995	priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure);
996
997	/* Calculate quality */
998	priv->wstats.qual.qual = max(quality, (u32)100);
999	priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1000	stats_valid = 1;
1001
1002	/* update stats asynchronously for future calls */
1003	libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
1004					0, 0, NULL);
1005	libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
1006					0, 0, NULL);
1007out:
1008	if (!stats_valid) {
1009		priv->wstats.miss.beacon = 0;
1010		priv->wstats.discard.retries = 0;
1011		priv->wstats.qual.qual = 0;
1012		priv->wstats.qual.level = 0;
1013		priv->wstats.qual.noise = 0;
1014		priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
1015		priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
1016		    IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
1017	}
1018
1019	lbs_deb_leave(LBS_DEB_WEXT);
1020	return &priv->wstats;
1021
1022
1023}
1024
1025static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
1026		  struct iw_freq *fwrq, char *extra)
1027{
1028	int ret = -EINVAL;
1029	wlan_private *priv = dev->priv;
1030	wlan_adapter *adapter = priv->adapter;
1031	struct chan_freq_power *cfp;
1032	struct assoc_request * assoc_req;
1033
1034	lbs_deb_enter(LBS_DEB_WEXT);
1035
1036	mutex_lock(&adapter->lock);
1037	assoc_req = wlan_get_association_request(adapter);
1038	if (!assoc_req) {
1039		ret = -ENOMEM;
1040		goto out;
1041	}
1042
1043	/* If setting by frequency, convert to a channel */
1044	if (fwrq->e == 1) {
1045		long f = fwrq->m / 100000;
1046
1047		cfp = find_cfp_by_band_and_freq(adapter, 0, f);
1048		if (!cfp) {
1049			lbs_deb_wext("invalid freq %ld\n", f);
1050			goto out;
1051		}
1052
1053		fwrq->e = 0;
1054		fwrq->m = (int) cfp->channel;
1055	}
1056
1057	/* Setting by channel number */
1058	if (fwrq->m > 1000 || fwrq->e > 0) {
1059		goto out;
1060	}
1061
1062	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m);
1063	if (!cfp) {
1064		goto out;
1065	}
1066
1067	assoc_req->channel = fwrq->m;
1068	ret = 0;
1069
1070out:
1071	if (ret == 0) {
1072		set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
1073		wlan_postpone_association_work(priv);
1074	} else {
1075		wlan_cancel_association_work(priv);
1076	}
1077	mutex_unlock(&adapter->lock);
1078
1079	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1080	return ret;
1081}
1082
1083/**
1084 *  @brief use index to get the data rate
1085 *
1086 *  @param index                The index of data rate
1087 *  @return 	   		data rate or 0
1088 */
1089u32 libertas_index_to_data_rate(u8 index)
1090{
1091	if (index >= sizeof(libertas_wlan_data_rates))
1092		index = 0;
1093
1094	return libertas_wlan_data_rates[index];
1095}
1096
1097/**
1098 *  @brief use rate to get the index
1099 *
1100 *  @param rate                 data rate
1101 *  @return 	   		index or 0
1102 */
1103u8 libertas_data_rate_to_index(u32 rate)
1104{
1105	u8 *ptr;
1106
1107	if (rate)
1108		if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1109				  sizeof(libertas_wlan_data_rates))))
1110			return (ptr - libertas_wlan_data_rates);
1111
1112	return 0;
1113}
1114
1115static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1116		  struct iw_param *vwrq, char *extra)
1117{
1118	wlan_private *priv = dev->priv;
1119	wlan_adapter *adapter = priv->adapter;
1120	u32 data_rate;
1121	u16 action;
1122	int ret = 0;
1123	u8 rates[WLAN_SUPPORTED_RATES];
1124	u8 *rate;
1125
1126	lbs_deb_enter(LBS_DEB_WEXT);
1127
1128	lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1129
1130	if (vwrq->value == -1) {
1131		action = cmd_act_set_tx_auto;	// Auto
1132		adapter->is_datarate_auto = 1;
1133		adapter->datarate = 0;
1134	} else {
1135		if (vwrq->value % 100000) {
1136			return -EINVAL;
1137		}
1138
1139		data_rate = vwrq->value / 500000;
1140
1141		memset(rates, 0, sizeof(rates));
1142		get_active_data_rates(adapter, rates);
1143		rate = rates;
1144		while (*rate) {
1145			lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
1146			       data_rate);
1147			if ((*rate & 0x7f) == (data_rate & 0x7f))
1148				break;
1149			rate++;
1150		}
1151		if (!*rate) {
1152			lbs_pr_alert("fixed data rate 0x%X out "
1153			       "of range\n", data_rate);
1154			return -EINVAL;
1155		}
1156
1157		adapter->datarate = data_rate;
1158		action = cmd_act_set_tx_fix_rate;
1159		adapter->is_datarate_auto = 0;
1160	}
1161
1162	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
1163				    action, cmd_option_waitforrsp, 0, NULL);
1164
1165	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1166	return ret;
1167}
1168
1169static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1170		  struct iw_param *vwrq, char *extra)
1171{
1172	wlan_private *priv = dev->priv;
1173	wlan_adapter *adapter = priv->adapter;
1174
1175	lbs_deb_enter(LBS_DEB_WEXT);
1176
1177	if (adapter->is_datarate_auto) {
1178		vwrq->fixed = 0;
1179	} else {
1180		vwrq->fixed = 1;
1181	}
1182
1183	vwrq->value = adapter->datarate * 500000;
1184
1185	lbs_deb_leave(LBS_DEB_WEXT);
1186	return 0;
1187}
1188
1189static int wlan_set_mode(struct net_device *dev,
1190		  struct iw_request_info *info, u32 * uwrq, char *extra)
1191{
1192	int ret = 0;
1193	wlan_private *priv = dev->priv;
1194	wlan_adapter *adapter = priv->adapter;
1195	struct assoc_request * assoc_req;
1196
1197	lbs_deb_enter(LBS_DEB_WEXT);
1198
1199	if (   (*uwrq != IW_MODE_ADHOC)
1200	    && (*uwrq != IW_MODE_INFRA)
1201	    && (*uwrq != IW_MODE_AUTO)) {
1202		lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
1203		ret = -EINVAL;
1204		goto out;
1205	}
1206
1207	mutex_lock(&adapter->lock);
1208	assoc_req = wlan_get_association_request(adapter);
1209	if (!assoc_req) {
1210		ret = -ENOMEM;
1211		wlan_cancel_association_work(priv);
1212	} else {
1213		assoc_req->mode = *uwrq;
1214		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1215		wlan_postpone_association_work(priv);
1216		lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
1217	}
1218	mutex_unlock(&adapter->lock);
1219
1220out:
1221	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1222	return ret;
1223}
1224
1225
1226/**
1227 *  @brief Get Encryption key
1228 *
1229 *  @param dev                  A pointer to net_device structure
1230 *  @param info			A pointer to iw_request_info structure
1231 *  @param vwrq 		A pointer to iw_param structure
1232 *  @param extra		A pointer to extra data buf
1233 *  @return 	   		0 --success, otherwise fail
1234 */
1235static int wlan_get_encode(struct net_device *dev,
1236			   struct iw_request_info *info,
1237			   struct iw_point *dwrq, u8 * extra)
1238{
1239	wlan_private *priv = dev->priv;
1240	wlan_adapter *adapter = priv->adapter;
1241	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1242
1243	lbs_deb_enter(LBS_DEB_WEXT);
1244
1245	lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
1246	       dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1247
1248	dwrq->flags = 0;
1249
1250	/* Authentication method */
1251	switch (adapter->secinfo.auth_mode) {
1252	case IW_AUTH_ALG_OPEN_SYSTEM:
1253		dwrq->flags = IW_ENCODE_OPEN;
1254		break;
1255
1256	case IW_AUTH_ALG_SHARED_KEY:
1257	case IW_AUTH_ALG_LEAP:
1258		dwrq->flags = IW_ENCODE_RESTRICTED;
1259		break;
1260	default:
1261		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1262		break;
1263	}
1264
1265	if (   adapter->secinfo.wep_enabled
1266	    || adapter->secinfo.WPAenabled
1267	    || adapter->secinfo.WPA2enabled) {
1268		dwrq->flags &= ~IW_ENCODE_DISABLED;
1269	} else {
1270		dwrq->flags |= IW_ENCODE_DISABLED;
1271	}
1272
1273	memset(extra, 0, 16);
1274
1275	mutex_lock(&adapter->lock);
1276
1277	/* Default to returning current transmit key */
1278	if (index < 0)
1279		index = adapter->wep_tx_keyidx;
1280
1281	if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
1282		memcpy(extra, adapter->wep_keys[index].key,
1283		       adapter->wep_keys[index].len);
1284		dwrq->length = adapter->wep_keys[index].len;
1285
1286		dwrq->flags |= (index + 1);
1287		/* Return WEP enabled */
1288		dwrq->flags &= ~IW_ENCODE_DISABLED;
1289	} else if ((adapter->secinfo.WPAenabled)
1290		   || (adapter->secinfo.WPA2enabled)) {
1291		/* return WPA enabled */
1292		dwrq->flags &= ~IW_ENCODE_DISABLED;
1293	} else {
1294		dwrq->flags |= IW_ENCODE_DISABLED;
1295	}
1296
1297	mutex_unlock(&adapter->lock);
1298
1299	dwrq->flags |= IW_ENCODE_NOKEY;
1300
1301	lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
1302	       extra[0], extra[1], extra[2],
1303	       extra[3], extra[4], extra[5], dwrq->length);
1304
1305	lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
1306
1307	lbs_deb_leave(LBS_DEB_WEXT);
1308	return 0;
1309}
1310
1311/**
1312 *  @brief Set Encryption key (internal)
1313 *
1314 *  @param priv			A pointer to private card structure
1315 *  @param key_material		A pointer to key material
1316 *  @param key_length		length of key material
1317 *  @param index		key index to set
1318 *  @param set_tx_key		Force set TX key (1 = yes, 0 = no)
1319 *  @return 	   		0 --success, otherwise fail
1320 */
1321static int wlan_set_wep_key(struct assoc_request *assoc_req,
1322			    const char *key_material,
1323			    u16 key_length,
1324			    u16 index,
1325			    int set_tx_key)
1326{
1327	int ret = 0;
1328	struct WLAN_802_11_KEY *pkey;
1329
1330	lbs_deb_enter(LBS_DEB_WEXT);
1331
1332	/* Paranoid validation of key index */
1333	if (index > 3) {
1334		ret = -EINVAL;
1335		goto out;
1336	}
1337
1338	/* validate max key length */
1339	if (key_length > KEY_LEN_WEP_104) {
1340		ret = -EINVAL;
1341		goto out;
1342	}
1343
1344	pkey = &assoc_req->wep_keys[index];
1345
1346	if (key_length > 0) {
1347		memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
1348		pkey->type = KEY_TYPE_ID_WEP;
1349
1350		/* Standardize the key length */
1351		pkey->len = (key_length > KEY_LEN_WEP_40) ?
1352		                KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1353		memcpy(pkey->key, key_material, key_length);
1354	}
1355
1356	if (set_tx_key) {
1357		/* Ensure the chosen key is valid */
1358		if (!pkey->len) {
1359			lbs_deb_wext("key not set, so cannot enable it\n");
1360			ret = -EINVAL;
1361			goto out;
1362		}
1363		assoc_req->wep_tx_keyidx = index;
1364	}
1365
1366	assoc_req->secinfo.wep_enabled = 1;
1367
1368out:
1369	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1370	return ret;
1371}
1372
1373static int validate_key_index(u16 def_index, u16 raw_index,
1374			      u16 *out_index, u16 *is_default)
1375{
1376	if (!out_index || !is_default)
1377		return -EINVAL;
1378
1379	/* Verify index if present, otherwise use default TX key index */
1380	if (raw_index > 0) {
1381		if (raw_index > 4)
1382			return -EINVAL;
1383		*out_index = raw_index - 1;
1384	} else {
1385		*out_index = def_index;
1386		*is_default = 1;
1387	}
1388	return 0;
1389}
1390
1391static void disable_wep(struct assoc_request *assoc_req)
1392{
1393	int i;
1394
1395	lbs_deb_enter(LBS_DEB_WEXT);
1396
1397	/* Set Open System auth mode */
1398	assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1399
1400	/* Clear WEP keys and mark WEP as disabled */
1401	assoc_req->secinfo.wep_enabled = 0;
1402	for (i = 0; i < 4; i++)
1403		assoc_req->wep_keys[i].len = 0;
1404
1405	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1406	set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1407
1408	lbs_deb_leave(LBS_DEB_WEXT);
1409}
1410
1411static void disable_wpa(struct assoc_request *assoc_req)
1412{
1413	lbs_deb_enter(LBS_DEB_WEXT);
1414
1415	memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
1416	assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1417	set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1418
1419	memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
1420	assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1421	set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1422
1423	assoc_req->secinfo.WPAenabled = 0;
1424	assoc_req->secinfo.WPA2enabled = 0;
1425	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1426
1427	lbs_deb_leave(LBS_DEB_WEXT);
1428}
1429
1430/**
1431 *  @brief Set Encryption key
1432 *
1433 *  @param dev                  A pointer to net_device structure
1434 *  @param info			A pointer to iw_request_info structure
1435 *  @param vwrq 		A pointer to iw_param structure
1436 *  @param extra		A pointer to extra data buf
1437 *  @return 	   		0 --success, otherwise fail
1438 */
1439static int wlan_set_encode(struct net_device *dev,
1440		    struct iw_request_info *info,
1441		    struct iw_point *dwrq, char *extra)
1442{
1443	int ret = 0;
1444	wlan_private *priv = dev->priv;
1445	wlan_adapter *adapter = priv->adapter;
1446	struct assoc_request * assoc_req;
1447	u16 is_default = 0, index = 0, set_tx_key = 0;
1448
1449	lbs_deb_enter(LBS_DEB_WEXT);
1450
1451	mutex_lock(&adapter->lock);
1452	assoc_req = wlan_get_association_request(adapter);
1453	if (!assoc_req) {
1454		ret = -ENOMEM;
1455		goto out;
1456	}
1457
1458	if (dwrq->flags & IW_ENCODE_DISABLED) {
1459		disable_wep (assoc_req);
1460		disable_wpa (assoc_req);
1461		goto out;
1462	}
1463
1464	ret = validate_key_index(assoc_req->wep_tx_keyidx,
1465	                         (dwrq->flags & IW_ENCODE_INDEX),
1466	                         &index, &is_default);
1467	if (ret) {
1468		ret = -EINVAL;
1469		goto out;
1470	}
1471
1472	/* If WEP isn't enabled, or if there is no key data but a valid
1473	 * index, set the TX key.
1474	 */
1475	if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
1476		set_tx_key = 1;
1477
1478	ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1479	if (ret)
1480		goto out;
1481
1482	if (dwrq->length)
1483		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1484	if (set_tx_key)
1485		set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1486
1487	if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1488		assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1489	} else if (dwrq->flags & IW_ENCODE_OPEN) {
1490		assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1491	}
1492
1493out:
1494	if (ret == 0) {
1495		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1496		wlan_postpone_association_work(priv);
1497	} else {
1498		wlan_cancel_association_work(priv);
1499	}
1500	mutex_unlock(&adapter->lock);
1501
1502	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1503	return ret;
1504}
1505
1506/**
1507 *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
1508 *
1509 *  @param dev                  A pointer to net_device structure
1510 *  @param info			A pointer to iw_request_info structure
1511 *  @param vwrq 		A pointer to iw_param structure
1512 *  @param extra		A pointer to extra data buf
1513 *  @return 	   		0 on success, otherwise failure
1514 */
1515static int wlan_get_encodeext(struct net_device *dev,
1516			      struct iw_request_info *info,
1517			      struct iw_point *dwrq,
1518			      char *extra)
1519{
1520	int ret = -EINVAL;
1521	wlan_private *priv = dev->priv;
1522	wlan_adapter *adapter = priv->adapter;
1523	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1524	int index, max_key_len;
1525
1526	lbs_deb_enter(LBS_DEB_WEXT);
1527
1528	max_key_len = dwrq->length - sizeof(*ext);
1529	if (max_key_len < 0)
1530		goto out;
1531
1532	index = dwrq->flags & IW_ENCODE_INDEX;
1533	if (index) {
1534		if (index < 1 || index > 4)
1535			goto out;
1536		index--;
1537	} else {
1538		index = adapter->wep_tx_keyidx;
1539	}
1540
1541	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
1542	    ext->alg != IW_ENCODE_ALG_WEP) {
1543		if (index != 0 || adapter->mode != IW_MODE_INFRA)
1544			goto out;
1545	}
1546
1547	dwrq->flags = index + 1;
1548	memset(ext, 0, sizeof(*ext));
1549
1550	if (   !adapter->secinfo.wep_enabled
1551	    && !adapter->secinfo.WPAenabled
1552	    && !adapter->secinfo.WPA2enabled) {
1553		ext->alg = IW_ENCODE_ALG_NONE;
1554		ext->key_len = 0;
1555		dwrq->flags |= IW_ENCODE_DISABLED;
1556	} else {
1557		u8 *key = NULL;
1558
1559		if (   adapter->secinfo.wep_enabled
1560		    && !adapter->secinfo.WPAenabled
1561		    && !adapter->secinfo.WPA2enabled) {
1562			/* WEP */
1563			ext->alg = IW_ENCODE_ALG_WEP;
1564			ext->key_len = adapter->wep_keys[index].len;
1565			key = &adapter->wep_keys[index].key[0];
1566		} else if (   !adapter->secinfo.wep_enabled
1567		           && (adapter->secinfo.WPAenabled ||
1568		               adapter->secinfo.WPA2enabled)) {
1569			/* WPA */
1570			struct WLAN_802_11_KEY * pkey = NULL;
1571
1572			if (   adapter->wpa_mcast_key.len
1573			    && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1574				pkey = &adapter->wpa_mcast_key;
1575			else if (   adapter->wpa_unicast_key.len
1576			         && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1577				pkey = &adapter->wpa_unicast_key;
1578
1579			if (pkey) {
1580				if (pkey->type == KEY_TYPE_ID_AES) {
1581					ext->alg = IW_ENCODE_ALG_CCMP;
1582				} else {
1583					ext->alg = IW_ENCODE_ALG_TKIP;
1584				}
1585				ext->key_len = pkey->len;
1586				key = &pkey->key[0];
1587			} else {
1588				ext->alg = IW_ENCODE_ALG_TKIP;
1589				ext->key_len = 0;
1590			}
1591		} else {
1592			goto out;
1593		}
1594
1595		if (ext->key_len > max_key_len) {
1596			ret = -E2BIG;
1597			goto out;
1598		}
1599
1600		if (ext->key_len)
1601			memcpy(ext->key, key, ext->key_len);
1602		else
1603			dwrq->flags |= IW_ENCODE_NOKEY;
1604		dwrq->flags |= IW_ENCODE_ENABLED;
1605	}
1606	ret = 0;
1607
1608out:
1609	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1610	return ret;
1611}
1612
1613/**
1614 *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
1615 *
1616 *  @param dev                  A pointer to net_device structure
1617 *  @param info			A pointer to iw_request_info structure
1618 *  @param vwrq 		A pointer to iw_param structure
1619 *  @param extra		A pointer to extra data buf
1620 *  @return 	   		0 --success, otherwise fail
1621 */
1622static int wlan_set_encodeext(struct net_device *dev,
1623			      struct iw_request_info *info,
1624			      struct iw_point *dwrq,
1625			      char *extra)
1626{
1627	int ret = 0;
1628	wlan_private *priv = dev->priv;
1629	wlan_adapter *adapter = priv->adapter;
1630	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1631	int alg = ext->alg;
1632	struct assoc_request * assoc_req;
1633
1634	lbs_deb_enter(LBS_DEB_WEXT);
1635
1636	mutex_lock(&adapter->lock);
1637	assoc_req = wlan_get_association_request(adapter);
1638	if (!assoc_req) {
1639		ret = -ENOMEM;
1640		goto out;
1641	}
1642
1643	if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1644		disable_wep (assoc_req);
1645		disable_wpa (assoc_req);
1646	} else if (alg == IW_ENCODE_ALG_WEP) {
1647		u16 is_default = 0, index, set_tx_key = 0;
1648
1649		ret = validate_key_index(assoc_req->wep_tx_keyidx,
1650		                         (dwrq->flags & IW_ENCODE_INDEX),
1651		                         &index, &is_default);
1652		if (ret)
1653			goto out;
1654
1655		/* If WEP isn't enabled, or if there is no key data but a valid
1656		 * index, or if the set-TX-key flag was passed, set the TX key.
1657		 */
1658		if (   !assoc_req->secinfo.wep_enabled
1659		    || (dwrq->length == 0 && !is_default)
1660		    || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1661			set_tx_key = 1;
1662
1663		/* Copy key to driver */
1664		ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1665					set_tx_key);
1666		if (ret)
1667			goto out;
1668
1669		if (dwrq->flags & IW_ENCODE_RESTRICTED) {
1670			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1671		} else if (dwrq->flags & IW_ENCODE_OPEN) {
1672			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1673		}
1674
1675		/* Mark the various WEP bits as modified */
1676		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1677		if (dwrq->length)
1678			set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1679		if (set_tx_key)
1680			set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1681	} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
1682		struct WLAN_802_11_KEY * pkey;
1683
1684		/* validate key length */
1685		if (((alg == IW_ENCODE_ALG_TKIP)
1686			&& (ext->key_len != KEY_LEN_WPA_TKIP))
1687		    || ((alg == IW_ENCODE_ALG_CCMP)
1688		        && (ext->key_len != KEY_LEN_WPA_AES))) {
1689				lbs_deb_wext("invalid size %d for key of alg"
1690				       "type %d\n",
1691				       ext->key_len,
1692				       alg);
1693				ret = -EINVAL;
1694				goto out;
1695		}
1696
1697		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1698			pkey = &assoc_req->wpa_mcast_key;
1699			set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1700		} else {
1701			pkey = &assoc_req->wpa_unicast_key;
1702			set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1703		}
1704
1705		memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
1706		memcpy(pkey->key, ext->key, ext->key_len);
1707		pkey->len = ext->key_len;
1708		if (pkey->len)
1709			pkey->flags |= KEY_INFO_WPA_ENABLED;
1710
1711		/* Do this after zeroing key structure */
1712		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1713			pkey->flags |= KEY_INFO_WPA_MCAST;
1714		} else {
1715			pkey->flags |= KEY_INFO_WPA_UNICAST;
1716		}
1717
1718		if (alg == IW_ENCODE_ALG_TKIP) {
1719			pkey->type = KEY_TYPE_ID_TKIP;
1720		} else if (alg == IW_ENCODE_ALG_CCMP) {
1721			pkey->type = KEY_TYPE_ID_AES;
1722		} else {
1723			ret = -EINVAL;
1724			goto out;
1725		}
1726
1727		/* If WPA isn't enabled yet, do that now */
1728		if (   assoc_req->secinfo.WPAenabled == 0
1729		    && assoc_req->secinfo.WPA2enabled == 0) {
1730			assoc_req->secinfo.WPAenabled = 1;
1731			assoc_req->secinfo.WPA2enabled = 1;
1732			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1733		}
1734
1735		disable_wep (assoc_req);
1736	}
1737
1738out:
1739	if (ret == 0) {
1740		wlan_postpone_association_work(priv);
1741	} else {
1742		wlan_cancel_association_work(priv);
1743	}
1744	mutex_unlock(&adapter->lock);
1745
1746	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1747	return ret;
1748}
1749
1750
1751static int wlan_set_genie(struct net_device *dev,
1752			  struct iw_request_info *info,
1753			  struct iw_point *dwrq,
1754			  char *extra)
1755{
1756	wlan_private *priv = dev->priv;
1757	wlan_adapter *adapter = priv->adapter;
1758	int ret = 0;
1759	struct assoc_request * assoc_req;
1760
1761	lbs_deb_enter(LBS_DEB_WEXT);
1762
1763	mutex_lock(&adapter->lock);
1764	assoc_req = wlan_get_association_request(adapter);
1765	if (!assoc_req) {
1766		ret = -ENOMEM;
1767		goto out;
1768	}
1769
1770	if (dwrq->length > MAX_WPA_IE_LEN ||
1771	    (dwrq->length && extra == NULL)) {
1772		ret = -EINVAL;
1773		goto out;
1774	}
1775
1776	if (dwrq->length) {
1777		memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1778		assoc_req->wpa_ie_len = dwrq->length;
1779	} else {
1780		memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1781		assoc_req->wpa_ie_len = 0;
1782	}
1783
1784out:
1785	if (ret == 0) {
1786		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
1787		wlan_postpone_association_work(priv);
1788	} else {
1789		wlan_cancel_association_work(priv);
1790	}
1791	mutex_unlock(&adapter->lock);
1792
1793	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1794	return ret;
1795}
1796
1797static int wlan_get_genie(struct net_device *dev,
1798			  struct iw_request_info *info,
1799			  struct iw_point *dwrq,
1800			  char *extra)
1801{
1802	int ret = 0;
1803	wlan_private *priv = dev->priv;
1804	wlan_adapter *adapter = priv->adapter;
1805
1806	lbs_deb_enter(LBS_DEB_WEXT);
1807
1808	if (adapter->wpa_ie_len == 0) {
1809		dwrq->length = 0;
1810		goto out;
1811	}
1812
1813	if (dwrq->length < adapter->wpa_ie_len) {
1814		ret = -E2BIG;
1815		goto out;
1816	}
1817
1818	dwrq->length = adapter->wpa_ie_len;
1819	memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1820
1821out:
1822	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1823	return ret;
1824}
1825
1826
1827static int wlan_set_auth(struct net_device *dev,
1828			 struct iw_request_info *info,
1829			 struct iw_param *dwrq,
1830			 char *extra)
1831{
1832	wlan_private *priv = dev->priv;
1833	wlan_adapter *adapter = priv->adapter;
1834	struct assoc_request * assoc_req;
1835	int ret = 0;
1836	int updated = 0;
1837
1838	lbs_deb_enter(LBS_DEB_WEXT);
1839
1840	mutex_lock(&adapter->lock);
1841	assoc_req = wlan_get_association_request(adapter);
1842	if (!assoc_req) {
1843		ret = -ENOMEM;
1844		goto out;
1845	}
1846
1847	switch (dwrq->flags & IW_AUTH_INDEX) {
1848	case IW_AUTH_TKIP_COUNTERMEASURES:
1849	case IW_AUTH_CIPHER_PAIRWISE:
1850	case IW_AUTH_CIPHER_GROUP:
1851	case IW_AUTH_KEY_MGMT:
1852	case IW_AUTH_DROP_UNENCRYPTED:
1853		/*
1854		 * libertas does not use these parameters
1855		 */
1856		break;
1857
1858	case IW_AUTH_WPA_VERSION:
1859		if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1860			assoc_req->secinfo.WPAenabled = 0;
1861			assoc_req->secinfo.WPA2enabled = 0;
1862			disable_wpa (assoc_req);
1863		}
1864		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1865			assoc_req->secinfo.WPAenabled = 1;
1866			assoc_req->secinfo.wep_enabled = 0;
1867			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1868		}
1869		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1870			assoc_req->secinfo.WPA2enabled = 1;
1871			assoc_req->secinfo.wep_enabled = 0;
1872			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1873		}
1874		updated = 1;
1875		break;
1876
1877	case IW_AUTH_80211_AUTH_ALG:
1878		if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
1879			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
1880		} else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1881			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1882		} else if (dwrq->value & IW_AUTH_ALG_LEAP) {
1883			assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
1884		} else {
1885			ret = -EINVAL;
1886		}
1887		updated = 1;
1888		break;
1889
1890	case IW_AUTH_WPA_ENABLED:
1891		if (dwrq->value) {
1892			if (!assoc_req->secinfo.WPAenabled &&
1893			    !assoc_req->secinfo.WPA2enabled) {
1894				assoc_req->secinfo.WPAenabled = 1;
1895				assoc_req->secinfo.WPA2enabled = 1;
1896				assoc_req->secinfo.wep_enabled = 0;
1897				assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
1898			}
1899		} else {
1900			assoc_req->secinfo.WPAenabled = 0;
1901			assoc_req->secinfo.WPA2enabled = 0;
1902			disable_wpa (assoc_req);
1903		}
1904		updated = 1;
1905		break;
1906
1907	default:
1908		ret = -EOPNOTSUPP;
1909		break;
1910	}
1911
1912out:
1913	if (ret == 0) {
1914		if (updated)
1915			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1916		wlan_postpone_association_work(priv);
1917	} else if (ret != -EOPNOTSUPP) {
1918		wlan_cancel_association_work(priv);
1919	}
1920	mutex_unlock(&adapter->lock);
1921
1922	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1923	return ret;
1924}
1925
1926static int wlan_get_auth(struct net_device *dev,
1927			 struct iw_request_info *info,
1928			 struct iw_param *dwrq,
1929			 char *extra)
1930{
1931	int ret = 0;
1932	wlan_private *priv = dev->priv;
1933	wlan_adapter *adapter = priv->adapter;
1934
1935	lbs_deb_enter(LBS_DEB_WEXT);
1936
1937	switch (dwrq->flags & IW_AUTH_INDEX) {
1938	case IW_AUTH_WPA_VERSION:
1939		dwrq->value = 0;
1940		if (adapter->secinfo.WPAenabled)
1941			dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
1942		if (adapter->secinfo.WPA2enabled)
1943			dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1944		if (!dwrq->value)
1945			dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1946		break;
1947
1948	case IW_AUTH_80211_AUTH_ALG:
1949		dwrq->value = adapter->secinfo.auth_mode;
1950		break;
1951
1952	case IW_AUTH_WPA_ENABLED:
1953		if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
1954			dwrq->value = 1;
1955		break;
1956
1957	default:
1958		ret = -EOPNOTSUPP;
1959	}
1960
1961	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1962	return ret;
1963}
1964
1965
1966static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
1967		   struct iw_param *vwrq, char *extra)
1968{
1969	int ret = 0;
1970	wlan_private *priv = dev->priv;
1971	wlan_adapter *adapter = priv->adapter;
1972
1973	u16 dbm;
1974
1975	lbs_deb_enter(LBS_DEB_WEXT);
1976
1977	if (vwrq->disabled) {
1978		wlan_radio_ioctl(priv, RADIO_OFF);
1979		return 0;
1980	}
1981
1982	adapter->preamble = cmd_type_auto_preamble;
1983
1984	wlan_radio_ioctl(priv, RADIO_ON);
1985
1986	if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
1987		dbm = (u16) mw_to_dbm(vwrq->value);
1988	} else
1989		dbm = (u16) vwrq->value;
1990
1991	/* auto tx power control */
1992
1993	if (vwrq->fixed == 0)
1994		dbm = 0xffff;
1995
1996	lbs_deb_wext("txpower set %d dbm\n", dbm);
1997
1998	ret = libertas_prepare_and_send_command(priv,
1999				    cmd_802_11_rf_tx_power,
2000				    cmd_act_tx_power_opt_set_low,
2001				    cmd_option_waitforrsp, 0, (void *)&dbm);
2002
2003	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2004	return ret;
2005}
2006
2007static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
2008		   struct iw_point *dwrq, char *extra)
2009{
2010	wlan_private *priv = dev->priv;
2011	wlan_adapter *adapter = priv->adapter;
2012
2013	lbs_deb_enter(LBS_DEB_WEXT);
2014
2015	/*
2016	 * Note : if dwrq->flags != 0, we should get the relevant SSID from
2017	 * the SSID list...
2018	 */
2019
2020	/*
2021	 * Get the current SSID
2022	 */
2023	if (adapter->connect_status == libertas_connected) {
2024		memcpy(extra, adapter->curbssparams.ssid,
2025		       adapter->curbssparams.ssid_len);
2026		extra[adapter->curbssparams.ssid_len] = '\0';
2027	} else {
2028		memset(extra, 0, 32);
2029		extra[adapter->curbssparams.ssid_len] = '\0';
2030	}
2031	/*
2032	 * If none, we may want to get the one that was set
2033	 */
2034
2035	/* To make the driver backward compatible with WPA supplicant v0.2.4 */
2036	if (dwrq->length == 32)	/* check with WPA supplicant buffer size */
2037		dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len,
2038				   IW_ESSID_MAX_SIZE);
2039	else
2040		dwrq->length = adapter->curbssparams.ssid_len + 1;
2041
2042	dwrq->flags = 1;	/* active */
2043
2044	lbs_deb_leave(LBS_DEB_WEXT);
2045	return 0;
2046}
2047
2048static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
2049		   struct iw_point *dwrq, char *extra)
2050{
2051	wlan_private *priv = dev->priv;
2052	wlan_adapter *adapter = priv->adapter;
2053	int ret = 0;
2054	u8 ssid[IW_ESSID_MAX_SIZE];
2055	u8 ssid_len = 0;
2056	struct assoc_request * assoc_req;
2057	int in_ssid_len = dwrq->length;
2058
2059	lbs_deb_enter(LBS_DEB_WEXT);
2060
2061	/*
2062	 * WE-20 and earlier NULL pad the end of the SSID and increment
2063	 * SSID length so it can be used like a string.  WE-21 and later don't,
2064	 * but some userspace tools aren't able to cope with the change.
2065	 */
2066	if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0'))
2067		in_ssid_len--;
2068
2069	/* Check the size of the string */
2070	if (in_ssid_len > IW_ESSID_MAX_SIZE) {
2071		ret = -E2BIG;
2072		goto out;
2073	}
2074
2075	memset(&ssid, 0, sizeof(ssid));
2076
2077	if (!dwrq->flags || !in_ssid_len) {
2078		/* "any" SSID requested; leave SSID blank */
2079	} else {
2080		/* Specific SSID requested */
2081		memcpy(&ssid, extra, in_ssid_len);
2082		ssid_len = in_ssid_len;
2083	}
2084
2085	if (!ssid_len) {
2086		lbs_deb_wext("requested any SSID\n");
2087	} else {
2088		lbs_deb_wext("requested SSID '%s'\n",
2089		             escape_essid(ssid, ssid_len));
2090	}
2091
2092out:
2093	mutex_lock(&adapter->lock);
2094	if (ret == 0) {
2095		/* Get or create the current association request */
2096		assoc_req = wlan_get_association_request(adapter);
2097		if (!assoc_req) {
2098			ret = -ENOMEM;
2099		} else {
2100			/* Copy the SSID to the association request */
2101			memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
2102			assoc_req->ssid_len = ssid_len;
2103			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
2104			wlan_postpone_association_work(priv);
2105		}
2106	}
2107
2108	/* Cancel the association request if there was an error */
2109	if (ret != 0) {
2110		wlan_cancel_association_work(priv);
2111	}
2112
2113	mutex_unlock(&adapter->lock);
2114
2115	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2116	return ret;
2117}
2118
2119/**
2120 *  @brief Connect to the AP or Ad-hoc Network with specific bssid
2121 *
2122 *  @param dev          A pointer to net_device structure
2123 *  @param info         A pointer to iw_request_info structure
2124 *  @param awrq         A pointer to iw_param structure
2125 *  @param extra        A pointer to extra data buf
2126 *  @return             0 --success, otherwise fail
2127 */
2128static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
2129		 struct sockaddr *awrq, char *extra)
2130{
2131	wlan_private *priv = dev->priv;
2132	wlan_adapter *adapter = priv->adapter;
2133	struct assoc_request * assoc_req;
2134	int ret = 0;
2135
2136	lbs_deb_enter(LBS_DEB_WEXT);
2137
2138	if (awrq->sa_family != ARPHRD_ETHER)
2139		return -EINVAL;
2140
2141	lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
2142
2143	mutex_lock(&adapter->lock);
2144
2145	/* Get or create the current association request */
2146	assoc_req = wlan_get_association_request(adapter);
2147	if (!assoc_req) {
2148		wlan_cancel_association_work(priv);
2149		ret = -ENOMEM;
2150	} else {
2151		/* Copy the BSSID to the association request */
2152		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2153		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
2154		wlan_postpone_association_work(priv);
2155	}
2156
2157	mutex_unlock(&adapter->lock);
2158
2159	return ret;
2160}
2161
2162void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2163{
2164	char fwver[32];
2165
2166	mutex_lock(&adapter->lock);
2167
2168	if (adapter->fwreleasenumber[3] == 0)
2169		sprintf(fwver, "%u.%u.%u",
2170			adapter->fwreleasenumber[2],
2171			adapter->fwreleasenumber[1],
2172			adapter->fwreleasenumber[0]);
2173	else
2174		sprintf(fwver, "%u.%u.%u.p%u",
2175			adapter->fwreleasenumber[2],
2176			adapter->fwreleasenumber[1],
2177			adapter->fwreleasenumber[0],
2178			adapter->fwreleasenumber[3]);
2179
2180	mutex_unlock(&adapter->lock);
2181	snprintf(fwversion, maxlen, fwver);
2182}
2183
2184
2185/*
2186 * iwconfig settable callbacks
2187 */
2188static const iw_handler wlan_handler[] = {
2189	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
2190	(iw_handler) wlan_get_name,	/* SIOCGIWNAME */
2191	(iw_handler) NULL,	/* SIOCSIWNWID */
2192	(iw_handler) NULL,	/* SIOCGIWNWID */
2193	(iw_handler) wlan_set_freq,	/* SIOCSIWFREQ */
2194	(iw_handler) wlan_get_freq,	/* SIOCGIWFREQ */
2195	(iw_handler) wlan_set_mode,	/* SIOCSIWMODE */
2196	(iw_handler) wlan_get_mode,	/* SIOCGIWMODE */
2197	(iw_handler) NULL,	/* SIOCSIWSENS */
2198	(iw_handler) NULL,	/* SIOCGIWSENS */
2199	(iw_handler) NULL,	/* SIOCSIWRANGE */
2200	(iw_handler) wlan_get_range,	/* SIOCGIWRANGE */
2201	(iw_handler) NULL,	/* SIOCSIWPRIV */
2202	(iw_handler) NULL,	/* SIOCGIWPRIV */
2203	(iw_handler) NULL,	/* SIOCSIWSTATS */
2204	(iw_handler) NULL,	/* SIOCGIWSTATS */
2205	iw_handler_set_spy,	/* SIOCSIWSPY */
2206	iw_handler_get_spy,	/* SIOCGIWSPY */
2207	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
2208	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
2209	(iw_handler) wlan_set_wap,	/* SIOCSIWAP */
2210	(iw_handler) wlan_get_wap,	/* SIOCGIWAP */
2211	(iw_handler) NULL,	/* SIOCSIWMLME */
2212	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
2213	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
2214	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
2215	(iw_handler) wlan_set_essid,	/* SIOCSIWESSID */
2216	(iw_handler) wlan_get_essid,	/* SIOCGIWESSID */
2217	(iw_handler) wlan_set_nick,	/* SIOCSIWNICKN */
2218	(iw_handler) wlan_get_nick,	/* SIOCGIWNICKN */
2219	(iw_handler) NULL,	/* -- hole -- */
2220	(iw_handler) NULL,	/* -- hole -- */
2221	(iw_handler) wlan_set_rate,	/* SIOCSIWRATE */
2222	(iw_handler) wlan_get_rate,	/* SIOCGIWRATE */
2223	(iw_handler) wlan_set_rts,	/* SIOCSIWRTS */
2224	(iw_handler) wlan_get_rts,	/* SIOCGIWRTS */
2225	(iw_handler) wlan_set_frag,	/* SIOCSIWFRAG */
2226	(iw_handler) wlan_get_frag,	/* SIOCGIWFRAG */
2227	(iw_handler) wlan_set_txpow,	/* SIOCSIWTXPOW */
2228	(iw_handler) wlan_get_txpow,	/* SIOCGIWTXPOW */
2229	(iw_handler) wlan_set_retry,	/* SIOCSIWRETRY */
2230	(iw_handler) wlan_get_retry,	/* SIOCGIWRETRY */
2231	(iw_handler) wlan_set_encode,	/* SIOCSIWENCODE */
2232	(iw_handler) wlan_get_encode,	/* SIOCGIWENCODE */
2233	(iw_handler) wlan_set_power,	/* SIOCSIWPOWER */
2234	(iw_handler) wlan_get_power,	/* SIOCGIWPOWER */
2235	(iw_handler) NULL,	/* -- hole -- */
2236	(iw_handler) NULL,	/* -- hole -- */
2237	(iw_handler) wlan_set_genie,	/* SIOCSIWGENIE */
2238	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
2239	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
2240	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
2241	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2242	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2243	(iw_handler) NULL,		/* SIOCSIWPMKSA */
2244};
2245
2246static const iw_handler mesh_wlan_handler[] = {
2247	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
2248	(iw_handler) wlan_get_name,	/* SIOCGIWNAME */
2249	(iw_handler) NULL,	/* SIOCSIWNWID */
2250	(iw_handler) NULL,	/* SIOCGIWNWID */
2251	(iw_handler) wlan_set_freq,	/* SIOCSIWFREQ */
2252	(iw_handler) wlan_get_freq,	/* SIOCGIWFREQ */
2253	(iw_handler) NULL,		/* SIOCSIWMODE */
2254	(iw_handler) mesh_wlan_get_mode,	/* SIOCGIWMODE */
2255	(iw_handler) NULL,	/* SIOCSIWSENS */
2256	(iw_handler) NULL,	/* SIOCGIWSENS */
2257	(iw_handler) NULL,	/* SIOCSIWRANGE */
2258	(iw_handler) wlan_get_range,	/* SIOCGIWRANGE */
2259	(iw_handler) NULL,	/* SIOCSIWPRIV */
2260	(iw_handler) NULL,	/* SIOCGIWPRIV */
2261	(iw_handler) NULL,	/* SIOCSIWSTATS */
2262	(iw_handler) NULL,	/* SIOCGIWSTATS */
2263	iw_handler_set_spy,	/* SIOCSIWSPY */
2264	iw_handler_get_spy,	/* SIOCGIWSPY */
2265	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
2266	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
2267	(iw_handler) NULL,	/* SIOCSIWAP */
2268	(iw_handler) NULL,	/* SIOCGIWAP */
2269	(iw_handler) NULL,	/* SIOCSIWMLME */
2270	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
2271	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
2272	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
2273	(iw_handler) NULL,		/* SIOCSIWESSID */
2274	(iw_handler) NULL,		/* SIOCGIWESSID */
2275	(iw_handler) NULL,		/* SIOCSIWNICKN */
2276	(iw_handler) mesh_get_nick,	/* SIOCGIWNICKN */
2277	(iw_handler) NULL,	/* -- hole -- */
2278	(iw_handler) NULL,	/* -- hole -- */
2279	(iw_handler) wlan_set_rate,	/* SIOCSIWRATE */
2280	(iw_handler) wlan_get_rate,	/* SIOCGIWRATE */
2281	(iw_handler) wlan_set_rts,	/* SIOCSIWRTS */
2282	(iw_handler) wlan_get_rts,	/* SIOCGIWRTS */
2283	(iw_handler) wlan_set_frag,	/* SIOCSIWFRAG */
2284	(iw_handler) wlan_get_frag,	/* SIOCGIWFRAG */
2285	(iw_handler) wlan_set_txpow,	/* SIOCSIWTXPOW */
2286	(iw_handler) wlan_get_txpow,	/* SIOCGIWTXPOW */
2287	(iw_handler) wlan_set_retry,	/* SIOCSIWRETRY */
2288	(iw_handler) wlan_get_retry,	/* SIOCGIWRETRY */
2289	(iw_handler) wlan_set_encode,	/* SIOCSIWENCODE */
2290	(iw_handler) wlan_get_encode,	/* SIOCGIWENCODE */
2291	(iw_handler) wlan_set_power,	/* SIOCSIWPOWER */
2292	(iw_handler) wlan_get_power,	/* SIOCGIWPOWER */
2293	(iw_handler) NULL,	/* -- hole -- */
2294	(iw_handler) NULL,	/* -- hole -- */
2295	(iw_handler) wlan_set_genie,	/* SIOCSIWGENIE */
2296	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
2297	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
2298	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
2299	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2300	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2301	(iw_handler) NULL,		/* SIOCSIWPMKSA */
2302};
2303struct iw_handler_def libertas_handler_def = {
2304	.num_standard	= sizeof(wlan_handler) / sizeof(iw_handler),
2305	.standard	= (iw_handler *) wlan_handler,
2306	.get_wireless_stats = wlan_get_wireless_stats,
2307};
2308
2309struct iw_handler_def mesh_handler_def = {
2310	.num_standard	= sizeof(mesh_wlan_handler) / sizeof(iw_handler),
2311	.standard	= (iw_handler *) mesh_wlan_handler,
2312	.get_wireless_stats = wlan_get_wireless_stats,
2313};
2314