xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_uap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file moal_uap.c
2  *
3  * @brief This file contains the major functions in UAP
4  * driver.
5  *
6  *
7  * Copyright 2008-2022 NXP
8  *
9  * This software file (the File) is distributed by NXP
10  * under the terms of the GNU General Public License Version 2, June 1991
11  * (the License).  You may use, redistribute and/or modify the File in
12  * accordance with the terms and conditions of the License, a copy of which
13  * is available by writing to the Free Software Foundation, Inc.,
14  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16  *
17  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
20  * this warranty disclaimer.
21  *
22  */
23 
24 /********************************************************
25 Change log:
26     10/21/2008: initial version
27 ********************************************************/
28 
29 #include "moal_main.h"
30 #include "moal_uap.h"
31 #ifdef SDIO
32 #include "moal_sdio.h"
33 #endif /* SDIO */
34 #include "moal_eth_ioctl.h"
35 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
36 #include "moal_cfg80211.h"
37 #endif
38 
39 /********************************************************
40 		Local Variables
41 ********************************************************/
42 
43 /********************************************************
44 		Global Variables
45 ********************************************************/
46 /********************************************************
47 		Local Functions
48 ********************************************************/
49 /**
50  *  @brief uap addba parameter handler
51  *
52  *  @param dev      A pointer to net_device structure
53  *  @param req      A pointer to ifreq structure
54  *  @return         0 --success, otherwise fail
55  */
woal_uap_addba_param(struct net_device * dev,struct ifreq * req)56 static int woal_uap_addba_param(struct net_device *dev, struct ifreq *req)
57 {
58 	moal_private *priv = (moal_private *)netdev_priv(dev);
59 	mlan_ioctl_req *ioctl_req = NULL;
60 	mlan_ds_11n_cfg *cfg_11n = NULL;
61 	uap_addba_param param;
62 	int ret = 0;
63 	mlan_status status = MLAN_STATUS_SUCCESS;
64 
65 	ENTER();
66 	memset(&param, 0, sizeof(param));
67 
68 	/* Sanity check */
69 	if (req->ifr_data == NULL) {
70 		PRINTM(MERROR, "uap_addba_param() corrupt data\n");
71 		ret = -EFAULT;
72 		goto done;
73 	}
74 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
75 		PRINTM(MERROR, "Copy from user failed\n");
76 		ret = -EFAULT;
77 		goto done;
78 	}
79 	PRINTM(MIOCTL,
80 	       "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n",
81 	       (int)param.action, (int)param.timeout, (int)param.txwinsize,
82 	       (int)param.rxwinsize, (int)param.txamsdu, (int)param.rxamsdu);
83 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
84 	if (ioctl_req == NULL) {
85 		LEAVE();
86 		return -ENOMEM;
87 	}
88 	cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
89 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
90 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
91 
92 	if (!param.action)
93 		/* Get addba param from MLAN */
94 		ioctl_req->action = MLAN_ACT_GET;
95 	else {
96 		/* Set addba param in MLAN */
97 		ioctl_req->action = MLAN_ACT_SET;
98 		cfg_11n->param.addba_param.timeout = param.timeout;
99 		cfg_11n->param.addba_param.txwinsize = param.txwinsize;
100 		cfg_11n->param.addba_param.rxwinsize = param.rxwinsize;
101 		cfg_11n->param.addba_param.txamsdu = param.txamsdu;
102 		cfg_11n->param.addba_param.rxamsdu = param.rxamsdu;
103 	}
104 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
105 	if (status != MLAN_STATUS_SUCCESS) {
106 		ret = -EFAULT;
107 		goto done;
108 	}
109 	param.timeout = cfg_11n->param.addba_param.timeout;
110 	param.txwinsize = cfg_11n->param.addba_param.txwinsize;
111 	param.rxwinsize = cfg_11n->param.addba_param.rxwinsize;
112 	param.txamsdu = cfg_11n->param.addba_param.txamsdu;
113 	param.rxamsdu = cfg_11n->param.addba_param.rxamsdu;
114 
115 	/* Copy to user */
116 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
117 		PRINTM(MERROR, "Copy to user failed!\n");
118 		ret = -EFAULT;
119 		goto done;
120 	}
121 done:
122 	if (status != MLAN_STATUS_PENDING)
123 		kfree(ioctl_req);
124 	LEAVE();
125 	return ret;
126 }
127 
128 /**
129  *  @brief uap aggr priority tbl
130  *
131  *  @param dev      A pointer to net_device structure
132  *  @param req      A pointer to ifreq structure
133  *  @return         0 --success, otherwise fail
134  */
woal_uap_aggr_priotbl(struct net_device * dev,struct ifreq * req)135 static int woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req)
136 {
137 	moal_private *priv = (moal_private *)netdev_priv(dev);
138 	mlan_ioctl_req *ioctl_req = NULL;
139 	mlan_ds_11n_cfg *cfg_11n = NULL;
140 	uap_aggr_prio_tbl param;
141 	int ret = 0;
142 	int i = 0;
143 	mlan_status status = MLAN_STATUS_SUCCESS;
144 
145 	ENTER();
146 	memset(&param, 0, sizeof(param));
147 
148 	/* Sanity check */
149 	if (req->ifr_data == NULL) {
150 		PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n");
151 		ret = -EFAULT;
152 		goto done;
153 	}
154 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
155 		PRINTM(MERROR, "Copy from user failed\n");
156 		ret = -EFAULT;
157 		goto done;
158 	}
159 	DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *)&param, sizeof(param));
160 
161 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
162 	if (ioctl_req == NULL) {
163 		LEAVE();
164 		return -ENOMEM;
165 	}
166 	cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
167 	cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
168 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
169 
170 	if (!param.action) {
171 		/* Get aggr_prio_tbl from MLAN */
172 		ioctl_req->action = MLAN_ACT_GET;
173 	} else {
174 		/* Set aggr_prio_tbl in MLAN */
175 		ioctl_req->action = MLAN_ACT_SET;
176 		for (i = 0; i < MAX_NUM_TID; i++) {
177 			cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i];
178 			cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i];
179 		}
180 	}
181 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
182 	if (status != MLAN_STATUS_SUCCESS) {
183 		ret = -EFAULT;
184 		goto done;
185 	}
186 	for (i = 0; i < MAX_NUM_TID; i++) {
187 		param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i];
188 		param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i];
189 	}
190 	/* Copy to user */
191 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
192 		PRINTM(MERROR, "Copy to user failed!\n");
193 		ret = -EFAULT;
194 		goto done;
195 	}
196 done:
197 	if (status != MLAN_STATUS_PENDING)
198 		kfree(ioctl_req);
199 	LEAVE();
200 	return ret;
201 }
202 
203 /**
204  *  @brief uap addba reject tbl
205  *
206  *  @param dev      A pointer to net_device structure
207  *  @param req      A pointer to ifreq structure
208  *  @return         0 --success, otherwise fail
209  */
woal_uap_addba_reject(struct net_device * dev,struct ifreq * req)210 static int woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
211 {
212 	moal_private *priv = (moal_private *)netdev_priv(dev);
213 	mlan_ioctl_req *ioctl_req = NULL;
214 	mlan_ds_11n_cfg *cfg_11n = NULL;
215 	addba_reject_para param;
216 	int ret = 0;
217 	int i = 0;
218 	mlan_status status = MLAN_STATUS_SUCCESS;
219 
220 	ENTER();
221 	memset(&param, 0, sizeof(param));
222 
223 	/* Sanity check */
224 	if (req->ifr_data == NULL) {
225 		PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
226 		ret = -EFAULT;
227 		goto done;
228 	}
229 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
230 		PRINTM(MERROR, "Copy from user failed\n");
231 		ret = -EFAULT;
232 		goto done;
233 	}
234 	DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *)&param, sizeof(param));
235 
236 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
237 	if (ioctl_req == NULL) {
238 		LEAVE();
239 		return -ENOMEM;
240 	}
241 	cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
242 	cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
243 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
244 
245 	if (!param.action) {
246 		/* Get addba_reject tbl from MLAN */
247 		ioctl_req->action = MLAN_ACT_GET;
248 	} else {
249 		/* Set addba_reject tbl in MLAN */
250 		ioctl_req->action = MLAN_ACT_SET;
251 		for (i = 0; i < MAX_NUM_TID; i++)
252 			cfg_11n->param.addba_reject[i] = param.addba_reject[i];
253 	}
254 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
255 	if (status != MLAN_STATUS_SUCCESS) {
256 		ret = -EFAULT;
257 		goto done;
258 	}
259 	for (i = 0; i < MAX_NUM_TID; i++)
260 		param.addba_reject[i] = cfg_11n->param.addba_reject[i];
261 	/* Copy to user */
262 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
263 		PRINTM(MERROR, "Copy to user failed!\n");
264 		ret = -EFAULT;
265 		goto done;
266 	}
267 done:
268 	if (status != MLAN_STATUS_PENDING)
269 		kfree(ioctl_req);
270 	LEAVE();
271 	return ret;
272 }
273 
274 /**
275  *  @brief uap get_fw_info handler
276  *
277  *  @param dev      A pointer to net_device structure
278  *  @param req      A pointer to ifreq structure
279  *  @return         0 --success, otherwise fail
280  */
woal_uap_get_fw_info(struct net_device * dev,struct ifreq * req)281 static int woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req)
282 {
283 	moal_private *priv = (moal_private *)netdev_priv(dev);
284 	uap_fw_info fw;
285 	mlan_fw_info fw_info;
286 	int ret = 0;
287 
288 	ENTER();
289 	memset(&fw, 0, sizeof(fw));
290 	memset(&fw_info, 0, sizeof(fw_info));
291 
292 	/* Sanity check */
293 	if (req->ifr_data == NULL) {
294 		PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n");
295 		ret = -EFAULT;
296 		goto done;
297 	}
298 	if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) {
299 		PRINTM(MERROR, "Copy from user failed\n");
300 		ret = -EFAULT;
301 		goto done;
302 	}
303 	if (MLAN_STATUS_SUCCESS !=
304 	    woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
305 		ret = -EFAULT;
306 		goto done;
307 	}
308 	fw.fw_release_number = fw_info.fw_ver;
309 	fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support;
310 	fw.fw_bands = fw_info.fw_bands;
311 	fw.region_code = fw_info.region_code;
312 	fw.hw_dot_11n_dev_cap = fw_info.hw_dot_11n_dev_cap;
313 	/* Copy to user */
314 	if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) {
315 		PRINTM(MERROR, "Copy to user failed!\n");
316 		ret = -EFAULT;
317 		goto done;
318 	}
319 done:
320 	LEAVE();
321 	return ret;
322 }
323 
324 /**
325  *  @brief configure deep sleep
326  *
327  *  @param dev      A pointer to net_device structure
328  *  @param req      A pointer to ifreq structure
329  *  @return         0 --success, otherwise fail
330  */
woal_uap_deep_sleep(struct net_device * dev,struct ifreq * req)331 static int woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
332 {
333 	moal_private *priv = (moal_private *)netdev_priv(dev);
334 	mlan_ioctl_req *ioctl_req = NULL;
335 	mlan_ds_pm_cfg *pm = NULL;
336 	deep_sleep_para param;
337 	int ret = 0;
338 	mlan_status status = MLAN_STATUS_SUCCESS;
339 
340 	ENTER();
341 	memset(&param, 0, sizeof(param));
342 
343 	/* Sanity check */
344 	if (req->ifr_data == NULL) {
345 		PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
346 		ret = -EFAULT;
347 		goto done;
348 	}
349 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
350 		PRINTM(MERROR, "Copy from user failed\n");
351 		ret = -EFAULT;
352 		goto done;
353 	}
354 	DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *)&param, sizeof(param));
355 
356 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
357 	if (ioctl_req == NULL) {
358 		LEAVE();
359 		return -ENOMEM;
360 	}
361 	pm = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
362 	pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
363 	ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
364 
365 	if (!param.action) {
366 		/* Get deep_sleep status from MLAN */
367 		ioctl_req->action = MLAN_ACT_GET;
368 	} else {
369 		/* Set deep_sleep in MLAN */
370 		ioctl_req->action = MLAN_ACT_SET;
371 		if (param.deep_sleep == MTRUE) {
372 			pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
373 			pm->param.auto_deep_sleep.idletime = param.idle_time;
374 		} else {
375 			pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
376 		}
377 	}
378 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
379 	if (status != MLAN_STATUS_SUCCESS) {
380 		ret = -EFAULT;
381 		goto done;
382 	}
383 	if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
384 		param.deep_sleep = MTRUE;
385 	else
386 		param.deep_sleep = MFALSE;
387 	param.idle_time = pm->param.auto_deep_sleep.idletime;
388 	/* Copy to user */
389 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
390 		PRINTM(MERROR, "Copy to user failed!\n");
391 		ret = -EFAULT;
392 		goto done;
393 	}
394 done:
395 	if (status != MLAN_STATUS_PENDING)
396 		kfree(ioctl_req);
397 	LEAVE();
398 	return ret;
399 }
400 
401 /**
402  *  @brief configure band steering
403  *
404  *  @param dev      A pointer to net_device structure
405  *  @param req      A pointer to ifreq structure
406  *  @return         0 --success, otherwise fail
407  */
woal_uap_band_steer(struct net_device * dev,struct ifreq * req)408 static int woal_uap_band_steer(struct net_device *dev, struct ifreq *req)
409 {
410 	moal_private *priv = (moal_private *)netdev_priv(dev);
411 	mlan_ioctl_req *ioctl_req = NULL;
412 	mlan_ds_misc_cfg *pm = NULL;
413 	band_steer_para param;
414 	int ret = 0;
415 	mlan_status status = MLAN_STATUS_SUCCESS;
416 	ENTER();
417 	memset(&param, 0, sizeof(param));
418 
419 	/* Sanity check */
420 	if (req->ifr_data == NULL) {
421 		PRINTM(MERROR, "woal_uap_band_steer() corrupt data\n");
422 		ret = -EFAULT;
423 		goto done;
424 	}
425 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
426 		PRINTM(MERROR, "Copy from user failed\n");
427 		ret = -EFAULT;
428 		goto done;
429 	}
430 	DBG_HEXDUMP(MCMD_D, "band_steer_para", (t_u8 *)&param, sizeof(param));
431 
432 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_band_steer_cfg));
433 	if (ioctl_req == NULL) {
434 		LEAVE();
435 		return -ENOMEM;
436 	}
437 	pm = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
438 	pm->sub_command = MLAN_OID_MISC_BAND_STEERING;
439 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
440 
441 	pm->param.band_steer_cfg.action = param.action;
442 	pm->param.band_steer_cfg.block_2g_prb_req = param.block_2g_prb_req;
443 	pm->param.band_steer_cfg.state = param.state;
444 	pm->param.band_steer_cfg.max_btm_req_allowed =
445 		param.max_btm_req_allowed;
446 
447 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
448 	if (status != MLAN_STATUS_SUCCESS) {
449 		ret = -EFAULT;
450 		goto done;
451 	}
452 
453 	param.action = pm->param.band_steer_cfg.action;
454 	param.block_2g_prb_req = pm->param.band_steer_cfg.block_2g_prb_req;
455 	param.state = pm->param.band_steer_cfg.state;
456 	param.max_btm_req_allowed =
457 		pm->param.band_steer_cfg.max_btm_req_allowed;
458 
459 	/* Copy to user */
460 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
461 		PRINTM(MERROR, "Copy to user failed!\n");
462 		ret = -EFAULT;
463 		goto done;
464 	}
465 done:
466 	if (status != MLAN_STATUS_PENDING)
467 		kfree(ioctl_req);
468 	LEAVE();
469 	return ret;
470 }
471 
472 /**
473  *  @brief configure beacon stuck detect mechanism
474  *
475  *  @param dev      A pointer to net_device structure
476  *  @param req      A pointer to ifreq structure
477  *  @return         0 --success, otherwise fail
478  */
woal_uap_beacon_stuck(struct net_device * dev,struct ifreq * req)479 static int woal_uap_beacon_stuck(struct net_device *dev, struct ifreq *req)
480 {
481 	moal_private *priv = (moal_private *)netdev_priv(dev);
482 	mlan_ioctl_req *ioctl_req = NULL;
483 	mlan_ds_misc_cfg *pm = NULL;
484 	beacon_stuck_detect_para param;
485 	int ret = 0;
486 	mlan_status status = MLAN_STATUS_SUCCESS;
487 
488 	ENTER();
489 
490 	memset(&param, 0, sizeof(param));
491 
492 	/* Sanity check */
493 	if (req->ifr_data == NULL) {
494 		PRINTM(MERROR, "woal_uap_beacon_stuck() corrupt data\n");
495 		ret = -EFAULT;
496 		goto done;
497 	}
498 
499 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
500 		PRINTM(MERROR, "Copy from user failed\n");
501 		ret = -EFAULT;
502 		goto done;
503 	}
504 
505 	DBG_HEXDUMP(MCMD_D, "beacon_stuck_detect_para", (t_u8 *)&param,
506 		    sizeof(param));
507 
508 	ioctl_req = woal_alloc_mlan_ioctl_req(
509 		sizeof(mlan_ds_beacon_stuck_param_cfg));
510 	if (ioctl_req == NULL) {
511 		LEAVE();
512 		return -ENOMEM;
513 	}
514 
515 	pm = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
516 	pm->sub_command = MLAN_OID_MISC_BEACON_STUCK;
517 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
518 
519 	pm->param.beacon_stuck_cfg.action = param.action;
520 	pm->param.beacon_stuck_cfg.beacon_stuck_detect_count =
521 		param.beacon_stuck_detect_count;
522 	pm->param.beacon_stuck_cfg.recovery_confirm_count =
523 		param.recovery_confirm_count;
524 
525 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
526 
527 	if (status != MLAN_STATUS_SUCCESS) {
528 		ret = -EFAULT;
529 		goto done;
530 	}
531 
532 	param.action = pm->param.beacon_stuck_cfg.action;
533 	param.beacon_stuck_detect_count =
534 		pm->param.beacon_stuck_cfg.beacon_stuck_detect_count;
535 	param.recovery_confirm_count =
536 		pm->param.beacon_stuck_cfg.recovery_confirm_count;
537 
538 	/* Copy to user */
539 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
540 		PRINTM(MERROR, "Copy to user failed!\n");
541 		ret = -EFAULT;
542 		goto done;
543 	}
544 
545 done:
546 	if (status != MLAN_STATUS_PENDING)
547 		kfree(ioctl_req);
548 
549 	LEAVE();
550 
551 	return ret;
552 }
553 
554 /**
555  *  @brief configure tx_pause settings
556  *
557  *  @param dev      A pointer to net_device structure
558  *  @param req      A pointer to ifreq structure
559  *  @return         0 --success, otherwise fail
560  */
woal_uap_txdatapause(struct net_device * dev,struct ifreq * req)561 static int woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
562 {
563 	moal_private *priv = (moal_private *)netdev_priv(dev);
564 	mlan_ioctl_req *ioctl_req = NULL;
565 	mlan_ds_misc_cfg *misc = NULL;
566 	tx_data_pause_para param;
567 	int ret = 0;
568 	mlan_status status = MLAN_STATUS_SUCCESS;
569 
570 	ENTER();
571 	memset(&param, 0, sizeof(param));
572 
573 	/* Sanity check */
574 	if (req->ifr_data == NULL) {
575 		PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
576 		ret = -EFAULT;
577 		goto done;
578 	}
579 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
580 		PRINTM(MERROR, "Copy from user failed\n");
581 		ret = -EFAULT;
582 		goto done;
583 	}
584 	DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *)&param,
585 		    sizeof(param));
586 
587 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
588 	if (ioctl_req == NULL) {
589 		LEAVE();
590 		return -ENOMEM;
591 	}
592 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
593 	misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
594 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
595 
596 	if (!param.action) {
597 		/* Get Tx data pause status from MLAN */
598 		ioctl_req->action = MLAN_ACT_GET;
599 	} else {
600 		/* Set Tx data pause in MLAN */
601 		ioctl_req->action = MLAN_ACT_SET;
602 		misc->param.tx_datapause.tx_pause = param.txpause;
603 		misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
604 	}
605 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
606 	if (status != MLAN_STATUS_SUCCESS) {
607 		ret = -EFAULT;
608 		goto done;
609 	}
610 
611 	param.txpause = misc->param.tx_datapause.tx_pause;
612 	param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;
613 
614 	/* Copy to user */
615 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
616 		PRINTM(MERROR, "Copy to user failed!\n");
617 		ret = -EFAULT;
618 		goto done;
619 	}
620 done:
621 	if (status != MLAN_STATUS_PENDING)
622 		kfree(ioctl_req);
623 	LEAVE();
624 	return ret;
625 }
626 
627 #ifdef SDIO
628 /**
629  *  @brief uap sdcmd52rw ioctl handler
630  *
631  *  @param dev      A pointer to net_device structure
632  *  @param req      A pointer to ifreq structure
633  *  @return         0 --success, otherwise fail
634  */
woal_uap_sdcmd52_rw(struct net_device * dev,struct ifreq * req)635 static int woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req)
636 {
637 	moal_private *priv = (moal_private *)netdev_priv(dev);
638 	sdcmd52_para param;
639 	t_u8 func, data = 0;
640 	int ret = 0, reg;
641 
642 	ENTER();
643 	memset(&param, 0, sizeof(param));
644 
645 	/* Sanity check */
646 	if (req->ifr_data == NULL) {
647 		PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n");
648 		ret = -EFAULT;
649 		goto done;
650 	}
651 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
652 		PRINTM(MERROR, "Copy from user failed\n");
653 		ret = -EFAULT;
654 		goto done;
655 	}
656 
657 	func = (t_u8)param.cmd52_params[0];
658 	reg = (t_u32)param.cmd52_params[1];
659 
660 	if (!param.action) {
661 		PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
662 #ifdef SDIO_MMC
663 		sdio_claim_host(
664 			((struct sdio_mmc_card *)priv->phandle->card)->func);
665 		if (func)
666 			data = sdio_readb(
667 				((struct sdio_mmc_card *)priv->phandle->card)
668 					->func,
669 				reg, &ret);
670 		else
671 			data = sdio_f0_readb(
672 				((struct sdio_mmc_card *)priv->phandle->card)
673 					->func,
674 				reg, &ret);
675 		sdio_release_host(
676 			((struct sdio_mmc_card *)priv->phandle->card)->func);
677 		if (ret) {
678 			PRINTM(MERROR,
679 			       "sdio_readb: reading register 0x%X failed\n",
680 			       reg);
681 			goto done;
682 		}
683 #else
684 		if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
685 		    0) {
686 			PRINTM(MERROR,
687 			       "sdio_read_ioreg: reading register 0x%X failed\n",
688 			       reg);
689 			ret = MLAN_STATUS_FAILURE;
690 			goto done;
691 		}
692 #endif
693 		param.cmd52_params[2] = data;
694 	} else {
695 		data = (t_u8)param.cmd52_params[2];
696 		PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
697 		       func, reg, data);
698 #ifdef SDIO_MMC
699 		sdio_claim_host(
700 			((struct sdio_mmc_card *)priv->phandle->card)->func);
701 		if (func)
702 			sdio_writeb(
703 				((struct sdio_mmc_card *)priv->phandle->card)
704 					->func,
705 				data, reg, &ret);
706 		else
707 			sdio_f0_writeb(
708 				((struct sdio_mmc_card *)priv->phandle->card)
709 					->func,
710 				data, reg, &ret);
711 		sdio_release_host(
712 			((struct sdio_mmc_card *)priv->phandle->card)->func);
713 		if (ret) {
714 			PRINTM(MERROR,
715 			       "sdio_writeb: writing register 0x%X failed\n",
716 			       reg);
717 			goto done;
718 		}
719 #else
720 		if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
721 		    0) {
722 			PRINTM(MERROR,
723 			       "sdio_write_ioreg: writing register 0x%X failed\n",
724 			       reg);
725 			ret = MLAN_STATUS_FAILURE;
726 			goto done;
727 		}
728 #endif
729 	}
730 	/* Copy to user */
731 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
732 		PRINTM(MERROR, "Copy to user failed!\n");
733 		ret = -EFAULT;
734 	}
735 done:
736 	LEAVE();
737 	return ret;
738 }
739 #endif
740 
741 /**
742  *  @brief enable/disable 11h
743  *
744  *  @param enable      MTRUE/MFALSE
745  *  @return            0 --success, otherwise fail
746  */
woal_uap_11h_ctrl(moal_private * priv,t_u32 enable)747 int woal_uap_11h_ctrl(moal_private *priv, t_u32 enable)
748 {
749 	mlan_ioctl_req *ioctl_req = NULL;
750 	mlan_ds_snmp_mib *snmp = NULL;
751 	int ret = 0;
752 	mlan_status status = MLAN_STATUS_SUCCESS;
753 	ENTER();
754 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
755 	if (ioctl_req == NULL) {
756 		LEAVE();
757 		return -ENOMEM;
758 	}
759 	snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
760 	ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
761 	snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
762 	snmp->param.oid_value = enable;
763 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
764 	if (status != MLAN_STATUS_SUCCESS) {
765 		ret = -EFAULT;
766 		goto done;
767 	}
768 done:
769 	if (status != MLAN_STATUS_PENDING)
770 		kfree(ioctl_req);
771 	LEAVE();
772 	return ret;
773 }
774 
775 /**
776  *  @brief configure snmp mib
777  *
778  *  @param dev      A pointer to net_device structure
779  *  @param req      A pointer to ifreq structure
780  *  @return         0 --success, otherwise fail
781  */
woal_uap_snmp_mib(struct net_device * dev,struct ifreq * req)782 static int woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req)
783 {
784 	moal_private *priv = (moal_private *)netdev_priv(dev);
785 	mlan_ioctl_req *ioctl_req = NULL;
786 	mlan_ds_snmp_mib *snmp = NULL;
787 	snmp_mib_para param;
788 	t_u8 value[MAX_SNMP_VALUE_SIZE];
789 	int ret = 0;
790 	mlan_status status = MLAN_STATUS_SUCCESS;
791 
792 	ENTER();
793 	memset(&param, 0, sizeof(param));
794 	memset(value, 0, MAX_SNMP_VALUE_SIZE);
795 
796 	/* Sanity check */
797 	if (req->ifr_data == NULL) {
798 		PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n");
799 		ret = -EFAULT;
800 		goto done;
801 	}
802 
803 	/* Copy from user */
804 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
805 		PRINTM(MERROR, "Copy from user failed\n");
806 		ret = -EFAULT;
807 		goto done;
808 	}
809 	DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *)&param, sizeof(param));
810 	if (param.action) {
811 		if (copy_from_user(value, req->ifr_data + sizeof(param),
812 				   MIN(param.oid_val_len,
813 				       MAX_SNMP_VALUE_SIZE))) {
814 			PRINTM(MERROR, "Copy from user failed\n");
815 			ret = -EFAULT;
816 			goto done;
817 		}
818 		DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value,
819 			    MIN(param.oid_val_len, sizeof(t_u32)));
820 	}
821 
822 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
823 	if (ioctl_req == NULL) {
824 		LEAVE();
825 		return -ENOMEM;
826 	}
827 	snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
828 	ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
829 	switch (param.oid) {
830 	case OID_80211D_ENABLE:
831 		snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
832 		break;
833 	case OID_80211H_ENABLE:
834 		snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
835 		break;
836 	default:
837 		ret = -EINVAL;
838 		PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __func__,
839 		       param.oid);
840 		goto done;
841 	}
842 
843 	if (!param.action) {
844 		/* Get mib value from MLAN */
845 		ioctl_req->action = MLAN_ACT_GET;
846 	} else {
847 		/* Set mib value to MLAN */
848 		ioctl_req->action = MLAN_ACT_SET;
849 		snmp->param.oid_value = *(t_u32 *)value;
850 	}
851 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
852 	if (status != MLAN_STATUS_SUCCESS) {
853 		ret = -EFAULT;
854 		goto done;
855 	}
856 
857 	/* Copy to user */
858 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
859 		PRINTM(MERROR, "Copy to user failed!\n");
860 		ret = -EFAULT;
861 		goto done;
862 	}
863 	if (!param.action) { /* GET */
864 		if (copy_to_user(req->ifr_data + sizeof(param),
865 				 &snmp->param.oid_value,
866 				 MIN(param.oid_val_len, sizeof(t_u32)))) {
867 			PRINTM(MERROR, "Copy from user failed\n");
868 			ret = -EFAULT;
869 			goto done;
870 		}
871 	}
872 
873 done:
874 	if (status != MLAN_STATUS_PENDING)
875 		kfree(ioctl_req);
876 	LEAVE();
877 	return ret;
878 }
879 
880 /**
881  *  @brief configure domain info
882  *
883  *  @param dev      A pointer to net_device structure
884  *  @param req      A pointer to ifreq structure
885  *  @return         0 --success, otherwise fail
886  */
woal_uap_domain_info(struct net_device * dev,struct ifreq * req)887 static int woal_uap_domain_info(struct net_device *dev, struct ifreq *req)
888 {
889 	moal_private *priv = (moal_private *)netdev_priv(dev);
890 	mlan_ioctl_req *ioctl_req = NULL;
891 	mlan_ds_11d_cfg *cfg11d = NULL;
892 	domain_info_para param;
893 	t_u8 tlv[MAX_DOMAIN_TLV_LEN + MAX_REG_DOMAIN_TLV_LEN];
894 	t_u16 tlv_data_len = 0;
895 	int ret = 0;
896 	mlan_status status = MLAN_STATUS_SUCCESS;
897 
898 	ENTER();
899 	memset(&param, 0, sizeof(param));
900 	memset(tlv, 0, MAX_DOMAIN_TLV_LEN + MAX_REG_DOMAIN_TLV_LEN);
901 
902 	/* Sanity check */
903 	if (req->ifr_data == NULL) {
904 		PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n");
905 		ret = -EFAULT;
906 		goto done;
907 	}
908 
909 	/* Copy from user */
910 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
911 		PRINTM(MERROR, "Copy from user failed\n");
912 		ret = -EFAULT;
913 		goto done;
914 	}
915 	DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *)&param, sizeof(param));
916 	if (param.action) {
917 		/* get tlv header */
918 		if (copy_from_user(tlv, req->ifr_data + sizeof(param),
919 				   TLV_HEADER_LEN)) {
920 			PRINTM(MERROR, "Copy from user failed\n");
921 			ret = -EFAULT;
922 			goto done;
923 		}
924 		tlv_data_len = ((t_u16 *)(tlv))[1];
925 		tlv_data_len += MAX_REG_DOMAIN_TLV_LEN;
926 		if ((TLV_HEADER_LEN + tlv_data_len) > (int)sizeof(tlv)) {
927 			PRINTM(MERROR, "TLV buffer is overflowed");
928 			ret = -EINVAL;
929 			goto done;
930 		}
931 		/* get full tlv */
932 		if (copy_from_user(tlv, req->ifr_data + sizeof(param),
933 				   TLV_HEADER_LEN + tlv_data_len)) {
934 			PRINTM(MERROR, "Copy from user failed\n");
935 			ret = -EFAULT;
936 			goto done;
937 		}
938 		DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv,
939 			    TLV_HEADER_LEN + tlv_data_len);
940 	}
941 
942 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
943 	if (ioctl_req == NULL) {
944 		LEAVE();
945 		return -ENOMEM;
946 	}
947 	cfg11d = (mlan_ds_11d_cfg *)ioctl_req->pbuf;
948 	ioctl_req->req_id = MLAN_IOCTL_11D_CFG;
949 	cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
950 
951 	if (!param.action) {
952 		/* Get mib value from MLAN */
953 		ioctl_req->action = MLAN_ACT_GET;
954 	} else {
955 		/* Set mib value to MLAN */
956 		ioctl_req->action = MLAN_ACT_SET;
957 		moal_memcpy_ext(priv->phandle, cfg11d->param.domain_tlv, tlv,
958 				TLV_HEADER_LEN + tlv_data_len,
959 				sizeof(cfg11d->param.domain_tlv));
960 	}
961 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
962 	if (status != MLAN_STATUS_SUCCESS) {
963 		ret = -EFAULT;
964 		goto done;
965 	}
966 
967 	/* Copy to user */
968 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
969 		PRINTM(MERROR, "Copy to user failed!\n");
970 		ret = -EFAULT;
971 		goto done;
972 	}
973 	if (!param.action) { /* GET */
974 		tlv_data_len = ((t_u16 *)(cfg11d->param.domain_tlv))[1];
975 		if (copy_to_user(req->ifr_data + sizeof(param),
976 				 &cfg11d->param.domain_tlv,
977 				 TLV_HEADER_LEN + tlv_data_len)) {
978 			PRINTM(MERROR, "Copy from user failed\n");
979 			ret = -EFAULT;
980 			goto done;
981 		}
982 	}
983 
984 done:
985 	if (status != MLAN_STATUS_PENDING)
986 		kfree(ioctl_req);
987 	LEAVE();
988 	return ret;
989 }
990 
991 /**
992  *  @brief configure dfs testing settings
993  *
994  *  @param dev      A pointer to net_device structure
995  *  @param req      A pointer to ifreq structure
996  *  @return         0 --success, otherwise fail
997  */
woal_uap_dfs_testing(struct net_device * dev,struct ifreq * req)998 static int woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req)
999 {
1000 	moal_private *priv = (moal_private *)netdev_priv(dev);
1001 	mlan_ioctl_req *ioctl_req = NULL;
1002 	mlan_ds_11h_cfg *cfg11h = NULL;
1003 	dfs_testing_para param;
1004 	int ret = 0;
1005 	mlan_status status = MLAN_STATUS_SUCCESS;
1006 
1007 	ENTER();
1008 	memset(&param, 0, sizeof(param));
1009 
1010 	/* Sanity check */
1011 	if (req->ifr_data == NULL) {
1012 		PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n");
1013 		ret = -EFAULT;
1014 		goto done;
1015 	}
1016 
1017 	/* Copy from user */
1018 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
1019 		PRINTM(MERROR, "Copy from user failed\n");
1020 		ret = -EFAULT;
1021 		goto done;
1022 	}
1023 	DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *)&param, sizeof(param));
1024 
1025 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
1026 	if (ioctl_req == NULL) {
1027 		LEAVE();
1028 		return -ENOMEM;
1029 	}
1030 	cfg11h = (mlan_ds_11h_cfg *)ioctl_req->pbuf;
1031 	ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
1032 	cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING;
1033 
1034 	if (!param.action) {
1035 		/* Get mib value from MLAN */
1036 		ioctl_req->action = MLAN_ACT_GET;
1037 	} else {
1038 		/* Set mib value to MLAN */
1039 		ioctl_req->action = MLAN_ACT_SET;
1040 		cfg11h->param.dfs_testing.usr_cac_period_msec =
1041 			param.usr_cac_period * 1000;
1042 		cfg11h->param.dfs_testing.usr_nop_period_sec =
1043 			param.usr_nop_period;
1044 		cfg11h->param.dfs_testing.usr_no_chan_change =
1045 			param.no_chan_change;
1046 		cfg11h->param.dfs_testing.usr_fixed_new_chan =
1047 			param.fixed_new_chan;
1048 		cfg11h->param.dfs_testing.usr_cac_restart = param.cac_restart;
1049 		priv->phandle->cac_restart = param.cac_restart;
1050 		priv->phandle->cac_period_jiffies = param.usr_cac_period * HZ;
1051 		priv->user_cac_period_msec =
1052 			cfg11h->param.dfs_testing.usr_cac_period_msec;
1053 	}
1054 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
1055 	if (status != MLAN_STATUS_SUCCESS) {
1056 		ret = -EFAULT;
1057 		goto done;
1058 	}
1059 
1060 	if (!param.action) { /* GET */
1061 		param.usr_cac_period =
1062 			cfg11h->param.dfs_testing.usr_cac_period_msec / 1000;
1063 		param.usr_nop_period =
1064 			cfg11h->param.dfs_testing.usr_nop_period_sec;
1065 		param.no_chan_change =
1066 			cfg11h->param.dfs_testing.usr_no_chan_change;
1067 		param.fixed_new_chan =
1068 			cfg11h->param.dfs_testing.usr_fixed_new_chan;
1069 		param.cac_restart = cfg11h->param.dfs_testing.usr_cac_restart;
1070 	}
1071 	/* Copy to user */
1072 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
1073 		PRINTM(MERROR, "Copy to user failed!\n");
1074 		ret = -EFAULT;
1075 		goto done;
1076 	}
1077 
1078 done:
1079 	if (status != MLAN_STATUS_PENDING)
1080 		kfree(ioctl_req);
1081 	LEAVE();
1082 	return ret;
1083 }
1084 
1085 /**
1086  *  @brief uap channel NOP status check ioctl handler
1087  *
1088  *  @param priv             A pointer to moal_private structure
1089  *  @param wait_option      Wait option
1090  *  @param data             BSS control type
1091  *  @return                 0 --success, otherwise fail
1092  */
woal_uap_get_channel_nop_info(moal_private * priv,t_u8 wait_option,mlan_ds_11h_chan_nop_info * ch_info)1093 int woal_uap_get_channel_nop_info(moal_private *priv, t_u8 wait_option,
1094 				  mlan_ds_11h_chan_nop_info *ch_info)
1095 {
1096 	mlan_ioctl_req *req = NULL;
1097 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
1098 
1099 	int ret = 0;
1100 	mlan_status status = MLAN_STATUS_SUCCESS;
1101 
1102 	ENTER();
1103 
1104 	if (!ch_info) {
1105 		PRINTM(MERROR, "Invalid chan_info\n");
1106 		LEAVE();
1107 		return -EFAULT;
1108 	}
1109 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
1110 	if (req == NULL) {
1111 		ret = -ENOMEM;
1112 		goto done;
1113 	}
1114 
1115 	req->req_id = MLAN_IOCTL_11H_CFG;
1116 	req->action = MLAN_ACT_GET;
1117 
1118 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
1119 	ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_NOP_INFO;
1120 	moal_memcpy_ext(priv->phandle, &ds_11hcfg->param.ch_nop_info, ch_info,
1121 			sizeof(mlan_ds_11h_chan_nop_info),
1122 			sizeof(ds_11hcfg->param.ch_nop_info));
1123 	status = woal_request_ioctl(priv, req, wait_option);
1124 	if (status == MLAN_STATUS_FAILURE) {
1125 		ret = -EFAULT;
1126 		goto done;
1127 	}
1128 	moal_memcpy_ext(priv->phandle, ch_info, &ds_11hcfg->param.ch_nop_info,
1129 			sizeof(mlan_ds_11h_chan_nop_info),
1130 			sizeof(mlan_ds_11h_chan_nop_info));
1131 
1132 done:
1133 	if (status != MLAN_STATUS_PENDING)
1134 		kfree(req);
1135 	LEAVE();
1136 	return ret;
1137 }
1138 
1139 /**
1140  *  @brief configure channel switch count
1141  *
1142  *  @param dev      A pointer to net_device structure
1143  *  @param req      A pointer to ifreq structure
1144  *  @return         0 --success, otherwise fail
1145  */
woal_uap_chan_switch_count_cfg(struct net_device * dev,struct ifreq * req)1146 static int woal_uap_chan_switch_count_cfg(struct net_device *dev,
1147 					  struct ifreq *req)
1148 {
1149 	moal_private *priv = (moal_private *)netdev_priv(dev);
1150 	mlan_ioctl_req *ioctl_req = NULL;
1151 	mlan_ds_11h_cfg *cfg11h = NULL;
1152 	cscount_cfg_t param;
1153 	int ret = 0;
1154 	mlan_status status = MLAN_STATUS_SUCCESS;
1155 
1156 	ENTER();
1157 	memset(&param, 0, sizeof(param));
1158 
1159 	/* Sanity check */
1160 	if (req->ifr_data == NULL) {
1161 		PRINTM(MERROR, "%s corrupt data\n", __func__);
1162 		ret = -EFAULT;
1163 		goto done;
1164 	}
1165 
1166 	/* Copy from user */
1167 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
1168 		PRINTM(MERROR, "Copy from user failed\n");
1169 		ret = -EFAULT;
1170 		goto done;
1171 	}
1172 	DBG_HEXDUMP(MCMD_D, "cscount_cfg_t", (t_u8 *)&param, sizeof(param));
1173 
1174 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
1175 	if (ioctl_req == NULL) {
1176 		LEAVE();
1177 		return -ENOMEM;
1178 	}
1179 	cfg11h = (mlan_ds_11h_cfg *)ioctl_req->pbuf;
1180 	ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
1181 	cfg11h->sub_command = MLAN_OID_11H_CHAN_SWITCH_COUNT;
1182 
1183 	if (!param.action) {
1184 		/* Get mib value from MLAN */
1185 		ioctl_req->action = MLAN_ACT_GET;
1186 	} else {
1187 		/* Set mib value to MLAN */
1188 		ioctl_req->action = MLAN_ACT_SET;
1189 		cfg11h->param.cs_count = param.cs_count;
1190 	}
1191 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
1192 	if (status != MLAN_STATUS_SUCCESS) {
1193 		ret = -EFAULT;
1194 		goto done;
1195 	}
1196 
1197 	if (!param.action) { /* GET */
1198 		param.cs_count = cfg11h->param.cs_count;
1199 	}
1200 	/* Copy to user */
1201 	if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
1202 		PRINTM(MERROR, "Copy to user failed!\n");
1203 		ret = -EFAULT;
1204 		goto done;
1205 	}
1206 
1207 done:
1208 	if (status != MLAN_STATUS_PENDING)
1209 		kfree(ioctl_req);
1210 	LEAVE();
1211 	return ret;
1212 }
1213 
1214 /**
1215  *  @brief Configure TX beamforming support
1216  *
1217  *  @param dev      A pointer to net_device structure
1218  *  @param req      A pointer to ifreq structure
1219  *  @return         0 --success, otherwise fail
1220  */
woal_uap_tx_bf_cfg(struct net_device * dev,struct ifreq * req)1221 static int woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req)
1222 {
1223 	int ret = 0;
1224 	moal_private *priv = (moal_private *)netdev_priv(dev);
1225 	mlan_ds_11n_tx_bf_cfg bf_cfg;
1226 	tx_bf_cfg_para_hdr param;
1227 	t_u16 action = 0;
1228 
1229 	ENTER();
1230 
1231 	memset(&param, 0, sizeof(param));
1232 	memset(&bf_cfg, 0, sizeof(bf_cfg));
1233 
1234 	/* Sanity check */
1235 	if (req->ifr_data == NULL) {
1236 		PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n");
1237 		ret = -EFAULT;
1238 		goto done;
1239 	}
1240 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
1241 		PRINTM(MERROR, "Copy from user failed\n");
1242 		ret = -EFAULT;
1243 		goto done;
1244 	}
1245 	if (!param.action)
1246 		/* Get BF configurations */
1247 		action = MLAN_ACT_GET;
1248 	else
1249 		/* Set BF configurations */
1250 		action = MLAN_ACT_SET;
1251 	if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
1252 			   sizeof(bf_cfg))) {
1253 		PRINTM(MERROR, "Copy from user failed\n");
1254 		ret = -EFAULT;
1255 		goto done;
1256 	}
1257 	DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *)&bf_cfg, sizeof(bf_cfg));
1258 
1259 	if (MLAN_STATUS_SUCCESS !=
1260 	    woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
1261 		ret = -EFAULT;
1262 		goto done;
1263 	}
1264 
1265 	/* Copy to user */
1266 	if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr), &bf_cfg,
1267 			 sizeof(bf_cfg))) {
1268 		PRINTM(MERROR, "Copy to user failed!\n");
1269 		ret = -EFAULT;
1270 		goto done;
1271 	}
1272 
1273 done:
1274 	LEAVE();
1275 	return ret;
1276 }
1277 
1278 /**
1279  *  @brief Set/Get 11n configurations
1280  *
1281  *  @param dev      A pointer to net_device structure
1282  *  @param req      A pointer to ifreq structure
1283  *  @return         0 --success, otherwise fail
1284  */
woal_uap_ht_tx_cfg(struct net_device * dev,struct ifreq * req)1285 static int woal_uap_ht_tx_cfg(struct net_device *dev, struct ifreq *req)
1286 {
1287 	int ret = 0;
1288 	moal_private *priv = (moal_private *)netdev_priv(dev);
1289 	mlan_ds_11n_cfg *cfg_11n = NULL;
1290 	mlan_ds_11n_tx_cfg httx_cfg;
1291 	mlan_ioctl_req *ioctl_req = NULL;
1292 	ht_tx_cfg_para_hdr param;
1293 	mlan_status status = MLAN_STATUS_SUCCESS;
1294 
1295 	ENTER();
1296 
1297 	memset(&param, 0, sizeof(ht_tx_cfg_para_hdr));
1298 	memset(&httx_cfg, 0, sizeof(mlan_ds_11n_tx_cfg));
1299 
1300 	/* Sanity check */
1301 	if (req->ifr_data == NULL) {
1302 		PRINTM(MERROR, "woal_uap_ht_tx_cfg corrupt data\n");
1303 		ret = -EFAULT;
1304 		goto done;
1305 	}
1306 	if (copy_from_user(&param, req->ifr_data, sizeof(ht_tx_cfg_para_hdr))) {
1307 		PRINTM(MERROR, "Copy from user failed\n");
1308 		ret = -EFAULT;
1309 		goto done;
1310 	}
1311 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1312 	if (ioctl_req == NULL) {
1313 		ret = -ENOMEM;
1314 		goto done;
1315 	}
1316 	cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
1317 	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
1318 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
1319 	if (copy_from_user(&httx_cfg,
1320 			   req->ifr_data + sizeof(ht_tx_cfg_para_hdr),
1321 			   sizeof(mlan_ds_11n_tx_cfg))) {
1322 		PRINTM(MERROR, "Copy from user failed\n");
1323 		ret = -EFAULT;
1324 		goto done;
1325 	}
1326 	if (!param.action) {
1327 		/* Get 11n tx parameters from MLAN */
1328 		ioctl_req->action = MLAN_ACT_GET;
1329 	} else {
1330 		/* Set HT Tx configurations */
1331 		cfg_11n->param.tx_cfg.httxcap = httx_cfg.httxcap;
1332 		PRINTM(MINFO, "SET: httxcap:0x%x\n", httx_cfg.httxcap);
1333 		/* Update 11n tx parameters in MLAN */
1334 		ioctl_req->action = MLAN_ACT_SET;
1335 	}
1336 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
1337 	if (status != MLAN_STATUS_SUCCESS) {
1338 		ret = -EFAULT;
1339 		goto done;
1340 	}
1341 	if (ioctl_req->action == MLAN_ACT_GET) {
1342 		httx_cfg.httxcap = cfg_11n->param.tx_cfg.httxcap;
1343 		PRINTM(MINFO, "GET: httxcap:0x%x\n", httx_cfg.httxcap);
1344 	}
1345 	/* Copy to user */
1346 	if (copy_to_user(req->ifr_data + sizeof(ht_tx_cfg_para_hdr), &httx_cfg,
1347 			 sizeof(mlan_ds_11n_tx_cfg))) {
1348 		PRINTM(MERROR, "Copy to user failed!\n");
1349 		ret = -EFAULT;
1350 		goto done;
1351 	}
1352 done:
1353 	if (status != MLAN_STATUS_PENDING)
1354 		kfree(ioctl_req);
1355 	LEAVE();
1356 	return ret;
1357 }
1358 
1359 /**
1360  *  @brief Set/Get Set/Get 11AC configurations
1361  *
1362  *  @param dev      A pointer to net_device structure
1363  *  @param req      A pointer to ifreq structure
1364  *  @return         0 --success, otherwise fail
1365  */
woal_uap_vht_cfg(struct net_device * dev,struct ifreq * req)1366 static int woal_uap_vht_cfg(struct net_device *dev, struct ifreq *req)
1367 {
1368 	moal_private *priv = (moal_private *)netdev_priv(dev);
1369 	int ret = 0, resbuf_len = 0;
1370 	mlan_ds_11ac_cfg *cfg_11ac = NULL;
1371 	mlan_ioctl_req *ioctl_req = NULL;
1372 	mlan_ds_11ac_vht_cfg *vhtcfg = NULL, vht_cfg;
1373 	t_u8 *respbuf = NULL;
1374 	vht_cfg_para_hdr param;
1375 	mlan_status status = MLAN_STATUS_SUCCESS;
1376 #define CMD_RESPBUF_LEN 2048
1377 	gfp_t flag;
1378 
1379 	ENTER();
1380 
1381 	memset(&param, 0, sizeof(vht_cfg_para_hdr));
1382 
1383 	flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
1384 	respbuf = kzalloc(CMD_RESPBUF_LEN, flag);
1385 	if (!respbuf) {
1386 		ret = -ENOMEM;
1387 		goto done;
1388 	}
1389 
1390 	/* Sanity check */
1391 	if (req->ifr_data == NULL) {
1392 		PRINTM(MERROR, "woal_uap_ht_tx_cfg corrupt data\n");
1393 		ret = -EFAULT;
1394 		goto done;
1395 	}
1396 	if (copy_from_user(&param, req->ifr_data, sizeof(vht_cfg_para_hdr))) {
1397 		PRINTM(MERROR, "Copy from user failed\n");
1398 		ret = -EFAULT;
1399 		goto done;
1400 	}
1401 
1402 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
1403 	if (ioctl_req == NULL) {
1404 		ret = -ENOMEM;
1405 		goto done;
1406 	}
1407 	cfg_11ac = (mlan_ds_11ac_cfg *)ioctl_req->pbuf;
1408 	cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
1409 	ioctl_req->req_id = MLAN_IOCTL_11AC_CFG;
1410 	if (copy_from_user(&vht_cfg, req->ifr_data + sizeof(vht_cfg_para_hdr),
1411 			   sizeof(mlan_ds_11ac_vht_cfg))) {
1412 		PRINTM(MERROR, "Copy from user failed\n");
1413 		ret = -EFAULT;
1414 		goto done;
1415 	}
1416 	if (vht_cfg.band == BAND_SELECT_BOTH) {
1417 		cfg_11ac->param.vht_cfg.band = (BAND_SELECT_BG | BAND_SELECT_A);
1418 	} else {
1419 		cfg_11ac->param.vht_cfg.band = vht_cfg.band;
1420 	}
1421 	if (!param.action) {
1422 		/* GET operation */
1423 		if (vht_cfg.band == BAND_SELECT_BOTH) {
1424 			/* if get both bands, get BG first */
1425 			cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
1426 		}
1427 		PRINTM(MINFO, "GET: vhtcfg band: 0x%x\n",
1428 		       cfg_11ac->param.vht_cfg.band);
1429 		if (priv->bss_role == MLAN_BSS_ROLE_UAP)
1430 			cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
1431 		else
1432 			cfg_11ac->param.vht_cfg.txrx = vht_cfg.txrx;
1433 		PRINTM(MINFO, "GET: vhtcfg txrx: 0x%x\n",
1434 		       cfg_11ac->param.vht_cfg.txrx);
1435 		ioctl_req->action = MLAN_ACT_GET;
1436 	} else {
1437 		/* Band */
1438 		if (vht_cfg.band == BAND_SELECT_BOTH)
1439 			cfg_11ac->param.vht_cfg.band =
1440 				(BAND_SELECT_BG | BAND_SELECT_A);
1441 		else
1442 			cfg_11ac->param.vht_cfg.band = vht_cfg.band;
1443 		PRINTM(MINFO, "SET: vhtcfg band: 0x%x\n",
1444 		       cfg_11ac->param.vht_cfg.band);
1445 		/* Tx/Rx */
1446 		cfg_11ac->param.vht_cfg.txrx = vht_cfg.txrx;
1447 		PRINTM(MINFO, "SET: vhtcfg txrx: 0x%x\n",
1448 		       cfg_11ac->param.vht_cfg.txrx);
1449 		/* BW cfg */
1450 		cfg_11ac->param.vht_cfg.bwcfg = vht_cfg.bwcfg;
1451 		PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
1452 		       cfg_11ac->param.vht_cfg.bwcfg);
1453 
1454 		cfg_11ac->param.vht_cfg.vht_cap_info = vht_cfg.vht_cap_info;
1455 		PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
1456 		       cfg_11ac->param.vht_cfg.vht_cap_info);
1457 		cfg_11ac->param.vht_cfg.vht_tx_mcs = vht_cfg.vht_tx_mcs;
1458 		cfg_11ac->param.vht_cfg.vht_rx_mcs = vht_cfg.vht_rx_mcs;
1459 		/* Update 11AC parameters in MLAN */
1460 		ioctl_req->action = MLAN_ACT_SET;
1461 	}
1462 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
1463 	if (status != MLAN_STATUS_SUCCESS) {
1464 		ret = -EFAULT;
1465 		goto done;
1466 	}
1467 
1468 	/* number of vhtcfg entries */
1469 	*respbuf = 1;
1470 	vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
1471 	moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1472 			sizeof(mlan_ds_11ac_vht_cfg),
1473 			sizeof(mlan_ds_11ac_vht_cfg));
1474 	resbuf_len = 1 + sizeof(mlan_ds_11ac_vht_cfg);
1475 
1476 	if ((ioctl_req->action == MLAN_ACT_GET) &&
1477 	    (vht_cfg.band == BAND_SELECT_BOTH)) {
1478 		cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
1479 		status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
1480 		if (status != MLAN_STATUS_SUCCESS) {
1481 			ret = -EFAULT;
1482 			goto done;
1483 		}
1484 		/* number of vhtcfg entries */
1485 		*respbuf = 2;
1486 		vhtcfg++;
1487 		moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1488 				sizeof(mlan_ds_11ac_vht_cfg),
1489 				sizeof(mlan_ds_11ac_vht_cfg));
1490 		resbuf_len += sizeof(mlan_ds_11ac_vht_cfg);
1491 	}
1492 	if (ioctl_req->action == MLAN_ACT_GET) {
1493 		if (copy_to_user(req->ifr_data, respbuf, resbuf_len)) {
1494 			PRINTM(MERROR, "Copy to user failed\n");
1495 			ret = -EFAULT;
1496 		}
1497 	}
1498 done:
1499 	if (status != MLAN_STATUS_PENDING)
1500 		kfree(ioctl_req);
1501 	if (respbuf)
1502 		kfree(respbuf);
1503 	LEAVE();
1504 	return ret;
1505 }
1506 
1507 /**
1508  *  @brief uap hs_cfg ioctl handler
1509  *
1510  *  @param dev      A pointer to net_device structure
1511  *  @param req      A pointer to ifreq structure
1512  *  @return         0 --success, otherwise fail
1513  */
woal_uap_hs_cfg(struct net_device * dev,struct ifreq * req,BOOLEAN invoke_hostcmd)1514 static int woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req,
1515 			   BOOLEAN invoke_hostcmd)
1516 {
1517 	moal_private *priv = (moal_private *)netdev_priv(dev);
1518 	mlan_ds_hs_cfg hscfg;
1519 	ds_hs_cfg hs_cfg;
1520 	mlan_bss_info bss_info;
1521 	t_u16 action;
1522 	int ret = 0;
1523 
1524 	ENTER();
1525 
1526 	memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
1527 	memset(&hs_cfg, 0, sizeof(ds_hs_cfg));
1528 
1529 	/* Sanity check */
1530 	if (req->ifr_data == NULL) {
1531 		PRINTM(MERROR, "uap_hs_cfg() corrupt data\n");
1532 		ret = -EFAULT;
1533 		goto done;
1534 	}
1535 	if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) {
1536 		PRINTM(MERROR, "Copy from user failed\n");
1537 		ret = -EFAULT;
1538 		goto done;
1539 	}
1540 
1541 	PRINTM(MIOCTL,
1542 	       "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n",
1543 	       hs_cfg.flags, hs_cfg.conditions, (int)hs_cfg.gpio, hs_cfg.gap);
1544 
1545 	/* HS config is blocked if HS is already activated */
1546 	if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) &&
1547 	    (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL ||
1548 	     invoke_hostcmd == MFALSE)) {
1549 		memset(&bss_info, 0, sizeof(bss_info));
1550 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1551 		if (bss_info.is_hs_configured) {
1552 			PRINTM(MERROR, "HS already configured\n");
1553 			ret = -EFAULT;
1554 			goto done;
1555 		}
1556 	}
1557 
1558 	if (hs_cfg.flags & HS_CFG_FLAG_SET) {
1559 		action = MLAN_ACT_SET;
1560 		if (hs_cfg.flags != HS_CFG_FLAG_ALL) {
1561 			woal_set_get_hs_params(priv, MLAN_ACT_GET,
1562 					       MOAL_IOCTL_WAIT, &hscfg);
1563 		}
1564 		if (hs_cfg.flags & HS_CFG_FLAG_CONDITION)
1565 			hscfg.conditions = hs_cfg.conditions;
1566 		if (hs_cfg.flags & HS_CFG_FLAG_GPIO)
1567 			hscfg.gpio = hs_cfg.gpio;
1568 		if (hs_cfg.flags & HS_CFG_FLAG_GAP)
1569 			hscfg.gap = hs_cfg.gap;
1570 
1571 		if (invoke_hostcmd == MTRUE) {
1572 			/* Issue IOCTL to set up parameters */
1573 			hscfg.is_invoke_hostcmd = MFALSE;
1574 			if (MLAN_STATUS_SUCCESS !=
1575 			    woal_set_get_hs_params(priv, action,
1576 						   MOAL_IOCTL_WAIT, &hscfg)) {
1577 				ret = -EFAULT;
1578 				goto done;
1579 			}
1580 		}
1581 	} else {
1582 		action = MLAN_ACT_GET;
1583 	}
1584 
1585 	/* Issue IOCTL to invoke hostcmd */
1586 	hscfg.is_invoke_hostcmd = invoke_hostcmd;
1587 	if (MLAN_STATUS_SUCCESS !=
1588 	    woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
1589 		ret = -EFAULT;
1590 		goto done;
1591 	}
1592 	if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) {
1593 		hs_cfg.flags = HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO |
1594 			       HS_CFG_FLAG_GAP;
1595 		hs_cfg.conditions = hscfg.conditions;
1596 		hs_cfg.gpio = hscfg.gpio;
1597 		hs_cfg.gap = hscfg.gap;
1598 		/* Copy to user */
1599 		if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) {
1600 			PRINTM(MERROR, "Copy to user failed!\n");
1601 			ret = -EFAULT;
1602 			goto done;
1603 		}
1604 	}
1605 
1606 done:
1607 	LEAVE();
1608 	return ret;
1609 }
1610 
1611 /**
1612  *  @brief Set Host Sleep parameters
1613  *
1614  *  @param priv         A pointer to moal_private structure
1615  *  @param wrq          A pointer to iwreq structure
1616  *
1617  *  @return             0 --success, otherwise fail
1618  */
woal_uap_hs_set_para(struct net_device * dev,struct ifreq * req)1619 static int woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req)
1620 {
1621 	int ret = 0;
1622 
1623 	ENTER();
1624 
1625 	if (req->ifr_data != NULL) {
1626 		ret = woal_uap_hs_cfg(dev, req, MFALSE);
1627 		goto done;
1628 	} else {
1629 		PRINTM(MERROR, "Invalid data\n");
1630 		ret = -EINVAL;
1631 		goto done;
1632 	}
1633 done:
1634 	LEAVE();
1635 	return ret;
1636 }
1637 
1638 /**
1639  *  @brief uap mgmt_frame_control ioctl handler
1640  *
1641  *  @param dev      A pointer to net_device structure
1642  *  @param req      A pointer to ifreq structure
1643  *  @return         0 --success, otherwise fail
1644  */
woal_uap_mgmt_frame_control(struct net_device * dev,struct ifreq * req)1645 static int woal_uap_mgmt_frame_control(struct net_device *dev,
1646 				       struct ifreq *req)
1647 {
1648 	moal_private *priv = (moal_private *)netdev_priv(dev);
1649 	int ret = 0;
1650 	t_u16 action = 0;
1651 	mgmt_frame_ctrl param;
1652 	mlan_uap_bss_param *sys_config = NULL;
1653 
1654 	ENTER();
1655 
1656 	/* Sanity check */
1657 	if (req->ifr_data == NULL) {
1658 		PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n");
1659 		ret = -EFAULT;
1660 		goto done;
1661 	}
1662 
1663 	/* Get user data */
1664 	if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
1665 		PRINTM(MERROR, "Copy from user failed\n");
1666 		ret = -EFAULT;
1667 		goto done;
1668 	}
1669 	sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
1670 	if (!sys_config) {
1671 		PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
1672 		ret = -EFAULT;
1673 		goto done;
1674 	}
1675 
1676 	if (param.action)
1677 		action = MLAN_ACT_SET;
1678 	else
1679 		action = MLAN_ACT_GET;
1680 	if (action == MLAN_ACT_SET) {
1681 		/* Initialize the invalid values so that the correct
1682 		   values below are downloaded to firmware */
1683 		woal_set_sys_config_invalid_data(sys_config);
1684 		sys_config->mgmt_ie_passthru_mask = param.mask;
1685 	}
1686 
1687 	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, action,
1688 							   MOAL_IOCTL_WAIT,
1689 							   sys_config)) {
1690 		ret = -EFAULT;
1691 		goto done;
1692 	}
1693 
1694 	if (action == MLAN_ACT_GET) {
1695 		param.mask = sys_config->mgmt_ie_passthru_mask;
1696 		if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
1697 			PRINTM(MERROR, "Copy to user failed\n");
1698 			ret = -EFAULT;
1699 		}
1700 	}
1701 done:
1702 	kfree(sys_config);
1703 	LEAVE();
1704 	return ret;
1705 }
1706 
1707 /**
1708  * @brief Set/Get tx rate
1709  *
1710  *  @param dev      A pointer to net_device structure
1711  *  @param req      A pointer to ifreq structure
1712  *
1713  * @return           0 --success, otherwise fail
1714  */
woal_uap_tx_rate_cfg(struct net_device * dev,struct ifreq * req)1715 static int woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req)
1716 {
1717 	moal_private *priv = (moal_private *)netdev_priv(dev);
1718 	int ret = 0, i = 0;
1719 	mlan_ds_rate *rate = NULL;
1720 	mlan_ioctl_req *mreq = NULL;
1721 	tx_rate_cfg_t tx_rate_config;
1722 	mlan_status status = MLAN_STATUS_SUCCESS;
1723 
1724 	ENTER();
1725 
1726 	/* Sanity check */
1727 	if (req->ifr_data == NULL) {
1728 		PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n");
1729 		ret = -EFAULT;
1730 		goto done;
1731 	}
1732 
1733 	memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t));
1734 	/* Get user data */
1735 	if (copy_from_user(&tx_rate_config, req->ifr_data,
1736 			   sizeof(tx_rate_cfg_t))) {
1737 		PRINTM(MERROR, "Copy from user failed\n");
1738 		ret = -EFAULT;
1739 		goto done;
1740 	}
1741 
1742 	mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
1743 	if (mreq == NULL) {
1744 		ret = -ENOMEM;
1745 		goto done;
1746 	}
1747 	rate = (mlan_ds_rate *)mreq->pbuf;
1748 	rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
1749 	rate->sub_command = MLAN_OID_RATE_CFG;
1750 	mreq->req_id = MLAN_IOCTL_RATE;
1751 	if (!(tx_rate_config.action))
1752 		mreq->action = MLAN_ACT_GET;
1753 	else {
1754 		if ((tx_rate_config.user_data_cnt <= 0) ||
1755 		    (tx_rate_config.user_data_cnt > 4)) {
1756 			PRINTM(MERROR, "Invalid user_data_cnt\n");
1757 			ret = -EINVAL;
1758 			goto done;
1759 		}
1760 
1761 		mreq->action = MLAN_ACT_SET;
1762 		if (tx_rate_config.rate_format == AUTO_RATE)
1763 			rate->param.rate_cfg.is_rate_auto = 1;
1764 		else {
1765 			if ((tx_rate_config.rate_format < 0) ||
1766 			    (tx_rate_config.rate < 0)) {
1767 				PRINTM(MERROR,
1768 				       "Invalid format or rate selection\n");
1769 				ret = -EINVAL;
1770 				goto done;
1771 			}
1772 			/* rate_format sanity check */
1773 			if ((tx_rate_config.rate_format >
1774 			     MLAN_RATE_FORMAT_HE)) {
1775 				PRINTM(MERROR, "Invalid format selection\n");
1776 				ret = -EINVAL;
1777 				goto done;
1778 			}
1779 			rate->param.rate_cfg.rate_format =
1780 				tx_rate_config.rate_format;
1781 
1782 			/* rate sanity check */
1783 			if (tx_rate_config.user_data_cnt >= 2) {
1784 				if (((tx_rate_config.rate_format ==
1785 				      MLAN_RATE_FORMAT_LG) &&
1786 				     (tx_rate_config.rate >
1787 				      MLAN_RATE_INDEX_OFDM7)) ||
1788 				    ((tx_rate_config.rate_format ==
1789 				      MLAN_RATE_FORMAT_HT) &&
1790 				     (tx_rate_config.rate != 32) &&
1791 				     (tx_rate_config.rate > 15)) ||
1792 				    ((tx_rate_config.rate_format ==
1793 				      MLAN_RATE_FORMAT_VHT) &&
1794 				     (tx_rate_config.rate >
1795 				      MLAN_RATE_INDEX_MCS9)) ||
1796 				    ((tx_rate_config.rate_format ==
1797 				      MLAN_RATE_FORMAT_HE) &&
1798 				     (tx_rate_config.rate >
1799 				      MLAN_RATE_INDEX_MCS11))) {
1800 					PRINTM(MERROR,
1801 					       "Invalid rate selection\n");
1802 					ret = -EINVAL;
1803 					goto done;
1804 				}
1805 				rate->param.rate_cfg.rate = tx_rate_config.rate;
1806 			}
1807 
1808 			/* nss sanity check */
1809 			if ((tx_rate_config.rate_format == 2) ||
1810 			    (tx_rate_config.rate_format == 3)) {
1811 				if ((tx_rate_config.nss < 1) ||
1812 				    (tx_rate_config.nss > 2)) {
1813 					PRINTM(MERROR,
1814 					       "Invalid nss selection %d\n",
1815 					       tx_rate_config.nss);
1816 					ret = -EINVAL;
1817 					goto done;
1818 				}
1819 				rate->param.rate_cfg.nss = tx_rate_config.nss;
1820 			}
1821 			if (tx_rate_config.user_data_cnt <= 3)
1822 				rate->param.rate_cfg.rate_setting = 0xffff;
1823 			else
1824 				rate->param.rate_cfg.rate_setting =
1825 					tx_rate_config.rate_setting;
1826 		}
1827 	}
1828 
1829 	status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
1830 	if (status != MLAN_STATUS_SUCCESS) {
1831 		ret = -EFAULT;
1832 		goto done;
1833 	}
1834 	if (tx_rate_config.action) {
1835 		priv->rate_index = tx_rate_config.action;
1836 	} else {
1837 		if (rate->param.rate_cfg.is_rate_auto)
1838 			tx_rate_config.rate_format = AUTO_RATE;
1839 		else {
1840 			/* fixed rate */
1841 			tx_rate_config.rate_format =
1842 				rate->param.rate_cfg.rate_format;
1843 			tx_rate_config.rate = rate->param.rate_cfg.rate;
1844 			if (rate->param.rate_cfg.rate_format ==
1845 				    MLAN_RATE_FORMAT_VHT ||
1846 			    rate->param.rate_cfg.rate_format ==
1847 				    MLAN_RATE_FORMAT_HE)
1848 				tx_rate_config.nss = rate->param.rate_cfg.nss;
1849 			tx_rate_config.rate_setting =
1850 				rate->param.rate_cfg.rate_setting;
1851 		}
1852 		for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
1853 			tx_rate_config.bitmap_rates[i] =
1854 				rate->param.rate_cfg.bitmap_rates[i];
1855 		}
1856 
1857 		if (copy_to_user(req->ifr_data, &tx_rate_config,
1858 				 sizeof(tx_rate_cfg_t))) {
1859 			PRINTM(MERROR, "Copy to user failed\n");
1860 			ret = -EFAULT;
1861 		}
1862 	}
1863 done:
1864 	if (status != MLAN_STATUS_PENDING)
1865 		kfree(mreq);
1866 	LEAVE();
1867 	return ret;
1868 }
1869 
1870 /**
1871  * @brief Set/Get RF antenna mode
1872  *
1873  *  @param dev      A pointer to net_device structure
1874  *  @param req      A pointer to ifreq structure
1875  *
1876  * @return           0 --success, otherwise fail
1877  */
woal_uap_antenna_cfg(struct net_device * dev,struct ifreq * req)1878 static int woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req)
1879 {
1880 	moal_private *priv = (moal_private *)netdev_priv(dev);
1881 	int ret = 0;
1882 	mlan_ds_radio_cfg *radio = NULL;
1883 	mlan_ioctl_req *mreq = NULL;
1884 	ant_cfg_t antenna_config;
1885 	mlan_status status = MLAN_STATUS_SUCCESS;
1886 
1887 	ENTER();
1888 
1889 	/* Sanity check */
1890 	if (req->ifr_data == NULL) {
1891 		PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
1892 		ret = -EFAULT;
1893 		goto done;
1894 	}
1895 
1896 	memset(&antenna_config, 0, sizeof(ant_cfg_t));
1897 	/* Get user data */
1898 	if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) {
1899 		PRINTM(MERROR, "Copy from user failed\n");
1900 		ret = -EFAULT;
1901 		goto done;
1902 	}
1903 	mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
1904 	if (mreq == NULL) {
1905 		ret = -ENOMEM;
1906 		goto done;
1907 	}
1908 	radio = (mlan_ds_radio_cfg *)mreq->pbuf;
1909 	radio->sub_command = MLAN_OID_ANT_CFG;
1910 	mreq->req_id = MLAN_IOCTL_RADIO_CFG;
1911 	if (!(antenna_config.action))
1912 		mreq->action = MLAN_ACT_GET;
1913 	else {
1914 		mreq->action = MLAN_ACT_SET;
1915 		radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode;
1916 		radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode;
1917 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
1918 		if (IS_CARD9098(priv->phandle->card_type) ||
1919 		    IS_CARD9097(priv->phandle->card_type)) {
1920 			if (IS_STA_CFG80211(
1921 				    priv->phandle->params.cfg80211_wext))
1922 				woal_cfg80211_notify_antcfg(
1923 					priv, priv->phandle->wiphy, radio);
1924 		}
1925 #endif
1926 	}
1927 
1928 	status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
1929 	if (status != MLAN_STATUS_SUCCESS) {
1930 		ret = -EFAULT;
1931 		goto done;
1932 	}
1933 	if (mreq->action == MLAN_ACT_GET) {
1934 		antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna;
1935 		antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna;
1936 		if (copy_to_user(req->ifr_data, &antenna_config,
1937 				 sizeof(ant_cfg_t))) {
1938 			PRINTM(MERROR, "Copy to user failed\n");
1939 			ret = -EFAULT;
1940 		}
1941 	}
1942 done:
1943 	if (status != MLAN_STATUS_PENDING)
1944 		kfree(mreq);
1945 	LEAVE();
1946 	return ret;
1947 }
1948 
1949 /**
1950  * @brief Set/Get HT stream configurations
1951  *
1952  *  @param dev      A pointer to net_device structure
1953  *  @param req      A pointer to ifreq structure
1954  *
1955  * @return           0 --success, otherwise fail
1956  */
woal_uap_htstream_cfg(struct net_device * dev,struct ifreq * req)1957 static int woal_uap_htstream_cfg(struct net_device *dev, struct ifreq *req)
1958 {
1959 	moal_private *priv = (moal_private *)netdev_priv(dev);
1960 	int ret = 0;
1961 	mlan_ds_11n_cfg *cfg = NULL;
1962 	mlan_ioctl_req *ioctl_req = NULL;
1963 	htstream_cfg_t htstream_cfg;
1964 	mlan_status status = MLAN_STATUS_SUCCESS;
1965 
1966 	ENTER();
1967 
1968 	memset(&htstream_cfg, 0, sizeof(htstream_cfg_t));
1969 
1970 	/* Sanity check */
1971 	if (req->ifr_data == NULL) {
1972 		PRINTM(MERROR, "woal_uap_htstream_cfg corrupt data\n");
1973 		ret = -EFAULT;
1974 		goto done;
1975 	}
1976 	if (copy_from_user(&htstream_cfg, req->ifr_data,
1977 			   sizeof(htstream_cfg_t))) {
1978 		PRINTM(MERROR, "Copy from user failed\n");
1979 		ret = -EFAULT;
1980 		goto done;
1981 	}
1982 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1983 	if (ioctl_req == NULL) {
1984 		ret = -ENOMEM;
1985 		goto done;
1986 	}
1987 	cfg = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
1988 	cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
1989 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
1990 
1991 	if (!htstream_cfg.action) {
1992 		/* Get operation */
1993 		ioctl_req->action = MLAN_ACT_GET;
1994 	} else {
1995 		/* Update HT stream parameter in MLAN */
1996 		ioctl_req->action = MLAN_ACT_SET;
1997 		/* Set HT Stream configuration */
1998 		cfg->param.stream_cfg = htstream_cfg.stream_cfg;
1999 		PRINTM(MINFO, "SET: htstream_cfg:0x%x\n",
2000 		       cfg->param.stream_cfg);
2001 	}
2002 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2003 	if (status != MLAN_STATUS_SUCCESS) {
2004 		ret = -EFAULT;
2005 		goto done;
2006 	}
2007 	/* Copy to user */
2008 	if (ioctl_req->action == MLAN_ACT_GET) {
2009 		PRINTM(MINFO, "GET: htstream_cfg:0x%x\n",
2010 		       htstream_cfg.stream_cfg);
2011 		htstream_cfg.stream_cfg = cfg->param.stream_cfg;
2012 		if (copy_to_user(req->ifr_data, &htstream_cfg,
2013 				 sizeof(htstream_cfg_t))) {
2014 			PRINTM(MERROR, "Copy to user failed!\n");
2015 			ret = -EFAULT;
2016 			goto done;
2017 		}
2018 	}
2019 done:
2020 	if (status != MLAN_STATUS_PENDING)
2021 		kfree(ioctl_req);
2022 	LEAVE();
2023 	return ret;
2024 }
2025 
2026 /**
2027  * @brief Get DFS_REPEATER mode
2028  *
2029  *  @param dev      A pointer to net_device structure
2030  *  @param req      A pointer to ifreq structure
2031  *
2032  * @return           0 --success, otherwise fail
2033  */
woal_uap_dfs_repeater(struct net_device * dev,struct ifreq * req)2034 static int woal_uap_dfs_repeater(struct net_device *dev, struct ifreq *req)
2035 {
2036 	moal_private *priv = (moal_private *)netdev_priv(dev);
2037 	int ret = 0;
2038 	dfs_repeater_mode param;
2039 	mlan_ds_misc_cfg *misc = NULL;
2040 	mlan_ioctl_req *mreq = NULL;
2041 	mlan_status status = MLAN_STATUS_SUCCESS;
2042 
2043 	ENTER();
2044 
2045 	/* Sanity check */
2046 	if (req->ifr_data == NULL) {
2047 		PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
2048 		ret = -EFAULT;
2049 		goto done;
2050 	}
2051 
2052 	memset(&param, 0, sizeof(dfs_repeater_mode));
2053 	/* Get user data */
2054 	if (copy_from_user(&param, req->ifr_data, sizeof(dfs_repeater_mode))) {
2055 		PRINTM(MERROR, "Copy from user failed\n");
2056 		ret = -EFAULT;
2057 		goto done;
2058 	}
2059 	mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
2060 	if (mreq == NULL) {
2061 		ret = -ENOMEM;
2062 		goto done;
2063 	}
2064 	misc = (mlan_ds_misc_cfg *)mreq->pbuf;
2065 	misc->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
2066 	mreq->req_id = MLAN_IOCTL_MISC_CFG;
2067 	mreq->action = MLAN_ACT_GET;
2068 
2069 	status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
2070 	if (status != MLAN_STATUS_SUCCESS) {
2071 		ret = -EFAULT;
2072 		goto done;
2073 	}
2074 	param.mode = misc->param.dfs_repeater.mode;
2075 
2076 	if (copy_to_user(req->ifr_data, &param, sizeof(dfs_repeater_mode))) {
2077 		PRINTM(MERROR, "Copy to user failed\n");
2078 		ret = -EFAULT;
2079 	}
2080 done:
2081 	if (status != MLAN_STATUS_PENDING)
2082 		kfree(mreq);
2083 	LEAVE();
2084 	return ret;
2085 }
2086 
2087 /**
2088  *  @brief Issue MLAN_OID_11H_CHAN_REPORT_REQUEST ioctl to cancel dozer
2089  *
2090  *  @param priv     Pointer to the moal_private driver data struct
2091  *  @param action   MLAN_ACT_SET/MLAN_ACT_GET
2092  *  @param
2093  *
2094  *  @return         0 --success, otherwise fail
2095  */
woal_11h_chan_dfs_state(moal_private * priv,t_u8 action,mlan_ds_11h_chan_dfs_state * ch_dfs_state)2096 int woal_11h_chan_dfs_state(moal_private *priv, t_u8 action,
2097 			    mlan_ds_11h_chan_dfs_state *ch_dfs_state)
2098 {
2099 	int ret = 0;
2100 	mlan_ioctl_req *req = NULL;
2101 	mlan_ds_11h_cfg *ds_11hcfg = NULL;
2102 	mlan_status status = MLAN_STATUS_SUCCESS;
2103 #ifdef UAP_CFG80211
2104 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2105 	int cfg80211_wext = priv->phandle->params.cfg80211_wext;
2106 #endif
2107 #endif
2108 
2109 	ENTER();
2110 #ifdef UAP_CFG80211
2111 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2112 	if (action == MLAN_ACT_GET) {
2113 		if (IS_UAP_CFG80211(cfg80211_wext)) {
2114 			ret = woal_get_wiphy_chan_dfs_state(
2115 				priv->phandle->wiphy, ch_dfs_state);
2116 			if (!ret) {
2117 				LEAVE();
2118 				return ret;
2119 			}
2120 		}
2121 	}
2122 #endif
2123 #endif
2124 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
2125 	if (req == NULL) {
2126 		ret = -ENOMEM;
2127 		goto done;
2128 	}
2129 	ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
2130 
2131 	ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_DFS_STATE;
2132 	req->req_id = MLAN_IOCTL_11H_CFG;
2133 	req->action = action;
2134 	moal_memcpy_ext(priv->phandle, &ds_11hcfg->param.ch_dfs_state,
2135 			ch_dfs_state, sizeof(mlan_ds_11h_chan_dfs_state),
2136 			sizeof(ds_11hcfg->param.ch_dfs_state));
2137 	/* Send Channel Check command and wait until the report is ready */
2138 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2139 	if (status != MLAN_STATUS_SUCCESS) {
2140 		ret = -EFAULT;
2141 		goto done;
2142 	}
2143 	moal_memcpy_ext(priv->phandle, ch_dfs_state,
2144 			&ds_11hcfg->param.ch_dfs_state,
2145 			sizeof(mlan_ds_11h_chan_dfs_state),
2146 			sizeof(mlan_ds_11h_chan_dfs_state));
2147 done:
2148 	if (status != MLAN_STATUS_PENDING)
2149 		kfree(req);
2150 	LEAVE();
2151 	return ret;
2152 }
2153 
2154 /**
2155  *  @brief find all bonded channel.
2156  *
2157  *  @param pri_chan   primary channel
2158  *  @param bw         channel bandwidth
2159  *  @param ch_dfs_state  a pointer to mlan_ds_11h_chan_dfs_state array
2160  *
2161  *  @return           number of channel
2162  */
woal_uap_get_dfs_chan(t_u8 pri_chan,t_u8 bw,mlan_ds_11h_chan_dfs_state * ch_dfs_state)2163 static int woal_uap_get_dfs_chan(t_u8 pri_chan, t_u8 bw,
2164 				 mlan_ds_11h_chan_dfs_state *ch_dfs_state)
2165 {
2166 	int ht40_plus[] = {52, 60, 100, 108, 116, 124, 132, 140};
2167 	int ht40_minus[] = {56, 64, 104, 112, 120, 128, 136, 144};
2168 	int vht80_dfs[4][4] = {{52, 56, 60, 64},
2169 			       {100, 104, 108, 112},
2170 			       {116, 120, 124, 128},
2171 			       {132, 136, 140, 144}};
2172 	t_u8 find = false;
2173 	int i, j;
2174 	t_u8 sec_chan = 0;
2175 	mlan_ds_11h_chan_dfs_state *pos = ch_dfs_state;
2176 	t_u8 n_chan = 1;
2177 
2178 	if (bw == CHAN_BW_20MHZ) {
2179 		pos->channel = pri_chan;
2180 	} else if (bw == CHAN_BW_40MHZ) {
2181 		pos->channel = pri_chan;
2182 		pos++;
2183 		for (i = 0; i < (sizeof(ht40_minus) / sizeof(int)); i++) {
2184 			if (pri_chan == (t_u8)ht40_plus[i]) {
2185 				sec_chan = pri_chan + 4;
2186 				n_chan = 2;
2187 				break;
2188 			}
2189 		}
2190 		for (i = 0; i < (sizeof(ht40_minus) / sizeof(int)); i++) {
2191 			if (pri_chan == (t_u8)ht40_minus[i]) {
2192 				sec_chan = pri_chan - 4;
2193 				n_chan = 2;
2194 				break;
2195 			}
2196 		}
2197 		pos->channel = sec_chan;
2198 	} else if (bw == CHAN_BW_80MHZ) {
2199 		for (i = 0; i < 4; i++) {
2200 			for (j = 0; j < 4; j++) {
2201 				if (pri_chan == (t_u8)vht80_dfs[i][j]) {
2202 					find = true;
2203 					break;
2204 				}
2205 			}
2206 			if (find)
2207 				break;
2208 		}
2209 		if (find) {
2210 			n_chan = 4;
2211 			for (j = 0; j < n_chan; j++) {
2212 				pos->channel = (t_u8)vht80_dfs[i][j];
2213 				pos++;
2214 			}
2215 		}
2216 	}
2217 	return n_chan;
2218 }
2219 
2220 #ifdef UAP_CFG80211
2221 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2222 /**
2223  * @brief update channel dfs state to all wiphy
2224  *
2225  * @param channel         given radar channel
2226  * @param bandwidth       channel's bandwidth
2227  * @param dfs_state       dfs_state
2228  *
2229  * @return                N/A
2230  */
woal_update_channels_dfs_state(moal_private * priv,t_u8 channel,t_u8 bandwidth,t_u8 dfs_state)2231 void woal_update_channels_dfs_state(moal_private *priv, t_u8 channel,
2232 				    t_u8 bandwidth, t_u8 dfs_state)
2233 {
2234 	mlan_ds_11h_chan_dfs_state ch_dfs_state[4];
2235 	int cfg80211_wext = priv->phandle->params.cfg80211_wext;
2236 	t_u8 n_chan;
2237 	int i;
2238 	ENTER();
2239 	memset(ch_dfs_state, 0, sizeof(ch_dfs_state));
2240 	n_chan = woal_uap_get_dfs_chan(channel, bandwidth, &ch_dfs_state[0]);
2241 	if (IS_UAP_CFG80211(cfg80211_wext)) {
2242 		for (i = 0; i < n_chan; i++) {
2243 			woal_update_channel_dfs_state(ch_dfs_state[i].channel,
2244 						      dfs_state);
2245 		}
2246 	}
2247 	LEAVE();
2248 	return;
2249 }
2250 #endif
2251 #endif
2252 
2253 /**
2254  * @brief skip cac on specific channel
2255  * @and Wext
2256  *
2257  *  @param dev      A pointer to net_device structure
2258  *  @param req      A pointer to ifreq structure
2259  *
2260  * @return           0 --success, otherwise fail
2261  */
woal_uap_skip_cac(struct net_device * dev,struct ifreq * req)2262 static int woal_uap_skip_cac(struct net_device *dev, struct ifreq *req)
2263 {
2264 	int ret = 0;
2265 	skip_cac_para param;
2266 	moal_private *priv = (moal_private *)netdev_priv(dev);
2267 #ifdef UAP_CFG80211
2268 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2269 	int cfg80211_wext = priv->phandle->params.cfg80211_wext;
2270 #endif
2271 #endif
2272 	dfs_state_t dfs_state;
2273 	mlan_ds_11h_chan_dfs_state ch_dfs_state[4];
2274 	t_u8 n_chan;
2275 	int i = 0;
2276 	ENTER();
2277 
2278 	/* Sanity check */
2279 	if (req->ifr_data == NULL) {
2280 		PRINTM(MERROR, "skip_dfs_cac() corrupt data\n");
2281 		ret = -EFAULT;
2282 		goto done;
2283 	}
2284 	memset(&param, 0, sizeof(skip_cac_para));
2285 	/* Get user data */
2286 	if (copy_from_user(&param, req->ifr_data, sizeof(skip_cac_para))) {
2287 		PRINTM(MERROR, "Copy from user failed\n");
2288 		ret = -EFAULT;
2289 		goto done;
2290 	}
2291 	if (param.skip_cac)
2292 		dfs_state = DFS_AVAILABLE;
2293 	else
2294 		dfs_state = DFS_USABLE;
2295 	memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
2296 	n_chan = woal_uap_get_dfs_chan(param.channel, param.bw,
2297 				       &ch_dfs_state[0]);
2298 	for (i = 0; i < n_chan; i++) {
2299 		if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
2300 					    &ch_dfs_state[i]))
2301 			PRINTM(MERROR, "Get DFS state for chan:%d failed\n",
2302 			       ch_dfs_state[i].channel);
2303 	}
2304 	for (i = 0; i < n_chan; i++) {
2305 		if (param.skip_cac && ch_dfs_state[i].dfs_state == DFS_USABLE)
2306 			PRINTM(MMSG,
2307 			       "DFS: Requst skip cac on the channel %d which hasn't do CAC before!\n",
2308 			       ch_dfs_state[i].channel);
2309 		ch_dfs_state[i].dfs_state = dfs_state;
2310 		if (woal_11h_chan_dfs_state(priv, MLAN_ACT_SET,
2311 					    &ch_dfs_state[i]))
2312 			PRINTM(MERROR, "Set DFS state for chan:%d failed\n",
2313 			       ch_dfs_state[i].channel);
2314 		else
2315 			PRINTM(MCMND, "DFS: Skip CAC on chan %d %d\n",
2316 			       ch_dfs_state[i].channel, param.skip_cac);
2317 	}
2318 #ifdef UAP_CFG80211
2319 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2320 	if (IS_UAP_CFG80211(cfg80211_wext)) {
2321 		for (i = 0; i < n_chan; i++) {
2322 			if (param.skip_cac)
2323 				woal_update_channel_dfs_state(
2324 					ch_dfs_state[i].channel, DFS_AVAILABLE);
2325 			else
2326 				woal_update_channel_dfs_state(
2327 					ch_dfs_state[i].channel, DFS_USABLE);
2328 		}
2329 	}
2330 #endif
2331 #endif
2332 done:
2333 	LEAVE();
2334 	return ret;
2335 }
2336 
2337 /**
2338  * @brief Get DFS_REPEATER mode
2339  *
2340  *  @param dev      A pointer to net_device structure
2341  *  @param req      A pointer to ifreq structure
2342  *
2343  * @return           0 --success, otherwise fail
2344  */
woal_uap_cac_timer_status(struct net_device * dev,struct ifreq * req)2345 static int woal_uap_cac_timer_status(struct net_device *dev, struct ifreq *req)
2346 {
2347 	moal_private *priv = (moal_private *)netdev_priv(dev);
2348 	int ret = 0;
2349 	cac_timer_status param;
2350 	mlan_status status = MLAN_STATUS_SUCCESS;
2351 
2352 	ENTER();
2353 
2354 	/* Sanity check */
2355 	if (req->ifr_data == NULL) {
2356 		PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
2357 		ret = -EFAULT;
2358 		goto done;
2359 	}
2360 
2361 	memset(&param, 0, sizeof(cac_timer_status));
2362 
2363 	/* Get user data */
2364 	if (copy_from_user(&param, req->ifr_data, sizeof(cac_timer_status))) {
2365 		PRINTM(MERROR, "Copy from user failed\n");
2366 		ret = -EFAULT;
2367 		goto done;
2368 	}
2369 
2370 	/* Currently default action is get */
2371 	param.mode = 0;
2372 
2373 	if (priv->phandle->cac_period == MTRUE) {
2374 		long cac_left_jiffies;
2375 
2376 		cac_left_jiffies =
2377 			MEAS_REPORT_TIME -
2378 			(jiffies - priv->phandle->meas_start_jiffies);
2379 
2380 		/* cac_left_jiffies would be negative if timer has already
2381 		 * elapsed. positive if timer is still yet to lapsed
2382 		 */
2383 		if (cac_left_jiffies > 0)
2384 			param.mode = (t_u32)cac_left_jiffies / HZ;
2385 	}
2386 
2387 	if (copy_to_user(req->ifr_data, &param, sizeof(cac_timer_status))) {
2388 		PRINTM(MERROR, "Copy to user failed\n");
2389 		ret = -EFAULT;
2390 	}
2391 done:
2392 	if (status != MLAN_STATUS_PENDING)
2393 		LEAVE();
2394 	return ret;
2395 }
2396 
2397 /**
2398  * @brief set/get uap operation control
2399  *
2400  *  @param dev      A pointer to net_device structure
2401  *  @param req      A pointer to ifreq structure
2402  *
2403  * @return           0 --success, otherwise fail
2404  */
woal_uap_operation_ctrl(struct net_device * dev,struct ifreq * req)2405 static int woal_uap_operation_ctrl(struct net_device *dev, struct ifreq *req)
2406 {
2407 	int ret = 0;
2408 	moal_private *priv = (moal_private *)netdev_priv(dev);
2409 	mlan_uap_oper_ctrl uap_oper;
2410 	uap_oper_para_hdr param;
2411 	mlan_ds_bss *bss = NULL;
2412 	mlan_ioctl_req *ioctl_req = NULL;
2413 	mlan_status status = MLAN_STATUS_SUCCESS;
2414 
2415 	ENTER();
2416 
2417 	memset(&param, 0, sizeof(uap_oper_para_hdr));
2418 	memset(&uap_oper, 0, sizeof(mlan_uap_oper_ctrl));
2419 
2420 	/* Sanity check */
2421 	if (req->ifr_data == NULL) {
2422 		PRINTM(MERROR, "woal_uap_operation_ctrl corrupt data\n");
2423 		ret = -EFAULT;
2424 		goto done;
2425 	}
2426 	if (copy_from_user(&param, req->ifr_data, sizeof(uap_oper_para_hdr))) {
2427 		PRINTM(MERROR, "Copy from user failed\n");
2428 		ret = -EFAULT;
2429 		goto done;
2430 	}
2431 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2432 	if (ioctl_req == NULL) {
2433 		ret = MLAN_STATUS_FAILURE;
2434 		goto done;
2435 	}
2436 
2437 	bss = (mlan_ds_bss *)ioctl_req->pbuf;
2438 	bss->sub_command = MLAN_OID_UAP_OPER_CTRL;
2439 	ioctl_req->req_id = MLAN_IOCTL_BSS;
2440 	if (copy_from_user(&uap_oper, req->ifr_data + sizeof(uap_oper_para_hdr),
2441 			   sizeof(mlan_uap_oper_ctrl))) {
2442 		PRINTM(MERROR, "Copy from user failed\n");
2443 		ret = -EFAULT;
2444 		goto done;
2445 	}
2446 	if (!param.action) {
2447 		/* Get uap operation control parameters from FW */
2448 		ioctl_req->action = MLAN_ACT_GET;
2449 	} else {
2450 		/* Set uap operation control configurations */
2451 		ioctl_req->action = MLAN_ACT_SET;
2452 		bss->param.ap_oper_ctrl.ctrl_value = uap_oper.ctrl_value;
2453 		if (uap_oper.ctrl_value == 2)
2454 			bss->param.ap_oper_ctrl.chan_opt = uap_oper.chan_opt;
2455 		if (uap_oper.chan_opt == 3) {
2456 			bss->param.ap_oper_ctrl.band_cfg = uap_oper.band_cfg;
2457 			bss->param.ap_oper_ctrl.channel = uap_oper.channel;
2458 		}
2459 	}
2460 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2461 	if (status != MLAN_STATUS_SUCCESS) {
2462 		ret = -EFAULT;
2463 		goto done;
2464 	}
2465 
2466 	/* Copy to user */
2467 	if (copy_to_user(req->ifr_data + sizeof(uap_oper_para_hdr),
2468 			 &bss->param.ap_oper_ctrl,
2469 			 sizeof(mlan_uap_oper_ctrl))) {
2470 		PRINTM(MERROR, "Copy to user failed!\n");
2471 		ret = -EFAULT;
2472 		goto done;
2473 	}
2474 done:
2475 	if (status != MLAN_STATUS_PENDING)
2476 		kfree(ioctl_req);
2477 	LEAVE();
2478 	return ret;
2479 }
2480 
2481 /**
2482  *  @brief uap ioctl handler
2483  *
2484  *  @param dev      A pointer to net_device structure
2485  *  @param req      A pointer to ifreq structure
2486  *  @return         0 --success, otherwise fail
2487  */
woal_uap_ioctl(struct net_device * dev,struct ifreq * req)2488 static int woal_uap_ioctl(struct net_device *dev, struct ifreq *req)
2489 {
2490 	int ret = 0;
2491 	t_u32 subcmd = 0;
2492 	ENTER();
2493 	/* Sanity check */
2494 	if (req->ifr_data == NULL) {
2495 		PRINTM(MERROR, "uap_ioctl() corrupt data\n");
2496 		ret = -EFAULT;
2497 		goto done;
2498 	}
2499 	if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) {
2500 		PRINTM(MERROR, "Copy from user failed\n");
2501 		ret = -EFAULT;
2502 		goto done;
2503 	}
2504 
2505 	PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int)subcmd);
2506 	switch (subcmd) {
2507 	case UAP_ADDBA_PARA:
2508 		ret = woal_uap_addba_param(dev, req);
2509 		break;
2510 	case UAP_AGGR_PRIOTBL:
2511 		ret = woal_uap_aggr_priotbl(dev, req);
2512 		break;
2513 	case UAP_ADDBA_REJECT:
2514 		ret = woal_uap_addba_reject(dev, req);
2515 		break;
2516 	case UAP_FW_INFO:
2517 		ret = woal_uap_get_fw_info(dev, req);
2518 		break;
2519 	case UAP_DEEP_SLEEP:
2520 		ret = woal_uap_deep_sleep(dev, req);
2521 		break;
2522 	case UAP_TX_DATA_PAUSE:
2523 		ret = woal_uap_txdatapause(dev, req);
2524 		break;
2525 #ifdef SDIO
2526 	case UAP_SDCMD52_RW:
2527 		ret = woal_uap_sdcmd52_rw(dev, req);
2528 		break;
2529 #endif
2530 	case UAP_SNMP_MIB:
2531 		ret = woal_uap_snmp_mib(dev, req);
2532 		break;
2533 	case UAP_DFS_TESTING:
2534 		ret = woal_uap_dfs_testing(dev, req);
2535 		break;
2536 	case UAP_CHAN_SWITCH_COUNT_CFG:
2537 		ret = woal_uap_chan_switch_count_cfg(dev, req);
2538 		break;
2539 	case UAP_DOMAIN_INFO:
2540 		ret = woal_uap_domain_info(dev, req);
2541 		break;
2542 	case UAP_TX_BF_CFG:
2543 		ret = woal_uap_tx_bf_cfg(dev, req);
2544 		break;
2545 	case UAP_HT_TX_CFG:
2546 		ret = woal_uap_ht_tx_cfg(dev, req);
2547 		break;
2548 	case UAP_VHT_CFG:
2549 		ret = woal_uap_vht_cfg(dev, req);
2550 		break;
2551 	case UAP_HS_CFG:
2552 		ret = woal_uap_hs_cfg(dev, req, MTRUE);
2553 		break;
2554 	case UAP_HS_SET_PARA:
2555 		ret = woal_uap_hs_set_para(dev, req);
2556 		break;
2557 	case UAP_MGMT_FRAME_CONTROL:
2558 		ret = woal_uap_mgmt_frame_control(dev, req);
2559 		break;
2560 	case UAP_TX_RATE_CFG:
2561 		ret = woal_uap_tx_rate_cfg(dev, req);
2562 		break;
2563 	case UAP_ANTENNA_CFG:
2564 		ret = woal_uap_antenna_cfg(dev, req);
2565 		break;
2566 	case UAP_HT_STREAM_CFG:
2567 		ret = woal_uap_htstream_cfg(dev, req);
2568 		break;
2569 	case UAP_DFS_REPEATER_MODE:
2570 		ret = woal_uap_dfs_repeater(dev, req);
2571 		break;
2572 	case UAP_CAC_TIMER_STATUS:
2573 		ret = woal_uap_cac_timer_status(dev, req);
2574 		break;
2575 	case UAP_SKIP_CAC:
2576 		ret = woal_uap_skip_cac(dev, req);
2577 		break;
2578 	case UAP_OPERATION_CTRL:
2579 		ret = woal_uap_operation_ctrl(dev, req);
2580 		break;
2581 	case UAP_BAND_STEER:
2582 		ret = woal_uap_band_steer(dev, req);
2583 		break;
2584 	case UAP_BEACON_STUCK_DETECT:
2585 		ret = woal_uap_beacon_stuck(dev, req);
2586 		break;
2587 	default:
2588 		break;
2589 	}
2590 done:
2591 	LEAVE();
2592 	return ret;
2593 }
2594 
2595 /**
2596  *  @brief uap station deauth ioctl handler
2597  *
2598  *  @param dev      A pointer to net_device structure
2599  *  @param req      A pointer to ifreq structure
2600  *  @return         0 --success, otherwise fail
2601  */
woal_uap_sta_deauth_ioctl(struct net_device * dev,struct ifreq * req)2602 static int woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req)
2603 {
2604 	moal_private *priv = (moal_private *)netdev_priv(dev);
2605 	mlan_ioctl_req *ioctl_req = NULL;
2606 	mlan_ds_bss *bss = NULL;
2607 	mlan_deauth_param deauth_param;
2608 	int ret = 0;
2609 	mlan_status status = MLAN_STATUS_SUCCESS;
2610 
2611 	ENTER();
2612 
2613 	memset(&deauth_param, 0, sizeof(mlan_deauth_param));
2614 	/* Sanity check */
2615 	if (req->ifr_data == NULL) {
2616 		PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n");
2617 		ret = -EFAULT;
2618 		goto done;
2619 	}
2620 	if (copy_from_user(&deauth_param, req->ifr_data,
2621 			   sizeof(mlan_deauth_param))) {
2622 		PRINTM(MERROR, "Copy from user failed\n");
2623 		ret = -EFAULT;
2624 		goto done;
2625 	}
2626 
2627 	PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
2628 	       MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);
2629 
2630 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2631 	if (ioctl_req == NULL) {
2632 		ret = -ENOMEM;
2633 		goto done;
2634 	}
2635 	bss = (mlan_ds_bss *)ioctl_req->pbuf;
2636 
2637 	bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
2638 	ioctl_req->req_id = MLAN_IOCTL_BSS;
2639 	ioctl_req->action = MLAN_ACT_SET;
2640 
2641 	moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
2642 			sizeof(mlan_deauth_param),
2643 			sizeof(bss->param.deauth_param));
2644 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2645 	if (status != MLAN_STATUS_SUCCESS) {
2646 		ret = -EFAULT;
2647 		if (copy_to_user(req->ifr_data, &ioctl_req->status_code,
2648 				 sizeof(t_u32)))
2649 			PRINTM(MERROR, "Copy to user failed!\n");
2650 		goto done;
2651 	}
2652 
2653 done:
2654 	if (status != MLAN_STATUS_PENDING)
2655 		kfree(ioctl_req);
2656 	LEAVE();
2657 	return ret;
2658 }
2659 
2660 /**
2661  * @brief Set/Get radio
2662  *
2663  *  @param dev      A pointer to net_device structure
2664  *  @param req      A pointer to ifreq structure
2665  *
2666  * @return           0 --success, otherwise fail
2667  */
woal_uap_radio_ctl(struct net_device * dev,struct ifreq * req)2668 static int woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req)
2669 {
2670 	moal_private *priv = (moal_private *)netdev_priv(dev);
2671 	int ret = 0;
2672 	mlan_ds_radio_cfg *radio = NULL;
2673 	mlan_ioctl_req *mreq = NULL;
2674 	int data[2] = {0, 0};
2675 	mlan_bss_info bss_info;
2676 	mlan_status status = MLAN_STATUS_SUCCESS;
2677 
2678 	ENTER();
2679 
2680 	/* Sanity check */
2681 	if (req->ifr_data == NULL) {
2682 		PRINTM(MERROR, "uap_radio_ctl() corrupt data\n");
2683 		ret = -EFAULT;
2684 		goto done;
2685 	}
2686 
2687 	/* Get user data */
2688 	if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
2689 		PRINTM(MERROR, "Copy from user failed\n");
2690 		ret = -EFAULT;
2691 		goto done;
2692 	}
2693 
2694 	if (data[0]) {
2695 		mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
2696 		if (mreq == NULL) {
2697 			ret = -ENOMEM;
2698 			goto done;
2699 		}
2700 		radio = (mlan_ds_radio_cfg *)mreq->pbuf;
2701 		radio->sub_command = MLAN_OID_RADIO_CTRL;
2702 		mreq->req_id = MLAN_IOCTL_RADIO_CFG;
2703 		mreq->action = MLAN_ACT_SET;
2704 		radio->param.radio_on_off = (t_u32)data[1];
2705 		status = woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT);
2706 		if (status != MLAN_STATUS_SUCCESS)
2707 			ret = -EFAULT;
2708 		if (status != MLAN_STATUS_PENDING)
2709 			kfree(mreq);
2710 	} else {
2711 		/* Get radio status */
2712 		memset(&bss_info, 0, sizeof(bss_info));
2713 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2714 
2715 		data[1] = bss_info.radio_on;
2716 		if (copy_to_user(req->ifr_data, data, sizeof(data))) {
2717 			PRINTM(MERROR, "Copy to user failed\n");
2718 			ret = -EFAULT;
2719 		}
2720 	}
2721 done:
2722 	LEAVE();
2723 	return ret;
2724 }
2725 
2726 /**
2727  *  @brief uap bss control ioctl handler
2728  *
2729  *  @param dev      A pointer to net_device structure
2730  *  @param req      A pointer to ifreq structure
2731  *  @return         0 --success, otherwise fail
2732  */
woal_uap_bss_ctrl_ioctl(struct net_device * dev,struct ifreq * req)2733 static int woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req)
2734 {
2735 	moal_private *priv = (moal_private *)netdev_priv(dev);
2736 	int ret = 0, data = 0;
2737 
2738 	ENTER();
2739 
2740 	/* Sanity check */
2741 	if (req->ifr_data == NULL) {
2742 		PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n");
2743 		ret = -EFAULT;
2744 		goto done;
2745 	}
2746 	if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
2747 		PRINTM(MERROR, "Copy from user failed\n");
2748 		ret = -EFAULT;
2749 		goto done;
2750 	}
2751 
2752 	ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data);
2753 
2754 done:
2755 	LEAVE();
2756 	return ret;
2757 }
2758 
2759 /**
2760  *  @brief uap report mic error ioctl handler
2761  *
2762  *  @param dev      A pointer to net_device structure
2763  *  @param req      A pointer to ifreq structure
2764  *  @return         0 --success, otherwise fail
2765  */
woal_uap_report_mic_ioctl(struct net_device * dev,struct ifreq * req)2766 static int woal_uap_report_mic_ioctl(struct net_device *dev, struct ifreq *req)
2767 {
2768 	moal_private *priv = (moal_private *)netdev_priv(dev);
2769 	mlan_ioctl_req *ioctl_req = NULL;
2770 	mlan_ds_sec_cfg *sec = NULL;
2771 	t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
2772 	int ret = 0;
2773 	mlan_status status = MLAN_STATUS_SUCCESS;
2774 
2775 	ENTER();
2776 
2777 	memset(mac_addr, 0, MLAN_MAC_ADDR_LENGTH);
2778 	/* Sanity check */
2779 	if (req->ifr_data == NULL) {
2780 		PRINTM(MERROR, "uap_report_mic_ioctl() corrupt data\n");
2781 		ret = -EFAULT;
2782 		goto done;
2783 	}
2784 	if (copy_from_user(mac_addr, req->ifr_data, MLAN_MAC_ADDR_LENGTH)) {
2785 		PRINTM(MERROR, "Copy from user failed\n");
2786 		ret = -EFAULT;
2787 		goto done;
2788 	}
2789 
2790 	PRINTM(MINFO, "ioctl report mic err station: " MACSTR "\n",
2791 	       MAC2STR(mac_addr));
2792 
2793 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2794 	if (ioctl_req == NULL) {
2795 		ret = -ENOMEM;
2796 		goto done;
2797 	}
2798 
2799 	sec = (mlan_ds_sec_cfg *)ioctl_req->pbuf;
2800 	sec->sub_command = MLAN_OID_SEC_CFG_REPORT_MIC_ERR;
2801 	ioctl_req->req_id = MLAN_IOCTL_SEC_CFG;
2802 	ioctl_req->action = MLAN_ACT_SET;
2803 	moal_memcpy_ext(priv->phandle, sec->param.sta_mac, mac_addr,
2804 			MLAN_MAC_ADDR_LENGTH, sizeof(sec->param.sta_mac));
2805 
2806 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2807 	if (status != MLAN_STATUS_SUCCESS) {
2808 		ret = -EFAULT;
2809 		goto done;
2810 	}
2811 
2812 done:
2813 	if (status != MLAN_STATUS_PENDING)
2814 		kfree(ioctl_req);
2815 	LEAVE();
2816 	return ret;
2817 }
2818 
2819 /**
2820  *  @brief uap set key ioctl handler
2821  *
2822  *  @param dev      A pointer to net_device structure
2823  *  @param req      A pointer to ifreq structure
2824  *  @return         0 --success, otherwise fail
2825  */
woal_uap_set_key_ioctl(struct net_device * dev,struct ifreq * req)2826 static int woal_uap_set_key_ioctl(struct net_device *dev, struct ifreq *req)
2827 {
2828 	moal_private *priv = (moal_private *)netdev_priv(dev);
2829 	mlan_ioctl_req *ioctl_req = NULL;
2830 	mlan_ds_sec_cfg *sec = NULL;
2831 	encrypt_key key;
2832 	int ret = 0;
2833 	t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2834 	mlan_status status = MLAN_STATUS_SUCCESS;
2835 
2836 	ENTER();
2837 
2838 	memset(&key, 0, sizeof(encrypt_key));
2839 	/* Sanity check */
2840 	if (req->ifr_data == NULL) {
2841 		PRINTM(MERROR, "uap_set_key_ioctl() corrupt data\n");
2842 		ret = -EFAULT;
2843 		goto done;
2844 	}
2845 	if (copy_from_user(&key, req->ifr_data, sizeof(encrypt_key))) {
2846 		PRINTM(MERROR, "Copy from user failed\n");
2847 		ret = -EFAULT;
2848 		goto done;
2849 	}
2850 
2851 	PRINTM(MIOCTL,
2852 	       "ioctl report set key: " MACSTR " key_index=%d, key_len=%d \n",
2853 	       MAC2STR(key.mac_addr), (int)key.key_index, (int)key.key_len);
2854 
2855 	if ((key.key_len > MLAN_MAX_KEY_LENGTH) || (key.key_index > 3)) {
2856 		ret = -EINVAL;
2857 		goto done;
2858 	}
2859 
2860 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2861 	if (ioctl_req == NULL) {
2862 		ret = -ENOMEM;
2863 		goto done;
2864 	}
2865 
2866 	sec = (mlan_ds_sec_cfg *)ioctl_req->pbuf;
2867 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY,
2868 	ioctl_req->req_id = MLAN_IOCTL_SEC_CFG;
2869 	ioctl_req->action = MLAN_ACT_SET;
2870 
2871 	moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
2872 			key.mac_addr, MLAN_MAC_ADDR_LENGTH,
2873 			sizeof(sec->param.encrypt_key.mac_addr));
2874 	sec->param.encrypt_key.key_index = key.key_index;
2875 	sec->param.encrypt_key.key_len = key.key_len;
2876 	moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.key_material,
2877 			key.key_material, key.key_len,
2878 			sizeof(sec->param.encrypt_key.key_material));
2879 	if (0 == memcmp(sec->param.encrypt_key.mac_addr, bcast_addr, ETH_ALEN))
2880 		sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
2881 	else
2882 		sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
2883 
2884 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2885 	if (status != MLAN_STATUS_SUCCESS) {
2886 		ret = -EFAULT;
2887 		goto done;
2888 	}
2889 done:
2890 	if (status != MLAN_STATUS_PENDING)
2891 		kfree(ioctl_req);
2892 	LEAVE();
2893 	return ret;
2894 }
2895 
2896 /**
2897  *  @brief Set/Get uap power mode
2898  *
2899  *  @param priv                 A pointer to moal_private structure
2900  *  @param action               Action set or get
2901  *  @param ps_mgmt              A pointer to mlan_ds_ps_mgmt structure
2902  *
2903  *  @return                     MLAN_STATUS_SUCCESS -- success, otherwise fail
2904  */
woal_set_get_uap_power_mode(moal_private * priv,t_u32 action,mlan_ds_ps_mgmt * ps_mgmt)2905 mlan_status woal_set_get_uap_power_mode(moal_private *priv, t_u32 action,
2906 					mlan_ds_ps_mgmt *ps_mgmt)
2907 {
2908 	mlan_ioctl_req *ioctl_req = NULL;
2909 	mlan_ds_pm_cfg *pm_cfg = NULL;
2910 	mlan_status status = MLAN_STATUS_SUCCESS;
2911 
2912 	ENTER();
2913 	if (!ps_mgmt) {
2914 		LEAVE();
2915 		return MLAN_STATUS_FAILURE;
2916 	}
2917 
2918 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
2919 	if (ioctl_req == NULL) {
2920 		LEAVE();
2921 		return MLAN_STATUS_FAILURE;
2922 	}
2923 	pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
2924 	pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
2925 	ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
2926 	ioctl_req->action = action;
2927 	if (action == MLAN_ACT_SET)
2928 		moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_mgmt, ps_mgmt,
2929 				sizeof(mlan_ds_ps_mgmt),
2930 				sizeof(pm_cfg->param.ps_mgmt));
2931 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2932 	if (status == MLAN_STATUS_SUCCESS) {
2933 		if (action == MLAN_ACT_GET)
2934 			moal_memcpy_ext(priv->phandle, ps_mgmt,
2935 					&pm_cfg->param.ps_mgmt,
2936 					sizeof(mlan_ds_ps_mgmt),
2937 					sizeof(mlan_ds_ps_mgmt));
2938 	}
2939 	if (status != MLAN_STATUS_PENDING)
2940 		kfree(ioctl_req);
2941 	LEAVE();
2942 	return status;
2943 }
2944 
2945 /**
2946  *  @brief uap power mode ioctl handler
2947  *
2948  *  @param dev      A pointer to net_device structure
2949  *  @param req      A pointer to ifreq structure
2950  *  @return         0 --success, otherwise fail
2951  */
woal_uap_power_mode_ioctl(struct net_device * dev,struct ifreq * req)2952 static int woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
2953 {
2954 	moal_private *priv = (moal_private *)netdev_priv(dev);
2955 	mlan_ioctl_req *ioctl_req = NULL;
2956 	mlan_ds_pm_cfg *pm_cfg = NULL;
2957 	mlan_ds_ps_mgmt ps_mgmt;
2958 	int ret = 0;
2959 	mlan_status status = MLAN_STATUS_SUCCESS;
2960 
2961 	ENTER();
2962 
2963 	memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt));
2964 
2965 	/* Sanity check */
2966 	if (req->ifr_data == NULL) {
2967 		PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n");
2968 		ret = -EFAULT;
2969 		goto done;
2970 	}
2971 	if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) {
2972 		PRINTM(MERROR, "Copy from user failed\n");
2973 		ret = -EFAULT;
2974 		goto done;
2975 	}
2976 	if (priv->bss_type != MLAN_BSS_TYPE_UAP) {
2977 		PRINTM(MERROR, "Invlaid BSS_TYPE for UAP power mode command\n");
2978 		ret = -EFAULT;
2979 		goto done;
2980 	}
2981 	PRINTM(MIOCTL,
2982 	       "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
2983 	       "inact_to=%d min_awake=%d max_awake=%d\n",
2984 	       ps_mgmt.flags, (int)ps_mgmt.ps_mode,
2985 	       (int)ps_mgmt.sleep_param.ctrl_bitmap,
2986 	       (int)ps_mgmt.sleep_param.min_sleep,
2987 	       (int)ps_mgmt.sleep_param.max_sleep,
2988 	       (int)ps_mgmt.inact_param.inactivity_to,
2989 	       (int)ps_mgmt.inact_param.min_awake,
2990 	       (int)ps_mgmt.inact_param.max_awake);
2991 
2992 	if (ps_mgmt.flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
2993 			      PS_FLAG_INACT_SLEEP_PARAM)) {
2994 		PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n",
2995 		       ps_mgmt.flags);
2996 		ret = -EINVAL;
2997 		goto done;
2998 	}
2999 
3000 	if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) {
3001 		PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n",
3002 		       (int)ps_mgmt.flags);
3003 		ret = -EINVAL;
3004 		goto done;
3005 	}
3006 
3007 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
3008 	if (ioctl_req == NULL) {
3009 		ret = -ENOMEM;
3010 		goto done;
3011 	}
3012 	pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
3013 	pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
3014 	ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
3015 	if (ps_mgmt.flags) {
3016 		ioctl_req->action = MLAN_ACT_SET;
3017 		moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_mgmt, &ps_mgmt,
3018 				sizeof(mlan_ds_ps_mgmt),
3019 				sizeof(pm_cfg->param.ps_mgmt));
3020 	} else {
3021 		ioctl_req->action = MLAN_ACT_GET;
3022 	}
3023 
3024 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
3025 	if (status != MLAN_STATUS_SUCCESS) {
3026 		ret = -EFAULT;
3027 		if (copy_to_user(req->ifr_data, &ioctl_req->status_code,
3028 				 sizeof(t_u32)))
3029 			PRINTM(MERROR, "Copy to user failed!\n");
3030 		goto done;
3031 	}
3032 	if (!ps_mgmt.flags) {
3033 		/* Copy to user */
3034 		if (copy_to_user(req->ifr_data, &pm_cfg->param.ps_mgmt,
3035 				 sizeof(mlan_ds_ps_mgmt))) {
3036 			PRINTM(MERROR, "Copy to user failed!\n");
3037 			ret = -EFAULT;
3038 			goto done;
3039 		}
3040 	}
3041 done:
3042 	if (status != MLAN_STATUS_PENDING)
3043 		kfree(ioctl_req);
3044 	LEAVE();
3045 	return ret;
3046 }
3047 
3048 /**
3049  *  @brief uap BSS config ioctl handler
3050  *
3051  *  @param dev      A pointer to net_device structure
3052  *  @param req      A pointer to ifreq structure
3053  *  @return         0 --success, otherwise fail
3054  */
woal_uap_bss_cfg_ioctl(struct net_device * dev,struct ifreq * req)3055 static int woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req)
3056 {
3057 	moal_private *priv = (moal_private *)netdev_priv(dev);
3058 	int ret = 0;
3059 	mlan_ds_bss *bss = NULL;
3060 	mlan_ioctl_req *ioctl_req = NULL;
3061 	int offset = 0;
3062 	t_u32 action = 0;
3063 	mlan_status status = MLAN_STATUS_SUCCESS;
3064 
3065 	ENTER();
3066 
3067 	/* Sanity check */
3068 	if (req->ifr_data == NULL) {
3069 		PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n");
3070 		ret = -EFAULT;
3071 		goto done;
3072 	}
3073 
3074 	/* Get action */
3075 	if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) {
3076 		PRINTM(MERROR, "Copy from user failed\n");
3077 		ret = -EFAULT;
3078 		goto done;
3079 	}
3080 	offset += sizeof(action);
3081 
3082 	/* Allocate an IOCTL request buffer */
3083 	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
3084 		sizeof(mlan_ds_bss));
3085 	if (ioctl_req == NULL) {
3086 		ret = -ENOMEM;
3087 		goto done;
3088 	}
3089 
3090 	bss = (mlan_ds_bss *)ioctl_req->pbuf;
3091 	bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
3092 	ioctl_req->req_id = MLAN_IOCTL_BSS;
3093 	if (action == 1)
3094 		ioctl_req->action = MLAN_ACT_SET;
3095 	else
3096 		ioctl_req->action = MLAN_ACT_GET;
3097 
3098 	if (ioctl_req->action == MLAN_ACT_SET) {
3099 		/* Get the BSS config from user */
3100 		if (copy_from_user(&bss->param.bss_config,
3101 				   req->ifr_data + offset,
3102 				   sizeof(mlan_uap_bss_param))) {
3103 			PRINTM(MERROR, "Copy from user failed\n");
3104 			ret = -EFAULT;
3105 			goto done;
3106 		}
3107 	}
3108 
3109 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
3110 	if (status != MLAN_STATUS_SUCCESS) {
3111 		ret = -EFAULT;
3112 		goto done;
3113 	}
3114 
3115 	if (ioctl_req->action == MLAN_ACT_GET) {
3116 		offset = sizeof(action);
3117 
3118 		/* Copy to user : BSS config */
3119 		if (copy_to_user(req->ifr_data + offset, &bss->param.bss_config,
3120 				 sizeof(mlan_uap_bss_param))) {
3121 			PRINTM(MERROR, "Copy to user failed!\n");
3122 			ret = -EFAULT;
3123 			goto done;
3124 		}
3125 	}
3126 done:
3127 	if (status != MLAN_STATUS_PENDING)
3128 		kfree(ioctl_req);
3129 	LEAVE();
3130 	return ret;
3131 }
3132 
3133 /**
3134  *  @brief uap get station list handler
3135  *
3136  *  @param dev      A pointer to net_device structure
3137  *  @param req      A pointer to ifreq structure
3138  *  @return         0 --success, otherwise fail
3139  */
woal_uap_get_sta_list_ioctl(struct net_device * dev,struct ifreq * req)3140 static int woal_uap_get_sta_list_ioctl(struct net_device *dev,
3141 				       struct ifreq *req)
3142 {
3143 	moal_private *priv = (moal_private *)netdev_priv(dev);
3144 	int ret = 0;
3145 	mlan_ds_get_info *info = NULL;
3146 	mlan_ioctl_req *ioctl_req = NULL;
3147 	mlan_status status = MLAN_STATUS_SUCCESS;
3148 
3149 	ENTER();
3150 
3151 	/* Sanity check */
3152 	if (req->ifr_data == NULL) {
3153 		PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n");
3154 		ret = -EFAULT;
3155 		goto done;
3156 	}
3157 
3158 	/* Allocate an IOCTL request buffer */
3159 	ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
3160 		sizeof(mlan_ds_get_info));
3161 	if (ioctl_req == NULL) {
3162 		ret = -ENOMEM;
3163 		goto done;
3164 	}
3165 
3166 	info = (mlan_ds_get_info *)ioctl_req->pbuf;
3167 	info->sub_command = MLAN_OID_UAP_STA_LIST;
3168 	ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
3169 	ioctl_req->action = MLAN_ACT_GET;
3170 
3171 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
3172 	if (status != MLAN_STATUS_SUCCESS) {
3173 		ret = -EFAULT;
3174 		goto done;
3175 	}
3176 
3177 	if (ioctl_req->action == MLAN_ACT_GET) {
3178 		/* Copy to user : sta_list */
3179 		if (copy_to_user(req->ifr_data, &info->param.sta_list,
3180 				 ioctl_req->data_read_written)) {
3181 			PRINTM(MERROR, "Copy to user failed!\n");
3182 			ret = -EFAULT;
3183 			goto done;
3184 		}
3185 	}
3186 done:
3187 	if (status != MLAN_STATUS_PENDING)
3188 		kfree(ioctl_req);
3189 	LEAVE();
3190 	return ret;
3191 }
3192 
3193 /**
3194  *  @brief uAP set WAPI key ioctl
3195  *
3196  *  @param priv      A pointer to moal_private structure
3197  *  @param msg       A pointer to wapi_msg structure
3198  *
3199  *  @return          0 --success, otherwise fail
3200  */
woal_uap_set_wapi_key_ioctl(moal_private * priv,wapi_msg * msg)3201 static int woal_uap_set_wapi_key_ioctl(moal_private *priv, wapi_msg *msg)
3202 {
3203 	mlan_ioctl_req *req = NULL;
3204 	mlan_ds_sec_cfg *sec = NULL;
3205 	int ret = 0;
3206 	wapi_key_msg *key_msg = NULL;
3207 	t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3208 	mlan_status status = MLAN_STATUS_SUCCESS;
3209 
3210 	ENTER();
3211 	if (msg->msg_len != sizeof(wapi_key_msg)) {
3212 		ret = -EINVAL;
3213 		goto done;
3214 	}
3215 	key_msg = (wapi_key_msg *)msg->msg;
3216 
3217 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
3218 	if (req == NULL) {
3219 		ret = -ENOMEM;
3220 		goto done;
3221 	}
3222 	sec = (mlan_ds_sec_cfg *)req->pbuf;
3223 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
3224 	req->req_id = MLAN_IOCTL_SEC_CFG;
3225 	req->action = MLAN_ACT_SET;
3226 
3227 	sec->param.encrypt_key.is_wapi_key = MTRUE;
3228 	sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH;
3229 	moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
3230 			key_msg->mac_addr, ETH_ALEN,
3231 			sizeof(sec->param.encrypt_key.mac_addr));
3232 	sec->param.encrypt_key.key_index = key_msg->key_id;
3233 	if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN))
3234 		sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
3235 	else
3236 		sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
3237 	moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.key_material,
3238 			key_msg->key, sec->param.encrypt_key.key_len,
3239 			sizeof(sec->param.encrypt_key.key_material));
3240 
3241 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3242 	if (status != MLAN_STATUS_SUCCESS)
3243 		ret = -EFAULT;
3244 done:
3245 	if (status != MLAN_STATUS_PENDING)
3246 		kfree(req);
3247 	LEAVE();
3248 	return ret;
3249 }
3250 
3251 /**
3252  *  @brief Enable/Disable wapi in firmware
3253  *
3254  *  @param priv          A pointer to moal_private structure
3255  *  @param enable        MTRUE/MFALSE
3256  *
3257  *  @return              MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
3258  * otherwise fail
3259  */
woal_enable_wapi(moal_private * priv,t_u8 enable)3260 static mlan_status woal_enable_wapi(moal_private *priv, t_u8 enable)
3261 {
3262 	mlan_ioctl_req *req = NULL;
3263 	mlan_ds_bss *bss = NULL;
3264 	mlan_status status;
3265 
3266 	ENTER();
3267 
3268 	/* Allocate an IOCTL request buffer */
3269 	req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
3270 	if (req == NULL) {
3271 		status = MLAN_STATUS_FAILURE;
3272 		goto done;
3273 	}
3274 
3275 	/* Fill request buffer */
3276 	bss = (mlan_ds_bss *)req->pbuf;
3277 	bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
3278 	req->req_id = MLAN_IOCTL_BSS;
3279 	req->action = MLAN_ACT_GET;
3280 
3281 	/* Send IOCTL request to MLAN */
3282 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3283 	if (status != MLAN_STATUS_SUCCESS) {
3284 		PRINTM(MERROR,
3285 		       "Get AP setting  failed! status=%d, error_code=0x%x\n",
3286 		       status, req->status_code);
3287 	}
3288 
3289 	/* Change AP default setting */
3290 	req->action = MLAN_ACT_SET;
3291 	if (enable == MFALSE) {
3292 		bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
3293 		bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY;
3294 	} else {
3295 		bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
3296 		bss->param.bss_config.protocol = PROTOCOL_WAPI;
3297 	}
3298 
3299 	/* Send IOCTL request to MLAN */
3300 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3301 	if (status != MLAN_STATUS_SUCCESS) {
3302 		PRINTM(MERROR,
3303 		       "Set AP setting failed! status=%d, error_code=0x%x\n",
3304 		       status, req->status_code);
3305 	}
3306 	if (enable) {
3307 		if (woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START))
3308 			PRINTM(MERROR, "%s: uap bss start failed \n", __func__);
3309 	}
3310 done:
3311 	if (status != MLAN_STATUS_PENDING)
3312 		kfree(req);
3313 	LEAVE();
3314 	return status;
3315 }
3316 
3317 /**
3318  *  @brief uAP set WAPI flag ioctl
3319  *
3320  *  @param priv      A pointer to moal_private structure
3321  *  @param msg       A pointer to wapi_msg structure
3322  *
3323  *  @return          0 --success, otherwise fail
3324  */
woal_uap_set_wapi_flag_ioctl(moal_private * priv,wapi_msg * msg)3325 static int woal_uap_set_wapi_flag_ioctl(moal_private *priv, wapi_msg *msg)
3326 {
3327 	t_u8 wapi_psk_ie[] = {0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14,
3328 			      0x72, 0x02, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
3329 			      0x00, 0x14, 0x72, 0x01, 0x00, 0x00};
3330 	t_u8 wapi_cert_ie[] = {0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14,
3331 			       0x72, 0x01, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
3332 			       0x00, 0x14, 0x72, 0x01, 0x00, 0x00};
3333 	mlan_ds_misc_cfg *misc = NULL;
3334 	mlan_ioctl_req *req = NULL;
3335 	int ret = 0;
3336 	mlan_status status = MLAN_STATUS_SUCCESS;
3337 
3338 	ENTER();
3339 
3340 	if (woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)) {
3341 		PRINTM(MERROR, "%s: uap bss stop failed \n", __func__);
3342 		ret = -EFAULT;
3343 		goto done;
3344 	}
3345 
3346 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3347 	if (req == NULL) {
3348 		ret = -ENOMEM;
3349 		goto done;
3350 	}
3351 	misc = (mlan_ds_misc_cfg *)req->pbuf;
3352 	misc->sub_command = MLAN_OID_MISC_GEN_IE;
3353 	req->req_id = MLAN_IOCTL_MISC_CFG;
3354 	req->action = MLAN_ACT_SET;
3355 
3356 	misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
3357 	misc->param.gen_ie.len = sizeof(wapi_psk_ie);
3358 	if (msg->msg[0] & WAPI_MODE_PSK) {
3359 		moal_memcpy_ext(priv->phandle, misc->param.gen_ie.ie_data,
3360 				wapi_psk_ie, misc->param.gen_ie.len,
3361 				sizeof(misc->param.gen_ie.ie_data));
3362 	} else if (msg->msg[0] & WAPI_MODE_CERT) {
3363 		moal_memcpy_ext(priv->phandle, misc->param.gen_ie.ie_data,
3364 				wapi_cert_ie, misc->param.gen_ie.len,
3365 				sizeof(misc->param.gen_ie.ie_data));
3366 	} else if (msg->msg[0] == 0) {
3367 		/* disable WAPI in driver */
3368 		if (MLAN_STATUS_SUCCESS !=
3369 		    woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0))
3370 			ret = -EFAULT;
3371 		woal_enable_wapi(priv, MFALSE);
3372 		goto done;
3373 	} else {
3374 		ret = -EINVAL;
3375 		goto done;
3376 	}
3377 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3378 	if (status != MLAN_STATUS_SUCCESS) {
3379 		ret = -EFAULT;
3380 		goto done;
3381 	}
3382 	woal_enable_wapi(priv, MTRUE);
3383 done:
3384 	if ((status != MLAN_STATUS_PENDING) && req)
3385 		kfree(req);
3386 	LEAVE();
3387 	return ret;
3388 }
3389 
3390 /**
3391  *  @brief set wapi ioctl function
3392  *
3393  *  @param dev      A pointer to net_device structure
3394  *  @param req      A pointer to ifreq structure
3395  *  @return         0 --success, otherwise fail
3396  */
woal_uap_set_wapi(struct net_device * dev,struct ifreq * req)3397 static int woal_uap_set_wapi(struct net_device *dev, struct ifreq *req)
3398 {
3399 	moal_private *priv = (moal_private *)netdev_priv(dev);
3400 	wapi_msg msg;
3401 	int ret = 0;
3402 
3403 	ENTER();
3404 
3405 	/* Sanity check */
3406 	if (req->ifr_data == NULL) {
3407 		PRINTM(MERROR, "uap_set_wapi() corrupt data\n");
3408 		ret = -EFAULT;
3409 		goto done;
3410 	}
3411 
3412 	memset(&msg, 0, sizeof(msg));
3413 
3414 	if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) {
3415 		PRINTM(MERROR, "Copy from user failed\n");
3416 		ret = -EFAULT;
3417 		goto done;
3418 	}
3419 
3420 	PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type,
3421 	       msg.msg_len);
3422 	DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg,
3423 		    MIN(msg.msg_len, sizeof(msg.msg)));
3424 
3425 	switch (msg.msg_type) {
3426 	case P80211_PACKET_WAPIFLAG:
3427 		ret = woal_uap_set_wapi_flag_ioctl(priv, &msg);
3428 		break;
3429 	case P80211_PACKET_SETKEY:
3430 		ret = woal_uap_set_wapi_key_ioctl(priv, &msg);
3431 		break;
3432 	default:
3433 		ret = -EOPNOTSUPP;
3434 		break;
3435 	}
3436 done:
3437 	LEAVE();
3438 	return ret;
3439 }
3440 
3441 /********************************************************
3442 		Global Functions
3443 ********************************************************/
3444 /**
3445  *  @brief Initialize the members of mlan_uap_bss_param
3446  *  which are uploaded from firmware
3447  *
3448  *  @param priv     A pointer to moal_private structure
3449  *  @param sys_cfg  A pointer to mlan_uap_bss_param structure
3450  *  @param wait_option      Wait option
3451  *
3452  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3453  */
woal_uap_get_bss_param(moal_private * priv,mlan_uap_bss_param * sys_cfg,t_u8 wait_option)3454 static mlan_status woal_uap_get_bss_param(moal_private *priv,
3455 					  mlan_uap_bss_param *sys_cfg,
3456 					  t_u8 wait_option)
3457 {
3458 	mlan_ds_bss *info = NULL;
3459 	mlan_ioctl_req *req = NULL;
3460 	mlan_status status = MLAN_STATUS_SUCCESS;
3461 
3462 	ENTER();
3463 
3464 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
3465 	if (req == NULL) {
3466 		LEAVE();
3467 		return MLAN_STATUS_FAILURE;
3468 	}
3469 
3470 	info = (mlan_ds_bss *)req->pbuf;
3471 	info->sub_command = MLAN_OID_UAP_BSS_CONFIG;
3472 	req->req_id = MLAN_IOCTL_BSS;
3473 	req->action = MLAN_ACT_GET;
3474 
3475 	status = woal_request_ioctl(priv, req, wait_option);
3476 	if (status != MLAN_STATUS_SUCCESS) {
3477 		PRINTM(MERROR, "Get bss info failed!\n");
3478 		status = MLAN_STATUS_FAILURE;
3479 		goto done;
3480 	}
3481 	moal_memcpy_ext(priv->phandle, sys_cfg, &info->param.bss_config,
3482 			sizeof(mlan_uap_bss_param), sizeof(mlan_uap_bss_param));
3483 
3484 done:
3485 	if (status != MLAN_STATUS_PENDING)
3486 		kfree(req);
3487 	LEAVE();
3488 	return status;
3489 }
3490 
3491 /**
3492  *  @brief  Set uap httxcfg
3493  *
3494  *  @param priv     A pointer to moal_private structure
3495  *  @param band_cfg Band cfg
3496  *  @param en       Enabled/Disabled
3497  *
3498  *  @return         0 --success, otherwise fail
3499  */
woal_set_uap_ht_tx_cfg(moal_private * priv,Band_Config_t bandcfg,t_u16 ht_cap,t_u8 en)3500 int woal_set_uap_ht_tx_cfg(moal_private *priv, Band_Config_t bandcfg,
3501 			   t_u16 ht_cap, t_u8 en)
3502 {
3503 	int ret = 0;
3504 	mlan_ds_11n_cfg *cfg_11n = NULL;
3505 	mlan_ioctl_req *ioctl_req = NULL;
3506 	mlan_status status = MLAN_STATUS_SUCCESS;
3507 
3508 	ENTER();
3509 
3510 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
3511 	if (ioctl_req == NULL) {
3512 		ret = -ENOMEM;
3513 		goto done;
3514 	}
3515 	cfg_11n = (mlan_ds_11n_cfg *)ioctl_req->pbuf;
3516 	cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
3517 	ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
3518 
3519 	/* Set HT Tx configurations */
3520 	if (bandcfg.chanBand == BAND_2GHZ) {
3521 		if (en)
3522 			cfg_11n->param.tx_cfg.httxcap = ht_cap;
3523 		else
3524 			cfg_11n->param.tx_cfg.httxcap = 0;
3525 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
3526 	} else if (bandcfg.chanBand == BAND_5GHZ) {
3527 		if (en)
3528 			cfg_11n->param.tx_cfg.httxcap = ht_cap;
3529 		else
3530 			cfg_11n->param.tx_cfg.httxcap = 0;
3531 		cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
3532 	}
3533 	PRINTM(MCMND, "SET: httxcap=0x%x band:0x%x\n",
3534 	       cfg_11n->param.tx_cfg.httxcap, cfg_11n->param.tx_cfg.misc_cfg);
3535 	/* Update 11n tx parameters in MLAN */
3536 	ioctl_req->action = MLAN_ACT_SET;
3537 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
3538 	if (status != MLAN_STATUS_SUCCESS) {
3539 		ret = -EFAULT;
3540 		goto done;
3541 	}
3542 done:
3543 	if (status != MLAN_STATUS_PENDING)
3544 		kfree(ioctl_req);
3545 	LEAVE();
3546 	return ret;
3547 }
3548 
3549 /**
3550  *  @brief Set 11n status based on the configured security mode
3551  *
3552  *  @param priv     A pointer to moal_private structure
3553  *  @param sys_cfg  A pointer to mlan_uap_bss_param structure
3554  *  @param action   MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
3555  *
3556  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3557  */
woal_uap_set_11n_status(moal_private * priv,mlan_uap_bss_param * sys_cfg,t_u8 action)3558 mlan_status woal_uap_set_11n_status(moal_private *priv,
3559 				    mlan_uap_bss_param *sys_cfg, t_u8 action)
3560 {
3561 	mlan_status status = MLAN_STATUS_SUCCESS;
3562 	mlan_fw_info fw_info;
3563 
3564 	ENTER();
3565 	memset(&fw_info, 0, sizeof(mlan_fw_info));
3566 	if (action == MLAN_ACT_DISABLE) {
3567 		if ((sys_cfg->supported_mcs_set[0] == 0) &&
3568 		    (sys_cfg->supported_mcs_set[4] == 0) &&
3569 		    (sys_cfg->supported_mcs_set[1] == 0)) {
3570 			goto done;
3571 		} else {
3572 			sys_cfg->supported_mcs_set[0] = 0;
3573 			sys_cfg->supported_mcs_set[4] = 0;
3574 			sys_cfg->supported_mcs_set[1] = 0;
3575 		}
3576 	}
3577 
3578 	if (action == MLAN_ACT_ENABLE) {
3579 		woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
3580 		sys_cfg->supported_mcs_set[0] = 0xFF;
3581 		if (sys_cfg->bandcfg.chan2Offset)
3582 			sys_cfg->supported_mcs_set[4] = 0x01;
3583 		else
3584 			sys_cfg->supported_mcs_set[4] = 0x0;
3585 		if (fw_info.usr_dev_mcs_support == HT_STREAM_MODE_2X2)
3586 			sys_cfg->supported_mcs_set[1] = 0xFF;
3587 		else
3588 			sys_cfg->supported_mcs_set[1] = 0;
3589 	}
3590 
3591 done:
3592 	LEAVE();
3593 	return status;
3594 }
3595 
3596 #define VHT_CAP_11AC_MASK 0x007fffff
3597 
3598 /**
3599  *  @brief enable/disable 11AC
3600  *
3601  *  @param priv     A pointer to moal_private structure
3602  *  @param action   MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
3603  *  @param vht20_40 Enable VHT 20 MHz or 40 MHz band
3604  *  @param vhtcap_ie A pointer to vht capability IE
3605  *
3606  *  @return         0--success, otherwise failure
3607  */
woal_uap_set_11ac_status(moal_private * priv,t_u8 action,t_u8 vht20_40,IEEEtypes_VHTCap_t * vhtcap_ie)3608 int woal_uap_set_11ac_status(moal_private *priv, t_u8 action, t_u8 vht20_40,
3609 			     IEEEtypes_VHTCap_t *vhtcap_ie)
3610 {
3611 	mlan_ioctl_req *req = NULL;
3612 	mlan_ds_11ac_cfg *cfg_11ac = NULL;
3613 	mlan_fw_info fw_info;
3614 	int ret = 0;
3615 	mlan_status status = MLAN_STATUS_SUCCESS;
3616 
3617 	ENTER();
3618 
3619 	memset(&fw_info, 0, sizeof(mlan_fw_info));
3620 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
3621 
3622 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
3623 	if (req == NULL) {
3624 		ret = -ENOMEM;
3625 		goto done;
3626 	}
3627 
3628 	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
3629 	cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
3630 	req->req_id = MLAN_IOCTL_11AC_CFG;
3631 	req->action = MLAN_ACT_SET;
3632 
3633 	cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
3634 	cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_TXRX;
3635 
3636 	/*
3637 	 * p2p GO (negotiation or auto GO) cases, wpa_supplicant will download
3638 	 * invalid vht capability with value 0 in beacon parameters, so for p2p
3639 	 * GO case (vht_cap_info = 0), driver will use hardware 11ac vht
3640 	 * capability value instead of up layer value.
3641 	 */
3642 	if (vhtcap_ie && vhtcap_ie->vht_cap.vht_cap_info != 0) {
3643 		cfg_11ac->param.vht_cfg.vht_cap_info =
3644 			woal_le32_to_cpu(vhtcap_ie->vht_cap.vht_cap_info);
3645 		/** todo mcs configuration */
3646 	} else {
3647 		cfg_11ac->param.vht_cfg.vht_cap_info =
3648 			fw_info.usr_dot_11ac_dev_cap_a;
3649 	}
3650 	if (action == MLAN_ACT_DISABLE) {
3651 		cfg_11ac->param.vht_cfg.bwcfg = MFALSE;
3652 		cfg_11ac->param.vht_cfg.vht_cap_info &= ~VHT_CAP_11AC_MASK;
3653 		cfg_11ac->param.vht_cfg.vht_rx_mcs =
3654 			cfg_11ac->param.vht_cfg.vht_tx_mcs = 0xffff;
3655 		cfg_11ac->param.vht_cfg.skip_usr_11ac_mcs_cfg = MTRUE;
3656 	} else {
3657 		if (vht20_40)
3658 			cfg_11ac->param.vht_cfg.bwcfg = MFALSE;
3659 		else
3660 			cfg_11ac->param.vht_cfg.bwcfg = MTRUE;
3661 		cfg_11ac->param.vht_cfg.vht_cap_info &=
3662 			~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
3663 		cfg_11ac->param.vht_cfg.vht_tx_mcs =
3664 			fw_info.usr_dot_11ac_mcs_support >> 16;
3665 		cfg_11ac->param.vht_cfg.vht_rx_mcs =
3666 			fw_info.usr_dot_11ac_mcs_support & 0xffff;
3667 		cfg_11ac->param.vht_cfg.skip_usr_11ac_mcs_cfg = MTRUE;
3668 	}
3669 	PRINTM(MCMND,
3670 	       "Uap:11ac=%d vht_cap_info=0x%x, vht_tx_mcs=0x%x, vht_rx_mcs=0x%x\n",
3671 	       action, cfg_11ac->param.vht_cfg.vht_cap_info,
3672 	       cfg_11ac->param.vht_cfg.vht_tx_mcs,
3673 	       cfg_11ac->param.vht_cfg.vht_rx_mcs);
3674 
3675 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3676 	if (status != MLAN_STATUS_SUCCESS) {
3677 		ret = -EFAULT;
3678 		goto done;
3679 	}
3680 done:
3681 	if (status != MLAN_STATUS_PENDING)
3682 		kfree(req);
3683 	LEAVE();
3684 	return ret;
3685 }
3686 
3687 /**
3688  *  @brief Get/Set 11ax cfg
3689  *
3690  *  @param priv     A pointer to moal_private structure
3691  *  @param action   MLAN_ACT_SET or MLAN_ACT_GET
3692  *  @param he_cfg   a pointer to mlan_ds_11ax_he_cfg
3693  *
3694  *  @return         0--success, otherwise failure
3695  */
woal_11ax_cfg(moal_private * priv,t_u8 action,mlan_ds_11ax_he_cfg * he_cfg)3696 int woal_11ax_cfg(moal_private *priv, t_u8 action, mlan_ds_11ax_he_cfg *he_cfg)
3697 {
3698 	int ret = 0;
3699 	mlan_status status = MLAN_STATUS_SUCCESS;
3700 	mlan_ioctl_req *req = NULL;
3701 	mlan_ds_11ax_cfg *cfg_11ax = NULL;
3702 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
3703 	if (req == NULL) {
3704 		ret = -ENOMEM;
3705 		goto done;
3706 	}
3707 	cfg_11ax = (mlan_ds_11ax_cfg *)req->pbuf;
3708 	cfg_11ax->sub_command = MLAN_OID_11AX_HE_CFG;
3709 	req->req_id = MLAN_IOCTL_11AX_CFG;
3710 	req->action = action;
3711 	moal_memcpy_ext(priv->phandle, &cfg_11ax->param.he_cfg, he_cfg,
3712 			sizeof(mlan_ds_11ax_he_cfg),
3713 			sizeof(mlan_ds_11ax_he_cfg));
3714 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3715 	if (status != MLAN_STATUS_SUCCESS) {
3716 		ret = -EFAULT;
3717 		goto done;
3718 	}
3719 	moal_memcpy_ext(priv->phandle, he_cfg, &cfg_11ax->param.he_cfg,
3720 			sizeof(mlan_ds_11ax_he_cfg),
3721 			sizeof(mlan_ds_11ax_he_cfg));
3722 done:
3723 	if (status != MLAN_STATUS_PENDING)
3724 		kfree(req);
3725 	LEAVE();
3726 	return ret;
3727 }
3728 
3729 /**
3730  *  @brief enable/disable 11AX
3731  *
3732  *  @param priv     A pointer to moal_private structure
3733  *  @param action   MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
3734  *  @param band     band config
3735  *  @param hecap_ie
3736  *
3737  *  @return         0--success, otherwise failure
3738  */
woal_uap_set_11ax_status(moal_private * priv,t_u8 action,t_u8 band,IEEEtypes_HECap_t * hecap_ie)3739 int woal_uap_set_11ax_status(moal_private *priv, t_u8 action, t_u8 band,
3740 			     IEEEtypes_HECap_t *hecap_ie)
3741 {
3742 	mlan_fw_info fw_info;
3743 	int ret = 0;
3744 	mlan_ds_11ax_he_cfg he_cfg;
3745 	ENTER();
3746 
3747 	memset(&fw_info, 0, sizeof(mlan_fw_info));
3748 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
3749 	if ((band == BAND_5GHZ && !(fw_info.fw_bands & BAND_AAX)) ||
3750 	    (band == BAND_2GHZ && !(fw_info.fw_bands & BAND_GAX))) {
3751 		PRINTM(MERROR, "fw doesn't support 11ax\n");
3752 		ret = -EFAULT;
3753 		goto done;
3754 	}
3755 	memset(&he_cfg, 0, sizeof(he_cfg));
3756 	if (band == BAND_5GHZ)
3757 		he_cfg.band = MBIT(1);
3758 	else if (band == BAND_2GHZ)
3759 		he_cfg.band = MBIT(0);
3760 	else {
3761 		PRINTM(MERROR, "Invalid band!\n");
3762 		ret = -EFAULT;
3763 		goto done;
3764 	}
3765 	if (woal_11ax_cfg(priv, MLAN_ACT_GET, &he_cfg)) {
3766 		PRINTM(MERROR, "Fail to get 11ax cfg!\n");
3767 		ret = -EFAULT;
3768 		goto done;
3769 	}
3770 	if (hecap_ie) {
3771 		DBG_HEXDUMP(MCMD_D, "hecap_ie", (t_u8 *)hecap_ie,
3772 			    hecap_ie->ieee_hdr.len +
3773 				    sizeof(IEEEtypes_Header_t));
3774 		he_cfg.he_cap.id = hecap_ie->ieee_hdr.element_id;
3775 		he_cfg.he_cap.len = hecap_ie->ieee_hdr.len;
3776 		moal_memcpy_ext(priv->phandle, &he_cfg.he_cap.ext_id,
3777 				&hecap_ie->ext_id, he_cfg.he_cap.len,
3778 				he_cfg.he_cap.len);
3779 	}
3780 #define HE_MAC_CAP_TWT_REQ_SUPPORT MBIT(1)
3781 	/* uap mode clear TWT request bit */
3782 	he_cfg.he_cap.he_mac_cap[0] &= ~HE_MAC_CAP_TWT_REQ_SUPPORT;
3783 
3784 	if (action == MLAN_ACT_DISABLE) {
3785 		if (he_cfg.he_cap.len &&
3786 		    (he_cfg.he_cap.ext_id == HE_CAPABILITY)) {
3787 			memset(he_cfg.he_cap.he_txrx_mcs_support, 0xff,
3788 			       sizeof(he_cfg.he_cap.he_txrx_mcs_support));
3789 		} else {
3790 			PRINTM(MCMND, "11ax already disabled\n");
3791 			goto done;
3792 		}
3793 	}
3794 	DBG_HEXDUMP(MCMD_D, "HE_CFG ", (t_u8 *)&he_cfg, sizeof(he_cfg));
3795 	ret = woal_11ax_cfg(priv, MLAN_ACT_SET, &he_cfg);
3796 done:
3797 	LEAVE();
3798 	return ret;
3799 }
3800 
3801 /**
3802  *  @brief Parse AP configuration from ASCII string
3803  *
3804  *  @param priv       A pointer to moal_private structure
3805  *  @param ap_cfg   A pointer to mlan_uap_bss_param structure
3806  *  @param buf      A pointer to user data
3807  *
3808  *  @return         0 --success, otherwise fail
3809  */
woal_uap_ap_cfg_parse_data(moal_private * priv,mlan_uap_bss_param * ap_cfg,char * buf)3810 static int woal_uap_ap_cfg_parse_data(moal_private *priv,
3811 				      mlan_uap_bss_param *ap_cfg, char *buf)
3812 {
3813 	int ret = 0, atoi_ret;
3814 	int set_sec = 0, set_key = 0, set_chan = 0;
3815 	int set_preamble = 0, set_scb = 0, set_ssid = 0;
3816 	char *begin = buf, *value = NULL, *opt = NULL;
3817 
3818 	ENTER();
3819 
3820 	while (begin) {
3821 		value = woal_strsep(&begin, ',', '/');
3822 		opt = woal_strsep(&value, '=', '/');
3823 		if (opt && !strncmp(opt, "END", strlen("END"))) {
3824 			if (!ap_cfg->ssid.ssid_len) {
3825 				PRINTM(MERROR,
3826 				       "Minimum option required is SSID\n");
3827 				ret = -EINVAL;
3828 				goto done;
3829 			}
3830 			PRINTM(MINFO, "Parsing terminated by string END\n");
3831 			break;
3832 		}
3833 		if (!opt || !value || !value[0]) {
3834 			PRINTM(MERROR, "Invalid option\n");
3835 			ret = -EINVAL;
3836 			goto done;
3837 		} else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) {
3838 			if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) {
3839 				PRINTM(MERROR,
3840 				       "ASCII_CMD: %s not matched with AP_CFG\n",
3841 				       value);
3842 				ret = -EFAULT;
3843 				goto done;
3844 			}
3845 			value = woal_strsep(&begin, ',', '/');
3846 			opt = woal_strsep(&value, '=', '/');
3847 			if (!opt || !value || !value[0]) {
3848 				PRINTM(MERROR,
3849 				       "Minimum option required is SSID\n");
3850 				ret = -EINVAL;
3851 				goto done;
3852 			} else if (!strncmp(opt, "SSID", strlen("SSID"))) {
3853 				if (set_ssid) {
3854 					PRINTM(MWARN,
3855 					       "Skipping SSID, found again!\n");
3856 					continue;
3857 				}
3858 				if (strlen(value) >= MLAN_MAX_SSID_LENGTH) {
3859 					PRINTM(MERROR,
3860 					       "SSID length exceeds max length\n");
3861 					ret = -EFAULT;
3862 					goto done;
3863 				}
3864 				ap_cfg->ssid.ssid_len = strlen(value);
3865 				strncpy((char *)ap_cfg->ssid.ssid, value,
3866 					MIN(MLAN_MAX_SSID_LENGTH - 1,
3867 					    strlen(value)));
3868 				PRINTM(MINFO, "ssid=%s, len=%d\n",
3869 				       ap_cfg->ssid.ssid,
3870 				       (int)ap_cfg->ssid.ssid_len);
3871 				set_ssid = 1;
3872 			} else {
3873 				PRINTM(MERROR,
3874 				       "AP_CFG: Invalid option %s, expect SSID\n",
3875 				       opt);
3876 				ret = -EINVAL;
3877 				goto done;
3878 			}
3879 		} else if (!strncmp(opt, "SEC", strlen("SEC"))) {
3880 			if (set_sec) {
3881 				PRINTM(MWARN, "Skipping SEC, found again!\n");
3882 				continue;
3883 			}
3884 			if (!strnicmp(value, "open", strlen("open"))) {
3885 				ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
3886 				if (set_key)
3887 					ap_cfg->wpa_cfg.length = 0;
3888 				ap_cfg->key_mgmt = KEY_MGMT_NONE;
3889 				ap_cfg->protocol = PROTOCOL_NO_SECURITY;
3890 			} else if (!strnicmp(value, "wpa2-psk",
3891 					     strlen("wpa2-psk"))) {
3892 				ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
3893 				ap_cfg->protocol = PROTOCOL_WPA2;
3894 				ap_cfg->key_mgmt = KEY_MGMT_PSK;
3895 				ap_cfg->wpa_cfg.pairwise_cipher_wpa =
3896 					CIPHER_AES_CCMP;
3897 				ap_cfg->wpa_cfg.pairwise_cipher_wpa2 =
3898 					CIPHER_AES_CCMP;
3899 				ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
3900 			} else if (!strnicmp(value, "wpa-psk",
3901 					     strlen("wpa-psk"))) {
3902 				ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
3903 				ap_cfg->protocol = PROTOCOL_WPA;
3904 				ap_cfg->key_mgmt = KEY_MGMT_PSK;
3905 				ap_cfg->wpa_cfg.pairwise_cipher_wpa =
3906 					CIPHER_TKIP;
3907 				ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
3908 			} else if (!strnicmp(value, "wep128",
3909 					     strlen("wep128"))) {
3910 				ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
3911 				if (set_key)
3912 					ap_cfg->wpa_cfg.length = 0;
3913 				ap_cfg->key_mgmt = KEY_MGMT_NONE;
3914 				ap_cfg->protocol = PROTOCOL_STATIC_WEP;
3915 			} else {
3916 				PRINTM(MERROR,
3917 				       "AP_CFG: Invalid value=%s for %s\n",
3918 				       value, opt);
3919 				ret = -EFAULT;
3920 				goto done;
3921 			}
3922 			set_sec = 1;
3923 		} else if (!strncmp(opt, "KEY", strlen("KEY"))) {
3924 			if (set_key) {
3925 				PRINTM(MWARN, "Skipping KEY, found again!\n");
3926 				continue;
3927 			}
3928 			if (set_sec &&
3929 			    ap_cfg->protocol == PROTOCOL_STATIC_WEP) {
3930 				if (strlen(value) != MAX_WEP_KEY_SIZE) {
3931 					PRINTM(MERROR,
3932 					       "Invalid WEP KEY length\n");
3933 					ret = -EFAULT;
3934 					goto done;
3935 				}
3936 				ap_cfg->wep_cfg.key0.key_index = 0;
3937 				ap_cfg->wep_cfg.key0.is_default = 1;
3938 				ap_cfg->wep_cfg.key0.length = strlen(value);
3939 				moal_memcpy_ext(
3940 					priv->phandle, ap_cfg->wep_cfg.key0.key,
3941 					value, strlen(value),
3942 					sizeof(ap_cfg->wep_cfg.key0.key));
3943 				set_key = 1;
3944 				continue;
3945 			}
3946 			if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2 &&
3947 			    ap_cfg->protocol != PROTOCOL_WPA) {
3948 				PRINTM(MWARN,
3949 				       "Warning! No KEY for open mode\n");
3950 				set_key = 1;
3951 				continue;
3952 			}
3953 			if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH ||
3954 			    strlen(value) > MLAN_PMK_HEXSTR_LENGTH) {
3955 				PRINTM(MERROR, "Invalid PSK/PMK length\n");
3956 				ret = -EINVAL;
3957 				goto done;
3958 			}
3959 			ap_cfg->wpa_cfg.length = strlen(value);
3960 			moal_memcpy_ext(priv->phandle,
3961 					ap_cfg->wpa_cfg.passphrase, value,
3962 					strlen(value),
3963 					sizeof(ap_cfg->wpa_cfg.passphrase));
3964 			set_key = 1;
3965 		} else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) {
3966 			if (set_chan) {
3967 				PRINTM(MWARN,
3968 				       "Skipping CHANNEL, found again!\n");
3969 				continue;
3970 			}
3971 			if (woal_atoi(&atoi_ret, value)) {
3972 				ret = -EINVAL;
3973 				goto done;
3974 			}
3975 			if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) {
3976 				PRINTM(MERROR,
3977 				       "AP_CFG: Channel must be between 1 and %d"
3978 				       "(both included)\n",
3979 				       MLAN_MAX_CHANNEL);
3980 				ret = -EINVAL;
3981 				goto done;
3982 			}
3983 			ap_cfg->channel = atoi_ret;
3984 			set_chan = 1;
3985 		} else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) {
3986 			if (set_preamble) {
3987 				PRINTM(MWARN,
3988 				       "Skipping PREAMBLE, found again!\n");
3989 				continue;
3990 			}
3991 			if (woal_atoi(&atoi_ret, value)) {
3992 				ret = -EINVAL;
3993 				goto done;
3994 			}
3995 			/* This is a READ only value from FW, so we
3996 			 * can not set this and pass it successfully */
3997 			set_preamble = 1;
3998 		} else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) {
3999 			if (set_scb) {
4000 				PRINTM(MWARN,
4001 				       "Skipping MAX_SCB, found again!\n");
4002 				continue;
4003 			}
4004 			if (woal_atoi(&atoi_ret, value)) {
4005 				ret = -EINVAL;
4006 				goto done;
4007 			}
4008 			if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) {
4009 				PRINTM(MERROR,
4010 				       "AP_CFG: MAX_SCB must be between 1 to %d "
4011 				       "(both included)\n",
4012 				       MAX_STA_COUNT);
4013 				ret = -EINVAL;
4014 				goto done;
4015 			}
4016 			ap_cfg->max_sta_count = (t_u16)atoi_ret;
4017 			set_scb = 1;
4018 		} else {
4019 			PRINTM(MERROR, "Invalid option %s\n", opt);
4020 			ret = -EINVAL;
4021 			goto done;
4022 		}
4023 	}
4024 
4025 done:
4026 	LEAVE();
4027 	return ret;
4028 }
4029 
4030 /**
4031  *  @brief Set AP configuration
4032  *
4033  *  @param priv     A pointer to moal_private structure
4034  *  @param data     A pointer to user data
4035  *  @param len      Length of buf
4036  *
4037  *  @return         0 --success, otherwise fail
4038  */
woal_uap_set_ap_cfg(moal_private * priv,t_u8 * data,int len)4039 int woal_uap_set_ap_cfg(moal_private *priv, t_u8 *data, int len)
4040 {
4041 	int ret = 0;
4042 	static char buf[MAX_BUF_LEN];
4043 	mlan_uap_bss_param *sys_config = NULL;
4044 	int restart = 0;
4045 
4046 	ENTER();
4047 
4048 #define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */
4049 	if ((len - 1) <= MIN_AP_CFG_CMD_LEN) {
4050 		PRINTM(MERROR, "Invalid length of command\n");
4051 		ret = -EINVAL;
4052 		goto done;
4053 	}
4054 	sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
4055 	if (!sys_config) {
4056 		PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
4057 		ret = -EFAULT;
4058 		goto done;
4059 	}
4060 	memset(buf, 0, MAX_BUF_LEN);
4061 	moal_memcpy_ext(priv->phandle, buf, data, len, sizeof(buf) - 1);
4062 
4063 	/* Initialize the uap bss values which are uploaded from firmware */
4064 	woal_uap_get_bss_param(priv, sys_config, MOAL_IOCTL_WAIT);
4065 
4066 	/* Setting the default values */
4067 	sys_config->channel = 6;
4068 	sys_config->preamble_type = 0;
4069 
4070 	ret = woal_uap_ap_cfg_parse_data(priv, sys_config, buf);
4071 	if (ret)
4072 		goto done;
4073 
4074 	/* If BSS already started stop it first and restart
4075 	 * after changing the setting */
4076 	if (priv->bss_started == MTRUE) {
4077 		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
4078 		if (ret)
4079 			goto done;
4080 		restart = 1;
4081 	}
4082 
4083 	/* If the security mode is configured as WEP or WPA-PSK,
4084 	 * it will disable 11n automatically, and if configured as
4085 	 * open(off) or wpa2-psk, it will automatically enable 11n */
4086 	if ((sys_config->protocol == PROTOCOL_STATIC_WEP) ||
4087 	    (sys_config->protocol == PROTOCOL_WPA)) {
4088 		if (MLAN_STATUS_SUCCESS !=
4089 		    woal_uap_set_11n_status(priv, sys_config,
4090 					    MLAN_ACT_DISABLE)) {
4091 			ret = -EFAULT;
4092 			goto done;
4093 		}
4094 	} else {
4095 		if (MLAN_STATUS_SUCCESS !=
4096 		    woal_uap_set_11n_status(priv, sys_config,
4097 					    MLAN_ACT_ENABLE)) {
4098 			ret = -EFAULT;
4099 			goto done;
4100 		}
4101 	}
4102 
4103 	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
4104 							   MOAL_IOCTL_WAIT,
4105 							   sys_config)) {
4106 		ret = -EFAULT;
4107 		goto done;
4108 	}
4109 
4110 	/* Start the BSS after successful configuration */
4111 	if (restart)
4112 		ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
4113 
4114 done:
4115 	kfree(sys_config);
4116 	LEAVE();
4117 	return ret;
4118 }
4119 
4120 /**
4121  *  @brief Set/Get ap scan channel list
4122  *
4123  *  @param priv             A pointer to moal_private structure
4124  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
4125  *  @param scan_channels    A pointer to mlan_uap_scan_channels structure
4126  *
4127  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4128  */
4129 static mlan_status
woal_set_get_ap_scan_channels(moal_private * priv,t_u16 action,mlan_uap_scan_channels * scan_channels)4130 woal_set_get_ap_scan_channels(moal_private *priv, t_u16 action,
4131 			      mlan_uap_scan_channels *scan_channels)
4132 {
4133 	mlan_status ret = MLAN_STATUS_SUCCESS;
4134 	mlan_ds_bss *bss = NULL;
4135 	mlan_ioctl_req *req = NULL;
4136 
4137 	ENTER();
4138 
4139 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4140 	if (req == NULL) {
4141 		ret = MLAN_STATUS_FAILURE;
4142 		goto done;
4143 	}
4144 
4145 	bss = (mlan_ds_bss *)req->pbuf;
4146 	bss->sub_command = MLAN_OID_UAP_SCAN_CHANNELS;
4147 	req->req_id = MLAN_IOCTL_BSS;
4148 	req->action = action;
4149 
4150 	moal_memcpy_ext(priv->phandle, &bss->param.ap_scan_channels,
4151 			scan_channels, sizeof(mlan_uap_scan_channels),
4152 			sizeof(bss->param.ap_scan_channels));
4153 
4154 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4155 	if (ret != MLAN_STATUS_SUCCESS)
4156 		goto done;
4157 	if (action == MLAN_ACT_GET)
4158 		moal_memcpy_ext(priv->phandle, scan_channels,
4159 				&bss->param.ap_scan_channels,
4160 				sizeof(mlan_uap_scan_channels),
4161 				sizeof(mlan_uap_scan_channels));
4162 
4163 done:
4164 	if (ret != MLAN_STATUS_PENDING)
4165 		kfree(req);
4166 	LEAVE();
4167 	return ret;
4168 }
4169 
4170 /**
4171  *  @brief Set/Get uap channel
4172  *
4173  *  @param priv             A pointer to moal_private structure
4174  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
4175  *  @param wait_option      wait option
4176  *  @param uap_channel      A pointer to mlan_uap_channel structure
4177  *
4178  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4179  */
woal_set_get_ap_channel(moal_private * priv,t_u16 action,t_u8 wait_option,chan_band_info * uap_channel)4180 mlan_status woal_set_get_ap_channel(moal_private *priv, t_u16 action,
4181 				    t_u8 wait_option,
4182 				    chan_band_info *uap_channel)
4183 {
4184 	mlan_status ret = MLAN_STATUS_SUCCESS;
4185 	mlan_ds_bss *bss = NULL;
4186 	mlan_ioctl_req *req = NULL;
4187 
4188 	ENTER();
4189 
4190 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4191 	if (req == NULL) {
4192 		ret = MLAN_STATUS_FAILURE;
4193 		goto done;
4194 	}
4195 
4196 	bss = (mlan_ds_bss *)req->pbuf;
4197 	bss->sub_command = MLAN_OID_UAP_CHANNEL;
4198 	req->req_id = MLAN_IOCTL_BSS;
4199 	req->action = action;
4200 
4201 	moal_memcpy_ext(priv->phandle, &bss->param.ap_channel, uap_channel,
4202 			sizeof(chan_band_info), sizeof(bss->param.ap_channel));
4203 	ret = woal_request_ioctl(priv, req, wait_option);
4204 	if (ret != MLAN_STATUS_SUCCESS)
4205 		goto done;
4206 	if (action == MLAN_ACT_GET)
4207 		moal_memcpy_ext(priv->phandle, uap_channel,
4208 				&bss->param.ap_channel, sizeof(chan_band_info),
4209 				sizeof(chan_band_info));
4210 
4211 done:
4212 	if (ret != MLAN_STATUS_PENDING)
4213 		kfree(req);
4214 	LEAVE();
4215 	return ret;
4216 }
4217 
4218 /**
4219  *  @brief start ACS scan
4220  *
4221  *  @param priv             A pointer to moal_private structure
4222  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
4223  *
4224  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4225  */
woal_start_acs_scan(moal_private * priv)4226 static mlan_status woal_start_acs_scan(moal_private *priv)
4227 {
4228 	mlan_status ret = MLAN_STATUS_SUCCESS;
4229 	mlan_ds_bss *bss = NULL;
4230 	mlan_ioctl_req *req = NULL;
4231 
4232 	ENTER();
4233 
4234 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4235 	if (req == NULL) {
4236 		ret = MLAN_STATUS_FAILURE;
4237 		goto done;
4238 	}
4239 
4240 	bss = (mlan_ds_bss *)req->pbuf;
4241 	bss->sub_command = MLAN_OID_UAP_ACS_SCAN;
4242 	req->req_id = MLAN_IOCTL_BSS;
4243 	req->action = MLAN_ACT_SET;
4244 
4245 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4246 	if (ret != MLAN_STATUS_SUCCESS)
4247 		goto done;
4248 	PRINTM(MIOCTL,
4249 	       "ACS scan done: bandcfg:[chanBand=0x%x chanWidth=0x%x chan2Offset=0x%x scanMode=0x%x], channel=%d\n",
4250 	       bss->param.ap_acs_scan.bandcfg.chanBand,
4251 	       bss->param.ap_acs_scan.bandcfg.chanWidth,
4252 	       bss->param.ap_acs_scan.bandcfg.chan2Offset,
4253 	       bss->param.ap_acs_scan.bandcfg.scanMode,
4254 	       bss->param.ap_acs_scan.chan);
4255 done:
4256 	if (ret != MLAN_STATUS_PENDING)
4257 		kfree(req);
4258 	LEAVE();
4259 	return ret;
4260 }
4261 
4262 /**
4263  *  @brie check if we need do ACS scan
4264  *
4265  *  @param priv             A pointer to moal_private structure
4266  *
4267  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4268  */
woal_do_acs_check(moal_private * priv)4269 static mlan_status woal_do_acs_check(moal_private *priv)
4270 {
4271 	mlan_status ret = MLAN_STATUS_SUCCESS;
4272 	mlan_uap_bss_param *sys_config = NULL;
4273 	mlan_uap_scan_channels *scan_channels = NULL;
4274 	chan_band_info uap_channel;
4275 	ENTER();
4276 
4277 	sys_config = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
4278 	if (!sys_config) {
4279 		PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
4280 		LEAVE();
4281 		return MLAN_STATUS_FAILURE;
4282 	}
4283 
4284 	if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
4285 							   MOAL_IOCTL_WAIT,
4286 							   sys_config)) {
4287 		PRINTM(MERROR, "Fail to get sys config data\n");
4288 		kfree(sys_config);
4289 		LEAVE();
4290 		return MLAN_STATUS_FAILURE;
4291 	}
4292 	if (!(sys_config->bandcfg.scanMode == SCAN_MODE_ACS)) {
4293 		kfree(sys_config);
4294 		LEAVE();
4295 		return ret;
4296 	}
4297 	scan_channels = kzalloc(sizeof(mlan_uap_scan_channels), GFP_ATOMIC);
4298 	if (scan_channels == NULL) {
4299 		PRINTM(MERROR, "Fail to alloc scan channels buffer\n");
4300 		kfree(sys_config);
4301 		LEAVE();
4302 		return MLAN_STATUS_FAILURE;
4303 	}
4304 	scan_channels->remove_nop_channel = MTRUE;
4305 	if (MLAN_STATUS_SUCCESS !=
4306 	    woal_set_get_ap_scan_channels(priv, MLAN_ACT_GET, scan_channels)) {
4307 		PRINTM(MERROR, "Fail to get scan channels\n");
4308 		goto done;
4309 	}
4310 
4311 	if (scan_channels->num_remvoed_channel && scan_channels->num_of_chan) {
4312 		scan_channels->remove_nop_channel = 0;
4313 		/** set back new channel list after remove nop channels */
4314 		if (MLAN_STATUS_SUCCESS !=
4315 		    woal_set_get_ap_scan_channels(priv, MLAN_ACT_SET,
4316 						  scan_channels)) {
4317 			PRINTM(MERROR, "Fail to get scan channels\n");
4318 			goto done;
4319 		}
4320 	}
4321 	if (scan_channels->num_of_chan)
4322 		ret = woal_start_acs_scan(priv);
4323 	else
4324 		ret = MLAN_STATUS_FAILURE;
4325 	/** set to default channel 6 when 5G ACS is configured */
4326 	if ((ret != MLAN_STATUS_SUCCESS) &&
4327 	    (sys_config->bandcfg.chanBand == BAND_5GHZ)) {
4328 		memset(&uap_channel, 0, sizeof(uap_channel));
4329 		uap_channel.bandcfg.chanBand = DEFAULT_UAP_BAND;
4330 		uap_channel.channel = DEFAULT_UAP_CHANNEL;
4331 		ret = woal_set_get_ap_channel(priv, MLAN_ACT_SET,
4332 					      MOAL_IOCTL_WAIT, &uap_channel);
4333 	}
4334 done:
4335 	kfree(scan_channels);
4336 	kfree(sys_config);
4337 	LEAVE();
4338 	return ret;
4339 }
4340 
4341 /**
4342  *  @brief uap BSS control ioctl handler
4343  *
4344  *  @param priv             A pointer to moal_private structure
4345  *  @param wait_option      Wait option
4346  *  @param data             BSS control type
4347  *  @return                 0 --success, otherwise fail
4348  */
woal_uap_bss_ctrl(moal_private * priv,t_u8 wait_option,int data)4349 int woal_uap_bss_ctrl(moal_private *priv, t_u8 wait_option, int data)
4350 {
4351 	mlan_ioctl_req *req = NULL;
4352 	mlan_ds_bss *bss = NULL;
4353 	int ret = 0;
4354 	mlan_status status = MLAN_STATUS_SUCCESS;
4355 
4356 	ENTER();
4357 
4358 	PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data);
4359 
4360 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4361 	if (req == NULL) {
4362 		ret = -ENOMEM;
4363 		goto done;
4364 	}
4365 	bss = (mlan_ds_bss *)req->pbuf;
4366 	switch (data) {
4367 	case UAP_BSS_START:
4368 		if (priv->bss_started == MTRUE) {
4369 			PRINTM(MWARN, "Warning: BSS already started!\n");
4370 			/* goto done; */
4371 		} else if (!priv->uap_host_based
4372 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
4373 			   || moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)
4374 #endif
4375 		) {
4376 			status = woal_do_acs_check(priv);
4377 			if (status)
4378 				PRINTM(MMSG, "woal_do_acs_check fails\n");
4379 			/* about to start bss: issue channel check */
4380 			status = woal_11h_channel_check_ioctl(priv,
4381 							      MOAL_IOCTL_WAIT);
4382 			if (status) {
4383 				PRINTM(MMSG, "11h channel check fails\n");
4384 				status = MLAN_STATUS_FAILURE;
4385 				ret = -1;
4386 				goto done;
4387 			}
4388 		}
4389 		bss->sub_command = MLAN_OID_BSS_START;
4390 		if (priv->uap_host_based) {
4391 			bss->param.host_based |= UAP_FLAG_HOST_BASED;
4392 #ifdef UAP_CFG80211
4393 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
4394 			if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
4395 				bss->param.host_based |= UAP_FLAG_HOST_MLME;
4396 #endif
4397 #endif
4398 		}
4399 		break;
4400 	case UAP_BSS_STOP:
4401 		if (priv->bss_started == MFALSE) {
4402 			PRINTM(MWARN, "Warning: BSS already stopped!\n");
4403 			/* This is a situation where CAC it started and BSS
4404 			 * start is dealyed and before CAC timer expires BSS
4405 			 * stop is triggered.
4406 			 *
4407 			 * Do not skip sending the BSS_STOP command since there
4408 			 * are many routines triggered on BSS_STOP command
4409 			 * response.
4410 			 */
4411 			woal_cancel_cac_block(priv);
4412 		}
4413 		bss->sub_command = MLAN_OID_BSS_STOP;
4414 		break;
4415 	case UAP_BSS_RESET:
4416 		bss->sub_command = MLAN_OID_UAP_BSS_RESET;
4417 		woal_cancel_cac_block(priv);
4418 		break;
4419 	default:
4420 		PRINTM(MMSG, "We don't support this uap_bss_ctrl cmd %d\n",
4421 		       data);
4422 		ret = -EFAULT;
4423 		goto done;
4424 	}
4425 	req->req_id = MLAN_IOCTL_BSS;
4426 	req->action = MLAN_ACT_SET;
4427 
4428 	status = woal_request_ioctl(priv, req, wait_option);
4429 	if (status == MLAN_STATUS_FAILURE) {
4430 		ret = -EFAULT;
4431 		goto done;
4432 	}
4433 	if (data == UAP_BSS_STOP || data == UAP_BSS_RESET) {
4434 		priv->bss_started = MFALSE;
4435 		woal_stop_queue(priv->netdev);
4436 		if (netif_carrier_ok(priv->netdev))
4437 			netif_carrier_off(priv->netdev);
4438 		if (data == UAP_BSS_RESET) {
4439 			if (MLAN_STATUS_FAILURE ==
4440 			    woal_request_set_mac_address(priv, wait_option))
4441 				PRINTM(MERROR,
4442 				       "Fail to set mac address after UAP_BSS_RESET\n");
4443 		}
4444 		woal_flush_tcp_sess_queue(priv);
4445 	}
4446 done:
4447 	if (status != MLAN_STATUS_PENDING)
4448 		kfree(req);
4449 	LEAVE();
4450 	return ret;
4451 }
4452 
4453 /**
4454  *  @brief This function sets multicast addresses to firmware
4455  *
4456  *  @param dev     A pointer to net_device structure
4457  *  @return        N/A
4458  */
woal_uap_set_multicast_list(struct net_device * dev)4459 void woal_uap_set_multicast_list(struct net_device *dev)
4460 {
4461 	ENTER();
4462 
4463 	LEAVE();
4464 }
4465 
4466 /**
4467  *  @brief ioctl function - entry point
4468  *
4469  *  @param dev      A pointer to net_device structure
4470  *  @param req      A pointer to ifreq structure
4471  *  @param cmd      Command
4472  *
4473  *  @return         0 --success, otherwise fail
4474  */
4475 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
woal_uap_do_ioctl(struct net_device * dev,struct ifreq * req,void __user * data,int cmd)4476 int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req,
4477 		      void __user *data, int cmd)
4478 #else
4479 int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
4480 #endif
4481 {
4482 	int ret = 0;
4483 	ENTER();
4484 
4485 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
4486 	if (in_compat_syscall()) /* not implemented yet */
4487 		return -EOPNOTSUPP;
4488 #endif
4489 
4490 	switch (cmd) {
4491 	case WOAL_ANDROID_DEF_CMD:
4492 		/** android default ioctl ID is SIOCDEVPRIVATE + 1 */
4493 		ret = woal_android_priv_cmd(dev, req);
4494 		break;
4495 	case UAP_IOCTL_CMD:
4496 		ret = woal_uap_ioctl(dev, req);
4497 		break;
4498 	case UAP_POWER_MODE:
4499 		ret = woal_uap_power_mode_ioctl(dev, req);
4500 		break;
4501 	case UAP_BSS_CTRL:
4502 		ret = woal_uap_bss_ctrl_ioctl(dev, req);
4503 		break;
4504 	case UAP_WAPI_MSG:
4505 		ret = woal_uap_set_wapi(dev, req);
4506 		break;
4507 	case UAP_BSS_CONFIG:
4508 		ret = woal_uap_bss_cfg_ioctl(dev, req);
4509 		break;
4510 	case UAP_STA_DEAUTH:
4511 		ret = woal_uap_sta_deauth_ioctl(dev, req);
4512 		break;
4513 	case UAP_RADIO_CTL:
4514 		ret = woal_uap_radio_ctl(dev, req);
4515 		break;
4516 	case UAP_REPORT_MIC_ERR:
4517 		ret = woal_uap_report_mic_ioctl(dev, req);
4518 		break;
4519 	case UAP_SET_KEY:
4520 		ret = woal_uap_set_key_ioctl(dev, req);
4521 		break;
4522 	case UAPHOSTPKTINJECT:
4523 		ret = woal_send_host_packet(dev, req);
4524 		break;
4525 	case UAP_GET_STA_LIST:
4526 		ret = woal_uap_get_sta_list_ioctl(dev, req);
4527 		break;
4528 	case UAP_CUSTOM_IE:
4529 		ret = woal_custom_ie_ioctl(dev, req);
4530 		break;
4531 	case UAP_GET_BSS_TYPE:
4532 		ret = woal_get_bss_type(dev, req);
4533 		break;
4534 	case WOAL_ANDROID_PRIV_CMD:
4535 		ret = woal_android_priv_cmd(dev, req);
4536 		break;
4537 	default:
4538 #ifdef UAP_WEXT
4539 		ret = woal_uap_do_priv_ioctl(dev, req, cmd);
4540 #else
4541 		ret = -EOPNOTSUPP;
4542 #endif
4543 		break;
4544 	}
4545 
4546 	LEAVE();
4547 	return ret;
4548 }
4549 
4550 #ifdef CONFIG_PROC_FS
4551 /**
4552  *  @brief Get version
4553  *
4554  *  @param priv         A pointer to moal_private structure
4555  *  @param version      A pointer to version buffer
4556  *  @param max_len      max length of version buffer
4557  *
4558  *  @return             N/A
4559  */
woal_uap_get_version(moal_private * priv,char * version,int max_len)4560 void woal_uap_get_version(moal_private *priv, char *version, int max_len)
4561 {
4562 	mlan_ds_get_info *info = NULL;
4563 	mlan_ioctl_req *req = NULL;
4564 	mlan_status status = MLAN_STATUS_SUCCESS;
4565 
4566 	ENTER();
4567 
4568 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
4569 	if (req == NULL) {
4570 		LEAVE();
4571 		return;
4572 	}
4573 
4574 	info = (mlan_ds_get_info *)req->pbuf;
4575 	info->sub_command = MLAN_OID_GET_VER_EXT;
4576 	req->req_id = MLAN_IOCTL_GET_INFO;
4577 	req->action = MLAN_ACT_GET;
4578 
4579 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4580 	if (status == MLAN_STATUS_SUCCESS) {
4581 		PRINTM(MINFO, "MOAL UAP VERSION: %s\n",
4582 		       info->param.ver_ext.version_str);
4583 		snprintf(version, max_len, priv->phandle->driver_version,
4584 			 info->param.ver_ext.version_str);
4585 	}
4586 
4587 	if (status != MLAN_STATUS_PENDING)
4588 		kfree(req);
4589 	LEAVE();
4590 	return;
4591 }
4592 #endif
4593 
4594 /**
4595  *  @brief Get uap statistics
4596  *
4597  *  @param priv                 A pointer to moal_private structure
4598  *  @param wait_option          Wait option
4599  *  @param ustats               A pointer to mlan_ds_uap_stats structure
4600  *
4601  *  @return                     MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
4602  * success, otherwise fail
4603  */
woal_uap_get_stats(moal_private * priv,t_u8 wait_option,mlan_ds_uap_stats * ustats)4604 mlan_status woal_uap_get_stats(moal_private *priv, t_u8 wait_option,
4605 			       mlan_ds_uap_stats *ustats)
4606 {
4607 	mlan_ds_get_info *info = NULL;
4608 	mlan_ioctl_req *req = NULL;
4609 	mlan_status status = MLAN_STATUS_SUCCESS;
4610 
4611 	ENTER();
4612 
4613 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
4614 	if (req == NULL) {
4615 		LEAVE();
4616 		return MLAN_STATUS_FAILURE;
4617 	}
4618 
4619 	info = (mlan_ds_get_info *)req->pbuf;
4620 	info->sub_command = MLAN_OID_GET_STATS;
4621 	req->req_id = MLAN_IOCTL_GET_INFO;
4622 	req->action = MLAN_ACT_GET;
4623 
4624 	status = woal_request_ioctl(priv, req, wait_option);
4625 	if (status == MLAN_STATUS_SUCCESS) {
4626 		if (ustats)
4627 			moal_memcpy_ext(priv->phandle, ustats,
4628 					&info->param.ustats,
4629 					sizeof(mlan_ds_uap_stats),
4630 					sizeof(mlan_ds_uap_stats));
4631 #ifdef UAP_WEXT
4632 		priv->w_stats.discard.fragment =
4633 			info->param.ustats.fcs_error_count;
4634 		priv->w_stats.discard.retries = info->param.ustats.retry_count;
4635 		priv->w_stats.discard.misc =
4636 			info->param.ustats.ack_failure_count;
4637 #endif
4638 	}
4639 
4640 	if (status != MLAN_STATUS_PENDING)
4641 		kfree(req);
4642 	LEAVE();
4643 	return status;
4644 }
4645 
4646 /**
4647  *  @brief Set/Get system configuration parameters
4648  *
4649  *  @param priv             A pointer to moal_private structure
4650  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
4651  *  @param ap_wmm_para      A pointer to wmm_parameter_t structure
4652  *
4653  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4654  */
woal_set_get_ap_wmm_para(moal_private * priv,t_u16 action,wmm_parameter_t * ap_wmm_para)4655 mlan_status woal_set_get_ap_wmm_para(moal_private *priv, t_u16 action,
4656 				     wmm_parameter_t *ap_wmm_para)
4657 {
4658 	mlan_status ret = MLAN_STATUS_SUCCESS;
4659 	mlan_ds_bss *bss = NULL;
4660 	mlan_ioctl_req *req = NULL;
4661 
4662 	ENTER();
4663 
4664 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4665 	if (req == NULL) {
4666 		ret = MLAN_STATUS_FAILURE;
4667 		goto done;
4668 	}
4669 
4670 	bss = (mlan_ds_bss *)req->pbuf;
4671 	bss->sub_command = MLAN_OID_UAP_CFG_WMM_PARAM;
4672 	req->req_id = MLAN_IOCTL_BSS;
4673 	req->action = action;
4674 
4675 	if (action == MLAN_ACT_SET)
4676 		moal_memcpy_ext(priv->phandle, &bss->param.ap_wmm_para,
4677 				ap_wmm_para, sizeof(wmm_parameter_t),
4678 				sizeof(bss->param.ap_wmm_para));
4679 
4680 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4681 	if (ret != MLAN_STATUS_SUCCESS)
4682 		goto done;
4683 	if (bss->param.ap_wmm_para.reserved != MLAN_STATUS_COMPLETE) {
4684 		ret = MLAN_STATUS_FAILURE;
4685 		goto done;
4686 	}
4687 	if (action == MLAN_ACT_GET)
4688 		moal_memcpy_ext(priv->phandle, ap_wmm_para,
4689 				&bss->param.ap_wmm_para,
4690 				sizeof(wmm_parameter_t),
4691 				sizeof(wmm_parameter_t));
4692 
4693 done:
4694 	if (ret != MLAN_STATUS_PENDING)
4695 		kfree(req);
4696 	LEAVE();
4697 	return ret;
4698 }
4699 
4700 /**
4701  *  @brief Set/Get system configuration parameters
4702  *
4703  *  @param priv             A pointer to moal_private structure
4704  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
4705  *  @param wait_option      Wait option
4706  *  @param sys_cfg          A pointer to mlan_uap_bss_param structure
4707  *
4708  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4709  */
woal_set_get_sys_config(moal_private * priv,t_u16 action,t_u8 wait_option,mlan_uap_bss_param * sys_cfg)4710 mlan_status woal_set_get_sys_config(moal_private *priv, t_u16 action,
4711 				    t_u8 wait_option,
4712 				    mlan_uap_bss_param *sys_cfg)
4713 {
4714 	mlan_status ret = MLAN_STATUS_SUCCESS;
4715 	mlan_ds_bss *bss = NULL;
4716 	mlan_ioctl_req *req = NULL;
4717 
4718 	ENTER();
4719 
4720 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4721 	if (req == NULL) {
4722 		ret = MLAN_STATUS_FAILURE;
4723 		goto done;
4724 	}
4725 
4726 	bss = (mlan_ds_bss *)req->pbuf;
4727 	bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
4728 	req->req_id = MLAN_IOCTL_BSS;
4729 	req->action = action;
4730 
4731 	if (action == MLAN_ACT_SET)
4732 		moal_memcpy_ext(priv->phandle, &bss->param.bss_config, sys_cfg,
4733 				sizeof(mlan_uap_bss_param),
4734 				sizeof(bss->param.bss_config));
4735 
4736 	ret = woal_request_ioctl(priv, req, wait_option);
4737 	if (ret != MLAN_STATUS_SUCCESS)
4738 		goto done;
4739 
4740 	if (action == MLAN_ACT_GET)
4741 		moal_memcpy_ext(priv->phandle, sys_cfg, &bss->param.bss_config,
4742 				sizeof(mlan_uap_bss_param),
4743 				sizeof(mlan_uap_bss_param));
4744 
4745 done:
4746 	if (ret != MLAN_STATUS_PENDING)
4747 		kfree(req);
4748 	LEAVE();
4749 	return ret;
4750 }
4751 
4752 /**
4753  *  @brief Set invalid data for each member of mlan_uap_bss_param
4754  *  structure
4755  *
4756  *  @param config   A pointer to mlan_uap_bss_param structure
4757  *
4758  *  @return         N/A
4759  */
woal_set_sys_config_invalid_data(mlan_uap_bss_param * config)4760 void woal_set_sys_config_invalid_data(mlan_uap_bss_param *config)
4761 {
4762 	ENTER();
4763 
4764 	memset(config, 0, sizeof(mlan_uap_bss_param));
4765 	config->bcast_ssid_ctl = 0x7F;
4766 	config->radio_ctl = 0x7F;
4767 	config->dtim_period = 0x7F;
4768 	config->beacon_period = 0x7FFF;
4769 	config->tx_data_rate = 0x7FFF;
4770 	config->mcbc_data_rate = 0x7FFF;
4771 	config->tx_power_level = 0x7F;
4772 	config->tx_antenna = 0x7F;
4773 	config->rx_antenna = 0x7F;
4774 	config->pkt_forward_ctl = 0x7F;
4775 	config->max_sta_count = 0x7FFF;
4776 	config->auth_mode = 0x7F;
4777 	config->sta_ageout_timer = 0x7FFFFFFF;
4778 	config->pairwise_update_timeout = 0x7FFFFFFF;
4779 	config->pwk_retries = 0x7FFFFFFF;
4780 	config->groupwise_update_timeout = 0x7FFFFFFF;
4781 	config->gwk_retries = 0x7FFFFFFF;
4782 	config->mgmt_ie_passthru_mask = 0x7FFFFFFF;
4783 	config->ps_sta_ageout_timer = 0x7FFFFFFF;
4784 	config->rts_threshold = 0x7FFF;
4785 	config->frag_threshold = 0x7FFF;
4786 	config->retry_limit = 0x7FFF;
4787 	config->filter.filter_mode = 0x7FFF;
4788 	config->filter.mac_count = 0x7FFF;
4789 	config->wpa_cfg.rsn_protection = 0x7F;
4790 	config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF;
4791 	config->enable_2040coex = 0x7F;
4792 	config->wmm_para.qos_info = 0x7F;
4793 
4794 	LEAVE();
4795 }
4796