1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <linux/kthread.h>
18 #include <linux/semaphore.h>
19 #include <bcmdefs.h>
20 #include <linux/netdevice.h>
21 #include <wlioctl.h>
22 
23 #include <bcmutils.h>
24 
25 #include <linux/if_arp.h>
26 #include <asm/uaccess.h>
27 
28 #include <dngl_stats.h>
29 #include <dhd.h>
30 #include <dhdioctl.h>
31 #include <linux/ieee80211.h>
32 typedef const struct si_pub si_t;
33 #include <wlioctl.h>
34 
35 #include <dngl_stats.h>
36 #include <dhd.h>
37 
38 #define WL_ERROR(fmt, args...)	printk(fmt, ##args)
39 #define WL_TRACE(fmt, args...)	no_printk(fmt, ##args)
40 #define WL_INFORM(fmt, args...)	no_printk(fmt, ##args)
41 #define WL_WSEC(fmt, args...)	no_printk(fmt, ##args)
42 #define WL_SCAN(fmt, args...)	no_printk(fmt, ##args)
43 
44 #include <wl_iw.h>
45 
46 #define IW_WSEC_ENABLED(wsec)	((wsec) & (WEP_ENABLED |	\
47 					 TKIP_ENABLED | AES_ENABLED))
48 
49 #include <linux/rtnetlink.h>
50 
51 #define WL_IW_USE_ISCAN  1
52 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS  1
53 
54 bool g_set_essid_before_scan = true;
55 
56 #define WL_IW_IOCTL_CALL(func_call) \
57 	do {				\
58 		func_call;		\
59 	} while (0)
60 
61 static int g_onoff = G_WLAN_SET_ON;
62 wl_iw_extra_params_t g_wl_iw_params;
63 
64 extern bool wl_iw_conn_status_str(u32 event_type, u32 status,
65 				  u32 reason, char *stringBuf, uint buflen);
66 
67 uint wl_msg_level = WL_ERROR_VAL;
68 
69 #define MAX_WLIW_IOCTL_LEN 1024
70 
71 #ifdef CONFIG_WIRELESS_EXT
72 
73 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
74 extern int dhd_wait_pend8021x(struct net_device *dev);
75 #endif
76 
77 #if WIRELESS_EXT < 19
78 #define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
79 #define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
80 #endif
81 
82 static void *g_scan;
83 static volatile uint g_scan_specified_ssid;
84 static wlc_ssid_t g_specific_ssid;
85 
86 static wlc_ssid_t g_ssid;
87 
88 #if defined(WL_IW_USE_ISCAN)
89 #define ISCAN_STATE_IDLE   0
90 #define ISCAN_STATE_SCANING 1
91 
92 #define WLC_IW_ISCAN_MAXLEN   2048
93 typedef struct iscan_buf {
94 	struct iscan_buf *next;
95 	char iscan_buf[WLC_IW_ISCAN_MAXLEN];
96 } iscan_buf_t;
97 
98 typedef struct iscan_info {
99 	struct net_device *dev;
100 	struct timer_list timer;
101 	u32 timer_ms;
102 	u32 timer_on;
103 	int iscan_state;
104 	iscan_buf_t *list_hdr;
105 	iscan_buf_t *list_cur;
106 
107 	struct task_struct *sysioc_tsk;
108 	struct semaphore sysioc_sem;
109 
110 #if defined CSCAN
111 	char ioctlbuf[WLC_IOCTL_MEDLEN];
112 #else
113 	char ioctlbuf[WLC_IOCTL_SMLEN];
114 #endif
115 	wl_iscan_params_t *iscan_ex_params_p;
116 	int iscan_ex_param_size;
117 } iscan_info_t;
118 iscan_info_t *g_iscan;
119 
120 static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
121 
122 static void wl_iw_timerfunc(unsigned long data);
123 static void wl_iw_set_event_mask(struct net_device *dev);
124 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action);
125 #endif				/* defined(WL_IW_USE_ISCAN) */
126 
127 static int
128 wl_iw_set_scan(struct net_device *dev,
129 	       struct iw_request_info *info,
130 	       union iwreq_data *wrqu, char *extra);
131 
132 static int
133 wl_iw_get_scan(struct net_device *dev,
134 	       struct iw_request_info *info,
135 	       struct iw_point *dwrq, char *extra);
136 
137 static uint
138 wl_iw_get_scan_prep(wl_scan_results_t *list,
139 		    struct iw_request_info *info, char *extra, short max_size);
140 
swap_key_from_BE(wl_wsec_key_t * key)141 static void swap_key_from_BE(wl_wsec_key_t *key)
142 {
143 	key->index = cpu_to_le32(key->index);
144 	key->len = cpu_to_le32(key->len);
145 	key->algo = cpu_to_le32(key->algo);
146 	key->flags = cpu_to_le32(key->flags);
147 	key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
148 	key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
149 	key->iv_initialized = cpu_to_le32(key->iv_initialized);
150 }
151 
swap_key_to_BE(wl_wsec_key_t * key)152 static void swap_key_to_BE(wl_wsec_key_t *key)
153 {
154 	key->index = le32_to_cpu(key->index);
155 	key->len = le32_to_cpu(key->len);
156 	key->algo = le32_to_cpu(key->algo);
157 	key->flags = le32_to_cpu(key->flags);
158 	key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
159 	key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
160 	key->iv_initialized = le32_to_cpu(key->iv_initialized);
161 }
162 
dev_wlc_ioctl(struct net_device * dev,int cmd,void * arg,int len)163 static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len)
164 {
165 	struct ifreq ifr;
166 	wl_ioctl_t ioc;
167 	mm_segment_t fs;
168 	int ret = -EINVAL;
169 
170 	if (!dev) {
171 		WL_ERROR("%s: dev is null\n", __func__);
172 		return ret;
173 	}
174 
175 	WL_INFORM("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d\n",
176 		  __func__, current->pid, cmd, arg, len);
177 
178 	if (g_onoff == G_WLAN_SET_ON) {
179 		memset(&ioc, 0, sizeof(ioc));
180 		ioc.cmd = cmd;
181 		ioc.buf = arg;
182 		ioc.len = len;
183 
184 		strcpy(ifr.ifr_name, dev->name);
185 		ifr.ifr_data = (caddr_t)&ioc;
186 
187 		ret = dev_open(dev);
188 		if (ret) {
189 			WL_ERROR("%s: Error dev_open: %d\n", __func__, ret);
190 			return ret;
191 		}
192 
193 		fs = get_fs();
194 		set_fs(get_ds());
195 		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
196 		set_fs(fs);
197 	} else {
198 		WL_TRACE("%s: call after driver stop : ignored\n", __func__);
199 	}
200 	return ret;
201 }
202 
dev_wlc_intvar_set(struct net_device * dev,char * name,int val)203 static int dev_wlc_intvar_set(struct net_device *dev, char *name, int val)
204 {
205 	char buf[WLC_IOCTL_SMLEN];
206 	uint len;
207 
208 	val = cpu_to_le32(val);
209 	len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
210 	ASSERT(len);
211 
212 	return dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len);
213 }
214 
215 #if defined(WL_IW_USE_ISCAN)
216 static int
dev_iw_iovar_setbuf(struct net_device * dev,char * iovar,void * param,int paramlen,void * bufptr,int buflen)217 dev_iw_iovar_setbuf(struct net_device *dev,
218 		    char *iovar,
219 		    void *param, int paramlen, void *bufptr, int buflen)
220 {
221 	int iolen;
222 
223 	iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
224 	ASSERT(iolen);
225 
226 	if (iolen == 0)
227 		return 0;
228 
229 	return dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
230 }
231 
232 static int
dev_iw_iovar_getbuf(struct net_device * dev,char * iovar,void * param,int paramlen,void * bufptr,int buflen)233 dev_iw_iovar_getbuf(struct net_device *dev,
234 		    char *iovar,
235 		    void *param, int paramlen, void *bufptr, int buflen)
236 {
237 	int iolen;
238 
239 	iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
240 	ASSERT(iolen);
241 
242 	return dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
243 }
244 #endif				/* defined(WL_IW_USE_ISCAN) */
245 
246 #if WIRELESS_EXT > 17
247 static int
dev_wlc_bufvar_set(struct net_device * dev,char * name,char * buf,int len)248 dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
249 {
250 	static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
251 	uint buflen;
252 
253 	buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
254 	ASSERT(buflen);
255 
256 	return dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
257 }
258 #endif				/* WIRELESS_EXT > 17 */
259 
260 static int
dev_wlc_bufvar_get(struct net_device * dev,char * name,char * buf,int buflen)261 dev_wlc_bufvar_get(struct net_device *dev, char *name, char *buf, int buflen)
262 {
263 	static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
264 	int error;
265 	uint len;
266 
267 	len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
268 	ASSERT(len);
269 	error =
270 	    dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf,
271 			  MAX_WLIW_IOCTL_LEN);
272 	if (!error)
273 		memcpy(buf, ioctlbuf, buflen);
274 
275 	return error;
276 }
277 
dev_wlc_intvar_get(struct net_device * dev,char * name,int * retval)278 static int dev_wlc_intvar_get(struct net_device *dev, char *name, int *retval)
279 {
280 	union {
281 		char buf[WLC_IOCTL_SMLEN];
282 		int val;
283 	} var;
284 	int error;
285 
286 	uint len;
287 	uint data_null;
288 
289 	len =
290 	    bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
291 			sizeof(var.buf));
292 	ASSERT(len);
293 	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
294 
295 	*retval = le32_to_cpu(var.val);
296 
297 	return error;
298 }
299 
300 #if WIRELESS_EXT < 13
301 struct iw_request_info {
302 	__u16 cmd;
303 	__u16 flags;
304 };
305 
306 typedef int (*iw_handler) (struct net_device *dev,
307 			   struct iw_request_info *info,
308 			   void *wrqu, char *extra);
309 #endif
310 
311 static int
wl_iw_config_commit(struct net_device * dev,struct iw_request_info * info,void * zwrq,char * extra)312 wl_iw_config_commit(struct net_device *dev,
313 		    struct iw_request_info *info, void *zwrq, char *extra)
314 {
315 	wlc_ssid_t ssid;
316 	int error;
317 	struct sockaddr bssid;
318 
319 	WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name);
320 
321 	error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
322 	if (error)
323 		return error;
324 
325 	ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
326 
327 	if (!ssid.SSID_len)
328 		return 0;
329 
330 	memset(&bssid, 0, sizeof(struct sockaddr));
331 	error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN);
332 	if (error) {
333 		WL_ERROR("%s: WLC_REASSOC to %s failed\n",
334 			 __func__, ssid.SSID);
335 		return error;
336 	}
337 
338 	return 0;
339 }
340 
341 static int
wl_iw_get_name(struct net_device * dev,struct iw_request_info * info,char * cwrq,char * extra)342 wl_iw_get_name(struct net_device *dev,
343 	       struct iw_request_info *info, char *cwrq, char *extra)
344 {
345 	WL_TRACE("%s: SIOCGIWNAME\n", dev->name);
346 
347 	strcpy(cwrq, "IEEE 802.11-DS");
348 
349 	return 0;
350 }
351 
352 static int
wl_iw_set_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)353 wl_iw_set_freq(struct net_device *dev,
354 	       struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
355 {
356 	int error, chan;
357 	uint sf = 0;
358 
359 	WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name);
360 
361 	if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
362 		chan = fwrq->m;
363 	} else {
364 		if (fwrq->e >= 6) {
365 			fwrq->e -= 6;
366 			while (fwrq->e--)
367 				fwrq->m *= 10;
368 		} else if (fwrq->e < 6) {
369 			while (fwrq->e++ < 6)
370 				fwrq->m /= 10;
371 		}
372 		if (fwrq->m > 4000 && fwrq->m < 5000)
373 			sf = WF_CHAN_FACTOR_4_G;
374 
375 		chan = wf_mhz2channel(fwrq->m, sf);
376 	}
377 	chan = cpu_to_le32(chan);
378 
379 	error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan));
380 	if (error)
381 		return error;
382 
383 	g_wl_iw_params.target_channel = chan;
384 	return -EINPROGRESS;
385 }
386 
387 static int
wl_iw_get_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)388 wl_iw_get_freq(struct net_device *dev,
389 	       struct iw_request_info *info, struct iw_freq *fwrq, char *extra)
390 {
391 	channel_info_t ci;
392 	int error;
393 
394 	WL_TRACE("%s: SIOCGIWFREQ\n", dev->name);
395 
396 	error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
397 	if (error)
398 		return error;
399 
400 	fwrq->m = le32_to_cpu(ci.hw_channel);
401 	fwrq->e = le32_to_cpu(0);
402 	return 0;
403 }
404 
405 static int
wl_iw_set_mode(struct net_device * dev,struct iw_request_info * info,__u32 * uwrq,char * extra)406 wl_iw_set_mode(struct net_device *dev,
407 	       struct iw_request_info *info, __u32 *uwrq, char *extra)
408 {
409 	int infra = 0, ap = 0, error = 0;
410 
411 	WL_TRACE("%s: SIOCSIWMODE\n", dev->name);
412 
413 	switch (*uwrq) {
414 	case IW_MODE_MASTER:
415 		infra = ap = 1;
416 		break;
417 	case IW_MODE_ADHOC:
418 	case IW_MODE_AUTO:
419 		break;
420 	case IW_MODE_INFRA:
421 		infra = 1;
422 		break;
423 	default:
424 		return -EINVAL;
425 	}
426 	infra = cpu_to_le32(infra);
427 	ap = cpu_to_le32(ap);
428 
429 	error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra));
430 	if (error)
431 		return error;
432 
433 	error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap));
434 	if (error)
435 		return error;
436 
437 	return -EINPROGRESS;
438 }
439 
440 static int
wl_iw_get_mode(struct net_device * dev,struct iw_request_info * info,__u32 * uwrq,char * extra)441 wl_iw_get_mode(struct net_device *dev,
442 	       struct iw_request_info *info, __u32 *uwrq, char *extra)
443 {
444 	int error, infra = 0, ap = 0;
445 
446 	WL_TRACE("%s: SIOCGIWMODE\n", dev->name);
447 
448 	error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra));
449 	if (error)
450 		return error;
451 
452 	error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap));
453 	if (error)
454 		return error;
455 
456 	infra = le32_to_cpu(infra);
457 	ap = le32_to_cpu(ap);
458 	*uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
459 
460 	return 0;
461 }
462 
463 static int
wl_iw_get_range(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)464 wl_iw_get_range(struct net_device *dev,
465 		struct iw_request_info *info,
466 		struct iw_point *dwrq, char *extra)
467 {
468 	struct iw_range *range = (struct iw_range *)extra;
469 	wl_u32_list_t *list;
470 	wl_rateset_t rateset;
471 	s8 *channels;
472 	int error, i, k;
473 	uint ch;
474 
475 	int phytype;
476 	int bw_cap = 0, sgi_tx = 0, nmode = 0;
477 	channel_info_t ci;
478 	u8 nrate_list2copy = 0;
479 	u16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
480 	{14, 29, 43, 58, 87, 116, 130, 144},
481 	{27, 54, 81, 108, 162, 216, 243, 270},
482 	{30, 60, 90, 120, 180, 240, 270, 300}
483 	};
484 
485 	WL_TRACE("%s: SIOCGIWRANGE\n", dev->name);
486 
487 	if (!extra)
488 		return -EINVAL;
489 
490 	channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL);
491 	if (!channels) {
492 		WL_ERROR("Could not alloc channels\n");
493 		return -ENOMEM;
494 	}
495 	list = (wl_u32_list_t *) channels;
496 
497 	dwrq->length = sizeof(struct iw_range);
498 	memset(range, 0, sizeof(range));
499 
500 	range->min_nwid = range->max_nwid = 0;
501 
502 	list->count = cpu_to_le32(MAXCHANNEL);
503 	error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels,
504 				(MAXCHANNEL + 1) * 4);
505 	if (error) {
506 		kfree(channels);
507 		return error;
508 	}
509 	for (i = 0; i < le32_to_cpu(list->count) && i < IW_MAX_FREQUENCIES;
510 	     i++) {
511 		range->freq[i].i = le32_to_cpu(list->element[i]);
512 
513 		ch = le32_to_cpu(list->element[i]);
514 		if (ch <= CH_MAX_2G_CHANNEL) {
515 			range->freq[i].m = ieee80211_dsss_chan_to_freq(ch);
516 		} else {
517 			range->freq[i].m = ieee80211_ofdm_chan_to_freq(
518 						WF_CHAN_FACTOR_5_G/2, ch);
519 		}
520 		range->freq[i].e = 6;
521 	}
522 	range->num_frequency = range->num_channels = i;
523 
524 	range->max_qual.qual = 5;
525 	range->max_qual.level = 0x100 - 200;
526 	range->max_qual.noise = 0x100 - 200;
527 	range->sensitivity = 65535;
528 
529 #if WIRELESS_EXT > 11
530 	range->avg_qual.qual = 3;
531 	range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
532 	range->avg_qual.noise = 0x100 - 75;
533 #endif
534 
535 	error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
536 				sizeof(rateset));
537 	if (error) {
538 		kfree(channels);
539 		return error;
540 	}
541 	rateset.count = le32_to_cpu(rateset.count);
542 	range->num_bitrates = rateset.count;
543 	for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
544 		range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000;
545 	dev_wlc_intvar_get(dev, "nmode", &nmode);
546 	dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
547 
548 	if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
549 		dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
550 		dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
551 		dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci,
552 			      sizeof(channel_info_t));
553 		ci.hw_channel = le32_to_cpu(ci.hw_channel);
554 
555 		if (bw_cap == 0 || (bw_cap == 2 && ci.hw_channel <= 14)) {
556 			if (sgi_tx == 0)
557 				nrate_list2copy = 0;
558 			else
559 				nrate_list2copy = 1;
560 		}
561 		if (bw_cap == 1 || (bw_cap == 2 && ci.hw_channel >= 36)) {
562 			if (sgi_tx == 0)
563 				nrate_list2copy = 2;
564 			else
565 				nrate_list2copy = 3;
566 		}
567 		range->num_bitrates += 8;
568 		for (k = 0; i < range->num_bitrates; k++, i++) {
569 			range->bitrate[i] =
570 			    (nrate_list[nrate_list2copy][k]) * 500000;
571 		}
572 	}
573 
574 	error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i));
575 	if (error) {
576 		kfree(channels);
577 		return error;
578 	}
579 	i = le32_to_cpu(i);
580 	if (i == WLC_PHY_TYPE_A)
581 		range->throughput = 24000000;
582 	else
583 		range->throughput = 1500000;
584 
585 	range->min_rts = 0;
586 	range->max_rts = 2347;
587 	range->min_frag = 256;
588 	range->max_frag = 2346;
589 
590 	range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
591 	range->num_encoding_sizes = 4;
592 	range->encoding_size[0] = WLAN_KEY_LEN_WEP40;
593 	range->encoding_size[1] = WLAN_KEY_LEN_WEP104;
594 #if WIRELESS_EXT > 17
595 	range->encoding_size[2] = WLAN_KEY_LEN_TKIP;
596 #else
597 	range->encoding_size[2] = 0;
598 #endif
599 	range->encoding_size[3] = WLAN_KEY_LEN_AES_CMAC;
600 
601 	range->min_pmp = 0;
602 	range->max_pmp = 0;
603 	range->min_pmt = 0;
604 	range->max_pmt = 0;
605 	range->pmp_flags = 0;
606 	range->pm_capa = 0;
607 
608 	range->num_txpower = 2;
609 	range->txpower[0] = 1;
610 	range->txpower[1] = 255;
611 	range->txpower_capa = IW_TXPOW_MWATT;
612 
613 #if WIRELESS_EXT > 10
614 	range->we_version_compiled = WIRELESS_EXT;
615 	range->we_version_source = 19;
616 
617 	range->retry_capa = IW_RETRY_LIMIT;
618 	range->retry_flags = IW_RETRY_LIMIT;
619 	range->r_time_flags = 0;
620 	range->min_retry = 1;
621 	range->max_retry = 255;
622 	range->min_r_time = 0;
623 	range->max_r_time = 0;
624 #endif
625 
626 #if WIRELESS_EXT > 17
627 	range->enc_capa = IW_ENC_CAPA_WPA;
628 	range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
629 	range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
630 	range->enc_capa |= IW_ENC_CAPA_WPA2;
631 
632 	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
633 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
634 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
635 	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
636 	IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
637 	IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
638 #endif				/* WIRELESS_EXT > 17 */
639 
640 	kfree(channels);
641 
642 	return 0;
643 }
644 
rssi_to_qual(int rssi)645 static int rssi_to_qual(int rssi)
646 {
647 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
648 		return 0;
649 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
650 		return 1;
651 	else if (rssi <= WL_IW_RSSI_LOW)
652 		return 2;
653 	else if (rssi <= WL_IW_RSSI_GOOD)
654 		return 3;
655 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
656 		return 4;
657 	else
658 		return 5;
659 }
660 
661 static int
wl_iw_set_spy(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)662 wl_iw_set_spy(struct net_device *dev,
663 	      struct iw_request_info *info, struct iw_point *dwrq, char *extra)
664 {
665 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
666 	struct sockaddr *addr = (struct sockaddr *)extra;
667 	int i;
668 
669 	WL_TRACE("%s: SIOCSIWSPY\n", dev->name);
670 
671 	if (!extra)
672 		return -EINVAL;
673 
674 	iw->spy_num = min_t(int, ARRAY_SIZE(iw->spy_addr), dwrq->length);
675 	for (i = 0; i < iw->spy_num; i++)
676 		memcpy(iw->spy_addr[i], addr[i].sa_data, ETH_ALEN);
677 	memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
678 
679 	return 0;
680 }
681 
682 static int
wl_iw_get_spy(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)683 wl_iw_get_spy(struct net_device *dev,
684 	      struct iw_request_info *info, struct iw_point *dwrq, char *extra)
685 {
686 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
687 	struct sockaddr *addr = (struct sockaddr *)extra;
688 	struct iw_quality *qual = (struct iw_quality *)&addr[iw->spy_num];
689 	int i;
690 
691 	WL_TRACE("%s: SIOCGIWSPY\n", dev->name);
692 
693 	if (!extra)
694 		return -EINVAL;
695 
696 	dwrq->length = iw->spy_num;
697 	for (i = 0; i < iw->spy_num; i++) {
698 		memcpy(addr[i].sa_data, iw->spy_addr[i], ETH_ALEN);
699 		addr[i].sa_family = AF_UNIX;
700 		memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
701 		iw->spy_qual[i].updated = 0;
702 	}
703 
704 	return 0;
705 }
706 
707 static int
wl_iw_ch_to_chanspec(int ch,wl_join_params_t * join_params,int * join_params_size)708 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params,
709 		     int *join_params_size)
710 {
711 	chanspec_t chanspec = 0;
712 
713 	if (ch != 0) {
714 		join_params->params.chanspec_num = 1;
715 		join_params->params.chanspec_list[0] = ch;
716 
717 		if (join_params->params.chanspec_list[0])
718 			chanspec |= WL_CHANSPEC_BAND_2G;
719 		else
720 			chanspec |= WL_CHANSPEC_BAND_5G;
721 
722 		chanspec |= WL_CHANSPEC_BW_20;
723 		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
724 
725 		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
726 		    join_params->params.chanspec_num * sizeof(chanspec_t);
727 
728 		join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
729 		join_params->params.chanspec_list[0] |= chanspec;
730 		join_params->params.chanspec_list[0] =
731 		    cpu_to_le16(join_params->params.chanspec_list[0]);
732 
733 		join_params->params.chanspec_num =
734 		    cpu_to_le32(join_params->params.chanspec_num);
735 
736 		WL_TRACE("%s  join_params->params.chanspec_list[0]= %X\n",
737 			 __func__, join_params->params.chanspec_list[0]);
738 	}
739 	return 1;
740 }
741 
742 static int
wl_iw_set_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)743 wl_iw_set_wap(struct net_device *dev,
744 	      struct iw_request_info *info, struct sockaddr *awrq, char *extra)
745 {
746 	int error = -EINVAL;
747 	wl_join_params_t join_params;
748 	int join_params_size;
749 
750 	WL_TRACE("%s: SIOCSIWAP\n", dev->name);
751 
752 	if (awrq->sa_family != ARPHRD_ETHER) {
753 		WL_ERROR("Invalid Header...sa_family\n");
754 		return -EINVAL;
755 	}
756 
757 	if (is_broadcast_ether_addr(awrq->sa_data) ||
758 	    is_zero_ether_addr(awrq->sa_data)) {
759 		scb_val_t scbval;
760 		memset(&scbval, 0, sizeof(scb_val_t));
761 		(void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
762 				    sizeof(scb_val_t));
763 		return 0;
764 	}
765 
766 	memset(&join_params, 0, sizeof(join_params));
767 	join_params_size = sizeof(join_params.ssid);
768 
769 	memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
770 	join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
771 	memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN);
772 
773 	WL_TRACE("%s  target_channel=%d\n",
774 		 __func__, g_wl_iw_params.target_channel);
775 	wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
776 			     &join_params_size);
777 
778 	error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
779 				join_params_size);
780 	if (error) {
781 		WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error);
782 	}
783 
784 	if (g_ssid.SSID_len) {
785 		WL_TRACE("%s: join SSID=%s BSSID=%pM ch=%d\n",
786 			 __func__, g_ssid.SSID, awrq->sa_data,
787 			 g_wl_iw_params.target_channel);
788 	}
789 
790 	memset(&g_ssid, 0, sizeof(g_ssid));
791 	return 0;
792 }
793 
794 static int
wl_iw_get_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)795 wl_iw_get_wap(struct net_device *dev,
796 	      struct iw_request_info *info, struct sockaddr *awrq, char *extra)
797 {
798 	WL_TRACE("%s: SIOCGIWAP\n", dev->name);
799 
800 	awrq->sa_family = ARPHRD_ETHER;
801 	memset(awrq->sa_data, 0, ETH_ALEN);
802 
803 	(void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN);
804 
805 	return 0;
806 }
807 
808 #if WIRELESS_EXT > 17
809 static int
wl_iw_mlme(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)810 wl_iw_mlme(struct net_device *dev,
811 	   struct iw_request_info *info, struct sockaddr *awrq, char *extra)
812 {
813 	struct iw_mlme *mlme;
814 	scb_val_t scbval;
815 	int error = -EINVAL;
816 
817 	WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name);
818 
819 	mlme = (struct iw_mlme *)extra;
820 	if (mlme == NULL) {
821 		WL_ERROR("Invalid ioctl data\n");
822 		return error;
823 	}
824 
825 	scbval.val = mlme->reason_code;
826 	memcpy(&scbval.ea, &mlme->addr.sa_data, ETH_ALEN);
827 
828 	if (mlme->cmd == IW_MLME_DISASSOC) {
829 		scbval.val = cpu_to_le32(scbval.val);
830 		error =
831 		    dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval,
832 				  sizeof(scb_val_t));
833 	} else if (mlme->cmd == IW_MLME_DEAUTH) {
834 		scbval.val = cpu_to_le32(scbval.val);
835 		error =
836 		    dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
837 				  &scbval, sizeof(scb_val_t));
838 	} else {
839 		WL_ERROR("Invalid ioctl data\n");
840 		return error;
841 	}
842 
843 	return error;
844 }
845 #endif				/* WIRELESS_EXT > 17 */
846 
847 #ifndef WL_IW_USE_ISCAN
848 static int
wl_iw_get_aplist(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)849 wl_iw_get_aplist(struct net_device *dev,
850 		 struct iw_request_info *info,
851 		 struct iw_point *dwrq, char *extra)
852 {
853 	wl_scan_results_t *list;
854 	struct sockaddr *addr = (struct sockaddr *)extra;
855 	struct iw_quality qual[IW_MAX_AP];
856 	wl_bss_info_t *bi = NULL;
857 	int error, i;
858 	uint buflen = dwrq->length;
859 
860 	WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
861 
862 	if (!extra)
863 		return -EINVAL;
864 
865 	list = kzalloc(buflen, GFP_KERNEL);
866 	if (!list)
867 		return -ENOMEM;
868 	list->buflen = cpu_to_le32(buflen);
869 	error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen);
870 	if (error) {
871 		WL_ERROR("%d: Scan results error %d\n", __LINE__, error);
872 		kfree(list);
873 		return error;
874 	}
875 	list->buflen = le32_to_cpu(list->buflen);
876 	list->version = le32_to_cpu(list->version);
877 	list->count = le32_to_cpu(list->count);
878 	if (list->version != WL_BSS_INFO_VERSION) {
879 		WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
880 			 __func__, list->version);
881 		kfree(list);
882 		return -EINVAL;
883 	}
884 
885 	for (i = 0, dwrq->length = 0;
886 	     i < list->count && dwrq->length < IW_MAX_AP; i++) {
887 		bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
888 					     le32_to_cpu(bi->length)) : list->
889 		    bss_info;
890 		ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
891 		       ((unsigned long)list + buflen));
892 
893 		if (!(le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS))
894 			continue;
895 
896 		memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETH_ALEN);
897 		addr[dwrq->length].sa_family = ARPHRD_ETHER;
898 		qual[dwrq->length].qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
899 		qual[dwrq->length].level = 0x100 + le16_to_cpu(bi->RSSI);
900 		qual[dwrq->length].noise = 0x100 + bi->phy_noise;
901 
902 #if WIRELESS_EXT > 18
903 		qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
904 #else
905 		qual[dwrq->length].updated = 7;
906 #endif
907 		dwrq->length++;
908 	}
909 
910 	kfree(list);
911 
912 	if (dwrq->length) {
913 		memcpy(&addr[dwrq->length], qual,
914 		       sizeof(struct iw_quality) * dwrq->length);
915 		dwrq->flags = 1;
916 	}
917 
918 	return 0;
919 }
920 #endif				/* WL_IW_USE_ISCAN */
921 
922 #ifdef WL_IW_USE_ISCAN
923 static int
wl_iw_iscan_get_aplist(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)924 wl_iw_iscan_get_aplist(struct net_device *dev,
925 		       struct iw_request_info *info,
926 		       struct iw_point *dwrq, char *extra)
927 {
928 	wl_scan_results_t *list;
929 	iscan_buf_t *buf;
930 	iscan_info_t *iscan = g_iscan;
931 
932 	struct sockaddr *addr = (struct sockaddr *)extra;
933 	struct iw_quality qual[IW_MAX_AP];
934 	wl_bss_info_t *bi = NULL;
935 	int i;
936 
937 	WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name);
938 
939 	if (!extra)
940 		return -EINVAL;
941 
942 	if ((!iscan) || (!iscan->sysioc_tsk)) {
943 		WL_ERROR("%s error\n", __func__);
944 		return 0;
945 	}
946 
947 	buf = iscan->list_hdr;
948 	while (buf) {
949 		list = &((wl_iscan_results_t *) buf->iscan_buf)->results;
950 		if (list->version != WL_BSS_INFO_VERSION) {
951 			WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
952 				 __func__, list->version);
953 			return -EINVAL;
954 		}
955 
956 		bi = NULL;
957 		for (i = 0, dwrq->length = 0;
958 		     i < list->count && dwrq->length < IW_MAX_AP; i++) {
959 			bi = bi ? (wl_bss_info_t *) ((unsigned long)bi +
960 						     le32_to_cpu(bi->length)) :
961 			    list->bss_info;
962 			ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
963 			       ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
964 
965 			if (!(le16_to_cpu(bi->capability) &
966 			      WLAN_CAPABILITY_ESS))
967 				continue;
968 
969 			memcpy(addr[dwrq->length].sa_data, &bi->BSSID,
970 			       ETH_ALEN);
971 			addr[dwrq->length].sa_family = ARPHRD_ETHER;
972 			qual[dwrq->length].qual =
973 			    rssi_to_qual(le16_to_cpu(bi->RSSI));
974 			qual[dwrq->length].level = 0x100 +
975 							le16_to_cpu(bi->RSSI);
976 			qual[dwrq->length].noise = 0x100 + bi->phy_noise;
977 
978 #if WIRELESS_EXT > 18
979 			qual[dwrq->length].updated =
980 			    IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
981 #else
982 			qual[dwrq->length].updated = 7;
983 #endif
984 
985 			dwrq->length++;
986 		}
987 		buf = buf->next;
988 	}
989 	if (dwrq->length) {
990 		memcpy(&addr[dwrq->length], qual,
991 		       sizeof(struct iw_quality) * dwrq->length);
992 		dwrq->flags = 1;
993 	}
994 
995 	return 0;
996 }
997 
wl_iw_iscan_prep(wl_scan_params_t * params,wlc_ssid_t * ssid)998 static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
999 {
1000 	int err = 0;
1001 
1002 	memcpy(params->bssid, ether_bcast, ETH_ALEN);
1003 	params->bss_type = DOT11_BSSTYPE_ANY;
1004 	params->scan_type = 0;
1005 	params->nprobes = -1;
1006 	params->active_time = -1;
1007 	params->passive_time = -1;
1008 	params->home_time = -1;
1009 	params->channel_num = 0;
1010 
1011 	params->nprobes = cpu_to_le32(params->nprobes);
1012 	params->active_time = cpu_to_le32(params->active_time);
1013 	params->passive_time = cpu_to_le32(params->passive_time);
1014 	params->home_time = cpu_to_le32(params->home_time);
1015 	if (ssid && ssid->SSID_len)
1016 		memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
1017 
1018 	return err;
1019 }
1020 
wl_iw_iscan(iscan_info_t * iscan,wlc_ssid_t * ssid,u16 action)1021 static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action)
1022 {
1023 	int err = 0;
1024 
1025 	iscan->iscan_ex_params_p->version = cpu_to_le32(ISCAN_REQ_VERSION);
1026 	iscan->iscan_ex_params_p->action = cpu_to_le16(action);
1027 	iscan->iscan_ex_params_p->scan_duration = cpu_to_le16(0);
1028 
1029 	WL_SCAN("%s : nprobes=%d\n",
1030 		__func__, iscan->iscan_ex_params_p->params.nprobes);
1031 	WL_SCAN("active_time=%d\n",
1032 		 iscan->iscan_ex_params_p->params.active_time);
1033 	WL_SCAN("passive_time=%d\n",
1034 		 iscan->iscan_ex_params_p->params.passive_time);
1035 	WL_SCAN("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time);
1036 	WL_SCAN("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type);
1037 	WL_SCAN("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type);
1038 
1039 	(void)dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
1040 				  iscan->iscan_ex_param_size, iscan->ioctlbuf,
1041 				  sizeof(iscan->ioctlbuf));
1042 
1043 	return err;
1044 }
1045 
wl_iw_timerfunc(unsigned long data)1046 static void wl_iw_timerfunc(unsigned long data)
1047 {
1048 	iscan_info_t *iscan = (iscan_info_t *) data;
1049 	if (iscan) {
1050 		iscan->timer_on = 0;
1051 		if (iscan->iscan_state != ISCAN_STATE_IDLE) {
1052 			WL_TRACE("timer trigger\n");
1053 			up(&iscan->sysioc_sem);
1054 		}
1055 	}
1056 }
1057 
wl_iw_set_event_mask(struct net_device * dev)1058 static void wl_iw_set_event_mask(struct net_device *dev)
1059 {
1060 	char eventmask[WL_EVENTING_MASK_LEN];
1061 	char iovbuf[WL_EVENTING_MASK_LEN + 12];
1062 
1063 	dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
1064 	memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
1065 	setbit(eventmask, WLC_E_SCAN_COMPLETE);
1066 	dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
1067 			    iovbuf, sizeof(iovbuf));
1068 }
1069 
wl_iw_iscan_get(iscan_info_t * iscan)1070 static u32 wl_iw_iscan_get(iscan_info_t *iscan)
1071 {
1072 	iscan_buf_t *buf;
1073 	iscan_buf_t *ptr;
1074 	wl_iscan_results_t *list_buf;
1075 	wl_iscan_results_t list;
1076 	wl_scan_results_t *results;
1077 	u32 status;
1078 	int res = 0;
1079 
1080 	MUTEX_LOCK_WL_SCAN_SET();
1081 	if (iscan->list_cur) {
1082 		buf = iscan->list_cur;
1083 		iscan->list_cur = buf->next;
1084 	} else {
1085 		buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
1086 		if (!buf) {
1087 			WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n",
1088 				 __func__);
1089 			MUTEX_UNLOCK_WL_SCAN_SET();
1090 			return WL_SCAN_RESULTS_NO_MEM;
1091 		}
1092 		buf->next = NULL;
1093 		if (!iscan->list_hdr)
1094 			iscan->list_hdr = buf;
1095 		else {
1096 			ptr = iscan->list_hdr;
1097 			while (ptr->next) {
1098 				ptr = ptr->next;
1099 			}
1100 			ptr->next = buf;
1101 		}
1102 	}
1103 	memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1104 	list_buf = (wl_iscan_results_t *) buf->iscan_buf;
1105 	results = &list_buf->results;
1106 	results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1107 	results->version = 0;
1108 	results->count = 0;
1109 
1110 	memset(&list, 0, sizeof(list));
1111 	list.results.buflen = cpu_to_le32(WLC_IW_ISCAN_MAXLEN);
1112 	res = dev_iw_iovar_getbuf(iscan->dev,
1113 				  "iscanresults",
1114 				  &list,
1115 				  WL_ISCAN_RESULTS_FIXED_SIZE,
1116 				  buf->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1117 	if (res == 0) {
1118 		results->buflen = le32_to_cpu(results->buflen);
1119 		results->version = le32_to_cpu(results->version);
1120 		results->count = le32_to_cpu(results->count);
1121 		WL_TRACE("results->count = %d\n", results->count);
1122 		WL_TRACE("results->buflen = %d\n", results->buflen);
1123 		status = le32_to_cpu(list_buf->status);
1124 	} else {
1125 		WL_ERROR("%s returns error %d\n", __func__, res);
1126 		status = WL_SCAN_RESULTS_NO_MEM;
1127 	}
1128 	MUTEX_UNLOCK_WL_SCAN_SET();
1129 	return status;
1130 }
1131 
wl_iw_force_specific_scan(iscan_info_t * iscan)1132 static void wl_iw_force_specific_scan(iscan_info_t *iscan)
1133 {
1134 	WL_TRACE("%s force Specific SCAN for %s\n",
1135 		 __func__, g_specific_ssid.SSID);
1136 	rtnl_lock();
1137 
1138 	(void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid,
1139 			    sizeof(g_specific_ssid));
1140 
1141 	rtnl_unlock();
1142 }
1143 
wl_iw_send_scan_complete(iscan_info_t * iscan)1144 static void wl_iw_send_scan_complete(iscan_info_t *iscan)
1145 {
1146 #ifndef SANDGATE2G
1147 	union iwreq_data wrqu;
1148 
1149 	memset(&wrqu, 0, sizeof(wrqu));
1150 
1151 	wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
1152 	WL_TRACE("Send Event ISCAN complete\n");
1153 #endif
1154 }
1155 
_iscan_sysioc_thread(void * data)1156 static int _iscan_sysioc_thread(void *data)
1157 {
1158 	u32 status;
1159 	iscan_info_t *iscan = (iscan_info_t *) data;
1160 	static bool iscan_pass_abort = false;
1161 
1162 	allow_signal(SIGTERM);
1163 	status = WL_SCAN_RESULTS_PARTIAL;
1164 	while (down_interruptible(&iscan->sysioc_sem) == 0) {
1165 		if (kthread_should_stop())
1166 			break;
1167 
1168 		if (iscan->timer_on) {
1169 			del_timer_sync(&iscan->timer);
1170 			iscan->timer_on = 0;
1171 		}
1172 		rtnl_lock();
1173 		status = wl_iw_iscan_get(iscan);
1174 		rtnl_unlock();
1175 		if (g_scan_specified_ssid && (iscan_pass_abort == true)) {
1176 			WL_TRACE("%s Get results from specific scan status = %d\n",
1177 				 __func__, status);
1178 			wl_iw_send_scan_complete(iscan);
1179 			iscan_pass_abort = false;
1180 			status = -1;
1181 		}
1182 
1183 		switch (status) {
1184 		case WL_SCAN_RESULTS_PARTIAL:
1185 			WL_TRACE("iscanresults incomplete\n");
1186 			rtnl_lock();
1187 			wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
1188 			rtnl_unlock();
1189 			mod_timer(&iscan->timer,
1190 				  jiffies + iscan->timer_ms * HZ / 1000);
1191 			iscan->timer_on = 1;
1192 			break;
1193 		case WL_SCAN_RESULTS_SUCCESS:
1194 			WL_TRACE("iscanresults complete\n");
1195 			iscan->iscan_state = ISCAN_STATE_IDLE;
1196 			wl_iw_send_scan_complete(iscan);
1197 			break;
1198 		case WL_SCAN_RESULTS_PENDING:
1199 			WL_TRACE("iscanresults pending\n");
1200 			mod_timer(&iscan->timer,
1201 				  jiffies + iscan->timer_ms * HZ / 1000);
1202 			iscan->timer_on = 1;
1203 			break;
1204 		case WL_SCAN_RESULTS_ABORTED:
1205 			WL_TRACE("iscanresults aborted\n");
1206 			iscan->iscan_state = ISCAN_STATE_IDLE;
1207 			if (g_scan_specified_ssid == 0)
1208 				wl_iw_send_scan_complete(iscan);
1209 			else {
1210 				iscan_pass_abort = true;
1211 				wl_iw_force_specific_scan(iscan);
1212 			}
1213 			break;
1214 		case WL_SCAN_RESULTS_NO_MEM:
1215 			WL_TRACE("iscanresults can't alloc memory: skip\n");
1216 			iscan->iscan_state = ISCAN_STATE_IDLE;
1217 			break;
1218 		default:
1219 			WL_TRACE("iscanresults returned unknown status %d\n",
1220 				 status);
1221 			break;
1222 		}
1223 	}
1224 
1225 	if (iscan->timer_on) {
1226 		del_timer_sync(&iscan->timer);
1227 		iscan->timer_on = 0;
1228 	}
1229 	return 0;
1230 }
1231 #endif				/* WL_IW_USE_ISCAN */
1232 
1233 static int
wl_iw_set_scan(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1234 wl_iw_set_scan(struct net_device *dev,
1235 	       struct iw_request_info *info,
1236 	       union iwreq_data *wrqu, char *extra)
1237 {
1238 	int error;
1239 	WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name);
1240 
1241 	g_set_essid_before_scan = false;
1242 #if defined(CSCAN)
1243 	WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1244 	return -EINVAL;
1245 #endif
1246 
1247 	if (g_onoff == G_WLAN_SET_OFF)
1248 		return 0;
1249 
1250 	memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
1251 #ifndef WL_IW_USE_ISCAN
1252 	g_scan_specified_ssid = 0;
1253 #endif
1254 
1255 #if WIRELESS_EXT > 17
1256 	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1257 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1258 			struct iw_scan_req *req = (struct iw_scan_req *)extra;
1259 			if (g_scan_specified_ssid) {
1260 				WL_TRACE("%s Specific SCAN is not done ignore scan for = %s\n",
1261 					 __func__, req->essid);
1262 				return -EBUSY;
1263 			} else {
1264 				g_specific_ssid.SSID_len = min_t(size_t,
1265 						sizeof(g_specific_ssid.SSID),
1266 						req->essid_len);
1267 				memcpy(g_specific_ssid.SSID, req->essid,
1268 				       g_specific_ssid.SSID_len);
1269 				g_specific_ssid.SSID_len =
1270 				    cpu_to_le32(g_specific_ssid.SSID_len);
1271 				g_scan_specified_ssid = 1;
1272 				WL_TRACE("### Specific scan ssid=%s len=%d\n",
1273 					 g_specific_ssid.SSID,
1274 					 g_specific_ssid.SSID_len);
1275 			}
1276 		}
1277 	}
1278 #endif				/* WIRELESS_EXT > 17 */
1279 	error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid,
1280 				sizeof(g_specific_ssid));
1281 	if (error) {
1282 		WL_TRACE("#### Set SCAN for %s failed with %d\n",
1283 			 g_specific_ssid.SSID, error);
1284 		g_scan_specified_ssid = 0;
1285 		return -EBUSY;
1286 	}
1287 
1288 	return 0;
1289 }
1290 
1291 #ifdef WL_IW_USE_ISCAN
wl_iw_iscan_set_scan_broadcast_prep(struct net_device * dev,uint flag)1292 int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
1293 {
1294 	wlc_ssid_t ssid;
1295 	iscan_info_t *iscan = g_iscan;
1296 
1297 	if (flag)
1298 		rtnl_lock();
1299 
1300 	wl_iw_set_event_mask(dev);
1301 
1302 	WL_TRACE("+++: Set Broadcast ISCAN\n");
1303 	memset(&ssid, 0, sizeof(ssid));
1304 
1305 	iscan->list_cur = iscan->list_hdr;
1306 	iscan->iscan_state = ISCAN_STATE_SCANING;
1307 
1308 	memset(&iscan->iscan_ex_params_p->params, 0,
1309 	       iscan->iscan_ex_param_size);
1310 	wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
1311 	wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
1312 
1313 	if (flag)
1314 		rtnl_unlock();
1315 
1316 	mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1317 
1318 	iscan->timer_on = 1;
1319 
1320 	return 0;
1321 }
1322 
1323 static int
wl_iw_iscan_set_scan(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1324 wl_iw_iscan_set_scan(struct net_device *dev,
1325 		     struct iw_request_info *info,
1326 		     union iwreq_data *wrqu, char *extra)
1327 {
1328 	wlc_ssid_t ssid;
1329 	iscan_info_t *iscan = g_iscan;
1330 
1331 	WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name);
1332 
1333 #if defined(CSCAN)
1334 	WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__);
1335 	return -EINVAL;
1336 #endif
1337 
1338 	if (g_onoff == G_WLAN_SET_OFF) {
1339 		WL_TRACE("%s: driver is not up yet after START\n", __func__);
1340 		return 0;
1341 	}
1342 #ifdef PNO_SUPPORT
1343 	if (dhd_dev_get_pno_status(dev)) {
1344 		WL_ERROR("%s: Scan called when PNO is active\n", __func__);
1345 	}
1346 #endif
1347 
1348 	if ((!iscan) || (!iscan->sysioc_tsk))
1349 		return wl_iw_set_scan(dev, info, wrqu, extra);
1350 
1351 	if (g_scan_specified_ssid) {
1352 		WL_TRACE("%s Specific SCAN already running ignoring BC scan\n",
1353 			 __func__);
1354 		return -EBUSY;
1355 	}
1356 
1357 	memset(&ssid, 0, sizeof(ssid));
1358 
1359 #if WIRELESS_EXT > 17
1360 	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
1361 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
1362 			struct iw_scan_req *req = (struct iw_scan_req *)extra;
1363 			ssid.SSID_len = min_t(size_t, sizeof(ssid.SSID),
1364 						req->essid_len);
1365 			memcpy(ssid.SSID, req->essid, ssid.SSID_len);
1366 			ssid.SSID_len = cpu_to_le32(ssid.SSID_len);
1367 		} else {
1368 			g_scan_specified_ssid = 0;
1369 
1370 			if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1371 				WL_TRACE("%s ISCAN already in progress\n",
1372 					 __func__);
1373 				return 0;
1374 			}
1375 		}
1376 	}
1377 #endif				/* WIRELESS_EXT > 17 */
1378 	wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1379 
1380 	return 0;
1381 }
1382 #endif				/* WL_IW_USE_ISCAN */
1383 
1384 #if WIRELESS_EXT > 17
ie_is_wpa_ie(u8 ** wpaie,u8 ** tlvs,int * tlvs_len)1385 static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len)
1386 {
1387 
1388 	u8 *ie = *wpaie;
1389 
1390 	if ((ie[1] >= 6) &&
1391 	    !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
1392 		return true;
1393 	}
1394 
1395 	ie += ie[1] + 2;
1396 	*tlvs_len -= (int)(ie - *tlvs);
1397 	*tlvs = ie;
1398 	return false;
1399 }
1400 
ie_is_wps_ie(u8 ** wpsie,u8 ** tlvs,int * tlvs_len)1401 static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len)
1402 {
1403 
1404 	u8 *ie = *wpsie;
1405 
1406 	if ((ie[1] >= 4) &&
1407 	    !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
1408 		return true;
1409 	}
1410 
1411 	ie += ie[1] + 2;
1412 	*tlvs_len -= (int)(ie - *tlvs);
1413 	*tlvs = ie;
1414 	return false;
1415 }
1416 #endif				/* WIRELESS_EXT > 17 */
1417 
1418 static int
wl_iw_handle_scanresults_ies(char ** event_p,char * end,struct iw_request_info * info,wl_bss_info_t * bi)1419 wl_iw_handle_scanresults_ies(char **event_p, char *end,
1420 			     struct iw_request_info *info, wl_bss_info_t *bi)
1421 {
1422 #if WIRELESS_EXT > 17
1423 	struct iw_event iwe;
1424 	char *event;
1425 
1426 	event = *event_p;
1427 	if (bi->ie_length) {
1428 		bcm_tlv_t *ie;
1429 		u8 *ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1430 		int ptr_len = bi->ie_length;
1431 
1432 		ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID);
1433 		if (ie) {
1434 			iwe.cmd = IWEVGENIE;
1435 			iwe.u.data.length = ie->len + 2;
1436 			event =
1437 			    IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1438 						 (char *)ie);
1439 		}
1440 		ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1441 
1442 		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1443 			if (ie_is_wps_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1444 				iwe.cmd = IWEVGENIE;
1445 				iwe.u.data.length = ie->len + 2;
1446 				event =
1447 				    IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1448 							 (char *)ie);
1449 				break;
1450 			}
1451 		}
1452 
1453 		ptr = ((u8 *) bi) + sizeof(wl_bss_info_t);
1454 		ptr_len = bi->ie_length;
1455 		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
1456 			if (ie_is_wpa_ie(((u8 **)&ie), &ptr, &ptr_len)) {
1457 				iwe.cmd = IWEVGENIE;
1458 				iwe.u.data.length = ie->len + 2;
1459 				event =
1460 				    IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1461 							 (char *)ie);
1462 				break;
1463 			}
1464 		}
1465 
1466 		*event_p = event;
1467 	}
1468 #endif		/* WIRELESS_EXT > 17 */
1469 	return 0;
1470 }
1471 
1472 static uint
wl_iw_get_scan_prep(wl_scan_results_t * list,struct iw_request_info * info,char * extra,short max_size)1473 wl_iw_get_scan_prep(wl_scan_results_t *list,
1474 		    struct iw_request_info *info, char *extra, short max_size)
1475 {
1476 	int i, j;
1477 	struct iw_event iwe;
1478 	wl_bss_info_t *bi = NULL;
1479 	char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
1480 	int ret = 0;
1481 
1482 	ASSERT(list);
1483 
1484 	for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
1485 		if (list->version != WL_BSS_INFO_VERSION) {
1486 			WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1487 				 __func__, list->version);
1488 			return ret;
1489 		}
1490 
1491 		bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1492 					     le32_to_cpu(bi->length)) : list->
1493 		    bss_info;
1494 
1495 		WL_TRACE("%s : %s\n", __func__, bi->SSID);
1496 
1497 		iwe.cmd = SIOCGIWAP;
1498 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1499 		memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETH_ALEN);
1500 		event =
1501 		    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1502 					 IW_EV_ADDR_LEN);
1503 		iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1504 		iwe.cmd = SIOCGIWESSID;
1505 		iwe.u.data.flags = 1;
1506 		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1507 
1508 		if (le16_to_cpu(bi->capability) & (WLAN_CAPABILITY_ESS |
1509 		    WLAN_CAPABILITY_IBSS)) {
1510 			iwe.cmd = SIOCGIWMODE;
1511 			if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_ESS)
1512 				iwe.u.mode = IW_MODE_INFRA;
1513 			else
1514 				iwe.u.mode = IW_MODE_ADHOC;
1515 			event =
1516 			    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1517 						 IW_EV_UINT_LEN);
1518 		}
1519 
1520 		iwe.cmd = SIOCGIWFREQ;
1521 
1522 		if (CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL)
1523 			iwe.u.freq.m = ieee80211_dsss_chan_to_freq(
1524 						CHSPEC_CHANNEL(bi->chanspec));
1525 		else
1526 			iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1527 						WF_CHAN_FACTOR_5_G/2,
1528 						CHSPEC_CHANNEL(bi->chanspec));
1529 
1530 		iwe.u.freq.e = 6;
1531 		event =
1532 		    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1533 					 IW_EV_FREQ_LEN);
1534 
1535 		iwe.cmd = IWEVQUAL;
1536 		iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1537 		iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1538 		iwe.u.qual.noise = 0x100 + bi->phy_noise;
1539 		event =
1540 		    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1541 					 IW_EV_QUAL_LEN);
1542 
1543 		wl_iw_handle_scanresults_ies(&event, end, info, bi);
1544 
1545 		iwe.cmd = SIOCGIWENCODE;
1546 		if (le16_to_cpu(bi->capability) & WLAN_CAPABILITY_PRIVACY)
1547 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1548 		else
1549 			iwe.u.data.flags = IW_ENCODE_DISABLED;
1550 		iwe.u.data.length = 0;
1551 		event =
1552 		    IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1553 
1554 		if (bi->rateset.count) {
1555 			if (((event - extra) +
1556 				IW_EV_LCP_LEN) <= (unsigned long)end) {
1557 				value = event + IW_EV_LCP_LEN;
1558 				iwe.cmd = SIOCGIWRATE;
1559 				iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1560 				    0;
1561 				for (j = 0;
1562 				     j < bi->rateset.count
1563 				     && j < IW_MAX_BITRATES; j++) {
1564 					iwe.u.bitrate.value =
1565 					    (bi->rateset.rates[j] & 0x7f) *
1566 					    500000;
1567 					value =
1568 					    IWE_STREAM_ADD_VALUE(info, event,
1569 						 value, end, &iwe,
1570 						 IW_EV_PARAM_LEN);
1571 				}
1572 				event = value;
1573 			}
1574 		}
1575 	}
1576 
1577 	ret = event - extra;
1578 	if (ret < 0) {
1579 		WL_ERROR("==> Wrong size\n");
1580 		ret = 0;
1581 	}
1582 	WL_TRACE("%s: size=%d bytes prepared\n",
1583 		 __func__, (unsigned int)(event - extra));
1584 	return (uint)ret;
1585 }
1586 
1587 static int
wl_iw_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1588 wl_iw_get_scan(struct net_device *dev,
1589 	       struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1590 {
1591 	channel_info_t ci;
1592 	wl_scan_results_t *list_merge;
1593 	wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
1594 	int error;
1595 	uint buflen_from_user = dwrq->length;
1596 	uint len = G_SCAN_RESULTS;
1597 	__u16 len_ret = 0;
1598 #if defined(WL_IW_USE_ISCAN)
1599 	iscan_info_t *iscan = g_iscan;
1600 	iscan_buf_t *p_buf;
1601 #endif
1602 
1603 	WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user);
1604 
1605 	if (!extra) {
1606 		WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name);
1607 		return -EINVAL;
1608 	}
1609 
1610 	error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
1611 	if (error)
1612 		return error;
1613 	ci.scan_channel = le32_to_cpu(ci.scan_channel);
1614 	if (ci.scan_channel)
1615 		return -EAGAIN;
1616 
1617 	if (g_scan_specified_ssid) {
1618 		list = kmalloc(len, GFP_KERNEL);
1619 		if (!list) {
1620 			WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n",
1621 				 dev->name);
1622 			g_scan_specified_ssid = 0;
1623 			return -ENOMEM;
1624 		}
1625 	}
1626 
1627 	memset(list, 0, len);
1628 	list->buflen = cpu_to_le32(len);
1629 	error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len);
1630 	if (error) {
1631 		WL_ERROR("%s: %s : Scan_results ERROR %d\n",
1632 			 dev->name, __func__, error);
1633 		dwrq->length = len;
1634 		if (g_scan_specified_ssid) {
1635 			g_scan_specified_ssid = 0;
1636 			kfree(list);
1637 		}
1638 		return 0;
1639 	}
1640 	list->buflen = le32_to_cpu(list->buflen);
1641 	list->version = le32_to_cpu(list->version);
1642 	list->count = le32_to_cpu(list->count);
1643 
1644 	if (list->version != WL_BSS_INFO_VERSION) {
1645 		WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1646 			 __func__, list->version);
1647 		if (g_scan_specified_ssid) {
1648 			g_scan_specified_ssid = 0;
1649 			kfree(list);
1650 		}
1651 		return -EINVAL;
1652 	}
1653 
1654 	if (g_scan_specified_ssid) {
1655 		WL_TRACE("%s: Specified scan APs in the list =%d\n",
1656 			 __func__, list->count);
1657 		len_ret =
1658 		    (__u16) wl_iw_get_scan_prep(list, info, extra,
1659 						buflen_from_user);
1660 		kfree(list);
1661 
1662 #if defined(WL_IW_USE_ISCAN)
1663 		p_buf = iscan->list_hdr;
1664 		while (p_buf != iscan->list_cur) {
1665 			list_merge =
1666 			    &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1667 			WL_TRACE("%s: Bcast APs list=%d\n",
1668 				 __func__, list_merge->count);
1669 			if (list_merge->count > 0)
1670 				len_ret +=
1671 				    (__u16) wl_iw_get_scan_prep(list_merge,
1672 					info, extra + len_ret,
1673 					buflen_from_user - len_ret);
1674 			p_buf = p_buf->next;
1675 		}
1676 #else
1677 		list_merge = (wl_scan_results_t *) g_scan;
1678 		WL_TRACE("%s: Bcast APs list=%d\n",
1679 			 __func__, list_merge->count);
1680 		if (list_merge->count > 0)
1681 			len_ret +=
1682 			    (__u16) wl_iw_get_scan_prep(list_merge, info,
1683 							extra + len_ret,
1684 							buflen_from_user -
1685 							len_ret);
1686 #endif				/* defined(WL_IW_USE_ISCAN) */
1687 	} else {
1688 		list = (wl_scan_results_t *) g_scan;
1689 		len_ret =
1690 		    (__u16) wl_iw_get_scan_prep(list, info, extra,
1691 						buflen_from_user);
1692 	}
1693 
1694 #if defined(WL_IW_USE_ISCAN)
1695 	g_scan_specified_ssid = 0;
1696 #endif
1697 	if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
1698 		len = len_ret;
1699 
1700 	dwrq->length = len;
1701 	dwrq->flags = 0;
1702 
1703 	WL_TRACE("%s return to WE %d bytes APs=%d\n",
1704 		 __func__, dwrq->length, list->count);
1705 	return 0;
1706 }
1707 
1708 #if defined(WL_IW_USE_ISCAN)
1709 static int
wl_iw_iscan_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1710 wl_iw_iscan_get_scan(struct net_device *dev,
1711 		     struct iw_request_info *info,
1712 		     struct iw_point *dwrq, char *extra)
1713 {
1714 	wl_scan_results_t *list;
1715 	struct iw_event iwe;
1716 	wl_bss_info_t *bi = NULL;
1717 	int ii, j;
1718 	int apcnt;
1719 	char *event = extra, *end = extra + dwrq->length, *value;
1720 	iscan_info_t *iscan = g_iscan;
1721 	iscan_buf_t *p_buf;
1722 	u32 counter = 0;
1723 	u8 channel;
1724 
1725 	WL_TRACE("%s %s buflen_from_user %d:\n",
1726 		 dev->name, __func__, dwrq->length);
1727 
1728 	if (!extra) {
1729 		WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n",
1730 			 dev->name);
1731 		return -EINVAL;
1732 	}
1733 
1734 	if ((!iscan) || (!iscan->sysioc_tsk)) {
1735 		WL_ERROR("%ssysioc_tsk\n", __func__);
1736 		return wl_iw_get_scan(dev, info, dwrq, extra);
1737 	}
1738 
1739 	if (iscan->iscan_state == ISCAN_STATE_SCANING) {
1740 		WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name);
1741 		return -EAGAIN;
1742 	}
1743 
1744 	WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name);
1745 	apcnt = 0;
1746 	p_buf = iscan->list_hdr;
1747 	while (p_buf != iscan->list_cur) {
1748 		list = &((wl_iscan_results_t *) p_buf->iscan_buf)->results;
1749 
1750 		counter += list->count;
1751 
1752 		if (list->version != WL_BSS_INFO_VERSION) {
1753 			WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n",
1754 				 __func__, list->version);
1755 			return -EINVAL;
1756 		}
1757 
1758 		bi = NULL;
1759 		for (ii = 0; ii < list->count && apcnt < IW_MAX_AP;
1760 		     apcnt++, ii++) {
1761 			bi = bi ? (wl_bss_info_t *)((unsigned long)bi +
1762 						     le32_to_cpu(bi->length)) :
1763 			    list->bss_info;
1764 			ASSERT(((unsigned long)bi + le32_to_cpu(bi->length)) <=
1765 			       ((unsigned long)list + WLC_IW_ISCAN_MAXLEN));
1766 
1767 			if (event + ETH_ALEN + bi->SSID_len +
1768 			    IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >=
1769 			    end)
1770 				return -E2BIG;
1771 			iwe.cmd = SIOCGIWAP;
1772 			iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1773 			memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID,
1774 			       ETH_ALEN);
1775 			event =
1776 			    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1777 						 IW_EV_ADDR_LEN);
1778 
1779 			iwe.u.data.length = le32_to_cpu(bi->SSID_len);
1780 			iwe.cmd = SIOCGIWESSID;
1781 			iwe.u.data.flags = 1;
1782 			event =
1783 			    IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1784 						 bi->SSID);
1785 
1786 			if (le16_to_cpu(bi->capability) &
1787 			    (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1788 				iwe.cmd = SIOCGIWMODE;
1789 				if (le16_to_cpu(bi->capability) &
1790 				    WLAN_CAPABILITY_ESS)
1791 					iwe.u.mode = IW_MODE_INFRA;
1792 				else
1793 					iwe.u.mode = IW_MODE_ADHOC;
1794 				event =
1795 				    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1796 							 IW_EV_UINT_LEN);
1797 			}
1798 
1799 			iwe.cmd = SIOCGIWFREQ;
1800 			channel =
1801 			    (bi->ctl_ch ==
1802 			     0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
1803 
1804 			if (channel <= CH_MAX_2G_CHANNEL)
1805 				iwe.u.freq.m =
1806 					ieee80211_dsss_chan_to_freq(channel);
1807 			else
1808 				iwe.u.freq.m = ieee80211_ofdm_chan_to_freq(
1809 							WF_CHAN_FACTOR_5_G/2,
1810 							channel);
1811 
1812 			iwe.u.freq.e = 6;
1813 			event =
1814 			    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1815 						 IW_EV_FREQ_LEN);
1816 
1817 			iwe.cmd = IWEVQUAL;
1818 			iwe.u.qual.qual = rssi_to_qual(le16_to_cpu(bi->RSSI));
1819 			iwe.u.qual.level = 0x100 + le16_to_cpu(bi->RSSI);
1820 			iwe.u.qual.noise = 0x100 + bi->phy_noise;
1821 			event =
1822 			    IWE_STREAM_ADD_EVENT(info, event, end, &iwe,
1823 						 IW_EV_QUAL_LEN);
1824 
1825 			wl_iw_handle_scanresults_ies(&event, end, info, bi);
1826 
1827 			iwe.cmd = SIOCGIWENCODE;
1828 			if (le16_to_cpu(bi->capability) &
1829 			    WLAN_CAPABILITY_PRIVACY)
1830 				iwe.u.data.flags =
1831 				    IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1832 			else
1833 				iwe.u.data.flags = IW_ENCODE_DISABLED;
1834 			iwe.u.data.length = 0;
1835 			event =
1836 			    IWE_STREAM_ADD_POINT(info, event, end, &iwe,
1837 						 (char *)event);
1838 
1839 			if (bi->rateset.count) {
1840 				if (event + IW_MAX_BITRATES * IW_EV_PARAM_LEN >=
1841 				    end)
1842 					return -E2BIG;
1843 
1844 				value = event + IW_EV_LCP_LEN;
1845 				iwe.cmd = SIOCGIWRATE;
1846 				iwe.u.bitrate.fixed = iwe.u.bitrate.disabled =
1847 				    0;
1848 				for (j = 0;
1849 				     j < bi->rateset.count
1850 				     && j < IW_MAX_BITRATES; j++) {
1851 					iwe.u.bitrate.value =
1852 					    (bi->rateset.rates[j] & 0x7f) *
1853 					    500000;
1854 					value =
1855 					    IWE_STREAM_ADD_VALUE(info, event,
1856 						 value, end,
1857 						 &iwe,
1858 						 IW_EV_PARAM_LEN);
1859 				}
1860 				event = value;
1861 			}
1862 		}
1863 		p_buf = p_buf->next;
1864 	}
1865 
1866 	dwrq->length = event - extra;
1867 	dwrq->flags = 0;
1868 
1869 	WL_TRACE("%s return to WE %d bytes APs=%d\n",
1870 		 __func__, dwrq->length, counter);
1871 
1872 	if (!dwrq->length)
1873 		return -EAGAIN;
1874 
1875 	return 0;
1876 }
1877 #endif				/* defined(WL_IW_USE_ISCAN) */
1878 
1879 static int
wl_iw_set_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1880 wl_iw_set_essid(struct net_device *dev,
1881 		struct iw_request_info *info,
1882 		struct iw_point *dwrq, char *extra)
1883 {
1884 	int error;
1885 	wl_join_params_t join_params;
1886 	int join_params_size;
1887 
1888 	WL_TRACE("%s: SIOCSIWESSID\n", dev->name);
1889 
1890 	if (g_set_essid_before_scan)
1891 		return -EAGAIN;
1892 
1893 	memset(&g_ssid, 0, sizeof(g_ssid));
1894 
1895 	CHECK_EXTRA_FOR_NULL(extra);
1896 
1897 	if (dwrq->length && extra) {
1898 #if WIRELESS_EXT > 20
1899 		g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1900 					dwrq->length);
1901 #else
1902 		g_ssid.SSID_len = min_t(size_t, sizeof(g_ssid.SSID),
1903 					dwrq->length - 1);
1904 #endif
1905 		memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
1906 	} else {
1907 		g_ssid.SSID_len = 0;
1908 	}
1909 	g_ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1910 
1911 	memset(&join_params, 0, sizeof(join_params));
1912 	join_params_size = sizeof(join_params.ssid);
1913 
1914 	memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
1915 	join_params.ssid.SSID_len = cpu_to_le32(g_ssid.SSID_len);
1916 	memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
1917 
1918 	wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params,
1919 			     &join_params_size);
1920 
1921 	error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params,
1922 				join_params_size);
1923 	if (error)
1924 		WL_ERROR("Invalid ioctl data=%d\n", error);
1925 
1926 	if (g_ssid.SSID_len) {
1927 		WL_TRACE("%s: join SSID=%s ch=%d\n",
1928 			 __func__, g_ssid.SSID, g_wl_iw_params.target_channel);
1929 	}
1930 	return 0;
1931 }
1932 
1933 static int
wl_iw_get_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1934 wl_iw_get_essid(struct net_device *dev,
1935 		struct iw_request_info *info,
1936 		struct iw_point *dwrq, char *extra)
1937 {
1938 	wlc_ssid_t ssid;
1939 	int error;
1940 
1941 	WL_TRACE("%s: SIOCGIWESSID\n", dev->name);
1942 
1943 	if (!extra)
1944 		return -EINVAL;
1945 
1946 	error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1947 	if (error) {
1948 		WL_ERROR("Error getting the SSID\n");
1949 		return error;
1950 	}
1951 
1952 	ssid.SSID_len = le32_to_cpu(ssid.SSID_len);
1953 
1954 	memcpy(extra, ssid.SSID, ssid.SSID_len);
1955 
1956 	dwrq->length = ssid.SSID_len;
1957 
1958 	dwrq->flags = 1;
1959 
1960 	return 0;
1961 }
1962 
1963 static int
wl_iw_set_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1964 wl_iw_set_nick(struct net_device *dev,
1965 	       struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1966 {
1967 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1968 
1969 	WL_TRACE("%s: SIOCSIWNICKN\n", dev->name);
1970 
1971 	if (!extra)
1972 		return -EINVAL;
1973 
1974 	if (dwrq->length > sizeof(iw->nickname))
1975 		return -E2BIG;
1976 
1977 	memcpy(iw->nickname, extra, dwrq->length);
1978 	iw->nickname[dwrq->length - 1] = '\0';
1979 
1980 	return 0;
1981 }
1982 
1983 static int
wl_iw_get_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1984 wl_iw_get_nick(struct net_device *dev,
1985 	       struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1986 {
1987 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
1988 
1989 	WL_TRACE("%s: SIOCGIWNICKN\n", dev->name);
1990 
1991 	if (!extra)
1992 		return -EINVAL;
1993 
1994 	strcpy(extra, iw->nickname);
1995 	dwrq->length = strlen(extra) + 1;
1996 
1997 	return 0;
1998 }
1999 
2000 static int
wl_iw_set_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2001 wl_iw_set_rate(struct net_device *dev,
2002 	       struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2003 {
2004 	wl_rateset_t rateset;
2005 	int error, rate, i, error_bg, error_a;
2006 
2007 	WL_TRACE("%s: SIOCSIWRATE\n", dev->name);
2008 
2009 	error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
2010 				sizeof(rateset));
2011 	if (error)
2012 		return error;
2013 
2014 	rateset.count = le32_to_cpu(rateset.count);
2015 
2016 	if (vwrq->value < 0)
2017 		rate = rateset.rates[rateset.count - 1] & 0x7f;
2018 	else if (vwrq->value < rateset.count)
2019 		rate = rateset.rates[vwrq->value] & 0x7f;
2020 	else
2021 		rate = vwrq->value / 500000;
2022 
2023 	if (vwrq->fixed) {
2024 		error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
2025 		error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
2026 
2027 		if (error_bg && error_a)
2028 			return error_bg | error_a;
2029 	} else {
2030 		error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
2031 		error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
2032 
2033 		if (error_bg && error_a)
2034 			return error_bg | error_a;
2035 
2036 		for (i = 0; i < rateset.count; i++)
2037 			if ((rateset.rates[i] & 0x7f) > rate)
2038 				break;
2039 		rateset.count = cpu_to_le32(i);
2040 
2041 		error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset,
2042 					sizeof(rateset));
2043 		if (error)
2044 			return error;
2045 	}
2046 
2047 	return 0;
2048 }
2049 
2050 static int
wl_iw_get_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2051 wl_iw_get_rate(struct net_device *dev,
2052 	       struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2053 {
2054 	int error, rate;
2055 
2056 	WL_TRACE("%s: SIOCGIWRATE\n", dev->name);
2057 
2058 	error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate));
2059 	if (error)
2060 		return error;
2061 	rate = le32_to_cpu(rate);
2062 	vwrq->value = rate * 500000;
2063 
2064 	return 0;
2065 }
2066 
2067 static int
wl_iw_set_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2068 wl_iw_set_rts(struct net_device *dev,
2069 	      struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2070 {
2071 	int error, rts;
2072 
2073 	WL_TRACE("%s: SIOCSIWRTS\n", dev->name);
2074 
2075 	if (vwrq->disabled)
2076 		rts = DOT11_DEFAULT_RTS_LEN;
2077 	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
2078 		return -EINVAL;
2079 	else
2080 		rts = vwrq->value;
2081 
2082 	error = dev_wlc_intvar_set(dev, "rtsthresh", rts);
2083 	if (error)
2084 		return error;
2085 
2086 	return 0;
2087 }
2088 
2089 static int
wl_iw_get_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2090 wl_iw_get_rts(struct net_device *dev,
2091 	      struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2092 {
2093 	int error, rts;
2094 
2095 	WL_TRACE("%s: SIOCGIWRTS\n", dev->name);
2096 
2097 	error = dev_wlc_intvar_get(dev, "rtsthresh", &rts);
2098 	if (error)
2099 		return error;
2100 
2101 	vwrq->value = rts;
2102 	vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
2103 	vwrq->fixed = 1;
2104 
2105 	return 0;
2106 }
2107 
2108 static int
wl_iw_set_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2109 wl_iw_set_frag(struct net_device *dev,
2110 	       struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2111 {
2112 	int error, frag;
2113 
2114 	WL_TRACE("%s: SIOCSIWFRAG\n", dev->name);
2115 
2116 	if (vwrq->disabled)
2117 		frag = DOT11_DEFAULT_FRAG_LEN;
2118 	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
2119 		return -EINVAL;
2120 	else
2121 		frag = vwrq->value;
2122 
2123 	error = dev_wlc_intvar_set(dev, "fragthresh", frag);
2124 	if (error)
2125 		return error;
2126 
2127 	return 0;
2128 }
2129 
2130 static int
wl_iw_get_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2131 wl_iw_get_frag(struct net_device *dev,
2132 	       struct iw_request_info *info, struct iw_param *vwrq, char *extra)
2133 {
2134 	int error, fragthreshold;
2135 
2136 	WL_TRACE("%s: SIOCGIWFRAG\n", dev->name);
2137 
2138 	error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold);
2139 	if (error)
2140 		return error;
2141 
2142 	vwrq->value = fragthreshold;
2143 	vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
2144 	vwrq->fixed = 1;
2145 
2146 	return 0;
2147 }
2148 
2149 static int
wl_iw_set_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2150 wl_iw_set_txpow(struct net_device *dev,
2151 		struct iw_request_info *info,
2152 		struct iw_param *vwrq, char *extra)
2153 {
2154 	int error, disable;
2155 	u16 txpwrmw;
2156 	WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name);
2157 
2158 	disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
2159 	disable += WL_RADIO_SW_DISABLE << 16;
2160 
2161 	disable = cpu_to_le32(disable);
2162 	error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable));
2163 	if (error)
2164 		return error;
2165 
2166 	if (disable & WL_RADIO_SW_DISABLE)
2167 		return 0;
2168 
2169 	if (!(vwrq->flags & IW_TXPOW_MWATT))
2170 		return -EINVAL;
2171 
2172 	if (vwrq->value < 0)
2173 		return 0;
2174 
2175 	if (vwrq->value > 0xffff)
2176 		txpwrmw = 0xffff;
2177 	else
2178 		txpwrmw = (u16) vwrq->value;
2179 
2180 	error =
2181 	    dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
2182 	return error;
2183 }
2184 
2185 static int
wl_iw_get_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2186 wl_iw_get_txpow(struct net_device *dev,
2187 		struct iw_request_info *info,
2188 		struct iw_param *vwrq, char *extra)
2189 {
2190 	int error, disable, txpwrdbm;
2191 	u8 result;
2192 
2193 	WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name);
2194 
2195 	error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable));
2196 	if (error)
2197 		return error;
2198 
2199 	error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm);
2200 	if (error)
2201 		return error;
2202 
2203 	disable = le32_to_cpu(disable);
2204 	result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2205 	vwrq->value = (s32) bcm_qdbm_to_mw(result);
2206 	vwrq->fixed = 0;
2207 	vwrq->disabled =
2208 	    (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
2209 	vwrq->flags = IW_TXPOW_MWATT;
2210 
2211 	return 0;
2212 }
2213 
2214 #if WIRELESS_EXT > 10
2215 static int
wl_iw_set_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2216 wl_iw_set_retry(struct net_device *dev,
2217 		struct iw_request_info *info,
2218 		struct iw_param *vwrq, char *extra)
2219 {
2220 	int error, lrl, srl;
2221 
2222 	WL_TRACE("%s: SIOCSIWRETRY\n", dev->name);
2223 
2224 	if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
2225 		return -EINVAL;
2226 
2227 	if (vwrq->flags & IW_RETRY_LIMIT) {
2228 
2229 #if WIRELESS_EXT > 20
2230 		if ((vwrq->flags & IW_RETRY_LONG)
2231 		    || (vwrq->flags & IW_RETRY_MAX)
2232 		    || !((vwrq->flags & IW_RETRY_SHORT)
2233 			 || (vwrq->flags & IW_RETRY_MIN))) {
2234 #else
2235 		if ((vwrq->flags & IW_RETRY_MAX)
2236 		    || !(vwrq->flags & IW_RETRY_MIN)) {
2237 #endif
2238 			lrl = cpu_to_le32(vwrq->value);
2239 			error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl,
2240 						sizeof(lrl));
2241 			if (error)
2242 				return error;
2243 		}
2244 #if WIRELESS_EXT > 20
2245 		if ((vwrq->flags & IW_RETRY_SHORT)
2246 		    || (vwrq->flags & IW_RETRY_MIN)
2247 		    || !((vwrq->flags & IW_RETRY_LONG)
2248 			 || (vwrq->flags & IW_RETRY_MAX))) {
2249 #else
2250 		if ((vwrq->flags & IW_RETRY_MIN)
2251 		    || !(vwrq->flags & IW_RETRY_MAX)) {
2252 #endif
2253 			srl = cpu_to_le32(vwrq->value);
2254 			error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl,
2255 						sizeof(srl));
2256 			if (error)
2257 				return error;
2258 		}
2259 	}
2260 	return 0;
2261 }
2262 
2263 static int
2264 wl_iw_get_retry(struct net_device *dev,
2265 		struct iw_request_info *info,
2266 		struct iw_param *vwrq, char *extra)
2267 {
2268 	int error, lrl, srl;
2269 
2270 	WL_TRACE("%s: SIOCGIWRETRY\n", dev->name);
2271 
2272 	vwrq->disabled = 0;
2273 
2274 	if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
2275 		return -EINVAL;
2276 
2277 	error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl));
2278 	if (error)
2279 		return error;
2280 
2281 	error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl));
2282 	if (error)
2283 		return error;
2284 
2285 	lrl = le32_to_cpu(lrl);
2286 	srl = le32_to_cpu(srl);
2287 
2288 	if (vwrq->flags & IW_RETRY_MAX) {
2289 		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
2290 		vwrq->value = lrl;
2291 	} else {
2292 		vwrq->flags = IW_RETRY_LIMIT;
2293 		vwrq->value = srl;
2294 		if (srl != lrl)
2295 			vwrq->flags |= IW_RETRY_MIN;
2296 	}
2297 
2298 	return 0;
2299 }
2300 #endif				/* WIRELESS_EXT > 10 */
2301 
2302 static int
2303 wl_iw_set_encode(struct net_device *dev,
2304 		 struct iw_request_info *info,
2305 		 struct iw_point *dwrq, char *extra)
2306 {
2307 	wl_wsec_key_t key;
2308 	int error, val, wsec;
2309 
2310 	WL_TRACE("%s: SIOCSIWENCODE\n", dev->name);
2311 
2312 	memset(&key, 0, sizeof(key));
2313 
2314 	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2315 		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2316 		     key.index++) {
2317 			val = cpu_to_le32(key.index);
2318 			error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2319 						sizeof(val));
2320 			if (error)
2321 				return error;
2322 			val = le32_to_cpu(val);
2323 			if (val)
2324 				break;
2325 		}
2326 		if (key.index == DOT11_MAX_DEFAULT_KEYS)
2327 			key.index = 0;
2328 	} else {
2329 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2330 		if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2331 			return -EINVAL;
2332 	}
2333 
2334 	if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
2335 		val = cpu_to_le32(key.index);
2336 		error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val,
2337 					sizeof(val));
2338 		if (error)
2339 			return error;
2340 	} else {
2341 		key.len = dwrq->length;
2342 
2343 		if (dwrq->length > sizeof(key.data))
2344 			return -EINVAL;
2345 
2346 		memcpy(key.data, extra, dwrq->length);
2347 
2348 		key.flags = WL_PRIMARY_KEY;
2349 		switch (key.len) {
2350 		case WLAN_KEY_LEN_WEP40:
2351 			key.algo = CRYPTO_ALGO_WEP1;
2352 			break;
2353 		case WLAN_KEY_LEN_WEP104:
2354 			key.algo = CRYPTO_ALGO_WEP128;
2355 			break;
2356 		case WLAN_KEY_LEN_TKIP:
2357 			key.algo = CRYPTO_ALGO_TKIP;
2358 			break;
2359 		case WLAN_KEY_LEN_AES_CMAC:
2360 			key.algo = CRYPTO_ALGO_AES_CCM;
2361 			break;
2362 		default:
2363 			return -EINVAL;
2364 		}
2365 
2366 		swap_key_from_BE(&key);
2367 		error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2368 		if (error)
2369 			return error;
2370 	}
2371 
2372 	val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
2373 
2374 	error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2375 	if (error)
2376 		return error;
2377 
2378 	wsec &= ~(WEP_ENABLED);
2379 	wsec |= val;
2380 
2381 	error = dev_wlc_intvar_set(dev, "wsec", wsec);
2382 	if (error)
2383 		return error;
2384 
2385 	val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
2386 	val = cpu_to_le32(val);
2387 	error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val));
2388 	if (error)
2389 		return error;
2390 
2391 	return 0;
2392 }
2393 
2394 static int
2395 wl_iw_get_encode(struct net_device *dev,
2396 		 struct iw_request_info *info,
2397 		 struct iw_point *dwrq, char *extra)
2398 {
2399 	wl_wsec_key_t key;
2400 	int error, val, wsec, auth;
2401 
2402 	WL_TRACE("%s: SIOCGIWENCODE\n", dev->name);
2403 
2404 	memset(&key, 0, sizeof(wl_wsec_key_t));
2405 
2406 	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
2407 		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS;
2408 		     key.index++) {
2409 			val = key.index;
2410 			error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val,
2411 						sizeof(val));
2412 			if (error)
2413 				return error;
2414 			val = le32_to_cpu(val);
2415 			if (val)
2416 				break;
2417 		}
2418 	} else
2419 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2420 
2421 	if (key.index >= DOT11_MAX_DEFAULT_KEYS)
2422 		key.index = 0;
2423 
2424 	error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec));
2425 	if (error)
2426 		return error;
2427 
2428 	error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth));
2429 	if (error)
2430 		return error;
2431 
2432 	swap_key_to_BE(&key);
2433 
2434 	wsec = le32_to_cpu(wsec);
2435 	auth = le32_to_cpu(auth);
2436 	dwrq->length = min_t(u16, WLAN_MAX_KEY_LEN, key.len);
2437 
2438 	dwrq->flags = key.index + 1;
2439 	if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)))
2440 		dwrq->flags |= IW_ENCODE_DISABLED;
2441 
2442 	if (auth)
2443 		dwrq->flags |= IW_ENCODE_RESTRICTED;
2444 
2445 	if (dwrq->length && extra)
2446 		memcpy(extra, key.data, dwrq->length);
2447 
2448 	return 0;
2449 }
2450 
2451 static int
2452 wl_iw_set_power(struct net_device *dev,
2453 		struct iw_request_info *info,
2454 		struct iw_param *vwrq, char *extra)
2455 {
2456 	int error, pm;
2457 
2458 	WL_TRACE("%s: SIOCSIWPOWER\n", dev->name);
2459 
2460 	pm = vwrq->disabled ? PM_OFF : PM_MAX;
2461 
2462 	pm = cpu_to_le32(pm);
2463 	error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
2464 	if (error)
2465 		return error;
2466 
2467 	return 0;
2468 }
2469 
2470 static int
2471 wl_iw_get_power(struct net_device *dev,
2472 		struct iw_request_info *info,
2473 		struct iw_param *vwrq, char *extra)
2474 {
2475 	int error, pm;
2476 
2477 	WL_TRACE("%s: SIOCGIWPOWER\n", dev->name);
2478 
2479 	error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
2480 	if (error)
2481 		return error;
2482 
2483 	pm = le32_to_cpu(pm);
2484 	vwrq->disabled = pm ? 0 : 1;
2485 	vwrq->flags = IW_POWER_ALL_R;
2486 
2487 	return 0;
2488 }
2489 
2490 #if WIRELESS_EXT > 17
2491 static int
2492 wl_iw_set_wpaie(struct net_device *dev,
2493 		struct iw_request_info *info, struct iw_point *iwp, char *extra)
2494 {
2495 
2496 	WL_TRACE("%s: SIOCSIWGENIE\n", dev->name);
2497 
2498 	CHECK_EXTRA_FOR_NULL(extra);
2499 
2500 	dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
2501 
2502 	return 0;
2503 }
2504 
2505 static int
2506 wl_iw_get_wpaie(struct net_device *dev,
2507 		struct iw_request_info *info, struct iw_point *iwp, char *extra)
2508 {
2509 	WL_TRACE("%s: SIOCGIWGENIE\n", dev->name);
2510 	iwp->length = 64;
2511 	dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
2512 	return 0;
2513 }
2514 
2515 static int
2516 wl_iw_set_encodeext(struct net_device *dev,
2517 		    struct iw_request_info *info,
2518 		    struct iw_point *dwrq, char *extra)
2519 {
2520 	wl_wsec_key_t key;
2521 	int error;
2522 	struct iw_encode_ext *iwe;
2523 
2524 	WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name);
2525 
2526 	CHECK_EXTRA_FOR_NULL(extra);
2527 
2528 	memset(&key, 0, sizeof(key));
2529 	iwe = (struct iw_encode_ext *)extra;
2530 
2531 	if (dwrq->flags & IW_ENCODE_DISABLED) {
2532 
2533 	}
2534 
2535 	key.index = 0;
2536 	if (dwrq->flags & IW_ENCODE_INDEX)
2537 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
2538 
2539 	key.len = iwe->key_len;
2540 
2541 	if (!is_multicast_ether_addr(iwe->addr.sa_data))
2542 		memcpy(&key.ea, &iwe->addr.sa_data, ETH_ALEN);
2543 
2544 	if (key.len == 0) {
2545 		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2546 			WL_WSEC("Changing the the primary Key to %d\n",
2547 				key.index);
2548 			key.index = cpu_to_le32(key.index);
2549 			error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
2550 					      &key.index, sizeof(key.index));
2551 			if (error)
2552 				return error;
2553 		} else {
2554 			swap_key_from_BE(&key);
2555 			dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2556 		}
2557 	} else {
2558 		if (iwe->key_len > sizeof(key.data))
2559 			return -EINVAL;
2560 
2561 		WL_WSEC("Setting the key index %d\n", key.index);
2562 		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
2563 			WL_WSEC("key is a Primary Key\n");
2564 			key.flags = WL_PRIMARY_KEY;
2565 		}
2566 
2567 		memcpy(key.data, iwe->key, iwe->key_len);
2568 
2569 		if (iwe->alg == IW_ENCODE_ALG_TKIP) {
2570 			u8 keybuf[8];
2571 			memcpy(keybuf, &key.data[24], sizeof(keybuf));
2572 			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2573 			memcpy(&key.data[16], keybuf, sizeof(keybuf));
2574 		}
2575 
2576 		if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
2577 			unsigned char *ivptr;
2578 			ivptr = (unsigned char *) iwe->rx_seq;
2579 			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2580 			    (ivptr[3] << 8) | ivptr[2];
2581 			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2582 			key.iv_initialized = true;
2583 		}
2584 
2585 		switch (iwe->alg) {
2586 		case IW_ENCODE_ALG_NONE:
2587 			key.algo = CRYPTO_ALGO_OFF;
2588 			break;
2589 		case IW_ENCODE_ALG_WEP:
2590 			if (iwe->key_len == WLAN_KEY_LEN_WEP40)
2591 				key.algo = CRYPTO_ALGO_WEP1;
2592 			else
2593 				key.algo = CRYPTO_ALGO_WEP128;
2594 			break;
2595 		case IW_ENCODE_ALG_TKIP:
2596 			key.algo = CRYPTO_ALGO_TKIP;
2597 			break;
2598 		case IW_ENCODE_ALG_CCMP:
2599 			key.algo = CRYPTO_ALGO_AES_CCM;
2600 			break;
2601 		default:
2602 			break;
2603 		}
2604 		swap_key_from_BE(&key);
2605 
2606 		dhd_wait_pend8021x(dev);
2607 
2608 		error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
2609 		if (error)
2610 			return error;
2611 	}
2612 	return 0;
2613 }
2614 
2615 #if WIRELESS_EXT > 17
2616 struct {
2617 	pmkid_list_t pmkids;
2618 	pmkid_t foo[MAXPMKID - 1];
2619 } pmkid_list;
2620 
2621 static int
2622 wl_iw_set_pmksa(struct net_device *dev,
2623 		struct iw_request_info *info,
2624 		struct iw_param *vwrq, char *extra)
2625 {
2626 	struct iw_pmksa *iwpmksa;
2627 	uint i;
2628 	int ret = 0;
2629 
2630 	WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name);
2631 
2632 	CHECK_EXTRA_FOR_NULL(extra);
2633 
2634 	iwpmksa = (struct iw_pmksa *)extra;
2635 
2636 	if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
2637 		WL_WSEC("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n");
2638 		memset((char *)&pmkid_list, 0, sizeof(pmkid_list));
2639 	}
2640 
2641 	else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
2642 		{
2643 			pmkid_list_t pmkid, *pmkidptr;
2644 			uint j;
2645 			pmkidptr = &pmkid;
2646 
2647 			memcpy(&pmkidptr->pmkid[0].BSSID,
2648 			       &iwpmksa->bssid.sa_data[0],
2649 			       ETH_ALEN);
2650 			memcpy(&pmkidptr->pmkid[0].PMKID,
2651 			       &iwpmksa->pmkid[0],
2652 			       WLAN_PMKID_LEN);
2653 
2654 			WL_WSEC("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: "
2655 				"%pM = ", &pmkidptr->pmkid[0].BSSID);
2656 			for (j = 0; j < WLAN_PMKID_LEN; j++)
2657 				WL_WSEC("%02x ", pmkidptr->pmkid[0].PMKID[j]);
2658 			WL_WSEC("\n");
2659 		}
2660 
2661 		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2662 			if (!memcmp
2663 			    (&iwpmksa->bssid.sa_data[0],
2664 			     &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2665 				break;
2666 
2667 		if ((pmkid_list.pmkids.npmkid > 0)
2668 		    && (i < pmkid_list.pmkids.npmkid)) {
2669 			memset(&pmkid_list.pmkids.pmkid[i], 0, sizeof(pmkid_t));
2670 			for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
2671 				memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2672 				       &pmkid_list.pmkids.pmkid[i + 1].BSSID,
2673 				       ETH_ALEN);
2674 				memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2675 				       &pmkid_list.pmkids.pmkid[i + 1].PMKID,
2676 				       WLAN_PMKID_LEN);
2677 			}
2678 			pmkid_list.pmkids.npmkid--;
2679 		} else
2680 			ret = -EINVAL;
2681 	}
2682 
2683 	else if (iwpmksa->cmd == IW_PMKSA_ADD) {
2684 		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
2685 			if (!memcmp
2686 			    (&iwpmksa->bssid.sa_data[0],
2687 			     &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN))
2688 				break;
2689 		if (i < MAXPMKID) {
2690 			memcpy(&pmkid_list.pmkids.pmkid[i].BSSID,
2691 			       &iwpmksa->bssid.sa_data[0],
2692 			       ETH_ALEN);
2693 			memcpy(&pmkid_list.pmkids.pmkid[i].PMKID,
2694 			       &iwpmksa->pmkid[0],
2695 			       WLAN_PMKID_LEN);
2696 			if (i == pmkid_list.pmkids.npmkid)
2697 				pmkid_list.pmkids.npmkid++;
2698 		} else
2699 			ret = -EINVAL;
2700 		{
2701 			uint j;
2702 			uint k;
2703 			k = pmkid_list.pmkids.npmkid;
2704 			WL_WSEC("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ",
2705 				&pmkid_list.pmkids.pmkid[k].BSSID);
2706 			for (j = 0; j < WLAN_PMKID_LEN; j++)
2707 				WL_WSEC("%02x ",
2708 					pmkid_list.pmkids.pmkid[k].PMKID[j]);
2709 			WL_WSEC("\n");
2710 		}
2711 	}
2712 	WL_WSEC("PRINTING pmkid LIST - No of elements %d\n",
2713 		pmkid_list.pmkids.npmkid);
2714 	for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
2715 		uint j;
2716 		WL_WSEC("PMKID[%d]: %pM = ",
2717 			i, &pmkid_list.pmkids.pmkid[i].BSSID);
2718 		for (j = 0; j < WLAN_PMKID_LEN; j++)
2719 			WL_WSEC("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]);
2720 		WL_WSEC("\n");
2721 	}
2722 	WL_WSEC("\n");
2723 
2724 	if (!ret)
2725 		ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
2726 					 sizeof(pmkid_list));
2727 	return ret;
2728 }
2729 #endif				/* WIRELESS_EXT > 17 */
2730 
2731 static int
2732 wl_iw_get_encodeext(struct net_device *dev,
2733 		    struct iw_request_info *info,
2734 		    struct iw_param *vwrq, char *extra)
2735 {
2736 	WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name);
2737 	return 0;
2738 }
2739 
2740 static int
2741 wl_iw_set_wpaauth(struct net_device *dev,
2742 		  struct iw_request_info *info,
2743 		  struct iw_param *vwrq, char *extra)
2744 {
2745 	int error = 0;
2746 	int paramid;
2747 	int paramval;
2748 	int val = 0;
2749 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2750 
2751 	WL_TRACE("%s: SIOCSIWAUTH\n", dev->name);
2752 
2753 	paramid = vwrq->flags & IW_AUTH_INDEX;
2754 	paramval = vwrq->value;
2755 
2756 	WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
2757 		 dev->name, paramid, paramval);
2758 
2759 	switch (paramid) {
2760 	case IW_AUTH_WPA_VERSION:
2761 		if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
2762 			val = WPA_AUTH_DISABLED;
2763 		else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
2764 			val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
2765 		else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
2766 			val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
2767 		WL_INFORM("%s: %d: setting wpa_auth to 0x%0x\n",
2768 			  __func__, __LINE__, val);
2769 		error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2770 		if (error)
2771 			return error;
2772 		break;
2773 	case IW_AUTH_CIPHER_PAIRWISE:
2774 	case IW_AUTH_CIPHER_GROUP:
2775 		if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2776 			val = WEP_ENABLED;
2777 		if (paramval & IW_AUTH_CIPHER_TKIP)
2778 			val = TKIP_ENABLED;
2779 		if (paramval & IW_AUTH_CIPHER_CCMP)
2780 			val = AES_ENABLED;
2781 
2782 		if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
2783 			iw->pwsec = val;
2784 			val |= iw->gwsec;
2785 		} else {
2786 			iw->gwsec = val;
2787 			val |= iw->pwsec;
2788 		}
2789 
2790 		if (iw->privacy_invoked && !val) {
2791 			WL_WSEC("%s: %s: 'Privacy invoked' true but clearing wsec, assuming we're a WPS enrollee\n",
2792 				dev->name, __func__);
2793 			error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2794 							true);
2795 			if (error) {
2796 				WL_WSEC("Failed to set is_WPS_enrollee\n");
2797 				return error;
2798 			}
2799 		} else if (val) {
2800 			error = dev_wlc_intvar_set(dev, "is_WPS_enrollee",
2801 							false);
2802 			if (error) {
2803 				WL_WSEC("Failed to clear is_WPS_enrollee\n");
2804 				return error;
2805 			}
2806 		}
2807 
2808 		error = dev_wlc_intvar_set(dev, "wsec", val);
2809 		if (error)
2810 			return error;
2811 
2812 		break;
2813 
2814 	case IW_AUTH_KEY_MGMT:
2815 		error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2816 		if (error)
2817 			return error;
2818 
2819 		if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
2820 			if (paramval & IW_AUTH_KEY_MGMT_PSK)
2821 				val = WPA_AUTH_PSK;
2822 			else
2823 				val = WPA_AUTH_UNSPECIFIED;
2824 		} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2825 			if (paramval & IW_AUTH_KEY_MGMT_PSK)
2826 				val = WPA2_AUTH_PSK;
2827 			else
2828 				val = WPA2_AUTH_UNSPECIFIED;
2829 		}
2830 		WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2831 			  __func__, __LINE__, val);
2832 		error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2833 		if (error)
2834 			return error;
2835 
2836 		break;
2837 	case IW_AUTH_TKIP_COUNTERMEASURES:
2838 		dev_wlc_bufvar_set(dev, "tkip_countermeasures",
2839 				   (char *)&paramval, 1);
2840 		break;
2841 
2842 	case IW_AUTH_80211_AUTH_ALG:
2843 		WL_INFORM("Setting the D11auth %d\n", paramval);
2844 		if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
2845 			val = 0;
2846 		else if (paramval == IW_AUTH_ALG_SHARED_KEY)
2847 			val = 1;
2848 		else if (paramval ==
2849 			 (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
2850 			val = 2;
2851 		else
2852 			error = 1;
2853 		if (!error) {
2854 			error = dev_wlc_intvar_set(dev, "auth", val);
2855 			if (error)
2856 				return error;
2857 		}
2858 		break;
2859 
2860 	case IW_AUTH_WPA_ENABLED:
2861 		if (paramval == 0) {
2862 			iw->pwsec = 0;
2863 			iw->gwsec = 0;
2864 			error = dev_wlc_intvar_get(dev, "wsec", &val);
2865 			if (error)
2866 				return error;
2867 			if (val & (TKIP_ENABLED | AES_ENABLED)) {
2868 				val &= ~(TKIP_ENABLED | AES_ENABLED);
2869 				dev_wlc_intvar_set(dev, "wsec", val);
2870 			}
2871 			val = 0;
2872 			WL_INFORM("%s: %d: setting wpa_auth to %d\n",
2873 				  __func__, __LINE__, val);
2874 			dev_wlc_intvar_set(dev, "wpa_auth", 0);
2875 			return error;
2876 		}
2877 		break;
2878 
2879 	case IW_AUTH_DROP_UNENCRYPTED:
2880 		dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
2881 		break;
2882 
2883 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2884 		dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol",
2885 				   (char *)&paramval, 1);
2886 		break;
2887 
2888 #if WIRELESS_EXT > 17
2889 	case IW_AUTH_ROAMING_CONTROL:
2890 		WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
2891 		break;
2892 	case IW_AUTH_PRIVACY_INVOKED:
2893 		{
2894 			int wsec;
2895 
2896 			if (paramval == 0) {
2897 				iw->privacy_invoked = false;
2898 				error = dev_wlc_intvar_set(dev,
2899 						"is_WPS_enrollee", false);
2900 				if (error) {
2901 					WL_WSEC("Failed to clear iovar is_WPS_enrollee\n");
2902 					return error;
2903 				}
2904 			} else {
2905 				iw->privacy_invoked = true;
2906 				error = dev_wlc_intvar_get(dev, "wsec", &wsec);
2907 				if (error)
2908 					return error;
2909 
2910 				if (!(IW_WSEC_ENABLED(wsec))) {
2911 					error = dev_wlc_intvar_set(dev,
2912 							"is_WPS_enrollee",
2913 							true);
2914 					if (error) {
2915 						WL_WSEC("Failed to set iovar is_WPS_enrollee\n");
2916 						return error;
2917 					}
2918 				} else {
2919 					error = dev_wlc_intvar_set(dev,
2920 							"is_WPS_enrollee",
2921 							false);
2922 					if (error) {
2923 						WL_WSEC("Failed to clear is_WPS_enrollee\n");
2924 						return error;
2925 					}
2926 				}
2927 			}
2928 			break;
2929 		}
2930 #endif				/* WIRELESS_EXT > 17 */
2931 	default:
2932 		break;
2933 	}
2934 	return 0;
2935 }
2936 
2937 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2938 
2939 static int
2940 wl_iw_get_wpaauth(struct net_device *dev,
2941 		  struct iw_request_info *info,
2942 		  struct iw_param *vwrq, char *extra)
2943 {
2944 	int error;
2945 	int paramid;
2946 	int paramval = 0;
2947 	int val;
2948 	wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev);
2949 
2950 	WL_TRACE("%s: SIOCGIWAUTH\n", dev->name);
2951 
2952 	paramid = vwrq->flags & IW_AUTH_INDEX;
2953 
2954 	switch (paramid) {
2955 	case IW_AUTH_WPA_VERSION:
2956 		error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2957 		if (error)
2958 			return error;
2959 		if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
2960 			paramval = IW_AUTH_WPA_VERSION_DISABLED;
2961 		else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
2962 			paramval = IW_AUTH_WPA_VERSION_WPA;
2963 		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
2964 			paramval = IW_AUTH_WPA_VERSION_WPA2;
2965 		break;
2966 	case IW_AUTH_CIPHER_PAIRWISE:
2967 	case IW_AUTH_CIPHER_GROUP:
2968 		if (paramid == IW_AUTH_CIPHER_PAIRWISE)
2969 			val = iw->pwsec;
2970 		else
2971 			val = iw->gwsec;
2972 
2973 		paramval = 0;
2974 		if (val) {
2975 			if (val & WEP_ENABLED)
2976 				paramval |=
2977 				    (IW_AUTH_CIPHER_WEP40 |
2978 				     IW_AUTH_CIPHER_WEP104);
2979 			if (val & TKIP_ENABLED)
2980 				paramval |= (IW_AUTH_CIPHER_TKIP);
2981 			if (val & AES_ENABLED)
2982 				paramval |= (IW_AUTH_CIPHER_CCMP);
2983 		} else
2984 			paramval = IW_AUTH_CIPHER_NONE;
2985 		break;
2986 	case IW_AUTH_KEY_MGMT:
2987 		error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
2988 		if (error)
2989 			return error;
2990 		if (VAL_PSK(val))
2991 			paramval = IW_AUTH_KEY_MGMT_PSK;
2992 		else
2993 			paramval = IW_AUTH_KEY_MGMT_802_1X;
2994 
2995 		break;
2996 	case IW_AUTH_TKIP_COUNTERMEASURES:
2997 		dev_wlc_bufvar_get(dev, "tkip_countermeasures",
2998 				   (char *)&paramval, 1);
2999 		break;
3000 
3001 	case IW_AUTH_DROP_UNENCRYPTED:
3002 		dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
3003 		break;
3004 
3005 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
3006 		dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol",
3007 				   (char *)&paramval, 1);
3008 		break;
3009 
3010 	case IW_AUTH_80211_AUTH_ALG:
3011 		error = dev_wlc_intvar_get(dev, "auth", &val);
3012 		if (error)
3013 			return error;
3014 		if (!val)
3015 			paramval = IW_AUTH_ALG_OPEN_SYSTEM;
3016 		else
3017 			paramval = IW_AUTH_ALG_SHARED_KEY;
3018 		break;
3019 	case IW_AUTH_WPA_ENABLED:
3020 		error = dev_wlc_intvar_get(dev, "wpa_auth", &val);
3021 		if (error)
3022 			return error;
3023 		if (val)
3024 			paramval = true;
3025 		else
3026 			paramval = false;
3027 		break;
3028 #if WIRELESS_EXT > 17
3029 	case IW_AUTH_ROAMING_CONTROL:
3030 		WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__);
3031 		break;
3032 	case IW_AUTH_PRIVACY_INVOKED:
3033 		paramval = iw->privacy_invoked;
3034 		break;
3035 
3036 #endif
3037 	}
3038 	vwrq->value = paramval;
3039 	return 0;
3040 }
3041 #endif				/* WIRELESS_EXT > 17 */
3042 
3043 static const iw_handler wl_iw_handler[] = {
3044 	(iw_handler) wl_iw_config_commit,
3045 	(iw_handler) wl_iw_get_name,
3046 	(iw_handler) NULL,
3047 	(iw_handler) NULL,
3048 	(iw_handler) wl_iw_set_freq,
3049 	(iw_handler) wl_iw_get_freq,
3050 	(iw_handler) wl_iw_set_mode,
3051 	(iw_handler) wl_iw_get_mode,
3052 	(iw_handler) NULL,
3053 	(iw_handler) NULL,
3054 	(iw_handler) NULL,
3055 	(iw_handler) wl_iw_get_range,
3056 	(iw_handler) NULL,
3057 	(iw_handler) NULL,
3058 	(iw_handler) NULL,
3059 	(iw_handler) NULL,
3060 	(iw_handler) wl_iw_set_spy,
3061 	(iw_handler) wl_iw_get_spy,
3062 	(iw_handler) NULL,
3063 	(iw_handler) NULL,
3064 	(iw_handler) wl_iw_set_wap,
3065 	(iw_handler) wl_iw_get_wap,
3066 #if WIRELESS_EXT > 17
3067 	(iw_handler) wl_iw_mlme,
3068 #else
3069 	(iw_handler) NULL,
3070 #endif
3071 #if defined(WL_IW_USE_ISCAN)
3072 	(iw_handler) wl_iw_iscan_get_aplist,
3073 #else
3074 	(iw_handler) wl_iw_get_aplist,
3075 #endif
3076 #if WIRELESS_EXT > 13
3077 #if defined(WL_IW_USE_ISCAN)
3078 	(iw_handler) wl_iw_iscan_set_scan,
3079 	(iw_handler) wl_iw_iscan_get_scan,
3080 #else
3081 	(iw_handler) wl_iw_set_scan,
3082 	(iw_handler) wl_iw_get_scan,
3083 #endif
3084 #else
3085 	(iw_handler) NULL,
3086 	(iw_handler) NULL,
3087 #endif				/* WIRELESS_EXT > 13 */
3088 	(iw_handler) wl_iw_set_essid,
3089 	(iw_handler) wl_iw_get_essid,
3090 	(iw_handler) wl_iw_set_nick,
3091 	(iw_handler) wl_iw_get_nick,
3092 	(iw_handler) NULL,
3093 	(iw_handler) NULL,
3094 	(iw_handler) wl_iw_set_rate,
3095 	(iw_handler) wl_iw_get_rate,
3096 	(iw_handler) wl_iw_set_rts,
3097 	(iw_handler) wl_iw_get_rts,
3098 	(iw_handler) wl_iw_set_frag,
3099 	(iw_handler) wl_iw_get_frag,
3100 	(iw_handler) wl_iw_set_txpow,
3101 	(iw_handler) wl_iw_get_txpow,
3102 #if WIRELESS_EXT > 10
3103 	(iw_handler) wl_iw_set_retry,
3104 	(iw_handler) wl_iw_get_retry,
3105 #endif
3106 	(iw_handler) wl_iw_set_encode,
3107 	(iw_handler) wl_iw_get_encode,
3108 	(iw_handler) wl_iw_set_power,
3109 	(iw_handler) wl_iw_get_power,
3110 #if WIRELESS_EXT > 17
3111 	(iw_handler) NULL,
3112 	(iw_handler) NULL,
3113 	(iw_handler) wl_iw_set_wpaie,
3114 	(iw_handler) wl_iw_get_wpaie,
3115 	(iw_handler) wl_iw_set_wpaauth,
3116 	(iw_handler) wl_iw_get_wpaauth,
3117 	(iw_handler) wl_iw_set_encodeext,
3118 	(iw_handler) wl_iw_get_encodeext,
3119 	(iw_handler) wl_iw_set_pmksa,
3120 #endif				/* WIRELESS_EXT > 17 */
3121 };
3122 
3123 #if WIRELESS_EXT > 12
3124 
3125 const struct iw_handler_def wl_iw_handler_def = {
3126 	.num_standard = ARRAY_SIZE(wl_iw_handler),
3127 	.standard = (iw_handler *) wl_iw_handler,
3128 	.num_private = 0,
3129 	.num_private_args = 0,
3130 	.private = 0,
3131 	.private_args = 0,
3132 
3133 #if WIRELESS_EXT >= 19
3134 	.get_wireless_stats = dhd_get_wireless_stats,
3135 #endif
3136 };
3137 #endif				/* WIRELESS_EXT > 12 */
3138 
3139 int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
3140 {
3141 	struct iwreq *wrq = (struct iwreq *)rq;
3142 	struct iw_request_info info;
3143 	iw_handler handler;
3144 	char *extra = NULL;
3145 	int token_size = 1, max_tokens = 0, ret = 0;
3146 
3147 	WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n",
3148 		 __func__, cmd);
3149 	if (cmd < SIOCIWFIRST ||
3150 		IW_IOCTL_IDX(cmd) >= ARRAY_SIZE(wl_iw_handler)) {
3151 		WL_ERROR("%s: error in cmd=%x : out of range\n",
3152 			 __func__, cmd);
3153 		return -EOPNOTSUPP;
3154 	}
3155 
3156 	handler = wl_iw_handler[IW_IOCTL_IDX(cmd)];
3157 	if (!handler) {
3158 		WL_ERROR("%s: error in cmd=%x : not supported\n",
3159 			 __func__, cmd);
3160 		return -EOPNOTSUPP;
3161 	}
3162 
3163 	switch (cmd) {
3164 
3165 	case SIOCSIWESSID:
3166 	case SIOCGIWESSID:
3167 	case SIOCSIWNICKN:
3168 	case SIOCGIWNICKN:
3169 		max_tokens = IW_ESSID_MAX_SIZE + 1;
3170 		break;
3171 
3172 	case SIOCSIWENCODE:
3173 	case SIOCGIWENCODE:
3174 #if WIRELESS_EXT > 17
3175 	case SIOCSIWENCODEEXT:
3176 	case SIOCGIWENCODEEXT:
3177 #endif
3178 		max_tokens = wrq->u.data.length;
3179 		break;
3180 
3181 	case SIOCGIWRANGE:
3182 		max_tokens = sizeof(struct iw_range) + 500;
3183 		break;
3184 
3185 	case SIOCGIWAPLIST:
3186 		token_size =
3187 		    sizeof(struct sockaddr) + sizeof(struct iw_quality);
3188 		max_tokens = IW_MAX_AP;
3189 		break;
3190 
3191 #if WIRELESS_EXT > 13
3192 	case SIOCGIWSCAN:
3193 #if defined(WL_IW_USE_ISCAN)
3194 		if (g_iscan)
3195 			max_tokens = wrq->u.data.length;
3196 		else
3197 #endif
3198 			max_tokens = IW_SCAN_MAX_DATA;
3199 		break;
3200 #endif				/* WIRELESS_EXT > 13 */
3201 
3202 	case SIOCSIWSPY:
3203 		token_size = sizeof(struct sockaddr);
3204 		max_tokens = IW_MAX_SPY;
3205 		break;
3206 
3207 	case SIOCGIWSPY:
3208 		token_size =
3209 		    sizeof(struct sockaddr) + sizeof(struct iw_quality);
3210 		max_tokens = IW_MAX_SPY;
3211 		break;
3212 
3213 #if WIRELESS_EXT > 17
3214 	case SIOCSIWPMKSA:
3215 	case SIOCSIWGENIE:
3216 #endif
3217 	case SIOCSIWPRIV:
3218 		max_tokens = wrq->u.data.length;
3219 		break;
3220 	}
3221 
3222 	if (max_tokens && wrq->u.data.pointer) {
3223 		if (wrq->u.data.length > max_tokens) {
3224 			WL_ERROR("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
3225 				 __func__, cmd, wrq->u.data.length, max_tokens);
3226 			return -E2BIG;
3227 		}
3228 		extra = kmalloc(max_tokens * token_size, GFP_KERNEL);
3229 		if (!extra)
3230 			return -ENOMEM;
3231 
3232 		if (copy_from_user
3233 		    (extra, wrq->u.data.pointer,
3234 		     wrq->u.data.length * token_size)) {
3235 			kfree(extra);
3236 			return -EFAULT;
3237 		}
3238 	}
3239 
3240 	info.cmd = cmd;
3241 	info.flags = 0;
3242 
3243 	ret = handler(dev, &info, &wrq->u, extra);
3244 
3245 	if (extra) {
3246 		if (copy_to_user
3247 		    (wrq->u.data.pointer, extra,
3248 		     wrq->u.data.length * token_size)) {
3249 			kfree(extra);
3250 			return -EFAULT;
3251 		}
3252 
3253 		kfree(extra);
3254 	}
3255 
3256 	return ret;
3257 }
3258 
3259 bool
3260 wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason,
3261 		      char *stringBuf, uint buflen)
3262 {
3263 	typedef struct conn_fail_event_map_t {
3264 		u32 inEvent;
3265 		u32 inStatus;
3266 		u32 inReason;
3267 		const char *outName;
3268 		const char *outCause;
3269 	} conn_fail_event_map_t;
3270 
3271 #define WL_IW_DONT_CARE	9999
3272 	const conn_fail_event_map_t event_map[] = {
3273 		{WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
3274 		 "Conn", "Success"},
3275 		{WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
3276 		 "Conn", "NoNetworks"},
3277 		{WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3278 		 "Conn", "ConfigMismatch"},
3279 		{WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
3280 		 "Conn", "EncrypMismatch"},
3281 		{WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
3282 		 "Conn", "RsnMismatch"},
3283 		{WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3284 		 "Conn", "AuthTimeout"},
3285 		{WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3286 		 "Conn", "AuthFail"},
3287 		{WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
3288 		 "Conn", "AuthNoAck"},
3289 		{WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
3290 		 "Conn", "ReassocFail"},
3291 		{WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
3292 		 "Conn", "ReassocTimeout"},
3293 		{WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
3294 		 "Conn", "ReassocAbort"},
3295 		{WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
3296 		 "Sup", "ConnSuccess"},
3297 		{WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3298 		 "Sup", "WpaHandshakeFail"},
3299 		{WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3300 		 "Conn", "Deauth"},
3301 		{WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3302 		 "Conn", "DisassocInd"},
3303 		{WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
3304 		 "Conn", "Disassoc"}
3305 	};
3306 
3307 	const char *name = "";
3308 	const char *cause = NULL;
3309 	int i;
3310 
3311 	for (i = 0; i < sizeof(event_map) / sizeof(event_map[0]); i++) {
3312 		const conn_fail_event_map_t *row = &event_map[i];
3313 		if (row->inEvent == event_type &&
3314 		    (row->inStatus == status
3315 		     || row->inStatus == WL_IW_DONT_CARE)
3316 		    && (row->inReason == reason
3317 			|| row->inReason == WL_IW_DONT_CARE)) {
3318 			name = row->outName;
3319 			cause = row->outCause;
3320 			break;
3321 		}
3322 	}
3323 
3324 	if (cause) {
3325 		memset(stringBuf, 0, buflen);
3326 		snprintf(stringBuf, buflen, "%s %s %02d %02d",
3327 			 name, cause, status, reason);
3328 		WL_INFORM("Connection status: %s\n", stringBuf);
3329 		return true;
3330 	} else {
3331 		return false;
3332 	}
3333 }
3334 
3335 #if WIRELESS_EXT > 14
3336 
3337 static bool
3338 wl_iw_check_conn_fail(wl_event_msg_t *e, char *stringBuf, uint buflen)
3339 {
3340 	u32 event = be32_to_cpu(e->event_type);
3341 	u32 status = be32_to_cpu(e->status);
3342 	u32 reason = be32_to_cpu(e->reason);
3343 
3344 	if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
3345 		return true;
3346 	} else
3347 		return false;
3348 }
3349 #endif
3350 
3351 #ifndef IW_CUSTOM_MAX
3352 #define IW_CUSTOM_MAX 256
3353 #endif
3354 
3355 void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data)
3356 {
3357 #if WIRELESS_EXT > 13
3358 	union iwreq_data wrqu;
3359 	char extra[IW_CUSTOM_MAX + 1];
3360 	int cmd = 0;
3361 	u32 event_type = be32_to_cpu(e->event_type);
3362 	u16 flags = be16_to_cpu(e->flags);
3363 	u32 datalen = be32_to_cpu(e->datalen);
3364 	u32 status = be32_to_cpu(e->status);
3365 	wl_iw_t *iw;
3366 	u32 toto;
3367 	memset(&wrqu, 0, sizeof(wrqu));
3368 	memset(extra, 0, sizeof(extra));
3369 	iw = 0;
3370 
3371 	if (!dev) {
3372 		WL_ERROR("%s: dev is null\n", __func__);
3373 		return;
3374 	}
3375 
3376 	iw = *(wl_iw_t **) netdev_priv(dev);
3377 
3378 	WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type);
3379 
3380 	switch (event_type) {
3381 	case WLC_E_TXFAIL:
3382 		cmd = IWEVTXDROP;
3383 		memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3384 		wrqu.addr.sa_family = ARPHRD_ETHER;
3385 		break;
3386 #if WIRELESS_EXT > 14
3387 	case WLC_E_JOIN:
3388 	case WLC_E_ASSOC_IND:
3389 	case WLC_E_REASSOC_IND:
3390 		memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3391 		wrqu.addr.sa_family = ARPHRD_ETHER;
3392 		cmd = IWEVREGISTERED;
3393 		break;
3394 	case WLC_E_DEAUTH_IND:
3395 	case WLC_E_DISASSOC_IND:
3396 		cmd = SIOCGIWAP;
3397 		memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3398 		wrqu.addr.sa_family = ARPHRD_ETHER;
3399 		memset(&extra, 0, ETH_ALEN);
3400 		break;
3401 	case WLC_E_LINK:
3402 	case WLC_E_NDIS_LINK:
3403 		cmd = SIOCGIWAP;
3404 		if (!(flags & WLC_EVENT_MSG_LINK)) {
3405 			memset(wrqu.addr.sa_data, 0, ETH_ALEN);
3406 			memset(&extra, 0, ETH_ALEN);
3407 		} else {
3408 			memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN);
3409 			WL_TRACE("Link UP\n");
3410 
3411 		}
3412 		wrqu.addr.sa_family = ARPHRD_ETHER;
3413 		break;
3414 	case WLC_E_ACTION_FRAME:
3415 		cmd = IWEVCUSTOM;
3416 		if (datalen + 1 <= sizeof(extra)) {
3417 			wrqu.data.length = datalen + 1;
3418 			extra[0] = WLC_E_ACTION_FRAME;
3419 			memcpy(&extra[1], data, datalen);
3420 			WL_TRACE("WLC_E_ACTION_FRAME len %d\n",
3421 				 wrqu.data.length);
3422 		}
3423 		break;
3424 
3425 	case WLC_E_ACTION_FRAME_COMPLETE:
3426 		cmd = IWEVCUSTOM;
3427 		memcpy(&toto, data, 4);
3428 		if (sizeof(status) + 1 <= sizeof(extra)) {
3429 			wrqu.data.length = sizeof(status) + 1;
3430 			extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
3431 			memcpy(&extra[1], &status, sizeof(status));
3432 			WL_TRACE("wl_iw_event status %d PacketId %d\n", status,
3433 				 toto);
3434 			WL_TRACE("WLC_E_ACTION_FRAME_COMPLETE len %d\n",
3435 				 wrqu.data.length);
3436 		}
3437 		break;
3438 #endif				/* WIRELESS_EXT > 14 */
3439 #if WIRELESS_EXT > 17
3440 	case WLC_E_MIC_ERROR:
3441 		{
3442 			struct iw_michaelmicfailure *micerrevt =
3443 			    (struct iw_michaelmicfailure *)&extra;
3444 			cmd = IWEVMICHAELMICFAILURE;
3445 			wrqu.data.length = sizeof(struct iw_michaelmicfailure);
3446 			if (flags & WLC_EVENT_MSG_GROUP)
3447 				micerrevt->flags |= IW_MICFAILURE_GROUP;
3448 			else
3449 				micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
3450 			memcpy(micerrevt->src_addr.sa_data, &e->addr,
3451 			       ETH_ALEN);
3452 			micerrevt->src_addr.sa_family = ARPHRD_ETHER;
3453 
3454 			break;
3455 		}
3456 	case WLC_E_PMKID_CACHE:
3457 		{
3458 			if (data) {
3459 				struct iw_pmkid_cand *iwpmkidcand =
3460 				    (struct iw_pmkid_cand *)&extra;
3461 				pmkid_cand_list_t *pmkcandlist;
3462 				pmkid_cand_t *pmkidcand;
3463 				int count;
3464 
3465 				cmd = IWEVPMKIDCAND;
3466 				pmkcandlist = data;
3467 				count = get_unaligned_be32(&pmkcandlist->
3468 							   npmkid_cand);
3469 				ASSERT(count >= 0);
3470 				wrqu.data.length = sizeof(struct iw_pmkid_cand);
3471 				pmkidcand = pmkcandlist->pmkid_cand;
3472 				while (count) {
3473 					memset(iwpmkidcand, 0,
3474 					      sizeof(struct iw_pmkid_cand));
3475 					if (pmkidcand->preauth)
3476 						iwpmkidcand->flags |=
3477 						    IW_PMKID_CAND_PREAUTH;
3478 					memcpy(&iwpmkidcand->bssid.sa_data,
3479 					       &pmkidcand->BSSID,
3480 					       ETH_ALEN);
3481 #ifndef SANDGATE2G
3482 					wireless_send_event(dev, cmd, &wrqu,
3483 							    extra);
3484 #endif
3485 					pmkidcand++;
3486 					count--;
3487 				}
3488 			}
3489 			return;
3490 		}
3491 #endif				/* WIRELESS_EXT > 17 */
3492 
3493 	case WLC_E_SCAN_COMPLETE:
3494 #if defined(WL_IW_USE_ISCAN)
3495 		if ((g_iscan) && (g_iscan->sysioc_tsk) &&
3496 		    (g_iscan->iscan_state != ISCAN_STATE_IDLE)) {
3497 			up(&g_iscan->sysioc_sem);
3498 		} else {
3499 			cmd = SIOCGIWSCAN;
3500 			wrqu.data.length = strlen(extra);
3501 			WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
3502 				 g_iscan->iscan_state);
3503 		}
3504 #else
3505 		cmd = SIOCGIWSCAN;
3506 		wrqu.data.length = strlen(extra);
3507 		WL_TRACE("Event WLC_E_SCAN_COMPLETE\n");
3508 #endif
3509 		break;
3510 
3511 	case WLC_E_PFN_NET_FOUND:
3512 		{
3513 			wlc_ssid_t *ssid;
3514 			ssid = (wlc_ssid_t *) data;
3515 			WL_ERROR("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
3516 				 __func__, PNO_EVENT_UP,
3517 				 ssid->SSID, ssid->SSID_len);
3518 			cmd = IWEVCUSTOM;
3519 			memset(&wrqu, 0, sizeof(wrqu));
3520 			strcpy(extra, PNO_EVENT_UP);
3521 			wrqu.data.length = strlen(extra);
3522 		}
3523 		break;
3524 
3525 	default:
3526 		WL_TRACE("Unknown Event %d: ignoring\n", event_type);
3527 		break;
3528 	}
3529 #ifndef SANDGATE2G
3530 	if (cmd) {
3531 		if (cmd == SIOCGIWSCAN)
3532 			wireless_send_event(dev, cmd, &wrqu, NULL);
3533 		else
3534 			wireless_send_event(dev, cmd, &wrqu, extra);
3535 	}
3536 #endif
3537 
3538 #if WIRELESS_EXT > 14
3539 	memset(extra, 0, sizeof(extra));
3540 	if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
3541 		cmd = IWEVCUSTOM;
3542 		wrqu.data.length = strlen(extra);
3543 #ifndef SANDGATE2G
3544 		wireless_send_event(dev, cmd, &wrqu, extra);
3545 #endif
3546 	}
3547 #endif				/* WIRELESS_EXT > 14 */
3548 #endif				/* WIRELESS_EXT > 13 */
3549 }
3550 
3551 int
3552 wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
3553 {
3554 	int res = 0;
3555 	struct wl_cnt cnt;
3556 	int phy_noise;
3557 	int rssi;
3558 	scb_val_t scb_val;
3559 
3560 	phy_noise = 0;
3561 	res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise,
3562 				sizeof(phy_noise));
3563 	if (res)
3564 		goto done;
3565 
3566 	phy_noise = le32_to_cpu(phy_noise);
3567 	WL_TRACE("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise);
3568 
3569 	memset(&scb_val, 0, sizeof(scb_val_t));
3570 	res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
3571 	if (res)
3572 		goto done;
3573 
3574 	rssi = le32_to_cpu(scb_val.val);
3575 	WL_TRACE("wl_iw_get_wireless_stats rssi=%d\n", rssi);
3576 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
3577 		wstats->qual.qual = 0;
3578 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
3579 		wstats->qual.qual = 1;
3580 	else if (rssi <= WL_IW_RSSI_LOW)
3581 		wstats->qual.qual = 2;
3582 	else if (rssi <= WL_IW_RSSI_GOOD)
3583 		wstats->qual.qual = 3;
3584 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
3585 		wstats->qual.qual = 4;
3586 	else
3587 		wstats->qual.qual = 5;
3588 
3589 	wstats->qual.level = 0x100 + rssi;
3590 	wstats->qual.noise = 0x100 + phy_noise;
3591 #if WIRELESS_EXT > 18
3592 	wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
3593 #else
3594 	wstats->qual.updated |= 7;
3595 #endif
3596 
3597 #if WIRELESS_EXT > 11
3598 	WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n",
3599 		 sizeof(struct wl_cnt));
3600 
3601 	memset(&cnt, 0, sizeof(struct wl_cnt));
3602 	res =
3603 	    dev_wlc_bufvar_get(dev, "counters", (char *)&cnt,
3604 			       sizeof(struct wl_cnt));
3605 	if (res) {
3606 		WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n",
3607 			 res);
3608 		goto done;
3609 	}
3610 
3611 	cnt.version = le16_to_cpu(cnt.version);
3612 	if (cnt.version != WL_CNT_T_VERSION) {
3613 		WL_TRACE("\tIncorrect counter version: expected %d; got %d\n",
3614 			 WL_CNT_T_VERSION, cnt.version);
3615 		goto done;
3616 	}
3617 
3618 	wstats->discard.nwid = 0;
3619 	wstats->discard.code = le32_to_cpu(cnt.rxundec);
3620 	wstats->discard.fragment = le32_to_cpu(cnt.rxfragerr);
3621 	wstats->discard.retries = le32_to_cpu(cnt.txfail);
3622 	wstats->discard.misc = le32_to_cpu(cnt.rxrunt) +
3623 		le32_to_cpu(cnt.rxgiant);
3624 	wstats->miss.beacon = 0;
3625 
3626 	WL_TRACE("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
3627 		 le32_to_cpu(cnt.txframe), le32_to_cpu(cnt.txbyte));
3628 	WL_TRACE("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n",
3629 		  le32_to_cpu(cnt.rxfrmtoolong));
3630 	WL_TRACE("wl_iw_get_wireless_stats counters rxbadplcp=%d\n",
3631 		  le32_to_cpu(cnt.rxbadplcp));
3632 	WL_TRACE("wl_iw_get_wireless_stats counters rxundec=%d\n",
3633 		  le32_to_cpu(cnt.rxundec));
3634 	WL_TRACE("wl_iw_get_wireless_stats counters rxfragerr=%d\n",
3635 		  le32_to_cpu(cnt.rxfragerr));
3636 	WL_TRACE("wl_iw_get_wireless_stats counters txfail=%d\n",
3637 		  le32_to_cpu(cnt.txfail));
3638 	WL_TRACE("wl_iw_get_wireless_stats counters rxrunt=%d\n",
3639 		  le32_to_cpu(cnt.rxrunt));
3640 	WL_TRACE("wl_iw_get_wireless_stats counters rxgiant=%d\n",
3641 		  le32_to_cpu(cnt.rxgiant));
3642 #endif				/* WIRELESS_EXT > 11 */
3643 
3644 done:
3645 	return res;
3646 }
3647 
3648 int wl_iw_attach(struct net_device *dev, void *dhdp)
3649 {
3650 	int params_size;
3651 	wl_iw_t *iw;
3652 #if defined(WL_IW_USE_ISCAN)
3653 	iscan_info_t *iscan = NULL;
3654 
3655 	if (!dev)
3656 		return 0;
3657 
3658 	memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
3659 
3660 #ifdef CSCAN
3661 	params_size =
3662 	    (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)) +
3663 	    (WL_NUMCHANNELS * sizeof(u16)) +
3664 	    WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
3665 #else
3666 	params_size =
3667 	    (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
3668 #endif
3669 	iscan = kzalloc(sizeof(iscan_info_t), GFP_KERNEL);
3670 
3671 	if (!iscan)
3672 		return -ENOMEM;
3673 
3674 	iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
3675 	if (!iscan->iscan_ex_params_p)
3676 		return -ENOMEM;
3677 	iscan->iscan_ex_param_size = params_size;
3678 	iscan->sysioc_tsk = NULL;
3679 
3680 	g_iscan = iscan;
3681 	iscan->dev = dev;
3682 	iscan->iscan_state = ISCAN_STATE_IDLE;
3683 
3684 	iscan->timer_ms = 3000;
3685 	init_timer(&iscan->timer);
3686 	iscan->timer.data = (unsigned long) iscan;
3687 	iscan->timer.function = wl_iw_timerfunc;
3688 
3689 	sema_init(&iscan->sysioc_sem, 0);
3690 	iscan->sysioc_tsk = kthread_run(_iscan_sysioc_thread, iscan,
3691 					"_iscan_sysioc");
3692 	if (IS_ERR(iscan->sysioc_tsk)) {
3693 		iscan->sysioc_tsk = NULL;
3694 		return -ENOMEM;
3695 	}
3696 #endif				/* defined(WL_IW_USE_ISCAN) */
3697 
3698 	iw = *(wl_iw_t **) netdev_priv(dev);
3699 	iw->pub = (dhd_pub_t *) dhdp;
3700 	MUTEX_LOCK_INIT(iw->pub);
3701 	MUTEX_LOCK_WL_SCAN_SET_INIT();
3702 #ifdef SOFTAP
3703 	priv_dev = dev;
3704 	MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
3705 #endif
3706 	g_scan = kzalloc(G_SCAN_RESULTS, GFP_KERNEL);
3707 	if (!g_scan)
3708 		return -ENOMEM;
3709 
3710 	g_scan_specified_ssid = 0;
3711 
3712 	return 0;
3713 }
3714 
3715 void wl_iw_detach(void)
3716 {
3717 #if defined(WL_IW_USE_ISCAN)
3718 	iscan_buf_t *buf;
3719 	iscan_info_t *iscan = g_iscan;
3720 
3721 	if (!iscan)
3722 		return;
3723 	if (iscan->sysioc_tsk) {
3724 		send_sig(SIGTERM, iscan->sysioc_tsk, 1);
3725 		kthread_stop(iscan->sysioc_tsk);
3726 		iscan->sysioc_tsk = NULL;
3727 	}
3728 
3729 	MUTEX_LOCK_WL_SCAN_SET();
3730 	while (iscan->list_hdr) {
3731 		buf = iscan->list_hdr->next;
3732 		kfree(iscan->list_hdr);
3733 		iscan->list_hdr = buf;
3734 	}
3735 	MUTEX_UNLOCK_WL_SCAN_SET();
3736 	kfree(iscan->iscan_ex_params_p);
3737 	kfree(iscan);
3738 	g_iscan = NULL;
3739 #endif				/* WL_IW_USE_ISCAN */
3740 
3741 	kfree(g_scan);
3742 
3743 	g_scan = NULL;
3744 }
3745