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