xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlinux/moal_wext.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file  moal_wext.c
2   *
3   * @brief This file contains wireless extension standard ioctl functions
4   *
5   * Copyright (C) 2008-2017, Marvell International Ltd.
6   *
7   * This software file (the "File") is distributed by Marvell International
8   * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9   * (the "License").  You may use, redistribute and/or modify this File in
10   * accordance with the terms and conditions of the License, a copy of which
11   * is available by writing to the Free Software Foundation, Inc.,
12   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14   *
15   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
18   * this warranty disclaimer.
19   *
20   */
21 
22 /************************************************************************
23 Change log:
24     10/21/2008: initial version
25 ************************************************************************/
26 
27 #include        "moal_main.h"
28 
29 #ifdef STA_SUPPORT
30 /** Approximate amount of data needed to pass a scan result back to iwlist */
31 #define MAX_SCAN_CELL_SIZE  \
32 	(IW_EV_ADDR_LEN             \
33 	+ MLAN_MAX_SSID_LENGTH      \
34 	+ IW_EV_UINT_LEN            \
35 	+ IW_EV_FREQ_LEN            \
36 	+ IW_EV_QUAL_LEN            \
37 	+ MLAN_MAX_SSID_LENGTH      \
38 	+ IW_EV_PARAM_LEN           \
39 	+ 40)			/* 40 for WPAIE */
40 /** Macro for minimum size of scan buffer */
41 #define MIN_ACCEPTED_GET_SCAN_BUF 8000
42 
43 /********************************************************
44 			Global Variables
45 ********************************************************/
46 extern int hw_test;
47 /********************************************************
48 			Local Functions
49 ********************************************************/
50 
51 /**
52  *  @brief Compare two SSIDs
53  *
54  *  @param ssid1    A pointer to ssid to compare
55  *  @param ssid2    A pointer to ssid to compare
56  *
57  *  @return         0--ssid is same, otherwise is different
58  */
59 static t_s32
woal_ssid_cmp(mlan_802_11_ssid * ssid1,mlan_802_11_ssid * ssid2)60 woal_ssid_cmp(mlan_802_11_ssid *ssid1, mlan_802_11_ssid *ssid2)
61 {
62 	ENTER();
63 
64 	if (!ssid1 || !ssid2) {
65 		LEAVE();
66 		return -1;
67 	}
68 	if (ssid1->ssid_len != ssid2->ssid_len) {
69 		LEAVE();
70 		return -1;
71 	}
72 
73 	LEAVE();
74 	return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
75 }
76 
77 /**
78  *  @brief Sort Channels
79  *
80  *  @param freq                 A pointer to iw_freq structure
81  *  @param num                  Number of Channels
82  *
83  *  @return                     N/A
84  */
85 static inline void
woal_sort_channels(struct iw_freq * freq,int num)86 woal_sort_channels(struct iw_freq *freq, int num)
87 {
88 	int i, j;
89 	struct iw_freq temp;
90 
91 	for (i = 0; i < num; i++)
92 		for (j = i + 1; j < num; j++)
93 			if (freq[i].i > freq[j].i) {
94 				temp.i = freq[i].i;
95 				temp.m = freq[i].m;
96 
97 				freq[i].i = freq[j].i;
98 				freq[i].m = freq[j].m;
99 
100 				freq[j].i = temp.i;
101 				freq[j].m = temp.m;
102 			}
103 }
104 
105 /**
106  *  @brief Convert RSSI to quality
107  *
108  *  @param rssi     RSSI in dBm
109  *
110  *  @return         Quality of the link (0-5)
111  */
112 static t_u8
woal_rssi_to_quality(t_s16 rssi)113 woal_rssi_to_quality(t_s16 rssi)
114 {
115 /** Macro for RSSI range */
116 #define MOAL_RSSI_NO_SIGNAL -90
117 #define MOAL_RSSI_VERY_LOW  -80
118 #define MOAL_RSSI_LOW       -70
119 #define MOAL_RSSI_GOOD      -60
120 #define MOAL_RSSI_VERY_GOOD -50
121 #define MOAL_RSSI_INVALID   0
122 	if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID)
123 		return 0;
124 	else if (rssi <= MOAL_RSSI_VERY_LOW)
125 		return 1;
126 	else if (rssi <= MOAL_RSSI_LOW)
127 		return 2;
128 	else if (rssi <= MOAL_RSSI_GOOD)
129 		return 3;
130 	else if (rssi <= MOAL_RSSI_VERY_GOOD)
131 		return 4;
132 	else
133 		return 5;
134 }
135 
136 /**
137  *  @brief Set Adapter Node Name
138  *
139  *  @param dev                  A pointer to net_device structure
140  *  @param info                 A pointer to iw_request_info structure
141  *  @param dwrq                 A pointer to iw_point structure
142  *  @param extra                A pointer to extra data buf
143  *
144  *  @return                     0 --success, otherwise fail
145  */
146 static int
woal_set_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)147 woal_set_nick(struct net_device *dev, struct iw_request_info *info,
148 	      struct iw_point *dwrq, char *extra)
149 {
150 	moal_private *priv = (moal_private *)netdev_priv(dev);
151 	ENTER();
152 	/*
153 	 * Check the size of the string
154 	 */
155 	if (dwrq->length > 16) {
156 		LEAVE();
157 		return -E2BIG;
158 	}
159 	memset(priv->nick_name, 0, sizeof(priv->nick_name));
160 	memcpy(priv->nick_name, extra, dwrq->length);
161 	LEAVE();
162 	return 0;
163 }
164 
165 /**
166  *  @brief Get Adapter Node Name
167  *
168  *  @param dev                  A pointer to net_device structure
169  *  @param info                 A pointer to iw_request_info structure
170  *  @param dwrq                 A pointer to iw_point structure
171  *  @param extra                A pointer to extra data buf
172  *
173  *  @return                     0 --success
174  */
175 static int
woal_get_nick(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)176 woal_get_nick(struct net_device *dev, struct iw_request_info *info,
177 	      struct iw_point *dwrq, char *extra)
178 {
179 	moal_private *priv = (moal_private *)netdev_priv(dev);
180 	ENTER();
181 	/*
182 	 * Get the Nick Name saved
183 	 */
184 	strncpy(extra, (char *)priv->nick_name, 16);
185 	extra[16] = '\0';
186 	/*
187 	 * If none, we may want to get the one that was set
188 	 */
189 
190 	/*
191 	 * Push it out !
192 	 */
193 	dwrq->length = strlen(extra) + 1;
194 	LEAVE();
195 	return 0;
196 }
197 
198 /**
199  *  @brief Commit handler: called after a bunch of SET operations
200  *
201  *  @param dev          A pointer to net_device structure
202  *  @param info         A pointer to iw_request_info structure
203  *  @param cwrq         A pointer to char buffer
204  *  @param extra        A pointer to extra data buf
205  *
206  *  @return             0 --success
207  */
208 static int
woal_config_commit(struct net_device * dev,struct iw_request_info * info,char * cwrq,char * extra)209 woal_config_commit(struct net_device *dev,
210 		   struct iw_request_info *info, char *cwrq, char *extra)
211 {
212 	ENTER();
213 
214 	LEAVE();
215 	return 0;
216 }
217 
218 /**
219  *  @brief Get name
220  *
221  *  @param dev          A pointer to net_device structure
222  *  @param info         A pointer to iw_request_info structure
223  *  @param cwrq         A pointer to char buffer
224  *  @param extra        A pointer to extra data buf
225  *
226  *  @return             0 --success
227  */
228 static int
woal_get_name(struct net_device * dev,struct iw_request_info * info,char * cwrq,char * extra)229 woal_get_name(struct net_device *dev, struct iw_request_info *info,
230 	      char *cwrq, char *extra)
231 {
232 	ENTER();
233 	strcpy(cwrq, "IEEE 802.11-DS");
234 	LEAVE();
235 	return 0;
236 }
237 
238 /**
239  *  @brief Set frequency
240  *
241  *  @param dev                  A pointer to net_device structure
242  *  @param info                 A pointer to iw_request_info structure
243  *  @param fwrq                 A pointer to iw_freq structure
244  *  @param extra                A pointer to extra data buf
245  *
246  *  @return                     0 --success, otherwise fail
247  */
248 static int
woal_set_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)249 woal_set_freq(struct net_device *dev, struct iw_request_info *info,
250 	      struct iw_freq *fwrq, char *extra)
251 {
252 	int ret = 0;
253 	moal_private *priv = (moal_private *)netdev_priv(dev);
254 	mlan_ds_bss *bss = NULL;
255 	mlan_ioctl_req *req = NULL;
256 	mlan_status status = MLAN_STATUS_SUCCESS;
257 
258 	ENTER();
259 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
260 	if (req == NULL) {
261 		ret = -ENOMEM;
262 		goto done;
263 	}
264 	bss = (mlan_ds_bss *)req->pbuf;
265 	/*
266 	 * If setting by frequency, convert to a channel
267 	 */
268 	if (fwrq->e == 1) {
269 		long f = fwrq->m / 100000;
270 		bss->param.bss_chan.freq = f;
271 	} else
272 		bss->param.bss_chan.channel = fwrq->m;
273 
274 	bss->sub_command = MLAN_OID_BSS_CHANNEL;
275 	req->req_id = MLAN_IOCTL_BSS;
276 	req->action = MLAN_ACT_SET;
277 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
278 	if (status != MLAN_STATUS_SUCCESS) {
279 		ret = -EFAULT;
280 		goto done;
281 	}
282 	if (MLAN_STATUS_SUCCESS !=
283 	    woal_change_adhoc_chan(priv, bss->param.bss_chan.channel,
284 				   MOAL_IOCTL_WAIT))
285 		ret = -EFAULT;
286 
287 done:
288 	if (status != MLAN_STATUS_PENDING)
289 		kfree(req);
290 	LEAVE();
291 	return ret;
292 }
293 
294 /**
295  *  @brief Get frequency
296  *
297  *  @param dev                  A pointer to net_device structure
298  *  @param info                 A pointer to iw_request_info structure
299  *  @param fwrq                 A pointer to iw_freq structure
300  *  @param extra                A pointer to extra data buf
301  *
302  *  @return                     0 --success, otherwise fail
303  */
304 static int
woal_get_freq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)305 woal_get_freq(struct net_device *dev, struct iw_request_info *info,
306 	      struct iw_freq *fwrq, char *extra)
307 {
308 	int ret = 0;
309 	moal_private *priv = (moal_private *)netdev_priv(dev);
310 	mlan_ds_bss *bss = NULL;
311 	mlan_ioctl_req *req = NULL;
312 	mlan_status status = MLAN_STATUS_SUCCESS;
313 
314 	ENTER();
315 
316 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
317 	if (req == NULL) {
318 		ret = -ENOMEM;
319 		goto done;
320 	}
321 	bss = (mlan_ds_bss *)req->pbuf;
322 	bss->sub_command = MLAN_OID_BSS_CHANNEL;
323 	req->req_id = MLAN_IOCTL_BSS;
324 	req->action = MLAN_ACT_GET;
325 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
326 	if (status != MLAN_STATUS_SUCCESS) {
327 		ret = -EFAULT;
328 		goto done;
329 	}
330 	fwrq->m = (long)bss->param.bss_chan.freq;
331 	fwrq->i = (long)bss->param.bss_chan.channel;
332 	fwrq->e = 6;
333 	fwrq->flags = IW_FREQ_FIXED;
334 done:
335 	if (status != MLAN_STATUS_PENDING)
336 		kfree(req);
337 	LEAVE();
338 	return ret;
339 }
340 
341 /**
342  *  @brief Set wlan mode
343  *
344  *  @param dev                  A pointer to net_device structure
345  *  @param info                 A pointer to iw_request_info structure
346  *  @param uwrq                 Wireless mode to set
347  *  @param extra                A pointer to extra data buf
348  *
349  *  @return                     0 --success, otherwise fail
350  */
351 static int
woal_set_bss_mode(struct net_device * dev,struct iw_request_info * info,t_u32 * uwrq,char * extra)352 woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info,
353 		  t_u32 *uwrq, char *extra)
354 {
355 	int ret = 0;
356 	moal_private *priv = (moal_private *)netdev_priv(dev);
357 	mlan_ds_bss *bss = NULL;
358 	mlan_ioctl_req *req = NULL;
359 	mlan_status status = MLAN_STATUS_SUCCESS;
360 
361 	ENTER();
362 
363 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
364 	if (req == NULL) {
365 		ret = -ENOMEM;
366 		goto done;
367 	}
368 	bss = (mlan_ds_bss *)req->pbuf;
369 	bss->sub_command = MLAN_OID_BSS_MODE;
370 	req->req_id = MLAN_IOCTL_BSS;
371 	req->action = MLAN_ACT_SET;
372 
373 	switch (*uwrq) {
374 	case IW_MODE_INFRA:
375 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
376 		break;
377 	case IW_MODE_ADHOC:
378 		bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
379 		break;
380 	case IW_MODE_AUTO:
381 		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
382 		break;
383 	default:
384 		ret = -EINVAL;
385 		break;
386 	}
387 	if (ret)
388 		goto done;
389 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
390 	if (status != MLAN_STATUS_SUCCESS) {
391 		ret = -EFAULT;
392 		goto done;
393 	}
394 done:
395 	if (status != MLAN_STATUS_PENDING)
396 		kfree(req);
397 	LEAVE();
398 	return ret;
399 }
400 
401 /**
402  *  @brief Get current BSSID
403  *
404  *  @param dev          A pointer to net_device structure
405  *  @param info         A pointer to iw_request_info structure
406  *  @param awrq         A pointer to sockaddr structure
407  *  @param extra        A pointer to extra data buf
408  *
409  *  @return             0 --success
410  */
411 static int
woal_get_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)412 woal_get_wap(struct net_device *dev, struct iw_request_info *info,
413 	     struct sockaddr *awrq, char *extra)
414 {
415 	int ret = 0;
416 	moal_private *priv = (moal_private *)netdev_priv(dev);
417 	mlan_bss_info bss_info;
418 
419 	ENTER();
420 
421 	memset(&bss_info, 0, sizeof(bss_info));
422 
423 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
424 
425 	if (bss_info.media_connected == MTRUE)
426 		memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH);
427 	else
428 		memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
429 	awrq->sa_family = ARPHRD_ETHER;
430 
431 	LEAVE();
432 	return ret;
433 }
434 
435 /**
436  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
437  *
438  * NOTE: Scan should be issued by application before this function is called
439  *
440  *  @param dev          A pointer to net_device structure
441  *  @param info         A pointer to iw_request_info structure
442  *  @param awrq         A pointer to sockaddr structure
443  *  @param extra        A pointer to extra data buf
444  *
445  *  @return             0 --success, otherwise fail
446  */
447 static int
woal_set_wap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)448 woal_set_wap(struct net_device *dev, struct iw_request_info *info,
449 	     struct sockaddr *awrq, char *extra)
450 {
451 	int ret = 0;
452 	const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {
453 		255, 255, 255, 255, 255, 255
454 	};
455 	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {
456 		0, 0, 0, 0, 0, 0
457 	};
458 	moal_private *priv = (moal_private *)netdev_priv(dev);
459 	mlan_ssid_bssid ssid_bssid;
460 	mlan_bss_info bss_info;
461 
462 	ENTER();
463 
464 	if (awrq->sa_family != ARPHRD_ETHER) {
465 		ret = -EINVAL;
466 		goto done;
467 	}
468 
469 	PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
470 	       MAC2STR((t_u8 *)awrq->sa_data));
471 
472 	if (MLAN_STATUS_SUCCESS !=
473 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
474 		ret = -EFAULT;
475 		goto done;
476 	}
477 #ifdef REASSOCIATION
478 	/* Cancel re-association */
479 	priv->reassoc_required = MFALSE;
480 #endif
481 
482 	/* zero_mac means disconnect */
483 	if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
484 		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
485 				DEF_DEAUTH_REASON_CODE);
486 		goto done;
487 	}
488 
489 	/* Broadcast MAC means search for best network */
490 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
491 
492 	if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
493 		/* Check if we are already assoicated to the AP */
494 		if (bss_info.media_connected == MTRUE) {
495 			if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
496 				goto done;
497 		}
498 		memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN);
499 	}
500 
501 	if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv,
502 							  MOAL_IOCTL_WAIT,
503 							  &ssid_bssid)) {
504 		PRINTM(MERROR,
505 		       "ASSOC: WAP: MAC address not found in BSSID List\n");
506 		ret = -ENETUNREACH;
507 		goto done;
508 	}
509 	/* Zero SSID implies use BSSID to connect */
510 	memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
511 	if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
512 						  MOAL_IOCTL_WAIT,
513 						  &ssid_bssid)) {
514 		ret = -EFAULT;
515 		goto done;
516 	}
517 #ifdef REASSOCIATION
518 	memset(&bss_info, 0, sizeof(bss_info));
519 	if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
520 						     MOAL_IOCTL_WAIT,
521 						     &bss_info)) {
522 		ret = -EFAULT;
523 		goto done;
524 	}
525 	memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
526 	       sizeof(mlan_802_11_ssid));
527 	memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid,
528 	       MLAN_MAC_ADDR_LENGTH);
529 #endif /* REASSOCIATION */
530 
531 done:
532 
533 	LEAVE();
534 	return ret;
535 }
536 
537 /**
538  *  @brief Get wlan mode
539  *
540  *  @param dev                  A pointer to net_device structure
541  *  @param info                 A pointer to iw_request_info structure
542  *  @param uwrq                 A pointer to t_u32 string
543  *  @param extra                A pointer to extra data buf
544  *
545  *  @return                     0 --success
546  */
547 static int
woal_get_bss_mode(struct net_device * dev,struct iw_request_info * info,t_u32 * uwrq,char * extra)548 woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info,
549 		  t_u32 *uwrq, char *extra)
550 {
551 	moal_private *priv = (moal_private *)netdev_priv(dev);
552 	ENTER();
553 	*uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT);
554 	LEAVE();
555 	return 0;
556 }
557 
558 /**
559  *  @brief Set sensitivity
560  *
561  *  @param dev                  A pointer to net_device structure
562  *  @param info                 A pointer to iw_request_info structure
563  *  @param vwrq                 A pointer to iw_param structure
564  *  @param extra                A pointer to extra data buf
565  *
566  *  @return                     0 --success
567  */
568 static int
woal_set_sens(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)569 woal_set_sens(struct net_device *dev, struct iw_request_info *info,
570 	      struct iw_param *vwrq, char *extra)
571 {
572 	int ret = 0;
573 
574 	ENTER();
575 
576 	LEAVE();
577 	return ret;
578 }
579 
580 /**
581  *  @brief Get sensitivity
582  *
583  *  @param dev                  A pointer to net_device structure
584  *  @param info                 A pointer to iw_request_info structure
585  *  @param vwrq                 A pointer to iw_param structure
586  *  @param extra                A pointer to extra data buf
587  *
588  *  @return                     -1
589  */
590 static int
woal_get_sens(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)591 woal_get_sens(struct net_device *dev, struct iw_request_info *info,
592 	      struct iw_param *vwrq, char *extra)
593 {
594 	int ret = -1;
595 
596 	ENTER();
597 
598 	LEAVE();
599 	return ret;
600 }
601 
602 /**
603  *  @brief Set Tx power
604  *
605  *  @param dev                  A pointer to net_device structure
606  *  @param info                 A pointer to iw_request_info structure
607  *  @param vwrq                 A pointer to iw_param structure
608  *  @param extra                A pointer to extra data buf
609  *
610  *  @return                     0 --success, otherwise fail
611  */
612 static int
woal_set_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)613 woal_set_txpow(struct net_device *dev, struct iw_request_info *info,
614 	       struct iw_param *vwrq, char *extra)
615 {
616 	int ret = 0;
617 	moal_private *priv = (moal_private *)netdev_priv(dev);
618 	mlan_power_cfg_t power_cfg;
619 
620 	ENTER();
621 	if (vwrq->disabled) {
622 		woal_set_radio(priv, 0);
623 		goto done;
624 	}
625 	woal_set_radio(priv, 1);
626 
627 	if (!vwrq->fixed)
628 		power_cfg.is_power_auto = 1;
629 	else {
630 		power_cfg.is_power_auto = 0;
631 		power_cfg.power_level = vwrq->value;
632 	}
633 
634 	if (MLAN_STATUS_SUCCESS !=
635 	    woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) {
636 		ret = -EFAULT;
637 		goto done;
638 	}
639 
640 done:
641 	LEAVE();
642 	return ret;
643 }
644 
645 /**
646  *  @brief Get Tx power
647  *
648  *  @param dev                  A pointer to net_device structure
649  *  @param info                 A pointer to iw_request_info structure
650  *  @param vwrq                 A pointer to iw_param structure
651  *  @param extra                A pointer to extra data buf
652  *
653  *  @return                     0 --success, otherwise fail
654  */
655 static int
woal_get_txpow(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)656 woal_get_txpow(struct net_device *dev, struct iw_request_info *info,
657 	       struct iw_param *vwrq, char *extra)
658 {
659 	int ret = 0;
660 	moal_private *priv = (moal_private *)netdev_priv(dev);
661 	mlan_power_cfg_t power_cfg;
662 	mlan_bss_info bss_info;
663 
664 	ENTER();
665 
666 	memset(&power_cfg, 0, sizeof(mlan_power_cfg_t));
667 	memset(&bss_info, 0, sizeof(bss_info));
668 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
669 
670 	if (MLAN_STATUS_SUCCESS !=
671 	    woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
672 		ret = -EFAULT;
673 		goto done;
674 	}
675 
676 	vwrq->value = power_cfg.power_level;
677 	if (power_cfg.is_power_auto)
678 		vwrq->fixed = 0;
679 	else
680 		vwrq->fixed = 1;
681 	if (bss_info.radio_on) {
682 		vwrq->disabled = 0;
683 		vwrq->flags = IW_TXPOW_DBM;
684 	} else {
685 		vwrq->disabled = 1;
686 	}
687 
688 done:
689 	LEAVE();
690 	return ret;
691 }
692 
693 /**
694  *  @brief  Set power management
695  *
696  *  @param dev                  A pointer to net_device structure
697  *  @param info                 A pointer to iw_request_info structure
698  *  @param vwrq                 A pointer to iw_param structure
699  *  @param extra                A pointer to extra data buf
700  *
701  *  @return                     MLAN_STATUS_SUCCESS --success, otherwise fail
702  */
703 static int
woal_set_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)704 woal_set_power(struct net_device *dev, struct iw_request_info *info,
705 	       struct iw_param *vwrq, char *extra)
706 {
707 	int ret = 0, disabled;
708 	moal_private *priv = (moal_private *)netdev_priv(dev);
709 
710 	ENTER();
711 
712 	if (hw_test) {
713 		PRINTM(MIOCTL, "block set power in hw_test mode\n");
714 		LEAVE();
715 		return ret;
716 	}
717 	disabled = vwrq->disabled;
718 
719 	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
720 							   MLAN_ACT_SET,
721 							   &disabled,
722 							   vwrq->flags,
723 							   MOAL_IOCTL_WAIT)) {
724 		ret = -EFAULT;
725 	}
726 
727 	LEAVE();
728 	return ret;
729 }
730 
731 /**
732  *  @brief  Get power management
733  *
734  *  @param dev                  A pointer to net_device structure
735  *  @param info                 A pointer to iw_request_info structure
736  *  @param vwrq                 A pointer to iw_param structure
737  *  @param extra                A pointer to extra data buf
738  *
739  *  @return                     MLAN_STATUS_SUCCESS --success, otherwise fail
740  */
741 static int
woal_get_power(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)742 woal_get_power(struct net_device *dev, struct iw_request_info *info,
743 	       struct iw_param *vwrq, char *extra)
744 {
745 	int ret = 0, ps_mode;
746 	moal_private *priv = (moal_private *)netdev_priv(dev);
747 
748 	ENTER();
749 
750 	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv,
751 							   MLAN_ACT_GET,
752 							   &ps_mode, 0,
753 							   MOAL_IOCTL_WAIT)) {
754 		ret = -EFAULT;
755 	}
756 
757 	if (ps_mode)
758 		vwrq->disabled = 0;
759 	else
760 		vwrq->disabled = 1;
761 
762 	vwrq->value = 0;
763 
764 	LEAVE();
765 	return ret;
766 }
767 
768 /**
769  *  @brief Set Tx retry count
770  *
771  *  @param dev                  A pointer to net_device structure
772  *  @param info                 A pointer to iw_request_info structure
773  *  @param vwrq                 A pointer to iw_param structure
774  *  @param extra                A pointer to extra data buf
775  *
776  *  @return                     0 --success, otherwise fail
777  */
778 static int
woal_set_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)779 woal_set_retry(struct net_device *dev, struct iw_request_info *info,
780 	       struct iw_param *vwrq, char *extra)
781 {
782 	int ret = 0, retry_val = vwrq->value;
783 	moal_private *priv = (moal_private *)netdev_priv(dev);
784 
785 	ENTER();
786 
787 	if (vwrq->flags == IW_RETRY_LIMIT) {
788 		/*
789 		 * The MAC has a 4-bit Total_Tx_Count register
790 		 * Total_Tx_Count = 1 + Tx_Retry_Count
791 		 */
792 
793 		if (MLAN_STATUS_SUCCESS !=
794 		    woal_set_get_retry(priv, MLAN_ACT_SET,
795 				       MOAL_IOCTL_WAIT, &retry_val)) {
796 			ret = -EFAULT;
797 			goto done;
798 		}
799 	} else {
800 		ret = -EOPNOTSUPP;
801 		goto done;
802 	}
803 
804 done:
805 	LEAVE();
806 	return ret;
807 }
808 
809 /**
810  *  @brief Get Tx retry count
811  *
812  *  @param dev                  A pointer to net_device structure
813  *  @param info                 A pointer to iw_request_info structure
814  *  @param vwrq                 A pointer to iw_param structure
815  *  @param extra                A pointer to extra data buf
816  *
817  *  @return                     0 --success, otherwise fail
818  */
819 static int
woal_get_retry(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)820 woal_get_retry(struct net_device *dev, struct iw_request_info *info,
821 	       struct iw_param *vwrq, char *extra)
822 {
823 	int retry_val, ret = 0;
824 	moal_private *priv = (moal_private *)netdev_priv(dev);
825 
826 	ENTER();
827 
828 	if (MLAN_STATUS_SUCCESS !=
829 	    woal_set_get_retry(priv, MLAN_ACT_GET,
830 			       MOAL_IOCTL_WAIT, &retry_val)) {
831 		ret = -EFAULT;
832 		goto done;
833 	}
834 
835 	vwrq->disabled = 0;
836 	if (!vwrq->flags) {
837 		vwrq->flags = IW_RETRY_LIMIT;
838 		/* Get Tx retry count */
839 		vwrq->value = retry_val;
840 	}
841 
842 done:
843 	LEAVE();
844 	return ret;
845 }
846 
847 /**
848  *  @brief Set encryption key
849  *
850  *  @param dev                  A pointer to net_device structure
851  *  @param info                 A pointer to iw_request_info structure
852  *  @param dwrq                 A pointer to iw_point structure
853  *  @param extra                A pointer to extra data buf
854  *
855  *  @return                     0 --success, otherwise fail
856  */
857 static int
woal_set_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)858 woal_set_encode(struct net_device *dev, struct iw_request_info *info,
859 		struct iw_point *dwrq, char *extra)
860 {
861 	int ret = 0;
862 	moal_private *priv = (moal_private *)netdev_priv(dev);
863 	mlan_ds_sec_cfg *sec = NULL;
864 	mlan_ioctl_req *req = NULL;
865 	int index = 0;
866 	t_u32 auth_mode = 0;
867 	mlan_status status = MLAN_STATUS_SUCCESS;
868 
869 	ENTER();
870 
871 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
872 	if (req == NULL) {
873 		ret = -ENOMEM;
874 		goto done;
875 	}
876 	sec = (mlan_ds_sec_cfg *)req->pbuf;
877 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
878 	req->req_id = MLAN_IOCTL_SEC_CFG;
879 	req->action = MLAN_ACT_SET;
880 
881 	/* Check index */
882 	index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
883 	if (index > 3) {
884 		PRINTM(MERROR, "Key index #%d out of range\n", index);
885 		ret = -EINVAL;
886 		goto done;
887 	}
888 
889 	sec->param.encrypt_key.key_len = 0;
890 	if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
891 		if (dwrq->length > MAX_WEP_KEY_SIZE) {
892 			PRINTM(MERROR, "Key length (%d) out of range\n",
893 			       dwrq->length);
894 			ret = -EINVAL;
895 			goto done;
896 		}
897 		if (index < 0)
898 			sec->param.encrypt_key.key_index =
899 				MLAN_KEY_INDEX_DEFAULT;
900 		else
901 			sec->param.encrypt_key.key_index = index;
902 		memcpy(sec->param.encrypt_key.key_material, extra,
903 		       dwrq->length);
904 		/* Set the length */
905 		if (dwrq->length > MIN_WEP_KEY_SIZE)
906 			sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE;
907 		else
908 			sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE;
909 	} else {
910 		/*
911 		 * No key provided so it is either enable key,
912 		 * on or off
913 		 */
914 		if (dwrq->flags & IW_ENCODE_DISABLED) {
915 			PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
916 			sec->param.encrypt_key.key_disable = MTRUE;
917 		} else {
918 			/*
919 			 * iwconfig mlanX key [n]
920 			 * iwconfig mlanX key on
921 			 * iwconfig mlanX key open
922 			 * iwconfig mlanX key restricted
923 			 * Do we want to just set the transmit key index ?
924 			 */
925 			if (index < 0) {
926 				PRINTM(MINFO,
927 				       "*** iwconfig mlanX key on ***\n");
928 				sec->param.encrypt_key.key_index =
929 					MLAN_KEY_INDEX_DEFAULT;
930 			} else
931 				sec->param.encrypt_key.key_index = index;
932 			sec->param.encrypt_key.is_current_wep_key = MTRUE;
933 		}
934 	}
935 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
936 	if (status != MLAN_STATUS_SUCCESS) {
937 		ret = -EFAULT;
938 		goto done;
939 	}
940 	if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
941 		switch (dwrq->flags & 0xf000) {
942 		case IW_ENCODE_RESTRICTED:
943 			/* iwconfig mlanX restricted key [1] */
944 			auth_mode = MLAN_AUTH_MODE_SHARED;
945 			PRINTM(MINFO, "Auth mode restricted!\n");
946 			break;
947 		case IW_ENCODE_OPEN:
948 			/* iwconfig mlanX key [2] open */
949 			auth_mode = MLAN_AUTH_MODE_OPEN;
950 			PRINTM(MINFO, "Auth mode open!\n");
951 			break;
952 		case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
953 		default:
954 			/* iwconfig mlanX key [2] open restricted */
955 			auth_mode = MLAN_AUTH_MODE_AUTO;
956 			PRINTM(MINFO, "Auth mode auto!\n");
957 			break;
958 		}
959 		if (MLAN_STATUS_SUCCESS !=
960 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
961 			ret = -EFAULT;
962 	}
963 done:
964 	if (status != MLAN_STATUS_PENDING)
965 		kfree(req);
966 	LEAVE();
967 	return ret;
968 }
969 
970 /**
971  *  @brief Get encryption key
972  *
973  *  @param dev                  A pointer to net_device structure
974  *  @param info                 A pointer to iw_request_info structure
975  *  @param dwrq                 A pointer to iw_point structure
976  *  @param extra                A pointer to extra data buf
977  *
978  *  @return                     0 --success, otherwise fail
979  */
980 static int
woal_get_encode(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)981 woal_get_encode(struct net_device *dev, struct iw_request_info *info,
982 		struct iw_point *dwrq, char *extra)
983 {
984 	int ret = 0;
985 	moal_private *priv = (moal_private *)netdev_priv(dev);
986 	mlan_ds_sec_cfg *sec = NULL;
987 	mlan_ioctl_req *req = NULL;
988 	t_u32 auth_mode;
989 	int index = (dwrq->flags & IW_ENCODE_INDEX);
990 	mlan_status status = MLAN_STATUS_SUCCESS;
991 
992 	ENTER();
993 	if (index < 0 || index > 4) {
994 		PRINTM(MERROR, "Key index #%d out of range\n", index);
995 		ret = -EINVAL;
996 		goto done;
997 	}
998 	if (MLAN_STATUS_SUCCESS !=
999 	    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
1000 		ret = -EFAULT;
1001 		goto done;
1002 	}
1003 	dwrq->flags = 0;
1004 	/*
1005 	 * Check encryption mode
1006 	 */
1007 	switch (auth_mode) {
1008 	case MLAN_AUTH_MODE_OPEN:
1009 		dwrq->flags = IW_ENCODE_OPEN;
1010 		break;
1011 
1012 	case MLAN_AUTH_MODE_SHARED:
1013 	case MLAN_AUTH_MODE_NETWORKEAP:
1014 		dwrq->flags = IW_ENCODE_RESTRICTED;
1015 		break;
1016 
1017 	case MLAN_AUTH_MODE_AUTO:
1018 		dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED;
1019 		break;
1020 
1021 	default:
1022 		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1023 		break;
1024 	}
1025 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1026 	if (req == NULL) {
1027 		ret = -ENOMEM;
1028 		goto done;
1029 	}
1030 
1031 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1032 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1033 	req->req_id = MLAN_IOCTL_SEC_CFG;
1034 	req->action = MLAN_ACT_GET;
1035 
1036 	if (!index)
1037 		sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT;
1038 	else
1039 		sec->param.encrypt_key.key_index = index - 1;
1040 
1041 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1042 	if (status != MLAN_STATUS_SUCCESS) {
1043 		ret = -EFAULT;
1044 		goto done;
1045 	}
1046 	memset(extra, 0, 16);
1047 	if (sec->param.encrypt_key.key_len) {
1048 		memcpy(extra, sec->param.encrypt_key.key_material,
1049 		       sec->param.encrypt_key.key_len);
1050 		dwrq->length = sec->param.encrypt_key.key_len;
1051 		dwrq->flags |= (sec->param.encrypt_key.key_index + 1);
1052 		dwrq->flags &= ~IW_ENCODE_DISABLED;
1053 	} else if (sec->param.encrypt_key.key_disable)
1054 		dwrq->flags |= IW_ENCODE_DISABLED;
1055 	else
1056 		dwrq->flags &= ~IW_ENCODE_DISABLED;
1057 
1058 	dwrq->flags |= IW_ENCODE_NOKEY;
1059 done:
1060 	if (status != MLAN_STATUS_PENDING)
1061 		kfree(req);
1062 	LEAVE();
1063 	return ret;
1064 }
1065 
1066 /**
1067  *  @brief Set data rate
1068  *
1069  *  @param dev          A pointer to net_device structure
1070  *  @param info         A pointer to iw_request_info structure
1071  *  @param vwrq         A pointer to iw_param structure
1072  *  @param extra        A pointer to extra data buf
1073  *
1074  *  @return             0 --success, otherwise fail
1075  */
1076 static int
woal_set_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1077 woal_set_rate(struct net_device *dev, struct iw_request_info *info,
1078 	      struct iw_param *vwrq, char *extra)
1079 {
1080 	int ret = 0;
1081 	moal_private *priv = (moal_private *)netdev_priv(dev);
1082 	mlan_rate_cfg_t rate_cfg;
1083 
1084 	ENTER();
1085 
1086 	if (vwrq->value == -1) {
1087 		rate_cfg.is_rate_auto = 1;
1088 	} else {
1089 		rate_cfg.is_rate_auto = 0;
1090 		rate_cfg.rate_type = MLAN_RATE_VALUE;
1091 		rate_cfg.rate = vwrq->value / 500000;
1092 	}
1093 	if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
1094 							  MLAN_ACT_SET,
1095 							  &rate_cfg)) {
1096 		ret = -EFAULT;
1097 	}
1098 
1099 	LEAVE();
1100 	return ret;
1101 }
1102 
1103 /**
1104  *  @brief Get data rate
1105  *
1106  *  @param dev          A pointer to net_device structure
1107  *  @param info         A pointer to iw_request_info structure
1108  *  @param vwrq         A pointer to iw_param structure
1109  *  @param extra        A pointer to extra data buf
1110  *
1111  *  @return             0 --success, otherwise fail
1112  */
1113 static int
woal_get_rate(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1114 woal_get_rate(struct net_device *dev, struct iw_request_info *info,
1115 	      struct iw_param *vwrq, char *extra)
1116 {
1117 	int ret = 0;
1118 	moal_private *priv = (moal_private *)netdev_priv(dev);
1119 	mlan_rate_cfg_t rate_cfg;
1120 
1121 	ENTER();
1122 
1123 	if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv,
1124 							  MLAN_ACT_GET,
1125 							  &rate_cfg)) {
1126 		ret = -EFAULT;
1127 		goto done;
1128 	}
1129 
1130 	if (rate_cfg.is_rate_auto)
1131 		vwrq->fixed = 0;
1132 	else
1133 		vwrq->fixed = 1;
1134 	vwrq->value = rate_cfg.rate * 500000;
1135 done:
1136 	LEAVE();
1137 	return ret;
1138 }
1139 
1140 /**
1141  *  @brief Set RTS threshold
1142  *
1143  *  @param dev                  A pointer to net_device structure
1144  *  @param info                 A pointer to iw_request_info structure
1145  *  @param vwrq                 A pointer to iw_param structure
1146  *  @param extra                A pointer to extra data buf
1147  *
1148  *  @return                     0 --success, otherwise fail
1149  */
1150 static int
woal_set_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1151 woal_set_rts(struct net_device *dev, struct iw_request_info *info,
1152 	     struct iw_param *vwrq, char *extra)
1153 {
1154 	int ret = 0;
1155 	moal_private *priv = (moal_private *)netdev_priv(dev);
1156 	int rthr = vwrq->value;
1157 
1158 	ENTER();
1159 
1160 	if (vwrq->disabled) {
1161 		rthr = MLAN_RTS_MAX_VALUE;
1162 	} else {
1163 		if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) {
1164 			ret = -EINVAL;
1165 			goto done;
1166 		}
1167 	}
1168 
1169 	if (MLAN_STATUS_SUCCESS !=
1170 	    woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) {
1171 		ret = -EFAULT;
1172 		goto done;
1173 	}
1174 
1175 done:
1176 	LEAVE();
1177 	return ret;
1178 }
1179 
1180 /**
1181  *  @brief Get RTS threshold
1182  *
1183  *  @param dev                  A pointer to net_device structure
1184  *  @param info                 A pointer to iw_request_info structure
1185  *  @param vwrq                 A pointer to iw_param structure
1186  *  @param extra                A pointer to extra data buf
1187  *
1188  *  @return                     0 --success, otherwise fail
1189  */
1190 static int
woal_get_rts(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1191 woal_get_rts(struct net_device *dev, struct iw_request_info *info,
1192 	     struct iw_param *vwrq, char *extra)
1193 {
1194 	int rthr, ret = 0;
1195 	moal_private *priv = (moal_private *)netdev_priv(dev);
1196 
1197 	ENTER();
1198 
1199 	if (MLAN_STATUS_SUCCESS !=
1200 	    woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) {
1201 		ret = -EFAULT;
1202 		goto done;
1203 	}
1204 
1205 	vwrq->value = rthr;
1206 	vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE)
1207 			  || (vwrq->value > MLAN_RTS_MAX_VALUE));
1208 	vwrq->fixed = 1;
1209 
1210 done:
1211 	LEAVE();
1212 	return ret;
1213 }
1214 
1215 /**
1216  *  @brief Set Fragment threshold
1217  *
1218  *  @param dev                  A pointer to net_device structure
1219  *  @param info                 A pointer to iw_request_info structure
1220  *  @param vwrq                 A pointer to iw_param structure
1221  *  @param extra                A pointer to extra data buf
1222  *
1223  *  @return                     0 --success, otherwise fail
1224  */
1225 static int
woal_set_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1226 woal_set_frag(struct net_device *dev, struct iw_request_info *info,
1227 	      struct iw_param *vwrq, char *extra)
1228 {
1229 	int ret = 0;
1230 	moal_private *priv = (moal_private *)netdev_priv(dev);
1231 	int fthr = vwrq->value;
1232 
1233 	ENTER();
1234 
1235 	if (vwrq->disabled) {
1236 		fthr = MLAN_FRAG_MAX_VALUE;
1237 	} else {
1238 		if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) {
1239 			ret = -EINVAL;
1240 			goto done;
1241 		}
1242 	}
1243 
1244 	if (MLAN_STATUS_SUCCESS !=
1245 	    woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) {
1246 		ret = -EFAULT;
1247 		goto done;
1248 	}
1249 
1250 done:
1251 	LEAVE();
1252 	return ret;
1253 }
1254 
1255 /**
1256  *  @brief Get Fragment threshold
1257  *
1258  *  @param dev                  A pointer to net_device structure
1259  *  @param info                 A pointer to iw_request_info structure
1260  *  @param vwrq                 A pointer to iw_param structure
1261  *  @param extra                A pointer to extra data buf
1262  *
1263  *  @return                     0 --success, otherwise fail
1264  */
1265 static int
woal_get_frag(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1266 woal_get_frag(struct net_device *dev, struct iw_request_info *info,
1267 	      struct iw_param *vwrq, char *extra)
1268 {
1269 	int ret = 0, fthr;
1270 	moal_private *priv = (moal_private *)netdev_priv(dev);
1271 
1272 	ENTER();
1273 
1274 	if (MLAN_STATUS_SUCCESS !=
1275 	    woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) {
1276 		ret = -EFAULT;
1277 		goto done;
1278 	}
1279 
1280 	vwrq->value = fthr;
1281 	vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE)
1282 			  || (vwrq->value > MLAN_FRAG_MAX_VALUE));
1283 	vwrq->fixed = 1;
1284 
1285 done:
1286 	LEAVE();
1287 	return ret;
1288 }
1289 
1290 #if (WIRELESS_EXT >= 18)
1291 /**
1292  *  @brief Get IE
1293  *
1294  *  @param dev                  A pointer to net_device structure
1295  *  @param info                 A pointer to iw_request_info structure
1296  *  @param dwrq                 A pointer to iw_point structure
1297  *  @param extra                A pointer to extra data buf
1298  *
1299  *  @return                     0 --success, otherwise fail
1300  */
1301 static int
woal_get_gen_ie(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1302 woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
1303 		struct iw_point *dwrq, char *extra)
1304 {
1305 	int ret = 0;
1306 	moal_private *priv = (moal_private *)netdev_priv(dev);
1307 	int copy_size = 0, ie_len;
1308 	t_u8 ie[MAX_IE_SIZE];
1309 
1310 	ENTER();
1311 
1312 	if (MLAN_STATUS_SUCCESS !=
1313 	    woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie, &ie_len,
1314 				MOAL_IOCTL_WAIT)) {
1315 		ret = -EFAULT;
1316 		goto done;
1317 	}
1318 
1319 	copy_size = MIN(ie_len, dwrq->length);
1320 	memcpy(extra, ie, copy_size);
1321 	dwrq->length = copy_size;
1322 
1323 done:
1324 	LEAVE();
1325 	return ret;
1326 }
1327 
1328 /**
1329  *  @brief Set IE
1330  *
1331  *  Pass an opaque block of data, expected to be IEEE IEs, to the driver
1332  *    for eventual passthrough to the firmware in an associate/join
1333  *    (and potentially start) command.
1334  *
1335  *  @param dev                  A pointer to net_device structure
1336  *  @param info                 A pointer to iw_request_info structure
1337  *  @param dwrq                 A pointer to iw_point structure
1338  *  @param extra                A pointer to extra data buf
1339  *
1340  *  @return                     0 --success, otherwise fail
1341  */
1342 static int
woal_set_gen_ie(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1343 woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
1344 		struct iw_point *dwrq, char *extra)
1345 {
1346 	int ret = 0;
1347 	moal_private *priv = (moal_private *)netdev_priv(dev);
1348 	int ie_len = dwrq->length;
1349 	const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
1350 	mlan_ds_wps_cfg *pwps = NULL;
1351 	mlan_ioctl_req *req = NULL;
1352 	mlan_status status = MLAN_STATUS_SUCCESS;
1353 
1354 	ENTER();
1355 
1356 	/* extra + 2 to skip element id and length */
1357 	if (!memcmp((t_u8 *)(extra + 2), wps_oui, sizeof(wps_oui))) {
1358 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
1359 		if (req == NULL) {
1360 			ret = -ENOMEM;
1361 			goto done;
1362 		}
1363 
1364 		pwps = (mlan_ds_wps_cfg *)req->pbuf;
1365 		req->req_id = MLAN_IOCTL_WPS_CFG;
1366 		req->action = MLAN_ACT_SET;
1367 		pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
1368 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
1369 
1370 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1371 		if (status != MLAN_STATUS_SUCCESS) {
1372 			ret = -EFAULT;
1373 			goto done;
1374 		}
1375 	}
1376 
1377 	if (MLAN_STATUS_SUCCESS !=
1378 	    woal_set_get_gen_ie(priv, MLAN_ACT_SET, (t_u8 *)extra, &ie_len,
1379 				MOAL_IOCTL_WAIT)) {
1380 		ret = -EFAULT;
1381 		goto done;
1382 	}
1383 
1384 done:
1385 	if (status != MLAN_STATUS_PENDING)
1386 		kfree(req);
1387 
1388 	LEAVE();
1389 	return ret;
1390 }
1391 
1392 /**
1393  *  @brief  Extended version of encoding configuration
1394  *
1395  *  @param dev          A pointer to net_device structure
1396  *  @param info         A pointer to iw_request_info structure
1397  *  @param dwrq         A pointer to iw_point structure
1398  *  @param extra        A pointer to extra data buf
1399  *
1400  *  @return              0 --success, otherwise fail
1401  */
1402 static int
woal_set_encode_ext(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1403 woal_set_encode_ext(struct net_device *dev,
1404 		    struct iw_request_info *info,
1405 		    struct iw_point *dwrq, char *extra)
1406 {
1407 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1408 	moal_private *priv = (moal_private *)netdev_priv(dev);
1409 	int key_index;
1410 	t_u8 *pkey_material = NULL;
1411 	mlan_ioctl_req *req = NULL;
1412 	mlan_ds_sec_cfg *sec = NULL;
1413 	int ret = 0;
1414 	mlan_status status = MLAN_STATUS_SUCCESS;
1415 
1416 	ENTER();
1417 	key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1418 	if (key_index < 0 || key_index > 5) {
1419 		ret = -EINVAL;
1420 		goto done;
1421 	}
1422 	if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
1423 		ret = -EINVAL;
1424 		goto done;
1425 	}
1426 	if (ext->key_len > (MLAN_MAX_KEY_LENGTH)) {
1427 		ret = -EINVAL;
1428 		goto done;
1429 	}
1430 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1431 	if (req == NULL) {
1432 		ret = -ENOMEM;
1433 		goto done;
1434 	}
1435 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1436 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
1437 	req->req_id = MLAN_IOCTL_SEC_CFG;
1438 	req->action = MLAN_ACT_SET;
1439 	pkey_material = (t_u8 *)(ext + 1);
1440 	sec->param.encrypt_key.key_len = ext->key_len;
1441 	memcpy(sec->param.encrypt_key.mac_addr, (u8 *)ext->addr.sa_data,
1442 	       ETH_ALEN);
1443 	/* Disable and Remove Key */
1444 	if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
1445 		sec->param.encrypt_key.key_remove = MTRUE;
1446 		sec->param.encrypt_key.key_index = key_index;
1447 		sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
1448 		PRINTM(MIOCTL,
1449 		       "Remove key key_index=%d, dwrq->flags=0x%x " MACSTR "\n",
1450 		       key_index, dwrq->flags,
1451 		       MAC2STR(sec->param.encrypt_key.mac_addr));
1452 	} else if (ext->key_len <= MAX_WEP_KEY_SIZE) {
1453 		/* Set WEP key */
1454 		sec->param.encrypt_key.key_index = key_index;
1455 		sec->param.encrypt_key.key_flags = ext->ext_flags;
1456 		memcpy(sec->param.encrypt_key.key_material, pkey_material,
1457 		       ext->key_len);
1458 		if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
1459 			sec->param.encrypt_key.is_current_wep_key = MTRUE;
1460 	} else {
1461 		/* Set WPA key */
1462 		sec->param.encrypt_key.key_index = key_index;
1463 		sec->param.encrypt_key.key_flags = ext->ext_flags;
1464 		if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
1465 			memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->rx_seq,
1466 			       SEQ_MAX_SIZE);
1467 			DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn,
1468 				    SEQ_MAX_SIZE);
1469 		}
1470 		if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
1471 			memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->tx_seq,
1472 			       SEQ_MAX_SIZE);
1473 			DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn,
1474 				    SEQ_MAX_SIZE);
1475 		}
1476 		memcpy(sec->param.encrypt_key.key_material, pkey_material,
1477 		       ext->key_len);
1478 		PRINTM(MIOCTL,
1479 		       "set wpa key key_index=%d, key_len=%d key_flags=0x%x "
1480 		       MACSTR "\n", key_index, ext->key_len,
1481 		       sec->param.encrypt_key.key_flags,
1482 		       MAC2STR(sec->param.encrypt_key.mac_addr));
1483 		DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len);
1484 #define IW_ENCODE_ALG_AES_CMAC  5
1485 		if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
1486 			sec->param.encrypt_key.key_flags |=
1487 				KEY_FLAG_AES_MCAST_IGTK;
1488 #define IW_ENCODE_ALG_SMS4   0x20
1489 		/* Set WAPI key */
1490 		if (ext->alg == IW_ENCODE_ALG_SMS4) {
1491 			sec->param.encrypt_key.is_wapi_key = MTRUE;
1492 			memcpy(sec->param.encrypt_key.pn, (t_u8 *)ext->tx_seq,
1493 			       SEQ_MAX_SIZE);
1494 			memcpy(&sec->param.encrypt_key.pn[SEQ_MAX_SIZE],
1495 			       (t_u8 *)ext->rx_seq, SEQ_MAX_SIZE);
1496 			DBG_HEXDUMP(MCMD_D, "WAPI PN",
1497 				    sec->param.encrypt_key.pn, PN_SIZE);
1498 		}
1499 	}
1500 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1501 	if (status != MLAN_STATUS_SUCCESS)
1502 		ret = -EFAULT;
1503 done:
1504 	if (status != MLAN_STATUS_PENDING)
1505 		kfree(req);
1506 	LEAVE();
1507 	return ret;
1508 }
1509 
1510 /**
1511  *  @brief  Extended version of encoding configuration
1512  *
1513  *  @param dev          A pointer to net_device structure
1514  *  @param info         A pointer to iw_request_info structure
1515  *  @param dwrq         A pointer to iw_point structure
1516  *  @param extra        A pointer to extra data buf
1517  *
1518  *  @return             -EOPNOTSUPP
1519  */
1520 static int
woal_get_encode_ext(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1521 woal_get_encode_ext(struct net_device *dev,
1522 		    struct iw_request_info *info,
1523 		    struct iw_point *dwrq, char *extra)
1524 {
1525 	ENTER();
1526 	LEAVE();
1527 	return -EOPNOTSUPP;
1528 }
1529 
1530 /**
1531  *  @brief  Request MLME operation
1532  *
1533  *  @param dev          A pointer to net_device structure
1534  *  @param info         A pointer to iw_request_info structure
1535  *  @param dwrq         A pointer to iw_point structure
1536  *  @param extra        A pointer to extra data buf
1537  *
1538  *  @return             0--success, otherwise fail
1539  */
1540 static int
woal_set_mlme(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1541 woal_set_mlme(struct net_device *dev,
1542 	      struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1543 {
1544 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
1545 	moal_private *priv = (moal_private *)netdev_priv(dev);
1546 	int ret = 0;
1547 
1548 	ENTER();
1549 	if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
1550 
1551 		if (MLAN_STATUS_SUCCESS !=
1552 		    woal_disconnect(priv, MOAL_IOCTL_WAIT,
1553 				    (t_u8 *)mlme->addr.sa_data,
1554 				    DEF_DEAUTH_REASON_CODE))
1555 			ret = -EFAULT;
1556 	}
1557 	LEAVE();
1558 	return ret;
1559 }
1560 
1561 /** @brief Set authentication mode parameters
1562  *
1563  *  @param dev                  A pointer to net_device structure
1564  *  @param info                 A pointer to iw_request_info structure
1565  *  @param vwrq                 A pointer to iw_param structure
1566  *  @param extra                A pointer to extra data buf
1567  *
1568  *  @return                     0 --success, otherwise fail
1569  */
1570 static int
woal_set_auth(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1571 woal_set_auth(struct net_device *dev, struct iw_request_info *info,
1572 	      struct iw_param *vwrq, char *extra)
1573 {
1574 	int ret = 0;
1575 	moal_private *priv = (moal_private *)netdev_priv(dev);
1576 	t_u32 auth_mode = 0;
1577 	t_u32 encrypt_mode = 0;
1578 	ENTER();
1579 
1580 	switch (vwrq->flags & IW_AUTH_INDEX) {
1581 	case IW_AUTH_CIPHER_PAIRWISE:
1582 	case IW_AUTH_CIPHER_GROUP:
1583 		if (vwrq->value & IW_AUTH_CIPHER_NONE)
1584 			encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
1585 		else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
1586 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
1587 		else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
1588 			encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
1589 		else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
1590 			encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
1591 		else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
1592 			encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
1593 		if (MLAN_STATUS_SUCCESS !=
1594 		    woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
1595 			ret = -EFAULT;
1596 		break;
1597 	case IW_AUTH_80211_AUTH_ALG:
1598 		switch (vwrq->value) {
1599 		case IW_AUTH_ALG_SHARED_KEY:
1600 			PRINTM(MINFO, "Auth mode shared key!\n");
1601 			auth_mode = MLAN_AUTH_MODE_SHARED;
1602 			break;
1603 		case IW_AUTH_ALG_LEAP:
1604 			PRINTM(MINFO, "Auth mode LEAP!\n");
1605 			auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
1606 			break;
1607 		case IW_AUTH_ALG_OPEN_SYSTEM:
1608 			PRINTM(MINFO, "Auth mode open!\n");
1609 			auth_mode = MLAN_AUTH_MODE_OPEN;
1610 			break;
1611 		case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM:
1612 		default:
1613 			PRINTM(MINFO, "Auth mode auto!\n");
1614 			auth_mode = MLAN_AUTH_MODE_AUTO;
1615 			break;
1616 		}
1617 		if (MLAN_STATUS_SUCCESS !=
1618 		    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
1619 			ret = -EFAULT;
1620 		break;
1621 	case IW_AUTH_WPA_ENABLED:
1622 		if (MLAN_STATUS_SUCCESS !=
1623 		    woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1624 			ret = -EFAULT;
1625 		break;
1626 #define IW_AUTH_WAPI_ENABLED	0x20
1627 	case IW_AUTH_WAPI_ENABLED:
1628 		if (MLAN_STATUS_SUCCESS !=
1629 		    woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value))
1630 			ret = -EFAULT;
1631 		break;
1632 	case IW_AUTH_WPA_VERSION:
1633 		/* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
1634 		priv->wpa_version = vwrq->value;
1635 		break;
1636 	case IW_AUTH_KEY_MGMT:
1637 		/* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
1638 		priv->key_mgmt = vwrq->value;
1639 		break;
1640 	case IW_AUTH_TKIP_COUNTERMEASURES:
1641 	case IW_AUTH_DROP_UNENCRYPTED:
1642 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1643 	case IW_AUTH_ROAMING_CONTROL:
1644 	case IW_AUTH_PRIVACY_INVOKED:
1645 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
1646 	case IW_AUTH_MFP:
1647 #endif
1648 		break;
1649 	default:
1650 		ret = -EOPNOTSUPP;
1651 		break;
1652 	}
1653 	LEAVE();
1654 	return ret;
1655 }
1656 
1657 /**
1658  *  @brief Get authentication mode parameters
1659  *
1660  *  @param dev                  A pointer to net_device structure
1661  *  @param info                 A pointer to iw_request_info structure
1662  *  @param vwrq                 A pointer to iw_param structure
1663  *  @param extra                A pointer to extra data buf
1664  *
1665  *  @return                     0 --success, otherwise fail
1666  */
1667 static int
woal_get_auth(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1668 woal_get_auth(struct net_device *dev, struct iw_request_info *info,
1669 	      struct iw_param *vwrq, char *extra)
1670 {
1671 	int ret = 0;
1672 	moal_private *priv = (moal_private *)netdev_priv(dev);
1673 	t_u32 encrypt_mode = 0;
1674 	t_u32 auth_mode;
1675 	t_u32 wpa_enable;
1676 	ENTER();
1677 	switch (vwrq->flags & IW_AUTH_INDEX) {
1678 	case IW_AUTH_CIPHER_PAIRWISE:
1679 	case IW_AUTH_CIPHER_GROUP:
1680 		if (MLAN_STATUS_SUCCESS !=
1681 		    woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode))
1682 			ret = -EFAULT;
1683 		else {
1684 			if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE)
1685 				vwrq->value = IW_AUTH_CIPHER_NONE;
1686 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40)
1687 				vwrq->value = IW_AUTH_CIPHER_WEP40;
1688 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP)
1689 				vwrq->value = IW_AUTH_CIPHER_TKIP;
1690 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP)
1691 				vwrq->value = IW_AUTH_CIPHER_CCMP;
1692 			else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104)
1693 				vwrq->value = IW_AUTH_CIPHER_WEP104;
1694 		}
1695 		break;
1696 	case IW_AUTH_80211_AUTH_ALG:
1697 		if (MLAN_STATUS_SUCCESS !=
1698 		    woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode))
1699 			ret = -EFAULT;
1700 		else {
1701 			if (auth_mode == MLAN_AUTH_MODE_SHARED)
1702 				vwrq->value = IW_AUTH_ALG_SHARED_KEY;
1703 			else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
1704 				vwrq->value = IW_AUTH_ALG_LEAP;
1705 			else
1706 				vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
1707 		}
1708 		break;
1709 	case IW_AUTH_WPA_ENABLED:
1710 		if (MLAN_STATUS_SUCCESS !=
1711 		    woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable))
1712 			ret = -EFAULT;
1713 		else
1714 			vwrq->value = wpa_enable;
1715 		break;
1716 	case IW_AUTH_WPA_VERSION:
1717 		vwrq->value = priv->wpa_version;
1718 		break;
1719 	case IW_AUTH_KEY_MGMT:
1720 		vwrq->value = priv->key_mgmt;
1721 		break;
1722 	case IW_AUTH_TKIP_COUNTERMEASURES:
1723 	case IW_AUTH_DROP_UNENCRYPTED:
1724 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1725 	case IW_AUTH_ROAMING_CONTROL:
1726 	case IW_AUTH_PRIVACY_INVOKED:
1727 	default:
1728 		ret = -EOPNOTSUPP;
1729 		goto done;
1730 	}
1731 
1732 done:
1733 	LEAVE();
1734 	return ret;
1735 }
1736 
1737 /**
1738  *  @brief Set PMKSA Cache
1739  *
1740  *  @param dev      A pointer to net_device structure
1741  *  @param info     A pointer to iw_request_info structure
1742  *  @param vwrq     A pointer to iw_param structure
1743  *  @param extra    A pointer to extra data buf
1744  *
1745  *  @return         -EOPNOTSUPP
1746  */
1747 static int
woal_set_pmksa(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1748 woal_set_pmksa(struct net_device *dev, struct iw_request_info *info,
1749 	       struct iw_param *vwrq, char *extra)
1750 {
1751 	ENTER();
1752 	LEAVE();
1753 	return -EOPNOTSUPP;
1754 }
1755 
1756 #endif /* WE >= 18 */
1757 
1758 /* Data rate listing
1759  *      MULTI_BANDS:
1760  *              abg             a       b       b/g
1761  *  Infra       G(12)           A(8)    B(4)    G(12)
1762  *  Adhoc       A+B(12)         A(8)    B(4)    B(4)
1763  *      non-MULTI_BANDS:
1764 										b       b/g
1765  *  Infra                               B(4)    G(12)
1766  *  Adhoc                               B(4)    B(4)
1767  */
1768 /**
1769  *  @brief Get Range Info
1770  *
1771  *  @param dev                  A pointer to net_device structure
1772  *  @param info                 A pointer to iw_request_info structure
1773  *  @param dwrq                 A pointer to iw_point structure
1774  *  @param extra                A pointer to extra data buf
1775  *
1776  *  @return                     0 --success, otherwise fail
1777  */
1778 static int
woal_get_range(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1779 woal_get_range(struct net_device *dev, struct iw_request_info *info,
1780 	       struct iw_point *dwrq, char *extra)
1781 {
1782 	int i;
1783 	moal_private *priv = (moal_private *)netdev_priv(dev);
1784 	struct iw_range *range = (struct iw_range *)extra;
1785 	moal_802_11_rates rates;
1786 	mlan_chan_list *pchan_list = NULL;
1787 	mlan_bss_info bss_info;
1788 	gfp_t flag;
1789 
1790 	ENTER();
1791 
1792 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
1793 	pchan_list = kzalloc(sizeof(mlan_chan_list), flag);
1794 	if (!pchan_list) {
1795 		LEAVE();
1796 		return -ENOMEM;
1797 	}
1798 
1799 	dwrq->length = sizeof(struct iw_range);
1800 	memset(range, 0, sizeof(struct iw_range));
1801 
1802 	range->min_nwid = 0;
1803 	range->max_nwid = 0;
1804 
1805 	memset(&rates, 0, sizeof(rates));
1806 	woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates);
1807 	range->num_bitrates = rates.num_of_rates;
1808 
1809 	for (i = 0;
1810 	     i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i];
1811 	     i++) {
1812 		range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000;
1813 	}
1814 	range->num_bitrates = i;
1815 	PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
1816 	       range->num_bitrates);
1817 
1818 	range->num_frequency = 0;
1819 
1820 	woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list);
1821 
1822 	range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES);
1823 
1824 	for (i = 0; i < range->num_frequency; i++) {
1825 		range->freq[i].i = (long)pchan_list->cf[i].channel;
1826 		range->freq[i].m = (long)pchan_list->cf[i].freq * 100000;
1827 		range->freq[i].e = 1;
1828 	}
1829 	kfree(pchan_list);
1830 
1831 	PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
1832 	       IW_MAX_FREQUENCIES, range->num_frequency);
1833 
1834 	range->num_channels = range->num_frequency;
1835 
1836 	woal_sort_channels(&range->freq[0], range->num_frequency);
1837 
1838 	/*
1839 	 * Set an indication of the max TCP throughput in bit/s that we can
1840 	 * expect using this interface
1841 	 */
1842 	if (i > 2)
1843 		range->throughput = 5000 * 1000;
1844 	else
1845 		range->throughput = 1500 * 1000;
1846 
1847 	range->min_rts = MLAN_RTS_MIN_VALUE;
1848 	range->max_rts = MLAN_RTS_MAX_VALUE;
1849 	range->min_frag = MLAN_FRAG_MIN_VALUE;
1850 	range->max_frag = MLAN_FRAG_MAX_VALUE;
1851 
1852 	range->encoding_size[0] = 5;
1853 	range->encoding_size[1] = 13;
1854 	range->num_encoding_sizes = 2;
1855 	range->max_encoding_tokens = 4;
1856 
1857 /** Minimum power period */
1858 #define IW_POWER_PERIOD_MIN 1000000	/* 1 sec */
1859 /** Maximum power period */
1860 #define IW_POWER_PERIOD_MAX 120000000	/* 2 min */
1861 /** Minimum power timeout value */
1862 #define IW_POWER_TIMEOUT_MIN 1000	/* 1 ms  */
1863 /** Maximim power timeout value */
1864 #define IW_POWER_TIMEOUT_MAX 1000000	/* 1 sec */
1865 
1866 	/* Power Management duration & timeout */
1867 	range->min_pmp = IW_POWER_PERIOD_MIN;
1868 	range->max_pmp = IW_POWER_PERIOD_MAX;
1869 	range->min_pmt = IW_POWER_TIMEOUT_MIN;
1870 	range->max_pmt = IW_POWER_TIMEOUT_MAX;
1871 	range->pmp_flags = IW_POWER_PERIOD;
1872 	range->pmt_flags = IW_POWER_TIMEOUT;
1873 	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
1874 
1875 	/*
1876 	 * Minimum version we recommend
1877 	 */
1878 	range->we_version_source = 15;
1879 
1880 	/*
1881 	 * Version we are compiled with
1882 	 */
1883 	range->we_version_compiled = WIRELESS_EXT;
1884 
1885 	range->retry_capa = IW_RETRY_LIMIT;
1886 	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
1887 
1888 	range->min_retry = MLAN_TX_RETRY_MIN;
1889 	range->max_retry = MLAN_TX_RETRY_MAX;
1890 
1891 	/*
1892 	 * Set the qual, level and noise range values
1893 	 */
1894 	/*
1895 	 * need to put the right values here
1896 	 */
1897 /** Maximum quality percentage */
1898 #define IW_MAX_QUAL_PERCENT 5
1899 /** Average quality percentage */
1900 #define IW_AVG_QUAL_PERCENT 3
1901 	range->max_qual.qual = IW_MAX_QUAL_PERCENT;
1902 	range->max_qual.level = 0;
1903 	range->max_qual.noise = 0;
1904 
1905 	range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
1906 	range->avg_qual.level = 0;
1907 	range->avg_qual.noise = 0;
1908 
1909 	range->sensitivity = 0;
1910 
1911 	/*
1912 	 * Setup the supported power level ranges
1913 	 */
1914 	memset(range->txpower, 0, sizeof(range->txpower));
1915 
1916 	memset(&bss_info, 0, sizeof(bss_info));
1917 
1918 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1919 
1920 	range->txpower[0] = bss_info.min_power_level;
1921 	range->txpower[1] = bss_info.max_power_level;
1922 	range->num_txpower = 2;
1923 	range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
1924 
1925 #if (WIRELESS_EXT >= 18)
1926 	range->enc_capa = IW_ENC_CAPA_WPA |
1927 		IW_ENC_CAPA_WPA2 |
1928 		IW_ENC_CAPA_CIPHER_CCMP | IW_ENC_CAPA_CIPHER_TKIP;
1929 #endif
1930 
1931 	LEAVE();
1932 	return 0;
1933 }
1934 
1935 #ifdef MEF_CFG_RX_FILTER
1936 /**
1937  *  @brief Enable/disable Rx broadcast/multicast filter in non-HS mode
1938  *
1939  *  @param priv                 A pointer to moal_private structure
1940  *  @param enable               MTRUE/MFALSE: enable/disable
1941  *
1942  *  @return                     0 -- success, otherwise fail
1943  */
1944 static int
woal_set_rxfilter(moal_private * priv,BOOLEAN enable)1945 woal_set_rxfilter(moal_private *priv, BOOLEAN enable)
1946 {
1947 	int ret = 0;
1948 	mlan_ioctl_req *req = NULL;
1949 	mlan_ds_misc_cfg *misc = NULL;
1950 	mlan_ds_misc_mef_cfg *mef_cfg = NULL;
1951 	mlan_status status = MLAN_STATUS_SUCCESS;
1952 
1953 	ENTER();
1954 
1955 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1956 	if (req == NULL) {
1957 		ret = -ENOMEM;
1958 		goto done;
1959 	}
1960 	misc = (mlan_ds_misc_cfg *)req->pbuf;
1961 	mef_cfg = &misc->param.mef_cfg;
1962 	req->req_id = MLAN_IOCTL_MISC_CFG;
1963 	misc->sub_command = MLAN_OID_MISC_MEF_CFG;
1964 	req->action = MLAN_ACT_SET;
1965 
1966 	mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE);
1967 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1968 	if (status != MLAN_STATUS_SUCCESS) {
1969 		ret = -EFAULT;
1970 		goto done;
1971 	}
1972 
1973 done:
1974 	if (status != MLAN_STATUS_PENDING)
1975 		kfree(req);
1976 	LEAVE();
1977 	return ret;
1978 }
1979 #endif
1980 
1981 /**
1982  *  @brief Set priv command
1983  *
1984  *  @param dev          A pointer to net_device structure
1985  *  @param info         A pointer to iw_request_info structure
1986  *  @param dwrq         A pointer to iw_point structure
1987  *  @param extra        A pointer to extra data buf
1988  *
1989  *  @return                     0 --success, otherwise fail
1990  */
1991 static int
woal_set_priv(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1992 woal_set_priv(struct net_device *dev, struct iw_request_info *info,
1993 	      struct iw_point *dwrq, char *extra)
1994 {
1995 	int ret = 0;
1996 	moal_private *priv = (moal_private *)netdev_priv(dev);
1997 	char *buf = NULL;
1998 	int power_mode = 0;
1999 	int band = 0;
2000 	char *pband = NULL;
2001 	mlan_bss_info bss_info;
2002 	mlan_ds_get_signal signal;
2003 	mlan_rate_cfg_t rate;
2004 	char *pdata = NULL;
2005 	t_u8 country_code[COUNTRY_CODE_LEN];
2006 	int len = 0;
2007 	gfp_t flag;
2008 	ENTER();
2009 	if (!priv || !priv->phandle) {
2010 		PRINTM(MERROR, "priv or handle is NULL\n");
2011 		ret = -EFAULT;
2012 		goto done;
2013 	}
2014 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
2015 	buf = kzalloc(dwrq->length + 1, flag);
2016 	if (!buf) {
2017 		ret = -ENOMEM;
2018 		goto done;
2019 	}
2020 	if (copy_from_user(buf, dwrq->pointer, dwrq->length)) {
2021 		ret = -EFAULT;
2022 		goto done;
2023 	}
2024 	PRINTM(MIOCTL, "SIOCSIWPRIV request = %s\n", buf);
2025 	if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) {
2026 		if (dwrq->length > strlen("RSSILOW-THRESHOLD") + 1) {
2027 			pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
2028 			if (MLAN_STATUS_SUCCESS !=
2029 			    woal_set_rssi_low_threshold(priv, pdata,
2030 							MOAL_IOCTL_WAIT)) {
2031 				ret = -EFAULT;
2032 				goto done;
2033 			}
2034 			len = sprintf(buf, "OK\n") + 1;
2035 		} else {
2036 			ret = -EFAULT;
2037 			goto done;
2038 		}
2039 	} else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
2040 		if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
2041 							     MOAL_IOCTL_WAIT,
2042 							     &bss_info)) {
2043 			ret = -EFAULT;
2044 			goto done;
2045 		}
2046 		if (bss_info.media_connected) {
2047 			if (MLAN_STATUS_SUCCESS !=
2048 			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
2049 						 &signal)) {
2050 				ret = -EFAULT;
2051 				goto done;
2052 			}
2053 			len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid,
2054 				      signal.bcn_rssi_avg) + 1;
2055 		} else {
2056 			len = sprintf(buf, "OK\n") + 1;
2057 		}
2058 	} else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
2059 		if (MLAN_STATUS_SUCCESS !=
2060 		    woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
2061 			ret = -EFAULT;
2062 			goto done;
2063 		}
2064 		PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
2065 		len = sprintf(buf, "LinkSpeed %d\n",
2066 			      (int)(rate.rate * 500000 / 1000000)) + 1;
2067 	} else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
2068 		len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2069 			      priv->current_addr[0], priv->current_addr[1],
2070 			      priv->current_addr[2], priv->current_addr[3],
2071 			      priv->current_addr[4], priv->current_addr[5]) + 1;
2072 	} else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
2073 		if (MLAN_STATUS_SUCCESS !=
2074 		    woal_get_powermode(priv, &power_mode)) {
2075 			ret = -EFAULT;
2076 			goto done;
2077 		}
2078 		len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
2079 	} else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
2080 		if (MLAN_STATUS_SUCCESS !=
2081 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
2082 			ret = -EFAULT;
2083 			goto done;
2084 		}
2085 		priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
2086 		PRINTM(MIOCTL, "Set Active Scan\n");
2087 		len = sprintf(buf, "OK\n") + 1;
2088 	} else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
2089 		if (MLAN_STATUS_SUCCESS !=
2090 		    woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
2091 			ret = -EFAULT;
2092 			goto done;
2093 		}
2094 		priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
2095 		PRINTM(MIOCTL, "Set Passive Scan\n");
2096 		len = sprintf(buf, "OK\n") + 1;
2097 	} else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
2098 		if (dwrq->length > strlen("POWERMODE") + 1) {
2099 			pdata = buf + strlen("POWERMODE") + 1;
2100 			if (!hw_test) {
2101 				if (MLAN_STATUS_SUCCESS !=
2102 				    woal_set_powermode(priv, pdata)) {
2103 					ret = -EFAULT;
2104 					goto done;
2105 				}
2106 			}
2107 			len = sprintf(buf, "OK\n") + 1;
2108 		} else {
2109 			ret = -EFAULT;
2110 			goto done;
2111 		}
2112 	} else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
2113 		memset(country_code, 0, sizeof(country_code));
2114 		if ((strlen(buf) - strlen("COUNTRY") - 1) > COUNTRY_CODE_LEN) {
2115 			ret = -EFAULT;
2116 			goto done;
2117 		}
2118 		memcpy(country_code, buf + strlen("COUNTRY") + 1,
2119 		       COUNTRY_CODE_LEN - 1);
2120 		PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
2121 		if (MLAN_STATUS_SUCCESS !=
2122 		    woal_set_region_code(priv, country_code)) {
2123 			ret = -EFAULT;
2124 			goto done;
2125 		}
2126 		len = sprintf(buf, "OK\n") + 1;
2127 	} else if (memcmp(buf, WEXT_CSCAN_HEADER, strlen(WEXT_CSCAN_HEADER)) ==
2128 		   0) {
2129 		PRINTM(MIOCTL, "Set Combo Scan\n");
2130 		if (MLAN_STATUS_SUCCESS !=
2131 		    woal_set_combo_scan(priv, buf, dwrq->length)) {
2132 			ret = -EFAULT;
2133 			goto done;
2134 		}
2135 		len = sprintf(buf, "OK\n") + 1;
2136 	} else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
2137 		if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
2138 			ret = -EFAULT;
2139 			goto done;
2140 		}
2141 		len = sprintf(buf, "Band %d\n", band) + 1;
2142 	} else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
2143 		pband = buf + strlen("SETBAND") + 1;
2144 		if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
2145 			ret = -EFAULT;
2146 			goto done;
2147 		}
2148 		len = sprintf(buf, "OK\n") + 1;
2149 	} else if (strncmp(buf, "START", strlen("START")) == 0) {
2150 		len = sprintf(buf, "OK\n") + 1;
2151 	} else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
2152 		len = sprintf(buf, "OK\n") + 1;
2153 	} else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
2154 		/* it will be done by GUI */
2155 		len = sprintf(buf, "OK\n") + 1;
2156 	} else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
2157 		len = sprintf(buf, "OK\n") + 1;
2158 	} else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START"))
2159 		   == 0) {
2160 		len = sprintf(buf, "OK\n") + 1;
2161 	} else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
2162 		   0) {
2163 		len = sprintf(buf, "OK\n") + 1;
2164 	} else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
2165 		len = sprintf(buf, "OK\n") + 1;
2166 	} else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) {
2167 		if (MLAN_STATUS_SUCCESS !=
2168 		    woal_set_bg_scan(priv, buf, dwrq->length)) {
2169 			ret = -EFAULT;
2170 			goto done;
2171 		}
2172 		priv->bg_scan_start = MTRUE;
2173 		priv->bg_scan_reported = MFALSE;
2174 		len = sprintf(buf, "OK\n") + 1;
2175 	} else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
2176 		if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
2177 			if (MLAN_STATUS_SUCCESS !=
2178 			    woal_stop_bg_scan(priv, MOAL_IOCTL_WAIT)) {
2179 				ret = -EFAULT;
2180 				goto done;
2181 			}
2182 			priv->bg_scan_start = MFALSE;
2183 			priv->bg_scan_reported = MFALSE;
2184 		}
2185 		len = sprintf(buf, "OK\n") + 1;
2186 	} else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
2187 		   0) {
2188 #ifdef MEF_CFG_RX_FILTER
2189 		ret = woal_set_rxfilter(priv, MTRUE);
2190 		if (ret)
2191 			goto done;
2192 #endif
2193 		len = sprintf(buf, "OK\n") + 1;
2194 	} else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) {
2195 #ifdef MEF_CFG_RX_FILTER
2196 		ret = woal_set_rxfilter(priv, MFALSE);
2197 		if (ret)
2198 			goto done;
2199 #endif
2200 		len = sprintf(buf, "OK\n") + 1;
2201 	} else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
2202 		if (dwrq->length > strlen("RXFILTER-ADD") + 1) {
2203 			pdata = buf + strlen("RXFILTER-ADD") + 1;
2204 			if (MLAN_STATUS_SUCCESS !=
2205 			    woal_add_rxfilter(priv, pdata)) {
2206 				ret = -EFAULT;
2207 				goto done;
2208 			}
2209 			len = sprintf(buf, "OK\n") + 1;
2210 		} else {
2211 			ret = -EFAULT;
2212 			goto done;
2213 		}
2214 	} else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
2215 		   0) {
2216 		if (dwrq->length > strlen("RXFILTER-REMOVE") + 1) {
2217 			pdata = buf + strlen("RXFILTER-REMOVE") + 1;
2218 			if (MLAN_STATUS_SUCCESS !=
2219 			    woal_remove_rxfilter(priv, pdata)) {
2220 				ret = -EFAULT;
2221 				goto done;
2222 			}
2223 			len = sprintf(buf, "OK\n") + 1;
2224 		} else {
2225 			ret = -EFAULT;
2226 			goto done;
2227 		}
2228 	} else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
2229 		if (dwrq->length > strlen("QOSINFO") + 1) {
2230 			pdata = buf + strlen("QOSINFO") + 1;
2231 			if (MLAN_STATUS_SUCCESS !=
2232 			    woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
2233 				ret = -EFAULT;
2234 				goto done;
2235 			}
2236 			len = sprintf(buf, "OK\n") + 1;
2237 		} else {
2238 			ret = -EFAULT;
2239 			goto done;
2240 		}
2241 	} else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
2242 		if (dwrq->length > strlen("SLEEPPD") + 1) {
2243 			pdata = buf + strlen("SLEEPPD") + 1;
2244 			if (MLAN_STATUS_SUCCESS !=
2245 			    woal_set_sleeppd(priv, pdata)) {
2246 				ret = -EFAULT;
2247 				goto done;
2248 			}
2249 			len = sprintf(buf, "OK\n") + 1;
2250 		} else {
2251 			ret = -EFAULT;
2252 			goto done;
2253 		}
2254 	} else {
2255 		PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf);
2256 		ret = -EFAULT;
2257 		goto done;
2258 	}
2259 	PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
2260 	dwrq->length = (t_u16)len;
2261 	if (copy_to_user(dwrq->pointer, buf, dwrq->length))
2262 		ret = -EFAULT;
2263 done:
2264 	kfree(buf);
2265 	LEAVE();
2266 	return ret;
2267 }
2268 
2269 /**
2270  *  @brief Scan Network
2271  *
2272  *  @param dev          A pointer to net_device structure
2273  *  @param info         A pointer to iw_request_info structure
2274  *  @param vwrq         A pointer to iw_param structure
2275  *  @param extra        A pointer to extra data buf
2276  *
2277  *  @return             0--success, otherwise fail
2278  */
2279 static int
woal_set_scan(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)2280 woal_set_scan(struct net_device *dev, struct iw_request_info *info,
2281 	      struct iw_param *vwrq, char *extra)
2282 {
2283 	int ret = 0;
2284 	moal_private *priv = (moal_private *)netdev_priv(dev);
2285 	moal_handle *handle = priv->phandle;
2286 #if WIRELESS_EXT >= 18
2287 	struct iw_scan_req *req;
2288 	struct iw_point *dwrq = (struct iw_point *)vwrq;
2289 #endif
2290 	mlan_802_11_ssid req_ssid;
2291 
2292 	ENTER();
2293 	if (handle->scan_pending_on_block == MTRUE) {
2294 		PRINTM(MINFO, "scan already in processing...\n");
2295 		LEAVE();
2296 		return ret;
2297 	}
2298 #ifdef REASSOCIATION
2299 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2300 		PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n");
2301 		LEAVE();
2302 		return -EBUSY;
2303 	}
2304 #endif /* REASSOCIATION */
2305 	priv->report_scan_result = MTRUE;
2306 
2307 	memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid));
2308 
2309 #if WIRELESS_EXT >= 18
2310 	if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
2311 	    (dwrq->length == sizeof(struct iw_scan_req))) {
2312 		req = (struct iw_scan_req *)extra;
2313 
2314 		if (req->essid_len <= MLAN_MAX_SSID_LENGTH) {
2315 
2316 			req_ssid.ssid_len = req->essid_len;
2317 			memcpy(req_ssid.ssid,
2318 			       (t_u8 *)req->essid, req->essid_len);
2319 			if (MLAN_STATUS_SUCCESS !=
2320 			    woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) {
2321 				ret = -EFAULT;
2322 				goto done;
2323 			}
2324 		}
2325 	} else {
2326 #endif
2327 		if (MLAN_STATUS_SUCCESS !=
2328 		    woal_request_scan(priv, MOAL_NO_WAIT, NULL)) {
2329 			ret = -EFAULT;
2330 			goto done;
2331 		}
2332 #if WIRELESS_EXT >= 18
2333 	}
2334 #endif
2335 
2336 	if (priv->phandle->surprise_removed) {
2337 		ret = -EFAULT;
2338 		goto done;
2339 	}
2340 
2341 done:
2342 #ifdef REASSOCIATION
2343 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2344 #endif
2345 
2346 	LEAVE();
2347 	return ret;
2348 }
2349 
2350 /**
2351  *  @brief Set essid
2352  *
2353  *  @param dev          A pointer to net_device structure
2354  *  @param info         A pointer to iw_request_info structure
2355  *  @param dwrq         A pointer to iw_point structure
2356  *  @param extra        A pointer to extra data buf
2357  *
2358  *  @return             0--success, otherwise fail
2359  */
2360 static int
woal_set_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2361 woal_set_essid(struct net_device *dev, struct iw_request_info *info,
2362 	       struct iw_point *dwrq, char *extra)
2363 {
2364 	moal_private *priv = (moal_private *)netdev_priv(dev);
2365 	mlan_802_11_ssid req_ssid;
2366 	mlan_ssid_bssid ssid_bssid;
2367 #ifdef REASSOCIATION
2368 	moal_handle *handle = priv->phandle;
2369 	mlan_bss_info bss_info;
2370 #endif
2371 	int ret = 0;
2372 	t_u32 mode = 0;
2373 
2374 	ENTER();
2375 
2376 #ifdef REASSOCIATION
2377 	/* Cancel re-association */
2378 	priv->reassoc_required = MFALSE;
2379 
2380 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2381 		PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
2382 		LEAVE();
2383 		return -EBUSY;
2384 	}
2385 #endif /* REASSOCIATION */
2386 
2387 	/* Check the size of the string */
2388 	if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
2389 		ret = -E2BIG;
2390 		goto setessid_ret;
2391 	}
2392 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2393 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
2394 	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
2395 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
2396 
2397 #if WIRELESS_EXT > 20
2398 	req_ssid.ssid_len = dwrq->length;
2399 #else
2400 	req_ssid.ssid_len = dwrq->length - 1;
2401 #endif
2402 
2403 	/*
2404 	 * Check if we asked for `any' or 'particular'
2405 	 */
2406 	if (!dwrq->flags) {
2407 #ifdef REASSOCIATION
2408 		if (!req_ssid.ssid_len) {
2409 			memset(&priv->prev_ssid_bssid.ssid, 0x00,
2410 			       sizeof(mlan_802_11_ssid));
2411 			memset(&priv->prev_ssid_bssid.bssid, 0x00,
2412 			       MLAN_MAC_ADDR_LENGTH);
2413 			goto setessid_ret;
2414 		}
2415 #endif
2416 		/* Do normal SSID scanning */
2417 		if (MLAN_STATUS_SUCCESS !=
2418 		    woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
2419 			ret = -EFAULT;
2420 			goto setessid_ret;
2421 		}
2422 	} else {
2423 		/* Set the SSID */
2424 		memcpy(req_ssid.ssid, extra,
2425 		       MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH));
2426 		if (!req_ssid.ssid_len ||
2427 		    (MFALSE == woal_ssid_valid(&req_ssid))) {
2428 			PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
2429 			ret = -EINVAL;
2430 			goto setessid_ret;
2431 		}
2432 
2433 		PRINTM(MINFO, "Requested new SSID = %s\n",
2434 		       (char *)req_ssid.ssid);
2435 		memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
2436 		if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
2437 			PRINTM(MIOCTL, "Already connect to the network\n");
2438 			goto setessid_ret;
2439 		}
2440 
2441 		if (dwrq->flags != 0xFFFF) {
2442 			if (MLAN_STATUS_SUCCESS !=
2443 			    woal_find_essid(priv, &ssid_bssid,
2444 					    MOAL_IOCTL_WAIT)) {
2445 				/* Do specific SSID scanning */
2446 				if (MLAN_STATUS_SUCCESS !=
2447 				    woal_request_scan(priv, MOAL_IOCTL_WAIT,
2448 						      &req_ssid)) {
2449 					ret = -EFAULT;
2450 					goto setessid_ret;
2451 				}
2452 			}
2453 		}
2454 
2455 	}
2456 
2457 	mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
2458 	if (mode == IW_MODE_ADHOC)
2459 		/* disconnect before try to associate */
2460 		woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2461 				DEF_DEAUTH_REASON_CODE);
2462 
2463 	if (mode != IW_MODE_ADHOC) {
2464 		if (MLAN_STATUS_SUCCESS !=
2465 		    woal_find_best_network(priv, MOAL_IOCTL_WAIT,
2466 					   &ssid_bssid)) {
2467 			ret = -EFAULT;
2468 			goto setessid_ret;
2469 		}
2470 		if (MLAN_STATUS_SUCCESS !=
2471 		    woal_11d_check_ap_channel(priv, MOAL_IOCTL_WAIT,
2472 					      &ssid_bssid)) {
2473 			PRINTM(MERROR,
2474 			       "The AP's channel is invalid for current region\n");
2475 			ret = -EFAULT;
2476 			goto setessid_ret;
2477 		}
2478 	} else if (MLAN_STATUS_SUCCESS !=
2479 		   woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
2480 		/* Adhoc start, Check the channel command */
2481 		woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
2482 
2483 	/* Connect to BSS by ESSID */
2484 	memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
2485 
2486 	if (MLAN_STATUS_SUCCESS != woal_bss_start(priv,
2487 						  MOAL_IOCTL_WAIT,
2488 						  &ssid_bssid)) {
2489 		ret = -EFAULT;
2490 		goto setessid_ret;
2491 	}
2492 #ifdef REASSOCIATION
2493 	memset(&bss_info, 0, sizeof(bss_info));
2494 	if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv,
2495 						     MOAL_IOCTL_WAIT,
2496 						     &bss_info)) {
2497 		ret = -EFAULT;
2498 		goto setessid_ret;
2499 	}
2500 	memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid,
2501 	       sizeof(mlan_802_11_ssid));
2502 	memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid,
2503 	       MLAN_MAC_ADDR_LENGTH);
2504 #endif /* REASSOCIATION */
2505 
2506 setessid_ret:
2507 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
2508 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
2509 #ifdef REASSOCIATION
2510 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2511 #endif
2512 
2513 	LEAVE();
2514 	return ret;
2515 }
2516 
2517 /**
2518  *  @brief Get current essid
2519  *
2520  *  @param dev      A pointer to net_device structure
2521  *  @param info     A pointer to iw_request_info structure
2522  *  @param dwrq     A pointer to iw_point structure
2523  *  @param extra    A pointer to extra data buf
2524  *
2525  *  @return         0--success, otherwise fail
2526  */
2527 static int
woal_get_essid(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2528 woal_get_essid(struct net_device *dev, struct iw_request_info *info,
2529 	       struct iw_point *dwrq, char *extra)
2530 {
2531 	moal_private *priv = (moal_private *)netdev_priv(dev);
2532 	mlan_bss_info bss_info;
2533 	int ret = 0;
2534 
2535 	ENTER();
2536 
2537 	memset(&bss_info, 0, sizeof(bss_info));
2538 
2539 	if (MLAN_STATUS_SUCCESS !=
2540 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2541 		ret = -EFAULT;
2542 		goto done;
2543 	}
2544 
2545 	if (bss_info.media_connected) {
2546 		dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len);
2547 		memcpy(extra, bss_info.ssid.ssid, dwrq->length);
2548 	} else
2549 		dwrq->length = 0;
2550 
2551 	if (bss_info.scan_table_idx)
2552 		dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX;
2553 	else
2554 		dwrq->flags = 1;
2555 
2556 done:
2557 	LEAVE();
2558 	return ret;
2559 }
2560 
2561 /**
2562  *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
2563  *
2564  *  @param dev          A pointer to net_device structure
2565  *  @param info         A pointer to iw_request_info structure
2566  *  @param dwrq         A pointer to iw_point structure
2567  *  @param extra        A pointer to extra data buf
2568  *
2569  *  @return             0--success, otherwise fail
2570  */
2571 static int
woal_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)2572 woal_get_scan(struct net_device *dev, struct iw_request_info *info,
2573 	      struct iw_point *dwrq, char *extra)
2574 {
2575 	moal_private *priv = (moal_private *)netdev_priv(dev);
2576 	int ret = 0;
2577 	char *current_ev = extra;
2578 	char *end_buf = extra + IW_SCAN_MAX_DATA;
2579 	char *current_val;	/* For rates */
2580 	struct iw_event iwe;	/* Temporary buffer */
2581 	unsigned int i;
2582 	unsigned int j;
2583 	mlan_scan_resp scan_resp;
2584 	mlan_bss_info bss_info;
2585 	BSSDescriptor_t *scan_table;
2586 	mlan_ds_get_signal rssi;
2587 	t_u16 buf_size = 16 + 256 * 2;
2588 	char *buf = NULL;
2589 	char *ptr;
2590 #if WIRELESS_EXT >= 18
2591 	t_u8 *praw_data;
2592 #endif
2593 	int beacon_size;
2594 	t_u8 *pbeacon;
2595 	IEEEtypes_ElementId_e element_id;
2596 	t_u8 element_len;
2597 	gfp_t flag;
2598 
2599 	ENTER();
2600 
2601 	if (priv->phandle->scan_pending_on_block == MTRUE) {
2602 		LEAVE();
2603 		return -EAGAIN;
2604 	}
2605 	flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL;
2606 	buf = kzalloc((buf_size), flag);
2607 	if (!buf) {
2608 		PRINTM(MERROR, "Cannot allocate buffer!\n");
2609 		ret = -EFAULT;
2610 		goto done;
2611 	}
2612 
2613 	memset(&bss_info, 0, sizeof(bss_info));
2614 	if (MLAN_STATUS_SUCCESS !=
2615 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2616 		ret = -EFAULT;
2617 		goto done;
2618 	}
2619 	memset(&scan_resp, 0, sizeof(scan_resp));
2620 	if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
2621 						       MOAL_IOCTL_WAIT,
2622 						       &scan_resp)) {
2623 		ret = -EFAULT;
2624 		goto done;
2625 	}
2626 	scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
2627 	if (dwrq->length)
2628 		end_buf = extra + dwrq->length;
2629 	if (priv->media_connected == MTRUE)
2630 		PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid);
2631 	PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n",
2632 	       (int)scan_resp.num_in_scan_table);
2633 
2634 #if WIRELESS_EXT > 13
2635 	/* The old API using SIOCGIWAPLIST had a hard limit of
2636 	 * IW_MAX_AP. The new API using SIOCGIWSCAN is only
2637 	 * limited by buffer size WE-14 -> WE-16 the buffer is
2638 	 * limited to IW_SCAN_MAX_DATA bytes which is 4096.
2639 	 */
2640 	for (i = 0; i < MIN(scan_resp.num_in_scan_table, 64); i++) {
2641 		if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
2642 			PRINTM(MINFO,
2643 			       "i=%d break out: current_ev=%p end_buf=%p "
2644 			       "MAX_SCAN_CELL_SIZE=%d\n", i, current_ev,
2645 			       end_buf, (t_u32)MAX_SCAN_CELL_SIZE);
2646 			ret = -E2BIG;
2647 			break;
2648 		}
2649 		if (!scan_table[i].freq) {
2650 			PRINTM(MWARN, "Invalid channel number %d\n",
2651 			       (int)scan_table[i].channel);
2652 			continue;
2653 		}
2654 		PRINTM(MINFO, "i=%d  Ssid: %-32s\n", i,
2655 		       scan_table[i].ssid.ssid);
2656 
2657 		/* check ssid is valid or not, ex. hidden ssid will be filter out */
2658 		if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE)
2659 			continue;
2660 
2661 		/* First entry *MUST* be the AP MAC address */
2662 		iwe.cmd = SIOCGIWAP;
2663 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
2664 		memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address,
2665 		       ETH_ALEN);
2666 
2667 		iwe.len = IW_EV_ADDR_LEN;
2668 		current_ev =
2669 			IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2670 					     iwe.len);
2671 
2672 		/* Add the ESSID */
2673 		iwe.u.data.length = scan_table[i].ssid.ssid_len;
2674 
2675 		if (iwe.u.data.length > 32)
2676 			iwe.u.data.length = 32;
2677 
2678 		iwe.cmd = SIOCGIWESSID;
2679 		iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
2680 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2681 		current_ev =
2682 			IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2683 					     (char *)scan_table[i].ssid.ssid);
2684 
2685 		/* Add mode */
2686 		iwe.cmd = SIOCGIWMODE;
2687 		if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS)
2688 			iwe.u.mode = IW_MODE_ADHOC;
2689 		else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA)
2690 			iwe.u.mode = IW_MODE_MASTER;
2691 		else
2692 			iwe.u.mode = IW_MODE_AUTO;
2693 
2694 		iwe.len = IW_EV_UINT_LEN;
2695 		current_ev =
2696 			IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2697 					     iwe.len);
2698 
2699 		/* Frequency */
2700 		iwe.cmd = SIOCGIWFREQ;
2701 		iwe.u.freq.m = (long)scan_table[i].freq;
2702 		iwe.u.freq.e = 6;
2703 		iwe.u.freq.flags = IW_FREQ_FIXED;
2704 		iwe.len = IW_EV_FREQ_LEN;
2705 		current_ev =
2706 			IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2707 					     iwe.len);
2708 
2709 		memset(&iwe, 0, sizeof(iwe));
2710 		/* Add quality statistics */
2711 		iwe.cmd = IWEVQUAL;
2712 		iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi);
2713 		if (!bss_info.bcn_nf_last)
2714 			iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
2715 		else
2716 			iwe.u.qual.noise = bss_info.bcn_nf_last;
2717 
2718 		if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
2719 		    !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
2720 		    && bss_info.adhoc_state == ADHOC_STARTED) {
2721 			memset(&rssi, 0, sizeof(mlan_ds_get_signal));
2722 			if (MLAN_STATUS_SUCCESS !=
2723 			    woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
2724 						 &rssi)) {
2725 				ret = -EFAULT;
2726 				break;
2727 			}
2728 			iwe.u.qual.level = rssi.data_rssi_avg;
2729 		}
2730 		iwe.u.qual.qual =
2731 			woal_rssi_to_quality((t_s16)(iwe.u.qual.level - 0x100));
2732 		iwe.len = IW_EV_QUAL_LEN;
2733 		current_ev =
2734 			IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,
2735 					     iwe.len);
2736 
2737 		/* Add encryption capability */
2738 		iwe.cmd = SIOCGIWENCODE;
2739 		if (scan_table[i].privacy)
2740 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
2741 		else
2742 			iwe.u.data.flags = IW_ENCODE_DISABLED;
2743 
2744 		iwe.u.data.length = 0;
2745 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2746 		current_ev =
2747 			IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2748 					     NULL);
2749 
2750 		current_val = current_ev + IW_EV_LCP_LEN;
2751 
2752 		iwe.cmd = SIOCGIWRATE;
2753 
2754 		iwe.u.bitrate.fixed = 0;
2755 		iwe.u.bitrate.disabled = 0;
2756 		iwe.u.bitrate.value = 0;
2757 
2758 		/* Bit rate given in 500 kb/s units (+ 0x80) */
2759 		for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
2760 			if (!scan_table[i].supported_rates[j])
2761 				break;
2762 
2763 			iwe.u.bitrate.value =
2764 				(scan_table[i].supported_rates[j] & 0x7f) *
2765 				500000;
2766 			iwe.len = IW_EV_PARAM_LEN;
2767 			current_val =
2768 				IWE_STREAM_ADD_VALUE(info, current_ev,
2769 						     current_val, end_buf, &iwe,
2770 						     iwe.len);
2771 
2772 		}
2773 		if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) &&
2774 		    !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid)
2775 		    && bss_info.adhoc_state == ADHOC_STARTED) {
2776 			iwe.u.bitrate.value = 22 * 500000;
2777 			iwe.len = IW_EV_PARAM_LEN;
2778 			current_val =
2779 				IWE_STREAM_ADD_VALUE(info, current_ev,
2780 						     current_val, end_buf, &iwe,
2781 						     iwe.len);
2782 		}
2783 
2784 		/* Check if an event is added */
2785 		if ((unsigned int)(current_val - current_ev) >= IW_EV_PARAM_LEN)
2786 			current_ev = current_val;
2787 
2788 		/* Beacon Interval */
2789 		memset(&iwe, 0, sizeof(iwe));
2790 		ptr = buf;
2791 		ptr += sprintf(ptr, "Beacon interval=%d",
2792 			       scan_table[i].beacon_period);
2793 
2794 		iwe.u.data.length = strlen(buf);
2795 		iwe.cmd = IWEVCUSTOM;
2796 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2797 		current_ev =
2798 			IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2799 					     buf);
2800 		current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
2801 
2802 		/* Parse and send the IEs */
2803 		pbeacon = scan_table[i].pbeacon_buf;
2804 		beacon_size = scan_table[i].beacon_buf_size;
2805 
2806 		/* Skip time stamp, beacon interval and capability */
2807 		if (pbeacon) {
2808 			pbeacon += sizeof(scan_table[i].beacon_period) +
2809 				sizeof(scan_table[i].time_stamp) +
2810 				sizeof(scan_table[i].cap_info);
2811 			beacon_size -= sizeof(scan_table[i].beacon_period) +
2812 				sizeof(scan_table[i].time_stamp) +
2813 				sizeof(scan_table[i].cap_info);
2814 
2815 			while ((unsigned int)beacon_size >=
2816 			       sizeof(IEEEtypes_Header_t)) {
2817 				element_id =
2818 					(IEEEtypes_ElementId_e)(*(t_u8 *)
2819 								pbeacon);
2820 				element_len = *((t_u8 *)pbeacon + 1);
2821 				if ((unsigned int)beacon_size <
2822 				    (unsigned int)element_len +
2823 				    sizeof(IEEEtypes_Header_t)) {
2824 					PRINTM(MERROR,
2825 					       "Get scan: Error in processing IE, "
2826 					       "bytes left < IE length\n");
2827 					break;
2828 				}
2829 
2830 				switch (element_id) {
2831 #if WIRELESS_EXT >= 18
2832 				case VENDOR_SPECIFIC_221:
2833 				case RSN_IE:
2834 				case WAPI_IE:
2835 					praw_data = (t_u8 *)pbeacon;
2836 					memset(&iwe, 0, sizeof(iwe));
2837 					memset(buf, 0, buf_size);
2838 					ptr = buf;
2839 					memcpy(buf, praw_data,
2840 					       element_len +
2841 					       sizeof(IEEEtypes_Header_t));
2842 					iwe.cmd = IWEVGENIE;
2843 					iwe.u.data.length =
2844 						element_len +
2845 						sizeof(IEEEtypes_Header_t);
2846 					iwe.len =
2847 						IW_EV_POINT_LEN +
2848 						iwe.u.data.length;
2849 					current_ev =
2850 						IWE_STREAM_ADD_POINT(info,
2851 								     current_ev,
2852 								     end_buf,
2853 								     &iwe, buf);
2854 					current_val =
2855 						current_ev + IW_EV_LCP_LEN +
2856 						strlen(buf);
2857 					break;
2858 #endif
2859 				default:
2860 					break;
2861 				}
2862 				pbeacon +=
2863 					element_len +
2864 					sizeof(IEEEtypes_Header_t);
2865 				beacon_size -=
2866 					element_len +
2867 					sizeof(IEEEtypes_Header_t);
2868 			}
2869 		}
2870 #if WIRELESS_EXT > 14
2871 		memset(&iwe, 0, sizeof(iwe));
2872 		memset(buf, 0, buf_size);
2873 		ptr = buf;
2874 		ptr += sprintf(ptr, "band=");
2875 		memset(&iwe, 0, sizeof(iwe));
2876 		if (scan_table[i].bss_band == BAND_A)
2877 			ptr += sprintf(ptr, "a");
2878 		else
2879 			ptr += sprintf(ptr, "bg");
2880 		iwe.u.data.length = strlen(buf);
2881 		PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length);
2882 		PRINTM(MINFO, "BUF: %s\n", buf);
2883 		iwe.cmd = IWEVCUSTOM;
2884 		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
2885 		current_ev =
2886 			IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,
2887 					     buf);
2888 		current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
2889 #endif
2890 		current_val = current_ev + IW_EV_LCP_LEN;
2891 
2892 		/*
2893 		 * Check if we added any event
2894 		 */
2895 		if ((unsigned int)(current_val - current_ev) > IW_EV_LCP_LEN)
2896 			current_ev = current_val;
2897 	}
2898 
2899 	dwrq->length = (current_ev - extra);
2900 	dwrq->flags = 0;
2901 #endif
2902 
2903 done:
2904 	kfree(buf);
2905 	LEAVE();
2906 	return ret;
2907 }
2908 
2909 /**
2910  * iwconfig settable callbacks
2911  */
2912 static const iw_handler woal_handler[] = {
2913 	(iw_handler) woal_config_commit,	/* SIOCSIWCOMMIT */
2914 	(iw_handler) woal_get_name,	/* SIOCGIWNAME */
2915 	(iw_handler) NULL,	/* SIOCSIWNWID */
2916 	(iw_handler) NULL,	/* SIOCGIWNWID */
2917 	(iw_handler) woal_set_freq,	/* SIOCSIWFREQ */
2918 	(iw_handler) woal_get_freq,	/* SIOCGIWFREQ */
2919 	(iw_handler) woal_set_bss_mode,	/* SIOCSIWMODE */
2920 	(iw_handler) woal_get_bss_mode,	/* SIOCGIWMODE */
2921 	(iw_handler) woal_set_sens,	/* SIOCSIWSENS */
2922 	(iw_handler) woal_get_sens,	/* SIOCGIWSENS */
2923 	(iw_handler) NULL,	/* SIOCSIWRANGE */
2924 	(iw_handler) woal_get_range,	/* SIOCGIWRANGE */
2925 	(iw_handler) woal_set_priv,	/* SIOCSIWPRIV */
2926 	(iw_handler) NULL,	/* SIOCGIWPRIV */
2927 	(iw_handler) NULL,	/* SIOCSIWSTATS */
2928 	(iw_handler) NULL,	/* SIOCGIWSTATS */
2929 #if WIRELESS_EXT > 15
2930 #ifdef CONFIG_WEXT_SPY
2931 	iw_handler_set_spy,	/* SIOCSIWSPY */
2932 	iw_handler_get_spy,	/* SIOCGIWSPY */
2933 	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
2934 	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
2935 #else
2936 	(iw_handler) NULL,	/* -- hole -- */
2937 	(iw_handler) NULL,	/* -- hole -- */
2938 	(iw_handler) NULL,	/* -- hole -- */
2939 	(iw_handler) NULL,	/* -- hole -- */
2940 #endif
2941 #else /* WIRELESS_EXT > 15 */
2942 	(iw_handler) NULL,	/* -- hole -- */
2943 	(iw_handler) NULL,	/* -- hole -- */
2944 	(iw_handler) NULL,	/* -- hole -- */
2945 	(iw_handler) NULL,	/* -- hole -- */
2946 #endif /* WIRELESS_EXT > 15 */
2947 	(iw_handler) woal_set_wap,	/* SIOCSIWAP */
2948 	(iw_handler) woal_get_wap,	/* SIOCGIWAP */
2949 #if WIRELESS_EXT >= 18
2950 	(iw_handler) woal_set_mlme,	/* SIOCSIWMLME  */
2951 #else
2952 	(iw_handler) NULL,	/* -- hole -- */
2953 #endif
2954 	/* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */
2955 	NULL,			/* SIOCGIWAPLIST */
2956 #if WIRELESS_EXT > 13
2957 	(iw_handler) woal_set_scan,	/* SIOCSIWSCAN */
2958 	(iw_handler) woal_get_scan,	/* SIOCGIWSCAN */
2959 #else /* WIRELESS_EXT > 13 */
2960 	(iw_handler) NULL,	/* SIOCSIWSCAN */
2961 	(iw_handler) NULL,	/* SIOCGIWSCAN */
2962 #endif /* WIRELESS_EXT > 13 */
2963 	(iw_handler) woal_set_essid,	/* SIOCSIWESSID */
2964 	(iw_handler) woal_get_essid,	/* SIOCGIWESSID */
2965 	(iw_handler) woal_set_nick,	/* SIOCSIWNICKN */
2966 	(iw_handler) woal_get_nick,	/* SIOCGIWNICKN */
2967 	(iw_handler) NULL,	/* -- hole -- */
2968 	(iw_handler) NULL,	/* -- hole -- */
2969 	(iw_handler) woal_set_rate,	/* SIOCSIWRATE */
2970 	(iw_handler) woal_get_rate,	/* SIOCGIWRATE */
2971 	(iw_handler) woal_set_rts,	/* SIOCSIWRTS */
2972 	(iw_handler) woal_get_rts,	/* SIOCGIWRTS */
2973 	(iw_handler) woal_set_frag,	/* SIOCSIWFRAG */
2974 	(iw_handler) woal_get_frag,	/* SIOCGIWFRAG */
2975 	(iw_handler) woal_set_txpow,	/* SIOCSIWTXPOW */
2976 	(iw_handler) woal_get_txpow,	/* SIOCGIWTXPOW */
2977 	(iw_handler) woal_set_retry,	/* SIOCSIWRETRY */
2978 	(iw_handler) woal_get_retry,	/* SIOCGIWRETRY */
2979 	(iw_handler) woal_set_encode,	/* SIOCSIWENCODE */
2980 	(iw_handler) woal_get_encode,	/* SIOCGIWENCODE */
2981 	(iw_handler) woal_set_power,	/* SIOCSIWPOWER */
2982 	(iw_handler) woal_get_power,	/* SIOCGIWPOWER */
2983 #if (WIRELESS_EXT >= 18)
2984 	(iw_handler) NULL,	/* -- hole -- */
2985 	(iw_handler) NULL,	/* -- hole -- */
2986 	(iw_handler) woal_set_gen_ie,	/* SIOCSIWGENIE */
2987 	(iw_handler) woal_get_gen_ie,	/* SIOCGIWGENIE */
2988 	(iw_handler) woal_set_auth,	/* SIOCSIWAUTH  */
2989 	(iw_handler) woal_get_auth,	/* SIOCGIWAUTH  */
2990 	(iw_handler) woal_set_encode_ext,	/* SIOCSIWENCODEEXT */
2991 	(iw_handler) woal_get_encode_ext,	/* SIOCGIWENCODEEXT */
2992 	(iw_handler) woal_set_pmksa,	/* SIOCSIWPMKSA */
2993 #endif /* WIRELESSS_EXT >= 18 */
2994 };
2995 
2996 /**
2997  * iwpriv settable callbacks
2998  */
2999 static const iw_handler woal_private_handler[] = {
3000 	NULL,			/* SIOCIWFIRSTPRIV */
3001 };
3002 #endif /* STA_SUPPORT */
3003 
3004 /********************************************************
3005 			Global Functions
3006 ********************************************************/
3007 
3008 #if WIRELESS_EXT > 14
3009 
3010 /**
3011  *  @brief This function sends customized event to application.
3012  *
3013  *  @param priv    A pointer to moal_private structure
3014  *  @param str     A pointer to event string
3015  *
3016  *  @return        N/A
3017  */
3018 void
woal_send_iwevcustom_event(moal_private * priv,char * str)3019 woal_send_iwevcustom_event(moal_private *priv, char *str)
3020 {
3021 	union iwreq_data iwrq;
3022 	char buf[IW_CUSTOM_MAX];
3023 
3024 	ENTER();
3025 
3026 	memset(&iwrq, 0, sizeof(union iwreq_data));
3027 	memset(buf, 0, sizeof(buf));
3028 
3029 	snprintf(buf, sizeof(buf) - 1, "%s", str);
3030 
3031 	iwrq.data.pointer = buf;
3032 	iwrq.data.length = strlen(buf) + 1;
3033 
3034 	/* Send Event to upper layer */
3035 	wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf);
3036 	PRINTM(MINFO, "Wireless event %s is sent to application\n", str);
3037 
3038 	LEAVE();
3039 	return;
3040 }
3041 #endif
3042 
3043 #if WIRELESS_EXT >= 18
3044 /**
3045  *  @brief This function sends mic error event to application.
3046  *
3047  *  @param priv    A pointer to moal_private structure
3048  *  @param event   MIC MERROR EVENT.
3049  *
3050  *  @return        N/A
3051  */
3052 void
woal_send_mic_error_event(moal_private * priv,t_u32 event)3053 woal_send_mic_error_event(moal_private *priv, t_u32 event)
3054 {
3055 	union iwreq_data iwrq;
3056 	struct iw_michaelmicfailure mic;
3057 
3058 	ENTER();
3059 
3060 	memset(&iwrq, 0, sizeof(iwrq));
3061 	memset(&mic, 0, sizeof(mic));
3062 	if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI)
3063 		mic.flags = IW_MICFAILURE_PAIRWISE;
3064 	else
3065 		mic.flags = IW_MICFAILURE_GROUP;
3066 	iwrq.data.pointer = &mic;
3067 	iwrq.data.length = sizeof(mic);
3068 
3069 	wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq,
3070 			    (char *)&mic);
3071 
3072 	LEAVE();
3073 	return;
3074 }
3075 #endif
3076 
3077 #ifdef STA_SUPPORT
3078 /** wlan_handler_def */
3079 struct iw_handler_def woal_handler_def = {
3080 num_standard:ARRAY_SIZE(woal_handler),
3081 num_private:ARRAY_SIZE(woal_private_handler),
3082 num_private_args:ARRAY_SIZE(woal_private_args),
3083 standard:(iw_handler *) woal_handler,
3084 private:(iw_handler *) woal_private_handler,
3085 private_args:(struct iw_priv_args *)woal_private_args,
3086 #if WIRELESS_EXT > 20
3087 get_wireless_stats:woal_get_wireless_stats,
3088 #endif
3089 };
3090 
3091 /**
3092  *  @brief Get wireless statistics
3093  *
3094  *  @param dev          A pointer to net_device structure
3095  *
3096  *  @return             A pointer to iw_statistics buf
3097  */
3098 struct iw_statistics *
woal_get_wireless_stats(struct net_device * dev)3099 woal_get_wireless_stats(struct net_device *dev)
3100 {
3101 	moal_private *priv = (moal_private *)netdev_priv(dev);
3102 	t_u16 wait_option = MOAL_IOCTL_WAIT;
3103 
3104 	ENTER();
3105 
3106 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
3107 	/*
3108 	 * Since schedule() is not allowed from an atomic context
3109 	 * such as when dev_base_lock for netdevices is acquired
3110 	 * for reading/writing in kernel before this call, HostCmd
3111 	 * is issued in non-blocking way in such contexts and
3112 	 * blocking in other cases.
3113 	 */
3114 	if (in_atomic() || !write_can_lock(&dev_base_lock))
3115 		wait_option = MOAL_NO_WAIT;
3116 #endif
3117 
3118 	priv->w_stats.status = woal_get_mode(priv, wait_option);
3119 	priv->w_stats.discard.retries = priv->stats.tx_errors;
3120 	priv->w_stats.qual.qual = 0;
3121 
3122 	/* Send RSSI command to get beacon RSSI/NF, valid only if associated */
3123 	if (priv->media_connected == MTRUE) {
3124 		if (MLAN_STATUS_SUCCESS ==
3125 		    woal_get_signal_info(priv, wait_option, NULL))
3126 			priv->w_stats.qual.qual =
3127 				woal_rssi_to_quality((t_s16)
3128 						     (priv->w_stats.qual.level -
3129 						      0x100));
3130 	}
3131 #if WIRELESS_EXT > 18
3132 	priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
3133 #else
3134 	priv->w_stats.qual.updated |= 7;
3135 #endif
3136 	if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE)
3137 		priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
3138 
3139 	PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual);
3140 	PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level);
3141 	PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise);
3142 	priv->w_stats.discard.code = 0;
3143 	woal_get_stats_info(priv, wait_option, NULL);
3144 
3145 	LEAVE();
3146 	return &priv->w_stats;
3147 }
3148 #endif /* STA_SUPPORT */
3149