1
2 /** @file moal_eth_ioctl.c
3 *
4 * @brief This file contains private ioctl functions
5
6 *
7 * Copyright 2014-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 01/05/2012: initial version
27 ************************************************************************/
28
29 #include "moal_main.h"
30 #include "moal_eth_ioctl.h"
31 #include "mlan_ioctl.h"
32 #if defined(STA_WEXT) || defined(UAP_WEXT)
33 #include "moal_priv.h"
34 #endif
35
36 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
37 #include "moal_cfg80211.h"
38 #endif
39 #ifdef UAP_SUPPORT
40 #include "moal_uap.h"
41 #endif
42 #ifdef USB
43 #include "moal_usb.h"
44 #endif
45 #ifdef SDIO
46 #include "moal_sdio.h"
47 #endif
48 #ifdef PCIE
49 #include "moal_pcie.h"
50 #endif
51 #ifdef STA_CFG80211
52 #include "moal_sta_cfg80211.h"
53 #endif
54 #ifdef STA_CFG80211
55 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
56 #include "moal_cfg80211_util.h"
57 #endif
58 #endif
59
60 /********************************************************
61 Local Variables
62 ********************************************************/
63
64 /** Bands supported in Infra mode */
65 static t_u16 SupportedInfraBand[] = {
66 BAND_B,
67 BAND_B | BAND_G,
68 BAND_G,
69 BAND_GN,
70 BAND_B | BAND_G | BAND_GN,
71 BAND_G | BAND_GN,
72 BAND_A,
73 BAND_B | BAND_A,
74 BAND_B | BAND_G | BAND_A,
75 BAND_G | BAND_A,
76 BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN,
77 BAND_A | BAND_G | BAND_AN | BAND_GN,
78 BAND_A | BAND_AN,
79 BAND_GN | BAND_GAC,
80 BAND_B | BAND_G | BAND_GN | BAND_GAC,
81 BAND_G | BAND_GN | BAND_GAC,
82 BAND_GN | BAND_GAC | BAND_GAX,
83 BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
84 BAND_G | BAND_GN | BAND_GAC | BAND_GAX,
85 BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
86 BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC,
87 BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC,
88 BAND_A | BAND_AN | BAND_AAC,
89 BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
90 BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC |
91 BAND_AAX,
92 BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX,
93 BAND_A | BAND_AN | BAND_AAC | BAND_AAX,
94 };
95
96 /** Bands supported in Ad-Hoc mode */
97 static t_u16 SupportedAdhocBand[] = {
98 BAND_B,
99 BAND_B | BAND_G,
100 BAND_G,
101 BAND_A,
102 };
103
104 /********************************************************
105 Global Variables
106 ********************************************************/
107 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
108 #ifdef UAP_SUPPORT
109 /** Network device handlers for uAP */
110 extern const struct net_device_ops woal_uap_netdev_ops;
111 #endif
112 #ifdef STA_SUPPORT
113 /** Network device handlers for STA */
114 extern const struct net_device_ops woal_netdev_ops;
115 #endif
116 #endif
117
118 /********************************************************
119 Local Functions
120 ********************************************************/
121 /**
122 * @brief Parse a string to extract numerical arguments
123 *
124 * @param pos Pointer to the arguments string
125 * @param data Pointer to the arguments buffer
126 * @param datalen Length of the arguments buffer
127 * @param user_data_len Pointer to the number of arguments extracted
128 *
129 * @return MLAN_STATUS_SUCCESS
130 */
parse_arguments(t_u8 * pos,int * data,int datalen,int * user_data_len)131 static mlan_status parse_arguments(t_u8 *pos, int *data, int datalen,
132 int *user_data_len)
133 {
134 int i, j, k;
135 char cdata[10];
136 int is_hex = 0;
137
138 if (strlen(pos) == 0) {
139 *user_data_len = 0;
140 return MLAN_STATUS_SUCCESS;
141 }
142
143 memset(cdata, 0, sizeof(cdata));
144 for (i = 0, j = 0, k = 0; i <= (int)strlen(pos); i++) {
145 if ((k == 0) && (i <= (int)(strlen(pos) - 2))) {
146 if ((pos[i] == '0') && (pos[i + 1] == 'x')) {
147 is_hex = 1;
148 i = i + 2;
149 }
150 }
151 if (pos[i] == '\0' || pos[i] == ' ') {
152 if (j >= datalen) {
153 j++;
154 break;
155 }
156 if (is_hex) {
157 data[j] = woal_atox(cdata);
158 is_hex = 0;
159 } else {
160 woal_atoi(&data[j], cdata);
161 }
162 j++;
163 k = 0;
164 memset(cdata, 0, sizeof(cdata));
165 if (pos[i] == '\0')
166 break;
167 } else {
168 if (k >= (int)sizeof(cdata)) {
169 PRINTM(MERROR, "Invalid numerical arguments\n");
170 break;
171 }
172 cdata[k] = pos[i];
173 k++;
174 }
175 }
176
177 *user_data_len = j;
178 return MLAN_STATUS_SUCCESS;
179 }
180
181 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
182 /**
183 * @brief Set wps & p2p ie in AP mode
184 *
185 * @param priv Pointer to priv stucture
186 * @param ie Pointer to ies data
187 * @param len Length of data
188 *
189 * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
190 */
woal_set_ap_wps_p2p_ie(moal_private * priv,t_u8 * ie,size_t len)191 mlan_status woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len)
192 {
193 mlan_status ret = MLAN_STATUS_SUCCESS;
194 t_u8 *pos = ie;
195 int ie_len;
196
197 ENTER();
198
199 ie_len = len - 2;
200 if (ie_len <= 0) {
201 PRINTM(MERROR, "IE len error: %d\n", ie_len);
202 ret = -EFAULT;
203 goto done;
204 }
205
206 /* Android cmd format:
207 * "SET_AP_WPS_P2P_IE 1" -- beacon IE
208 * "SET_AP_WPS_P2P_IE 2" -- proberesp IE
209 * "SET_AP_WPS_P2P_IE 4" -- assocresp IE
210 */
211 if (*pos == '1') {
212 /* set the beacon wps/p2p ies */
213 pos += 2;
214 if (MLAN_STATUS_SUCCESS !=
215 woal_cfg80211_mgmt_frame_ie(
216 priv, pos, ie_len, NULL, 0, NULL, 0, NULL, 0,
217 MGMT_MASK_BEACON_WPS_P2P, MOAL_IOCTL_WAIT)) {
218 PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
219 ret = -EFAULT;
220 goto done;
221 }
222 } else if (*pos == '2') {
223 /* set the probe resp ies */
224 pos += 2;
225 if (MLAN_STATUS_SUCCESS !=
226 woal_cfg80211_mgmt_frame_ie(
227 priv, NULL, 0, pos, ie_len, NULL, 0, NULL, 0,
228 MGMT_MASK_PROBE_RESP, MOAL_IOCTL_WAIT)) {
229 PRINTM(MERROR, "Failed to set probe resp ie\n");
230 ret = -EFAULT;
231 goto done;
232 }
233 } else if (*pos == '4') {
234 /* set the assoc resp ies */
235 pos += 2;
236 if (MLAN_STATUS_SUCCESS !=
237 woal_cfg80211_mgmt_frame_ie(
238 priv, NULL, 0, NULL, 0, pos, ie_len, NULL, 0,
239 MGMT_MASK_ASSOC_RESP, MOAL_IOCTL_WAIT)) {
240 PRINTM(MERROR, "Failed to set assoc resp ie\n");
241 ret = -EFAULT;
242 goto done;
243 }
244 }
245
246 done:
247 LEAVE();
248 return ret;
249 }
250 #endif
251
252 #ifdef WIFI_DIRECT_SUPPORT
253 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
254 /**
255 * @brief Set miracast mode
256 *
257 * @param priv Pointer to priv stucture
258 * @param pdata Pointer to cmd buffer
259 * @param len Length of data
260 *
261 * @return MLAN_STATUS_SUCCESS -- success, otherwise fail
262 */
woal_set_miracast_mode(moal_private * priv,t_u8 * pdata,size_t len)263 static mlan_status woal_set_miracast_mode(moal_private *priv, t_u8 *pdata,
264 size_t len)
265 {
266 mlan_status ret = MLAN_STATUS_SUCCESS;
267 t_u8 *pos = pdata;
268
269 ENTER();
270 if (!pos || (len == 0)) {
271 PRINTM(MERROR, "%s: Null buf!\n", __func__);
272 ret = MLAN_STATUS_FAILURE;
273 goto done;
274 }
275 while (!isdigit(*pos) && --len > 0)
276 pos++;
277 switch (*pos) {
278 case '0':
279 /* disable miracast mode */
280 priv->phandle->miracast_mode = 0;
281 break;
282 case '1':
283 /* Source */
284 priv->phandle->miracast_mode = 1;
285 break;
286 case '2':
287 /* Sink */
288 priv->phandle->miracast_mode = 2;
289 break;
290 default:
291 PRINTM(MERROR, "%s: Unknown miracast mode (%c)\n",
292 priv->netdev->name, *pos);
293 ret = MLAN_STATUS_FAILURE;
294 break;
295 }
296 done:
297 LEAVE();
298 return ret;
299 }
300 #endif
301 #endif
302
303 /**
304 * @brief Get Driver Version
305 *
306 * @param priv A pointer to moal_private structure
307 * @param respbuf A pointer to response buffer
308 * @param respbuflen Available length of response buffer
309 *
310 * @return Number of bytes written, negative for failure.
311 */
woal_get_priv_driver_version(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)312 static int woal_get_priv_driver_version(moal_private *priv, t_u8 *respbuf,
313 t_u32 respbuflen)
314 {
315 int len = 0, ret = -1;
316 char buf[MLAN_MAX_VER_STR_LEN];
317
318 ENTER();
319
320 if (!respbuf) {
321 LEAVE();
322 return 0;
323 }
324
325 memset(buf, 0, sizeof(buf));
326
327 /* Get version string to local buffer */
328 woal_get_version(priv->phandle, buf, sizeof(buf) - 1);
329 len = strlen(buf);
330
331 if (len) {
332 /* Copy back the retrieved version string */
333 PRINTM(MINFO, "MOAL VERSION: %s\n", buf);
334 ret = MIN(len, (int)(respbuflen - 1));
335 moal_memcpy_ext(priv->phandle, respbuf, buf, ret,
336 respbuflen - 1);
337 } else {
338 ret = -1;
339 PRINTM(MERROR, "Get version failed!\n");
340 }
341
342 LEAVE();
343 return ret;
344 }
345 /**
346 * @brief Hostcmd interface from application
347 *
348 * @param priv A pointer to moal_private structure
349 * @param respbuf A pointer to response buffer
350 * @param respbuflen Available length of response buffer
351 * @param wait_option Wait option
352 *
353 * @return Number of bytes written, negative for failure.
354 */
woal_priv_hostcmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 wait_option)355 int woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
356 t_u8 wait_option)
357 {
358 int ret = 0;
359 t_u8 *data_ptr;
360 t_u32 buf_len = 0;
361 HostCmd_Header cmd_header;
362 mlan_ioctl_req *req = NULL;
363 mlan_ds_misc_cfg *misc_cfg = NULL;
364 mlan_status status = MLAN_STATUS_SUCCESS;
365
366 ENTER();
367
368 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD));
369 buf_len = *((t_u32 *)data_ptr);
370 moal_memcpy_ext(priv->phandle, &cmd_header, data_ptr + sizeof(buf_len),
371 sizeof(HostCmd_Header), sizeof(HostCmd_Header));
372
373 PRINTM(MINFO, "Host command len = %d\n",
374 woal_le16_to_cpu(cmd_header.size));
375 if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) {
376 LEAVE();
377 return -EINVAL;
378 }
379
380 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
381 if (req == NULL) {
382 ret = -ENOMEM;
383 goto error;
384 }
385 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
386 misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
387 req->req_id = MLAN_IOCTL_MISC_CFG;
388 req->action = MLAN_ACT_SET;
389 misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size);
390 /* get the whole command */
391 moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
392 data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.len,
393 MRVDRV_SIZE_OF_CMD_BUFFER);
394
395 status = woal_request_ioctl(priv, req, wait_option);
396 if (status != MLAN_STATUS_SUCCESS) {
397 ret = -EFAULT;
398 goto error;
399 }
400 ret = misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_NXP) +
401 strlen(PRIV_CMD_HOSTCMD);
402 if (ret > (int)respbuflen) {
403 ret = -EFAULT;
404 goto error;
405 }
406 moal_memcpy_ext(
407 priv->phandle, data_ptr + sizeof(buf_len),
408 misc_cfg->param.hostcmd.cmd, misc_cfg->param.hostcmd.len,
409 respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD) +
410 sizeof(buf_len)));
411 moal_memcpy_ext(priv->phandle, data_ptr,
412 (t_u8 *)&misc_cfg->param.hostcmd.len, sizeof(t_u32),
413 sizeof(t_u32));
414
415 error:
416 if (status != MLAN_STATUS_PENDING)
417 kfree(req);
418
419 LEAVE();
420 return ret;
421 }
422
423 /**
424 * @brief configure 11ax HE capability or HE operation
425 *
426 *
427 * @param priv Pointer to the mlan_private driver data struct
428 * @param respbuf A pointer to response buffer
429 * @param len length used
430 * @param respbuflen Available length of response buffer
431 *
432 * @return Number of bytes written if successful else negative value
433 */
woal_setget_priv_11axcmdcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 wait_option)434 static int woal_setget_priv_11axcmdcfg(moal_private *priv, t_u8 *respbuf,
435 t_u32 respbuflen, t_u8 wait_option)
436 {
437 mlan_ioctl_req *req = NULL;
438 mlan_ds_11ax_cmd_cfg *cfg = NULL;
439 int ret = 0;
440 mlan_status status = MLAN_STATUS_SUCCESS;
441 int header_len = 0, user_data_len = 0;
442 int data[3] = {0};
443 ENTER();
444
445 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cmd_cfg));
446 if (req == NULL) {
447 ret = -ENOMEM;
448 goto done;
449 }
450
451 req->req_id = MLAN_IOCTL_11AX_CFG;
452 req->action = MLAN_ACT_SET;
453
454 cfg = (mlan_ds_11ax_cmd_cfg *)req->pbuf;
455 cfg->sub_command = MLAN_OID_11AX_CMD_CFG;
456
457 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
458 &user_data_len);
459 PRINTM(MINFO, "data_len=%d,data=%d,%d,%d\n", user_data_len, data[0],
460 data[1], data[2]);
461
462 if (user_data_len > 3 || user_data_len == 0) {
463 PRINTM(MERROR, "Invalid parameters\n");
464 ret = -EFAULT;
465 goto done;
466 } else if (user_data_len == 1) {
467 req->action = MLAN_ACT_GET;
468 }
469
470 switch (data[0]) {
471 case MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET:
472 cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
473 cfg->param.sr_cfg.type = MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID;
474 cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_obss_pd_offset);
475 cfg->param.sr_cfg.param.obss_pd_offset.offset[0] = data[1];
476 cfg->param.sr_cfg.param.obss_pd_offset.offset[1] = data[2];
477 break;
478 case MLAN_11AXCMD_CFG_ID_SR_ENABLE:
479 cfg->sub_id = MLAN_11AXCMD_SR_SUBID;
480 cfg->param.sr_cfg.type = MRVL_DOT11AX_ENABLE_SR_TLV_ID;
481 cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_sr_control);
482 cfg->param.sr_cfg.param.sr_control.control = data[1];
483 break;
484 case MLAN_11AXCMD_CFG_ID_BEAM_CHANGE:
485 cfg->sub_id = MLAN_11AXCMD_BEAM_SUBID;
486 cfg->param.beam_cfg.value = data[1];
487 break;
488 case MLAN_11AXCMD_CFG_ID_HTC_ENABLE:
489 cfg->sub_id = MLAN_11AXCMD_HTC_SUBID;
490 cfg->param.htc_cfg.value = data[1];
491 break;
492 case MLAN_11AXCMD_CFG_ID_TXOP_RTS:
493 cfg->sub_id = MLAN_11AXCMD_TXOPRTS_SUBID;
494 cfg->param.txop_cfg.rts_thres = data[1];
495 break;
496 case MLAN_11AXCMD_CFG_ID_TX_OMI:
497 cfg->sub_id = MLAN_11AXCMD_TXOMI_SUBID;
498 cfg->param.txomi_cfg.omi = data[1];
499 break;
500 case MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME:
501 cfg->sub_id = MLAN_11AXCMD_OBSS_TOLTIME_SUBID;
502 cfg->param.toltime_cfg.tol_time = data[1];
503 break;
504 default:
505 PRINTM(MERROR, "unknown 11axcmd\n");
506 ret = -EFAULT;
507 goto done;
508 }
509
510 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
511 if (status != MLAN_STATUS_SUCCESS) {
512 ret = -EFAULT;
513 goto done;
514 }
515 moal_memcpy_ext(priv->phandle, respbuf, &req->action,
516 sizeof(req->action), sizeof(req->action));
517 respbuf += sizeof(req->action);
518
519 cfg = (mlan_ds_11ax_cmd_cfg *)respbuf;
520 moal_memcpy_ext(priv->phandle, cfg, req->pbuf,
521 sizeof(mlan_ds_11ax_cmd_cfg), respbuflen);
522
523 ret = sizeof(req->action) + sizeof(mlan_ds_11ax_cmd_cfg);
524
525 done:
526 if (status != MLAN_STATUS_PENDING)
527 kfree(req);
528 LEAVE();
529 return ret;
530 }
531
532 /**
533 * @brief Set/get range ext mode
534 *
535 *
536 * @param priv Pointer to the mlan_private driver data struct
537 * @param respbuf A pointer to response buffer
538 * @param len length used
539 * @param respbuflen Available length of response buffer
540 *
541 * @return Number of bytes written if successful else negative value
542 */
woal_setget_priv_range_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)543 static int woal_setget_priv_range_ext(moal_private *priv, t_u8 *respbuf,
544 t_u32 respbuflen)
545 {
546 mlan_ioctl_req *req = NULL;
547 mlan_ds_misc_cfg *misc = NULL;
548 int ret = 0;
549 int data[1];
550 int header_len = 0, user_data_len = 0;
551 mlan_status status = MLAN_STATUS_SUCCESS;
552
553 ENTER();
554
555 if (!respbuf) {
556 PRINTM(MERROR, "response buffer is not available!\n");
557 ret = -EINVAL;
558 goto done;
559 }
560 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RANGE_EXT);
561 user_data_len = strlen(respbuf) - header_len;
562
563 /* Allocate an IOCTL request buffer */
564 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
565 if (req == NULL) {
566 ret = -ENOMEM;
567 goto done;
568 }
569 /* Fill request buffer */
570 misc = (mlan_ds_misc_cfg *)req->pbuf;
571 misc->sub_command = MLAN_OID_MISC_RANGE_EXT;
572 req->req_id = MLAN_IOCTL_MISC_CFG;
573 if ((int)strlen(respbuf) == header_len) {
574 /* GET operation */
575 user_data_len = 0;
576 req->action = MLAN_ACT_GET;
577 } else {
578 /* SET operation */
579 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
580 &user_data_len);
581 if (user_data_len != 1) {
582 PRINTM(MERROR, "Invalid Parameter\n");
583 ret = -EFAULT;
584 goto done;
585 }
586 if (data[0] < 0 || data[0] > 2) {
587 PRINTM(MERROR,
588 "Invalid Parameter: range_ext mode 0-2\n");
589 ret = -EFAULT;
590 goto done;
591 }
592 misc->param.range_ext_mode = (t_u8)data[0];
593 req->action = MLAN_ACT_SET;
594 }
595 /* Send IOCTL request to MLAN */
596 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
597 if (status != MLAN_STATUS_SUCCESS) {
598 ret = -EFAULT;
599 goto done;
600 }
601
602 data[0] = misc->param.range_ext_mode;
603 moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
604 respbuflen);
605 ret = sizeof(data);
606 done:
607 if (status != MLAN_STATUS_PENDING)
608 kfree(req);
609
610 LEAVE();
611 return ret;
612 }
613
614 /**
615 * @brief Custom IE setting
616 *
617 * @param priv A pointer to moal_private structure
618 * @param respbuf A pointer to response buffer
619 * @param respbuflen Available length of response buffer
620 *
621 * @return Number of bytes written, negative for failure.
622 */
woal_priv_customie(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)623 static int woal_priv_customie(moal_private *priv, t_u8 *respbuf,
624 t_u32 respbuflen)
625 {
626 int ret = 0;
627 t_u8 *data_ptr;
628 mlan_ioctl_req *ioctl_req = NULL;
629 mlan_ds_misc_cfg *misc = NULL;
630 mlan_ds_misc_custom_ie *pcustom_ie = NULL;
631 mlan_status status = MLAN_STATUS_SUCCESS;
632
633 ENTER();
634 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE));
635
636 pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
637 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
638 if (ioctl_req == NULL) {
639 ret = -ENOMEM;
640 goto done;
641 }
642
643 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
644 misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
645 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
646 if ((pcustom_ie->len == 0) ||
647 (pcustom_ie->len == sizeof(pcustom_ie->ie_data_list[0].ie_index)))
648 ioctl_req->action = MLAN_ACT_GET;
649 else
650 ioctl_req->action = MLAN_ACT_SET;
651
652 moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, pcustom_ie,
653 sizeof(mlan_ds_misc_custom_ie),
654 sizeof(mlan_ds_misc_custom_ie));
655
656 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
657 if (status != MLAN_STATUS_SUCCESS) {
658 ret = -EFAULT;
659 goto done;
660 }
661 pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr;
662 moal_memcpy_ext(priv->phandle, pcustom_ie, &misc->param.cust_ie,
663 sizeof(mlan_ds_misc_custom_ie),
664 respbuflen -
665 (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE)));
666 ret = sizeof(mlan_ds_misc_custom_ie);
667 if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) {
668 /* send a separate error code to indicate error from driver */
669 ret = EFAULT;
670 }
671 done:
672 if (status != MLAN_STATUS_PENDING)
673 kfree(ioctl_req);
674 LEAVE();
675 return ret;
676 }
677
678 /**
679 * @brief Set/Get Band and Adhoc-band setting
680 *
681 * @param priv A pointer to moal_private structure
682 * @param respbuf A pointer to response buffer
683 * @param respbuflen Available length of response buffer
684 *
685 * @return Number of bytes written, negative for failure.
686 */
woal_setget_priv_bandcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)687 static int woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf,
688 t_u32 respbuflen)
689 {
690 int ret = 0;
691 unsigned int i;
692 int data[3];
693 int user_data_len = 0;
694 t_u32 infra_band = 0;
695 t_u32 adhoc_band = 0;
696 t_u32 adhoc_channel = 0;
697 mlan_ioctl_req *req = NULL;
698 mlan_ds_radio_cfg *radio_cfg = NULL;
699 mlan_ds_band_cfg *band_cfg = NULL;
700 mlan_status status = MLAN_STATUS_SUCCESS;
701
702 ENTER();
703
704 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BANDCFG))) {
705 /* GET operation */
706 user_data_len = 0;
707 } else {
708 /* SET operation */
709 memset((char *)data, 0, sizeof(data));
710 parse_arguments(respbuf + strlen(CMD_NXP) +
711 strlen(PRIV_CMD_BANDCFG),
712 data, ARRAY_SIZE(data), &user_data_len);
713 }
714
715 if (sizeof(int) * user_data_len > sizeof(data)) {
716 PRINTM(MERROR, "Too many arguments\n");
717 LEAVE();
718 return -EINVAL;
719 }
720
721 if (user_data_len > 0) {
722 if (priv->media_connected == MTRUE) {
723 LEAVE();
724 return -EOPNOTSUPP;
725 }
726 }
727
728 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
729 if (req == NULL) {
730 ret = -ENOMEM;
731 goto error;
732 }
733 radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
734 radio_cfg->sub_command = MLAN_OID_BAND_CFG;
735 req->req_id = MLAN_IOCTL_RADIO_CFG;
736
737 if (user_data_len == 0) {
738 /* Get config_bands, adhoc_start_band and adhoc_channel values
739 * from MLAN
740 */
741 req->action = MLAN_ACT_GET;
742 } else {
743 /* To support only <b/bg/bgn/n/aac/gac> */
744 infra_band = data[0];
745
746 for (i = 0; i < (sizeof(SupportedInfraBand) /
747 sizeof(SupportedInfraBand[0]));
748 i++)
749 if (infra_band == SupportedInfraBand[i])
750 break;
751 if (i == sizeof(SupportedInfraBand)) {
752 ret = -EINVAL;
753 goto error;
754 }
755
756 /* Set Adhoc band */
757 if (user_data_len >= 2) {
758 adhoc_band = data[1];
759 for (i = 0; i < (sizeof(SupportedAdhocBand) /
760 sizeof(SupportedAdhocBand[0]));
761 i++)
762 if (adhoc_band == SupportedAdhocBand[i])
763 break;
764 if (i == sizeof(SupportedAdhocBand)) {
765 ret = -EINVAL;
766 goto error;
767 }
768 }
769
770 /* Set Adhoc channel */
771 if (user_data_len >= 3) {
772 adhoc_channel = data[2];
773 if (adhoc_channel == 0) {
774 /* Check if specified adhoc channel is non-zero
775 */
776 ret = -EINVAL;
777 goto error;
778 }
779 }
780 /* Set config_bands and adhoc_start_band values to MLAN */
781 req->action = MLAN_ACT_SET;
782 radio_cfg->param.band_cfg.config_bands = infra_band;
783 radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band;
784 radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel;
785 }
786
787 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
788 if (status != MLAN_STATUS_SUCCESS) {
789 ret = -EFAULT;
790 goto error;
791 }
792
793 band_cfg = (mlan_ds_band_cfg *)respbuf;
794
795 moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
796 sizeof(mlan_ds_band_cfg), respbuflen);
797
798 ret = sizeof(mlan_ds_band_cfg);
799
800 error:
801 if (status != MLAN_STATUS_PENDING)
802 kfree(req);
803
804 LEAVE();
805 return ret;
806 }
807
808 /**
809 * @brief Set/Get 11n configurations
810 *
811 * @param priv A pointer to moal_private structure
812 * @param respbuf A pointer to response buffer
813 * @param respbuflen Available length of response buffer
814 *
815 * @return Number of bytes written, negative for failure.
816 */
woal_setget_priv_httxcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)817 static int woal_setget_priv_httxcfg(moal_private *priv, t_u8 *respbuf,
818 t_u32 respbuflen)
819 {
820 t_u32 data[2];
821 mlan_ioctl_req *req = NULL;
822 mlan_ds_11n_cfg *cfg_11n = NULL;
823 int ret = 0;
824 int user_data_len = 0;
825 mlan_status status = MLAN_STATUS_SUCCESS;
826
827 ENTER();
828
829 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTTXCFG))) {
830 /* GET operation */
831 user_data_len = 0;
832 } else {
833 /* SET operation */
834 memset((char *)data, 0, sizeof(data));
835 parse_arguments(respbuf + strlen(CMD_NXP) +
836 strlen(PRIV_CMD_HTTXCFG),
837 data, ARRAY_SIZE(data), &user_data_len);
838 }
839
840 if (user_data_len > 2) {
841 PRINTM(MERROR, "Too many arguments\n");
842 ret = -EINVAL;
843 goto done;
844 }
845 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
846 if (req == NULL) {
847 ret = -ENOMEM;
848 goto done;
849 }
850
851 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
852 cfg_11n->sub_command = MLAN_OID_11N_CFG_TX;
853 req->req_id = MLAN_IOCTL_11N_CFG;
854
855 if (user_data_len == 0) {
856 /* Get 11n tx parameters from MLAN */
857 req->action = MLAN_ACT_GET;
858 cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG;
859 } else {
860 cfg_11n->param.tx_cfg.httxcap = data[0];
861 PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]);
862 cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH;
863 if (user_data_len == 2) {
864 if (data[1] != BAND_SELECT_BG &&
865 data[1] != BAND_SELECT_A &&
866 data[1] != BAND_SELECT_BOTH) {
867 PRINTM(MERROR, "Invalid band selection\n");
868 ret = -EINVAL;
869 goto done;
870 }
871 cfg_11n->param.tx_cfg.misc_cfg = data[1];
872 PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]);
873 }
874 /* Update 11n tx parameters in MLAN */
875 req->action = MLAN_ACT_SET;
876 }
877 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
878 if (status != MLAN_STATUS_SUCCESS) {
879 ret = -EFAULT;
880 goto done;
881 }
882 data[0] = cfg_11n->param.tx_cfg.httxcap;
883 PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]);
884
885 if (req->action == MLAN_ACT_GET) {
886 cfg_11n->param.tx_cfg.httxcap = 0;
887 cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A;
888 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
889 if (status != MLAN_STATUS_SUCCESS) {
890 ret = -EFAULT;
891 goto done;
892 }
893 data[1] = cfg_11n->param.tx_cfg.httxcap;
894 PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]);
895 }
896
897 moal_memcpy_ext(priv->phandle, respbuf, data, sizeof(data), respbuflen);
898 ret = sizeof(data);
899
900 done:
901 if (status != MLAN_STATUS_PENDING)
902 kfree(req);
903 LEAVE();
904 return ret;
905 }
906
907 /**
908 * @brief Set/Get 11n capability information
909 *
910 * @param priv A pointer to moal_private structure
911 * @param respbuf A pointer to response buffer
912 * @param respbuflen Available length of response buffer
913 *
914 * @return Number of bytes written, negative for failure.
915 */
woal_setget_priv_htcapinfo(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)916 static int woal_setget_priv_htcapinfo(moal_private *priv, t_u8 *respbuf,
917 t_u32 respbuflen)
918 {
919 int data[2];
920 mlan_ioctl_req *req = NULL;
921 mlan_ds_11n_cfg *cfg_11n = NULL;
922 woal_ht_cap_info *ht_cap = NULL;
923 int ret = 0;
924 int user_data_len = 0;
925 mlan_status status = MLAN_STATUS_SUCCESS;
926
927 ENTER();
928
929 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTCAPINFO))) {
930 /* GET operation */
931 user_data_len = 0;
932 } else {
933 /* SET operation */
934 memset((char *)data, 0, sizeof(data));
935 parse_arguments(respbuf + strlen(CMD_NXP) +
936 strlen(PRIV_CMD_HTCAPINFO),
937 data, ARRAY_SIZE(data), &user_data_len);
938 }
939
940 if (user_data_len > 2) {
941 PRINTM(MERROR, "Too many arguments\n");
942 ret = -EINVAL;
943 goto done;
944 }
945 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
946 if (req == NULL) {
947 ret = -ENOMEM;
948 goto done;
949 }
950
951 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
952 cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
953 req->req_id = MLAN_IOCTL_11N_CFG;
954
955 if (user_data_len == 0) {
956 /* Get 11n tx parameters from MLAN */
957 req->action = MLAN_ACT_GET;
958 cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG;
959 } else {
960 cfg_11n->param.htcap_cfg.htcap = data[0];
961 PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]);
962 cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH;
963 if (user_data_len == 2) {
964 if (data[1] != BAND_SELECT_BG &&
965 data[1] != BAND_SELECT_A &&
966 data[1] != BAND_SELECT_BOTH) {
967 PRINTM(MERROR, "Invalid band selection\n");
968 ret = -EINVAL;
969 goto done;
970 }
971 cfg_11n->param.htcap_cfg.misc_cfg = data[1];
972 PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]);
973 }
974 /* Update 11n tx parameters in MLAN */
975 req->action = MLAN_ACT_SET;
976 }
977 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
978 if (status != MLAN_STATUS_SUCCESS) {
979 ret = -EFAULT;
980 goto done;
981 }
982 data[0] = cfg_11n->param.htcap_cfg.htcap;
983 PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]);
984
985 if (req->action == MLAN_ACT_GET) {
986 cfg_11n->param.htcap_cfg.htcap = 0;
987 cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A;
988 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
989 if (status != MLAN_STATUS_SUCCESS) {
990 ret = -EFAULT;
991 goto done;
992 }
993 data[1] = cfg_11n->param.htcap_cfg.htcap;
994 PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]);
995 }
996
997 ht_cap = (woal_ht_cap_info *)respbuf;
998 ht_cap->ht_cap_info_bg = data[0];
999 ht_cap->ht_cap_info_a = data[1];
1000 ret = sizeof(woal_ht_cap_info);
1001
1002 done:
1003 if (status != MLAN_STATUS_PENDING)
1004 kfree(req);
1005 LEAVE();
1006 return ret;
1007 }
1008
1009 /**
1010 * @brief Set/Get add BA parameters
1011 *
1012 * @param priv A pointer to moal_private structure
1013 * @param respbuf A pointer to response buffer
1014 * @param respbuflen Available length of response buffer
1015 *
1016 * @return Number of bytes written, negative for failure.
1017 */
woal_setget_priv_addbapara(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1018 static int woal_setget_priv_addbapara(moal_private *priv, t_u8 *respbuf,
1019 t_u32 respbuflen)
1020 {
1021 int data[5];
1022 mlan_ioctl_req *req = NULL;
1023 mlan_ds_11n_cfg *cfg_11n = NULL;
1024 woal_addba *addba = NULL;
1025 int ret = 0;
1026 int user_data_len = 0;
1027 mlan_status status = MLAN_STATUS_SUCCESS;
1028
1029 ENTER();
1030
1031 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAPARA))) {
1032 /* GET operation */
1033 user_data_len = 0;
1034 } else {
1035 /* SET operation */
1036 memset((char *)data, 0, sizeof(data));
1037 parse_arguments(respbuf + strlen(CMD_NXP) +
1038 strlen(PRIV_CMD_ADDBAPARA),
1039 data, ARRAY_SIZE(data), &user_data_len);
1040
1041 if (user_data_len != ARRAY_SIZE(data)) {
1042 PRINTM(MERROR, "Invalid number of arguments\n");
1043 ret = -EINVAL;
1044 goto done;
1045 }
1046 if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) {
1047 PRINTM(MERROR, "Incorrect addba timeout value.\n");
1048 ret = -EFAULT;
1049 goto done;
1050 }
1051 if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE ||
1052 data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) {
1053 PRINTM(MERROR, "Incorrect Tx/Rx window size.\n");
1054 ret = -EFAULT;
1055 goto done;
1056 }
1057 if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) {
1058 PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n");
1059 ret = -EFAULT;
1060 goto done;
1061 }
1062 }
1063 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1064 if (req == NULL) {
1065 ret = -ENOMEM;
1066 goto done;
1067 }
1068
1069 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1070 cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
1071 req->req_id = MLAN_IOCTL_11N_CFG;
1072
1073 if (user_data_len == 0) {
1074 /* Get add BA parameters from MLAN */
1075 req->action = MLAN_ACT_GET;
1076 } else {
1077 cfg_11n->param.addba_param.timeout = data[0];
1078 cfg_11n->param.addba_param.txwinsize = data[1];
1079 cfg_11n->param.addba_param.rxwinsize = data[2];
1080 cfg_11n->param.addba_param.txamsdu = data[3];
1081 cfg_11n->param.addba_param.rxamsdu = data[4];
1082 PRINTM(MINFO,
1083 "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n",
1084 data[0], data[1], data[2], data[3], data[4]);
1085 /* Update add BA parameters in MLAN */
1086 req->action = MLAN_ACT_SET;
1087 }
1088 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1089 if (status != MLAN_STATUS_SUCCESS) {
1090 ret = -EFAULT;
1091 goto done;
1092 }
1093
1094 addba = (woal_addba *)respbuf;
1095
1096 addba->time_out = cfg_11n->param.addba_param.timeout;
1097 addba->tx_win_size = cfg_11n->param.addba_param.txwinsize;
1098 addba->rx_win_size = cfg_11n->param.addba_param.rxwinsize;
1099 addba->tx_amsdu = cfg_11n->param.addba_param.txamsdu;
1100 addba->rx_amsdu = cfg_11n->param.addba_param.rxamsdu;
1101 PRINTM(MINFO,
1102 "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n",
1103 addba->time_out, addba->tx_win_size, addba->rx_win_size,
1104 addba->tx_amsdu, addba->rx_amsdu);
1105
1106 ret = sizeof(woal_addba);
1107
1108 done:
1109 if (status != MLAN_STATUS_PENDING)
1110 kfree(req);
1111 LEAVE();
1112 return ret;
1113 }
1114
1115 /**
1116 * @brief Delete selective BA based on parameters
1117 *
1118 * @param priv A pointer to moal_private structure
1119 * @param respbuf A pointer to response buffer
1120 * @param respbuflen Available length of response buffer
1121 *
1122 * @return Number of bytes written, negative for failure.
1123 */
woal_priv_delba(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1124 static int woal_priv_delba(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
1125 {
1126 t_u32 data[2] = {0xFF, 0xFF};
1127 mlan_ioctl_req *req = NULL;
1128 mlan_ds_11n_cfg *cfg_11n = NULL;
1129 mlan_ds_11n_delba *del_ba = NULL;
1130 int ret = 0;
1131 int user_data_len = 0;
1132 int header_len = 0;
1133 t_u8 *mac_pos = NULL;
1134 t_u8 peer_mac[ETH_ALEN] = {0};
1135 mlan_status status = MLAN_STATUS_SUCCESS;
1136
1137 ENTER();
1138
1139 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELBA);
1140
1141 if ((int)strlen(respbuf) == header_len) {
1142 /* Incorrect number of arguments */
1143 PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1144 ret = -EINVAL;
1145 goto done;
1146 }
1147
1148 mac_pos = strstr(respbuf + header_len, " ");
1149 if (mac_pos)
1150 mac_pos = strstr(mac_pos + 1, " ");
1151 if (mac_pos) {
1152 #define MAC_STRING_LENGTH 17
1153 if (strlen(mac_pos + 1) != MAC_STRING_LENGTH) {
1154 PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1155 ret = -EINVAL;
1156 goto done;
1157 }
1158 woal_mac2u8(peer_mac, mac_pos + 1);
1159 *mac_pos = '\0';
1160 }
1161
1162 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
1163 &user_data_len);
1164
1165 if (mac_pos)
1166 user_data_len++;
1167
1168 if (user_data_len > 3 || (!(data[0] & (DELBA_TX | DELBA_RX))) ||
1169 (data[1] != DELBA_ALL_TIDS && !(data[1] <= 7))) {
1170 /* Incorrect number of arguments */
1171 PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
1172 ret = -EINVAL;
1173 goto done;
1174 }
1175
1176 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1177 if (req == NULL) {
1178 ret = -ENOMEM;
1179 goto done;
1180 }
1181 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1182 req->req_id = MLAN_IOCTL_11N_CFG;
1183 cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA;
1184
1185 del_ba = &cfg_11n->param.del_ba;
1186 memset(del_ba, 0, sizeof(mlan_ds_11n_delba));
1187 del_ba->direction = (t_u8)data[0];
1188 del_ba->tid = DELBA_ALL_TIDS;
1189 if (user_data_len > 1)
1190 del_ba->tid = (t_u8)data[1];
1191 if (user_data_len > 2)
1192 moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, peer_mac,
1193 ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
1194
1195 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1196
1197 if (status != MLAN_STATUS_SUCCESS) {
1198 ret = -EFAULT;
1199 goto done;
1200 }
1201
1202 ret = sprintf(respbuf, "OK. BA deleted successfully.\n") + 1;
1203
1204 done:
1205 if (status != MLAN_STATUS_PENDING)
1206 kfree(req);
1207 LEAVE();
1208 return ret;
1209 }
1210
1211 /**
1212 * @brief Set/Get the reject addba requst conditions
1213 *
1214 * @param priv A pointer to moal_private structure
1215 * @param respbuf A pointer to response buffer
1216 * @param respbuflen Available length of response buffer
1217 *
1218 * @return Number of bytes written, negative for failure.
1219 */
woal_priv_rejectaddbareq(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1220 static int woal_priv_rejectaddbareq(moal_private *priv, t_u8 *respbuf,
1221 t_u32 respbuflen)
1222 {
1223 t_u32 data[1];
1224 mlan_ioctl_req *req = NULL;
1225 mlan_ds_11n_cfg *cfg_11n = NULL;
1226 int ret = 0;
1227 int user_data_len = 0;
1228 mlan_status status = MLAN_STATUS_SUCCESS;
1229
1230 ENTER();
1231
1232 if (strlen(respbuf) ==
1233 (strlen(CMD_NXP) + strlen(PRIV_CMD_REJECTADDBAREQ))) {
1234 /* GET operation */
1235 user_data_len = 0;
1236 } else {
1237 /* SET operation */
1238 memset((char *)data, 0, sizeof(data));
1239 parse_arguments(respbuf + strlen(CMD_NXP) +
1240 strlen(PRIV_CMD_REJECTADDBAREQ),
1241 data, ARRAY_SIZE(data), &user_data_len);
1242 }
1243
1244 if (user_data_len > 1) {
1245 PRINTM(MERROR, "Too many arguments\n");
1246 ret = -EINVAL;
1247 goto done;
1248 }
1249
1250 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1251 if (req == NULL) {
1252 ret = -ENOMEM;
1253 goto done;
1254 }
1255
1256 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1257 cfg_11n->sub_command = MLAN_OID_11N_CFG_REJECT_ADDBA_REQ;
1258 req->req_id = MLAN_IOCTL_11N_CFG;
1259
1260 if (user_data_len == 0) {
1261 /* Get the reject addba req conditions*/
1262 req->action = MLAN_ACT_GET;
1263 } else {
1264 /* Set the reject addba req conditions */
1265 cfg_11n->param.reject_addba_req.conditions = data[0];
1266 req->action = MLAN_ACT_SET;
1267 }
1268
1269 /* Send IOCTL request to MLAN */
1270 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1271 if (status != MLAN_STATUS_SUCCESS) {
1272 ret = -EFAULT;
1273 goto done;
1274 }
1275 if (req->action == MLAN_ACT_GET) {
1276 sprintf(respbuf, "0x%x",
1277 cfg_11n->param.reject_addba_req.conditions);
1278 ret = strlen(respbuf) + 1;
1279 } else {
1280 ret = sprintf(respbuf, "OK\n") + 1;
1281 }
1282
1283 done:
1284 if (status != MLAN_STATUS_PENDING)
1285 kfree(req);
1286 LEAVE();
1287 return ret;
1288 }
1289
1290 /**
1291 * @brief Set/Get the addba reject setting
1292 *
1293 * @param priv A pointer to moal_private structure
1294 * @param action Action set or get
1295 * @param addba_reject A pointer to addba_reject array.
1296 *
1297 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1298 * otherwise fail
1299 */
woal_ioctl_addba_reject(moal_private * priv,t_u32 action,t_u8 * addba_reject)1300 static mlan_status woal_ioctl_addba_reject(moal_private *priv, t_u32 action,
1301 t_u8 *addba_reject)
1302 {
1303 mlan_ioctl_req *req = NULL;
1304 mlan_ds_11n_cfg *cfg_11n = NULL;
1305 mlan_status ret = MLAN_STATUS_SUCCESS;
1306
1307 ENTER();
1308 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1309 if (req == NULL) {
1310 ret = -ENOMEM;
1311 goto done;
1312 }
1313
1314 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1315 cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
1316 req->req_id = MLAN_IOCTL_11N_CFG;
1317
1318 req->action = action;
1319 if (action == MLAN_ACT_SET)
1320 moal_memcpy_ext(priv->phandle, cfg_11n->param.addba_reject,
1321 addba_reject,
1322 sizeof(cfg_11n->param.addba_reject),
1323 sizeof(cfg_11n->param.addba_reject));
1324 /* Send IOCTL request to MLAN */
1325 ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1326 if (ret != MLAN_STATUS_SUCCESS)
1327 goto done;
1328 if (action == MLAN_ACT_GET)
1329 moal_memcpy_ext(priv->phandle, addba_reject,
1330 cfg_11n->param.addba_reject,
1331 sizeof(cfg_11n->param.addba_reject),
1332 MAX_NUM_TID);
1333 done:
1334 if (ret != MLAN_STATUS_PENDING)
1335 kfree(req);
1336 LEAVE();
1337 return ret;
1338 }
1339
1340 /**
1341 * @brief Set/Get addba prio_tbl
1342 *
1343 * @param priv A pointer to moal_private structure
1344 * @param action Action set or get
1345 * @param aggr_prio_tbl A pointer to mlan_ds_11n_aggr_prio_tbl.
1346 *
1347 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1348 * otherwise fail
1349 */
woal_ioctl_aggr_prio_tbl(moal_private * priv,t_u32 action,mlan_ds_11n_aggr_prio_tbl * aggr_prio_tbl)1350 mlan_status woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action,
1351 mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl)
1352 {
1353 mlan_ioctl_req *req = NULL;
1354 mlan_ds_11n_cfg *cfg_11n = NULL;
1355 mlan_status ret = MLAN_STATUS_SUCCESS;
1356
1357 ENTER();
1358
1359 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1360 if (req == NULL) {
1361 ret = -ENOMEM;
1362 goto done;
1363 }
1364
1365 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1366 cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
1367 req->req_id = MLAN_IOCTL_11N_CFG;
1368
1369 req->action = action;
1370 if (action == MLAN_ACT_SET)
1371 moal_memcpy_ext(priv->phandle, &cfg_11n->param.aggr_prio_tbl,
1372 aggr_prio_tbl,
1373 sizeof(mlan_ds_11n_aggr_prio_tbl),
1374 sizeof(mlan_ds_11n_aggr_prio_tbl));
1375 /* Send IOCTL request to MLAN */
1376 ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1377 if (ret != MLAN_STATUS_SUCCESS)
1378 goto done;
1379 if (action == MLAN_ACT_GET)
1380 moal_memcpy_ext(priv->phandle, aggr_prio_tbl,
1381 &cfg_11n->param.aggr_prio_tbl,
1382 sizeof(mlan_ds_11n_aggr_prio_tbl),
1383 sizeof(mlan_ds_11n_aggr_prio_tbl));
1384 done:
1385 if (ret != MLAN_STATUS_PENDING)
1386 kfree(req);
1387 LEAVE();
1388 return ret;
1389 }
1390
1391 /**
1392 * @brief Set/Get addba_param
1393 *
1394 * @param priv A pointer to moal_private structure
1395 * @param action Action set or get
1396 * @param addba_param A pointer to mlan_ds_11n_addba_param.
1397 *
1398 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
1399 * otherwise fail
1400 */
woal_ioctl_addba_param(moal_private * priv,t_u32 action,mlan_ds_11n_addba_param * addba_param)1401 static mlan_status woal_ioctl_addba_param(moal_private *priv, t_u32 action,
1402 mlan_ds_11n_addba_param *addba_param)
1403 {
1404 mlan_ioctl_req *req = NULL;
1405 mlan_ds_11n_cfg *cfg_11n = NULL;
1406 mlan_status ret = MLAN_STATUS_SUCCESS;
1407
1408 ENTER();
1409
1410 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1411 if (req == NULL) {
1412 ret = -ENOMEM;
1413 goto done;
1414 }
1415
1416 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1417 cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
1418 req->req_id = MLAN_IOCTL_11N_CFG;
1419
1420 req->action = action;
1421 if (action == MLAN_ACT_SET)
1422 moal_memcpy_ext(priv->phandle, &cfg_11n->param.addba_param,
1423 addba_param, sizeof(mlan_ds_11n_addba_param),
1424 sizeof(mlan_ds_11n_addba_param));
1425 /* Send IOCTL request to MLAN */
1426 ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1427 if (ret != MLAN_STATUS_SUCCESS)
1428 goto done;
1429 if (action == MLAN_ACT_GET)
1430 moal_memcpy_ext(priv->phandle, addba_param,
1431 &cfg_11n->param.addba_param,
1432 sizeof(mlan_ds_11n_addba_param),
1433 sizeof(mlan_ds_11n_addba_param));
1434 done:
1435 if (ret != MLAN_STATUS_PENDING)
1436 kfree(req);
1437 LEAVE();
1438 return ret;
1439 }
1440
1441 /**
1442 * @brief Configuring rx block-ack window size
1443 *
1444 * @param priv A pointer to moal_private structure
1445 * @param respbuf A pointer to response buffer
1446 * @param respbuflen Available length of response buffer
1447 *
1448 * @return 0 --success, otherwise failure
1449 */
woal_set_rx_ba_winsize(moal_private * priv,t_u8 * respbuf,int respbuflen)1450 static int woal_set_rx_ba_winsize(moal_private *priv, t_u8 *respbuf,
1451 int respbuflen)
1452 {
1453 int data[2];
1454 t_u8 addba_reject[MAX_NUM_TID];
1455 mlan_ds_11n_addba_param addba_param;
1456 int ret = 0;
1457 int user_data_len = 0;
1458
1459 ENTER();
1460
1461 memset((char *)data, 0, sizeof(data));
1462 if (respbuf && strlen(respbuf) > 0)
1463 parse_arguments(respbuf, data, ARRAY_SIZE(data),
1464 &user_data_len);
1465
1466 if (user_data_len != 2) {
1467 PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
1468 ret = -EINVAL;
1469 goto done;
1470 }
1471 if (data[0] > 7 || data[0] < 0) {
1472 PRINTM(MERROR, "Invalid tid %d\n", data[0]);
1473 ret = -EINVAL;
1474 goto done;
1475 }
1476 if (data[1] < 0) {
1477 PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
1478 ret = -EINVAL;
1479 goto done;
1480 }
1481 memset(addba_reject, 0, sizeof(addba_reject));
1482 if (MLAN_STATUS_SUCCESS !=
1483 woal_ioctl_addba_reject(priv, MLAN_ACT_GET, addba_reject)) {
1484 ret = -EFAULT;
1485 goto done;
1486 }
1487 /* disable tx ba */
1488 if (data[1] == 0) {
1489 addba_reject[data[0]] = MTRUE;
1490 if (MLAN_STATUS_SUCCESS !=
1491 woal_ioctl_addba_reject(priv, MLAN_ACT_SET, addba_reject))
1492 ret = -EFAULT;
1493 } else {
1494 if (addba_reject[data[0]] == MTRUE) {
1495 addba_reject[data[0]] = MFALSE;
1496 if (MLAN_STATUS_SUCCESS !=
1497 woal_ioctl_addba_reject(priv, MLAN_ACT_SET,
1498 addba_reject)) {
1499 ret = -EFAULT;
1500 goto done;
1501 }
1502 }
1503 memset(&addba_param, 0, sizeof(addba_param));
1504 if (MLAN_STATUS_SUCCESS !=
1505 woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
1506 ret = -EFAULT;
1507 goto done;
1508 }
1509 if (data[1] != (int)addba_param.rxwinsize) {
1510 addba_param.rxwinsize = data[1];
1511 if (MLAN_STATUS_SUCCESS !=
1512 woal_ioctl_addba_param(priv, MLAN_ACT_SET,
1513 &addba_param))
1514 ret = -EFAULT;
1515 }
1516 }
1517 done:
1518 LEAVE();
1519 return ret;
1520 }
1521 /**
1522 * @brief Configuring trx block-ack window size
1523 *
1524 * @param priv A pointer to moal_private structure
1525 * @param respbuf A pointer to response buffer
1526 * @param respbuflen Available length of response buffer
1527 *
1528 * @return 0 --success, otherwise failure
1529 */
woal_set_tx_ba_winsize(moal_private * priv,t_u8 * respbuf,int respbuflen)1530 static int woal_set_tx_ba_winsize(moal_private *priv, t_u8 *respbuf,
1531 int respbuflen)
1532 {
1533 int data[2];
1534 mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl;
1535 mlan_ds_11n_addba_param addba_param;
1536 t_u8 tos_to_tid_inv[] = {0x02, 0x00, 0x01, 0x03,
1537 0x04, 0x05, 0x06, 0x07};
1538 int ret = 0;
1539 int user_data_len = 0;
1540
1541 ENTER();
1542
1543 memset((char *)data, 0, sizeof(data));
1544 if (respbuf && strlen(respbuf) > 0)
1545 parse_arguments(respbuf, data, ARRAY_SIZE(data),
1546 &user_data_len);
1547
1548 if (user_data_len != 2) {
1549 PRINTM(MERROR, "Invalid arguments for ba_winsize command\n");
1550 ret = -EINVAL;
1551 goto done;
1552 }
1553 if (data[0] > 7 || data[0] < 0) {
1554 PRINTM(MERROR, "Invalid tid %d\n", data[0]);
1555 ret = -EINVAL;
1556 goto done;
1557 }
1558 if (data[1] < 0) {
1559 PRINTM(MERROR, "Invalid winsize %d\n", data[1]);
1560 ret = -EINVAL;
1561 goto done;
1562 }
1563 memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl));
1564 if (MLAN_STATUS_SUCCESS !=
1565 woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) {
1566 ret = -EFAULT;
1567 goto done;
1568 }
1569 /* disable tx ba */
1570 if (data[1] == 0) {
1571 if (aggr_prio_tbl.ampdu[data[0]] != 0xff) {
1572 aggr_prio_tbl.ampdu[data[0]] = 0xff;
1573 if (MLAN_STATUS_SUCCESS !=
1574 woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
1575 &aggr_prio_tbl))
1576 ret = -EFAULT;
1577 }
1578 } else {
1579 if (aggr_prio_tbl.ampdu[data[0]] == 0xff) {
1580 aggr_prio_tbl.ampdu[data[0]] = tos_to_tid_inv[data[0]];
1581 if (MLAN_STATUS_SUCCESS !=
1582 woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET,
1583 &aggr_prio_tbl)) {
1584 ret = -EFAULT;
1585 goto done;
1586 }
1587 }
1588 memset(&addba_param, 0, sizeof(addba_param));
1589 if (MLAN_STATUS_SUCCESS !=
1590 woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) {
1591 ret = -EFAULT;
1592 goto done;
1593 }
1594 if (data[1] != (int)addba_param.txwinsize) {
1595 addba_param.txwinsize = data[1];
1596 if (MLAN_STATUS_SUCCESS !=
1597 woal_ioctl_addba_param(priv, MLAN_ACT_SET,
1598 &addba_param))
1599 ret = -EFAULT;
1600 }
1601 }
1602 done:
1603 LEAVE();
1604 return ret;
1605 }
1606
1607 /**
1608 * @brief Set/Get aggregation priority table configurations
1609 *
1610 * @param priv A pointer to moal_private structure
1611 * @param respbuf A pointer to response buffer
1612 * @param respbuflen Available length of response buffer
1613 *
1614 * @return Number of bytes written, negative for failure.
1615 */
woal_setget_priv_aggrpriotbl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1616 static int woal_setget_priv_aggrpriotbl(moal_private *priv, t_u8 *respbuf,
1617 t_u32 respbuflen)
1618 {
1619 int data[MAX_NUM_TID * 2], i, j;
1620 mlan_ioctl_req *req = NULL;
1621 mlan_ds_11n_cfg *cfg_11n = NULL;
1622 int ret = 0;
1623 int user_data_len = 0;
1624 mlan_status status = MLAN_STATUS_SUCCESS;
1625
1626 ENTER();
1627
1628 if (strlen(respbuf) ==
1629 (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRPRIOTBL))) {
1630 /* GET operation */
1631 user_data_len = 0;
1632 } else {
1633 /* SET operation */
1634 memset((char *)data, 0, sizeof(data));
1635 parse_arguments(respbuf + strlen(CMD_NXP) +
1636 strlen(PRIV_CMD_AGGRPRIOTBL),
1637 data, ARRAY_SIZE(data), &user_data_len);
1638
1639 if (user_data_len != ARRAY_SIZE(data)) {
1640 PRINTM(MERROR, "Invalid number of arguments\n");
1641 ret = -EINVAL;
1642 goto done;
1643 }
1644 for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
1645 if ((data[i] > 7 && data[i] != 0xff) ||
1646 (data[i + 1] > 7 && data[i + 1] != 0xff)) {
1647 PRINTM(MERROR,
1648 "Invalid priority, valid value 0-7 or 0xff.\n");
1649 ret = -EFAULT;
1650 goto done;
1651 }
1652 }
1653 }
1654 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1655 if (req == NULL) {
1656 ret = -ENOMEM;
1657 goto done;
1658 }
1659
1660 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1661 cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
1662 req->req_id = MLAN_IOCTL_11N_CFG;
1663
1664 if (user_data_len == 0) {
1665 /* Get aggr priority table from MLAN */
1666 req->action = MLAN_ACT_GET;
1667 } else {
1668 for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) {
1669 cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i];
1670 cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1];
1671 }
1672 /* Update aggr priority table in MLAN */
1673 req->action = MLAN_ACT_SET;
1674 }
1675 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1676 if (status != MLAN_STATUS_SUCCESS) {
1677 ret = -EFAULT;
1678 goto done;
1679 }
1680
1681 for (i = 0, j = 0; i < (MAX_NUM_TID * 2); i = i + 2, ++j) {
1682 respbuf[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j];
1683 respbuf[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j];
1684 }
1685
1686 ret = sizeof(data);
1687
1688 done:
1689 if (status != MLAN_STATUS_PENDING)
1690 kfree(req);
1691 LEAVE();
1692 return ret;
1693 }
1694
1695 /**
1696 * @brief Set/Get Add BA reject configurations
1697 *
1698 * @param priv A pointer to moal_private structure
1699 * @param respbuf A pointer to response buffer
1700 * @param respbuflen Available length of response buffer
1701 *
1702 * @return Number of bytes written, negative for failure.
1703 */
woal_setget_priv_addbareject(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1704 static int woal_setget_priv_addbareject(moal_private *priv, t_u8 *respbuf,
1705 t_u32 respbuflen)
1706 {
1707 int data[MAX_NUM_TID], i;
1708 mlan_ioctl_req *req = NULL;
1709 mlan_ds_11n_cfg *cfg_11n = NULL;
1710 int ret = 0;
1711 int user_data_len = 0;
1712 mlan_status status = MLAN_STATUS_SUCCESS;
1713
1714 ENTER();
1715
1716 if (strlen(respbuf) ==
1717 (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAREJECT))) {
1718 /* GET operation */
1719 user_data_len = 0;
1720 } else {
1721 /* SET operation */
1722 memset((char *)data, 0, sizeof(data));
1723 parse_arguments(respbuf + strlen(CMD_NXP) +
1724 strlen(PRIV_CMD_ADDBAREJECT),
1725 data, ARRAY_SIZE(data), &user_data_len);
1726
1727 if (user_data_len != ARRAY_SIZE(data)) {
1728 PRINTM(MERROR, "Invalid number of arguments\n");
1729 ret = -EINVAL;
1730 goto done;
1731 }
1732 for (i = 0; i < user_data_len; i++) {
1733 if (data[i] != 0 && data[i] != 1) {
1734 PRINTM(MERROR,
1735 "addba reject only takes argument as 0 or 1\n");
1736 ret = -EFAULT;
1737 goto done;
1738 }
1739 }
1740 }
1741 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
1742 if (req == NULL) {
1743 ret = -ENOMEM;
1744 goto done;
1745 }
1746
1747 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
1748 cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
1749 req->req_id = MLAN_IOCTL_11N_CFG;
1750
1751 if (user_data_len == 0) {
1752 /* Get add BA reject configuration from MLAN */
1753 req->action = MLAN_ACT_GET;
1754 } else {
1755 for (i = 0; i < user_data_len; i++)
1756 cfg_11n->param.addba_reject[i] = data[i];
1757 /* Update add BA reject configuration in MLAN */
1758 req->action = MLAN_ACT_SET;
1759 }
1760 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1761 if (status != MLAN_STATUS_SUCCESS) {
1762 ret = -EFAULT;
1763 goto done;
1764 }
1765
1766 for (i = 0; i < MAX_NUM_TID; i++)
1767 respbuf[i] = cfg_11n->param.addba_reject[i];
1768
1769 ret = sizeof(data);
1770
1771 done:
1772 if (status != MLAN_STATUS_PENDING)
1773 kfree(req);
1774 LEAVE();
1775 return ret;
1776 }
1777
1778 /**
1779 * @brief Set/Get 11AC configurations
1780 *
1781 * @param priv A pointer to moal_private structure
1782 * @param respbuf A pointer to response buffer
1783 * @param respbuflen Available length of response buffer
1784 *
1785 * @return Number of bytes written, negative for failure.
1786 */
woal_setget_priv_vhtcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1787 static int woal_setget_priv_vhtcfg(moal_private *priv, t_u8 *respbuf,
1788 t_u32 respbuflen)
1789 {
1790 int data[6];
1791 mlan_ioctl_req *req = NULL;
1792 mlan_ds_11ac_cfg *cfg_11ac = NULL;
1793 mlan_ds_11ac_vht_cfg *vhtcfg = NULL;
1794 int ret = 0;
1795 int user_data_len = 0;
1796 mlan_status status = MLAN_STATUS_SUCCESS;
1797
1798 ENTER();
1799
1800 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG))) {
1801 PRINTM(MERROR, "Invalid number of arguments\n");
1802 ret = -EINVAL;
1803 goto done;
1804 }
1805 memset((char *)data, 0, sizeof(data));
1806 parse_arguments(respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG),
1807 data, ARRAY_SIZE(data), &user_data_len);
1808
1809 if ((user_data_len > 6) || (user_data_len < 2)) {
1810 PRINTM(MERROR, "Invalid number of arguments\n");
1811 ret = -EINVAL;
1812 goto done;
1813 }
1814 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
1815 if (req == NULL) {
1816 ret = -ENOMEM;
1817 goto done;
1818 }
1819
1820 cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
1821 cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
1822 req->req_id = MLAN_IOCTL_11AC_CFG;
1823
1824 /* Band */
1825 if ((data[0] < 0) || (data[0] > 2)) {
1826 PRINTM(MERROR, "Invalid band selection\n");
1827 ret = -EINVAL;
1828 goto done;
1829 } else {
1830 if (data[0] == BAND_SELECT_BOTH) {
1831 cfg_11ac->param.vht_cfg.band =
1832 (BAND_SELECT_BG | BAND_SELECT_A);
1833 } else {
1834 cfg_11ac->param.vht_cfg.band = data[0];
1835 }
1836 PRINTM(MINFO, "GET/SET: vhtcfg band: 0x%x\n", data[0]);
1837 }
1838
1839 /* Tx/Rx */
1840 if ((data[1] <= 0) || (data[1] > 3)) {
1841 PRINTM(MERROR, "Invalid Tx/Rx selection\n");
1842 ret = -EINVAL;
1843 goto done;
1844 } else {
1845 cfg_11ac->param.vht_cfg.txrx = data[1];
1846 PRINTM(MINFO, "GET/SET: vhtcfg txrx: 0x%x\n", data[1]);
1847 }
1848
1849 if (user_data_len == 2) {
1850 /* GET operation */
1851 if (data[0] == BAND_SELECT_BOTH) {
1852 /* if get both bands, get BG first */
1853 cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG;
1854 }
1855 if (priv->bss_role == MLAN_BSS_ROLE_UAP)
1856 cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
1857
1858 req->action = MLAN_ACT_GET;
1859 } else {
1860 if (user_data_len == 3) {
1861 PRINTM(MERROR, "Invalid number of arguments\n");
1862 ret = -EINVAL;
1863 goto done;
1864 }
1865 if (user_data_len >= 4) {
1866 /* BW cfg */
1867 if ((data[2] < 0) || (data[2] > 1) ||
1868 ((data[2] == 1) && (data[0] & BAND_SELECT_BG))) {
1869 PRINTM(MERROR, "Invalid BW cfg selection\n");
1870 ret = -EINVAL;
1871 goto done;
1872 } else {
1873 cfg_11ac->param.vht_cfg.bwcfg = data[2];
1874 PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n",
1875 data[2]);
1876 }
1877
1878 cfg_11ac->param.vht_cfg.vht_cap_info = data[3];
1879 PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n",
1880 data[3]);
1881 }
1882 if (user_data_len == 4) {
1883 data[4] = 0xffffffff;
1884 data[5] = 0xffffffff;
1885 }
1886 if (user_data_len == 5) {
1887 PRINTM(MERROR, "Invalid number of arguments\n");
1888 ret = -EINVAL;
1889 goto done;
1890 }
1891 if (user_data_len >= 4) {
1892 cfg_11ac->param.vht_cfg.vht_tx_mcs = data[4];
1893 cfg_11ac->param.vht_cfg.vht_rx_mcs = data[5];
1894 }
1895 /* Update 11AC parameters in MLAN */
1896 req->action = MLAN_ACT_SET;
1897 }
1898 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1899 if (status != MLAN_STATUS_SUCCESS) {
1900 ret = -EFAULT;
1901 goto done;
1902 }
1903
1904 /* number of vhtcfg entries */
1905 *respbuf = 1;
1906 vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1);
1907 moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1908 sizeof(mlan_ds_11ac_vht_cfg), respbuflen - 1);
1909 ret = 1 + sizeof(mlan_ds_11ac_vht_cfg);
1910
1911 if ((req->action == MLAN_ACT_GET) && (data[0] == BAND_SELECT_BOTH)) {
1912 cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
1913 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1914 if (status != MLAN_STATUS_SUCCESS) {
1915 ret = -EFAULT;
1916 goto done;
1917 }
1918 /* number of vhtcfg entries */
1919 *respbuf = 2;
1920 vhtcfg++;
1921 moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg,
1922 sizeof(mlan_ds_11ac_vht_cfg),
1923 respbuflen - 1 - sizeof(mlan_ds_11ac_vht_cfg));
1924 ret += sizeof(mlan_ds_11ac_vht_cfg);
1925 }
1926
1927 done:
1928 if (status != MLAN_STATUS_PENDING)
1929 kfree(req);
1930 LEAVE();
1931 return ret;
1932 }
1933
1934 /**
1935 * @brief Set/Get 11AC Operating Mode Notification configurations
1936 *
1937 * @param priv A pointer to moal_private structure
1938 * @param respbuf A pointer to response buffer
1939 * @param respbuflen Available length of response buffer
1940 *
1941 * @return Number of bytes written, negative for failure.
1942 */
woal_setget_priv_opermodecfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)1943 static int woal_setget_priv_opermodecfg(moal_private *priv, t_u8 *respbuf,
1944 t_u32 respbuflen)
1945 {
1946 int data[2];
1947 mlan_ioctl_req *req = NULL;
1948 mlan_ds_11ac_cfg *cfg_11ac = NULL;
1949 mlan_ds_11ac_opermode_cfg *opermodecfg = NULL;
1950 int ret = 0;
1951 int user_data_len = 0;
1952 mlan_status status = MLAN_STATUS_SUCCESS;
1953
1954 ENTER();
1955
1956 memset((char *)data, 0, sizeof(data));
1957 parse_arguments(respbuf + strlen(CMD_NXP) +
1958 strlen(PRIV_CMD_OPERMODECFG),
1959 data, ARRAY_SIZE(data), &user_data_len);
1960
1961 if ((user_data_len != 0) && (user_data_len != 2)) {
1962 PRINTM(MERROR, "Invalid number of arguments\n");
1963 ret = -EINVAL;
1964 goto done;
1965 }
1966 if (user_data_len == 2) {
1967 /* Channel width */
1968 if ((data[0] < 1) || (data[0] > 4)) {
1969 PRINTM(MERROR, "Invalid channel width: 0x%x\n",
1970 data[0]);
1971 ret = -EINVAL;
1972 goto done;
1973 }
1974 /* nss */
1975 if ((data[1] < 1) || (data[1] > 8)) {
1976 PRINTM(MERROR, "Invalid nss: 0x%x\n", data[1]);
1977 ret = -EINVAL;
1978 goto done;
1979 }
1980 }
1981
1982 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
1983 if (req == NULL) {
1984 ret = -ENOMEM;
1985 goto done;
1986 }
1987
1988 cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
1989 cfg_11ac->sub_command = MLAN_OID_11AC_OPERMODE_CFG;
1990 req->req_id = MLAN_IOCTL_11AC_CFG;
1991
1992 if (user_data_len == 0) {
1993 req->action = MLAN_ACT_GET;
1994 } else {
1995 req->action = MLAN_ACT_SET;
1996 cfg_11ac->param.opermode_cfg.bw = data[0];
1997 cfg_11ac->param.opermode_cfg.nss = data[1];
1998 }
1999 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2000 if (status != MLAN_STATUS_SUCCESS) {
2001 ret = -EFAULT;
2002 goto done;
2003 }
2004 opermodecfg = (mlan_ds_11ac_opermode_cfg *)respbuf;
2005 moal_memcpy_ext(priv->phandle, opermodecfg,
2006 &(cfg_11ac->param.opermode_cfg), sizeof(*opermodecfg),
2007 respbuflen);
2008 ret = sizeof(*opermodecfg);
2009
2010 done:
2011 if (status != MLAN_STATUS_PENDING)
2012 kfree(req);
2013 LEAVE();
2014 return ret;
2015 }
2016
2017 /**
2018 * @brief Set/Get 11AC configurations
2019 *
2020 * @param priv A pointer to moal_private structure
2021 * @param respbuf A pointer to response buffer
2022 * @param respbuflen Available length of response buffer
2023 *
2024 * @return Number of bytes written, negative for failure.
2025 */
woal_get_priv_datarate(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2026 static int woal_get_priv_datarate(moal_private *priv, t_u8 *respbuf,
2027 t_u32 respbuflen)
2028 {
2029 mlan_ioctl_req *req = NULL;
2030 mlan_ds_rate *rate = NULL;
2031 mlan_data_rate *data_rate = NULL;
2032 int ret = 0;
2033 mlan_status status = MLAN_STATUS_SUCCESS;
2034
2035 ENTER();
2036
2037 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2038 if (req == NULL) {
2039 ret = -ENOMEM;
2040 goto done;
2041 }
2042
2043 rate = (mlan_ds_rate *)req->pbuf;
2044 rate->sub_command = MLAN_OID_GET_DATA_RATE;
2045 req->req_id = MLAN_IOCTL_RATE;
2046 req->action = MLAN_ACT_GET;
2047
2048 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2049 if (status != MLAN_STATUS_SUCCESS) {
2050 ret = -EFAULT;
2051 goto done;
2052 }
2053
2054 data_rate = (mlan_data_rate *)respbuf;
2055
2056 moal_memcpy_ext(priv->phandle, data_rate, &rate->param.data_rate,
2057 sizeof(mlan_data_rate), respbuflen);
2058
2059 ret = sizeof(mlan_data_rate);
2060
2061 done:
2062 if (status != MLAN_STATUS_PENDING)
2063 kfree(req);
2064 LEAVE();
2065 return ret;
2066 }
2067
2068 /**
2069 * @brief Set/Get tx rate configurations
2070 *
2071 * @param priv A pointer to moal_private structure
2072 * @param respbuf A pointer to response buffer
2073 * @param respbuflen Available length of response buffer
2074 *
2075 * @return Number of bytes written, negative for failure.
2076 */
woal_setget_priv_txratecfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2077 static int woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf,
2078 t_u32 respbuflen)
2079 {
2080 t_u32 data[4];
2081 mlan_ioctl_req *req = NULL;
2082 mlan_ds_rate *rate = NULL;
2083 woal_tx_rate_cfg *ratecfg = NULL;
2084 int ret = 0;
2085 int user_data_len = 0;
2086 mlan_status status = MLAN_STATUS_SUCCESS;
2087 txrate_setting *rate_setting = NULL;
2088
2089 ENTER();
2090
2091 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) {
2092 /* GET operation */
2093 user_data_len = 0;
2094 } else {
2095 /* SET operation */
2096 memset((char *)data, 0, sizeof(data));
2097 parse_arguments(respbuf + strlen(CMD_NXP) +
2098 strlen(PRIV_CMD_TXRATECFG),
2099 data, ARRAY_SIZE(data), &user_data_len);
2100 }
2101
2102 if (user_data_len > 4) {
2103 PRINTM(MERROR, "Too many arguments\n");
2104 ret = -EINVAL;
2105 goto done;
2106 }
2107
2108 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2109 if (req == NULL) {
2110 ret = -ENOMEM;
2111 goto done;
2112 }
2113
2114 req->req_id = MLAN_IOCTL_RATE;
2115 rate = (mlan_ds_rate *)req->pbuf;
2116 rate->sub_command = MLAN_OID_RATE_CFG;
2117 rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
2118
2119 if (user_data_len == 0) {
2120 /* Get operation */
2121 req->action = MLAN_ACT_GET;
2122 } else {
2123 /* Set operation */
2124 req->action = MLAN_ACT_SET;
2125 /* format */
2126 if ((data[0] != AUTO_RATE) && (data[0] >= 4)) {
2127 PRINTM(MERROR, "Invalid format selection\n");
2128 ret = -EINVAL;
2129 goto done;
2130 }
2131 if (data[0] == AUTO_RATE) {
2132 /* auto */
2133 rate->param.rate_cfg.is_rate_auto = 1;
2134 } else {
2135 /* fixed rate */
2136 PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]);
2137 if ((data[0] != AUTO_RATE) &&
2138 (data[0] > MLAN_RATE_FORMAT_HE)) {
2139 PRINTM(MERROR, "Invalid format selection\n");
2140 ret = -EINVAL;
2141 goto done;
2142 }
2143 rate->param.rate_cfg.rate_format = data[0];
2144
2145 if (user_data_len >= 2) {
2146 PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
2147 data[1]);
2148 /* sanity check */
2149 if (((data[0] == MLAN_RATE_FORMAT_LG) &&
2150 (data[1] > MLAN_RATE_INDEX_OFDM7)) ||
2151 ((data[0] == MLAN_RATE_FORMAT_HT) &&
2152 (data[1] != 32) && (data[1] > 15)) ||
2153 ((data[0] == MLAN_RATE_FORMAT_VHT) &&
2154 (data[1] > MLAN_RATE_INDEX_MCS9)) ||
2155 ((data[0] == MLAN_RATE_FORMAT_HE) &&
2156 (data[1] > MLAN_RATE_INDEX_MCS11))) {
2157 PRINTM(MERROR,
2158 "Invalid index selection\n");
2159 ret = -EINVAL;
2160 goto done;
2161 }
2162
2163 PRINTM(MINFO, "SET: txratefg index: 0x%x\n",
2164 data[1]);
2165 rate->param.rate_cfg.rate = data[1];
2166 }
2167
2168 if (data[0] == 2 || data[0] == 3) {
2169 PRINTM(MINFO, "SET: txratefg nss: 0x%x\n",
2170 data[2]);
2171 /* NSS is supported up to 2 */
2172 if ((data[2] <= 0) || (data[2] >= 3)) {
2173 PRINTM(MERROR,
2174 "Invalid nss selection\n");
2175 ret = -EINVAL;
2176 goto done;
2177 }
2178 rate->param.rate_cfg.nss = data[2];
2179 }
2180 if (user_data_len == 4) {
2181 rate->param.rate_cfg.rate_setting =
2182 data[3] & ~0x0C00;
2183 PRINTM(MIOCTL,
2184 "SET: txratefg HE Rate Setting: 0x%x\n",
2185 data[3]);
2186
2187 /* HE Preamble type */
2188 //#define HE_SU_PREAMBLE 0
2189 #define HE_ER_PREAMBLE 1
2190
2191 /* HE ER SU Type */
2192 #define HE_ER_SU_BANDWIDTH_TONE242 0
2193 #define HE_ER_SU_BANDWIDTH_TONE106 1
2194
2195 rate_setting = (txrate_setting *)&data[3];
2196
2197 if (data[0] == MLAN_RATE_FORMAT_HE) {
2198 if (rate_setting->preamble ==
2199 HE_ER_PREAMBLE) {
2200 if (rate_setting->bandwidth ==
2201 HE_ER_SU_BANDWIDTH_TONE242) {
2202 if ((data[1] >
2203 MLAN_RATE_INDEX_MCS2) ||
2204 data[2] >
2205 MLAN_RATE_NSS1) {
2206 PRINTM(MERROR,
2207 "Invalid rate and MCS or NSS configuration for 242 tone\n");
2208 ret = -EINVAL;
2209 goto done;
2210 }
2211 } else if (rate_setting
2212 ->bandwidth ==
2213 HE_ER_SU_BANDWIDTH_TONE106) {
2214 if ((data[1] !=
2215 MLAN_RATE_INDEX_MCS0) ||
2216 data[2] !=
2217 MLAN_RATE_NSS1) {
2218 PRINTM(MERROR,
2219 "Invalid rate and MCS or NSS configuration\n for 106 tone");
2220 ret = -EINVAL;
2221 goto done;
2222 }
2223 } else {
2224 PRINTM(MERROR,
2225 "Invalid Bandwidth for HE ER Preamble\n");
2226 ret = -EINVAL;
2227 goto done;
2228 }
2229 }
2230 if ((rate_setting->dcm) &&
2231 (rate_setting->stbc == 0)) {
2232 if ((data[1] ==
2233 MLAN_RATE_INDEX_MCS2) ||
2234 (data[1] >
2235 MLAN_RATE_INDEX_MCS4)) {
2236 PRINTM(MERROR,
2237 "Invalid MCS configuration if DCM is supported\n");
2238 ret = -EINVAL;
2239 goto done;
2240 }
2241 }
2242 }
2243 } else {
2244 rate->param.rate_cfg.rate_setting = 0xffff;
2245 }
2246 }
2247 }
2248
2249 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2250 if (status != MLAN_STATUS_SUCCESS) {
2251 ret = -EFAULT;
2252 goto done;
2253 }
2254
2255 ratecfg = (woal_tx_rate_cfg *)respbuf;
2256 if (rate->param.rate_cfg.is_rate_auto == MTRUE) {
2257 ratecfg->rate_format = 0xFF;
2258 } else {
2259 /* fixed rate */
2260 ratecfg->rate_format = rate->param.rate_cfg.rate_format;
2261 ratecfg->rate_index = rate->param.rate_cfg.rate;
2262 if (rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_VHT ||
2263 rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_HE)
2264 ratecfg->nss = rate->param.rate_cfg.nss;
2265 ratecfg->rate_setting = rate->param.rate_cfg.rate_setting;
2266 }
2267
2268 ret = sizeof(woal_tx_rate_cfg);
2269
2270 done:
2271 if (status != MLAN_STATUS_PENDING)
2272 kfree(req);
2273 LEAVE();
2274 return ret;
2275 }
2276
2277 #if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
2278 /**
2279 * @brief Get statistics information
2280 *
2281 * @param priv A pointer to moal_private structure
2282 * @param wait_option Wait option
2283 * @param stats A pointer to mlan_ds_get_stats structure
2284 *
2285 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success,
2286 * otherwise fail
2287 */
woal_get_stats_info(moal_private * priv,t_u8 wait_option,mlan_ds_get_stats * stats)2288 mlan_status woal_get_stats_info(moal_private *priv, t_u8 wait_option,
2289 mlan_ds_get_stats *stats)
2290 {
2291 mlan_ds_get_info *info = NULL;
2292 mlan_ioctl_req *req = NULL;
2293 mlan_status status = MLAN_STATUS_SUCCESS;
2294 ENTER();
2295
2296 /* Allocate an IOCTL request buffer */
2297 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
2298 if (req == NULL) {
2299 status = MLAN_STATUS_FAILURE;
2300 goto done;
2301 }
2302
2303 /* Fill request buffer */
2304 info = (mlan_ds_get_info *)req->pbuf;
2305 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
2306 info->sub_command = MLAN_OID_GET_STATS;
2307 else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
2308 info->sub_command = MLAN_OID_GET_UAP_STATS_LOG;
2309 req->req_id = MLAN_IOCTL_GET_INFO;
2310 req->action = MLAN_ACT_GET;
2311
2312 /* Send IOCTL request to MLAN */
2313 status = woal_request_ioctl(priv, req, wait_option);
2314 if (status == MLAN_STATUS_SUCCESS) {
2315 if (stats)
2316 moal_memcpy_ext(priv->phandle, stats,
2317 &info->param.stats,
2318 sizeof(mlan_ds_get_stats),
2319 sizeof(mlan_ds_get_stats));
2320 #if defined(STA_WEXT) || defined(UAP_WEXT)
2321 priv->w_stats.discard.fragment = info->param.stats.fcs_error;
2322 priv->w_stats.discard.retries = info->param.stats.retry;
2323 priv->w_stats.discard.misc = info->param.stats.ack_failure;
2324 #endif
2325 }
2326 done:
2327 if (status != MLAN_STATUS_PENDING)
2328 kfree(req);
2329 LEAVE();
2330 return status;
2331 }
2332
2333 /**
2334 * @brief Get wireless stats information
2335 *
2336 * @param priv A pointer to moal_private structure
2337 * @param respbuf A pointer to response buffer
2338 * @param respbuflen Available length of response buffer
2339 *
2340 * @return Number of bytes written, negative for failure.
2341 */
woal_get_priv_getlog(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2342 static int woal_get_priv_getlog(moal_private *priv, t_u8 *respbuf,
2343 t_u32 respbuflen)
2344 {
2345 int ret = 0;
2346 mlan_ds_get_stats *stats;
2347 ENTER();
2348
2349 if (respbuflen < sizeof(*stats)) {
2350 PRINTM(MERROR, "Get log: respbuflen (%d) too small!",
2351 (int)respbuflen);
2352 ret = -EFAULT;
2353 goto done;
2354 }
2355 stats = (mlan_ds_get_stats *)respbuf;
2356 if (MLAN_STATUS_SUCCESS !=
2357 woal_get_stats_info(priv, MOAL_IOCTL_WAIT, stats)) {
2358 PRINTM(MERROR, "Get log: Failed to get stats info!");
2359 ret = -EFAULT;
2360 goto done;
2361 }
2362
2363 if (priv->phandle->fw_getlog_enable)
2364 ret = sizeof(mlan_ds_get_stats);
2365 else
2366 ret = sizeof(mlan_ds_get_stats_org);
2367
2368 done:
2369 LEAVE();
2370 return ret;
2371 }
2372 #endif
2373
2374 /**
2375 * @brief Set/Get esupplicant mode configurations
2376 *
2377 * @param priv A pointer to moal_private structure
2378 * @param respbuf A pointer to response buffer
2379 * @param respbuflen Available length of response buffer
2380 *
2381 * @return Number of bytes written, negative for failure.
2382 */
woal_setget_priv_esuppmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2383 static int woal_setget_priv_esuppmode(moal_private *priv, t_u8 *respbuf,
2384 t_u32 respbuflen)
2385 {
2386 t_u32 data[3];
2387 mlan_ioctl_req *req = NULL;
2388 mlan_ds_sec_cfg *sec = NULL;
2389 woal_esuppmode_cfg *esupp_mode = NULL;
2390 int ret = 0;
2391 int user_data_len = 0;
2392 mlan_status status = MLAN_STATUS_SUCCESS;
2393
2394 ENTER();
2395
2396 if (!priv->phandle->card_info->embedded_supp) {
2397 PRINTM(MERROR, "Not supported cmd on this card\n");
2398 ret = -EOPNOTSUPP;
2399 goto done;
2400 }
2401 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ESUPPMODE))) {
2402 /* GET operation */
2403 user_data_len = 0;
2404 } else {
2405 /* SET operation */
2406 memset((char *)data, 0, sizeof(data));
2407 parse_arguments(respbuf + strlen(CMD_NXP) +
2408 strlen(PRIV_CMD_ESUPPMODE),
2409 data, ARRAY_SIZE(data), &user_data_len);
2410 }
2411
2412 if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) {
2413 PRINTM(MERROR, "Invalid number of arguments\n");
2414 ret = -EINVAL;
2415 goto done;
2416 }
2417
2418 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2419 if (req == NULL) {
2420 ret = -ENOMEM;
2421 goto done;
2422 }
2423
2424 req->req_id = MLAN_IOCTL_SEC_CFG;
2425 sec = (mlan_ds_sec_cfg *)req->pbuf;
2426 sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE;
2427
2428 if (user_data_len == 0) {
2429 /* Get operation */
2430 req->action = MLAN_ACT_GET;
2431 } else {
2432 /* Set operation */
2433 req->action = MLAN_ACT_SET;
2434 /* RSN mode */
2435 sec->param.esupp_mode.rsn_mode = data[0];
2436 /* Pairwise cipher */
2437 sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF);
2438 /* Group cipher */
2439 sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF);
2440 }
2441
2442 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2443 if (status != MLAN_STATUS_SUCCESS) {
2444 ret = -EFAULT;
2445 goto done;
2446 }
2447
2448 esupp_mode = (woal_esuppmode_cfg *)respbuf;
2449 esupp_mode->rsn_mode =
2450 (t_u16)((sec->param.esupp_mode.rsn_mode) & 0xFFFF);
2451 esupp_mode->pairwise_cipher =
2452 (t_u8)((sec->param.esupp_mode.act_paircipher) & 0xFF);
2453 esupp_mode->group_cipher =
2454 (t_u8)((sec->param.esupp_mode.act_groupcipher) & 0xFF);
2455
2456 ret = sizeof(woal_esuppmode_cfg);
2457 done:
2458 if (status != MLAN_STATUS_PENDING)
2459 kfree(req);
2460 LEAVE();
2461 return ret;
2462 }
2463
2464 /**
2465 * @brief Set/Get esupplicant passphrase configurations
2466 *
2467 * @param priv A pointer to moal_private structure
2468 * @param respbuf A pointer to response buffer
2469 * @param respbuflen Available length of response buffer
2470 *
2471 * @return Number of bytes written, negative for failure.
2472 */
woal_setget_priv_passphrase(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2473 static int woal_setget_priv_passphrase(moal_private *priv, t_u8 *respbuf,
2474 t_u32 respbuflen)
2475 {
2476 mlan_ioctl_req *req = NULL;
2477 mlan_ds_sec_cfg *sec = NULL;
2478 int ret = 0, action = -1, i = 0;
2479 char *begin, *end, *opt;
2480 t_u16 len = 0;
2481 t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0};
2482 t_u8 *mac = NULL;
2483 mlan_status status = MLAN_STATUS_SUCCESS;
2484
2485 ENTER();
2486
2487 if (!priv->phandle->card_info->embedded_supp) {
2488 PRINTM(MERROR, "Not supported cmd on this card\n");
2489 ret = -EOPNOTSUPP;
2490 goto done;
2491 }
2492
2493 if (strlen(respbuf) ==
2494 (strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE))) {
2495 PRINTM(MERROR, "No arguments provided\n");
2496 ret = -EINVAL;
2497 goto done;
2498 }
2499
2500 /* Parse the buf to get the cmd_action */
2501 begin = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE);
2502 end = woal_strsep(&begin, ';', '/');
2503 if (end)
2504 action = woal_atox(end);
2505 if (action < 0 || action > 2 || end[1] != '\0') {
2506 PRINTM(MERROR, "Invalid action argument %s\n", end);
2507 ret = -EINVAL;
2508 goto done;
2509 }
2510
2511 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
2512 if (req == NULL) {
2513 ret = -ENOMEM;
2514 goto done;
2515 }
2516
2517 req->req_id = MLAN_IOCTL_SEC_CFG;
2518 sec = (mlan_ds_sec_cfg *)req->pbuf;
2519 sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
2520 if (action == 0)
2521 req->action = MLAN_ACT_GET;
2522 else
2523 req->action = MLAN_ACT_SET;
2524
2525 while (begin) {
2526 end = woal_strsep(&begin, ';', '/');
2527 opt = woal_strsep(&end, '=', '/');
2528 if (!opt || !end || !end[0]) {
2529 PRINTM(MERROR, "Invalid option\n");
2530 ret = -EINVAL;
2531 break;
2532 } else if (!strnicmp(opt, "ssid", strlen(opt))) {
2533 if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
2534 PRINTM(MERROR,
2535 "SSID length exceeds max length\n");
2536 ret = -EFAULT;
2537 break;
2538 }
2539 sec->param.passphrase.ssid.ssid_len = strlen(end);
2540 moal_memcpy_ext(priv->phandle,
2541 sec->param.passphrase.ssid.ssid, end,
2542 strlen(end), MLAN_MAX_SSID_LENGTH);
2543 PRINTM(MINFO, "ssid=%s, len=%d\n",
2544 sec->param.passphrase.ssid.ssid,
2545 (int)sec->param.passphrase.ssid.ssid_len);
2546 } else if (!strnicmp(opt, "bssid", strlen(opt))) {
2547 woal_mac2u8((t_u8 *)&sec->param.passphrase.bssid, end);
2548 } else if (!strnicmp(opt, "psk", strlen(opt)) &&
2549 req->action == MLAN_ACT_SET) {
2550 if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) {
2551 PRINTM(MERROR, "Invalid PMK length\n");
2552 ret = -EINVAL;
2553 break;
2554 }
2555 woal_ascii2hex(
2556 (t_u8 *)(sec->param.passphrase.psk.pmk.pmk),
2557 end, MLAN_PMK_HEXSTR_LENGTH / 2);
2558 sec->param.passphrase.psk_type = MLAN_PSK_PMK;
2559 } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
2560 req->action == MLAN_ACT_SET) {
2561 if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH ||
2562 strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) {
2563 PRINTM(MERROR,
2564 "Invalid length for passphrase\n");
2565 ret = -EINVAL;
2566 break;
2567 }
2568 sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE;
2569 moal_memcpy_ext(
2570 priv->phandle,
2571 sec->param.passphrase.psk.passphrase.passphrase,
2572 end,
2573 sizeof(sec->param.passphrase.psk.passphrase
2574 .passphrase),
2575 sizeof(sec->param.passphrase.psk.passphrase
2576 .passphrase));
2577 sec->param.passphrase.psk.passphrase.passphrase_len =
2578 strlen(end);
2579 PRINTM(MINFO, "passphrase=%s, len=%d\n",
2580 sec->param.passphrase.psk.passphrase.passphrase,
2581 (int)sec->param.passphrase.psk.passphrase
2582 .passphrase_len);
2583 } else if (!strnicmp(opt, "sae_password", strlen(opt)) &&
2584 req->action == MLAN_ACT_SET) {
2585 if (strlen(end) < MLAN_MIN_SAE_PASSWORD_LENGTH ||
2586 strlen(end) > MLAN_MAX_SAE_PASSWORD_LENGTH) {
2587 PRINTM(MERROR,
2588 "Invalid length for sae password\n");
2589 ret = -EINVAL;
2590 break;
2591 }
2592 sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD;
2593 moal_memcpy_ext(
2594 priv->phandle,
2595 sec->param.passphrase.psk.sae_password
2596 .sae_password,
2597 end,
2598 sizeof(sec->param.passphrase.psk.sae_password
2599 .sae_password),
2600 sizeof(sec->param.passphrase.psk.sae_password
2601 .sae_password));
2602 sec->param.passphrase.psk.sae_password.sae_password_len =
2603 strlen(end);
2604 PRINTM(MINFO, "sae_password=%s, len=%d\n",
2605 sec->param.passphrase.psk.sae_password
2606 .sae_password,
2607 (int)sec->param.passphrase.psk.sae_password
2608 .sae_password_len);
2609 } else {
2610 PRINTM(MERROR, "Invalid option %s\n", opt);
2611 ret = -EINVAL;
2612 break;
2613 }
2614 }
2615 if (ret)
2616 goto done;
2617
2618 if (action == 2)
2619 sec->param.passphrase.psk_type = MLAN_PSK_CLEAR;
2620 else if (action == 0)
2621 sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
2622
2623 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2624 if (status != MLAN_STATUS_SUCCESS) {
2625 ret = -EFAULT;
2626 goto done;
2627 }
2628
2629 memset(respbuf, 0, respbuflen);
2630 if (sec->param.passphrase.ssid.ssid_len) {
2631 len += sprintf(respbuf + len, "ssid:");
2632 moal_memcpy_ext(priv->phandle, respbuf + len,
2633 sec->param.passphrase.ssid.ssid,
2634 sec->param.passphrase.ssid.ssid_len,
2635 respbuflen - len);
2636 len += sec->param.passphrase.ssid.ssid_len;
2637 len += sprintf(respbuf + len, " ");
2638 }
2639 if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) {
2640 mac = (t_u8 *)&sec->param.passphrase.bssid;
2641 len += sprintf(respbuf + len, "bssid:");
2642 for (i = 0; i < ETH_ALEN - 1; ++i)
2643 len += sprintf(respbuf + len, "%02x:", mac[i]);
2644 len += sprintf(respbuf + len, "%02x ", mac[i]);
2645 }
2646 if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) {
2647 len += sprintf(respbuf + len, "psk:");
2648 for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i)
2649 len += sprintf(respbuf + len, "%02x",
2650 sec->param.passphrase.psk.pmk.pmk[i]);
2651 len += sprintf(respbuf + len, "\n");
2652 }
2653 if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE)
2654 len += sprintf(respbuf + len, "passphrase:%s\n",
2655 sec->param.passphrase.psk.passphrase.passphrase);
2656 if (sec->param.passphrase.psk_type == MLAN_PSK_SAE_PASSWORD)
2657 len += sprintf(
2658 respbuf + len, "sae_password:%s\n",
2659 sec->param.passphrase.psk.sae_password.sae_password);
2660
2661 ret = len;
2662 done:
2663 if (status != MLAN_STATUS_PENDING)
2664 kfree(req);
2665 LEAVE();
2666 return ret;
2667 }
2668
2669 /**
2670 * @brief Deauthenticate
2671 *
2672 * @param priv A pointer to moal_private structure
2673 * @param respbuf A pointer to response buffer
2674 * @param respbuflen Available length of response buffer
2675 *
2676 * @return Number of bytes written, negative for failure.
2677 */
woal_priv_deauth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2678 static int woal_priv_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
2679 {
2680 int ret = 0;
2681 t_u8 mac[ETH_ALEN];
2682
2683 ENTER();
2684
2685 if (strlen(respbuf) > (strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH))) {
2686 /* Deauth mentioned BSSID */
2687 woal_mac2u8(mac, respbuf + strlen(CMD_NXP) +
2688 strlen(PRIV_CMD_DEAUTH));
2689 if (MLAN_STATUS_SUCCESS !=
2690 woal_disconnect(priv, MOAL_IOCTL_WAIT, mac,
2691 DEF_DEAUTH_REASON_CODE)) {
2692 ret = -EFAULT;
2693 goto done;
2694 }
2695 } else {
2696 if (MLAN_STATUS_SUCCESS !=
2697 woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
2698 DEF_DEAUTH_REASON_CODE))
2699 ret = -EFAULT;
2700 }
2701
2702 done:
2703 LEAVE();
2704 return ret;
2705 }
2706
2707 #ifdef UAP_SUPPORT
2708 /**
2709 * @brief uap station deauth ioctl handler
2710 *
2711 * @param priv A pointer to moal_private structure
2712 * @param respbuf A pointer to response buffer
2713 * @param respbuflen Available length of response buffer
2714 *
2715 * @return Number of bytes written, negative for failure.
2716 */
woal_priv_ap_deauth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2717 static int woal_priv_ap_deauth(moal_private *priv, t_u8 *respbuf,
2718 t_u32 respbuflen)
2719 {
2720 t_u8 *data_ptr;
2721 mlan_ioctl_req *ioctl_req = NULL;
2722 mlan_ds_bss *bss = NULL;
2723 mlan_deauth_param deauth_param;
2724 int ret = 0;
2725 mlan_status status = MLAN_STATUS_SUCCESS;
2726
2727 ENTER();
2728
2729 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH));
2730 memset(&deauth_param, 0, sizeof(mlan_deauth_param));
2731 moal_memcpy_ext(priv->phandle, &deauth_param, data_ptr,
2732 sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
2733
2734 PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n",
2735 MAC2STR(deauth_param.mac_addr), deauth_param.reason_code);
2736
2737 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2738 if (ioctl_req == NULL) {
2739 ret = -ENOMEM;
2740 goto done;
2741 }
2742 bss = (mlan_ds_bss *)ioctl_req->pbuf;
2743
2744 bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
2745 ioctl_req->req_id = MLAN_IOCTL_BSS;
2746 ioctl_req->action = MLAN_ACT_SET;
2747
2748 moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param,
2749 sizeof(mlan_deauth_param), sizeof(mlan_deauth_param));
2750 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2751 if (status != MLAN_STATUS_SUCCESS) {
2752 ret = -EFAULT;
2753 goto done;
2754 }
2755
2756 moal_memcpy_ext(
2757 priv->phandle, data_ptr, &ioctl_req->status_code, sizeof(t_u32),
2758 respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH)));
2759 ret = sizeof(t_u32);
2760 done:
2761 if (status != MLAN_STATUS_PENDING)
2762 kfree(ioctl_req);
2763 LEAVE();
2764 return ret;
2765 }
2766
2767 /**
2768 * @brief uap get station list handler
2769 *
2770 * @param dev A pointer to net_device structure
2771 * @param req A pointer to ifreq structure
2772 * @return 0 --success, otherwise fail
2773 */
woal_priv_get_sta_list(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2774 static int woal_priv_get_sta_list(moal_private *priv, t_u8 *respbuf,
2775 t_u32 respbuflen)
2776 {
2777 int ret = 0;
2778 mlan_ds_get_info *info = NULL;
2779 mlan_ds_sta_list *sta_list = NULL;
2780 mlan_ioctl_req *ioctl_req = NULL;
2781 mlan_status status = MLAN_STATUS_SUCCESS;
2782
2783 ENTER();
2784
2785 /* Allocate an IOCTL request buffer */
2786 ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
2787 sizeof(mlan_ds_get_info));
2788 if (ioctl_req == NULL) {
2789 ret = -ENOMEM;
2790 goto done;
2791 }
2792
2793 info = (mlan_ds_get_info *)ioctl_req->pbuf;
2794 info->sub_command = MLAN_OID_UAP_STA_LIST;
2795 ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
2796 ioctl_req->action = MLAN_ACT_GET;
2797
2798 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2799 if (status != MLAN_STATUS_SUCCESS) {
2800 ret = -EFAULT;
2801 goto done;
2802 }
2803
2804 sta_list = (mlan_ds_sta_list *)(respbuf + strlen(CMD_NXP) +
2805 strlen(PRIV_CMD_GET_STA_LIST));
2806 moal_memcpy_ext(
2807 priv->phandle, sta_list, &info->param.sta_list,
2808 ioctl_req->data_read_written,
2809 respbuflen - (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_STA_LIST)));
2810 ret = ioctl_req->data_read_written + strlen(CMD_NXP) +
2811 strlen(PRIV_CMD_GET_STA_LIST);
2812 done:
2813 if (status != MLAN_STATUS_PENDING)
2814 kfree(ioctl_req);
2815 LEAVE();
2816 return ret;
2817 }
2818
2819 /**
2820 * @brief uap bss_config 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_priv_bss_config(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2826 static int woal_priv_bss_config(moal_private *priv, t_u8 *respbuf,
2827 t_u32 respbuflen)
2828 {
2829 int ret = 0;
2830 mlan_ds_bss *bss = NULL;
2831 mlan_ioctl_req *ioctl_req = NULL;
2832 t_u32 action = 0;
2833 int offset = 0;
2834 mlan_status status = MLAN_STATUS_SUCCESS;
2835
2836 ENTER();
2837
2838 offset = strlen(CMD_NXP) + strlen(PRIV_CMD_BSS_CONFIG);
2839 moal_memcpy_ext(priv->phandle, (u8 *)&action, respbuf + offset,
2840 sizeof(action), sizeof(action));
2841 offset += sizeof(action);
2842
2843 /* Allocate an IOCTL request buffer */
2844 ioctl_req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(
2845 sizeof(mlan_ds_bss));
2846 if (ioctl_req == NULL) {
2847 ret = -ENOMEM;
2848 goto done;
2849 }
2850
2851 bss = (mlan_ds_bss *)ioctl_req->pbuf;
2852 bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
2853 ioctl_req->req_id = MLAN_IOCTL_BSS;
2854 if (action == 1) {
2855 ioctl_req->action = MLAN_ACT_SET;
2856 /* Get the BSS config from user */
2857 moal_memcpy_ext(priv->phandle, &bss->param.bss_config,
2858 respbuf + offset, sizeof(mlan_uap_bss_param),
2859 sizeof(mlan_uap_bss_param));
2860 } else {
2861 ioctl_req->action = MLAN_ACT_GET;
2862 }
2863
2864 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
2865 if (status != MLAN_STATUS_SUCCESS) {
2866 ret = -EFAULT;
2867 goto done;
2868 }
2869
2870 if (ioctl_req->action == MLAN_ACT_GET) {
2871 moal_memcpy_ext(priv->phandle, respbuf + offset,
2872 &bss->param.bss_config,
2873 sizeof(mlan_uap_bss_param),
2874 respbuflen - (t_u32)offset);
2875 }
2876 ret = sizeof(mlan_uap_bss_param);
2877 done:
2878 if (status != MLAN_STATUS_PENDING)
2879 kfree(ioctl_req);
2880 LEAVE();
2881 return ret;
2882 }
2883 #endif
2884
2885 #ifdef WIFI_DIRECT_SUPPORT
2886 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
2887 /**
2888 * @brief Set/Get BSS role
2889 *
2890 * @param priv A pointer to moal_private structure
2891 * @param respbuf A pointer to response buffer
2892 * @param respbuflen Available length of response buffer
2893 *
2894 * @return Number of bytes written, negative for failure.
2895 */
woal_priv_bssrole(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2896 static int woal_priv_bssrole(moal_private *priv, t_u8 *respbuf,
2897 t_u32 respbuflen)
2898 {
2899 t_u32 data[1];
2900 int ret = 0;
2901 int user_data_len = 0;
2902 t_u8 action = MLAN_ACT_GET;
2903
2904 ENTER();
2905
2906 memset((char *)data, 0, sizeof(data));
2907 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BSSROLE))) {
2908 /* GET operation */
2909 user_data_len = 0;
2910 } else {
2911 /* SET operation */
2912 parse_arguments(respbuf + strlen(CMD_NXP) +
2913 strlen(PRIV_CMD_BSSROLE),
2914 data, ARRAY_SIZE(data), &user_data_len);
2915 }
2916
2917 if (user_data_len >= 2) {
2918 PRINTM(MERROR, "Too many arguments\n");
2919 ret = -EINVAL;
2920 goto error;
2921 }
2922
2923 if (user_data_len == 0) {
2924 action = MLAN_ACT_GET;
2925 } else {
2926 if ((data[0] != MLAN_BSS_ROLE_STA &&
2927 data[0] != MLAN_BSS_ROLE_UAP) ||
2928 priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
2929 PRINTM(MWARN, "Invalid BSS role\n");
2930 ret = -EINVAL;
2931 goto error;
2932 }
2933 if (data[0] == GET_BSS_ROLE(priv)) {
2934 PRINTM(MWARN, "Already BSS is in desired role\n");
2935 goto done;
2936 }
2937 action = MLAN_ACT_SET;
2938 /* Reset interface */
2939 if (MLAN_STATUS_SUCCESS !=
2940 woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE)) {
2941 PRINTM(MERROR, "%s: woal_reset_intf failed \n",
2942 __func__);
2943 ret = -EFAULT;
2944 goto error;
2945 }
2946 }
2947
2948 if (MLAN_STATUS_SUCCESS !=
2949 woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, (t_u8 *)data)) {
2950 ret = -EFAULT;
2951 goto error;
2952 }
2953
2954 if (user_data_len) {
2955 /* Initialize private structures */
2956 woal_init_priv(priv, MOAL_IOCTL_WAIT);
2957 /* Enable interfaces */
2958 netif_device_attach(priv->netdev);
2959 woal_start_queue(priv->netdev);
2960 }
2961
2962 done:
2963 memset(respbuf, 0, respbuflen);
2964 respbuf[0] = (t_u8)data[0];
2965 ret = 1;
2966
2967 error:
2968 LEAVE();
2969 return ret;
2970 }
2971 #endif /* STA_SUPPORT && UAP_SUPPORT */
2972 #endif /* WIFI_DIRECT_SUPPORT */
2973
2974 #ifdef STA_SUPPORT
2975 /**
2976 * @brief Set user scan
2977 *
2978 * @param priv A pointer to moal_private structure
2979 * @param respbuf A pointer to response buffer
2980 * @param respbuflen Available length of response buffer
2981 *
2982 * @return Number of bytes written, negative for failure.
2983 */
woal_priv_setuserscan(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)2984 static int woal_priv_setuserscan(moal_private *priv, t_u8 *respbuf,
2985 t_u32 respbuflen)
2986 {
2987 wlan_user_scan_cfg *scan_cfg;
2988 int ret = 0;
2989
2990 ENTER();
2991
2992 scan_cfg = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
2993 GFP_KERNEL);
2994 if (!scan_cfg) {
2995 PRINTM(MERROR, "Malloc buffer failed\n");
2996 LEAVE();
2997 return -ENOMEM;
2998 }
2999
3000 /* Create the scan_cfg structure */
3001 memset(scan_cfg, 0, sizeof(wlan_user_scan_cfg));
3002
3003 /* We expect the scan_cfg structure to be passed in respbuf */
3004 moal_memcpy_ext(priv->phandle, (char *)scan_cfg,
3005 respbuf + strlen(CMD_NXP) +
3006 strlen(PRIV_CMD_SETUSERSCAN),
3007 sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg));
3008 moal_memcpy_ext(priv->phandle, scan_cfg->random_mac, priv->random_mac,
3009 ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
3010 /* Call for scan */
3011 if (MLAN_STATUS_FAILURE == woal_do_scan(priv, scan_cfg))
3012 ret = -EFAULT;
3013 kfree(scan_cfg);
3014 LEAVE();
3015 return ret;
3016 }
3017
3018 /**
3019 * @brief Get channel statistics
3020 *
3021 * @param priv A pointer to moal_private structure
3022 * @param respbuf A pointer to response buffer
3023 * @param respbuflen Available length of response buffer
3024 *
3025 * @return Number of bytes written, negative for failure.
3026 */
woal_priv_get_chanstats(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3027 static int woal_priv_get_chanstats(moal_private *priv, t_u8 *respbuf,
3028 t_u32 respbuflen)
3029 {
3030 mlan_scan_resp scan_resp;
3031 chan_stats *stats = NULL;
3032 int ret = 0;
3033 ENTER();
3034
3035 if (!respbuf) {
3036 PRINTM(MERROR, "response buffer is not available!\n");
3037 ret = -EINVAL;
3038 goto done;
3039 }
3040 mdelay(10);
3041 memset(&scan_resp, 0, sizeof(scan_resp));
3042 if (MLAN_STATUS_SUCCESS !=
3043 woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
3044 ret = -EFAULT;
3045 goto done;
3046 }
3047 memset(respbuf, 0, respbuflen);
3048 stats = (chan_stats *)respbuf;
3049 stats->num_in_chan_stats = scan_resp.num_in_chan_stats;
3050 ret = sizeof(ChanStatistics_t) * stats->num_in_chan_stats;
3051 moal_memcpy_ext(priv->phandle, (t_u8 *)stats->stats,
3052 (t_u8 *)scan_resp.pchan_stats, ret, respbuflen);
3053 ret += sizeof(stats->num_in_chan_stats);
3054 done:
3055 LEAVE();
3056 return ret;
3057 }
3058
3059 /**
3060 * @brief Retrieve the scan response/beacon table
3061 *
3062 * @param respbuf A pointer to response buffer
3063 * @param respbuflen Available length of response buffer
3064 * @param scan_resp A pointer to mlan_scan_resp structure
3065 * @param scan_start Argument
3066 *
3067 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
3068 */
moal_ret_get_scan_table_ioctl(t_u8 * respbuf,t_u32 respbuflen,mlan_scan_resp * scan_resp,t_u32 scan_start)3069 static int moal_ret_get_scan_table_ioctl(t_u8 *respbuf, t_u32 respbuflen,
3070 mlan_scan_resp *scan_resp,
3071 t_u32 scan_start)
3072 {
3073 pBSSDescriptor_t pbss_desc, scan_table;
3074 wlan_ioctl_get_scan_table_info *prsp_info;
3075 int ret_code;
3076 int ret_len;
3077 int space_left;
3078 t_u8 *pcurrent;
3079 t_u8 *pbuffer_end;
3080 t_u32 num_scans_done;
3081
3082 ENTER();
3083
3084 num_scans_done = 0;
3085 ret_code = MLAN_STATUS_SUCCESS;
3086
3087 prsp_info = (wlan_ioctl_get_scan_table_info *)respbuf;
3088 pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf;
3089
3090 pbuffer_end = respbuf + respbuflen - 1;
3091 space_left = pbuffer_end - pcurrent;
3092 scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table);
3093
3094 PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start);
3095 PRINTM(MINFO, "GetScanTable: length avail = %d\n", respbuflen);
3096
3097 if (!scan_start) {
3098 PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n");
3099
3100 /* Use to get current association saved descriptor */
3101 pbss_desc = scan_table;
3102
3103 ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent,
3104 &space_left);
3105
3106 if (ret_code == MLAN_STATUS_SUCCESS)
3107 num_scans_done = 1;
3108
3109 } else {
3110 scan_start--;
3111
3112 while (space_left &&
3113 (scan_start + num_scans_done <
3114 scan_resp->num_in_scan_table) &&
3115 (ret_code == MLAN_STATUS_SUCCESS)) {
3116 pbss_desc =
3117 (scan_table + (scan_start + num_scans_done));
3118
3119 PRINTM(MINFO,
3120 "GetScanTable: get current BSS Descriptor [%d]\n",
3121 scan_start + num_scans_done);
3122
3123 ret_code = wlan_get_scan_table_ret_entry(
3124 pbss_desc, &pcurrent, &space_left);
3125
3126 if (ret_code == MLAN_STATUS_SUCCESS)
3127 num_scans_done++;
3128 }
3129 }
3130
3131 prsp_info->scan_number = num_scans_done;
3132 ret_len = pcurrent - respbuf;
3133
3134 LEAVE();
3135 return ret_len;
3136 }
3137
3138 /**
3139 * @brief Get scan table
3140 *
3141 * @param priv A pointer to moal_private structure
3142 * @param respbuf A pointer to response buffer
3143 * @param respbuflen Available length of response buffer
3144 *
3145 * @return Number of bytes written, negative for failure.
3146 */
woal_priv_getscantable(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3147 static int woal_priv_getscantable(moal_private *priv, t_u8 *respbuf,
3148 t_u32 respbuflen)
3149 {
3150 int ret = 0;
3151 mlan_ioctl_req *req = NULL;
3152 mlan_ds_scan *scan = NULL;
3153 t_u32 scan_start;
3154 mlan_status status = MLAN_STATUS_SUCCESS;
3155 moal_handle *handle = priv->phandle;
3156
3157 ENTER();
3158
3159 /* First make sure scanning is not in progress */
3160 if (handle->scan_pending_on_block == MTRUE) {
3161 ret = -EAGAIN;
3162 goto done;
3163 }
3164
3165 /* Allocate an IOCTL request buffer */
3166 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
3167 if (req == NULL) {
3168 ret = -ENOMEM;
3169 goto done;
3170 }
3171
3172 /* Fill request buffer */
3173 scan = (mlan_ds_scan *)req->pbuf;
3174 req->req_id = MLAN_IOCTL_SCAN;
3175 req->action = MLAN_ACT_GET;
3176
3177 /* Get the whole command from user */
3178 moal_memcpy_ext(handle, &scan_start,
3179 respbuf + strlen(CMD_NXP) +
3180 strlen(PRIV_CMD_GETSCANTABLE),
3181 sizeof(scan_start), sizeof(scan_start));
3182 if (scan_start)
3183 scan->sub_command = MLAN_OID_SCAN_NORMAL;
3184 else
3185 scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS;
3186
3187 /* Send IOCTL request to MLAN */
3188 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3189 if (status == MLAN_STATUS_SUCCESS) {
3190 ret = moal_ret_get_scan_table_ioctl(respbuf, respbuflen,
3191 &scan->param.scan_resp,
3192 scan_start);
3193 }
3194 done:
3195 if (status != MLAN_STATUS_PENDING)
3196 kfree(req);
3197 LEAVE();
3198 return ret;
3199 }
3200 /**
3201 * @brief Extended capabilities configuration
3202 *
3203 * @param priv A pointer to moal_private structure
3204 * @param respbuf A pointer to response buffer
3205 * @param respbuflen Available length of response buffer
3206 *
3207 * @return Number of bytes written, negative for failure.
3208 */
woal_priv_extcapcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3209 static int woal_priv_extcapcfg(moal_private *priv, t_u8 *respbuf,
3210 t_u32 respbuflen)
3211 {
3212 int ret, header;
3213 mlan_ioctl_req *req = NULL;
3214 mlan_ds_misc_cfg *cfg = NULL;
3215 IEEEtypes_Header_t *ie;
3216 mlan_status status = MLAN_STATUS_SUCCESS;
3217
3218 ENTER();
3219
3220 if (!respbuf) {
3221 LEAVE();
3222 return 0;
3223 }
3224
3225 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3226 if (req == NULL) {
3227 ret = -ENOMEM;
3228 goto done;
3229 }
3230
3231 cfg = (mlan_ds_misc_cfg *)req->pbuf;
3232 cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG;
3233 req->req_id = MLAN_IOCTL_MISC_CFG;
3234 header = strlen(CMD_NXP) + strlen(PRIV_CMD_EXTCAPCFG);
3235 if ((int)strlen(respbuf) == header)
3236 /* GET operation */
3237 req->action = MLAN_ACT_GET;
3238 else {
3239 /* SET operation */
3240 ie = (IEEEtypes_Header_t *)(respbuf + header);
3241 if (ie->len > sizeof(ExtCap_t)) {
3242 PRINTM(MERROR,
3243 "Extended Capability lenth is invalid\n");
3244 ret = -EFAULT;
3245 goto done;
3246 }
3247 req->action = MLAN_ACT_SET;
3248 memset(&cfg->param.ext_cap, 0, sizeof(ExtCap_t));
3249 moal_memcpy_ext(priv->phandle, &cfg->param.ext_cap, ie + 1,
3250 ie->len, sizeof(ExtCap_t));
3251 }
3252
3253 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3254 if (status != MLAN_STATUS_SUCCESS) {
3255 ret = -EFAULT;
3256 goto done;
3257 }
3258
3259 memset(respbuf, 0, respbuflen);
3260 ie = (IEEEtypes_Header_t *)respbuf;
3261 ie->element_id = EXT_CAPABILITY;
3262 ie->len = sizeof(ExtCap_t);
3263 moal_memcpy_ext(priv->phandle, ie + 1, &cfg->param.ext_cap,
3264 sizeof(ExtCap_t),
3265 respbuflen - sizeof(IEEEtypes_Header_t));
3266
3267 ret = sizeof(IEEEtypes_Header_t) + ie->len;
3268
3269 done:
3270 if (status != MLAN_STATUS_PENDING)
3271 kfree(req);
3272 LEAVE();
3273 return ret;
3274 }
3275 #endif
3276
3277 /**
3278 * @brief Set/Get deep sleep mode configurations
3279 *
3280 * @param priv A pointer to moal_private structure
3281 * @param respbuf A pointer to response buffer
3282 * @param respbuflen Available length of response buffer
3283 *
3284 * @return Number of bytes written, negative for failure.
3285 */
woal_priv_setgetdeepsleep(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3286 static int woal_priv_setgetdeepsleep(moal_private *priv, t_u8 *respbuf,
3287 t_u32 respbuflen)
3288 {
3289 t_u32 data[2];
3290 int ret = 0;
3291 int user_data_len = 0;
3292
3293 ENTER();
3294
3295 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DEEPSLEEP))) {
3296 /* GET operation */
3297 user_data_len = 0;
3298 } else {
3299 /* SET operation */
3300 memset((char *)data, 0, sizeof(data));
3301 parse_arguments(respbuf + strlen(CMD_NXP) +
3302 strlen(PRIV_CMD_DEEPSLEEP),
3303 data, ARRAY_SIZE(data), &user_data_len);
3304 }
3305
3306 if (user_data_len >= 3) {
3307 PRINTM(MERROR, "Too many arguments\n");
3308 ret = -EINVAL;
3309 goto done;
3310 }
3311
3312 if (user_data_len == 0) {
3313 if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) {
3314 ret = -EFAULT;
3315 goto done;
3316 }
3317 sprintf(respbuf, "%d %d", data[0], data[1]);
3318 ret = strlen(respbuf) + 1;
3319 } else {
3320 if (data[0] == DEEP_SLEEP_OFF) {
3321 PRINTM(MINFO, "Exit Deep Sleep Mode\n");
3322 ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE,
3323 0);
3324 if (ret != MLAN_STATUS_SUCCESS) {
3325 ret = -EINVAL;
3326 goto done;
3327 }
3328 } else if (data[0] == DEEP_SLEEP_ON) {
3329 PRINTM(MINFO, "Enter Deep Sleep Mode\n");
3330 if (user_data_len != 2)
3331 data[1] = 0;
3332 ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE,
3333 data[1]);
3334 if (ret != MLAN_STATUS_SUCCESS) {
3335 ret = -EINVAL;
3336 goto done;
3337 }
3338 } else {
3339 PRINTM(MERROR, "Unknown option = %u\n", data[0]);
3340 ret = -EINVAL;
3341 goto done;
3342 }
3343 ret = sprintf(respbuf, "OK\n") + 1;
3344 }
3345
3346 done:
3347 LEAVE();
3348 return ret;
3349 }
3350
3351 /**
3352 * @brief Set/Get IP address configurations
3353 *
3354 * @param priv A pointer to moal_private structure
3355 * @param respbuf A pointer to response buffer
3356 * @param respbuflen Available length of response buffer
3357 *
3358 * @return Number of bytes written, negative for failure.
3359 */
woal_priv_setgetipaddr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3360 static int woal_priv_setgetipaddr(moal_private *priv, t_u8 *respbuf,
3361 t_u32 respbuflen)
3362 {
3363 mlan_ioctl_req *req = NULL;
3364 mlan_ds_misc_cfg *misc = NULL;
3365 int ret = 0, op_code = 0, data_length = 0, header = 0;
3366 mlan_status status = MLAN_STATUS_SUCCESS;
3367
3368 ENTER();
3369
3370 if (priv->bss_type != MLAN_BSS_TYPE_STA) {
3371 PRINTM(MIOCTL, "Bss type[%d]: Not STA, ignore it\n",
3372 priv->bss_type);
3373 ret = sprintf(respbuf, "OK\n") + 1;
3374 goto done;
3375 }
3376
3377 header = strlen(CMD_NXP) + strlen(PRIV_CMD_IPADDR);
3378 data_length = strlen(respbuf) - header;
3379
3380 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3381 if (req == NULL) {
3382 ret = -ENOMEM;
3383 goto done;
3384 }
3385 misc = (mlan_ds_misc_cfg *)req->pbuf;
3386
3387 if (data_length < 1) { /* GET */
3388 req->action = MLAN_ACT_GET;
3389 } else {
3390 /* Make sure we have the operation argument */
3391 if (data_length > 2 && respbuf[header + 1] != ';') {
3392 PRINTM(MERROR,
3393 "No operation argument. Separate with ';'\n");
3394 ret = -EINVAL;
3395 goto done;
3396 } else {
3397 respbuf[header + 1] = '\0';
3398 }
3399 req->action = MLAN_ACT_SET;
3400
3401 /* Only one IP is supported in current firmware */
3402 memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN);
3403 if (data_length > 2)
3404 in4_pton(&respbuf[header + 2],
3405 MIN((IPADDR_MAX_BUF - 3), (data_length - 2)),
3406 misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL);
3407 misc->param.ipaddr_cfg.ip_addr_num = 1;
3408 misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4;
3409
3410 if (woal_atoi(&op_code, &respbuf[header]) !=
3411 MLAN_STATUS_SUCCESS) {
3412 ret = -EINVAL;
3413 goto done;
3414 }
3415 misc->param.ipaddr_cfg.op_code = (t_u32)op_code;
3416 }
3417
3418 req->req_id = MLAN_IOCTL_MISC_CFG;
3419 misc->sub_command = MLAN_OID_MISC_IP_ADDR;
3420
3421 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3422 if (status != MLAN_STATUS_SUCCESS) {
3423 ret = -EFAULT;
3424 goto done;
3425 }
3426
3427 if (req->action == MLAN_ACT_GET) {
3428 snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d",
3429 misc->param.ipaddr_cfg.op_code,
3430 misc->param.ipaddr_cfg.ip_addr[0][0],
3431 misc->param.ipaddr_cfg.ip_addr[0][1],
3432 misc->param.ipaddr_cfg.ip_addr[0][2],
3433 misc->param.ipaddr_cfg.ip_addr[0][3]);
3434 ret = IPADDR_MAX_BUF + 1;
3435 } else {
3436 ret = sprintf(respbuf, "OK\n") + 1;
3437 }
3438
3439 done:
3440 if (status != MLAN_STATUS_PENDING)
3441 kfree(req);
3442 LEAVE();
3443 return ret;
3444 }
3445
3446 /**
3447 * @brief Set/Get WPS session configurations
3448 *
3449 * @param priv A pointer to moal_private structure
3450 * @param respbuf A pointer to response buffer
3451 * @param respbuflen Available length of response buffer
3452 *
3453 * @return Number of bytes written, negative for failure.
3454 */
woal_priv_setwpssession(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3455 static int woal_priv_setwpssession(moal_private *priv, t_u8 *respbuf,
3456 t_u32 respbuflen)
3457 {
3458 mlan_ioctl_req *req = NULL;
3459 mlan_ds_wps_cfg *pwps = NULL;
3460 t_u32 data[1];
3461 int ret = 0;
3462 int user_data_len = 0;
3463 mlan_status status = MLAN_STATUS_SUCCESS;
3464
3465 ENTER();
3466
3467 memset((char *)data, 0, sizeof(data));
3468 if (strlen(respbuf) ==
3469 (strlen(CMD_NXP) + strlen(PRIV_CMD_WPSSESSION))) {
3470 /* GET operation */
3471 user_data_len = 0;
3472 } else {
3473 /* SET operation */
3474 parse_arguments(respbuf + strlen(CMD_NXP) +
3475 strlen(PRIV_CMD_WPSSESSION),
3476 data, ARRAY_SIZE(data), &user_data_len);
3477 }
3478
3479 if (user_data_len > 1) {
3480 PRINTM(MERROR, "Too many arguments\n");
3481 ret = -EINVAL;
3482 goto done;
3483 }
3484
3485 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
3486 if (req == NULL) {
3487 ret = -ENOMEM;
3488 goto done;
3489 }
3490 pwps = (mlan_ds_wps_cfg *)req->pbuf;
3491
3492 req->req_id = MLAN_IOCTL_WPS_CFG;
3493 req->action = MLAN_ACT_SET;
3494 pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
3495
3496 if (data[0] == 1)
3497 pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
3498 else
3499 pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
3500
3501 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3502 if (status != MLAN_STATUS_SUCCESS) {
3503 ret = -EFAULT;
3504 goto done;
3505 }
3506
3507 ret = sprintf(respbuf, "OK\n") + 1;
3508 done:
3509 if (status != MLAN_STATUS_PENDING)
3510 kfree(req);
3511 LEAVE();
3512 return ret;
3513 }
3514
3515 /**
3516 * @brief Get OTP user data
3517 *
3518 * @param priv A pointer to moal_private structure
3519 * @param respbuf A pointer to response buffer
3520 * @param respbuflen Available length of response buffer
3521 *
3522 * @return Number of bytes written, negative for failure.
3523 */
woal_priv_otpuserdata(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3524 static int woal_priv_otpuserdata(moal_private *priv, t_u8 *respbuf,
3525 t_u32 respbuflen)
3526 {
3527 int data[1];
3528 int user_data_len = 0;
3529 mlan_ioctl_req *req = NULL;
3530 mlan_ds_misc_cfg *misc = NULL;
3531 mlan_ds_misc_otp_user_data *otp = NULL;
3532 int ret = 0;
3533 mlan_status status = MLAN_STATUS_SUCCESS;
3534
3535 ENTER();
3536
3537 if (strlen(respbuf) ==
3538 (strlen(CMD_NXP) + strlen(PRIV_CMD_OTPUSERDATA))) {
3539 PRINTM(MERROR, "Invalid number of arguments\n");
3540 ret = -EINVAL;
3541 goto done;
3542 }
3543 memset((char *)data, 0, sizeof(data));
3544 parse_arguments(respbuf + strlen(CMD_NXP) +
3545 strlen(PRIV_CMD_OTPUSERDATA),
3546 data, ARRAY_SIZE(data), &user_data_len);
3547
3548 if (user_data_len != 1) {
3549 PRINTM(MERROR, "Invalid number of arguments\n");
3550 ret = -EINVAL;
3551 goto done;
3552 }
3553
3554 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3555 if (req == NULL) {
3556 ret = -ENOMEM;
3557 goto done;
3558 }
3559 req->action = MLAN_ACT_GET;
3560 req->req_id = MLAN_IOCTL_MISC_CFG;
3561
3562 misc = (mlan_ds_misc_cfg *)req->pbuf;
3563 misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA;
3564 misc->param.otp_user_data.user_data_length = data[0];
3565
3566 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3567 if (status != MLAN_STATUS_SUCCESS) {
3568 ret = -EFAULT;
3569 goto done;
3570 }
3571 otp = (mlan_ds_misc_otp_user_data *)req->pbuf;
3572
3573 if (req->action == MLAN_ACT_GET) {
3574 ret = MIN(otp->user_data_length, data[0]);
3575 moal_memcpy_ext(priv->phandle, respbuf, otp->user_data, ret,
3576 respbuflen);
3577 }
3578
3579 done:
3580 if (status != MLAN_STATUS_PENDING)
3581 kfree(req);
3582 LEAVE();
3583 return ret;
3584 }
3585
3586 /**
3587 * @brief Set / Get country code
3588 *
3589 * @param priv A pointer to moal_private structure
3590 * @param respbuf A pointer to response buffer
3591 * @param respbuflen Available length of response buffer
3592 *
3593 * @return Number of bytes written, negative for failure.
3594 */
woal_priv_set_get_countrycode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3595 static int woal_priv_set_get_countrycode(moal_private *priv, t_u8 *respbuf,
3596 t_u32 respbuflen)
3597 {
3598 int ret = 0;
3599 /* char data[COUNTRY_CODE_LEN] = {0, 0, 0}; */
3600 int header = 0, data_length = 0; /* wrq->u.data.length; */
3601 mlan_ioctl_req *req = NULL;
3602 mlan_ds_misc_cfg *pcfg_misc = NULL;
3603 mlan_ds_misc_country_code *country_code = NULL;
3604 mlan_status status = MLAN_STATUS_SUCCESS;
3605
3606 ENTER();
3607
3608 header = strlen(CMD_NXP) + strlen(PRIV_CMD_COUNTRYCODE);
3609 data_length = strlen(respbuf) - header;
3610
3611 if (data_length > COUNTRY_CODE_LEN) {
3612 PRINTM(MERROR, "Invalid argument!\n");
3613 ret = -EINVAL;
3614 goto done;
3615 }
3616
3617 /* Allocate an IOCTL request buffer */
3618 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3619 if (req == NULL) {
3620 ret = -ENOMEM;
3621 goto done;
3622 }
3623
3624 /* Fill request buffer */
3625 pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
3626 country_code = &pcfg_misc->param.country_code;
3627 pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE;
3628 req->req_id = MLAN_IOCTL_MISC_CFG;
3629
3630 if (data_length <= 1) {
3631 req->action = MLAN_ACT_GET;
3632 } else {
3633 memset(country_code->country_code, 0, COUNTRY_CODE_LEN);
3634 moal_memcpy_ext(priv->phandle, country_code->country_code,
3635 respbuf + header, COUNTRY_CODE_LEN,
3636 COUNTRY_CODE_LEN);
3637 req->action = MLAN_ACT_SET;
3638 }
3639
3640 /* Send IOCTL request to MLAN */
3641 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3642 if (status != MLAN_STATUS_SUCCESS) {
3643 ret = -EFAULT;
3644 goto done;
3645 }
3646
3647 if (req->action == MLAN_ACT_GET) {
3648 ret = data_length = COUNTRY_CODE_LEN;
3649 memset(respbuf + header, 0, COUNTRY_CODE_LEN);
3650 moal_memcpy_ext(priv->phandle, respbuf,
3651 country_code->country_code, COUNTRY_CODE_LEN,
3652 respbuflen);
3653 }
3654
3655 done:
3656 if (status != MLAN_STATUS_PENDING)
3657 kfree(req);
3658
3659 LEAVE();
3660 return ret;
3661 }
3662
3663 /**
3664 * @brief Get cfp information
3665 *
3666 * @param priv A pointer to moal_private structure
3667 * @param respbuf A pointer to response buffer
3668 * @param respbuflen Available length of response buffer
3669 *
3670 * @return Number of bytes written, negative for failure.
3671 */
woal_priv_get_cfpinfo(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3672 static int woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf,
3673 t_u32 respbuflen)
3674 {
3675 int ret = 0;
3676 mlan_ioctl_req *req = NULL;
3677 mlan_ds_misc_cfg *cfp_misc = NULL;
3678 mlan_status status = MLAN_STATUS_SUCCESS;
3679
3680 ENTER();
3681
3682 if (!respbuf) {
3683 PRINTM(MERROR, "response buffer is not available!\n");
3684 ret = -EINVAL;
3685 goto done;
3686 }
3687
3688 /* Allocate an IOCTL request buffer */
3689 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3690 if (req == NULL) {
3691 ret = -ENOMEM;
3692 goto done;
3693 }
3694
3695 /* Fill request buffer */
3696 cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
3697 cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO;
3698 req->req_id = MLAN_IOCTL_MISC_CFG;
3699 req->action = MLAN_ACT_GET;
3700
3701 /* Send IOCTL request to MLAN */
3702 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3703 if (status != MLAN_STATUS_SUCCESS) {
3704 ret = -EFAULT;
3705 goto done;
3706 }
3707 if (respbuflen < req->data_read_written) {
3708 PRINTM(MERROR, "response buffer length is too short!\n");
3709 ret = -EINVAL;
3710 goto done;
3711 }
3712 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)req->pbuf,
3713 req->data_read_written, respbuflen);
3714 ret = req->data_read_written;
3715 done:
3716 if (status != MLAN_STATUS_PENDING)
3717 kfree(req);
3718
3719 LEAVE();
3720 return ret;
3721 }
3722
3723 /**
3724 * @brief Set/Get TCP Ack enhancement configurations
3725 *
3726 * @param priv A pointer to moal_private structure
3727 * @param respbuf A pointer to response buffer
3728 * @param respbuflen Available length of response buffer
3729 *
3730 * @return Number of bytes written, negative for failure.
3731 */
woal_priv_setgettcpackenh(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3732 static int woal_priv_setgettcpackenh(moal_private *priv, t_u8 *respbuf,
3733 t_u32 respbuflen)
3734 {
3735 t_u32 data[2] = {0, 0};
3736 int ret = 0;
3737 int user_data_len = 0;
3738
3739 ENTER();
3740 if (!priv || !priv->phandle) {
3741 PRINTM(MERROR, "priv or handle is null\n");
3742 ret = -EFAULT;
3743 goto done;
3744 }
3745
3746 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TCPACKENH))) {
3747 /* GET operation */
3748 user_data_len = 0;
3749 } else {
3750 /* SET operation */
3751 memset((char *)data, 0, sizeof(data));
3752 parse_arguments(respbuf + strlen(CMD_NXP) +
3753 strlen(PRIV_CMD_TCPACKENH),
3754 data, ARRAY_SIZE(data), &user_data_len);
3755 }
3756
3757 if (user_data_len == 0) {
3758 /* get operation */
3759 data[0] = priv->enable_tcp_ack_enh;
3760 data[1] = priv->tcp_ack_max_hold;
3761 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
3762 sizeof(data), respbuflen);
3763 ret = sizeof(data);
3764 } else {
3765 /* set operation */
3766 if (user_data_len >= 3) {
3767 PRINTM(MERROR, "Too many arguments\n");
3768 ret = -EINVAL;
3769 goto done;
3770 }
3771 if (data[0] > 1 || data[1] > TCP_ACK_MAX_HOLD) {
3772 PRINTM(MERROR, "Invalid argument\n");
3773 ret = -EINVAL;
3774 goto done;
3775 }
3776 if (data[0] == MTRUE) {
3777 PRINTM(MINFO, "Enabling TCP Ack enhancement\n");
3778 priv->enable_tcp_ack_enh = MTRUE;
3779 } else if (data[0] == MFALSE) {
3780 PRINTM(MINFO, "Disabling TCP Ack enhancement\n");
3781 priv->enable_tcp_ack_enh = MFALSE;
3782 /* release the tcp sessions if any */
3783 woal_flush_tcp_sess_queue(priv);
3784 }
3785 if (user_data_len >= 2) {
3786 PRINTM(MINFO, "TCP drop Ack configure: %d\n", data[1]);
3787 priv->tcp_ack_max_hold = data[1];
3788 }
3789 data[0] = priv->enable_tcp_ack_enh;
3790 data[1] = priv->tcp_ack_max_hold;
3791 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
3792 sizeof(data), respbuflen);
3793 ret = sizeof(data);
3794 }
3795
3796 done:
3797 LEAVE();
3798 return ret;
3799 }
3800
3801 #ifdef REASSOCIATION
3802 /**
3803 * @brief Set Asynced ESSID
3804 *
3805 * @param priv A pointer to moal_private structure
3806 * @param respbuf A pointer to response buffer
3807 * @param respbuflen Available length of response buffer
3808 * @param bBSSID A variable that bssid is set or not
3809 *
3810 * @return Number of bytes written, negative for failure.
3811 */
woal_priv_assocessid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,t_u8 bBSSID)3812 static int woal_priv_assocessid(moal_private *priv, t_u8 *respbuf,
3813 t_u32 respbuflen, t_u8 bBSSID)
3814 {
3815 mlan_ssid_bssid ssid_bssid;
3816 moal_handle *handle = priv->phandle;
3817 int ret = 0;
3818 int header_len = 0;
3819 int copy_len = 0;
3820 char buf[64];
3821 t_u8 buflen = 0;
3822 t_u8 i = 0;
3823 t_u8 mac_idx = 0;
3824
3825 ENTER();
3826
3827 if (bBSSID)
3828 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCBSSID);
3829 else
3830 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCESSID);
3831
3832 if ((int)strlen(respbuf) == header_len) {
3833 PRINTM(MERROR, "No argument, invalid operation!\n");
3834 ret = -EINVAL;
3835 LEAVE();
3836 return ret;
3837 }
3838 copy_len = strlen(respbuf) - header_len;
3839 buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
3840 memset(buf, 0, sizeof(buf));
3841 memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
3842 moal_memcpy_ext(handle, buf, respbuf + header_len, buflen, sizeof(buf));
3843 priv->assoc_with_mac = MFALSE;
3844
3845 /* check if has parameter BSSID */
3846 if (bBSSID) {
3847 if (buflen < (3 * ETH_ALEN) + 2) {
3848 PRINTM(MERROR,
3849 "Associate: Insufficient length in IOCTL input\n");
3850 /* buffer should be at least 3 characters per BSSID
3851 *octet "00:"
3852 ** plus a space separater and at least 1 char in the
3853 *SSID
3854 */
3855 ret = -EINVAL;
3856 goto setessid_ret;
3857 }
3858 for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' ');
3859 i++) {
3860 if (buf[i] == ':') {
3861 mac_idx++;
3862 } else {
3863 ssid_bssid.bssid[mac_idx] =
3864 (t_u8)woal_atox(buf + i);
3865 while ((i < buflen) && isxdigit(buf[i + 1]))
3866 /* Skip entire hex value */
3867 i++;
3868 }
3869 }
3870 /* Skip one space between the BSSID and start of the SSID */
3871 i++;
3872 PRINTM(MMSG, "Trying to associate AP BSSID = [" MACSTR "]\n",
3873 MAC2STR(ssid_bssid.bssid));
3874 priv->assoc_with_mac = MTRUE;
3875 }
3876
3877 ssid_bssid.ssid.ssid_len = buflen - i;
3878 /* Check the size of the ssid_len */
3879 if (ssid_bssid.ssid.ssid_len > MLAN_MAX_SSID_LENGTH + 1) {
3880 PRINTM(MERROR, "ssid_bssid.ssid.ssid_len = %d\n",
3881 ssid_bssid.ssid.ssid_len);
3882 ret = -E2BIG;
3883 goto setessid_ret;
3884 }
3885
3886 /* Copy the SSID */
3887 moal_memcpy_ext(handle, ssid_bssid.ssid.ssid, buf + i,
3888 ssid_bssid.ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
3889
3890 if (!ssid_bssid.ssid.ssid_len ||
3891 (MFALSE == woal_ssid_valid(&ssid_bssid.ssid))) {
3892 PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
3893 ret = -EINVAL;
3894 goto setessid_ret;
3895 }
3896
3897 PRINTM(MMSG, "Trying to associate AP SSID = %s\n",
3898 (char *)ssid_bssid.ssid.ssid);
3899
3900 /* Cancel re-association */
3901 priv->reassoc_required = MFALSE;
3902
3903 if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
3904 PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
3905 ret = -EBUSY;
3906 LEAVE();
3907 return ret;
3908 }
3909
3910 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3911 woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
3912
3913 if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
3914 PRINTM(MIOCTL, "Already connect to the network\n");
3915 ret = sprintf(respbuf,
3916 "Has already connected to this ESSID!\n") +
3917 1;
3918 goto setessid_ret;
3919 }
3920 moal_memcpy_ext(handle, &priv->prev_ssid_bssid, &ssid_bssid,
3921 sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid));
3922 priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
3923 priv->auto_assoc_priv.auto_assoc_trigger_flag =
3924 AUTO_ASSOC_TYPE_DRV_ASSOC;
3925 priv->auto_assoc_priv.drv_assoc.status = MTRUE;
3926 if (priv->auto_assoc_priv.auto_assoc_type_on &
3927 (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
3928 PRINTM(MINFO, " auto assoc: trigger driver auto re-assoc\n");
3929 } else {
3930 PRINTM(MINFO, " Set Asynced ESSID: trigger auto re-assoc\n");
3931 }
3932 priv->reassoc_required = MTRUE;
3933 priv->phandle->is_reassoc_timer_set = MTRUE;
3934 woal_mod_timer(&priv->phandle->reassoc_timer, 0);
3935 ret = sprintf(respbuf, "%s\n", buf) + 1;
3936
3937 setessid_ret:
3938 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3939 woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
3940 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
3941 LEAVE();
3942 return ret;
3943 }
3944 #endif
3945
3946 /**
3947 * @brief Set/Get deep auto assoc configurations
3948 *
3949 * @param priv A pointer to moal_private structure
3950 * @param respbuf A pointer to response buffer
3951 * @param respbuflen Available length of response buffer
3952 *
3953 * @return Number of bytes written, negative for failure.
3954 */
woal_priv_setgetautoassoc(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)3955 static int woal_priv_setgetautoassoc(moal_private *priv, t_u8 *respbuf,
3956 t_u32 respbuflen)
3957 {
3958 #ifdef REASSOCIATION
3959 moal_handle *handle = priv->phandle;
3960 #endif
3961 mlan_ioctl_req *req = NULL;
3962 mlan_ds_misc_cfg *misc = NULL;
3963 t_u32 data[5];
3964 int ret = 0;
3965 int user_data_len = 0;
3966 mlan_status status = MLAN_STATUS_SUCCESS;
3967
3968 ENTER();
3969
3970 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTOASSOC))) {
3971 PRINTM(MERROR, "No argument, invalid operation!\n");
3972 ret = -EINVAL;
3973 goto done;
3974 } else {
3975 /* GET/SET operation */
3976 memset((char *)data, 0, sizeof(data));
3977 parse_arguments(respbuf + strlen(CMD_NXP) +
3978 strlen(PRIV_CMD_AUTOASSOC),
3979 data, ARRAY_SIZE(data), &user_data_len);
3980 }
3981
3982 if (sizeof(t_u32) * user_data_len > sizeof(data)) {
3983 PRINTM(MERROR, "Too many arguments\n");
3984 ret = -EINVAL;
3985 goto done;
3986 }
3987
3988 if (data[0] != AUTO_ASSOC_TYPE_DRV_ASSOC &&
3989 data[0] != AUTO_ASSOC_TYPE_DRV_RECONN &&
3990 data[0] != AUTO_ASSOC_TYPE_FW_RECONN) {
3991 PRINTM(MERROR, "Invalid auto assoc type option = %u\n",
3992 data[0]);
3993 ret = -EINVAL;
3994 goto done;
3995 }
3996
3997 if (user_data_len == 1) {
3998 /* Get operation */
3999 if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
4000 /* Get fw auto re-connect parameters */
4001 req = woal_alloc_mlan_ioctl_req(
4002 sizeof(mlan_ds_misc_cfg));
4003 if (req == NULL) {
4004 LEAVE();
4005 return -ENOMEM;
4006 }
4007
4008 misc = (mlan_ds_misc_cfg *)req->pbuf;
4009 misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
4010 req->req_id = MLAN_IOCTL_MISC_CFG;
4011 req->action = MLAN_ACT_GET;
4012
4013 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4014 if (status != MLAN_STATUS_SUCCESS) {
4015 ret = -EFAULT;
4016 if (status != MLAN_STATUS_PENDING)
4017 kfree(req);
4018 goto done;
4019 } else {
4020 data[2] = misc->param.fw_auto_reconnect
4021 .fw_reconn_counter;
4022 if (data[2] == 0) {
4023 data[1] = 0;
4024 sprintf(respbuf, "%d %d", data[0],
4025 data[1]);
4026 ret = strlen(respbuf) + 1;
4027 } else {
4028 data[1] = 1;
4029 data[3] = misc->param.fw_auto_reconnect
4030 .fw_reconn_interval;
4031 data[4] = misc->param.fw_auto_reconnect
4032 .fw_reconn_flags;
4033 sprintf(respbuf, "%d %d 0x%x 0x%x 0x%x",
4034 data[0], data[1], data[2],
4035 data[3], data[4]);
4036 ret = strlen(respbuf) + 1;
4037 }
4038 kfree(req);
4039 }
4040 } else {
4041 if (priv->auto_assoc_priv.auto_assoc_type_on &
4042 (0x1 << (data[0] - 1))) {
4043 data[1] = 1;
4044 if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
4045 /* Get driver auto re-connect parameters
4046 */
4047 data[2] = priv->auto_assoc_priv
4048 .drv_reconnect
4049 .retry_count;
4050 data[3] = priv->auto_assoc_priv
4051 .drv_reconnect
4052 .retry_interval;
4053 } else {
4054 /* Get driver auto assoc parameters */
4055 data[2] =
4056 priv->auto_assoc_priv.drv_assoc
4057 .retry_count;
4058 data[3] =
4059 priv->auto_assoc_priv.drv_assoc
4060 .retry_interval;
4061 }
4062 sprintf(respbuf, "%d %d 0x%x 0x%x", data[0],
4063 data[1], data[2], data[3]);
4064 ret = strlen(respbuf) + 1;
4065 } else {
4066 data[1] = 0;
4067 sprintf(respbuf, "%d %d", data[0], data[1]);
4068 ret = strlen(respbuf) + 1;
4069 }
4070 }
4071 } else {
4072 /* Set operation */
4073 if (data[1] == MFALSE) {
4074 /* Set Disable */
4075 if (user_data_len > 2) {
4076 PRINTM(MERROR,
4077 "Invalid number of arguments for setting Disable\n");
4078 ret = -EINVAL;
4079 goto done;
4080 }
4081 priv->auto_assoc_priv.auto_assoc_type_on &=
4082 ~(0x1 << (data[0] - 1));
4083 } else if (data[1] == MTRUE) {
4084 /* Set Enable */
4085 if (user_data_len > 2) {
4086 if (data[2] == 0 || data[2] > 0xFF) {
4087 PRINTM(MERROR,
4088 "Invalid auto assoc retry count option = %u\n",
4089 data[2]);
4090 ret = -EINVAL;
4091 goto done;
4092 }
4093 if (user_data_len > 3) {
4094 if (data[3] > 0xFF) {
4095 PRINTM(MERROR,
4096 "Invalid auto assoc interval option = %u\n",
4097 data[3]);
4098 ret = -EINVAL;
4099 goto done;
4100 }
4101 } else {
4102 data[3] = 0xa; /* Default retry
4103 interval: 10 seconds
4104 */
4105 }
4106 } else {
4107 data[2] = 0xff; /* Default retry count: retry
4108 forever */
4109 data[3] = 0xa; /* Default retry interval: 10
4110 seconds */
4111 }
4112 priv->auto_assoc_priv.auto_assoc_type_on |=
4113 0x1 << (data[0] - 1);
4114 } else {
4115 PRINTM(MERROR,
4116 "Invalid auto assoc on/off option = %u\n",
4117 data[1]);
4118 ret = -EINVAL;
4119 goto done;
4120 }
4121
4122 if (data[0] == AUTO_ASSOC_TYPE_FW_RECONN) {
4123 /* Set fw auto re-connect operation */
4124 if (user_data_len == 5) {
4125 if (data[4] > 0x1) {
4126 PRINTM(MERROR,
4127 "Invalid fw auto re-connect flag option = %u\n",
4128 data[4]);
4129 ret = -EINVAL;
4130 goto done;
4131 }
4132 } else {
4133 data[4] = 0; /* Default fw auto re-connect flags
4134 */
4135 }
4136 req = woal_alloc_mlan_ioctl_req(
4137 sizeof(mlan_ds_misc_cfg));
4138 if (req == NULL) {
4139 LEAVE();
4140 return -ENOMEM;
4141 }
4142
4143 misc = (mlan_ds_misc_cfg *)req->pbuf;
4144 misc->sub_command = MLAN_OID_MISC_AUTO_ASSOC;
4145 req->req_id = MLAN_IOCTL_MISC_CFG;
4146 req->action = MLAN_ACT_SET;
4147
4148 if (data[1] == MFALSE) {
4149 /* Set fw auto re-connect Disable */
4150 misc->param.fw_auto_reconnect.fw_reconn_counter =
4151 0;
4152 misc->param.fw_auto_reconnect
4153 .fw_reconn_interval = 0;
4154 misc->param.fw_auto_reconnect.fw_reconn_flags =
4155 0;
4156 } else {
4157 /* Set fw auto re-connect Enable */
4158 misc->param.fw_auto_reconnect.fw_reconn_counter =
4159 data[2];
4160 misc->param.fw_auto_reconnect
4161 .fw_reconn_interval = data[3];
4162 misc->param.fw_auto_reconnect.fw_reconn_flags =
4163 data[4];
4164 }
4165
4166 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4167 if (status != MLAN_STATUS_SUCCESS) {
4168 ret = -EFAULT;
4169 if (status != MLAN_STATUS_PENDING)
4170 kfree(req);
4171 goto done;
4172 } else {
4173 kfree(req);
4174 }
4175 } else {
4176 if (user_data_len == 5) {
4177 PRINTM(MERROR,
4178 "The fifth parameter is only used for FW auto re-connect!\n");
4179 ret = -EINVAL;
4180 goto done;
4181 }
4182 if (data[0] == AUTO_ASSOC_TYPE_DRV_RECONN) {
4183 /* Set driver auto re-connect operation */
4184 if (data[1] == MFALSE) {
4185 if (!(priv->auto_assoc_priv
4186 .auto_assoc_type_on &
4187 (0x1
4188 << (AUTO_ASSOC_TYPE_DRV_ASSOC -
4189 1)))) {
4190 priv->auto_assoc_priv
4191 .drv_reconnect.status =
4192 MFALSE;
4193 #ifdef REASSOCIATION
4194 handle->reassoc_on &=
4195 ~MBIT(priv->bss_index);
4196 priv->reassoc_on = MFALSE;
4197 priv->reassoc_required = MFALSE;
4198 if (!handle->reassoc_on &&
4199 handle->is_reassoc_timer_set ==
4200 MTRUE) {
4201 woal_cancel_timer(
4202 &handle->reassoc_timer);
4203 handle->is_reassoc_timer_set =
4204 MFALSE;
4205 }
4206 #endif
4207 }
4208 }
4209 #ifdef REASSOCIATION
4210 else {
4211 handle->reassoc_on |=
4212 MBIT(priv->bss_index);
4213 priv->reassoc_on = MTRUE;
4214 }
4215 #endif
4216 priv->auto_assoc_priv.drv_reconnect.retry_count =
4217 data[2];
4218 priv->auto_assoc_priv.drv_reconnect
4219 .retry_interval = data[3];
4220 }
4221 if (data[0] == AUTO_ASSOC_TYPE_DRV_ASSOC) {
4222 /* Set driver auto assoc operation */
4223 if (data[1] == MFALSE) {
4224 if (!(priv->auto_assoc_priv
4225 .auto_assoc_type_on &
4226 (0x1
4227 << (AUTO_ASSOC_TYPE_DRV_RECONN -
4228 1)))) {
4229 priv->auto_assoc_priv.drv_assoc
4230 .status = MFALSE;
4231 #ifdef REASSOCIATION
4232 handle->reassoc_on &=
4233 ~MBIT(priv->bss_index);
4234 priv->reassoc_on = MFALSE;
4235 priv->reassoc_required = MFALSE;
4236 if (!handle->reassoc_on &&
4237 handle->is_reassoc_timer_set ==
4238 MTRUE) {
4239 woal_cancel_timer(
4240 &handle->reassoc_timer);
4241 handle->is_reassoc_timer_set =
4242 MFALSE;
4243 }
4244 #endif
4245 }
4246 }
4247 #ifdef REASSOCIATION
4248 else {
4249 handle->reassoc_on |=
4250 MBIT(priv->bss_index);
4251 priv->reassoc_on = MTRUE;
4252 }
4253 #endif
4254 priv->auto_assoc_priv.drv_assoc.retry_count =
4255 data[2];
4256 priv->auto_assoc_priv.drv_assoc.retry_interval =
4257 data[3];
4258 }
4259 }
4260 ret = sprintf(respbuf, "OK\n") + 1;
4261 }
4262
4263 done:
4264 LEAVE();
4265 return ret;
4266 }
4267
4268 /**
4269 * @brief Get wakeup reason
4270 *
4271 * @param priv A pointer to moal_private structure
4272 * @param respbuf A pointer to response buffer
4273 * @param respbuflen Available length of response buffer
4274 *
4275 * @return Number of bytes written, negative for failure.
4276 */
woal_priv_getwakeupreason(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4277 static int woal_priv_getwakeupreason(moal_private *priv, t_u8 *respbuf,
4278 t_u32 respbuflen)
4279 {
4280 mlan_ioctl_req *req = NULL;
4281 mlan_ds_pm_cfg *pm_cfg = NULL;
4282 t_u32 data;
4283 int ret = 0;
4284 mlan_status status = MLAN_STATUS_SUCCESS;
4285
4286 ENTER();
4287
4288 if (strlen(respbuf) ==
4289 (strlen(CMD_NXP) + strlen(PRIV_CMD_WAKEUPREASON))) {
4290 /* GET operation */
4291 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
4292 if (req == NULL) {
4293 LEAVE();
4294 return -ENOMEM;
4295 }
4296
4297 pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
4298 pm_cfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON;
4299 req->req_id = MLAN_IOCTL_PM_CFG;
4300 req->action = MLAN_ACT_GET;
4301
4302 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4303 if (status != MLAN_STATUS_SUCCESS) {
4304 ret = -EFAULT;
4305 if (status != MLAN_STATUS_PENDING)
4306 kfree(req);
4307 goto done;
4308 } else {
4309 data = pm_cfg->param.wakeup_reason.hs_wakeup_reason;
4310 sprintf(respbuf, " %d", data);
4311 ret = strlen(respbuf) + 1;
4312 kfree(req);
4313 }
4314 } else {
4315 PRINTM(MERROR, "Not need argument, invalid operation!\n");
4316 ret = -EINVAL;
4317 goto done;
4318 }
4319
4320 done:
4321 LEAVE();
4322 return ret;
4323 }
4324
4325 #ifdef STA_SUPPORT
4326 /**
4327 * @brief Set / Get listen interval
4328 *
4329 * @param priv A pointer to moal_private structure
4330 * @param respbuf A pointer to response buffer
4331 * @param respbuflen Available length of response buffer
4332 *
4333 * @return Number of bytes written, negative for failure.
4334 */
woal_priv_set_get_listeninterval(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4335 static int woal_priv_set_get_listeninterval(moal_private *priv, t_u8 *respbuf,
4336 t_u32 respbuflen)
4337 {
4338 int data[1];
4339 int user_data_len = 0;
4340 int ret = 0;
4341 mlan_ioctl_req *req = NULL;
4342 mlan_ds_bss *pcfg_bss = NULL;
4343 mlan_status status = MLAN_STATUS_SUCCESS;
4344
4345 ENTER();
4346
4347 if (strlen(respbuf) ==
4348 (strlen(CMD_NXP) + strlen(PRIV_CMD_LISTENINTERVAL))) {
4349 /* GET operation */
4350 user_data_len = 0;
4351 } else {
4352 /* SET operation */
4353 memset((char *)data, 0, sizeof(data));
4354 parse_arguments(respbuf + strlen(CMD_NXP) +
4355 strlen(PRIV_CMD_LISTENINTERVAL),
4356 data, ARRAY_SIZE(data), &user_data_len);
4357 }
4358
4359 if (user_data_len > 1) {
4360 PRINTM(MERROR, "Too many arguments\n");
4361 ret = -EINVAL;
4362 goto done;
4363 }
4364
4365 /* Allocate an IOCTL request buffer */
4366 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4367 if (req == NULL) {
4368 ret = -ENOMEM;
4369 goto done;
4370 }
4371
4372 /* Fill request buffer */
4373 pcfg_bss = (mlan_ds_bss *)req->pbuf;
4374 pcfg_bss->sub_command = MLAN_OID_BSS_LISTEN_INTERVAL;
4375 req->req_id = MLAN_IOCTL_BSS;
4376
4377 if (user_data_len) {
4378 pcfg_bss->param.listen_interval = (t_u16)data[0];
4379 req->action = MLAN_ACT_SET;
4380 } else {
4381 req->action = MLAN_ACT_GET;
4382 }
4383
4384 /* Send IOCTL request to MLAN */
4385 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4386 if (status != MLAN_STATUS_SUCCESS) {
4387 ret = -EFAULT;
4388 goto done;
4389 }
4390 if (req->action == MLAN_ACT_GET) {
4391 sprintf(respbuf, "%d", pcfg_bss->param.listen_interval);
4392 ret = strlen(respbuf) + 1;
4393 } else {
4394 ret = sprintf(respbuf, "OK\n") + 1;
4395 }
4396
4397 done:
4398 if (status != MLAN_STATUS_PENDING)
4399 kfree(req);
4400
4401 LEAVE();
4402 return ret;
4403 }
4404 #endif
4405
4406 #ifdef DEBUG_LEVEL1
4407 /**
4408 * @brief Set / Get driver debug level
4409 *
4410 * @param priv A pointer to moal_private structure
4411 * @param respbuf A pointer to response buffer
4412 * @param respbuflen Available length of response buffer
4413 *
4414 * @return Number of bytes written, negative for failure.
4415 */
woal_priv_set_get_drvdbg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4416 static int woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf,
4417 t_u32 respbuflen)
4418 {
4419 int data[4];
4420 int user_data_len = 0;
4421 int ret = 0;
4422
4423 ENTER();
4424
4425 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DRVDBG))) {
4426 /* GET operation */
4427 user_data_len = 0;
4428 } else {
4429 /* SET operation */
4430 memset((char *)data, 0, sizeof(data));
4431 parse_arguments(respbuf + strlen(CMD_NXP) +
4432 strlen(PRIV_CMD_DRVDBG),
4433 data, ARRAY_SIZE(data), &user_data_len);
4434 }
4435
4436 if (user_data_len > 1) {
4437 PRINTM(MERROR, "Too many arguments\n");
4438 ret = -EINVAL;
4439 goto done;
4440 }
4441
4442 if (user_data_len) {
4443 /* Get the driver debug bit masks from user */
4444 drvdbg = data[0];
4445 /* Set the driver debug bit masks into mlan */
4446 if (woal_set_drvdbg(priv, drvdbg)) {
4447 PRINTM(MERROR, "Set drvdbg failed!\n");
4448 ret = MLAN_STATUS_FAILURE;
4449 goto done;
4450 }
4451 }
4452
4453 ret = sizeof(drvdbg);
4454
4455 moal_memcpy_ext(priv->phandle, respbuf, &drvdbg, sizeof(drvdbg),
4456 respbuflen);
4457
4458 printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg);
4459 #ifdef DEBUG_LEVEL2
4460 printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO,
4461 (drvdbg & MINFO) ? "X" : "");
4462 printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN,
4463 (drvdbg & MWARN) ? "X" : "");
4464 printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY,
4465 (drvdbg & MENTRY) ? "X" : "");
4466 #endif
4467 printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D,
4468 (drvdbg & MMPA_D) ? "X" : "");
4469 printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D,
4470 (drvdbg & MIF_D) ? "X" : "");
4471 printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D,
4472 (drvdbg & MFW_D) ? "X" : "");
4473 printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D,
4474 (drvdbg & MEVT_D) ? "X" : "");
4475 printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D,
4476 (drvdbg & MCMD_D) ? "X" : "");
4477 printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D,
4478 (drvdbg & MDAT_D) ? "X" : "");
4479 printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D,
4480 (drvdbg & MREG_D) ? "X" : "");
4481 printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL,
4482 (drvdbg & MIOCTL) ? "X" : "");
4483 printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR,
4484 (drvdbg & MINTR) ? "X" : "");
4485 printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT,
4486 (drvdbg & MEVENT) ? "X" : "");
4487 printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND,
4488 (drvdbg & MCMND) ? "X" : "");
4489 printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA,
4490 (drvdbg & MDATA) ? "X" : "");
4491 printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR,
4492 (drvdbg & MERROR) ? "X" : "");
4493 printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL,
4494 (drvdbg & MFATAL) ? "X" : "");
4495 printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG,
4496 (drvdbg & MMSG) ? "X" : "");
4497
4498 done:
4499 LEAVE();
4500 return ret;
4501 }
4502
4503 #endif
4504
4505 /**
4506 * @brief management frame filter wakeup config
4507 *
4508 * @param priv A pointer to moal_private structure
4509 * @param respbuf A pointer to response buffer
4510 * @param respbuflen Available length of response buffer
4511 *
4512 * @return 0 --success, otherwise fail
4513 */
woal_priv_mgmt_filter(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4514 static int woal_priv_mgmt_filter(moal_private *priv, t_u8 *respbuf,
4515 t_u32 respbuflen)
4516 {
4517 mlan_ioctl_req *ioctl_req = NULL;
4518 mlan_ds_pm_cfg *pm_cfg = NULL;
4519 mlan_status status = MLAN_STATUS_SUCCESS;
4520 int header_len = 0, data_len = 0;
4521 int ret = 0;
4522 t_u16 action;
4523 t_u8 *argument;
4524
4525 ENTER();
4526
4527 if (!priv || !priv->phandle) {
4528 PRINTM(MERROR, "priv or handle is null\n");
4529 ret = -EFAULT;
4530 goto done;
4531 }
4532
4533 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4534 if (ioctl_req == NULL) {
4535 ret = -ENOMEM;
4536 goto done;
4537 }
4538
4539 pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf;
4540 pm_cfg->sub_command = MLAN_OID_PM_MGMT_FILTER;
4541 ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
4542
4543 header_len = strlen(PRIV_CMD_MGMT_FILTER) + strlen(CMD_NXP);
4544
4545 if ((int)strlen(respbuf) == header_len) {
4546 /* GET operation */
4547 action = MLAN_ACT_GET;
4548 } else {
4549 /* SET operation */
4550 argument = (t_u8 *)(respbuf + header_len);
4551 data_len = respbuflen - header_len;
4552 if (data_len > (int)(MAX_MGMT_FRAME_FILTER *
4553 sizeof(mlan_mgmt_frame_wakeup))) {
4554 PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__);
4555 ret = -EINVAL;
4556 goto done;
4557 }
4558 moal_memcpy_ext(priv->phandle,
4559 (t_u8 *)pm_cfg->param.mgmt_filter, argument,
4560 data_len, sizeof(pm_cfg->param.mgmt_filter));
4561 action = MLAN_ACT_SET;
4562 }
4563
4564 ioctl_req->action = action;
4565 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
4566 if (status != MLAN_STATUS_SUCCESS) {
4567 ret = -EFAULT;
4568 goto done;
4569 }
4570
4571 done:
4572 if (status != MLAN_STATUS_PENDING)
4573 kfree(ioctl_req);
4574
4575 LEAVE();
4576 return ret;
4577 }
4578
4579 #define PARAMETER_GPIO_INDICATION 1
4580 #define PARAMETER_EXTEND_HSCFG 2
4581 #define PARAMETER_HS_WAKEUP_INTERVAL 3
4582 #define PARAMETER_MIN_WAKE_HOLDOFF 4
4583 /**
4584 * @brief Set/Get Host Sleep configuration
4585 *
4586 * @param priv A pointer to moal_private structure
4587 * @param respbuf A pointer to response buffer
4588 * @param respbuflen Available length of response buffer
4589 * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE
4590 *
4591 * @return 0 --success, otherwise fail
4592 */
woal_priv_hscfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen,BOOLEAN invoke_hostcmd)4593 static int woal_priv_hscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen,
4594 BOOLEAN invoke_hostcmd)
4595 {
4596 int data[15] = {0};
4597 int *temp_data, type;
4598 int user_data_len = 0;
4599 int ret = 0;
4600 mlan_ds_hs_cfg hscfg, hscfg_temp;
4601 t_u16 action;
4602 mlan_bss_info bss_info;
4603 int is_negative = MFALSE;
4604 t_u8 *arguments = NULL;
4605
4606 ENTER();
4607
4608 memset(data, 0, sizeof(data));
4609 memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
4610 memset(&hscfg_temp, 0, sizeof(mlan_ds_hs_cfg));
4611
4612 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG))) {
4613 /* GET operation */
4614 user_data_len = 0;
4615 } else {
4616 /* SET operation */
4617 memset((char *)data, 0, sizeof(data));
4618 arguments = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG);
4619 if (*arguments == '-') {
4620 is_negative = MTRUE;
4621 arguments += 1;
4622 }
4623 parse_arguments(arguments, data, ARRAY_SIZE(data),
4624 &user_data_len);
4625
4626 if (is_negative == MTRUE) {
4627 if (data[0] == 1) {
4628 data[0] = -1;
4629 } else {
4630 PRINTM(MERROR, "Invalid arguments\n");
4631 ret = -EINVAL;
4632 goto done;
4633 }
4634 }
4635 }
4636
4637 if (sizeof(int) * user_data_len > sizeof(data)) {
4638 PRINTM(MERROR, "Too many arguments\n");
4639 LEAVE();
4640 return -EINVAL;
4641 }
4642
4643 if (user_data_len == 0) {
4644 action = MLAN_ACT_GET;
4645 } else {
4646 if (user_data_len >= 1 && user_data_len <= 15) {
4647 action = MLAN_ACT_SET;
4648 } else {
4649 PRINTM(MERROR, "Invalid arguments\n");
4650 ret = -EINVAL;
4651 goto done;
4652 }
4653 }
4654
4655 /* HS config is blocked if HS is already activated */
4656 if (user_data_len && (data[0] != (int)HOST_SLEEP_CFG_CANCEL ||
4657 invoke_hostcmd == MFALSE)) {
4658 memset(&bss_info, 0, sizeof(bss_info));
4659 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
4660 if (bss_info.is_hs_configured) {
4661 PRINTM(MERROR, "HS already configured\n");
4662 ret = -EFAULT;
4663 goto done;
4664 }
4665 }
4666
4667 /* Do a GET first if some arguments are not provided */
4668 if (user_data_len >= 1 && user_data_len < 11) {
4669 woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
4670 &hscfg_temp);
4671 }
4672 hscfg.conditions = hscfg_temp.conditions;
4673 hscfg.gpio = hscfg_temp.gpio;
4674 hscfg.gap = hscfg_temp.gap;
4675
4676 if (user_data_len)
4677 hscfg.conditions = data[0];
4678 if (user_data_len >= 2)
4679 hscfg.gpio = data[1];
4680 if (user_data_len >= 3)
4681 hscfg.gap = data[2];
4682 user_data_len = user_data_len - 3;
4683 if (user_data_len > 0) {
4684 temp_data = data + 3;
4685 while ((user_data_len > 0) && temp_data) {
4686 type = *temp_data;
4687 switch (type) {
4688 case PARAMETER_GPIO_INDICATION:
4689 if (user_data_len >= 2)
4690 hscfg.ind_gpio = *(++temp_data);
4691 else {
4692 PRINTM(MERROR,
4693 "Invaild number of parameters\n");
4694 ret = -EINVAL;
4695 goto done;
4696 }
4697 if (user_data_len >= 3) {
4698 hscfg.level = *(++temp_data);
4699 if (hscfg.level != 0 &&
4700 hscfg.level != 1) {
4701 PRINTM(MERROR,
4702 "Invalid indication gpio arguments\n");
4703 ret = -EINVAL;
4704 goto done;
4705 }
4706 }
4707 hscfg.param_type_ind = type;
4708 user_data_len = user_data_len - 3;
4709 temp_data++;
4710 break;
4711 case PARAMETER_EXTEND_HSCFG:
4712 if (user_data_len >= 4) {
4713 hscfg.event_force_ignore =
4714 *(++temp_data);
4715 hscfg.event_use_ext_gap =
4716 *(++temp_data);
4717 hscfg.ext_gap = *(++temp_data);
4718 hscfg.gpio_wave = *(++temp_data);
4719 } else {
4720 PRINTM(MERROR,
4721 "Invaild number of parameters\n");
4722 ret = -EINVAL;
4723 goto done;
4724 }
4725 /* Force_ignore_gpio and ext_gap_gpio should not
4726 * set the same bit(s)*/
4727 if ((hscfg.event_force_ignore &
4728 hscfg.event_use_ext_gap) ||
4729 (hscfg.gpio_wave != 1 &&
4730 hscfg.gpio_wave != 0)) {
4731 PRINTM(MERROR,
4732 "Invalid arguments for extend hscfg\n");
4733 ret = -EINVAL;
4734 goto done;
4735 }
4736 hscfg.param_type_ext = type;
4737 user_data_len = user_data_len - 5;
4738 temp_data++;
4739 break;
4740 case PARAMETER_HS_WAKEUP_INTERVAL:
4741 if (user_data_len >= 2)
4742 hscfg.hs_wake_interval = *(++temp_data);
4743 else {
4744 PRINTM(MERROR,
4745 "Invaild number of parameters\n");
4746 ret = -EINVAL;
4747 goto done;
4748 }
4749 user_data_len = user_data_len - 2;
4750 temp_data++;
4751 break;
4752 case PARAMETER_MIN_WAKE_HOLDOFF:
4753 if (user_data_len >= 2)
4754 hscfg.min_wake_holdoff = *(++temp_data);
4755 else {
4756 PRINTM(MERROR,
4757 "Invaild number of parameters\n");
4758 ret = -EINVAL;
4759 goto done;
4760 }
4761 user_data_len = user_data_len - 2;
4762 temp_data++;
4763 break;
4764 default:
4765 PRINTM(MERROR, "Unsupported type\n");
4766 ret = -EINVAL;
4767 goto done;
4768 }
4769 }
4770 }
4771
4772 if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) {
4773 /* Need to issue an extra IOCTL first to set up parameters */
4774 hscfg.is_invoke_hostcmd = MFALSE;
4775 if (MLAN_STATUS_SUCCESS !=
4776 woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
4777 &hscfg)) {
4778 ret = -EFAULT;
4779 goto done;
4780 }
4781 }
4782 hscfg.is_invoke_hostcmd = invoke_hostcmd;
4783 if (MLAN_STATUS_SUCCESS !=
4784 woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
4785 ret = -EFAULT;
4786 goto done;
4787 }
4788
4789 if (action == MLAN_ACT_GET) {
4790 /* Return the current driver host sleep configurations */
4791 moal_memcpy_ext(priv->phandle, respbuf, &hscfg,
4792 sizeof(mlan_ds_hs_cfg), respbuflen);
4793 ret = sizeof(mlan_ds_hs_cfg);
4794 }
4795 done:
4796 LEAVE();
4797 return ret;
4798 }
4799
4800 /**
4801 * @brief Process Set Host Sleep parameters from proc buffer
4802 *
4803 * @param handle A pointer to moal_handle structure
4804 * @param pbuf A pointer to buffer for host sleep parameters
4805 * @param respbuflen Available length of response buffer
4806 *
4807 * @return 0 --success, otherwise fail
4808 */
woal_process_proc_hssetpara(moal_handle * handle,t_u8 * buf)4809 int woal_process_proc_hssetpara(moal_handle *handle, t_u8 *buf)
4810 {
4811 int data[15] = {0};
4812 int user_data_len = 0;
4813 int ret = 0;
4814 t_u8 respbuf[500];
4815 moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
4816
4817 ENTER();
4818 if (!priv) {
4819 LEAVE();
4820 return ret;
4821 }
4822 memset((char *)data, 0, sizeof(data));
4823 parse_arguments(buf, data, ARRAY_SIZE(data), &user_data_len);
4824 if (sizeof(int) * user_data_len > sizeof(data)) {
4825 PRINTM(MERROR, "Too many arguments\n");
4826 LEAVE();
4827 return -EINVAL;
4828 }
4829 if (user_data_len >= 1 && user_data_len <= 15) {
4830 sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG, buf);
4831 ret = woal_priv_hscfg(priv, respbuf, sizeof(respbuf), MFALSE);
4832 }
4833 LEAVE();
4834 return ret;
4835 }
4836
4837 /**
4838 * @brief Set Host Sleep parameters
4839 *
4840 * @param priv A pointer to moal_private structure
4841 * @param respbuf A pointer to response buffer
4842 * @param respbuflen Available length of response buffer
4843 *
4844 * @return 0 --success, otherwise fail
4845 */
woal_priv_hssetpara(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4846 static int woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf,
4847 t_u32 respbuflen)
4848 {
4849 int data[15] = {0};
4850 int user_data_len = 0;
4851 int ret = 0;
4852
4853 ENTER();
4854
4855 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))) {
4856 PRINTM(MERROR, "Invalid arguments\n");
4857 ret = -EINVAL;
4858 goto done;
4859 } else {
4860 /* SET operation */
4861 memset((char *)data, 0, sizeof(data));
4862 parse_arguments(respbuf + strlen(CMD_NXP) +
4863 strlen(PRIV_CMD_HSSETPARA),
4864 data, ARRAY_SIZE(data), &user_data_len);
4865 }
4866
4867 if (sizeof(int) * user_data_len > sizeof(data)) {
4868 PRINTM(MERROR, "Too many arguments\n");
4869 LEAVE();
4870 return -EINVAL;
4871 }
4872
4873 if (user_data_len >= 1 && user_data_len <= 15) {
4874 sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG,
4875 respbuf +
4876 (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA)));
4877 respbuflen = strlen(respbuf);
4878 ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE);
4879 goto done;
4880 }
4881 done:
4882 LEAVE();
4883 return ret;
4884 }
4885
4886 /**
4887 * @brief Set/Get scan configuration parameters
4888 *
4889 * @param priv A pointer to moal_private structure
4890 * @param respbuf A pointer to response buffer
4891 * @param respbuflen Available length of response buffer
4892 *
4893 * @return 0 --success, otherwise fail
4894 */
woal_priv_set_get_scancfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)4895 static int woal_priv_set_get_scancfg(moal_private *priv, t_u8 *respbuf,
4896 t_u32 respbuflen)
4897 {
4898 int ret = 0;
4899 int user_data_len = 0;
4900 int data[9];
4901 mlan_ds_scan *scan = NULL;
4902 mlan_ioctl_req *req = NULL;
4903 mlan_status status = MLAN_STATUS_SUCCESS;
4904
4905 ENTER();
4906
4907 memset(data, 0, sizeof(data));
4908 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_SCANCFG))) {
4909 /* GET operation */
4910 user_data_len = 0;
4911 } else {
4912 /* SET operation */
4913 memset((char *)data, 0, sizeof(data));
4914 parse_arguments(respbuf + strlen(CMD_NXP) +
4915 strlen(PRIV_CMD_SCANCFG),
4916 data, ARRAY_SIZE(data), &user_data_len);
4917 }
4918
4919 if (sizeof(int) * user_data_len > sizeof(data)) {
4920 PRINTM(MERROR, "Too many arguments\n");
4921 LEAVE();
4922 return -EINVAL;
4923 }
4924
4925 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan));
4926 if (req == NULL) {
4927 ret = -ENOMEM;
4928 goto done;
4929 }
4930 scan = (mlan_ds_scan *)req->pbuf;
4931 scan->sub_command = MLAN_OID_SCAN_CONFIG;
4932 req->req_id = MLAN_IOCTL_SCAN;
4933
4934 if (user_data_len) {
4935 moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
4936 sizeof(data), sizeof(scan->param.scan_cfg));
4937 if (scan->param.scan_cfg.scan_type > MLAN_SCAN_TYPE_PASSIVE) {
4938 PRINTM(MERROR, "Invalid argument for scan type\n");
4939 ret = -EINVAL;
4940 goto done;
4941 }
4942 if (scan->param.scan_cfg.scan_mode > MLAN_SCAN_MODE_ANY) {
4943 PRINTM(MERROR, "Invalid argument for scan mode\n");
4944 ret = -EINVAL;
4945 goto done;
4946 }
4947 if (scan->param.scan_cfg.scan_probe > MAX_PROBES) {
4948 PRINTM(MERROR, "Invalid argument for scan probes\n");
4949 ret = -EINVAL;
4950 goto done;
4951 }
4952 if ((scan->param.scan_cfg.scan_time.specific_scan_time >
4953 MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
4954 (scan->param.scan_cfg.scan_time.active_scan_time >
4955 MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) ||
4956 (scan->param.scan_cfg.scan_time.passive_scan_time >
4957 MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME)) {
4958 PRINTM(MERROR, "Invalid argument for scan time\n");
4959 ret = -EINVAL;
4960 goto done;
4961 }
4962 if (scan->param.scan_cfg.passive_to_active_scan >
4963 MLAN_PASS_TO_ACT_SCAN_DIS) {
4964 PRINTM(MERROR,
4965 "Invalid argument for Passive to Active Scan\n");
4966 ret = -EINVAL;
4967 goto done;
4968 }
4969 if (scan->param.scan_cfg.ext_scan > MLAN_EXT_SCAN_ENH) {
4970 PRINTM(MERROR, "Invalid argument for extended scan\n");
4971 ret = -EINVAL;
4972 goto done;
4973 }
4974 if (scan->param.scan_cfg.scan_chan_gap >
4975 MRVDRV_MAX_SCAN_CHAN_GAP_TIME) {
4976 PRINTM(MERROR,
4977 "Invalid argument for scan channel gap\n");
4978 ret = -EINVAL;
4979 goto done;
4980 }
4981
4982 req->action = MLAN_ACT_SET;
4983 moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data,
4984 sizeof(data), sizeof(scan->param.scan_cfg));
4985 } else
4986 req->action = MLAN_ACT_GET;
4987
4988 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4989 if (status != MLAN_STATUS_SUCCESS) {
4990 ret = -EFAULT;
4991 goto done;
4992 }
4993 moal_memcpy_ext(priv->phandle, respbuf, &scan->param.scan_cfg,
4994 sizeof(mlan_scan_cfg), respbuflen);
4995 ret = sizeof(mlan_scan_cfg);
4996 done:
4997 if (status != MLAN_STATUS_PENDING)
4998 kfree(req);
4999 LEAVE();
5000 return ret;
5001 }
5002
5003 /**
5004 * @brief Get Netlink Number
5005 *
5006 * @param priv A pointer to moal_private structure
5007 * @param respbuf A pointer to response buffer
5008 * @param respbuflen Available length of response buffer
5009 *
5010 * @return Number of bytes written, negative for failure.
5011 */
woal_priv_getnlnum(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5012 static int woal_priv_getnlnum(moal_private *priv, t_u8 *respbuf,
5013 t_u32 respbuflen)
5014 {
5015 int ret = 0;
5016 int data = 0;
5017
5018 ENTER();
5019
5020 if (!priv || !priv->phandle) {
5021 PRINTM(MERROR, "priv or handle is null in %s\n", __FUNCTION__);
5022 ret = -EFAULT;
5023 goto done;
5024 }
5025
5026 data = priv->phandle->netlink_num;
5027 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
5028 respbuflen);
5029 ret = sizeof(data);
5030
5031 done:
5032 LEAVE();
5033 return ret;
5034 }
5035
5036 /**
5037 * @brief Set / Get packet aggregation control
5038 *
5039 * @param priv A pointer to moal_private structure
5040 * @param respbuf A pointer to response buffer
5041 * @param respbuflen Available length of response buffer
5042 *
5043 * @return Number of bytes written, negative for failure.
5044 */
woal_priv_set_get_aggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5045 static int woal_priv_set_get_aggrctrl(moal_private *priv, t_u8 *respbuf,
5046 t_u32 respbuflen)
5047 {
5048 int data[1];
5049 int user_data_len = 0;
5050 int ret = 0;
5051 mlan_ioctl_req *req = NULL;
5052 mlan_ds_misc_cfg *pcfg_misc = NULL;
5053 moal_handle *handle = priv->phandle;
5054 mlan_status status = MLAN_STATUS_SUCCESS;
5055
5056 ENTER();
5057
5058 if (!handle || !handle->card) {
5059 PRINTM(MERROR, "Handle or card is null\n");
5060 ret = -EFAULT;
5061 goto done;
5062 }
5063
5064 memset((char *)data, 0, sizeof(data));
5065 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRCTRL))) {
5066 /* GET operation */
5067 user_data_len = 0;
5068 } else {
5069 if (woal_is_any_interface_active(priv->phandle)) {
5070 PRINTM(MERROR,
5071 "aggrctrl are not allowed to change after BSS active!\n");
5072 ret = -EFAULT;
5073 goto done;
5074 }
5075 /* SET operation */
5076 parse_arguments(respbuf + strlen(CMD_NXP) +
5077 strlen(PRIV_CMD_AGGRCTRL),
5078 data, ARRAY_SIZE(data), &user_data_len);
5079
5080 if (sizeof(int) * user_data_len > sizeof(data)) {
5081 PRINTM(MERROR, "Too many arguments\n");
5082 ret = -EINVAL;
5083 goto done;
5084 }
5085 }
5086
5087 /* Allocate an IOCTL request buffer */
5088 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
5089 if (req == NULL) {
5090 ret = -ENOMEM;
5091 goto done;
5092 }
5093
5094 /* Fill request buffer */
5095 pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
5096 pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL;
5097 req->req_id = MLAN_IOCTL_MISC_CFG;
5098
5099 /* Get the values first, then modify these values if user had modified
5100 * them */
5101 if (user_data_len == 0)
5102 req->action = MLAN_ACT_GET;
5103 else {
5104 req->action = MLAN_ACT_SET;
5105 pcfg_misc->param.aggr_params.tx.enable = (t_u16)data[0];
5106 }
5107
5108 /* Send IOCTL request to MLAN */
5109 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5110 if (status != MLAN_STATUS_SUCCESS) {
5111 /* MLAN will return CMD_INVALID if FW does not support this
5112 * feature */
5113 if (MLAN_ERROR_CMD_INVALID == req->status_code)
5114 ret = -EOPNOTSUPP;
5115 else
5116 ret = -EFAULT;
5117 goto done;
5118 }
5119
5120 moal_memcpy_ext(handle, respbuf, (t_u8 *)&pcfg_misc->param.aggr_params,
5121 sizeof(mlan_ds_misc_aggr_ctrl), respbuflen);
5122 ret = sizeof(mlan_ds_misc_aggr_ctrl);
5123 done:
5124 if (status != MLAN_STATUS_PENDING)
5125 kfree(req);
5126
5127 LEAVE();
5128 return ret;
5129 }
5130
5131 #ifdef USB
5132 /**
5133 * @brief Set / Get USB packet aggregation control
5134 *
5135 * @param priv A pointer to moal_private structure
5136 * @param respbuf A pointer to response buffer
5137 * @param respbuflen Available length of response buffer
5138 *
5139 * @return Number of bytes written, negative for failure.
5140 */
woal_priv_set_get_usbaggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5141 static int woal_priv_set_get_usbaggrctrl(moal_private *priv, t_u8 *respbuf,
5142 t_u32 respbuflen)
5143 {
5144 int data[8];
5145 int user_data_len = 0;
5146 int ret = 0;
5147 mlan_ioctl_req *req = NULL;
5148 mlan_ds_misc_cfg *pcfg_misc = NULL;
5149 moal_handle *handle = priv->phandle;
5150 struct usb_card_rec *cardp = NULL;
5151 int i = 0, usb_resubmit_urbs = 0;
5152 mlan_status status = MLAN_STATUS_SUCCESS;
5153
5154 ENTER();
5155
5156 if (!handle || !handle->card) {
5157 PRINTM(MERROR, "Handle or card is null\n");
5158 ret = -EFAULT;
5159 goto done;
5160 }
5161 cardp = (struct usb_card_rec *)handle->card;
5162
5163 memset((char *)data, 0, sizeof(data));
5164 if (strlen(respbuf) ==
5165 (strlen(CMD_NXP) + strlen(PRIV_CMD_USBAGGRCTRL))) {
5166 /* GET operation */
5167 user_data_len = 0;
5168 } else {
5169 /* SET operation */
5170 parse_arguments(respbuf + strlen(CMD_NXP) +
5171 strlen(PRIV_CMD_USBAGGRCTRL),
5172 data, ARRAY_SIZE(data), &user_data_len);
5173
5174 if (sizeof(int) * user_data_len > sizeof(data)) {
5175 PRINTM(MERROR, "Too many arguments\n");
5176 ret = -EINVAL;
5177 goto done;
5178 }
5179 }
5180
5181 /* Allocate an IOCTL request buffer */
5182 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
5183 if (req == NULL) {
5184 ret = -ENOMEM;
5185 goto done;
5186 }
5187
5188 /* Fill request buffer */
5189 pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf;
5190 pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
5191 req->req_id = MLAN_IOCTL_MISC_CFG;
5192
5193 /* Get the values first, then modify these values if user had modified
5194 * them */
5195 req->action = MLAN_ACT_GET;
5196 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5197 if (status != MLAN_STATUS_SUCCESS) {
5198 /* MLAN will return CMD_INVALID if FW does not support this
5199 * feature */
5200 if (MLAN_ERROR_CMD_INVALID == req->status_code)
5201 ret = -EOPNOTSUPP;
5202 else
5203 ret = -EFAULT;
5204 goto done;
5205 }
5206
5207 if (user_data_len == 0) {
5208 moal_memcpy_ext(handle, respbuf,
5209 (t_u8 *)&pcfg_misc->param.usb_aggr_params,
5210 sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
5211 ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
5212 goto done;
5213 }
5214
5215 switch (user_data_len) {
5216 case 8:
5217 if (data[7] < 0) {
5218 PRINTM(MERROR, "Invalid Rx timeout value (%d)\n",
5219 data[7]);
5220 ret = -EINVAL;
5221 goto done;
5222 }
5223 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_tmo =
5224 (t_u16)data[7];
5225 /* fall through */
5226 case 7:
5227 if (data[6] < 0 || (data[6] > 10000 &&
5228 data[6] != MLAN_USB_TX_AGGR_TIMEOUT_DYN)) {
5229 PRINTM(MERROR, "Invalid Tx timeout value (%d)\n",
5230 data[6]);
5231 ret = -EINVAL;
5232 goto done;
5233 }
5234 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_tmo =
5235 (t_u16)data[6];
5236 /* fall through */
5237 case 6:
5238 if ((data[5] < 512) || ((data[5] % 512) != 0)) {
5239 PRINTM(MERROR, "Invalid Rx alignment value (%d)\n",
5240 data[5]);
5241 ret = -EINVAL;
5242 goto done;
5243 }
5244 if (cardp->rx_deaggr_ctrl.enable &&
5245 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align !=
5246 (t_u16)data[5])
5247 usb_resubmit_urbs = 1;
5248 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align =
5249 (t_u16)data[5];
5250 /* fall through */
5251 case 5:
5252 if ((data[4] < 2048) || ((data[4] % 2048) != 0)) {
5253 PRINTM(MERROR, "Invalid Tx alignment value (%d)\n",
5254 data[4]);
5255 ret = -EINVAL;
5256 goto done;
5257 }
5258 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_align =
5259 (t_u16)data[4];
5260 /* fall through */
5261 case 4:
5262 if ((data[3] == 2) || (data[3] == 4) || (data[3] == 8) ||
5263 (data[3] == 16)) {
5264 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
5265 .aggr_mode = MLAN_USB_AGGR_MODE_NUM;
5266 } else if ((data[3] == 4096) || (data[3] == 8192) ||
5267 (data[3] == 16384) || (data[3] == 32768)) {
5268 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl
5269 .aggr_mode = MLAN_USB_AGGR_MODE_LEN;
5270 } else {
5271 PRINTM(MERROR, "Invalid Rx max size/num value (%d)\n",
5272 data[3]);
5273 ret = -EINVAL;
5274 goto done;
5275 }
5276 if (cardp->rx_deaggr_ctrl.enable &&
5277 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max !=
5278 (t_u16)data[3])
5279 usb_resubmit_urbs = 1;
5280 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max =
5281 (t_u16)data[3];
5282 /* fall through */
5283 case 3:
5284 if ((data[2] == 2) || (data[2] == 4) || (data[2] == 8) ||
5285 (data[2] == 16)) {
5286 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
5287 MLAN_USB_AGGR_MODE_NUM;
5288 } else if ((data[2] == 4096) || (data[2] == 8192) ||
5289 (data[2] == 16384) || (data[2] == 32768)) {
5290 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_mode =
5291 MLAN_USB_AGGR_MODE_LEN;
5292 } else {
5293 PRINTM(MERROR, "Invalid Tx max size/num value (%d)\n",
5294 data[2]);
5295 ret = -EINVAL;
5296 goto done;
5297 }
5298 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_max =
5299 (t_u16)data[2];
5300 /* fall through */
5301 case 2:
5302 if ((data[1] != 0) && (data[1] != 1)) {
5303 PRINTM(MERROR, "Invalid Rx enable value (%d)\n",
5304 data[1]);
5305 ret = -EINVAL;
5306 goto done;
5307 }
5308 if (pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable !=
5309 (t_u16)data[1])
5310 usb_resubmit_urbs = 1;
5311 pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable =
5312 (t_u16)data[1];
5313 /* fall through */
5314 case 1:
5315 if ((data[0] != 0) && (data[0] != 1)) {
5316 PRINTM(MERROR, "Invalid Tx enable value (%d)\n",
5317 data[0]);
5318 ret = -EINVAL;
5319 goto done;
5320 }
5321 pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.enable =
5322 (t_u16)data[0];
5323 default:
5324 break;
5325 }
5326
5327 pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL;
5328 req->req_id = MLAN_IOCTL_MISC_CFG;
5329 req->action = MLAN_ACT_SET;
5330
5331 /* Send IOCTL request to MLAN */
5332 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5333 if (status != MLAN_STATUS_SUCCESS) {
5334 ret = -EFAULT;
5335 goto done;
5336 }
5337
5338 moal_memcpy_ext(handle, respbuf,
5339 (t_u8 *)&pcfg_misc->param.usb_aggr_params,
5340 sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen);
5341 ret = sizeof(mlan_ds_misc_usb_aggr_ctrl);
5342
5343 /* Keep a copy of the latest Tx aggregation parameters in MOAL */
5344 moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl,
5345 &pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl,
5346 sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));
5347
5348 if (usb_resubmit_urbs) {
5349 /* Indicate resubmition from here */
5350 cardp->resubmit_urbs = 1;
5351 /* Rx SG parameters has changed or disabled, kill the URBs, they
5352 will be resubmitted after saving the parameters to USB card
5353 */
5354 if (atomic_read(&cardp->rx_data_urb_pending)) {
5355 for (i = 0; i < MVUSB_RX_DATA_URB; i++) {
5356 if (cardp->rx_data_list[i].urb) {
5357 usb_kill_urb(
5358 cardp->rx_data_list[i].urb);
5359 usb_init_urb(
5360 cardp->rx_data_list[i].urb);
5361 }
5362 }
5363 }
5364 }
5365
5366 /* Keep a copy of the latest Rx deaggregation parameters in MOAL */
5367 moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl,
5368 &pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl,
5369 sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg));
5370
5371 if (usb_resubmit_urbs) {
5372 /* Ensure the next data URBs will use the modified parameters */
5373 if (!atomic_read(&cardp->rx_data_urb_pending)) {
5374 /* Submit multiple Rx data URBs */
5375 woal_usb_submit_rx_data_urbs(handle);
5376 }
5377 cardp->resubmit_urbs = 0;
5378 }
5379
5380 done:
5381 if (status != MLAN_STATUS_PENDING)
5382 kfree(req);
5383
5384 LEAVE();
5385 return ret;
5386 }
5387 #endif
5388
5389 #ifdef STA_SUPPORT
5390 /**
5391 * @brief Set AP settings
5392 *
5393 * @param priv A pointer to moal_private structure
5394 * @param respbuf A pointer to response buffer
5395 * @param respbuflen Available length of response buffer
5396 *
5397 * @return Number of bytes written if successful, otherwise fail
5398 */
woal_priv_set_ap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5399 static int woal_priv_set_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
5400 {
5401 int ret = 0;
5402 t_u8 *data_ptr;
5403 const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = {255, 255, 255, 255, 255, 255};
5404 const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
5405 mlan_ssid_bssid ssid_bssid;
5406 mlan_bss_info bss_info;
5407 struct mwreq *mwr;
5408 struct sockaddr *awrq;
5409
5410 ENTER();
5411 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AP));
5412
5413 mwr = (struct mwreq *)data_ptr;
5414
5415 if (mwr->u.ap_addr.sa_family != ARPHRD_ETHER) {
5416 ret = -EINVAL;
5417 goto done;
5418 }
5419
5420 awrq = (struct sockaddr *)&(mwr->u.ap_addr);
5421
5422 PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n",
5423 MAC2STR((t_u8 *)awrq->sa_data));
5424
5425 if (MLAN_STATUS_SUCCESS !=
5426 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5427 ret = -EFAULT;
5428 goto done;
5429 }
5430
5431 #ifdef REASSOCIATION
5432 /* Cancel re-association */
5433 priv->reassoc_required = MFALSE;
5434 #endif
5435
5436 /* zero_mac means disconnect */
5437 if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
5438 woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL,
5439 DEF_DEAUTH_REASON_CODE);
5440 goto done;
5441 }
5442
5443 /* Broadcast MAC means search for best network */
5444 memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5445
5446 if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
5447 /* Check if we are already assoicated to the AP */
5448 if (bss_info.media_connected == MTRUE) {
5449 if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN))
5450 goto done;
5451 }
5452 moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data,
5453 ETH_ALEN, sizeof(mlan_802_11_mac_addr));
5454 }
5455
5456 if (MLAN_STATUS_SUCCESS !=
5457 woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5458 PRINTM(MERROR,
5459 "ASSOC: WAP: MAC address not found in BSSID List\n");
5460 ret = -ENETUNREACH;
5461 goto done;
5462 }
5463 /* Zero SSID implies use BSSID to connect */
5464 memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
5465 if (MLAN_STATUS_SUCCESS !=
5466 woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5467 ret = -EFAULT;
5468 goto done;
5469 }
5470
5471 #ifdef REASSOCIATION
5472 memset(&bss_info, 0, sizeof(bss_info));
5473 if (MLAN_STATUS_SUCCESS !=
5474 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5475 ret = -EFAULT;
5476 goto done;
5477 }
5478 moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
5479 &bss_info.ssid, sizeof(mlan_802_11_ssid),
5480 sizeof(mlan_802_11_ssid));
5481 moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
5482 &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
5483 sizeof(mlan_802_11_mac_addr));
5484 #endif /* REASSOCIATION */
5485
5486 done:
5487 LEAVE();
5488 return ret;
5489 }
5490 #endif
5491
5492 /**
5493 * @brief Set BSS mode
5494 *
5495 * @param priv A pointer to moal_private structure
5496 * @param respbuf A pointer to response buffer
5497 * @param respbuflen Available length of response buffer
5498 *
5499 * @return Number of bytes written if successful, otherwise fail
5500 */
woal_priv_set_bss_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5501 static int woal_priv_set_bss_mode(moal_private *priv, t_u8 *respbuf,
5502 t_u32 respbuflen)
5503 {
5504 int ret = 0;
5505 mlan_ds_bss *bss = NULL;
5506 mlan_ioctl_req *req = NULL;
5507 struct mwreq *mwr;
5508 t_u8 *data_ptr;
5509 t_u32 mode;
5510 mlan_status status = MLAN_STATUS_SUCCESS;
5511
5512 ENTER();
5513
5514 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_BSS_MODE));
5515
5516 mwr = (struct mwreq *)data_ptr;
5517 mode = mwr->u.mode;
5518 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
5519 if (req == NULL) {
5520 ret = -ENOMEM;
5521 goto done;
5522 }
5523 bss = (mlan_ds_bss *)req->pbuf;
5524 bss->sub_command = MLAN_OID_BSS_MODE;
5525 req->req_id = MLAN_IOCTL_BSS;
5526 req->action = MLAN_ACT_SET;
5527
5528 switch (mode) {
5529 case MW_MODE_INFRA:
5530 bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
5531 break;
5532 case MW_MODE_ADHOC:
5533 bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
5534 break;
5535 case MW_MODE_AUTO:
5536 bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
5537 break;
5538 default:
5539 ret = -EINVAL;
5540 break;
5541 }
5542 if (ret)
5543 goto done;
5544 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
5545 if (status != MLAN_STATUS_SUCCESS) {
5546 ret = -EFAULT;
5547 goto done;
5548 }
5549 done:
5550 if (status != MLAN_STATUS_PENDING)
5551 kfree(req);
5552 LEAVE();
5553 return ret;
5554 }
5555
5556 #ifdef STA_SUPPORT
5557 /**
5558 * @brief Set power management
5559 *
5560 * @param priv A pointer to moal_private structure
5561 * @param respbuf A pointer to response buffer
5562 * @param respbuflen Available length of response buffer
5563 *
5564 * @return Number of bytes written if successful, otherwise fail
5565 */
woal_priv_set_power(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5566 static int woal_priv_set_power(moal_private *priv, t_u8 *respbuf,
5567 t_u32 respbuflen)
5568 {
5569 struct mwreq *mwr;
5570 t_u8 *data_ptr;
5571 int ret = 0, disabled;
5572
5573 ENTER();
5574
5575 if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
5576 PRINTM(MIOCTL, "block set power in hw_test mode\n");
5577 LEAVE();
5578 return ret;
5579 }
5580
5581 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_POWER));
5582
5583 mwr = (struct mwreq *)data_ptr;
5584 disabled = mwr->u.power.disabled;
5585
5586 if (MLAN_STATUS_SUCCESS !=
5587 woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled,
5588 mwr->u.power.flags, MOAL_IOCTL_WAIT)) {
5589 return -EFAULT;
5590 }
5591 LEAVE();
5592 return ret;
5593 }
5594
5595 /**
5596 * @brief Set essid
5597 *
5598 * @param priv A pointer to moal_private structure
5599 * @param respbuf A pointer to response buffer
5600 * @param respbuflen Available length of response buffer
5601 *
5602 * @return Number of bytes written if successful, otherwise fail
5603 */
woal_priv_set_essid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5604 static int woal_priv_set_essid(moal_private *priv, t_u8 *respbuf,
5605 t_u32 respbuflen)
5606 {
5607 mlan_802_11_ssid req_ssid;
5608 mlan_ssid_bssid ssid_bssid;
5609 moal_handle *handle = priv->phandle;
5610 #ifdef REASSOCIATION
5611 mlan_bss_info bss_info;
5612 #endif
5613 int ret = 0;
5614 t_u32 mode = 0;
5615 struct mwreq *mwr;
5616 t_u8 *data_ptr;
5617
5618 ENTER();
5619
5620 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_ESSID));
5621
5622 mwr = (struct mwreq *)data_ptr;
5623
5624 #ifdef REASSOCIATION
5625 /* Cancel re-association */
5626 priv->reassoc_required = MFALSE;
5627
5628 if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
5629 PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n");
5630 LEAVE();
5631 return -EBUSY;
5632 }
5633 #endif /* REASSOCIATION */
5634
5635 /* Check the size of the string */
5636 if (mwr->u.essid.length > MW_ESSID_MAX_SIZE - 1) {
5637 ret = -E2BIG;
5638 goto setessid_ret;
5639 }
5640 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5641 woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
5642 memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
5643 memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5644
5645 req_ssid.ssid_len = mwr->u.essid.length;
5646
5647 /* Check if we asked for 'any' or 'particular' */
5648 if (!mwr->u.essid.flags) {
5649 #ifdef REASSOCIATION
5650 if (!req_ssid.ssid_len) {
5651 memset(&priv->prev_ssid_bssid.ssid, 0x00,
5652 sizeof(mlan_802_11_ssid));
5653 memset(&priv->prev_ssid_bssid.bssid, 0x00,
5654 MLAN_MAC_ADDR_LENGTH);
5655 goto setessid_ret;
5656 }
5657 #endif
5658 /* Do normal SSID scanning */
5659 if (MLAN_STATUS_SUCCESS !=
5660 woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) {
5661 ret = -EFAULT;
5662 goto setessid_ret;
5663 }
5664 } else {
5665 /* Set the SSID */
5666 moal_memcpy_ext(handle, req_ssid.ssid, mwr->u.essid.pointer,
5667 req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH);
5668 if (!req_ssid.ssid_len ||
5669 (MFALSE == woal_ssid_valid(&req_ssid))) {
5670 PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
5671 ret = -EINVAL;
5672 goto setessid_ret;
5673 }
5674
5675 PRINTM(MINFO, "Requested new SSID = %s\n",
5676 (char *)req_ssid.ssid);
5677 moal_memcpy_ext(handle, &ssid_bssid.ssid, &req_ssid,
5678 sizeof(mlan_802_11_ssid),
5679 sizeof(mlan_802_11_ssid));
5680 if (MTRUE == woal_is_connected(priv, &ssid_bssid)) {
5681 PRINTM(MIOCTL, "Already connect to the network\n");
5682 goto setessid_ret;
5683 }
5684
5685 priv->auto_assoc_priv.drv_assoc.status = MFALSE;
5686 priv->auto_assoc_priv.drv_reconnect.status = MFALSE;
5687 #ifdef REASSOCIATION
5688 if (priv->reassoc_on == MTRUE) {
5689 if (priv->auto_assoc_priv.auto_assoc_type_on &
5690 (0x1 << (AUTO_ASSOC_TYPE_DRV_ASSOC - 1))) {
5691 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5692 woal_set_scan_type(
5693 priv, MLAN_SCAN_TYPE_PASSIVE);
5694 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
5695 moal_memcpy_ext(handle,
5696 &priv->prev_ssid_bssid.ssid,
5697 &req_ssid,
5698 sizeof(mlan_802_11_ssid),
5699 sizeof(mlan_802_11_ssid));
5700 priv->auto_assoc_priv.auto_assoc_trigger_flag =
5701 AUTO_ASSOC_TYPE_DRV_ASSOC;
5702 priv->auto_assoc_priv.drv_assoc.status = MTRUE;
5703 priv->reassoc_required = MTRUE;
5704 priv->phandle->is_reassoc_timer_set = MTRUE;
5705 PRINTM(MINFO,
5706 " auto assoc: trigger driver auto re-assoc\n");
5707 woal_mod_timer(&priv->phandle->reassoc_timer,
5708 0);
5709 ret = MLAN_STATUS_SUCCESS;
5710
5711 LEAVE();
5712 return ret;
5713 }
5714 }
5715 #endif
5716
5717 if (mwr->u.essid.flags != 0xFFFF) {
5718 if (MLAN_STATUS_SUCCESS !=
5719 woal_find_essid(priv, &ssid_bssid,
5720 MOAL_IOCTL_WAIT)) {
5721 /* Do specific SSID scanning */
5722 if (MLAN_STATUS_SUCCESS !=
5723 woal_request_scan(priv, MOAL_IOCTL_WAIT,
5724 &req_ssid)) {
5725 ret = -EFAULT;
5726 goto setessid_ret;
5727 }
5728 }
5729 }
5730 }
5731
5732 mode = woal_get_mode(priv, MOAL_IOCTL_WAIT);
5733
5734 if (mode != MW_MODE_ADHOC) {
5735 if (MLAN_STATUS_SUCCESS !=
5736 woal_find_best_network(priv, MOAL_IOCTL_WAIT,
5737 &ssid_bssid)) {
5738 ret = -EFAULT;
5739 goto setessid_ret;
5740 }
5741 }
5742 #ifdef UAP_SUPPORT
5743 else if (MLAN_STATUS_SUCCESS !=
5744 woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid))
5745 /* Adhoc start, Check the channel command */
5746 woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT);
5747 #endif
5748
5749 /* Connect to BSS by ESSID */
5750 memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
5751
5752 if (MLAN_STATUS_SUCCESS !=
5753 woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
5754 ret = -EFAULT;
5755 goto setessid_ret;
5756 }
5757
5758 #ifdef REASSOCIATION
5759 memset(&bss_info, 0, sizeof(bss_info));
5760 if (MLAN_STATUS_SUCCESS !=
5761 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5762 ret = -EFAULT;
5763 goto setessid_ret;
5764 }
5765 moal_memcpy_ext(handle, &priv->prev_ssid_bssid.ssid, &bss_info.ssid,
5766 sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid));
5767 moal_memcpy_ext(handle, &priv->prev_ssid_bssid.bssid, &bss_info.bssid,
5768 MLAN_MAC_ADDR_LENGTH, sizeof(mlan_802_11_mac_addr));
5769 #endif /* REASSOCIATION */
5770
5771 setessid_ret:
5772 if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5773 woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
5774 #ifdef REASSOCIATION
5775 MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
5776 #endif
5777 LEAVE();
5778 return ret;
5779 }
5780
5781 /**
5782 * @brief Set authentication mode parameters
5783 *
5784 * @param priv A pointer to moal_private structure
5785 * @param respbuf A pointer to response buffer
5786 * @param respbuflen Available length of response buffer
5787 *
5788 * @return Number of bytes written if successful, otherwise fail
5789 */
woal_priv_set_auth(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5790 static int woal_priv_set_auth(moal_private *priv, t_u8 *respbuf,
5791 t_u32 respbuflen)
5792 {
5793 struct mwreq *mwr;
5794 t_u8 *data_ptr;
5795 int ret = 0;
5796 t_u32 auth_mode = 0;
5797 t_u32 encrypt_mode = 0;
5798
5799 ENTER();
5800
5801 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AUTH));
5802
5803 mwr = (struct mwreq *)data_ptr;
5804
5805 switch (mwr->u.param.flags & MW_AUTH_INDEX) {
5806 case MW_AUTH_CIPHER_PAIRWISE:
5807 case MW_AUTH_CIPHER_GROUP:
5808 if (mwr->u.param.value & MW_AUTH_CIPHER_NONE)
5809 encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
5810 else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP40)
5811 encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
5812 else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP104)
5813 encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
5814 else if (mwr->u.param.value & MW_AUTH_CIPHER_TKIP)
5815 encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
5816 else if (mwr->u.param.value & MW_AUTH_CIPHER_CCMP)
5817 encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
5818 if (MLAN_STATUS_SUCCESS !=
5819 woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode))
5820 ret = -EFAULT;
5821 break;
5822 case MW_AUTH_80211_AUTH_ALG:
5823 switch (mwr->u.param.value) {
5824 case MW_AUTH_ALG_SHARED_KEY:
5825 PRINTM(MINFO, "Auth mode shared key!\n");
5826 auth_mode = MLAN_AUTH_MODE_SHARED;
5827 break;
5828 case MW_AUTH_ALG_LEAP:
5829 PRINTM(MINFO, "Auth mode LEAP!\n");
5830 auth_mode = MLAN_AUTH_MODE_NETWORKEAP;
5831 break;
5832 case MW_AUTH_ALG_OPEN_SYSTEM:
5833 PRINTM(MINFO, "Auth mode open!\n");
5834 auth_mode = MLAN_AUTH_MODE_OPEN;
5835 break;
5836 case MW_AUTH_ALG_SHARED_KEY | MW_AUTH_ALG_OPEN_SYSTEM:
5837 default:
5838 PRINTM(MINFO, "Auth mode auto!\n");
5839 auth_mode = MLAN_AUTH_MODE_AUTO;
5840 break;
5841 }
5842 if (MLAN_STATUS_SUCCESS !=
5843 woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode))
5844 ret = -EFAULT;
5845 break;
5846 case MW_AUTH_WPA_ENABLED:
5847 if (MLAN_STATUS_SUCCESS !=
5848 woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT,
5849 mwr->u.param.value))
5850 ret = -EFAULT;
5851 break;
5852 #define MW_AUTH_WAPI_ENABLED 0x20
5853 case MW_AUTH_WAPI_ENABLED:
5854 if (MLAN_STATUS_SUCCESS !=
5855 woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT,
5856 mwr->u.param.value))
5857 ret = -EFAULT;
5858 break;
5859 case MW_AUTH_WPA_VERSION:
5860 /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */
5861 priv->wpa_version = mwr->u.param.value;
5862 break;
5863 case MW_AUTH_KEY_MGMT:
5864 /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */
5865 priv->key_mgmt = mwr->u.param.value;
5866 break;
5867 case MW_AUTH_TKIP_COUNTERMEASURES:
5868 case MW_AUTH_DROP_UNENCRYPTED:
5869 case MW_AUTH_RX_UNENCRYPTED_EAPOL:
5870 case MW_AUTH_ROAMING_CONTROL:
5871 case MW_AUTH_PRIVACY_INVOKED:
5872 break;
5873 default:
5874 ret = -EOPNOTSUPP;
5875 break;
5876 }
5877 LEAVE();
5878 return ret;
5879 }
5880
5881 /**
5882 * @brief Get current BSSID
5883 *
5884 * @param priv A pointer to moal_private structure
5885 * @param respbuf A pointer to response buffer
5886 * @param respbuflen Available length of response buffer
5887 *
5888 * @return Number of bytes written if successful else negative value
5889 */
woal_priv_get_ap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5890 static int woal_priv_get_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
5891 {
5892 struct mwreq *mwr;
5893 t_u8 *data_ptr;
5894 int ret = 0;
5895 mlan_bss_info bss_info;
5896
5897 ENTER();
5898
5899 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP));
5900
5901 mwr = (struct mwreq *)data_ptr;
5902
5903 memset(&bss_info, 0, sizeof(bss_info));
5904
5905 ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
5906 if (ret != MLAN_STATUS_SUCCESS)
5907 return -EFAULT;
5908
5909 if (bss_info.media_connected == MTRUE) {
5910 moal_memcpy_ext(priv->phandle, mwr->u.ap_addr.sa_data,
5911 &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
5912 sizeof(mwr->u.ap_addr.sa_data));
5913 } else {
5914 memset(mwr->u.ap_addr.sa_data, 0, MLAN_MAC_ADDR_LENGTH);
5915 }
5916 mwr->u.ap_addr.sa_family = ARPHRD_ETHER;
5917 ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP) + sizeof(struct mwreq);
5918
5919 LEAVE();
5920 return ret;
5921 }
5922
5923 /**
5924 * @brief Get power management
5925 *
5926 * @param priv A pointer to moal_private structure
5927 * @param respbuf A pointer to response buffer
5928 * @param respbuflen Available length of response buffer
5929 *
5930 * @return Number of bytes written if successful else negative value
5931 */
woal_priv_get_power(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5932 static int woal_priv_get_power(moal_private *priv, t_u8 *respbuf,
5933 t_u32 respbuflen)
5934 {
5935 struct mwreq *mwr;
5936 t_u8 *data_ptr;
5937 int ret = 0, ps_mode;
5938
5939 ENTER();
5940
5941 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER));
5942
5943 mwr = (struct mwreq *)data_ptr;
5944
5945 if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
5946 &ps_mode, 0,
5947 MOAL_IOCTL_WAIT)) {
5948 return -EFAULT;
5949 }
5950
5951 if (ps_mode)
5952 mwr->u.power.disabled = 0;
5953 else
5954 mwr->u.power.disabled = 1;
5955
5956 mwr->u.power.value = 0;
5957 ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER) +
5958 sizeof(struct mwreq);
5959 LEAVE();
5960 return ret;
5961 }
5962
5963 /**
5964 * @brief Set/Get power save mode
5965 *
5966 * @param priv A pointer to moal_private structure
5967 * @param respbuf A pointer to response buffer
5968 * @param respbuflen Available length of response buffer
5969 *
5970 * @return 0 --success, otherwise fail
5971 */
woal_priv_set_get_psmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)5972 static int woal_priv_set_get_psmode(moal_private *priv, t_u8 *respbuf,
5973 t_u32 respbuflen)
5974 {
5975 int ret = 0;
5976 int data = 0;
5977 int user_data_len = 0, header_len = 0;
5978 t_u32 action = MLAN_ACT_GET;
5979
5980 ENTER();
5981
5982 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSMODE);
5983
5984 if ((int)strlen(respbuf) == header_len) {
5985 /* GET operation */
5986 user_data_len = 0;
5987 action = MLAN_ACT_GET;
5988 } else {
5989 /* SET operation */
5990 parse_arguments(respbuf + header_len, &data,
5991 sizeof(data) / sizeof(int), &user_data_len);
5992 action = MLAN_ACT_SET;
5993 }
5994
5995 if (sizeof(int) * user_data_len > sizeof(data)) {
5996 PRINTM(MERROR, "Too many arguments\n");
5997 ret = -EINVAL;
5998 goto done;
5999 }
6000
6001 if (data != 0 && data != 1) {
6002 PRINTM(MERROR, "Invalid psmode=%d\n", data);
6003 ret = -EINVAL;
6004 goto done;
6005 }
6006
6007 /* Flip the value */
6008 data = !data;
6009
6010 if (MLAN_STATUS_SUCCESS !=
6011 woal_set_get_power_mgmt(priv, action, &data, 0, MOAL_IOCTL_WAIT)) {
6012 ret = -EFAULT;
6013 goto done;
6014 }
6015
6016 if (action == MLAN_ACT_SET)
6017 data = !data;
6018
6019 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
6020 respbuflen);
6021 ret = sizeof(data);
6022
6023 done:
6024 LEAVE();
6025 return ret;
6026 }
6027 #endif /* STA_SUPPORT */
6028
6029 /**
6030 * @brief Performs warm reset
6031 *
6032 * @param priv A pointer to moal_private structure
6033 * @param respbuf A pointer to response buffer
6034 * @param respbuflen Available length of response buffer
6035 *
6036 * @return Number of bytes written if successful else negative value
6037 */
woal_priv_warmreset(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6038 static int woal_priv_warmreset(moal_private *priv, t_u8 *respbuf,
6039 t_u32 respbuflen)
6040 {
6041 int ret = 0;
6042 moal_handle *handle = priv->phandle;
6043 moal_handle *ref_handle;
6044 moal_private *ref_priv;
6045 ENTER();
6046 ret = woal_pre_warmreset(priv);
6047 if (ret)
6048 goto done;
6049 ref_handle = (moal_handle *)handle->pref_mac;
6050 if (ref_handle) {
6051 ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
6052 if (ref_priv) {
6053 ret = woal_pre_warmreset(ref_priv);
6054 if (ret)
6055 goto done;
6056 ret = woal_warmreset(ref_priv);
6057 if (ret)
6058 goto done;
6059 }
6060 }
6061 ret = woal_warmreset(priv);
6062 done:
6063 LEAVE();
6064 return ret;
6065 }
6066
6067 /**
6068 * @brief Set/Get TX power configurations
6069 *
6070 * @param priv A pointer to moal_private structure
6071 * @param respbuf A pointer to response buffer
6072 * @param respbuflen Available length of response buffer
6073 *
6074 * @return 0 --success, otherwise fail
6075 */
woal_priv_txpowercfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6076 static int woal_priv_txpowercfg(moal_private *priv, t_u8 *respbuf,
6077 t_u32 respbuflen)
6078 {
6079 int data[5];
6080 int user_data_len;
6081 int ret = 0;
6082 mlan_bss_info bss_info;
6083 mlan_ds_power_cfg *pcfg = NULL;
6084 mlan_ioctl_req *req = NULL;
6085 t_u8 *arguments = NULL;
6086 mlan_status status = MLAN_STATUS_SUCCESS;
6087 ENTER();
6088
6089 memset(data, 0, sizeof(data));
6090 memset(&bss_info, 0, sizeof(bss_info));
6091 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
6092
6093 if (strlen(respbuf) ==
6094 (strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG))) {
6095 /* GET operation */
6096 user_data_len = 0;
6097 } else {
6098 /* SET operation */
6099 arguments =
6100 respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG);
6101 parse_arguments(arguments, data, ARRAY_SIZE(data),
6102 &user_data_len);
6103 }
6104
6105 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg));
6106 if (req == NULL) {
6107 ret = -ENOMEM;
6108 goto done;
6109 }
6110 pcfg = (mlan_ds_power_cfg *)req->pbuf;
6111 pcfg->sub_command = MLAN_OID_POWER_CFG_EXT;
6112 req->req_id = MLAN_IOCTL_POWER_CFG;
6113
6114 if (!user_data_len)
6115 req->action = MLAN_ACT_GET;
6116 else {
6117 /* SET operation */
6118 req->action = MLAN_ACT_SET;
6119 if (sizeof(int) * user_data_len > sizeof(data)) {
6120 PRINTM(MERROR, "Too many arguments\n");
6121 ret = -EINVAL;
6122 goto done;
6123 }
6124 switch (user_data_len) {
6125 case 1:
6126 if (data[0] == 0xFF)
6127 pcfg->param.power_ext.power_group[0]
6128 .rate_format = TX_PWR_CFG_AUTO_CTRL_OFF;
6129 else
6130 ret = -EINVAL;
6131 break;
6132 case 3:
6133 case 5:
6134 switch (data[0]) {
6135 case 0: /* LG */
6136 pcfg->param.power_ext.power_group[0]
6137 .rate_format = MLAN_RATE_FORMAT_LG;
6138 pcfg->param.power_ext.power_group[0].bandwidth =
6139 MLAN_HT_BW20;
6140 break;
6141 case 1: /* 20 MHz HT */
6142 pcfg->param.power_ext.power_group[0]
6143 .rate_format = MLAN_RATE_FORMAT_HT;
6144 pcfg->param.power_ext.power_group[0].bandwidth =
6145 MLAN_HT_BW20;
6146 break;
6147 case 2: /* 40 MHz HT */
6148 pcfg->param.power_ext.power_group[0]
6149 .rate_format = MLAN_RATE_FORMAT_HT;
6150 pcfg->param.power_ext.power_group[0].bandwidth =
6151 MLAN_HT_BW40;
6152 break;
6153 case 3: /* 1 NSS 20 MHZ VHT */
6154 pcfg->param.power_ext.power_group[0]
6155 .rate_format = MLAN_RATE_FORMAT_VHT;
6156 pcfg->param.power_ext.power_group[0].bandwidth =
6157 MLAN_HT_BW20;
6158 pcfg->param.power_ext.power_group[0].nss = 1;
6159 break;
6160 case 4: /* 2 NSS 20 MHZ VHT */
6161 pcfg->param.power_ext.power_group[0]
6162 .rate_format = MLAN_RATE_FORMAT_VHT;
6163 pcfg->param.power_ext.power_group[0].bandwidth =
6164 MLAN_HT_BW20;
6165 pcfg->param.power_ext.power_group[0].nss = 2;
6166 break;
6167 case 5: /* 1 NSS 40 MHZ VHT */
6168 pcfg->param.power_ext.power_group[0]
6169 .rate_format = MLAN_RATE_FORMAT_VHT;
6170 pcfg->param.power_ext.power_group[0].bandwidth =
6171 MLAN_HT_BW40;
6172 pcfg->param.power_ext.power_group[0].nss = 1;
6173 break;
6174 case 6: /* 2 NSS 40 MHZ VHT */
6175 pcfg->param.power_ext.power_group[0]
6176 .rate_format = MLAN_RATE_FORMAT_VHT;
6177 pcfg->param.power_ext.power_group[0].bandwidth =
6178 MLAN_HT_BW40;
6179 pcfg->param.power_ext.power_group[0].nss = 2;
6180 break;
6181 case 7: /* 1 NSS 80 MHZ VHT */
6182 pcfg->param.power_ext.power_group[0]
6183 .rate_format = MLAN_RATE_FORMAT_VHT;
6184 pcfg->param.power_ext.power_group[0].bandwidth =
6185 MLAN_VHT_BW80;
6186 pcfg->param.power_ext.power_group[0].nss = 1;
6187 break;
6188 case 8: /* 2 NSS 80 MHZ VHT */
6189 pcfg->param.power_ext.power_group[0]
6190 .rate_format = MLAN_RATE_FORMAT_VHT;
6191 pcfg->param.power_ext.power_group[0].bandwidth =
6192 MLAN_VHT_BW80;
6193 pcfg->param.power_ext.power_group[0].nss = 2;
6194 break;
6195 default:
6196 ret = -EINVAL;
6197 break;
6198 }
6199 pcfg->param.power_ext.power_group[0].first_rate_ind =
6200 data[1];
6201 pcfg->param.power_ext.power_group[0].last_rate_ind =
6202 data[1];
6203 if (data[2] < bss_info.min_power_level) {
6204 PRINTM(MERROR,
6205 "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
6206 data[2], (int)bss_info.min_power_level,
6207 (int)bss_info.max_power_level);
6208 ret = -EINVAL;
6209 break;
6210 }
6211 if (data[2] > bss_info.max_power_level) {
6212 PRINTM(MERROR,
6213 "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n",
6214 data[2], (int)bss_info.min_power_level,
6215 (int)bss_info.max_power_level);
6216 ret = -EINVAL;
6217 break;
6218 }
6219 pcfg->param.power_ext.power_group[0].power_min =
6220 data[2];
6221 pcfg->param.power_ext.power_group[0].power_max =
6222 data[2];
6223 pcfg->param.power_ext.power_group[0].power_step = 0;
6224 pcfg->param.power_ext.num_pwr_grp = 1;
6225
6226 break;
6227 default:
6228 ret = -EINVAL;
6229 break;
6230 }
6231 if (ret)
6232 goto done;
6233 }
6234 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6235 if (status != MLAN_STATUS_SUCCESS) {
6236 ret = -EFAULT;
6237 goto done;
6238 }
6239 if (!user_data_len) {
6240 /* GET operation */
6241 moal_memcpy_ext(priv->phandle, respbuf,
6242 (t_u8 *)&pcfg->param.power_ext,
6243 sizeof(pcfg->param.power_ext.num_pwr_grp) +
6244 (MIN(pcfg->param.power_ext.num_pwr_grp,
6245 MAX_POWER_GROUP) *
6246 sizeof(mlan_power_group)),
6247 respbuflen);
6248 ret = sizeof(pcfg->param.power_ext.num_pwr_grp) +
6249 (MIN(pcfg->param.power_ext.num_pwr_grp, MAX_POWER_GROUP) *
6250 sizeof(mlan_power_group));
6251 }
6252 done:
6253 if (status != MLAN_STATUS_PENDING)
6254 kfree(req);
6255 LEAVE();
6256 return ret;
6257 }
6258
6259 /**
6260 * @brief Set/Get PS configuration parameters
6261 *
6262 * @param priv A pointer to moal_private structure
6263 * @param respbuf A pointer to response buffer
6264 * @param respbuflen Available length of response buffer
6265 *
6266 * @return 0 --success, otherwise fail
6267 */
woal_priv_pscfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6268 static int woal_priv_pscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
6269 {
6270 int data[7] = {0}, ret = 0;
6271 mlan_ds_pm_cfg *pm_cfg = NULL;
6272 mlan_ioctl_req *req = NULL;
6273 int allowed = 3;
6274 int i = 3;
6275 int user_data_len = 0, header_len = 0;
6276 mlan_status status = MLAN_STATUS_SUCCESS;
6277
6278 ENTER();
6279
6280 allowed++; /* For beacon missing timeout parameter */
6281 allowed += 2; /* For delay to PS and PS mode parameters */
6282 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6283 if (req == NULL) {
6284 ret = -ENOMEM;
6285 goto done;
6286 }
6287
6288 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSCFG);
6289
6290 if ((int)strlen(respbuf) == header_len) {
6291 /* GET operation */
6292 user_data_len = 0;
6293 } else {
6294 /* SET operation */
6295 memset((char *)data, 0, sizeof(data));
6296 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6297 &user_data_len);
6298 }
6299
6300 if (user_data_len && user_data_len > allowed) {
6301 PRINTM(MERROR, "Too many arguments\n");
6302 ret = -EINVAL;
6303 goto done;
6304 }
6305 pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6306 pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG;
6307 req->req_id = MLAN_IOCTL_PM_CFG;
6308 if (user_data_len) {
6309 if ((data[0] < PS_NULL_DISABLE)) {
6310 PRINTM(MERROR,
6311 "Invalid argument for PS null interval\n");
6312 ret = -EINVAL;
6313 goto done;
6314 }
6315 if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) &&
6316 (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) &&
6317 ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) ||
6318 (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) {
6319 PRINTM(MERROR, "Invalid argument for multiple DTIM\n");
6320 ret = -EINVAL;
6321 goto done;
6322 }
6323
6324 if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) &&
6325 (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) {
6326 PRINTM(MERROR,
6327 "Invalid argument for listen interval\n");
6328 ret = -EINVAL;
6329 goto done;
6330 }
6331
6332 if ((data[i] != DISABLE_BCN_MISS_TO) &&
6333 ((data[i] < MIN_BCN_MISS_TO) ||
6334 (data[i] > MAX_BCN_MISS_TO))) {
6335 PRINTM(MERROR,
6336 "Invalid argument for beacon miss timeout\n");
6337 ret = -EINVAL;
6338 goto done;
6339 }
6340 i++;
6341 if (user_data_len < allowed - 1)
6342 data[i] = DELAY_TO_PS_UNCHANGED;
6343 else if ((data[i] < MIN_DELAY_TO_PS) ||
6344 (data[i] > MAX_DELAY_TO_PS)) {
6345 PRINTM(MERROR, "Invalid argument for delay to PS\n");
6346 ret = -EINVAL;
6347 goto done;
6348 }
6349 i++;
6350 if ((data[i] != PS_MODE_UNCHANGED) &&
6351 (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) &&
6352 (data[i] != PS_MODE_NULL)) {
6353 PRINTM(MERROR, "Invalid argument for PS mode\n");
6354 ret = -EINVAL;
6355 goto done;
6356 }
6357 i++;
6358 req->action = MLAN_ACT_SET;
6359 moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data,
6360 sizeof(data), sizeof(pm_cfg->param.ps_cfg));
6361 } else
6362 req->action = MLAN_ACT_GET;
6363
6364 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6365 if (status != MLAN_STATUS_SUCCESS) {
6366 ret = -EFAULT;
6367 goto done;
6368 }
6369 moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg,
6370 MIN((sizeof(int) * allowed),
6371 sizeof(pm_cfg->param.ps_cfg)),
6372 sizeof(data));
6373 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
6374 sizeof(int) * allowed, respbuflen);
6375 ret = sizeof(int) * allowed;
6376 if (req->action == MLAN_ACT_SET) {
6377 pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6378 pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS;
6379 pm_cfg->param.ps_mode = 1;
6380 req->req_id = MLAN_IOCTL_PM_CFG;
6381 req->action = MLAN_ACT_SET;
6382 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6383 }
6384
6385 done:
6386 if (status != MLAN_STATUS_PENDING)
6387 kfree(req);
6388 LEAVE();
6389 return ret;
6390 }
6391
6392 /**
6393 * @brief Set/Get PS configuration parameters
6394 *
6395 * @param priv A pointer to moal_private structure
6396 * @param respbuf A pointer to response buffer
6397 * @param respbuflen Available length of response buffer
6398 *
6399 * @return 0 --success, otherwise fail
6400 */
woal_priv_bcntimeoutcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6401 static int woal_priv_bcntimeoutcfg(moal_private *priv, t_u8 *respbuf,
6402 t_u32 respbuflen)
6403 {
6404 int data[4] = {0}, ret = 0;
6405 mlan_ds_pm_cfg *pm_cfg = NULL;
6406 mlan_ioctl_req *req = NULL;
6407 int allowed = 4;
6408 int i = 0;
6409 int user_data_len = 0, header_len = 0;
6410 mlan_status status = MLAN_STATUS_SUCCESS;
6411
6412 ENTER();
6413
6414 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCNTIMEOUTCFG);
6415
6416 memset((char *)data, 0, sizeof(data));
6417 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6418 &user_data_len);
6419 if (user_data_len != allowed) {
6420 PRINTM(MERROR, "Invalid args num: input=%d allowed=%d\n",
6421 user_data_len, allowed);
6422 ret = -EINVAL;
6423 goto done;
6424 }
6425 for (i = 0; i < allowed; i++) {
6426 if (data[i] <= 0) {
6427 PRINTM(MERROR, "Invalid data[%d]=%d\n", i, data[i]);
6428 ret = -EINVAL;
6429 goto done;
6430 }
6431 }
6432
6433 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6434 if (req == NULL) {
6435 ret = -ENOMEM;
6436 goto done;
6437 }
6438 pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6439 pm_cfg->sub_command = MLAN_OID_PM_CFG_BCN_TIMEOUT;
6440 req->req_id = MLAN_IOCTL_PM_CFG;
6441 req->action = MLAN_ACT_SET;
6442 pm_cfg->param.bcn_timeout.bcn_miss_tmo_window = (t_u16)data[0];
6443 pm_cfg->param.bcn_timeout.bcn_miss_tmo_period = (t_u16)data[1];
6444 pm_cfg->param.bcn_timeout.bcn_rq_tmo_window = (t_u16)data[2];
6445 pm_cfg->param.bcn_timeout.bcn_rq_tmo_period = (t_u16)data[3];
6446
6447 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6448 if (status != MLAN_STATUS_SUCCESS) {
6449 ret = -EFAULT;
6450 goto done;
6451 }
6452
6453 done:
6454 if (status != MLAN_STATUS_PENDING)
6455 kfree(req);
6456 LEAVE();
6457 return ret;
6458 }
6459
6460 /**
6461 * @brief Set/Get sleep period
6462 *
6463 * @param priv A pointer to moal_private structure
6464 * @param respbuf A pointer to response buffer
6465 * @param respbuflen Available length of response buffer
6466 *
6467 * @return 0 --success, otherwise fail
6468 */
woal_priv_sleeppd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6469 static int woal_priv_sleeppd(moal_private *priv, t_u8 *respbuf,
6470 t_u32 respbuflen)
6471 {
6472 int ret = 0;
6473 mlan_ds_pm_cfg *pm_cfg = NULL;
6474 mlan_ioctl_req *req = NULL;
6475 int data = 0;
6476 int user_data_len = 0, header_len = 0;
6477 mlan_status status = MLAN_STATUS_SUCCESS;
6478
6479 ENTER();
6480
6481 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
6482 if (req == NULL) {
6483 ret = -ENOMEM;
6484 goto done;
6485 }
6486 pm_cfg = (mlan_ds_pm_cfg *)req->pbuf;
6487 pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD;
6488 req->req_id = MLAN_IOCTL_PM_CFG;
6489
6490 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEPPD);
6491
6492 if ((int)strlen(respbuf) == header_len) {
6493 /* GET operation */
6494 user_data_len = 0;
6495 } else {
6496 /* SET operation */
6497 parse_arguments(respbuf + header_len, &data,
6498 sizeof(data) / sizeof(int), &user_data_len);
6499 }
6500
6501 if (sizeof(int) * user_data_len > sizeof(data)) {
6502 PRINTM(MERROR, "Too many arguments\n");
6503 ret = -EINVAL;
6504 goto done;
6505 }
6506
6507 if (user_data_len) {
6508 if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
6509 (data == 0) || (data == SLEEP_PERIOD_RESERVED_FF)) {
6510 req->action = MLAN_ACT_SET;
6511 pm_cfg->param.sleep_period = data;
6512 } else {
6513 ret = -EINVAL;
6514 goto done;
6515 }
6516 } else
6517 req->action = MLAN_ACT_GET;
6518
6519 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6520 if (status != MLAN_STATUS_SUCCESS) {
6521 ret = -EFAULT;
6522 goto done;
6523 }
6524 if (!user_data_len) {
6525 data = pm_cfg->param.sleep_period;
6526 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
6527 sizeof(data), respbuflen);
6528 ret = sizeof(data);
6529 }
6530
6531 done:
6532 if (status != MLAN_STATUS_PENDING)
6533 kfree(req);
6534 LEAVE();
6535 return ret;
6536 }
6537
6538 /**
6539 * @brief Set/Get Tx control flag
6540 *
6541 * @param priv A pointer to moal_private structure
6542 * @param respbuf A pointer to response buffer
6543 * @param respbuflen Available length of response buffer
6544 *
6545 * @return 0 --success, otherwise fail
6546 */
woal_priv_txcontrol(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6547 static int woal_priv_txcontrol(moal_private *priv, t_u8 *respbuf,
6548 t_u32 respbuflen)
6549 {
6550 int ret = 0;
6551 mlan_ds_misc_cfg *misc_cfg = NULL;
6552 mlan_ioctl_req *req = NULL;
6553 int data = 0;
6554 int user_data_len = 0, header_len = 0;
6555 mlan_status status = MLAN_STATUS_SUCCESS;
6556
6557 ENTER();
6558
6559 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6560 if (req == NULL) {
6561 ret = -ENOMEM;
6562 goto done;
6563 }
6564 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
6565 misc_cfg->sub_command = MLAN_OID_MISC_TXCONTROL;
6566 req->req_id = MLAN_IOCTL_MISC_CFG;
6567
6568 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXCONTROL);
6569
6570 if ((int)strlen(respbuf) == header_len) {
6571 /* GET operation */
6572 user_data_len = 0;
6573 } else {
6574 /* SET operation */
6575 parse_arguments(respbuf + header_len, &data,
6576 sizeof(data) / sizeof(int), &user_data_len);
6577 }
6578
6579 if (sizeof(int) * user_data_len > sizeof(data)) {
6580 PRINTM(MERROR, "Too many arguments\n");
6581 ret = -EINVAL;
6582 goto done;
6583 }
6584
6585 if (user_data_len) {
6586 req->action = MLAN_ACT_SET;
6587 misc_cfg->param.tx_control = (t_u32)data;
6588 } else {
6589 req->action = MLAN_ACT_GET;
6590 }
6591
6592 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6593 if (status != MLAN_STATUS_SUCCESS) {
6594 ret = -EFAULT;
6595 goto done;
6596 }
6597 if (!user_data_len) {
6598 data = misc_cfg->param.tx_control;
6599 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
6600 sizeof(data), respbuflen);
6601 ret = sizeof(data);
6602 }
6603
6604 done:
6605 if (status != MLAN_STATUS_PENDING)
6606 kfree(req);
6607 LEAVE();
6608 return ret;
6609 }
6610
6611 /**
6612 * @brief Read/Write adapter registers value
6613 *
6614 * @param priv A pointer to moal_private structure
6615 * @param respbuf A pointer to response buffer
6616 * @param respbuflen Available length of response buffer
6617 *
6618 * @return 0 --success, otherwise fail
6619 */
woal_priv_regrdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6620 static int woal_priv_regrdwr(moal_private *priv, t_u8 *respbuf,
6621 t_u32 respbuflen)
6622 {
6623 int data[3];
6624 int ret = 0;
6625 mlan_ioctl_req *req = NULL;
6626 mlan_ds_reg_mem *reg_mem = NULL;
6627 int user_data_len = 0, header_len = 0;
6628 t_u8 *arguments = NULL, *space_ind = NULL;
6629 t_u32 is_negative_val = MFALSE;
6630 mlan_status status = MLAN_STATUS_SUCCESS;
6631 gfp_t flag;
6632
6633 ENTER();
6634
6635 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6636 if (req == NULL) {
6637 ret = -ENOMEM;
6638 goto done;
6639 }
6640
6641 reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6642 reg_mem->sub_command = MLAN_OID_REG_RW;
6643 req->req_id = MLAN_IOCTL_REG_MEM;
6644
6645 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGRDWR);
6646
6647 if ((int)strlen(respbuf) == header_len) {
6648 ret = -EINVAL;
6649 goto done;
6650 }
6651 /* SET operation */
6652 memset((char *)data, 0, sizeof(data));
6653 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
6654 arguments = kzalloc(strlen(respbuf) * sizeof(char), flag);
6655 if (arguments == NULL) {
6656 ret = -ENOMEM;
6657 goto done;
6658 }
6659 strcpy(arguments, respbuf + header_len);
6660 space_ind = strstr((char *)arguments, " ");
6661 if (space_ind)
6662 space_ind = strstr(space_ind + 1, " ");
6663 if (space_ind) {
6664 if (*(char *)(space_ind + 1) == '-') {
6665 is_negative_val = MTRUE;
6666 arguments[space_ind + 1 - arguments] = '\0';
6667 strcat(arguments, space_ind + 2);
6668 }
6669 }
6670 parse_arguments(arguments, data, ARRAY_SIZE(data), &user_data_len);
6671 if (is_negative_val == MTRUE)
6672 data[2] *= -1;
6673
6674 if (user_data_len == 2) {
6675 req->action = MLAN_ACT_GET;
6676 } else if (user_data_len == 3) {
6677 req->action = MLAN_ACT_SET;
6678 } else {
6679 ret = -EINVAL;
6680 goto done;
6681 }
6682
6683 reg_mem->param.reg_rw.type = (t_u32)data[0];
6684 reg_mem->param.reg_rw.offset = (t_u32)data[1];
6685 if (user_data_len == 3)
6686 reg_mem->param.reg_rw.value = (t_u32)data[2];
6687
6688 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6689 if (status != MLAN_STATUS_SUCCESS) {
6690 ret = -EFAULT;
6691 goto done;
6692 }
6693
6694 if (req->action == MLAN_ACT_GET) {
6695 moal_memcpy_ext(priv->phandle, respbuf, ®_mem->param.reg_rw,
6696 sizeof(reg_mem->param.reg_rw), respbuflen);
6697 ret = sizeof(reg_mem->param.reg_rw);
6698 }
6699
6700 done:
6701 if (status != MLAN_STATUS_PENDING)
6702 kfree(req);
6703 kfree(arguments);
6704 LEAVE();
6705 return ret;
6706 }
6707
6708 /**
6709 * @brief Read the EEPROM contents of the card
6710 *
6711 * @param priv A pointer to moal_private structure
6712 * @param respbuf A pointer to response buffer
6713 * @param respbuflen Available length of response buffer
6714 *
6715 * @return 0 --success, otherwise fail
6716 */
woal_priv_rdeeprom(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6717 static int woal_priv_rdeeprom(moal_private *priv, t_u8 *respbuf,
6718 t_u32 respbuflen)
6719 {
6720 int data[2];
6721 int ret = 0;
6722 mlan_ioctl_req *req = NULL;
6723 mlan_ds_reg_mem *reg_mem = NULL;
6724 int user_data_len = 0, header_len = 0;
6725 mlan_status status = MLAN_STATUS_SUCCESS;
6726
6727 ENTER();
6728
6729 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6730 if (req == NULL) {
6731 ret = -ENOMEM;
6732 goto done;
6733 }
6734
6735 reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6736 reg_mem->sub_command = MLAN_OID_EEPROM_RD;
6737 req->req_id = MLAN_IOCTL_REG_MEM;
6738
6739 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RDEEPROM);
6740
6741 if ((int)strlen(respbuf) == header_len) {
6742 ret = -EINVAL;
6743 goto done;
6744 }
6745 /* SET operation */
6746 memset((char *)data, 0, sizeof(data));
6747 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6748 &user_data_len);
6749
6750 if (user_data_len == 2) {
6751 req->action = MLAN_ACT_GET;
6752 } else {
6753 ret = -EINVAL;
6754 goto done;
6755 }
6756
6757 reg_mem->param.rd_eeprom.offset = (t_u16)data[0];
6758 reg_mem->param.rd_eeprom.byte_count = (t_u16)data[1];
6759
6760 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6761 if (status != MLAN_STATUS_SUCCESS) {
6762 ret = -EFAULT;
6763 goto done;
6764 }
6765
6766 if (req->action == MLAN_ACT_GET) {
6767 moal_memcpy_ext(priv->phandle, respbuf,
6768 ®_mem->param.rd_eeprom,
6769 sizeof(reg_mem->param.rd_eeprom), respbuflen);
6770 ret = sizeof(reg_mem->param.rd_eeprom);
6771 }
6772
6773 done:
6774 if (status != MLAN_STATUS_PENDING)
6775 kfree(req);
6776 LEAVE();
6777 return ret;
6778 }
6779
6780 /**
6781 * @brief Read/Write device memory value
6782 *
6783 * @param priv A pointer to moal_private structure
6784 * @param respbuf A pointer to response buffer
6785 * @param respbuflen Available length of response buffer
6786 *
6787 * @return 0 --success, otherwise fail
6788 */
woal_priv_memrdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6789 static int woal_priv_memrdwr(moal_private *priv, t_u8 *respbuf,
6790 t_u32 respbuflen)
6791 {
6792 int data[2];
6793 int ret = 0;
6794 mlan_ioctl_req *req = NULL;
6795 mlan_ds_reg_mem *reg_mem = NULL;
6796 int user_data_len = 0, header_len = 0;
6797 mlan_status status = MLAN_STATUS_SUCCESS;
6798
6799 ENTER();
6800
6801 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem));
6802 if (req == NULL) {
6803 ret = -ENOMEM;
6804 goto done;
6805 }
6806
6807 reg_mem = (mlan_ds_reg_mem *)req->pbuf;
6808 reg_mem->sub_command = MLAN_OID_MEM_RW;
6809 req->req_id = MLAN_IOCTL_REG_MEM;
6810
6811 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MEMRDWR);
6812
6813 if ((int)strlen(respbuf) == header_len) {
6814 ret = -EINVAL;
6815 goto done;
6816 }
6817 /* SET operation */
6818 memset((char *)data, 0, sizeof(data));
6819 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
6820 &user_data_len);
6821
6822 if (user_data_len == 1) {
6823 PRINTM(MINFO, "MEM_RW: GET\n");
6824 req->action = MLAN_ACT_GET;
6825 } else if (user_data_len == 2) {
6826 PRINTM(MINFO, "MEM_RW: SET\n");
6827 req->action = MLAN_ACT_SET;
6828 } else {
6829 ret = -EINVAL;
6830 goto done;
6831 }
6832
6833 reg_mem->param.mem_rw.addr = (t_u32)data[0];
6834 if (user_data_len == 2)
6835 reg_mem->param.mem_rw.value = (t_u32)data[1];
6836
6837 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6838 if (status != MLAN_STATUS_SUCCESS) {
6839 ret = -EFAULT;
6840 goto done;
6841 }
6842
6843 if (req->action == MLAN_ACT_GET) {
6844 moal_memcpy_ext(priv->phandle, respbuf, ®_mem->param.mem_rw,
6845 sizeof(reg_mem->param.mem_rw), respbuflen);
6846 ret = sizeof(reg_mem->param.mem_rw);
6847 }
6848
6849 done:
6850 if (status != MLAN_STATUS_PENDING)
6851 kfree(req);
6852 LEAVE();
6853 return ret;
6854 }
6855
6856 #ifdef SDIO
6857 /**
6858 * @brief Cmd52 read/write register
6859 *
6860 * @param priv A pointer to moal_private structure
6861 * @param respbuf A pointer to response buffer
6862 * @param respbuflen Available length of response buffer
6863 *
6864 * @return MLAN_STATUS_SUCCESS --success, otherwise fail
6865 */
woal_priv_sdcmd52rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6866 static int woal_priv_sdcmd52rw(moal_private *priv, t_u8 *respbuf,
6867 t_u32 respbuflen)
6868 {
6869 t_u8 rw = 0, func, data = 0;
6870 int buf[3], reg, ret = MLAN_STATUS_SUCCESS;
6871 int user_data_len = 0, header_len = 0;
6872
6873 ENTER();
6874
6875 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDCMD52RW);
6876 memset((t_u8 *)buf, 0, sizeof(buf));
6877
6878 if ((int)strlen(respbuf) == header_len) {
6879 PRINTM(MERROR, "Invalid number of arguments\n");
6880 ret = -EINVAL;
6881 goto done;
6882 }
6883 parse_arguments(respbuf + header_len, buf, ARRAY_SIZE(buf),
6884 &user_data_len);
6885
6886 if (user_data_len < 2 || user_data_len > 3) {
6887 PRINTM(MERROR, "Invalid number of arguments\n");
6888 ret = -EINVAL;
6889 goto done;
6890 }
6891
6892 func = (t_u8)buf[0];
6893 if (func > 7) {
6894 PRINTM(MERROR, "Invalid function number!\n");
6895 ret = -EINVAL;
6896 goto done;
6897 }
6898 reg = (t_u32)buf[1];
6899 if (user_data_len == 2) {
6900 rw = 0; /* CMD52 read */
6901 PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
6902 }
6903 if (user_data_len == 3) {
6904 rw = 1; /* CMD52 write */
6905 data = (t_u8)buf[2];
6906 PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n",
6907 func, reg, data);
6908 }
6909
6910 if (!rw) {
6911 #ifdef SDIO_MMC
6912 sdio_claim_host(
6913 ((struct sdio_mmc_card *)priv->phandle->card)->func);
6914 if (func)
6915 data = sdio_readb(
6916 ((struct sdio_mmc_card *)priv->phandle->card)
6917 ->func,
6918 reg, &ret);
6919 else
6920 data = sdio_f0_readb(
6921 ((struct sdio_mmc_card *)priv->phandle->card)
6922 ->func,
6923 reg, &ret);
6924 sdio_release_host(
6925 ((struct sdio_mmc_card *)priv->phandle->card)->func);
6926 if (ret) {
6927 PRINTM(MERROR,
6928 "sdio_readb: reading register 0x%X failed\n",
6929 reg);
6930 goto done;
6931 }
6932 #else
6933 if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) <
6934 0) {
6935 PRINTM(MERROR,
6936 "sdio_read_ioreg: reading register 0x%X failed\n",
6937 reg);
6938 ret = MLAN_STATUS_FAILURE;
6939 goto done;
6940 }
6941 #endif /* SDIO_MMC */
6942 } else {
6943 #ifdef SDIO_MMC
6944 sdio_claim_host(
6945 ((struct sdio_mmc_card *)priv->phandle->card)->func);
6946 if (func)
6947 sdio_writeb(
6948 ((struct sdio_mmc_card *)priv->phandle->card)
6949 ->func,
6950 data, reg, &ret);
6951 else
6952 sdio_f0_writeb(
6953 ((struct sdio_mmc_card *)priv->phandle->card)
6954 ->func,
6955 data, reg, &ret);
6956 sdio_release_host(
6957 ((struct sdio_mmc_card *)priv->phandle->card)->func);
6958 if (ret) {
6959 PRINTM(MERROR,
6960 "sdio_writeb: writing register 0x%X failed\n",
6961 reg);
6962 goto done;
6963 }
6964 #else
6965 if (sdio_write_ioreg(priv->phandle->card, func, reg, data) <
6966 0) {
6967 PRINTM(MERROR,
6968 "sdio_write_ioreg: writing register 0x%X failed\n",
6969 reg);
6970 ret = MLAN_STATUS_FAILURE;
6971 goto done;
6972 }
6973 #endif /* SDIO_MMC */
6974 }
6975
6976 /* Action = GET */
6977 buf[0] = data;
6978
6979 moal_memcpy_ext(priv->phandle, respbuf, &buf, sizeof(int), respbuflen);
6980 ret = sizeof(int);
6981
6982 done:
6983 LEAVE();
6984 return ret;
6985 }
6986 #endif /* SDIO */
6987
6988 #ifdef STA_SUPPORT
6989 /**
6990 * @brief arpfilter ioctl function
6991 *
6992 * @param priv A pointer to moal_private structure
6993 * @param respbuf A pointer to response buffer
6994 * @param respbuflen Available length of response buffer
6995 *
6996 * @return 0 --success, otherwise fail
6997 */
woal_priv_arpfilter(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)6998 static int woal_priv_arpfilter(moal_private *priv, t_u8 *respbuf,
6999 t_u32 respbuflen)
7000 {
7001 int ret = 0;
7002 mlan_ds_misc_cfg *misc = NULL;
7003 mlan_ioctl_req *req = NULL;
7004 t_u8 *data_ptr = NULL;
7005 t_u32 buf_len = 0;
7006 mlan_status status = MLAN_STATUS_SUCCESS;
7007
7008 ENTER();
7009
7010 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7011 if (req == NULL) {
7012 ret = -ENOMEM;
7013 goto done;
7014 }
7015 misc = (mlan_ds_misc_cfg *)req->pbuf;
7016 misc->sub_command = MLAN_OID_MISC_GEN_IE;
7017 req->req_id = MLAN_IOCTL_MISC_CFG;
7018 req->action = MLAN_ACT_SET;
7019 misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER;
7020
7021 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_ARPFILTER));
7022 buf_len = *((t_u16 *)data_ptr);
7023 misc->param.gen_ie.len = buf_len;
7024 moal_memcpy_ext(priv->phandle, (void *)(misc->param.gen_ie.ie_data),
7025 data_ptr + sizeof(buf_len), buf_len, MAX_IE_SIZE);
7026
7027 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7028 if (status != MLAN_STATUS_SUCCESS) {
7029 ret = -EFAULT;
7030 goto done;
7031 }
7032 done:
7033 if (status != MLAN_STATUS_PENDING)
7034 kfree(req);
7035 LEAVE();
7036 return ret;
7037 }
7038 #endif /* STA_SUPPORT */
7039
7040 /**
7041 * @brief Set / Get Auto ARP Response configuration
7042 *
7043 * @param priv A pointer to moal_private structure
7044 * @param respbuf A pointer to response buffer
7045 * @param respbuflen Available length of response buffer
7046 *
7047 * @return Number of bytes written, negative for failure.
7048 */
woal_priv_set_get_auto_arp(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7049 static int woal_priv_set_get_auto_arp(moal_private *priv, t_u8 *respbuf,
7050 t_u32 respbuflen)
7051 {
7052 int data[4];
7053 int user_data_len = 0;
7054 int ret = 0;
7055 moal_handle *handle = NULL;
7056
7057 ENTER();
7058
7059 if (priv == NULL) {
7060 PRINTM(MERROR, "Invalid priv\n");
7061 goto done;
7062 }
7063 handle = priv->phandle;
7064
7065 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_ARP))) {
7066 /* GET operation */
7067 user_data_len = 0;
7068 } else {
7069 /* SET operation */
7070 memset((char *)data, 0, sizeof(data));
7071 parse_arguments(respbuf + strlen(CMD_NXP) +
7072 strlen(PRIV_CMD_AUTO_ARP),
7073 data, ARRAY_SIZE(data), &user_data_len);
7074 }
7075
7076 if (user_data_len > 1) {
7077 PRINTM(MERROR, "Too many arguments\n");
7078 ret = -EINVAL;
7079 goto done;
7080 }
7081
7082 if (user_data_len) {
7083 /* Get the enable/disable value from user */
7084 handle->hs_auto_arp = data[0];
7085 PRINTM(MIOCTL, "Auto ARP : %s\n",
7086 handle->hs_auto_arp ? "enable" : "disable");
7087 }
7088
7089 moal_memcpy_ext(handle, respbuf, &handle->hs_auto_arp,
7090 sizeof(handle->hs_auto_arp), respbuflen);
7091 ret = sizeof(handle->hs_auto_arp);
7092
7093 done:
7094 LEAVE();
7095 return ret;
7096 }
7097
7098 /**
7099 * @brief Get/Set deauth control
7100 *
7101 * @param priv A pointer to moal_private structure
7102 * @param respbuf A pointer to response buffer
7103 * @param respbuflen Available length of response buffer
7104 *
7105 * @return Number of bytes written, negative for failure.
7106 */
woal_priv_deauth_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7107 static int woal_priv_deauth_ctrl(moal_private *priv, t_u8 *respbuf,
7108 t_u32 respbuflen)
7109 {
7110 mlan_ds_snmp_mib *cfg = NULL;
7111 mlan_ioctl_req *req = NULL;
7112 int ret = 0, header_len = 0, data = 0, user_data_len = 0;
7113 mlan_status status = MLAN_STATUS_SUCCESS;
7114
7115 ENTER();
7116
7117 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
7118 if (req == NULL) {
7119 ret = -ENOMEM;
7120 goto done;
7121 }
7122
7123 cfg = (mlan_ds_snmp_mib *)req->pbuf;
7124 cfg->sub_command = MLAN_OID_SNMP_MIB_CTRL_DEAUTH;
7125 req->req_id = MLAN_IOCTL_SNMP_MIB;
7126
7127 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH_CTRL);
7128
7129 if ((int)strlen(respbuf) == header_len) {
7130 /* GET operation */
7131 req->action = MLAN_ACT_GET;
7132 } else {
7133 /* SET operation */
7134 parse_arguments(respbuf + header_len, &data,
7135 sizeof(data) / sizeof(int), &user_data_len);
7136 if (user_data_len != 1) {
7137 PRINTM(MERROR, "Invalid number of args! %d\n",
7138 user_data_len);
7139 ret = -EINVAL;
7140 goto done;
7141 }
7142 req->action = MLAN_ACT_SET;
7143 cfg->param.deauthctrl = (t_u8)data;
7144 }
7145
7146 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7147 if (status != MLAN_STATUS_SUCCESS) {
7148 ret = -EFAULT;
7149 goto done;
7150 }
7151
7152 data = (int)cfg->param.deauthctrl;
7153 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
7154 respbuflen);
7155 ret = sizeof(data);
7156
7157 done:
7158 if (status != MLAN_STATUS_PENDING)
7159 kfree(req);
7160 LEAVE();
7161 return ret;
7162 }
7163
7164 #define MRVL_TLV_HEADER_SIZE 4
7165 /**
7166 * @brief Get/Set per packet Txctl and Rxinfo configuration
7167 *
7168 * @param priv A pointer to moal_private structure
7169 * @param respbuf A pointer to response buffer
7170 * @param respbuflen Available length of response buffer
7171 *
7172 * @return Number of bytes written, negative for failure.
7173 */
woal_priv_per_pkt_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7174 static int woal_priv_per_pkt_cfg(moal_private *priv, t_u8 *respbuf,
7175 t_u32 respbuflen)
7176 {
7177 mlan_ds_misc_cfg *misc = NULL;
7178 mlan_ioctl_req *req = NULL;
7179 int ret = 0;
7180 t_u8 *pos = NULL;
7181 int left_len, header_len = 0;
7182 mlan_per_pkt_cfg *perpkt = NULL;
7183 mlan_status status = MLAN_STATUS_SUCCESS;
7184
7185 ENTER();
7186
7187 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PER_PKT_CFG);
7188 pos = respbuf + header_len;
7189 left_len = respbuflen - header_len;
7190
7191 if (priv->phandle->card_info->per_pkt_cfg_support == 0) {
7192 PRINTM(MERROR, "Device not support per packet configuration\n");
7193 ret = -EFAULT;
7194 goto done;
7195 }
7196
7197 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7198 if (req == NULL) {
7199 ret = -ENOMEM;
7200 goto done;
7201 }
7202
7203 misc = (mlan_ds_misc_cfg *)req->pbuf;
7204 misc->sub_command = MLAN_OID_MISC_PER_PKT_CFG;
7205 req->req_id = MLAN_IOCTL_MISC_CFG;
7206
7207 if (*pos == 0) {
7208 /* GET operation */
7209 pos++;
7210 if (priv->tx_protocols.protocol_num) {
7211 perpkt = (mlan_per_pkt_cfg *)pos;
7212 perpkt->type = TLV_TYPE_PER_PKT_CFG;
7213 perpkt->tx_rx_control = TX_PKT_CTRL;
7214 perpkt->proto_type_num =
7215 priv->tx_protocols.protocol_num;
7216 moal_memcpy_ext(priv->phandle, perpkt->ether_type,
7217 priv->tx_protocols.protocols,
7218 perpkt->proto_type_num * sizeof(t_u16),
7219 MAX_NUM_ETHER_TYPE * sizeof(t_u16));
7220 perpkt->len =
7221 (perpkt->proto_type_num + 1) * sizeof(t_u16);
7222 pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7223 }
7224 if (priv->rx_protocols.protocol_num) {
7225 perpkt = (mlan_per_pkt_cfg *)pos;
7226 perpkt->type = TLV_TYPE_PER_PKT_CFG;
7227 perpkt->tx_rx_control = RX_PKT_INFO;
7228 perpkt->proto_type_num =
7229 priv->rx_protocols.protocol_num;
7230 moal_memcpy_ext(priv->phandle, perpkt->ether_type,
7231 priv->rx_protocols.protocols,
7232 perpkt->proto_type_num * sizeof(t_u16),
7233 MAX_NUM_ETHER_TYPE * sizeof(t_u16));
7234 perpkt->len =
7235 (perpkt->proto_type_num + 1) * sizeof(t_u16);
7236 pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7237 }
7238 ret = pos - respbuf;
7239 goto done;
7240 } else if (*pos == 1) {
7241 /* SET operation */
7242 req->action = MLAN_ACT_SET;
7243 pos++;
7244 left_len--;
7245 while (*pos == TLV_TYPE_PER_PKT_CFG && (left_len > 2)) {
7246 perpkt = (mlan_per_pkt_cfg *)pos;
7247 if (perpkt->tx_rx_control & TX_PKT_CTRL) {
7248 priv->tx_protocols.protocol_num =
7249 perpkt->proto_type_num;
7250 if (perpkt->proto_type_num <=
7251 MAX_NUM_ETHER_TYPE)
7252 moal_memcpy_ext(
7253 priv->phandle,
7254 priv->tx_protocols.protocols,
7255 perpkt->ether_type,
7256 perpkt->proto_type_num *
7257 sizeof(t_u16),
7258 MAX_NUM_ETHER_TYPE *
7259 sizeof(t_u16));
7260 }
7261 if (perpkt->tx_rx_control & RX_PKT_INFO) {
7262 priv->rx_protocols.protocol_num =
7263 perpkt->proto_type_num;
7264 if (perpkt->proto_type_num <=
7265 MAX_NUM_ETHER_TYPE)
7266 moal_memcpy_ext(
7267 priv->phandle,
7268 priv->rx_protocols.protocols,
7269 perpkt->ether_type,
7270 perpkt->proto_type_num *
7271 sizeof(t_u16),
7272 MAX_NUM_ETHER_TYPE *
7273 sizeof(t_u16));
7274 }
7275 if (!perpkt->tx_rx_control) {
7276 memset(&priv->tx_protocols, 0,
7277 sizeof(dot11_protocol));
7278 memset(&priv->rx_protocols, 0,
7279 sizeof(dot11_protocol));
7280 }
7281 pos += perpkt->len + MRVL_TLV_HEADER_SIZE;
7282 left_len -= (perpkt->len + MRVL_TLV_HEADER_SIZE);
7283 }
7284 } else
7285 goto done;
7286
7287 if (perpkt != NULL)
7288 misc->param.txrx_pkt_ctrl = perpkt->tx_rx_control;
7289 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7290 if (status != MLAN_STATUS_SUCCESS) {
7291 ret = -EFAULT;
7292 goto done;
7293 }
7294
7295 done:
7296 if (status != MLAN_STATUS_PENDING)
7297 kfree(req);
7298 LEAVE();
7299 return ret;
7300 }
7301
7302 /**
7303 * @brief Get Region Channel Power
7304 *
7305 * @param priv A pointer to moal_private structure
7306 * @param respbuf A pointer to response buffer
7307 * @param respbuflen Available length of response buffer
7308 *
7309 * @return Number of bytes written, negative for failure.
7310 */
woal_priv_get_chnrgpwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7311 static int woal_priv_get_chnrgpwr(moal_private *priv, t_u8 *respbuf,
7312 t_u32 respbuflen)
7313 {
7314 int ret = 0;
7315 mlan_ioctl_req *req = NULL;
7316 mlan_ds_misc_cfg *misc = NULL;
7317 int header_len = 0;
7318 t_u8 *pos = NULL;
7319 mlan_status status = MLAN_STATUS_SUCCESS;
7320
7321 ENTER();
7322 header_len = strlen(PRIV_CMD_GET_CHNRGPWR);
7323 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7324 if (req == NULL) {
7325 ret = -ENOMEM;
7326 goto done;
7327 }
7328 misc = (mlan_ds_misc_cfg *)req->pbuf;
7329 misc->sub_command = MLAN_OID_MISC_GET_REGIONPWR_CFG;
7330 req->req_id = MLAN_IOCTL_MISC_CFG;
7331 req->action = MLAN_ACT_GET;
7332 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7333 if (status != MLAN_STATUS_SUCCESS) {
7334 ret = -EFAULT;
7335 goto done;
7336 }
7337 ret = header_len + sizeof(t_u16) + misc->param.rgchnpwr_cfg.length;
7338 pos = respbuf + header_len;
7339 moal_memcpy_ext(priv->phandle, pos, &misc->param.rgchnpwr_cfg,
7340 sizeof(t_u16) + misc->param.rgchnpwr_cfg.length,
7341 respbuflen - header_len);
7342 done:
7343 if (status != MLAN_STATUS_PENDING)
7344 kfree(req);
7345 LEAVE();
7346 return ret;
7347 }
7348
7349 /**
7350 * @brief Get TX/RX histogram statistic
7351 *
7352 * @param priv A pointer to moal_private structure
7353 * @param respbuf A pointer to response buffer
7354 * @param respbuflen Available length of response buffer
7355 *
7356 * @return Number of bytes written, negative for failure.
7357 */
woal_priv_get_txpwrlimit(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7358 static int woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf,
7359 t_u32 respbuflen)
7360 {
7361 int ret = 0;
7362 mlan_ioctl_req *req = NULL;
7363 mlan_ds_misc_cfg *misc = NULL;
7364 mlan_ds_misc_chan_trpc_cfg *trpc_cfg = NULL;
7365 int header_len = 0;
7366 t_u8 *pos = NULL;
7367 mlan_status status = MLAN_STATUS_SUCCESS;
7368
7369 ENTER();
7370 header_len = strlen(PRIV_CMD_GET_TXPWR_LIMIT);
7371 trpc_cfg = (mlan_ds_misc_chan_trpc_cfg *)(respbuf + header_len);
7372 if ((trpc_cfg->sub_band != 0) && (trpc_cfg->sub_band != 0x10) &&
7373 (trpc_cfg->sub_band != 0x11) && (trpc_cfg->sub_band != 0x12) &&
7374 (trpc_cfg->sub_band != 0x13)) {
7375 PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band);
7376 ret = -EINVAL;
7377 goto done;
7378 }
7379 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7380 if (req == NULL) {
7381 ret = -ENOMEM;
7382 goto done;
7383 }
7384 misc = (mlan_ds_misc_cfg *)req->pbuf;
7385 misc->sub_command = MLAN_OID_MISC_GET_CHAN_TRPC_CFG;
7386 req->req_id = MLAN_IOCTL_MISC_CFG;
7387 req->action = MLAN_ACT_GET;
7388 misc->param.trpc_cfg.sub_band = trpc_cfg->sub_band;
7389 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7390 if (status != MLAN_STATUS_SUCCESS) {
7391 ret = -EFAULT;
7392 goto done;
7393 }
7394 ret = header_len + sizeof(t_u16) + sizeof(t_u16) +
7395 misc->param.trpc_cfg.length;
7396 pos = respbuf + header_len;
7397 moal_memcpy_ext(priv->phandle, pos, &misc->param.trpc_cfg,
7398 sizeof(t_u16) + sizeof(t_u16) +
7399 misc->param.trpc_cfg.length,
7400 respbuflen - header_len);
7401 done:
7402 if (status != MLAN_STATUS_PENDING)
7403 kfree(req);
7404 LEAVE();
7405 return ret;
7406 }
7407
7408 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
7409 /**
7410 * @brief Get TX/RX histogram statistic
7411 *
7412 * @param priv A pointer to moal_private structure
7413 * @param respbuf A pointer to response buffer
7414 * @param respbuflen Available length of response buffer
7415 *
7416 * @return Number of bytes written, negative for failure.
7417 */
woal_priv_getcfgchanlist(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7418 static int woal_priv_getcfgchanlist(moal_private *priv, t_u8 *respbuf,
7419 t_u32 respbuflen)
7420 {
7421 int ret = 0;
7422 int num_chan = 0;
7423 wlan_ieee80211_chan_list *plist = NULL;
7424 struct ieee80211_supported_band *sband;
7425 struct wiphy *wiphy = NULL;
7426 int i;
7427
7428 ENTER();
7429 if (priv && priv->wdev)
7430 wiphy = priv->wdev->wiphy;
7431 if (!wiphy) {
7432 PRINTM(MERROR, "wiphy is NULL\n");
7433 ret = -EFAULT;
7434 goto done;
7435 }
7436 plist = (wlan_ieee80211_chan_list *)respbuf;
7437 sband = wiphy->bands[NL80211_BAND_2GHZ];
7438 if (sband) {
7439 num_chan += sband->n_channels;
7440 for (i = 0; i < sband->n_channels; i++) {
7441 plist->chan_list[i].center_freq =
7442 sband->channels[i].center_freq;
7443 plist->chan_list[i].hw_value =
7444 sband->channels[i].hw_value;
7445 plist->chan_list[i].flags = sband->channels[i].flags;
7446 plist->chan_list[i].max_power =
7447 sband->channels[i].max_power;
7448 }
7449 }
7450 sband = wiphy->bands[NL80211_BAND_5GHZ];
7451 if (sband) {
7452 for (i = 0; i < sband->n_channels; i++) {
7453 plist->chan_list[i + num_chan].center_freq =
7454 sband->channels[i].center_freq;
7455 plist->chan_list[i + num_chan].hw_value =
7456 sband->channels[i].hw_value;
7457 plist->chan_list[i + num_chan].flags =
7458 sband->channels[i].flags;
7459 plist->chan_list[i + num_chan].max_power =
7460 sband->channels[i].max_power;
7461 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
7462 plist->chan_list[i + num_chan].dfs_state =
7463 sband->channels[i].dfs_state;
7464 #endif
7465 }
7466 num_chan += sband->n_channels;
7467 }
7468 plist->num_chan = num_chan;
7469 ret = sizeof(wlan_ieee80211_chan_list) +
7470 sizeof(wlan_ieee80211_chan) * num_chan;
7471 done:
7472 LEAVE();
7473 return ret;
7474 }
7475 #endif
7476
7477 /**
7478 * @brief Get TX/RX histogram statistic
7479 *
7480 * @param priv A pointer to moal_private structure
7481 * @param respbuf A pointer to response buffer
7482 * @param respbuflen Available length of response buffer
7483 *
7484 * @return Number of bytes written, negative for failure.
7485 */
woal_priv_get_rx_tx_histogram(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7486 static int woal_priv_get_rx_tx_histogram(moal_private *priv, t_u8 *respbuf,
7487 t_u32 respbuflen)
7488 {
7489 int ret = 0;
7490 mlan_ioctl_req *req = NULL;
7491 mlan_ds_misc_cfg *misc = NULL;
7492 tx_rx_histogram *tx_rx_info = NULL;
7493 int header_len = 0;
7494 t_u8 *pos = NULL;
7495 mlan_status status = MLAN_STATUS_SUCCESS;
7496
7497 ENTER();
7498 header_len = strlen(PRIV_CMD_TX_RX_HISTOGRAM);
7499 tx_rx_info = (tx_rx_histogram *)(respbuf + header_len);
7500 if (tx_rx_info->enable > 2 ||
7501 (tx_rx_info->enable == GET_TX_RX_HISTOGRAM &&
7502 (tx_rx_info->action > 3 || tx_rx_info->action <= 0))) {
7503 PRINTM(MERROR, "Invalid parameters\n");
7504 ret = -EINVAL;
7505 goto done;
7506 }
7507 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7508 if (req == NULL) {
7509 ret = -ENOMEM;
7510 goto done;
7511 }
7512 misc = (mlan_ds_misc_cfg *)req->pbuf;
7513 misc->sub_command = MLAN_OID_MISC_GET_TX_RX_HISTOGRAM;
7514 req->req_id = MLAN_IOCTL_MISC_CFG;
7515 if (tx_rx_info->enable == GET_TX_RX_HISTOGRAM) {
7516 misc->param.tx_rx_histogram.enable = ENABLE_TX_RX_HISTOGRAM;
7517 misc->param.tx_rx_histogram.action = (t_u16)tx_rx_info->action;
7518 } else {
7519 misc->param.tx_rx_histogram.enable = tx_rx_info->enable;
7520 misc->param.tx_rx_histogram.action |=
7521 FLAG_TX_HISTOGRAM | FLAG_RX_HISTOGRAM;
7522 }
7523
7524 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7525 if (status != MLAN_STATUS_SUCCESS) {
7526 ret = -EFAULT;
7527 goto done;
7528 }
7529
7530 ret = header_len + 2 * sizeof(t_u8);
7531 if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) {
7532 pos = respbuf + header_len + 2 * sizeof(t_u8);
7533 /* Save tx/rx histogram size */
7534 moal_memcpy_ext(priv->phandle, pos,
7535 &misc->param.tx_rx_histogram.size,
7536 sizeof(misc->param.tx_rx_histogram.size),
7537 respbuflen - (header_len + 2 * sizeof(t_u8)));
7538 ret += sizeof(misc->param.tx_rx_histogram.size);
7539 pos += sizeof(misc->param.tx_rx_histogram.size);
7540 moal_memcpy_ext(
7541 priv->phandle, pos, &misc->param.tx_rx_histogram.value,
7542 misc->param.tx_rx_histogram.size,
7543 respbuflen - (header_len + 2 * sizeof(t_u8)) -
7544 sizeof(misc->param.tx_rx_histogram.size));
7545 ret += misc->param.tx_rx_histogram.size;
7546 }
7547
7548 done:
7549 if (status != MLAN_STATUS_PENDING)
7550 kfree(req);
7551 LEAVE();
7552 return ret;
7553 }
7554
7555 /**
7556 * @brief Set/Get hotspot mode configurations
7557 *
7558 * @param priv A pointer to moal_private structure
7559 * @param respbuf A pointer to response buffer
7560 * @param respbuflen Available length of response buffer
7561 *
7562 * @return 0 --success, otherwise fail
7563 */
woal_priv_hotspotcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7564 static int woal_priv_hotspotcfg(moal_private *priv, t_u8 *respbuf,
7565 t_u32 respbuflen)
7566 {
7567 int ret = 0;
7568 mlan_ioctl_req *req = NULL;
7569 mlan_ds_misc_cfg *cfg = NULL;
7570 int data = 0;
7571 int user_data_len = 0, header_len = 0;
7572 mlan_status status = MLAN_STATUS_SUCCESS;
7573
7574 ENTER();
7575
7576 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOTSPOTCFG);
7577 if ((int)strlen(respbuf) == header_len) {
7578 /* GET operation */
7579 user_data_len = 0;
7580 } else {
7581 /* SET operation */
7582 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
7583 }
7584 if (user_data_len >= 2) {
7585 PRINTM(MERROR, "Too many arguments\n");
7586 ret = -EINVAL;
7587 goto done;
7588 } else {
7589 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7590 if (req == NULL) {
7591 ret = -ENOMEM;
7592 goto done;
7593 }
7594
7595 cfg = (mlan_ds_misc_cfg *)req->pbuf;
7596 if (user_data_len == 0) {
7597 req->action = MLAN_ACT_GET;
7598 } else {
7599 cfg->param.hotspot_cfg = data;
7600 req->action = MLAN_ACT_SET;
7601 }
7602 }
7603 cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG;
7604 req->req_id = MLAN_IOCTL_MISC_CFG;
7605
7606 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7607 if (status != MLAN_STATUS_SUCCESS) {
7608 ret = -EFAULT;
7609 goto done;
7610 }
7611 data = cfg->param.hotspot_cfg;
7612 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
7613 respbuflen);
7614 ret = sizeof(data);
7615
7616 done:
7617 if (status != MLAN_STATUS_PENDING)
7618 kfree(req);
7619 LEAVE();
7620 return ret;
7621 }
7622
7623 /**
7624 * @brief Set/Get Mgmt Frame passthru mask
7625 *
7626 * @param priv A pointer to moal_private structure
7627 * @param respbuf A pointer to response buffer
7628 * @param respbuflen Available length of response buffer
7629 *
7630 * @return 0 --success, otherwise fail
7631 */
woal_priv_mgmt_frame_passthru_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7632 static int woal_priv_mgmt_frame_passthru_ctrl(moal_private *priv, t_u8 *respbuf,
7633 t_u32 respbuflen)
7634 {
7635 int ret = 0;
7636 int data = 0;
7637 int user_data_len = 0, header_len = 0;
7638 mlan_ioctl_req *req = NULL;
7639 mlan_ds_misc_cfg *mgmt_cfg = NULL;
7640 mlan_status status = MLAN_STATUS_SUCCESS;
7641
7642 ENTER();
7643 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MGMT_FRAME_CTRL);
7644 if ((int)strlen(respbuf) == header_len) {
7645 /* GET operation */
7646 user_data_len = 0;
7647 } else {
7648 /* SET operation */
7649 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
7650 }
7651
7652 if (user_data_len >= 2) {
7653 PRINTM(MERROR, "Too many arguments\n");
7654 ret = -EINVAL;
7655 goto done;
7656 } else {
7657 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7658 if (req == NULL) {
7659 ret = -ENOMEM;
7660 goto done;
7661 }
7662 mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf;
7663 req->req_id = MLAN_IOCTL_MISC_CFG;
7664 mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND;
7665
7666 if (user_data_len == 0) { /* Get */
7667 req->action = MLAN_ACT_GET;
7668 } else { /* Set */
7669 mgmt_cfg->param.mgmt_subtype_mask = data;
7670 req->action = MLAN_ACT_SET;
7671 }
7672 }
7673
7674 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7675 if (status != MLAN_STATUS_SUCCESS) {
7676 ret = -EFAULT;
7677 goto done;
7678 }
7679
7680 data = mgmt_cfg->param.mgmt_subtype_mask;
7681 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data),
7682 respbuflen);
7683 ret = sizeof(data);
7684
7685 done:
7686 if (status != MLAN_STATUS_PENDING)
7687 kfree(req);
7688 LEAVE();
7689 return ret;
7690 }
7691
7692 /**
7693 * @brief Private IOCTL entry to send an ADDTS TSPEC
7694 *
7695 * Receive a ADDTS command from the application. The command structure
7696 * contains a TSPEC and timeout in milliseconds. The timeout is performed
7697 * in the firmware after the ADDTS command frame is sent.
7698 *
7699 * The TSPEC is received in the API as an opaque block. The firmware will
7700 * send the entire data block, including the bytes after the TSPEC. This
7701 * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS
7702 * action frame.
7703 *
7704 * The IOCTL structure contains two return fields:
7705 * - The firmware command result, which indicates failure and timeouts
7706 * - The IEEE Status code which contains the corresponding value from
7707 * any ADDTS response frame received.
7708 *
7709 * In addition, the opaque TSPEC data block passed in is replaced with the
7710 * TSPEC received in the ADDTS response frame. In case of failure, the
7711 * AP may modify the TSPEC on return and in the case of success, the
7712 * medium time is returned as calculated by the AP. Along with the TSPEC,
7713 * any IEs that are sent in the ADDTS response are also returned and can be
7714 * parsed using the IOCTL length as an indicator of extra elements.
7715 *
7716 * The return value to the application layer indicates a driver execution
7717 * success or failure. A successful return could still indicate a firmware
7718 * failure or AP negotiation failure via the commandResult field copied
7719 * back to the application.
7720 *
7721 * @param priv Pointer to the mlan_private driver data struct
7722 * @param respbuf A pointer to response buffer
7723 * @param respbuflen Available length of response buffer
7724 *
7725 * @return Number of bytes written if successful else negative value
7726 */
woal_priv_wmm_addts_req_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7727 static int woal_priv_wmm_addts_req_ioctl(moal_private *priv, t_u8 *respbuf,
7728 t_u32 respbuflen)
7729 {
7730 mlan_ioctl_req *req = NULL;
7731 mlan_ds_wmm_cfg *cfg = NULL;
7732 wlan_ioctl_wmm_addts_req_t addts_ioctl;
7733 int ret = 0, header_len = 0, copy_len = sizeof(addts_ioctl);
7734 t_u8 *data_ptr;
7735 mlan_status status = MLAN_STATUS_SUCCESS;
7736
7737 ENTER();
7738
7739 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ADDTS);
7740 data_ptr = respbuf + header_len;
7741 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7742 if (req == NULL) {
7743 ret = -ENOMEM;
7744 goto done;
7745 }
7746
7747 req->req_id = MLAN_IOCTL_WMM_CFG;
7748 cfg = (mlan_ds_wmm_cfg *)req->pbuf;
7749 cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS;
7750
7751 memset(&addts_ioctl, 0x00, sizeof(addts_ioctl));
7752
7753 moal_memcpy_ext(priv->phandle, (t_u8 *)&addts_ioctl, data_ptr,
7754 sizeof(addts_ioctl), sizeof(addts_ioctl));
7755
7756 cfg->param.addts.timeout = addts_ioctl.timeout_ms;
7757 cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len;
7758
7759 moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data,
7760 addts_ioctl.ie_data, cfg->param.addts.ie_data_len,
7761 MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
7762
7763 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7764 if (status != MLAN_STATUS_SUCCESS) {
7765 ret = -EFAULT;
7766 goto done;
7767 }
7768 addts_ioctl.cmd_result = cfg->param.addts.result;
7769 addts_ioctl.ieee_status_code = (t_u8)cfg->param.addts.status_code;
7770 addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len;
7771
7772 moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data,
7773 cfg->param.addts.ie_data, cfg->param.addts.ie_data_len,
7774 MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES);
7775
7776 copy_len = (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) +
7777 cfg->param.addts.ie_data_len);
7778
7779 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&addts_ioctl, copy_len,
7780 respbuflen);
7781 ret = copy_len;
7782
7783 done:
7784 if (status != MLAN_STATUS_PENDING)
7785 kfree(req);
7786 LEAVE();
7787 return ret;
7788 }
7789
7790 /**
7791 * @brief Private IOCTL entry to send a DELTS TSPEC
7792 *
7793 * Receive a DELTS command from the application. The command structure
7794 * contains a TSPEC and reason code along with space for a command result
7795 * to be returned. The information is packaged is sent to the wlan_cmd.c
7796 * firmware command prep and send routines for execution in the firmware.
7797 *
7798 * The reason code is not used for WMM implementations but is indicated in
7799 * the 802.11e specification.
7800 *
7801 * The return value to the application layer indicates a driver execution
7802 * success or failure. A successful return could still indicate a firmware
7803 * failure via the cmd_result field copied back to the application.
7804 *
7805 * @param priv Pointer to the mlan_private driver data struct
7806 * @param respbuf A pointer to response buffer
7807 * @param respbuflen Available length of response buffer
7808 *
7809 * @return Number of bytes written if successful else negative value
7810 */
woal_priv_wmm_delts_req_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7811 static int woal_priv_wmm_delts_req_ioctl(moal_private *priv, t_u8 *respbuf,
7812 t_u32 respbuflen)
7813 {
7814 mlan_ioctl_req *req = NULL;
7815 mlan_ds_wmm_cfg *cfg = NULL;
7816 wlan_ioctl_wmm_delts_req_t delts_ioctl;
7817 int ret = 0, header_len = 0, copy_len = 0;
7818 t_u8 *data_ptr;
7819 mlan_status status = MLAN_STATUS_SUCCESS;
7820
7821 ENTER();
7822
7823 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELTS);
7824 data_ptr = respbuf + header_len;
7825 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7826 if (req == NULL) {
7827 ret = -ENOMEM;
7828 goto done;
7829 }
7830
7831 req->req_id = MLAN_IOCTL_WMM_CFG;
7832 cfg = (mlan_ds_wmm_cfg *)req->pbuf;
7833 cfg->sub_command = MLAN_OID_WMM_CFG_DELTS;
7834
7835 memset(&delts_ioctl, 0x00, sizeof(delts_ioctl));
7836
7837 if ((int)strlen(respbuf) > header_len) {
7838 copy_len = MIN(strlen(data_ptr), sizeof(delts_ioctl));
7839 moal_memcpy_ext(priv->phandle, (t_u8 *)&delts_ioctl, data_ptr,
7840 copy_len, sizeof(delts_ioctl));
7841
7842 cfg->param.delts.status_code =
7843 (t_u32)delts_ioctl.ieee_reason_code;
7844 cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len;
7845
7846 moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data,
7847 delts_ioctl.ie_data,
7848 cfg->param.delts.ie_data_len,
7849 MLAN_WMM_TSPEC_SIZE);
7850
7851 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7852 if (status != MLAN_STATUS_SUCCESS) {
7853 ret = -EFAULT;
7854 goto done;
7855 }
7856
7857 /* Return the firmware command result back to the application
7858 * layer */
7859 delts_ioctl.cmd_result = cfg->param.delts.result;
7860 copy_len = sizeof(delts_ioctl);
7861 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&delts_ioctl,
7862 copy_len, respbuflen);
7863 ret = copy_len;
7864 }
7865
7866 done:
7867 if (status != MLAN_STATUS_PENDING)
7868 kfree(req);
7869 LEAVE();
7870 return ret;
7871 }
7872
7873 /**
7874 * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
7875 *
7876 * Receive a AC Queue configuration command which is used to get, set, or
7877 * default the parameters associated with a specific WMM AC Queue.
7878 *
7879 * @param priv A pointer to moal_private structure
7880 * @param respbuf A pointer to response buffer
7881 * @param respbuflen Available length of response buffer
7882 *
7883 * @return 0 --success, otherwise fail
7884 */
woal_priv_qconfig(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7885 static int woal_priv_qconfig(moal_private *priv, t_u8 *respbuf,
7886 t_u32 respbuflen)
7887 {
7888 mlan_ioctl_req *req = NULL;
7889 mlan_ds_wmm_cfg *pwmm = NULL;
7890 mlan_ds_wmm_queue_config *pqcfg = NULL;
7891 wlan_ioctl_wmm_queue_config_t qcfg_ioctl;
7892 t_u8 *data_ptr;
7893 int ret = 0;
7894 mlan_status status = MLAN_STATUS_SUCCESS;
7895
7896 ENTER();
7897
7898 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7899 if (req == NULL) {
7900 ret = -ENOMEM;
7901 goto done;
7902 }
7903
7904 req->req_id = MLAN_IOCTL_WMM_CFG;
7905 pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
7906 pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG;
7907
7908 memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
7909 pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg;
7910 data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG));
7911
7912 moal_memcpy_ext(priv->phandle, (t_u8 *)&qcfg_ioctl, data_ptr,
7913 sizeof(qcfg_ioctl), sizeof(qcfg_ioctl));
7914 pqcfg->action = qcfg_ioctl.action;
7915 pqcfg->access_category = qcfg_ioctl.access_category;
7916 pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry;
7917
7918 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7919 if (status != MLAN_STATUS_SUCCESS) {
7920 ret = -EFAULT;
7921 goto done;
7922 }
7923 memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl));
7924 qcfg_ioctl.action = pqcfg->action;
7925 qcfg_ioctl.access_category = pqcfg->access_category;
7926 qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry;
7927 moal_memcpy_ext(priv->phandle, data_ptr, (t_u8 *)&qcfg_ioctl,
7928 sizeof(qcfg_ioctl),
7929 respbuflen -
7930 (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG)));
7931 ret = strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG) + sizeof(qcfg_ioctl);
7932 done:
7933 if (status != MLAN_STATUS_PENDING)
7934 kfree(req);
7935 LEAVE();
7936 return ret;
7937 }
7938
7939 /**
7940 * @brief Private IOCTL entry to get the status of the WMM queues
7941 *
7942 * Return the following information for each WMM AC:
7943 * - WMM IE Acm Required
7944 * - Firmware Flow Required
7945 * - Firmware Flow Established
7946 * - Firmware Queue Enabled
7947 * - Firmware Delivery Enabled
7948 * - Firmware Trigger Enabled
7949 *
7950 * @param priv Pointer to the moal_private driver data struct
7951 * @param respbuf A pointer to response buffer
7952 * @param respbuflen Available length of response buffer
7953 *
7954 * @return Number of bytes written if successful else negative value
7955 */
woal_priv_wmm_queue_status_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)7956 static int woal_priv_wmm_queue_status_ioctl(moal_private *priv, t_u8 *respbuf,
7957 t_u32 respbuflen)
7958 {
7959 mlan_ioctl_req *req = NULL;
7960 mlan_ds_wmm_cfg *pwmm = NULL;
7961 wlan_ioctl_wmm_queue_status_t qstatus_ioctl;
7962 int ret = 0, header_len = 0;
7963 mlan_status status = MLAN_STATUS_SUCCESS;
7964
7965 ENTER();
7966
7967 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_QSTATUS);
7968 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
7969 if (req == NULL) {
7970 ret = -ENOMEM;
7971 goto done;
7972 }
7973
7974 req->req_id = MLAN_IOCTL_WMM_CFG;
7975 pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
7976 pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS;
7977
7978 if ((int)strlen(respbuf) == header_len) {
7979 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
7980 if (status != MLAN_STATUS_SUCCESS) {
7981 ret = -EFAULT;
7982 goto done;
7983 }
7984
7985 memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl));
7986 moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl,
7987 (void *)&pwmm->param.q_status,
7988 sizeof(qstatus_ioctl), sizeof(qstatus_ioctl));
7989 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&qstatus_ioctl,
7990 sizeof(qstatus_ioctl), respbuflen);
7991 ret = sizeof(qstatus_ioctl);
7992 }
7993
7994 done:
7995 if (status != MLAN_STATUS_PENDING)
7996 kfree(req);
7997 LEAVE();
7998 return ret;
7999 }
8000
8001 /**
8002 * @brief Private IOCTL entry to get the status of the WMM Traffic Streams
8003 *
8004 * @param priv Pointer to the moal_private driver data struct
8005 * @param respbuf A pointer to response buffer
8006 * @param respbuflen Available length of response buffer
8007 *
8008 * @return Number of bytes written if successful else negative value
8009 */
woal_priv_wmm_ts_status_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8010 static int woal_priv_wmm_ts_status_ioctl(moal_private *priv, t_u8 *respbuf,
8011 t_u32 respbuflen)
8012 {
8013 mlan_ioctl_req *req = NULL;
8014 mlan_ds_wmm_cfg *pwmm = NULL;
8015 wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
8016 int ret = 0, header_len = 0;
8017 t_u8 *data_ptr;
8018 mlan_status status = MLAN_STATUS_SUCCESS;
8019
8020 ENTER();
8021
8022 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TS_STATUS);
8023 data_ptr = respbuf + header_len;
8024 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
8025 if (req == NULL) {
8026 ret = -ENOMEM;
8027 goto done;
8028 }
8029
8030 req->req_id = MLAN_IOCTL_WMM_CFG;
8031 pwmm = (mlan_ds_wmm_cfg *)req->pbuf;
8032 pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS;
8033
8034 memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
8035
8036 moal_memcpy_ext(priv->phandle, (t_u8 *)&ts_status_ioctl, data_ptr,
8037 sizeof(ts_status_ioctl), sizeof(ts_status_ioctl));
8038
8039 memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl));
8040 pwmm->param.ts_status.tid = ts_status_ioctl.tid;
8041
8042 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8043 if (status != MLAN_STATUS_SUCCESS) {
8044 ret = -EFAULT;
8045 goto done;
8046 }
8047
8048 memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl));
8049 moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl,
8050 (void *)&pwmm->param.ts_status, sizeof(ts_status_ioctl),
8051 sizeof(ts_status_ioctl));
8052 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&ts_status_ioctl,
8053 sizeof(ts_status_ioctl), respbuflen);
8054 ret = sizeof(ts_status_ioctl);
8055
8056 done:
8057 if (status != MLAN_STATUS_PENDING)
8058 kfree(req);
8059 LEAVE();
8060 return ret;
8061 }
8062
8063 /**
8064 * @brief Set/Get MAC control
8065 *
8066 * @param priv A pointer to moal_private structure
8067 * @param respbuf A pointer to response buffer
8068 * @param respbuflen Available length of response buffer
8069 *
8070 * @return Number of bytes written, negative for failure.
8071 */
woal_priv_macctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8072 static int woal_priv_macctrl(moal_private *priv, t_u8 *respbuf,
8073 t_u32 respbuflen)
8074 {
8075 int data = 0;
8076 mlan_ioctl_req *req = NULL;
8077 mlan_ds_misc_cfg *cfg = NULL;
8078 int ret = 0;
8079 int user_data_len = 0, header_len = 0;
8080 mlan_status status = MLAN_STATUS_SUCCESS;
8081
8082 ENTER();
8083
8084 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MAC_CTRL);
8085 if ((int)strlen(respbuf) == header_len) {
8086 /* GET operation */
8087 user_data_len = 0;
8088 } else {
8089 /* SET operation */
8090 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8091 }
8092
8093 if (user_data_len > 1) {
8094 PRINTM(MERROR, "Invalid number of arguments\n");
8095 ret = -EINVAL;
8096 goto done;
8097 }
8098 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8099 if (req == NULL) {
8100 ret = -ENOMEM;
8101 goto done;
8102 }
8103
8104 cfg = (mlan_ds_misc_cfg *)req->pbuf;
8105 cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL;
8106 req->req_id = MLAN_IOCTL_MISC_CFG;
8107
8108 if (user_data_len == 0)
8109 req->action = MLAN_ACT_GET;
8110 else {
8111 cfg->param.mac_ctrl = (t_u32)data;
8112 req->action = MLAN_ACT_SET;
8113 }
8114
8115 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8116 if (status != MLAN_STATUS_SUCCESS) {
8117 ret = -EFAULT;
8118 goto done;
8119 }
8120
8121 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.mac_ctrl,
8122 sizeof(data), respbuflen);
8123 ret = sizeof(data);
8124
8125 done:
8126 if (status != MLAN_STATUS_PENDING)
8127 kfree(req);
8128 LEAVE();
8129 return ret;
8130 }
8131
8132 /**
8133 * @brief Get connection status
8134 *
8135 * @param priv A pointer to moal_private structure
8136 * @param respbuf A pointer to response buffer
8137 * @param respbuflen Available length of response buffer
8138 *
8139 * @return 0 --success, otherwise fail
8140 */
woal_priv_getwap(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8141 static int woal_priv_getwap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
8142 {
8143 int ret = 0;
8144 #ifdef STA_SUPPORT
8145 mlan_bss_info bss_info;
8146 #endif
8147
8148 ENTER();
8149
8150 #ifdef STA_SUPPORT
8151 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
8152 memset(&bss_info, 0, sizeof(bss_info));
8153
8154 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8155
8156 if (bss_info.media_connected == MTRUE) {
8157 moal_memcpy_ext(priv->phandle, respbuf,
8158 (t_u8 *)&bss_info.bssid,
8159 MLAN_MAC_ADDR_LENGTH, respbuflen);
8160 } else {
8161 memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
8162 }
8163 }
8164 #endif
8165 #ifdef UAP_SUPPORT
8166 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
8167 if (priv->bss_started) {
8168 moal_memcpy_ext(priv->phandle, respbuf,
8169 priv->current_addr,
8170 MLAN_MAC_ADDR_LENGTH, respbuflen);
8171 } else {
8172 memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH);
8173 }
8174 }
8175 #endif
8176 ret = MLAN_MAC_ADDR_LENGTH;
8177 LEAVE();
8178 return ret;
8179 }
8180
8181 /**
8182 * @brief Set/Get Region Code
8183 *
8184 * @param priv A pointer to moal_private structure
8185 * @param respbuf A pointer to response buffer
8186 * @param respbuflen Available length of response buffer
8187 *
8188 * @return Number of bytes written, negative for failure.
8189 */
woal_priv_region_code(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8190 static int woal_priv_region_code(moal_private *priv, t_u8 *respbuf,
8191 t_u32 respbuflen)
8192 {
8193 int data = 0;
8194 mlan_ioctl_req *req = NULL;
8195 mlan_ds_misc_cfg *cfg = NULL;
8196 int ret = 0;
8197 int user_data_len = 0, header_len = 0;
8198 mlan_status status = MLAN_STATUS_SUCCESS;
8199
8200 ENTER();
8201
8202 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGION_CODE);
8203 if ((int)strlen(respbuf) == header_len) {
8204 /* GET operation */
8205 user_data_len = 0;
8206 } else {
8207 /* SET operation */
8208 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8209 }
8210
8211 if (user_data_len > 1) {
8212 PRINTM(MERROR, "Invalid number of arguments\n");
8213 ret = -EINVAL;
8214 goto done;
8215 }
8216 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8217 if (req == NULL) {
8218 ret = -ENOMEM;
8219 goto done;
8220 }
8221
8222 cfg = (mlan_ds_misc_cfg *)req->pbuf;
8223 cfg->sub_command = MLAN_OID_MISC_REGION;
8224 req->req_id = MLAN_IOCTL_MISC_CFG;
8225
8226 if (user_data_len == 0)
8227 req->action = MLAN_ACT_GET;
8228 else {
8229 cfg->param.region_code = (t_u32)data;
8230 req->action = MLAN_ACT_SET;
8231 }
8232
8233 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8234 if (status != MLAN_STATUS_SUCCESS) {
8235 ret = -EFAULT;
8236 goto done;
8237 }
8238
8239 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.region_code,
8240 sizeof(data), respbuflen);
8241 ret = sizeof(data);
8242
8243 done:
8244 if (status != MLAN_STATUS_PENDING)
8245 kfree(req);
8246 LEAVE();
8247 return ret;
8248 }
8249
8250 #ifdef RX_PACKET_COALESCE
8251 /**
8252 * @brief Set/Get RX packet coalesceing setting
8253 *
8254 * @param priv A pointer to moal_private structure
8255 * @param respbuf A pointer to response buffer
8256 * @param respbuflen Available length of response buffer
8257 *
8258 * @return Number of bytes written, negative for failure.
8259 */
woal_priv_rx_pkt_coalesce_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8260 static int woal_priv_rx_pkt_coalesce_cfg(moal_private *priv, t_u8 *respbuf,
8261 t_u32 respbuflen)
8262 {
8263 int ret = 0;
8264 t_u32 data[2];
8265 int user_data_len = 0, header_len = 0;
8266 mlan_ds_misc_cfg *cfg = NULL;
8267 t_u8 *data_ptr;
8268 mlan_ioctl_req *req = NULL;
8269 mlan_status status = MLAN_STATUS_SUCCESS;
8270
8271 ENTER();
8272
8273 data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
8274 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG);
8275 if ((int)strlen(respbuf) == header_len) {
8276 /* GET operation */
8277 user_data_len = 0;
8278 } else {
8279 /* SET operation */
8280 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
8281 &user_data_len);
8282 }
8283
8284 if (sizeof(int) * user_data_len > sizeof(data)) {
8285 PRINTM(MERROR, "Too many arguments\n");
8286 ret = -EINVAL;
8287 goto done;
8288 }
8289
8290 if ((user_data_len != 0) && (user_data_len != 2)) {
8291 PRINTM(MERROR, "Invalid arguments\n");
8292 ret = -EINVAL;
8293 goto done;
8294 }
8295
8296 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8297 if (req == NULL) {
8298 ret = -ENOMEM;
8299 goto done;
8300 }
8301
8302 cfg = (mlan_ds_misc_cfg *)req->pbuf;
8303 cfg->sub_command = MLAN_OID_MISC_RX_PACKET_COALESCE;
8304 req->req_id = MLAN_IOCTL_MISC_CFG;
8305
8306 if (user_data_len == 0) {
8307 req->action = MLAN_ACT_GET;
8308 } else {
8309 req->action = MLAN_ACT_SET;
8310 cfg->param.rx_coalesce.packet_threshold = data[0];
8311 cfg->param.rx_coalesce.delay = data[1];
8312 }
8313
8314 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8315 if (status != MLAN_STATUS_SUCCESS) {
8316 ret = -EFAULT;
8317 goto done;
8318 }
8319
8320 moal_memcpy_ext(
8321 priv->phandle, respbuf,
8322 (mlan_ds_misc_rx_packet_coalesce *)&cfg->param.rx_coalesce,
8323 req->buf_len, respbuflen);
8324 ret = req->buf_len;
8325
8326 done:
8327 LEAVE();
8328 return ret;
8329 }
8330 #endif
8331 /**
8332 * @brief Set/Get FW side mac address
8333 *
8334 * @param priv A pointer to moal_private structure
8335 * @param respbuf A pointer to response buffer
8336 * @param respbuflen Available length of response buffer
8337 *
8338 * @return 0 --success, otherwise fail
8339 */
woal_priv_fwmacaddr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8340 static int woal_priv_fwmacaddr(moal_private *priv, t_u8 *respbuf,
8341 t_u32 respbuflen)
8342 {
8343 t_u8 data[ETH_ALEN];
8344 int ret = 0;
8345 int header_len = 0;
8346 mlan_ioctl_req *req = NULL;
8347 mlan_ds_bss *bss = NULL;
8348 mlan_status status = MLAN_STATUS_SUCCESS;
8349
8350 ENTER();
8351
8352 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FWMACADDR);
8353
8354 /* Allocate an IOCTL request buffer */
8355 req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
8356 if (req == NULL) {
8357 ret = -ENOMEM;
8358 goto done;
8359 }
8360 /* Fill request buffer */
8361 bss = (mlan_ds_bss *)req->pbuf;
8362 bss->sub_command = MLAN_OID_BSS_MAC_ADDR;
8363 req->req_id = MLAN_IOCTL_BSS;
8364
8365 if ((int)strlen(respbuf) == header_len) {
8366 /* GET operation */
8367 req->action = MLAN_ACT_GET;
8368 } else {
8369 /* SET operation */
8370 req->action = MLAN_ACT_SET;
8371 memset(data, 0, sizeof(data));
8372 woal_mac2u8(data, respbuf + header_len);
8373 moal_memcpy_ext(priv->phandle, bss->param.mac_addr, data,
8374 ETH_ALEN, sizeof(mlan_802_11_mac_addr));
8375 }
8376
8377 /* Send IOCTL request to MLAN */
8378 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8379 if (status != MLAN_STATUS_SUCCESS) {
8380 ret = -EFAULT;
8381 goto done;
8382 }
8383
8384 moal_memcpy_ext(priv->phandle, respbuf, bss->param.mac_addr,
8385 sizeof(data), respbuflen);
8386 ret = sizeof(data);
8387 HEXDUMP("FW MAC Addr:", respbuf, ETH_ALEN);
8388
8389 done:
8390 if (status != MLAN_STATUS_PENDING)
8391 kfree(req);
8392 LEAVE();
8393 return ret;
8394 }
8395
8396 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
8397 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
8398 /**
8399 * @brief Set offchannel
8400 *
8401 * @param priv A pointer to moal_private structure
8402 * @param respbuf A pointer to response buffer
8403 * @param respbuflen Available length of response buffer
8404 *
8405 * @return 0 --success, otherwise fail
8406 */
woal_priv_offchannel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8407 static int woal_priv_offchannel(moal_private *priv, t_u8 *respbuf,
8408 t_u32 respbuflen)
8409 {
8410 int data[4];
8411 int ret = 0;
8412 t_u8 status = 1;
8413 t_u8 chan_type = CHAN_NO_HT;
8414 int user_data_len = 0, header_len = 0;
8415
8416 ENTER();
8417
8418 memset(data, 0, sizeof(data));
8419
8420 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFFCHANNEL);
8421
8422 if (header_len == (int)strlen(respbuf)) {
8423 /* Query current remain on channel status */
8424 if (priv->phandle->remain_on_channel)
8425 ret = sprintf(respbuf,
8426 "There is pending remain on channel from bss %d\n",
8427 priv->phandle->remain_bss_index) +
8428 1;
8429 else
8430 ret = sprintf(respbuf,
8431 "There is no pending remain on channel\n") +
8432 1;
8433 goto done;
8434 } else
8435 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
8436 &user_data_len);
8437
8438 if (sizeof(int) * user_data_len > sizeof(data)) {
8439 PRINTM(MERROR, "Too many arguments\n");
8440 ret = -EINVAL;
8441 goto done;
8442 }
8443
8444 if (user_data_len >= 1) {
8445 if ((data[0] != 0) && (data[0] != 1)) {
8446 PRINTM(MERROR, "action (%d) must be either 0 or 1\n",
8447 data[0]);
8448 ret = -EINVAL;
8449 goto done;
8450 }
8451 }
8452 if (user_data_len == 2) {
8453 if (data[0] == 1) {
8454 PRINTM(MERROR,
8455 "channel and duration must both the mentioned\n");
8456 ret = -EINVAL;
8457 goto done;
8458 } else {
8459 PRINTM(MWARN,
8460 "extra arguments are ignored since action is 'cancel'\n");
8461 }
8462 }
8463 if (user_data_len >= 3) {
8464 if (data[0] == 1) {
8465 if (data[1] < 0) {
8466 PRINTM(MERROR, "channel cannot be negative\n");
8467 ret = -EINVAL;
8468 goto done;
8469 }
8470 if (data[2] < 0) {
8471 PRINTM(MERROR, "duration cannot be negative\n");
8472 ret = -EINVAL;
8473 goto done;
8474 }
8475 if (user_data_len == 4) {
8476 if (data[3] &&
8477 (data[3] != CHANNEL_BW_40MHZ_ABOVE) &&
8478 (data[3] != CHANNEL_BW_40MHZ_BELOW) &&
8479 (data[3] != CHANNEL_BW_80MHZ)) {
8480 PRINTM(MERROR, "invalid bandwidth");
8481 ret = -EINVAL;
8482 goto done;
8483 }
8484 switch (data[3]) {
8485 case CHANNEL_BW_40MHZ_ABOVE:
8486 chan_type = CHAN_HT40PLUS;
8487 break;
8488 case CHANNEL_BW_40MHZ_BELOW:
8489 chan_type = CHAN_HT40MINUS;
8490 break;
8491 case CHANNEL_BW_80MHZ:
8492 chan_type = CHAN_VHT80;
8493 break;
8494 default:
8495 break;
8496 }
8497 }
8498 }
8499 }
8500
8501 if (data[0] == 0) {
8502 if (!priv->phandle->remain_on_channel) {
8503 ret = sprintf(respbuf,
8504 "There is no pending remain on channel to be canceled\n") +
8505 1;
8506 goto done;
8507 }
8508 if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
8509 MTRUE, &status, NULL, 0,
8510 0)) {
8511 PRINTM(MERROR, "remain_on_channel: Failed to cancel\n");
8512 ret = -EFAULT;
8513 goto done;
8514 }
8515 if (status == MLAN_STATUS_SUCCESS)
8516 priv->phandle->remain_on_channel = MFALSE;
8517 } else if (data[0] == 1) {
8518 if (woal_cfg80211_remain_on_channel_cfg(
8519 priv, MOAL_IOCTL_WAIT, MFALSE, &status,
8520 ieee80211_get_channel(
8521 priv->wdev->wiphy,
8522 ieee80211_channel_to_frequency(
8523 data[1]
8524 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
8525 ,
8526 (data[1] <= 14 ?
8527 IEEE80211_BAND_2GHZ :
8528 IEEE80211_BAND_5GHZ)
8529 #endif
8530 )),
8531 chan_type, (t_u32)data[2])) {
8532 PRINTM(MERROR, "remain_on_channel: Failed to start\n");
8533 ret = -EFAULT;
8534 goto done;
8535 }
8536 if (status == MLAN_STATUS_SUCCESS) {
8537 priv->phandle->remain_on_channel = MTRUE;
8538 priv->phandle->remain_bss_index = priv->bss_index;
8539 }
8540 }
8541
8542 if (status != MLAN_STATUS_SUCCESS)
8543 ret = -EFAULT;
8544 else
8545 ret = sprintf(respbuf, "OK\n") + 1;
8546
8547 done:
8548 LEAVE();
8549 return ret;
8550 }
8551 #endif
8552 #endif
8553
8554 /**
8555 * @brief Set/Get dscp map
8556 *
8557 * @param priv A pointer to moal_private structure
8558 * @param respbuf A pointer to response buffer
8559 * @param respbuflen Available length of response buffer
8560 *
8561 * @return 0 --success, otherwise fail
8562 */
woal_priv_set_get_dscp_map(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8563 static int woal_priv_set_get_dscp_map(moal_private *priv, t_u8 *respbuf,
8564 t_u32 respbuflen)
8565 {
8566 int ret = MLAN_STATUS_SUCCESS;
8567 t_u8 *pos = NULL;
8568 int copy_size = 0, header_len = 0;
8569
8570 ENTER();
8571
8572 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DSCP_MAP);
8573 if ((int)strlen(respbuf) != header_len) {
8574 /* SET operation */
8575 pos = respbuf + header_len;
8576 moal_memcpy_ext(priv->phandle, priv->dscp_map, pos,
8577 sizeof(priv->dscp_map), sizeof(priv->dscp_map));
8578 }
8579
8580 copy_size = MIN(sizeof(priv->dscp_map), respbuflen);
8581 moal_memcpy_ext(priv->phandle, respbuf, priv->dscp_map, copy_size,
8582 respbuflen);
8583 ret = copy_size;
8584
8585 LEAVE();
8586 return ret;
8587 }
8588
8589 /**
8590 * @brief Get extended driver version
8591 *
8592 * @param priv A pointer to moal_private structure
8593 * @param respbuf A pointer to response buffer
8594 * @param respbuflen Available length of response buffer
8595 *
8596 * @return Number of bytes written, negative for failure.
8597 */
woal_priv_get_driver_verext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8598 static int woal_priv_get_driver_verext(moal_private *priv, t_u8 *respbuf,
8599 t_u32 respbuflen)
8600 {
8601 int data = 0;
8602 mlan_ds_get_info *info = NULL;
8603 mlan_ioctl_req *req = NULL;
8604 int ret = 0;
8605 int copy_size = 0;
8606 int user_data_len = 0, header_len = 0;
8607 mlan_status status = MLAN_STATUS_SUCCESS;
8608
8609 ENTER();
8610
8611 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
8612 if (req == NULL) {
8613 ret = -ENOMEM;
8614 goto done;
8615 }
8616
8617 info = (mlan_ds_get_info *)req->pbuf;
8618 info->sub_command = MLAN_OID_GET_VER_EXT;
8619 req->req_id = MLAN_IOCTL_GET_INFO;
8620 req->action = MLAN_ACT_GET;
8621
8622 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_VEREXT);
8623
8624 if ((int)strlen(respbuf) == header_len) {
8625 /* GET operation */
8626 user_data_len = 0;
8627 } else {
8628 /* SET operation */
8629 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8630 }
8631
8632 if (user_data_len > 1) {
8633 PRINTM(MERROR, "Too many arguments\n");
8634 ret = -EINVAL;
8635 goto done;
8636 }
8637 info->param.ver_ext.version_str_sel = data;
8638 if (((t_s32)(info->param.ver_ext.version_str_sel)) < 0) {
8639 PRINTM(MERROR, "Invalid arguments!\n");
8640 ret = -EINVAL;
8641 goto done;
8642 }
8643
8644 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8645 if (status != MLAN_STATUS_SUCCESS) {
8646 ret = -EFAULT;
8647 goto done;
8648 }
8649
8650 /*
8651 * Set the amount to copy back to the application as the minimum of the
8652 * available assoc resp data or the buffer provided by the application
8653 */
8654 copy_size = MIN(strlen(info->param.ver_ext.version_str), respbuflen);
8655 moal_memcpy_ext(priv->phandle, respbuf, info->param.ver_ext.version_str,
8656 copy_size, respbuflen);
8657 ret = copy_size;
8658 PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n",
8659 info->param.ver_ext.version_str);
8660
8661 done:
8662 if (status != MLAN_STATUS_PENDING)
8663 kfree(req);
8664 LEAVE();
8665 return ret;
8666 }
8667
8668 #ifdef USB
8669 #ifdef CONFIG_USB_SUSPEND
8670 /**
8671 * @brief This function makes USB device to suspend.
8672 *
8673 * @param priv A pointer to moal_private structure
8674 * @param respbuf A pointer to response buffer
8675 * @param respbuflen Available length of response buffer
8676 *
8677 * @return Number of bytes written, negative for failure.
8678 */
woal_priv_enter_usb_suspend(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8679 static int woal_priv_enter_usb_suspend(moal_private *priv, t_u8 *respbuf,
8680 t_u32 respbuflen)
8681 {
8682 int ret = 0;
8683
8684 ENTER();
8685 ret = woal_enter_usb_suspend(priv->phandle);
8686 moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
8687 ret = sizeof(int);
8688
8689 LEAVE();
8690 return ret;
8691 }
8692
8693 /**
8694 * @brief This function makes USB device to resume.
8695 *
8696 * @param priv A pointer to moal_private structure
8697 * @param respbuf A pointer to response buffer
8698 * @param respbuflen Available length of response buffer
8699 *
8700 * @return Number of bytes written, negative for failure.
8701 */
woal_priv_exit_usb_suspend(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8702 static int woal_priv_exit_usb_suspend(moal_private *priv, t_u8 *respbuf,
8703 t_u32 respbuflen)
8704 {
8705 int ret = 0;
8706
8707 ENTER();
8708 ret = woal_exit_usb_suspend(priv->phandle);
8709 moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen);
8710 ret = sizeof(int);
8711
8712 LEAVE();
8713 return ret;
8714 }
8715 #endif /* CONFIG_USB_SUSPEND */
8716 #endif
8717
8718 #if defined(STA_SUPPORT) && defined(STA_WEXT)
8719 /**
8720 * @brief SET/Get radio
8721 *
8722 * @param priv A pointer to moal_private structure
8723 * @param respbuf A pointer to response buffer
8724 * @param respbuflen Available length of response buffer
8725 *
8726 * @return Number of bytes written, negative for failure.
8727 */
woal_priv_radio_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8728 static int woal_priv_radio_ctrl(moal_private *priv, t_u8 *respbuf,
8729 t_u32 respbuflen)
8730 {
8731 int ret = 0, option = 0;
8732 int user_data_len = 0, header_len = 0;
8733 mlan_bss_info bss_info;
8734
8735 ENTER();
8736
8737 memset(&bss_info, 0, sizeof(bss_info));
8738
8739 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RADIO_CTRL);
8740
8741 if ((int)strlen(respbuf) == header_len) {
8742 /* GET operation */
8743 user_data_len = 0;
8744 } else {
8745 /* SET operation */
8746 parse_arguments(respbuf + header_len, &option, 1,
8747 &user_data_len);
8748 }
8749
8750 if (user_data_len > 1) {
8751 PRINTM(MERROR, "Too many arguments\n");
8752 ret = -EINVAL;
8753 goto done;
8754 }
8755 if (user_data_len == 1) {
8756 /* Set radio */
8757 if (option < 0 || option > 1) {
8758 PRINTM(MERROR, "Invalid arguments!\n");
8759 ret = -EINVAL;
8760 goto done;
8761 }
8762 if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option))
8763 ret = -EFAULT;
8764 goto done;
8765 } else {
8766 /* Get radio status */
8767 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8768 moal_memcpy_ext(priv->phandle, respbuf, &bss_info.radio_on,
8769 sizeof(bss_info.radio_on), respbuflen);
8770 ret = sizeof(bss_info.radio_on);
8771 }
8772 done:
8773 LEAVE();
8774 return ret;
8775 }
8776 #endif
8777
8778 /**
8779 * @brief Implement WMM enable command
8780 *
8781 * @param priv A pointer to moal_private structure
8782 * @param respbuf A pointer to response buffer
8783 * @param respbuflen Available length of response buffer
8784 *
8785 * @return Number of bytes written, negative for failure.
8786 */
woal_priv_wmm_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8787 static int woal_priv_wmm_cfg(moal_private *priv, t_u8 *respbuf,
8788 t_u32 respbuflen)
8789 {
8790 int data = 0;
8791 mlan_ds_wmm_cfg *wmm = NULL;
8792 mlan_ioctl_req *req = NULL;
8793 int ret = 0;
8794 int user_data_len = 0, header_len = 0;
8795 mlan_status status = MLAN_STATUS_SUCCESS;
8796
8797 ENTER();
8798
8799 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg));
8800 if (req == NULL) {
8801 ret = -ENOMEM;
8802 goto done;
8803 }
8804
8805 wmm = (mlan_ds_wmm_cfg *)req->pbuf;
8806 wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE;
8807 req->req_id = MLAN_IOCTL_WMM_CFG;
8808
8809 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WMM_CFG);
8810
8811 if ((int)strlen(respbuf) == header_len) {
8812 /* GET operation */
8813 req->action = MLAN_ACT_GET;
8814 user_data_len = 0;
8815 } else {
8816 /* SET operation */
8817 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8818 if (user_data_len == 1) {
8819 /* Set wmm */
8820 if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
8821 PRINTM(MERROR, "Invalid arguments!\n");
8822 ret = -EINVAL;
8823 goto done;
8824 }
8825 req->action = MLAN_ACT_SET;
8826 if (data == CMD_DISABLED)
8827 wmm->param.wmm_enable = MFALSE;
8828 else
8829 wmm->param.wmm_enable = MTRUE;
8830 } else {
8831 PRINTM(MERROR, "Too many arguments\n");
8832 ret = -EINVAL;
8833 goto done;
8834 }
8835 }
8836 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8837 if (status != MLAN_STATUS_SUCCESS) {
8838 ret = -EFAULT;
8839 goto done;
8840 }
8841
8842 moal_memcpy_ext(priv->phandle, respbuf, &wmm->param.wmm_enable,
8843 sizeof(wmm->param.wmm_enable), respbuflen);
8844 ret = sizeof(wmm->param.wmm_enable);
8845
8846 done:
8847 if (status != MLAN_STATUS_PENDING)
8848 kfree(req);
8849 LEAVE();
8850 return ret;
8851 }
8852
8853 /**
8854 * @brief Implement Mininum BA Threshold cfg command
8855 *
8856 * @param priv A pointer to moal_private structure
8857 * @param respbuf A pointer to response buffer
8858 * @param respbuflen Available length of response buffer
8859 *
8860 * @return Number of bytes written, negative for failure.
8861 */
woal_priv_min_ba_threshold_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8862 static int woal_priv_min_ba_threshold_cfg(moal_private *priv, t_u8 *respbuf,
8863 t_u32 respbuflen)
8864 {
8865 int data = 0;
8866 mlan_ds_11n_cfg *cfg_11n = NULL;
8867 mlan_ioctl_req *req = NULL;
8868 int ret = 0;
8869 int user_data_len = 0, header_len = 0;
8870 mlan_status status = MLAN_STATUS_SUCCESS;
8871
8872 ENTER();
8873
8874 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
8875 if (req == NULL) {
8876 ret = -ENOMEM;
8877 goto done;
8878 }
8879 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
8880 cfg_11n->sub_command = MLAN_OID_11N_CFG_MIN_BA_THRESHOLD;
8881 req->req_id = MLAN_IOCTL_11N_CFG;
8882
8883 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIN_BA_THRESH_CFG);
8884
8885 if ((int)strlen(respbuf) == header_len) {
8886 /* GET operation */
8887 req->action = MLAN_ACT_GET;
8888 user_data_len = 0;
8889 } else {
8890 /* SET operation */
8891 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8892 if (user_data_len == 1) {
8893 /* Set minimum BA Threshold */
8894 if ((data < 0) || (data > 16)) {
8895 PRINTM(MERROR,
8896 "Error: Valid minimum BA threshold range (0-16)!\n");
8897 ret = -EINVAL;
8898 goto done;
8899 }
8900 req->action = MLAN_ACT_SET;
8901 cfg_11n->param.min_ba_threshold = data;
8902 } else {
8903 PRINTM(MERROR, "Too many arguments\n");
8904 ret = -EINVAL;
8905 goto done;
8906 }
8907 }
8908 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8909 if (status != MLAN_STATUS_SUCCESS) {
8910 ret = -EFAULT;
8911 goto done;
8912 }
8913
8914 moal_memcpy_ext(priv->phandle, respbuf,
8915 &cfg_11n->param.min_ba_threshold,
8916 sizeof(cfg_11n->param.min_ba_threshold), respbuflen);
8917 ret = sizeof(cfg_11n->param.min_ba_threshold);
8918
8919 done:
8920 if (status != MLAN_STATUS_PENDING)
8921 kfree(req);
8922 LEAVE();
8923 return ret;
8924 }
8925
8926 #if defined(STA_SUPPORT)
8927 /**
8928 * @brief Implement 802.11D enable command
8929 *
8930 * @param priv A pointer to moal_private structure
8931 * @param respbuf A pointer to response buffer
8932 * @param respbuflen Available length of response buffer
8933 *
8934 * @return Number of bytes written, negative for failure.
8935 */
woal_priv_11d_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)8936 static int woal_priv_11d_cfg(moal_private *priv, t_u8 *respbuf,
8937 t_u32 respbuflen)
8938 {
8939 int data = 0;
8940 mlan_ds_11d_cfg *pcfg_11d = NULL;
8941 mlan_ioctl_req *req = NULL;
8942 int ret = 0;
8943 int user_data_len = 0, header_len = 0;
8944 mlan_status status = MLAN_STATUS_SUCCESS;
8945
8946 ENTER();
8947
8948 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
8949 if (req == NULL) {
8950 ret = -ENOMEM;
8951 goto done;
8952 }
8953
8954 pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
8955 pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE;
8956 req->req_id = MLAN_IOCTL_11D_CFG;
8957
8958 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CFG);
8959
8960 if ((int)strlen(respbuf) == header_len) {
8961 /* GET operation */
8962 req->action = MLAN_ACT_GET;
8963 user_data_len = 0;
8964 } else {
8965 /* SET operation */
8966 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
8967 if (user_data_len == 1) {
8968 if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
8969 PRINTM(MERROR, "Invalid arguments!\n");
8970 ret = -EINVAL;
8971 goto done;
8972 }
8973 req->action = MLAN_ACT_SET;
8974 if (data == CMD_DISABLED)
8975 pcfg_11d->param.enable_11d = MFALSE;
8976 else
8977 pcfg_11d->param.enable_11d = MTRUE;
8978 } else {
8979 PRINTM(MERROR, "Too many arguments\n");
8980 ret = -EINVAL;
8981 goto done;
8982 }
8983 }
8984 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
8985 if (status != MLAN_STATUS_SUCCESS) {
8986 ret = -EFAULT;
8987 goto done;
8988 }
8989
8990 moal_memcpy_ext(priv->phandle, respbuf, &pcfg_11d->param.enable_11d,
8991 sizeof(pcfg_11d->param.enable_11d), respbuflen);
8992 ret = sizeof(pcfg_11d->param.enable_11d);
8993
8994 done:
8995 if (status != MLAN_STATUS_PENDING)
8996 kfree(req);
8997 LEAVE();
8998 return ret;
8999 }
9000
9001 /**
9002 * @brief Implement 802.11D clear chan table command
9003 *
9004 * @param priv A pointer to moal_private structure
9005 * @param respbuf A pointer to response buffer
9006 * @param respbuflen Available length of response buffer
9007 *
9008 * @return 0 --success, otherwise fail
9009 */
woal_priv_11d_clr_chan_tbl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9010 static int woal_priv_11d_clr_chan_tbl(moal_private *priv, t_u8 *respbuf,
9011 t_u32 respbuflen)
9012 {
9013 mlan_ds_11d_cfg *pcfg_11d = NULL;
9014 mlan_ioctl_req *req = NULL;
9015 int ret = 0;
9016 int header_len = 0;
9017 mlan_status status = MLAN_STATUS_SUCCESS;
9018
9019 ENTER();
9020
9021 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
9022 if (req == NULL) {
9023 ret = -ENOMEM;
9024 goto done;
9025 }
9026
9027 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CLR_TBL);
9028
9029 if ((int)strlen(respbuf) != header_len) {
9030 PRINTM(MERROR, "Too many arguments\n");
9031 ret = -EINVAL;
9032 goto done;
9033 }
9034 pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
9035 pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE;
9036 req->req_id = MLAN_IOCTL_11D_CFG;
9037 req->action = MLAN_ACT_SET;
9038
9039 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9040 if (status != MLAN_STATUS_SUCCESS) {
9041 ret = -EFAULT;
9042 goto done;
9043 }
9044
9045 done:
9046 if (status != MLAN_STATUS_PENDING)
9047 kfree(req);
9048 LEAVE();
9049 return ret;
9050 }
9051 #endif
9052
9053 #ifndef OPCHAN
9054 /**
9055 * @brief Set/Get WWS mode
9056 *
9057 * @param priv A pointer to moal_private structure
9058 * @param respbuf A pointer to response buffer
9059 * @param respbuflen Available length of response buffer
9060 *
9061 * @return Number of bytes written, negative for failure.
9062 */
woal_priv_wws_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9063 static int woal_priv_wws_cfg(moal_private *priv, t_u8 *respbuf,
9064 t_u32 respbuflen)
9065 {
9066 int data = 0;
9067 mlan_ds_misc_cfg *wws = NULL;
9068 mlan_ioctl_req *req = NULL;
9069 int ret = 0;
9070 int user_data_len = 0, header_len = 0;
9071 mlan_status status = MLAN_STATUS_SUCCESS;
9072
9073 ENTER();
9074
9075 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
9076 if (req == NULL) {
9077 ret = -ENOMEM;
9078 goto done;
9079 }
9080
9081 wws = (mlan_ds_misc_cfg *)req->pbuf;
9082 wws->sub_command = MLAN_OID_MISC_WWS;
9083 req->req_id = MLAN_IOCTL_MISC_CFG;
9084
9085 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WWS_CFG);
9086
9087 if ((int)strlen(respbuf) == header_len) {
9088 /* GET operation */
9089 req->action = MLAN_ACT_GET;
9090 user_data_len = 0;
9091 } else {
9092 /* SET operation */
9093 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9094 if (user_data_len == 1) {
9095 if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) {
9096 PRINTM(MERROR,
9097 "Invalid arguments, WWS config not changed!\n");
9098 ret = -EINVAL;
9099 goto done;
9100 }
9101 req->action = MLAN_ACT_SET;
9102 wws->param.wws_cfg = (t_u16)data;
9103 } else {
9104 PRINTM(MERROR, "Too many arguments\n");
9105 ret = -EINVAL;
9106 goto done;
9107 }
9108 }
9109 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9110 if (status != MLAN_STATUS_SUCCESS) {
9111 ret = -EFAULT;
9112 goto done;
9113 }
9114
9115 moal_memcpy_ext(priv->phandle, respbuf, &wws->param.wws_cfg,
9116 sizeof(wws->param.wws_cfg), respbuflen);
9117 ret = sizeof(wws->param.wws_cfg);
9118
9119 done:
9120 if (status != MLAN_STATUS_PENDING)
9121 kfree(req);
9122 LEAVE();
9123 return ret;
9124 }
9125 #endif
9126
9127 #if defined(REASSOCIATION)
9128 /**
9129 * @brief Set/Get reassociation settings
9130 *
9131 * @param priv A pointer to moal_private structure
9132 * @param respbuf A pointer to response buffer
9133 * @param respbuflen Available length of response buffer
9134 *
9135 * @return Number of bytes written, negative for failure.
9136 */
woal_priv_set_get_reassoc(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9137 static int woal_priv_set_get_reassoc(moal_private *priv, t_u8 *respbuf,
9138 t_u32 respbuflen)
9139 {
9140 moal_handle *handle = priv->phandle;
9141 int data = 0;
9142 int ret = 0;
9143 int user_data_len = 0, header_len = 0;
9144
9145 ENTER();
9146
9147 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REASSOCTRL);
9148
9149 if ((int)strlen(respbuf) == header_len) {
9150 /* GET operation */
9151 user_data_len = 0;
9152 data = (int)(priv->reassoc_on);
9153 moal_memcpy_ext(handle, respbuf, &data, sizeof(data),
9154 respbuflen);
9155 ret = sizeof(data);
9156 } else {
9157 /* SET operation */
9158 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9159 if (user_data_len == 1) {
9160 if (data == 0) {
9161 handle->reassoc_on &= ~MBIT(priv->bss_index);
9162 priv->reassoc_on = MFALSE;
9163 priv->reassoc_required = MFALSE;
9164 if (!handle->reassoc_on &&
9165 handle->is_reassoc_timer_set == MTRUE) {
9166 woal_cancel_timer(
9167 &handle->reassoc_timer);
9168 handle->is_reassoc_timer_set = MFALSE;
9169 }
9170 } else if (data == 1) {
9171 handle->reassoc_on |= MBIT(priv->bss_index);
9172 priv->reassoc_on = MTRUE;
9173 } else {
9174 PRINTM(MERROR, "Invalid arguments!\n");
9175 ret = -EINVAL;
9176 }
9177 } else {
9178 PRINTM(MERROR, "Too many arguments\n");
9179 ret = -EINVAL;
9180 }
9181 }
9182
9183 LEAVE();
9184 return ret;
9185 }
9186 #endif /* REASSOCIATION */
9187
9188 /**
9189 * @brief Get Transmit buffer size
9190 *
9191 * @param priv A pointer to moal_private structure
9192 * @param respbuf A pointer to response buffer
9193 * @param respbuflen Available length of response buffer
9194 *
9195 * @return Number of bytes written, negative for failure.
9196 */
woal_priv_txbuf_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9197 static int woal_priv_txbuf_cfg(moal_private *priv, t_u8 *respbuf,
9198 t_u32 respbuflen)
9199 {
9200 mlan_ds_11n_cfg *cfg_11n = NULL;
9201 mlan_ioctl_req *req = NULL;
9202 int ret = 0;
9203 int buf_size = 0, header_len = 0;
9204 mlan_status status = MLAN_STATUS_SUCCESS;
9205
9206 ENTER();
9207
9208 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
9209 if (req == NULL) {
9210 ret = -ENOMEM;
9211 goto done;
9212 }
9213
9214 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
9215 cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE;
9216 req->req_id = MLAN_IOCTL_11N_CFG;
9217
9218 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXBUF_CFG);
9219
9220 if ((int)strlen(respbuf) != header_len) {
9221 PRINTM(MERROR,
9222 "Don't support set Tx buffer size after driver loaded!\n");
9223 ret = -EINVAL;
9224 goto done;
9225 } else {
9226 /* Get Tx buffer size from MLAN */
9227 req->action = MLAN_ACT_GET;
9228 }
9229 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9230 if (status != MLAN_STATUS_SUCCESS) {
9231 ret = -EFAULT;
9232 goto done;
9233 }
9234
9235 buf_size = cfg_11n->param.tx_buf_size;
9236 moal_memcpy_ext(priv->phandle, respbuf, &buf_size, sizeof(buf_size),
9237 respbuflen);
9238 ret = sizeof(buf_size);
9239
9240 done:
9241 if (status != MLAN_STATUS_PENDING)
9242 kfree(req);
9243 LEAVE();
9244 return ret;
9245 }
9246
9247 #ifdef STA_SUPPORT
9248 /**
9249 * @brief Set/Get auth type
9250 *
9251 * @param priv A pointer to moal_private structure
9252 * @param respbuf A pointer to response buffer
9253 * @param respbuflen Available length of response buffer
9254 *
9255 * @return Number of bytes written, negative for failure.
9256 */
woal_priv_auth_type(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9257 static int woal_priv_auth_type(moal_private *priv, t_u8 *respbuf,
9258 t_u32 respbuflen)
9259 {
9260 int auth_type = 0;
9261 t_u32 auth_mode;
9262 int ret = 0;
9263 int user_data_len = 0, header_len = 0;
9264
9265 ENTER();
9266
9267 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_TYPE);
9268
9269 if ((int)strlen(respbuf) == header_len) {
9270 /* GET operation */
9271 if (MLAN_STATUS_SUCCESS !=
9272 woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) {
9273 ret = -EFAULT;
9274 goto done;
9275 }
9276 user_data_len = 0;
9277 auth_type = auth_mode;
9278 moal_memcpy_ext(priv->phandle, respbuf, &auth_type,
9279 sizeof(auth_type), respbuflen);
9280 ret = sizeof(auth_type);
9281 goto done;
9282 } else {
9283 /* SET operation */
9284 parse_arguments(respbuf + header_len, &auth_type, 1,
9285 &user_data_len);
9286 if (user_data_len == 1) {
9287 PRINTM(MINFO, "SET: auth_type %d\n", auth_type);
9288 if (((auth_type < MLAN_AUTH_MODE_OPEN) ||
9289 (auth_type > MLAN_AUTH_MODE_SAE)) &&
9290 (auth_type != MLAN_AUTH_MODE_AUTO)) {
9291 ret = -EINVAL;
9292 goto done;
9293 }
9294 auth_mode = auth_type;
9295 if (MLAN_STATUS_SUCCESS !=
9296 woal_set_auth_mode(priv, MOAL_IOCTL_WAIT,
9297 auth_mode)) {
9298 ret = -EFAULT;
9299 goto done;
9300 }
9301 } else {
9302 PRINTM(MERROR, "Too many arguments\n");
9303 ret = -EINVAL;
9304 }
9305 }
9306
9307 done:
9308 LEAVE();
9309 return ret;
9310 }
9311 #endif
9312
9313 /**
9314 * @brief Set/get user provisioned local power constraint
9315 *
9316 * @param priv A pointer to moal_private structure
9317 * @param respbuf A pointer to response buffer
9318 * @param respbuflen Available length of response buffer
9319 *
9320 * @return Number of bytes written, negative for failure.
9321 */
woal_priv_11h_local_pwr_constraint(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9322 static int woal_priv_11h_local_pwr_constraint(moal_private *priv, t_u8 *respbuf,
9323 t_u32 respbuflen)
9324 {
9325 int data = 0;
9326 mlan_ds_11h_cfg *ds_11hcfg = NULL;
9327 mlan_ioctl_req *req = NULL;
9328 int ret = 0;
9329 int user_data_len = 0, header_len = 0;
9330 mlan_status status = MLAN_STATUS_SUCCESS;
9331
9332 ENTER();
9333
9334 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
9335 if (req == NULL) {
9336 ret = -ENOMEM;
9337 goto done;
9338 }
9339
9340 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
9341 ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT;
9342 req->req_id = MLAN_IOCTL_11H_CFG;
9343
9344 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_POWER_CONS);
9345
9346 if ((int)strlen(respbuf) == header_len) {
9347 /* GET operation */
9348 req->action = MLAN_ACT_GET;
9349 user_data_len = 0;
9350 } else {
9351 /* SET operation */
9352 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9353 if (user_data_len == 1) {
9354 req->action = MLAN_ACT_SET;
9355 ds_11hcfg->param.usr_local_power_constraint =
9356 (t_s8)data;
9357 } else {
9358 PRINTM(MERROR, "Too many arguments\n");
9359 ret = -EINVAL;
9360 goto done;
9361 }
9362 }
9363 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9364 if (status != MLAN_STATUS_SUCCESS) {
9365 ret = -EFAULT;
9366 goto done;
9367 }
9368
9369 if (req->action == MLAN_ACT_GET) {
9370 data = (int)ds_11hcfg->param.usr_local_power_constraint;
9371 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9372 respbuflen);
9373 ret = sizeof(data);
9374 }
9375
9376 done:
9377 if (status != MLAN_STATUS_PENDING)
9378 kfree(req);
9379 LEAVE();
9380 return ret;
9381 }
9382
9383 /**
9384 * @brief Set/get HT stream configurations
9385 *
9386 * @param priv A pointer to moal_private structure
9387 * @param respbuf A pointer to response buffer
9388 * @param respbuflen Available length of response buffer
9389 *
9390 * @return Number of bytes written, negative for failure.
9391 */
woal_priv_ht_stream_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9392 static int woal_priv_ht_stream_cfg(moal_private *priv, t_u8 *respbuf,
9393 t_u32 respbuflen)
9394 {
9395 int data = 0;
9396 mlan_ds_11n_cfg *cfg = NULL;
9397 mlan_ioctl_req *req = NULL;
9398 int ret = 0;
9399 int user_data_len = 0, header_len = 0;
9400 mlan_status status = MLAN_STATUS_SUCCESS;
9401
9402 ENTER();
9403
9404 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
9405 if (req == NULL) {
9406 ret = -ENOMEM;
9407 goto done;
9408 }
9409
9410 cfg = (mlan_ds_11n_cfg *)req->pbuf;
9411 cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG;
9412 req->req_id = MLAN_IOCTL_11N_CFG;
9413
9414 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HT_STREAM_CFG);
9415
9416 if ((int)strlen(respbuf) == header_len) {
9417 /* GET operation */
9418 req->action = MLAN_ACT_GET;
9419 user_data_len = 0;
9420 } else {
9421 /* SET operation */
9422 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9423 if (user_data_len == 1) {
9424 if (data != HT_STREAM_MODE_1X1 &&
9425 data != HT_STREAM_MODE_2X2) {
9426 PRINTM(MERROR, "Invalid arguments!\n");
9427 ret = -EINVAL;
9428 goto done;
9429 }
9430 req->action = MLAN_ACT_SET;
9431 cfg->param.stream_cfg = data;
9432 } else {
9433 PRINTM(MERROR, "Too many arguments\n");
9434 ret = -EINVAL;
9435 goto done;
9436 }
9437 }
9438 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9439 if (status != MLAN_STATUS_SUCCESS) {
9440 ret = -EFAULT;
9441 goto done;
9442 }
9443
9444 data = ((mlan_ds_11n_cfg *)req->pbuf)->param.stream_cfg;
9445 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9446 respbuflen);
9447 ret = sizeof(data);
9448
9449 done:
9450 if (status != MLAN_STATUS_PENDING)
9451 kfree(req);
9452 LEAVE();
9453 return ret;
9454 }
9455
9456 /**
9457 * @brief Set mimo switch configurations
9458 *
9459 * @param priv A pointer to moal_private structure
9460 * @param respbuf A pointer to response buffer
9461 * @param respbuflen Available length of response buffer
9462 *
9463 * @return Number of bytes written, negative for failure.
9464 */
woal_priv_mimo_switch(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9465 static int woal_priv_mimo_switch(moal_private *priv, t_u8 *respbuf,
9466 t_u32 respbuflen)
9467 {
9468 int data[2] = {0};
9469 mlan_ds_radio_cfg *radio = NULL;
9470 mlan_ioctl_req *req = NULL;
9471 int ret = 0;
9472 int user_data_len = 0, header_len = 0;
9473 mlan_status status = MLAN_STATUS_SUCCESS;
9474
9475 ENTER();
9476
9477 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
9478 if (req == NULL) {
9479 ret = -ENOMEM;
9480 goto done;
9481 }
9482
9483 radio = (mlan_ds_radio_cfg *)req->pbuf;
9484 radio->sub_command = MLAN_OID_MIMO_SWITCH;
9485 req->req_id = MLAN_IOCTL_RADIO_CFG;
9486
9487 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIMO_SWITCH);
9488
9489 if ((int)strlen(respbuf) > header_len) {
9490 /* SET operation */
9491 req->action = MLAN_ACT_SET;
9492 parse_arguments(respbuf + header_len, data, 2, &user_data_len);
9493 if (user_data_len == 2) {
9494 radio->param.mimo_switch_cfg.txpath_antmode = data[0];
9495 radio->param.mimo_switch_cfg.rxpath_antmode = data[1];
9496 } else {
9497 PRINTM(MERROR, "Invalid arguments!\n");
9498 ret = -EINVAL;
9499 goto done;
9500 }
9501 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9502 if (status != MLAN_STATUS_SUCCESS) {
9503 ret = -EFAULT;
9504 goto done;
9505 }
9506 } else {
9507 PRINTM(MERROR, "Invalid arguments!\n");
9508 ret = -EINVAL;
9509 goto done;
9510 }
9511
9512 done:
9513 if (status != MLAN_STATUS_PENDING)
9514 kfree(req);
9515 LEAVE();
9516 return ret;
9517 }
9518
9519 /**
9520 * @brief Get thermal reading
9521 *
9522 * @param priv A pointer to moal_private structure
9523 * @param respbuf A pointer to response buffer
9524 * @param respbuflen Available length of response buffer
9525 *
9526 * @return Number of bytes written, negative for failure.
9527 */
woal_priv_thermal(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9528 static int woal_priv_thermal(moal_private *priv, t_u8 *respbuf,
9529 t_u32 respbuflen)
9530 {
9531 mlan_ds_misc_cfg *cfg = NULL;
9532 mlan_ioctl_req *req = NULL;
9533 int ret = 0, header_len = 0, data = 0;
9534 mlan_status status = MLAN_STATUS_SUCCESS;
9535
9536 ENTER();
9537
9538 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
9539 if (req == NULL) {
9540 ret = -ENOMEM;
9541 goto done;
9542 }
9543
9544 cfg = (mlan_ds_misc_cfg *)req->pbuf;
9545 cfg->sub_command = MLAN_OID_MISC_THERMAL;
9546 req->req_id = MLAN_IOCTL_MISC_CFG;
9547
9548 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_THERMAL);
9549
9550 if ((int)strlen(respbuf) != header_len) {
9551 PRINTM(MERROR, "Set is not supported for this command\n");
9552 ret = -EINVAL;
9553 goto done;
9554 }
9555 req->action = MLAN_ACT_GET;
9556
9557 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9558 if (status != MLAN_STATUS_SUCCESS) {
9559 ret = -EFAULT;
9560 goto done;
9561 }
9562
9563 data = (int)cfg->param.thermal;
9564 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9565 respbuflen);
9566 ret = sizeof(data);
9567
9568 done:
9569 if (status != MLAN_STATUS_PENDING)
9570 kfree(req);
9571 LEAVE();
9572 return ret;
9573 }
9574
9575 /**
9576 * @brief Set/Get beacon interval
9577 *
9578 * @param priv A pointer to moal_private structure
9579 * @param respbuf A pointer to response buffer
9580 * @param respbuflen Available length of response buffer
9581 *
9582 * @return Number of bytes written, negative for failure.
9583 */
woal_priv_beacon_interval(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9584 static int woal_priv_beacon_interval(moal_private *priv, t_u8 *respbuf,
9585 t_u32 respbuflen)
9586 {
9587 int data = 0;
9588 mlan_ds_bss *bss = NULL;
9589 mlan_ioctl_req *req = NULL;
9590 int ret = 0;
9591 int user_data_len = 0, header_len = 0;
9592 mlan_status status = MLAN_STATUS_SUCCESS;
9593
9594 ENTER();
9595
9596 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
9597 if (req == NULL) {
9598 ret = -ENOMEM;
9599 goto done;
9600 }
9601
9602 bss = (mlan_ds_bss *)req->pbuf;
9603 bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
9604 req->req_id = MLAN_IOCTL_BSS;
9605
9606 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCN_INTERVAL);
9607
9608 if ((int)strlen(respbuf) == header_len) {
9609 /* GET operation */
9610 req->action = MLAN_ACT_GET;
9611 user_data_len = 0;
9612 } else {
9613 /* SET operation */
9614 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
9615 if (user_data_len == 1) {
9616 if ((data < MLAN_MIN_BEACON_INTERVAL) ||
9617 (data > MLAN_MAX_BEACON_INTERVAL)) {
9618 PRINTM(MERROR, "Invalid arguments!\n");
9619 ret = -EINVAL;
9620 goto done;
9621 }
9622 req->action = MLAN_ACT_SET;
9623 bss->param.bcn_interval = data;
9624 } else {
9625 PRINTM(MERROR, "Too many arguments\n");
9626 ret = -EINVAL;
9627 goto done;
9628 }
9629 }
9630 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9631 if (status != MLAN_STATUS_SUCCESS) {
9632 ret = -EFAULT;
9633 goto done;
9634 }
9635
9636 data = ((mlan_ds_bss *)req->pbuf)->param.bcn_interval;
9637 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
9638 respbuflen);
9639 ret = sizeof(data);
9640
9641 done:
9642 if (status != MLAN_STATUS_PENDING)
9643 kfree(req);
9644 LEAVE();
9645 return ret;
9646 }
9647
9648 #ifdef STA_SUPPORT
9649 /**
9650 * @brief Get signal
9651 *
9652 * @param priv A pointer to moal_private structure
9653 * @param respbuf A pointer to response buffer
9654 * @param respbuflen Available length of response buffer
9655 *
9656 * @return Number of bytes written, negative for failure.
9657 */
woal_priv_get_signal(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9658 static int woal_priv_get_signal(moal_private *priv, t_u8 *respbuf,
9659 t_u32 respbuflen)
9660 {
9661 /** Input data size */
9662 #define IN_DATA_SIZE 2
9663 /** Output data size */
9664 #define OUT_DATA_SIZE 12
9665 int ret = 0;
9666 int in_data[IN_DATA_SIZE];
9667 int out_data[OUT_DATA_SIZE];
9668 mlan_ds_get_signal signal;
9669 int data_length = 0;
9670 int user_data_len = 0, header_len = 0;
9671
9672 ENTER();
9673
9674 memset(in_data, 0, sizeof(in_data));
9675 memset(out_data, 0, sizeof(out_data));
9676
9677 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL);
9678
9679 if ((int)strlen(respbuf) != header_len)
9680 parse_arguments(respbuf + header_len, in_data, IN_DATA_SIZE,
9681 &user_data_len);
9682
9683 if (priv->media_connected == MFALSE) {
9684 PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
9685 ret = -ENOTSUPP;
9686 goto done;
9687 }
9688
9689 if (user_data_len) {
9690 if (user_data_len > IN_DATA_SIZE) {
9691 PRINTM(MERROR, "Too many arguments\n");
9692 ret = -EINVAL;
9693 goto done;
9694 }
9695 }
9696
9697 switch (user_data_len) {
9698 case 0: /* No checking, get everything */
9699 break;
9700 case 2: /* Check subtype range */
9701 if (in_data[1] < 1 || in_data[1] > 4) {
9702 ret = -EINVAL;
9703 goto done;
9704 }
9705 /* Fall through */
9706 case 1: /* Check type range */
9707 if (in_data[0] < 1 || in_data[0] > 3) {
9708 ret = -EINVAL;
9709 goto done;
9710 }
9711 break;
9712 default:
9713 ret = -EINVAL;
9714 goto done;
9715 }
9716
9717 memset(&signal, 0, sizeof(mlan_ds_get_signal));
9718 if (MLAN_STATUS_SUCCESS !=
9719 woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
9720 ret = -EFAULT;
9721 goto done;
9722 }
9723 PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int)signal.bcn_rssi_last);
9724 PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg);
9725 PRINTM(MINFO, "RSSI Data Last : %d\n", (int)signal.data_rssi_last);
9726 PRINTM(MINFO, "RSSI Data Average : %d\n", (int)signal.data_rssi_avg);
9727 PRINTM(MINFO, "SNR Beacon Last : %d\n", (int)signal.bcn_snr_last);
9728 PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg);
9729 PRINTM(MINFO, "SNR Data Last : %d\n", (int)signal.data_snr_last);
9730 PRINTM(MINFO, "SNR Data Average : %d\n", (int)signal.data_snr_avg);
9731 PRINTM(MINFO, "NF Beacon Last : %d\n", (int)signal.bcn_nf_last);
9732 PRINTM(MINFO, "NF Beacon Average : %d\n", (int)signal.bcn_nf_avg);
9733 PRINTM(MINFO, "NF Data Last : %d\n", (int)signal.data_nf_last);
9734 PRINTM(MINFO, "NF Data Average : %d\n", (int)signal.data_nf_avg);
9735
9736 /* Check type */
9737 switch (in_data[0]) {
9738 case 0: /* Send everything */
9739 out_data[data_length++] = signal.bcn_rssi_last;
9740 out_data[data_length++] = signal.bcn_rssi_avg;
9741 out_data[data_length++] = signal.data_rssi_last;
9742 out_data[data_length++] = signal.data_rssi_avg;
9743 out_data[data_length++] = signal.bcn_snr_last;
9744 out_data[data_length++] = signal.bcn_snr_avg;
9745 out_data[data_length++] = signal.data_snr_last;
9746 out_data[data_length++] = signal.data_snr_avg;
9747 out_data[data_length++] = signal.bcn_nf_last;
9748 out_data[data_length++] = signal.bcn_nf_avg;
9749 out_data[data_length++] = signal.data_nf_last;
9750 out_data[data_length++] = signal.data_nf_avg;
9751 break;
9752 case 1: /* RSSI */
9753 /* Check subtype */
9754 switch (in_data[1]) {
9755 case 0: /* Everything */
9756 out_data[data_length++] = signal.bcn_rssi_last;
9757 out_data[data_length++] = signal.bcn_rssi_avg;
9758 out_data[data_length++] = signal.data_rssi_last;
9759 out_data[data_length++] = signal.data_rssi_avg;
9760 break;
9761 case 1: /* bcn last */
9762 out_data[data_length++] = signal.bcn_rssi_last;
9763 break;
9764 case 2: /* bcn avg */
9765 out_data[data_length++] = signal.bcn_rssi_avg;
9766 break;
9767 case 3: /* data last */
9768 out_data[data_length++] = signal.data_rssi_last;
9769 break;
9770 case 4: /* data avg */
9771 out_data[data_length++] = signal.data_rssi_avg;
9772 break;
9773 default:
9774 break;
9775 }
9776 break;
9777 case 2: /* SNR */
9778 /* Check subtype */
9779 switch (in_data[1]) {
9780 case 0: /* Everything */
9781 out_data[data_length++] = signal.bcn_snr_last;
9782 out_data[data_length++] = signal.bcn_snr_avg;
9783 out_data[data_length++] = signal.data_snr_last;
9784 out_data[data_length++] = signal.data_snr_avg;
9785 break;
9786 case 1: /* bcn last */
9787 out_data[data_length++] = signal.bcn_snr_last;
9788 break;
9789 case 2: /* bcn avg */
9790 out_data[data_length++] = signal.bcn_snr_avg;
9791 break;
9792 case 3: /* data last */
9793 out_data[data_length++] = signal.data_snr_last;
9794 break;
9795 case 4: /* data avg */
9796 out_data[data_length++] = signal.data_snr_avg;
9797 break;
9798 default:
9799 break;
9800 }
9801 break;
9802 case 3: /* NF */
9803 /* Check subtype */
9804 switch (in_data[1]) {
9805 case 0: /* Everything */
9806 out_data[data_length++] = signal.bcn_nf_last;
9807 out_data[data_length++] = signal.bcn_nf_avg;
9808 out_data[data_length++] = signal.data_nf_last;
9809 out_data[data_length++] = signal.data_nf_avg;
9810 break;
9811 case 1: /* bcn last */
9812 out_data[data_length++] = signal.bcn_nf_last;
9813 break;
9814 case 2: /* bcn avg */
9815 out_data[data_length++] = signal.bcn_nf_avg;
9816 break;
9817 case 3: /* data last */
9818 out_data[data_length++] = signal.data_nf_last;
9819 break;
9820 case 4: /* data avg */
9821 out_data[data_length++] = signal.data_nf_avg;
9822 break;
9823 default:
9824 break;
9825 }
9826 break;
9827 default:
9828 break;
9829 }
9830
9831 moal_memcpy_ext(priv->phandle, respbuf, out_data,
9832 (data_length * sizeof(int)), respbuflen);
9833 ret = data_length * sizeof(int);
9834
9835 done:
9836 LEAVE();
9837 return ret;
9838 }
9839
woal_signal_ext_enable(moal_private * priv,t_u8 enable)9840 static int woal_signal_ext_enable(moal_private *priv, t_u8 enable)
9841 {
9842 int ret = 0;
9843 mlan_ioctl_req *req = NULL;
9844 mlan_ds_snmp_mib *snmp = NULL;
9845 mlan_status status = MLAN_STATUS_SUCCESS;
9846
9847 /* Allocate an IOCTL request buffer */
9848 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
9849 if (req == NULL) {
9850 ret = -ENOMEM;
9851 goto done;
9852 }
9853
9854 snmp = (mlan_ds_snmp_mib *)req->pbuf;
9855 snmp->sub_command = MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE;
9856 req->req_id = MLAN_IOCTL_SNMP_MIB;
9857 req->action = MLAN_ACT_SET;
9858 snmp->param.signalext_enable = enable;
9859
9860 /* Send IOCTL request to MLAN */
9861 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9862 if (status != MLAN_STATUS_SUCCESS) {
9863 ret = -EFAULT;
9864 goto done;
9865 }
9866
9867 done:
9868 if (status != MLAN_STATUS_PENDING)
9869 kfree(req);
9870 LEAVE();
9871 return ret;
9872 }
9873
9874 /**
9875 * @brief Get signal
9876 *
9877 * @param priv A pointer to moal_private structure
9878 * @param respbuf A pointer to response buffer
9879 * @param respbuflen Available length of response buffer
9880 *
9881 * @return Number of bytes written, negative for failure.
9882 */
woal_priv_get_signal_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)9883 static int woal_priv_get_signal_ext(moal_private *priv, t_u8 *respbuf,
9884 t_u32 respbuflen)
9885 {
9886 #define PATH_SIZE 13
9887 int ret = 0;
9888 int data = 0, path = 0, data_len = 0;
9889 int user_data_len = 0, header_len = 0;
9890 int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
9891 mlan_ioctl_req *req = NULL;
9892 mlan_ds_get_info *info = NULL;
9893 mlan_ds_get_signal signal_get[MAX_PATH_NUM];
9894 mlan_status status = MLAN_STATUS_SUCCESS;
9895 int path_num;
9896 t_u8 enable = 1;
9897
9898 ENTER();
9899
9900 if (priv->media_connected == MFALSE) {
9901 PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
9902 ret = -ENOTSUPP;
9903 goto done;
9904 }
9905
9906 /* Allocate an IOCTL request buffer */
9907 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
9908 if (req == NULL) {
9909 ret = -ENOMEM;
9910 goto done;
9911 }
9912
9913 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT);
9914
9915 if ((int)strlen(respbuf) != header_len) {
9916 parse_arguments(respbuf + header_len, &data,
9917 sizeof(data) / sizeof(int), &user_data_len);
9918 }
9919
9920 if (user_data_len > 1) {
9921 PRINTM(MERROR, "Too many arguments\n");
9922 ret = -EINVAL;
9923 goto done;
9924 }
9925 if (data < PATH_ALL || data > PATH_AB) {
9926 PRINTM(MERROR, "Wrong arguments\n");
9927 ret = -EINVAL;
9928 goto done;
9929 }
9930
9931 /** Enable signalext feature in firmware */
9932 if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
9933 ret = -EFAULT;
9934 goto done;
9935 }
9936 woal_sched_timeout(1000);
9937 enable = 0;
9938
9939 /* Fill request buffer */
9940 info = (mlan_ds_get_info *)req->pbuf;
9941 info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
9942 req->req_id = MLAN_IOCTL_GET_INFO;
9943 req->action = MLAN_ACT_GET;
9944 info->param.path_id = (t_u16)data;
9945
9946 /* Send IOCTL request to MLAN */
9947 if (MLAN_STATUS_SUCCESS !=
9948 woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
9949 woal_signal_ext_enable(priv, enable);
9950 ret = -EFAULT;
9951 goto done;
9952 }
9953 if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) {
9954 ret = -EFAULT;
9955 goto done;
9956 }
9957 path_num = 1;
9958 if (data == PATH_ALL) {
9959 moal_memcpy_ext(priv->phandle, signal_get,
9960 info->param.signal_ext, sizeof(signal_get),
9961 sizeof(signal_get));
9962 path_num = MAX_PATH_NUM;
9963 } else
9964 moal_memcpy_ext(priv->phandle, signal_get,
9965 info->param.signal_ext,
9966 sizeof(mlan_ds_get_signal), sizeof(signal_get));
9967
9968 for (path = 0; path < path_num; path++) {
9969 if (signal_get[path].selector == PATH_AB)
9970 PRINTM(MINFO, "PATH A+B:\n");
9971 else if (signal_get[path].selector == PATH_A)
9972 PRINTM(MINFO, "PATH A:\n");
9973 else if (signal_get[path].selector == PATH_B)
9974 PRINTM(MINFO, "PATH B:\n");
9975 PRINTM(MINFO, "RSSI Beacon Last : %d\n",
9976 (int)signal_get[path].bcn_rssi_last);
9977 PRINTM(MINFO, "RSSI Beacon Average: %d\n",
9978 (int)signal_get[path].bcn_rssi_avg);
9979 PRINTM(MINFO, "RSSI Data Last : %d\n",
9980 (int)signal_get[path].data_rssi_last);
9981 PRINTM(MINFO, "RSSI Data Average : %d\n",
9982 (int)signal_get[path].data_rssi_avg);
9983 PRINTM(MINFO, "SNR Beacon Last : %d\n",
9984 (int)signal_get[path].bcn_snr_last);
9985 PRINTM(MINFO, "SNR Beacon Average : %d\n",
9986 (int)signal_get[path].bcn_snr_avg);
9987 PRINTM(MINFO, "SNR Data Last : %d\n",
9988 (int)signal_get[path].data_snr_last);
9989 PRINTM(MINFO, "SNR Data Average : %d\n",
9990 (int)signal_get[path].data_snr_avg);
9991 PRINTM(MINFO, "NF Beacon Last : %d\n",
9992 (int)signal_get[path].bcn_nf_last);
9993 PRINTM(MINFO, "NF Beacon Average : %d\n",
9994 (int)signal_get[path].bcn_nf_avg);
9995 PRINTM(MINFO, "NF Data Last : %d\n",
9996 (int)signal_get[path].data_nf_last);
9997 PRINTM(MINFO, "NF Data Average : %d\n",
9998 (int)signal_get[path].data_nf_avg);
9999 out_data[data_len++] = (int)signal_get[path].selector;
10000 out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
10001 out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
10002 out_data[data_len++] = (int)signal_get[path].data_rssi_last;
10003 out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
10004 out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
10005 out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
10006 out_data[data_len++] = (int)signal_get[path].data_snr_last;
10007 out_data[data_len++] = (int)signal_get[path].data_snr_avg;
10008 out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
10009 out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
10010 out_data[data_len++] = (int)signal_get[path].data_nf_last;
10011 out_data[data_len++] = (int)signal_get[path].data_nf_avg;
10012 }
10013 moal_memcpy_ext(
10014 priv->phandle, respbuf, out_data,
10015 (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
10016 respbuflen);
10017 ret = data_len * sizeof(int);
10018 done:
10019 if (status != MLAN_STATUS_PENDING)
10020 kfree(req);
10021 LEAVE();
10022 return ret;
10023 }
10024
10025 /**
10026 * @brief Get signalext v2
10027 *
10028 * @param priv A pointer to moal_private structure
10029 * @param respbuf A pointer to response buffer
10030 * @param respbuflen Available length of response buffer
10031 *
10032 * @return Number of bytes written, negative for failure.
10033 */
woal_priv_get_signal_ext_v2(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10034 static int woal_priv_get_signal_ext_v2(moal_private *priv, t_u8 *respbuf,
10035 t_u32 respbuflen)
10036 {
10037 #define PATH_SIZE 13
10038 int ret = 0;
10039 int data = 0, path = 0, data_len = 0;
10040 int user_data_len = 0, header_len = 0;
10041 int out_data[PATH_SIZE * MAX_PATH_NUM] = {0};
10042 mlan_ioctl_req *req = NULL;
10043 mlan_ds_get_info *info = NULL;
10044 mlan_ds_get_signal signal_get[MAX_PATH_NUM];
10045 mlan_status status = MLAN_STATUS_SUCCESS;
10046 int path_num;
10047
10048 ENTER();
10049
10050 if (priv->media_connected == MFALSE) {
10051 PRINTM(MERROR, "Can not get RSSI in disconnected state\n");
10052 ret = -ENOTSUPP;
10053 goto done;
10054 }
10055
10056 /* Allocate an IOCTL request buffer */
10057 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
10058 if (req == NULL) {
10059 ret = -ENOMEM;
10060 goto done;
10061 }
10062
10063 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT_V2);
10064 if ((int)strlen(respbuf) != header_len) {
10065 parse_arguments(respbuf + header_len, &data,
10066 sizeof(data) / sizeof(int), &user_data_len);
10067 }
10068
10069 if (user_data_len > 1) {
10070 PRINTM(MERROR, "Too many arguments\n");
10071 ret = -EINVAL;
10072 goto done;
10073 }
10074 if (data < PATH_ALL || data > PATH_AB) {
10075 PRINTM(MERROR, "Wrong arguments\n");
10076 ret = -EINVAL;
10077 goto done;
10078 }
10079
10080 /* Fill request buffer */
10081 info = (mlan_ds_get_info *)req->pbuf;
10082 info->sub_command = MLAN_OID_GET_SIGNAL_EXT;
10083 req->req_id = MLAN_IOCTL_GET_INFO;
10084 req->action = MLAN_ACT_GET;
10085 info->param.path_id = (t_u16)data;
10086
10087 /* Send IOCTL request to MLAN */
10088 if (MLAN_STATUS_SUCCESS !=
10089 woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
10090 PRINTM(MERROR,
10091 "Enable signalextcfg: mlanutl mlanX signalextcfg 1"
10092 " before issuing this command\n");
10093 ret = -EFAULT;
10094 goto done;
10095 }
10096 path_num = 1;
10097
10098 if (data == PATH_ALL) {
10099 moal_memcpy_ext(priv->phandle, signal_get,
10100 info->param.signal_ext, sizeof(signal_get),
10101 sizeof(signal_get));
10102 path_num = MAX_PATH_NUM;
10103 } else
10104 moal_memcpy_ext(priv->phandle, signal_get,
10105 info->param.signal_ext,
10106 sizeof(mlan_ds_get_signal), sizeof(signal_get));
10107
10108 PRINTM(MMSG, "data=%d path_num=%d\n", data, path_num);
10109
10110 for (path = 0; path < path_num; path++) {
10111 if (signal_get[path].selector == PATH_AB)
10112 PRINTM(MINFO, "PATH A+B:\n");
10113 else if (signal_get[path].selector == PATH_A)
10114 PRINTM(MINFO, "PATH A:\n");
10115 else if (signal_get[path].selector == PATH_B)
10116 PRINTM(MINFO, "PATH B:\n");
10117 PRINTM(MINFO, "RSSI Beacon Last : %d\n",
10118 (int)signal_get[path].bcn_rssi_last);
10119 PRINTM(MINFO, "RSSI Beacon Average: %d\n",
10120 (int)signal_get[path].bcn_rssi_avg);
10121 PRINTM(MINFO, "RSSI Data Last : %d\n",
10122 (int)signal_get[path].data_rssi_last);
10123 PRINTM(MINFO, "RSSI Data Average : %d\n",
10124 (int)signal_get[path].data_rssi_avg);
10125 PRINTM(MINFO, "SNR Beacon Last : %d\n",
10126 (int)signal_get[path].bcn_snr_last);
10127 PRINTM(MINFO, "SNR Beacon Average : %d\n",
10128 (int)signal_get[path].bcn_snr_avg);
10129 PRINTM(MINFO, "SNR Data Last : %d\n",
10130 (int)signal_get[path].data_snr_last);
10131 PRINTM(MINFO, "SNR Data Average : %d\n",
10132 (int)signal_get[path].data_snr_avg);
10133 PRINTM(MINFO, "NF Beacon Last : %d\n",
10134 (int)signal_get[path].bcn_nf_last);
10135 PRINTM(MINFO, "NF Beacon Average : %d\n",
10136 (int)signal_get[path].bcn_nf_avg);
10137 PRINTM(MINFO, "NF Data Last : %d\n",
10138 (int)signal_get[path].data_nf_last);
10139 PRINTM(MINFO, "NF Data Average : %d\n",
10140 (int)signal_get[path].data_nf_avg);
10141 out_data[data_len++] = (int)signal_get[path].selector;
10142 out_data[data_len++] = (int)signal_get[path].bcn_rssi_last;
10143 out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg;
10144 out_data[data_len++] = (int)signal_get[path].data_rssi_last;
10145 out_data[data_len++] = (int)signal_get[path].data_rssi_avg;
10146 out_data[data_len++] = (int)signal_get[path].bcn_snr_last;
10147 out_data[data_len++] = (int)signal_get[path].bcn_snr_avg;
10148 out_data[data_len++] = (int)signal_get[path].data_snr_last;
10149 out_data[data_len++] = (int)signal_get[path].data_snr_avg;
10150 out_data[data_len++] = (int)signal_get[path].bcn_nf_last;
10151 out_data[data_len++] = (int)signal_get[path].bcn_nf_avg;
10152 out_data[data_len++] = (int)signal_get[path].data_nf_last;
10153 out_data[data_len++] = (int)signal_get[path].data_nf_avg;
10154 }
10155 moal_memcpy_ext(
10156 priv->phandle, respbuf, out_data,
10157 (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * sizeof(int)),
10158 respbuflen);
10159 ret = data_len * sizeof(int);
10160 done:
10161 if (status != MLAN_STATUS_PENDING)
10162 kfree(req);
10163 LEAVE();
10164 return ret;
10165 }
10166
10167 /**
10168 * @brief Set signalext cfg
10169 *
10170 * @param priv A pointer to moal_private structure
10171 * @param respbuf A pointer to response buffer
10172 * @param respbuflen Available length of response buffer
10173 *
10174 * @return The result of this processing.
10175 */
woal_priv_signalext_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10176 static int woal_priv_signalext_cfg(moal_private *priv, t_u8 *respbuf,
10177 t_u32 respbuflen)
10178 {
10179 int enable = 0;
10180 int ret = 0;
10181 int user_data_len = 0, header_len = 0;
10182 ENTER();
10183 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SIGNALEXT_CFG);
10184 if ((int)strlen(respbuf) == header_len) {
10185 PRINTM(MERROR, "Invalid arguments!\n");
10186 ret = -EINVAL;
10187 goto done;
10188 } else {
10189 /* SET operation */
10190 parse_arguments(respbuf + header_len, &enable, 1,
10191 &user_data_len);
10192 if (user_data_len == 1) {
10193 if (enable != 0x0 && enable != 0x1) {
10194 PRINTM(MERROR, "Invalid arguments!\n");
10195 ret = -EINVAL;
10196 goto done;
10197 }
10198 ret = woal_signal_ext_enable(priv, enable);
10199 } else {
10200 PRINTM(MERROR, "Too many arguments\n");
10201 ret = -EINVAL;
10202 goto done;
10203 }
10204 }
10205 done:
10206 LEAVE();
10207 return ret;
10208 }
10209 #endif /* #ifdef STA_SUPPORT */
10210
10211 #if defined(STA_SUPPORT)
10212 /**
10213 * @brief Make PMF bit required/optional
10214 * @param priv Pointer to moal_private structure
10215 * @param respbuf Pointer to response buffer
10216 * @param resplen Response buffer length
10217 *
10218 * @return 0 -- success, otherwise fail
10219 */
woal_priv_set_get_pmfcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10220 static int woal_priv_set_get_pmfcfg(moal_private *priv, t_u8 *respbuf,
10221 t_u32 respbuflen)
10222 {
10223 int data[2] = {0, 0};
10224 mlan_ioctl_req *req = NULL;
10225 mlan_ds_misc_cfg *cfg = NULL;
10226 mlan_ds_misc_pmfcfg *pmfcfg;
10227 int ret = 0;
10228 int user_data_len = 0, header_len = 0;
10229 mlan_status status = MLAN_STATUS_SUCCESS;
10230
10231 ENTER();
10232
10233 if (!priv->phandle->card_info->embedded_supp) {
10234 PRINTM(MERROR, "Not supported cmd on this card\n");
10235 ret = -EOPNOTSUPP;
10236 goto done;
10237 }
10238
10239 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PMFCFG);
10240 if ((int)strlen(respbuf) == header_len) {
10241 /* GET operation */
10242 user_data_len = 0;
10243 } else {
10244 /* SET operation */
10245 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10246 &user_data_len);
10247 }
10248
10249 if (user_data_len > 2) {
10250 PRINTM(MERROR, "Invalid number of arguments\n");
10251 ret = -EINVAL;
10252 goto done;
10253 }
10254 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10255 if (req == NULL) {
10256 ret = -ENOMEM;
10257 goto done;
10258 }
10259
10260 cfg = (mlan_ds_misc_cfg *)req->pbuf;
10261 pmfcfg = (mlan_ds_misc_pmfcfg *)&cfg->param.pmfcfg;
10262 cfg->sub_command = MLAN_OID_MISC_PMFCFG;
10263 req->req_id = MLAN_IOCTL_MISC_CFG;
10264
10265 if (user_data_len == 0)
10266 req->action = MLAN_ACT_GET;
10267 else {
10268 pmfcfg->mfpc = (t_u8)data[0];
10269 pmfcfg->mfpr = (t_u8)data[1];
10270 req->action = MLAN_ACT_SET;
10271 }
10272
10273 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10274 if (status != MLAN_STATUS_SUCCESS) {
10275 ret = -EFAULT;
10276 goto done;
10277 }
10278
10279 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.pmfcfg,
10280 sizeof(mlan_ds_misc_pmfcfg), respbuflen);
10281 ret = sizeof(mlan_ds_misc_pmfcfg);
10282
10283 done:
10284 if (status != MLAN_STATUS_PENDING)
10285 kfree(req);
10286 LEAVE();
10287 return ret;
10288 }
10289 #endif
10290
10291 /**
10292 * @brief Get/Set inactivity timeout extend
10293 * @param priv Pointer to moal_private structure
10294 * @param respbuf Pointer to response buffer
10295 * @param resplen Response buffer length
10296 *
10297 * @return Number of bytes written, negative for failure.
10298 */
woal_priv_inactivity_timeout_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10299 static int woal_priv_inactivity_timeout_ext(moal_private *priv, t_u8 *respbuf,
10300 t_u32 respbuflen)
10301 {
10302 int data[4];
10303 mlan_ioctl_req *req = NULL;
10304 mlan_ds_pm_cfg *pmcfg = NULL;
10305 pmlan_ds_inactivity_to inac_to = NULL;
10306 int ret = 0;
10307 int user_data_len = 0, header_len = 0;
10308 mlan_status status = MLAN_STATUS_SUCCESS;
10309
10310 ENTER();
10311
10312 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_INACTIVITYTO);
10313 memset(data, 0, sizeof(data));
10314 if ((int)strlen(respbuf) == header_len) {
10315 /* GET operation */
10316 user_data_len = 0;
10317 } else {
10318 /* SET operation */
10319 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10320 &user_data_len);
10321 }
10322
10323 if (user_data_len != 0 && user_data_len != 3 && user_data_len != 4) {
10324 PRINTM(MERROR, "Invalid number of parameters\n");
10325 ret = -EINVAL;
10326 goto done;
10327 }
10328 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
10329 if (req == NULL) {
10330 ret = -ENOMEM;
10331 goto done;
10332 }
10333
10334 pmcfg = (mlan_ds_pm_cfg *)req->pbuf;
10335 inac_to = &pmcfg->param.inactivity_to;
10336 pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO;
10337 req->req_id = MLAN_IOCTL_PM_CFG;
10338 req->action = MLAN_ACT_GET;
10339
10340 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10341 if (status != MLAN_STATUS_SUCCESS) {
10342 ret = -EFAULT;
10343 goto done;
10344 }
10345
10346 if (user_data_len) {
10347 inac_to->timeout_unit = data[0];
10348 inac_to->unicast_timeout = data[1];
10349 inac_to->mcast_timeout = data[2];
10350 if (user_data_len == 4)
10351 inac_to->ps_entry_timeout = data[3];
10352 req->action = MLAN_ACT_SET;
10353
10354 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10355 if (status != MLAN_STATUS_SUCCESS) {
10356 ret = -EFAULT;
10357 goto done;
10358 }
10359 } else {
10360 data[0] = inac_to->timeout_unit;
10361 data[1] = inac_to->unicast_timeout;
10362 data[2] = inac_to->mcast_timeout;
10363 data[3] = inac_to->ps_entry_timeout;
10364
10365 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
10366 sizeof(data), respbuflen);
10367 ret = sizeof(data);
10368 }
10369
10370 done:
10371 if (status != MLAN_STATUS_PENDING)
10372 kfree(req);
10373 LEAVE();
10374 return ret;
10375 }
10376
10377 /**
10378 * @brief Enable/Disable amsdu_aggr_ctrl
10379 *
10380 * @param priv Pointer to moal_private structure
10381 * @param respbuf Pointer to response buffer
10382 * @param resplen Response buffer length
10383 *
10384 * @return Number of bytes written, negative for failure.
10385 */
woal_priv_11n_amsdu_aggr_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10386 static int woal_priv_11n_amsdu_aggr_ctrl(moal_private *priv, t_u8 *respbuf,
10387 t_u32 respbuflen)
10388 {
10389 mlan_ioctl_req *req = NULL;
10390 mlan_ds_11n_cfg *cfg_11n = NULL;
10391 int ret = 0, data[2] = {0};
10392 int user_data_len = 0, header_len = 0;
10393 mlan_status status = MLAN_STATUS_SUCCESS;
10394
10395 ENTER();
10396
10397 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AMSDU_AGGR_CTRL);
10398 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
10399 if (req == NULL) {
10400 ret = -ENOMEM;
10401 goto done;
10402 }
10403
10404 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
10405 cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL;
10406 req->req_id = MLAN_IOCTL_11N_CFG;
10407
10408 if ((int)strlen(respbuf) == header_len) {
10409 /* GET operation */
10410 user_data_len = 0;
10411 req->action = MLAN_ACT_GET;
10412 } else {
10413 /* SET operation */
10414 parse_arguments(respbuf + header_len, data, 1, &user_data_len);
10415
10416 if (user_data_len != 1) {
10417 PRINTM(MERROR, "Invalid number of parameters\n");
10418 ret = -EINVAL;
10419 goto done;
10420 }
10421 req->action = MLAN_ACT_SET;
10422 cfg_11n->param.amsdu_aggr_ctrl.enable = data[0];
10423 }
10424
10425 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10426 if (status != MLAN_STATUS_SUCCESS) {
10427 ret = -EFAULT;
10428 goto done;
10429 }
10430
10431 data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable;
10432 data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size;
10433
10434 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
10435 respbuflen);
10436 ret = sizeof(data);
10437
10438 done:
10439 if (status != MLAN_STATUS_PENDING)
10440 kfree(req);
10441 LEAVE();
10442 return ret;
10443 }
10444
10445 /**
10446 * @brief Set/Get Transmit beamforming capabilities
10447 *
10448 * @param priv Pointer to moal_private structure
10449 * @param respbuf Pointer to response buffer
10450 * @param resplen Response buffer length
10451 *
10452 * @return Number of bytes written, negative for failure.
10453 */
woal_priv_tx_bf_cap_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10454 static int woal_priv_tx_bf_cap_ioctl(moal_private *priv, t_u8 *respbuf,
10455 t_u32 respbuflen)
10456 {
10457 mlan_ioctl_req *req = NULL;
10458 mlan_ds_11n_cfg *bf_cfg = NULL;
10459 int ret = 0, bf_cap = 0;
10460 int user_data_len = 0, header_len = 0;
10461 mlan_status status = MLAN_STATUS_SUCCESS;
10462
10463 ENTER();
10464
10465 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CAP);
10466 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
10467 if (req == NULL) {
10468 ret = -ENOMEM;
10469 goto done;
10470 }
10471
10472 bf_cfg = (mlan_ds_11n_cfg *)req->pbuf;
10473 bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP;
10474 req->req_id = MLAN_IOCTL_11N_CFG;
10475
10476 if ((int)strlen(respbuf) == header_len) {
10477 /* GET operation */
10478 user_data_len = 0;
10479 req->action = MLAN_ACT_GET;
10480 } else {
10481 /* SET operation */
10482 parse_arguments(respbuf + header_len, &bf_cap, 1,
10483 &user_data_len);
10484
10485 if (user_data_len != 1) {
10486 PRINTM(MERROR, "Invalid number of parameters\n");
10487 ret = -EINVAL;
10488 goto done;
10489 }
10490 req->action = MLAN_ACT_SET;
10491 bf_cfg->param.tx_bf_cap = bf_cap;
10492 }
10493
10494 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10495 if (status != MLAN_STATUS_SUCCESS) {
10496 ret = -EFAULT;
10497 goto done;
10498 }
10499
10500 bf_cap = bf_cfg->param.tx_bf_cap;
10501
10502 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&bf_cap, sizeof(bf_cap),
10503 respbuflen);
10504 ret = sizeof(bf_cap);
10505
10506 done:
10507 if (status != MLAN_STATUS_PENDING)
10508 kfree(req);
10509 LEAVE();
10510 return ret;
10511 }
10512
10513 #ifdef SDIO
10514 /**
10515 * @brief Turn on/off the sdio clock
10516 *
10517 * @param priv Pointer to moal_private structure
10518 * @param respbuf Pointer to response buffer
10519 * @param resplen Response buffer length
10520 *
10521 * @return Number of bytes written, negative for failure.
10522 */
woal_priv_sdio_clock_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10523 static int woal_priv_sdio_clock_ioctl(moal_private *priv, t_u8 *respbuf,
10524 t_u32 respbuflen)
10525 {
10526 int ret = 0;
10527 int data = 2;
10528 int user_data_len = 0, header_len = 0;
10529 /* Initialize the clock state as on */
10530 static int clock_state = 1;
10531
10532 ENTER();
10533
10534 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDIO_CLOCK);
10535 if ((int)strlen(respbuf) == header_len) {
10536 /* GET operation */
10537 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&clock_state,
10538 sizeof(clock_state), respbuflen);
10539 ret = sizeof(clock_state);
10540 goto done;
10541 } else {
10542 /* SET operation */
10543 parse_arguments(respbuf + header_len, &data, 1, &user_data_len);
10544
10545 if (user_data_len != 1) {
10546 PRINTM(MERROR, "Invalid number of parameters\n");
10547 ret = -EINVAL;
10548 goto done;
10549 }
10550 }
10551 switch (data) {
10552 case CMD_DISABLED:
10553 PRINTM(MINFO, "SDIO clock is turned off\n");
10554 ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE);
10555 clock_state = data;
10556 break;
10557 case CMD_ENABLED:
10558 PRINTM(MINFO, "SDIO clock is turned on\n");
10559 ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE);
10560 clock_state = data;
10561 break;
10562 default:
10563 ret = -EINVAL;
10564 PRINTM(MINFO, "sdioclock: wrong parameter\n");
10565 break;
10566 }
10567 done:
10568 LEAVE();
10569 return ret;
10570 }
10571 #endif
10572
10573 #ifdef SDIO
10574 /**
10575 * @brief Set SDIO Multi-point aggregation control parameters
10576 *
10577 * @param priv Pointer to moal_private structure
10578 * @param respbuf Pointer to response buffer
10579 * @param resplen Response buffer length
10580 *
10581 * @return Number of bytes written, negative for failure.
10582 */
woal_priv_sdio_mpa_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10583 static int woal_priv_sdio_mpa_ctrl(moal_private *priv, t_u8 *respbuf,
10584 t_u32 respbuflen)
10585 {
10586 mlan_ioctl_req *req = NULL;
10587 mlan_ds_misc_cfg *misc = NULL;
10588 int ret = 0, data[6];
10589 int user_data_len = 0, header_len = 0;
10590 mlan_status status = MLAN_STATUS_SUCCESS;
10591
10592 ENTER();
10593
10594 memset(data, 0, sizeof(data));
10595 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MPA_CTRL);
10596 if ((int)strlen(respbuf) == header_len) {
10597 /* GET operation */
10598 user_data_len = 0;
10599 } else {
10600 /* SET operation */
10601 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10602 &user_data_len);
10603
10604 if (user_data_len > 6) {
10605 PRINTM(MERROR, "Invalid number of parameters\n");
10606 ret = -EINVAL;
10607 goto done;
10608 }
10609 }
10610 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10611 if (req == NULL) {
10612 ret = -ENOMEM;
10613 goto done;
10614 }
10615
10616 misc = (mlan_ds_misc_cfg *)req->pbuf;
10617 misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL;
10618 req->req_id = MLAN_IOCTL_MISC_CFG;
10619 req->action = MLAN_ACT_GET;
10620 /* Get the values first, then modify these values if
10621 * user had modified them */
10622
10623 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10624 if (status != MLAN_STATUS_SUCCESS) {
10625 PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret);
10626 ret = -EFAULT;
10627 goto done;
10628 }
10629
10630 if (user_data_len == 0) {
10631 data[0] = misc->param.mpa_ctrl.tx_enable;
10632 data[1] = misc->param.mpa_ctrl.rx_enable;
10633 data[2] = misc->param.mpa_ctrl.tx_buf_size;
10634 data[3] = misc->param.mpa_ctrl.rx_buf_size;
10635 data[4] = misc->param.mpa_ctrl.tx_max_ports;
10636 data[5] = misc->param.mpa_ctrl.rx_max_ports;
10637
10638 PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0],
10639 data[1], data[2], data[3], data[4], data[5]);
10640
10641 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
10642 sizeof(data), respbuflen);
10643 ret = sizeof(data);
10644 goto done;
10645 }
10646
10647 switch (user_data_len) {
10648 case 6:
10649 misc->param.mpa_ctrl.rx_max_ports = data[5];
10650 /* fall through */
10651 case 5:
10652 misc->param.mpa_ctrl.tx_max_ports = data[4];
10653 /* fall through */
10654 case 4:
10655 misc->param.mpa_ctrl.rx_buf_size = data[3];
10656 /* fall through */
10657 case 3:
10658 misc->param.mpa_ctrl.tx_buf_size = data[2];
10659 /* fall through */
10660 case 2:
10661 misc->param.mpa_ctrl.rx_enable = data[1];
10662 /* fall through */
10663 case 1:
10664 /* Set cmd */
10665 req->action = MLAN_ACT_SET;
10666
10667 PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0],
10668 data[1], data[2], data[3], data[4], data[5]);
10669
10670 misc->param.mpa_ctrl.tx_enable = data[0];
10671 break;
10672 default:
10673 PRINTM(MERROR, "Default case error\n");
10674 ret = -EINVAL;
10675 goto done;
10676 }
10677
10678 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10679 if (status != MLAN_STATUS_SUCCESS) {
10680 ret = -EFAULT;
10681 goto done;
10682 }
10683
10684 done:
10685 if (status != MLAN_STATUS_PENDING)
10686 kfree(req);
10687 LEAVE();
10688 return ret;
10689 }
10690 #endif
10691
10692 /**
10693 * @brief Configure sleep parameters
10694 *
10695 * @param priv Pointer to moal_private structure
10696 * @param respbuf Pointer to response buffer
10697 * @param resplen Response buffer length
10698 *
10699 * @return Number of bytes written, negative for failure.
10700 */
woal_priv_sleep_params_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10701 static int woal_priv_sleep_params_ioctl(moal_private *priv, t_u8 *respbuf,
10702 t_u32 respbuflen)
10703 {
10704 int ret = 0;
10705 mlan_ioctl_req *req = NULL;
10706 mlan_ds_pm_cfg *pm = NULL;
10707 mlan_ds_sleep_params *psleep_params = NULL;
10708 int data[6] = {0}, i;
10709 int user_data_len = 0, header_len = 0;
10710 #ifdef DEBUG_LEVEL1
10711 char err_str[][36] = {{"sleep clock error in ppm"},
10712 {"wakeup offset in usec"},
10713 {"clock stabilization time in usec"},
10714 {"control periodic calibration(0-2)"},
10715 {"control of external sleepClock(0-2)"},
10716 {"value of reserved for debug"}};
10717 #endif
10718 mlan_status status = MLAN_STATUS_SUCCESS;
10719
10720 ENTER();
10721
10722 memset(data, 0, sizeof(data));
10723 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
10724 if (req == NULL) {
10725 ret = -ENOMEM;
10726 goto done;
10727 }
10728 pm = (mlan_ds_pm_cfg *)req->pbuf;
10729 pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS;
10730 req->req_id = MLAN_IOCTL_PM_CFG;
10731 psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params;
10732
10733 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEP_PARAMS);
10734 if ((int)strlen(respbuf) == header_len) {
10735 /* GET operation */
10736 user_data_len = 0;
10737 req->action = MLAN_ACT_GET;
10738 } else {
10739 /* SET operation */
10740 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10741 &user_data_len);
10742 if (user_data_len != 6) {
10743 PRINTM(MERROR, "Invalid number of parameters\n");
10744 ret = -EINVAL;
10745 goto done;
10746 }
10747 #define MIN_VAL 0x0000
10748 #define MAX_VAL 0xFFFF
10749 for (i = 0; i < 6; i++) {
10750 if ((i == 3) || (i == 4)) {
10751 /* These two cases are handled below the loop */
10752 continue;
10753 }
10754 if (data[i] < MIN_VAL || data[i] > MAX_VAL) {
10755 PRINTM(MERROR, "Invalid %s (0-65535)!\n",
10756 err_str[i]);
10757 ret = -EINVAL;
10758 goto done;
10759 }
10760 }
10761 if (data[3] < 0 || data[3] > 2) {
10762 PRINTM(MERROR,
10763 "Invalid control periodic calibration (0-2)!\n");
10764 ret = -EINVAL;
10765 goto done;
10766 }
10767 if (data[4] < 0 || data[4] > 2) {
10768 PRINTM(MERROR,
10769 "Invalid control of external sleep clock (0-2)!\n");
10770 ret = -EINVAL;
10771 goto done;
10772 }
10773 req->action = MLAN_ACT_SET;
10774 psleep_params->error = data[0];
10775 psleep_params->offset = data[1];
10776 psleep_params->stable_time = data[2];
10777 psleep_params->cal_control = data[3];
10778 psleep_params->ext_sleep_clk = data[4];
10779 psleep_params->reserved = data[5];
10780 }
10781
10782 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10783 if (status != MLAN_STATUS_SUCCESS) {
10784 ret = -EFAULT;
10785 goto done;
10786 }
10787
10788 data[0] = psleep_params->error;
10789 data[1] = psleep_params->offset;
10790 data[2] = psleep_params->stable_time;
10791 data[3] = psleep_params->cal_control;
10792 data[4] = psleep_params->ext_sleep_clk;
10793 data[5] = psleep_params->reserved;
10794
10795 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
10796 respbuflen);
10797 ret = sizeof(data);
10798
10799 done:
10800 if (status != MLAN_STATUS_PENDING)
10801 kfree(req);
10802
10803 LEAVE();
10804 return ret;
10805 }
10806
10807 #ifdef UAP_SUPPORT
10808 /**
10809 * @brief Set/Get network monitor configurations
10810 *
10811 * @param priv Pointer to moal_private structure
10812 * @param respbuf Pointer to response buffer
10813 * @param resplen Response buffer length
10814 *
10815 * @return Number of bytes written, negative for failure.
10816 */
woal_priv_net_monitor_ioctl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)10817 static int woal_priv_net_monitor_ioctl(moal_private *priv, t_u8 *respbuf,
10818 t_u32 respbuflen)
10819 {
10820 int user_data_len = 0, header_len = 0;
10821 int data_length = 0;
10822 int data[5] = {0};
10823 int ret = 0;
10824 mlan_ioctl_req *req = NULL;
10825 mlan_ds_misc_cfg *misc = NULL;
10826 mlan_ds_misc_net_monitor *net_mon = NULL;
10827 mlan_status status = MLAN_STATUS_SUCCESS;
10828 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10829 moal_handle *handle = priv->phandle;
10830 monitor_iface *mon_if = NULL;
10831 struct net_device *ndev = NULL;
10832 #endif
10833
10834 ENTER();
10835
10836 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_NET_MON);
10837 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
10838 if (req == NULL) {
10839 LEAVE();
10840 return -ENOMEM;
10841 }
10842 misc = (mlan_ds_misc_cfg *)req->pbuf;
10843 net_mon = (mlan_ds_misc_net_monitor *)&misc->param.net_mon;
10844 misc->sub_command = MLAN_OID_MISC_NET_MONITOR;
10845 req->req_id = MLAN_IOCTL_MISC_CFG;
10846 if ((int)strlen(respbuf) == header_len) {
10847 /* GET operation */
10848 user_data_len = 0;
10849 req->action = MLAN_ACT_GET;
10850 } else {
10851 /* SET operation */
10852 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
10853 &user_data_len);
10854 if (user_data_len == 1 || user_data_len == 4 ||
10855 user_data_len == 5) {
10856 if (data[0] != MFALSE &&
10857 data[0] != CHANNEL_SPEC_SNIFFER_MODE) {
10858 PRINTM(MERROR,
10859 "NET_MON: Activity should be enable(=1/2)/disable(=0)\n");
10860 ret = -EINVAL;
10861 goto done;
10862 }
10863 if ((data[0] == MFALSE && user_data_len != 1) ||
10864 (data[0] == CHANNEL_SPEC_SNIFFER_MODE &&
10865 (user_data_len != 4 && user_data_len != 5))) {
10866 PRINTM(MERROR,
10867 "NET_MON: Sniffer activity not match with user_data_len\n");
10868 ret = -EINVAL;
10869 goto done;
10870 }
10871 net_mon->enable_net_mon = data[0];
10872 if (data[0] == CHANNEL_SPEC_SNIFFER_MODE) {
10873 int i;
10874 if (user_data_len != 4 && user_data_len != 5) {
10875 PRINTM(MERROR,
10876 "NET_MON: Invalid number of args!\n");
10877 ret = -EINVAL;
10878 goto done;
10879 }
10880 /* Supported filter flags */
10881 if (!data[1] ||
10882 data[1] & ~(MLAN_NETMON_DATA_FRAME |
10883 MLAN_NETMON_MANAGEMENT_FRAME |
10884 MLAN_NETMON_CONTROL_FRAME)) {
10885 PRINTM(MERROR,
10886 "NET_MON: Invalid filter flag\n");
10887 ret = -EINVAL;
10888 goto done;
10889 }
10890
10891 if (user_data_len > 2) {
10892 /* Supported bands */
10893
10894 for (i = 0;
10895 i <
10896 (int)(sizeof(SupportedInfraBand) /
10897 sizeof(SupportedInfraBand[0]));
10898 i++)
10899 if (data[2] ==
10900 SupportedInfraBand[i])
10901 break;
10902 if (i == sizeof(SupportedInfraBand)) {
10903 PRINTM(MERROR,
10904 "NET_MON: Invalid band\n");
10905 ret = -EINVAL;
10906 goto done;
10907 }
10908 }
10909 /* Supported channel */
10910 if (user_data_len > 3 &&
10911 (data[3] < 1 ||
10912 data[3] > MLAN_MAX_CHANNEL)) {
10913 PRINTM(MERROR,
10914 "NET_MON: Invalid channel number\n");
10915 ret = -EINVAL;
10916 goto done;
10917 }
10918 if (user_data_len == 5) {
10919 /* Secondary channel offset */
10920 if (!(data[2] & (BAND_GN | BAND_AN))) {
10921 PRINTM(MERROR,
10922 "No 11n in band, can not set "
10923 "secondary channel offset\n");
10924 ret = -EINVAL;
10925 goto done;
10926 }
10927 if ((data[4] != CHANNEL_BW_20MHZ) &&
10928 (data[4] !=
10929 CHANNEL_BW_40MHZ_ABOVE) &&
10930 (data[4] !=
10931 CHANNEL_BW_40MHZ_BELOW) &&
10932 (data[4] != CHANNEL_BW_80MHZ)) {
10933 PRINTM(MERROR,
10934 "Invalid secondary channel bandwidth, "
10935 "only allowed 0, 1, 3 or 4\n");
10936 ret = -EINVAL;
10937 goto done;
10938 }
10939 net_mon->chan_bandwidth = data[4];
10940 }
10941
10942 net_mon->filter_flag = data[1];
10943 net_mon->band = data[2];
10944 net_mon->channel = data[3];
10945 }
10946 req->action = MLAN_ACT_SET;
10947 } else {
10948 PRINTM(MERROR, "NET_MON: Invalid number of args!\n");
10949 ret = -EINVAL;
10950 goto done;
10951 }
10952 }
10953
10954 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
10955 if (status != MLAN_STATUS_SUCCESS) {
10956 PRINTM(MERROR, "NET_MON: woal_request_ioctl fail\n");
10957 ret = -EFAULT;
10958 goto done;
10959 }
10960
10961 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
10962 if (req->action == MLAN_ACT_SET) {
10963 if (data[0]) { /** Enable sniffer mode: 1/2 */
10964 if (!handle->mon_if) {
10965 mon_if = woal_prepare_mon_if(priv, "rtap", 0,
10966 data[0]);
10967 if (!mon_if) {
10968 PRINTM(MFATAL,
10969 "Prepare mon_if fail.\n");
10970 ret = -EFAULT;
10971 goto done;
10972 }
10973 ndev = mon_if->mon_ndev;
10974 ret = register_netdevice(ndev);
10975 if (ret) {
10976 PRINTM(MFATAL,
10977 "register net_device failed, ret=%d\n",
10978 ret);
10979 free_netdev(ndev);
10980 ret = -EFAULT;
10981 goto done;
10982 }
10983 handle->mon_if = mon_if;
10984 }
10985 /* Save band channel config */
10986 handle->mon_if->band_chan_cfg.band = net_mon->band;
10987 handle->mon_if->band_chan_cfg.channel =
10988 net_mon->channel;
10989 handle->mon_if->band_chan_cfg.chan_bandwidth =
10990 net_mon->chan_bandwidth;
10991 } else { /** Disable sniffer mode: 0 */
10992 if (handle->mon_if) {
10993 ndev = handle->mon_if->mon_ndev;
10994 handle->mon_if = NULL;
10995 unregister_netdevice(ndev);
10996 }
10997 }
10998 }
10999 #endif
11000
11001 data[0] = net_mon->enable_net_mon;
11002 data[1] = net_mon->filter_flag;
11003 data[2] = net_mon->band;
11004 data[3] = net_mon->channel;
11005 data[4] = net_mon->chan_bandwidth;
11006 data_length = 5;
11007 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
11008 sizeof(int) * data_length, respbuflen);
11009 ret = sizeof(int) * data_length;
11010
11011 done:
11012 if (status != MLAN_STATUS_PENDING)
11013 kfree(req);
11014
11015 LEAVE();
11016 return ret;
11017 }
11018 #endif
11019
11020 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
11021 /**
11022 * @brief Set/Get monitor mode
11023 *
11024 * @param priv A pointer to moal_private structure
11025 * @param respbuf A pointer to response buffer
11026 * @param respbuflen Available length of response buffer
11027 *
11028 * @return 0 --success, otherwise fail
11029 */
woal_priv_set_get_monitor_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11030 static int woal_priv_set_get_monitor_mode(moal_private *priv, t_u8 *respbuf,
11031 t_u32 respbuflen)
11032 {
11033 int ret = 0;
11034 int data = 0;
11035 int user_data_len = 0, header_len = 0;
11036 t_u32 action = MLAN_ACT_GET;
11037
11038 ENTER();
11039
11040 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MONITOR_MODE);
11041
11042 if ((int)strlen(respbuf) == header_len) {
11043 /* GET operation */
11044 user_data_len = 0;
11045 action = MLAN_ACT_GET;
11046 } else {
11047 /* SET operation */
11048 parse_arguments(respbuf + header_len, &data,
11049 sizeof(data) / sizeof(int), &user_data_len);
11050 action = MLAN_ACT_SET;
11051 }
11052
11053 if (sizeof(int) * user_data_len > sizeof(data)) {
11054 PRINTM(MERROR, "Too many arguments\n");
11055 ret = -EINVAL;
11056 goto done;
11057 }
11058
11059 if (action == MLAN_ACT_SET) {
11060 if (data == 1) {
11061 priv->phandle->wiphy->interface_modes |=
11062 MBIT(NL80211_IFTYPE_MONITOR);
11063 } else if (data == 0) {
11064 priv->phandle->wiphy->interface_modes &=
11065 ~(MBIT(NL80211_IFTYPE_MONITOR));
11066 } else {
11067 PRINTM(MERROR, "Invalid input arguments\n");
11068 ret = -EINVAL;
11069 goto done;
11070 }
11071 }
11072 data = !!(priv->phandle->wiphy->interface_modes &
11073 MBIT(NL80211_IFTYPE_MONITOR));
11074
11075 ret = sprintf(respbuf, "Monitor mode: %d\n", data) + 1;
11076
11077 done:
11078 LEAVE();
11079 return ret;
11080 }
11081 #endif
11082
11083 /**
11084 * @brief This function get nop list.
11085 *
11086 * @param priv A pointer to moal_private structure
11087 * @param respbuf A pointer to response buffer
11088 * @param respbuflen Available length of response buffer
11089 *
11090 * @return Number of bytes written, negative for failure.
11091 */
woal_priv_nop_list(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11092 static int woal_priv_nop_list(moal_private *priv, t_u8 *respbuf,
11093 t_u32 respbuflen)
11094 {
11095 mlan_ioctl_req *req = NULL;
11096 mlan_ds_11h_cfg *ds_11hcfg = NULL;
11097
11098 int ret = 0;
11099 mlan_status status = MLAN_STATUS_SUCCESS;
11100
11101 ENTER();
11102
11103 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11104 if (req == NULL) {
11105 ret = -ENOMEM;
11106 goto done;
11107 }
11108
11109 req->req_id = MLAN_IOCTL_11H_CFG;
11110 req->action = MLAN_ACT_GET;
11111
11112 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11113 ds_11hcfg->sub_command = MLAN_OID_11H_NOP_CHAN_LIST;
11114 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11115 if (status == MLAN_STATUS_FAILURE) {
11116 ret = -EFAULT;
11117 goto done;
11118 }
11119 moal_memcpy_ext(priv->phandle, respbuf,
11120 (t_u8 *)&ds_11hcfg->param.nop_chan_list,
11121 sizeof(mlan_ds_11h_nop_chan_list), respbuflen);
11122 ret = sizeof(mlan_ds_11h_nop_chan_list);
11123 done:
11124 if (status != MLAN_STATUS_PENDING)
11125 kfree(req);
11126 LEAVE();
11127 return ret;
11128 }
11129
11130 /**
11131 * @brief clear NOP list
11132 *
11133 * @param priv A pointer to moal_private structure
11134 * @return 0 --success, otherwise fail
11135 */
woal_uap_clear_nop(moal_private * priv)11136 static int woal_uap_clear_nop(moal_private *priv)
11137 {
11138 mlan_ioctl_req *req = NULL;
11139 mlan_ds_11h_cfg *ds_11hcfg = NULL;
11140
11141 int ret = 0;
11142 mlan_status status = MLAN_STATUS_SUCCESS;
11143
11144 ENTER();
11145
11146 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11147 if (req == NULL) {
11148 ret = -ENOMEM;
11149 goto done;
11150 }
11151
11152 req->req_id = MLAN_IOCTL_11H_CFG;
11153 req->action = MLAN_ACT_CLEAR;
11154
11155 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11156 ds_11hcfg->sub_command = MLAN_OID_11H_CHAN_NOP_INFO;
11157 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11158 if (status == MLAN_STATUS_FAILURE) {
11159 ret = -EFAULT;
11160 goto done;
11161 }
11162 done:
11163 if (status != MLAN_STATUS_PENDING)
11164 kfree(req);
11165 LEAVE();
11166 return ret;
11167 }
11168
11169 /**
11170 * @brief This function clear nop flags.
11171 *
11172 * @param priv A pointer to moal_private structure
11173 * @param respbuf A pointer to response buffer
11174 * @param respbuflen Available length of response buffer
11175 *
11176 * @return Number of bytes written, negative for failure.
11177 */
woal_priv_clear_nop(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11178 static int woal_priv_clear_nop(moal_private *priv, t_u8 *respbuf,
11179 t_u32 respbuflen)
11180 {
11181 int ret = 0;
11182 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11183 struct wiphy *wiphy = priv->phandle->wiphy;
11184 #endif
11185
11186 ENTER();
11187 PRINTM(MCMND, "clear nop\n");
11188 ret = woal_uap_clear_nop(priv);
11189 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11190 if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext)) {
11191 if (wiphy)
11192 woal_clear_wiphy_dfs_state(wiphy);
11193 }
11194 #endif
11195 ret = sizeof(int);
11196 LEAVE();
11197 return ret;
11198 }
11199
11200 /**
11201 * @brief This function detects fake RADAR.
11202 *
11203 * @param priv A pointer to moal_private structure
11204 * @param respbuf A pointer to response buffer
11205 * @param respbuflen Available length of response buffer
11206 *
11207 * @return positive for success, negative for failure.
11208 */
woal_priv_fake_radar(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11209 static int woal_priv_fake_radar(moal_private *priv, t_u8 *respbuf,
11210 t_u32 respbuflen)
11211 {
11212 mlan_ioctl_req *ioctl_req = NULL;
11213 mlan_ds_snmp_mib *snmp = NULL;
11214 int ret = 0;
11215 mlan_status status = MLAN_STATUS_SUCCESS;
11216 ENTER();
11217 #ifdef UAP_CFG80211
11218 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
11219 if (priv && priv->chan.chan &&
11220 !(priv->chan.chan->flags & IEEE80211_CHAN_RADAR)) {
11221 PRINTM(MERROR, "Current op channel NOT DFS\n");
11222 LEAVE();
11223 return -EINVAL;
11224 }
11225 #endif
11226 #endif
11227 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
11228 if (ioctl_req == NULL) {
11229 LEAVE();
11230 return -ENOMEM;
11231 }
11232 snmp = (mlan_ds_snmp_mib *)ioctl_req->pbuf;
11233 ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
11234 snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H_FAKERADAR;
11235 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11236 if (status != MLAN_STATUS_SUCCESS) {
11237 ret = -EFAULT;
11238 goto done;
11239 }
11240 done:
11241 if (status != MLAN_STATUS_PENDING)
11242 kfree(ioctl_req);
11243 LEAVE();
11244 return ret;
11245 }
11246
11247 /**
11248 * @brief Set/Get DFS Testing settings
11249 *
11250 * @param priv Pointer to moal_private structure
11251 * @param respbuf Pointer to response buffer
11252 * @param resplen Response buffer length
11253 *
11254 * @return Number of bytes written, negative for failure.
11255 */
woal_priv_dfs_testing(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11256 static int woal_priv_dfs_testing(moal_private *priv, t_u8 *respbuf,
11257 t_u32 respbuflen)
11258 {
11259 mlan_ioctl_req *req = NULL;
11260 mlan_ds_11h_cfg *ds_11hcfg = NULL;
11261 int ret = 0;
11262 int data[5] = {0};
11263 int user_data_len = 0, header_len = 0;
11264 mlan_status status = MLAN_STATUS_SUCCESS;
11265
11266 ENTER();
11267
11268 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_TESTING);
11269 /* Allocate an IOCTL request buffer */
11270 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11271 if (req == NULL) {
11272 ret = -ENOMEM;
11273 goto done;
11274 }
11275
11276 /* Fill request buffer */
11277 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11278 ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING;
11279 req->req_id = MLAN_IOCTL_11H_CFG;
11280
11281 if ((int)strlen(respbuf) == header_len) {
11282 /* GET operation */
11283 user_data_len = 0;
11284 req->action = MLAN_ACT_GET;
11285 } else {
11286 /* SET operation */
11287 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
11288 &user_data_len);
11289 if (user_data_len != 5) {
11290 PRINTM(MERROR, "Invalid number of args!\n");
11291 ret = -EINVAL;
11292 goto done;
11293 }
11294 if ((unsigned)data[0] > 1800) {
11295 PRINTM(MERROR,
11296 "The maximum user CAC is 1800 seconds (30 mins).\n");
11297 ret = -EINVAL;
11298 goto done;
11299 }
11300 if ((unsigned)data[1] > 0xFFFF) {
11301 PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n");
11302 ret = -EINVAL;
11303 goto done;
11304 }
11305 if ((unsigned)data[3] > 0xFF) {
11306 PRINTM(MERROR,
11307 "The maximum user fixed channel is 255.\n");
11308 ret = -EINVAL;
11309 goto done;
11310 }
11311 if ((unsigned)data[4] != 0 && ((unsigned)data[4] != 1)) {
11312 PRINTM(MERROR, "CAC restart should be 0/1\n");
11313 ret = -EINVAL;
11314 goto done;
11315 }
11316
11317 ds_11hcfg->param.dfs_testing.usr_cac_period_msec =
11318 (t_u32)data[0] * 1000;
11319 ds_11hcfg->param.dfs_testing.usr_nop_period_sec =
11320 (t_u16)data[1];
11321 ds_11hcfg->param.dfs_testing.usr_no_chan_change =
11322 data[2] ? 1 : 0;
11323 ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3];
11324 ds_11hcfg->param.dfs_testing.usr_cac_restart = (t_u8)data[4];
11325 priv->phandle->cac_restart = (t_u8)data[4];
11326 priv->phandle->cac_period_jiffies = (t_u32)data[0] * HZ;
11327 priv->phandle->usr_nop_period_sec = (t_u16)data[1];
11328 req->action = MLAN_ACT_SET;
11329 #ifdef UAP_SUPPORT
11330 priv->user_cac_period_msec =
11331 ds_11hcfg->param.dfs_testing.usr_cac_period_msec;
11332 #endif
11333 }
11334
11335 /* Send IOCTL request to MLAN */
11336 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11337 if (status != MLAN_STATUS_SUCCESS) {
11338 ret = -EFAULT;
11339 goto done;
11340 }
11341
11342 if (!user_data_len) {
11343 data[0] =
11344 ds_11hcfg->param.dfs_testing.usr_cac_period_msec / 1000;
11345 data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec;
11346 data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change;
11347 data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan;
11348 data[4] = ds_11hcfg->param.dfs_testing.usr_cac_restart;
11349 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
11350 sizeof(data), respbuflen);
11351 ret = sizeof(data);
11352 }
11353
11354 done:
11355 if (status != MLAN_STATUS_PENDING)
11356 kfree(req);
11357
11358 LEAVE();
11359 return ret;
11360 }
11361
11362 /**
11363 * @brief Set/Get DFS W53 settings
11364 *
11365 * @param priv Pointer to moal_private structure
11366 * @param respbuf Pointer to response buffer
11367 * @param resplen Response buffer length
11368 *
11369 * @return Number of bytes written, negative for failure.
11370 */
woal_priv_dfs53cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11371 static int woal_priv_dfs53cfg(moal_private *priv, t_u8 *respbuf,
11372 t_u32 respbuflen)
11373 {
11374 mlan_ioctl_req *req = NULL;
11375 mlan_ds_11h_cfg *ds_11hcfg = NULL;
11376 int ret = 0;
11377 int data = 0;
11378 int user_data_len = 0, header_len = 0;
11379 mlan_status status = MLAN_STATUS_SUCCESS;
11380
11381 ENTER();
11382
11383 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS53_CFG);
11384 /* Allocate an IOCTL request buffer */
11385 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11386 if (req == NULL) {
11387 ret = -ENOMEM;
11388 goto done;
11389 }
11390
11391 /* Fill request buffer */
11392 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11393 ds_11hcfg->sub_command = MLAN_OID_11H_DFS_W53_CFG;
11394 req->req_id = MLAN_IOCTL_11H_CFG;
11395
11396 if ((int)strlen(respbuf) == header_len) {
11397 /* GET operation */
11398 user_data_len = 0;
11399 req->action = MLAN_ACT_GET;
11400 } else {
11401 /* SET operation */
11402 parse_arguments(respbuf + header_len, &data,
11403 sizeof(data) / sizeof(int), &user_data_len);
11404 if (user_data_len != 1) {
11405 PRINTM(MERROR, "Invalid number of args !\n");
11406 ret = -EINVAL;
11407 goto done;
11408 }
11409 if (data > DFS_W53_OLD) {
11410 PRINTM(MERROR, "Invalid config !\n");
11411 ret = -EINVAL;
11412 goto done;
11413 }
11414
11415 ds_11hcfg->param.dfs_w53_cfg.dfs53cfg = (t_u8)data;
11416 req->action = MLAN_ACT_SET;
11417 }
11418
11419 /* Send IOCTL request to MLAN */
11420 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11421 if (status != MLAN_STATUS_SUCCESS) {
11422 ret = -EFAULT;
11423 goto done;
11424 }
11425
11426 if (!user_data_len) {
11427 moal_memcpy_ext(priv->phandle, respbuf,
11428 (t_u8 *)&ds_11hcfg->param.dfs_w53_cfg.dfs53cfg,
11429 sizeof(ds_11hcfg->param.dfs_w53_cfg.dfs53cfg),
11430 respbuflen);
11431 ret = sizeof(t_u8);
11432 }
11433
11434 PRINTM(MIOCTL, "dfs w53 cfg %d\n",
11435 ds_11hcfg->param.dfs_w53_cfg.dfs53cfg);
11436
11437 done:
11438 if (status != MLAN_STATUS_PENDING)
11439 kfree(req);
11440
11441 LEAVE();
11442 return ret;
11443 }
11444
11445 /**
11446 * @brief Set/Get DFS mode settings
11447 *
11448 * @param priv Pointer to moal_private structure
11449 * @param respbuf Pointer to response buffer
11450 * @param resplen Response buffer length
11451 *
11452 * @return Number of bytes written, negative for failure.
11453 */
woal_priv_dfs_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)11454 static int woal_priv_dfs_mode(moal_private *priv, t_u8 *respbuf,
11455 t_u32 respbuflen)
11456 {
11457 mlan_ioctl_req *req = NULL;
11458 mlan_ds_11h_cfg *ds_11hcfg = NULL;
11459 int ret = 0;
11460 int data = 0;
11461 int user_data_len = 0, header_len = 0;
11462 mlan_status status = MLAN_STATUS_SUCCESS;
11463
11464 ENTER();
11465
11466 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_MODE);
11467 /* Allocate an IOCTL request buffer */
11468 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
11469 if (req == NULL) {
11470 ret = -ENOMEM;
11471 goto done;
11472 }
11473
11474 /* Fill request buffer */
11475 ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf;
11476 ds_11hcfg->sub_command = MLAN_OID_11H_DFS_MODE;
11477 req->req_id = MLAN_IOCTL_11H_CFG;
11478
11479 if ((int)strlen(respbuf) == header_len) {
11480 /* GET operation */
11481 user_data_len = 0;
11482 req->action = MLAN_ACT_GET;
11483 } else {
11484 /* SET operation */
11485 parse_arguments(respbuf + header_len, &data,
11486 sizeof(data) / sizeof(int), &user_data_len);
11487 if (user_data_len != 1) {
11488 PRINTM(MERROR, "Invalid number of args !\n");
11489 ret = -EINVAL;
11490 goto done;
11491 }
11492 if (data > DFS_MODE_ENH) {
11493 PRINTM(MERROR, "Invalid config for dfs_mode!\n");
11494 ret = -EINVAL;
11495 goto done;
11496 }
11497
11498 ds_11hcfg->param.dfs_mode = (t_u8)data;
11499 req->action = MLAN_ACT_SET;
11500 }
11501
11502 /* Send IOCTL request to MLAN */
11503 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
11504 if (status != MLAN_STATUS_SUCCESS) {
11505 ret = -EFAULT;
11506 goto done;
11507 }
11508
11509 if (!user_data_len) {
11510 moal_memcpy_ext(priv->phandle, respbuf,
11511 (t_u8 *)&ds_11hcfg->param.dfs_mode,
11512 sizeof(ds_11hcfg->param.dfs_mode), respbuflen);
11513 ret = sizeof(t_u8);
11514 }
11515
11516 PRINTM(MIOCTL, "dfs_mode %d\n", ds_11hcfg->param.dfs_mode);
11517
11518 done:
11519 if (status != MLAN_STATUS_PENDING)
11520 kfree(req);
11521
11522 LEAVE();
11523 return ret;
11524 }
11525
11526 #ifdef UAP_SUPPORT
11527 /**
11528 * @brief determine the center frquency center index for bandwidth
11529 * of 80 MHz and 160 MHz
11530 *
11531 ** @param priv Pointer to moal_private structure
11532 * @param band band
11533 * @param pri_chan primary channel
11534 * @param chan_bw channel bandwidth
11535 *
11536 * @return channel center frequency center, if found; O, otherwise
11537 */
11538
woal_get_center_freq_idx(moal_private * priv,t_u16 band,t_u32 pri_chan,t_u8 chan_bw)11539 static t_u8 woal_get_center_freq_idx(moal_private *priv, t_u16 band,
11540 t_u32 pri_chan, t_u8 chan_bw)
11541 {
11542 t_u8 center_freq_idx = 0;
11543
11544 if (band & BAND_AAC) {
11545 switch (pri_chan) {
11546 case 36:
11547 case 40:
11548 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11549 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11550 center_freq_idx = 38;
11551 break;
11552 }
11553 /* fall through */
11554 case 44:
11555 case 48:
11556 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11557 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11558 center_freq_idx = 46;
11559 break;
11560 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11561 center_freq_idx = 42;
11562 break;
11563 }
11564 /* fall through */
11565 case 52:
11566 case 56:
11567 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11568 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11569 center_freq_idx = 54;
11570 break;
11571 }
11572 /* fall through */
11573 case 60:
11574 case 64:
11575 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11576 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11577 center_freq_idx = 62;
11578 break;
11579 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11580 center_freq_idx = 58;
11581 break;
11582 } else if (chan_bw == CHANNEL_BW_160MHZ) {
11583 center_freq_idx = 50;
11584 break;
11585 }
11586 /* fall through */
11587 case 68:
11588 case 72:
11589 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11590 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11591 center_freq_idx = 70;
11592 break;
11593 }
11594 /* fall through */
11595 case 76:
11596 case 80:
11597 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11598 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11599 center_freq_idx = 78;
11600 break;
11601 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11602 center_freq_idx = 74;
11603 break;
11604 }
11605 /* fall through */
11606 case 84:
11607 case 88:
11608 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11609 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11610 center_freq_idx = 86;
11611 break;
11612 }
11613 /* fall through */
11614 case 92:
11615 case 96:
11616 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11617 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11618 center_freq_idx = 94;
11619 break;
11620 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11621 center_freq_idx = 90;
11622 break;
11623 }
11624 /* fall through */
11625 case 100:
11626 case 104:
11627 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11628 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11629 center_freq_idx = 102;
11630 break;
11631 }
11632 /* fall through */
11633 case 108:
11634 case 112:
11635 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11636 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11637 center_freq_idx = 110;
11638 break;
11639 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11640 center_freq_idx = 106;
11641 break;
11642 }
11643 /* fall through */
11644 case 116:
11645 case 120:
11646 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11647 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11648 center_freq_idx = 118;
11649 break;
11650 }
11651 /* fall through */
11652 case 124:
11653 case 128:
11654 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11655 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11656 center_freq_idx = 126;
11657 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11658 center_freq_idx = 122;
11659 } else if (chan_bw == CHANNEL_BW_160MHZ) {
11660 center_freq_idx = 114;
11661 }
11662 break;
11663 case 132:
11664 case 136:
11665 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11666 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11667 center_freq_idx = 134;
11668 break;
11669 }
11670 /* fall through */
11671 case 140:
11672 case 144:
11673 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11674 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11675 center_freq_idx = 126;
11676 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11677 center_freq_idx = 138;
11678 }
11679 break;
11680 case 149:
11681 case 153:
11682 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11683 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11684 center_freq_idx = 151;
11685 break;
11686 }
11687 /* fall through */
11688 case 157:
11689 case 161:
11690 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11691 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11692 center_freq_idx = 159;
11693 break;
11694 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11695 center_freq_idx = 155;
11696 break;
11697 }
11698 /* fall through */
11699 case 165:
11700 case 169:
11701 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11702 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11703 center_freq_idx = 167;
11704 break;
11705 }
11706 /* fall through */
11707 case 173:
11708 case 177:
11709 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11710 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11711 center_freq_idx = 175;
11712 break;
11713 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11714 center_freq_idx = 171;
11715 break;
11716 }
11717 /* fall through */
11718 case 184:
11719 case 188:
11720 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11721 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11722 center_freq_idx = 186;
11723 break;
11724 }
11725 /* fall through */
11726 case 192:
11727 case 196:
11728 if (chan_bw == CHANNEL_BW_40MHZ_ABOVE ||
11729 chan_bw == CHANNEL_BW_40MHZ_BELOW) {
11730 center_freq_idx = 194;
11731 break;
11732 } else if (chan_bw == CHANNEL_BW_80MHZ) {
11733 center_freq_idx = 190;
11734 break;
11735 }
11736 /* fall through */
11737 default: /* error. go to the default */
11738 center_freq_idx = 42;
11739 }
11740 }
11741 return center_freq_idx;
11742 }
11743 #endif
11744
11745 #if defined(UAP_SUPPORT)
11746 /**
11747 * @brief This function handles channel switch with CSA/ECSA IE.
11748 *
11749 ** @param priv Pointer to moal_private structure
11750 * @param block_tx 0-no need block traffic 1- need block traffic
11751 * @param oper_class oper_class
11752 * @param channel channel
11753 * @param switch count how many csa/ecsa beacon will send out
11754 * @param band_width 1-40Mhz above, 3-40Mhz below, 4-80Mhz, 5-160Mhz
11755 * @param ecsa MTRUE/MFALSE;
11756 *
11757 * @return channel center frequency center, if found; O, otherwise
11758 */
woal_channel_switch(moal_private * priv,t_u8 block_tx,t_u8 oper_class,t_u8 channel,t_u8 switch_count,t_u8 band_width,t_u8 ecsa)11759 static int woal_channel_switch(moal_private *priv, t_u8 block_tx,
11760 t_u8 oper_class, t_u8 channel, t_u8 switch_count,
11761 t_u8 band_width, t_u8 ecsa)
11762 {
11763 IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
11764 IEEEtypes_ChanSwitchAnn_t *chan_switch = NULL;
11765 custom_ie *pcust_chansw_ie = NULL;
11766 t_u8 center_freq_idx = 0;
11767 IEEEtypes_Header_t *pChanSwWrap_ie = NULL;
11768 IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = NULL;
11769 IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = NULL;
11770 mlan_ioctl_req *ioctl_req = NULL;
11771 mlan_ds_misc_cfg *misc = NULL;
11772 mlan_status status = MLAN_STATUS_SUCCESS;
11773 t_u8 bw;
11774 t_u8 new_oper_class = oper_class;
11775 int ret = 0;
11776
11777 ENTER();
11778
11779 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
11780 if (ioctl_req == NULL) {
11781 ret = -ENOMEM;
11782 goto done;
11783 }
11784 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
11785 misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
11786 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
11787 ioctl_req->action = MLAN_ACT_SET;
11788 misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
11789 misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
11790
11791 pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
11792 pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
11793 pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
11794 pcust_chansw_ie->mgmt_subtype_mask =
11795 MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
11796 BEACON/probe resp*/
11797 chan_switch = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
11798 chan_switch->element_id = CHANNEL_SWITCH_ANN;
11799 chan_switch->len = 3;
11800 chan_switch->chan_switch_mode = block_tx;
11801 chan_switch->new_channel_num = channel;
11802 chan_switch->chan_switch_count = switch_count;
11803 DBG_HEXDUMP(MCMD_D, "CSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
11804 pcust_chansw_ie->ie_length);
11805 switch (band_width) {
11806 case CHANNEL_BW_40MHZ_ABOVE:
11807 case CHANNEL_BW_40MHZ_BELOW:
11808 bw = 40;
11809 break;
11810 case CHANNEL_BW_80MHZ:
11811 bw = 80;
11812 break;
11813 case CHANNEL_BW_160MHZ:
11814 bw = 160;
11815 break;
11816 default:
11817 bw = 20;
11818 break;
11819 }
11820 if (!new_oper_class && ecsa)
11821 woal_priv_get_nonglobal_operclass_by_bw_channel(
11822 priv, bw, channel, &new_oper_class);
11823 if (new_oper_class) {
11824 pcust_chansw_ie->ie_length +=
11825 sizeof(IEEEtypes_ExtChanSwitchAnn_t);
11826 ext_chan_switch =
11827 (IEEEtypes_ExtChanSwitchAnn_t
11828 *)(pcust_chansw_ie->ie_buffer +
11829 sizeof(IEEEtypes_ChanSwitchAnn_t));
11830 ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
11831 ext_chan_switch->len = 4;
11832 ext_chan_switch->chan_switch_mode = block_tx;
11833 ext_chan_switch->new_oper_class = new_oper_class;
11834 ext_chan_switch->new_channel_num = channel;
11835 ext_chan_switch->chan_switch_count = switch_count;
11836 DBG_HEXDUMP(MCMD_D, "ECSA IE",
11837 (t_u8 *)(pcust_chansw_ie->ie_buffer +
11838 sizeof(IEEEtypes_ChanSwitchAnn_t)),
11839 pcust_chansw_ie->ie_length -
11840 sizeof(IEEEtypes_ChanSwitchAnn_t));
11841 }
11842 /* bandwidth 40/80/160 should set channel switch wrapper ie for 11ac 5G
11843 * channel*/
11844 if (band_width && channel > 14) {
11845 pChanSwWrap_ie =
11846 (IEEEtypes_Header_t *)(pcust_chansw_ie->ie_buffer +
11847 pcust_chansw_ie->ie_length);
11848 pChanSwWrap_ie->element_id = EXT_POWER_CONSTR;
11849 pChanSwWrap_ie->len = sizeof(IEEEtypes_WideBWChanSwitch_t);
11850
11851 pbwchansw_ie = (IEEEtypes_WideBWChanSwitch_t
11852 *)((t_u8 *)pChanSwWrap_ie +
11853 sizeof(IEEEtypes_Header_t));
11854 pbwchansw_ie->ieee_hdr.element_id = BW_CHANNEL_SWITCH;
11855 pbwchansw_ie->ieee_hdr.len =
11856 sizeof(IEEEtypes_WideBWChanSwitch_t) -
11857 sizeof(IEEEtypes_Header_t);
11858
11859 center_freq_idx = woal_get_center_freq_idx(priv, BAND_AAC,
11860 channel, band_width);
11861 if (band_width == CHANNEL_BW_40MHZ_ABOVE ||
11862 band_width == CHANNEL_BW_40MHZ_BELOW) {
11863 pbwchansw_ie->new_channel_width = 0;
11864 pbwchansw_ie->new_channel_center_freq0 =
11865 center_freq_idx;
11866 } else if (band_width == CHANNEL_BW_80MHZ) {
11867 pbwchansw_ie->new_channel_width = 1;
11868 pbwchansw_ie->new_channel_center_freq0 =
11869 center_freq_idx - 4;
11870 pbwchansw_ie->new_channel_center_freq1 =
11871 center_freq_idx + 4;
11872 } else if (band_width == CHANNEL_BW_160MHZ) {
11873 pbwchansw_ie->new_channel_width = 2;
11874 pbwchansw_ie->new_channel_center_freq0 =
11875 center_freq_idx - 8;
11876 pbwchansw_ie->new_channel_center_freq1 =
11877 center_freq_idx + 8;
11878 } else
11879 PRINTM(MERROR,
11880 "Invalid bandwidth.Support value 1/3/4/5 for 40+/40-/80/160MHZ\n");
11881
11882 /*prepare the VHT Transmit Power Envelope IE*/
11883 pvhttpcEnv_ie =
11884 (IEEEtypes_VhtTpcEnvelope_t
11885 *)((t_u8 *)pChanSwWrap_ie +
11886 sizeof(IEEEtypes_Header_t) +
11887 sizeof(IEEEtypes_WideBWChanSwitch_t));
11888 pvhttpcEnv_ie->ieee_hdr.element_id = VHT_TX_POWER_ENV;
11889 pvhttpcEnv_ie->ieee_hdr.len =
11890 sizeof(IEEEtypes_VhtTpcEnvelope_t) -
11891 sizeof(IEEEtypes_Header_t);
11892 /* Local Max TX Power Count= 3,
11893 * Local TX Power Unit Inter=EIP(0) */
11894 pvhttpcEnv_ie->tpc_info = 3;
11895 pvhttpcEnv_ie->local_max_tp_20mhz = 0xff;
11896 pvhttpcEnv_ie->local_max_tp_40mhz = 0xff;
11897 pvhttpcEnv_ie->local_max_tp_80mhz = 0xff;
11898 pvhttpcEnv_ie->local_max_tp_160mhz_80_80mhz = 0xff;
11899 pChanSwWrap_ie->len += sizeof(IEEEtypes_VhtTpcEnvelope_t);
11900 pcust_chansw_ie->ie_length +=
11901 pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t);
11902 DBG_HEXDUMP(MCMD_D, "Channel switch wrapper IE",
11903 (t_u8 *)pChanSwWrap_ie,
11904 pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t));
11905 }
11906 if (block_tx) {
11907 if (netif_carrier_ok(priv->netdev))
11908 netif_carrier_off(priv->netdev);
11909 woal_stop_queue(priv->netdev);
11910 priv->uap_tx_blocked = MTRUE;
11911 }
11912
11913 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11914 if (status != MLAN_STATUS_SUCCESS) {
11915 PRINTM(MERROR, "Failed to set ECSA IE\n");
11916 ret = -EFAULT;
11917 goto done;
11918 }
11919
11920 priv->phandle->chsw_wait_q_woken = MFALSE;
11921 /* wait for channel switch to complete */
11922 wait_event_interruptible_timeout(
11923 priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
11924 (u32)HZ * (switch_count + 2) * 110 / 1000);
11925
11926 pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
11927 pcust_chansw_ie->mgmt_subtype_mask = 0;
11928 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
11929 if (status != MLAN_STATUS_SUCCESS) {
11930 PRINTM(MERROR, "Failed to clear ECSA IE\n");
11931 }
11932 done:
11933 if (status != MLAN_STATUS_PENDING)
11934 kfree(ioctl_req);
11935
11936 LEAVE();
11937 return ret;
11938 }
11939 #endif
11940
11941 #ifdef UAP_SUPPORT
11942 /**
11943 * @brief Given bandwidth and channel, create Band_Config
11944 *
11945 * @param priv A pointer to moal_private
11946 * @param bandcfg A pointer to Band_Config_t structure
11947 * @param channel A pointer to cfg80211_chan_def structure
11948 * @param bandwidth 0/1/3/4
11949 *
11950 * @return N/A
11951 */
woal_convert_chanbw_to_bandconfig(moal_private * priv,Band_Config_t * bandcfg,t_u8 channel,t_u8 bandwidth)11952 static void woal_convert_chanbw_to_bandconfig(moal_private *priv,
11953 Band_Config_t *bandcfg,
11954 t_u8 channel, t_u8 bandwidth)
11955 {
11956 ENTER();
11957
11958 if (channel <= MAX_BG_CHANNEL)
11959 bandcfg->chanBand = BAND_2GHZ;
11960 else
11961 bandcfg->chanBand = BAND_5GHZ;
11962 switch (bandwidth) {
11963 case CHANNEL_BW_40MHZ_ABOVE:
11964 bandcfg->chanWidth = CHAN_BW_40MHZ;
11965 bandcfg->chan2Offset = SEC_CHAN_ABOVE;
11966 break;
11967 case CHANNEL_BW_40MHZ_BELOW:
11968 bandcfg->chanWidth = CHAN_BW_40MHZ;
11969 bandcfg->chan2Offset = SEC_CHAN_BELOW;
11970 break;
11971 case CHANNEL_BW_80MHZ:
11972 bandcfg->chanWidth = CHAN_BW_80MHZ;
11973 bandcfg->chan2Offset =
11974 woal_get_second_channel_offset(priv, channel);
11975 break;
11976 case CHANNEL_BW_20MHZ:
11977 default:
11978 bandcfg->chanWidth = CHAN_BW_20MHZ;
11979 break;
11980 }
11981 LEAVE();
11982 return;
11983 }
11984
11985 /**
11986 * @brief Get DFS channel list
11987 *
11988 * @param priv A pointer to moal_private
11989 *
11990 * @return N/A
11991 */
woal_get_dfs_chan_list(moal_private * priv)11992 static void woal_get_dfs_chan_list(moal_private *priv)
11993 {
11994 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
11995 struct wiphy *wiphy = priv->phandle->wiphy;
11996 struct ieee80211_supported_band *sband;
11997 #endif
11998 int i;
11999 mlan_ioctl_req *req = NULL;
12000 mlan_ds_misc_cfg *cfp_misc = NULL;
12001 mlan_status status = MLAN_STATUS_SUCCESS;
12002
12003 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
12004 if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext) &&
12005 wiphy) {
12006 sband = wiphy->bands[NL80211_BAND_5GHZ];
12007 if (sband) {
12008 for (i = 0; i < sband->n_channels; i++) {
12009 if (sband->channels[i].flags &
12010 IEEE80211_CHAN_RADAR) {
12011 priv->auto_dfs_cfg.dfs_chan_list
12012 [priv->auto_dfs_cfg.num_of_chan] =
12013 sband->channels[i].hw_value;
12014 priv->auto_dfs_cfg.num_of_chan++;
12015 }
12016 }
12017 return;
12018 }
12019 }
12020 #endif
12021 /* Allocate an IOCTL request buffer */
12022 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12023 if (req == NULL)
12024 goto done;
12025
12026 /* Fill request buffer */
12027 cfp_misc = (mlan_ds_misc_cfg *)req->pbuf;
12028 cfp_misc->sub_command = MLAN_OID_MISC_CFP_TABLE;
12029 req->req_id = MLAN_IOCTL_MISC_CFG;
12030 req->action = MLAN_ACT_GET;
12031 cfp_misc->param.cfp.band = BAND_A;
12032
12033 /* Send IOCTL request to MLAN */
12034 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12035 if (status != MLAN_STATUS_SUCCESS)
12036 goto done;
12037
12038 for (i = 0; i < cfp_misc->param.cfp.num_chan; i++) {
12039 if (cfp_misc->param.cfp.cfp_tbl[i].dynamic.flags &
12040 NXP_CHANNEL_DISABLED)
12041 continue;
12042 if (cfp_misc->param.cfp.cfp_tbl[i].passive_scan_or_radar_detect) {
12043 priv->auto_dfs_cfg
12044 .dfs_chan_list[priv->auto_dfs_cfg.num_of_chan] =
12045 cfp_misc->param.cfp.cfp_tbl[i].channel;
12046 priv->auto_dfs_cfg.num_of_chan++;
12047 }
12048 }
12049 done:
12050 if (status != MLAN_STATUS_PENDING)
12051 kfree(req);
12052
12053 LEAVE();
12054 return;
12055 }
12056
12057 /**
12058 * @brief Process dfs cac command
12059 *
12060 * @param priv a pointer to moal_private structure
12061 * @param ch_rpt_req a pointer to mlan_ds_11h_chan_rep_req structure
12062 *
12063 * @return MLAN_STATUS_FAILRUE or MLAN_STATUS_SUCCESS
12064 */
woal_do_dfs_cac(moal_private * priv,mlan_ds_11h_chan_rep_req * ch_rpt_req)12065 mlan_status woal_do_dfs_cac(moal_private *priv,
12066 mlan_ds_11h_chan_rep_req *ch_rpt_req)
12067 {
12068 mlan_ioctl_req *req = NULL;
12069 mlan_ds_11h_cfg *p11h_cfg = NULL;
12070 mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
12071 mlan_status status = MLAN_STATUS_SUCCESS;
12072
12073 ENTER();
12074 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
12075 if (NULL == req) {
12076 LEAVE();
12077 return MLAN_STATUS_FAILURE;
12078 }
12079 p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
12080 pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
12081
12082 moal_memcpy_ext(priv->phandle, pchan_rpt_req, ch_rpt_req,
12083 sizeof(mlan_ds_11h_chan_rep_req),
12084 sizeof(mlan_ds_11h_chan_rep_req));
12085
12086 if (priv->bss_type == MLAN_BSS_TYPE_DFS)
12087 p11h_cfg->sub_command = MLAN_OID_11H_CHAN_REPORT_REQUEST;
12088 else
12089 p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
12090
12091 req->req_id = MLAN_IOCTL_11H_CFG;
12092
12093 req->action = MLAN_ACT_SET;
12094 /* Send Channel Check command and wait until the report is ready */
12095 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12096 if (status != MLAN_STATUS_PENDING)
12097 kfree(req);
12098 LEAVE();
12099 return status;
12100 }
12101
12102 /**
12103 * @brief Get Next DFS channel from dfs_chan_list
12104 *
12105 * @param priv a pointer to moal_private structure
12106 *
12107 * @return N/A
12108 *
12109 */
woal_get_next_dfs_chan(moal_private * priv)12110 static t_u8 woal_get_next_dfs_chan(moal_private *priv)
12111 {
12112 int i;
12113 int idx = priv->curr_cac_idx;
12114 mlan_ds_11h_chan_dfs_state ch_dfs_state;
12115 t_u8 chan = 0;
12116 ENTER();
12117 idx++;
12118 if (idx >= priv->auto_dfs_cfg.num_of_chan)
12119 idx = 0;
12120 for (i = 0; i < priv->auto_dfs_cfg.num_of_chan; i++) {
12121 if (priv->chan_rpt_req.chanNum !=
12122 priv->auto_dfs_cfg.dfs_chan_list[idx]) {
12123 memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12124 ch_dfs_state.channel =
12125 priv->auto_dfs_cfg.dfs_chan_list[idx];
12126 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12127 &ch_dfs_state)) {
12128 PRINTM(MERROR,
12129 "%s: woal_11h_chan_dfs_state failed \n",
12130 __func__);
12131 continue;
12132 }
12133 if (ch_dfs_state.dfs_state != DFS_UNAVAILABLE) {
12134 chan = priv->auto_dfs_cfg.dfs_chan_list[idx];
12135 priv->curr_cac_idx = idx;
12136 break;
12137 }
12138 }
12139 idx++;
12140 if (idx >= priv->auto_dfs_cfg.num_of_chan)
12141 idx = 0;
12142 }
12143 LEAVE();
12144 return chan;
12145 }
12146
12147 /**
12148 * @brief Process auto dfs cac
12149 *
12150 * @param priv a pointer to moal_private structure
12151 *
12152 * @return N/A
12153 *
12154 */
woal_do_auto_dfs(moal_private * priv)12155 static void woal_do_auto_dfs(moal_private *priv)
12156 {
12157 mlan_ds_11h_chan_rep_req chan_rpt_req;
12158 ENTER();
12159 if (priv->auto_dfs_cfg.multi_chan_dfs &&
12160 priv->auto_dfs_cfg.num_of_chan) {
12161 memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12162 chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12163 chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
12164 if (priv->chan_rpt_req.chanNum) {
12165 if (woal_11h_cancel_chan_report_ioctl(priv,
12166 MOAL_IOCTL_WAIT))
12167 PRINTM(MERROR,
12168 "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12169 __func__);
12170 memset(&priv->chan_rpt_req, 0,
12171 sizeof(mlan_ds_11h_chan_rep_req));
12172 }
12173 if (chan_rpt_req.chanNum) {
12174 chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12175 chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12176 chan_rpt_req.millisec_dwell_time =
12177 priv->auto_dfs_cfg.cac_timer;
12178 moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12179 &chan_rpt_req,
12180 sizeof(mlan_ds_11h_chan_rep_req),
12181 sizeof(mlan_ds_11h_chan_rep_req));
12182 PRINTM(MCMND,
12183 "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12184 chan_rpt_req.chanNum,
12185 (int)(chan_rpt_req.bandcfg.chanWidth),
12186 chan_rpt_req.millisec_dwell_time);
12187 if (MLAN_STATUS_SUCCESS !=
12188 woal_do_dfs_cac(priv, &chan_rpt_req))
12189 PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12190 __func__);
12191 }
12192 }
12193 LEAVE();
12194 return;
12195 }
12196
12197 /*
12198 * @brief prepare and send WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12199 *
12200 * @param priv A pointer moal_private structure
12201 * @param type WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12202 * @param channel channel
12203 * @param radar MTRUE/MFALSE
12204 *
12205 * @return N/A
12206 */
woal_chan_event(moal_private * priv,t_u8 type,t_u8 channel,t_u8 radar)12207 void woal_chan_event(moal_private *priv, t_u8 type, t_u8 channel, t_u8 radar)
12208 {
12209 struct woal_event *evt;
12210 unsigned long flags;
12211 moal_handle *handle = priv->phandle;
12212
12213 evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
12214 if (!evt) {
12215 PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
12216 LEAVE();
12217 return;
12218 }
12219 evt->priv = priv;
12220 evt->type = type;
12221 evt->radar_info.channel = channel;
12222 evt->radar_info.radar = radar;
12223 INIT_LIST_HEAD(&evt->link);
12224 spin_lock_irqsave(&handle->evt_lock, flags);
12225 list_add_tail(&evt->link, &handle->evt_queue);
12226 spin_unlock_irqrestore(&handle->evt_lock, flags);
12227 queue_work(handle->evt_workqueue, &handle->evt_work);
12228 }
12229
12230 /**
12231 * @brief Get active UAP handler
12232 *
12233 * @param handle a pointer to moal_handle structure
12234 *
12235 * @return N/A
12236 *
12237 */
woal_get_active_uap_interface(moal_handle * handle)12238 static moal_private *woal_get_active_uap_interface(moal_handle *handle)
12239 {
12240 int i;
12241 moal_private *priv = NULL;
12242 for (i = 0; i < handle->priv_num; i++) {
12243 if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
12244 if (handle->priv[i]->bss_started == MTRUE) {
12245 priv = handle->priv[i];
12246 break;
12247 }
12248 }
12249 }
12250 return priv;
12251 }
12252
12253 /**
12254 * @brief handle auto uap channel switch
12255 *
12256 * @param priv a pointer to moal_private structure
12257 * @param channel channel
12258 *
12259 * @return N/A
12260 *
12261 */
woal_auto_uap_channel_switch(moal_private * priv,t_u8 channel)12262 static void woal_auto_uap_channel_switch(moal_private *priv, t_u8 channel)
12263 {
12264 moal_private *pmpriv = NULL;
12265 chan_band_info chaninfo;
12266 moal_handle *ref_handle;
12267 t_u8 band_width = CHANNEL_BW_20MHZ;
12268
12269 pmpriv = woal_get_active_uap_interface(priv->phandle);
12270 if (!pmpriv) {
12271 ref_handle = (moal_handle *)priv->phandle->pref_mac;
12272 pmpriv = woal_get_active_uap_interface(ref_handle);
12273 }
12274 if (pmpriv) {
12275 if (MLAN_STATUS_SUCCESS !=
12276 woal_set_get_ap_channel(pmpriv, MLAN_ACT_GET,
12277 MOAL_IOCTL_WAIT, &chaninfo)) {
12278 PRINTM(MERROR, "Fail to get ap channel \n");
12279 return;
12280 }
12281 if (chaninfo.channel != channel) {
12282 switch (chaninfo.bandcfg.chanWidth) {
12283 case CHAN_BW_40MHZ:
12284 if (chaninfo.bandcfg.chan2Offset ==
12285 SEC_CHAN_BELOW)
12286 band_width = CHANNEL_BW_40MHZ_BELOW;
12287 else if (chaninfo.bandcfg.chan2Offset ==
12288 SEC_CHAN_ABOVE)
12289 band_width = CHANNEL_BW_40MHZ_ABOVE;
12290 break;
12291 case CHAN_BW_80MHZ:
12292 band_width = CHANNEL_BW_80MHZ;
12293 break;
12294 default:
12295 band_width = CHANNEL_BW_20MHZ;
12296 break;
12297 }
12298 #define DEF_SWITCH_COUNT 10
12299 woal_channel_switch(pmpriv, MTRUE, 0, channel,
12300 DEF_SWITCH_COUNT, band_width,
12301 MTRUE);
12302 }
12303 }
12304 }
12305
12306 /**
12307 * @brief Process channel event
12308 *
12309 * @param priv a pointer to moal_private structure
12310 * @param type WOAL_EVENT_CHAN_RPT/WOAL_EVENT_RADAR
12311 * @param channel channel
12312 * @param radar radar
12313 *
12314 * @return N/A
12315 *
12316 */
woal_process_chan_event(moal_private * priv,t_u8 type,t_u8 channel,t_u8 radar)12317 void woal_process_chan_event(moal_private *priv, t_u8 type, t_u8 channel,
12318 t_u8 radar)
12319 {
12320 mlan_ds_11h_chan_rep_req chan_rpt_req;
12321
12322 if (!priv->auto_dfs_cfg.start_auto_zero_dfs)
12323 return;
12324 if (type == WOAL_EVENT_CHAN_RPT) {
12325 if (priv->auto_dfs_cfg.uap_chan_switch && !radar) {
12326 priv->auto_dfs_cfg.uap_chan_switch = MFALSE;
12327 PRINTM(MCMND, "Trying uap_chan_switch to %d\n",
12328 channel);
12329 woal_auto_uap_channel_switch(priv, channel);
12330 }
12331 woal_do_auto_dfs(priv);
12332 } else if (type == WOAL_EVENT_RADAR) {
12333 memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12334 chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12335 chan_rpt_req.chanNum = woal_get_next_dfs_chan(priv);
12336 if (priv->chan_rpt_req.chanNum) {
12337 if (woal_11h_cancel_chan_report_ioctl(priv,
12338 MOAL_IOCTL_WAIT))
12339 PRINTM(MERROR,
12340 "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12341 __func__);
12342 memset(&priv->chan_rpt_req, 0,
12343 sizeof(mlan_ds_11h_chan_rep_req));
12344 }
12345 if (chan_rpt_req.chanNum) {
12346 chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12347 chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12348 chan_rpt_req.millisec_dwell_time =
12349 priv->auto_dfs_cfg.cac_timer;
12350 moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12351 &chan_rpt_req,
12352 sizeof(mlan_ds_11h_chan_rep_req),
12353 sizeof(mlan_ds_11h_chan_rep_req));
12354 PRINTM(MCMND,
12355 "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12356 chan_rpt_req.chanNum,
12357 (int)(chan_rpt_req.bandcfg.chanWidth),
12358 chan_rpt_req.millisec_dwell_time);
12359 if (MLAN_STATUS_SUCCESS !=
12360 woal_do_dfs_cac(priv, &chan_rpt_req))
12361 PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12362 __func__);
12363 }
12364 }
12365 }
12366
12367 /**
12368 * @brief check if channel under nop
12369 *
12370 * @param priv a pointer to moal_private structure
12371 * @param channel WIFI channel
12372 *
12373 * @return length
12374 */
woal_is_channel_under_nop(moal_private * priv,t_u8 channel)12375 static t_u8 woal_is_channel_under_nop(moal_private *priv, t_u8 channel)
12376 {
12377 mlan_ds_11h_chan_nop_info chan_nop_info;
12378 t_u8 ret = MFALSE;
12379 ENTER();
12380 memset(&chan_nop_info, 0, sizeof(chan_nop_info));
12381 chan_nop_info.curr_chan = channel;
12382 woal_uap_get_channel_nop_info(priv, MOAL_IOCTL_WAIT, &chan_nop_info);
12383 if (chan_nop_info.chan_under_nop)
12384 ret = MTRUE;
12385 LEAVE();
12386 return ret;
12387 }
12388
12389 /**
12390 * @brief Process dfs cac command
12391 *
12392 * @param priv a pointer to moal_private structure
12393 * @param respbuf respbuf buffer
12394 * @param respbuflen respbuf length
12395 *
12396 * @return length
12397 */
woal_priv_do_dfs_cac(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12398 static int woal_priv_do_dfs_cac(moal_private *priv, t_u8 *respbuf,
12399 t_u32 respbuflen)
12400 {
12401 int ret = 0;
12402 int data[3] = {0};
12403 int user_data_len = 0, header_len = 0;
12404 mlan_ds_11h_chan_rep_req chan_rpt_req;
12405 mlan_status status = MLAN_STATUS_SUCCESS;
12406 mlan_ds_11h_chan_dfs_state ch_dfs_state;
12407
12408 ENTER();
12409
12410 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_CAC);
12411
12412 if ((int)strlen(respbuf) >= header_len) {
12413 memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12414 /* SET operation */
12415 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
12416 &user_data_len);
12417 if (user_data_len >= 1) {
12418 if (!data[0] ||
12419 (priv->chan_rpt_req.chanNum &&
12420 (priv->chan_rpt_req.chanNum != data[0]))) {
12421 if (priv->chan_rpt_pending ||
12422 (priv->bss_type == MLAN_BSS_TYPE_DFS)) {
12423 if (woal_11h_cancel_chan_report_ioctl(
12424 priv, MOAL_IOCTL_WAIT)) {
12425 PRINTM(MERROR,
12426 "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12427 __func__);
12428 LEAVE();
12429 return -EFAULT;
12430 }
12431 priv->chan_rpt_pending = MFALSE;
12432 }
12433 memset(&priv->chan_rpt_req, 0,
12434 sizeof(mlan_ds_11h_chan_rep_req));
12435 PRINTM(MCMND, "DFS: Stop Radar detect\n");
12436 if (!data[0]) {
12437 if (priv->bss_type == MLAN_BSS_TYPE_UAP)
12438 woal_uap_11h_ctrl(priv, MFALSE);
12439 LEAVE();
12440 return ret;
12441 }
12442 }
12443 if (data[0] == priv->chan_rpt_req.chanNum &&
12444 priv->bss_type == MLAN_BSS_TYPE_UAP)
12445 woal_uap_11h_ctrl(priv, MFALSE);
12446 memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12447 ch_dfs_state.channel = data[0];
12448 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12449 &ch_dfs_state)) {
12450 PRINTM(MERROR,
12451 "%s: woal_11h_chan_dfs_state failed \n",
12452 __func__);
12453 LEAVE();
12454 return -EFAULT;
12455 }
12456 if (!ch_dfs_state.dfs_required ||
12457 ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
12458 PRINTM(MCMND,
12459 "DFS: This channel=%d under NOP or not DFS channel\n",
12460 data[0]);
12461 LEAVE();
12462 return -EINVAL;
12463 }
12464 if (woal_is_channel_under_nop(priv, data[0])) {
12465 PRINTM(MCMND,
12466 "DFS: This channel=%d under NOP\n",
12467 data[0]);
12468 LEAVE();
12469 return -EINVAL;
12470 }
12471 chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12472 chan_rpt_req.chanNum = data[0];
12473 chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12474 chan_rpt_req.bandcfg.chanWidth = CHAN_BW_20MHZ;
12475 chan_rpt_req.millisec_dwell_time = DEF_CAC_DWELL_TIME;
12476 chan_rpt_req.host_based = MTRUE;
12477 }
12478 if (user_data_len >= 2) {
12479 if (data[1] < 0 || data[1] > CHANNEL_BW_80MHZ) {
12480 PRINTM(MERROR, "Inavalid bandwidth %d\n",
12481 data[1]);
12482 LEAVE();
12483 return -EINVAL;
12484 }
12485 woal_convert_chanbw_to_bandconfig(priv,
12486 &chan_rpt_req.bandcfg,
12487 chan_rpt_req.chanNum,
12488 data[1]);
12489 }
12490 if (user_data_len >= 3)
12491 chan_rpt_req.millisec_dwell_time =
12492 MIN(MAX_CAC_DWELL_TIME, data[2] * 1000);
12493 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
12494 else {
12495 if ((woal_is_etsi_country(
12496 priv->phandle->country_code) == MTRUE)) {
12497 if (chan_rpt_req.chanNum == 120 ||
12498 chan_rpt_req.chanNum == 124 ||
12499 chan_rpt_req.chanNum == 128) {
12500 chan_rpt_req.millisec_dwell_time =
12501 DEF_CAC_DWELL_TIME * 10;
12502 }
12503 if (chan_rpt_req.chanNum == 116 &&
12504 user_data_len >= 2 && data[1] > 0)
12505 chan_rpt_req.millisec_dwell_time =
12506 DEF_CAC_DWELL_TIME * 10;
12507 }
12508 }
12509 #endif
12510 moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12511 &chan_rpt_req, sizeof(mlan_ds_11h_chan_rep_req),
12512 sizeof(mlan_ds_11h_chan_rep_req));
12513 PRINTM(MCMND,
12514 "DFS: Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12515 chan_rpt_req.chanNum,
12516 (int)(chan_rpt_req.bandcfg.chanWidth),
12517 chan_rpt_req.millisec_dwell_time);
12518 status = woal_do_dfs_cac(priv, &chan_rpt_req);
12519 if (status != MLAN_STATUS_SUCCESS)
12520 ret = -EFAULT;
12521 else
12522 priv->chan_rpt_pending = MTRUE;
12523 }
12524 LEAVE();
12525 return ret;
12526 }
12527
12528 /**
12529 * @brief Set Auto Zero DFS configure
12530 *
12531 * @param priv Pointer to moal_private structure
12532 * @param respbuf Pointer to response buffer
12533 * @param resplen Response buffer length
12534 *
12535 * @return 0 --success, otherwise fail
12536 */
woal_priv_auto_dfs_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12537 static int woal_priv_auto_dfs_cfg(moal_private *priv, t_u8 *respbuf,
12538 t_u32 respbuflen)
12539 {
12540 int ret = 0;
12541 int header_len = 0;
12542 auto_zero_dfs_cfg *auto_dfs_cfg = NULL;
12543 int i;
12544 int idx = 0;
12545 mlan_ds_11h_chan_dfs_state ch_dfs_state;
12546 mlan_ds_11h_chan_rep_req chan_rpt_req;
12547
12548 ENTER();
12549 if (priv->bss_type != MLAN_BSS_TYPE_DFS) {
12550 PRINTM(MWARN, "Invalid BSS type\n");
12551 ret = -EINVAL;
12552 goto done;
12553 }
12554
12555 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTODFS);
12556 auto_dfs_cfg = (auto_zero_dfs_cfg *)(respbuf + header_len);
12557 /** Auto DFS is enabled and save config to moal_private structure */
12558 if (auto_dfs_cfg->start_auto_zero_dfs) {
12559 if (priv->auto_dfs_cfg.start_auto_zero_dfs ||
12560 priv->chan_rpt_req.chanNum) {
12561 if (woal_11h_cancel_chan_report_ioctl(
12562 priv, MOAL_IOCTL_WAIT)) {
12563 PRINTM(MERROR,
12564 "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12565 __func__);
12566 ret = -EFAULT;
12567 goto done;
12568 }
12569 memset(&priv->chan_rpt_req, 0,
12570 sizeof(mlan_ds_11h_chan_rep_req));
12571 }
12572 memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
12573 if (auto_dfs_cfg->cac_start_chan) {
12574 memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12575 ch_dfs_state.channel = auto_dfs_cfg->cac_start_chan;
12576 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12577 &ch_dfs_state)) {
12578 PRINTM(MERROR,
12579 "%s: woal_11h_chan_dfs_state failed \n",
12580 __func__);
12581 ret = -EFAULT;
12582 goto done;
12583 }
12584 if (!ch_dfs_state.dfs_required ||
12585 ch_dfs_state.dfs_state == DFS_UNAVAILABLE) {
12586 PRINTM(MCMND,
12587 "ZeroDFS: This channel=%d under NOP or not DFS channel\n",
12588 auto_dfs_cfg->cac_start_chan);
12589 LEAVE();
12590 return -EINVAL;
12591 }
12592 }
12593 priv->auto_dfs_cfg.cac_start_chan =
12594 auto_dfs_cfg->cac_start_chan;
12595 if (auto_dfs_cfg->cac_timer)
12596 priv->auto_dfs_cfg.cac_timer =
12597 MIN(MAX_CAC_DWELL_TIME,
12598 auto_dfs_cfg->cac_timer * 1000);
12599 else
12600 priv->auto_dfs_cfg.cac_timer = DEF_CAC_DWELL_TIME;
12601 if ((auto_dfs_cfg->bw != CHANNEL_BW_20MHZ) &&
12602 (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_ABOVE) &&
12603 (auto_dfs_cfg->bw != CHANNEL_BW_40MHZ_BELOW) &&
12604 (auto_dfs_cfg->bw != CHANNEL_BW_80MHZ)) {
12605 PRINTM(MERROR, "ZeroDFS: Invalid bw = %d\n",
12606 auto_dfs_cfg->bw);
12607 LEAVE();
12608 return -EINVAL;
12609 }
12610 priv->auto_dfs_cfg.bw = auto_dfs_cfg->bw;
12611 priv->auto_dfs_cfg.uap_chan_switch =
12612 auto_dfs_cfg->uap_chan_switch;
12613 priv->auto_dfs_cfg.multi_chan_dfs =
12614 auto_dfs_cfg->multi_chan_dfs;
12615 if (auto_dfs_cfg->num_of_chan) {
12616 for (i = 0; i < auto_dfs_cfg->num_of_chan; i++) {
12617 memset(&ch_dfs_state, 0, sizeof(ch_dfs_state));
12618 ch_dfs_state.channel =
12619 auto_dfs_cfg->dfs_chan_list[i];
12620 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET,
12621 &ch_dfs_state)) {
12622 PRINTM(MERROR,
12623 "%s: woal_11h_chan_dfs_state failed \n",
12624 __func__);
12625 ret = -EFAULT;
12626 goto done;
12627 }
12628 if (!ch_dfs_state.dfs_required)
12629 continue;
12630 priv->auto_dfs_cfg.dfs_chan_list[idx] =
12631 auto_dfs_cfg->dfs_chan_list[i];
12632 idx++;
12633 }
12634 priv->auto_dfs_cfg.num_of_chan = idx;
12635 }
12636 if (!priv->auto_dfs_cfg.num_of_chan)
12637 woal_get_dfs_chan_list(priv);
12638 priv->curr_cac_idx = -1;
12639 if (!priv->auto_dfs_cfg.cac_start_chan)
12640 priv->auto_dfs_cfg.cac_start_chan =
12641 woal_get_next_dfs_chan(priv);
12642 PRINTM(MCMND, "Start Auto ZeroDFS\n");
12643 PRINTM(MCMND, "cac_start_chan=%d\n",
12644 priv->auto_dfs_cfg.cac_start_chan);
12645 PRINTM(MCMND, "cac_timer=%d\n", priv->auto_dfs_cfg.cac_timer);
12646 PRINTM(MCMND, "bw=%d\n", priv->auto_dfs_cfg.bw);
12647 PRINTM(MCMND, "uap_chan_switch=%d\n",
12648 priv->auto_dfs_cfg.uap_chan_switch);
12649 PRINTM(MCMND, "multi_chan_dfs=%d\n",
12650 priv->auto_dfs_cfg.multi_chan_dfs);
12651 PRINTM(MCMND, "num of chan=%d\n",
12652 priv->auto_dfs_cfg.num_of_chan);
12653 DBG_HEXDUMP(MCMD_D, "dfs chan list",
12654 priv->auto_dfs_cfg.dfs_chan_list,
12655 priv->auto_dfs_cfg.num_of_chan);
12656 if (priv->auto_dfs_cfg.cac_start_chan) {
12657 priv->auto_dfs_cfg.start_auto_zero_dfs = MTRUE;
12658 memset(&chan_rpt_req, 0, sizeof(chan_rpt_req));
12659 chan_rpt_req.startFreq = START_FREQ_11A_BAND;
12660 chan_rpt_req.chanNum =
12661 priv->auto_dfs_cfg.cac_start_chan;
12662 chan_rpt_req.bandcfg.chanBand = BAND_5GHZ;
12663 chan_rpt_req.bandcfg.chanWidth = priv->auto_dfs_cfg.bw;
12664 chan_rpt_req.millisec_dwell_time =
12665 priv->auto_dfs_cfg.cac_timer;
12666 moal_memcpy_ext(priv->phandle, &priv->chan_rpt_req,
12667 &chan_rpt_req,
12668 sizeof(mlan_ds_11h_chan_rep_req),
12669 sizeof(mlan_ds_11h_chan_rep_req));
12670 PRINTM(MCMND,
12671 "ZeroDFS: AUTO DFS Start Radar detect on channel=%d, bandwidth=%d, cac time=%d\n",
12672 chan_rpt_req.chanNum,
12673 (int)(chan_rpt_req.bandcfg.chanWidth),
12674 chan_rpt_req.millisec_dwell_time);
12675 if (MLAN_STATUS_SUCCESS !=
12676 woal_do_dfs_cac(priv, &chan_rpt_req)) {
12677 PRINTM(MERROR, "%s: woal_do_dfs_cac failed \n",
12678 __func__);
12679 ret = -EFAULT;
12680 }
12681 }
12682 } else {
12683 PRINTM(MCMND, "Stop Auto ZeroDFS\n");
12684 if (woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT))
12685 PRINTM(MERROR,
12686 "%s: woal_11h_cancel_chan_report_ioctl failed \n",
12687 __func__);
12688 memset(&priv->chan_rpt_req, 0,
12689 sizeof(mlan_ds_11h_chan_rep_req));
12690 memset(&priv->auto_dfs_cfg, 0, sizeof(auto_zero_dfs_cfg));
12691 }
12692 done:
12693 LEAVE();
12694 return ret;
12695 }
12696 #endif
12697
12698 /**
12699 * @brief Set/Get CFP table codes
12700 *
12701 * @param priv Pointer to moal_private structure
12702 * @param respbuf Pointer to response buffer
12703 * @param resplen Response buffer length
12704 *
12705 * @return Number of bytes written, negative for failure.
12706 */
woal_priv_cfp_code(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12707 static int woal_priv_cfp_code(moal_private *priv, t_u8 *respbuf,
12708 t_u32 respbuflen)
12709 {
12710 int ret = 0;
12711 int user_data_len = 0, header_len = 0;
12712 int data[2] = {0};
12713 mlan_ioctl_req *req = NULL;
12714 mlan_ds_misc_cfg *misc_cfg = NULL;
12715 mlan_ds_misc_cfp_code *cfp_code = NULL;
12716 mlan_status status = MLAN_STATUS_SUCCESS;
12717
12718 ENTER();
12719
12720 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFP_CODE);
12721
12722 /* Allocate an IOCTL request buffer */
12723 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12724 if (req == NULL) {
12725 ret = -ENOMEM;
12726 goto done;
12727 }
12728
12729 /* Fill request buffer */
12730 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
12731 cfp_code = &misc_cfg->param.cfp_code;
12732 misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE;
12733 req->req_id = MLAN_IOCTL_MISC_CFG;
12734
12735 if ((int)strlen(respbuf) == header_len) {
12736 /* GET operation */
12737 user_data_len = 0;
12738 req->action = MLAN_ACT_GET;
12739 } else {
12740 /* SET operation */
12741 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
12742 &user_data_len);
12743 if (user_data_len > 2) {
12744 PRINTM(MERROR, "Invalid number of args!\n");
12745 ret = -EINVAL;
12746 goto done;
12747 }
12748 cfp_code->cfp_code_bg = data[0];
12749 if (user_data_len == 2)
12750 cfp_code->cfp_code_a = data[1];
12751 req->action = MLAN_ACT_SET;
12752 }
12753
12754 /* Send IOCTL request to MLAN */
12755 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
12756 if (status != MLAN_STATUS_SUCCESS) {
12757 ret = -EFAULT;
12758 goto done;
12759 }
12760
12761 if (!user_data_len) {
12762 data[0] = cfp_code->cfp_code_bg;
12763 data[1] = cfp_code->cfp_code_a;
12764 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
12765 sizeof(data), respbuflen);
12766 ret = sizeof(data);
12767 }
12768
12769 done:
12770 if (status != MLAN_STATUS_PENDING)
12771 kfree(req);
12772
12773 LEAVE();
12774 return ret;
12775 }
12776
12777 /**
12778 * @brief mcast aggr group configure
12779 *
12780 * @param priv Pointer to moal_private structure
12781 * @param respbuf Pointer to response buffer
12782 * @param resplen Response buffer length
12783 *
12784 * @return 0 --success, otherwise fail
12785 */
woal_priv_mcast_aggr_group_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12786 static int woal_priv_mcast_aggr_group_cfg(moal_private *priv, t_u8 *respbuf,
12787 t_u32 respbuflen)
12788 {
12789 int ret = 0;
12790 int header_len = 0;
12791 mcast_aggr_group *mcast_cfg = NULL;
12792 int index = 0;
12793 struct mcast_node *node = NULL;
12794 unsigned long flags;
12795
12796 ENTER();
12797
12798 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MCAST_AGGR_GROUP);
12799 mcast_cfg = (mcast_aggr_group *)(respbuf + header_len);
12800 if (mcast_cfg->action == ACTION_ADD) {
12801 if (priv->num_mcast_addr >= MLAN_MAX_MULTICAST_LIST_SIZE) {
12802 PRINTM(MERROR, "mcast_aggr_group already full!\n");
12803 ret = -EINVAL;
12804 goto done;
12805 }
12806 woal_add_mcast_node(priv, mcast_cfg->mcast_addr);
12807 } else if (mcast_cfg->action == ACTION_REMOVE) {
12808 woal_remove_mcast_node(priv, mcast_cfg->mcast_addr);
12809 }
12810 memset(mcast_cfg, 0, sizeof(mcast_aggr_group));
12811
12812 spin_lock_irqsave(&priv->mcast_lock, flags);
12813 list_for_each_entry (node, &priv->mcast_list, link) {
12814 moal_memcpy_ext(priv->phandle, &mcast_cfg->mac_list[index],
12815 node->mcast_addr, ETH_ALEN, ETH_ALEN);
12816 index++;
12817 }
12818 spin_unlock_irqrestore(&priv->mcast_lock, flags);
12819 mcast_cfg->num_mcast_addr = index;
12820 priv->num_mcast_addr = index;
12821 ret = header_len + sizeof(mcast_aggr_group);
12822 done:
12823 LEAVE();
12824 return ret;
12825 }
12826
12827 /**
12828 * @brief mcast aggr configure
12829 *
12830 * @param priv Pointer to moal_private structure
12831 * @param respbuf Pointer to response buffer
12832 * @param resplen Response buffer length
12833 *
12834 * @return 0 --success, otherwise fail
12835 */
woal_priv_mc_aggr_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12836 static int woal_priv_mc_aggr_cfg(moal_private *priv, t_u8 *respbuf,
12837 t_u32 respbuflen)
12838 {
12839 mlan_ioctl_req *ioctl_req = NULL;
12840 mlan_ds_misc_cfg *misc = NULL;
12841 mlan_status status = MLAN_STATUS_SUCCESS;
12842 mlan_ds_mc_aggr_cfg *mc_cfg;
12843 int ret = 0;
12844 int header_len = 0;
12845
12846 ENTER();
12847
12848 if (!priv || !priv->phandle) {
12849 PRINTM(MERROR, "priv or handle is null\n");
12850 ret = -EFAULT;
12851 goto done;
12852 }
12853
12854 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12855 if (ioctl_req == NULL) {
12856 ret = -ENOMEM;
12857 goto done;
12858 }
12859
12860 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12861 misc->sub_command = MLAN_OID_MISC_MC_AGGR_CFG;
12862 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12863
12864 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MC_AGGR_CFG);
12865 mc_cfg = (mlan_ds_mc_aggr_cfg *)(respbuf + header_len);
12866 ioctl_req->action = mc_cfg->action;
12867 misc->param.mc_aggr_cfg.enable_bitmap = mc_cfg->enable_bitmap;
12868 misc->param.mc_aggr_cfg.mask_bitmap = mc_cfg->mask_bitmap;
12869 misc->param.mc_aggr_cfg.cts2self_offset = mc_cfg->cts2self_offset;
12870
12871 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12872 if (status != MLAN_STATUS_SUCCESS) {
12873 ret = -EFAULT;
12874 goto done;
12875 }
12876
12877 mc_cfg->enable_bitmap = misc->param.mc_aggr_cfg.enable_bitmap;
12878 mc_cfg->mask_bitmap = misc->param.mc_aggr_cfg.mask_bitmap;
12879 mc_cfg->cts2self_offset = misc->param.mc_aggr_cfg.cts2self_offset;
12880 ret = header_len + sizeof(misc->param.mc_aggr_cfg);
12881
12882 if (mc_cfg->mask_bitmap & MC_AGGR_CTRL) {
12883 if (mc_cfg->enable_bitmap & MC_AGGR_CTRL)
12884 priv->enable_mc_aggr = MTRUE;
12885 else
12886 priv->enable_mc_aggr = MFALSE;
12887 }
12888 done:
12889 if (status != MLAN_STATUS_PENDING)
12890 kfree(ioctl_req);
12891
12892 LEAVE();
12893 return ret;
12894 }
12895
12896 /**
12897 * @brief per peer stats configure
12898 *
12899 * @param priv Pointer to moal_private structure
12900 * @param respbuf Pointer to response buffer
12901 * @param resplen Response buffer length
12902 *
12903 * @return 0 --success, otherwise fail
12904 */
woal_priv_stats(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12905 static int woal_priv_stats(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
12906 {
12907 mlan_ioctl_req *ioctl_req = NULL;
12908 mlan_ds_misc_cfg *misc = NULL;
12909 mlan_ds_stats *stats;
12910 mlan_status status = MLAN_STATUS_SUCCESS;
12911 int ret = 0;
12912 int header_len = 0;
12913
12914 ENTER();
12915
12916 if (!priv || !priv->phandle) {
12917 PRINTM(MERROR, "priv or handle is null\n");
12918 ret = -EFAULT;
12919 goto done;
12920 }
12921
12922 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12923 if (ioctl_req == NULL) {
12924 ret = -ENOMEM;
12925 goto done;
12926 }
12927
12928 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12929 misc->sub_command = MLAN_OID_MISC_STATS;
12930 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12931
12932 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_STATS);
12933 stats = (mlan_ds_stats *)(respbuf + header_len);
12934 ioctl_req->action = stats->action;
12935
12936 moal_memcpy_ext(priv->phandle, &misc->param.stats, stats,
12937 sizeof(mlan_ds_stats) + stats->tlv_len - 1,
12938 sizeof(mlan_ds_stats) + stats->tlv_len - 1);
12939
12940 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12941 if (status != MLAN_STATUS_SUCCESS) {
12942 ret = -EFAULT;
12943 goto done;
12944 }
12945
12946 moal_memcpy_ext(priv->phandle, respbuf + header_len,
12947 (mlan_ds_stats *)&misc->param.stats, ioctl_req->buf_len,
12948 respbuflen - header_len);
12949 ret = header_len + ioctl_req->buf_len;
12950
12951 done:
12952 LEAVE();
12953 return ret;
12954 }
12955 /**
12956 * @brief get channel load results
12957 *
12958 * @param priv Pointer to moal_private structure
12959 * @param respbuf Pointer to response buffer
12960 * @param resplen Response buffer length
12961 *
12962 * @return 0 --success, otherwise fail
12963 */
woal_priv_get_ch_load_results(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)12964 static int woal_priv_get_ch_load_results(moal_private *priv, t_u8 *respbuf,
12965 t_u32 respbuflen)
12966 {
12967 mlan_ioctl_req *ioctl_req = NULL;
12968 mlan_ds_misc_cfg *misc = NULL;
12969 mlan_status status = MLAN_STATUS_SUCCESS;
12970 mlan_ds_ch_load *cl_cfg;
12971 int ret = 0;
12972 int header_len = 0;
12973
12974 ENTER();
12975
12976 if (!priv || !priv->phandle) {
12977 PRINTM(MERROR, "priv or handle is null\n");
12978 ret = -EFAULT;
12979 goto done;
12980 }
12981
12982 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
12983 if (ioctl_req == NULL) {
12984 ret = -ENOMEM;
12985 goto done;
12986 }
12987
12988 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
12989 misc->sub_command = MLAN_OID_MISC_CH_LOAD_RESULTS;
12990 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
12991
12992 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD_RESULTS);
12993 cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
12994 ioctl_req->action = cl_cfg->action;
12995 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
12996 if (status != MLAN_STATUS_SUCCESS) {
12997 ret = -EAGAIN;
12998 goto done;
12999 }
13000
13001 cl_cfg->ch_load_param = misc->param.ch_load.ch_load_param;
13002 cl_cfg->noise = misc->param.ch_load.noise;
13003 cl_cfg->rx_quality = misc->param.ch_load.rx_quality;
13004 ret = header_len + sizeof(misc->param.ch_load);
13005
13006 done:
13007 if (status != MLAN_STATUS_PENDING)
13008 kfree(ioctl_req);
13009
13010 LEAVE();
13011 return ret;
13012 }
13013
13014 /**
13015 * @brief get channel load
13016 *
13017 * @param priv Pointer to moal_private structure
13018 * @param respbuf Pointer to response buffer
13019 * @param resplen Response buffer length
13020 *
13021 * @return 0 --success, otherwise fail
13022 */
woal_priv_get_ch_load(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13023 static int woal_priv_get_ch_load(moal_private *priv, t_u8 *respbuf,
13024 t_u32 respbuflen)
13025 {
13026 mlan_ioctl_req *ioctl_req = NULL;
13027 mlan_ds_misc_cfg *misc = NULL;
13028 mlan_status status = MLAN_STATUS_SUCCESS;
13029 mlan_ds_ch_load *cl_cfg;
13030 int ret = 0;
13031 int header_len = 0;
13032
13033 ENTER();
13034
13035 if (!priv || !priv->phandle) {
13036 PRINTM(MERROR, "priv or handle is null\n");
13037 ret = -EFAULT;
13038 goto done;
13039 }
13040
13041 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13042 if (ioctl_req == NULL) {
13043 ret = -ENOMEM;
13044 goto done;
13045 }
13046
13047 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
13048 misc->sub_command = MLAN_OID_MISC_CH_LOAD;
13049 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
13050
13051 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CH_LOAD);
13052 cl_cfg = (mlan_ds_ch_load *)(respbuf + header_len);
13053 ioctl_req->action = cl_cfg->action;
13054 misc->param.ch_load.ch_load_param = cl_cfg->ch_load_param;
13055 misc->param.ch_load.noise = cl_cfg->noise;
13056 misc->param.ch_load.rx_quality = cl_cfg->rx_quality;
13057 misc->param.ch_load.duration = cl_cfg->duration;
13058 status = woal_request_ioctl(priv, ioctl_req, MOAL_NO_WAIT);
13059 if (status != MLAN_STATUS_SUCCESS && status != MLAN_STATUS_PENDING) {
13060 ret = -EFAULT;
13061 goto done;
13062 }
13063
13064 ret = header_len + sizeof(misc->param.ch_load);
13065
13066 done:
13067 if (status != MLAN_STATUS_PENDING)
13068 kfree(ioctl_req);
13069
13070 LEAVE();
13071 return ret;
13072 }
13073
13074 /**
13075 * @brief Set/Get Tx/Rx antenna
13076 *
13077 * @param priv Pointer to moal_private structure
13078 * @param respbuf Pointer to response buffer
13079 * @param resplen Response buffer length
13080 *
13081 * @return Number of bytes written, negative for failure.
13082 */
woal_priv_set_get_tx_rx_ant(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13083 static int woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf,
13084 t_u32 respbuflen)
13085 {
13086 int ret = 0;
13087 int user_data_len = 0, header_len = 0;
13088 mlan_ds_radio_cfg *radio = NULL;
13089 mlan_ioctl_req *req = NULL;
13090 int data[3] = {0};
13091 mlan_status status = MLAN_STATUS_SUCCESS;
13092
13093 ENTER();
13094
13095 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ANT_CFG);
13096 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
13097 if (req == NULL) {
13098 ret = -ENOMEM;
13099 goto done;
13100 }
13101 radio = (mlan_ds_radio_cfg *)req->pbuf;
13102 radio->sub_command = MLAN_OID_ANT_CFG;
13103 req->req_id = MLAN_IOCTL_RADIO_CFG;
13104
13105 if ((int)strlen(respbuf) == header_len) {
13106 /* GET operation */
13107 user_data_len = 0;
13108 req->action = MLAN_ACT_GET;
13109 } else {
13110 /* SET operation */
13111 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13112 &user_data_len);
13113 if (user_data_len > 2) {
13114 PRINTM(MERROR, "Invalid number of args!\n");
13115 ret = -EINVAL;
13116 goto done;
13117 }
13118 if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
13119 radio->param.ant_cfg.tx_antenna = data[0];
13120 radio->param.ant_cfg.rx_antenna = data[0];
13121 if (user_data_len == 2)
13122 radio->param.ant_cfg.rx_antenna = data[1];
13123 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
13124 if (IS_CARD9098(priv->phandle->card_type) ||
13125 IS_CARD9097(priv->phandle->card_type)) {
13126 woal_cfg80211_notify_antcfg(
13127 priv, priv->phandle->wiphy, radio);
13128 }
13129 #endif
13130 } else {
13131 radio->param.ant_cfg_1x1.antenna = data[0];
13132 if (user_data_len == 2)
13133 radio->param.ant_cfg_1x1.evaluate_time =
13134 data[1];
13135 }
13136 req->action = MLAN_ACT_SET;
13137 }
13138 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13139 if (status != MLAN_STATUS_SUCCESS) {
13140 ret = -EFAULT;
13141 goto done;
13142 }
13143 if (!user_data_len) {
13144 if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) {
13145 data[0] = radio->param.ant_cfg.tx_antenna;
13146 data[1] = radio->param.ant_cfg.rx_antenna;
13147 if (data[0] && data[1])
13148 ret = sizeof(int) * 2;
13149 else
13150 ret = sizeof(int) * 1;
13151 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
13152 sizeof(data), respbuflen);
13153 } else {
13154 data[0] = (int)radio->param.ant_cfg_1x1.antenna;
13155 data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time;
13156 data[2] = (int)radio->param.ant_cfg_1x1.current_antenna;
13157 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
13158 sizeof(data), respbuflen);
13159 ret = sizeof(data);
13160 }
13161 }
13162 done:
13163 if (status != MLAN_STATUS_PENDING)
13164 kfree(req);
13165 LEAVE();
13166 return ret;
13167 }
13168
13169 /*
13170 * @brief Set/Get CWMode
13171 *
13172 * @param priv Pointer to moal_private structure
13173 * @param respbuf Pointer to response buffer
13174 * @param resplen Response buffer length
13175 *
13176 * @return Number of bytes written, negative for failure.
13177 */
woal_priv_set_get_cwmode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13178 static int woal_priv_set_get_cwmode(moal_private *priv, t_u8 *respbuf,
13179 t_u32 respbuflen)
13180 {
13181 mlan_ioctl_req *ioctl_req = NULL;
13182 mlan_ds_misc_cfg *misc = NULL;
13183 mlan_status status = MLAN_STATUS_SUCCESS;
13184 mlan_ds_cw_mode_ctrl *cwmode;
13185 int ret = 0;
13186 int header_len = 0;
13187
13188 ENTER();
13189
13190 if (!priv || !priv->phandle) {
13191 PRINTM(MERROR, "priv or handle is null\n");
13192 ret = -EFAULT;
13193 goto done;
13194 }
13195
13196 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13197 if (ioctl_req == NULL) {
13198 ret = -ENOMEM;
13199 goto done;
13200 }
13201
13202 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
13203 misc->sub_command = MLAN_OID_MISC_CWMODE_CTRL;
13204 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
13205
13206 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CWMODE);
13207 if ((int)strlen(respbuf) == header_len) {
13208 /* GET operation */
13209 ioctl_req->action = MLAN_ACT_GET;
13210 } else {
13211 /* SET operation */
13212 ioctl_req->action = MLAN_ACT_SET;
13213
13214 cwmode = (mlan_ds_cw_mode_ctrl *)(respbuf + header_len +
13215 sizeof(t_u8));
13216 misc->param.cwmode.mode = cwmode->mode;
13217 misc->param.cwmode.txPower = cwmode->txPower;
13218 misc->param.cwmode.rateInfo = cwmode->rateInfo;
13219 misc->param.cwmode.channel = cwmode->channel;
13220 misc->param.cwmode.chanInfo = cwmode->chanInfo;
13221 misc->param.cwmode.pktLength = cwmode->pktLength;
13222 }
13223
13224 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
13225 if (status != MLAN_STATUS_SUCCESS) {
13226 ret = -EFAULT;
13227 goto done;
13228 }
13229
13230 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.cwmode,
13231 sizeof(misc->param.cwmode), respbuflen);
13232 ret = sizeof(misc->param.cwmode);
13233
13234 done:
13235 if (status != MLAN_STATUS_PENDING)
13236 kfree(ioctl_req);
13237
13238 LEAVE();
13239 return ret;
13240 }
13241
13242 /**
13243 * @brief Set/Get out band independent reset
13244 *
13245 * @param priv Pointer to moal_private structure
13246 * @param respbuf Pointer to response buffer
13247 * @param resplen Response buffer length
13248 *
13249 * @return Number of bytes written, negative for failure.
13250 */
woal_priv_ind_rst_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13251 static int woal_priv_ind_rst_cfg(moal_private *priv, t_u8 *respbuf,
13252 t_u32 respbuflen)
13253 {
13254 int ret = 0;
13255 int user_data_len = 0, header_len = 0;
13256 mlan_ds_misc_cfg *misc = NULL;
13257 mlan_ioctl_req *req = NULL;
13258 int data[2] = {0};
13259 mlan_status status = MLAN_STATUS_SUCCESS;
13260
13261 ENTER();
13262
13263 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_IND_RST_CFG);
13264 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13265 if (req == NULL) {
13266 ret = -ENOMEM;
13267 goto done;
13268 }
13269 misc = (mlan_ds_misc_cfg *)req->pbuf;
13270 memset(misc, 0, sizeof(mlan_ds_misc_cfg));
13271 misc->sub_command = MLAN_OID_MISC_IND_RST_CFG;
13272 req->req_id = MLAN_IOCTL_MISC_CFG;
13273
13274 if ((int)strlen(respbuf) == header_len) {
13275 /* GET operation */
13276 user_data_len = 0;
13277 req->action = MLAN_ACT_GET;
13278 } else {
13279 /* SET operation */
13280 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13281 &user_data_len);
13282 if (user_data_len > 2) {
13283 PRINTM(MERROR, "Invalid number of args!\n");
13284 ret = -EINVAL;
13285 goto done;
13286 }
13287
13288 if ((user_data_len == 1) || (user_data_len == 2)) {
13289 req->action = MLAN_ACT_SET;
13290
13291 /* ir_mode */
13292 if (data[0] < 0 || data[0] > 2) {
13293 PRINTM(MERROR, "Invalid ir mode parameter!\n");
13294 ret = -EINVAL;
13295 goto done;
13296 }
13297 misc->param.ind_rst_cfg.ir_mode = data[0];
13298
13299 /* gpio_pin */
13300 if (user_data_len == 2) {
13301 if ((data[1] != 0xFF) && (data[1] < 0)) {
13302 PRINTM(MERROR,
13303 "Invalid gpio pin no!\n");
13304 ret = -EINVAL;
13305 goto done;
13306 }
13307 misc->param.ind_rst_cfg.gpio_pin = data[1];
13308 }
13309 }
13310 }
13311 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13312 if (status != MLAN_STATUS_SUCCESS) {
13313 ret = -EFAULT;
13314 goto done;
13315 }
13316
13317 data[0] = (int)misc->param.ind_rst_cfg.ir_mode;
13318 data[1] = (int)misc->param.ind_rst_cfg.gpio_pin;
13319 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
13320 respbuflen);
13321 ret = sizeof(data);
13322
13323 done:
13324 if (status != MLAN_STATUS_PENDING)
13325 kfree(req);
13326 LEAVE();
13327 return ret;
13328 }
13329
13330 /**
13331 * @brief Get/Set system clock
13332 * @param priv Pointer to moal_private structure
13333 * @param respbuf Pointer to response buffer
13334 * @param resplen Response buffer length
13335 *
13336 * @return Number of bytes written, negative for failure.
13337 */
woal_priv_sysclock(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13338 static int woal_priv_sysclock(moal_private *priv, t_u8 *respbuf,
13339 t_u32 respbuflen)
13340 {
13341 int data[65];
13342 mlan_ioctl_req *req = NULL;
13343 mlan_ds_misc_cfg *cfg = NULL;
13344 int ret = 0, i = 0;
13345 int user_data_len = 0, header_len = 0;
13346 int data_length = 0, length_index = 0;
13347 mlan_status status = MLAN_STATUS_SUCCESS;
13348
13349 ENTER();
13350
13351 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SYSCLOCK);
13352 memset(data, 0, sizeof(data));
13353 if ((int)strlen(respbuf) == header_len) {
13354 /* GET operation */
13355 user_data_len = 0;
13356 } else {
13357 /* SET operation */
13358 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
13359 &user_data_len);
13360 }
13361
13362 if (user_data_len > MLAN_MAX_CLK_NUM) {
13363 PRINTM(MERROR, "Invalid number of parameters\n");
13364 ret = -EINVAL;
13365 goto done;
13366 }
13367 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
13368 if (req == NULL) {
13369 ret = -ENOMEM;
13370 goto done;
13371 }
13372
13373 cfg = (mlan_ds_misc_cfg *)req->pbuf;
13374 cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK;
13375 req->req_id = MLAN_IOCTL_MISC_CFG;
13376
13377 if (user_data_len) {
13378 /* SET operation */
13379 req->action = MLAN_ACT_SET;
13380
13381 /* Set configurable clocks */
13382 cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
13383 cfg->param.sys_clock.sys_clk_num =
13384 MIN(MLAN_MAX_CLK_NUM, user_data_len);
13385 for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++)
13386 cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i];
13387
13388 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13389 if (status != MLAN_STATUS_SUCCESS) {
13390 ret = -EFAULT;
13391 goto done;
13392 }
13393 } else {
13394 /* GET operation */
13395 req->action = MLAN_ACT_GET;
13396
13397 /* Get configurable clocks */
13398 cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE;
13399 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13400 if (status != MLAN_STATUS_SUCCESS) {
13401 ret = -EFAULT;
13402 goto done;
13403 }
13404
13405 /* Current system clock */
13406 data[1] = (int)cfg->param.sys_clock.cur_sys_clk;
13407 data_length = 1;
13408
13409 length_index =
13410 MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
13411
13412 /* Configurable clocks */
13413 for (i = 1; i <= length_index; i++)
13414 data[i + data_length] =
13415 (int)cfg->param.sys_clock.sys_clk[i - 1];
13416
13417 data_length += length_index;
13418
13419 /* Get supported clocks */
13420 cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED;
13421 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13422 if (status != MLAN_STATUS_SUCCESS) {
13423 ret = -EFAULT;
13424 goto done;
13425 }
13426
13427 length_index =
13428 MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM);
13429
13430 /* Supported clocks */
13431 for (i = 1; i <= length_index; i++)
13432 data[i + data_length] =
13433 (int)cfg->param.sys_clock.sys_clk[i - 1];
13434
13435 data_length += length_index;
13436
13437 /* Send length as first element */
13438 data[0] = data_length;
13439 data_length++;
13440
13441 moal_memcpy_ext(priv->phandle, respbuf, data,
13442 sizeof(int) * data_length, respbuflen);
13443 ret = data_length * sizeof(int);
13444 }
13445
13446 done:
13447 if (status != MLAN_STATUS_PENDING)
13448 kfree(req);
13449 LEAVE();
13450 return ret;
13451 }
13452
13453 /**
13454 * @brief Get GTK/PTK
13455 * @param priv Pointer to moal_private structure
13456 * @param respbuf Pointer to response buffer
13457 * @param resplen Response buffer length
13458 *
13459 * @return Number of bytes written, negative for failure.
13460 */
woal_priv_get_key(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13461 static int woal_priv_get_key(moal_private *priv, t_u8 *respbuf,
13462 t_u32 respbuflen)
13463 {
13464 int ret = 0, copy_len = 0;
13465 int header_len = 0;
13466 unsigned int i;
13467 t_u8 key_ascii[256];
13468 t_u8 *tmp;
13469 mlan_ds_sec_cfg *sec = NULL;
13470 mlan_ioctl_req *req = NULL;
13471 mlan_status status = MLAN_STATUS_SUCCESS;
13472
13473 ENTER();
13474
13475 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_KEY);
13476 if ((int)strlen(respbuf) != header_len) {
13477 PRINTM(MERROR, "Invalid number of parameters\n");
13478 ret = -EINVAL;
13479 goto done;
13480 }
13481 memset(key_ascii, 0x00, sizeof(key_ascii));
13482 tmp = key_ascii;
13483
13484 if (priv->media_connected == MFALSE) {
13485 PRINTM(MERROR, "Can't get key in un-associated state\n");
13486 ret = -EFAULT;
13487 goto done;
13488 }
13489
13490 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
13491 if (req == NULL) {
13492 ret = -ENOMEM;
13493 goto done;
13494 }
13495
13496 /* Get Unicast Key */
13497 req->req_id = MLAN_IOCTL_SEC_CFG;
13498 req->action = MLAN_ACT_GET;
13499 sec = (mlan_ds_sec_cfg *)req->pbuf;
13500 sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13501 sec->param.encrypt_key.key_index = 0;
13502 sec->param.encrypt_key.key_flags = 0;
13503 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13504 if (status != MLAN_STATUS_SUCCESS) {
13505 ret = -EFAULT;
13506 goto done;
13507 }
13508 if (sec->param.encrypt_key.key_len) {
13509 sprintf((char *)tmp, "\n%s", "PTK: ");
13510 tmp += 5;
13511 for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13512 tmp += sprintf((char *)tmp, "%02x",
13513 sec->param.encrypt_key.key_material[i]);
13514 }
13515
13516 /* Get Multicase Key */
13517 req->req_id = MLAN_IOCTL_SEC_CFG;
13518 req->action = MLAN_ACT_GET;
13519 sec = (mlan_ds_sec_cfg *)req->pbuf;
13520 sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13521 sec->param.encrypt_key.key_index = 0;
13522 sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
13523 memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
13524 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13525 if (status != MLAN_STATUS_SUCCESS) {
13526 ret = -EFAULT;
13527 goto done;
13528 }
13529 if (sec->param.encrypt_key.key_len) {
13530 sprintf((char *)tmp, "\n%s", "GTK: ");
13531 tmp += 5;
13532 for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13533 tmp += sprintf((char *)tmp, "%02x",
13534 sec->param.encrypt_key.key_material[i]);
13535 }
13536
13537 /* Get IGTK Key */
13538 req->req_id = MLAN_IOCTL_SEC_CFG;
13539 req->action = MLAN_ACT_GET;
13540 sec = (mlan_ds_sec_cfg *)req->pbuf;
13541 sec->sub_command = MLAN_OID_SEC_QUERY_KEY;
13542 sec->param.encrypt_key.key_index = 0;
13543 sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK;
13544 memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH);
13545 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
13546 if (status != MLAN_STATUS_SUCCESS) {
13547 ret = -EFAULT;
13548 goto done;
13549 }
13550 if (sec->param.encrypt_key.key_len) {
13551 sprintf((char *)tmp, "\n%s", "IGTK: ");
13552 tmp += 6;
13553 for (i = 0; i < sec->param.encrypt_key.key_len; i++)
13554 tmp += sprintf((char *)tmp, "%02x",
13555 sec->param.encrypt_key.key_material[i]);
13556 }
13557
13558 copy_len = tmp - key_ascii;
13559 moal_memcpy_ext(priv->phandle, respbuf, &key_ascii, copy_len,
13560 respbuflen);
13561 ret = copy_len;
13562 done:
13563 if (status != MLAN_STATUS_PENDING)
13564 kfree(req);
13565
13566 LEAVE();
13567 return ret;
13568 }
13569
13570 /**
13571 * @brief Associate to a specific indexed entry in the ScanTable
13572 * @param priv Pointer to moal_private structure
13573 * @param respbuf Pointer to response buffer
13574 * @param resplen Response buffer length
13575 *
13576 * @return Number of bytes written, negative for failure.
13577 */
woal_priv_associate_ssid_bssid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13578 static int woal_priv_associate_ssid_bssid(moal_private *priv, t_u8 *respbuf,
13579 t_u32 respbuflen)
13580 {
13581 int ret = 0, copy_len = 0;
13582 int header_len = 0;
13583 mlan_ssid_bssid ssid_bssid;
13584 #ifdef REASSOCIATION
13585 mlan_bss_info bss_info;
13586 #endif
13587 char buf[64];
13588 t_u8 buflen;
13589 t_u8 mac_idx;
13590 t_u8 i;
13591
13592 ENTER();
13593
13594 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCIATE);
13595 if ((int)strlen(respbuf) == header_len) {
13596 PRINTM(MERROR, "Invalid number of parameters\n");
13597 ret = -EINVAL;
13598 goto done;
13599 }
13600 copy_len = strlen(respbuf) - header_len;
13601 mac_idx = 0;
13602 buflen = MIN(copy_len, (int)(sizeof(buf) - 1));
13603 memset(buf, 0, sizeof(buf));
13604 memset(&ssid_bssid, 0, sizeof(ssid_bssid));
13605
13606 if (buflen < (3 * ETH_ALEN) + 2) {
13607 PRINTM(MERROR,
13608 "Associate: Insufficient length in IOCTL input\n");
13609
13610 /* buffer should be at least 3 characters per BSSID octet "00:"
13611 ** plus a space separater and at least 1 char in the SSID
13612 */
13613 ret = -EINVAL;
13614 goto done;
13615 }
13616
13617 moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, buflen,
13618 sizeof(buf));
13619
13620 /* Skip white space */
13621 for (i = 0; (i < buflen) && (buf[i] == ' '); i++)
13622 ;
13623
13624 /* Copy/Convert the BSSID */
13625 for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) {
13626 if (buf[i] == ':') {
13627 mac_idx++;
13628 } else {
13629 ssid_bssid.bssid[mac_idx] = (t_u8)woal_atox(buf + i);
13630
13631 while (((i < buflen) && isxdigit(buf[i + 1])))
13632 /* Skip entire hex value */
13633 i++;
13634 }
13635 }
13636
13637 /* Skip one space between the BSSID and start of the SSID */
13638 i++;
13639
13640 /* Copy the SSID */
13641 ssid_bssid.ssid.ssid_len = buflen - i;
13642 moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i,
13643 sizeof(ssid_bssid.ssid.ssid),
13644 sizeof(ssid_bssid.ssid.ssid));
13645
13646 PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n",
13647 MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len,
13648 ssid_bssid.ssid.ssid);
13649
13650 if (MLAN_STATUS_SUCCESS !=
13651 woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
13652 ret = -EFAULT;
13653 goto done;
13654 }
13655
13656 #ifdef REASSOCIATION
13657 memset(&bss_info, 0x00, sizeof(bss_info));
13658 if (MLAN_STATUS_SUCCESS ==
13659 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
13660 moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid,
13661 &bss_info.ssid, sizeof(mlan_802_11_ssid),
13662 sizeof(mlan_802_11_ssid));
13663 moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid,
13664 &bss_info.bssid, MLAN_MAC_ADDR_LENGTH,
13665 sizeof(mlan_802_11_mac_addr));
13666 }
13667 #endif /* REASSOCIATION */
13668
13669 done:
13670 LEAVE();
13671 return ret;
13672 }
13673
13674 /* Maximum input output characters in group WOAL_SET_GET_256_CHAR */
13675 #define MAX_IN_OUT_CHAR 256
13676 /** Tx BF Global conf argument index */
13677 #define BF_ENABLE_PARAM 1
13678 #define SOUND_ENABLE_PARAM 2
13679 #define FB_TYPE_PARAM 3
13680 #define SNR_THRESHOLD_PARAM 4
13681 #define SOUND_INTVL_PARAM 5
13682 #define BF_MODE_PARAM 6
13683 #define BF_CFG_ACT_GET 0
13684 #define BF_CFG_ACT_SET 1
13685
13686 /**
13687 * @brief Set/Get Transmit beamforming configuration
13688 * @param priv Pointer to moal_private structure
13689 * @param respbuf Pointer to response buffer
13690 * @param resplen Response buffer length
13691 *
13692 * @return Number of bytes written, negative for failure.
13693 */
woal_priv_tx_bf_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13694 static int woal_priv_tx_bf_cfg(moal_private *priv, t_u8 *respbuf,
13695 t_u32 respbuflen)
13696 {
13697 int header_len = 0;
13698 int ret = 0, copy_len = 0;
13699 int bf_action = 0, interval = 0;
13700 int snr = 0, i, tmp_val = 0;
13701 t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0;
13702 t_u8 *str, *token, *pos;
13703 t_u16 action = 0;
13704
13705 mlan_ds_11n_tx_bf_cfg bf_cfg;
13706 mlan_trigger_sound_args *bf_sound = NULL;
13707 mlan_tx_bf_peer_args *tx_bf_peer = NULL;
13708 mlan_snr_thr_args *bf_snr = NULL;
13709 mlan_bf_periodicity_args *bf_periodicity = NULL;
13710 mlan_bf_global_cfg_args *bf_global = NULL;
13711
13712 ENTER();
13713
13714 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CFG);
13715 if ((int)strlen(respbuf) == header_len) {
13716 PRINTM(MERROR, "Invalid number of parameters\n");
13717 ret = -EINVAL;
13718 goto done;
13719 }
13720 memset(&bf_cfg, 0, sizeof(bf_cfg));
13721 /* Pointer to corresponding buffer */
13722 bf_sound = bf_cfg.body.bf_sound;
13723 tx_bf_peer = bf_cfg.body.tx_bf_peer;
13724 bf_snr = bf_cfg.body.bf_snr;
13725 bf_periodicity = bf_cfg.body.bf_periodicity;
13726 bf_global = &bf_cfg.body.bf_global_cfg;
13727
13728 /* Total characters in buffer */
13729 char_count = strlen(respbuf) - header_len;
13730 copy_len = char_count;
13731 memset(buf, 0, sizeof(buf));
13732 if (char_count) {
13733 if (copy_len > (int)sizeof(buf)) {
13734 PRINTM(MERROR, "Too many arguments\n");
13735 ret = -EINVAL;
13736 goto done;
13737 }
13738 moal_memcpy_ext(priv->phandle, buf, respbuf + header_len,
13739 copy_len, sizeof(buf));
13740
13741 if (char_count > 1 && buf[1] != ';') {
13742 PRINTM(MERROR,
13743 "No action argument. Separate with ';'\n");
13744 ret = -EINVAL;
13745 goto done;
13746 }
13747 /* Replace ';' with NULL in the string to separate args */
13748 for (i = 0; i < char_count; i++) {
13749 if (buf[i] == ';')
13750 buf[i] = '\0';
13751 }
13752 /* The first byte represents the beamforming action */
13753 if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) {
13754 ret = -EINVAL;
13755 goto done;
13756 }
13757 switch (bf_action) {
13758 case BF_GLOBAL_CONFIGURATION:
13759 if (char_count == 1) {
13760 action = MLAN_ACT_GET;
13761 bf_cfg.action = BF_CFG_ACT_GET;
13762 } else {
13763 action = MLAN_ACT_SET;
13764 bf_cfg.action = BF_CFG_ACT_SET;
13765 /* Eliminate action field */
13766 token = &buf[2];
13767 for (i = 1, str = &buf[2]; token != NULL; i++) {
13768 token = strstr(str, " ");
13769 pos = str;
13770 if (token != NULL) {
13771 *token = '\0';
13772 str = token + 1;
13773 }
13774 woal_atoi(&tmp_val, pos);
13775 switch (i) {
13776 case BF_ENABLE_PARAM:
13777 bf_global->bf_enbl =
13778 (t_u8)tmp_val;
13779 break;
13780 case SOUND_ENABLE_PARAM:
13781 bf_global->sounding_enbl =
13782 (t_u8)tmp_val;
13783 break;
13784 case FB_TYPE_PARAM:
13785 bf_global->fb_type =
13786 (t_u8)tmp_val;
13787 break;
13788 case SNR_THRESHOLD_PARAM:
13789 bf_global->snr_threshold =
13790 (t_u8)tmp_val;
13791 break;
13792 case SOUND_INTVL_PARAM:
13793 bf_global->sounding_interval =
13794 (t_u16)tmp_val;
13795 break;
13796 case BF_MODE_PARAM:
13797 bf_global->bf_mode =
13798 (t_u8)tmp_val;
13799 break;
13800 default:
13801 PRINTM(MERROR,
13802 "Invalid Argument\n");
13803 ret = -EINVAL;
13804 goto done;
13805 }
13806 }
13807 }
13808 break;
13809 case TRIGGER_SOUNDING_FOR_PEER:
13810 /* First arg = 2 BfAction
13811 * Second arg = 17 MAC "00:50:43:20:BF:64" */
13812 if (char_count != 19) {
13813 PRINTM(MERROR, "Invalid argument\n");
13814 ret = -EINVAL;
13815 goto done;
13816 }
13817 woal_mac2u8(bf_sound->peer_mac, &buf[2]);
13818 action = MLAN_ACT_SET;
13819 bf_cfg.action = BF_CFG_ACT_SET;
13820 break;
13821 case SET_GET_BF_PERIODICITY:
13822 /* First arg = 2 BfAction
13823 * Second arg = 18 MAC "00:50:43:20:BF:64;"
13824 * Third arg = 1 (min char) TX BF interval
13825 * 10 (max char) u32 maximum value
13826 * 4294967295 */
13827 if (char_count < 19 || char_count > 30) {
13828 PRINTM(MERROR, "Invalid argument\n");
13829 ret = -EINVAL;
13830 goto done;
13831 }
13832
13833 woal_mac2u8(bf_periodicity->peer_mac, &buf[2]);
13834 if (char_count == 19) {
13835 action = MLAN_ACT_GET;
13836 bf_cfg.action = BF_CFG_ACT_GET;
13837 } else {
13838 action = MLAN_ACT_SET;
13839 bf_cfg.action = BF_CFG_ACT_SET;
13840 if (woal_atoi(&interval, &buf[20]) !=
13841 MLAN_STATUS_SUCCESS) {
13842 ret = -EINVAL;
13843 goto done;
13844 }
13845 bf_periodicity->interval = interval;
13846 }
13847 break;
13848 case TX_BF_FOR_PEER_ENBL:
13849 /* Handle only SET operation here
13850 * First arg = 2 BfAction
13851 * Second arg = 18 MAC "00:50:43:20:BF:64;"
13852 * Third arg = 2 enable/disable bf
13853 * Fourth arg = 2 enable/disable sounding
13854 * Fifth arg = 1 FB Type */
13855 if (char_count != 25 && char_count != 1) {
13856 PRINTM(MERROR, "Invalid argument\n");
13857 ret = -EINVAL;
13858 goto done;
13859 }
13860 if (char_count == 1) {
13861 action = MLAN_ACT_GET;
13862 bf_cfg.action = BF_CFG_ACT_GET;
13863 } else {
13864 woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]);
13865 woal_atoi(&tmp_val, &buf[20]);
13866 tx_bf_peer->bf_enbl = (t_u8)tmp_val;
13867 woal_atoi(&tmp_val, &buf[22]);
13868 tx_bf_peer->sounding_enbl = (t_u8)tmp_val;
13869 woal_atoi(&tmp_val, &buf[24]);
13870 tx_bf_peer->fb_type = (t_u8)tmp_val;
13871 action = MLAN_ACT_SET;
13872 bf_cfg.action = BF_CFG_ACT_SET;
13873 }
13874 break;
13875 case SET_SNR_THR_PEER:
13876 /* First arg = 2 BfAction
13877 * Second arg = 18 MAC "00:50:43:20:BF:64;"
13878 * Third arg = 1/2 SNR u8 - can be 1/2 charerters */
13879 if (char_count != 1 &&
13880 !(char_count == 21 || char_count == 22)) {
13881 PRINTM(MERROR, "Invalid argument\n");
13882 ret = -EINVAL;
13883 goto done;
13884 }
13885 if (char_count == 1) {
13886 action = MLAN_ACT_GET;
13887 bf_cfg.action = BF_CFG_ACT_GET;
13888 } else {
13889 woal_mac2u8(bf_snr->peer_mac, &buf[2]);
13890 if (woal_atoi(&snr, &buf[20]) !=
13891 MLAN_STATUS_SUCCESS) {
13892 ret = -EINVAL;
13893 goto done;
13894 }
13895 bf_snr->snr = snr;
13896 action = MLAN_ACT_SET;
13897 bf_cfg.action = BF_CFG_ACT_SET;
13898 }
13899 break;
13900 default:
13901 ret = -EINVAL;
13902 goto done;
13903 }
13904
13905 /* Save the value */
13906 bf_cfg.bf_action = bf_action;
13907 if (MLAN_STATUS_SUCCESS !=
13908 woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
13909 ret = -EFAULT;
13910 goto done;
13911 }
13912 } else {
13913 ret = -EINVAL;
13914 goto done;
13915 }
13916
13917 switch (bf_action) {
13918 case BF_GLOBAL_CONFIGURATION:
13919 moal_memcpy_ext(priv->phandle, respbuf, bf_global,
13920 sizeof(mlan_bf_global_cfg_args), respbuflen);
13921 ret = sizeof(mlan_bf_global_cfg_args);
13922 break;
13923 case TRIGGER_SOUNDING_FOR_PEER:
13924 moal_memcpy_ext(priv->phandle, respbuf, bf_sound,
13925 sizeof(mlan_bf_global_cfg_args), respbuflen);
13926 ret = sizeof(mlan_bf_global_cfg_args);
13927 break;
13928 case SET_GET_BF_PERIODICITY:
13929 moal_memcpy_ext(priv->phandle, respbuf, bf_periodicity,
13930 sizeof(mlan_bf_periodicity_args), respbuflen);
13931 ret = sizeof(mlan_bf_periodicity_args);
13932 break;
13933 case TX_BF_FOR_PEER_ENBL:
13934 moal_memcpy_ext(priv->phandle, respbuf, tx_bf_peer,
13935 sizeof(mlan_tx_bf_peer_args), respbuflen);
13936 ret = sizeof(mlan_tx_bf_peer_args);
13937 break;
13938 case SET_SNR_THR_PEER:
13939 moal_memcpy_ext(priv->phandle, respbuf, bf_snr,
13940 sizeof(mlan_snr_thr_args), respbuflen);
13941 ret = sizeof(mlan_snr_thr_args);
13942 break;
13943 /** Default case not required as bf_action value already
13944 * sanitized */
13945 }
13946
13947 done:
13948 LEAVE();
13949 return ret;
13950 }
13951
13952 #ifdef SDIO
13953 /**
13954 * @brief Cmd53 read/write register
13955 * @param priv Pointer to moal_private structure
13956 * @param respbuf Pointer to response buffer
13957 * @param resplen Response buffer length
13958 *
13959 * @return Number of bytes written, negative for failure.
13960 */
woal_priv_cmd53rdwr(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)13961 static int woal_priv_cmd53rdwr(moal_private *priv, t_u8 *respbuf,
13962 t_u32 respbuflen)
13963 {
13964 int header_len = 0;
13965 int ret = 0;
13966 t_u8 *buf = NULL;
13967 t_u8 *data = NULL;
13968 t_u8 rw, mode;
13969 t_u16 blklen = 0, blknum = 0;
13970 int reg = 0;
13971 t_u32 pattern_len = 0, total_len = 0;
13972 t_u16 cmd_len;
13973 gfp_t flag;
13974
13975 ENTER();
13976
13977 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SD_CMD53_RW);
13978
13979 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
13980 data = kzalloc(WOAL_2K_BYTES, flag);
13981 if (!data) {
13982 PRINTM(MERROR, "Cannot allocate buffer for command!\n");
13983 ret = -EFAULT;
13984 goto done;
13985 }
13986 moal_memcpy_ext(priv->phandle, &cmd_len, respbuf + header_len,
13987 sizeof(cmd_len), sizeof(cmd_len));
13988 buf = respbuf + header_len + sizeof(cmd_len);
13989
13990 rw = buf[0]; /* read/write (0/1) */
13991 reg = buf[5]; /* address */
13992 reg = (reg << 8) | buf[4];
13993 reg = (reg << 8) | buf[3];
13994 reg = (reg << 8) | buf[2];
13995 mode = buf[6]; /* byte mode/block mode (0/1) */
13996 blklen = buf[8]; /* block size */
13997 blklen = (blklen << 8) | buf[7];
13998 blknum = buf[10]; /* block number or byte number */
13999 blknum = (blknum << 8) | buf[9];
14000
14001 if (mode == BYTE_MODE)
14002 blklen = 1;
14003 else
14004 mode = BLOCK_MODE;
14005
14006 total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum;
14007 if (total_len > WOAL_2K_BYTES) {
14008 PRINTM(MERROR, "Total data length is too large!\n");
14009 ret = -EINVAL;
14010 goto done;
14011 }
14012 PRINTM(MINFO,
14013 "CMD53 read/write, addr = %#x, mode = %d, "
14014 "block size = %d, block(byte) number = %d\n",
14015 reg, mode, blklen, blknum);
14016
14017 if (!rw) {
14018 sdio_claim_host(
14019 ((struct sdio_mmc_card *)priv->phandle->card)->func);
14020 if (sdio_readsb(
14021 ((struct sdio_mmc_card *)priv->phandle->card)->func,
14022 respbuf, reg, total_len)) {
14023 PRINTM(MERROR,
14024 "sdio_readsb: reading memory 0x%x failed\n",
14025 reg);
14026 goto done;
14027 }
14028 sdio_release_host(
14029 ((struct sdio_mmc_card *)priv->phandle->card)->func);
14030 ret = total_len;
14031 } else {
14032 int pos = 0;
14033 pattern_len = cmd_len - 11;
14034 if (pattern_len > total_len)
14035 pattern_len = total_len;
14036
14037 /* Copy/duplicate the pattern to data buffer */
14038 for (pos = 0; pos < (int)total_len; pos++)
14039 data[pos] = buf[11 + (pos % pattern_len)];
14040 sdio_claim_host(
14041 ((struct sdio_mmc_card *)priv->phandle->card)->func);
14042 if (sdio_writesb(
14043 ((struct sdio_mmc_card *)priv->phandle->card)->func,
14044 reg, data, total_len))
14045 PRINTM(MERROR,
14046 "sdio_writesb: writing memory 0x%x failed\n",
14047 reg);
14048 sdio_release_host(
14049 ((struct sdio_mmc_card *)priv->phandle->card)->func);
14050 }
14051
14052 done:
14053 kfree(data);
14054 LEAVE();
14055 return ret;
14056 }
14057 #endif /* SDIO */
14058
14059 /**
14060 * @brief Set/Get Port Control mode
14061 * @param priv Pointer to moal_private structure
14062 * @param respbuf Pointer to response buffer
14063 * @param resplen Response buffer length
14064 *
14065 * @return Number of bytes written, negative for failure.
14066 */
woal_priv_port_ctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14067 static int woal_priv_port_ctrl(moal_private *priv, t_u8 *respbuf,
14068 t_u32 respbuflen)
14069 {
14070 int header_len = 0, user_data_len = 0;
14071 mlan_ioctl_req *req = NULL;
14072 mlan_ds_sec_cfg *sec = NULL;
14073 int ret = 0, data = 0;
14074 mlan_status status = MLAN_STATUS_SUCCESS;
14075 ENTER();
14076
14077 /* Allocate an IOCTL request buffer */
14078 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
14079 if (req == NULL) {
14080 ret = -ENOMEM;
14081 goto done;
14082 }
14083
14084 /* Fill request buffer */
14085 sec = (mlan_ds_sec_cfg *)req->pbuf;
14086 sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED;
14087 req->req_id = MLAN_IOCTL_SEC_CFG;
14088
14089 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PORT_CTRL);
14090 if ((int)strlen(respbuf) == header_len) {
14091 /* GET operation */
14092 user_data_len = 0;
14093 req->action = MLAN_ACT_GET;
14094 } else {
14095 /* SET operation */
14096 parse_arguments(respbuf + header_len, &data,
14097 sizeof(data) / sizeof(int), &user_data_len);
14098 if (user_data_len == 1) {
14099 sec->param.port_ctrl_enabled = data;
14100 req->action = MLAN_ACT_SET;
14101 } else {
14102 PRINTM(MERROR, "Invalid number of parameters\n");
14103 ret = -EINVAL;
14104 goto done;
14105 }
14106 }
14107
14108 /* Send IOCTL request to MLAN */
14109 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14110 if (status != MLAN_STATUS_SUCCESS) {
14111 ret = -EFAULT;
14112 goto done;
14113 }
14114
14115 if (!user_data_len) {
14116 moal_memcpy_ext(priv->phandle, respbuf,
14117 &sec->param.port_ctrl_enabled, sizeof(int),
14118 respbuflen);
14119 ret = sizeof(int);
14120 }
14121
14122 done:
14123 if (status != MLAN_STATUS_PENDING)
14124 kfree(req);
14125
14126 LEAVE();
14127 return ret;
14128 }
14129
14130 /**
14131 * @brief Private IOCTL entry to get the By-passed TX packet from
14132 * upper layer
14133 * @param priv Pointer to moal_private structure
14134 * @param respbuf Pointer to response buffer
14135 * @param resplen Response buffer length
14136 *
14137 * @return Number of bytes written, negative for failure.
14138 */
woal_priv_bypassed_packet(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14139 static int woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf,
14140 t_u32 respbuflen)
14141 {
14142 int header_len = 0;
14143 int ret = 0;
14144 struct sk_buff *skb = NULL;
14145 struct ethhdr *eth;
14146 t_u16 moreLen = 0, copyLen = 0;
14147 ENTER();
14148
14149 #define MLAN_BYPASS_PKT_EXTRA_OFFSET (4)
14150
14151 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PB_BYPASS);
14152 copyLen = strlen(respbuf) - header_len;
14153 moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET +
14154 sizeof(mlan_buffer);
14155
14156 skb = alloc_skb(copyLen + moreLen, GFP_KERNEL);
14157 if (skb == NULL) {
14158 PRINTM(MERROR, "kmalloc no memory !!\n");
14159 LEAVE();
14160 return -ENOMEM;
14161 }
14162
14163 skb_reserve(skb, moreLen);
14164
14165 moal_memcpy_ext(priv->phandle, skb_put(skb, copyLen),
14166 respbuf + header_len, copyLen, copyLen);
14167
14168 eth = (struct ethhdr *)skb->data;
14169 eth->h_proto = __constant_htons(eth->h_proto);
14170 skb->dev = priv->netdev;
14171
14172 HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100));
14173
14174 woal_hard_start_xmit(skb, priv->netdev);
14175
14176 LEAVE();
14177 return ret;
14178 }
14179
14180 /**
14181 * @brief Set Robustcoex gpiocfg
14182 * @param priv Pointer to moal_private structure
14183 * @param respbuf Pointer to response buffer
14184 * @param resplen Response buffer length
14185 *
14186 * @return Number of bytes written, negative for failure.
14187 */
woal_priv_robustcoex(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14188 static int woal_priv_robustcoex(moal_private *priv, t_u8 *respbuf,
14189 t_u32 respbuflen)
14190 {
14191 int header_len = 0, user_data_len = 0;
14192 int ret = 0, data[3] = {0};
14193 mlan_ds_misc_cfg *robust_coex_cfg = NULL;
14194 mlan_ioctl_req *req = NULL;
14195 mlan_status status = MLAN_STATUS_SUCCESS;
14196
14197 ENTER();
14198
14199 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14200 if (req == NULL) {
14201 ret = -ENOMEM;
14202 goto done;
14203 }
14204 robust_coex_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14205 while (respbuf[0] == ' ') {
14206 /** skip space */
14207 respbuf++;
14208 }
14209
14210 if (strncmp(respbuf, "gpiocfg", strlen("gpiocfg")) == 0) {
14211 header_len = strlen("gpiocfg") + 1;
14212 parse_arguments(respbuf + header_len, data,
14213 sizeof(data) / sizeof(int), &user_data_len);
14214 if (user_data_len > 3) {
14215 PRINTM(MERROR, "Invalid parameter number\n");
14216 ret = -EINVAL;
14217 goto done;
14218 }
14219 if (data[0] != ROBUSTCOEX_GPIOCFG_ENABLE &&
14220 data[0] != ROBUSTCOEX_GPIOCFG_DISABLE) {
14221 PRINTM(MERROR, "Invalid parameter number\n");
14222 ret = -EINVAL;
14223 goto done;
14224 }
14225 if (data[0] == ROBUSTCOEX_GPIOCFG_ENABLE) {
14226 if (user_data_len != 3) {
14227 PRINTM(MMSG,
14228 "Please provide gpio num and gpio polarity for ROBUSTCOEX_GPIOCFG_ENABLE\n");
14229 ret = -EINVAL;
14230 goto done;
14231 }
14232 robust_coex_cfg->param.robustcoexparams.method =
14233 ROBUSTCOEX_GPIO_CFG;
14234 robust_coex_cfg->param.robustcoexparams.enable =
14235 ROBUSTCOEX_GPIOCFG_ENABLE;
14236 robust_coex_cfg->param.robustcoexparams.gpio_num =
14237 data[1];
14238 robust_coex_cfg->param.robustcoexparams.gpio_polarity =
14239 data[2];
14240 } else {
14241 robust_coex_cfg->param.robustcoexparams.method =
14242 ROBUSTCOEX_GPIO_CFG;
14243 robust_coex_cfg->param.robustcoexparams.enable =
14244 ROBUSTCOEX_GPIOCFG_DISABLE;
14245 robust_coex_cfg->param.robustcoexparams.gpio_num = 0;
14246 robust_coex_cfg->param.robustcoexparams.gpio_polarity =
14247 0;
14248 }
14249 req->action = MLAN_ACT_SET;
14250 req->req_id = MLAN_IOCTL_MISC_CFG;
14251 robust_coex_cfg->sub_command = MLAN_OID_MISC_ROBUSTCOEX;
14252 } else {
14253 PRINTM(MERROR, "Invalid parameter\n");
14254 ret = -EFAULT;
14255 goto done;
14256 }
14257 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14258 if (status != MLAN_STATUS_SUCCESS) {
14259 ret = -EFAULT;
14260 goto done;
14261 }
14262
14263 done:
14264 if (status != MLAN_STATUS_PENDING)
14265 kfree(req);
14266 LEAVE();
14267 return ret;
14268 }
14269
14270 /**
14271 * @brief Set DMCS mapping policy or get DMCS status
14272 * @param priv Pointer to moal_private structure
14273 * @param respbuf Pointer to response buffer
14274 * @param resplen Response buffer length
14275 *
14276 * @return Number of bytes written, negative for failure.
14277 */
woal_priv_dmcs(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14278 static int woal_priv_dmcs(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
14279 {
14280 int header_len = 0, user_data_len = 0;
14281 int ret = 0, data[2] = {0};
14282 mlan_ds_misc_cfg *dmcs_cfg = NULL;
14283 mlan_ioctl_req *req = NULL;
14284 mlan_status status = MLAN_STATUS_SUCCESS;
14285
14286 ENTER();
14287
14288 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14289 if (req == NULL) {
14290 ret = -ENOMEM;
14291 goto done;
14292 }
14293 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DMCS);
14294 dmcs_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14295 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14296 &user_data_len);
14297 if (user_data_len > 2) {
14298 PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
14299 ret = -EINVAL;
14300 goto done;
14301 }
14302 req->req_id = MLAN_IOCTL_MISC_CFG;
14303 dmcs_cfg->sub_command = MLAN_OID_MISC_DMCS_CONFIG;
14304 dmcs_cfg->param.dmcs_policy.subcmd = data[0];
14305 switch (data[0]) {
14306 case 0:
14307 if (user_data_len != 2) {
14308 PRINTM(MERROR, "Please provide mapping policy\n");
14309 ret = -EINVAL;
14310 goto done;
14311 }
14312 req->action = MLAN_ACT_SET;
14313 dmcs_cfg->param.dmcs_policy.mapping_policy = data[1];
14314 break;
14315 case 1:
14316 req->action = MLAN_ACT_GET;
14317 break;
14318 default:
14319 break;
14320 }
14321
14322 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14323 if (status != MLAN_STATUS_SUCCESS) {
14324 ret = -EFAULT;
14325 goto done;
14326 }
14327 if (req->action == MLAN_ACT_GET) {
14328 moal_memcpy_ext(priv->phandle, respbuf,
14329 &dmcs_cfg->param.dmcs_status,
14330 sizeof(mlan_ds_misc_dmcs_status), respbuflen);
14331 }
14332 ret = sizeof(mlan_ds_misc_dmcs_status);
14333 done:
14334 if (status != MLAN_STATUS_PENDING)
14335 kfree(req);
14336 LEAVE();
14337 return ret;
14338 }
14339
14340 /**
14341 * @brief Set and get boot sleep configure
14342 * @param priv Pointer to moal_private structure
14343 * @param respbuf Pointer to response buffer
14344 * @param resplen Response buffer length
14345 *
14346 * @return Number of bytes written, negative for failure.
14347 */
woal_priv_bootsleep(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14348 static int woal_priv_bootsleep(moal_private *priv, t_u8 *respbuf,
14349 t_u32 respbuflen)
14350 {
14351 int ret = MLAN_STATUS_SUCCESS;
14352 int user_data_len = 0;
14353 int header_len = 0;
14354 int allowed = 1;
14355 int data[1] = {0};
14356 mlan_ioctl_req *req = NULL;
14357 mlan_ds_misc_cfg *misc = NULL;
14358
14359 ENTER();
14360
14361 if (!priv || !priv->phandle) {
14362 PRINTM(MERROR, "priv or handle is null\n");
14363 ret = -EFAULT;
14364 goto done;
14365 }
14366
14367 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14368 if (req == NULL) {
14369 LEAVE();
14370 return -ENOMEM;
14371 }
14372
14373 misc = (mlan_ds_misc_cfg *)req->pbuf;
14374 misc->sub_command = MLAN_OID_MISC_BOOT_SLEEP;
14375 req->req_id = MLAN_IOCTL_MISC_CFG;
14376
14377 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BOOTSLEEP);
14378
14379 if ((int)strlen(respbuf) == header_len) {
14380 req->action = MLAN_ACT_GET;
14381 } else {
14382 req->action = MLAN_ACT_SET;
14383 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14384 &user_data_len);
14385 if (user_data_len != allowed) {
14386 PRINTM(MERROR, "Invalid number of args! %d\n",
14387 user_data_len);
14388 ret = -EINVAL;
14389 goto done;
14390 }
14391 misc->param.boot_sleep = data[0] ? 1 : 0;
14392 PRINTM(MIOCTL, "boot sleep cfg:%u\n", misc->param.boot_sleep);
14393 }
14394
14395 ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT);
14396 if (ret != MLAN_STATUS_SUCCESS) {
14397 ret = -EFAULT;
14398 goto done;
14399 }
14400
14401 moal_memcpy_ext(priv->phandle, respbuf, &misc->param.boot_sleep,
14402 sizeof(misc->param.boot_sleep), respbuflen);
14403 ret = sizeof(misc->param.boot_sleep);
14404
14405 PRINTM(MIOCTL, "boot sleep cfg: %u\n", misc->param.boot_sleep);
14406
14407 done:
14408 if (ret != MLAN_STATUS_PENDING)
14409 kfree(req);
14410 LEAVE();
14411 return ret;
14412 }
14413
14414 /**
14415 * * @brief Set and get txwatchdog check
14416 * * @param priv Pointer to moal_private structure
14417 * * @param respbuf Pointer to response buffer
14418 * * @param resplen Response buffer length
14419 * *
14420 * * @return Number of bytes written, negative for failure.
14421 * */
woal_priv_txwatchdog(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14422 static int woal_priv_txwatchdog(moal_private *priv, t_u8 *respbuf,
14423 t_u32 respbuflen)
14424 {
14425 int ret = 0;
14426 int header_len = 0;
14427 int user_data_len = 0;
14428 int data[1] = {0};
14429 int allowed = 1;
14430 t_u32 action;
14431
14432 ENTER();
14433
14434 if (!priv || !priv->phandle) {
14435 PRINTM(MERROR, "priv or handle is null\n");
14436 ret = -EFAULT;
14437 goto done;
14438 }
14439
14440 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXWATCHDOG);
14441
14442 if (strlen(respbuf) == header_len) {
14443 action = MLAN_ACT_GET;
14444 ret = sizeof(t_u32);
14445 } else {
14446 action = MLAN_ACT_SET;
14447 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14448 &user_data_len);
14449 if (user_data_len != allowed) {
14450 PRINTM(MERROR, "Invalid number of args! %d\n",
14451 user_data_len);
14452 ret = -EINVAL;
14453 goto done;
14454 }
14455 }
14456
14457 if (action == MLAN_ACT_SET) {
14458 priv->txwatchdog_disable = ((*data == 0) ? MTRUE : MFALSE);
14459 } else {
14460 *data = ((priv->txwatchdog_disable == MTRUE) ? 0 : 1);
14461 }
14462 memcpy(respbuf, data, sizeof(t_u32));
14463 PRINTM(MINFO, "priv->txwatchdog_disable:%u, action:%u, data[0]=%d\n",
14464 priv->txwatchdog_disable, action, data[0]);
14465
14466 done:
14467 LEAVE();
14468 return ret;
14469 }
14470
14471 #if defined(PCIE)
14472 /**
14473 * @brief Enable SSU support
14474 * @param priv Pointer to moal_private structure
14475 * @param used_len used length
14476 * @param respbuf Pointer to response buffer
14477 * @param resplen Response buffer length
14478 *
14479 * @return Number of bytes written, negative for failure.
14480 */
woal_priv_ssu_cmd(moal_private * priv,t_u8 used_len,t_u8 * respbuf,t_u32 respbuflen)14481 static int woal_priv_ssu_cmd(moal_private *priv, t_u8 used_len, t_u8 *respbuf,
14482 t_u32 respbuflen)
14483 {
14484 int ret = 0;
14485 mlan_ds_misc_cfg *ssu_cfg = NULL;
14486 mlan_ioctl_req *req = NULL;
14487 ssu_params_cfg *ssu_params;
14488 mlan_status status = MLAN_STATUS_SUCCESS;
14489
14490 ENTER();
14491
14492 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14493 if (req == NULL) {
14494 ret = -ENOMEM;
14495 goto done;
14496 }
14497 ssu_cfg = (mlan_ds_misc_cfg *)req->pbuf;
14498 memset(&ssu_cfg->param.ssu_params, 0, sizeof(mlan_ds_ssu_params));
14499 if (!used_len) {
14500 req->action = MLAN_ACT_SET;
14501 ssu_cfg->param.ssu_params.nskip = 0;
14502 ssu_cfg->param.ssu_params.nsel = 1;
14503 ssu_cfg->param.ssu_params.adcdownsample = 3;
14504 ssu_cfg->param.ssu_params.mask_adc_pkt = 0;
14505 ssu_cfg->param.ssu_params.out_16bits = 1;
14506 } else {
14507 ssu_params = (ssu_params_cfg *)respbuf;
14508 DBG_HEXDUMP(MCMD_D, "User SSU params:", respbuf,
14509 sizeof(mlan_ds_ssu_params));
14510 if (ssu_params->ssu_mode == 2)
14511 req->action = MLAN_ACT_DEFAULT;
14512 else {
14513 req->action = MLAN_ACT_SET;
14514 ssu_cfg->param.ssu_params.nskip = ssu_params->nskip;
14515 ssu_cfg->param.ssu_params.nsel = ssu_params->nsel;
14516 ssu_cfg->param.ssu_params.adcdownsample =
14517 ssu_params->adcdownsample;
14518 ssu_cfg->param.ssu_params.mask_adc_pkt =
14519 ssu_params->mask_adc_pkt;
14520 ssu_cfg->param.ssu_params.out_16bits =
14521 ssu_params->out_16bits;
14522 ssu_cfg->param.ssu_params.spec_pwr_enable =
14523 ssu_params->spec_pwr_enable;
14524 ssu_cfg->param.ssu_params.rate_deduction =
14525 ssu_params->rate_deduction;
14526 ssu_cfg->param.ssu_params.n_pkt_avg =
14527 ssu_params->n_pkt_avg;
14528 }
14529 }
14530 req->req_id = MLAN_IOCTL_MISC_CFG;
14531 ssu_cfg->sub_command = MLAN_OID_MISC_SSU;
14532
14533 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14534 if (status != MLAN_STATUS_SUCCESS) {
14535 ret = -EFAULT;
14536 goto done;
14537 }
14538
14539 done:
14540 if (status != MLAN_STATUS_PENDING)
14541 kfree(req);
14542 LEAVE();
14543 return ret;
14544 }
14545 #endif
14546
14547 /**
14548 * @brief Configure the hal/phy cfg params
14549 *
14550 * The command structure contains the following parameters
14551 * dot11b_psd_mask: 1: enable, 0: disable
14552 * Reserved : reserved 7 params for future such use
14553 *
14554 * @param priv Pointer to the mlan_private driver data struct
14555 * @param respbuf A pointer to response buffer
14556 * @param respbuflen Available length of response buffer
14557 *
14558 * @return Number of bytes written if successful else negative value
14559 */
woal_priv_hal_phy_cfg_cmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14560 static int woal_priv_hal_phy_cfg_cmd(moal_private *priv, t_u8 *respbuf,
14561 t_u32 respbuflen)
14562 {
14563 mlan_ioctl_req *req = NULL;
14564 mlan_ds_misc_cfg *cfg = NULL;
14565 int ret = 0;
14566 mlan_ds_hal_phy_cfg_params *data_ptr;
14567 mlan_status status = MLAN_STATUS_SUCCESS;
14568
14569 ENTER();
14570
14571 data_ptr = (mlan_ds_hal_phy_cfg_params *)respbuf;
14572 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14573 if (req == NULL) {
14574 ret = -ENOMEM;
14575 goto done;
14576 }
14577
14578 req->req_id = MLAN_IOCTL_MISC_CFG;
14579 cfg = (mlan_ds_misc_cfg *)req->pbuf;
14580 cfg->sub_command = MLAN_OID_MISC_HAL_PHY_CFG;
14581
14582 cfg->param.hal_phy_cfg_params.dot11b_psd_mask_cfg =
14583 data_ptr->dot11b_psd_mask_cfg;
14584
14585 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14586 if (status != MLAN_STATUS_SUCCESS) {
14587 ret = -EFAULT;
14588 goto done;
14589 }
14590
14591 done:
14592 if (status != MLAN_STATUS_PENDING)
14593 kfree(req);
14594 LEAVE();
14595 return ret;
14596 }
14597
14598 /**
14599 * @brief Enable/disable CSI support
14600 *
14601 * The command structure contains the following parameters
14602 * csi_enable: 1: enable, 0: diable
14603 * csi_filter_cnt: Number of CSI filters
14604 * csi_filter: CSI filters
14605 *
14606 * @param priv Pointer to the mlan_private driver data struct
14607 * @param respbuf A pointer to response buffer
14608 * @param respbuflen Available length of response buffer
14609 *
14610 * @return Number of bytes written if successful else negative value
14611 */
woal_priv_csi_cmd(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14612 static int woal_priv_csi_cmd(moal_private *priv, t_u8 *respbuf,
14613 t_u32 respbuflen)
14614 {
14615 mlan_ioctl_req *req = NULL;
14616 mlan_ds_misc_cfg *cfg = NULL;
14617 int ret = 0;
14618 mlan_ds_csi_params *data_ptr;
14619 mlan_status status = MLAN_STATUS_SUCCESS;
14620
14621 ENTER();
14622
14623 data_ptr = (mlan_ds_csi_params *)respbuf;
14624 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
14625 if (req == NULL) {
14626 ret = -ENOMEM;
14627 goto done;
14628 }
14629
14630 req->req_id = MLAN_IOCTL_MISC_CFG;
14631 cfg = (mlan_ds_misc_cfg *)req->pbuf;
14632 cfg->sub_command = MLAN_OID_MISC_CSI;
14633
14634 cfg->param.csi_params.csi_enable = data_ptr->csi_enable;
14635 if (data_ptr->csi_enable == 1) {
14636 cfg->param.csi_params.head_id = data_ptr->head_id;
14637 cfg->param.csi_params.tail_id = data_ptr->tail_id;
14638 cfg->param.csi_params.csi_filter_cnt = data_ptr->csi_filter_cnt;
14639 cfg->param.csi_params.chip_id = data_ptr->chip_id;
14640 if (cfg->param.csi_params.csi_filter_cnt > CSI_FILTER_MAX)
14641 cfg->param.csi_params.csi_filter_cnt = CSI_FILTER_MAX;
14642 moal_memcpy_ext(priv->phandle, cfg->param.csi_params.csi_filter,
14643 data_ptr->csi_filter,
14644 sizeof(mlan_csi_filter_t) *
14645 cfg->param.csi_params.csi_filter_cnt,
14646 sizeof(mlan_csi_filter_t) * CSI_FILTER_MAX);
14647 }
14648
14649 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14650 if (status != MLAN_STATUS_SUCCESS) {
14651 ret = -EFAULT;
14652 goto done;
14653 }
14654
14655 done:
14656 if (status != MLAN_STATUS_PENDING)
14657 kfree(req);
14658 LEAVE();
14659 return ret;
14660 }
14661
14662 /**
14663 * @brief configure 11ax HE capability or HE operation
14664 *
14665 *
14666 * @param priv Pointer to the mlan_private driver data struct
14667 * @param respbuf A pointer to response buffer
14668 * @param len length used
14669 * @param respbuflen Available length of response buffer
14670 *
14671 * @return Number of bytes written if successful else negative value
14672 */
woal_priv_11axcfg_cmd(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14673 static int woal_priv_11axcfg_cmd(moal_private *priv, t_u8 *respbuf, t_u8 len,
14674 t_u32 respbuflen)
14675 {
14676 mlan_ioctl_req *req = NULL;
14677 mlan_ds_11ax_cfg *cfg = NULL;
14678 int ret = 0;
14679 mlan_status status = MLAN_STATUS_SUCCESS;
14680
14681 ENTER();
14682
14683 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg));
14684 if (req == NULL) {
14685 ret = -ENOMEM;
14686 goto done;
14687 }
14688
14689 req->req_id = MLAN_IOCTL_11AX_CFG;
14690 req->action = MLAN_ACT_SET;
14691 cfg = (mlan_ds_11ax_cfg *)req->pbuf;
14692 cfg->sub_command = MLAN_OID_11AX_HE_CFG;
14693 if (len)
14694 moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.he_cfg,
14695 respbuf, len, sizeof(mlan_ds_11ax_he_cfg));
14696 else
14697 req->action = MLAN_ACT_GET;
14698 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14699 if (status != MLAN_STATUS_SUCCESS) {
14700 ret = -EFAULT;
14701 goto done;
14702 }
14703 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.he_cfg,
14704 sizeof(mlan_ds_11ax_he_cfg), respbuflen);
14705 ret = sizeof(mlan_ds_11ax_he_cfg);
14706 done:
14707 if (status != MLAN_STATUS_PENDING)
14708 kfree(req);
14709 LEAVE();
14710 return ret;
14711 }
14712 /**
14713 * @brief Configure TWT Setup parameters
14714 *
14715 * @param priv Pointer to the mlan_private driver data struct
14716 * @param respbuf A pointer to response buffer
14717 * @param len Length used
14718 * @param respbuflen Available length of response buffer
14719 *
14720 * @return Number of bytes written if successful else negative
14721 * value
14722 */
woal_priv_twt_setup(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14723 static int woal_priv_twt_setup(moal_private *priv, t_u8 *respbuf, t_u8 len,
14724 t_u32 respbuflen)
14725 {
14726 mlan_ioctl_req *req = NULL;
14727 mlan_ds_twtcfg *cfg = NULL;
14728 int ret = 0;
14729 mlan_status status = MLAN_STATUS_SUCCESS;
14730
14731 ENTER();
14732
14733 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
14734 if (req == NULL) {
14735 PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
14736 ret = -ENOMEM;
14737 goto done;
14738 }
14739
14740 req->req_id = MLAN_IOCTL_11AX_CFG;
14741 req->action = MLAN_ACT_SET;
14742 cfg = (mlan_ds_twtcfg *)req->pbuf;
14743 cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
14744 cfg->sub_id = MLAN_11AX_TWT_SETUP_SUBID;
14745
14746 if (len) {
14747 moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_setup,
14748 respbuf, len, sizeof(mlan_ds_twt_setup));
14749 }
14750
14751 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14752 if (status != MLAN_STATUS_SUCCESS) {
14753 PRINTM(MERROR, "woal_request_ioctl failed!\n");
14754 ret = -EFAULT;
14755 goto done;
14756 }
14757
14758 ret = sizeof(mlan_ds_twt_setup);
14759 done:
14760 if (status != MLAN_STATUS_PENDING) {
14761 kfree(req);
14762 }
14763 LEAVE();
14764 return ret;
14765 }
14766
14767 /**
14768 * @brief Configure TWT Tear down parameters
14769 *
14770 * @param priv Pointer to the mlan_private driver data struct
14771 * @param respbuf A pointer to response buffer
14772 * @param len Length used
14773 * @param respbuflen Available length of response buffer
14774 *
14775 * @return Number of bytes written if successful else negative
14776 * value
14777 */
woal_priv_twt_teardown(moal_private * priv,t_u8 * respbuf,t_u8 len,t_u32 respbuflen)14778 static int woal_priv_twt_teardown(moal_private *priv, t_u8 *respbuf, t_u8 len,
14779 t_u32 respbuflen)
14780 {
14781 mlan_ioctl_req *req = NULL;
14782 mlan_ds_twtcfg *cfg = NULL;
14783 int ret = 0;
14784 mlan_status status = MLAN_STATUS_SUCCESS;
14785
14786 ENTER();
14787
14788 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg));
14789 if (req == NULL) {
14790 PRINTM(MERROR, "Failed to allocate ioctl_req!\n");
14791 ret = -ENOMEM;
14792 goto done;
14793 }
14794
14795 req->req_id = MLAN_IOCTL_11AX_CFG;
14796 req->action = MLAN_ACT_SET;
14797 cfg = (mlan_ds_twtcfg *)req->pbuf;
14798 cfg->sub_command = MLAN_OID_11AX_TWT_CFG;
14799 cfg->sub_id = MLAN_11AX_TWT_TEARDOWN_SUBID;
14800
14801 if (len) {
14802 moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_teardown,
14803 respbuf, len, sizeof(mlan_ds_twt_teardown));
14804 }
14805
14806 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
14807 if (status != MLAN_STATUS_SUCCESS) {
14808 PRINTM(MERROR, "woal_request_ioctl failed!\n");
14809 ret = -EFAULT;
14810 goto done;
14811 }
14812
14813 ret = sizeof(mlan_ds_twt_teardown);
14814 done:
14815 if (status != MLAN_STATUS_PENDING) {
14816 kfree(req);
14817 }
14818 LEAVE();
14819 return ret;
14820 }
14821
14822 #ifdef WIFI_DIRECT_SUPPORT
14823 #if defined(UAP_CFG80211)
14824 /**
14825 * @brief Set/Get P2P NoA (Notice of Absence) parameters
14826 * @param priv Pointer to moal_private structure
14827 * @param respbuf Pointer to response buffer
14828 * @param resplen Response buffer length
14829 *
14830 * @return Number of bytes written, negative for failure.
14831 */
woal_priv_cfg_noa(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14832 static int woal_priv_cfg_noa(moal_private *priv, t_u8 *respbuf,
14833 t_u32 respbuflen)
14834 {
14835 int header_len = 0, user_data_len = 0;
14836 int ret = 0, data[7];
14837 mlan_ds_wifi_direct_config noa_cfg;
14838
14839 ENTER();
14840
14841 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_NOA);
14842 memset(&noa_cfg, 0, sizeof(noa_cfg));
14843
14844 memset(data, 0, sizeof(data));
14845 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14846 &user_data_len);
14847
14848 if (user_data_len > 5) {
14849 PRINTM(MERROR, "invalid parameters\n");
14850 ret = -EINVAL;
14851 goto done;
14852 }
14853
14854 noa_cfg.flags |= WIFI_DIRECT_NOA;
14855
14856 if (woal_p2p_config(priv, MLAN_ACT_GET, &noa_cfg) !=
14857 MLAN_STATUS_SUCCESS) {
14858 PRINTM(MERROR, "Could not get P2P noa config\n");
14859 ret = -EINVAL;
14860 goto done;
14861 }
14862
14863 if ((int)strlen(respbuf) == header_len) {
14864 /* GET operation */
14865 moal_memcpy_ext(priv->phandle, respbuf, &noa_cfg,
14866 sizeof(noa_cfg), respbuflen);
14867 ret = sizeof(noa_cfg);
14868 } else {
14869 switch (user_data_len) {
14870 case 5:
14871 noa_cfg.noa_interval = (t_u32)data[4];
14872 /* fall through */
14873 case 4:
14874 noa_cfg.noa_duration = (t_u32)data[3];
14875 /* fall through */
14876 case 3:
14877 if (data[2] < 1 || data[2] > 255) {
14878 PRINTM(MERROR,
14879 "Invalid number of absence intervals\n");
14880 ret = -EINVAL;
14881 goto done;
14882 }
14883 noa_cfg.noa_count = (t_u8)data[2];
14884 /* fall through */
14885 case 2:
14886 if (data[1] < 0 || data[1] > 255) {
14887 PRINTM(MERROR, "Invalid Index\n");
14888 ret = -EINVAL;
14889 goto done;
14890 }
14891 noa_cfg.index = (t_u16)data[1];
14892 /* fall through */
14893 case 1:
14894 if (data[0] < 0 || data[0] > 1) {
14895 PRINTM(MERROR, "Invalid noa enable\n");
14896 ret = -EINVAL;
14897 goto done;
14898 }
14899 noa_cfg.noa_enable = (t_u8)data[0];
14900 noa_cfg.flags |= WIFI_DIRECT_NOA;
14901 break;
14902 default:
14903 break;
14904 }
14905 if (woal_p2p_config(priv, MLAN_ACT_SET, &noa_cfg) !=
14906 MLAN_STATUS_SUCCESS) {
14907 PRINTM(MERROR, "woal_p2p_config fail\n");
14908 ret = -EFAULT;
14909 }
14910 }
14911
14912 done:
14913
14914 LEAVE();
14915 return ret;
14916 }
14917
14918 /**
14919 * @brief Set/Get P2P OPP-PS parameters
14920 * @param priv Pointer to moal_private structure
14921 * @param respbuf Pointer to response buffer
14922 * @param resplen Response buffer length
14923 *
14924 * @return Number of bytes written, negative for failure.
14925 */
woal_priv_cfg_opp_ps(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)14926 static int woal_priv_cfg_opp_ps(moal_private *priv, t_u8 *respbuf,
14927 t_u32 respbuflen)
14928 {
14929 int header_len = 0, user_data_len = 0;
14930 int ret = 0, data[7];
14931 mlan_ds_wifi_direct_config opp_ps_cfg;
14932
14933 ENTER();
14934
14935 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_OPP_PS);
14936 memset(&opp_ps_cfg, 0, sizeof(opp_ps_cfg));
14937
14938 memset(data, 0, sizeof(data));
14939 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
14940 &user_data_len);
14941
14942 if (user_data_len > 2) {
14943 PRINTM(MERROR, "invalid parameters\n");
14944 ret = -EINVAL;
14945 goto done;
14946 }
14947
14948 opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
14949
14950 if (woal_p2p_config(priv, MLAN_ACT_GET, &opp_ps_cfg) !=
14951 MLAN_STATUS_SUCCESS) {
14952 PRINTM(MERROR, "Could not get P2P opp ps config\n");
14953 ret = -EINVAL;
14954 goto done;
14955 }
14956
14957 if ((int)strlen(respbuf) == header_len) {
14958 /* GET operation */
14959 moal_memcpy_ext(priv->phandle, respbuf, &opp_ps_cfg,
14960 sizeof(opp_ps_cfg), respbuflen);
14961 ret = sizeof(opp_ps_cfg);
14962 } else {
14963 switch (user_data_len) {
14964 case 2:
14965 opp_ps_cfg.ct_window = (t_u8)data[1];
14966 /* fall through */
14967 case 1:
14968 if (data[0] < 0 || data[0] > 1) {
14969 PRINTM(MERROR, "Invalid ps enable\n");
14970 ret = -EINVAL;
14971 goto done;
14972 }
14973 opp_ps_cfg.opp_ps_enable = (t_u8)data[0];
14974 opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS;
14975 /* fall through */
14976 default:
14977 break;
14978 }
14979 if (woal_p2p_config(priv, MLAN_ACT_SET, &opp_ps_cfg) !=
14980 MLAN_STATUS_SUCCESS) {
14981 PRINTM(MERROR, "woal_p2p_config fail\n");
14982 ret = -EINVAL;
14983 }
14984 }
14985
14986 done:
14987 LEAVE();
14988 return ret;
14989 }
14990 #endif
14991 #endif
14992
14993 /**
14994 * @brief Set/Get GPIO TSF latch clock sync config parameters
14995 * @param priv Pointer to moal_private structure
14996 * @param respbuf Pointer to response buffer
14997 * @param resplen Response buffer length
14998 *
14999 * @return Number of bytes written, negative for failure.
15000 */
woal_priv_cfg_clock_sync(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15001 static int woal_priv_cfg_clock_sync(moal_private *priv, t_u8 *respbuf,
15002 t_u32 respbuflen)
15003 {
15004 int header_len = 0, user_data_len = 0;
15005 int ret = 0, data[5];
15006 mlan_ds_gpio_tsf_latch *clock_sync_cfg = NULL;
15007 mlan_ioctl_req *req = NULL;
15008 mlan_ds_misc_cfg *misc_cfg = NULL;
15009 mlan_status status = MLAN_STATUS_SUCCESS;
15010
15011 ENTER();
15012
15013 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_CLOCK_SYNC);
15014
15015 memset(data, 0, sizeof(data));
15016 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15017 &user_data_len);
15018
15019 if (user_data_len > 5) {
15020 PRINTM(MERROR, "invalid parameters\n");
15021 ret = -EINVAL;
15022 goto done;
15023 }
15024
15025 /* Allocate an IOCTL request buffer */
15026 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15027 if (req == NULL) {
15028 ret = -ENOMEM;
15029 goto done;
15030 }
15031
15032 /* Fill request buffer */
15033 req->req_id = MLAN_IOCTL_MISC_CFG;
15034 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15035 misc_cfg->sub_command = MLAN_OID_MISC_GPIO_TSF_LATCH;
15036 clock_sync_cfg = &misc_cfg->param.gpio_tsf_latch_config;
15037 memset(clock_sync_cfg, 0, sizeof(mlan_ds_gpio_tsf_latch));
15038
15039 if ((int)strlen(respbuf) == header_len) {
15040 /* GET operation */
15041 req->action = MLAN_ACT_GET;
15042 user_data_len = 0;
15043 } else {
15044 req->action = MLAN_ACT_SET;
15045 switch (user_data_len) {
15046 case 5:
15047 clock_sync_cfg->clock_sync_gpio_pulse_width =
15048 (t_u16)data[4];
15049 /* fall through */
15050 case 4:
15051 if (data[3] < 0 || data[3] > 1) {
15052 PRINTM(MERROR, "Invalid Level/Trigger\n");
15053 ret = -EINVAL;
15054 goto done;
15055 }
15056 clock_sync_cfg->clock_sync_gpio_level_toggle =
15057 (t_u8)data[3];
15058 /* fall through */
15059 case 3:
15060 if (data[2] < 1 || data[2] > 255) {
15061 PRINTM(MERROR,
15062 "Invalid number of GPIO Pin Number\n");
15063 ret = -EINVAL;
15064 goto done;
15065 }
15066 clock_sync_cfg->clock_sync_gpio_pin_number =
15067 (t_u8)data[2];
15068 /* fall through */
15069 case 2:
15070 if (data[1] < 0 || data[1] > 2) {
15071 PRINTM(MERROR, "Invalid Role\n");
15072 ret = -EINVAL;
15073 goto done;
15074 }
15075 clock_sync_cfg->clock_sync_Role = (t_u8)data[1];
15076 /* fall through */
15077 case 1:
15078 if (data[0] < 0 || data[0] > 2) {
15079 PRINTM(MERROR, "Invalid Mode\n");
15080 ret = -EINVAL;
15081 goto done;
15082 }
15083 clock_sync_cfg->clock_sync_mode = (t_u8)data[0];
15084 break;
15085 default:
15086 break;
15087 }
15088 }
15089 /* Send IOCTL request to MLAN */
15090 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15091 if (status != MLAN_STATUS_SUCCESS) {
15092 ret = -EFAULT;
15093 goto done;
15094 }
15095
15096 if (!user_data_len) {
15097 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)clock_sync_cfg,
15098 sizeof(mlan_ds_gpio_tsf_latch), respbuflen);
15099 ret = sizeof(mlan_ds_gpio_tsf_latch);
15100 }
15101
15102 done:
15103 if (status != MLAN_STATUS_PENDING)
15104 kfree(req);
15105
15106 LEAVE();
15107 return ret;
15108 }
15109
15110 /**
15111 * @brief Set/Get GPIO TSF latch get tsf info config parameters
15112 * @param priv Pointer to moal_private structure
15113 * @param respbuf Pointer to response buffer
15114 * @param resplen Response buffer length
15115 *
15116 * @return Number of bytes written, negative for failure.
15117 */
woal_priv_cfg_get_tsf_info(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15118 static int woal_priv_cfg_get_tsf_info(moal_private *priv, t_u8 *respbuf,
15119 t_u32 respbuflen)
15120 {
15121 int header_len = 0, user_data_len = 0;
15122 int ret = 0, data[1];
15123 mlan_ds_tsf_info *tsf_info;
15124 mlan_ioctl_req *req = NULL;
15125 mlan_ds_misc_cfg *misc_cfg = NULL;
15126 mlan_status status = MLAN_STATUS_SUCCESS;
15127
15128 ENTER();
15129
15130 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_GET_TSF_INFO);
15131
15132 memset(data, 0, sizeof(data));
15133 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15134 &user_data_len);
15135
15136 if (user_data_len > 1) {
15137 PRINTM(MERROR, "invalid parameters\n");
15138 ret = -EINVAL;
15139 goto done;
15140 }
15141 /* Allocate an IOCTL request buffer */
15142 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15143 if (req == NULL) {
15144 ret = -ENOMEM;
15145 goto done;
15146 }
15147
15148 /* Fill request buffer */
15149 req->req_id = MLAN_IOCTL_MISC_CFG;
15150 req->action = MLAN_ACT_GET;
15151 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15152 misc_cfg->sub_command = MLAN_OID_MISC_GET_TSF_INFO;
15153 tsf_info = &misc_cfg->param.tsf_info;
15154 memset(tsf_info, 0, sizeof(mlan_ds_tsf_info));
15155 if (user_data_len == 1) {
15156 if (data[0] < 0 || data[0] > 1) {
15157 PRINTM(MERROR, "Invalid tsf Format\n");
15158 ret = -EINVAL;
15159 goto done;
15160 }
15161 tsf_info->tsf_format = data[0];
15162 }
15163 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15164 if (status != MLAN_STATUS_SUCCESS) {
15165 ret = -EFAULT;
15166 goto done;
15167 }
15168 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)tsf_info,
15169 sizeof(mlan_ds_tsf_info), respbuflen);
15170 ret = sizeof(mlan_ds_tsf_info);
15171 done:
15172 if (status != MLAN_STATUS_PENDING)
15173 kfree(req);
15174
15175 LEAVE();
15176 return ret;
15177 }
15178
15179 #ifdef UAP_SUPPORT
15180 /**
15181 * @brief Set/Get target channel
15182 * @param priv Pointer to moal_private structure
15183 * @param respbuf Pointer to response buffer
15184 * @param resplen Response buffer length
15185 *
15186 * @return Number of bytes written, negative for failure.
15187 */
woal_priv_target_channel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15188 static int woal_priv_target_channel(moal_private *priv, t_u8 *respbuf,
15189 t_u32 respbuflen)
15190 {
15191 int header_len = 0, user_data_len = 0;
15192 int ret = 0, data[1];
15193
15194 ENTER();
15195 if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
15196 PRINTM(MERROR, "priv is null or interface is not AP");
15197 ret = -EFAULT;
15198 LEAVE();
15199 return ret;
15200 }
15201
15202 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TARGET_CHANNEL);
15203 if ((int)strlen(respbuf) == header_len) {
15204 /* GET operation */
15205 user_data_len = 0;
15206 } else {
15207 /* SET operation */
15208 parse_arguments(respbuf + header_len, data,
15209 sizeof(data) / sizeof(int), &user_data_len);
15210 if (user_data_len > 1) {
15211 PRINTM(MERROR, "Invalid parameter number\n");
15212 ret = -EINVAL;
15213 goto done;
15214 }
15215 if (user_data_len)
15216 priv->target_chan = data[0];
15217 }
15218 data[0] = priv->target_chan;
15219 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
15220 respbuflen);
15221 ret = sizeof(int);
15222 done:
15223
15224 LEAVE();
15225 return ret;
15226 }
15227
15228 /**
15229 * @brief Set/Get backup channel
15230 * @param priv Pointer to moal_private structure
15231 * @param respbuf Pointer to response buffer
15232 * @param resplen Response buffer length
15233 *
15234 * @return Number of bytes written, negative for failure.
15235 */
woal_priv_backup_channel(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15236 static int woal_priv_backup_channel(moal_private *priv, t_u8 *respbuf,
15237 t_u32 respbuflen)
15238 {
15239 int header_len = 0, user_data_len = 0;
15240 int ret = 0, data[1];
15241
15242 ENTER();
15243 if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) {
15244 PRINTM(MERROR, "priv is null or interface is not AP");
15245 ret = -EFAULT;
15246 LEAVE();
15247 return ret;
15248 }
15249
15250 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BACKUP_CHANNEL);
15251 if ((int)strlen(respbuf) == header_len) {
15252 /* GET operation */
15253 user_data_len = 0;
15254 } else {
15255 /* SET operation */
15256 parse_arguments(respbuf + header_len, data,
15257 sizeof(data) / sizeof(int), &user_data_len);
15258 if (user_data_len > 1) {
15259 PRINTM(MERROR, "Invalid parameter number\n");
15260 ret = -EINVAL;
15261 goto done;
15262 }
15263 if (user_data_len)
15264 priv->backup_chan = data[0];
15265 }
15266 data[0] = priv->backup_chan;
15267 moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data),
15268 respbuflen);
15269 ret = sizeof(int);
15270 done:
15271
15272 LEAVE();
15273 return ret;
15274 }
15275 #endif
15276
15277 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15278 #ifdef WIFI_DIRECT_SUPPORT
15279 #define DEF_NOA_INTERVAL 100
15280 /**
15281 ** @brief Set/Get P2P NoA (Notice of Absence) parameters
15282 ** @param priv Pointer to moal_private structure
15283 ** @param respbuf Pointer to response buffer
15284 ** @param resplen Response buffer length
15285 **
15286 ** @return Number of bytes written, negative for failure.
15287 **/
woal_p2p_ps_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15288 static int woal_p2p_ps_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
15289 {
15290 int user_data_len = 0;
15291 int ret = 0, data[2];
15292 u32 duration = priv->phandle->noa_duration;
15293 u32 interval = 0;
15294
15295 ENTER();
15296 if (strlen(respbuf) > strlen("P2P_PERIODIC_SLEEP")) {
15297 memset((char *)data, 0, sizeof(data));
15298 parse_arguments(respbuf + strlen("P2P_PERIODIC_SLEEP") + 1,
15299 data, ARRAY_SIZE(data), &user_data_len);
15300 }
15301 if ((user_data_len != 1) && (user_data_len != 2)) {
15302 PRINTM(MERROR,
15303 " Invalid parameter number for P2P_PERIODIC_SLEEP");
15304 ret = -EINVAL;
15305 goto done;
15306 }
15307 if (data[0] < DEF_NOA_INTERVAL)
15308 interval = DEF_NOA_INTERVAL;
15309 else
15310 interval = (data[0] + DEF_NOA_INTERVAL - 1) / DEF_NOA_INTERVAL *
15311 DEF_NOA_INTERVAL;
15312
15313 if (user_data_len == 2)
15314 duration = data[1];
15315 if (duration >= interval) {
15316 PRINTM(MERROR,
15317 " Invalid noa duration/interval! duration=%d interval=%d\n",
15318 duration, interval);
15319 ret = -EINVAL;
15320 goto done;
15321 }
15322 priv->phandle->noa_interval = interval;
15323 priv->phandle->noa_duration = duration;
15324 PRINTM(MIOCTL, "configure noa interval=%d, duration=%d\n",
15325 priv->phandle->noa_interval, priv->phandle->noa_duration);
15326 done:
15327 LEAVE();
15328 return ret;
15329 }
15330 #endif
15331 #endif
15332
15333 /**
15334 * @brief Set/Get DFS repeater mode
15335 *
15336 * @param priv Pointer to moal_private structure
15337 * @param respbuf Pointer to response buffer
15338 * @param resplen Response buffer length
15339 *
15340 * @return Number of bytes written, negative for failure.
15341 */
woal_priv_dfs_repeater_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15342 static int woal_priv_dfs_repeater_cfg(moal_private *priv, t_u8 *respbuf,
15343 t_u32 respbuflen)
15344 {
15345 int ret = 0;
15346 int user_data_len = 0, header_len = 0, data[1] = {0};
15347 mlan_ioctl_req *req = NULL;
15348 mlan_ds_misc_cfg *misc_cfg = NULL;
15349 mlan_ds_misc_dfs_repeater *dfs_repeater = NULL;
15350 mlan_status status = MLAN_STATUS_SUCCESS;
15351
15352 ENTER();
15353
15354 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_REPEATER_CFG);
15355
15356 /* Allocate an IOCTL request buffer */
15357 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15358 if (req == NULL) {
15359 ret = -ENOMEM;
15360 goto done;
15361 }
15362
15363 /* Fill request buffer */
15364 req->req_id = MLAN_IOCTL_MISC_CFG;
15365 misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
15366 misc_cfg->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE;
15367 dfs_repeater =
15368 (mlan_ds_misc_dfs_repeater *)&misc_cfg->param.dfs_repeater;
15369
15370 if ((int)strlen(respbuf) == header_len) {
15371 /* GET operation */
15372 user_data_len = 0;
15373 req->action = MLAN_ACT_GET;
15374 } else {
15375 /* SET operation */
15376 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15377 &user_data_len);
15378 if (user_data_len != 1) {
15379 PRINTM(MERROR, "Invalid number of args! %d\n",
15380 user_data_len);
15381 ret = -EINVAL;
15382 goto done;
15383 }
15384 if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
15385 PRINTM(MERROR, "Invalid DFS repeater mode %d\n",
15386 data[0]);
15387 ret = -EINVAL;
15388 goto done;
15389 }
15390 dfs_repeater->mode = (t_u16)data[0];
15391
15392 req->action = MLAN_ACT_SET;
15393 }
15394
15395 /* Send IOCTL request to MLAN */
15396 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15397 if (status != MLAN_STATUS_SUCCESS) {
15398 ret = -EFAULT;
15399 goto done;
15400 }
15401
15402 if (!user_data_len) {
15403 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)dfs_repeater,
15404 sizeof(mlan_ds_misc_dfs_repeater), respbuflen);
15405 ret = sizeof(mlan_ds_misc_dfs_repeater);
15406 }
15407
15408 /* Store current value of DFS repeater mode for futher references. eg.,
15409 * for avoiding CAC timers
15410 */
15411 priv->phandle->dfs_repeater_mode = dfs_repeater->mode;
15412
15413 done:
15414 if (status != MLAN_STATUS_PENDING)
15415 kfree(req);
15416
15417 LEAVE();
15418 return ret;
15419 }
15420
15421 #ifdef WIFI_DIRECT_SUPPORT
15422 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15423 /**
15424 * @brief Set/Get MIRACAST configuration parameters
15425 *
15426 * @param priv Pointer to moal_private structure
15427 * @param respbuf Pointer to response buffer
15428 * @param resplen Response buffer length
15429 *
15430 * @return Number of bytes written, negative for failure.
15431 */
woal_priv_miracast_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15432 static int woal_priv_miracast_cfg(moal_private *priv, t_u8 *respbuf,
15433 t_u32 respbuflen)
15434 {
15435 int ret = 0;
15436 int user_data_len = 0, header_len = 0, data[3] = {0, 0, 0};
15437
15438 ENTER();
15439
15440 if (!priv || !priv->phandle) {
15441 PRINTM(MERROR, "priv or handle is null\n");
15442 ret = -EFAULT;
15443 goto done;
15444 }
15445
15446 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIRACAST_CFG);
15447
15448 if ((int)strlen(respbuf) == header_len) {
15449 /* GET operation */
15450 data[0] = priv->phandle->miracast_mode;
15451 data[1] = priv->phandle->miracast_scan_time;
15452 data[2] = priv->phandle->scan_chan_gap;
15453
15454 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
15455 sizeof(data), respbuflen);
15456 ret = sizeof(data);
15457 } else {
15458 /* SET operation */
15459 memset(data, 0, sizeof(data));
15460 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15461 &user_data_len);
15462
15463 if (user_data_len > 3) {
15464 PRINTM(MERROR, "Too many arguments\n");
15465 ret = -EINVAL;
15466 goto done;
15467 }
15468 if (data[0] < 0 || data[0] > 2 || data[1] < 0 || data[2] < 0) {
15469 PRINTM(MERROR, "Invalid argument\n");
15470 ret = -EINVAL;
15471 goto done;
15472 }
15473 }
15474
15475 if (user_data_len >= 1)
15476 priv->phandle->miracast_mode = (t_u8)data[0];
15477 if (user_data_len >= 2)
15478 priv->phandle->miracast_scan_time = (t_u16)data[1];
15479 if (user_data_len == 3)
15480 priv->phandle->scan_chan_gap = (t_u16)data[2];
15481
15482 done:
15483 LEAVE();
15484 return ret;
15485 }
15486
15487 /**
15488 * @brief Configuring scan gap for miracast mode
15489 *
15490 * @param priv A pointer to moal_private structure
15491 * @param respbuf A pointer to response buffer
15492 * @param respbuflen Available length of response buffer
15493 *
15494 * @return 0 --success, otherwise failure
15495 */
woal_set_scan_chan_gap(moal_private * priv,t_u8 * respbuf,int respbuflen)15496 static int woal_set_scan_chan_gap(moal_private *priv, t_u8 *respbuf,
15497 int respbuflen)
15498 {
15499 t_u32 data[2];
15500 int ret = 0;
15501 int user_data_len = 0;
15502
15503 ENTER();
15504
15505 if (strlen(respbuf) > strlen("SCAN_TIMING")) {
15506 memset((char *)data, 0, sizeof(data));
15507 parse_arguments(respbuf + strlen("SCAN_TIMING") + 1, data,
15508 ARRAY_SIZE(data), &user_data_len);
15509 }
15510
15511 if (user_data_len != 2) {
15512 PRINTM(MERROR, "Invalid arguments for scan timing\n");
15513 ret = -EINVAL;
15514 goto done;
15515 }
15516 priv->phandle->miracast_scan_time = (t_u16)data[0];
15517 priv->phandle->scan_chan_gap = (t_u16)data[1];
15518 done:
15519 LEAVE();
15520 return ret;
15521 }
15522 #endif
15523 #endif
15524
15525 /**
15526 * @brief Set/Get control to coex RX window size configuration
15527 *
15528 * @param priv Pointer to moal_private structure
15529 * @param respbuf Pointer to response buffer
15530 * @param resplen Response buffer length
15531 *
15532 * @return Number of bytes written, negative for failure.
15533 */
woal_priv_coex_rx_winsize(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15534 static int woal_priv_coex_rx_winsize(moal_private *priv, t_u8 *respbuf,
15535 t_u32 respbuflen)
15536 {
15537 int ret = 0;
15538 int user_data_len = 0, header_len = 0, data = 0;
15539 mlan_ioctl_req *req = NULL;
15540 mlan_ds_11n_cfg *cfg_11n = NULL;
15541 mlan_status status = MLAN_STATUS_SUCCESS;
15542
15543 ENTER();
15544
15545 if (!priv || !priv->phandle) {
15546 PRINTM(MERROR, "priv or handle is null\n");
15547 ret = -EFAULT;
15548 goto done;
15549 }
15550
15551 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_COEX_RX_WINSIZE);
15552
15553 /* Allocate an IOCTL request buffer */
15554 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
15555 if (req == NULL) {
15556 ret = -ENOMEM;
15557 goto done;
15558 }
15559
15560 /* Fill request buffer */
15561 req->req_id = MLAN_IOCTL_11N_CFG;
15562 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
15563 cfg_11n->sub_command = MLAN_OID_11N_CFG_COEX_RX_WINSIZE;
15564
15565 if ((int)strlen(respbuf) == header_len) {
15566 /* GET operation */
15567 user_data_len = 0;
15568 req->action = MLAN_ACT_GET;
15569 } else {
15570 /* SET operation */
15571 parse_arguments(respbuf + header_len, &data,
15572 sizeof(data) / sizeof(int), &user_data_len);
15573 if (user_data_len != 1) {
15574 PRINTM(MERROR, "Invalid number of args! %d\n",
15575 user_data_len);
15576 ret = -EINVAL;
15577 goto done;
15578 }
15579 if ((data != MTRUE) && (data != MFALSE)) {
15580 PRINTM(MERROR,
15581 "Invalid coex RX window size parameter %d\n",
15582 data);
15583 ret = -EINVAL;
15584 goto done;
15585 }
15586 cfg_11n->param.coex_rx_winsize = data;
15587 req->action = MLAN_ACT_SET;
15588 }
15589
15590 /* Send IOCTL request to MLAN */
15591 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15592 if (status != MLAN_STATUS_SUCCESS) {
15593 ret = -EFAULT;
15594 goto done;
15595 }
15596
15597 if (!user_data_len) {
15598 moal_memcpy_ext(priv->phandle, respbuf,
15599 (t_u8 *)&cfg_11n->param.coex_rx_winsize,
15600 sizeof(t_u32), respbuflen);
15601 ret = sizeof(t_u32);
15602 }
15603
15604 done:
15605 if (status != MLAN_STATUS_PENDING)
15606 kfree(req);
15607
15608 LEAVE();
15609 return ret;
15610 }
15611
15612 /**
15613 * @brief Set/Get control to TX AMPDU configuration on infra link
15614 *
15615 * @param priv Pointer to moal_private structure
15616 * @param respbuf Pointer to response buffer
15617 * @param resplen Response buffer length
15618 *
15619 * @return Number of bytes written, negative for failure.
15620 */
woal_priv_txaggrctrl(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15621 static int woal_priv_txaggrctrl(moal_private *priv, t_u8 *respbuf,
15622 t_u32 respbuflen)
15623 {
15624 int ret = 0;
15625 int user_data_len = 0, header_len = 0, data = 0;
15626 mlan_ioctl_req *req = NULL;
15627 mlan_ds_11n_cfg *cfg_11n = NULL;
15628 mlan_status status = MLAN_STATUS_SUCCESS;
15629
15630 ENTER();
15631
15632 if (!priv || !priv->phandle) {
15633 PRINTM(MERROR, "priv or handle is null\n");
15634 ret = -EFAULT;
15635 goto done;
15636 }
15637
15638 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AGGR_CTRL);
15639
15640 /* Allocate an IOCTL request buffer */
15641 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
15642 if (req == NULL) {
15643 ret = -ENOMEM;
15644 goto done;
15645 }
15646
15647 /* Fill request buffer */
15648 req->req_id = MLAN_IOCTL_11N_CFG;
15649 cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
15650 cfg_11n->sub_command = MLAN_OID_11N_CFG_TX_AGGR_CTRL;
15651
15652 if ((int)strlen(respbuf) == header_len) {
15653 /* GET operation */
15654 user_data_len = 0;
15655 req->action = MLAN_ACT_GET;
15656 } else {
15657 /* SET operation */
15658 parse_arguments(respbuf + header_len, &data,
15659 sizeof(data) / sizeof(int), &user_data_len);
15660 if (user_data_len != 1) {
15661 PRINTM(MERROR, "Invalid number of args! %d\n",
15662 user_data_len);
15663 ret = -EINVAL;
15664 goto done;
15665 }
15666 if ((data != MTRUE) && (data != MFALSE)) {
15667 PRINTM(MERROR, "Invalid txaggrctrl parameter %d\n",
15668 data);
15669 ret = -EINVAL;
15670 goto done;
15671 }
15672 cfg_11n->param.txaggrctrl = data;
15673 req->action = MLAN_ACT_SET;
15674 }
15675
15676 /* Send IOCTL request to MLAN */
15677 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15678 if (status != MLAN_STATUS_SUCCESS) {
15679 ret = -EFAULT;
15680 goto done;
15681 }
15682
15683 if (!user_data_len) {
15684 moal_memcpy_ext(priv->phandle, respbuf,
15685 (t_u8 *)&cfg_11n->param.txaggrctrl,
15686 sizeof(t_u32), respbuflen);
15687 ret = sizeof(t_u32);
15688 }
15689
15690 done:
15691 if (status != MLAN_STATUS_PENDING)
15692 kfree(req);
15693
15694 LEAVE();
15695 return ret;
15696 }
15697
15698 /**
15699 * @brief Set/Get control to enable/disable auto TDLS
15700 *
15701 * @param priv Pointer to moal_private structure
15702 * @param respbuf Pointer to response buffer
15703 * @param resplen Response buffer length
15704 *
15705 * @return Number of bytes written, negative for failure.
15706 */
woal_priv_auto_tdls(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15707 static int woal_priv_auto_tdls(moal_private *priv, t_u8 *respbuf,
15708 t_u32 respbuflen)
15709 {
15710 int ret = 0;
15711 int user_data_len = 0, header_len = 0, data = 0;
15712
15713 ENTER();
15714
15715 if (!priv || !priv->phandle) {
15716 PRINTM(MERROR, "priv or handle is null\n");
15717 ret = -EFAULT;
15718 goto done;
15719 }
15720
15721 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_TDLS);
15722
15723 if ((int)strlen(respbuf) == header_len) {
15724 /* GET operation */
15725 data = priv->enable_auto_tdls;
15726 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
15727 sizeof(data), respbuflen);
15728 ret = sizeof(data);
15729 } else {
15730 /* SET operation */
15731 parse_arguments(respbuf + header_len, &data,
15732 sizeof(data) / sizeof(int), &user_data_len);
15733 if (user_data_len != 1) {
15734 PRINTM(MERROR, "Invalid number of args! %d\n",
15735 user_data_len);
15736 ret = -EINVAL;
15737 goto done;
15738 }
15739 if ((data != MTRUE) && (data != MFALSE)) {
15740 PRINTM(MERROR, "Invalid autotdls parameter %d\n", data);
15741 ret = -EINVAL;
15742 goto done;
15743 }
15744 priv->enable_auto_tdls = (t_u8)data;
15745 }
15746
15747 done:
15748 LEAVE();
15749 return ret;
15750 }
15751
15752 #ifdef PCIE
15753 /**
15754 * @brief Read/Write PCIE register
15755 *
15756 * @param priv Pointer to moal_private structure
15757 * @param respbuf Pointer to response buffer
15758 * @param resplen Response buffer length
15759 *
15760 * @return Number of bytes written, negative for failure.
15761 */
woal_priv_pcie_reg_rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15762 static int woal_priv_pcie_reg_rw(moal_private *priv, t_u8 *respbuf,
15763 t_u32 respbuflen)
15764 {
15765 moal_handle *handle = priv->phandle;
15766 int data[3];
15767 t_u32 reg;
15768 t_u32 value;
15769 int ret = MLAN_STATUS_SUCCESS;
15770 int user_data_len = 0, header_len = 0;
15771
15772 ENTER();
15773
15774 memset(data, 0, sizeof(data));
15775 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_REG_RW);
15776 if ((int)strlen(respbuf) == header_len) {
15777 PRINTM(MERROR, "Invalid number of parameters\n");
15778 ret = -EINVAL;
15779 goto done;
15780 }
15781
15782 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15783 &user_data_len);
15784 if ((user_data_len != 1) && (user_data_len != 2)) {
15785 PRINTM(MERROR, "Invalid number of parameters\n");
15786 ret = -EINVAL;
15787 goto done;
15788 }
15789
15790 reg = (t_u32)data[0];
15791 if (user_data_len == 1) {
15792 if (moal_read_reg(handle, reg, &value)) {
15793 ret = -EFAULT;
15794 goto done;
15795 }
15796 data[1] = value;
15797 } else {
15798 value = data[1];
15799 if (moal_write_reg(handle, reg, value)) {
15800 ret = -EFAULT;
15801 goto done;
15802 }
15803 }
15804 moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
15805 respbuflen);
15806 ret = sizeof(data);
15807
15808 done:
15809 LEAVE();
15810 return ret;
15811 }
15812
15813 /**
15814 * @brief Read/Write PCIE register/memory from BAR0
15815 *
15816 * @param priv Pointer to moal_private structure
15817 * @param respbuf Pointer to response buffer
15818 * @param resplen Response buffer length
15819 *
15820 * @return Number of bytes written, negative for failure.
15821 */
woal_priv_pcie_bar0_reg_rw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15822 static int woal_priv_pcie_bar0_reg_rw(moal_private *priv, t_u8 *respbuf,
15823 t_u32 respbuflen)
15824 {
15825 moal_handle *handle = priv->phandle;
15826 pcie_service_card *card = (pcie_service_card *)handle->card;
15827 int data[3];
15828 t_u32 reg;
15829 t_u32 value;
15830 int ret = MLAN_STATUS_SUCCESS;
15831 int user_data_len = 0, header_len = 0;
15832
15833 ENTER();
15834
15835 memset(data, 0, sizeof(data));
15836 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_BAR0_REG_RW);
15837 if ((int)strlen(respbuf) == header_len) {
15838 PRINTM(MERROR, "Invalid number of parameters\n");
15839 ret = -EINVAL;
15840 goto done;
15841 }
15842
15843 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
15844 &user_data_len);
15845 if ((user_data_len != 1) && (user_data_len != 2)) {
15846 PRINTM(MERROR, "Invalid number of parameters\n");
15847 ret = -EINVAL;
15848 goto done;
15849 }
15850
15851 reg = (t_u32)data[0];
15852 if (user_data_len == 1) {
15853 value = ioread32(card->pci_mmap + reg);
15854 if (value == MLAN_STATUS_FAILURE) {
15855 ret = -EFAULT;
15856 goto done;
15857 }
15858 data[1] = value;
15859 } else {
15860 value = data[1];
15861 iowrite32(value, card->pci_mmap + reg);
15862 }
15863 moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data),
15864 respbuflen);
15865 ret = sizeof(data);
15866
15867 done:
15868 LEAVE();
15869 return ret;
15870 }
15871 #endif
15872
15873 /**
15874 * @brief Get SOC temperature
15875 *
15876 * @param priv Pointer to moal_private structure
15877 * @param respbuf Pointer to response buffer
15878 * @param resplen Response buffer length
15879 *
15880 * @return Number of bytes written, negative for failure.
15881 */
woal_priv_get_sensor_temp(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15882 static int woal_priv_get_sensor_temp(moal_private *priv, t_u8 *respbuf,
15883 t_u32 respbuflen)
15884 {
15885 mlan_ioctl_req *req = NULL;
15886 mlan_ds_misc_cfg *pcfg = NULL;
15887 int ret = 0;
15888 mlan_status status = MLAN_STATUS_SUCCESS;
15889
15890 ENTER();
15891
15892 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
15893 if (req == NULL) {
15894 ret = -ENOMEM;
15895 goto done;
15896 }
15897
15898 pcfg = (mlan_ds_misc_cfg *)req->pbuf;
15899 pcfg->sub_command = MLAN_OID_MISC_GET_SENSOR_TEMP;
15900 req->req_id = MLAN_IOCTL_MISC_CFG;
15901 req->action = MLAN_ACT_GET;
15902
15903 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
15904 if (status != MLAN_STATUS_SUCCESS) {
15905 ret = -EFAULT;
15906 goto done;
15907 }
15908
15909 memset(respbuf, 0, respbuflen);
15910 moal_memcpy_ext(priv->phandle, respbuf,
15911 &pcfg->param.sensor_temp.temperature, sizeof(t_u32),
15912 respbuflen);
15913
15914 ret = sizeof(t_u32);
15915
15916 done:
15917 if (status != MLAN_STATUS_PENDING)
15918 kfree(req);
15919 LEAVE();
15920 return ret;
15921 }
15922
15923 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
15924 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
15925 /**
15926 * @brief Enable/disable DFS offload
15927 *
15928 * @param priv Pointer to moal_private structure
15929 * @param respbuf Pointer to response buffer
15930 * @param resplen Response buffer length
15931 *
15932 * @return Number of bytes written, negative for failure.
15933 */
woal_priv_dfs_offload_enable(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15934 static int woal_priv_dfs_offload_enable(moal_private *priv, t_u8 *respbuf,
15935 t_u32 respbuflen)
15936 {
15937 int ret = 0, dfs_offload_en = 0, user_data_len = 0, header_len = 0,
15938 dfs_offload;
15939
15940 ENTER();
15941
15942 if (!priv) {
15943 PRINTM(MERROR, "priv is NULL\n");
15944 ret = -EFAULT;
15945 goto done;
15946 }
15947
15948 dfs_offload = moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD);
15949 if (woal_is_any_interface_active(priv->phandle)) {
15950 PRINTM(MERROR,
15951 "DFS offload enable/disable do not allowed after BSS started!\n");
15952 ret = -EFAULT;
15953 goto done;
15954 }
15955 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_OFFLOAD);
15956 parse_arguments(respbuf + header_len, &dfs_offload_en,
15957 sizeof(dfs_offload_en) / sizeof(int), &user_data_len);
15958 if (user_data_len != 1) {
15959 PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len);
15960 ret = -EINVAL;
15961 goto done;
15962 }
15963
15964 if (dfs_offload_en != 0 && dfs_offload_en != 1) {
15965 PRINTM(MERROR, "Invalid args!\n");
15966 ret = -EINVAL;
15967 goto done;
15968 }
15969 if (dfs_offload != dfs_offload_en) {
15970 dfs_offload = dfs_offload_en;
15971 if (dfs_offload)
15972 moal_extflg_set(priv->phandle, EXT_DFS_OFFLOAD);
15973 else
15974 moal_extflg_clear(priv->phandle, EXT_DFS_OFFLOAD);
15975 }
15976 done:
15977 LEAVE();
15978 return ret;
15979 }
15980 #endif
15981 #endif
15982
15983 /**
15984 * @brief Set/Get TDLS CS off channel value
15985 *
15986 * @param priv Pointer to moal_private structure
15987 * @param respbuf Pointer to response buffer
15988 * @param resplen Response buffer length
15989
15990 * @return Number of bytes written, negative for failure.
15991 */
woal_priv_tdls_cs_chan(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)15992 static int woal_priv_tdls_cs_chan(moal_private *priv, t_u8 *respbuf,
15993 t_u32 respbuflen)
15994 {
15995 mlan_ioctl_req *ioctl_req = NULL;
15996 mlan_ds_misc_cfg *misc = NULL;
15997 mlan_status status = MLAN_STATUS_SUCCESS;
15998 int ret = 0;
15999 int user_data_len = 0, header_len = 0, data = 0;
16000
16001 ENTER();
16002
16003 if (!priv || !priv->phandle) {
16004 PRINTM(MERROR, "priv or handle is null\n");
16005 ret = -EFAULT;
16006 goto done;
16007 }
16008
16009 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16010 if (ioctl_req == NULL) {
16011 ret = -ENOMEM;
16012 goto done;
16013 }
16014
16015 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16016 misc->sub_command = MLAN_OID_MISC_TDLS_CS_CHANNEL;
16017 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16018
16019 header_len = strlen("TDLS_CS_CHAN");
16020 if ((int)strlen(respbuf) == header_len) {
16021 /* GET operation */
16022 ioctl_req->action = MLAN_ACT_GET;
16023 } else {
16024 /* SET operation */
16025 parse_arguments(respbuf + header_len + 1, &data,
16026 sizeof(data) / sizeof(int), &user_data_len);
16027 if (user_data_len != 1) {
16028 PRINTM(MERROR, "Invalid number of args! %d\n",
16029 user_data_len);
16030 ret = -EINVAL;
16031 goto done;
16032 }
16033 ioctl_req->action = MLAN_ACT_SET;
16034 misc->param.tdls_cs_channel = (t_u8)data;
16035 }
16036
16037 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16038 if (status != MLAN_STATUS_SUCCESS) {
16039 ret = -EFAULT;
16040 goto done;
16041 }
16042
16043 ret = sprintf(respbuf, "off channel %d\n",
16044 misc->param.tdls_cs_channel) +
16045 1;
16046
16047 PRINTM(MIOCTL, "tdls CS channel %d\n", misc->param.tdls_cs_channel);
16048 done:
16049 if (status != MLAN_STATUS_PENDING)
16050 kfree(ioctl_req);
16051
16052 LEAVE();
16053 return ret;
16054 }
16055 /**
16056 * @brief Set/Get TDLS idle timeout value
16057 *
16058 * @param priv Pointer to moal_private structure
16059 * @param respbuf Pointer to response buffer
16060 * @param resplen Response buffer length
16061
16062 * @return Number of bytes written, negative for failure.
16063 */
woal_priv_tdls_idle_time(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16064 static int woal_priv_tdls_idle_time(moal_private *priv, t_u8 *respbuf,
16065 t_u32 respbuflen)
16066 {
16067 mlan_ioctl_req *ioctl_req = NULL;
16068 mlan_ds_misc_cfg *misc = NULL;
16069 mlan_status status = MLAN_STATUS_SUCCESS;
16070 int ret = 0;
16071 int user_data_len = 0, header_len = 0, data = 0;
16072
16073 ENTER();
16074
16075 if (!priv || !priv->phandle) {
16076 PRINTM(MERROR, "priv or handle is null\n");
16077 ret = -EFAULT;
16078 goto done;
16079 }
16080
16081 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16082 if (ioctl_req == NULL) {
16083 ret = -ENOMEM;
16084 goto done;
16085 }
16086
16087 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16088 misc->sub_command = MLAN_OID_MISC_TDLS_IDLE_TIME;
16089 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16090
16091 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TDLS_IDLE_TIME);
16092 if ((int)strlen(respbuf) == header_len) {
16093 /* GET operation */
16094 ioctl_req->action = MLAN_ACT_GET;
16095 } else {
16096 /* SET operation */
16097 parse_arguments(respbuf + header_len, &data,
16098 sizeof(data) / sizeof(int), &user_data_len);
16099 if (user_data_len != 1) {
16100 PRINTM(MERROR, "Invalid number of args! %d\n",
16101 user_data_len);
16102 ret = -EINVAL;
16103 goto done;
16104 }
16105 ioctl_req->action = MLAN_ACT_SET;
16106 misc->param.tdls_idle_time = (t_u16)data;
16107 }
16108
16109 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16110 if (status != MLAN_STATUS_SUCCESS) {
16111 ret = -EFAULT;
16112 goto done;
16113 }
16114
16115 moal_memcpy_ext(priv->phandle, respbuf,
16116 (t_u8 *)&misc->param.tdls_idle_time, sizeof(t_u16),
16117 respbuflen);
16118 ret = sizeof(t_u16);
16119
16120 PRINTM(MIOCTL, "tdls idle time %d\n", misc->param.tdls_idle_time);
16121 done:
16122 if (status != MLAN_STATUS_PENDING)
16123 kfree(ioctl_req);
16124
16125 LEAVE();
16126 return ret;
16127 }
16128
16129 /**
16130 * @brief Set/Get dynamic bandwidth
16131 *
16132 * @param priv Pointer to moal_private structure
16133 * @param respbuf Pointer to response buffer
16134 * @param resplen Response buffer length
16135
16136 * @return Number of bytes written, negative for failure.
16137 */
woal_priv_config_dyn_bw(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16138 static int woal_priv_config_dyn_bw(moal_private *priv, t_u8 *respbuf,
16139 t_u32 respbuflen)
16140 {
16141 mlan_ioctl_req *ioctl_req = NULL;
16142 mlan_ds_misc_cfg *misc = NULL;
16143 mlan_status status = MLAN_STATUS_SUCCESS;
16144 int ret = 0;
16145 int user_data_len = 0, header_len = 0, data = 0;
16146
16147 ENTER();
16148
16149 if (!priv || !priv->phandle) {
16150 PRINTM(MERROR, "priv or handle is null\n");
16151 ret = -EFAULT;
16152 goto done;
16153 }
16154
16155 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16156 if (ioctl_req == NULL) {
16157 ret = -ENOMEM;
16158 goto done;
16159 }
16160
16161 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16162 misc->sub_command = MLAN_OID_MISC_DYN_BW;
16163 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16164
16165 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DYN_BW);
16166 if ((int)strlen(respbuf) == header_len) {
16167 /* GET operation */
16168 ioctl_req->action = MLAN_ACT_GET;
16169 } else {
16170 /* SET operation */
16171 parse_arguments(respbuf + header_len, &data,
16172 sizeof(data) / sizeof(int), &user_data_len);
16173 if (user_data_len != 1) {
16174 PRINTM(MERROR, "Invalid number of args! %d\n",
16175 user_data_len);
16176 ret = -EINVAL;
16177 goto done;
16178 }
16179 ioctl_req->action = MLAN_ACT_SET;
16180 misc->param.dyn_bw = (t_u16)data;
16181 }
16182
16183 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16184 if (status != MLAN_STATUS_SUCCESS) {
16185 ret = -EFAULT;
16186 goto done;
16187 }
16188
16189 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.dyn_bw,
16190 sizeof(t_u16), respbuflen);
16191 ret = sizeof(t_u16);
16192
16193 PRINTM(MIOCTL, "Dynamic bandwidth %d\n", misc->param.dyn_bw);
16194 done:
16195 if (status != MLAN_STATUS_PENDING)
16196 kfree(ioctl_req);
16197
16198 LEAVE();
16199 return ret;
16200 }
16201
16202 #if defined(UAP_SUPPORT)
16203 /**
16204 * @brief Check validation of channel and oper class
16205 *
16206 * @param priv Pointer to moal_private structure
16207 * @param channel channel
16208 * @param oper_class oper_class
16209
16210 * @return SUCCESS/FAIL
16211 */
woal_check_valid_channel_operclass(moal_private * priv,int channel,int oper_class)16212 static int woal_check_valid_channel_operclass(moal_private *priv, int channel,
16213 int oper_class)
16214 {
16215 int ret = 0;
16216 mlan_ioctl_req *ioctl_req = NULL;
16217 mlan_ds_misc_cfg *misc = NULL;
16218 mlan_status status = MLAN_STATUS_SUCCESS;
16219
16220 ENTER();
16221
16222 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16223 if (ioctl_req == NULL) {
16224 ret = -ENOMEM;
16225 goto done;
16226 }
16227
16228 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16229 misc->sub_command = MLAN_OID_MISC_OPER_CLASS_CHECK;
16230 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16231 ioctl_req->action = MLAN_ACT_GET;
16232 misc->param.bw_chan_oper.oper_class = (t_u8)oper_class;
16233 misc->param.bw_chan_oper.channel = (t_u8)channel;
16234
16235 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16236 if (status != MLAN_STATUS_SUCCESS) {
16237 ret = -EFAULT;
16238 goto done;
16239 }
16240
16241 done:
16242 if (status != MLAN_STATUS_PENDING)
16243 kfree(ioctl_req);
16244
16245 LEAVE();
16246 return ret;
16247 }
16248
16249 /**
16250 * @brief Enable radar detect for DFS channel
16251 *
16252 * @param priv A pointer to moal private structure
16253 * @param chan channel
16254 * @return N/A
16255 */
woal_enable_dfs(moal_private * priv,t_u8 channel,t_u8 wait_option)16256 static void woal_enable_dfs(moal_private *priv, t_u8 channel, t_u8 wait_option)
16257 {
16258 mlan_ioctl_req *req = NULL;
16259 mlan_ds_11h_chan_rep_req *pchan_rpt_req = NULL;
16260 mlan_ds_11h_cfg *p11h_cfg = NULL;
16261 mlan_status status = MLAN_STATUS_SUCCESS;
16262 ENTER();
16263 PRINTM(MCMND, "Enable Radar detect, chan %d\n", channel);
16264 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
16265 if (NULL == req) {
16266 PRINTM(MIOCTL, "No Memory to allocate ioctl buffer\n");
16267 LEAVE();
16268 return;
16269 }
16270 p11h_cfg = (mlan_ds_11h_cfg *)req->pbuf;
16271 pchan_rpt_req = &p11h_cfg->param.chan_rpt_req;
16272 pchan_rpt_req->startFreq = 5000;
16273 pchan_rpt_req->chanNum = channel;
16274 pchan_rpt_req->host_based = MTRUE;
16275 pchan_rpt_req->millisec_dwell_time = 0;
16276
16277 p11h_cfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK;
16278 req->req_id = MLAN_IOCTL_11H_CFG;
16279 req->action = MLAN_ACT_SET;
16280 /* Send Channel Check command and wait until the report is ready */
16281 status = woal_request_ioctl(priv, req, wait_option);
16282 if (status != MLAN_STATUS_PENDING)
16283 kfree(req);
16284 LEAVE();
16285 return;
16286 }
16287
16288 /**
16289 * @brief send CSA/ECSA action frame
16290 *
16291 ** @param priv Pointer to moal_private structure
16292 * @param block_tx 0-no need block traffic 1- need block traffic
16293 * @param oper_class oper_class
16294 * @param channel channel
16295 * @param switch count how many csa/ecsa beacon will send out
16296 * @param wait_option
16297 *
16298 * @return channel center frequency center, if found; O, otherwise
16299 */
woal_action_channel_switch(moal_private * priv,t_u8 block_tx,t_u8 oper_class,t_u8 channel,t_u8 switch_count,t_u8 wait_option)16300 static int woal_action_channel_switch(moal_private *priv, t_u8 block_tx,
16301 t_u8 oper_class, t_u8 channel,
16302 t_u8 switch_count, t_u8 wait_option)
16303 {
16304 mlan_status ret = MLAN_STATUS_SUCCESS;
16305 mlan_ds_bss *bss = NULL;
16306 mlan_ioctl_req *req = NULL;
16307
16308 ENTER();
16309
16310 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
16311 if (req == NULL) {
16312 ret = MLAN_STATUS_FAILURE;
16313 goto done;
16314 }
16315
16316 bss = (mlan_ds_bss *)req->pbuf;
16317 bss->sub_command = MLAN_OID_ACTION_CHAN_SWITCH;
16318 req->req_id = MLAN_IOCTL_BSS;
16319 req->action = MLAN_ACT_SET;
16320 bss->param.chanswitch.chan_switch_mode = block_tx;
16321 bss->param.chanswitch.new_channel_num = channel;
16322 if (!switch_count)
16323 bss->param.chanswitch.chan_switch_count = DEF_NUM_PKTS;
16324 else
16325 bss->param.chanswitch.chan_switch_count =
16326 MIN(switch_count, MAX_NUM_PKTS);
16327 bss->param.chanswitch.new_oper_class = oper_class;
16328 ret = woal_request_ioctl(priv, req, wait_option);
16329 done:
16330 if (ret != MLAN_STATUS_PENDING)
16331 kfree(req);
16332 LEAVE();
16333 return ret;
16334 }
16335
16336 #ifdef UAP_SUPPORT
16337 /**
16338 * @brief move the uAP to transition channel
16339 *
16340 * @param priv Pointer to moal_private structure
16341 *
16342 * @return N/A
16343 */
woal_move_to_next_channel(moal_private * priv)16344 void woal_move_to_next_channel(moal_private *priv)
16345 {
16346 mlan_ds_11h_chan_dfs_state ch_dfs;
16347 t_u8 next_chan = 0;
16348 if (priv->target_chan) {
16349 next_chan = priv->target_chan;
16350 priv->target_chan = 0;
16351 } else if (priv->backup_chan) {
16352 next_chan = priv->backup_chan;
16353 }
16354 if (!next_chan)
16355 return;
16356 memset(&ch_dfs, 0, sizeof(ch_dfs));
16357 ch_dfs.channel = next_chan;
16358 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs))
16359 PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
16360 __func__);
16361 if (ch_dfs.dfs_required)
16362 woal_enable_dfs(priv, next_chan, MOAL_NO_WAIT);
16363 woal_action_channel_switch(priv, MTRUE, 0, next_chan, 0, MOAL_NO_WAIT);
16364 return;
16365 }
16366 #endif
16367
16368 /**
16369 * @brief Set extended channel switch ie
16370 *
16371 * @param priv Pointer to moal_private structure
16372 * @param respbuf Pointer to response buffer
16373 * @param resplen Response buffer length
16374 *
16375 * @return Number of bytes written, negative for failure.
16376 */
woal_priv_extend_channel_switch(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16377 static int woal_priv_extend_channel_switch(moal_private *priv, t_u8 *respbuf,
16378 t_u32 respbuflen)
16379 {
16380 int ret = 0;
16381 int user_data_len = 0;
16382 int data[5] = {0};
16383 t_u8 channel;
16384 mlan_ds_11h_chan_dfs_state ch_dfs;
16385 ENTER();
16386
16387 if (!priv || !priv->phandle || (priv->bss_role != MLAN_BSS_ROLE_UAP) ||
16388 (priv->bss_started != MTRUE)) {
16389 PRINTM(MERROR,
16390 "priv or handle is null or interface is not AP/GO"
16391 "or AP is not started\n");
16392 ret = -EFAULT;
16393 LEAVE();
16394 return ret;
16395 }
16396
16397 parse_arguments(respbuf + strlen(CMD_NXP) +
16398 strlen(PRIV_CMD_EXTEND_CHAN_SWITCH),
16399 data, ARRAY_SIZE(data), &user_data_len);
16400
16401 if (sizeof(int) * user_data_len > sizeof(data)) {
16402 PRINTM(MERROR, "Too many arguments\n");
16403 ret = -EINVAL;
16404 LEAVE();
16405 return ret;
16406 }
16407 if (user_data_len < 4) {
16408 PRINTM(MERROR, "Too few arguments\n");
16409 ret = -EINVAL;
16410 LEAVE();
16411 return ret;
16412 }
16413
16414 /* For 2.4G channels skip the DFS checks */
16415 channel = data[2];
16416 if (channel > MAX_BG_CHANNEL) {
16417 memset(&ch_dfs, 0, sizeof(ch_dfs));
16418 ch_dfs.channel = data[2];
16419
16420 if (woal_11h_chan_dfs_state(priv, MLAN_ACT_GET, &ch_dfs)) {
16421 PRINTM(MERROR, "%s: woal_11h_chan_dfs_state failed \n",
16422 __func__);
16423 ret = -EFAULT;
16424 LEAVE();
16425 return ret;
16426 }
16427
16428 if (ch_dfs.dfs_required &&
16429 (ch_dfs.dfs_state == DFS_UNAVAILABLE ||
16430 ch_dfs.dfs_state == DFS_USABLE)) {
16431 PRINTM(MERROR,
16432 "DFS: Channel=%d is not Available, cannot switch to this channel\n",
16433 data[2]);
16434 ret = -EFAULT;
16435 LEAVE();
16436 return ret;
16437 }
16438
16439 if (ch_dfs.dfs_required)
16440 woal_enable_dfs(priv, data[2], MOAL_IOCTL_WAIT);
16441 }
16442 if (data[1]) {
16443 if (woal_check_valid_channel_operclass(priv, data[2],
16444 data[1])) {
16445 PRINTM(MERROR, "Wrong channel switch parameters!\n");
16446 ret = -EINVAL;
16447 goto done;
16448 }
16449 }
16450 if (data[3])
16451 woal_channel_switch(priv, data[0], data[1], data[2], data[3],
16452 data[4], MFALSE);
16453 else
16454 woal_action_channel_switch(priv, data[0], data[1], data[2],
16455 data[4], MOAL_IOCTL_WAIT);
16456 done:
16457 LEAVE();
16458 return ret;
16459 }
16460
16461 /**
16462 * @brief P2P extended channel switch
16463 *
16464 * @param priv Pointer to moal_private structure
16465 * @param respbuf Pointer to response buffer
16466 * @param resplen Response buffer length
16467
16468 * @return Number of bytes written, negative for failure.
16469 */
woal_priv_p2p_ecsa(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16470 static int woal_priv_p2p_ecsa(moal_private *priv, t_u8 *respbuf,
16471 t_u32 respbuflen)
16472 {
16473 int ret = 0;
16474 int user_data_len = 0, header_len = 0;
16475 int data[2] = {0};
16476 t_u8 bw = 0, oper_class = 0, channel = 0;
16477 IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL;
16478 custom_ie *pcust_chansw_ie = NULL;
16479 mlan_ioctl_req *ioctl_req = NULL;
16480 mlan_ds_misc_cfg *misc = NULL;
16481 mlan_status status = MLAN_STATUS_SUCCESS;
16482
16483 ENTER();
16484
16485 if (!priv || !priv->phandle) {
16486 PRINTM(MERROR, "priv or handle is null\n");
16487 ret = -EFAULT;
16488 goto done;
16489 }
16490
16491 if (priv->bss_role != MLAN_BSS_ROLE_UAP) {
16492 PRINTM(MERROR,
16493 "Extended Channel Switch is only allowed for AP/GO mode\n");
16494 ret = -EFAULT;
16495 goto done;
16496 }
16497
16498 if (priv->bss_started != MTRUE) {
16499 PRINTM(MERROR, "AP is not started!\n");
16500 ret = -EFAULT;
16501 goto done;
16502 }
16503
16504 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16505 if (ioctl_req == NULL) {
16506 ret = -ENOMEM;
16507 goto done;
16508 }
16509
16510 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16511 misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
16512 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16513 ioctl_req->action = MLAN_ACT_SET;
16514 misc->param.cust_ie.type = TLV_TYPE_MGMT_IE;
16515 misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
16516
16517 pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0];
16518 pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
16519 pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ExtChanSwitchAnn_t);
16520 pcust_chansw_ie->mgmt_subtype_mask =
16521 MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for
16522 BEACON/probe resp*/
16523 ext_chan_switch =
16524 (IEEEtypes_ExtChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
16525
16526 header_len = strlen("P2P_ECSA");
16527 parse_arguments(respbuf + header_len + 1, data, ARRAY_SIZE(data),
16528 &user_data_len);
16529
16530 if (user_data_len != 2) {
16531 PRINTM(MERROR, "Invalid parameters\n");
16532 ret = -EFAULT;
16533 goto done;
16534 }
16535
16536 channel = data[0];
16537 /* bandwidth 20:20M 40:40M 80:80M*/
16538 bw = data[1];
16539 if (bw != 20 && bw != 40 && bw != 80) {
16540 PRINTM(MERROR, "Unsupported bandwidth\n");
16541 ret = -EINVAL;
16542 goto done;
16543 }
16544 if (channel >= 52 && channel <= 144) {
16545 PRINTM(MERROR, "Switch to DFS channel is not allowed!\n");
16546 ret = -EINVAL;
16547 goto done;
16548 }
16549
16550 woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, channel,
16551 &oper_class);
16552 if (oper_class == 0) {
16553 PRINTM(MERROR, "Wrong parameters!\n");
16554 ret = -EFAULT;
16555 goto done;
16556 }
16557 ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN;
16558 ext_chan_switch->len = 4;
16559 ext_chan_switch->chan_switch_mode = 1;
16560 ext_chan_switch->new_oper_class = oper_class;
16561 ext_chan_switch->new_channel_num = channel;
16562 ext_chan_switch->chan_switch_count = DEF_CHAN_SWITCH_COUNT;
16563
16564 if (ext_chan_switch->chan_switch_mode) {
16565 if (netif_carrier_ok(priv->netdev))
16566 netif_carrier_off(priv->netdev);
16567 woal_stop_queue(priv->netdev);
16568 priv->uap_tx_blocked = MTRUE;
16569 }
16570
16571 DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer,
16572 pcust_chansw_ie->ie_length);
16573
16574 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16575 if (status != MLAN_STATUS_SUCCESS) {
16576 ret = -EFAULT;
16577 goto done;
16578 }
16579
16580 priv->phandle->chsw_wait_q_woken = MFALSE;
16581 /* wait for channel switch to complete */
16582 wait_event_interruptible_timeout(
16583 priv->phandle->chsw_wait_q, priv->phandle->chsw_wait_q_woken,
16584 (u32)HZ * (ext_chan_switch->chan_switch_count + 2) * 110 /
16585 1000);
16586
16587 pcust_chansw_ie->ie_index = 0xffff; /*Auto index */
16588 pcust_chansw_ie->mgmt_subtype_mask = 0;
16589 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16590 if (status != MLAN_STATUS_SUCCESS) {
16591 PRINTM(MERROR, "Failed to clear ECSA IE\n");
16592 }
16593 done:
16594 if (status != MLAN_STATUS_PENDING)
16595 kfree(ioctl_req);
16596
16597 LEAVE();
16598 return ret;
16599 }
16600 #endif
16601
16602 /**
16603 * @brief Set random mac configure value (ON/OFF)
16604 *
16605 * @param priv Pointer to moal_private structure
16606 * @param respbuf Pointer to response buffer
16607 * @param resplen Response buffer length
16608
16609 * @return Number of bytes written, negative for failure.
16610 */
woal_priv_config_random_mac(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16611 static int woal_priv_config_random_mac(moal_private *priv, t_u8 *respbuf,
16612 t_u32 respbuflen)
16613 {
16614 int ret = 0;
16615 int header_len = 0, space_len = 0, i;
16616 t_u8 rand_data[3];
16617 const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
16618
16619 ENTER();
16620
16621 if (!priv || !priv->phandle) {
16622 PRINTM(MERROR, "priv or handle is null\n");
16623 ret = -EFAULT;
16624 goto done;
16625 }
16626
16627 header_len = strlen("FAKEMAC");
16628 if ((int)strlen(respbuf) >= header_len) {
16629 for (i = 0; i < (int)(strlen(respbuf) - header_len - 1); i++) {
16630 if (respbuf[header_len + 1 + i] != ' ')
16631 break;
16632 }
16633 space_len = i;
16634
16635 if (strncmp(respbuf + header_len + 1 + space_len, "On",
16636 strlen("On")) == 0) {
16637 if (memcmp(priv->random_mac, zero_mac,
16638 MLAN_MAC_ADDR_LENGTH)) {
16639 ret = sprintf(respbuf,
16640 "FAKEMAC has been On\n") +
16641 1;
16642 goto done;
16643 }
16644 moal_memcpy_ext(priv->phandle, priv->random_mac,
16645 priv->current_addr, ETH_ALEN,
16646 MLAN_MAC_ADDR_LENGTH);
16647 get_random_bytes(rand_data, 3);
16648 moal_memcpy_ext(priv->phandle, priv->random_mac + 3,
16649 rand_data, 3, 3);
16650 PRINTM(MMSG, "FAKEMAC parameter is On\n");
16651 } else if (strncmp(respbuf + header_len + 1 + space_len, "Off",
16652 strlen("Off")) == 0) {
16653 memset(priv->random_mac, 0, ETH_ALEN);
16654 PRINTM(MMSG, "FAKEMAC parameter is Off\n");
16655 } else {
16656 PRINTM(MERROR, "Invalid parameter!\n");
16657 ret = -EINVAL;
16658 goto done;
16659 }
16660 } else {
16661 PRINTM(MERROR, "Invalid parameter!\n");
16662 ret = -EINVAL;
16663 goto done;
16664 }
16665
16666 done:
16667 LEAVE();
16668 return ret;
16669 }
16670
16671 /**
16672 * @brief enable/disable roaming offload to firmware
16673 *
16674 * @param priv Pointer to moal_private structure
16675 * @param respbuf Pointer to response buffer
16676 * @param resplen Response buffer length
16677
16678 * @return Number of bytes written, negative for failure.
16679 */
woal_priv_set_roam_offload(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16680 static int woal_priv_set_roam_offload(moal_private *priv, t_u8 *respbuf,
16681 t_u32 respbuflen)
16682 {
16683 int user_data_len = 0, header_len = 0, ret = 0;
16684 int data = 0;
16685 #ifdef STA_CFG80211
16686 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
16687 t_u8 enable = 0;
16688 #endif
16689 #endif
16690
16691 ENTER();
16692
16693 if (!priv || !priv->phandle) {
16694 PRINTM(MERROR, "priv or handle is null\n");
16695 ret = -EFAULT;
16696 goto done;
16697 }
16698
16699 #ifdef STA_CFG80211
16700 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16701 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16702 ret = -EFAULT;
16703 goto done;
16704 }
16705 #endif
16706 #endif
16707
16708 header_len = strlen("SETROAMOFFLOAD");
16709 parse_arguments(respbuf + header_len + 1, &data, 1, &user_data_len);
16710
16711 if (data < 0 || data > 5) {
16712 PRINTM(MERROR, "Invalid parameters\n");
16713 ret = -EFAULT;
16714 goto done;
16715 }
16716
16717 #ifdef STA_CFG80211
16718 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
16719 if (!data) {
16720 woal_cfg80211_vendor_event(priv, event_set_key_mgmt_offload,
16721 &enable, sizeof(enable));
16722 }
16723 #endif
16724 #endif
16725
16726 ret = woal_enable_fw_roaming(priv, data);
16727 done:
16728
16729 LEAVE();
16730 return ret;
16731 }
16732
16733 /**
16734 * @brief set roaming offload aplist to firmware
16735 *
16736 * @param priv Pointer to moal_private structure
16737 * @param respbuf Pointer to response buffer
16738 * @param resplen Response buffer length
16739
16740 * @return Number of bytes written, negative for failure.
16741 */
woal_priv_set_roam_offload_aplist(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16742 static int woal_priv_set_roam_offload_aplist(moal_private *priv, t_u8 *respbuf,
16743 t_u32 respbuflen)
16744 {
16745 mlan_ioctl_req *ioctl_req = NULL;
16746 mlan_ds_misc_cfg *misc = NULL;
16747 mlan_ds_misc_roam_offload *roam = NULL;
16748 mlan_ds_misc_roam_offload_aplist *aplist = NULL;
16749 mlan_status status = MLAN_STATUS_SUCCESS;
16750 int ret = 0, i = 0;
16751 int user_data_len = 0, header_len = 0;
16752 int ap_count = 0;
16753 char *begin = NULL, *end = NULL;
16754 t_u8 mac_addr[6];
16755
16756 ENTER();
16757
16758 if (!priv || !priv->phandle) {
16759 PRINTM(MERROR, "priv or handle is null\n");
16760 ret = -EFAULT;
16761 goto done;
16762 }
16763
16764 #ifdef STA_CFG80211
16765 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16766 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16767 ret = -EFAULT;
16768 goto done;
16769 }
16770 #endif
16771 #endif
16772
16773 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
16774 if (ioctl_req == NULL) {
16775 ret = -ENOMEM;
16776 goto done;
16777 }
16778
16779 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
16780 misc->sub_command = MLAN_OID_MISC_ROAM_OFFLOAD_APLIST;
16781 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
16782
16783 roam = (mlan_ds_misc_roam_offload *)&misc->param.roam_offload;
16784 /*Set enable to invalid value(valid: 0, 1, 2)*/
16785 roam->enable = 3;
16786 aplist = &roam->aplist;
16787
16788 header_len = strlen("SETROAMOFFLAPLIST");
16789 user_data_len = strlen(respbuf) - header_len;
16790 if (!user_data_len) {
16791 /* GET operation */
16792 ioctl_req->action = MLAN_ACT_GET;
16793 } else {
16794 begin = &respbuf[header_len + 1];
16795 end = begin;
16796 while (begin && *begin == ' ') {
16797 begin++;
16798 end++;
16799 }
16800 while (end && *end != ' ')
16801 end++;
16802 if (end != NULL)
16803 *end = '\0';
16804 end++;
16805 if (begin) {
16806 if (woal_atoi(&ap_count, begin) !=
16807 MLAN_STATUS_SUCCESS) {
16808 ret = -EINVAL;
16809 goto done;
16810 }
16811 }
16812 aplist->ap_num = ap_count;
16813 if (ap_count > 0 && ap_count <= MAX_AP_LIST) {
16814 /* SET operation */
16815 ioctl_req->action = MLAN_ACT_SET;
16816 for (i = 0; i < ap_count; i++) {
16817 begin = end;
16818 while (begin && *begin == ' ') {
16819 begin++;
16820 end++;
16821 }
16822 while (end && *end != ' ' && *end != '\0')
16823 end++;
16824 if (end == begin) {
16825 PRINTM(MERROR,
16826 "AP number %d is wrong\n",
16827 ap_count);
16828 ret = -EINVAL;
16829 goto done;
16830 }
16831 if (end != NULL)
16832 *end = '\0';
16833 end++;
16834 woal_mac2u8(mac_addr, begin);
16835 moal_memcpy_ext(priv->phandle,
16836 aplist->ap_mac[i], mac_addr,
16837 MLAN_MAC_ADDR_LENGTH,
16838 MLAN_MAC_ADDR_LENGTH);
16839 }
16840 } else {
16841 PRINTM(MERROR,
16842 "AP number is wrong.Support max 8 APs\n");
16843 ret = -EINVAL;
16844 goto done;
16845 }
16846 }
16847
16848 DBG_HEXDUMP(MERROR, "APLIST", (t_u8 *)aplist->ap_mac,
16849 aplist->ap_num * MLAN_MAC_ADDR_LENGTH);
16850 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
16851 if (status != MLAN_STATUS_SUCCESS) {
16852 ret = -EFAULT;
16853 goto done;
16854 }
16855
16856 done:
16857 if (status != MLAN_STATUS_PENDING)
16858 kfree(ioctl_req);
16859
16860 LEAVE();
16861 return ret;
16862 }
16863 /**
16864 * @brief Configure roaming offload to firmware
16865 *
16866 * @param priv Pointer to moal_private structure
16867 * @param respbuf Pointer to response buffer
16868 * @param resplen Response buffer length
16869
16870 * @return Number of bytes written, negative for failure.
16871 */
woal_priv_roam_offload_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)16872 static int woal_priv_roam_offload_cfg(moal_private *priv, t_u8 *respbuf,
16873 t_u32 respbuflen)
16874 {
16875 int ret = 0, user_data_len = 0, header_len = 0, data = 0;
16876 char *begin = NULL, *end = NULL, *pvariable_name = NULL;
16877 t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH];
16878 woal_roam_offload_cfg roam_offload_cfg;
16879 t_u8 len = 0;
16880 int count = 0, i = 0;
16881
16882 ENTER();
16883
16884 if (!priv || !priv->phandle) {
16885 PRINTM(MERROR, "priv or handle is null\n");
16886 ret = -EFAULT;
16887 goto done;
16888 }
16889
16890 #ifdef STA_CFG80211
16891 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
16892 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
16893 ret = -EFAULT;
16894 goto done;
16895 }
16896 #endif
16897 #endif
16898
16899 memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
16900 header_len = strlen("CFGROAMOFFLOAD");
16901 user_data_len = strlen(respbuf) - header_len;
16902 if (!user_data_len) {
16903 PRINTM(MERROR, "Invalid number of parameters\n");
16904 ret = -EINVAL;
16905 goto done;
16906 }
16907 roam_offload_cfg.band_rssi.band_preferred = 0xff;
16908 roam_offload_cfg.trigger_condition = 0xff;
16909 end = &respbuf[header_len];
16910 while (((t_u8 *)end - &respbuf[header_len]) < user_data_len - 1) {
16911 end++;
16912 begin = end;
16913 while (begin && *begin == ' ') {
16914 begin++;
16915 end++;
16916 }
16917 while (end && *end != ' ' && *end != '\0' && *end != '=')
16918 end++;
16919 if (end == begin) {
16920 PRINTM(MERROR, "Invalid command specified!\n");
16921 ret = -EINVAL;
16922 goto done;
16923 }
16924 if (end)
16925 *end = '\0';
16926 pvariable_name = begin;
16927
16928 if (((t_u8 *)end - &respbuf[header_len]) >= user_data_len) {
16929 PRINTM(MERROR, "Invalid command length!\n");
16930 ret = -EINVAL;
16931 goto done;
16932 }
16933 end++;
16934 begin = end;
16935 while (begin && (*begin == ' ' || *begin == '=')) {
16936 begin++;
16937 end++;
16938 }
16939 while (end && *end != ' ' && *end != '\0' && *end != '=')
16940 end++;
16941 if (end == begin) {
16942 PRINTM(MERROR, "Invalid command specified!\n");
16943 ret = -EINVAL;
16944 goto done;
16945 }
16946 if (end != NULL)
16947 *end = '\0';
16948 if (pvariable_name && begin) {
16949 if (strcmp(pvariable_name, "AUTO_RECONNECT") == 0) {
16950 woal_atoi(&data, begin);
16951 } else if (strcmp(pvariable_name, "BSSID") == 0) {
16952 woal_mac2u8(mac_addr, begin);
16953 moal_memcpy_ext(priv->phandle,
16954 roam_offload_cfg.bssid,
16955 mac_addr, MLAN_MAC_ADDR_LENGTH,
16956 MLAN_MAC_ADDR_LENGTH);
16957 } else if (strcmp(pvariable_name, "BLACKLIST") == 0) {
16958 if (woal_atoi(&count, begin) !=
16959 MLAN_STATUS_SUCCESS) {
16960 ret = -EINVAL;
16961 goto done;
16962 }
16963 if (count > 0 && count <= MAX_AP_LIST) {
16964 roam_offload_cfg.black_list.ap_num =
16965 count;
16966 for (i = 0; i < count; i++) {
16967 end++;
16968 begin = end;
16969 while (begin && *begin == ' ') {
16970 begin++;
16971 end++;
16972 }
16973 while (end && *end != ' ' &&
16974 *end != '\0')
16975 end++;
16976 if (end == begin) {
16977 PRINTM(MERROR,
16978 "BSSID %d is wrong\n",
16979 count);
16980 ret = -EINVAL;
16981 goto done;
16982 }
16983 if (end != NULL)
16984 *end = '\0';
16985 woal_mac2u8(mac_addr, begin);
16986 moal_memcpy_ext(
16987 priv->phandle,
16988 roam_offload_cfg
16989 .black_list
16990 .ap_mac[i],
16991 mac_addr,
16992 MLAN_MAC_ADDR_LENGTH,
16993 MLAN_MAC_ADDR_LENGTH);
16994 }
16995 } else {
16996 PRINTM(MERROR,
16997 "BSSID number is wrong.Support max %d BSSIDs\n",
16998 MAX_AP_LIST);
16999 ret = -EINVAL;
17000 goto done;
17001 }
17002 } else if (strcmp(pvariable_name, "SSID") == 0) {
17003 if (woal_atoi(&count, begin) !=
17004 MLAN_STATUS_SUCCESS) {
17005 ret = -EINVAL;
17006 goto done;
17007 }
17008 if (count > 0 && count <= MAX_SSID_NUM) {
17009 roam_offload_cfg.ssid_list.ssid_num =
17010 count;
17011 for (i = 0; i < count; i++) {
17012 end++;
17013 begin = end;
17014 while (begin && *begin == ' ') {
17015 begin++;
17016 end++;
17017 }
17018 while (end && *end != ' ' &&
17019 *end != '\0') {
17020 end++;
17021 len++;
17022 }
17023 if ((end == begin) ||
17024 len >= MLAN_MAX_SSID_LENGTH) {
17025 PRINTM(MERROR,
17026 "SSID %d is wrong\n",
17027 count);
17028 ret = -EINVAL;
17029 goto done;
17030 }
17031 if (end != NULL)
17032 *end = '\0';
17033 roam_offload_cfg.ssid_list
17034 .ssids[i]
17035 .ssid_len = len + 1;
17036 moal_memcpy_ext(
17037 priv->phandle,
17038 (t_u8 *)&roam_offload_cfg
17039 .ssid_list
17040 .ssids[i]
17041 .ssid,
17042 begin, len + 1,
17043 MLAN_MAX_SSID_LENGTH);
17044 len = 0;
17045 }
17046 } else {
17047 PRINTM(MERROR,
17048 "SSID number is wrong.Support max %d SSIDs\n",
17049 MAX_SSID_NUM);
17050 ret = -EINVAL;
17051 goto done;
17052 }
17053 } else if (strcmp(pvariable_name, "RETRY_COUNT") == 0) {
17054 woal_atoi(&data, begin);
17055 roam_offload_cfg.retry_count = (t_u8)data;
17056 } else if (strcmp(pvariable_name,
17057 "TRIGGER_CONDITION") == 0) {
17058 woal_atoi(&data, begin);
17059 roam_offload_cfg.trigger_condition =
17060 (t_u16)data;
17061 } else if (strcmp(pvariable_name, "MAX_RSSI") == 0) {
17062 woal_atoi(&data, begin);
17063 roam_offload_cfg.max_rssi = (t_u8)data;
17064 roam_offload_cfg.rssi_param_set_flag = 1;
17065 } else if (strcmp(pvariable_name, "MIN_RSSI") == 0) {
17066 woal_atoi(&data, begin);
17067 roam_offload_cfg.min_rssi = (t_u8)data;
17068 roam_offload_cfg.rssi_param_set_flag = 1;
17069 } else if (strcmp(pvariable_name, "STEP_RSSI") == 0) {
17070 woal_atoi(&data, begin);
17071 roam_offload_cfg.step_rssi = (t_u8)data;
17072 roam_offload_cfg.rssi_param_set_flag = 1;
17073 } else if (strcmp(pvariable_name, "BAND_PREFER") == 0) {
17074 woal_atoi(&data, begin);
17075 roam_offload_cfg.band_rssi.band_preferred =
17076 (t_u8)data;
17077 roam_offload_cfg.band_rssi_flag = 1;
17078 } else if (strcmp(pvariable_name, "RSSI_HYSTERESIS") ==
17079 0) {
17080 woal_atoi(&data, begin);
17081 roam_offload_cfg.band_rssi.rssi_hysteresis =
17082 (t_u8)data;
17083 roam_offload_cfg.band_rssi_flag = 1;
17084 }
17085
17086 else if (strcmp(pvariable_name, "BSSTYPE") == 0) {
17087 woal_atoi(&data, begin);
17088 roam_offload_cfg.bgscan_cfg.bss_type =
17089 (t_u8)data;
17090 roam_offload_cfg.bgscan_set_flag++;
17091 } else if (strcmp(pvariable_name, "CHANSPERSCAN") ==
17092 0) {
17093 woal_atoi(&data, begin);
17094 roam_offload_cfg.bgscan_cfg.channels_per_scan =
17095 (t_u8)data;
17096 roam_offload_cfg.bgscan_set_flag++;
17097 } else if (strcmp(pvariable_name, "BGRPTCONDITION") ==
17098 0) {
17099 woal_atoi(&data, begin);
17100 roam_offload_cfg.bgscan_cfg.bg_rpt_condition =
17101 (t_u32)data;
17102 roam_offload_cfg.bgscan_set_flag++;
17103 } else if (strcmp(pvariable_name, "SCANINTERVAL") ==
17104 0) {
17105 woal_atoi(&data, begin);
17106 roam_offload_cfg.bgscan_cfg.scan_interval =
17107 (t_u32)data;
17108 roam_offload_cfg.bgscan_set_flag++;
17109 }
17110
17111 else if (strcmp(pvariable_name, "EESMODE") == 0) {
17112 woal_atoi(&data, begin);
17113 roam_offload_cfg.ees_cfg.ees_mode = (t_u16)data;
17114 roam_offload_cfg.ees_param_set_flag++;
17115 } else if (strcmp(pvariable_name, "EESRPTCONDITION") ==
17116 0) {
17117 woal_atoi(&data, begin);
17118 roam_offload_cfg.ees_cfg.ees_rpt_condition =
17119 (t_u16)data;
17120 roam_offload_cfg.ees_param_set_flag++;
17121 } else if (strcmp(pvariable_name, "HIGHSCANPERIOD") ==
17122 0) {
17123 woal_atoi(&data, begin);
17124 roam_offload_cfg.ees_cfg.high_scan_period =
17125 (t_u16)data;
17126 roam_offload_cfg.ees_param_set_flag++;
17127 } else if (strcmp(pvariable_name, "HIGHSCANCOUNT") ==
17128 0) {
17129 woal_atoi(&data, begin);
17130 roam_offload_cfg.ees_cfg.high_scan_count =
17131 (t_u16)data;
17132 roam_offload_cfg.ees_param_set_flag++;
17133 } else if (strcmp(pvariable_name, "MIDSCANPERIOD") ==
17134 0) {
17135 woal_atoi(&data, begin);
17136 roam_offload_cfg.ees_cfg.mid_scan_period =
17137 (t_u16)data;
17138 roam_offload_cfg.ees_param_set_flag++;
17139 } else if (strcmp(pvariable_name, "MIDSCANCOUNT") ==
17140 0) {
17141 woal_atoi(&data, begin);
17142 roam_offload_cfg.ees_cfg.mid_scan_count =
17143 (t_u16)data;
17144 roam_offload_cfg.ees_param_set_flag++;
17145 } else if (strcmp(pvariable_name, "LOWSCANPERIOD") ==
17146 0) {
17147 woal_atoi(&data, begin);
17148 roam_offload_cfg.ees_cfg.low_scan_period =
17149 (t_u16)data;
17150 roam_offload_cfg.ees_param_set_flag++;
17151 } else if (strcmp(pvariable_name, "LOWSCANCOUNT") ==
17152 0) {
17153 woal_atoi(&data, begin);
17154 roam_offload_cfg.ees_cfg.low_scan_count =
17155 (t_u16)data;
17156 roam_offload_cfg.ees_param_set_flag++;
17157 }
17158
17159 else if (strcmp(pvariable_name, "BCNMISSTHRESHOLD") ==
17160 0) {
17161 woal_atoi(&data, begin);
17162 roam_offload_cfg.bcn_miss_threshold =
17163 (t_u8)data;
17164 }
17165
17166 else if (strcmp(pvariable_name,
17167 "PREBCNMISSTHRESHOLD") == 0) {
17168 woal_atoi(&data, begin);
17169 roam_offload_cfg.pre_bcn_miss_threshold =
17170 (t_u8)data;
17171 } else if (strcmp(pvariable_name, "REPEATCOUNT") == 0) {
17172 woal_atoi(&data, begin);
17173 roam_offload_cfg.repeat_count = (t_u16)data;
17174 } else {
17175 PRINTM(MERROR, "Un-support parameter: %s\n",
17176 pvariable_name);
17177 ret = -EINVAL;
17178 goto done;
17179 }
17180 }
17181 }
17182 if (priv->phandle->fw_roam_enable == AUTO_RECONNECT) {
17183 moal_memcpy_ext(priv->phandle,
17184 priv->phandle->auto_reconnect_bssid,
17185 roam_offload_cfg.bssid, MLAN_MAC_ADDR_LENGTH,
17186 sizeof(mlan_802_11_mac_addr));
17187 moal_memcpy_ext(priv->phandle,
17188 &priv->phandle->auto_reconnect_ssid,
17189 &roam_offload_cfg.ssid_list.ssids[0],
17190 sizeof(mlan_802_11_ssid),
17191 sizeof(mlan_802_11_ssid));
17192 priv->phandle->auto_reconnect_retry_count = (t_u8)data;
17193 } else {
17194 if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS))
17195 moal_memcpy_ext(priv->phandle,
17196 (void *)&priv->phandle->fw_roam_params,
17197 (void *)&roam_offload_cfg,
17198 sizeof(roam_offload_cfg),
17199 sizeof(priv->phandle->fw_roam_params));
17200 else {
17201 if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_PARAM_CFG,
17202 &roam_offload_cfg)) {
17203 PRINTM(MERROR,
17204 "%s: config fw roaming failed \n",
17205 __func__);
17206 ret = -EFAULT;
17207 }
17208 }
17209 }
17210 done:
17211 LEAVE();
17212 return ret;
17213 }
17214
17215 /**
17216 * @brief Configure roaming SSID passphrase
17217 *
17218 * @param priv Pointer to moal_private structure
17219 * @param respbuf Pointer to response buffer
17220 * @param resplen Response buffer length
17221
17222 * @return Number of bytes written, negative for failure.
17223 */
woal_priv_set_roam_passphrase(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17224 static int woal_priv_set_roam_passphrase(moal_private *priv, t_u8 *respbuf,
17225 t_u32 respbuflen)
17226 {
17227 mlan_ioctl_req *req = NULL;
17228 mlan_ds_sec_cfg *sec = NULL;
17229 int ret = 0, action = -1;
17230 int user_data_len = 0, header_len = 0;
17231 char *begin, *end, *opt, *item;
17232 mlan_status status = MLAN_STATUS_SUCCESS;
17233 woal_roam_offload_cfg roam_offload_cfg;
17234 mlan_ds_passphrase *ssid_passphrase = NULL;
17235
17236 ENTER();
17237
17238 if (!priv || !priv->phandle) {
17239 PRINTM(MERROR, "priv or handle is null\n");
17240 ret = -EFAULT;
17241 goto done;
17242 }
17243
17244 #ifdef STA_CFG80211
17245 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
17246 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
17247 ret = -EFAULT;
17248 goto done;
17249 }
17250 #endif
17251 #endif
17252
17253 memset((char *)&roam_offload_cfg, 0, sizeof(roam_offload_cfg));
17254 header_len = strlen("SETROAMPASSPHRASE");
17255 user_data_len = strlen(respbuf) - header_len;
17256 if (!user_data_len) {
17257 PRINTM(MERROR, "Invalid number of parameters\n");
17258 ret = -EINVAL;
17259 goto done;
17260 }
17261
17262 /* Parse the buf to get the cmd_action */
17263 begin = respbuf + header_len;
17264 while (begin && *begin == ' ')
17265 begin++;
17266 end = woal_strsep(&begin, ';', '/');
17267 if (end)
17268 action = woal_atox(end);
17269 PRINTM(MMSG, "action= %d\n", action);
17270 if (action != 1 || end[1] != '\0') {
17271 PRINTM(MERROR, "Invalid action argument %s\n", end);
17272 ret = -EINVAL;
17273 goto done;
17274 }
17275
17276 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
17277 if (req == NULL) {
17278 ret = -ENOMEM;
17279 goto done;
17280 }
17281
17282 req->req_id = MLAN_IOCTL_SEC_CFG;
17283 sec = (mlan_ds_sec_cfg *)req->pbuf;
17284 sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
17285 sec->multi_passphrase = 1;
17286 req->action = MLAN_ACT_SET;
17287
17288 /*Parse the buffer like "ssid=xxx passphrase=xxxx;ssid=xxx
17289 * passphrase=xxx"*/
17290 while (begin) {
17291 while (begin && *begin == ' ')
17292 begin++;
17293 end = woal_strsep(&begin, ';', '/');
17294 item = woal_strsep(&end, ' ', '/');
17295 opt = woal_strsep(&item, '=', '/');
17296 while (opt) {
17297 if (roam_offload_cfg.userset_passphrase >=
17298 MAX_SEC_SSID_NUM - 1) {
17299 PRINTM(MERROR,
17300 "Support max %d security SSIDs!\n",
17301 MAX_SEC_SSID_NUM);
17302 break;
17303 }
17304 ssid_passphrase =
17305 &sec->param.roam_passphrase
17306 [roam_offload_cfg.userset_passphrase];
17307 if (!opt || !item || !end) {
17308 PRINTM(MERROR, "Invalid option\n");
17309 ret = -EINVAL;
17310 goto done;
17311 } else if (!strnicmp(opt, "ssid", strlen(opt))) {
17312 if (strlen(end) > MLAN_MAX_SSID_LENGTH) {
17313 PRINTM(MERROR,
17314 "SSID length exceeds max length\n");
17315 ret = -EFAULT;
17316 goto done;
17317 }
17318 ssid_passphrase->ssid.ssid_len = strlen(item);
17319 strncpy((char *)ssid_passphrase->ssid.ssid,
17320 item,
17321 MIN(strlen(item),
17322 MLAN_MAX_SSID_LENGTH));
17323 PRINTM(MINFO, "ssid=%s, len=%d\n",
17324 ssid_passphrase->ssid.ssid,
17325 (int)ssid_passphrase->ssid.ssid_len);
17326 } else if (!strnicmp(opt, "passphrase", strlen(opt)) &&
17327 req->action == MLAN_ACT_SET) {
17328 if (strlen(item) < MLAN_MIN_PASSPHRASE_LENGTH ||
17329 strlen(item) > MLAN_MAX_PASSPHRASE_LENGTH) {
17330 PRINTM(MERROR,
17331 "Invalid length for passphrase\n");
17332 ret = -EINVAL;
17333 goto done;
17334 }
17335 ssid_passphrase->psk_type = MLAN_PSK_PASSPHRASE;
17336 moal_memcpy_ext(priv->phandle,
17337 ssid_passphrase->psk.passphrase
17338 .passphrase,
17339 item, strlen(item),
17340 MLAN_MAX_PASSPHRASE_LENGTH);
17341 ssid_passphrase->psk.passphrase.passphrase_len =
17342 strlen(item);
17343 PRINTM(MINFO, "passphrase=%s, len=%d\n",
17344 ssid_passphrase->psk.passphrase
17345 .passphrase,
17346 (int)ssid_passphrase->psk.passphrase
17347 .passphrase_len);
17348 } else {
17349 PRINTM(MERROR, "Invalid option %s\n", opt);
17350 ret = -EINVAL;
17351 goto done;
17352 }
17353 if (!end || *end == '\0')
17354 break;
17355 while (end && *end == ' ')
17356 end++;
17357 item = woal_strsep(&end, ' ', '/');
17358 opt = woal_strsep(&item, '=', '/');
17359 }
17360 roam_offload_cfg.userset_passphrase++;
17361 }
17362
17363 if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS)) {
17364 moal_memcpy_ext(priv->phandle,
17365 (char *)priv->phandle->ssid_passphrase,
17366 (char *)sec->param.roam_passphrase,
17367 MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase),
17368 MAX_SEC_SSID_NUM * sizeof(mlan_ds_passphrase));
17369 priv->phandle->fw_roam_params.userset_passphrase =
17370 roam_offload_cfg.userset_passphrase;
17371 goto done;
17372 }
17373
17374 if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_ENABLE,
17375 &roam_offload_cfg)) {
17376 PRINTM(MERROR, "%s: config fw roaming failed \n", __func__);
17377 ret = -EFAULT;
17378 goto done;
17379 }
17380 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17381 if (status != MLAN_STATUS_SUCCESS) {
17382 ret = -EFAULT;
17383 goto done;
17384 }
17385
17386 done:
17387 if (status != MLAN_STATUS_PENDING)
17388 kfree(req);
17389 LEAVE();
17390 return ret;
17391 }
17392
17393 /**
17394 * @brief Download start keep alive parameters
17395 *
17396 * @param priv Pointer to moal_private structure
17397 * @param mkeep_alive_id keep alive ID number
17398 * @param ip_pke IP packet from host
17399 * @param ip_pke_len IP packet length from host
17400 * @param src_mac Source MAC address
17401 * @param dst_mac Destination MAC address
17402 * @param period_msec Send keep alive packet interval
17403
17404 * @return 0: success fail otherwise
17405 */
woal_start_mkeep_alive(moal_private * priv,t_u8 mkeep_alive_id,t_u8 * ip_pkt,t_u16 ip_pkt_len,t_u8 * src_mac,t_u8 * dst_mac,t_u32 period_msec,t_u32 retry_interval,t_u8 retry_cnt)17406 int woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id,
17407 t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac,
17408 t_u8 *dst_mac, t_u32 period_msec,
17409 t_u32 retry_interval, t_u8 retry_cnt)
17410 {
17411 mlan_ioctl_req *ioctl_req = NULL;
17412 mlan_ds_misc_cfg *misc = NULL;
17413 mlan_status status = MLAN_STATUS_SUCCESS;
17414 int ret = 0;
17415
17416 ENTER();
17417
17418 if (!priv || !priv->phandle) {
17419 PRINTM(MERROR, "priv or handle is null\n");
17420 ret = -EFAULT;
17421 goto done;
17422 }
17423
17424 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17425 if (ioctl_req == NULL) {
17426 ret = -ENOMEM;
17427 goto done;
17428 }
17429
17430 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17431 misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17432 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17433
17434 if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17435 PRINTM(MERROR, "Invalid parameters\n");
17436 ret = -EFAULT;
17437 goto done;
17438 }
17439
17440 /* SET operation */
17441 ioctl_req->action = MLAN_ACT_SET;
17442 misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
17443 misc->param.keep_alive.enable = true;
17444 misc->param.keep_alive.send_interval = period_msec;
17445 misc->param.keep_alive.retry_interval = retry_interval;
17446 misc->param.keep_alive.retry_count = retry_cnt;
17447 moal_memcpy_ext(priv->phandle, misc->param.keep_alive.dst_mac, dst_mac,
17448 MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17449 moal_memcpy_ext(priv->phandle, misc->param.keep_alive.src_mac, src_mac,
17450 MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17451 misc->param.keep_alive.pkt_len =
17452 MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17453 moal_memcpy_ext(priv->phandle, misc->param.keep_alive.packet, ip_pkt,
17454 ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17455
17456 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17457 if (status != MLAN_STATUS_SUCCESS) {
17458 ret = -EFAULT;
17459 goto done;
17460 }
17461
17462 done:
17463 if (status != MLAN_STATUS_PENDING)
17464 kfree(ioctl_req);
17465
17466 LEAVE();
17467 return ret;
17468 }
17469
17470 /**
17471 * @brief Download stop keep alive parameters
17472 *
17473 * @param priv Pointer to moal_private structure
17474 * @param mkeep_alive_id keep alive ID number
17475 * @param ip_pkt Last packet
17476 * @param ip_pkt_len Last packet length
17477
17478 * @return 0: success fail otherwise
17479 */
woal_stop_mkeep_alive(moal_private * priv,t_u8 mkeep_alive_id,t_u8 reset,t_u8 * ip_pkt,t_u8 * pkt_len)17480 int woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset,
17481 t_u8 *ip_pkt, t_u8 *pkt_len)
17482 {
17483 mlan_ioctl_req *ioctl_req = NULL;
17484 mlan_ds_misc_cfg *misc = NULL;
17485 mlan_status status = MLAN_STATUS_SUCCESS;
17486 mlan_ds_misc_keep_alive *misc_keep_alive = NULL;
17487 int ret = 0;
17488
17489 ENTER();
17490
17491 if (!priv || !priv->phandle) {
17492 PRINTM(MERROR, "priv or handle is null\n");
17493 ret = -EFAULT;
17494 goto done;
17495 }
17496
17497 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17498 if (ioctl_req == NULL) {
17499 ret = -ENOMEM;
17500 goto done;
17501 }
17502
17503 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17504 misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17505 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17506 misc_keep_alive = &misc->param.keep_alive;
17507
17508 if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17509 PRINTM(MERROR, "Invalid parameters\n");
17510 ret = -EFAULT;
17511 goto done;
17512 }
17513
17514 /* GET operation */
17515 ioctl_req->action = MLAN_ACT_GET;
17516 misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
17517 misc_keep_alive->enable = false;
17518
17519 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17520 if (status != MLAN_STATUS_SUCCESS) {
17521 ret = -EFAULT;
17522 goto done;
17523 }
17524
17525 if (!misc_keep_alive->enable) {
17526 PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id);
17527 goto done;
17528 }
17529
17530 if (reset)
17531 ioctl_req->action = MLAN_ACT_RESET;
17532 else
17533 /* SET operation */
17534 ioctl_req->action = MLAN_ACT_SET;
17535 misc_keep_alive->mkeep_alive_id = mkeep_alive_id;
17536 misc_keep_alive->enable = false;
17537
17538 status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17539 if (status != MLAN_STATUS_SUCCESS) {
17540 ret = -EFAULT;
17541 goto done;
17542 }
17543
17544 #ifdef STA_CFG80211
17545 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
17546 if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
17547 ret = woal_mkeep_alive_vendor_event(priv,
17548 &misc->param.keep_alive);
17549 if (ret)
17550 PRINTM(MERROR,
17551 "Keep alive vendor event upload failed\n");
17552 }
17553 #endif
17554 #endif
17555 if (pkt_len) {
17556 *pkt_len = MIN(misc_keep_alive->pkt_len,
17557 (MKEEP_ALIVE_IP_PKT_MAX - 1));
17558 PRINTM(MINFO, "keep alive stop pkt_len is %d\n", *pkt_len);
17559 }
17560 if (*pkt_len && ip_pkt)
17561 moal_memcpy_ext(priv->phandle, ip_pkt, misc_keep_alive->packet,
17562 *pkt_len, *pkt_len);
17563
17564 done:
17565 if (status != MLAN_STATUS_PENDING)
17566 kfree(ioctl_req);
17567
17568 LEAVE();
17569 return ret;
17570 }
17571
17572 /**
17573 * @brief Save cloud keep alive params in driver handle
17574 *
17575 * @param priv Pointer to moal_private structure
17576 * @params Other params for keep alive
17577
17578 * @return Number of bytes written, negative for failure.
17579 */
woal_priv_save_cloud_keep_alive_params(moal_private * priv,t_u8 mkeep_alive_id,t_u8 enable,t_u16 ether_type,t_u8 * ip_pkt,t_u16 ip_pkt_len,t_u8 * src_mac,t_u8 * dst_mac,t_u32 period_msec,t_u32 retry_interval,t_u8 retry_cnt)17580 int woal_priv_save_cloud_keep_alive_params(moal_private *priv,
17581 t_u8 mkeep_alive_id, t_u8 enable,
17582 t_u16 ether_type, t_u8 *ip_pkt,
17583 t_u16 ip_pkt_len, t_u8 *src_mac,
17584 t_u8 *dst_mac, t_u32 period_msec,
17585 t_u32 retry_interval, t_u8 retry_cnt)
17586
17587 {
17588 mlan_ioctl_req *ioctl_req = NULL;
17589 mlan_ds_misc_cfg *misc = NULL;
17590 int ret = 0;
17591 mlan_ds_misc_keep_alive *keep_alive = NULL;
17592 moal_handle *phandle = NULL;
17593
17594 ENTER();
17595
17596 if (!priv || !priv->phandle) {
17597 PRINTM(MERROR, "priv or handle is null\n");
17598 ret = -EFAULT;
17599 goto done;
17600 }
17601 phandle = priv->phandle;
17602
17603 ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17604 if (ioctl_req == NULL) {
17605 ret = -ENOMEM;
17606 goto done;
17607 }
17608
17609 misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
17610 misc->sub_command = MLAN_OID_MISC_CLOUD_KEEP_ALIVE;
17611 ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
17612
17613 if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) {
17614 PRINTM(MERROR, "Invalid parameters\n");
17615 ret = -EINVAL;
17616 goto done;
17617 }
17618
17619 /* GET operation */
17620 ioctl_req->action = MLAN_ACT_GET;
17621 misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id;
17622 misc->param.keep_alive.enable = true;
17623
17624 ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
17625 if (ret != MLAN_STATUS_SUCCESS) {
17626 ret = -EFAULT;
17627 goto done;
17628 }
17629
17630 if (misc->param.keep_alive.enable) {
17631 PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id);
17632 ret = -EINVAL;
17633 goto done;
17634 }
17635
17636 keep_alive = &phandle->keep_alive[mkeep_alive_id];
17637 keep_alive->mkeep_alive_id = mkeep_alive_id;
17638 keep_alive->enable = enable;
17639 if (enable) {
17640 keep_alive->cached = true;
17641 keep_alive->send_interval = period_msec;
17642 keep_alive->retry_interval = retry_interval;
17643 keep_alive->retry_count = retry_cnt;
17644 moal_memcpy_ext(phandle, keep_alive->dst_mac, dst_mac,
17645 MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17646 moal_memcpy_ext(phandle, keep_alive->src_mac, src_mac,
17647 MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
17648 keep_alive->pkt_len = MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX);
17649 moal_memcpy_ext(phandle, keep_alive->packet, ip_pkt, ip_pkt_len,
17650 MKEEP_ALIVE_IP_PKT_MAX);
17651 if (ether_type)
17652 keep_alive->ether_type = ether_type;
17653 else
17654 keep_alive->ether_type = 0;
17655 }
17656
17657 done:
17658 if (ret != MLAN_STATUS_PENDING)
17659 kfree(ioctl_req);
17660
17661 LEAVE();
17662 return ret;
17663 }
17664
17665 /**
17666 * @brief Cloud keep alive feature
17667 *
17668 * @param priv Pointer to moal_private structure
17669 * @param respbuf Pointer to response buffer
17670 * @param resplen Response buffer length
17671
17672 * @return Number of bytes written, negative for failure.
17673 */
woal_priv_cloud_keep_alive(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17674 static int woal_priv_cloud_keep_alive(moal_private *priv, t_u8 *respbuf,
17675 t_u32 respbuflen)
17676 {
17677 int ret = 0;
17678 cloud_keep_alive *keep_alive = NULL;
17679 int header_len = 0;
17680
17681 ENTER();
17682
17683 header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE);
17684
17685 keep_alive = (cloud_keep_alive *)(respbuf + header_len);
17686
17687 if (keep_alive->enable) {
17688 ret = woal_priv_save_cloud_keep_alive_params(
17689 priv, keep_alive->mkeep_alive_id, keep_alive->enable, 0,
17690 keep_alive->pkt, keep_alive->pkt_len,
17691 keep_alive->src_mac, keep_alive->dst_mac,
17692 keep_alive->sendInterval, keep_alive->retryInterval,
17693 keep_alive->retryCount);
17694 } else {
17695 if (0 != woal_stop_mkeep_alive(priv, keep_alive->mkeep_alive_id,
17696 keep_alive->reset,
17697 keep_alive->pkt,
17698 &keep_alive->pkt_len)) {
17699 ret = -EFAULT;
17700 return ret;
17701 }
17702 ret = respbuflen;
17703 }
17704
17705 LEAVE();
17706 return ret;
17707 }
17708
17709 /**
17710 * @brief Set/Get static rx abort config
17711 *
17712 * @param priv A pointer to moal_private structure
17713 * @param respbuf A pointer to response buffer
17714 * @param respbuflen Available length of response buffer
17715 *
17716 * @return Number of bytes written, negative for failure.
17717 */
woal_priv_rx_abort_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17718 static int woal_priv_rx_abort_cfg(moal_private *priv, t_u8 *respbuf,
17719 t_u32 respbuflen)
17720 {
17721 mlan_ioctl_req *req = NULL;
17722 mlan_ds_misc_cfg *misc = NULL;
17723 int ret = 0;
17724 int data[2] = {0};
17725 int header_len = 0, user_data_len = 0;
17726 mlan_status status = MLAN_STATUS_SUCCESS;
17727
17728 ENTER();
17729
17730 if (!respbuf) {
17731 PRINTM(MERROR, "response buffer is not available!\n");
17732 ret = -EINVAL;
17733 goto done;
17734 }
17735 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG);
17736 user_data_len = strlen(respbuf) - header_len;
17737
17738 /* Allocate an IOCTL request buffer */
17739 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17740 if (req == NULL) {
17741 ret = -ENOMEM;
17742 goto done;
17743 }
17744
17745 /* Fill request buffer */
17746 misc = (mlan_ds_misc_cfg *)req->pbuf;
17747 misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG;
17748 req->req_id = MLAN_IOCTL_MISC_CFG;
17749 if ((int)strlen(respbuf) == header_len) {
17750 /* GET operation */
17751 user_data_len = 0;
17752 req->action = MLAN_ACT_GET;
17753 } else {
17754 /* SET operation */
17755 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17756 &user_data_len);
17757 if (user_data_len > 2 ||
17758 (data[0] == MTRUE && user_data_len != 2)) {
17759 PRINTM(MERROR, "Invalid number of args!\n");
17760 ret = -EINVAL;
17761 goto done;
17762 }
17763 if (data[0] == MTRUE && data[1] > 0x7f) {
17764 PRINTM(MERROR, "Invalid threshold value\n");
17765 ret = -EINVAL;
17766 goto done;
17767 }
17768 misc->param.rx_abort_cfg.enable = (t_u8)data[0];
17769 if (user_data_len == 2)
17770 misc->param.rx_abort_cfg.rssi_threshold = (t_s8)data[1];
17771 req->action = MLAN_ACT_SET;
17772 }
17773 /* Send IOCTL request to MLAN */
17774 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17775 if (status != MLAN_STATUS_SUCCESS) {
17776 ret = -EFAULT;
17777 goto done;
17778 }
17779
17780 data[0] = misc->param.rx_abort_cfg.enable;
17781 data[1] = misc->param.rx_abort_cfg.rssi_threshold;
17782 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17783 respbuflen);
17784 ret = sizeof(data);
17785 done:
17786 if (status != MLAN_STATUS_PENDING)
17787 kfree(req);
17788
17789 LEAVE();
17790 return ret;
17791 }
17792
17793 /**
17794 * @brief Set/Get dynamic rx abort config
17795 *
17796 * @param priv A pointer to moal_private structure
17797 * @param respbuf A pointer to response buffer
17798 * @param respbuflen Available length of response buffer
17799 *
17800 * @return Number of bytes written, negative for failure.
17801 */
woal_priv_rx_abort_cfg_ext(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17802 static int woal_priv_rx_abort_cfg_ext(moal_private *priv, t_u8 *respbuf,
17803 t_u32 respbuflen)
17804 {
17805 mlan_ioctl_req *req = NULL;
17806 mlan_ds_misc_cfg *misc = NULL;
17807 int ret = 0;
17808 int data[3] = {0};
17809 int header_len = 0, user_data_len = 0;
17810 mlan_status status = MLAN_STATUS_SUCCESS;
17811
17812 ENTER();
17813
17814 if (!respbuf) {
17815 PRINTM(MERROR, "response buffer is not available!\n");
17816 ret = -EINVAL;
17817 goto done;
17818 }
17819 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG_EXT);
17820 user_data_len = strlen(respbuf) - header_len;
17821
17822 /* Allocate an IOCTL request buffer */
17823 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17824 if (req == NULL) {
17825 ret = -ENOMEM;
17826 goto done;
17827 }
17828
17829 /* Fill request buffer */
17830 misc = (mlan_ds_misc_cfg *)req->pbuf;
17831 misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG_EXT;
17832 req->req_id = MLAN_IOCTL_MISC_CFG;
17833 if ((int)strlen(respbuf) == header_len) {
17834 /* GET operation */
17835 user_data_len = 0;
17836 req->action = MLAN_ACT_GET;
17837 } else {
17838 /* SET operation */
17839 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17840 &user_data_len);
17841 if (user_data_len > 3 ||
17842 (data[0] == MTRUE && user_data_len != 3)) {
17843 PRINTM(MERROR, "Invalid number of args!\n");
17844 ret = -EINVAL;
17845 goto done;
17846 }
17847 if (data[0] == MTRUE) {
17848 if (data[1] > 0x7f) {
17849 PRINTM(MERROR, "Invalid margin value\n");
17850 ret = -EINVAL;
17851 goto done;
17852 }
17853 if (data[2] > 0x7f) {
17854 PRINTM(MERROR,
17855 "Invalid ceil threshold value\n");
17856 ret = -EINVAL;
17857 goto done;
17858 }
17859 }
17860 misc->param.rx_abort_cfg_ext.enable = (t_u8)data[0];
17861 if (user_data_len > 1) {
17862 misc->param.rx_abort_cfg_ext.rssi_margin =
17863 (t_s8)data[1];
17864 misc->param.rx_abort_cfg_ext.ceil_rssi_threshold =
17865 (t_s8)data[2];
17866 }
17867 req->action = MLAN_ACT_SET;
17868 }
17869 /* Send IOCTL request to MLAN */
17870 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17871 if (status != MLAN_STATUS_SUCCESS) {
17872 ret = -EFAULT;
17873 goto done;
17874 }
17875
17876 data[0] = misc->param.rx_abort_cfg_ext.enable;
17877 data[1] = misc->param.rx_abort_cfg_ext.rssi_margin;
17878 data[2] = misc->param.rx_abort_cfg_ext.ceil_rssi_threshold;
17879 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17880 respbuflen);
17881 ret = sizeof(data);
17882 done:
17883 if (status != MLAN_STATUS_PENDING)
17884 kfree(req);
17885
17886 LEAVE();
17887 return ret;
17888 }
17889
17890 /**
17891 * @brief Enable/Disable Un-associated Dot11mc FTM Frame exchanges
17892 *
17893 * @param priv A pointer to moal_private structure
17894 * @param respbuf A pointer to response buffer
17895 * @param respbuflen Available length of response buffer
17896 *
17897 * @return Number of bytes written, negative for failure.
17898 */
woal_priv_dot11mc_unassoc_ftm_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17899 static int woal_priv_dot11mc_unassoc_ftm_cfg(moal_private *priv, t_u8 *respbuf,
17900 t_u32 respbuflen)
17901 {
17902 mlan_ioctl_req *req = NULL;
17903 mlan_ds_misc_cfg *misc = NULL;
17904 int ret = 0;
17905 int data[1] = {0};
17906 int header_len = 0, user_data_len = 0;
17907 mlan_status status = MLAN_STATUS_SUCCESS;
17908
17909 ENTER();
17910
17911 if (!respbuf) {
17912 PRINTM(MERROR, "response buffer is not available!\n");
17913 ret = -EINVAL;
17914 goto done;
17915 }
17916 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG);
17917 user_data_len = strlen(respbuf) - header_len;
17918
17919 /* Allocate an IOCTL request buffer */
17920 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
17921 if (req == NULL) {
17922 ret = -ENOMEM;
17923 goto done;
17924 }
17925
17926 /* Fill request buffer */
17927 misc = (mlan_ds_misc_cfg *)req->pbuf;
17928 misc->sub_command = MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG;
17929 req->req_id = MLAN_IOCTL_MISC_CFG;
17930 if ((int)strlen(respbuf) == header_len) {
17931 /* GET operation */
17932 user_data_len = 0;
17933 req->action = MLAN_ACT_GET;
17934 } else {
17935 /* SET operation */
17936 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
17937 &user_data_len);
17938 if (user_data_len > 1) {
17939 PRINTM(MERROR, "Invalid number of args!\n");
17940 ret = -EINVAL;
17941 goto done;
17942 }
17943 if ((data[0] != MTRUE) && (data[0] != MFALSE)) {
17944 PRINTM(MERROR, "Invalid state for unassoc ftm\n");
17945 ret = -EINVAL;
17946 goto done;
17947 }
17948 misc->param.dot11mc_unassoc_ftm_cfg.state = (t_u16)data[0];
17949 req->action = MLAN_ACT_SET;
17950 }
17951 /* Send IOCTL request to MLAN */
17952 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
17953 if (status != MLAN_STATUS_SUCCESS) {
17954 ret = -EFAULT;
17955 goto done;
17956 }
17957
17958 data[0] = misc->param.dot11mc_unassoc_ftm_cfg.state;
17959 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
17960 respbuflen);
17961 ret = sizeof(data);
17962 done:
17963 if (status != MLAN_STATUS_PENDING)
17964 kfree(req);
17965
17966 LEAVE();
17967 return ret;
17968 }
17969
17970 /**
17971 * @brief Set/Get Tx AMPDU protection mode
17972 *
17973 * @param priv A pointer to moal_private structure
17974 * @param respbuf A pointer to response buffer
17975 * @param respbuflen Available length of response buffer
17976 *
17977 * @return Number of bytes written, negative for failure.
17978 */
woal_priv_tx_ampdu_prot_mode(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)17979 static int woal_priv_tx_ampdu_prot_mode(moal_private *priv, t_u8 *respbuf,
17980 t_u32 respbuflen)
17981 {
17982 mlan_ioctl_req *req = NULL;
17983 mlan_ds_misc_cfg *misc = NULL;
17984 int ret = 0;
17985 int data[1] = {0};
17986 int header_len = 0, user_data_len = 0;
17987 mlan_status status = MLAN_STATUS_SUCCESS;
17988
17989 ENTER();
17990
17991 if (!respbuf) {
17992 PRINTM(MERROR, "response buffer is not available!\n");
17993 ret = -EINVAL;
17994 goto done;
17995 }
17996 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AMPDU_PROT_MODE);
17997 user_data_len = strlen(respbuf) - header_len;
17998
17999 /* Allocate an IOCTL request buffer */
18000 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18001 if (req == NULL) {
18002 ret = -ENOMEM;
18003 goto done;
18004 }
18005
18006 /* Fill request buffer */
18007 misc = (mlan_ds_misc_cfg *)req->pbuf;
18008 misc->sub_command = MLAN_OID_MISC_TX_AMPDU_PROT_MODE;
18009 req->req_id = MLAN_IOCTL_MISC_CFG;
18010 if ((int)strlen(respbuf) == header_len) {
18011 /* GET operation */
18012 user_data_len = 0;
18013 req->action = MLAN_ACT_GET;
18014 } else {
18015 /* SET operation */
18016 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18017 &user_data_len);
18018 if (user_data_len > 1) {
18019 PRINTM(MERROR, "Invalid number of args!\n");
18020 ret = -EINVAL;
18021 goto done;
18022 }
18023 if (data[0] > TX_AMPDU_DYNAMIC_RTS_CTS) {
18024 PRINTM(MERROR, "Invalid protection mode\n");
18025 ret = -EINVAL;
18026 goto done;
18027 }
18028 misc->param.tx_ampdu_prot_mode.mode = (t_u16)data[0];
18029 req->action = MLAN_ACT_SET;
18030 }
18031 /* Send IOCTL request to MLAN */
18032 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18033 if (status != MLAN_STATUS_SUCCESS) {
18034 ret = -EFAULT;
18035 goto done;
18036 }
18037
18038 data[0] = misc->param.tx_ampdu_prot_mode.mode;
18039 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18040 respbuflen);
18041 ret = sizeof(data);
18042 done:
18043 if (status != MLAN_STATUS_PENDING)
18044 kfree(req);
18045
18046 LEAVE();
18047 return ret;
18048 }
18049
18050 /**
18051 * @brief Set/Get Tx rate adapt config
18052 *
18053 * @param priv A pointer to moal_private structure
18054 * @param respbuf A pointer to response buffer
18055 * @param respbuflen Available length of response buffer
18056 *
18057 * @return Number of bytes written, negative for failure.
18058 */
woal_priv_rate_adapt_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18059 static int woal_priv_rate_adapt_cfg(moal_private *priv, t_u8 *respbuf,
18060 t_u32 respbuflen)
18061 {
18062 mlan_ioctl_req *req = NULL;
18063 mlan_ds_misc_cfg *misc = NULL;
18064 int ret = 0;
18065 int data[4] = {0};
18066 int header_len = 0, user_data_len = 0;
18067 mlan_status status = MLAN_STATUS_SUCCESS;
18068
18069 ENTER();
18070
18071 if (!respbuf) {
18072 PRINTM(MERROR, "response buffer is not available!\n");
18073 ret = -EINVAL;
18074 goto done;
18075 }
18076 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RATE_ADAPT_CFG);
18077 user_data_len = strlen(respbuf) - header_len;
18078
18079 /* Allocate an IOCTL request buffer */
18080 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18081 if (req == NULL) {
18082 ret = -ENOMEM;
18083 goto done;
18084 }
18085
18086 /* Fill request buffer */
18087 misc = (mlan_ds_misc_cfg *)req->pbuf;
18088 misc->sub_command = MLAN_OID_MISC_RATE_ADAPT_CFG;
18089 req->req_id = MLAN_IOCTL_MISC_CFG;
18090 if ((int)strlen(respbuf) == header_len) {
18091 /* GET operation */
18092 user_data_len = 0;
18093 req->action = MLAN_ACT_GET;
18094 } else {
18095 /* SET operation */
18096 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18097 &user_data_len);
18098 if (user_data_len < 1) {
18099 PRINTM(MERROR, "Invalid number of args!\n");
18100 ret = -EINVAL;
18101 goto done;
18102 }
18103 if (data[0] > RATEADAPT_ALGO_SR) {
18104 PRINTM(MERROR, "Invalid Rateadapt Algorithm\n");
18105 ret = -EINVAL;
18106 goto done;
18107 }
18108 if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
18109 if ((data[1] & data[2]) == 0xff) {
18110 /* dynamic CCA noise based rate adapation enable
18111 * request nothing to do here
18112 */
18113 } else if (data[1] > 100 || data[2] > 100) {
18114 PRINTM(MERROR,
18115 "Invalid success rate threshold value\n");
18116 ret = -EINVAL;
18117 goto done;
18118 }
18119 if (data[3] < 10 || data[3] > 0xffff) {
18120 PRINTM(MERROR, "Invalid interval value\n");
18121 ret = -EINVAL;
18122 goto done;
18123 }
18124 }
18125 misc->param.rate_adapt_cfg.sr_rateadapt = (t_u8)data[0];
18126 if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) {
18127 misc->param.rate_adapt_cfg.ra_low_thresh =
18128 (t_u8)data[1];
18129 misc->param.rate_adapt_cfg.ra_high_thresh =
18130 (t_u8)data[2];
18131 misc->param.rate_adapt_cfg.ra_interval = (t_u16)data[3];
18132 }
18133 req->action = MLAN_ACT_SET;
18134 }
18135 /* Send IOCTL request to MLAN */
18136 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18137 if (status != MLAN_STATUS_SUCCESS) {
18138 ret = -EFAULT;
18139 goto done;
18140 }
18141 data[0] = misc->param.rate_adapt_cfg.sr_rateadapt;
18142 data[1] = misc->param.rate_adapt_cfg.ra_low_thresh;
18143 data[2] = misc->param.rate_adapt_cfg.ra_high_thresh;
18144 data[3] = misc->param.rate_adapt_cfg.ra_interval;
18145 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18146 respbuflen);
18147 ret = sizeof(data);
18148 done:
18149 if (status != MLAN_STATUS_PENDING)
18150 kfree(req);
18151
18152 LEAVE();
18153 return ret;
18154 }
18155
18156 /**
18157 * @brief Set/Get global cck desense config
18158 *
18159 * @param priv A pointer to moal_private structure
18160 * @param respbuf A pointer to response buffer
18161 * @param respbuflen Available length of response buffer
18162 *
18163 * @return Number of bytes written, negative for failure.
18164 */
woal_priv_cck_desense_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18165 static int woal_priv_cck_desense_cfg(moal_private *priv, t_u8 *respbuf,
18166 t_u32 respbuflen)
18167 {
18168 mlan_ioctl_req *req = NULL;
18169 mlan_ds_misc_cfg *misc = NULL;
18170 int ret = 0;
18171 int data[5] = {0};
18172 int header_len = 0, user_data_len = 0;
18173 mlan_status status = MLAN_STATUS_SUCCESS;
18174
18175 ENTER();
18176
18177 if (!respbuf) {
18178 PRINTM(MERROR, "response buffer is not available!\n");
18179 ret = -EINVAL;
18180 goto done;
18181 }
18182 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CCK_DESENSE_CFG);
18183 user_data_len = strlen(respbuf) - header_len;
18184
18185 /* Allocate an IOCTL request buffer */
18186 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18187 if (req == NULL) {
18188 ret = -ENOMEM;
18189 goto done;
18190 }
18191
18192 /* Fill request buffer */
18193 misc = (mlan_ds_misc_cfg *)req->pbuf;
18194 misc->sub_command = MLAN_OID_MISC_CCK_DESENSE_CFG;
18195 req->req_id = MLAN_IOCTL_MISC_CFG;
18196 if ((int)strlen(respbuf) == header_len) {
18197 /* GET operation */
18198 user_data_len = 0;
18199 req->action = MLAN_ACT_GET;
18200 } else {
18201 /* SET operation */
18202 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18203 &user_data_len);
18204 if (user_data_len > 5) {
18205 PRINTM(MERROR, "Invalid number of args!\n");
18206 ret = -EINVAL;
18207 goto done;
18208 }
18209 if (data[0] > CCK_DESENSE_MODE_DYN_ENH) {
18210 PRINTM(MERROR, "Invalid cck desense mode\n");
18211 ret = -EINVAL;
18212 goto done;
18213 }
18214 if ((data[0] == CCK_DESENSE_MODE_DISABLED &&
18215 user_data_len > 1) ||
18216 (data[0] == CCK_DESENSE_MODE_DYNAMIC &&
18217 user_data_len != 3) ||
18218 (data[0] == CCK_DESENSE_MODE_DYN_ENH &&
18219 (user_data_len < 3 || user_data_len == 4))) {
18220 PRINTM(MERROR,
18221 "Invalid number of args for requested mode\n");
18222 ret = -EINVAL;
18223 goto done;
18224 }
18225 if (user_data_len > 1) {
18226 if (data[1] > 0x7f) {
18227 PRINTM(MERROR, "Invalid margin value\n");
18228 ret = -EINVAL;
18229 goto done;
18230 }
18231 if (data[2] > 0x7f) {
18232 PRINTM(MERROR,
18233 "Invalid ceil threshold value\n");
18234 ret = -EINVAL;
18235 goto done;
18236 }
18237 }
18238 if (user_data_len > 3) {
18239 if (data[3] > 0xff || data[4] > 0xff) {
18240 PRINTM(MERROR,
18241 "Invalid ON/OFF intervals value\n");
18242 ret = -EINVAL;
18243 goto done;
18244 }
18245 }
18246 misc->param.cck_desense_cfg.mode = (t_u8)data[0];
18247 if (user_data_len > 1) {
18248 misc->param.cck_desense_cfg.margin = (t_s8)data[1];
18249 misc->param.cck_desense_cfg.ceil_thresh = (t_s8)data[2];
18250 }
18251 if (data[0] == CCK_DESENSE_MODE_DYN_ENH) {
18252 if (user_data_len > 3) {
18253 misc->param.cck_desense_cfg.num_on_intervals =
18254 (t_u8)data[3];
18255 misc->param.cck_desense_cfg.num_off_intervals =
18256 (t_u8)data[4];
18257 } else {
18258 /* set these to 0xff. This will indicate the FW
18259 * to use previously set values.
18260 */
18261 misc->param.cck_desense_cfg.num_on_intervals =
18262 0xff;
18263 misc->param.cck_desense_cfg.num_off_intervals =
18264 0xff;
18265 }
18266 }
18267 req->action = MLAN_ACT_SET;
18268 }
18269 /* Send IOCTL request to MLAN */
18270 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18271 if (status != MLAN_STATUS_SUCCESS) {
18272 ret = -EFAULT;
18273 goto done;
18274 }
18275
18276 data[0] = misc->param.cck_desense_cfg.mode;
18277 data[1] = misc->param.cck_desense_cfg.margin;
18278 data[2] = misc->param.cck_desense_cfg.ceil_thresh;
18279 data[3] = misc->param.cck_desense_cfg.num_on_intervals;
18280 data[4] = misc->param.cck_desense_cfg.num_off_intervals;
18281 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data),
18282 respbuflen);
18283 ret = sizeof(data);
18284
18285 done:
18286 if (status != MLAN_STATUS_PENDING)
18287 kfree(req);
18288
18289 LEAVE();
18290 return ret;
18291 }
18292
18293 /**
18294 * @brief set/get low power mode
18295 *
18296 * @param priv Pointer to moal_private structure
18297 * @param respbuf Pointer to response buffer
18298 * @param resplen Response buffer length
18299
18300 * @return Number of bytes written, negative for failure.
18301 */
woal_priv_set_get_lpm(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18302 static int woal_priv_set_get_lpm(moal_private *priv, t_u8 *respbuf,
18303 t_u32 respbuflen)
18304 {
18305 int ret = 0;
18306 mlan_ioctl_req *req = NULL;
18307 mlan_ds_power_cfg *cfg = NULL;
18308 int data = 0;
18309 int user_data_len = 0, header_len = 0;
18310 mlan_status status = MLAN_STATUS_SUCCESS;
18311
18312 ENTER();
18313
18314 if (IS_CARD9098(priv->phandle->card_type) ||
18315 IS_CARD9097(priv->phandle->card_type)) {
18316 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_LPM);
18317 if ((int)strlen(respbuf) == header_len) {
18318 /* GET operation */
18319 user_data_len = 0;
18320 } else {
18321 /* SET operation */
18322 parse_arguments(respbuf + header_len, &data, 1,
18323 &user_data_len);
18324 }
18325 if (user_data_len >= 2) {
18326 PRINTM(MERROR, "Too many arguments\n");
18327 ret = -EINVAL;
18328 goto done;
18329 } else {
18330 req = woal_alloc_mlan_ioctl_req(
18331 sizeof(mlan_ds_power_cfg));
18332 if (req == NULL) {
18333 ret = -ENOMEM;
18334 goto done;
18335 }
18336
18337 cfg = (mlan_ds_power_cfg *)req->pbuf;
18338 if (user_data_len == 0) {
18339 req->action = MLAN_ACT_GET;
18340 } else {
18341 cfg->param.lpm = data;
18342 req->action = MLAN_ACT_SET;
18343 }
18344 }
18345 cfg->sub_command = MLAN_OID_POWER_LOW_POWER_MODE;
18346 req->req_id = MLAN_IOCTL_POWER_CFG;
18347
18348 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18349 if (status != MLAN_STATUS_SUCCESS) {
18350 ret = -EFAULT;
18351 goto done;
18352 }
18353
18354 data = cfg->param.lpm;
18355 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data,
18356 sizeof(data), respbuflen);
18357 ret = sizeof(data);
18358 } else
18359 PRINTM(MERROR, "Low power mode command is not supported!\n");
18360
18361 done:
18362 if (status != MLAN_STATUS_PENDING)
18363 kfree(req);
18364 LEAVE();
18365 return ret;
18366 }
18367
18368 /**
18369 * @brief Set/Get HW ARB config
18370 *
18371 * @param priv A pointer to moal_private structure
18372 * @param respbuf A pointer to response buffer
18373 * @param respbuflen Available length of response buffer
18374 *
18375 * @return Number of bytes written, negative for failure.
18376 */
woal_priv_arbcfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18377 static int woal_priv_arbcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen)
18378 {
18379 mlan_ioctl_req *req = NULL;
18380 mlan_ds_misc_cfg *misc = NULL;
18381 int ret = 0;
18382 int data[1];
18383 int header_len = 0, user_data_len = 0;
18384 mlan_status status = MLAN_STATUS_SUCCESS;
18385
18386 ENTER();
18387
18388 if (!respbuf) {
18389 PRINTM(MERROR, "response buffer is not available!\n");
18390 ret = -EINVAL;
18391 goto done;
18392 }
18393 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ARB_CFG);
18394 user_data_len = strlen(respbuf) - header_len;
18395
18396 /* Allocate an IOCTL request buffer */
18397 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18398 if (req == NULL) {
18399 ret = -ENOMEM;
18400 goto done;
18401 }
18402 /* Fill request buffer */
18403 misc = (mlan_ds_misc_cfg *)req->pbuf;
18404 misc->sub_command = MLAN_OID_MISC_ARB_CONFIG;
18405 req->req_id = MLAN_IOCTL_MISC_CFG;
18406 if ((int)strlen(respbuf) == header_len) {
18407 /* GET operation */
18408 user_data_len = 0;
18409 req->action = MLAN_ACT_GET;
18410 } else {
18411 /* SET operation */
18412 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18413 &user_data_len);
18414 if (user_data_len != 1) {
18415 PRINTM(MERROR, "Invalid Parameter\n");
18416 ret = -EFAULT;
18417 goto done;
18418 }
18419 if (data[0] < 0 || data[0] > 4) {
18420 PRINTM(MERROR, "Invalid Parameter: arb mode 0-4\n");
18421 ret = -EFAULT;
18422 goto done;
18423 }
18424 misc->param.arb_cfg.arb_mode = (t_u32)data[0];
18425 req->action = MLAN_ACT_SET;
18426 }
18427 /* Send IOCTL request to MLAN */
18428 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18429 if (status != MLAN_STATUS_SUCCESS) {
18430 ret = -EFAULT;
18431 goto done;
18432 }
18433
18434 data[0] = misc->param.arb_cfg.arb_mode;
18435 moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data),
18436 respbuflen);
18437 ret = sizeof(data);
18438 done:
18439 if (status != MLAN_STATUS_PENDING)
18440 kfree(req);
18441
18442 LEAVE();
18443 return ret;
18444 }
18445
18446 /**
18447 * @brief Timer function for TP state command.
18448 *
18449 * @param data pointer to a buffer
18450 *
18451 * @return N/A
18452 */
woal_tp_acnt_timer_func(void * context)18453 void woal_tp_acnt_timer_func(void *context)
18454 {
18455 moal_handle *phandle = (moal_handle *)context;
18456 int i = 0;
18457
18458 if (phandle == NULL)
18459 return;
18460 PRINTM(MDATA, "####### CPU%d: tp acnt timer\n", smp_processor_id());
18461 /* Tx TP accounting */
18462 for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
18463 phandle->tp_acnt.tx_bytes_rate[i] =
18464 phandle->tp_acnt.tx_bytes[i] -
18465 phandle->tp_acnt.tx_bytes_last[i];
18466 phandle->tp_acnt.tx_bytes_last[i] =
18467 phandle->tp_acnt.tx_bytes[i];
18468 phandle->tp_acnt.tx_packets_rate[i] =
18469 phandle->tp_acnt.tx_packets[i] -
18470 phandle->tp_acnt.tx_packets_last[i];
18471 phandle->tp_acnt.tx_packets_last[i] =
18472 phandle->tp_acnt.tx_packets[i];
18473 }
18474 phandle->tp_acnt.tx_pending = atomic_read(&phandle->tx_pending);
18475 /* Tx Interrupt accounting */
18476 phandle->tp_acnt.tx_intr_rate =
18477 phandle->tp_acnt.tx_intr_cnt - phandle->tp_acnt.tx_intr_last;
18478 phandle->tp_acnt.tx_intr_last = phandle->tp_acnt.tx_intr_cnt;
18479
18480 /* Rx TP accounting */
18481 for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
18482 phandle->tp_acnt.rx_bytes_rate[i] =
18483 phandle->tp_acnt.rx_bytes[i] -
18484 phandle->tp_acnt.rx_bytes_last[i];
18485 phandle->tp_acnt.rx_bytes_last[i] =
18486 phandle->tp_acnt.rx_bytes[i];
18487 phandle->tp_acnt.rx_packets_rate[i] =
18488 phandle->tp_acnt.rx_packets[i] -
18489 phandle->tp_acnt.rx_packets_last[i];
18490 phandle->tp_acnt.rx_packets_last[i] =
18491 phandle->tp_acnt.rx_packets[i];
18492 }
18493 phandle->tp_acnt.rx_pending = atomic_read(&phandle->rx_pending);
18494 // Interrupt accounting, RX
18495 phandle->tp_acnt.rx_intr_rate =
18496 phandle->tp_acnt.rx_intr_cnt - phandle->tp_acnt.rx_intr_last;
18497 phandle->tp_acnt.rx_intr_last = phandle->tp_acnt.rx_intr_cnt;
18498 phandle->tp_acnt.rx_amsdu_cnt_rate = phandle->tp_acnt.rx_amsdu_cnt -
18499 phandle->tp_acnt.rx_amsdu_cnt_last;
18500 phandle->tp_acnt.rx_amsdu_cnt_last = phandle->tp_acnt.rx_amsdu_cnt;
18501
18502 phandle->tp_acnt.rx_amsdu_pkt_cnt_rate =
18503 phandle->tp_acnt.rx_amsdu_pkt_cnt -
18504 phandle->tp_acnt.rx_amsdu_pkt_cnt_last;
18505 phandle->tp_acnt.rx_amsdu_pkt_cnt_last =
18506 phandle->tp_acnt.rx_amsdu_pkt_cnt;
18507
18508 phandle->tp_acnt.tx_amsdu_cnt_rate = phandle->tp_acnt.tx_amsdu_cnt -
18509 phandle->tp_acnt.tx_amsdu_cnt_last;
18510 phandle->tp_acnt.tx_amsdu_cnt_last = phandle->tp_acnt.tx_amsdu_cnt;
18511
18512 phandle->tp_acnt.tx_amsdu_pkt_cnt_rate =
18513 phandle->tp_acnt.tx_amsdu_pkt_cnt -
18514 phandle->tp_acnt.tx_amsdu_pkt_cnt_last;
18515 phandle->tp_acnt.tx_amsdu_pkt_cnt_last =
18516 phandle->tp_acnt.tx_amsdu_pkt_cnt;
18517
18518 /* re-arm timer */
18519 woal_mod_timer(&phandle->tp_acnt.timer, 1000);
18520 }
18521
18522 /**
18523 * @brief set tp state to mlan
18524 *
18525 * @param priv pointer to moal_private
18526 *
18527 * @return N/A
18528 */
woal_set_tp_state(moal_private * priv)18529 void woal_set_tp_state(moal_private *priv)
18530 {
18531 mlan_ioctl_req *req = NULL;
18532 mlan_ds_misc_cfg *misc = NULL;
18533 moal_handle *handle = priv->phandle;
18534 mlan_status status = MLAN_STATUS_SUCCESS;
18535 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18536 if (req == NULL)
18537 return;
18538 /* Fill request buffer */
18539 misc = (mlan_ds_misc_cfg *)req->pbuf;
18540 misc->sub_command = MLAN_OID_MISC_TP_STATE;
18541 req->req_id = MLAN_IOCTL_MISC_CFG;
18542 misc->param.tp_state.on = handle->tp_acnt.on;
18543 misc->param.tp_state.drop_point = handle->tp_acnt.drop_point;
18544 req->action = MLAN_ACT_SET;
18545 /* Send IOCTL request to MLAN */
18546 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18547 if (status != MLAN_STATUS_PENDING)
18548 kfree(req);
18549 return;
18550 }
18551
18552 /**
18553 * @brief Set/Get TP statistics.
18554 *
18555 * @param priv A pointer to moal_private structure
18556 * @param respbuf A pointer to response buffer
18557 * @param respbuflen Available length of response buffer
18558 *
18559 * @return Number of bytes written, negative for failure.
18560 */
woal_priv_set_tp_state(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18561 static int woal_priv_set_tp_state(moal_private *priv, t_u8 *respbuf,
18562 t_u32 respbuflen)
18563 {
18564 moal_handle *handle = priv->phandle;
18565 int ret = 0;
18566 int data[2];
18567 int header_len = 0, user_data_len = 0;
18568
18569 ENTER();
18570
18571 if (!respbuf) {
18572 PRINTM(MERROR, "response buffer is not available!\n");
18573 ret = -EINVAL;
18574 goto done;
18575 }
18576 header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TP_STATE);
18577 user_data_len = strlen(respbuf) - header_len;
18578 parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data),
18579 &user_data_len);
18580 if (user_data_len > 2) {
18581 PRINTM(MERROR, "Invalid number of args!\n");
18582 ret = -EINVAL;
18583 goto done;
18584 }
18585 if (user_data_len) {
18586 handle->tp_acnt.on = data[0];
18587 /* Enable TP statistics collection */
18588 if (data[0] == 1) {
18589 handle->tp_acnt.drop_point = data[1];
18590 if (handle->is_tp_acnt_timer_set == MFALSE) {
18591 woal_initialize_timer(&handle->tp_acnt.timer,
18592 woal_tp_acnt_timer_func,
18593 handle);
18594 handle->is_tp_acnt_timer_set = MTRUE;
18595 woal_mod_timer(&handle->tp_acnt.timer, 1000);
18596 }
18597 } else {
18598 if (handle->is_tp_acnt_timer_set) {
18599 woal_cancel_timer(&handle->tp_acnt.timer);
18600 handle->is_tp_acnt_timer_set = MFALSE;
18601 }
18602 memset((void *)&handle->tp_acnt, 0,
18603 sizeof(moal_tp_acnt_t));
18604 }
18605 woal_set_tp_state(priv);
18606 }
18607 /* Get command results */
18608 if (user_data_len == 0) {
18609 moal_memcpy_ext(handle, respbuf, (t_u8 *)(&handle->tp_acnt),
18610 sizeof(handle->tp_acnt), respbuflen);
18611 ret = sizeof(handle->tp_acnt);
18612 }
18613
18614 done:
18615 LEAVE();
18616 return ret;
18617 }
18618
woal_priv_ips_cfg(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18619 static int woal_priv_ips_cfg(moal_private *priv, t_u8 *respbuf,
18620 t_u32 respbuflen)
18621 {
18622 moal_handle *handle = priv->phandle;
18623 mlan_ioctl_req *req = NULL;
18624 mlan_ds_misc_cfg *misc = NULL;
18625 t_u32 data[1];
18626 int ret = 0;
18627 int user_data_len = 0;
18628 mlan_status status = MLAN_STATUS_SUCCESS;
18629
18630 ENTER();
18631 if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_IPS_CFG))) {
18632 /* GET operation */
18633 user_data_len = 0;
18634 } else {
18635 /* SET operation */
18636 memset((char *)data, 0, sizeof(data));
18637 parse_arguments(respbuf + strlen(CMD_NXP) +
18638 strlen(PRIV_CMD_IPS_CFG),
18639 data, ARRAY_SIZE(data), &user_data_len);
18640 }
18641 if (user_data_len) {
18642 /* Allocate an IOCTL request buffer */
18643 req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
18644 if (req == NULL) {
18645 ret = -ENOMEM;
18646 goto done;
18647 }
18648 /* Fill request buffer */
18649 misc = (mlan_ds_misc_cfg *)req->pbuf;
18650 misc->sub_command = MLAN_OID_MISC_IPS_CFG;
18651 req->req_id = MLAN_IOCTL_MISC_CFG;
18652 misc->param.ips_ctrl = data[0];
18653 req->action = MLAN_ACT_SET;
18654 /* Send IOCTL request to MLAN */
18655 status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
18656 if (status != MLAN_STATUS_SUCCESS) {
18657 ret = -EFAULT;
18658 goto done;
18659 }
18660 handle->ips_ctrl = data[0];
18661 } else {
18662 data[0] = handle->ips_ctrl;
18663 moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data,
18664 sizeof(data), respbuflen);
18665 }
18666 ret = sizeof(data);
18667 done:
18668 if (status != MLAN_STATUS_PENDING)
18669 kfree(req);
18670 LEAVE();
18671 return ret;
18672 }
18673
woal_priv_get_uuid(moal_private * priv,t_u8 * respbuf,t_u32 respbuflen)18674 static int woal_priv_get_uuid(moal_private *priv, t_u8 *respbuf,
18675 t_u32 respbuflen)
18676 {
18677 int ret = -1;
18678 mlan_fw_info fw_info;
18679
18680 ENTER();
18681
18682 if (!respbuf) {
18683 PRINTM(MERROR, "response buffer is not available!\n");
18684 ret = -1;
18685 } else {
18686 fw_info.uuid_lo = fw_info.uuid_hi = 0x0ULL;
18687
18688 woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
18689 snprintf(respbuf, MLAN_MAX_UUID_LEN + 1, "%016llx%016llx",
18690 fw_info.uuid_lo, fw_info.uuid_hi);
18691 ret = strlen(respbuf);
18692 }
18693
18694 LEAVE();
18695 return ret;
18696 }
18697
18698 /**
18699 * @brief Set priv command for Android
18700 * @param dev A pointer to net_device structure
18701 * @param req A pointer to ifreq structure
18702 *
18703 * @return 0 --success, otherwise fail
18704 */
woal_android_priv_cmd(struct net_device * dev,struct ifreq * req)18705 int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req)
18706 {
18707 int ret = 0;
18708 android_wifi_priv_cmd priv_cmd;
18709 moal_private *priv = (moal_private *)netdev_priv(dev);
18710 char *buf = NULL;
18711 char *pdata;
18712 #ifdef STA_SUPPORT
18713 int power_mode = 0;
18714 int band = 0;
18715 char *pband = NULL;
18716 mlan_bss_info bss_info;
18717 mlan_ds_get_signal signal;
18718 mlan_rate_cfg_t rate;
18719 t_u8 country_code[COUNTRY_CODE_LEN];
18720 int copy_len = 0;
18721 #endif
18722 int len = 0;
18723 gfp_t flag;
18724 char *cmd_buf = NULL;
18725 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
18726 int cfg80211_wext;
18727 #endif
18728
18729 ENTER();
18730 if (!priv || !priv->phandle) {
18731 PRINTM(MERROR, "priv or handle is NULL\n");
18732 ret = -EFAULT;
18733 goto done;
18734 }
18735 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
18736 cfg80211_wext = priv->phandle->params.cfg80211_wext;
18737 #endif
18738 if (copy_from_user(&priv_cmd, req->ifr_data,
18739 sizeof(android_wifi_priv_cmd))) {
18740 ret = -EFAULT;
18741 goto done;
18742 }
18743 #define CMD_BUF_LEN 4096
18744 if (priv_cmd.used_len < 0 || priv_cmd.total_len <= 0 ||
18745 priv_cmd.used_len > priv_cmd.total_len) {
18746 PRINTM(MERROR,
18747 "Invalid Android priv cmd len. used_len: %d, total_len: %d\n",
18748 priv_cmd.used_len, priv_cmd.total_len);
18749 ret = -EINVAL;
18750 goto done;
18751 }
18752 if (priv_cmd.total_len + 1 > CMD_BUF_LEN)
18753 priv_cmd.total_len = CMD_BUF_LEN - 1;
18754
18755 flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
18756 buf = kzalloc(CMD_BUF_LEN, flag);
18757 if (!buf) {
18758 PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__);
18759 ret = -ENOMEM;
18760 goto done;
18761 }
18762 #ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT
18763 moal_memcpy_ext(priv->phandle, &cmd_buf, &priv_cmd.buf, sizeof(cmd_buf),
18764 sizeof(cmd_buf));
18765 #else
18766 cmd_buf = priv_cmd.buf;
18767 #endif
18768 if (copy_from_user(buf, (const void __user *)cmd_buf,
18769 priv_cmd.total_len)) {
18770 ret = -EFAULT;
18771 goto done;
18772 }
18773 buf[CMD_BUF_LEN - 1] = '\0';
18774
18775 PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name);
18776
18777 if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) &&
18778 woal_check_driver_status(priv->phandle)) {
18779 PRINTM(MERROR, "%s fail when driver hang\n", buf);
18780 ret = -EFAULT;
18781 goto done;
18782 }
18783
18784 if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) == 0) {
18785 /* This command has come from mlanutl app */
18786
18787 /* Check command */
18788 if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VERSION,
18789 strlen(PRIV_CMD_VERSION)) == 0) {
18790 /* Get version */
18791 len = woal_get_priv_driver_version(priv, buf,
18792 priv_cmd.total_len);
18793 goto handled;
18794 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BANDCFG,
18795 strlen(PRIV_CMD_BANDCFG)) == 0) {
18796 /* Set/Get band configuration */
18797 len = woal_setget_priv_bandcfg(priv, buf,
18798 priv_cmd.total_len);
18799 goto handled;
18800 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOSTCMD,
18801 strlen(PRIV_CMD_HOSTCMD)) == 0) {
18802 /* hostcmd configuration */
18803 len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len,
18804 MOAL_IOCTL_WAIT);
18805 goto handled;
18806 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCMDCFG,
18807 strlen(PRIV_CMD_11AXCMDCFG)) == 0) {
18808 /* 11ax command */
18809 pdata = buf + strlen(CMD_NXP) +
18810 strlen(PRIV_CMD_11AXCMDCFG);
18811 len = priv_cmd.total_len - strlen(CMD_NXP) +
18812 strlen(PRIV_CMD_11AXCMDCFG);
18813 len = woal_setget_priv_11axcmdcfg(priv, pdata, len,
18814 MOAL_IOCTL_WAIT);
18815 len += strlen(CMD_NXP) + strlen(PRIV_CMD_11AXCMDCFG);
18816 goto handled;
18817 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RANGE_EXT,
18818 strlen(PRIV_CMD_RANGE_EXT)) == 0) {
18819 len = woal_setget_priv_range_ext(priv, buf,
18820 priv_cmd.total_len);
18821 goto handled;
18822 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTTXCFG,
18823 strlen(PRIV_CMD_HTTXCFG)) == 0) {
18824 /* Set/Get HT Tx configuration */
18825 len = woal_setget_priv_httxcfg(priv, buf,
18826 priv_cmd.total_len);
18827 goto handled;
18828 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTCAPINFO,
18829 strlen(PRIV_CMD_HTCAPINFO)) == 0) {
18830 /* Set/Get HT Capability information */
18831 len = woal_setget_priv_htcapinfo(priv, buf,
18832 priv_cmd.total_len);
18833 goto handled;
18834 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAPARA,
18835 strlen(PRIV_CMD_ADDBAPARA)) == 0) {
18836 /* Set/Get Add BA parameters */
18837 len = woal_setget_priv_addbapara(priv, buf,
18838 priv_cmd.total_len);
18839 goto handled;
18840 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRPRIOTBL,
18841 strlen(PRIV_CMD_AGGRPRIOTBL)) == 0) {
18842 /* Set/Get Aggregation priority table parameters */
18843 len = woal_setget_priv_aggrpriotbl(priv, buf,
18844 priv_cmd.total_len);
18845 goto handled;
18846 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAREJECT,
18847 strlen(PRIV_CMD_ADDBAREJECT)) == 0) {
18848 /* Set/Get Add BA reject parameters */
18849 len = woal_setget_priv_addbareject(priv, buf,
18850 priv_cmd.total_len);
18851 goto handled;
18852 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELBA,
18853 strlen(PRIV_CMD_DELBA)) == 0) {
18854 /* Delete selective BA based on parameters */
18855 len = woal_priv_delba(priv, buf, priv_cmd.total_len);
18856 goto handled;
18857 } else if (strnicmp(buf + strlen(CMD_NXP),
18858 PRIV_CMD_REJECTADDBAREQ,
18859 strlen(PRIV_CMD_REJECTADDBAREQ)) == 0) {
18860 /* Set/Get the reject addba requst conditions*/
18861 len = woal_priv_rejectaddbareq(priv, buf,
18862 priv_cmd.total_len);
18863 goto handled;
18864 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VHTCFG,
18865 strlen(PRIV_CMD_VHTCFG)) == 0) {
18866 /* Set/Get 11AC configuration */
18867 len = woal_setget_priv_vhtcfg(priv, buf,
18868 priv_cmd.total_len);
18869 goto handled;
18870 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OPERMODECFG,
18871 strlen(PRIV_CMD_OPERMODECFG)) == 0) {
18872 /* Set/Get 11AC configuration */
18873 len = woal_setget_priv_opermodecfg(priv, buf,
18874 priv_cmd.total_len);
18875 goto handled;
18876 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DATARATE,
18877 strlen(PRIV_CMD_DATARATE)) == 0) {
18878 /* Get data rate */
18879 len = woal_get_priv_datarate(priv, buf,
18880 priv_cmd.total_len);
18881 goto handled;
18882 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXRATECFG,
18883 strlen(PRIV_CMD_TXRATECFG)) == 0) {
18884 /* Set/Get tx rate cfg */
18885 len = woal_setget_priv_txratecfg(priv, buf,
18886 priv_cmd.total_len);
18887 goto handled;
18888 #if defined(STA_SUPPORT) || defined(UAP_SUPPORT)
18889 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETLOG,
18890 strlen(PRIV_CMD_GETLOG)) == 0) {
18891 /* Get wireless stats information */
18892 len = woal_get_priv_getlog(priv, buf,
18893 priv_cmd.total_len);
18894 goto handled;
18895 #endif
18896 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CUSTOMIE,
18897 strlen(PRIV_CMD_CUSTOMIE)) == 0) {
18898 /* Custom IE configuration */
18899 len = woal_priv_customie(priv, buf, priv_cmd.total_len);
18900 goto handled;
18901 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ESUPPMODE,
18902 strlen(PRIV_CMD_ESUPPMODE)) == 0) {
18903 /* Esupplicant mode configuration */
18904 len = woal_setget_priv_esuppmode(priv, buf,
18905 priv_cmd.total_len);
18906 goto handled;
18907 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PASSPHRASE,
18908 strlen(PRIV_CMD_PASSPHRASE)) == 0) {
18909 /* Esupplicant passphrase configuration */
18910 len = woal_setget_priv_passphrase(priv, buf,
18911 priv_cmd.total_len);
18912 goto handled;
18913 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH,
18914 strlen(PRIV_CMD_DEAUTH)) == 0) {
18915 /* Deauth */
18916 len = woal_priv_deauth(priv, buf, priv_cmd.total_len);
18917 goto handled;
18918 #ifdef UAP_SUPPORT
18919 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AP_DEAUTH,
18920 strlen(PRIV_CMD_AP_DEAUTH)) == 0) {
18921 /* AP Deauth */
18922 len = woal_priv_ap_deauth(priv, buf,
18923 priv_cmd.total_len);
18924 goto handled;
18925 } else if (strnicmp(buf + strlen(CMD_NXP),
18926 PRIV_CMD_GET_STA_LIST,
18927 strlen(PRIV_CMD_GET_STA_LIST)) == 0) {
18928 /* Get STA list */
18929 len = woal_priv_get_sta_list(priv, buf,
18930 priv_cmd.total_len);
18931 goto handled;
18932 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSS_CONFIG,
18933 strlen(PRIV_CMD_BSS_CONFIG)) == 0) {
18934 /* BSS config */
18935 len = woal_priv_bss_config(priv, buf,
18936 priv_cmd.total_len);
18937 goto handled;
18938 #endif
18939 #ifdef WIFI_DIRECT_SUPPORT
18940 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
18941 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSSROLE,
18942 strlen(PRIV_CMD_BSSROLE)) == 0) {
18943 /* BSS Role */
18944 len = woal_priv_bssrole(priv, buf,
18945 (t_u32)priv_cmd.total_len);
18946 goto handled;
18947 #endif
18948 #endif
18949 #ifdef STA_SUPPORT
18950 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SETUSERSCAN,
18951 strlen(PRIV_CMD_SETUSERSCAN)) == 0) {
18952 /* Set user scan */
18953 len = woal_priv_setuserscan(priv, buf,
18954 priv_cmd.total_len);
18955 goto handled;
18956 } else if (strnicmp(buf + strlen(CMD_NXP),
18957 PRIV_CMD_GETSCANTABLE,
18958 strlen(PRIV_CMD_GETSCANTABLE)) == 0) {
18959 /* Get scan table */
18960 len = woal_priv_getscantable(priv, buf,
18961 priv_cmd.total_len);
18962 goto handled;
18963 } else if (strnicmp(buf + strlen(CMD_NXP),
18964 PRIV_CMD_GETCHANSTATS,
18965 strlen(PRIV_CMD_GETCHANSTATS)) == 0) {
18966 /* Get channel statistics */
18967 len = woal_priv_get_chanstats(priv, buf,
18968 priv_cmd.total_len);
18969 goto handled;
18970 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_EXTCAPCFG,
18971 strlen(PRIV_CMD_EXTCAPCFG)) == 0) {
18972 /* Extended capabilities configure */
18973 len = woal_priv_extcapcfg(priv, buf,
18974 (t_u32)priv_cmd.total_len);
18975 goto handled;
18976 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CANCELSCAN,
18977 strlen(PRIV_CMD_CANCELSCAN)) == 0) {
18978 /* Cancel scan */
18979 len = woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
18980 goto handled;
18981 #endif
18982 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEEPSLEEP,
18983 strlen(PRIV_CMD_DEEPSLEEP)) == 0) {
18984 /* Deep sleep */
18985 len = woal_priv_setgetdeepsleep(priv, buf,
18986 priv_cmd.total_len);
18987 goto handled;
18988 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPADDR,
18989 strlen(PRIV_CMD_IPADDR)) == 0) {
18990 /* IP address */
18991 len = woal_priv_setgetipaddr(priv, buf,
18992 (t_u32)priv_cmd.total_len);
18993 goto handled;
18994 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WPSSESSION,
18995 strlen(PRIV_CMD_WPSSESSION)) == 0) {
18996 /* WPS Session */
18997 len = woal_priv_setwpssession(priv, buf,
18998 priv_cmd.total_len);
18999 goto handled;
19000 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OTPUSERDATA,
19001 strlen(PRIV_CMD_OTPUSERDATA)) == 0) {
19002 /* OTP user data */
19003 len = woal_priv_otpuserdata(priv, buf,
19004 priv_cmd.total_len);
19005 goto handled;
19006 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_COUNTRYCODE,
19007 strlen(PRIV_CMD_COUNTRYCODE)) == 0) {
19008 /* Country code */
19009 len = woal_priv_set_get_countrycode(priv, buf,
19010 priv_cmd.total_len);
19011 goto handled;
19012 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFPINFO,
19013 strlen(PRIV_CMD_CFPINFO)) == 0) {
19014 /* CFP info */
19015 len = woal_priv_get_cfpinfo(priv, buf,
19016 priv_cmd.total_len);
19017 goto handled;
19018 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TCPACKENH,
19019 strlen(PRIV_CMD_TCPACKENH)) == 0) {
19020 /* TCP ack enhancement */
19021 len = woal_priv_setgettcpackenh(priv, buf,
19022 priv_cmd.total_len);
19023 goto handled;
19024 #ifdef REASSOCIATION
19025 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCBSSID,
19026 strlen(PRIV_CMD_ASSOCBSSID)) == 0) {
19027 /* Associate to essid */
19028 len = woal_priv_assocessid(priv, buf,
19029 priv_cmd.total_len, 1);
19030 goto handled;
19031 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCESSID,
19032 strlen(PRIV_CMD_ASSOCESSID)) == 0) {
19033 /* Associate to essid */
19034 len = woal_priv_assocessid(priv, buf,
19035 priv_cmd.total_len, 0);
19036 goto handled;
19037 #endif
19038 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTOASSOC,
19039 strlen(PRIV_CMD_AUTOASSOC)) == 0) {
19040 /* Auto assoc */
19041 len = woal_priv_setgetautoassoc(priv, buf,
19042 priv_cmd.total_len);
19043 goto handled;
19044 } else if (strnicmp(buf + strlen(CMD_NXP),
19045 PRIV_CMD_WAKEUPREASON,
19046 strlen(PRIV_CMD_WAKEUPREASON)) == 0) {
19047 /* wakeup reason */
19048 len = woal_priv_getwakeupreason(priv, buf,
19049 priv_cmd.total_len);
19050 goto handled;
19051 #ifdef STA_SUPPORT
19052 } else if (strnicmp(buf + strlen(CMD_NXP),
19053 PRIV_CMD_LISTENINTERVAL,
19054 strlen(PRIV_CMD_LISTENINTERVAL)) == 0) {
19055 /* Listen Interval */
19056 len = woal_priv_set_get_listeninterval(
19057 priv, buf, priv_cmd.total_len);
19058 goto handled;
19059 #endif
19060 #ifdef DEBUG_LEVEL1
19061 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRVDBG,
19062 strlen(PRIV_CMD_DRVDBG)) == 0) {
19063 /* Driver debug bit mask */
19064 len = woal_priv_set_get_drvdbg(priv, buf,
19065 priv_cmd.total_len);
19066 goto handled;
19067 #endif
19068 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSCFG,
19069 strlen(PRIV_CMD_HSCFG)) == 0) {
19070 /* HS configuration */
19071 len = woal_priv_hscfg(priv, buf, priv_cmd.total_len,
19072 MTRUE);
19073 goto handled;
19074 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSSETPARA,
19075 strlen(PRIV_CMD_HSSETPARA)) == 0) {
19076 /* Set HS parameter */
19077 len = woal_priv_hssetpara(priv, buf,
19078 priv_cmd.total_len);
19079 goto handled;
19080 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MGMT_FILTER,
19081 strlen(PRIV_CMD_MGMT_FILTER)) == 0) {
19082 /* Management frame filter wakeup */
19083 len = woal_priv_mgmt_filter(priv, buf,
19084 priv_cmd.total_len);
19085 goto handled;
19086 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SCANCFG,
19087 strlen(PRIV_CMD_SCANCFG)) == 0) {
19088 /* Scan configuration */
19089 len = woal_priv_set_get_scancfg(priv, buf,
19090 priv_cmd.total_len);
19091 goto handled;
19092 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM,
19093 strlen(PRIV_CMD_GETNLNUM)) == 0) {
19094 /* Scan configuration */
19095 len = woal_priv_getnlnum(priv, buf, priv_cmd.total_len);
19096 goto handled;
19097 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRCTRL,
19098 strlen(PRIV_CMD_AGGRCTRL)) == 0) {
19099 /* aggregation control */
19100 len = woal_priv_set_get_aggrctrl(priv, buf,
19101 priv_cmd.total_len);
19102 goto handled;
19103 #ifdef USB
19104 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USBAGGRCTRL,
19105 strlen(PRIV_CMD_USBAGGRCTRL)) == 0) {
19106 /* USB aggregation control */
19107 len = woal_priv_set_get_usbaggrctrl(priv, buf,
19108 priv_cmd.total_len);
19109 goto handled;
19110 #endif
19111 } else if (strnicmp(buf + strlen(CMD_NXP),
19112 PRIV_CMD_SET_BSS_MODE,
19113 strlen(PRIV_CMD_SET_BSS_MODE)) == 0) {
19114 /* Set bss mode */
19115 len = woal_priv_set_bss_mode(priv, buf,
19116 priv_cmd.total_len);
19117 goto handled;
19118 #ifdef STA_SUPPORT
19119 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AP,
19120 strlen(PRIV_CMD_SET_AP)) == 0) {
19121 /* Set AP */
19122 len = woal_priv_set_ap(priv, buf, priv_cmd.total_len);
19123 goto handled;
19124 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_POWER,
19125 strlen(PRIV_CMD_SET_POWER)) == 0) {
19126 /* Set power management parameters */
19127 len = woal_priv_set_power(priv, buf,
19128 priv_cmd.total_len);
19129 goto handled;
19130 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_ESSID,
19131 strlen(PRIV_CMD_SET_ESSID)) == 0) {
19132 /* Set essid */
19133 len = woal_priv_set_essid(priv, buf,
19134 priv_cmd.total_len);
19135 goto handled;
19136 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AUTH,
19137 strlen(PRIV_CMD_SET_AUTH)) == 0) {
19138 /* Set authentication mode parameters */
19139 len = woal_priv_set_auth(priv, buf, priv_cmd.total_len);
19140 goto handled;
19141 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_AP,
19142 strlen(PRIV_CMD_GET_AP)) == 0) {
19143 /* Get AP */
19144 len = woal_priv_get_ap(priv, buf, priv_cmd.total_len);
19145 goto handled;
19146 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_POWER,
19147 strlen(PRIV_CMD_GET_POWER)) == 0) {
19148 /* Get power management parameters */
19149 len = woal_priv_get_power(priv, buf,
19150 priv_cmd.total_len);
19151 goto handled;
19152 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSMODE,
19153 strlen(PRIV_CMD_PSMODE)) == 0) {
19154 /* Set/Get PS mode */
19155 len = woal_priv_set_get_psmode(priv, buf,
19156 priv_cmd.total_len);
19157 goto handled;
19158 #endif
19159 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WARMRESET,
19160 strlen(PRIV_CMD_WARMRESET)) == 0) {
19161 /* Performs warm reset */
19162 len = woal_priv_warmreset(priv, buf,
19163 priv_cmd.total_len);
19164 goto handled;
19165 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXPOWERCFG,
19166 strlen(PRIV_CMD_TXPOWERCFG)) == 0) {
19167 /* TX power configurations */
19168 len = woal_priv_txpowercfg(priv, buf,
19169 priv_cmd.total_len);
19170 goto handled;
19171 } else if (strnicmp(buf + strlen(CMD_NXP),
19172 PRIV_CMD_RX_ABORT_CFG_EXT,
19173 strlen(PRIV_CMD_RX_ABORT_CFG_EXT)) == 0) {
19174 /* dynamic Rx Abort config */
19175 len = woal_priv_rx_abort_cfg_ext(priv, buf,
19176 priv_cmd.total_len);
19177 goto handled;
19178 } else if (strnicmp(buf + strlen(CMD_NXP),
19179 PRIV_CMD_RX_ABORT_CFG,
19180 strlen(PRIV_CMD_RX_ABORT_CFG)) == 0) {
19181 /* static Rx Abort config */
19182 len = woal_priv_rx_abort_cfg(priv, buf,
19183 priv_cmd.total_len);
19184 goto handled;
19185 } else if (strnicmp(buf + strlen(CMD_NXP),
19186 PRIV_CMD_TX_AMPDU_PROT_MODE,
19187 strlen(PRIV_CMD_TX_AMPDU_PROT_MODE)) == 0) {
19188 /* tx ampdu protection mode setting */
19189 len = woal_priv_tx_ampdu_prot_mode(priv, buf,
19190 priv_cmd.total_len);
19191 goto handled;
19192 } else if (strnicmp(buf + strlen(CMD_NXP),
19193 PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG,
19194 strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG)) ==
19195 0) {
19196 /* setting for dot11mc un-associated case FTM frame
19197 * exchange */
19198 len = woal_priv_dot11mc_unassoc_ftm_cfg(
19199 priv, buf, priv_cmd.total_len);
19200 goto handled;
19201 } else if (strnicmp(buf + strlen(CMD_NXP),
19202 PRIV_CMD_RATE_ADAPT_CFG,
19203 strlen(PRIV_CMD_RATE_ADAPT_CFG)) == 0) {
19204 /* rate adapt config */
19205 len = woal_priv_rate_adapt_cfg(priv, buf,
19206 priv_cmd.total_len);
19207 goto handled;
19208 } else if (strnicmp(buf + strlen(CMD_NXP),
19209 PRIV_CMD_CCK_DESENSE_CFG,
19210 strlen(PRIV_CMD_CCK_DESENSE_CFG)) == 0) {
19211 /* cck desense config */
19212 len = woal_priv_cck_desense_cfg(priv, buf,
19213 priv_cmd.total_len);
19214 goto handled;
19215 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSCFG,
19216 strlen(PRIV_CMD_PSCFG)) == 0) {
19217 /* PS configurations */
19218 len = woal_priv_pscfg(priv, buf, priv_cmd.total_len);
19219 goto handled;
19220 } else if (strnicmp(buf + strlen(CMD_NXP),
19221 PRIV_CMD_BCNTIMEOUTCFG,
19222 strlen(PRIV_CMD_BCNTIMEOUTCFG)) == 0) {
19223 /* Beacon timeout configurations */
19224 len = woal_priv_bcntimeoutcfg(priv, buf,
19225 priv_cmd.total_len);
19226 goto handled;
19227 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SLEEPPD,
19228 strlen(PRIV_CMD_SLEEPPD)) == 0) {
19229 /* Sleep period */
19230 len = woal_priv_sleeppd(priv, buf, priv_cmd.total_len);
19231 goto handled;
19232 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXCONTROL,
19233 strlen(PRIV_CMD_TXCONTROL)) == 0) {
19234 /* Tx control */
19235 len = woal_priv_txcontrol(priv, buf,
19236 priv_cmd.total_len);
19237 goto handled;
19238 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGRDWR,
19239 strlen(PRIV_CMD_REGRDWR)) == 0) {
19240 /* Register Read/Write */
19241 len = woal_priv_regrdwr(priv, buf, priv_cmd.total_len);
19242 goto handled;
19243 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RDEEPROM,
19244 strlen(PRIV_CMD_RDEEPROM)) == 0) {
19245 /* Read the EEPROM contents of the card */
19246 len = woal_priv_rdeeprom(priv, buf, priv_cmd.total_len);
19247 goto handled;
19248 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MEMRDWR,
19249 strlen(PRIV_CMD_MEMRDWR)) == 0) {
19250 /* Memory Read/Write */
19251 len = woal_priv_memrdwr(priv, buf, priv_cmd.total_len);
19252 goto handled;
19253 #ifdef SDIO
19254 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDCMD52RW,
19255 strlen(PRIV_CMD_SDCMD52RW)) == 0) {
19256 /* Cmd52 read/write register */
19257 len = woal_priv_sdcmd52rw(priv, buf,
19258 priv_cmd.total_len);
19259 goto handled;
19260 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDIO_CLOCK,
19261 strlen(PRIV_CMD_SDIO_CLOCK)) == 0) {
19262 /* Turn on/off the sdio clock */
19263 len = woal_priv_sdio_clock_ioctl(priv, buf,
19264 priv_cmd.total_len);
19265 goto handled;
19266 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MPA_CTRL,
19267 strlen(PRIV_CMD_MPA_CTRL)) == 0) {
19268 /* Set SDIO Multi-point aggregation
19269 * control parameters */
19270 len = woal_priv_sdio_mpa_ctrl(priv, buf,
19271 priv_cmd.total_len);
19272 goto handled;
19273 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SD_CMD53_RW,
19274 strlen(PRIV_CMD_SD_CMD53_RW)) == 0) {
19275 /* Cmd53 read/write register */
19276 len = woal_priv_cmd53rdwr(priv, buf,
19277 priv_cmd.total_len);
19278 goto handled;
19279 #endif
19280 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ROBUSTCOEX,
19281 strlen(PRIV_CMD_ROBUSTCOEX)) == 0) {
19282 /* Set Robustcoex GPIOcfg */
19283 pdata = buf + strlen(CMD_NXP) +
19284 strlen(PRIV_CMD_ROBUSTCOEX);
19285 len = priv_cmd.total_len - strlen(PRIV_CMD_ROBUSTCOEX) -
19286 strlen(CMD_NXP);
19287 len = woal_priv_robustcoex(priv, pdata, len);
19288 goto handled;
19289 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DMCS,
19290 strlen(PRIV_CMD_DMCS)) == 0) {
19291 /* Set/Get DMCS config */
19292 len = woal_priv_dmcs(priv, buf, priv_cmd.total_len);
19293 goto handled;
19294 #if defined(PCIE)
19295 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SSU,
19296 strlen(PRIV_CMD_SSU)) == 0) {
19297 /* Set SSU config */
19298 pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_SSU);
19299 len = priv_cmd.used_len - strlen(PRIV_CMD_SSU) -
19300 strlen(CMD_NXP);
19301 len = woal_priv_ssu_cmd(priv, len, pdata,
19302 priv_cmd.total_len);
19303 goto handled;
19304 #endif
19305 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HAL_PHY_CFG,
19306 strlen(PRIV_CMD_HAL_PHY_CFG)) == 0) {
19307 /* Set hal_phy config */
19308 pdata = buf + strlen(CMD_NXP) +
19309 strlen(PRIV_CMD_HAL_PHY_CFG);
19310 len = priv_cmd.total_len -
19311 strlen(PRIV_CMD_HAL_PHY_CFG) - strlen(CMD_NXP);
19312 len = woal_priv_hal_phy_cfg_cmd(priv, pdata, len);
19313 goto handled;
19314 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CSI,
19315 strlen(PRIV_CMD_CSI)) == 0) {
19316 /* Set CSI config */
19317 pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_CSI);
19318 len = priv_cmd.total_len - strlen(PRIV_CMD_CSI) -
19319 strlen(CMD_NXP);
19320 priv->csi_seq = 0;
19321 len = woal_priv_csi_cmd(priv, pdata, len);
19322 goto handled;
19323 #ifdef STA_SUPPORT
19324 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARPFILTER,
19325 strlen(PRIV_CMD_ARPFILTER)) == 0) {
19326 /* ARPFilter Configuration */
19327 len = woal_priv_arpfilter(priv, buf,
19328 priv_cmd.total_len);
19329 goto handled;
19330 #endif
19331 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_ARP,
19332 strlen(PRIV_CMD_AUTO_ARP)) == 0) {
19333 /* Auto ARP enable/disable */
19334 len = woal_priv_set_get_auto_arp(priv, buf,
19335 priv_cmd.total_len);
19336 goto handled;
19337 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOTSPOTCFG,
19338 strlen(PRIV_CMD_HOTSPOTCFG)) == 0) {
19339 /* Hotspot CFG */
19340 len = woal_priv_hotspotcfg(priv, buf,
19341 priv_cmd.total_len);
19342 goto handled;
19343 #ifdef RX_PACKET_COALESCE
19344 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RX_COAL_CFG,
19345 strlen(PRIV_CMD_RX_COAL_CFG)) == 0) {
19346 /* RX packet coalescing Configuration */
19347 len = woal_priv_rx_pkt_coalesce_cfg(priv, buf,
19348 priv_cmd.total_len);
19349 goto handled;
19350 #endif
19351
19352 } else if (strnicmp(buf + strlen(CMD_NXP),
19353 PRIV_CMD_MGMT_FRAME_CTRL,
19354 strlen(PRIV_CMD_MGMT_FRAME_CTRL)) == 0) {
19355 /* Mgmt Frame Passthrough Ctrl */
19356 len = woal_priv_mgmt_frame_passthru_ctrl(
19357 priv, buf, priv_cmd.total_len);
19358 goto handled;
19359 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QCONFIG,
19360 strlen(PRIV_CMD_QCONFIG)) == 0) {
19361 /* Queue config */
19362 len = woal_priv_qconfig(priv, buf, priv_cmd.total_len);
19363 goto handled;
19364 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDTS,
19365 strlen(PRIV_CMD_ADDTS)) == 0) {
19366 /* Send an ADDTS TSPEC */
19367 len = woal_priv_wmm_addts_req_ioctl(priv, buf,
19368 priv_cmd.total_len);
19369 goto handled;
19370 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELTS,
19371 strlen(PRIV_CMD_DELTS)) == 0) {
19372 /* Send a DELTS TSPE */
19373 len = woal_priv_wmm_delts_req_ioctl(priv, buf,
19374 priv_cmd.total_len);
19375 goto handled;
19376 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QSTATUS,
19377 strlen(PRIV_CMD_QSTATUS)) == 0) {
19378 /* Get the status of the WMM queues */
19379 len = woal_priv_wmm_queue_status_ioctl(
19380 priv, buf, priv_cmd.total_len);
19381 goto handled;
19382 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TS_STATUS,
19383 strlen(PRIV_CMD_TS_STATUS)) == 0) {
19384 /* Get the status of the WMM Traffic Streams */
19385 len = woal_priv_wmm_ts_status_ioctl(priv, buf,
19386 priv_cmd.total_len);
19387 goto handled;
19388 #ifdef STA_SUPPORT
19389 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QOS_CFG,
19390 strlen(PRIV_CMD_QOS_CFG)) == 0) {
19391 t_u32 action = MLAN_ACT_GET;
19392 if (strlen(buf) ==
19393 strlen(CMD_NXP) + strlen(PRIV_CMD_QOS_CFG)) {
19394 pdata = buf; /* GET operation */
19395 } else {
19396 pdata = buf + strlen(CMD_NXP) +
19397 strlen(PRIV_CMD_QOS_CFG);
19398 action = MLAN_ACT_SET; /* SET operation */
19399 }
19400 if (MLAN_STATUS_SUCCESS !=
19401 woal_priv_qos_cfg(priv, action, pdata)) {
19402 ret = -EFAULT;
19403 goto done;
19404 }
19405 if (action == MLAN_ACT_GET)
19406 len = sizeof(t_u8);
19407 goto handled;
19408 #endif
19409 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MAC_CTRL,
19410 strlen(PRIV_CMD_MAC_CTRL)) == 0) {
19411 /* MAC CTRL */
19412 len = woal_priv_macctrl(priv, buf, priv_cmd.total_len);
19413 goto handled;
19414 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETWAP,
19415 strlen(PRIV_CMD_GETWAP)) == 0) {
19416 /* Get WAP */
19417 len = woal_priv_getwap(priv, buf, priv_cmd.total_len);
19418 goto handled;
19419 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGION_CODE,
19420 strlen(PRIV_CMD_REGION_CODE)) == 0) {
19421 /* Region Code */
19422 len = woal_priv_region_code(priv, buf,
19423 priv_cmd.total_len);
19424 goto handled;
19425 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FWMACADDR,
19426 strlen(PRIV_CMD_FWMACADDR)) == 0) {
19427 /* Set FW MAC address */
19428 len = woal_priv_fwmacaddr(priv, buf,
19429 priv_cmd.total_len);
19430 goto handled;
19431 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19432 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
19433 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OFFCHANNEL,
19434 strlen(PRIV_CMD_OFFCHANNEL)) == 0) {
19435 if (IS_STA_CFG80211(cfg80211_wext)) {
19436 /* Set offchannel */
19437 len = woal_priv_offchannel(priv, buf,
19438 priv_cmd.total_len);
19439 } else
19440 len = sprintf(buf,
19441 "CFG80211 is not enabled\n") +
19442 1;
19443 goto handled;
19444 #endif
19445 #endif
19446
19447 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DSCP_MAP,
19448 strlen(PRIV_CMD_DSCP_MAP)) == 0) {
19449 /* Set/Get DSCP Map */
19450 len = woal_priv_set_get_dscp_map(priv, buf,
19451 priv_cmd.total_len);
19452 goto handled;
19453 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VEREXT,
19454 strlen(PRIV_CMD_VEREXT)) == 0) {
19455 /* Get Extended version */
19456 len = woal_priv_get_driver_verext(priv, buf,
19457 priv_cmd.total_len);
19458 goto handled;
19459 #ifdef USB
19460 #ifdef CONFIG_USB_SUSPEND
19461 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_SUSPEND,
19462 strlen(PRIV_CMD_USB_SUSPEND)) == 0) {
19463 /* Makes USB device to suspend */
19464 len = woal_priv_enter_usb_suspend(priv, buf,
19465 priv_cmd.total_len);
19466 goto handled;
19467 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_RESUME,
19468 strlen(PRIV_CMD_USB_RESUME)) == 0) {
19469 /* Makes USB device to resume */
19470 len = woal_priv_exit_usb_suspend(priv, buf,
19471 priv_cmd.total_len);
19472 goto handled;
19473 #endif /* CONFIG_USB_SUSPEND */
19474 #endif
19475 #if defined(STA_SUPPORT) && defined(STA_WEXT)
19476 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RADIO_CTRL,
19477 strlen(PRIV_CMD_RADIO_CTRL)) == 0) {
19478 /* Set/Get radio */
19479 len = woal_priv_radio_ctrl(priv, buf,
19480 priv_cmd.total_len);
19481 goto handled;
19482 #endif
19483 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WMM_CFG,
19484 strlen(PRIV_CMD_WMM_CFG)) == 0) {
19485 /* Implement WMM enable command */
19486 len = woal_priv_wmm_cfg(priv, buf, priv_cmd.total_len);
19487 goto handled;
19488 } else if (strnicmp(buf + strlen(CMD_NXP),
19489 PRIV_CMD_MIN_BA_THRESH_CFG,
19490 strlen(PRIV_CMD_MIN_BA_THRESH_CFG)) == 0) {
19491 /* Implement Minimum BA threshold configuration command
19492 */
19493 len = woal_priv_min_ba_threshold_cfg(
19494 priv, buf, priv_cmd.total_len);
19495 goto handled;
19496 #if defined(STA_SUPPORT)
19497 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CFG,
19498 strlen(PRIV_CMD_11D_CFG)) == 0) {
19499 /* Implement 802.11D enable command */
19500 len = woal_priv_11d_cfg(priv, buf, priv_cmd.total_len);
19501 goto handled;
19502 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CLR_TBL,
19503 strlen(PRIV_CMD_11D_CLR_TBL)) == 0) {
19504 /* Implement 802.11D clear chan table command */
19505 len = woal_priv_11d_clr_chan_tbl(priv, buf,
19506 priv_cmd.total_len);
19507 goto handled;
19508 #endif
19509 #ifndef OPCHAN
19510 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WWS_CFG,
19511 strlen(PRIV_CMD_WWS_CFG)) == 0) {
19512 /* Set/Get WWS configuration */
19513 len = woal_priv_wws_cfg(priv, buf, priv_cmd.total_len);
19514 goto handled;
19515 #endif
19516 #if defined(REASSOCIATION)
19517 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REASSOCTRL,
19518 strlen(PRIV_CMD_REASSOCTRL)) == 0) {
19519 /* Set/Get reassociation settings */
19520 len = woal_priv_set_get_reassoc(priv, buf,
19521 priv_cmd.total_len);
19522 goto handled;
19523 #endif
19524 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXBUF_CFG,
19525 strlen(PRIV_CMD_TXBUF_CFG)) == 0) {
19526 /* Get Transmit buffer size */
19527 len = woal_priv_txbuf_cfg(priv, buf,
19528 priv_cmd.total_len);
19529 goto handled;
19530 #ifdef STA_SUPPORT
19531 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTH_TYPE,
19532 strlen(PRIV_CMD_AUTH_TYPE)) == 0) {
19533 /* Set/Get auth type */
19534 len = woal_priv_auth_type(priv, buf,
19535 priv_cmd.total_len);
19536 goto handled;
19537 #endif
19538 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_POWER_CONS,
19539 strlen(PRIV_CMD_POWER_CONS)) == 0) {
19540 /* Set/get user provisioned local power constraint */
19541 len = woal_priv_11h_local_pwr_constraint(
19542 priv, buf, priv_cmd.total_len);
19543 goto handled;
19544 } else if (strnicmp(buf + strlen(CMD_NXP),
19545 PRIV_CMD_HT_STREAM_CFG,
19546 strlen(PRIV_CMD_HT_STREAM_CFG)) == 0) {
19547 /* Set/get HT stream configurations */
19548 len = woal_priv_ht_stream_cfg(priv, buf,
19549 priv_cmd.total_len);
19550 goto handled;
19551 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MIMO_SWITCH,
19552 strlen(PRIV_CMD_MIMO_SWITCH)) == 0) {
19553 /* Set mimo switch configurations */
19554 len = woal_priv_mimo_switch(priv, buf,
19555 priv_cmd.total_len);
19556 goto handled;
19557 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_THERMAL,
19558 strlen(PRIV_CMD_THERMAL)) == 0) {
19559 /* Get thermal reading */
19560 len = woal_priv_thermal(priv, buf, priv_cmd.total_len);
19561 goto handled;
19562 } else if (strnicmp(buf + strlen(CMD_NXP),
19563 PRIV_CMD_BCN_INTERVAL,
19564 strlen(PRIV_CMD_BCN_INTERVAL)) == 0) {
19565 /* Set/Get beacon interval */
19566 len = woal_priv_beacon_interval(priv, buf,
19567 priv_cmd.total_len);
19568 goto handled;
19569 #ifdef STA_SUPPORT
19570 } else if (strnicmp(buf + strlen(CMD_NXP),
19571 PRIV_CMD_SIGNALEXT_CFG,
19572 strlen(PRIV_CMD_SIGNALEXT_CFG)) == 0) {
19573 /* Set signalext flag */
19574 len = woal_priv_signalext_cfg(priv, buf,
19575 priv_cmd.total_len);
19576 goto handled;
19577 } else if (strnicmp(buf + strlen(CMD_NXP),
19578 PRIV_CMD_GET_SIGNAL_EXT_V2,
19579 strlen(PRIV_CMD_GET_SIGNAL_EXT_V2)) == 0) {
19580 /* Get signal info */
19581 len = woal_priv_get_signal_ext_v2(priv, buf,
19582 priv_cmd.total_len);
19583 goto handled;
19584 } else if (strnicmp(buf + strlen(CMD_NXP),
19585 PRIV_CMD_GET_SIGNAL_EXT,
19586 strlen(PRIV_CMD_GET_SIGNAL_EXT)) == 0) {
19587 /* Get signal info */
19588 len = woal_priv_get_signal_ext(priv, buf,
19589 priv_cmd.total_len);
19590 goto handled;
19591 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SIGNAL,
19592 strlen(PRIV_CMD_GET_SIGNAL)) == 0) {
19593 /* Get signal */
19594 len = woal_priv_get_signal(priv, buf,
19595 priv_cmd.total_len);
19596 goto handled;
19597 #endif
19598 #if defined(STA_SUPPORT)
19599 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PMFCFG,
19600 strlen(PRIV_CMD_PMFCFG)) == 0) {
19601 /* Configure PMF */
19602 len = woal_priv_set_get_pmfcfg(priv, buf,
19603 priv_cmd.total_len);
19604 goto handled;
19605 #endif
19606 } else if (strnicmp(buf + strlen(CMD_NXP),
19607 PRIV_CMD_INACTIVITYTO,
19608 strlen(PRIV_CMD_INACTIVITYTO)) == 0) {
19609 /* Get/Set inactivity timeout extend */
19610 len = woal_priv_inactivity_timeout_ext(
19611 priv, buf, priv_cmd.total_len);
19612 goto handled;
19613 } else if (strnicmp(buf + strlen(CMD_NXP),
19614 PRIV_CMD_AMSDU_AGGR_CTRL,
19615 strlen(PRIV_CMD_AMSDU_AGGR_CTRL)) == 0) {
19616 /* Enable/Disable amsdu_aggr_ctrl */
19617 len = woal_priv_11n_amsdu_aggr_ctrl(priv, buf,
19618 priv_cmd.total_len);
19619 goto handled;
19620 } else if (strnicmp(buf + strlen(CMD_NXP),
19621 PRIV_CMD_MCAST_AGGR_GROUP,
19622 strlen(PRIV_CMD_MCAST_AGGR_GROUP)) == 0) {
19623 /* mcast_aggr_group cfg*/
19624 len = woal_priv_mcast_aggr_group_cfg(
19625 priv, buf, priv_cmd.total_len);
19626 goto handled;
19627 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MC_AGGR_CFG,
19628 strlen(PRIV_CMD_MC_AGGR_CFG)) == 0) {
19629 /* mc_aggr_cfg*/
19630 len = woal_priv_mc_aggr_cfg(priv, buf,
19631 priv_cmd.total_len);
19632 goto handled;
19633 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_STATS,
19634 strlen(PRIV_CMD_STATS)) == 0) {
19635 /* stats */
19636 len = woal_priv_stats(priv, buf, priv_cmd.total_len);
19637 goto handled;
19638 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CH_LOAD,
19639 strlen(PRIV_CMD_CH_LOAD)) == 0) {
19640 /* mc_aggr_cfg*/
19641 len = woal_priv_get_ch_load(priv, buf,
19642 priv_cmd.total_len);
19643 goto handled;
19644 } else if (strnicmp(buf + strlen(CMD_NXP),
19645 PRIV_CMD_CH_LOAD_RESULTS,
19646 strlen(PRIV_CMD_CH_LOAD_RESULTS)) == 0) {
19647 /* mc_aggr_cfg*/
19648 len = woal_priv_get_ch_load_results(priv, buf,
19649 priv_cmd.total_len);
19650 goto handled;
19651 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CAP,
19652 strlen(PRIV_CMD_TX_BF_CAP)) == 0) {
19653 /* Set/Get Transmit beamforming capabilities */
19654 len = woal_priv_tx_bf_cap_ioctl(priv, buf,
19655 priv_cmd.total_len);
19656 goto handled;
19657 } else if (strnicmp(buf + strlen(CMD_NXP),
19658 PRIV_CMD_SLEEP_PARAMS,
19659 strlen(PRIV_CMD_SLEEP_PARAMS)) == 0) {
19660 /* Configure sleep parameters */
19661 len = woal_priv_sleep_params_ioctl(priv, buf,
19662 priv_cmd.total_len);
19663 goto handled;
19664 #ifdef UAP_SUPPORT
19665 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NET_MON,
19666 strlen(PRIV_CMD_NET_MON)) == 0) {
19667 /* Set/Get network monitor configurations */
19668 len = woal_priv_net_monitor_ioctl(priv, buf,
19669 priv_cmd.total_len);
19670 goto handled;
19671 #endif
19672 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
19673 } else if (strnicmp(buf + strlen(CMD_NXP),
19674 PRIV_CMD_MONITOR_MODE,
19675 strlen(PRIV_CMD_MONITOR_MODE)) == 0) {
19676 if (IS_STA_CFG80211(cfg80211_wext)) {
19677 /* Set/Get monitor mode */
19678 len = woal_priv_set_get_monitor_mode(
19679 priv, buf, priv_cmd.total_len);
19680 } else
19681 len = sprintf(buf,
19682 "CFG80211 is not enabled\n") +
19683 1;
19684 goto handled;
19685 #endif
19686 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_TESTING,
19687 strlen(PRIV_CMD_DFS_TESTING)) == 0) {
19688 /* Set/Get DFS Testing settings */
19689 len = woal_priv_dfs_testing(priv, buf,
19690 priv_cmd.total_len);
19691 goto handled;
19692 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CLEAR_NOP,
19693 strlen(PRIV_CMD_CLEAR_NOP)) == 0) {
19694 /* Set/Get DFS Testing settings */
19695 len = woal_priv_clear_nop(priv, buf,
19696 priv_cmd.total_len);
19697 goto handled;
19698 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_NOP_LIST,
19699 strlen(PRIV_CMD_NOP_LIST)) == 0) {
19700 /* Set/Get DFS Testing settings */
19701 len = woal_priv_nop_list(priv, buf, priv_cmd.total_len);
19702 goto handled;
19703 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FAKE_RADAR,
19704 strlen(PRIV_CMD_FAKE_RADAR)) == 0) {
19705 /* mcast_aggr_group cfg*/
19706 len = woal_priv_fake_radar(priv, buf,
19707 priv_cmd.total_len);
19708 goto handled;
19709 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS53_CFG,
19710 strlen(PRIV_CMD_DFS53_CFG)) == 0) {
19711 /* Set/Get DFS W53 settings */
19712 len = woal_priv_dfs53cfg(priv, buf, priv_cmd.total_len);
19713 goto handled;
19714 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_MODE,
19715 strlen(PRIV_CMD_DFS_MODE)) == 0) {
19716 /* Set/Get DFS mode settings */
19717 len = woal_priv_dfs_mode(priv, buf, priv_cmd.total_len);
19718 goto handled;
19719 #ifdef UAP_SUPPORT
19720 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_CAC,
19721 strlen(PRIV_CMD_DFS_CAC)) == 0) {
19722 /* perform CAC */
19723 len = woal_priv_do_dfs_cac(priv, buf,
19724 priv_cmd.total_len);
19725 goto handled;
19726 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTODFS,
19727 strlen(PRIV_CMD_AUTODFS)) == 0) {
19728 len = woal_priv_auto_dfs_cfg(priv, buf,
19729 priv_cmd.total_len);
19730 goto handled;
19731 #endif
19732 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARB_CFG,
19733 strlen(PRIV_CMD_ARB_CFG)) == 0) {
19734 /* Set/Get CFP table codes */
19735 len = woal_priv_arbcfg(priv, buf, priv_cmd.total_len);
19736 goto handled;
19737 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFP_CODE,
19738 strlen(PRIV_CMD_CFP_CODE)) == 0) {
19739 /* Set/Get CFP table codes */
19740 len = woal_priv_cfp_code(priv, buf, priv_cmd.total_len);
19741 goto handled;
19742 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CWMODE,
19743 strlen(PRIV_CMD_CWMODE)) == 0) {
19744 /* Set/Get Tx CWMode */
19745 len = woal_priv_set_get_cwmode(priv, buf,
19746 priv_cmd.total_len);
19747 goto handled;
19748 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ANT_CFG,
19749 strlen(PRIV_CMD_ANT_CFG)) == 0) {
19750 /* Set/Get Tx/Rx antenna */
19751 len = woal_priv_set_get_tx_rx_ant(priv, buf,
19752 priv_cmd.total_len);
19753 goto handled;
19754 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SYSCLOCK,
19755 strlen(PRIV_CMD_SYSCLOCK)) == 0) {
19756 /* Get/Set system clock */
19757 len = woal_priv_sysclock(priv, buf, priv_cmd.total_len);
19758 goto handled;
19759 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_KEY,
19760 strlen(PRIV_CMD_GET_KEY)) == 0) {
19761 /* Get GTK/PTK */
19762 len = woal_priv_get_key(priv, buf, priv_cmd.total_len);
19763 goto handled;
19764 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCIATE,
19765 strlen(PRIV_CMD_ASSOCIATE)) == 0) {
19766 /* Associate to a specific indexed entry in the
19767 * ScanTable */
19768 len = woal_priv_associate_ssid_bssid(
19769 priv, buf, priv_cmd.total_len);
19770 goto handled;
19771 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CFG,
19772 strlen(PRIV_CMD_TX_BF_CFG)) == 0) {
19773 /* Set/Get Transmit beamforming configuration */
19774 len = woal_priv_tx_bf_cfg(priv, buf,
19775 priv_cmd.total_len);
19776 goto handled;
19777 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BOOTSLEEP,
19778 strlen(PRIV_CMD_BOOTSLEEP)) == 0) {
19779 len = woal_priv_bootsleep(priv, buf,
19780 priv_cmd.total_len);
19781 goto handled;
19782 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PORT_CTRL,
19783 strlen(PRIV_CMD_PORT_CTRL)) == 0) {
19784 /* Set/Get Port Control mode */
19785 len = woal_priv_port_ctrl(priv, buf,
19786 priv_cmd.total_len);
19787 goto handled;
19788 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXWATCHDOG,
19789 strlen(PRIV_CMD_TXWATCHDOG)) == 0) {
19790 len = woal_priv_txwatchdog(priv, buf,
19791 priv_cmd.total_len);
19792 goto handled;
19793 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PB_BYPASS,
19794 strlen(PRIV_CMD_PB_BYPASS)) == 0) {
19795 /* Private IOCTL entry to get the By-passed TX packet
19796 * from upper layer */
19797 len = woal_priv_bypassed_packet(priv, buf,
19798 priv_cmd.total_len);
19799 goto handled;
19800 #ifdef WIFI_DIRECT_SUPPORT
19801 #if defined(UAP_CFG80211)
19802 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA,
19803 strlen(PRIV_CMD_CFG_NOA)) == 0) {
19804 /* Set/Get P2P NoA (Notice of Absence) parameters */
19805 len = woal_priv_cfg_noa(priv, buf, priv_cmd.total_len);
19806 goto handled;
19807 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_OPP_PS,
19808 strlen(PRIV_CMD_CFG_OPP_PS)) == 0) {
19809 /* Set/Get P2P OPP-PS parameters */
19810 len = woal_priv_cfg_opp_ps(priv, buf,
19811 priv_cmd.total_len);
19812 goto handled;
19813 #endif
19814 #endif
19815 } else if (strnicmp(buf + strlen(CMD_NXP),
19816 PRIV_CMD_CFG_CLOCK_SYNC,
19817 strlen(PRIV_CMD_CFG_CLOCK_SYNC)) == 0) {
19818 /* Set/Get P2P NoA (Notice of Absence) parameters */
19819 len = woal_priv_cfg_clock_sync(priv, buf,
19820 priv_cmd.total_len);
19821 goto handled;
19822 } else if (strnicmp(buf + strlen(CMD_NXP),
19823 PRIV_CMD_CFG_GET_TSF_INFO,
19824 strlen(PRIV_CMD_CFG_GET_TSF_INFO)) == 0) {
19825 /* Get TSF info */
19826 len = woal_priv_cfg_get_tsf_info(priv, buf,
19827 priv_cmd.total_len);
19828 goto handled;
19829 #ifdef UAP_SUPPORT
19830 } else if (strnicmp(buf + strlen(CMD_NXP),
19831 PRIV_CMD_TARGET_CHANNEL,
19832 strlen(PRIV_CMD_TARGET_CHANNEL)) == 0) {
19833 /* Get/Set Target channel*/
19834 len = woal_priv_target_channel(priv, buf,
19835 priv_cmd.total_len);
19836 goto handled;
19837 } else if (strnicmp(buf + strlen(CMD_NXP),
19838 PRIV_CMD_BACKUP_CHANNEL,
19839 strlen(PRIV_CMD_BACKUP_CHANNEL)) == 0) {
19840 /* Get/Set Backup channel*/
19841 len = woal_priv_backup_channel(priv, buf,
19842 priv_cmd.total_len);
19843 goto handled;
19844 #endif
19845 } else if (strnicmp(buf + strlen(CMD_NXP),
19846 PRIV_CMD_DFS_REPEATER_CFG,
19847 strlen(PRIV_CMD_DFS_REPEATER_CFG)) == 0) {
19848 /* Set/Get DFS_REPEATER mode */
19849 len = woal_priv_dfs_repeater_cfg(priv, buf,
19850 priv_cmd.total_len);
19851 goto handled;
19852 #ifdef WIFI_DIRECT_SUPPORT
19853 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19854 } else if (strnicmp(buf + strlen(CMD_NXP),
19855 PRIV_CMD_MIRACAST_CFG,
19856 strlen(PRIV_CMD_MIRACAST_CFG)) == 0) {
19857 /* Set/Get MIRACAST configuration parameters */
19858 len = woal_priv_miracast_cfg(priv, buf,
19859 priv_cmd.total_len);
19860 goto handled;
19861 #endif
19862 #endif
19863 } else if (strnicmp(buf + strlen(CMD_NXP),
19864 PRIV_CMD_COEX_RX_WINSIZE,
19865 strlen(PRIV_CMD_COEX_RX_WINSIZE)) == 0) {
19866 /* Set/Get control to coex RX window size */
19867 len = woal_priv_coex_rx_winsize(priv, buf,
19868 priv_cmd.total_len);
19869 goto handled;
19870 } else if (strnicmp(buf + strlen(CMD_NXP),
19871 PRIV_CMD_TX_AGGR_CTRL,
19872 strlen(PRIV_CMD_TX_AGGR_CTRL)) == 0) {
19873 /* Set/Get control to TX AMPDU on infra link */
19874 len = woal_priv_txaggrctrl(priv, buf,
19875 priv_cmd.total_len);
19876 goto handled;
19877 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_TDLS,
19878 strlen(PRIV_CMD_AUTO_TDLS)) == 0) {
19879 /* Set/Get control to enable/disable auto TDLS */
19880 len = woal_priv_auto_tdls(priv, buf,
19881 priv_cmd.total_len);
19882 goto handled;
19883 #ifdef PCIE
19884 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PCIE_REG_RW,
19885 strlen(PRIV_CMD_PCIE_REG_RW)) == 0) {
19886 /* Read/Write PCIE register */
19887 len = woal_priv_pcie_reg_rw(priv, buf,
19888 priv_cmd.total_len);
19889 goto handled;
19890 } else if (strnicmp(buf + strlen(CMD_NXP),
19891 PRIV_CMD_PCIE_BAR0_REG_RW,
19892 strlen(PRIV_CMD_PCIE_BAR0_REG_RW)) == 0) {
19893 /* Read/Write PCIE register/memory from BAR0 */
19894 len = woal_priv_pcie_bar0_reg_rw(priv, buf,
19895 priv_cmd.total_len);
19896 goto handled;
19897 #endif
19898 } else if (strnicmp(buf + strlen(CMD_NXP),
19899 PRIV_CMD_TDLS_IDLE_TIME,
19900 strlen(PRIV_CMD_TDLS_IDLE_TIME)) == 0) {
19901 /* Set/Get TDLS idle timeout value */
19902 len = woal_priv_tdls_idle_time(priv, buf,
19903 priv_cmd.total_len);
19904 goto handled;
19905 } else if (strnicmp(buf + strlen(CMD_NXP),
19906 PRIV_CMD_GET_SENSOR_TEMP,
19907 strlen(PRIV_CMD_GET_SENSOR_TEMP)) == 0) {
19908 /* Get SOC temperature */
19909 len = woal_priv_get_sensor_temp(priv, buf,
19910 priv_cmd.total_len);
19911 goto handled;
19912 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
19913 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19914 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_OFFLOAD,
19915 strlen(PRIV_CMD_DFS_OFFLOAD)) == 0) {
19916 /* Enable/disable DFS offload */
19917 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
19918 len = woal_priv_dfs_offload_enable(
19919 priv, buf, priv_cmd.total_len);
19920 else
19921 len = sprintf(buf,
19922 "CFG80211 is not enabled\n") +
19923 1;
19924 goto handled;
19925 #endif
19926 #endif
19927 #if defined(UAP_SUPPORT)
19928 } else if (strnicmp(buf + strlen(CMD_NXP),
19929 PRIV_CMD_EXTEND_CHAN_SWITCH,
19930 strlen(PRIV_CMD_EXTEND_CHAN_SWITCH)) == 0) {
19931 /* Extended channel switch */
19932 len = woal_priv_extend_channel_switch(
19933 priv, buf, priv_cmd.total_len);
19934 goto handled;
19935 #endif
19936 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DYN_BW,
19937 strlen(PRIV_CMD_DYN_BW)) == 0) {
19938 /* Set/Get dynamic bandwidth */
19939 len = woal_priv_config_dyn_bw(priv, buf,
19940 priv_cmd.total_len);
19941 goto handled;
19942 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IND_RST_CFG,
19943 strlen(PRIV_CMD_IND_RST_CFG)) == 0) {
19944 /* Set/Get out band independent reset */
19945 len = woal_priv_ind_rst_cfg(priv, buf,
19946 priv_cmd.total_len);
19947 goto handled;
19948 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PER_PKT_CFG,
19949 strlen(PRIV_CMD_PER_PKT_CFG)) == 0) {
19950 /* Get/Set per packet Txctl and Rxinfo configuration */
19951 len = woal_priv_per_pkt_cfg(priv, buf,
19952 priv_cmd.total_len);
19953 goto handled;
19954 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH_CTRL,
19955 strlen(PRIV_CMD_DEAUTH_CTRL)) == 0) {
19956 len = woal_priv_deauth_ctrl(priv, buf,
19957 priv_cmd.total_len);
19958 goto handled;
19959 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCFG,
19960 strlen(PRIV_CMD_11AXCFG)) == 0) {
19961 pdata = buf + strlen(CMD_NXP) +
19962 strlen(PRIV_CMD_11AXCFG);
19963 len = priv_cmd.used_len - strlen(PRIV_CMD_11AXCFG) -
19964 strlen(CMD_NXP);
19965 len = woal_priv_11axcfg_cmd(priv, pdata, len,
19966 priv_cmd.total_len);
19967 len += strlen(PRIV_CMD_11AXCFG) + strlen(CMD_NXP);
19968 goto handled;
19969 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_SETUP,
19970 strlen(PRIV_CMD_TWT_SETUP)) == 0) {
19971 pdata = buf + strlen(CMD_NXP) +
19972 strlen(PRIV_CMD_TWT_SETUP);
19973 len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_SETUP) -
19974 strlen(CMD_NXP);
19975 len = woal_priv_twt_setup(priv, pdata, len,
19976 priv_cmd.total_len);
19977 len += strlen(PRIV_CMD_TWT_SETUP) + strlen(CMD_NXP);
19978 goto handled;
19979
19980 } else if (strnicmp(buf + strlen(CMD_NXP),
19981 PRIV_CMD_TWT_TEARDOWN,
19982 strlen(PRIV_CMD_TWT_TEARDOWN)) == 0) {
19983 pdata = buf + strlen(CMD_NXP) +
19984 strlen(PRIV_CMD_TWT_TEARDOWN);
19985 len = priv_cmd.used_len -
19986 strlen(PRIV_CMD_TWT_TEARDOWN) - strlen(CMD_NXP);
19987 len = woal_priv_twt_teardown(priv, pdata, len,
19988 priv_cmd.total_len);
19989 len += strlen(PRIV_CMD_TWT_TEARDOWN) + strlen(CMD_NXP);
19990 goto handled;
19991 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
19992 } else if (strnicmp(buf + strlen(CMD_NXP),
19993 PRIV_CMD_GET_CFG_CHAN_LIST,
19994 strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) {
19995 /* Get txpwrlimit */
19996 if (IS_STA_OR_UAP_CFG80211(cfg80211_wext))
19997 len = woal_priv_getcfgchanlist(
19998 priv, buf, priv_cmd.total_len);
19999 else
20000 len = sprintf(buf,
20001 "CFG80211 is not enabled\n") +
20002 1;
20003 goto handled;
20004 #endif
20005 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_LPM,
20006 strlen(PRIV_CMD_LPM)) == 0) {
20007 /* Set/Get low power mode */
20008 len = woal_priv_set_get_lpm(priv, buf,
20009 priv_cmd.total_len);
20010 goto handled;
20011 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TP_STATE,
20012 strlen(PRIV_CMD_TP_STATE)) == 0) {
20013 /* Set/Get TP accounting state */
20014 len = woal_priv_set_tp_state(priv, buf,
20015 priv_cmd.total_len);
20016 goto handled;
20017 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPS_CFG,
20018 strlen(PRIV_CMD_IPS_CFG)) == 0) {
20019 len = woal_priv_ips_cfg(priv, buf, priv_cmd.total_len);
20020 goto handled;
20021 } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SB_UUID,
20022 strlen(PRIV_CMD_GET_SB_UUID)) == 0) {
20023 len = woal_priv_get_uuid(priv, buf, priv_cmd.total_len);
20024 goto handled;
20025 } else {
20026 PRINTM(MERROR,
20027 "Unknown NXP PRIVATE command %s, ignored\n",
20028 buf);
20029 ret = -EFAULT;
20030 goto done;
20031 }
20032 }
20033 #ifdef STA_SUPPORT
20034 if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) ==
20035 0) {
20036 pdata = buf + strlen("RSSILOW-THRESHOLD") + 1;
20037 if (MLAN_STATUS_SUCCESS !=
20038 woal_set_rssi_low_threshold(priv, pdata, MOAL_IOCTL_WAIT)) {
20039 ret = -EFAULT;
20040 goto done;
20041 }
20042 len = sprintf(buf, "OK\n") + 1;
20043 } else if (strncmp(buf, "SCAN-CFG", strlen("SCAN-CFG")) == 0) {
20044 PRINTM(MIOCTL, "Set SCAN CFG\n");
20045 if (MLAN_STATUS_SUCCESS !=
20046 woal_set_scan_cfg(priv, buf, priv_cmd.total_len)) {
20047 ret = -EFAULT;
20048 goto done;
20049 }
20050 len = sprintf(buf, "OK\n") + 1;
20051 } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) {
20052 if (MLAN_STATUS_SUCCESS !=
20053 woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
20054 ret = -EFAULT;
20055 goto done;
20056 }
20057 if (bss_info.media_connected) {
20058 if (MLAN_STATUS_SUCCESS !=
20059 woal_get_signal_info(priv, MOAL_IOCTL_WAIT,
20060 &signal)) {
20061 ret = -EFAULT;
20062 goto done;
20063 }
20064 len = sprintf(buf, "%.32s rssi %d\n",
20065 bss_info.ssid.ssid, signal.bcn_rssi_avg) +
20066 1;
20067 } else {
20068 len = sprintf(buf, "OK\n") + 1;
20069 }
20070 } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) {
20071 if (MLAN_STATUS_SUCCESS !=
20072 woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) {
20073 ret = -EFAULT;
20074 goto done;
20075 }
20076 PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate);
20077 len = sprintf(buf, "LinkSpeed %d\n",
20078 (int)(rate.rate * 500000 / 1000000)) +
20079 1;
20080 } else
20081 #endif
20082 if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) {
20083 len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
20084 priv->current_addr[0], priv->current_addr[1],
20085 priv->current_addr[2], priv->current_addr[3],
20086 priv->current_addr[4], priv->current_addr[5]) +
20087 1;
20088 }
20089 #ifdef STA_SUPPORT
20090 else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) {
20091 if (MLAN_STATUS_SUCCESS !=
20092 woal_get_powermode(priv, &power_mode)) {
20093 ret = -EFAULT;
20094 goto done;
20095 }
20096 len = sprintf(buf, "powermode = %d\n", power_mode) + 1;
20097 } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
20098 if (MLAN_STATUS_SUCCESS !=
20099 woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) {
20100 ret = -EFAULT;
20101 goto done;
20102 }
20103 priv->scan_type = MLAN_SCAN_TYPE_ACTIVE;
20104 PRINTM(MIOCTL, "Set Active Scan\n");
20105 len = sprintf(buf, "OK\n") + 1;
20106 } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) {
20107 if (MLAN_STATUS_SUCCESS !=
20108 woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) {
20109 ret = -EFAULT;
20110 goto done;
20111 }
20112 priv->scan_type = MLAN_SCAN_TYPE_PASSIVE;
20113 PRINTM(MIOCTL, "Set Passive Scan\n");
20114 len = sprintf(buf, "OK\n") + 1;
20115 } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) {
20116 pdata = buf + strlen("POWERMODE") + 1;
20117 if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) {
20118 if (MLAN_STATUS_SUCCESS !=
20119 woal_set_powermode(priv, pdata)) {
20120 ret = -EFAULT;
20121 goto done;
20122 }
20123 }
20124 len = sprintf(buf, "OK\n") + 1;
20125 } else if (strncmp(buf, "SETROAMING", strlen("SETROAMING")) == 0) {
20126 pdata = buf + strlen("SETROAMING") + 1;
20127 #ifdef STA_CFG80211
20128 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
20129 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
20130 goto done;
20131 #endif
20132 #endif
20133 #ifdef STA_CFG80211
20134 if (*pdata == '1') {
20135 priv->roaming_enabled = MTRUE;
20136 PRINTM(MIOCTL, "Roaming enabled\n");
20137 } else if (*pdata == '0') {
20138 priv->roaming_enabled = MFALSE;
20139 PRINTM(MIOCTL, "Roaming disabled\n");
20140 }
20141 #endif
20142 len = sprintf(buf, "OK\n") + 1;
20143 } else if (strncmp(buf, "ROAM", strlen("ROAM")) == 0) {
20144 pdata = buf + strlen("ROAM") + 1;
20145 #ifdef STA_CFG80211
20146 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
20147 if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
20148 goto done;
20149 #endif
20150 #endif
20151 #ifdef STA_CFG80211
20152 if (*pdata == '1') {
20153 priv->roaming_enabled = MTRUE;
20154 PRINTM(MIOCTL, "Roaming enabled\n");
20155 } else if (*pdata == '0') {
20156 priv->roaming_enabled = MFALSE;
20157 PRINTM(MIOCTL, "Roaming disabled\n");
20158 }
20159 #endif
20160 len = sprintf(buf, "OK\n") + 1;
20161 } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) {
20162 copy_len = strlen(buf) - strlen("COUNTRY") - 1;
20163 if (copy_len > COUNTRY_CODE_LEN || copy_len <= 0) {
20164 PRINTM(MERROR, "Invalid country length\n");
20165 ret = -EFAULT;
20166 goto done;
20167 }
20168 memset(country_code, 0, sizeof(country_code));
20169 moal_memcpy_ext(priv->phandle, country_code,
20170 buf + strlen("COUNTRY") + 1, copy_len,
20171 COUNTRY_CODE_LEN);
20172 PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code);
20173 if (priv->phandle->params.cntry_txpwr) {
20174 if (MLAN_STATUS_SUCCESS !=
20175 woal_request_country_power_table(priv,
20176 country_code)) {
20177 ret = -EFAULT;
20178 goto done;
20179 }
20180 }
20181 #ifdef STA_CFG80211
20182 if (IS_STA_CFG80211(cfg80211_wext)) {
20183 PRINTM(MIOCTL, "Notify country code=%s\n",
20184 country_code);
20185 if (!moal_extflg_isset(priv->phandle,
20186 EXT_DISABLE_REGD_BY_DRIVER))
20187 regulatory_hint(priv->wdev->wiphy,
20188 country_code);
20189 len = sprintf(buf, "OK\n") + 1;
20190 goto done;
20191 }
20192 #endif
20193 if (MLAN_STATUS_SUCCESS !=
20194 woal_set_region_code(priv, country_code)) {
20195 ret = -EFAULT;
20196 goto done;
20197 }
20198 len = sprintf(buf, "OK\n") + 1;
20199 } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) ==
20200 0) {
20201 PRINTM(MIOCTL, "Set Combo Scan\n");
20202 if (MLAN_STATUS_SUCCESS !=
20203 woal_set_combo_scan(priv, buf, priv_cmd.total_len)) {
20204 ret = -EFAULT;
20205 goto done;
20206 }
20207 len = sprintf(buf, "OK\n") + 1;
20208 } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) {
20209 if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) {
20210 ret = -EFAULT;
20211 goto done;
20212 }
20213 len = sprintf(buf, "Band %d\n", band) + 1;
20214 } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) {
20215 pband = buf + strlen("SETBAND") + 1;
20216 if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) {
20217 ret = -EFAULT;
20218 goto done;
20219 }
20220 len = sprintf(buf, "OK\n") + 1;
20221 }
20222 #endif
20223 else if (strncmp(buf, "START", strlen("START")) == 0) {
20224 len = sprintf(buf, "OK\n") + 1;
20225 } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) {
20226 len = sprintf(buf, "OK\n") + 1;
20227 }
20228 #ifdef UAP_SUPPORT
20229 else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
20230 ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
20231 if (ret)
20232 goto done;
20233 len = sprintf(buf, "OK\n") + 1;
20234 } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
20235 ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
20236 if (ret)
20237 goto done;
20238 len = sprintf(buf, "OK\n") + 1;
20239 } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) {
20240 if (priv_cmd.total_len <= (int)strlen("AP_SET_CFG") + 1)
20241 goto done;
20242 pdata = buf + strlen("AP_SET_CFG") + 1;
20243 ret = woal_uap_set_ap_cfg(priv, pdata,
20244 priv_cmd.total_len -
20245 strlen("AP_SET_CFG") - 1);
20246 if (ret)
20247 goto done;
20248 len = sprintf(buf, "OK\n") + 1;
20249 } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) {
20250 len = sprintf(buf, "OK\n") + 1;
20251 } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) ==
20252 0) {
20253 /* TODO Add STA list support */
20254 len = sprintf(buf, "OK\n") + 1;
20255 }
20256 #endif
20257 else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) {
20258 /* it will be done by GUI */
20259 len = sprintf(buf, "OK\n") + 1;
20260 } else if (strncmp(buf, "SETSUSPENDMODE", strlen("SETSUSPENDMODE")) ==
20261 0) {
20262 /* it will be done by GUI */
20263 len = sprintf(buf, "OK\n") + 1;
20264 } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
20265 len = sprintf(buf, "OK\n") + 1;
20266 } else if (strncmp(buf, "BTCOEXSCAN-START",
20267 strlen("BTCOEXSCAN-START")) == 0) {
20268 len = sprintf(buf, "OK\n") + 1;
20269 } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) ==
20270 0) {
20271 len = sprintf(buf, "OK\n") + 1;
20272 }
20273 #ifdef STA_SUPPORT
20274 else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) {
20275 len = sprintf(buf, "OK\n") + 1;
20276 } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) ==
20277 0) {
20278 if (MLAN_STATUS_SUCCESS !=
20279 woal_set_bg_scan(priv, buf, priv_cmd.total_len)) {
20280 ret = -EFAULT;
20281 goto done;
20282 }
20283 priv->bg_scan_start = MTRUE;
20284 priv->bg_scan_reported = MFALSE;
20285 len = sprintf(buf, "OK\n") + 1;
20286 } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) {
20287 if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) {
20288 if (MLAN_STATUS_FAILURE ==
20289 woal_stop_bg_scan(priv, MOAL_NO_WAIT)) {
20290 ret = -EFAULT;
20291 goto done;
20292 }
20293 priv->bg_scan_start = MFALSE;
20294 priv->bg_scan_reported = MFALSE;
20295 }
20296 len = sprintf(buf, "OK\n") + 1;
20297 } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) ==
20298 0) {
20299 #ifdef MEF_CFG_RX_FILTER
20300 ret = woal_set_rxfilter(priv, MTRUE);
20301 if (ret)
20302 goto done;
20303 #endif
20304 len = sprintf(buf, "OK\n") + 1;
20305 } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) ==
20306 0) {
20307 #ifdef MEF_CFG_RX_FILTER
20308 ret = woal_set_rxfilter(priv, MFALSE);
20309 if (ret)
20310 goto done;
20311 #endif
20312 len = sprintf(buf, "OK\n") + 1;
20313 }
20314 #ifdef STA_CFG80211
20315 else if (strncmp(buf, "GET_EVENT", strlen("GET_EVENT")) == 0) {
20316 if (IS_STA_CFG80211(cfg80211_wext)) {
20317 if (priv->last_event & EVENT_BG_SCAN_REPORT)
20318 woal_inform_bss_from_scan_result(
20319 priv, NULL, MOAL_IOCTL_WAIT);
20320 }
20321 len = sprintf(buf, "EVENT=%d\n", priv->last_event) + 1;
20322 priv->last_event = 0;
20323 } else if (strncmp(buf, "GET_802_11W", strlen("GET_802_11W")) == 0) {
20324 len = sprintf(buf, "802_11W=ENABLED\n") + 1;
20325 }
20326 #endif /* STA_CFG80211 */
20327 else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) {
20328 pdata = buf + strlen("RXFILTER-ADD") + 1;
20329 if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) {
20330 ret = -EFAULT;
20331 goto done;
20332 }
20333 len = sprintf(buf, "OK\n") + 1;
20334 } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) ==
20335 0) {
20336 pdata = buf + strlen("RXFILTER-REMOVE") + 1;
20337 if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) {
20338 ret = -EFAULT;
20339 goto done;
20340 }
20341 len = sprintf(buf, "OK\n") + 1;
20342 } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) {
20343 pdata = buf + strlen("QOSINFO") + 1;
20344 #ifdef STA_SUPPORT
20345 if (MLAN_STATUS_SUCCESS !=
20346 woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) {
20347 ret = -EFAULT;
20348 goto done;
20349 }
20350 #endif
20351 len = sprintf(buf, "OK\n") + 1;
20352 } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) {
20353 pdata = buf + strlen("SLEEPPD") + 1;
20354 if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) {
20355 ret = -EFAULT;
20356 goto done;
20357 }
20358 len = sprintf(buf, "OK\n") + 1;
20359 } else if (strncmp(buf, "SET_AP_WPS_P2P_IE",
20360 strlen("SET_AP_WPS_P2P_IE")) == 0) {
20361 pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1;
20362 /* Android cmd format:
20363 * "SET_AP_WPS_P2P_IE 1" -- beacon IE
20364 * "SET_AP_WPS_P2P_IE 2" -- proberesp IE
20365 * "SET_AP_WPS_P2P_IE 4" -- assocresp IE
20366 */
20367 #if defined(STA_CFG80211) && defined(UAP_CFG80211)
20368 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
20369 if (MLAN_STATUS_SUCCESS !=
20370 woal_set_ap_wps_p2p_ie(priv, (t_u8 *)pdata,
20371 priv_cmd.used_len -
20372 strlen("SET_AP_WPS_P2P_IE") -
20373 1)) {
20374 ret = -EFAULT;
20375 goto done;
20376 }
20377 #endif
20378 #endif
20379 len = sprintf(buf, "OK\n") + 1;
20380 }
20381 #endif
20382 else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) {
20383 memset(buf, 0x0, (size_t)priv_cmd.total_len);
20384 moal_memcpy_ext(priv->phandle, buf, priv->current_addr,
20385 ETH_ALEN, (t_u32)priv_cmd.total_len);
20386 len = ETH_ALEN;
20387 } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) {
20388 /* TODO
20389 * Just return '\0'
20390 */
20391 memset(buf, 0x0, (size_t)priv_cmd.total_len);
20392 *buf = 0;
20393 len = 1;
20394 } else if (strnicmp(buf, "MIRACAST", strlen("MIRACAST")) == 0) {
20395 pdata = buf + strlen("MIRACAST");
20396 /* Android cmd format:
20397 * "MIRACAST 0" -- disabled
20398 * "MIRACAST 1" -- operating as source
20399 * "MIRACAST 2" -- operating as sink
20400 */
20401 #ifdef WIFI_DIRECT_SUPPORT
20402 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20403 if (MLAN_STATUS_SUCCESS !=
20404 woal_set_miracast_mode(priv, (t_u8 *)pdata,
20405 priv_cmd.used_len -
20406 strlen("MIRACAST"))) {
20407 ret = -EFAULT;
20408 goto done;
20409 }
20410 #endif
20411 #endif
20412 len = sprintf(buf, "OK\n") + 1;
20413 } else if (strnicmp(buf, "SCAN_TIMING", strlen("SCAN_TIMING")) == 0) {
20414 #ifdef WIFI_DIRECT_SUPPORT
20415 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20416 if (MLAN_STATUS_SUCCESS !=
20417 woal_set_scan_chan_gap(priv, buf, priv_cmd.total_len)) {
20418 ret = -EFAULT;
20419 goto done;
20420 }
20421 #endif
20422 #endif
20423 len = sprintf(buf, "OK\n") + 1;
20424 } else if (strnicmp(buf, "BA_WSIZE_RX", strlen("BA_WSIZE_RX")) == 0) {
20425 pdata = buf + strlen("BA_WSIZE_RX") + 1;
20426 len = priv_cmd.total_len - strlen("BA_WSIZE_RX") - 1;
20427 if (MLAN_STATUS_SUCCESS !=
20428 woal_set_rx_ba_winsize(priv, pdata, len)) {
20429 ret = -EFAULT;
20430 goto done;
20431 }
20432 len = sprintf(buf, "OK\n") + 1;
20433 } else if (strnicmp(buf, "BA_WSIZE_TX", strlen("BA_WSIZE_TX")) == 0) {
20434 pdata = buf + strlen("BA_WSIZE_TX") + 1;
20435 len = priv_cmd.total_len - strlen("BA_WSIZE_TX") - 1;
20436 if (MLAN_STATUS_SUCCESS !=
20437 woal_set_tx_ba_winsize(priv, pdata, len)) {
20438 ret = -EFAULT;
20439 goto done;
20440 }
20441 len = sprintf(buf, "OK\n") + 1;
20442 } else if (strncmp(buf, "FAKE_SCAN_COMPLETE",
20443 strlen("FAKE_SCAN_COMPLETE")) == 0) {
20444 pdata = buf + strlen("FAKE_SCAN_COMPLETE") + 1;
20445 #ifdef STA_CFG80211
20446 if (*pdata == '1') {
20447 priv->fake_scan_complete = MTRUE;
20448 PRINTM(MIOCTL, "fake scan complete enabled\n");
20449 } else if (*pdata == '0') {
20450 priv->fake_scan_complete = MFALSE;
20451 PRINTM(MIOCTL, "fake scan complete disabled\n");
20452 }
20453 #endif
20454 len = sprintf(buf, "OK\n") + 1;
20455 }
20456 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
20457 #ifdef WIFI_DIRECT_SUPPORT
20458 else if (strncmp(buf, "P2P_PERIODIC_SLEEP",
20459 strlen("P2P_PERIODIC_SLEEP")) == 0) {
20460 if (MLAN_STATUS_SUCCESS !=
20461 woal_p2p_ps_cfg(priv, buf, priv_cmd.total_len)) {
20462 ret = -EFAULT;
20463 goto done;
20464 }
20465 len = sprintf(buf, "OK\n") + 1;
20466 }
20467 #endif
20468 #endif
20469 else if (strncmp(buf, "WLS_BATCHING", strlen("WLS_BATCHING")) == 0) {
20470 /* TODO */
20471 len = sprintf(buf, "OK\n") + 1;
20472 } else if (strncmp(buf, "TDLS_CS_CHAN", strlen("TDLS_CS_CHAN")) == 0) {
20473 len = woal_priv_tdls_cs_chan(priv, buf, priv_cmd.total_len);
20474 }
20475 #if defined(UAP_SUPPORT)
20476 else if (strncmp(buf, "P2P_ECSA", strlen("P2P_ECSA")) == 0) {
20477 len = woal_priv_p2p_ecsa(priv, buf, priv_cmd.total_len);
20478 }
20479 #endif
20480 else if (strncmp(buf, "FAKEMAC", strlen("FAKEMAC")) == 0) {
20481 len = woal_priv_config_random_mac(priv, buf,
20482 priv_cmd.total_len);
20483 } else if (strncmp(buf, "SETROAMOFFLOAD", strlen("SETROAMOFFLOAD")) ==
20484 0) {
20485 len = woal_priv_set_roam_offload(priv, buf, priv_cmd.total_len);
20486 } else if (strncmp(buf, "SETROAMOFFLAPLIST",
20487 strlen("SETROAMOFFLAPLIST")) == 0) {
20488 len = woal_priv_set_roam_offload_aplist(priv, buf,
20489 priv_cmd.total_len);
20490 } else if (strncmp(buf, "CFGROAMOFFLOAD", strlen("CFGROAMOFFLOAD")) ==
20491 0) {
20492 len = woal_priv_roam_offload_cfg(priv, buf, priv_cmd.total_len);
20493 } else if (strncmp(buf, "SETROAMPASSPHRASE",
20494 strlen("SETROAMPASSPHRASE")) == 0) {
20495 len = woal_priv_set_roam_passphrase(priv, buf,
20496 priv_cmd.total_len);
20497 } else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE,
20498 strlen(PRIV_CMD_CLOUD_KEEP_ALIVE)) == 0) {
20499 len = woal_priv_cloud_keep_alive(priv, buf, priv_cmd.total_len);
20500 } else if (strnicmp(buf, PRIV_CMD_TX_RX_HISTOGRAM,
20501 strlen(PRIV_CMD_TX_RX_HISTOGRAM)) == 0) {
20502 /* Get TX/RX histogram statistic */
20503 len = woal_priv_get_rx_tx_histogram(priv, buf,
20504 priv_cmd.total_len);
20505 goto handled;
20506 } else if (strnicmp(buf, PRIV_CMD_GET_CHNRGPWR,
20507 strlen(PRIV_CMD_GET_CHNRGPWR)) == 0) {
20508 /* Get chnrgpwr */
20509 len = woal_priv_get_chnrgpwr(priv, buf, priv_cmd.total_len);
20510 goto handled;
20511 } else if (strnicmp(buf, PRIV_CMD_GET_TXPWR_LIMIT,
20512 strlen(PRIV_CMD_GET_TXPWR_LIMIT)) == 0) {
20513 /* Get txpwrlimit */
20514 len = woal_priv_get_txpwrlimit(priv, buf, priv_cmd.total_len);
20515 goto handled;
20516 } else {
20517 PRINTM(MIOCTL, "Unknown PRIVATE command: %s, ignored\n", buf);
20518 ret = -EFAULT;
20519 goto done;
20520 }
20521
20522 handled:
20523 PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len);
20524
20525 if (len > 0) {
20526 priv_cmd.used_len = len;
20527 if (priv_cmd.used_len <= priv_cmd.total_len) {
20528 memset(buf + priv_cmd.used_len, 0,
20529 (size_t)(CMD_BUF_LEN - priv_cmd.used_len));
20530 if (copy_to_user((void __user *)cmd_buf, buf,
20531 priv_cmd.total_len)) {
20532 PRINTM(MERROR,
20533 "%s: failed to copy data to user buffer\n",
20534 __FUNCTION__);
20535 ret = -EFAULT;
20536 goto done;
20537 }
20538 if (copy_to_user(req->ifr_data, &priv_cmd,
20539 sizeof(android_wifi_priv_cmd))) {
20540 PRINTM(MERROR,
20541 "%s: failed to copy command header to user buffer\n",
20542 __FUNCTION__);
20543 ret = -EFAULT;
20544 }
20545 } else {
20546 PRINTM(MERROR,
20547 "%s: the buffer supplied by appl is too small (supplied: %d, used: %d)\n",
20548 __FUNCTION__, priv_cmd.total_len,
20549 priv_cmd.used_len);
20550 ret = -EFAULT;
20551 }
20552 } else {
20553 ret = len;
20554 }
20555
20556 done:
20557 kfree(buf);
20558 LEAVE();
20559 return ret;
20560 }
20561
20562 /********************************************************
20563 Global Functions
20564 ********************************************************/
20565 /**
20566 * @brief Create a brief scan resp to relay basic BSS info to the app layer
20567 *
20568 * When the beacon/probe response has not been buffered, use the saved BSS
20569 * information available to provide a minimum response for the application
20570 * ioctl retrieval routines. Include:
20571 * - Timestamp
20572 * - Beacon Period
20573 * - Capabilities (including WMM Element if available)
20574 * - SSID
20575 *
20576 * @param ppbuffer Output parameter: Buffer used to create basic scan rsp
20577 * @param pbss_desc Pointer to a BSS entry in the scan table to create
20578 * scan response from for delivery to the application layer
20579 *
20580 * @return N/A
20581 */
wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer,BSSDescriptor_t * pbss_desc)20582 void wlan_scan_create_brief_table_entry(t_u8 **ppbuffer,
20583 BSSDescriptor_t *pbss_desc)
20584 {
20585 t_u8 *ptmp_buf = *ppbuffer;
20586 t_u8 tmp_ssid_hdr[2];
20587 t_u8 ie_len = 0;
20588
20589 ENTER();
20590
20591 moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->time_stamp,
20592 sizeof(pbss_desc->time_stamp),
20593 sizeof(pbss_desc->time_stamp));
20594 ptmp_buf += sizeof(pbss_desc->time_stamp);
20595
20596 moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->beacon_period,
20597 sizeof(pbss_desc->beacon_period),
20598 sizeof(pbss_desc->beacon_period));
20599 ptmp_buf += sizeof(pbss_desc->beacon_period);
20600
20601 moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->cap_info,
20602 sizeof(pbss_desc->cap_info),
20603 sizeof(pbss_desc->cap_info));
20604 ptmp_buf += sizeof(pbss_desc->cap_info);
20605
20606 tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */
20607 tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len;
20608 moal_memcpy_ext(NULL, ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr),
20609 sizeof(tmp_ssid_hdr));
20610 ptmp_buf += sizeof(tmp_ssid_hdr);
20611
20612 moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->ssid.ssid,
20613 pbss_desc->ssid.ssid_len, pbss_desc->ssid.ssid_len);
20614 ptmp_buf += pbss_desc->ssid.ssid_len;
20615
20616 if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
20617 ie_len = sizeof(IEEEtypes_Header_t) +
20618 pbss_desc->wmm_ie.vend_hdr.len;
20619 moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->wmm_ie, ie_len,
20620 ie_len);
20621 ptmp_buf += ie_len;
20622 }
20623
20624 if (pbss_desc->pwpa_ie) {
20625 if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) {
20626 ie_len = sizeof(IEEEtypes_Header_t) +
20627 (*(pbss_desc->pwpa_ie)).vend_hdr.len;
20628 moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->pwpa_ie,
20629 ie_len, ie_len);
20630 }
20631
20632 ptmp_buf += ie_len;
20633 }
20634 if (pbss_desc->prsn_ie) {
20635 if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) {
20636 ie_len = sizeof(IEEEtypes_Header_t) +
20637 (*(pbss_desc->prsn_ie)).ieee_hdr.len;
20638 moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->prsn_ie,
20639 ie_len, ie_len);
20640 }
20641
20642 ptmp_buf += ie_len;
20643 }
20644 *ppbuffer = ptmp_buf;
20645 LEAVE();
20646 }
20647
20648 /**
20649 * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
20650 * Descriptor for inclusion in the ioctl response to the user space
20651 * application.
20652 *
20653 *
20654 * @param pbss_desc Pointer to a BSS entry in the scan table to form
20655 * scan response from for delivery to the application layer
20656 * @param ppbuffer Output parameter: Buffer used to output scan return
20657 * struct
20658 * @param pspace_left Output parameter: Number of bytes available in the
20659 * response buffer.
20660 *
20661 * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
20662 */
wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc,t_u8 ** ppbuffer,int * pspace_left)20663 int wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer,
20664 int *pspace_left)
20665 {
20666 wlan_ioctl_get_scan_table_entry *prsp_entry;
20667 wlan_ioctl_get_scan_table_entry tmp_rsp_entry;
20668 int space_needed;
20669 t_u8 *pcurrent;
20670 int variable_size;
20671
20672 const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry);
20673
20674 ENTER();
20675
20676 pcurrent = *ppbuffer;
20677
20678 /* The variable size returned is the stored beacon size */
20679 variable_size = pbss_desc->beacon_buf_size;
20680
20681 /* If we stored a beacon and its size was zero, set the variable
20682 * size return value to the size of the brief scan response
20683 * wlan_scan_create_brief_table_entry creates. Also used if
20684 * we are not configured to store beacons in the first place
20685 */
20686 if (!variable_size) {
20687 variable_size = pbss_desc->ssid.ssid_len + 2;
20688 variable_size += (sizeof(pbss_desc->beacon_period) +
20689 sizeof(pbss_desc->time_stamp) +
20690 sizeof(pbss_desc->cap_info));
20691 if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) {
20692 variable_size += (sizeof(IEEEtypes_Header_t) +
20693 pbss_desc->wmm_ie.vend_hdr.len);
20694 }
20695
20696 if (pbss_desc->pwpa_ie) {
20697 if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
20698 WPA_IE) {
20699 variable_size +=
20700 (sizeof(IEEEtypes_Header_t) +
20701 (*(pbss_desc->pwpa_ie)).vend_hdr.len);
20702 }
20703 }
20704
20705 if (pbss_desc->prsn_ie) {
20706 if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
20707 RSN_IE) {
20708 variable_size +=
20709 (sizeof(IEEEtypes_Header_t) +
20710 (*(pbss_desc->prsn_ie)).ieee_hdr.len);
20711 }
20712 }
20713 }
20714
20715 space_needed = fixed_size + variable_size;
20716
20717 PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", space_needed,
20718 *pspace_left);
20719
20720 if (space_needed >= *pspace_left) {
20721 *pspace_left = 0;
20722 LEAVE();
20723 return -E2BIG;
20724 }
20725
20726 *pspace_left -= space_needed;
20727
20728 tmp_rsp_entry.fixed_field_length =
20729 (sizeof(tmp_rsp_entry) -
20730 sizeof(tmp_rsp_entry.fixed_field_length) -
20731 sizeof(tmp_rsp_entry.bss_info_length));
20732
20733 moal_memcpy_ext(NULL, tmp_rsp_entry.fixed_fields.bssid,
20734 pbss_desc->mac_address,
20735 sizeof(prsp_entry->fixed_fields.bssid),
20736 sizeof(prsp_entry->fixed_fields.bssid));
20737
20738 tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi;
20739 tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel;
20740 tmp_rsp_entry.fixed_fields.chan_load = pbss_desc->chan_load;
20741 tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf;
20742 tmp_rsp_entry.bss_info_length = variable_size;
20743
20744 /*
20745 * Copy fixed fields to user space
20746 */
20747 moal_memcpy_ext(NULL, pcurrent, &tmp_rsp_entry, fixed_size, fixed_size);
20748 pcurrent += fixed_size;
20749
20750 if (pbss_desc->pbeacon_buf) {
20751 /*
20752 * Copy variable length elements to user space
20753 */
20754 moal_memcpy_ext(NULL, pcurrent, pbss_desc->pbeacon_buf,
20755 pbss_desc->beacon_buf_size,
20756 pbss_desc->beacon_buf_size);
20757
20758 pcurrent += pbss_desc->beacon_buf_size;
20759 } else {
20760 wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc);
20761 }
20762
20763 *ppbuffer = pcurrent;
20764
20765 LEAVE();
20766
20767 return MLAN_STATUS_SUCCESS;
20768 }
20769
20770 /**
20771 * @brief ioctl function - entry point
20772 *
20773 * @param dev A pointer to net_device structure
20774 * @param req A pointer to ifreq structure
20775 * @param cmd Command
20776 *
20777 * @return 0 --success, otherwise fail
20778 */
20779 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
woal_do_ioctl(struct net_device * dev,struct ifreq * req,void __user * data,int cmd)20780 int woal_do_ioctl(struct net_device *dev, struct ifreq *req, void __user *data,
20781 int cmd)
20782 #else
20783 int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
20784 #endif
20785
20786 {
20787 int ret = 0;
20788
20789 ENTER();
20790
20791 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
20792 if (in_compat_syscall()) /* not implemented yet */
20793 return -EOPNOTSUPP;
20794 #endif
20795
20796 PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd);
20797 switch (cmd) {
20798 case WOAL_ANDROID_DEF_CMD:
20799 /** android default ioctl ID is SIOCDEVPRIVATE + 1 */
20800 ret = woal_android_priv_cmd(dev, req);
20801 break;
20802 case WOAL_CUSTOM_IE_CFG:
20803 ret = woal_custom_ie_ioctl(dev, req);
20804 break;
20805 case WOAL_MGMT_FRAME_TX:
20806 ret = woal_send_host_packet(dev, req);
20807 break;
20808 case WOAL_TDLS_CONFIG:
20809 ret = woal_tdls_config_ioctl(dev, req);
20810 break;
20811 case WOAL_ANDROID_PRIV_CMD:
20812 ret = woal_android_priv_cmd(dev, req);
20813 break;
20814 case WOAL_GET_BSS_TYPE:
20815 ret = woal_get_bss_type(dev, req);
20816 break;
20817 default:
20818 #if defined(STA_WEXT)
20819 #ifdef STA_SUPPORT
20820 ret = woal_wext_do_ioctl(dev, req, cmd);
20821 #else
20822 ret = -EINVAL;
20823 #endif
20824 #else
20825 ret = -EINVAL;
20826 #endif
20827 break;
20828 }
20829
20830 LEAVE();
20831 return ret;
20832 }
20833