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