1 /*
2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Include Files */
21
22 #include "osif_sync.h"
23 #include <wlan_hdd_includes.h>
24 #include <wlan_hdd_wowl.h>
25 #include <wlan_hdd_stats.h>
26 #include "cfg_ucfg_api.h"
27 #include "wlan_hdd_trace.h"
28 #include "wlan_hdd_ioctl.h"
29 #include "wlan_hdd_power.h"
30 #include "wlan_hdd_regulatory.h"
31 #include "wlan_osif_request_manager.h"
32 #include "wlan_hdd_driver_ops.h"
33 #include "wlan_policy_mgr_api.h"
34 #include "wlan_hdd_hostapd.h"
35 #include "scheduler_api.h"
36 #include "wlan_reg_ucfg_api.h"
37 #include "wlan_hdd_p2p.h"
38 #include <linux/ctype.h>
39 #include "wma.h"
40 #include "wlan_hdd_napi.h"
41 #include "wlan_mlme_ucfg_api.h"
42 #include "target_type.h"
43 #ifdef FEATURE_WLAN_ESE
44 #include <sme_api.h>
45 #include <sir_api.h>
46 #endif
47 #include "wlan_hdd_object_manager.h"
48 #include "hif.h"
49 #include "wlan_scan_ucfg_api.h"
50 #include "wlan_reg_ucfg_api.h"
51 #include "qdf_func_tracker.h"
52 #include "wlan_cm_roam_ucfg_api.h"
53 #include "wlan_tdls_api.h"
54
55 #if defined(LINUX_QCMBR)
56 #define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
57 #endif
58
59 #define SIZE_OF_WIFI6E_CHAN_LIST 512
60
61 /*
62 * Size of Driver command strings from upper layer
63 */
64 #define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */
65 #define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */
66 #define SIZE_OF_SETSUSPENDMODE 14
67
68 /*
69 * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) +
70 * (sizeof("country_code") = 3) +
71 * one (NULL terminating character)
72 */
73 #define SIZE_OF_GETCOUNTRYREV_OUTPUT 20
74
75 #ifdef FEATURE_WLAN_ESE
76 #define TID_MIN_VALUE 0
77 #define TID_MAX_VALUE 15
78 #endif /* FEATURE_WLAN_ESE */
79
80 /*
81 * Maximum buffer size used for returning the data back to user space
82 */
83 #define WLAN_MAX_BUF_SIZE 1024
84 #define WLAN_PRIV_DATA_MAX_LEN 8192
85
86 /*
87 * Driver miracast parameters:
88 * 0-Disabled
89 * 1-Source, 2-Sink
90 * 128: miracast connecting time optimization enabled. At present host
91 * will disable imps to reduce connection time for p2p.
92 * 129: miracast connecting time optimization disabled
93 */
94 enum miracast_param {
95 MIRACAST_DISABLED,
96 MIRACAST_SOURCE,
97 MIRACAST_SINK,
98 MIRACAST_CONN_OPT_ENABLED = 128,
99 MIRACAST_CONN_OPT_DISABLED = 129,
100 };
101
102 /*
103 * When ever we need to print IBSSPEERINFOALL for more than 16 STA
104 * we will split the printing.
105 */
106 #define NUM_OF_STA_DATA_TO_PRINT 16
107
108 /*
109 * The host sends the maximum channel count in RCL(Roam channel list) via a
110 * supplicant vendor event to notify RCL on disconnection.
111 */
112 #define MAX_RCL_CHANNEL_COUNT 30
113
114 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
115 /**
116 * struct enable_ext_wow_priv - Private data structure for ext wow
117 * @ext_wow_should_suspend: Suspend status of ext wow
118 */
119 struct enable_ext_wow_priv {
120 bool ext_wow_should_suspend;
121 };
122 #endif
123
124 /*
125 * Android DRIVER command structures
126 */
127 struct android_wifi_reassoc_params {
128 unsigned char bssid[18];
129 int channel;
130 };
131
132 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
133 struct android_wifi_af_params {
134 unsigned char bssid[18];
135 int channel;
136 int dwell_time;
137 int len;
138 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
139 };
140
141 /*
142 * Define HDD driver command handling entry, each contains a command
143 * string and the handler.
144 */
145 typedef int (*hdd_drv_cmd_handler_t)(struct wlan_hdd_link_info *link_info,
146 struct hdd_context *hdd_ctx,
147 uint8_t *cmd,
148 uint8_t cmd_name_len,
149 struct hdd_priv_data *priv_data);
150
151 /**
152 * struct hdd_drv_cmd - Structure to store ioctl command handling info
153 * @cmd: Name of the command
154 * @handler: Command handler to be invoked
155 * @args: Set to true if command expects input parameters
156 */
157 struct hdd_drv_cmd {
158 const char *cmd;
159 hdd_drv_cmd_handler_t handler;
160 bool args;
161 };
162
163 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
164 #define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000
165 #define WLAN_HDD_MAX_TCP_PORT 65535
166 #endif
167
168 /**
169 * drv_cmd_validate() - Validates for space in hdd driver command
170 * @command: pointer to input data (its a NULL terminated string)
171 * @len: length of command name
172 *
173 * This function checks for space after command name and if no space
174 * is found returns error.
175 *
176 * Return: 0 for success non-zero for failure
177 */
drv_cmd_validate(uint8_t * command,int len)178 static int drv_cmd_validate(uint8_t *command, int len)
179 {
180 if (command[len] != ' ')
181 return -EINVAL;
182
183 return 0;
184 }
185
186 #ifdef FEATURE_WLAN_ESE
187 struct tsm_priv {
188 tAniTrafStrmMetrics tsm_metrics;
189 };
190
hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,void * context)191 static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics,
192 void *context)
193 {
194 struct osif_request *request;
195 struct tsm_priv *priv;
196
197 request = osif_request_get(context);
198 if (!request) {
199 hdd_err("Obsolete request");
200 return;
201 }
202 priv = osif_request_priv(request);
203 priv->tsm_metrics = tsm_metrics;
204 osif_request_complete(request);
205 osif_request_put(request);
206 hdd_exit();
207
208 }
209
hdd_get_tsm_stats(struct hdd_adapter * adapter,const uint8_t tid,tAniTrafStrmMetrics * tsm_metrics)210 static int hdd_get_tsm_stats(struct hdd_adapter *adapter,
211 const uint8_t tid,
212 tAniTrafStrmMetrics *tsm_metrics)
213 {
214 struct hdd_context *hdd_ctx;
215 struct hdd_station_ctx *hdd_sta_ctx;
216 QDF_STATUS status;
217 int ret;
218 void *cookie;
219 struct osif_request *request;
220 struct tsm_priv *priv;
221 static const struct osif_request_params params = {
222 .priv_size = sizeof(*priv),
223 .timeout_ms = WLAN_WAIT_TIME_STATS,
224 };
225
226 if (!adapter) {
227 hdd_err("adapter is NULL");
228 return -EINVAL;
229 }
230
231 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
232 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
233
234 request = osif_request_alloc(¶ms);
235 if (!request) {
236 hdd_err("Request allocation failure");
237 return -ENOMEM;
238 }
239 cookie = osif_request_cookie(request);
240
241 status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb,
242 hdd_sta_ctx->conn_info.bssid,
243 cookie, tid);
244 if (QDF_STATUS_SUCCESS != status) {
245 hdd_err("Unable to retrieve tsm statistics");
246 ret = qdf_status_to_os_return(status);
247 goto cleanup;
248 }
249
250 ret = osif_request_wait_for_response(request);
251 if (ret) {
252 hdd_err("SME timed out while retrieving tsm statistics");
253 goto cleanup;
254 }
255
256 priv = osif_request_priv(request);
257 *tsm_metrics = priv->tsm_metrics;
258
259 cleanup:
260 osif_request_put(request);
261
262 return ret;
263 }
264 #endif /*FEATURE_WLAN_ESE */
265
hdd_get_band_helper(struct hdd_context * hdd_ctx,int * ui_band)266 static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band)
267 {
268 enum band_info band = -1;
269
270 ucfg_reg_get_band(hdd_ctx->pdev, &band);
271 switch (band) {
272 case BAND_ALL:
273 *ui_band = WLAN_HDD_UI_BAND_AUTO;
274 break;
275
276 case BAND_2G:
277 *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ;
278 break;
279
280 case BAND_5G:
281 *ui_band = WLAN_HDD_UI_BAND_5_GHZ;
282 break;
283
284 default:
285 hdd_warn("Invalid Band %d", band);
286 *ui_band = -1;
287 break;
288 }
289 }
290
291 /**
292 * hdd_check_and_fill_freq() - to validate chan and convert into freq
293 * @in_chan: input as channel number or freq to be checked
294 * @freq: frequency for input in_chan (output parameter)
295 * @pdev: pdev object
296 *
297 * This function checks input "in_chan" is channel number, if yes then fills
298 * appropriate frequency into "freq" out param. If the "in_param" is greater
299 * than WNI_CFG_CURRENT_CHANNEL_STAMAX then checks for valid frequencies.
300 *
301 * Return: true if "in_chan" is valid channel/frequency; false otherwise
302 */
hdd_check_and_fill_freq(uint32_t in_chan,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)303 static bool hdd_check_and_fill_freq(uint32_t in_chan, qdf_freq_t *freq,
304 struct wlan_objmgr_pdev *pdev)
305 {
306 if (in_chan <= WNI_CFG_CURRENT_CHANNEL_STAMAX)
307 *freq = wlan_reg_legacy_chan_to_freq(pdev, in_chan);
308 else if (WLAN_REG_IS_24GHZ_CH_FREQ(in_chan) ||
309 WLAN_REG_IS_5GHZ_CH_FREQ(in_chan) ||
310 WLAN_REG_IS_6GHZ_CHAN_FREQ(in_chan))
311 *freq = in_chan;
312 else
313 return false;
314
315 return true;
316 }
317
318 /**
319 * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel
320 * @data: input data
321 * @bssid: pointer to bssid (output parameter)
322 * @freq: pointer to freq (output parameter)
323 * @pdev: pdev object
324 *
325 * Return: 0 if parsing is successful; -EINVAL otherwise
326 */
_hdd_parse_bssid_and_chan(const uint8_t ** data,uint8_t * bssid,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)327 static int _hdd_parse_bssid_and_chan(const uint8_t **data,
328 uint8_t *bssid, qdf_freq_t *freq,
329 struct wlan_objmgr_pdev *pdev)
330 {
331 const uint8_t *in_ptr;
332 int v = 0;
333 int temp_int;
334 uint8_t temp_buf[32];
335
336 /* 12 hexa decimal digits, 5 ':' and '\0' */
337 uint8_t mac_addr[18];
338
339 if (!data || !*data)
340 return -EINVAL;
341
342 in_ptr = *data;
343
344 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
345 /* no argument after the command */
346 if (!in_ptr)
347 goto error;
348 /* no space after the command */
349 else if (SPACE_ASCII_VALUE != *in_ptr)
350 goto error;
351
352 /* remove empty spaces */
353 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
354 in_ptr++;
355
356 /* no argument followed by spaces */
357 if ('\0' == *in_ptr)
358 goto error;
359
360 v = sscanf(in_ptr, "%17s", mac_addr);
361 if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) {
362 hdd_err("Invalid MAC address or All hex inputs are not read (%d)",
363 v);
364 goto error;
365 }
366
367 bssid[0] = hex_to_bin(mac_addr[0]) << 4 |
368 hex_to_bin(mac_addr[1]);
369 bssid[1] = hex_to_bin(mac_addr[3]) << 4 |
370 hex_to_bin(mac_addr[4]);
371 bssid[2] = hex_to_bin(mac_addr[6]) << 4 |
372 hex_to_bin(mac_addr[7]);
373 bssid[3] = hex_to_bin(mac_addr[9]) << 4 |
374 hex_to_bin(mac_addr[10]);
375 bssid[4] = hex_to_bin(mac_addr[12]) << 4 |
376 hex_to_bin(mac_addr[13]);
377 bssid[5] = hex_to_bin(mac_addr[15]) << 4 |
378 hex_to_bin(mac_addr[16]);
379
380 /* point to the next argument */
381 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
382 /* no argument after the command */
383 if (!in_ptr)
384 goto error;
385
386 /* remove empty spaces */
387 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
388 in_ptr++;
389
390 /* no argument followed by spaces */
391 if ('\0' == *in_ptr)
392 goto error;
393
394 /* get the next argument ie the channel/freq number */
395 v = sscanf(in_ptr, "%31s ", temp_buf);
396 if (1 != v)
397 goto error;
398
399 v = kstrtos32(temp_buf, 10, &temp_int);
400 if (v < 0 || temp_int < 0)
401 goto error;
402 else if (!hdd_check_and_fill_freq(temp_int, freq, pdev))
403 goto error;
404
405 *data = in_ptr;
406 return 0;
407 error:
408 *data = in_ptr;
409 return -EINVAL;
410 }
411
412 /**
413 * hdd_parse_send_action_frame_v1_data() - HDD Parse send action frame data
414 * @command: Pointer to input data
415 * @bssid: Pointer to target AP BSSID
416 * @freq: Pointer to the Target AP channel frequency
417 * @dwell_time: Pointer to the time to stay off-channel
418 * after transmitting action frame
419 * @buf: Pointer to data
420 * @buf_len: Pointer to data length
421 * @pdev: pdev object
422 *
423 * This function parses the send action frame data passed in the format
424 * SENDACTIONFRAME<space><bssid><space><channel | frequency><space><dwelltime>
425 * <space><data>
426 *
427 * Return: 0 for success non-zero for failure
428 */
429 static int
hdd_parse_send_action_frame_v1_data(const uint8_t * command,uint8_t * bssid,qdf_freq_t * freq,uint8_t * dwell_time,uint8_t ** buf,uint8_t * buf_len,struct wlan_objmgr_pdev * pdev)430 hdd_parse_send_action_frame_v1_data(const uint8_t *command,
431 uint8_t *bssid,
432 qdf_freq_t *freq, uint8_t *dwell_time,
433 uint8_t **buf, uint8_t *buf_len,
434 struct wlan_objmgr_pdev *pdev)
435 {
436 const uint8_t *in_ptr = command;
437 const uint8_t *end_ptr;
438 int temp_int;
439 int j = 0;
440 int i = 0;
441 int v = 0;
442 uint8_t temp_buf[32];
443 uint8_t temp_u8 = 0;
444
445 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev))
446 return -EINVAL;
447
448 /* point to the next argument */
449 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
450 /* no argument after the command */
451 if (!in_ptr)
452 return -EINVAL;
453 /* removing empty spaces */
454 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
455 in_ptr++;
456
457 /* no argument followed by spaces */
458 if ('\0' == *in_ptr)
459 return -EINVAL;
460
461 /* getting the next argument ie the dwell time */
462 v = sscanf(in_ptr, "%31s ", temp_buf);
463 if (1 != v)
464 return -EINVAL;
465
466 v = kstrtos32(temp_buf, 10, &temp_int);
467 if (v < 0 || temp_int < 0)
468 return -EINVAL;
469
470 *dwell_time = temp_int;
471
472 /* point to the next argument */
473 in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE);
474 /* no argument after the command */
475 if (!in_ptr)
476 return -EINVAL;
477 /* removing empty spaces */
478 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
479 in_ptr++;
480
481 /* no argument followed by spaces */
482 if ('\0' == *in_ptr)
483 return -EINVAL;
484
485 /* find the length of data */
486 end_ptr = in_ptr;
487 while (('\0' != *end_ptr))
488 end_ptr++;
489
490 *buf_len = end_ptr - in_ptr;
491 if (*buf_len <= 0)
492 return -EINVAL;
493
494 /*
495 * Allocate the number of bytes based on the number of input characters
496 * whether it is even or odd.
497 * if the number of input characters are even, then we need N/2 byte.
498 * if the number of input characters are odd, then we need do (N+1)/2
499 * to compensate rounding off.
500 * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough.
501 * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes
502 */
503 *buf = qdf_mem_malloc((*buf_len + 1) / 2);
504 if (!*buf)
505 return -ENOMEM;
506
507 /* the buffer received from the upper layer is character buffer,
508 * we need to prepare the buffer taking 2 characters in to a U8 hex
509 * decimal number for example 7f0000f0...form a buffer to contain 7f
510 * in 0th location, 00 in 1st and f0 in 3rd location
511 */
512 for (i = 0, j = 0; j < *buf_len; j += 2) {
513 if (j + 1 == *buf_len) {
514 temp_u8 = hex_to_bin(in_ptr[j]);
515 } else {
516 temp_u8 =
517 (hex_to_bin(in_ptr[j]) << 4) |
518 (hex_to_bin(in_ptr[j + 1]));
519 }
520 (*buf)[i++] = temp_u8;
521 }
522 *buf_len = i;
523 return 0;
524 }
525
526 /**
527 * hdd_parse_reassoc_command_v1_data() - HDD Parse reassoc command data
528 * @command: Pointer to input data (its a NULL terminated string)
529 * @bssid: Pointer to target Ap bssid
530 * @freq: Pointer to the Target AP frequency
531 * @pdev: pdev object
532 *
533 * This function parses the reasoc command data passed in the format
534 * REASSOC<space><bssid><space><channel/frequency>.
535 *
536 * If reassoc MAC from user space is broadcast MAC as:
537 * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0",
538 * user space invoked roaming candidate selection will base on firmware score
539 * algorithm, current connection will be kept if current AP has highest
540 * score. It is requirement from customer which can avoid ping-pong roaming.
541 *
542 * Return: 0 for success non-zero for failure
543 */
hdd_parse_reassoc_command_v1_data(const uint8_t * command,uint8_t * bssid,qdf_freq_t * freq,struct wlan_objmgr_pdev * pdev)544 static int hdd_parse_reassoc_command_v1_data(const uint8_t *command,
545 uint8_t *bssid, qdf_freq_t *freq,
546 struct wlan_objmgr_pdev *pdev)
547 {
548 const uint8_t *in_ptr = command;
549
550 if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev))
551 return -EINVAL;
552
553 return 0;
554 }
555
556 /**
557 * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command
558 * @adapter: Adapter upon which the command was received
559 * @command: ASCII text command that was received
560 *
561 * This function parses the v1 REASSOC command with the format
562 *
563 * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
564 *
565 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
566 * BSSID and CH/FREQ is the ASCII representation of the channel/frequency.
567 * For example
568 *
569 * REASSOC 00:0a:0b:11:22:33 48
570 * REASSOC 00:0a:0b:11:22:33 2412
571 *
572 * Return: 0 for success non-zero for failure
573 */
hdd_parse_reassoc_v1(struct hdd_adapter * adapter,const char * command)574 static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command)
575 {
576 qdf_freq_t freq = 0;
577 tSirMacAddr bssid;
578 int ret;
579 struct qdf_mac_addr target_bssid;
580 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
581 QDF_STATUS status;
582 struct wlan_objmgr_pdev *pdev;
583
584 pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
585 ret = hdd_parse_reassoc_command_v1_data(command, bssid, &freq, pdev);
586 if (ret) {
587 hdd_err("Failed to parse reassoc command data");
588 return ret;
589 }
590
591 qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
592 status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev,
593 adapter->deflink->vdev_id,
594 &target_bssid, freq,
595 CM_ROAMING_USER);
596 return qdf_status_to_os_return(status);
597 }
598
599 /**
600 * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command
601 * @adapter: Adapter upon which the command was received
602 * @command: Command that was received, ASCII command
603 * followed by binary data
604 * @total_len: Total length of the command received
605 *
606 * This function parses the v2 REASSOC command with the format
607 *
608 * REASSOC <android_wifi_reassoc_params>
609 *
610 * Return: 0 for success non-zero for failure
611 */
hdd_parse_reassoc_v2(struct hdd_adapter * adapter,const char * command,int total_len)612 static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter,
613 const char *command,
614 int total_len)
615 {
616 struct android_wifi_reassoc_params params;
617 tSirMacAddr bssid;
618 qdf_freq_t freq = 0;
619 int ret;
620 struct qdf_mac_addr target_bssid;
621 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
622 QDF_STATUS status;
623 struct wlan_objmgr_pdev *pdev;
624
625 pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
626 if (total_len < sizeof(params) + 8) {
627 hdd_err("Invalid command length");
628 return -EINVAL;
629 }
630
631 /* The params are located after "REASSOC " */
632 memcpy(¶ms, command + 8, sizeof(params));
633
634 if (!mac_pton(params.bssid, (u8 *) &bssid)) {
635 hdd_err("MAC address parsing failed");
636 ret = -EINVAL;
637 } else {
638 /*
639 * In Reassoc command, user can send channel number or frequency
640 * along with BSSID. If params.channel param of REASSOC command
641 * is less than WNI_CFG_CURRENT_CHANNEL_STAMAX, then host
642 * consider this as channel number else frequency.
643 */
644 if (!hdd_check_and_fill_freq(params.channel, &freq, pdev))
645 return -EINVAL;
646
647 qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
648 status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev,
649 adapter->deflink->vdev_id,
650 &target_bssid, freq,
651 CM_ROAMING_USER);
652 ret = qdf_status_to_os_return(status);
653 }
654
655 return ret;
656 }
657
658 /**
659 * hdd_parse_reassoc() - parse the REASSOC command
660 * @adapter: Adapter upon which the command was received
661 * @command: Command that was received
662 * @total_len: Total length of the command received
663 *
664 * There are two different versions of the REASSOC command. Version 1
665 * of the command contains a parameter list that is ASCII characters
666 * whereas version 2 contains a combination of ASCII and binary
667 * payload. Determine if a version 1 or a version 2 command is being
668 * parsed by examining the parameters, and then dispatch the parser
669 * that is appropriate for the command.
670 *
671 * Return: 0 for success non-zero for failure
672 */
hdd_parse_reassoc(struct hdd_adapter * adapter,const char * command,int total_len)673 static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command,
674 int total_len)
675 {
676 int ret;
677
678 /* both versions start with "REASSOC "
679 * v1 has a bssid and channel # as an ASCII string
680 * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ
681 * v2 has a C struct
682 * REASSOC <binary c struct>
683 *
684 * The first field in the v2 struct is also the bssid in ASCII.
685 * But in the case of a v2 message the BSSID is NUL-terminated.
686 * Hence we can peek at that offset to see if this is V1 or V2
687 * REASSOC xx:xx:xx:xx:xx:xx*
688 * 1111111111222222
689 * 01234567890123456789012345
690 */
691
692 if (total_len < 26) {
693 hdd_err("Invalid command, total_len = %d", total_len);
694 return -EINVAL;
695 }
696
697 if (command[25])
698 ret = hdd_parse_reassoc_v1(adapter, command);
699 else
700 ret = hdd_parse_reassoc_v2(adapter, command, total_len);
701
702 return ret;
703 }
704
705 /**
706 * hdd_sendactionframe() - send a userspace-supplied action frame
707 * @adapter: Adapter upon which the command was received
708 * @bssid: BSSID target of the action frame
709 * @freq: Frequency upon which to send the frame
710 * @dwell_time: Amount of time to dwell when the frame is sent
711 * @payload_len:Length of the payload
712 * @payload: Payload of the frame
713 *
714 * This function sends a userspace-supplied action frame
715 *
716 * Return: 0 for success non-zero for failure
717 */
718 static int
hdd_sendactionframe(struct hdd_adapter * adapter,const uint8_t * bssid,const qdf_freq_t freq,const uint8_t dwell_time,const int payload_len,const uint8_t * payload)719 hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid,
720 const qdf_freq_t freq, const uint8_t dwell_time,
721 const int payload_len, const uint8_t *payload)
722 {
723 struct ieee80211_channel chan;
724 int frame_len, ret = 0;
725 uint8_t *frame;
726 struct ieee80211_hdr_3addr *hdr;
727 u64 cookie;
728 struct hdd_station_ctx *sta_ctx;
729 struct hdd_context *hdd_ctx;
730 tpSirMacVendorSpecificFrameHdr vendor =
731 (tpSirMacVendorSpecificFrameHdr) payload;
732 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
733 struct cfg80211_mgmt_tx_params params;
734 #endif
735
736 if (payload_len < sizeof(tSirMacVendorSpecificFrameHdr)) {
737 hdd_warn("Invalid payload length: %d", payload_len);
738 return -EINVAL;
739 }
740
741 if (QDF_STA_MODE != adapter->device_mode) {
742 hdd_warn("Unsupported in mode %s(%d)",
743 qdf_opmode_str(adapter->device_mode),
744 adapter->device_mode);
745 return -EINVAL;
746 }
747
748 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
749 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
750
751 /* if not associated, no need to send action frame */
752 if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
753 hdd_warn("Not associated");
754 ret = -EINVAL;
755 goto exit;
756 }
757
758 /*
759 * if the target bssid is different from currently associated AP,
760 * then no need to send action frame
761 */
762 if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes,
763 QDF_MAC_ADDR_SIZE)) {
764 hdd_warn("STA is not associated to this AP");
765 ret = -EINVAL;
766 goto exit;
767 }
768
769 chan.center_freq = freq;
770 /* Check if it is specific action frame */
771 if (vendor->category ==
772 ACTION_CATEGORY_VENDOR_SPECIFIC) {
773 static const uint8_t oui[] = { 0x00, 0x00, 0xf0 };
774
775 if (!qdf_mem_cmp(vendor->Oui, oui, 3)) {
776 /*
777 * if the freq number is different from operating
778 * freq then no need to send action frame
779 */
780 if (freq) {
781 if (freq != sta_ctx->conn_info.chan_freq) {
782 hdd_warn("freq(%u) is different from operating freq(%u)",
783 freq,
784 sta_ctx->conn_info.chan_freq);
785 ret = -EINVAL;
786 goto exit;
787 }
788 /*
789 * If channel number is specified and same
790 * as home channel, ensure that action frame
791 * is sent immediately by cancelling
792 * roaming scans. Otherwise large dwell times
793 * may cause long delays in sending action
794 * frames.
795 */
796 ucfg_cm_abort_roam_scan(
797 hdd_ctx->pdev,
798 adapter->deflink->vdev_id);
799 } else {
800 /*
801 * 0 is accepted as current home frequency,
802 * delayed transmission of action frame is ok.
803 */
804 chan.center_freq = sta_ctx->conn_info.chan_freq;
805 }
806 }
807 }
808 if (chan.center_freq == 0) {
809 hdd_nofl_err("Invalid freq : %d", freq);
810 ret = -EINVAL;
811 goto exit;
812 }
813
814 frame_len = payload_len + 24;
815 frame = qdf_mem_malloc(frame_len);
816 if (!frame) {
817 ret = -ENOMEM;
818 goto exit;
819 }
820
821 hdr = (struct ieee80211_hdr_3addr *)frame;
822 hdr->frame_control =
823 cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
824 qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE);
825 qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes,
826 QDF_MAC_ADDR_SIZE);
827 qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE);
828 qdf_mem_copy(hdr + 1, payload, payload_len);
829
830 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
831 params.chan = &chan;
832 params.offchan = 0;
833 params.wait = dwell_time;
834 params.buf = frame;
835 params.len = frame_len;
836 params.no_cck = 1;
837 params.dont_wait_for_ack = 1;
838 ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, ¶ms, &cookie);
839 #else
840 ret = wlan_hdd_mgmt_tx(NULL,
841 &(adapter->wdev),
842 &chan, 0,
843
844 dwell_time, frame, frame_len, 1, 1, &cookie);
845 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
846
847 qdf_mem_free(frame);
848 exit:
849 return ret;
850 }
851
852 /**
853 * hdd_parse_sendactionframe_v1() - parse version 1 of the
854 * SENDACTIONFRAME command
855 * @adapter: Adapter upon which the command was received
856 * @command: ASCII text command that was received
857 *
858 * This function parses the v1 SENDACTIONFRAME command with the format
859 *
860 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx
861 *
862 * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the
863 * BSSID, CH is the ASCII representation of the channel, DW is the
864 * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII
865 * payload. For example
866 *
867 * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee
868 *
869 * Return: 0 for success non-zero for failure
870 */
871 static int
hdd_parse_sendactionframe_v1(struct hdd_adapter * adapter,const char * command)872 hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command)
873 {
874 qdf_freq_t freq = 0;
875 uint8_t dwell_time = 0;
876 uint8_t payload_len = 0;
877 uint8_t *payload = NULL;
878 tSirMacAddr bssid;
879 int ret;
880 struct wlan_objmgr_pdev *pdev;
881
882 pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
883 ret = hdd_parse_send_action_frame_v1_data(command, bssid, &freq,
884 &dwell_time, &payload,
885 &payload_len, pdev);
886 if (ret) {
887 hdd_nofl_err("Failed to parse send action frame data");
888 } else {
889 ret = hdd_sendactionframe(adapter, bssid, freq,
890 dwell_time, payload_len, payload);
891 qdf_mem_free(payload);
892 }
893
894 return ret;
895 }
896
897 /**
898 * hdd_parse_sendactionframe_v2() - parse version 2 of the
899 * SENDACTIONFRAME command
900 * @adapter: Adapter upon which the command was received
901 * @command: Command that was received, ASCII command
902 * followed by binary data
903 * @total_len: Length of @command
904 *
905 * This function parses the v2 SENDACTIONFRAME command with the format
906 *
907 * SENDACTIONFRAME <android_wifi_af_params>
908 *
909 * Return: 0 for success non-zero for failure
910 */
911 static int
hdd_parse_sendactionframe_v2(struct hdd_adapter * adapter,const char * command,int total_len)912 hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter,
913 const char *command, int total_len)
914 {
915 struct android_wifi_af_params *params;
916 tSirMacAddr bssid;
917 int ret;
918 int len_wo_payload = 0;
919 qdf_freq_t freq = 0;
920 struct wlan_objmgr_pdev *pdev;
921
922 pdev = wlan_vdev_get_pdev(adapter->deflink->vdev);
923
924 /* The params are located after "SENDACTIONFRAME " */
925 total_len -= 16;
926 len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE;
927 if (total_len <= len_wo_payload) {
928 hdd_err("Invalid command len");
929 return -EINVAL;
930 }
931
932 params = (struct android_wifi_af_params *)(command + 16);
933
934 if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE ||
935 (params->len > (total_len - len_wo_payload))) {
936 hdd_err("Invalid payload length: %d", params->len);
937 return -EINVAL;
938 }
939
940 if (!mac_pton(params->bssid, (u8 *)&bssid)) {
941 hdd_err("MAC address parsing failed");
942 return -EINVAL;
943 }
944
945 if (params->channel < 0 ||
946 params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) {
947 hdd_err("Invalid channel: %d", params->channel);
948 return -EINVAL;
949 }
950
951 if (params->dwell_time < 0) {
952 hdd_err("Invalid dwell_time: %d", params->dwell_time);
953 return -EINVAL;
954 }
955
956 if (!hdd_check_and_fill_freq(params->channel, &freq, pdev)) {
957 hdd_err("Invalid channel: %d", params->channel);
958 return -EINVAL;
959 }
960
961 ret = hdd_sendactionframe(adapter, bssid, freq, params->dwell_time,
962 params->len, params->data);
963
964 return ret;
965 }
966
967 /**
968 * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command
969 * @adapter: Adapter upon which the command was received
970 * @command: Command that was received
971 * @total_len: Length of @command
972 *
973 * There are two different versions of the SENDACTIONFRAME command.
974 * Version 1 of the command contains a parameter list that is ASCII
975 * characters whereas version 2 contains a combination of ASCII and
976 * binary payload. Determine if a version 1 or a version 2 command is
977 * being parsed by examining the parameters, and then dispatch the
978 * parser that is appropriate for the version of the command.
979 *
980 * Return: 0 for success non-zero for failure
981 */
982 static int
hdd_parse_sendactionframe(struct hdd_adapter * adapter,const char * command,int total_len)983 hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command,
984 int total_len)
985 {
986 int ret;
987
988 /*
989 * both versions start with "SENDACTIONFRAME "
990 * v1 has a bssid and other parameters as an ASCII string
991 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME
992 * v2 has a C struct
993 * SENDACTIONFRAME <binary c struct>
994 *
995 * The first field in the v2 struct is also the bssid in ASCII.
996 * But in the case of a v2 message the BSSID is NUL-terminated.
997 * Hence we can peek at that offset to see if this is V1 or V2
998 * SENDACTIONFRAME xx:xx:xx:xx:xx:xx*
999 * 111111111122222222223333
1000 * 0123456789012345678901234567890123
1001 * For both the commands, a valid command must have atleast
1002 * first 34 length of data.
1003 */
1004 if (total_len < 34) {
1005 hdd_err("Invalid command (total_len=%d)", total_len);
1006 return -EINVAL;
1007 }
1008
1009 if (command[33])
1010 ret = hdd_parse_sendactionframe_v1(adapter, command);
1011 else
1012 ret = hdd_parse_sendactionframe_v2(adapter, command, total_len);
1013
1014 return ret;
1015 }
1016
1017 #ifdef FEATURE_WLAN_ESE
1018 /**
1019 * hdd_parse_channellist() - HDD Parse channel list
1020 * @hdd_ctx: hdd context
1021 * @command: Pointer to input channel list
1022 * @channel_freq_list: Pointer to local output array to record
1023 * channel list
1024 * @num_channels: Pointer to number of roam scan channels
1025 *
1026 * This function parses the channel list passed in the format
1027 * SETROAMSCANCHANNELS<space><Number of channels><space>Channel 1<space>
1028 * Channel 2<space>Channel N
1029 * if the Number of channels (N) does not match with the actual number
1030 * of channels passed then take the minimum of N and count of
1031 * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48,
1032 * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48,
1033 * ignore 5 and take 36, 40, 44 and 48. This function does not take care of
1034 * removing duplicate channels from the list
1035 *
1036 * Return: 0 for success non-zero for failure
1037 */
1038 static int
hdd_parse_channellist(struct hdd_context * hdd_ctx,const uint8_t * command,uint32_t * channel_freq_list,uint8_t * num_channels)1039 hdd_parse_channellist(struct hdd_context *hdd_ctx,
1040 const uint8_t *command,
1041 uint32_t *channel_freq_list,
1042 uint8_t *num_channels)
1043 {
1044 const uint8_t *in_ptr = command;
1045 int temp_int;
1046 int j = 0;
1047 int v = 0;
1048 char buf[32];
1049
1050 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1051 /* no argument after the command */
1052 if (!in_ptr)
1053 return -EINVAL;
1054 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
1055 return -EINVAL;
1056
1057 /* remove empty spaces */
1058 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1059 in_ptr++;
1060
1061 /* no argument followed by spaces */
1062 if ('\0' == *in_ptr)
1063 return -EINVAL;
1064
1065 /* get the first argument ie the number of channels */
1066 v = sscanf(in_ptr, "%31s ", buf);
1067 if (1 != v)
1068 return -EINVAL;
1069
1070 v = kstrtos32(buf, 10, &temp_int);
1071 if ((v < 0) ||
1072 (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN))
1073 return -EINVAL;
1074
1075 *num_channels = temp_int;
1076
1077 hdd_debug("Number of channels are: %d", *num_channels);
1078
1079 for (j = 0; j < (*num_channels); j++) {
1080 /*
1081 * in_ptr pointing to the beginning of first space after number
1082 * of channels
1083 */
1084 in_ptr = strpbrk(in_ptr, " ");
1085 /* no channel list after the number of channels argument */
1086 if (!in_ptr) {
1087 if ((j != 0) && (*num_channels == j))
1088 return 0;
1089 else
1090 goto cnt_mismatch;
1091 }
1092
1093 /* remove empty space */
1094 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1095 in_ptr++;
1096
1097 /*
1098 * no channel list after the number of channels
1099 * argument and spaces
1100 */
1101 if ('\0' == *in_ptr) {
1102 if ((j != 0) && (*num_channels == j))
1103 return 0;
1104 else
1105 goto cnt_mismatch;
1106 }
1107
1108 v = sscanf(in_ptr, "%31s ", buf);
1109 if (1 != v)
1110 return -EINVAL;
1111
1112 v = kstrtos32(buf, 10, &temp_int);
1113 if ((v < 0) ||
1114 (temp_int <= 0) ||
1115 (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
1116 return -EINVAL;
1117 }
1118 channel_freq_list[j] =
1119 wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, temp_int);
1120
1121 hdd_debug("Channel %d added to preferred channel list",
1122 channel_freq_list[j]);
1123 }
1124
1125 return 0;
1126
1127 cnt_mismatch:
1128 hdd_debug("Mismatch in ch cnt: %d and num of ch: %d", *num_channels, j);
1129 *num_channels = 0;
1130 return -EINVAL;
1131
1132 }
1133
1134 /**
1135 * hdd_parse_plm_cmd() - HDD Parse Plm command
1136 * @command: Pointer to input data
1137 * @req: Pointer to output struct plm_req
1138 *
1139 * This function parses the plm command passed in the format
1140 * CCXPLMREQ<space><enable><space><dialog_token><space>
1141 * <meas_token><space><num_of_bursts><space><burst_int><space>
1142 * <measu duration><space><burst_len><space><desired_tx_pwr>
1143 * <space><multcast_addr><space><number_of_channels>
1144 * <space><channel_numbers>
1145 *
1146 * Return: 0 for success non-zero for failure
1147 */
hdd_parse_plm_cmd(uint8_t * command,struct plm_req_params * req)1148 static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command,
1149 struct plm_req_params *req)
1150 {
1151 uint8_t *in_ptr = NULL;
1152 int count, content = 0, ret = 0;
1153 char buf[32];
1154
1155 /* move to argument list */
1156 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1157 if (!in_ptr)
1158 return QDF_STATUS_E_FAILURE;
1159
1160 /* no space after the command */
1161 if (SPACE_ASCII_VALUE != *in_ptr)
1162 return QDF_STATUS_E_FAILURE;
1163
1164 /* remove empty spaces */
1165 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1166 in_ptr++;
1167
1168 /* START/STOP PLM req */
1169 ret = sscanf(in_ptr, "%31s ", buf);
1170 if (1 != ret)
1171 return QDF_STATUS_E_FAILURE;
1172
1173 ret = kstrtos32(buf, 10, &content);
1174 if (ret < 0)
1175 return QDF_STATUS_E_FAILURE;
1176
1177 req->enable = content;
1178 in_ptr = strpbrk(in_ptr, " ");
1179
1180 if (!in_ptr)
1181 return QDF_STATUS_E_FAILURE;
1182
1183 /* remove empty spaces */
1184 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1185 in_ptr++;
1186
1187 /* Dialog token of radio meas req containing meas reqIE */
1188 ret = sscanf(in_ptr, "%31s ", buf);
1189 if (1 != ret)
1190 return QDF_STATUS_E_FAILURE;
1191
1192 ret = kstrtos32(buf, 10, &content);
1193 if (ret < 0)
1194 return QDF_STATUS_E_FAILURE;
1195
1196 req->diag_token = content;
1197 hdd_debug("diag token %d", req->diag_token);
1198 in_ptr = strpbrk(in_ptr, " ");
1199
1200 if (!in_ptr)
1201 return QDF_STATUS_E_FAILURE;
1202
1203 /* remove empty spaces */
1204 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1205 in_ptr++;
1206
1207 /* measurement token of meas req IE */
1208 ret = sscanf(in_ptr, "%31s ", buf);
1209 if (1 != ret)
1210 return QDF_STATUS_E_FAILURE;
1211
1212 ret = kstrtos32(buf, 10, &content);
1213 if (ret < 0)
1214 return QDF_STATUS_E_FAILURE;
1215
1216 req->meas_token = content;
1217 hdd_debug("meas token %d", req->meas_token);
1218
1219 hdd_debug("PLM req %s", req->enable ? "START" : "STOP");
1220 if (req->enable) {
1221
1222 in_ptr = strpbrk(in_ptr, " ");
1223
1224 if (!in_ptr)
1225 return QDF_STATUS_E_FAILURE;
1226
1227 /* remove empty spaces */
1228 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1229 in_ptr++;
1230
1231 /* total number of bursts after which STA stops sending */
1232 ret = sscanf(in_ptr, "%31s ", buf);
1233 if (1 != ret)
1234 return QDF_STATUS_E_FAILURE;
1235
1236 ret = kstrtos32(buf, 10, &content);
1237 if (ret < 0)
1238 return QDF_STATUS_E_FAILURE;
1239
1240 if (content < 0)
1241 return QDF_STATUS_E_FAILURE;
1242
1243 req->num_bursts = content;
1244 hdd_debug("num bursts %d", req->num_bursts);
1245 in_ptr = strpbrk(in_ptr, " ");
1246
1247 if (!in_ptr)
1248 return QDF_STATUS_E_FAILURE;
1249
1250 /* remove empty spaces */
1251 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1252 in_ptr++;
1253
1254 /* burst interval in seconds */
1255 ret = sscanf(in_ptr, "%31s ", buf);
1256 if (1 != ret)
1257 return QDF_STATUS_E_FAILURE;
1258
1259 ret = kstrtos32(buf, 10, &content);
1260 if (ret < 0)
1261 return QDF_STATUS_E_FAILURE;
1262
1263 if (content <= 0)
1264 return QDF_STATUS_E_FAILURE;
1265
1266 req->burst_int = content;
1267 hdd_debug("burst int %d", req->burst_int);
1268 in_ptr = strpbrk(in_ptr, " ");
1269
1270 if (!in_ptr)
1271 return QDF_STATUS_E_FAILURE;
1272
1273 /* remove empty spaces */
1274 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1275 in_ptr++;
1276
1277 /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */
1278 ret = sscanf(in_ptr, "%31s ", buf);
1279 if (1 != ret)
1280 return QDF_STATUS_E_FAILURE;
1281
1282 ret = kstrtos32(buf, 10, &content);
1283 if (ret < 0)
1284 return QDF_STATUS_E_FAILURE;
1285
1286 if (content <= 0)
1287 return QDF_STATUS_E_FAILURE;
1288
1289 req->meas_duration = content;
1290 hdd_debug("meas duration %d", req->meas_duration);
1291 in_ptr = strpbrk(in_ptr, " ");
1292
1293 if (!in_ptr)
1294 return QDF_STATUS_E_FAILURE;
1295
1296 /* remove empty spaces */
1297 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1298 in_ptr++;
1299
1300 /* burst length of PLM bursts */
1301 ret = sscanf(in_ptr, "%31s ", buf);
1302 if (1 != ret)
1303 return QDF_STATUS_E_FAILURE;
1304
1305 ret = kstrtos32(buf, 10, &content);
1306 if (ret < 0)
1307 return QDF_STATUS_E_FAILURE;
1308
1309 if (content <= 0)
1310 return QDF_STATUS_E_FAILURE;
1311
1312 req->burst_len = content;
1313 hdd_debug("burst len %d", req->burst_len);
1314 in_ptr = strpbrk(in_ptr, " ");
1315
1316 if (!in_ptr)
1317 return QDF_STATUS_E_FAILURE;
1318
1319 /* remove empty spaces */
1320 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1321 in_ptr++;
1322
1323 /* desired tx power for transmission of PLM bursts */
1324 ret = sscanf(in_ptr, "%31s ", buf);
1325 if (1 != ret)
1326 return QDF_STATUS_E_FAILURE;
1327
1328 ret = kstrtos32(buf, 10, &content);
1329 if (ret < 0)
1330 return QDF_STATUS_E_FAILURE;
1331
1332 if (content <= 0)
1333 return QDF_STATUS_E_FAILURE;
1334
1335 req->desired_tx_pwr = content;
1336 hdd_debug("desired tx pwr %d", req->desired_tx_pwr);
1337
1338 for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) {
1339 in_ptr = strpbrk(in_ptr, " ");
1340
1341 if (!in_ptr)
1342 return QDF_STATUS_E_FAILURE;
1343
1344 /* remove empty spaces */
1345 while ((SPACE_ASCII_VALUE == *in_ptr)
1346 && ('\0' != *in_ptr))
1347 in_ptr++;
1348
1349 ret = sscanf(in_ptr, "%31s ", buf);
1350 if (1 != ret)
1351 return QDF_STATUS_E_FAILURE;
1352
1353 ret = kstrtos32(buf, 16, &content);
1354 if (ret < 0)
1355 return QDF_STATUS_E_FAILURE;
1356
1357 req->mac_addr.bytes[count] = content;
1358 }
1359
1360 hdd_debug("MAC addr " QDF_MAC_ADDR_FMT,
1361 QDF_MAC_ADDR_REF(req->mac_addr.bytes));
1362
1363 in_ptr = strpbrk(in_ptr, " ");
1364
1365 if (!in_ptr)
1366 return QDF_STATUS_E_FAILURE;
1367
1368 /* remove empty spaces */
1369 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1370 in_ptr++;
1371
1372 /* number of channels */
1373 ret = sscanf(in_ptr, "%31s ", buf);
1374 if (1 != ret)
1375 return QDF_STATUS_E_FAILURE;
1376
1377 ret = kstrtos32(buf, 10, &content);
1378 if (ret < 0)
1379 return QDF_STATUS_E_FAILURE;
1380
1381 if (content < 0)
1382 return QDF_STATUS_E_FAILURE;
1383
1384 content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN);
1385 req->plm_num_ch = content;
1386 hdd_debug("num ch: %d", req->plm_num_ch);
1387
1388 /* Channel numbers */
1389 for (count = 0; count < req->plm_num_ch; count++) {
1390 in_ptr = strpbrk(in_ptr, " ");
1391
1392 if (!in_ptr)
1393 return QDF_STATUS_E_FAILURE;
1394
1395 /* remove empty spaces */
1396 while ((SPACE_ASCII_VALUE == *in_ptr)
1397 && ('\0' != *in_ptr))
1398 in_ptr++;
1399
1400 ret = sscanf(in_ptr, "%31s ", buf);
1401 if (1 != ret)
1402 return QDF_STATUS_E_FAILURE;
1403
1404 ret = kstrtos32(buf, 10, &content);
1405 if (ret < 0 || content <= 0 ||
1406 content > WNI_CFG_CURRENT_CHANNEL_STAMAX)
1407 return QDF_STATUS_E_FAILURE;
1408
1409 req->plm_ch_freq_list[count] =
1410 cds_chan_to_freq(content);
1411 hdd_debug(" ch-freq- %d", req->plm_ch_freq_list[count]);
1412 }
1413 }
1414 /* If PLM START */
1415 return QDF_STATUS_SUCCESS;
1416 }
1417 #endif
1418
1419 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
1420 /**
1421 * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow
1422 * @cookie: callback context
1423 * @is_success: suspend status of ext wow
1424 *
1425 * Return: none
1426 */
wlan_hdd_ready_to_extwow(void * cookie,bool is_success)1427 static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success)
1428 {
1429 struct osif_request *request = NULL;
1430 struct enable_ext_wow_priv *priv = NULL;
1431
1432 request = osif_request_get(cookie);
1433 if (!request) {
1434 hdd_err("obsolete request");
1435 return;
1436 }
1437 priv = osif_request_priv(request);
1438 priv->ext_wow_should_suspend = is_success;
1439
1440 osif_request_complete(request);
1441 osif_request_put(request);
1442 }
1443
hdd_enable_ext_wow(struct hdd_adapter * adapter,tpSirExtWoWParams arg_params)1444 static int hdd_enable_ext_wow(struct hdd_adapter *adapter,
1445 tpSirExtWoWParams arg_params)
1446 {
1447 tSirExtWoWParams params;
1448 QDF_STATUS status;
1449 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1450 int rc;
1451 struct enable_ext_wow_priv *priv = NULL;
1452 struct osif_request *request = NULL;
1453 void *cookie = NULL;
1454 struct osif_request_params hdd_params = {
1455 .priv_size = sizeof(*priv),
1456 .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW,
1457 };
1458
1459 qdf_mem_copy(¶ms, arg_params, sizeof(params));
1460
1461 request = osif_request_alloc(&hdd_params);
1462 if (!request) {
1463 hdd_err("Request Allocation Failure");
1464 return -ENOMEM;
1465 }
1466 cookie = osif_request_cookie(request);
1467
1468 status = sme_configure_ext_wow(hdd_ctx->mac_handle, ¶ms,
1469 &wlan_hdd_ready_to_extwow,
1470 cookie);
1471 if (QDF_STATUS_SUCCESS != status) {
1472 hdd_err("sme_configure_ext_wow returned failure %d",
1473 status);
1474 rc = -EPERM;
1475 goto exit;
1476 }
1477
1478 rc = osif_request_wait_for_response(request);
1479 if (rc) {
1480 hdd_err("Failed to get ready to extwow");
1481 rc = -EPERM;
1482 goto exit;
1483 }
1484
1485 priv = osif_request_priv(request);
1486 if (!priv->ext_wow_should_suspend) {
1487 hdd_err("Received ready to ExtWoW failure");
1488 rc = -EPERM;
1489 goto exit;
1490 }
1491
1492 if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) {
1493 hdd_info("Received ready to ExtWoW. Going to suspend");
1494
1495 rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
1496 if (rc < 0) {
1497 hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d",
1498 rc);
1499 goto exit;
1500 }
1501 rc = wlan_hdd_bus_suspend();
1502 if (rc) {
1503 hdd_err("wlan_hdd_bus_suspend failed, status = %d",
1504 rc);
1505 wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
1506 goto exit;
1507 }
1508 }
1509
1510 exit:
1511 osif_request_put(request);
1512 return rc;
1513 }
1514
hdd_enable_ext_wow_parser(struct hdd_adapter * adapter,int vdev_id,int value)1515 static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id,
1516 int value)
1517 {
1518 tSirExtWoWParams params;
1519 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1520 int rc;
1521 uint8_t pin1, pin2;
1522
1523 rc = wlan_hdd_validate_context(hdd_ctx);
1524 if (rc)
1525 return rc;
1526
1527 if (value < EXT_WOW_TYPE_APP_TYPE1 ||
1528 value > EXT_WOW_TYPE_APP_TYPE1_2) {
1529 hdd_err("Invalid type: %d", value);
1530 return -EINVAL;
1531 }
1532
1533 if (value == EXT_WOW_TYPE_APP_TYPE1 &&
1534 hdd_ctx->is_extwow_app_type1_param_set)
1535 params.type = value;
1536 else if (value == EXT_WOW_TYPE_APP_TYPE2 &&
1537 hdd_ctx->is_extwow_app_type2_param_set)
1538 params.type = value;
1539 else if (value == EXT_WOW_TYPE_APP_TYPE1_2 &&
1540 hdd_ctx->is_extwow_app_type1_param_set &&
1541 hdd_ctx->is_extwow_app_type2_param_set)
1542 params.type = value;
1543 else {
1544 hdd_err("Set app params before enable it value %d",
1545 value);
1546 return -EINVAL;
1547 }
1548
1549 params.vdev_id = vdev_id;
1550 pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc);
1551 pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc);
1552 params.wakeup_pin_num = pin1 | (pin2 << 8);
1553
1554 return hdd_enable_ext_wow(adapter, ¶ms);
1555 }
1556
hdd_set_app_type1_params(mac_handle_t mac_handle,tpSirAppType1Params arg_params)1557 static int hdd_set_app_type1_params(mac_handle_t mac_handle,
1558 tpSirAppType1Params arg_params)
1559 {
1560 tSirAppType1Params params;
1561 QDF_STATUS status;
1562
1563 qdf_mem_copy(¶ms, arg_params, sizeof(params));
1564
1565 status = sme_configure_app_type1_params(mac_handle, ¶ms);
1566 if (QDF_STATUS_SUCCESS != status) {
1567 hdd_err("sme_configure_app_type1_params returned failure %d",
1568 status);
1569 return -EPERM;
1570 }
1571
1572 return 0;
1573 }
1574
hdd_set_app_type1_parser(struct hdd_adapter * adapter,char * arg,int len)1575 static int hdd_set_app_type1_parser(struct hdd_adapter *adapter,
1576 char *arg, int len)
1577 {
1578 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1579 char id[20], password[20];
1580 tSirAppType1Params params;
1581 int rc;
1582
1583 rc = wlan_hdd_validate_context(hdd_ctx);
1584 if (rc)
1585 return rc;
1586
1587 if (2 != sscanf(arg, "%8s %16s", id, password)) {
1588 hdd_err("Invalid Number of arguments");
1589 return -EINVAL;
1590 }
1591
1592 memset(¶ms, 0, sizeof(tSirAppType1Params));
1593 params.vdev_id = adapter->deflink->vdev_id;
1594 qdf_copy_macaddr(¶ms.wakee_mac_addr, &adapter->mac_addr);
1595
1596 params.id_length = strlen(id);
1597 qdf_mem_copy(params.identification_id, id, params.id_length);
1598 params.pass_length = strlen(password);
1599 qdf_mem_copy(params.password, password, params.pass_length);
1600
1601 hdd_debug("%d "QDF_MAC_ADDR_FMT" %.8s %u %.16s %u",
1602 params.vdev_id,
1603 QDF_MAC_ADDR_REF(params.wakee_mac_addr.bytes),
1604 params.identification_id, params.id_length,
1605 params.password, params.pass_length);
1606
1607 return hdd_set_app_type1_params(hdd_ctx->mac_handle, ¶ms);
1608 }
1609
hdd_set_app_type2_params(mac_handle_t mac_handle,tpSirAppType2Params arg_params)1610 static int hdd_set_app_type2_params(mac_handle_t mac_handle,
1611 tpSirAppType2Params arg_params)
1612 {
1613 tSirAppType2Params params;
1614 QDF_STATUS status;
1615
1616 qdf_mem_copy(¶ms, arg_params, sizeof(params));
1617
1618 status = sme_configure_app_type2_params(mac_handle, ¶ms);
1619 if (QDF_STATUS_SUCCESS != status) {
1620 hdd_err("sme_configure_app_type2_params returned failure %d",
1621 status);
1622 return -EPERM;
1623 }
1624
1625 return 0;
1626 }
1627
hdd_set_app_type2_parser(struct hdd_adapter * adapter,char * arg,int len)1628 static int hdd_set_app_type2_parser(struct hdd_adapter *adapter,
1629 char *arg, int len)
1630 {
1631 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1632 char mac_addr[20], rc4_key[20];
1633 unsigned int gateway_mac[QDF_MAC_ADDR_SIZE];
1634 tSirAppType2Params params;
1635 int ret;
1636
1637 ret = wlan_hdd_validate_context(hdd_ctx);
1638 if (ret)
1639 return ret;
1640
1641 memset(¶ms, 0, sizeof(tSirAppType2Params));
1642
1643 ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u",
1644 mac_addr, rc4_key, (unsigned int *)¶ms.ip_id,
1645 (unsigned int *)¶ms.ip_device_ip,
1646 (unsigned int *)¶ms.ip_server_ip,
1647 (unsigned int *)¶ms.tcp_seq,
1648 (unsigned int *)¶ms.tcp_ack_seq,
1649 (uint16_t *)¶ms.tcp_src_port,
1650 (uint16_t *)¶ms.tcp_dst_port,
1651 (unsigned int *)¶ms.keepalive_init,
1652 (unsigned int *)¶ms.keepalive_min,
1653 (unsigned int *)¶ms.keepalive_max,
1654 (unsigned int *)¶ms.keepalive_inc,
1655 (unsigned int *)¶ms.tcp_tx_timeout_val,
1656 (unsigned int *)¶ms.tcp_rx_timeout_val);
1657
1658 if (ret != 15 && ret != 7) {
1659 hdd_err("Invalid Number of arguments");
1660 return -EINVAL;
1661 }
1662
1663 if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
1664 &gateway_mac[0], &gateway_mac[1], &gateway_mac[2],
1665 &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) {
1666 hdd_err("Invalid MacAddress Input %s", mac_addr);
1667 return -EINVAL;
1668 }
1669
1670 if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT ||
1671 params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) {
1672 hdd_err("Invalid TCP Port Number");
1673 return -EINVAL;
1674 }
1675
1676 qdf_mem_copy(¶ms.gateway_mac.bytes, (uint8_t *) &gateway_mac,
1677 QDF_MAC_ADDR_SIZE);
1678
1679 params.rc4_key_len = strlen(rc4_key);
1680 qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len);
1681
1682 params.vdev_id = adapter->deflink->vdev_id;
1683
1684 if (!params.tcp_src_port)
1685 params.tcp_src_port =
1686 ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc);
1687
1688 if (!params.tcp_dst_port)
1689 params.tcp_dst_port =
1690 ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc);
1691
1692 if (!params.keepalive_init)
1693 params.keepalive_init =
1694 ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc);
1695
1696 if (!params.keepalive_min)
1697 params.keepalive_min =
1698 ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc);
1699
1700 if (!params.keepalive_max)
1701 params.keepalive_max =
1702 ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc);
1703
1704 if (!params.keepalive_inc)
1705 params.keepalive_inc =
1706 ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc);
1707
1708 if (!params.tcp_tx_timeout_val)
1709 params.tcp_tx_timeout_val =
1710 ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc);
1711
1712 if (!params.tcp_rx_timeout_val)
1713 params.tcp_rx_timeout_val =
1714 ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc);
1715
1716 hdd_debug(QDF_MAC_ADDR_FMT" %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u",
1717 QDF_MAC_ADDR_REF(gateway_mac), rc4_key, params.ip_id,
1718 params.ip_device_ip, params.ip_server_ip, params.tcp_seq,
1719 params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port,
1720 params.keepalive_init, params.keepalive_min,
1721 params.keepalive_max, params.keepalive_inc,
1722 params.tcp_tx_timeout_val, params.tcp_rx_timeout_val);
1723
1724 return hdd_set_app_type2_params(hdd_ctx->mac_handle, ¶ms);
1725 }
1726 #endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
1727
1728 /**
1729 * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command
1730 * @command: Pointer to MAXTXPOWER command
1731 * @tx_power: Pointer to tx power
1732 *
1733 * This function parses the MAXTXPOWER command passed in the format
1734 * MAXTXPOWER<space>X(Tx power in dbm)
1735 *
1736 * For example input commands:
1737 * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm
1738 * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm
1739 *
1740 * Return: 0 for success non-zero for failure
1741 */
hdd_parse_setmaxtxpower_command(uint8_t * command,int * tx_power)1742 static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power)
1743 {
1744 uint8_t *in_ptr = command;
1745 int temp_int;
1746 int v = 0;
1747 *tx_power = 0;
1748
1749 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
1750 /* no argument after the command */
1751 if (!in_ptr)
1752 return -EINVAL;
1753 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
1754 return -EINVAL;
1755
1756 /* remove empty spaces */
1757 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
1758 in_ptr++;
1759
1760 /* no argument followed by spaces */
1761 if ('\0' == *in_ptr)
1762 return 0;
1763
1764 v = kstrtos32(in_ptr, 10, &temp_int);
1765
1766 /* Range checking for passed parameter */
1767 if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER))
1768 return -EINVAL;
1769
1770 *tx_power = temp_int;
1771
1772 hdd_debug("SETMAXTXPOWER: %d", *tx_power);
1773
1774 return 0;
1775 } /* End of hdd_parse_setmaxtxpower_command */
1776
1777 #ifdef CONFIG_BAND_6GHZ
hdd_get_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1778 static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1779 uint8_t *command, char *extra, uint8_t n,
1780 uint8_t *len)
1781 {
1782 uint32_t val = 0;
1783 QDF_STATUS status = QDF_STATUS_E_INVAL;
1784
1785 if (strncmp(command, "GETDWELLTIME 6G MAX", 19) == 0) {
1786 status = ucfg_scan_cfg_get_active_6g_dwelltime(psoc, &val);
1787 hdd_debug("active 6g dwelltime:%d", val);
1788 if (QDF_IS_STATUS_SUCCESS(status))
1789 *len = scnprintf(extra, n, "GETDWELLTIME 6G MAX %u\n",
1790 val);
1791 } else if (strncmp(command, "GETDWELLTIME PASSIVE 6G MAX", 27) == 0) {
1792 status = ucfg_scan_cfg_get_passive_6g_dwelltime(psoc, &val);
1793 hdd_debug("passive 6g dwelltime:%d", val);
1794 if (QDF_IS_STATUS_SUCCESS(status))
1795 *len = scnprintf(extra, n,
1796 "GETDWELLTIME PASSIVE 6G MAX %u\n",
1797 val);
1798 }
1799
1800 return qdf_status_to_os_return(status);
1801 }
1802
hdd_set_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command)1803 static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1804 uint8_t *command)
1805 {
1806 uint8_t *value = command;
1807 int temp = 0;
1808 uint32_t val = 0;
1809 QDF_STATUS status = QDF_STATUS_E_INVAL;
1810
1811 if (strncmp(command, "SETDWELLTIME 6G MAX", 19) == 0) {
1812 if (drv_cmd_validate(command, 19))
1813 return -EINVAL;
1814
1815 value = value + 20;
1816 temp = kstrtou32(value, 10, &val);
1817 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_6G_CHANNEL_TIME,
1818 val)) {
1819 hdd_err_rl("argument passed for SETDWELLTIME 6G MAX is incorrect");
1820 return -EFAULT;
1821 }
1822 status = ucfg_scan_cfg_set_active_6g_dwelltime(psoc, val);
1823 } else if (strncmp(command, "SETDWELLTIME PASSIVE 6G MAX", 27) == 0) {
1824 if (drv_cmd_validate(command, 27))
1825 return -EINVAL;
1826
1827 value = value + 28;
1828 temp = kstrtou32(value, 10, &val);
1829 if (temp || !cfg_in_range(CFG_PASSIVE_MAX_6G_CHANNEL_TIME,
1830 val)) {
1831 hdd_err_rl("argument passed for SETDWELLTIME PASSIVE 6G MAX is incorrect");
1832 return -EFAULT;
1833 }
1834 status = ucfg_scan_cfg_set_passive_6g_dwelltime(psoc, val);
1835 }
1836
1837 return qdf_status_to_os_return(status);
1838 }
1839 #else
hdd_get_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1840 static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1841 uint8_t *command, char *extra, uint8_t n,
1842 uint8_t *len)
1843 {
1844 return -EINVAL;
1845 }
1846
hdd_set_dwell_time_6g(struct wlan_objmgr_psoc * psoc,uint8_t * command)1847 static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc,
1848 uint8_t *command)
1849 {
1850 return -EINVAL;
1851 }
1852 #endif
1853
hdd_get_dwell_time(struct wlan_objmgr_psoc * psoc,uint8_t * command,char * extra,uint8_t n,uint8_t * len)1854 static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command,
1855 char *extra, uint8_t n, uint8_t *len)
1856 {
1857 uint32_t val = 0;
1858
1859 if (!psoc || !command || !extra || !len) {
1860 hdd_err("argument passed for GETDWELLTIME is incorrect");
1861 return -EINVAL;
1862 }
1863
1864 if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) {
1865 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
1866 hdd_debug("active max dwelltime:%d", val);
1867 *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val);
1868 return 0;
1869 }
1870 if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) {
1871 ucfg_scan_cfg_get_passive_dwelltime(psoc, &val);
1872 hdd_debug("passive dwelltime:%d", val);
1873 *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n",
1874 val);
1875 return 0;
1876 }
1877 if (strncmp(command, "GETDWELLTIME 2G MAX", 19) == 0) {
1878 ucfg_scan_cfg_get_active_2g_dwelltime(psoc, &val);
1879 hdd_debug("active 2g dwelltime:%d", val);
1880 *len = scnprintf(extra, n, "GETDWELLTIME 2G MAX %u\n",
1881 val);
1882 return 0;
1883 }
1884 if (strncmp(command, "GETDWELLTIME", 12) == 0) {
1885 ucfg_scan_cfg_get_active_dwelltime(psoc, &val);
1886 hdd_debug("active dwelltime:%d", val);
1887 *len = scnprintf(extra, n, "GETDWELLTIME %u\n", val);
1888 return 0;
1889 }
1890
1891 return hdd_get_dwell_time_6g(psoc, command, extra, n, len);
1892 }
1893
hdd_set_dwell_time(struct wlan_objmgr_psoc * psoc,uint8_t * command)1894 static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command)
1895 {
1896 uint8_t *value = command;
1897 int retval = 0, temp = 0;
1898 uint32_t val = 0;
1899
1900 if (!psoc) {
1901 hdd_err("psoc is null");
1902 return -EINVAL;
1903 }
1904
1905 if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) {
1906 if (drv_cmd_validate(command, 23))
1907 return -EINVAL;
1908
1909 value = value + 24;
1910 temp = kstrtou32(value, 10, &val);
1911 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
1912 hdd_err_rl("argument passed for SETDWELLTIME ACTIVE MAX is incorrect");
1913 return -EFAULT;
1914 }
1915 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
1916 } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) {
1917 if (drv_cmd_validate(command, 24))
1918 return -EINVAL;
1919
1920 value = value + 25;
1921 temp = kstrtou32(value, 10, &val);
1922 if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) {
1923 hdd_err_rl("argument passed for SETDWELLTIME PASSIVE MAX is incorrect");
1924 return -EFAULT;
1925 }
1926 ucfg_scan_cfg_set_passive_dwelltime(psoc, val);
1927 } else if (strncmp(command, "SETDWELLTIME 2G MAX", 19) == 0) {
1928 if (drv_cmd_validate(command, 19))
1929 return -EINVAL;
1930
1931 value = value + 20;
1932 temp = kstrtou32(value, 10, &val);
1933 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_2G_CHANNEL_TIME,
1934 val)) {
1935 hdd_err_rl("argument passed for SETDWELLTIME 2G MAX is incorrect");
1936 return -EFAULT;
1937 }
1938 ucfg_scan_cfg_set_active_2g_dwelltime(psoc, val);
1939 } else if (strncmp(command, "SETDWELLTIME", 12) == 0) {
1940 if (drv_cmd_validate(command, 12))
1941 return -EINVAL;
1942
1943 value = value + 13;
1944 temp = kstrtou32(value, 10, &val);
1945 if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) {
1946 hdd_err_rl("argument passed for SETDWELLTIME is incorrect");
1947 return -EFAULT;
1948 }
1949 ucfg_scan_cfg_set_active_dwelltime(psoc, val);
1950 } else {
1951 retval = hdd_set_dwell_time_6g(psoc, command);
1952 }
1953
1954 return retval;
1955 }
1956
1957 struct link_status_priv {
1958 uint8_t link_status;
1959 };
1960
1961 /**
1962 * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters
1963 * @adapter: Adapter upon which the command was received
1964 * @command: ASCII text command that is received
1965 *
1966 * Driver commands:
1967 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX <value>
1968 * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN <value>
1969 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX <value>
1970 * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN <value>
1971 *
1972 * Return: 0 for success non-zero for failure
1973 */
hdd_conc_set_dwell_time(struct hdd_adapter * adapter,uint8_t * command)1974 static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter,
1975 uint8_t *command)
1976 {
1977 u8 *value = command;
1978 int val = 0, temp = 0;
1979 int retval = 0;
1980
1981 if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) {
1982 if (drv_cmd_validate(command, 27)) {
1983 hdd_err("Invalid driver command");
1984 return -EINVAL;
1985 }
1986
1987 value = value + 28;
1988 temp = kstrtou32(value, 10, &val);
1989 if (temp ||
1990 !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) {
1991 hdd_err("CONC ACTIVE MAX value %d incorrect", val);
1992 return -EFAULT;
1993 }
1994 ucfg_scan_cfg_set_conc_active_dwelltime(
1995 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
1996 } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) {
1997 if (drv_cmd_validate(command, 28)) {
1998 hdd_err("Invalid driver command");
1999 return -EINVAL;
2000 }
2001
2002 value = value + 29;
2003 temp = kstrtou32(value, 10, &val);
2004 if (temp ||
2005 !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) {
2006 hdd_err("CONC PASSIVE MAX val %d incorrect", val);
2007 return -EFAULT;
2008 }
2009 ucfg_scan_cfg_set_conc_passive_dwelltime(
2010 (WLAN_HDD_GET_CTX(adapter))->psoc, val);
2011 } else {
2012 retval = -EINVAL;
2013 }
2014
2015 return retval;
2016 }
2017
hdd_enable_unit_test_commands(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx)2018 static int hdd_enable_unit_test_commands(struct hdd_adapter *adapter,
2019 struct hdd_context *hdd_ctx)
2020 {
2021 enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev);
2022 u32 arg[3];
2023 QDF_STATUS status;
2024
2025 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
2026 hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
2027 return -EPERM;
2028
2029 if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) {
2030 hdd_err_rl("Invalid vdev id");
2031 return -EINVAL;
2032 }
2033
2034 if (bus_type == PLD_BUS_TYPE_PCIE) {
2035 arg[0] = 360;
2036 arg[1] = 1;
2037
2038 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2039 WLAN_MODULE_TX,
2040 2,
2041 arg);
2042 if (status != QDF_STATUS_SUCCESS)
2043 return qdf_status_to_os_return(status);
2044
2045 arg[0] = 361;
2046 arg[1] = 1;
2047
2048 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2049 WLAN_MODULE_TX,
2050 2,
2051 arg);
2052 if (status != QDF_STATUS_SUCCESS)
2053 return qdf_status_to_os_return(status);
2054
2055 arg[0] = 84;
2056 arg[1] = 1;
2057 arg[2] = 1;
2058
2059 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2060 WLAN_MODULE_TX,
2061 3,
2062 arg);
2063 if (status != QDF_STATUS_SUCCESS)
2064 return qdf_status_to_os_return(status);
2065
2066 if (hdd_ctx->target_type == TARGET_TYPE_QCA6390) {
2067 arg[0] = 37;
2068 arg[1] = 3000;
2069
2070 status = sme_send_unit_test_cmd(
2071 adapter->deflink->vdev_id,
2072 WLAN_MODULE_RX, 2, arg);
2073 if (status != QDF_STATUS_SUCCESS)
2074 return qdf_status_to_os_return(status);
2075 }
2076
2077 if (hdd_ctx->target_type == TARGET_TYPE_QCA6490) {
2078 arg[0] = 44;
2079 arg[1] = 3000;
2080
2081 status = sme_send_unit_test_cmd(
2082 adapter->deflink->vdev_id,
2083 WLAN_MODULE_RX, 2, arg);
2084 if (status != QDF_STATUS_SUCCESS)
2085 return qdf_status_to_os_return(status);
2086 }
2087 } else if (bus_type == PLD_BUS_TYPE_SNOC) {
2088 arg[0] = 7;
2089 arg[1] = 1;
2090
2091 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2092 0x44,
2093 2,
2094 arg);
2095 if (status != QDF_STATUS_SUCCESS)
2096 return qdf_status_to_os_return(status);
2097 } else {
2098 return -EINVAL;
2099 }
2100 return 0;
2101 }
2102
hdd_disable_unit_test_commands(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx)2103 static int hdd_disable_unit_test_commands(struct hdd_adapter *adapter,
2104 struct hdd_context *hdd_ctx)
2105 {
2106 enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev);
2107 u32 arg[2];
2108 QDF_STATUS status;
2109
2110 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE ||
2111 hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
2112 return -EPERM;
2113
2114 if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) {
2115 hdd_err_rl("Invalid vdev id");
2116 return -EINVAL;
2117 }
2118
2119 if (bus_type == PLD_BUS_TYPE_PCIE) {
2120 arg[0] = 360;
2121 arg[1] = 0;
2122
2123 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2124 WLAN_MODULE_TX,
2125 2,
2126 arg);
2127 if (status != QDF_STATUS_SUCCESS)
2128 return qdf_status_to_os_return(status);
2129
2130 arg[0] = 361;
2131 arg[1] = 0;
2132
2133 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2134 WLAN_MODULE_TX,
2135 2,
2136 arg);
2137 if (status != QDF_STATUS_SUCCESS)
2138 return qdf_status_to_os_return(status);
2139
2140 arg[0] = 44;
2141 arg[1] = 0;
2142
2143 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2144 WLAN_MODULE_RX,
2145 2,
2146 arg);
2147 if (status != QDF_STATUS_SUCCESS)
2148 return qdf_status_to_os_return(status);
2149
2150 arg[0] = 84;
2151 arg[1] = 0;
2152
2153 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2154 WLAN_MODULE_RX,
2155 2,
2156 arg);
2157 if (status != QDF_STATUS_SUCCESS)
2158 return qdf_status_to_os_return(status);
2159
2160 } else if (bus_type == PLD_BUS_TYPE_SNOC) {
2161 arg[0] = 7;
2162 arg[1] = 0;
2163
2164 status = sme_send_unit_test_cmd(adapter->deflink->vdev_id,
2165 0x44,
2166 2,
2167 arg);
2168 if (status != QDF_STATUS_SUCCESS)
2169 return qdf_status_to_os_return(status);
2170 } else {
2171 return -EINVAL;
2172 }
2173 return 0;
2174 }
2175
hdd_get_link_status_cb(uint8_t status,void * context)2176 static void hdd_get_link_status_cb(uint8_t status, void *context)
2177 {
2178 struct osif_request *request;
2179 struct link_status_priv *priv;
2180
2181 request = osif_request_get(context);
2182 if (!request) {
2183 hdd_err("Obsolete request");
2184 return;
2185 }
2186
2187 priv = osif_request_priv(request);
2188 priv->link_status = status;
2189 osif_request_complete(request);
2190 osif_request_put(request);
2191 }
2192
2193 /**
2194 * wlan_hdd_get_link_status() - get link status
2195 * @adapter: pointer to the adapter
2196 *
2197 * This function sends a request to query the link status and waits
2198 * on a timer to invoke the callback. if the callback is invoked then
2199 * latest link status shall be returned or otherwise cached value
2200 * will be returned.
2201 *
2202 * Return: On success, link status shall be returned.
2203 * On error or not associated, link status 0 will be returned.
2204 */
wlan_hdd_get_link_status(struct hdd_adapter * adapter)2205 static int wlan_hdd_get_link_status(struct hdd_adapter *adapter)
2206 {
2207 struct hdd_station_ctx *sta_ctx;
2208 QDF_STATUS status;
2209 int ret;
2210 void *cookie;
2211 struct osif_request *request;
2212 struct link_status_priv *priv;
2213 static const struct osif_request_params params = {
2214 .priv_size = sizeof(*priv),
2215 .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
2216 };
2217
2218 if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
2219 hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
2220 cds_get_driver_state());
2221 return 0;
2222 }
2223
2224 if ((QDF_STA_MODE != adapter->device_mode) &&
2225 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
2226 hdd_warn("Unsupported in mode %s(%d)",
2227 qdf_opmode_str(adapter->device_mode),
2228 adapter->device_mode);
2229 return 0;
2230 }
2231
2232 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
2233 if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
2234 /* If not associated, then expected link status return
2235 * value is 0
2236 */
2237 hdd_warn("Not associated!");
2238 return 0;
2239 }
2240
2241 request = osif_request_alloc(¶ms);
2242 if (!request) {
2243 hdd_err("Request allocation failure");
2244 return 0;
2245 }
2246 cookie = osif_request_cookie(request);
2247
2248 status = sme_get_link_status(adapter->hdd_ctx->mac_handle,
2249 hdd_get_link_status_cb,
2250 cookie, adapter->deflink->vdev_id);
2251 if (QDF_STATUS_SUCCESS != status) {
2252 hdd_err("Unable to retrieve link status");
2253 /* return a cached value */
2254 } else {
2255 /* request is sent -- wait for the response */
2256 ret = osif_request_wait_for_response(request);
2257 if (ret) {
2258 hdd_err("SME timed out while retrieving link status");
2259 /* return a cached value */
2260 } else {
2261 /* update the adapter with the fresh results */
2262 priv = osif_request_priv(request);
2263 adapter->link_status = priv->link_status;
2264 }
2265 }
2266
2267 /*
2268 * either we never sent a request, we sent a request and
2269 * received a response or we sent a request and timed out.
2270 * regardless we are done with the request.
2271 */
2272 osif_request_put(request);
2273
2274 /* either callback updated adapter stats or it has cached data */
2275 return adapter->link_status;
2276 }
2277
2278 #ifdef FEATURE_WLAN_ESE
2279 /**
2280 * hdd_parse_ese_beacon_req() - Parse ese beacon request
2281 * @pdev: pdev object
2282 * @command: Pointer to data
2283 * @req: Output pointer to store parsed ie information
2284 *
2285 * This function parses the ese beacon request passed in the format
2286 * CCXBEACONREQ<space><Number of fields><space><Measurement token>
2287 * <space>Channel 1<space>Scan Mode <space>Meas Duration<space>Channel N
2288 * <space>Scan Mode N<space>Meas Duration N
2289 *
2290 * If the Number of bcn req fields (N) does not match with the
2291 * actual number of fields passed then take N.
2292 * <Meas Token><Channel><Scan Mode> and <Meas Duration> are treated
2293 * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40.
2294 * This function does not take care of removing duplicate channels from the
2295 * list
2296 *
2297 * Return: 0 for success non-zero for failure
2298 */
hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev * pdev,uint8_t * command,tCsrEseBeaconReq * req)2299 static int hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev *pdev,
2300 uint8_t *command,
2301 tCsrEseBeaconReq *req)
2302 {
2303 uint8_t *in_ptr = command;
2304 uint8_t input = 0;
2305 uint32_t temp_int = 0;
2306 int j = 0, i = 0, v = 0;
2307 char buf[32];
2308
2309 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
2310 if (!in_ptr) /* no argument after the command */
2311 return -EINVAL;
2312 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
2313 return -EINVAL;
2314
2315 /* remove empty spaces */
2316 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2317 in_ptr++;
2318
2319 /* no argument followed by spaces */
2320 if ('\0' == *in_ptr)
2321 return -EINVAL;
2322
2323 /* Getting the first argument ie Number of IE fields */
2324 v = sscanf(in_ptr, "%31s ", buf);
2325 if (1 != v)
2326 return -EINVAL;
2327
2328 v = kstrtou8(buf, 10, &input);
2329 if (v < 0)
2330 return -EINVAL;
2331
2332 input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS);
2333 req->numBcnReqIe = input;
2334
2335 hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe);
2336
2337 for (j = 0; j < (req->numBcnReqIe); j++) {
2338 for (i = 0; i < 4; i++) {
2339 /*
2340 * in_ptr pointing to the beginning of 1st space
2341 * after number of ie fields
2342 */
2343 in_ptr = strpbrk(in_ptr, " ");
2344 /* no ie data after the number of ie fields argument */
2345 if (!in_ptr)
2346 return -EINVAL;
2347
2348 /* remove empty space */
2349 while ((SPACE_ASCII_VALUE == *in_ptr)
2350 && ('\0' != *in_ptr))
2351 in_ptr++;
2352
2353 /*
2354 * no ie data after the number of ie fields
2355 * argument and spaces
2356 */
2357 if ('\0' == *in_ptr)
2358 return -EINVAL;
2359
2360 v = sscanf(in_ptr, "%31s ", buf);
2361 if (1 != v)
2362 return -EINVAL;
2363
2364 v = kstrtou32(buf, 10, &temp_int);
2365 if (v < 0)
2366 return -EINVAL;
2367
2368 switch (i) {
2369 case 0: /* Measurement token */
2370 if (!temp_int) {
2371 hdd_err("Invalid Measurement Token: %u",
2372 temp_int);
2373 return -EINVAL;
2374 }
2375 req->bcnReq[j].measurementToken =
2376 temp_int;
2377 break;
2378
2379 case 1: /* Channel number */
2380 if (!temp_int ||
2381 (temp_int >
2382 WNI_CFG_CURRENT_CHANNEL_STAMAX)) {
2383 hdd_err("Invalid Channel Number: %u",
2384 temp_int);
2385 return -EINVAL;
2386 }
2387 req->bcnReq[j].ch_freq =
2388 wlan_reg_legacy_chan_to_freq(pdev, temp_int);
2389 break;
2390
2391 case 2: /* Scan mode */
2392 if ((temp_int < eSIR_PASSIVE_SCAN)
2393 || (temp_int > eSIR_BEACON_TABLE)) {
2394 hdd_err("Invalid Scan Mode: %u Expected{0|1|2}",
2395 temp_int);
2396 return -EINVAL;
2397 }
2398 req->bcnReq[j].scanMode = temp_int;
2399 break;
2400
2401 case 3: /* Measurement duration */
2402 if ((!temp_int
2403 && (req->bcnReq[j].scanMode !=
2404 eSIR_BEACON_TABLE)) ||
2405 (req->bcnReq[j].scanMode ==
2406 eSIR_BEACON_TABLE)) {
2407 hdd_err("Invalid Measurement Duration: %u",
2408 temp_int);
2409 return -EINVAL;
2410 }
2411 req->bcnReq[j].measurementDuration =
2412 temp_int;
2413 break;
2414 }
2415 }
2416 }
2417
2418 for (j = 0; j < req->numBcnReqIe; j++) {
2419 hdd_debug("Index: %d Measurement Token: %u ch_freq: %u Scan Mode: %u Measurement Duration: %u",
2420 j,
2421 req->bcnReq[j].measurementToken,
2422 req->bcnReq[j].ch_freq,
2423 req->bcnReq[j].scanMode,
2424 req->bcnReq[j].measurementDuration);
2425 }
2426
2427 return 0;
2428 }
2429
2430 /**
2431 * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE
2432 * @command: Pointer to input data
2433 * @cckm_ie: Pointer to output cckm Ie
2434 * @cckm_ie_len: Pointer to output cckm ie length
2435 *
2436 * This function parses the SETCCKM IE command
2437 * SETCCKMIE<space><ie data>
2438 *
2439 * Return: 0 for success non-zero for failure
2440 */
hdd_parse_get_cckm_ie(uint8_t * command,uint8_t ** cckm_ie,uint8_t * cckm_ie_len)2441 static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie,
2442 uint8_t *cckm_ie_len)
2443 {
2444 uint8_t *in_ptr = command;
2445 uint8_t *end_ptr;
2446 int j = 0;
2447 int i = 0;
2448 uint8_t temp_u8 = 0;
2449
2450 in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE);
2451 /* no argument after the command */
2452 if (!in_ptr)
2453 return -EINVAL;
2454 else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */
2455 return -EINVAL;
2456
2457 /* remove empty spaces */
2458 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
2459 in_ptr++;
2460 /* no argument followed by spaces */
2461 if ('\0' == *in_ptr)
2462 return -EINVAL;
2463
2464 /* find the length of data */
2465 end_ptr = in_ptr;
2466 while (('\0' != *end_ptr)) {
2467 end_ptr++;
2468 ++(*cckm_ie_len);
2469 }
2470 if (*cckm_ie_len <= 0)
2471 return -EINVAL;
2472 /*
2473 * Allocate the number of bytes based on the number of input characters
2474 * whether it is even or odd.
2475 * if the number of input characters are even, then we need N / 2 byte.
2476 * if the number of input characters are odd, then we need do
2477 * (N + 1) / 2 to compensate rounding off.
2478 * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough.
2479 * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes
2480 */
2481 *cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2);
2482 if (!*cckm_ie)
2483 return -ENOMEM;
2484
2485 /*
2486 * the buffer received from the upper layer is character buffer,
2487 * we need to prepare the buffer taking 2 characters in to a U8 hex
2488 * decimal number for example 7f0000f0...form a buffer to contain
2489 * 7f in 0th location, 00 in 1st and f0 in 3rd location
2490 */
2491 for (i = 0, j = 0; j < *cckm_ie_len; j += 2) {
2492 temp_u8 = (hex_to_bin(in_ptr[j]) << 4) |
2493 (hex_to_bin(in_ptr[j + 1]));
2494 (*cckm_ie)[i++] = temp_u8;
2495 }
2496 *cckm_ie_len = i;
2497 return 0;
2498 }
2499 #endif /* FEATURE_WLAN_ESE */
2500
wlan_hdd_set_mc_rate(struct wlan_hdd_link_info * link_info,int target_rate)2501 int wlan_hdd_set_mc_rate(struct wlan_hdd_link_info *link_info, int target_rate)
2502 {
2503 tSirRateUpdateInd rate_update = {0};
2504 QDF_STATUS status;
2505 struct hdd_adapter *adapter = link_info->adapter;
2506 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2507 bool bval = false;
2508
2509 if (!hdd_ctx) {
2510 hdd_err("HDD context is null");
2511 return -EINVAL;
2512 }
2513 if ((QDF_SAP_MODE != adapter->device_mode) &&
2514 (QDF_STA_MODE != adapter->device_mode)) {
2515 hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)",
2516 qdf_opmode_str(adapter->device_mode),
2517 adapter->device_mode);
2518 hdd_err("SETMCRATE cmd is allowed only in STA or SOFTAP mode");
2519 return -EINVAL;
2520 }
2521
2522 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
2523 if (!QDF_IS_STATUS_SUCCESS(status)) {
2524 hdd_err("unable to get vht_enable2x2");
2525 return -EINVAL;
2526 }
2527 rate_update.nss = (bval == 0) ? 0 : 1;
2528
2529 rate_update.dev_mode = adapter->device_mode;
2530 rate_update.mcastDataRate24GHz = target_rate;
2531 rate_update.mcastDataRate24GHzTxFlag = 1;
2532 rate_update.mcastDataRate5GHz = target_rate;
2533 rate_update.bcastDataRate = -1;
2534 qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr);
2535 hdd_debug("MC Target rate %d, mac = "QDF_MAC_ADDR_FMT", dev_mode %s(%d)",
2536 rate_update.mcastDataRate24GHz,
2537 QDF_MAC_ADDR_REF(rate_update.bssid.bytes),
2538 qdf_opmode_str(adapter->device_mode), adapter->device_mode);
2539 status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update);
2540 if (QDF_STATUS_SUCCESS != status) {
2541 hdd_err("SETMCRATE failed");
2542 return -EFAULT;
2543 }
2544 return 0;
2545 }
2546
drv_cmd_p2p_dev_addr(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2547 static int drv_cmd_p2p_dev_addr(struct wlan_hdd_link_info *link_info,
2548 struct hdd_context *hdd_ctx,
2549 uint8_t *command,
2550 uint8_t command_len,
2551 struct hdd_priv_data *priv_data)
2552 {
2553 struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address;
2554 size_t user_size = qdf_min(sizeof(addr->bytes),
2555 (size_t)priv_data->total_len);
2556
2557 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2558 TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL,
2559 link_info->vdev_id,
2560 (unsigned int)(*(addr->bytes + 2) << 24 |
2561 *(addr->bytes + 3) << 16 |
2562 *(addr->bytes + 4) << 8 |
2563 *(addr->bytes + 5)));
2564
2565
2566 if (copy_to_user(priv_data->buf, addr->bytes, user_size)) {
2567 hdd_err("failed to copy data to user buffer");
2568 return -EFAULT;
2569 }
2570
2571 return 0;
2572 }
2573
2574 /**
2575 * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command
2576 * @link_info: Link info pointer in HDD adapter
2577 * @hdd_ctx: HDD global context
2578 * @command: Entire driver command received from userspace
2579 * @command_len: Length of @command
2580 * @priv_data: Pointer to ioctl private data structure
2581 *
2582 * This is a trivial command handler function which simply forwards the
2583 * command to the actual command processor within the P2P module.
2584 *
2585 * Return: 0 on success, non-zero on failure
2586 */
drv_cmd_p2p_set_noa(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2587 static int drv_cmd_p2p_set_noa(struct wlan_hdd_link_info *link_info,
2588 struct hdd_context *hdd_ctx,
2589 uint8_t *command,
2590 uint8_t command_len,
2591 struct hdd_priv_data *priv_data)
2592 {
2593 return hdd_set_p2p_noa(link_info->adapter->dev, command);
2594 }
2595
2596 /**
2597 * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command
2598 * @link_info: Link info pointer in adapter
2599 * @hdd_ctx: HDD global context
2600 * @command: Entire driver command received from userspace
2601 * @command_len: Length of @command
2602 * @priv_data: Pointer to ioctl private data structure
2603 *
2604 * This is a trivial command handler function which simply forwards the
2605 * command to the actual command processor within the P2P module.
2606 *
2607 * Return: 0 on success, non-zero on failure
2608 */
drv_cmd_p2p_set_ps(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2609 static int drv_cmd_p2p_set_ps(struct wlan_hdd_link_info *link_info,
2610 struct hdd_context *hdd_ctx,
2611 uint8_t *command,
2612 uint8_t command_len,
2613 struct hdd_priv_data *priv_data)
2614 {
2615 return hdd_set_p2p_opps(link_info->adapter->dev, command);
2616 }
2617
drv_cmd_set_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2618 static int drv_cmd_set_band(struct wlan_hdd_link_info *link_info,
2619 struct hdd_context *hdd_ctx,
2620 uint8_t *command,
2621 uint8_t command_len,
2622 struct hdd_priv_data *priv_data)
2623 {
2624 int err;
2625 uint8_t band;
2626 uint32_t band_bitmap;
2627
2628 /*
2629 * Parse the band value passed from userspace. The first 8 bytes
2630 * should be "SETBAND " and the 9th byte should be a UI band value
2631 */
2632 err = kstrtou8(command + command_len + 1, 10, &band);
2633 if (err) {
2634 hdd_err("error %d parsing userspace band parameter", err);
2635 return err;
2636 }
2637
2638 band_bitmap = hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(band);
2639
2640 return hdd_reg_set_band(link_info->adapter->dev, band_bitmap);
2641 }
2642
drv_cmd_set_wmmps(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2643 static int drv_cmd_set_wmmps(struct wlan_hdd_link_info *link_info,
2644 struct hdd_context *hdd_ctx,
2645 uint8_t *command,
2646 uint8_t command_len,
2647 struct hdd_priv_data *priv_data)
2648 {
2649 return hdd_wmmps_helper(link_info->adapter, command);
2650 }
2651
2652 #ifdef CONFIG_BAND_6GHZ
2653 /**
2654 * drv_cmd_get_wifi6e_channels() - Handler for GET_WIFI6E_CHANNELS driver
2655 * command
2656 * @link_info: Link info pointer in adapter
2657 * @hdd_ctx: pointer to hdd context
2658 * @command: command name
2659 * @command_len: command buffer length
2660 * @priv_data: output pointer to hold current country code
2661 *
2662 * Return: On success 0, negative value on error.
2663 */
drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2664 static int drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info *link_info,
2665 struct hdd_context *hdd_ctx,
2666 uint8_t *command,
2667 uint8_t command_len,
2668 struct hdd_priv_data *priv_data)
2669 {
2670 uint8_t power_type;
2671 char extra[SIZE_OF_WIFI6E_CHAN_LIST] = {0};
2672 int i, ret, copied_length = 0;
2673 enum channel_state state;
2674 struct regulatory_channel *chan_list;
2675 size_t max_buf_len = QDF_MIN(priv_data->total_len,
2676 SIZE_OF_WIFI6E_CHAN_LIST);
2677 QDF_STATUS status;
2678
2679 if (wlan_hdd_validate_context(hdd_ctx))
2680 return -EINVAL;
2681
2682 ret = kstrtou8(command + command_len + 1, 10, &power_type);
2683 if (ret) {
2684 hdd_err("error %d parsing userspace 6 GHz power type parameter",
2685 ret);
2686 return -EINVAL;
2687 }
2688
2689 switch (power_type) {
2690 case 0:
2691 power_type = REG_CLI_DEF_LPI;
2692 break;
2693 case 1:
2694 power_type = REG_CLI_DEF_VLP;
2695 break;
2696 case 2:
2697 power_type = REG_CLI_DEF_SP;
2698 break;
2699 default:
2700 hdd_err("The power type : %u, is incorrect", power_type);
2701 return -EINVAL;
2702 }
2703
2704 chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*chan_list));
2705 if (!chan_list)
2706 return -ENOMEM;
2707
2708 status = wlan_reg_get_pwrmode_chan_list(hdd_ctx->pdev, chan_list,
2709 power_type);
2710 if (QDF_IS_STATUS_ERROR(status)) {
2711 hdd_err("Failed to get wifi6e channel list for given power type %u",
2712 power_type);
2713 ret = qdf_status_to_os_return(status);
2714 goto free;
2715 }
2716
2717 for (i = 0; i < NUM_6GHZ_CHANNELS && copied_length < max_buf_len - 1;
2718 i++) {
2719 state = chan_list[i + MIN_6GHZ_CHANNEL].state;
2720 if (state == CHANNEL_STATE_INVALID ||
2721 state == CHANNEL_STATE_DISABLE)
2722 continue;
2723 copied_length += scnprintf(extra + copied_length,
2724 max_buf_len - copied_length, "%u ",
2725 chan_list[i + MIN_6GHZ_CHANNEL].chan_num);
2726 }
2727
2728 if (copied_length == 0) {
2729 hdd_err("No Channel List found for given power type %u",
2730 power_type);
2731 ret = -EINVAL;
2732 goto free;
2733 }
2734
2735 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
2736 hdd_err("failed to copy data to user buffer");
2737 ret = -EFAULT;
2738 goto free;
2739 }
2740
2741 hdd_debug("Power type = %u, Data = %s", power_type, extra);
2742 free:
2743 qdf_mem_free(chan_list);
2744 return ret;
2745 }
2746 #endif
2747
__drv_cmd_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2748 static inline int __drv_cmd_country(struct wlan_hdd_link_info *link_info,
2749 struct hdd_context *hdd_ctx,
2750 uint8_t *command,
2751 uint8_t command_len,
2752 struct hdd_priv_data *priv_data)
2753 {
2754 char *country_code;
2755
2756 country_code = strnchr(command, strlen(command), ' ');
2757 /* no argument after the command */
2758 if (!country_code)
2759 return -EINVAL;
2760
2761 /* no space after the command */
2762 if (*country_code != SPACE_ASCII_VALUE)
2763 return -EINVAL;
2764
2765 country_code++;
2766
2767 /* removing empty spaces */
2768 while ((*country_code == SPACE_ASCII_VALUE) &&
2769 (*country_code != '\0'))
2770 country_code++;
2771
2772 /* no or less than 2 arguments followed by spaces */
2773 if (*country_code == '\0' || *(country_code + 1) == '\0')
2774 return -EINVAL;
2775
2776 return hdd_reg_set_country(hdd_ctx, country_code);
2777 }
2778
drv_cmd_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2779 static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info,
2780 struct hdd_context *hdd_ctx,
2781 uint8_t *command,
2782 uint8_t command_len,
2783 struct hdd_priv_data *priv_data)
2784 {
2785 struct osif_psoc_sync *psoc_sync;
2786 int errno;
2787
2788 errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
2789 if (errno)
2790 return errno;
2791 errno = __drv_cmd_country(link_info, hdd_ctx, command, command_len,
2792 priv_data);
2793
2794 osif_psoc_sync_op_stop(psoc_sync);
2795
2796 return errno;
2797 }
2798
2799 /**
2800 * drv_cmd_get_country() - Helper function to get current county code
2801 * @link_info: Link info pointer in HDD adapter
2802 * @hdd_ctx: pointer to hdd context
2803 * @command: command name
2804 * @command_len: command buffer length
2805 * @priv_data: output pointer to hold current country code
2806 *
2807 * Return: On success 0, negative value on error.
2808 */
drv_cmd_get_country(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2809 static int drv_cmd_get_country(struct wlan_hdd_link_info *link_info,
2810 struct hdd_context *hdd_ctx,
2811 uint8_t *command, uint8_t command_len,
2812 struct hdd_priv_data *priv_data)
2813 {
2814 uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0};
2815 uint8_t cc[REG_ALPHA2_LEN + 1];
2816 int ret = 0, len;
2817
2818 qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN);
2819 cc[REG_ALPHA2_LEN] = '\0';
2820
2821 len = scnprintf(buf, sizeof(buf), "%s %s",
2822 "GETCOUNTRYREV", cc);
2823 hdd_debug("buf = %s", buf);
2824 len = QDF_MIN(priv_data->total_len, len + 1);
2825 if (copy_to_user(priv_data->buf, buf, len)) {
2826 hdd_err("failed to copy data to user buffer");
2827 ret = -EFAULT;
2828 }
2829
2830 return ret;
2831 }
2832
drv_cmd_set_roam_trigger(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2833 static int drv_cmd_set_roam_trigger(struct wlan_hdd_link_info *link_info,
2834 struct hdd_context *hdd_ctx,
2835 uint8_t *command,
2836 uint8_t command_len,
2837 struct hdd_priv_data *priv_data)
2838 {
2839 int ret;
2840 uint8_t *value = command;
2841 int8_t rssi = 0;
2842 uint8_t lookup_threshold = cfg_default(
2843 CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD);
2844 QDF_STATUS status = QDF_STATUS_SUCCESS;
2845
2846 /* Move pointer to ahead of SETROAMTRIGGER<delimiter> */
2847 value = value + command_len + 1;
2848
2849 /* Convert the value from ascii to integer */
2850 ret = kstrtos8(value, 10, &rssi);
2851 if (ret < 0) {
2852 /*
2853 * If the input value is greater than max value of datatype,
2854 * then also kstrtou8 fails
2855 */
2856 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2857 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2858 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
2859 ret = -EINVAL;
2860 goto exit;
2861 }
2862
2863 if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD,
2864 rssi)) {
2865 hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)",
2866 lookup_threshold,
2867 cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD),
2868 cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD));
2869 ret = -EINVAL;
2870 goto exit;
2871 }
2872
2873 lookup_threshold = abs(rssi);
2874
2875 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2876 TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL,
2877 link_info->vdev_id, lookup_threshold);
2878
2879 hdd_debug("Set Roam trigger: Neighbor lookup threshold = %d",
2880 lookup_threshold);
2881
2882 status = sme_set_neighbor_lookup_rssi_threshold(
2883 hdd_ctx->mac_handle,
2884 link_info->vdev_id,
2885 lookup_threshold);
2886 if (QDF_STATUS_SUCCESS != status) {
2887 hdd_err("Failed to set roam trigger, try again");
2888 ret = -EPERM;
2889 goto exit;
2890 }
2891
2892 exit:
2893 return ret;
2894 }
2895
drv_cmd_get_roam_trigger(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2896 static int drv_cmd_get_roam_trigger(struct wlan_hdd_link_info *link_info,
2897 struct hdd_context *hdd_ctx,
2898 uint8_t *command,
2899 uint8_t command_len,
2900 struct hdd_priv_data *priv_data)
2901 {
2902 int ret = 0;
2903 uint8_t lookup_threshold;
2904 int rssi;
2905 char extra[32];
2906 uint8_t len = 0;
2907 QDF_STATUS status;
2908
2909 status = ucfg_cm_get_neighbor_lookup_rssi_threshold(
2910 hdd_ctx->psoc,
2911 link_info->vdev_id,
2912 &lookup_threshold);
2913 if (QDF_IS_STATUS_ERROR(status))
2914 return qdf_status_to_os_return(status);
2915
2916 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2917 TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL,
2918 link_info->vdev_id, lookup_threshold);
2919
2920 hdd_debug("vdev_id: %u, lookup_threshold: %u",
2921 link_info->vdev_id, lookup_threshold);
2922
2923 rssi = (-1) * lookup_threshold;
2924
2925 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
2926 len = QDF_MIN(priv_data->total_len, len + 1);
2927 if (copy_to_user(priv_data->buf, &extra, len)) {
2928 hdd_err("failed to copy data to user buffer");
2929 ret = -EFAULT;
2930 }
2931
2932 return ret;
2933 }
2934
drv_cmd_set_roam_scan_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)2935 static int drv_cmd_set_roam_scan_period(struct wlan_hdd_link_info *link_info,
2936 struct hdd_context *hdd_ctx,
2937 uint8_t *command,
2938 uint8_t command_len,
2939 struct hdd_priv_data *priv_data)
2940 {
2941 int ret = 0;
2942 uint8_t *value = command;
2943 uint8_t roam_scan_period = 0;
2944 uint16_t empty_scan_refresh_period;
2945 bool flag = false, val = false;
2946
2947 ucfg_mlme_get_connection_roaming_ini_present(hdd_ctx->psoc, &val);
2948 if (val) {
2949 flag = true;
2950 empty_scan_refresh_period =
2951 cfg_default(CFG_ROAM_SCAN_FIRST_TIMER) * 1000;
2952 } else {
2953 empty_scan_refresh_period =
2954 cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD);
2955 }
2956
2957 /* input refresh period is in terms of seconds */
2958
2959 /* Move pointer to ahead of SETROAMSCANPERIOD<delimiter> */
2960 value = value + command_len + 1;
2961
2962 /* Convert the value from ascii to integer */
2963 ret = kstrtou8(value, 10, &roam_scan_period);
2964 if (ret < 0) {
2965 /*
2966 * If the input value is greater than max value of datatype,
2967 * then also kstrtou8 fails
2968 */
2969 if (flag)
2970 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2971 cfg_min(CFG_ROAM_SCAN_FIRST_TIMER),
2972 cfg_max(CFG_ROAM_SCAN_FIRST_TIMER));
2973 else
2974 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
2975 (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000),
2976 (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000));
2977 ret = -EINVAL;
2978 goto exit;
2979 }
2980
2981 if (!ucfg_mlme_validate_scan_period(hdd_ctx->psoc,
2982 roam_scan_period * 1000)) {
2983 ret = -EINVAL;
2984 goto exit;
2985 }
2986
2987 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
2988 TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL,
2989 link_info->vdev_id, roam_scan_period);
2990
2991 empty_scan_refresh_period = roam_scan_period * 1000;
2992
2993 hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d",
2994 roam_scan_period);
2995
2996 sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle,
2997 link_info->vdev_id,
2998 empty_scan_refresh_period);
2999
3000 exit:
3001 return ret;
3002 }
3003
drv_cmd_get_roam_scan_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3004 static int drv_cmd_get_roam_scan_period(struct wlan_hdd_link_info *link_info,
3005 struct hdd_context *hdd_ctx,
3006 uint8_t *command,
3007 uint8_t command_len,
3008 struct hdd_priv_data *priv_data)
3009 {
3010 int ret = 0;
3011 uint16_t empty_scan_refresh_period;
3012 char extra[32];
3013 uint8_t len;
3014 QDF_STATUS status;
3015
3016 status = ucfg_cm_get_empty_scan_refresh_period(
3017 hdd_ctx->psoc,
3018 link_info->vdev_id,
3019 &empty_scan_refresh_period);
3020 if (QDF_IS_STATUS_ERROR(status))
3021 return qdf_status_to_os_return(status);
3022
3023 hdd_debug("vdev_id: %u, empty_scan_refresh_period: %u",
3024 link_info->vdev_id, empty_scan_refresh_period);
3025
3026 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3027 TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL,
3028 link_info->vdev_id,
3029 empty_scan_refresh_period);
3030
3031 len = scnprintf(extra, sizeof(extra), "%s %d",
3032 "GETROAMSCANPERIOD",
3033 (empty_scan_refresh_period / 1000));
3034 /* Returned value is in units of seconds */
3035 len = QDF_MIN(priv_data->total_len, len + 1);
3036 if (copy_to_user(priv_data->buf, &extra, len)) {
3037 hdd_err("failed to copy data to user buffer");
3038 ret = -EFAULT;
3039 }
3040
3041 return ret;
3042 }
3043
3044 static int
drv_cmd_set_roam_scan_refresh_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3045 drv_cmd_set_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info,
3046 struct hdd_context *hdd_ctx,
3047 uint8_t *command, uint8_t command_len,
3048 struct hdd_priv_data *priv_data)
3049 {
3050 int ret;
3051 uint8_t *value = command;
3052 uint8_t roam_scan_refresh_period = 0;
3053 uint16_t neighbor_scan_refresh_period =
3054 cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD);
3055
3056 /* input refresh period is in terms of seconds */
3057 /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD<delimiter> */
3058 value = value + command_len + 1;
3059
3060 /* Convert the value from ascii to integer */
3061 ret = kstrtou8(value, 10, &roam_scan_refresh_period);
3062 if (ret < 0) {
3063 /*
3064 * If the input value is greater than max value of datatype,
3065 * then also kstrtou8 fails
3066 */
3067 hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]",
3068 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3069 / 1000),
3070 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3071 / 1000));
3072 ret = -EINVAL;
3073 goto exit;
3074 }
3075
3076 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD,
3077 roam_scan_refresh_period)) {
3078 hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)",
3079 roam_scan_refresh_period,
3080 (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3081 / 1000),
3082 (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD)
3083 / 1000));
3084 ret = -EINVAL;
3085 goto exit;
3086 }
3087 neighbor_scan_refresh_period = roam_scan_refresh_period * 1000;
3088
3089 hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d",
3090 neighbor_scan_refresh_period);
3091
3092 sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle,
3093 link_info->vdev_id,
3094 neighbor_scan_refresh_period);
3095
3096 exit:
3097 return ret;
3098 }
3099
3100 static int
drv_cmd_get_roam_scan_refresh_period(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3101 drv_cmd_get_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info,
3102 struct hdd_context *hdd_ctx,
3103 uint8_t *command, uint8_t command_len,
3104 struct hdd_priv_data *priv_data)
3105 {
3106 int ret = 0;
3107 uint16_t value = 0;
3108 char extra[32];
3109 uint8_t len;
3110
3111 ucfg_cm_get_neighbor_scan_refresh_period(hdd_ctx->psoc, &value);
3112 len = scnprintf(extra, sizeof(extra), "%s %d",
3113 "GETROAMSCANREFRESHPERIOD",
3114 (value / 1000));
3115 /* Returned value is in units of seconds */
3116 len = QDF_MIN(priv_data->total_len, len + 1);
3117 if (copy_to_user(priv_data->buf, &extra, len)) {
3118 hdd_err("failed to copy data to user buffer");
3119 ret = -EFAULT;
3120 }
3121
3122 return ret;
3123 }
3124
drv_cmd_set_roam_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3125 static int drv_cmd_set_roam_mode(struct wlan_hdd_link_info *link_info,
3126 struct hdd_context *hdd_ctx,
3127 uint8_t *command,
3128 uint8_t command_len,
3129 struct hdd_priv_data *priv_data)
3130 {
3131 mac_handle_t mac_handle;
3132 int ret;
3133 uint8_t *value = command;
3134 uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
3135
3136 /* Move pointer to ahead of SETROAMMODE<delimiter> */
3137 value = value + SIZE_OF_SETROAMMODE + 1;
3138
3139 /* Convert the value from ascii to integer */
3140 ret = kstrtou8(value, 10, &roam_mode);
3141 if (ret < 0) {
3142 /*
3143 * If the input value is greater than max value of datatype,
3144 * then also kstrtou8 fails
3145 */
3146 hdd_err("kstrtou8 failed range [%d - %d]",
3147 cfg_min(CFG_LFR_FEATURE_ENABLED),
3148 cfg_max(CFG_LFR_FEATURE_ENABLED));
3149 ret = -EINVAL;
3150 goto exit;
3151 }
3152
3153 hdd_debug("Received Command to Set Roam Mode = %d",
3154 roam_mode);
3155
3156 if (sme_roaming_in_progress(hdd_ctx->mac_handle,
3157 link_info->vdev_id)) {
3158 hdd_err_rl("Roaming in progress for vdev %d",
3159 link_info->vdev_id);
3160 return -EAGAIN;
3161 }
3162
3163 /*
3164 * Note that
3165 * SETROAMMODE 0 is to enable LFR while
3166 * SETROAMMODE 1 is to disable LFR, but
3167 * notify_is_fast_roam_ini_feature_enabled 0/1 is to
3168 * enable/disable. So, we have to invert the value
3169 * to call sme_update_is_fast_roam_ini_feature_enabled.
3170 */
3171 if (roam_mode) {
3172 /* Roam enable */
3173 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3174 } else {
3175 /* Roam disable */
3176 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3177 }
3178
3179 mac_handle = hdd_ctx->mac_handle;
3180 if (roam_mode) {
3181 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3182 (bool)roam_mode);
3183 sme_update_is_fast_roam_ini_feature_enabled(
3184 mac_handle, link_info->vdev_id, roam_mode);
3185 } else {
3186 sme_update_is_fast_roam_ini_feature_enabled(
3187 mac_handle, link_info->vdev_id, roam_mode);
3188 ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc,
3189 roam_mode);
3190 }
3191
3192 exit:
3193 return ret;
3194 }
3195
drv_cmd_set_suspend_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3196 static int drv_cmd_set_suspend_mode(struct wlan_hdd_link_info *link_info,
3197 struct hdd_context *hdd_ctx,
3198 uint8_t *command,
3199 uint8_t command_len,
3200 struct hdd_priv_data *priv_data)
3201 {
3202 struct hdd_adapter *adapter = link_info->adapter;
3203 int errno;
3204 uint8_t *value = command;
3205 QDF_STATUS status;
3206 uint8_t idle_monitor;
3207
3208 if (QDF_STA_MODE != adapter->device_mode) {
3209 hdd_debug("Non-STA interface");
3210 return 0;
3211 }
3212
3213 /* Move pointer to ahead of SETSUSPENDMODE<delimiter> */
3214 value = value + SIZE_OF_SETSUSPENDMODE + 1;
3215
3216 /* Convert the value from ascii to integer */
3217 errno = kstrtou8(value, 10, &idle_monitor);
3218 if (errno < 0) {
3219 /*
3220 * If the input value is greater than max value of datatype,
3221 * then also kstrtou8 fails
3222 */
3223 hdd_err("Range validation failed");
3224 return -EINVAL;
3225 }
3226
3227 hdd_debug("idle_monitor:%d", idle_monitor);
3228 status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc,
3229 idle_monitor);
3230 if (QDF_IS_STATUS_ERROR(status)) {
3231 hdd_debug("Send suspend mode to fw failed");
3232 return -EINVAL;
3233 }
3234 return 0;
3235 }
3236
drv_cmd_get_roam_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3237 static int drv_cmd_get_roam_mode(struct wlan_hdd_link_info *link_info,
3238 struct hdd_context *hdd_ctx,
3239 uint8_t *command,
3240 uint8_t command_len,
3241 struct hdd_priv_data *priv_data)
3242 {
3243 int ret = 0;
3244 bool roam_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc);
3245 char extra[32];
3246 uint8_t len;
3247
3248 /*
3249 * roamMode value shall be inverted because the sementics is different.
3250 */
3251 if (roam_mode)
3252 roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED);
3253 else
3254 roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED);
3255
3256 len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode);
3257 len = QDF_MIN(priv_data->total_len, len + 1);
3258 if (copy_to_user(priv_data->buf, &extra, len)) {
3259 hdd_err("failed to copy data to user buffer");
3260 ret = -EFAULT;
3261 }
3262
3263 return ret;
3264 }
3265
drv_cmd_set_roam_delta(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3266 static int drv_cmd_set_roam_delta(struct wlan_hdd_link_info *link_info,
3267 struct hdd_context *hdd_ctx,
3268 uint8_t *command,
3269 uint8_t command_len,
3270 struct hdd_priv_data *priv_data)
3271 {
3272 int ret;
3273 uint8_t *value = command;
3274 uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF);
3275
3276 /* Move pointer to ahead of SETROAMDELTA<delimiter> */
3277 value = value + command_len + 1;
3278
3279 /* Convert the value from ascii to integer */
3280 ret = kstrtou8(value, 10, &roam_rssi_diff);
3281 if (ret < 0) {
3282 /*
3283 * If the input value is greater than max value of datatype,
3284 * then also kstrtou8 fails
3285 */
3286 hdd_err("kstrtou8 failed range [%d - %d]",
3287 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3288 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
3289 ret = -EINVAL;
3290 goto exit;
3291 }
3292
3293 if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) {
3294 hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)",
3295 roam_rssi_diff,
3296 cfg_min(CFG_LFR_ROAM_RSSI_DIFF),
3297 cfg_max(CFG_LFR_ROAM_RSSI_DIFF));
3298 ret = -EINVAL;
3299 goto exit;
3300 }
3301
3302 hdd_debug("Received Command to Set roam rssi diff = %d",
3303 roam_rssi_diff);
3304
3305 sme_update_roam_rssi_diff(hdd_ctx->mac_handle,
3306 link_info->vdev_id,
3307 roam_rssi_diff);
3308
3309 exit:
3310 return ret;
3311 }
3312
drv_cmd_get_roam_delta(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3313 static int drv_cmd_get_roam_delta(struct wlan_hdd_link_info *link_info,
3314 struct hdd_context *hdd_ctx,
3315 uint8_t *command,
3316 uint8_t command_len,
3317 struct hdd_priv_data *priv_data)
3318 {
3319 int ret = 0;
3320 uint8_t rssi_diff;
3321 char extra[32];
3322 uint8_t len;
3323 QDF_STATUS status;
3324
3325 status = ucfg_cm_get_roam_rssi_diff(hdd_ctx->psoc,
3326 link_info->vdev_id,
3327 &rssi_diff);
3328 if (QDF_IS_STATUS_ERROR(status))
3329 return qdf_status_to_os_return(status);
3330
3331 hdd_debug("vdev_id: %u, rssi_diff: %u",
3332 link_info->vdev_id, rssi_diff);
3333
3334 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3335 TRACE_CODE_HDD_GETROAMDELTA_IOCTL,
3336 link_info->vdev_id, rssi_diff);
3337 len = scnprintf(extra, sizeof(extra), "%s %d",
3338 command, rssi_diff);
3339 len = QDF_MIN(priv_data->total_len, len + 1);
3340
3341 if (copy_to_user(priv_data->buf, &extra, len)) {
3342 hdd_err("failed to copy data to user buffer");
3343 ret = -EFAULT;
3344 }
3345
3346 return ret;
3347 }
3348
drv_cmd_get_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3349 static int drv_cmd_get_band(struct wlan_hdd_link_info *link_info,
3350 struct hdd_context *hdd_ctx,
3351 uint8_t *command,
3352 uint8_t command_len,
3353 struct hdd_priv_data *priv_data)
3354 {
3355 int ret = 0, band = -1;
3356 char extra[32];
3357 uint8_t len = 0;
3358
3359 hdd_get_band_helper(hdd_ctx, &band);
3360
3361 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3362 TRACE_CODE_HDD_GETBAND_IOCTL,
3363 link_info->vdev_id, band);
3364
3365 len = scnprintf(extra, sizeof(extra), "%s %d", command, band);
3366 len = QDF_MIN(priv_data->total_len, len + 1);
3367
3368 if (copy_to_user(priv_data->buf, &extra, len)) {
3369 hdd_err("failed to copy data to user buffer");
3370 ret = -EFAULT;
3371 }
3372
3373 return ret;
3374 }
3375
3376 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
is_roam_ch_from_fw_supported(struct hdd_context * hdd_ctx)3377 static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx)
3378 {
3379 return hdd_ctx->roam_ch_from_fw_supported;
3380 }
3381
3382 struct roam_ch_priv {
3383 struct roam_scan_ch_resp roam_ch;
3384 };
3385
3386 /**
3387 * hdd_dump_roam_scan_ch_list() - Function to dump roam scan chan list content
3388 * @chan_list: pointer to channel list received from FW via an event
3389 * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID
3390 * @num_channels: Number of channels
3391 *
3392 * Return: none
3393 */
3394 static void
hdd_dump_roam_scan_ch_list(uint32_t * chan_list,uint16_t num_channels)3395 hdd_dump_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels)
3396 {
3397 uint8_t i, j;
3398 uint8_t ch_cache_str[128] = {0};
3399
3400 /* print channel list after sorting in ascending order */
3401 for (i = 0, j = 0; i < num_channels; i++) {
3402 if (j < sizeof(ch_cache_str))
3403 j += snprintf(ch_cache_str + j,
3404 sizeof(ch_cache_str) - j, " %d",
3405 chan_list[i]);
3406 else
3407 break;
3408 }
3409
3410 hdd_debug("No of freq:%d, freq list : %s", num_channels, ch_cache_str);
3411 }
3412
3413 /**
3414 * hdd_sort_roam_scan_ch_list() - Function to sort roam scan channel list in
3415 * descending order before sending it to supplicant
3416 * @chan_list: pointer to channel list received from FW via an event
3417 * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID
3418 * @num_channels: Number of channels
3419 *
3420 * Return: none
3421 */
3422 static void
hdd_sort_roam_scan_ch_list(uint32_t * chan_list,uint16_t num_channels)3423 hdd_sort_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels)
3424 {
3425 uint8_t i, j;
3426 uint32_t swap = 0;
3427
3428 for (i = 0; i < (num_channels - 1) &&
3429 i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
3430 for (j = 0; j < (num_channels - i - 1); j++) {
3431 if (chan_list[j] < chan_list[j + 1]) {
3432 swap = chan_list[j];
3433 chan_list[j] = chan_list[j + 1];
3434 chan_list[j + 1] = swap;
3435 }
3436 }
3437 }
3438 }
3439
hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,struct roam_scan_ch_resp * roam_ch,void * context)3440 void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle,
3441 struct roam_scan_ch_resp *roam_ch,
3442 void *context)
3443 {
3444 struct osif_request *request;
3445 struct roam_ch_priv *priv;
3446 uint8_t *event = NULL, i = 0;
3447 uint32_t *freq = NULL, len;
3448 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
3449
3450 hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d",
3451 roam_ch->vdev_id, roam_ch->command_resp);
3452 /**
3453 * If command response is set in the response message, then it is
3454 * getroamscanchannels command response else this event is asynchronous
3455 * event raised by firmware.
3456 */
3457 if (!roam_ch->command_resp) {
3458 /*
3459 * Maximum allowed channel count is 30 in supplicant vendor
3460 * event of RCL list. So if number of channels present in
3461 * channel list received from FW is more than 30 channels then
3462 * restrict it to 30 channels only.
3463 */
3464 if (roam_ch->num_channels > MAX_RCL_CHANNEL_COUNT)
3465 roam_ch->num_channels = MAX_RCL_CHANNEL_COUNT;
3466
3467 len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]);
3468 if (!len) {
3469 hdd_err("Invalid len");
3470 return;
3471 }
3472 event = (uint8_t *)qdf_mem_malloc(len);
3473 if (!event)
3474 return;
3475
3476 freq = (uint32_t *)event;
3477 hdd_sort_roam_scan_ch_list(roam_ch->chan_list,
3478 roam_ch->num_channels);
3479 hdd_dump_roam_scan_ch_list(roam_ch->chan_list,
3480 roam_ch->num_channels);
3481 for (i = 0; i < roam_ch->num_channels &&
3482 i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
3483 freq[i] = roam_ch->chan_list[i];
3484 }
3485
3486 hdd_send_roam_scan_ch_list_event(hdd_ctx, roam_ch->vdev_id,
3487 len, event);
3488 qdf_mem_free(event);
3489 return;
3490 }
3491
3492 request = osif_request_get(context);
3493 if (!request) {
3494 hdd_err("Obsolete request");
3495 return;
3496 }
3497 priv = osif_request_priv(request);
3498
3499 hdd_sort_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels);
3500 hdd_dump_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels);
3501
3502 priv->roam_ch.num_channels = roam_ch->num_channels;
3503 for (i = 0; i < priv->roam_ch.num_channels &&
3504 i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++)
3505 priv->roam_ch.chan_list[i] = roam_ch->chan_list[i];
3506
3507 osif_request_complete(request);
3508 osif_request_put(request);
3509 }
3510
3511 static uint32_t
hdd_get_roam_chan_from_fw(struct hdd_adapter * adapter,uint32_t * chan_list,uint8_t * num_channels)3512 hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list,
3513 uint8_t *num_channels)
3514 {
3515 QDF_STATUS status = QDF_STATUS_E_INVAL;
3516 struct hdd_context *hdd_ctx;
3517 int ret, i;
3518 void *cookie;
3519 struct osif_request *request;
3520 struct roam_ch_priv *priv;
3521 struct roam_scan_ch_resp *p_roam_ch;
3522 static const struct osif_request_params params = {
3523 .priv_size = sizeof(*priv) +
3524 sizeof(priv->roam_ch.chan_list[0]) *
3525 WNI_CFG_VALID_CHANNEL_LIST_LEN,
3526 .timeout_ms = WLAN_WAIT_TIME_STATS,
3527 };
3528
3529 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3530 request = osif_request_alloc(¶ms);
3531 if (!request) {
3532 hdd_err("Request allocation failure");
3533 return -ENOMEM;
3534 }
3535
3536 priv = osif_request_priv(request);
3537 p_roam_ch = &priv->roam_ch;
3538 /** channel list starts after response structure*/
3539 priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1);
3540 cookie = osif_request_cookie(request);
3541 status = sme_get_roam_scan_ch(hdd_ctx->mac_handle,
3542 adapter->deflink->vdev_id, cookie);
3543
3544 if (QDF_IS_STATUS_ERROR(status)) {
3545 hdd_err("Unable to retrieve roam channels");
3546 ret = qdf_status_to_os_return(status);
3547 goto cleanup;
3548 }
3549
3550 ret = osif_request_wait_for_response(request);
3551 if (ret) {
3552 hdd_err("SME timed out while retrieving raom channels");
3553 goto cleanup;
3554 }
3555
3556 priv = osif_request_priv(request);
3557 *num_channels = priv->roam_ch.num_channels;
3558 for (i = 0; i < *num_channels; i++)
3559 chan_list[i] = priv->roam_ch.chan_list[i];
3560
3561 cleanup:
3562 osif_request_put(request);
3563
3564 return ret;
3565 }
3566
3567 int
hdd_get_roam_scan_freq(struct hdd_adapter * adapter,mac_handle_t mac_handle,uint32_t * chan_list,uint8_t * num_channels)3568 hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle,
3569 uint32_t *chan_list, uint8_t *num_channels)
3570 {
3571 int ret = 0;
3572
3573 if (!adapter || !mac_handle || !chan_list || !num_channels) {
3574 hdd_err("failed to get roam scan channel, invalid input");
3575 return -EFAULT;
3576 }
3577
3578 if (is_roam_ch_from_fw_supported(adapter->hdd_ctx)) {
3579 ret = hdd_get_roam_chan_from_fw(adapter, chan_list,
3580 num_channels);
3581 if (ret != QDF_STATUS_SUCCESS) {
3582 hdd_err("failed to get roam scan channel list from FW");
3583 return -EFAULT;
3584 }
3585
3586 return ret;
3587 }
3588
3589 if (sme_get_roam_scan_channel_list(mac_handle, chan_list, num_channels,
3590 adapter->deflink->vdev_id) !=
3591 QDF_STATUS_SUCCESS) {
3592 hdd_err("failed to get roam scan channel list");
3593 return -EFAULT;
3594 }
3595
3596 return ret;
3597 }
3598 #endif
3599
3600 enum host_target_comm_log {
3601 HTC_CREDIT_HISTORY_LOG = 0,
3602 COMMAND_LOG,
3603 COMMAND_TX_CMP_LOG,
3604 MGMT_COMMAND_LOG,
3605 MGMT_COMMAND_TX_CMP_LOG,
3606 EVENT_LOG,
3607 RX_EVENT_LOG,
3608 MGMT_EVENT_LOG
3609 };
3610
printk_adapter(void * priv,const char * fmt,...)3611 static int printk_adapter(void *priv, const char *fmt, ...)
3612 {
3613 int ret;
3614 va_list args;
3615
3616 va_start(args, fmt);
3617 ret = vprintk(fmt, args);
3618 ret += printk("\n");
3619 va_end(args);
3620
3621 return ret;
3622 }
3623
hdd_ioctl_log_buffer(int log_id,uint32_t count,qdf_abstract_print * custom_print,void * print_ctx)3624 void hdd_ioctl_log_buffer(int log_id, uint32_t count, qdf_abstract_print
3625 *custom_print,
3626 void *print_ctx)
3627 {
3628 qdf_abstract_print *print;
3629
3630 if (custom_print)
3631 print = custom_print;
3632 else
3633 print = &printk_adapter;
3634 switch (log_id) {
3635 case HTC_CREDIT_HISTORY_LOG:
3636 cds_print_htc_credit_history(count, print, print_ctx);
3637 break;
3638 case COMMAND_LOG:
3639 wma_print_wmi_cmd_log(count, print, print_ctx);
3640 break;
3641 case COMMAND_TX_CMP_LOG:
3642 wma_print_wmi_cmd_tx_cmp_log(count, print, print_ctx);
3643 break;
3644 case MGMT_COMMAND_LOG:
3645 wma_print_wmi_mgmt_cmd_log(count, print, print_ctx);
3646 break;
3647 case MGMT_COMMAND_TX_CMP_LOG:
3648 wma_print_wmi_mgmt_cmd_tx_cmp_log(count, print, print_ctx);
3649 break;
3650 case EVENT_LOG:
3651 wma_print_wmi_event_log(count, print, print_ctx);
3652 break;
3653 case RX_EVENT_LOG:
3654 wma_print_wmi_rx_event_log(count, print, print_ctx);
3655 break;
3656 case MGMT_EVENT_LOG:
3657 wma_print_wmi_mgmt_event_log(count, print, print_ctx);
3658 break;
3659 default:
3660 print(print_ctx, "Invalid Log Id %d", log_id);
3661 break;
3662 }
3663 }
3664
3665 #ifdef WLAN_DUMP_LOG_BUF_CNT
hdd_dump_log_buffer(void * print_ctx,qdf_abstract_print * custom_print)3666 void hdd_dump_log_buffer(void *print_ctx, qdf_abstract_print *custom_print)
3667 {
3668 int i;
3669
3670 for (i = 0; i <= MGMT_EVENT_LOG; i++)
3671 hdd_ioctl_log_buffer(i, WLAN_DUMP_LOG_BUF_CNT, custom_print,
3672 print_ctx);
3673 }
3674 #endif
3675
drv_cmd_get_ccx_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3676 static int drv_cmd_get_ccx_mode(struct wlan_hdd_link_info *link_info,
3677 struct hdd_context *hdd_ctx,
3678 uint8_t *command,
3679 uint8_t command_len,
3680 struct hdd_priv_data *priv_data)
3681 {
3682 int ret = 0;
3683 bool ese_mode = ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc);
3684 char extra[32];
3685 uint8_t len = 0;
3686 struct pmkid_mode_bits pmkid_modes;
3687
3688 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
3689 /*
3690 * Check if the features PMKID/ESE/11R are supported simultaneously,
3691 * then this operation is not permitted (return FAILURE)
3692 */
3693 if (ese_mode &&
3694 (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) &&
3695 ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
3696 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
3697 ret = -EPERM;
3698 goto exit;
3699 }
3700
3701 len = scnprintf(extra, sizeof(extra), "%s %d",
3702 "GETCCXMODE", ese_mode);
3703 len = QDF_MIN(priv_data->total_len, len + 1);
3704 if (copy_to_user(priv_data->buf, &extra, len)) {
3705 hdd_err("failed to copy data to user buffer");
3706 ret = -EFAULT;
3707 goto exit;
3708 }
3709
3710 exit:
3711 return ret;
3712 }
3713
drv_cmd_get_okc_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3714 static int drv_cmd_get_okc_mode(struct wlan_hdd_link_info *link_info,
3715 struct hdd_context *hdd_ctx,
3716 uint8_t *command,
3717 uint8_t command_len,
3718 struct hdd_priv_data *priv_data)
3719 {
3720 int ret = 0;
3721 struct pmkid_mode_bits pmkid_modes;
3722 char extra[32];
3723 uint8_t len = 0;
3724
3725 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
3726 /*
3727 * Check if the features OKC/ESE/11R are supported simultaneously,
3728 * then this operation is not permitted (return FAILURE)
3729 */
3730 if (pmkid_modes.fw_okc &&
3731 ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
3732 ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
3733 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
3734 ret = -EPERM;
3735 goto exit;
3736 }
3737
3738 len = scnprintf(extra, sizeof(extra), "%s %d",
3739 "GETOKCMODE", pmkid_modes.fw_okc);
3740 len = QDF_MIN(priv_data->total_len, len + 1);
3741
3742 if (copy_to_user(priv_data->buf, &extra, len)) {
3743 hdd_err("failed to copy data to user buffer");
3744 ret = -EFAULT;
3745 goto exit;
3746 }
3747
3748 exit:
3749 return ret;
3750 }
3751
drv_cmd_get_fast_roam(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3752 static int drv_cmd_get_fast_roam(struct wlan_hdd_link_info *link_info,
3753 struct hdd_context *hdd_ctx,
3754 uint8_t *command,
3755 uint8_t command_len,
3756 struct hdd_priv_data *priv_data)
3757 {
3758 int ret = 0;
3759 bool lfr_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc);
3760 char extra[32];
3761 uint8_t len = 0;
3762
3763 len = scnprintf(extra, sizeof(extra), "%s %d",
3764 "GETFASTROAM", lfr_mode);
3765 len = QDF_MIN(priv_data->total_len, len + 1);
3766
3767 if (copy_to_user(priv_data->buf, &extra, len)) {
3768 hdd_err("failed to copy data to user buffer");
3769 ret = -EFAULT;
3770 }
3771
3772 return ret;
3773 }
3774
drv_cmd_get_fast_transition(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3775 static int drv_cmd_get_fast_transition(struct wlan_hdd_link_info *link_info,
3776 struct hdd_context *hdd_ctx,
3777 uint8_t *command,
3778 uint8_t command_len,
3779 struct hdd_priv_data *priv_data)
3780 {
3781 int ret = 0;
3782 bool ft = ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc);
3783 char extra[32];
3784 uint8_t len = 0;
3785
3786 len = scnprintf(extra, sizeof(extra), "%s %d",
3787 "GETFASTTRANSITION", ft);
3788 len = QDF_MIN(priv_data->total_len, len + 1);
3789
3790 if (copy_to_user(priv_data->buf, &extra, len)) {
3791 hdd_err("failed to copy data to user buffer");
3792 ret = -EFAULT;
3793 }
3794
3795 return ret;
3796 }
3797
3798 static int
drv_cmd_set_roam_scan_channel_min_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3799 drv_cmd_set_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info,
3800 struct hdd_context *hdd_ctx,
3801 uint8_t *command, uint8_t command_len,
3802 struct hdd_priv_data *priv_data)
3803 {
3804 int ret = 0;
3805 uint8_t *value = command;
3806 uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME);
3807
3808 /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME<delimiter> */
3809 value = value + command_len + 1;
3810
3811 /* Convert the value from ascii to integer */
3812 ret = kstrtou8(value, 10, &min_time);
3813 if (ret < 0) {
3814 /*
3815 * If the input value is greater than max value of datatype,
3816 * then also kstrtou8 fails
3817 */
3818 hdd_err("kstrtou8 failed range [%d - %d]",
3819 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3820 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
3821 ret = -EINVAL;
3822 goto exit;
3823 }
3824
3825 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) {
3826 hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)",
3827 min_time,
3828 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME),
3829 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME));
3830 ret = -EINVAL;
3831 goto exit;
3832 }
3833
3834 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3835 TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL,
3836 link_info->vdev_id, min_time);
3837
3838 hdd_debug("Received Command to change channel min time = %d",
3839 min_time);
3840
3841 sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle,
3842 min_time, link_info->vdev_id);
3843
3844 exit:
3845 return ret;
3846 }
3847
drv_cmd_send_action_frame(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3848 static int drv_cmd_send_action_frame(struct wlan_hdd_link_info *link_info,
3849 struct hdd_context *hdd_ctx,
3850 uint8_t *command,
3851 uint8_t command_len,
3852 struct hdd_priv_data *priv_data)
3853 {
3854 return hdd_parse_sendactionframe(link_info->adapter, command,
3855 priv_data->total_len);
3856 }
3857
3858 static int
drv_cmd_get_roam_scan_channel_min_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3859 drv_cmd_get_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info,
3860 struct hdd_context *hdd_ctx,
3861 uint8_t *command, uint8_t command_len,
3862 struct hdd_priv_data *priv_data)
3863 {
3864 int ret = 0;
3865 uint16_t val;
3866 char extra[32];
3867 uint8_t len = 0;
3868
3869 val = ucfg_cm_get_neighbor_scan_min_chan_time(hdd_ctx->psoc,
3870 link_info->vdev_id);
3871 /* value is interms of msec */
3872 len = scnprintf(extra, sizeof(extra), "%s %d",
3873 "GETROAMSCANCHANNELMINTIME", val);
3874 len = QDF_MIN(priv_data->total_len, len + 1);
3875
3876 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
3877 TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL,
3878 link_info->vdev_id, val);
3879
3880 if (copy_to_user(priv_data->buf, &extra, len)) {
3881 hdd_err("failed to copy data to user buffer");
3882 ret = -EFAULT;
3883 }
3884
3885 return ret;
3886 }
3887
drv_cmd_set_scan_channel_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3888 static int drv_cmd_set_scan_channel_time(struct wlan_hdd_link_info *link_info,
3889 struct hdd_context *hdd_ctx,
3890 uint8_t *command,
3891 uint8_t command_len,
3892 struct hdd_priv_data *priv_data)
3893 {
3894 int ret = 0;
3895 uint8_t *value = command;
3896 uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME);
3897
3898 /* Move pointer to ahead of SETSCANCHANNELTIME<delimiter> */
3899 value = value + command_len + 1;
3900
3901 /* Convert the value from ascii to integer */
3902 ret = kstrtou16(value, 10, &max_time);
3903 if (ret < 0) {
3904 /*
3905 * If the input value is greater than max value of datatype,
3906 * then also kstrtou8 fails
3907 */
3908 hdd_err("kstrtou16 failed range [%d - %d]",
3909 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3910 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
3911 ret = -EINVAL;
3912 goto exit;
3913 }
3914
3915 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) {
3916 hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)",
3917 max_time,
3918 cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME),
3919 cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME));
3920 ret = -EINVAL;
3921 goto exit;
3922 }
3923
3924 hdd_debug("Received Command to change channel max time = %d",
3925 max_time);
3926
3927 sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle,
3928 link_info->vdev_id,
3929 max_time);
3930
3931 exit:
3932 return ret;
3933 }
3934
drv_cmd_get_scan_channel_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3935 static int drv_cmd_get_scan_channel_time(struct wlan_hdd_link_info *link_info,
3936 struct hdd_context *hdd_ctx,
3937 uint8_t *command,
3938 uint8_t command_len,
3939 struct hdd_priv_data *priv_data)
3940 {
3941 int ret = 0;
3942 uint16_t val;
3943 char extra[32];
3944 uint8_t len = 0;
3945
3946 val = ucfg_cm_get_neighbor_scan_max_chan_time(hdd_ctx->psoc,
3947 link_info->vdev_id);
3948
3949 hdd_debug("vdev_id: %u, scan channel time: %u",
3950 link_info->vdev_id, val);
3951
3952 /* value is interms of msec */
3953 len = scnprintf(extra, sizeof(extra), "%s %d",
3954 "GETSCANCHANNELTIME", val);
3955 len = QDF_MIN(priv_data->total_len, len + 1);
3956
3957 if (copy_to_user(priv_data->buf, &extra, len)) {
3958 hdd_err("failed to copy data to user buffer");
3959 ret = -EFAULT;
3960 }
3961
3962 return ret;
3963 }
3964
drv_cmd_set_scan_home_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)3965 static int drv_cmd_set_scan_home_time(struct wlan_hdd_link_info *link_info,
3966 struct hdd_context *hdd_ctx,
3967 uint8_t *command,
3968 uint8_t command_len,
3969 struct hdd_priv_data *priv_data)
3970 {
3971 int ret = 0;
3972 uint8_t *value = command;
3973 uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD);
3974
3975 /* Move pointer to ahead of SETSCANHOMETIME<delimiter> */
3976 value = value + command_len + 1;
3977
3978 /* Convert the value from ascii to integer */
3979 ret = kstrtou16(value, 10, &val);
3980 if (ret < 0) {
3981 /*
3982 * If the input value is greater than max value of datatype,
3983 * then also kstrtou8 fails
3984 */
3985 hdd_err("kstrtou16 failed range [%d - %d]",
3986 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3987 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
3988 ret = -EINVAL;
3989 goto exit;
3990 }
3991
3992 if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) {
3993 hdd_err("scan home time value %d is out of range (Min: %d Max: %d)",
3994 val,
3995 cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD),
3996 cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD));
3997 ret = -EINVAL;
3998 goto exit;
3999 }
4000
4001 hdd_debug("Received Command to change scan home time = %d",
4002 val);
4003
4004 sme_set_neighbor_scan_period(hdd_ctx->mac_handle,
4005 link_info->vdev_id, val);
4006
4007 exit:
4008 return ret;
4009 }
4010
drv_cmd_get_scan_home_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4011 static int drv_cmd_get_scan_home_time(struct wlan_hdd_link_info *link_info,
4012 struct hdd_context *hdd_ctx,
4013 uint8_t *command,
4014 uint8_t command_len,
4015 struct hdd_priv_data *priv_data)
4016 {
4017 int ret = 0;
4018 uint16_t val;
4019 char extra[32];
4020 uint8_t len = 0;
4021
4022 val = ucfg_cm_get_neighbor_scan_period(hdd_ctx->psoc,
4023 link_info->vdev_id);
4024 hdd_debug("vdev_id: %u, scan home time: %u",
4025 link_info->vdev_id, val);
4026
4027 /* value is interms of msec */
4028 len = scnprintf(extra, sizeof(extra), "%s %d",
4029 "GETSCANHOMETIME", val);
4030 len = QDF_MIN(priv_data->total_len, len + 1);
4031
4032 if (copy_to_user(priv_data->buf, &extra, len)) {
4033 hdd_err("failed to copy data to user buffer");
4034 ret = -EFAULT;
4035 }
4036
4037 return ret;
4038 }
4039
drv_cmd_set_roam_intra_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4040 static int drv_cmd_set_roam_intra_band(struct wlan_hdd_link_info *link_info,
4041 struct hdd_context *hdd_ctx,
4042 uint8_t *command,
4043 uint8_t command_len,
4044 struct hdd_priv_data *priv_data)
4045 {
4046 int ret = 0;
4047 uint8_t *value = command;
4048 uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND);
4049
4050 /* Move pointer to ahead of SETROAMINTRABAND<delimiter> */
4051 value = value + command_len + 1;
4052
4053 /* Convert the value from ascii to integer */
4054 ret = kstrtou8(value, 10, &val);
4055 if (ret < 0) {
4056 /*
4057 * If the input value is greater than max value of datatype,
4058 * then also kstrtou8 fails
4059 */
4060 hdd_err("kstrtou8 failed range [%d - %d]",
4061 cfg_min(CFG_LFR_ROAM_INTRA_BAND),
4062 cfg_max(CFG_LFR_ROAM_INTRA_BAND));
4063 ret = -EINVAL;
4064 goto exit;
4065 }
4066
4067 hdd_debug("Received Command to change intra band = %d",
4068 val);
4069
4070 ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val);
4071
4072 /* Disable roaming on Vdev before setting PCL */
4073 sme_stop_roaming(hdd_ctx->mac_handle, link_info->vdev_id,
4074 REASON_DRIVER_DISABLED, RSO_SET_PCL);
4075
4076 policy_mgr_set_pcl_for_existing_combo(hdd_ctx->psoc, PM_STA_MODE,
4077 link_info->vdev_id);
4078
4079 /* Enable roaming once SET pcl is done */
4080 sme_start_roaming(hdd_ctx->mac_handle, link_info->vdev_id,
4081 REASON_DRIVER_ENABLED, RSO_SET_PCL);
4082
4083 exit:
4084 return ret;
4085 }
4086
drv_cmd_get_roam_intra_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4087 static int drv_cmd_get_roam_intra_band(struct wlan_hdd_link_info *link_info,
4088 struct hdd_context *hdd_ctx,
4089 uint8_t *command,
4090 uint8_t command_len,
4091 struct hdd_priv_data *priv_data)
4092 {
4093 int ret = 0;
4094 uint16_t val = 0;
4095 char extra[32];
4096 uint8_t len = 0;
4097
4098 ucfg_cm_get_roam_intra_band(hdd_ctx->psoc, &val);
4099 /* value is interms of msec */
4100 len = scnprintf(extra, sizeof(extra), "%s %d",
4101 "GETROAMINTRABAND", val);
4102 len = QDF_MIN(priv_data->total_len, len + 1);
4103 if (copy_to_user(priv_data->buf, &extra, len)) {
4104 hdd_err("failed to copy data to user buffer");
4105 ret = -EFAULT;
4106 }
4107
4108 return ret;
4109 }
4110
drv_cmd_set_scan_n_probes(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4111 static int drv_cmd_set_scan_n_probes(struct wlan_hdd_link_info *link_info,
4112 struct hdd_context *hdd_ctx,
4113 uint8_t *command,
4114 uint8_t command_len,
4115 struct hdd_priv_data *priv_data)
4116 {
4117 int ret = 0;
4118 uint8_t *value = command;
4119 uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES);
4120
4121 /* Move pointer to ahead of SETSCANNPROBES<delimiter> */
4122 value = value + command_len + 1;
4123
4124 /* Convert the value from ascii to integer */
4125 ret = kstrtou8(value, 10, &nprobes);
4126 if (ret < 0) {
4127 /*
4128 * If the input value is greater than max value of datatype,
4129 * then also kstrtou8 fails
4130 */
4131 hdd_err("kstrtou8 failed range [%d - %d]",
4132 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4133 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
4134 ret = -EINVAL;
4135 goto exit;
4136 }
4137
4138 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) {
4139 hdd_err("NProbes value %d is out of range (Min: %d Max: %d)",
4140 nprobes,
4141 cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES),
4142 cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES));
4143 ret = -EINVAL;
4144 goto exit;
4145 }
4146
4147 hdd_debug("Received Command to Set nProbes = %d",
4148 nprobes);
4149
4150 sme_update_roam_scan_n_probes(hdd_ctx->mac_handle,
4151 link_info->vdev_id, nprobes);
4152
4153 exit:
4154 return ret;
4155 }
4156
drv_cmd_get_scan_n_probes(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4157 static int drv_cmd_get_scan_n_probes(struct wlan_hdd_link_info *link_info,
4158 struct hdd_context *hdd_ctx,
4159 uint8_t *command,
4160 uint8_t command_len,
4161 struct hdd_priv_data *priv_data)
4162 {
4163 int ret = 0;
4164 uint8_t val;
4165 char extra[32];
4166 uint8_t len = 0;
4167 QDF_STATUS status;
4168
4169 status = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle,
4170 link_info->vdev_id, &val);
4171 if (QDF_IS_STATUS_ERROR(status))
4172 return qdf_status_to_os_return(status);
4173
4174 hdd_debug("vdev_id: %u, scan_n_probes: %u",
4175 link_info->vdev_id, val);
4176
4177 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4178 len = QDF_MIN(priv_data->total_len, len + 1);
4179 if (copy_to_user(priv_data->buf, &extra, len)) {
4180 hdd_err("failed to copy data to user buffer");
4181 ret = -EFAULT;
4182 }
4183
4184 return ret;
4185 }
4186
drv_cmd_set_scan_home_away_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4187 static int drv_cmd_set_scan_home_away_time(struct wlan_hdd_link_info *link_info,
4188 struct hdd_context *hdd_ctx,
4189 uint8_t *command,
4190 uint8_t command_len,
4191 struct hdd_priv_data *priv_data)
4192 {
4193 int ret = 0;
4194 uint8_t *value = command;
4195 uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME);
4196
4197 /* input value is in units of msec */
4198
4199 /* Move pointer to ahead of SETSCANHOMEAWAYTIME<delimiter> */
4200 value = value + command_len + 1;
4201
4202 /* Convert the value from ascii to integer */
4203 ret = kstrtou16(value, 10, &home_away_time);
4204 if (ret < 0) {
4205 /*
4206 * If the input value is greater than max value of datatype,
4207 * then also kstrtou8 fails
4208 */
4209 hdd_err("kstrtou8 failed range [%d - %d]",
4210 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4211 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
4212 ret = -EINVAL;
4213 goto exit;
4214 }
4215
4216 if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) {
4217 hdd_err("home_away_time value %d is out of range (min: %d max: %d)",
4218 home_away_time,
4219 cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME),
4220 cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME));
4221 ret = -EINVAL;
4222 goto exit;
4223 }
4224
4225 hdd_debug("Received Command to Set scan away time = %d",
4226 home_away_time);
4227
4228 sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle,
4229 link_info->vdev_id,
4230 home_away_time, true);
4231
4232 exit:
4233 return ret;
4234 }
4235
drv_cmd_get_scan_home_away_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4236 static int drv_cmd_get_scan_home_away_time(struct wlan_hdd_link_info *link_info,
4237 struct hdd_context *hdd_ctx,
4238 uint8_t *command,
4239 uint8_t command_len,
4240 struct hdd_priv_data *priv_data)
4241 {
4242 int ret = 0;
4243 uint16_t val;
4244 char extra[32] = {0};
4245 uint8_t len = 0;
4246 QDF_STATUS status;
4247
4248 status = ucfg_cm_get_roam_scan_home_away_time(hdd_ctx->psoc,
4249 link_info->vdev_id,
4250 &val);
4251 if (QDF_IS_STATUS_ERROR(status))
4252 return qdf_status_to_os_return(status);
4253
4254 hdd_debug("vdev_id: %u, scan home away time: %u",
4255 link_info->vdev_id, val);
4256
4257 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4258 len = QDF_MIN(priv_data->total_len, len + 1);
4259
4260 if (copy_to_user(priv_data->buf, &extra, len)) {
4261 hdd_err("failed to copy data to user buffer");
4262 ret = -EFAULT;
4263 }
4264
4265 return ret;
4266 }
4267
drv_cmd_reassoc(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4268 static int drv_cmd_reassoc(struct wlan_hdd_link_info *link_info,
4269 struct hdd_context *hdd_ctx,
4270 uint8_t *command,
4271 uint8_t command_len,
4272 struct hdd_priv_data *priv_data)
4273 {
4274 return hdd_parse_reassoc(link_info->adapter, command,
4275 priv_data->total_len);
4276 }
4277
drv_cmd_set_wes_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4278 static int drv_cmd_set_wes_mode(struct wlan_hdd_link_info *link_info,
4279 struct hdd_context *hdd_ctx,
4280 uint8_t *command,
4281 uint8_t command_len,
4282 struct hdd_priv_data *priv_data)
4283 {
4284 int ret = 0;
4285 uint8_t *value = command;
4286 uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE);
4287
4288 /* Move pointer to ahead of SETWESMODE<delimiter> */
4289 value = value + command_len + 1;
4290
4291 /* Convert the value from ascii to integer */
4292 ret = kstrtou8(value, 10, &wes_mode);
4293 if (ret < 0) {
4294 /*
4295 * If the input value is greater than max value of datatype,
4296 * then also kstrtou8 fails
4297 */
4298 hdd_err("kstrtou8 failed range [%d - %d]",
4299 cfg_min(CFG_LFR_ENABLE_WES_MODE),
4300 cfg_max(CFG_LFR_ENABLE_WES_MODE));
4301 ret = -EINVAL;
4302 goto exit;
4303 }
4304
4305 hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode);
4306
4307 sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, link_info->vdev_id);
4308
4309 exit:
4310 return ret;
4311 }
4312
drv_cmd_get_wes_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4313 static int drv_cmd_get_wes_mode(struct wlan_hdd_link_info *link_info,
4314 struct hdd_context *hdd_ctx,
4315 uint8_t *command,
4316 uint8_t command_len,
4317 struct hdd_priv_data *priv_data)
4318 {
4319 int ret = 0;
4320 bool wes_mode = ucfg_cm_get_wes_mode(hdd_ctx->psoc);
4321 char extra[32];
4322 uint8_t len = 0;
4323
4324 len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode);
4325 len = QDF_MIN(priv_data->total_len, len + 1);
4326 if (copy_to_user(priv_data->buf, &extra, len)) {
4327 hdd_err("failed to copy data to user buffer");
4328 ret = -EFAULT;
4329 }
4330
4331 return ret;
4332 }
4333
4334 static int
drv_cmd_set_opportunistic_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4335 drv_cmd_set_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info,
4336 struct hdd_context *hdd_ctx,
4337 uint8_t *command, uint8_t command_len,
4338 struct hdd_priv_data *priv_data)
4339 {
4340 int ret = 0;
4341 uint8_t *value = command;
4342 uint8_t diff =
4343 cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF);
4344
4345 /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF<delimiter> */
4346 value = value + command_len + 1;
4347
4348 /* Convert the value from ascii to integer */
4349 ret = kstrtou8(value, 10, &diff);
4350 if (ret < 0) {
4351 /*
4352 * If the input value is greater than max value of datatype,
4353 * then also kstrtou8 fails
4354 */
4355 hdd_err("kstrtou8 failed");
4356 ret = -EINVAL;
4357 goto exit;
4358 }
4359
4360 hdd_debug("Received Command to Set Opportunistic Threshold diff = %d",
4361 diff);
4362
4363 sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle,
4364 link_info->vdev_id,
4365 diff);
4366
4367 exit:
4368 return ret;
4369 }
4370
4371 static int
drv_cmd_get_opportunistic_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4372 drv_cmd_get_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info,
4373 struct hdd_context *hdd_ctx,
4374 uint8_t *command, uint8_t command_len,
4375 struct hdd_priv_data *priv_data)
4376 {
4377 int ret = 0;
4378 int8_t val = 0;
4379 char extra[32];
4380 uint8_t len = 0;
4381
4382 ucfg_cm_get_roam_opportunistic_scan_threshold_diff(hdd_ctx->psoc, &val);
4383 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4384 len = QDF_MIN(priv_data->total_len, len + 1);
4385 if (copy_to_user(priv_data->buf, &extra, len)) {
4386 hdd_err("failed to copy data to user buffer");
4387 ret = -EFAULT;
4388 }
4389
4390 return ret;
4391 }
4392
4393 static int
drv_cmd_set_roam_rescan_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4394 drv_cmd_set_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info,
4395 struct hdd_context *hdd_ctx,
4396 uint8_t *command, uint8_t command_len,
4397 struct hdd_priv_data *priv_data)
4398 {
4399 int ret = 0;
4400 uint8_t *value = command;
4401 uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF);
4402
4403 /* Move pointer to ahead of SETROAMRESCANRSSIDIFF<delimiter> */
4404 value = value + command_len + 1;
4405
4406 /* Convert the value from ascii to integer */
4407 ret = kstrtou8(value, 10, &rescan_rssi_diff);
4408 if (ret < 0) {
4409 /*
4410 * If the input value is greater than max value of datatype,
4411 * then also kstrtou8 fails
4412 */
4413 hdd_err("kstrtou8 failed");
4414 ret = -EINVAL;
4415 goto exit;
4416 }
4417
4418 hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d",
4419 rescan_rssi_diff);
4420
4421 sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle,
4422 link_info->vdev_id, rescan_rssi_diff);
4423
4424 exit:
4425 return ret;
4426 }
4427
4428 static int
drv_cmd_get_roam_rescan_rssi_diff(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4429 drv_cmd_get_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info,
4430 struct hdd_context *hdd_ctx,
4431 uint8_t *command, uint8_t command_len,
4432 struct hdd_priv_data *priv_data)
4433 {
4434 int ret = 0;
4435 uint8_t val = 0;
4436 char extra[32];
4437 uint8_t len = 0;
4438
4439 ucfg_cm_get_roam_rescan_rssi_diff(hdd_ctx->psoc, &val);
4440 len = scnprintf(extra, sizeof(extra), "%s %d", command, val);
4441 len = QDF_MIN(priv_data->total_len, len + 1);
4442 if (copy_to_user(priv_data->buf, &extra, len)) {
4443 hdd_err("failed to copy data to user buffer");
4444 ret = -EFAULT;
4445 }
4446
4447 return ret;
4448 }
4449
drv_cmd_set_fast_roam(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4450 static int drv_cmd_set_fast_roam(struct wlan_hdd_link_info *link_info,
4451 struct hdd_context *hdd_ctx,
4452 uint8_t *command,
4453 uint8_t command_len,
4454 struct hdd_priv_data *priv_data)
4455 {
4456 int ret = 0;
4457 uint8_t *value = command;
4458 uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED);
4459
4460 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4461 value = value + command_len + 1;
4462
4463 /* Convert the value from ascii to integer */
4464 ret = kstrtou8(value, 10, &lfr_mode);
4465 if (ret < 0) {
4466 /*
4467 * If the input value is greater than max value of datatype,
4468 * then also kstrtou8 fails
4469 */
4470 hdd_err("kstrtou8 failed range [%d - %d]",
4471 cfg_min(CFG_LFR_FEATURE_ENABLED),
4472 cfg_max(CFG_LFR_FEATURE_ENABLED));
4473 ret = -EINVAL;
4474 goto exit;
4475 }
4476
4477 hdd_debug("Received Command to change lfr mode = %d",
4478 lfr_mode);
4479
4480 if (sme_roaming_in_progress(hdd_ctx->mac_handle,
4481 link_info->vdev_id)) {
4482 hdd_err_rl("Roaming in progress for vdev %d",
4483 link_info->vdev_id);
4484 return -EAGAIN;
4485 }
4486
4487 ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode);
4488 sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle,
4489 link_info->vdev_id,
4490 lfr_mode);
4491
4492 exit:
4493 return ret;
4494 }
4495
drv_cmd_set_fast_transition(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4496 static int drv_cmd_set_fast_transition(struct wlan_hdd_link_info *link_info,
4497 struct hdd_context *hdd_ctx,
4498 uint8_t *command,
4499 uint8_t command_len,
4500 struct hdd_priv_data *priv_data)
4501 {
4502 int ret = 0;
4503 uint8_t *value = command;
4504 uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED);
4505
4506 /* Move pointer to ahead of SETFASTROAM<delimiter> */
4507 value = value + command_len + 1;
4508
4509 /* Convert the value from ascii to integer */
4510 ret = kstrtou8(value, 10, &ft);
4511 if (ret < 0) {
4512 /*
4513 * If the input value is greater than max value of datatype,
4514 * then also kstrtou8 fails
4515 */
4516 hdd_err("kstrtou8 failed range [%d - %d]",
4517 cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED),
4518 cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED));
4519 ret = -EINVAL;
4520 goto exit;
4521 }
4522
4523 hdd_debug("Received Command to change ft mode = %d", ft);
4524
4525 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft);
4526
4527 exit:
4528 return ret;
4529 }
4530
4531 /**
4532 * drv_cmd_fast_reassoc() - Handler for FASTREASSOC driver command
4533 * @link_info: Carries link specific info, which contains adapter
4534 * @hdd_ctx: pointer to hdd context
4535 * @command: Buffer that carries actual command data, which can be parsed by
4536 * hdd_parse_reassoc_command_v1_data()
4537 * @command_len: Command length
4538 * @priv_data: to carry any priv data, FASTREASSOC doesn't have any priv
4539 * data for now.
4540 *
4541 * This function parses the reasoc command data passed in the format
4542 * FASTREASSOC<space><bssid><space><channel/frequency>
4543 *
4544 * If MAC from user space is broadcast MAC as:
4545 * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0",
4546 * user space invoked roaming candidate selection will base on firmware score
4547 * algorithm, current connection will be kept if current AP has highest
4548 * score. It is requirement from customer which can avoid ping-pong roaming.
4549 *
4550 * If firmware fails to roam to new AP due to any reason, host to disconnect
4551 * from current AP as it's unable to roam.
4552 *
4553 * Return: 0 for success non-zero for failure
4554 */
drv_cmd_fast_reassoc(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4555 static int drv_cmd_fast_reassoc(struct wlan_hdd_link_info *link_info,
4556 struct hdd_context *hdd_ctx,
4557 uint8_t *command,
4558 uint8_t command_len,
4559 struct hdd_priv_data *priv_data)
4560 {
4561 int ret = 0;
4562 uint8_t *value = command;
4563 qdf_freq_t freq = 0;
4564 tSirMacAddr bssid;
4565 struct qdf_mac_addr target_bssid;
4566 struct hdd_adapter *adapter = link_info->adapter;
4567
4568 if (QDF_STA_MODE != adapter->device_mode) {
4569 hdd_warn("Unsupported in mode %s(%d)",
4570 qdf_opmode_str(adapter->device_mode),
4571 adapter->device_mode);
4572 return -EINVAL;
4573 }
4574
4575 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
4576
4577 /* if not associated, no need to proceed with reassoc */
4578 if (!hdd_cm_is_vdev_associated(link_info)) {
4579 hdd_warn("Not associated!");
4580 ret = -EINVAL;
4581 goto exit;
4582 }
4583
4584 ret = hdd_parse_reassoc_command_v1_data(value, bssid,
4585 &freq, hdd_ctx->pdev);
4586 if (ret) {
4587 hdd_err("Failed to parse reassoc command data");
4588 goto exit;
4589 }
4590
4591 qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr));
4592 ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, link_info->vdev_id,
4593 &target_bssid, freq, CM_ROAMING_HOST);
4594
4595 exit:
4596 return ret;
4597 }
4598
drv_cmd_set_okc_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4599 static int drv_cmd_set_okc_mode(struct wlan_hdd_link_info *link_info,
4600 struct hdd_context *hdd_ctx,
4601 uint8_t *command,
4602 uint8_t command_len,
4603 struct hdd_priv_data *priv_data)
4604 {
4605 int ret = 0;
4606 uint8_t *value = command;
4607 uint32_t okc_mode;
4608 struct pmkid_mode_bits pmkid_modes;
4609 uint32_t cur_pmkid_modes;
4610 QDF_STATUS status;
4611
4612 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
4613
4614 /*
4615 * Check if the features PMKID/ESE/11R are supported simultaneously,
4616 * then this operation is not permitted (return FAILURE)
4617 */
4618 if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
4619 pmkid_modes.fw_okc &&
4620 ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
4621 hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!");
4622 ret = -EPERM;
4623 goto exit;
4624 }
4625
4626 /* Move pointer to ahead of SETOKCMODE<delimiter> */
4627 value = value + command_len + 1;
4628
4629 /* get the current configured value */
4630 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc, &cur_pmkid_modes);
4631 if (status != QDF_STATUS_SUCCESS)
4632 hdd_err("get pmkid modes failed");
4633
4634 okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC;
4635
4636 /* Convert the value from ascii to integer */
4637 ret = kstrtou32(value, 10, &okc_mode);
4638 if (ret < 0) {
4639 /*
4640 * If the input value is greater than max value of datatype,
4641 * then also kstrtou8 fails
4642 */
4643 hdd_err("value out of range [0 - 1]");
4644 ret = -EINVAL;
4645 goto exit;
4646 }
4647
4648 if ((okc_mode < 0) ||
4649 (okc_mode > 1)) {
4650 hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)",
4651 okc_mode);
4652 ret = -EINVAL;
4653 goto exit;
4654 }
4655 hdd_debug("Received Command to change okc mode = %d", okc_mode);
4656
4657 if (okc_mode)
4658 cur_pmkid_modes |= CFG_PMKID_MODES_OKC;
4659 else
4660 cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC;
4661 status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc,
4662 cur_pmkid_modes);
4663 if (status != QDF_STATUS_SUCCESS) {
4664 ret = -EPERM;
4665 hdd_err("set pmkid modes failed");
4666 }
4667 exit:
4668 return ret;
4669 }
4670
drv_cmd_bt_coex_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4671 static int drv_cmd_bt_coex_mode(struct wlan_hdd_link_info *link_info,
4672 struct hdd_context *hdd_ctx,
4673 uint8_t *command,
4674 uint8_t command_len,
4675 struct hdd_priv_data *priv_data)
4676 {
4677 int ret = 0;
4678 char *coex_mode;
4679
4680 coex_mode = command + 11;
4681 if ('1' == *coex_mode) {
4682 hdd_debug("BTCOEXMODE %d", *coex_mode);
4683 hdd_ctx->bt_coex_mode_set = true;
4684 ret = wlan_hdd_scan_abort(link_info);
4685 if (ret < 0) {
4686 hdd_err("Failed to abort existing scan status: %d",
4687 ret);
4688 }
4689 } else if ('2' == *coex_mode) {
4690 hdd_debug("BTCOEXMODE %d", *coex_mode);
4691 hdd_ctx->bt_coex_mode_set = false;
4692 }
4693
4694 return ret;
4695 }
4696
drv_cmd_scan_active(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4697 static int drv_cmd_scan_active(struct wlan_hdd_link_info *link_info,
4698 struct hdd_context *hdd_ctx,
4699 uint8_t *command,
4700 uint8_t command_len,
4701 struct hdd_priv_data *priv_data)
4702 {
4703 hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN;
4704 return 0;
4705 }
4706
drv_cmd_scan_passive(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4707 static int drv_cmd_scan_passive(struct wlan_hdd_link_info *link_info,
4708 struct hdd_context *hdd_ctx,
4709 uint8_t *command,
4710 uint8_t command_len,
4711 struct hdd_priv_data *priv_data)
4712 {
4713 hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN;
4714 return 0;
4715 }
4716
drv_cmd_get_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4717 static int drv_cmd_get_dwell_time(struct wlan_hdd_link_info *link_info,
4718 struct hdd_context *hdd_ctx,
4719 uint8_t *command,
4720 uint8_t command_len,
4721 struct hdd_priv_data *priv_data)
4722 {
4723 int ret = 0;
4724 char extra[32];
4725 uint8_t len = 0;
4726
4727 memset(extra, 0, sizeof(extra));
4728 ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra,
4729 sizeof(extra), &len);
4730 len = QDF_MIN(priv_data->total_len, len + 1);
4731 if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) {
4732 hdd_err("failed to copy data to user buffer");
4733 ret = -EFAULT;
4734 goto exit;
4735 }
4736 ret = len;
4737 exit:
4738 return ret;
4739 }
4740
drv_cmd_set_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4741 static int drv_cmd_set_dwell_time(struct wlan_hdd_link_info *link_info,
4742 struct hdd_context *hdd_ctx,
4743 uint8_t *command,
4744 uint8_t command_len,
4745 struct hdd_priv_data *priv_data)
4746 {
4747 return hdd_set_dwell_time(hdd_ctx->psoc, command);
4748 }
4749
drv_cmd_conc_set_dwell_time(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4750 static int drv_cmd_conc_set_dwell_time(struct wlan_hdd_link_info *link_info,
4751 struct hdd_context *hdd_ctx,
4752 u8 *command,
4753 u8 command_len,
4754 struct hdd_priv_data *priv_data)
4755 {
4756 return hdd_conc_set_dwell_time(link_info->adapter, command);
4757 }
4758
drv_cmd_miracast(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4759 static int drv_cmd_miracast(struct wlan_hdd_link_info *link_info,
4760 struct hdd_context *hdd_ctx,
4761 uint8_t *command,
4762 uint8_t command_len,
4763 struct hdd_priv_data *priv_data)
4764 {
4765 QDF_STATUS ret_status;
4766 int ret = 0;
4767 uint8_t filter_type = 0;
4768 uint8_t *value;
4769
4770 if (wlan_hdd_validate_context(hdd_ctx))
4771 return -EINVAL;
4772
4773 value = command + 9;
4774
4775 /* Convert the value from ascii to integer */
4776 ret = kstrtou8(value, 10, &filter_type);
4777 if (ret < 0) {
4778 /*
4779 * If the input value is greater than max value of datatype,
4780 * then also kstrtou8 fails
4781 */
4782 hdd_err("kstrtou8 failed range");
4783 ret = -EINVAL;
4784 goto exit;
4785 }
4786 hdd_debug("filter_type %d", filter_type);
4787
4788 switch (filter_type) {
4789 case MIRACAST_DISABLED:
4790 case MIRACAST_SOURCE:
4791 case MIRACAST_SINK:
4792 break;
4793 case MIRACAST_CONN_OPT_ENABLED:
4794 case MIRACAST_CONN_OPT_DISABLED:
4795 {
4796 wma_cli_set_command(
4797 link_info->vdev_id,
4798 wmi_pdev_param_power_collapse_enable,
4799 (filter_type == MIRACAST_CONN_OPT_ENABLED ?
4800 0 : 1), PDEV_CMD);
4801 return 0;
4802 }
4803 default:
4804 hdd_err("accepted Values: 0-Disabled, 1-Source, 2-Sink, 128,129");
4805 ret = -EINVAL;
4806 goto exit;
4807 }
4808
4809 /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */
4810 hdd_ctx->miracast_value = filter_type;
4811 ucfg_mlme_set_vdev_traffic_low_latency(hdd_ctx->psoc,
4812 link_info->vdev_id,
4813 filter_type !=
4814 MIRACAST_DISABLED);
4815
4816 ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type);
4817 if (QDF_STATUS_SUCCESS != ret_status) {
4818 hdd_err("Failed to set miracast");
4819 return -EBUSY;
4820 }
4821 ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc,
4822 filter_type ? true : false);
4823 if (QDF_IS_STATUS_ERROR(ret_status)) {
4824 hdd_err("Failed to set miracastn scan");
4825 return -EBUSY;
4826 }
4827
4828 if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc))
4829 return wlan_hdd_set_mas(link_info->adapter, filter_type);
4830
4831 exit:
4832 return ret;
4833 }
4834
drv_cmd_tput_debug_mode_enable(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4835 static int drv_cmd_tput_debug_mode_enable(struct wlan_hdd_link_info *link_info,
4836 struct hdd_context *hdd_ctx,
4837 u8 *command,
4838 u8 command_len,
4839 struct hdd_priv_data *priv_data)
4840 {
4841 return hdd_enable_unit_test_commands(link_info->adapter, hdd_ctx);
4842 }
4843
drv_cmd_tput_debug_mode_disable(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,u8 * command,u8 command_len,struct hdd_priv_data * priv_data)4844 static int drv_cmd_tput_debug_mode_disable(struct wlan_hdd_link_info *link_info,
4845 struct hdd_context *hdd_ctx,
4846 u8 *command,
4847 u8 command_len,
4848 struct hdd_priv_data *priv_data)
4849 {
4850 return hdd_disable_unit_test_commands(link_info->adapter, hdd_ctx);
4851 }
4852
4853 #ifdef FEATURE_WLAN_ESE
4854 static int
drv_cmd_set_ccx_roam_scan_channels(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4855 drv_cmd_set_ccx_roam_scan_channels(struct wlan_hdd_link_info *link_info,
4856 struct hdd_context *hdd_ctx,
4857 uint8_t *command, uint8_t command_len,
4858 struct hdd_priv_data *priv_data)
4859 {
4860 int ret = 0;
4861 uint8_t *value = command;
4862 uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
4863 uint8_t num_channels = 0;
4864 QDF_STATUS status;
4865 mac_handle_t mac_handle;
4866
4867 if (!hdd_ctx) {
4868 hdd_err("invalid hdd ctx");
4869 ret = -EINVAL;
4870 goto exit;
4871 }
4872
4873 ret = hdd_parse_channellist(hdd_ctx, value, channel_freq_list,
4874 &num_channels);
4875 if (ret) {
4876 hdd_err("Failed to parse channel list information");
4877 goto exit;
4878 }
4879 if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) {
4880 hdd_err("number of channels (%d) supported exceeded max (%d)",
4881 num_channels, CFG_VALID_CHANNEL_LIST_LEN);
4882 ret = -EINVAL;
4883 goto exit;
4884 }
4885
4886 mac_handle = hdd_ctx->mac_handle;
4887 if (!sme_validate_channel_list(mac_handle, channel_freq_list,
4888 num_channels)) {
4889 hdd_err("List contains invalid channel(s)");
4890 ret = -EINVAL;
4891 goto exit;
4892 }
4893
4894 status = ucfg_cm_set_ese_roam_scan_channel_list(hdd_ctx->pdev,
4895 link_info->vdev_id,
4896 channel_freq_list,
4897 num_channels);
4898 if (QDF_STATUS_SUCCESS != status) {
4899 hdd_err("Failed to update channel list information");
4900 ret = -EINVAL;
4901 goto exit;
4902 }
4903
4904 exit:
4905 return ret;
4906 }
4907
drv_cmd_get_tsm_stats(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)4908 static int drv_cmd_get_tsm_stats(struct wlan_hdd_link_info *link_info,
4909 struct hdd_context *hdd_ctx,
4910 uint8_t *command,
4911 uint8_t command_len,
4912 struct hdd_priv_data *priv_data)
4913 {
4914 int ret = 0;
4915 uint8_t *value = command;
4916 char extra[128] = { 0 };
4917 int len = 0;
4918 uint8_t tid = 0;
4919 struct hdd_adapter *adapter = link_info->adapter;
4920 struct hdd_station_ctx *sta_ctx;
4921 tAniTrafStrmMetrics tsm_metrics = {0};
4922
4923 if ((QDF_STA_MODE != adapter->device_mode) &&
4924 (QDF_P2P_CLIENT_MODE != adapter->device_mode)) {
4925 hdd_warn("Unsupported in mode %s(%d)",
4926 qdf_opmode_str(adapter->device_mode),
4927 adapter->device_mode);
4928 return -EINVAL;
4929 }
4930
4931 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
4932
4933 /* if not associated, return error */
4934 if (!hdd_cm_is_vdev_associated(link_info)) {
4935 hdd_err("Not associated!");
4936 ret = -EINVAL;
4937 goto exit;
4938 }
4939
4940 /* Move pointer to ahead of GETTSMSTATS<delimiter> */
4941 value = value + command_len + 1;
4942
4943 /* Convert the value from ascii to integer */
4944 ret = kstrtou8(value, 10, &tid);
4945 if (ret < 0) {
4946 /*
4947 * If the input value is greater than max value of datatype,
4948 * then also kstrtou8 fails
4949 */
4950 hdd_err("kstrtou8 failed range [%d - %d]",
4951 TID_MIN_VALUE,
4952 TID_MAX_VALUE);
4953 ret = -EINVAL;
4954 goto exit;
4955 }
4956 if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) {
4957 hdd_err("tid value %d is out of range (Min: %d Max: %d)",
4958 tid, TID_MIN_VALUE, TID_MAX_VALUE);
4959 ret = -EINVAL;
4960 goto exit;
4961 }
4962 hdd_debug("Received Command to get tsm stats tid = %d",
4963 tid);
4964 ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics);
4965 if (ret) {
4966 hdd_err("failed to get tsm stats");
4967 goto exit;
4968 }
4969 hdd_debug(
4970 "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)",
4971 tsm_metrics.UplinkPktQueueDly,
4972 tsm_metrics.UplinkPktQueueDlyHist[0],
4973 tsm_metrics.UplinkPktQueueDlyHist[1],
4974 tsm_metrics.UplinkPktQueueDlyHist[2],
4975 tsm_metrics.UplinkPktQueueDlyHist[3],
4976 tsm_metrics.UplinkPktTxDly,
4977 tsm_metrics.UplinkPktLoss,
4978 tsm_metrics.UplinkPktCount,
4979 tsm_metrics.RoamingCount,
4980 tsm_metrics.RoamingDly);
4981 /*
4982 * Output TSM stats is of the format
4983 * GETTSMSTATS [PktQueueDly]
4984 * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly]
4985 * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800
4986 */
4987 len = scnprintf(extra,
4988 sizeof(extra),
4989 "%s %d %d:%d:%d:%d %u %d %d %d %d",
4990 command,
4991 tsm_metrics.UplinkPktQueueDly,
4992 tsm_metrics.UplinkPktQueueDlyHist[0],
4993 tsm_metrics.UplinkPktQueueDlyHist[1],
4994 tsm_metrics.UplinkPktQueueDlyHist[2],
4995 tsm_metrics.UplinkPktQueueDlyHist[3],
4996 tsm_metrics.UplinkPktTxDly,
4997 tsm_metrics.UplinkPktLoss,
4998 tsm_metrics.UplinkPktCount,
4999 tsm_metrics.RoamingCount,
5000 tsm_metrics.RoamingDly);
5001 len = QDF_MIN(priv_data->total_len, len + 1);
5002 if (copy_to_user(priv_data->buf, &extra, len)) {
5003 hdd_err("failed to copy data to user buffer");
5004 ret = -EFAULT;
5005 goto exit;
5006 }
5007
5008 exit:
5009 return ret;
5010 }
5011
drv_cmd_set_cckm_ie(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5012 static int drv_cmd_set_cckm_ie(struct wlan_hdd_link_info *link_info,
5013 struct hdd_context *hdd_ctx,
5014 uint8_t *command,
5015 uint8_t command_len,
5016 struct hdd_priv_data *priv_data)
5017 {
5018 int ret;
5019 uint8_t *value = command;
5020 uint8_t *cckm_ie = NULL;
5021 uint8_t cckm_ie_len = 0;
5022
5023 ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len);
5024 if (ret) {
5025 hdd_err("Failed to parse cckm ie data");
5026 goto exit;
5027 }
5028
5029 if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) {
5030 hdd_err("CCKM Ie input length is more than max[%d]",
5031 DOT11F_IE_RSN_MAX_LEN);
5032 if (cckm_ie) {
5033 qdf_mem_free(cckm_ie);
5034 cckm_ie = NULL;
5035 }
5036 ret = -EINVAL;
5037 goto exit;
5038 }
5039
5040 ucfg_cm_set_cckm_ie(hdd_ctx->psoc, link_info->vdev_id, cckm_ie,
5041 cckm_ie_len);
5042 if (cckm_ie) {
5043 qdf_mem_free(cckm_ie);
5044 cckm_ie = NULL;
5045 }
5046
5047 exit:
5048 return ret;
5049 }
5050
drv_cmd_ccx_beacon_req(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5051 static int drv_cmd_ccx_beacon_req(struct wlan_hdd_link_info *link_info,
5052 struct hdd_context *hdd_ctx,
5053 uint8_t *command,
5054 uint8_t command_len,
5055 struct hdd_priv_data *priv_data)
5056 {
5057 int ret;
5058 uint8_t *value = command;
5059 tCsrEseBeaconReq req = {0};
5060 QDF_STATUS status = QDF_STATUS_SUCCESS;
5061 struct hdd_adapter *adapter = link_info->adapter;
5062
5063 if (QDF_STA_MODE != adapter->device_mode) {
5064 hdd_warn("Unsupported in mode %s(%d)",
5065 qdf_opmode_str(adapter->device_mode),
5066 adapter->device_mode);
5067 return -EINVAL;
5068 }
5069
5070 ret = hdd_parse_ese_beacon_req(hdd_ctx->pdev, value, &req);
5071 if (ret) {
5072 hdd_err("Failed to parse ese beacon req");
5073 goto exit;
5074 }
5075
5076 if (!hdd_cm_is_vdev_associated(link_info)) {
5077 hdd_debug("Not associated");
5078
5079 if (!req.numBcnReqIe)
5080 return -EINVAL;
5081
5082 hdd_indicate_ese_bcn_report_no_results(adapter,
5083 req.bcnReq[0].measurementToken,
5084 0x02, /* BIT(1) set for measurement done */
5085 0); /* no BSS */
5086 goto exit;
5087 }
5088
5089 status = sme_set_ese_beacon_request(hdd_ctx->mac_handle,
5090 link_info->vdev_id,
5091 &req);
5092
5093 if (QDF_STATUS_E_RESOURCES == status) {
5094 hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress",
5095 status);
5096 ret = -EBUSY;
5097 goto exit;
5098 } else if (QDF_STATUS_SUCCESS != status) {
5099 hdd_err("sme_set_ese_beacon_request failed (%d)",
5100 status);
5101 ret = -EINVAL;
5102 goto exit;
5103 }
5104
5105 exit:
5106 return ret;
5107 }
5108
5109 /**
5110 * drv_cmd_ccx_plm_req() - Set ESE PLM request
5111 * @link_info: Link info pointer in HDD adapter
5112 * @hdd_ctx: Pointer to the HDD context
5113 * @command: Driver command string
5114 * @command_len: Driver command string length
5115 * @priv_data: Private data coming with the driver command. Unused here
5116 *
5117 * This function handles driver command that sets the ESE PLM request
5118 *
5119 * Return: 0 on success; negative errno otherwise
5120 */
drv_cmd_ccx_plm_req(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5121 static int drv_cmd_ccx_plm_req(struct wlan_hdd_link_info *link_info,
5122 struct hdd_context *hdd_ctx,
5123 uint8_t *command,
5124 uint8_t command_len,
5125 struct hdd_priv_data *priv_data)
5126 {
5127 QDF_STATUS status;
5128 struct plm_req_params *req;
5129
5130 req = qdf_mem_malloc(sizeof(*req));
5131 if (!req)
5132 return -ENOMEM;
5133
5134 status = hdd_parse_plm_cmd(command, req);
5135 if (QDF_IS_STATUS_SUCCESS(status)) {
5136 req->vdev_id = link_info->vdev_id;
5137 status = sme_set_plm_request(hdd_ctx->mac_handle, req);
5138 }
5139 qdf_mem_free(req);
5140
5141 return qdf_status_to_os_return(status);
5142 }
5143
5144 /**
5145 * drv_cmd_set_ccx_mode() - Set ESE mode
5146 * @link_info: Link info pointer in HDD adapter
5147 * @hdd_ctx: Pointer to the HDD context
5148 * @command: Driver command string
5149 * @command_len: Driver command string length
5150 * @priv_data: Private data coming with the driver command. Unused here
5151 *
5152 * This function handles driver command that sets ESE mode
5153 *
5154 * Return: 0 on success; negative errno otherwise
5155 */
drv_cmd_set_ccx_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5156 static int drv_cmd_set_ccx_mode(struct wlan_hdd_link_info *link_info,
5157 struct hdd_context *hdd_ctx,
5158 uint8_t *command,
5159 uint8_t command_len,
5160 struct hdd_priv_data *priv_data)
5161 {
5162 int ret = 0;
5163 uint8_t *value = command;
5164 uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED);
5165 struct pmkid_mode_bits pmkid_modes;
5166 mac_handle_t mac_handle;
5167
5168 hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes);
5169 mac_handle = hdd_ctx->mac_handle;
5170 /*
5171 * Check if the features OKC/ESE/11R are supported simultaneously,
5172 * then this operation is not permitted (return FAILURE)
5173 */
5174 if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) &&
5175 pmkid_modes.fw_okc &&
5176 ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) {
5177 hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!");
5178 ret = -EPERM;
5179 goto exit;
5180 }
5181
5182 /* Move pointer to ahead of SETCCXMODE<delimiter> */
5183 value = value + command_len + 1;
5184
5185 /* Convert the value from ascii to integer */
5186 ret = kstrtou8(value, 10, &ese_mode);
5187 if (ret < 0) {
5188 /*
5189 * If the input value is greater than max value of datatype,
5190 * then also kstrtou8 fails
5191 */
5192 hdd_err("kstrtou8 failed range [%d - %d]",
5193 cfg_min(CFG_LFR_ESE_FEATURE_ENABLED),
5194 cfg_max(CFG_LFR_ESE_FEATURE_ENABLED));
5195 ret = -EINVAL;
5196 goto exit;
5197 }
5198
5199 hdd_debug("Received Command to change ese mode = %d", ese_mode);
5200
5201 sme_update_is_ese_feature_enabled(mac_handle,
5202 link_info->vdev_id,
5203 ese_mode);
5204
5205 exit:
5206 return ret;
5207 }
5208 #endif /* FEATURE_WLAN_ESE */
5209
drv_cmd_set_mc_rate(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5210 static int drv_cmd_set_mc_rate(struct wlan_hdd_link_info *link_info,
5211 struct hdd_context *hdd_ctx,
5212 uint8_t *command, uint8_t command_len,
5213 struct hdd_priv_data *priv_data)
5214 {
5215 int ret = 0;
5216 uint8_t *value = command;
5217 uint32_t target_rate = 0;
5218
5219 /* input value is in units of hundred kbps */
5220
5221 /* Move pointer to ahead of SETMCRATE<delimiter> */
5222 value = value + command_len + 1;
5223
5224 /* Convert the value from ascii to integer, decimal base */
5225 ret = kstrtouint(value, 10, &target_rate);
5226
5227 ret = wlan_hdd_set_mc_rate(link_info, target_rate);
5228 return ret;
5229 }
5230
drv_cmd_max_tx_power(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5231 static int drv_cmd_max_tx_power(struct wlan_hdd_link_info *link_info,
5232 struct hdd_context *hdd_ctx,
5233 uint8_t *command,
5234 uint8_t command_len,
5235 struct hdd_priv_data *priv_data)
5236 {
5237 int ret;
5238 int tx_power;
5239 QDF_STATUS status;
5240 uint8_t *value = command;
5241 struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT;
5242 struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT;
5243 struct hdd_adapter *adapter = link_info->adapter, *next_adapter = NULL;
5244 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DRV_CMD_MAX_TX_POWER;
5245
5246 ret = hdd_parse_setmaxtxpower_command(value, &tx_power);
5247 if (ret) {
5248 hdd_err("Invalid MAXTXPOWER command");
5249 return ret;
5250 }
5251
5252 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
5253 dbgid) {
5254 /* Assign correct self MAC address */
5255 if (adapter->device_mode == QDF_SAP_MODE ||
5256 adapter->device_mode == QDF_P2P_GO_MODE) {
5257 qdf_copy_macaddr(&bssid, &adapter->mac_addr);
5258 } else {
5259 struct hdd_station_ctx *sta_ctx =
5260 WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
5261
5262 if (hdd_cm_is_vdev_associated(adapter->deflink))
5263 qdf_copy_macaddr(&bssid,
5264 &sta_ctx->conn_info.bssid);
5265 }
5266
5267 qdf_copy_macaddr(&selfmac,
5268 &adapter->mac_addr);
5269
5270 hdd_debug("Device mode %d max tx power %d selfMac: "
5271 QDF_MAC_ADDR_FMT " bssId: " QDF_MAC_ADDR_FMT,
5272 adapter->device_mode, tx_power,
5273 QDF_MAC_ADDR_REF(selfmac.bytes),
5274 QDF_MAC_ADDR_REF(bssid.bytes));
5275
5276 status = sme_set_max_tx_power(hdd_ctx->mac_handle,
5277 bssid, selfmac, tx_power);
5278 if (QDF_STATUS_SUCCESS != status) {
5279 hdd_err("Set max tx power failed");
5280 ret = -EINVAL;
5281 hdd_adapter_dev_put_debug(adapter, dbgid);
5282 if (next_adapter)
5283 hdd_adapter_dev_put_debug(next_adapter,
5284 dbgid);
5285 goto exit;
5286 }
5287 hdd_debug("Set max tx power success");
5288 hdd_adapter_dev_put_debug(adapter, dbgid);
5289 }
5290
5291 exit:
5292 return ret;
5293 }
5294
drv_cmd_set_dfs_scan_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5295 static int drv_cmd_set_dfs_scan_mode(struct wlan_hdd_link_info *link_info,
5296 struct hdd_context *hdd_ctx,
5297 uint8_t *command, uint8_t command_len,
5298 struct hdd_priv_data *priv_data)
5299 {
5300 int ret = 0;
5301 uint8_t *value = command;
5302 uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL);
5303
5304 /* Move pointer to ahead of SETDFSSCANMODE<delimiter> */
5305 value = value + command_len + 1;
5306
5307 /* Convert the value from ascii to integer */
5308 ret = kstrtou8(value, 10, &dfs_scan_mode);
5309 if (ret < 0) {
5310 /*
5311 * If the input value is greater than max value of datatype,
5312 * then also kstrtou8 fails
5313 */
5314 hdd_err("kstrtou8 failed range [%d - %d]",
5315 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5316 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
5317 ret = -EINVAL;
5318 goto exit;
5319 }
5320
5321 if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) {
5322 hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)",
5323 dfs_scan_mode,
5324 cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL),
5325 cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL));
5326 ret = -EINVAL;
5327 goto exit;
5328 }
5329
5330 hdd_debug("Received Command to Set DFS Scan Mode = %d",
5331 dfs_scan_mode);
5332
5333 /* When DFS scanning is disabled, the DFS channels need to be
5334 * removed from the operation of device.
5335 */
5336 ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx,
5337 dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED);
5338 if (ret < 0) {
5339 /* Some conditions prevented it from disabling DFS channels */
5340 hdd_err("disable/enable DFS channel request was denied");
5341 goto exit;
5342 }
5343
5344 sme_update_dfs_scan_mode(hdd_ctx->mac_handle, link_info->vdev_id,
5345 dfs_scan_mode);
5346
5347 exit:
5348 return ret;
5349 }
5350
drv_cmd_get_dfs_scan_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5351 static int drv_cmd_get_dfs_scan_mode(struct wlan_hdd_link_info *link_info,
5352 struct hdd_context *hdd_ctx,
5353 uint8_t *command,
5354 uint8_t command_len,
5355 struct hdd_priv_data *priv_data)
5356 {
5357 int ret = 0;
5358 uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle);
5359 char extra[32];
5360 uint8_t len = 0;
5361
5362 len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode);
5363 len = QDF_MIN(priv_data->total_len, len + 1);
5364 if (copy_to_user(priv_data->buf, &extra, len)) {
5365 hdd_err("failed to copy data to user buffer");
5366 ret = -EFAULT;
5367 }
5368
5369 return ret;
5370 }
5371
drv_cmd_get_link_status(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5372 static int drv_cmd_get_link_status(struct wlan_hdd_link_info *link_info,
5373 struct hdd_context *hdd_ctx,
5374 uint8_t *command,
5375 uint8_t command_len,
5376 struct hdd_priv_data *priv_data)
5377 {
5378 int ret = 0;
5379 int value = wlan_hdd_get_link_status(link_info->adapter);
5380 char extra[32];
5381 uint8_t len;
5382
5383 len = scnprintf(extra, sizeof(extra), "%s %d", command, value);
5384 len = QDF_MIN(priv_data->total_len, len + 1);
5385 if (copy_to_user(priv_data->buf, &extra, len)) {
5386 hdd_err("failed to copy data to user buffer");
5387 ret = -EFAULT;
5388 }
5389
5390 return ret;
5391 }
5392
5393 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
drv_cmd_enable_ext_wow(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5394 static int drv_cmd_enable_ext_wow(struct wlan_hdd_link_info *link_info,
5395 struct hdd_context *hdd_ctx,
5396 uint8_t *command,
5397 uint8_t command_len,
5398 struct hdd_priv_data *priv_data)
5399 {
5400 uint8_t *value = command;
5401 int set_value;
5402
5403 /* Move pointer to ahead of ENABLEEXTWOW */
5404 value = value + command_len;
5405
5406 if (!(sscanf(value, "%d", &set_value))) {
5407 hdd_info("No input identified");
5408 return -EINVAL;
5409 }
5410
5411 return hdd_enable_ext_wow_parser(link_info->adapter,
5412 link_info->vdev_id, set_value);
5413 }
5414
drv_cmd_set_app1_params(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5415 static int drv_cmd_set_app1_params(struct wlan_hdd_link_info *link_info,
5416 struct hdd_context *hdd_ctx,
5417 uint8_t *command,
5418 uint8_t command_len,
5419 struct hdd_priv_data *priv_data)
5420 {
5421 int ret;
5422 uint8_t *value = command;
5423
5424 /* Move pointer to ahead of SETAPP1PARAMS */
5425 value = value + command_len;
5426
5427 ret = hdd_set_app_type1_parser(link_info->adapter,
5428 value, strlen(value));
5429 if (ret >= 0)
5430 hdd_ctx->is_extwow_app_type1_param_set = true;
5431
5432 return ret;
5433 }
5434
drv_cmd_set_app2_params(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5435 static int drv_cmd_set_app2_params(struct wlan_hdd_link_info *link_info,
5436 struct hdd_context *hdd_ctx,
5437 uint8_t *command,
5438 uint8_t command_len,
5439 struct hdd_priv_data *priv_data)
5440 {
5441 int ret;
5442 uint8_t *value = command;
5443
5444 /* Move pointer to ahead of SETAPP2PARAMS */
5445 value = value + command_len;
5446
5447 ret = hdd_set_app_type2_parser(link_info->adapter,
5448 value, strlen(value));
5449 if (ret >= 0)
5450 hdd_ctx->is_extwow_app_type2_param_set = true;
5451
5452 return ret;
5453 }
5454 #endif /* WLAN_FEATURE_EXTWOW_SUPPORT */
5455
5456 #ifdef FEATURE_WLAN_TDLS
5457 /**
5458 * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset
5459 * @link_info: Link info pointer in HDD adapter
5460 * @hdd_ctx: Pointer to the HDD context
5461 * @command: Driver command string
5462 * @command_len: Driver command string length
5463 * @priv_data: Private data coming with the driver command. Unused here
5464 *
5465 * This function handles driver command that sets the secondary tdls off channel
5466 * offset
5467 *
5468 * Return: 0 on success; negative errno otherwise
5469 */
5470 static int
drv_cmd_tdls_secondary_channel_offset(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5471 drv_cmd_tdls_secondary_channel_offset(struct wlan_hdd_link_info *link_info,
5472 struct hdd_context *hdd_ctx,
5473 uint8_t *command, uint8_t command_len,
5474 struct hdd_priv_data *priv_data)
5475 {
5476 int ret;
5477 uint8_t *value = command;
5478 int set_value;
5479
5480 /* Move pointer to point the string */
5481 value += command_len;
5482
5483 ret = sscanf(value, "%d", &set_value);
5484 if (ret != 1)
5485 return -EINVAL;
5486
5487 hdd_debug("Tdls offchannel offset:%d", set_value);
5488
5489 ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, link_info->adapter,
5490 set_value);
5491
5492 return ret;
5493 }
5494
5495 /**
5496 * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode
5497 * @link_info: Link info pointer in HDD adapter
5498 * @hdd_ctx: Pointer to the HDD context
5499 * @command: Driver command string
5500 * @command_len: Driver command string length
5501 * @priv_data: Private data coming with the driver command. Unused here
5502 *
5503 * This function handles driver command that sets tdls off channel mode
5504 *
5505 * Return: 0 on success; negative errno otherwise
5506 */
drv_cmd_tdls_off_channel_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5507 static int drv_cmd_tdls_off_channel_mode(struct wlan_hdd_link_info *link_info,
5508 struct hdd_context *hdd_ctx,
5509 uint8_t *command,
5510 uint8_t command_len,
5511 struct hdd_priv_data *priv_data)
5512 {
5513 int ret;
5514 uint8_t *value = command;
5515 int set_value;
5516
5517 /* Move pointer to point the string */
5518 value += command_len;
5519
5520 ret = sscanf(value, "%d", &set_value);
5521 if (ret != 1)
5522 return -EINVAL;
5523
5524 hdd_debug("Tdls offchannel mode:%d", set_value);
5525
5526 ret = hdd_set_tdls_offchannelmode(hdd_ctx,
5527 link_info->adapter, set_value);
5528
5529 return ret;
5530 }
5531
5532 /**
5533 * drv_cmd_tdls_off_channel() - set tdls off channel number
5534 * @link_info: Link info pointer in HDD adapter
5535 * @hdd_ctx: Pointer to the HDD context
5536 * @command: Driver command string
5537 * @command_len: Driver command string length
5538 * @priv_data: Private data coming with the driver command. Unused here
5539 *
5540 * This function handles driver command that sets tdls off channel number
5541 *
5542 * Return: 0 on success; negative errno otherwise
5543 */
drv_cmd_tdls_off_channel(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5544 static int drv_cmd_tdls_off_channel(struct wlan_hdd_link_info *link_info,
5545 struct hdd_context *hdd_ctx,
5546 uint8_t *command,
5547 uint8_t command_len,
5548 struct hdd_priv_data *priv_data)
5549 {
5550 int ret;
5551 uint8_t *value = command;
5552 int channel;
5553 enum channel_state reg_state;
5554 qdf_freq_t ch_freq;
5555
5556 /* Move pointer to point the string */
5557 value += command_len;
5558
5559 ret = sscanf(value, "%d", &channel);
5560 if (ret != 1)
5561 return -EINVAL;
5562
5563 ch_freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, channel);
5564 reg_state =
5565 wlan_reg_get_channel_state_for_pwrmode(hdd_ctx->pdev, ch_freq,
5566 REG_CURRENT_PWR_MODE);
5567
5568 if (reg_state == CHANNEL_STATE_DFS ||
5569 reg_state == CHANNEL_STATE_DISABLE ||
5570 reg_state == CHANNEL_STATE_INVALID) {
5571 hdd_err("reg state of the channel %d is %d and not supported",
5572 channel, reg_state);
5573 return -EINVAL;
5574 }
5575
5576 hdd_debug("Tdls offchannel num: %d", channel);
5577
5578 ret = hdd_set_tdls_offchannel(hdd_ctx, link_info->adapter, channel);
5579
5580 return ret;
5581 }
5582
5583 /**
5584 * drv_cmd_tdls_scan() - set tdls scan type
5585 * @link_info: Link info pointer in HDD adapter
5586 * @hdd_ctx: Pointer to the HDD context
5587 * @command: Driver command string
5588 * @command_len: Driver command string length
5589 * @priv_data: Private data coming with the driver command. Unused here
5590 *
5591 * This function handles driver command that sets tdls scan type
5592 *
5593 * Return: 0 on success; negative errno otherwise
5594 */
drv_cmd_tdls_scan(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5595 static int drv_cmd_tdls_scan(struct wlan_hdd_link_info *link_info,
5596 struct hdd_context *hdd_ctx,
5597 uint8_t *command, uint8_t command_len,
5598 struct hdd_priv_data *priv_data)
5599 {
5600 int ret;
5601 uint8_t *value = command;
5602 int set_value;
5603
5604 /* Move pointer to point the string */
5605 value += command_len;
5606
5607 ret = sscanf(value, "%d", &set_value);
5608 if (ret != 1)
5609 return -EINVAL;
5610
5611 hdd_debug("Tdls scan type val: %d", set_value);
5612
5613 ret = hdd_set_tdls_scan_type(hdd_ctx, set_value);
5614
5615 return ret;
5616 }
5617 #endif
5618
drv_cmd_get_rssi(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5619 static int drv_cmd_get_rssi(struct wlan_hdd_link_info *link_info,
5620 struct hdd_context *hdd_ctx,
5621 uint8_t *command, uint8_t command_len,
5622 struct hdd_priv_data *priv_data)
5623 {
5624 int ret = 0;
5625 int8_t rssi = 0;
5626 char extra[32];
5627
5628 uint8_t len = 0;
5629
5630 wlan_hdd_get_rssi(link_info, &rssi);
5631
5632 len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi);
5633 len = QDF_MIN(priv_data->total_len, len + 1);
5634
5635 if (copy_to_user(priv_data->buf, &extra, len)) {
5636 hdd_err("Failed to copy data to user buffer");
5637 ret = -EFAULT;
5638 }
5639
5640 return ret;
5641 }
5642
5643 /**
5644 * drv_cmd_get_sap_go_linkspeed() - Driver command to get SAP/P2P Go peer link
5645 * speed
5646 * @link_info: Link info pointer in HDD adapter
5647 * @hdd_ctx: HDD context pointer
5648 * @command: Driver command string
5649 * @command_len: Driver command string length
5650 * @priv_data: Pointer to HDD private data
5651 *
5652 * Return: 0 if linkspeed data is available, negative errno otherwise
5653 */
drv_cmd_get_sap_go_linkspeed(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5654 static int drv_cmd_get_sap_go_linkspeed(struct wlan_hdd_link_info *link_info,
5655 struct hdd_context *hdd_ctx,
5656 uint8_t *command,
5657 uint8_t command_len,
5658 struct hdd_priv_data *priv_data)
5659 {
5660 int ret;
5661 uint32_t link_speed = 0;
5662 char extra[64];
5663 uint8_t len = 0;
5664 struct hdd_adapter *adapter = link_info->adapter;
5665
5666 if (adapter->device_mode == QDF_P2P_GO_MODE ||
5667 adapter->device_mode == QDF_SAP_MODE) {
5668 ret = wlan_hdd_get_sap_go_peer_linkspeed(link_info,
5669 &link_speed,
5670 command,
5671 command_len);
5672 } else {
5673 hdd_err("Link Speed is not allowed in Device mode %s(%d)",
5674 qdf_opmode_str(adapter->device_mode),
5675 adapter->device_mode);
5676 ret = -ENOTSUPP;
5677 }
5678
5679 if (0 != ret)
5680 return ret;
5681
5682 len = scnprintf(extra, sizeof(extra), "%s %d\n",
5683 "SOFT-AP LINKSPEED", link_speed);
5684 len = QDF_MIN(priv_data->total_len, len + 1);
5685 if (copy_to_user(priv_data->buf, &extra, len)) {
5686 hdd_err("Failed to copy data to user buffer");
5687 ret = -EFAULT;
5688 }
5689
5690 return ret;
5691 }
5692
drv_cmd_get_linkspeed(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5693 static int drv_cmd_get_linkspeed(struct wlan_hdd_link_info *link_info,
5694 struct hdd_context *hdd_ctx,
5695 uint8_t *command,
5696 uint8_t command_len,
5697 struct hdd_priv_data *priv_data)
5698 {
5699 int ret;
5700 uint32_t link_speed = 0;
5701 char extra[32];
5702 uint8_t len = 0;
5703
5704 ret = wlan_hdd_get_link_speed(link_info, &link_speed);
5705 if (0 != ret)
5706 return ret;
5707
5708 len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed);
5709 len = QDF_MIN(priv_data->total_len, len + 1);
5710 if (copy_to_user(priv_data->buf, &extra, len)) {
5711 hdd_err("Failed to copy data to user buffer");
5712 ret = -EFAULT;
5713 }
5714
5715 return ret;
5716 }
5717
5718 #ifdef WLAN_FEATURE_PACKET_FILTERING
5719 /**
5720 * hdd_set_rx_filter() - set RX filter
5721 * @adapter: Pointer to adapter
5722 * @action: Filter action
5723 * @pattern: Address pattern
5724 *
5725 * Address pattern is most significant byte of address for example
5726 * 0x01 for IPV4 multicast address
5727 * 0x33 for IPV6 multicast address
5728 * 0xFF for broadcast address
5729 *
5730 * Return: 0 for success, non-zero for failure
5731 */
hdd_set_rx_filter(struct hdd_adapter * adapter,bool action,uint8_t pattern)5732 static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action,
5733 uint8_t pattern)
5734 {
5735 int ret;
5736 uint8_t i, j;
5737 tSirRcvFltMcAddrList *filter;
5738 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
5739 mac_handle_t mac_handle;
5740
5741 ret = wlan_hdd_validate_context(hdd_ctx);
5742 if (0 != ret)
5743 return ret;
5744
5745 mac_handle = hdd_ctx->mac_handle;
5746 if (!mac_handle) {
5747 hdd_err("MAC Handle is NULL");
5748 return -EINVAL;
5749 }
5750
5751 if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) {
5752 hdd_warn("mc addr ini is disabled");
5753 return -EINVAL;
5754 }
5755
5756 /*
5757 * If action is false it means start dropping packets
5758 * Set addr_filter_pattern which will be used when sending
5759 * MC/BC address list to target
5760 */
5761 if (!action)
5762 adapter->addr_filter_pattern = pattern;
5763 else
5764 adapter->addr_filter_pattern = 0;
5765
5766 if (((adapter->device_mode == QDF_STA_MODE) ||
5767 (adapter->device_mode == QDF_P2P_CLIENT_MODE)) &&
5768 adapter->mc_addr_list.mc_cnt &&
5769 hdd_cm_is_vdev_associated(adapter->deflink)) {
5770
5771
5772 filter = qdf_mem_malloc(sizeof(*filter));
5773 if (!filter)
5774 return -ENOMEM;
5775
5776 filter->action = action;
5777 for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) {
5778 if (!memcmp(adapter->mc_addr_list.addr[i],
5779 &pattern, 1)) {
5780 memcpy(filter->multicastAddr[j].bytes,
5781 adapter->mc_addr_list.addr[i],
5782 sizeof(adapter->mc_addr_list.addr[i]));
5783
5784 hdd_debug("%s RX filter : addr ="
5785 QDF_MAC_ADDR_FMT,
5786 action ? "setting" : "clearing",
5787 QDF_MAC_ADDR_REF(filter->multicastAddr[j].bytes));
5788 j++;
5789 }
5790 if (j == SIR_MAX_NUM_MULTICAST_ADDRESS)
5791 break;
5792 }
5793 filter->ulMulticastAddrCnt = j;
5794 /* Set rx filter */
5795 sme_8023_multicast_list(mac_handle, adapter->deflink->vdev_id,
5796 filter);
5797 qdf_mem_free(filter);
5798 } else {
5799 hdd_debug("mode %d mc_cnt %d",
5800 adapter->device_mode, adapter->mc_addr_list.mc_cnt);
5801 }
5802
5803 return 0;
5804 }
5805
5806 /**
5807 * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler
5808 * @command: Pointer to input string driver command
5809 * @adapter: Pointer to adapter
5810 * @action: Action to enable/disable filtering
5811 *
5812 * If action == false
5813 * Start filtering out data packets based on type
5814 * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets
5815 * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets
5816 * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets
5817 * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets
5818 *
5819 * if action == true
5820 * Stop filtering data packets based on type
5821 * RXFILTER-ADD 0 -> Stop filtering unicast data packets
5822 * RXFILTER-ADD 1 -> Stop filtering broadcast data packets
5823 * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets
5824 * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets
5825 *
5826 * Current implementation only supports IPV4 address filtering by
5827 * selectively allowing IPV4 multicast data packest based on
5828 * address list received in .ndo_set_rx_mode
5829 *
5830 * Return: 0 for success, non-zero for failure
5831 */
hdd_driver_rxfilter_command_handler(uint8_t * command,struct hdd_adapter * adapter,bool action)5832 static int hdd_driver_rxfilter_command_handler(uint8_t *command,
5833 struct hdd_adapter *adapter,
5834 bool action)
5835 {
5836 int ret = 0;
5837 uint8_t *value;
5838 uint8_t type;
5839
5840 value = command;
5841 /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */
5842 if (!action)
5843 value = command + 16;
5844 else
5845 value = command + 13;
5846 ret = kstrtou8(value, 10, &type);
5847 if (ret < 0) {
5848 hdd_err("kstrtou8 failed invalid input value");
5849 return -EINVAL;
5850 }
5851
5852 switch (type) {
5853 case 2:
5854 /* Set rx filter for IPV4 multicast data packets */
5855 ret = hdd_set_rx_filter(adapter, action, 0x01);
5856 break;
5857 default:
5858 hdd_debug("Unsupported RXFILTER type %d", type);
5859 break;
5860 }
5861
5862 return ret;
5863 }
5864
5865 /**
5866 * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler
5867 * @link_info: Link info pointer in HDD adapter
5868 * @hdd_ctx: Pointer to hdd context
5869 * @command: Pointer to input command
5870 * @command_len: Command length
5871 * @priv_data: Pointer to private data in command
5872 */
drv_cmd_rx_filter_remove(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5873 static int drv_cmd_rx_filter_remove(struct wlan_hdd_link_info *link_info,
5874 struct hdd_context *hdd_ctx,
5875 uint8_t *command, uint8_t command_len,
5876 struct hdd_priv_data *priv_data)
5877 {
5878 return hdd_driver_rxfilter_command_handler(command,
5879 link_info->adapter, false);
5880 }
5881
5882 /**
5883 * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler
5884 * @link_info: Link info pointer in HDD adapter
5885 * @hdd_ctx: Pointer to hdd context
5886 * @command: Pointer to input command
5887 * @command_len: Command length
5888 * @priv_data: Pointer to private data in command
5889 */
drv_cmd_rx_filter_add(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)5890 static int drv_cmd_rx_filter_add(struct wlan_hdd_link_info *link_info,
5891 struct hdd_context *hdd_ctx,
5892 uint8_t *command, uint8_t command_len,
5893 struct hdd_priv_data *priv_data)
5894 {
5895 return hdd_driver_rxfilter_command_handler(command,
5896 link_info->adapter, true);
5897 }
5898 #endif /* WLAN_FEATURE_PACKET_FILTERING */
5899
5900 /**
5901 * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE
5902 * command
5903 * @value: Pointer to SETANTENNAMODE command
5904 *
5905 * This function parses the SETANTENNAMODE command passed in the format
5906 * SETANTENNAMODE<space>mode
5907 *
5908 * Return: parsed antenna mode
5909 */
hdd_parse_setantennamode_command(const uint8_t * value)5910 static int hdd_parse_setantennamode_command(const uint8_t *value)
5911 {
5912 const uint8_t *in_ptr = value;
5913 int tmp, v;
5914 char arg1[32];
5915
5916 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
5917
5918 /* no argument after the command */
5919 if (!in_ptr) {
5920 hdd_err("No argument after the command");
5921 return -EINVAL;
5922 }
5923
5924 /* no space after the command */
5925 if (SPACE_ASCII_VALUE != *in_ptr) {
5926 hdd_err("No space after the command");
5927 return -EINVAL;
5928 }
5929
5930 /* remove empty spaces */
5931 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
5932 in_ptr++;
5933
5934 /* no argument followed by spaces */
5935 if ('\0' == *in_ptr) {
5936 hdd_err("No argument followed by spaces");
5937 return -EINVAL;
5938 }
5939
5940 /* get the argument i.e. antenna mode */
5941 v = sscanf(in_ptr, "%31s ", arg1);
5942 if (1 != v) {
5943 hdd_err("argument retrieval from cmd string failed");
5944 return -EINVAL;
5945 }
5946
5947 v = kstrtos32(arg1, 10, &tmp);
5948 if (v < 0) {
5949 hdd_err("argument string to int conversion failed");
5950 return -EINVAL;
5951 }
5952
5953 return tmp;
5954 }
5955
5956 /**
5957 * hdd_is_supported_chain_mask_2x2() - Verify if supported chain
5958 * mask is 2x2 mode
5959 * @hdd_ctx: Pointer to hdd context
5960 *
5961 * Return: true if supported chain mask 2x2 else false
5962 */
hdd_is_supported_chain_mask_2x2(struct hdd_context * hdd_ctx)5963 static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx)
5964 {
5965 QDF_STATUS status;
5966 bool bval = false;
5967
5968 /*
5969 * Revisit and the update logic to determine the number
5970 * of TX/RX chains supported in the system when
5971 * antenna sharing per band chain mask support is
5972 * brought in
5973 */
5974 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
5975 if (!QDF_IS_STATUS_SUCCESS(status))
5976 hdd_err("unable to get vht_enable2x2");
5977
5978 return (bval == 0x01) ? true : false;
5979 }
5980
5981 /**
5982 * hdd_is_supported_chain_mask_1x1() - Verify if the supported
5983 * chain mask is 1x1
5984 * @hdd_ctx: Pointer to hdd context
5985 *
5986 * Return: true if supported chain mask 1x1 else false
5987 */
hdd_is_supported_chain_mask_1x1(struct hdd_context * hdd_ctx)5988 static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx)
5989 {
5990 QDF_STATUS status;
5991 bool bval = false;
5992
5993 /*
5994 * Revisit and update the logic to determine the number
5995 * of TX/RX chains supported in the system when
5996 * antenna sharing per band chain mask support is
5997 * brought in
5998 */
5999 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
6000 if (!QDF_IS_STATUS_SUCCESS(status))
6001 hdd_err("unable to get vht_enable2x2");
6002
6003 return (!bval) ? true : false;
6004 }
6005
hdd_update_smps_antenna_mode(struct hdd_context * hdd_ctx,int mode)6006 QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode)
6007 {
6008 mac_handle_t mac_handle = hdd_ctx->mac_handle;
6009
6010 hdd_ctx->current_antenna_mode = mode;
6011 /*
6012 * Update the user requested nss in the mac context.
6013 * This will be used in tdls protocol engine to form tdls
6014 * Management frames.
6015 */
6016 sme_update_user_configured_nss(mac_handle,
6017 hdd_ctx->current_antenna_mode);
6018
6019 hdd_debug("Successfully switched to mode: %d x %d",
6020 hdd_ctx->current_antenna_mode,
6021 hdd_ctx->current_antenna_mode);
6022
6023 return QDF_STATUS_SUCCESS;
6024 }
6025
6026 /**
6027 * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode
6028 * @status: Status of set antenna mode
6029 * @context: callback context
6030 *
6031 * Callback on setting antenna mode
6032 *
6033 * Return: None
6034 */
6035 static void
wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,void * context)6036 wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status,
6037 void *context)
6038 {
6039 struct osif_request *request = NULL;
6040
6041 hdd_debug("Status: %d", status);
6042
6043 request = osif_request_get(context);
6044 if (!request) {
6045 hdd_err("obsolete request");
6046 return;
6047 }
6048
6049 /* Signal the completion of set dual mac config */
6050 osif_request_complete(request);
6051 osif_request_put(request);
6052 }
6053
hdd_set_antenna_mode(struct wlan_hdd_link_info * link_info,int mode)6054 int hdd_set_antenna_mode(struct wlan_hdd_link_info *link_info, int mode)
6055 {
6056 struct hdd_adapter *adapter = link_info->adapter;
6057 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6058 struct sir_antenna_mode_param params;
6059 QDF_STATUS status;
6060 int ret = 0;
6061 struct osif_request *request = NULL;
6062 static const struct osif_request_params request_params = {
6063 .priv_size = 0,
6064 .timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
6065 };
6066
6067 if (QDF_STATUS_SUCCESS ==
6068 wlan_is_tdls_session_present(link_info->vdev)) {
6069 hdd_debug("TDLS session exists");
6070 ret = -EINVAL;
6071 goto exit;
6072 }
6073
6074 switch (mode) {
6075 case HDD_ANTENNA_MODE_1X1:
6076 params.num_rx_chains = 1;
6077 params.num_tx_chains = 1;
6078 break;
6079 case HDD_ANTENNA_MODE_2X2:
6080 params.num_rx_chains = 2;
6081 params.num_tx_chains = 2;
6082 break;
6083 default:
6084 hdd_err("unsupported antenna mode");
6085 ret = -EINVAL;
6086 goto exit;
6087 }
6088
6089 if (hdd_ctx->dynamic_nss_chains_support)
6090 return hdd_set_dynamic_antenna_mode(link_info,
6091 params.num_rx_chains,
6092 params.num_tx_chains);
6093
6094 if ((HDD_ANTENNA_MODE_2X2 == mode) &&
6095 (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) {
6096 hdd_err("System does not support 2x2 mode");
6097 ret = -EPERM;
6098 goto exit;
6099 }
6100
6101 if ((HDD_ANTENNA_MODE_1X1 == mode) &&
6102 hdd_is_supported_chain_mask_1x1(hdd_ctx)) {
6103 hdd_err("System only supports 1x1 mode");
6104 goto exit;
6105 }
6106
6107 /* Check TDLS status and update antenna mode */
6108 if ((QDF_STA_MODE == adapter->device_mode) &&
6109 policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) {
6110 ret = wlan_hdd_tdls_antenna_switch(link_info, mode);
6111 if (0 != ret)
6112 goto exit;
6113 }
6114
6115 request = osif_request_alloc(&request_params);
6116 if (!request) {
6117 hdd_err("Request Allocation Failure");
6118 ret = -ENOMEM;
6119 goto exit;
6120 }
6121
6122 params.set_antenna_mode_ctx = osif_request_cookie(request);
6123 params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb;
6124 hdd_debug("Set antenna mode rx chains: %d tx chains: %d",
6125 params.num_rx_chains,
6126 params.num_tx_chains);
6127
6128 status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, ¶ms);
6129 if (QDF_IS_STATUS_ERROR(status)) {
6130 hdd_err("set antenna mode failed status : %d", status);
6131 ret = -EFAULT;
6132 goto request_put;
6133 }
6134
6135 ret = osif_request_wait_for_response(request);
6136 if (ret) {
6137 hdd_err("send set antenna mode timed out");
6138 goto request_put;
6139 }
6140
6141 status = hdd_update_smps_antenna_mode(hdd_ctx, mode);
6142 if (QDF_STATUS_SUCCESS != status) {
6143 ret = -EFAULT;
6144 goto request_put;
6145 }
6146 ret = 0;
6147 request_put:
6148 osif_request_put(request);
6149 exit:
6150 hdd_debug("Set antenna status: %d current mode: %d",
6151 ret, hdd_ctx->current_antenna_mode);
6152
6153 return ret;
6154 }
6155
6156 /**
6157 * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command
6158 * handler
6159 * @link_info: Link info pointer in HDD adapter
6160 * @hdd_ctx: Pointer to hdd context
6161 * @command: Pointer to input command
6162 * @command_len: Command length
6163 * @priv_data: Pointer to private data in command
6164 */
drv_cmd_set_antenna_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6165 static int drv_cmd_set_antenna_mode(struct wlan_hdd_link_info *link_info,
6166 struct hdd_context *hdd_ctx,
6167 uint8_t *command, uint8_t command_len,
6168 struct hdd_priv_data *priv_data)
6169 {
6170 int mode;
6171 uint8_t *value = command;
6172
6173 mode = hdd_parse_setantennamode_command(value);
6174 if (mode < 0) {
6175 hdd_err("Invalid SETANTENNA command");
6176 return mode;
6177 }
6178
6179 hdd_debug("Processing antenna mode switch to: %d", mode);
6180
6181 return hdd_set_antenna_mode(link_info, mode);
6182 }
6183
6184 /**
6185 * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev
6186 * @antenna_mode: pointer to antenna mode of vdev
6187 * @dynamic_nss_chains_support: feature support for dynamic nss chains update
6188 * @vdev: Pointer to vdev
6189 *
6190 * This API will check for the num of chains configured for the vdev, and fill
6191 * that info in the antenna mode if the dynamic chains per vdev are supported.
6192 *
6193 * Return: None
6194 */
6195 static void
hdd_get_dynamic_antenna_mode(uint32_t * antenna_mode,bool dynamic_nss_chains_support,struct wlan_objmgr_vdev * vdev)6196 hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode,
6197 bool dynamic_nss_chains_support,
6198 struct wlan_objmgr_vdev *vdev)
6199 {
6200 struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg;
6201
6202 if (!dynamic_nss_chains_support)
6203 return;
6204
6205 nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev);
6206 if (!nss_chains_dynamic_cfg) {
6207 hdd_err("nss chain dynamic config NULL");
6208 return;
6209 }
6210 /*
6211 * At present, this command doesn't include band, so by default
6212 * it will return the band 2ghz present rf chains.
6213 */
6214 *antenna_mode =
6215 nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
6216 }
6217
6218 /**
6219 * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command
6220 * handler
6221 * @link_info: Link info pointer in HDD adapter
6222 * @hdd_ctx: Pointer to hdd context
6223 * @command: Pointer to input command
6224 * @command_len: length of the command
6225 * @priv_data: private data coming with the driver command
6226 *
6227 * Return: 0 for success non-zero for failure
6228 */
drv_cmd_get_antenna_mode(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6229 static inline int drv_cmd_get_antenna_mode(struct wlan_hdd_link_info *link_info,
6230 struct hdd_context *hdd_ctx,
6231 uint8_t *command,
6232 uint8_t command_len,
6233 struct hdd_priv_data *priv_data)
6234 {
6235 uint32_t antenna_mode = 0;
6236 char extra[32];
6237 uint8_t len = 0;
6238 struct wlan_objmgr_vdev *vdev;
6239
6240 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
6241 if (!vdev) {
6242 hdd_err("vdev is NULL");
6243 return -EINVAL;
6244 }
6245
6246 antenna_mode = hdd_ctx->current_antenna_mode;
6247 /* Overwrite this antenna mode if dynamic vdev chains are supported */
6248 hdd_get_dynamic_antenna_mode(&antenna_mode,
6249 hdd_ctx->dynamic_nss_chains_support, vdev);
6250 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
6251 len = scnprintf(extra, sizeof(extra), "%s %d", command,
6252 antenna_mode);
6253 len = QDF_MIN(priv_data->total_len, len + 1);
6254 if (copy_to_user(priv_data->buf, &extra, len)) {
6255 hdd_err("Failed to copy data to user buffer");
6256 return -EFAULT;
6257 }
6258
6259 hdd_debug("Get antenna mode: %d", antenna_mode);
6260
6261 return 0;
6262 }
6263
6264 /*
6265 * dummy (no-op) hdd driver command handler
6266 */
drv_cmd_dummy(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6267 static int drv_cmd_dummy(struct wlan_hdd_link_info *link_info,
6268 struct hdd_context *hdd_ctx,
6269 uint8_t *command,
6270 uint8_t command_len,
6271 struct hdd_priv_data *priv_data)
6272 {
6273 hdd_debug("%s: Ignoring driver command \"%s\"",
6274 link_info->adapter->dev->name, command);
6275 return 0;
6276 }
6277
6278 /*
6279 * handler for any unsupported wlan hdd driver command
6280 */
drv_cmd_invalid(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6281 static int drv_cmd_invalid(struct hdd_adapter *adapter,
6282 struct hdd_context *hdd_ctx,
6283 uint8_t *command,
6284 uint8_t command_len,
6285 struct hdd_priv_data *priv_data)
6286 {
6287 qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
6288 TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
6289 adapter->deflink->vdev_id, 0);
6290
6291 hdd_debug("%s: Unsupported driver command \"%s\"",
6292 adapter->dev->name, command);
6293
6294 return -ENOTSUPP;
6295 }
6296
6297 /**
6298 * hdd_apply_fcc_constraint() - Set FCC constraint
6299 * @hdd_ctx: Pointer to hdd context
6300 * @fcc_constraint: Fcc constraint flag
6301 *
6302 * Return: Return 0 incase of success else return error number
6303 */
hdd_apply_fcc_constraint(struct hdd_context * hdd_ctx,bool fcc_constraint)6304 static int hdd_apply_fcc_constraint(struct hdd_context *hdd_ctx,
6305 bool fcc_constraint)
6306 {
6307 QDF_STATUS status;
6308
6309 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev,
6310 fcc_constraint);
6311 if (QDF_IS_STATUS_ERROR(status)) {
6312 hdd_err("Failed to update tx power for channels 12/13");
6313 return qdf_status_to_os_return(status);
6314 }
6315
6316 status = wlan_reg_recompute_current_chan_list(hdd_ctx->psoc,
6317 hdd_ctx->pdev);
6318 if (QDF_IS_STATUS_ERROR(status)) {
6319 hdd_err("Failed to update tx power for channels 12/13");
6320 return qdf_status_to_os_return(status);
6321 }
6322
6323 return 0;
6324 }
6325
6326 /**
6327 * hdd_apply_fcc_constraint_update_band() - Set FCC constraint and update band
6328 * @link_info: Link info pointer in HDD adapter
6329 * @hdd_ctx: Pointer to hdd context
6330 * @fcc_constraint: FCC constraint flag
6331 * @dis_6g_keep_sta_cli_conn: Disable 6 GHz band and keep STA, P2P client
6332 * connection flag
6333 * @band_bitmap: Band bitmap
6334 *
6335 * Return: Return 0 incase of success else return error number
6336 */
6337 static int
hdd_apply_fcc_constraint_update_band(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,bool fcc_constraint,bool dis_6g_keep_sta_cli_conn,uint32_t band_bitmap)6338 hdd_apply_fcc_constraint_update_band(struct wlan_hdd_link_info *link_info,
6339 struct hdd_context *hdd_ctx,
6340 bool fcc_constraint,
6341 bool dis_6g_keep_sta_cli_conn,
6342 uint32_t band_bitmap)
6343 {
6344 QDF_STATUS status;
6345
6346 status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev,
6347 fcc_constraint);
6348 if (status) {
6349 hdd_err("Failed to update tx power for channels 12/13");
6350 return qdf_status_to_os_return(status);
6351 }
6352
6353 status = ucfg_reg_set_keep_6ghz_sta_cli_connection(hdd_ctx->pdev,
6354 dis_6g_keep_sta_cli_conn);
6355 if (QDF_IS_STATUS_ERROR(status)) {
6356 hdd_err("Failed to update keep sta cli connection");
6357 return qdf_status_to_os_return(status);
6358 }
6359
6360 return hdd_reg_set_band(link_info->adapter->dev, band_bitmap);
6361 }
6362
6363 /**
6364 * drv_cmd_set_fcc_channel() - Handle fcc constraint request
6365 * @link_info: Link info pointer in HDD adapter
6366 * @hdd_ctx: HDD context
6367 * @command: command ptr, SET_FCC_CHANNEL 0/1/2/-1 is the command
6368 * @command_len: command len
6369 * @priv_data: private data
6370 *
6371 * Return: status
6372 */
drv_cmd_set_fcc_channel(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6373 static int drv_cmd_set_fcc_channel(struct wlan_hdd_link_info *link_info,
6374 struct hdd_context *hdd_ctx,
6375 uint8_t *command, uint8_t command_len,
6376 struct hdd_priv_data *priv_data)
6377 {
6378 QDF_STATUS status;
6379 QDF_STATUS status_6G = QDF_STATUS_SUCCESS;
6380 int8_t input_value;
6381 int err;
6382 uint32_t band_bitmap = 0, curr_band_bitmap;
6383 bool rf_test_mode, fcc_constraint, dis_6g_keep_sta_cli_conn;
6384 bool modify_band = false;
6385
6386 /*
6387 * This command would be called by user-space when it detects WLAN
6388 * ON after airplane mode is set. When APM is set, WLAN turns off.
6389 * But it can be turned back on. Otherwise; when APM is turned back
6390 * off, WLAN would turn back on. So at that point the command is
6391 * expected to come down.
6392 * a) 0 means reduce power as per fcc constraint and disable 6 GHz band
6393 * but keep existing STA/P2P Client connections intact.
6394 * b) 1 means reduce power as per fcc constraint and enable 6 GHz band.
6395 * c) 2 means reset fcc constraint but disable 6 GHz band but keep
6396 * existing STA/P2P Client connections intact.
6397 * d) -1 means reset fcc constraint and enable 6 GHz band.
6398 */
6399
6400 err = kstrtos8(command + command_len + 1, 10, &input_value);
6401 if (err) {
6402 hdd_err("error %d parsing userspace fcc parameter", err);
6403 return err;
6404 }
6405
6406 hdd_debug("input_value = %d", input_value);
6407
6408 switch (input_value) {
6409 case -1:
6410 fcc_constraint = false;
6411 dis_6g_keep_sta_cli_conn = false;
6412 break;
6413 case 0:
6414 fcc_constraint = true;
6415 dis_6g_keep_sta_cli_conn = true;
6416 break;
6417 case 1:
6418 fcc_constraint = true;
6419 dis_6g_keep_sta_cli_conn = false;
6420 break;
6421 case 2:
6422 fcc_constraint = false;
6423 dis_6g_keep_sta_cli_conn = true;
6424 break;
6425 default:
6426 hdd_err("Invalie input value");
6427 return -EINVAL;
6428 }
6429
6430 status = ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc,
6431 &rf_test_mode);
6432 if (!QDF_IS_STATUS_SUCCESS(status_6G)) {
6433 hdd_err("Get rf test mode failed");
6434 return qdf_status_to_os_return(status);
6435 }
6436
6437 if (!rf_test_mode) {
6438 status = ucfg_reg_get_band(hdd_ctx->pdev, &curr_band_bitmap);
6439 if (!QDF_IS_STATUS_SUCCESS(status)) {
6440 hdd_err("failed to get band");
6441 return qdf_status_to_os_return(status);
6442 }
6443
6444 if (dis_6g_keep_sta_cli_conn) {
6445 band_bitmap |= (BIT(REG_BAND_5G) | BIT(REG_BAND_2G));
6446 } else {
6447 if (wlan_reg_is_6ghz_supported(hdd_ctx->psoc))
6448 band_bitmap = REG_BAND_MASK_ALL;
6449 else
6450 band_bitmap = curr_band_bitmap;
6451 }
6452
6453 hdd_debug("Current band bitmap = %d, set band bitmap = %d",
6454 curr_band_bitmap,
6455 band_bitmap);
6456
6457 if (band_bitmap != curr_band_bitmap)
6458 modify_band = true;
6459
6460 if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) ==
6461 fcc_constraint &&
6462 ucfg_reg_get_keep_6ghz_sta_cli_connection(hdd_ctx->pdev) ==
6463 dis_6g_keep_sta_cli_conn) {
6464 hdd_debug("Same FCC constraint and band bitmap value");
6465 return 0;
6466 } else if (modify_band) {
6467 return hdd_apply_fcc_constraint_update_band(link_info,
6468 hdd_ctx,
6469 fcc_constraint,
6470 dis_6g_keep_sta_cli_conn,
6471 band_bitmap);
6472 }
6473 } else {
6474 if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) ==
6475 fcc_constraint) {
6476 hdd_debug("Same FCC constraint value");
6477 return 0;
6478 }
6479 }
6480
6481 return hdd_apply_fcc_constraint(hdd_ctx, fcc_constraint);
6482 }
6483
6484 /**
6485 * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH
6486 * command
6487 * @value: Pointer to the command
6488 * @chan_number: Pointer to the channel number
6489 * @chan_bw: Pointer to the channel bandwidth
6490 *
6491 * Parses and provides the channel number and channel width from the input
6492 * command which is expected to be of the format: CHANNEL_SWITCH <CH> <BW>
6493 * <CH> is channel number to move (where 1 = channel 1, 149 = channel 149, ...)
6494 * <BW> is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80)
6495 *
6496 * Return: 0 for success, non-zero for failure
6497 */
hdd_parse_set_channel_switch_command(uint8_t * value,uint32_t * chan_number,uint32_t * chan_bw)6498 static int hdd_parse_set_channel_switch_command(uint8_t *value,
6499 uint32_t *chan_number,
6500 uint32_t *chan_bw)
6501 {
6502 const uint8_t *in_ptr = value;
6503 int ret;
6504
6505 in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE);
6506
6507 /* no argument after the command */
6508 if (!in_ptr) {
6509 hdd_err("No argument after the command");
6510 return -EINVAL;
6511 }
6512
6513 /* no space after the command */
6514 if (SPACE_ASCII_VALUE != *in_ptr) {
6515 hdd_err("No space after the command ");
6516 return -EINVAL;
6517 }
6518
6519 /* remove empty spaces and move the next argument */
6520 while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr))
6521 in_ptr++;
6522
6523 /* no argument followed by spaces */
6524 if ('\0' == *in_ptr) {
6525 hdd_err("No argument followed by spaces");
6526 return -EINVAL;
6527 }
6528
6529 /* get the two arguments: channel number and bandwidth */
6530 ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw);
6531 if (ret != 2) {
6532 hdd_err("Arguments retrieval from cmd string failed");
6533 return -EINVAL;
6534 }
6535
6536 return 0;
6537 }
6538
6539 /**
6540 * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel
6541 * @link_info: Link info pointer in HDD adapter
6542 * @hdd_ctx: HDD context
6543 * @command: Pointer to the input command CHANNEL_SWITCH
6544 * @command_len: Command len
6545 * @priv_data: Private data
6546 *
6547 * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel
6548 * of SAP/P2P-GO
6549 *
6550 * Return: 0 for success, non-zero for failure
6551 */
drv_cmd_set_channel_switch(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6552 static int drv_cmd_set_channel_switch(struct wlan_hdd_link_info *link_info,
6553 struct hdd_context *hdd_ctx,
6554 uint8_t *command, uint8_t command_len,
6555 struct hdd_priv_data *priv_data)
6556 {
6557 struct hdd_adapter *adapter = link_info->adapter;
6558 struct net_device *dev = adapter->dev;
6559 int status;
6560 uint32_t chan_number = 0, chan_bw = 0;
6561 uint8_t *value = command;
6562 enum phy_ch_width width;
6563
6564 if ((adapter->device_mode != QDF_P2P_GO_MODE) &&
6565 (adapter->device_mode != QDF_SAP_MODE)) {
6566 hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d",
6567 adapter->device_mode);
6568 return -EINVAL;
6569 }
6570
6571 if (!qdf_atomic_test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) {
6572 hdd_err("SAP not started");
6573 return -EINVAL;
6574 }
6575
6576 status = hdd_parse_set_channel_switch_command(value,
6577 &chan_number, &chan_bw);
6578 if (status) {
6579 hdd_err("Invalid CHANNEL_SWITCH command");
6580 return status;
6581 }
6582
6583 if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80) &&
6584 (chan_bw != 160)) {
6585 hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw);
6586 return -EINVAL;
6587 }
6588
6589 if (chan_bw == 160)
6590 width = CH_WIDTH_160MHZ;
6591 else if (chan_bw == 80)
6592 width = CH_WIDTH_80MHZ;
6593 else if (chan_bw == 40)
6594 width = CH_WIDTH_40MHZ;
6595 else
6596 width = CH_WIDTH_20MHZ;
6597
6598 hdd_debug("CH:%d BW:%d", chan_number, chan_bw);
6599
6600 wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, link_info->vdev_id,
6601 CSA_REASON_USER_INITIATED);
6602
6603 if (chan_number <= wlan_reg_max_5ghz_ch_num())
6604 chan_number = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev,
6605 chan_number);
6606
6607 status = hdd_softap_set_channel_change(dev, chan_number, width, false);
6608 if (status) {
6609 hdd_err("Set channel change fail");
6610 return status;
6611 }
6612
6613 return 0;
6614 }
6615
6616 #ifdef DISABLE_CHANNEL_LIST
wlan_hdd_free_cache_channels(struct hdd_context * hdd_ctx)6617 void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
6618 {
6619 hdd_enter();
6620
6621 if (!hdd_ctx->original_channels)
6622 return;
6623
6624 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
6625 hdd_ctx->original_channels->num_channels = 0;
6626 if (hdd_ctx->original_channels->channel_info) {
6627 qdf_mem_free(hdd_ctx->original_channels->channel_info);
6628 hdd_ctx->original_channels->channel_info = NULL;
6629 }
6630 qdf_mem_free(hdd_ctx->original_channels);
6631 hdd_ctx->original_channels = NULL;
6632 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6633
6634 hdd_exit();
6635 }
6636
6637 /**
6638 * hdd_alloc_chan_cache() - Allocate the memory to cache the channel
6639 * info for the channels received in command SET_DISABLE_CHANNEL_LIST
6640 * @hdd_ctx: Pointer to HDD context
6641 * @num_chan: Number of channels for which memory needs to
6642 * be allocated
6643 *
6644 * Return: 0 on success and error code on failure
6645 */
hdd_alloc_chan_cache(struct hdd_context * hdd_ctx,int num_chan)6646 static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan)
6647 {
6648 hdd_ctx->original_channels =
6649 qdf_mem_malloc(sizeof(struct hdd_cache_channels));
6650 if (!hdd_ctx->original_channels)
6651 return -ENOMEM;
6652
6653 hdd_ctx->original_channels->num_channels = num_chan;
6654 hdd_ctx->original_channels->channel_info =
6655 qdf_mem_malloc(num_chan *
6656 sizeof(struct hdd_cache_channel_info));
6657 if (!hdd_ctx->original_channels->channel_info) {
6658 hdd_ctx->original_channels->num_channels = 0;
6659 qdf_mem_free(hdd_ctx->original_channels);
6660 hdd_ctx->original_channels = NULL;
6661 return -ENOMEM;
6662 }
6663 return 0;
6664 }
6665
6666 /**
6667 * check_disable_channels() - Check for disable channel
6668 * @hdd_ctx: Pointer to hdd context
6669 * @operating_freq: Current operating frequency of adapter
6670 *
6671 * This function checks original_channels array for a specific channel
6672 *
6673 * Return: 0 if channel not found, 1 if channel found
6674 */
check_disable_channels(struct hdd_context * hdd_ctx,qdf_freq_t operating_freq)6675 static bool check_disable_channels(struct hdd_context *hdd_ctx,
6676 qdf_freq_t operating_freq)
6677 {
6678 uint32_t num_channels;
6679 uint8_t i;
6680 if (!hdd_ctx || !hdd_ctx->original_channels ||
6681 !hdd_ctx->original_channels->channel_info)
6682 return false;
6683
6684 num_channels = hdd_ctx->original_channels->num_channels;
6685 for (i = 0; i < num_channels; i++) {
6686 if (operating_freq ==
6687 hdd_ctx->original_channels->channel_info[i].freq)
6688 return true;
6689 }
6690
6691 return false;
6692 }
6693
6694 /**
6695 * disconnect_sta_and_restart_sap() - Disconnect STA and restart SAP
6696 *
6697 * @hdd_ctx: Pointer to hdd context
6698 * @reason: Disconnect reason code as per @enum wlan_reason_code
6699 *
6700 * Disable channels provided by user and disconnect STA if it is
6701 * connected to any AP, restart SAP.
6702 *
6703 * Return: None
6704 */
disconnect_sta_and_restart_sap(struct hdd_context * hdd_ctx,enum wlan_reason_code reason)6705 static void disconnect_sta_and_restart_sap(struct hdd_context *hdd_ctx,
6706 enum wlan_reason_code reason)
6707 {
6708 struct hdd_adapter *adapter, *next = NULL;
6709 QDF_STATUS status;
6710 struct hdd_ap_ctx *ap_ctx;
6711 uint32_t ch_list[NUM_CHANNELS];
6712 uint32_t ch_count = 0;
6713 bool is_valid_chan_present = true;
6714
6715 if (!hdd_ctx)
6716 return;
6717
6718 hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason);
6719
6720 status = policy_mgr_get_valid_chans(hdd_ctx->psoc, ch_list, &ch_count);
6721 if (QDF_IS_STATUS_ERROR(status) || !ch_count) {
6722 hdd_debug("No valid channels present, stop the SAPs");
6723 is_valid_chan_present = false;
6724 }
6725
6726 status = hdd_get_front_adapter(hdd_ctx, &adapter);
6727 while (adapter && (status == QDF_STATUS_SUCCESS)) {
6728 if (hdd_validate_adapter(adapter) ||
6729 adapter->device_mode != QDF_SAP_MODE) {
6730 goto next_adapter;
6731 }
6732
6733 ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink);
6734 if (!is_valid_chan_present)
6735 wlan_hdd_stop_sap(adapter);
6736 else if (check_disable_channels(hdd_ctx,
6737 ap_ctx->operating_chan_freq))
6738 policy_mgr_check_sap_restart(hdd_ctx->psoc,
6739 adapter->deflink->vdev_id);
6740 next_adapter:
6741 status = hdd_get_next_adapter(hdd_ctx, adapter, &next);
6742 adapter = next;
6743 }
6744 }
6745
6746 /**
6747 * hdd_check_chan_and_fill_freq() - to validate chan and convert into freq
6748 * @pdev: The physical dev to cache the channels for
6749 * @in_chan: input as channel number or freq
6750 * @freq: frequency for input in_chan (output parameter)
6751 *
6752 * This function checks input "in_chan" is channel number, if yes then fills
6753 * appropriate frequency into "freq" out param. If the "in_param" is greater
6754 * than MAX_5GHZ_CHANNEL then gets the valid frequencies for legacy channels
6755 * else get the valid channel for 6Ghz frequency.
6756 *
6757 * Return: true if "in_chan" is valid channel/frequency; false otherwise
6758 */
hdd_check_chan_and_fill_freq(struct wlan_objmgr_pdev * pdev,uint32_t * in_chan,qdf_freq_t * freq)6759 static bool hdd_check_chan_and_fill_freq(struct wlan_objmgr_pdev *pdev,
6760 uint32_t *in_chan, qdf_freq_t *freq)
6761 {
6762 if (IS_CHANNEL_VALID(*in_chan)) {
6763 *freq = wlan_reg_legacy_chan_to_freq(pdev, *in_chan);
6764 } else if (WLAN_REG_IS_24GHZ_CH_FREQ(*in_chan) ||
6765 WLAN_REG_IS_5GHZ_CH_FREQ(*in_chan) ||
6766 WLAN_REG_IS_6GHZ_CHAN_FREQ(*in_chan)) {
6767 *freq = *in_chan;
6768 *in_chan = wlan_reg_freq_to_chan(pdev, *in_chan);
6769 } else {
6770 return false;
6771 }
6772
6773 return true;
6774 }
6775
6776 /**
6777 * hdd_parse_disable_chan_cmd() - Parse the channel list received
6778 * in command.
6779 * @adapter: pointer to hdd adapter
6780 * @ptr: Pointer to the command string
6781 *
6782 * This function parses the channel list/frequency received in the command.
6783 * command should be a string having format
6784 * SET_DISABLE_CHANNEL_LIST <num of channels>
6785 * <channels separated by spaces>/<frequency separated by spaces>.
6786 * If this command has frequency as input, this function first converts into
6787 * equivalent channel.
6788 * If the command comes multiple times then the channels received in the
6789 * command or channels converted from frequency will be compared with the
6790 * channels cached in the first command, if the channel list matches with
6791 * the cached channels, it returns success otherwise returns failure.
6792 *
6793 * Return: 0 on success, Error code on failure
6794 */
6795
hdd_parse_disable_chan_cmd(struct hdd_adapter * adapter,uint8_t * ptr)6796 static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr)
6797 {
6798 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
6799 uint8_t *param;
6800 int j, i, temp_int, ret = 0, num_channels;
6801 qdf_freq_t *chan_freq_list = NULL;
6802 bool is_command_repeated = false;
6803 qdf_freq_t freq = 0;
6804
6805 if (!hdd_ctx) {
6806 hdd_err("HDD Context is NULL");
6807 return -EINVAL;
6808 }
6809
6810 param = strnchr(ptr, strlen(ptr), ' ');
6811 /*no argument after the command*/
6812 if (!param)
6813 return -EINVAL;
6814
6815 /*no space after the command*/
6816 else if (SPACE_ASCII_VALUE != *param)
6817 return -EINVAL;
6818
6819 param++;
6820
6821 /*removing empty spaces*/
6822 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
6823 param++;
6824
6825 /*no argument followed by spaces*/
6826 if ('\0' == *param)
6827 return -EINVAL;
6828
6829 /*getting the first argument ie the number of channels*/
6830 if (sscanf(param, "%d ", &temp_int) != 1) {
6831 hdd_err("Cannot get number of channels from input");
6832 return -EINVAL;
6833 }
6834
6835 if (temp_int < 0 || temp_int > NUM_CHANNELS) {
6836 hdd_err("Invalid Number of channel received");
6837 return -EINVAL;
6838 }
6839
6840 hdd_debug("Number of channel to disable are: %d", temp_int);
6841
6842 if (!temp_int) {
6843 /*
6844 * Restore and Free the cache channels when the command is
6845 * received with num channels as 0
6846 */
6847 wlan_hdd_restore_channels(hdd_ctx);
6848 return 0;
6849 }
6850
6851 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
6852
6853 if (!hdd_ctx->original_channels) {
6854 if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) {
6855 ret = -ENOMEM;
6856 goto mem_alloc_failed;
6857 }
6858 } else if (hdd_ctx->original_channels->num_channels != temp_int) {
6859 hdd_err("Invalid Number of channels");
6860 ret = -EINVAL;
6861 is_command_repeated = true;
6862 goto parse_failed;
6863 } else {
6864 is_command_repeated = true;
6865 }
6866 num_channels = temp_int;
6867
6868 chan_freq_list = qdf_mem_malloc(num_channels * sizeof(qdf_freq_t));
6869 if (!chan_freq_list)
6870 return -ENOMEM;
6871
6872 for (j = 0; j < num_channels; j++) {
6873 /*
6874 * param pointing to the beginning of first space
6875 * after number of channels
6876 */
6877 param = strpbrk(param, " ");
6878 /*no channel list after the number of channels argument*/
6879 if (!param) {
6880 hdd_err("Invalid No of channel provided in the list");
6881 ret = -EINVAL;
6882 goto parse_failed;
6883 }
6884
6885 param++;
6886
6887 /*removing empty space*/
6888 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
6889 param++;
6890
6891 if ('\0' == *param) {
6892 hdd_err("No channel is provided in the list");
6893 ret = -EINVAL;
6894 goto parse_failed;
6895 }
6896
6897 if (sscanf(param, "%d ", &temp_int) != 1) {
6898 hdd_err("Cannot read channel number");
6899 ret = -EINVAL;
6900 goto parse_failed;
6901 }
6902
6903 if (!hdd_check_chan_and_fill_freq(hdd_ctx->pdev, &temp_int,
6904 &freq)) {
6905 hdd_err("Invalid channel number received");
6906 ret = -EINVAL;
6907 goto parse_failed;
6908 }
6909
6910 hdd_debug("channel[%d] = %d Frequency[%d] = %d", j, temp_int,
6911 j, freq);
6912 chan_freq_list[j] = freq;
6913 }
6914
6915 /*extra arguments check*/
6916 param = strpbrk(param, " ");
6917 if (param) {
6918 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
6919 param++;
6920
6921 if ('\0' != *param) {
6922 hdd_err("Invalid argument received");
6923 ret = -EINVAL;
6924 goto parse_failed;
6925 }
6926 }
6927
6928 /*
6929 * If command is received first time, cache the channels to
6930 * be disabled else compare the channels received in the
6931 * command with the cached channels, if channel list matches
6932 * return success otherwise return failure.
6933 */
6934 if (!is_command_repeated) {
6935 for (j = 0; j < num_channels; j++)
6936 hdd_ctx->original_channels->channel_info[j].freq =
6937 chan_freq_list[j];
6938
6939 /* Cache the channel list in regulatory also */
6940 ucfg_reg_cache_channel_freq_state(hdd_ctx->pdev,
6941 chan_freq_list,
6942 num_channels);
6943 } else {
6944 for (i = 0; i < num_channels; i++) {
6945 for (j = 0; j < num_channels; j++)
6946 if (hdd_ctx->original_channels->
6947 channel_info[i].freq ==
6948 chan_freq_list[j])
6949 break;
6950 if (j == num_channels) {
6951 ret = -EINVAL;
6952 goto parse_failed;
6953 }
6954 }
6955 ret = 0;
6956 }
6957 mem_alloc_failed:
6958 if (chan_freq_list)
6959 qdf_mem_free(chan_freq_list);
6960 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6961 /* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */
6962 if (!is_command_repeated && hdd_ctx->original_channels) {
6963 ret = wlan_hdd_disable_channels(hdd_ctx);
6964 if (ret)
6965 return ret;
6966 disconnect_sta_and_restart_sap(
6967 hdd_ctx,
6968 REASON_OPER_CHANNEL_BAND_CHANGE);
6969 }
6970
6971 hdd_exit();
6972
6973 return ret;
6974
6975 parse_failed:
6976 if (!is_command_repeated)
6977 wlan_hdd_free_cache_channels(hdd_ctx);
6978
6979 if (chan_freq_list)
6980 qdf_mem_free(chan_freq_list);
6981 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
6982 hdd_exit();
6983
6984 return ret;
6985 }
6986
drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)6987 static int drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info,
6988 struct hdd_context *hdd_ctx,
6989 uint8_t *command,
6990 uint8_t command_len,
6991 struct hdd_priv_data *priv_data)
6992 {
6993 return hdd_parse_disable_chan_cmd(link_info->adapter, command);
6994 }
6995
6996 /**
6997 * hdd_get_disable_ch_list() - get disable channel list
6998 * @hdd_ctx: hdd context
6999 * @buf: buffer to hold disable channel list
7000 * @buf_len: buffer length
7001 *
7002 * Return: length of data copied to buf
7003 */
hdd_get_disable_ch_list(struct hdd_context * hdd_ctx,uint8_t * buf,uint32_t buf_len)7004 static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf,
7005 uint32_t buf_len)
7006 {
7007 struct hdd_cache_channel_info *ch_list;
7008 unsigned char i, num_ch;
7009 int len = 0;
7010
7011 qdf_mutex_acquire(&hdd_ctx->cache_channel_lock);
7012 if (hdd_ctx->original_channels &&
7013 hdd_ctx->original_channels->num_channels &&
7014 hdd_ctx->original_channels->channel_info) {
7015 num_ch = hdd_ctx->original_channels->num_channels;
7016
7017 len = scnprintf(buf, buf_len, "%s %hhu",
7018 "GET_DISABLE_CHANNEL_LIST", num_ch);
7019 ch_list = hdd_ctx->original_channels->channel_info;
7020 for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) {
7021 len += scnprintf(buf + len, buf_len - len,
7022 " %d",
7023 wlan_reg_freq_to_chan(hdd_ctx->pdev,
7024 ch_list[i].freq));
7025 }
7026 }
7027 qdf_mutex_release(&hdd_ctx->cache_channel_lock);
7028
7029 return len;
7030 }
7031
drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7032 static int drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info,
7033 struct hdd_context *hdd_ctx,
7034 uint8_t *command, uint8_t command_len,
7035 struct hdd_priv_data *priv_data)
7036 {
7037 char extra[512] = {0};
7038 int max_len, copied_length;
7039
7040 hdd_debug("Received Command to get disable Channels list");
7041
7042 max_len = QDF_MIN(priv_data->total_len, sizeof(extra));
7043 copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len);
7044 if (copied_length == 0) {
7045 hdd_err("disable channel list is not yet programmed");
7046 return -EINVAL;
7047 }
7048
7049 if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) {
7050 hdd_err("failed to copy data to user buffer");
7051 return -EFAULT;
7052 }
7053
7054 hdd_debug("data:%s", extra);
7055 return 0;
7056 }
7057 #else
7058
7059 static inline int
drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7060 drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info,
7061 struct hdd_context *hdd_ctx,
7062 uint8_t *command, uint8_t command_len,
7063 struct hdd_priv_data *priv_data)
7064 {
7065 return 0;
7066 }
7067
wlan_hdd_free_cache_channels(struct hdd_context * hdd_ctx)7068 void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx)
7069 {
7070 }
7071
7072 static inline int
drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7073 drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info,
7074 struct hdd_context *hdd_ctx,
7075 uint8_t *command, uint8_t command_len,
7076 struct hdd_priv_data *priv_data)
7077 {
7078 return 0;
7079 }
7080 #endif
7081
7082 #ifdef FEATURE_ANI_LEVEL_REQUEST
drv_cmd_get_ani_level(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7083 static int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info,
7084 struct hdd_context *hdd_ctx,
7085 uint8_t *command, uint8_t command_len,
7086 struct hdd_priv_data *priv_data)
7087 {
7088 struct hdd_adapter *adapter = link_info->adapter;
7089 char *extra;
7090 int copied_length = 0, j, temp_int, ret = 0;
7091 uint8_t *param, num_freqs, num_recv_channels;
7092 uint32_t parsed_freqs[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7093 struct wmi_host_ani_level_event ani[MAX_NUM_FREQS_FOR_ANI_LEVEL];
7094 size_t user_size = priv_data->total_len;
7095
7096 hdd_debug("Received Command to get ANI level");
7097
7098 param = strnchr(command, strlen(command), ' ');
7099
7100 /* No argument after the command */
7101 if (!param)
7102 return -EINVAL;
7103
7104 /* No space after the command */
7105 else if (SPACE_ASCII_VALUE != *param)
7106 return -EINVAL;
7107
7108 param++;
7109
7110 /* Removing empty spaces*/
7111 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7112 param++;
7113
7114 /*no argument followed by spaces */
7115 if ('\0' == *param)
7116 return -EINVAL;
7117
7118 /* Getting the first argument ie the number of channels */
7119 if (sscanf(param, "%d ", &temp_int) != 1) {
7120 hdd_err("Cannot get number of freq from input");
7121 return -EINVAL;
7122 }
7123
7124 if (temp_int < 0 || temp_int > MAX_NUM_FREQS_FOR_ANI_LEVEL) {
7125 hdd_err("Invalid Number of channel received");
7126 return -EINVAL;
7127 }
7128
7129 hdd_debug("Number of freq to fetch ANI level are: %d", temp_int);
7130
7131 if (!temp_int)
7132 return 0;
7133
7134 num_freqs = temp_int;
7135
7136 for (j = 0; j < num_freqs; j++) {
7137 /*
7138 * Param pointing to the beginning of first space
7139 * after number of channels.
7140 */
7141 param = strpbrk(param, " ");
7142 /*no channel list after the number of channels argument*/
7143 if (!param) {
7144 hdd_err("Invalid No of freq provided in the list");
7145 ret = -EINVAL;
7146 goto parse_failed;
7147 }
7148
7149 param++;
7150
7151 /* Removing empty space */
7152 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7153 param++;
7154
7155 if ('\0' == *param) {
7156 hdd_err("No freq is provided in the list");
7157 ret = -EINVAL;
7158 goto parse_failed;
7159 }
7160
7161 if (sscanf(param, "%d ", &temp_int) != 1) {
7162 hdd_err("Cannot read freq number");
7163 ret = -EINVAL;
7164 goto parse_failed;
7165 }
7166
7167 hdd_debug("channel_freq[%d] = %d", j, temp_int);
7168 parsed_freqs[j] = temp_int;
7169 }
7170
7171 /* Extra arguments check */
7172 param = strpbrk(param, " ");
7173 if (param) {
7174 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7175 param++;
7176
7177 if ('\0' != *param) {
7178 hdd_err("Invalid argument received");
7179 ret = -EINVAL;
7180 goto parse_failed;
7181 }
7182 }
7183
7184 qdf_mem_zero(ani, sizeof(ani));
7185 hdd_debug("num_freq: %d", num_freqs);
7186 if (QDF_IS_STATUS_ERROR(wlan_hdd_get_ani_level(adapter, ani,
7187 parsed_freqs,
7188 num_freqs))) {
7189 hdd_err("Unable to retrieve ani level");
7190 return -EINVAL;
7191 }
7192
7193 extra = qdf_mem_malloc(user_size);
7194 if (!extra) {
7195 ret = -ENOMEM;
7196 goto parse_failed;
7197 }
7198
7199 /*
7200 * Find the number of channels that are populated. If freq is not
7201 * filled then stop count there
7202 */
7203 for (num_recv_channels = 0;
7204 (num_recv_channels < num_freqs &&
7205 ani[num_recv_channels].chan_freq); num_recv_channels++)
7206 ;
7207
7208 for (j = 0; j < num_recv_channels; j++) {
7209 /* Sanity check for ANI level validity */
7210 if (ani[j].ani_level > MAX_ANI_LEVEL)
7211 continue;
7212
7213 copied_length += scnprintf(extra + copied_length,
7214 user_size - copied_length, "%d:%d\n",
7215 ani[j].chan_freq, ani[j].ani_level);
7216 }
7217
7218 if (copied_length == 0) {
7219 hdd_err("ANI level not fetched");
7220 ret = -EINVAL;
7221 goto free;
7222 }
7223
7224 hdd_debug("data: %s", extra);
7225
7226 if (copy_to_user(priv_data->buf, extra, copied_length + 1)) {
7227 hdd_err("failed to copy data to user buffer");
7228 ret = -EFAULT;
7229 goto free;
7230 }
7231
7232 free:
7233 qdf_mem_free(extra);
7234
7235 parse_failed:
7236 return ret;
7237 }
7238
7239 #else
drv_cmd_get_ani_level(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7240 static inline int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info,
7241 struct hdd_context *hdd_ctx,
7242 uint8_t *command, uint8_t command_len,
7243 struct hdd_priv_data *priv_data)
7244 {
7245 return 0;
7246 }
7247 #endif
7248
7249 #ifdef FUNC_CALL_MAP
drv_cmd_get_function_call_map(struct wlan_hdd_link_info * link_info,struct hdd_context * hdd_ctx,uint8_t * command,uint8_t command_len,struct hdd_priv_data * priv_data)7250 static int drv_cmd_get_function_call_map(struct wlan_hdd_link_info *link_info,
7251 struct hdd_context *hdd_ctx,
7252 uint8_t *command,
7253 uint8_t command_len,
7254 struct hdd_priv_data *priv_data)
7255 {
7256 char *cc_buf = qdf_mem_malloc(QDF_FUNCTION_CALL_MAP_BUF_LEN);
7257 uint8_t *param;
7258 int temp_int;
7259
7260 param = strnchr(command, strlen(command), ' ');
7261 /*no argument after the command*/
7262 if (NULL == param)
7263 return -EINVAL;
7264
7265 /*no space after the command*/
7266 else if (SPACE_ASCII_VALUE != *param)
7267 return -EINVAL;
7268
7269 param++;
7270
7271 /*removing empty spaces*/
7272 while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param))
7273 param++;
7274
7275 /*no argument followed by spaces*/
7276 if ('\0' == *param)
7277 return -EINVAL;
7278
7279 /*getting the first argument */
7280 if (sscanf(param, "%d ", &temp_int) != 1) {
7281 hdd_err("No option given");
7282 return -EINVAL;
7283 }
7284
7285 if (temp_int < 0 || temp_int > 1) {
7286 hdd_err("Invalid option given");
7287 return -EINVAL;
7288 }
7289
7290 /* Read the buffer */
7291 if (temp_int) {
7292 /*
7293 * These logs are required as these indicates the start and end of the
7294 * dump for the auto script to parse
7295 */
7296 hdd_info("Function call map dump start");
7297 qdf_get_func_call_map(cc_buf);
7298 qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
7299 cc_buf, QDF_FUNCTION_CALL_MAP_BUF_LEN);
7300 hdd_info("Function call map dump end");
7301 } else {
7302 qdf_clear_func_call_map();
7303 hdd_info("Function call map clear");
7304 }
7305 qdf_mem_free(cc_buf);
7306
7307 return 0;
7308 }
7309 #endif
7310
7311 /*
7312 * The following table contains all supported WLAN HDD
7313 * IOCTL driver commands and the handler for each of them.
7314 */
7315 static const struct hdd_drv_cmd hdd_drv_cmds[] = {
7316 {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false},
7317 {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true},
7318 {"P2P_SET_PS", drv_cmd_p2p_set_ps, true},
7319 {"SETBAND", drv_cmd_set_band, true},
7320 {"SETWMMPS", drv_cmd_set_wmmps, true},
7321 {"COUNTRY", drv_cmd_country, true},
7322 {"SETCOUNTRYREV", drv_cmd_country, true},
7323 {"GETCOUNTRYREV", drv_cmd_get_country, false},
7324 {"SETSUSPENDMODE", drv_cmd_set_suspend_mode, true},
7325 {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false},
7326 {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true},
7327 {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false},
7328 {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true},
7329 {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false},
7330 {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period,
7331 true},
7332 {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period,
7333 false},
7334 {"SETROAMMODE", drv_cmd_set_roam_mode, true},
7335 {"GETROAMMODE", drv_cmd_get_roam_mode, false},
7336 {"SETROAMDELTA", drv_cmd_set_roam_delta, true},
7337 {"GETROAMDELTA", drv_cmd_get_roam_delta, false},
7338 {"GETBAND", drv_cmd_get_band, false},
7339 {"GETCCXMODE", drv_cmd_get_ccx_mode, false},
7340 {"GETOKCMODE", drv_cmd_get_okc_mode, false},
7341 {"GETFASTROAM", drv_cmd_get_fast_roam, false},
7342 {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false},
7343 {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time,
7344 true},
7345 {"SENDACTIONFRAME", drv_cmd_send_action_frame, true},
7346 {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time,
7347 false},
7348 {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true},
7349 {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false},
7350 {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true},
7351 {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false},
7352 {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true},
7353 {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false},
7354 {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true},
7355 {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false},
7356 {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true},
7357 {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false},
7358 {"REASSOC", drv_cmd_reassoc, true},
7359 {"SETWESMODE", drv_cmd_set_wes_mode, true},
7360 {"GETWESMODE", drv_cmd_get_wes_mode, false},
7361 {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff,
7362 true},
7363 {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff,
7364 false},
7365 {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true},
7366 {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false},
7367 {"SETFASTROAM", drv_cmd_set_fast_roam, true},
7368 {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true},
7369 {"FASTREASSOC", drv_cmd_fast_reassoc, true},
7370 {"SETOKCMODE", drv_cmd_set_okc_mode, true},
7371 {"BTCOEXMODE", drv_cmd_bt_coex_mode, true},
7372 {"SCAN-ACTIVE", drv_cmd_scan_active, false},
7373 {"SCAN-PASSIVE", drv_cmd_scan_passive, false},
7374 {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true},
7375 {"GETDWELLTIME", drv_cmd_get_dwell_time, false},
7376 {"SETDWELLTIME", drv_cmd_set_dwell_time, true},
7377 {"MIRACAST", drv_cmd_miracast, true},
7378 {"TPUT_DEBUG_MODE_ENABLE", drv_cmd_tput_debug_mode_enable, false},
7379 {"TPUT_DEBUG_MODE_DISABLE", drv_cmd_tput_debug_mode_disable, false},
7380 #ifdef FEATURE_WLAN_ESE
7381 {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true},
7382 {"GETTSMSTATS", drv_cmd_get_tsm_stats, true},
7383 {"SETCCKMIE", drv_cmd_set_cckm_ie, true},
7384 {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true},
7385 {"CCXPLMREQ", drv_cmd_ccx_plm_req, true},
7386 {"SETCCXMODE", drv_cmd_set_ccx_mode, true},
7387 #endif /* FEATURE_WLAN_ESE */
7388 {"SETMCRATE", drv_cmd_set_mc_rate, true},
7389 {"MAXTXPOWER", drv_cmd_max_tx_power, true},
7390 {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true},
7391 {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false},
7392 {"GETLINKSTATUS", drv_cmd_get_link_status, false},
7393 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
7394 {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true},
7395 {"SETAPP1PARAMS", drv_cmd_set_app1_params, true},
7396 {"SETAPP2PARAMS", drv_cmd_set_app2_params, true},
7397 #endif
7398 #ifdef FEATURE_WLAN_TDLS
7399 {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset,
7400 true},
7401 {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true},
7402 {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true},
7403 {"TDLSSCAN", drv_cmd_tdls_scan, true},
7404 #endif
7405 {"RSSI", drv_cmd_get_rssi, false},
7406 {"LINKSPEED", drv_cmd_get_linkspeed, false},
7407 #ifdef WLAN_FEATURE_PACKET_FILTERING
7408 {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true},
7409 {"RXFILTER-ADD", drv_cmd_rx_filter_add, true},
7410 #endif
7411 {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true},
7412 {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true},
7413 {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true},
7414 {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false},
7415 {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true},
7416 {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false},
7417 {"GET_ANI_LEVEL", drv_cmd_get_ani_level, false},
7418 #ifdef FUNC_CALL_MAP
7419 {"GET_FUNCTION_CALL_MAP", drv_cmd_get_function_call_map, true},
7420 #endif
7421 {"STOP", drv_cmd_dummy, false},
7422 /* Deprecated commands */
7423 {"RXFILTER-START", drv_cmd_dummy, false},
7424 {"RXFILTER-STOP", drv_cmd_dummy, false},
7425 {"BTCOEXSCAN-START", drv_cmd_dummy, false},
7426 {"BTCOEXSCAN-STOP", drv_cmd_dummy, false},
7427 {"GET_SOFTAP_LINK_SPEED", drv_cmd_get_sap_go_linkspeed, true},
7428 #ifdef CONFIG_BAND_6GHZ
7429 {"GET_WIFI6E_CHANNELS", drv_cmd_get_wifi6e_channels, true},
7430 #endif
7431 };
7432
7433 /**
7434 * hdd_drv_cmd_process() - chooses and runs the proper
7435 * handler based on the input command
7436 * @link_info: Link info pointer in adapter.
7437 * @cmd: Pointer to the driver command
7438 * @priv_data: Pointer to the data associated with the command
7439 *
7440 * This function parses the input hdd driver command and runs
7441 * the proper handler
7442 *
7443 * Return: 0 for success non-zero for failure
7444 */
hdd_drv_cmd_process(struct wlan_hdd_link_info * link_info,uint8_t * cmd,struct hdd_priv_data * priv_data)7445 static int hdd_drv_cmd_process(struct wlan_hdd_link_info *link_info,
7446 uint8_t *cmd, struct hdd_priv_data *priv_data)
7447 {
7448 struct hdd_adapter *adapter = link_info->adapter;
7449 struct hdd_context *hdd_ctx;
7450 int i;
7451 const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds);
7452 uint8_t *cmd_i = NULL;
7453 hdd_drv_cmd_handler_t handler = NULL;
7454 int len = 0, cmd_len = 0;
7455 uint8_t *ptr;
7456 bool args;
7457
7458 if (!cmd || !priv_data) {
7459 hdd_err("at least 1 param is NULL");
7460 return -EINVAL;
7461 }
7462
7463 /* Calculate length of the first word */
7464 ptr = strchrnul(cmd, ' ');
7465 cmd_len = ptr - cmd;
7466
7467 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7468
7469 for (i = 0; i < cmd_num_total; i++) {
7470
7471 cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd;
7472 handler = hdd_drv_cmds[i].handler;
7473 len = strlen(cmd_i);
7474 args = hdd_drv_cmds[i].args;
7475
7476 if (!handler) {
7477 hdd_err("no. %d handler is NULL", i);
7478 return -EINVAL;
7479 }
7480
7481 if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) {
7482 if (args && drv_cmd_validate(cmd, len))
7483 return -EINVAL;
7484
7485 return handler(link_info, hdd_ctx,
7486 cmd, len, priv_data);
7487 }
7488 }
7489
7490 return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data);
7491 }
7492
7493 /**
7494 * hdd_driver_command() - top level wlan hdd driver command handler
7495 * @link_info: Link info pointer in HDD adapter
7496 * @priv_data: Pointer to the raw command data
7497 *
7498 * This function is the top level wlan hdd driver command handler. It
7499 * handles the command with the help of hdd_drv_cmd_process()
7500 *
7501 * Return: 0 for success non-zero for failure
7502 */
hdd_driver_command(struct wlan_hdd_link_info * link_info,struct hdd_priv_data * priv_data)7503 static int hdd_driver_command(struct wlan_hdd_link_info *link_info,
7504 struct hdd_priv_data *priv_data)
7505 {
7506 struct hdd_adapter *adapter = link_info->adapter;
7507 uint8_t *command = NULL;
7508 int ret = 0;
7509 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7510
7511 hdd_enter();
7512
7513 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
7514 hdd_err("Command not allowed in FTM mode");
7515 return -EINVAL;
7516 }
7517
7518 ret = wlan_hdd_validate_context(hdd_ctx);
7519 if (ret)
7520 return ret;
7521
7522 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
7523 hdd_err("Driver module is closed; command can not be processed");
7524 return -EINVAL;
7525 }
7526
7527 /*
7528 * Note that valid pointers are provided by caller
7529 */
7530
7531 /* copy to local struct to avoid numerous changes to legacy code */
7532 if (priv_data->total_len <= 0 ||
7533 priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) {
7534 hdd_warn("Invalid priv_data.total_len: %d!!!",
7535 priv_data->total_len);
7536 ret = -EINVAL;
7537 goto exit;
7538 }
7539
7540 /* Allocate +1 for '\0' */
7541 command = qdf_mem_malloc(priv_data->total_len + 1);
7542 if (!command) {
7543 ret = -ENOMEM;
7544 goto exit;
7545 }
7546
7547 if (copy_from_user(command, priv_data->buf, priv_data->total_len)) {
7548 ret = -EFAULT;
7549 goto exit;
7550 }
7551
7552 /* Make sure the command is NUL-terminated */
7553 command[priv_data->total_len] = '\0';
7554
7555 hdd_debug("%s: %s", adapter->dev->name, command);
7556 ret = hdd_drv_cmd_process(link_info, command, priv_data);
7557
7558 exit:
7559 if (command)
7560 qdf_mem_free(command);
7561 hdd_exit();
7562 return ret;
7563 }
7564
7565 #ifdef CONFIG_COMPAT
hdd_driver_compat_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7566 static int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info,
7567 void __user *data)
7568 {
7569 struct {
7570 compat_uptr_t buf;
7571 int used_len;
7572 int total_len;
7573 } compat_priv_data;
7574 struct hdd_priv_data priv_data;
7575 int ret = 0;
7576
7577 /*
7578 * Note that adapter and ifr have already been verified by caller,
7579 * and HDD context has also been validated
7580 */
7581 if (copy_from_user(&compat_priv_data, data,
7582 sizeof(compat_priv_data))) {
7583 ret = -EFAULT;
7584 goto exit;
7585 }
7586 priv_data.buf = compat_ptr(compat_priv_data.buf);
7587 priv_data.used_len = compat_priv_data.used_len;
7588 priv_data.total_len = compat_priv_data.total_len;
7589 ret = hdd_driver_command(link_info, &priv_data);
7590 exit:
7591 return ret;
7592 }
7593 #else /* CONFIG_COMPAT */
hdd_driver_compat_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7594 static inline int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info,
7595 void __user *data)
7596 {
7597 /* will never be invoked */
7598 return 0;
7599 }
7600 #endif /* CONFIG_COMPAT */
7601
hdd_driver_ioctl(struct wlan_hdd_link_info * link_info,void __user * data)7602 static int hdd_driver_ioctl(struct wlan_hdd_link_info *link_info,
7603 void __user *data)
7604 {
7605 struct hdd_priv_data priv_data;
7606 int ret = 0;
7607
7608 /*
7609 * Note that adapter and ifr have already been verified by caller,
7610 * and HDD context has also been validated
7611 */
7612 if (copy_from_user(&priv_data, data, sizeof(priv_data)))
7613 ret = -EFAULT;
7614 else
7615 ret = hdd_driver_command(link_info, &priv_data);
7616
7617 return ret;
7618 }
7619
7620 /**
7621 * __hdd_ioctl() - ioctl handler for wlan network interfaces
7622 * @dev: device upon which the ioctl was received
7623 * @data: pointer to the raw command data in the ioctl request
7624 * @cmd: ioctl command
7625 *
7626 * This function does initial processing of wlan device ioctls.
7627 * Currently two flavors of ioctls are supported. The primary ioctl
7628 * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used
7629 * for Android "DRIVER" commands. The other ioctl that is
7630 * conditionally supported is the SIOCIOCTLTX99 ioctl which is used
7631 * for FTM on some platforms. This function simply verifies that the
7632 * driver is in a sane state, and that the ioctl is one of the
7633 * supported flavors, in which case flavor-specific handlers are
7634 * dispatched.
7635 *
7636 * Return: 0 on success, non-zero on error
7637 */
__hdd_ioctl(struct net_device * dev,void __user * data,int cmd)7638 static int __hdd_ioctl(struct net_device *dev, void __user *data, int cmd)
7639 {
7640 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
7641 struct hdd_context *hdd_ctx;
7642 int ret;
7643
7644 hdd_enter_dev(dev);
7645
7646 if (dev != adapter->dev) {
7647 hdd_err("HDD adapter/dev inconsistency");
7648 ret = -ENODEV;
7649 goto exit;
7650 }
7651
7652 if (!data) {
7653 hdd_err("invalid data cmd: %d", cmd);
7654 ret = -EINVAL;
7655 goto exit;
7656 }
7657 #if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
7658 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
7659 if (SIOCIOCTLTX99 == cmd) {
7660 ret = wlan_hdd_qcmbr_unified_ioctl(adapter, data);
7661 goto exit;
7662 }
7663 }
7664 #endif
7665
7666 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
7667 ret = wlan_hdd_validate_context(hdd_ctx);
7668 if (ret)
7669 goto exit;
7670
7671 switch (cmd) {
7672 case (SIOCDEVPRIVATE + 1):
7673 if (in_compat_syscall())
7674 ret = hdd_driver_compat_ioctl(adapter->deflink, data);
7675 else
7676 ret = hdd_driver_ioctl(adapter->deflink, data);
7677 break;
7678 default:
7679 hdd_warn("unknown ioctl %d", cmd);
7680 ret = -EINVAL;
7681 break;
7682 }
7683 exit:
7684 hdd_exit();
7685 return ret;
7686 }
7687
hdd_ioctl(struct net_device * net_dev,struct ifreq * ifr,int cmd)7688 int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
7689 {
7690 struct osif_vdev_sync *vdev_sync;
7691 int errno;
7692
7693 errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
7694 if (errno)
7695 return errno;
7696
7697 errno = __hdd_ioctl(net_dev, ifr->ifr_data, cmd);
7698
7699 osif_vdev_sync_op_stop(vdev_sync);
7700
7701 return errno;
7702 }
7703
hdd_dev_private_ioctl(struct net_device * dev,struct ifreq * ifr,void __user * data,int cmd)7704 int hdd_dev_private_ioctl(struct net_device *dev, struct ifreq *ifr,
7705 void __user *data, int cmd)
7706 {
7707 struct osif_vdev_sync *vdev_sync;
7708 int errno;
7709
7710 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
7711 if (errno)
7712 return errno;
7713
7714 errno = __hdd_ioctl(dev, data, cmd);
7715
7716 osif_vdev_sync_op_stop(vdev_sync);
7717
7718 return errno;
7719 }
7720