1  /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  *  DOC:    wma_scan_roam.c
22  *  This file contains functions related to scan and
23  *  roaming functionality.
24  */
25 
26 /* Header files */
27 
28 #include "wma.h"
29 #include "wma_api.h"
30 #include "cds_api.h"
31 #include "wmi_unified_api.h"
32 #include "wlan_qct_sys.h"
33 #include "wni_api.h"
34 #include "ani_global.h"
35 #include "wmi_unified.h"
36 #include "wni_cfg.h"
37 #include <cdp_txrx_peer_ops.h>
38 #include <cdp_txrx_cfg.h>
39 #include <cdp_txrx_ctrl.h>
40 
41 #include "qdf_nbuf.h"
42 #include "qdf_types.h"
43 #include "qdf_mem.h"
44 #include "wlan_dlm_api.h"
45 
46 #include "wma_types.h"
47 #include "lim_api.h"
48 #include "lim_session_utils.h"
49 
50 #include "cds_utils.h"
51 #include "wlan_policy_mgr_api.h"
52 #include <wlan_utility.h>
53 
54 #if !defined(REMOVE_PKT_LOG)
55 #include "pktlog_ac.h"
56 #endif /* REMOVE_PKT_LOG */
57 
58 #include "dbglog_host.h"
59 #include "csr_api.h"
60 #include "ol_fw.h"
61 
62 #include "wma_internal.h"
63 #if defined(CONFIG_HL_SUPPORT)
64 #include "wlan_tgt_def_config_hl.h"
65 #else
66 #include "wlan_tgt_def_config.h"
67 #endif
68 #include "wlan_reg_services_api.h"
69 #include "wlan_roam_debug.h"
70 #include "wlan_mlme_public_struct.h"
71 #include "wlan_mgmt_txrx_utils_api.h"
72 
73 /* This is temporary, should be removed */
74 #include "ol_htt_api.h"
75 #include <cdp_txrx_handle.h>
76 #include "wma_he.h"
77 #include <wlan_scan_public_structs.h>
78 #include <wlan_scan_ucfg_api.h>
79 #include "wma_nan_datapath.h"
80 #include "wlan_mlme_api.h"
81 #include <wlan_mlme_main.h>
82 #include <wlan_crypto_global_api.h>
83 #include <cdp_txrx_mon.h>
84 #include <cdp_txrx_ctrl.h>
85 #include "wlan_dlm_api.h"
86 #include "wlan_cm_roam_api.h"
87 #ifdef FEATURE_WLAN_DIAG_SUPPORT    /* FEATURE_WLAN_DIAG_SUPPORT */
88 #include "host_diag_core_log.h"
89 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
90 #include <../../core/src/wlan_cm_roam_i.h>
91 #include "wlan_cm_roam_api.h"
92 #include "wlan_mlo_mgr_roam.h"
93 #include "lim_mlo.h"
94 #include "wlan_dp_api.h"
95 #ifdef FEATURE_WLAN_EXTSCAN
96 #define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED
97 
98 /*
99  * Maximum number of entries that could be present in the
100  * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware
101  */
102 #define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10
103 #endif
104 
105 static inline wmi_host_channel_width
wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width)106 wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width)
107 {
108 	switch (ch_width) {
109 	case CH_WIDTH_20MHZ:
110 		return WMI_HOST_CHAN_WIDTH_20;
111 	case CH_WIDTH_40MHZ:
112 		return WMI_HOST_CHAN_WIDTH_40;
113 	case CH_WIDTH_80MHZ:
114 		return WMI_HOST_CHAN_WIDTH_80;
115 	case CH_WIDTH_160MHZ:
116 		return WMI_HOST_CHAN_WIDTH_160;
117 	case CH_WIDTH_5MHZ:
118 		return WMI_HOST_CHAN_WIDTH_5;
119 	case CH_WIDTH_10MHZ:
120 		return WMI_HOST_CHAN_WIDTH_10;
121 	case CH_WIDTH_320MHZ:
122 		return WMI_HOST_CHAN_WIDTH_320;
123 	default:
124 		return WMI_HOST_CHAN_WIDTH_20;
125 	}
126 }
127 
128 #define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ      0
129 #define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ         1
130 #define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ        2
131 #define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3
132 
133 #if defined(WLAN_FEATURE_11BE)
wma_update_ch_list_11be_params(struct ch_params * ch)134 static void wma_update_ch_list_11be_params(struct ch_params *ch)
135 {
136 	ch->ch_width = CH_WIDTH_320MHZ;
137 }
138 #else /* !WLAN_FEATURE_11BE */
wma_update_ch_list_11be_params(struct ch_params * ch)139 static void wma_update_ch_list_11be_params(struct ch_params *ch)
140 {
141 	ch->ch_width = CH_WIDTH_160MHZ;
142 }
143 #endif /* WLAN_FEATURE_11BE */
144 
145 /**
146  * wma_update_channel_list() - update channel list
147  * @handle: wma handle
148  * @chan_list: channel list
149  *
150  * Function is used to update the support channel list in fw.
151  *
152  * Return: QDF status
153  */
wma_update_channel_list(WMA_HANDLE handle,tSirUpdateChanList * chan_list)154 QDF_STATUS wma_update_channel_list(WMA_HANDLE handle,
155 				   tSirUpdateChanList *chan_list)
156 {
157 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
158 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
159 	int i, len;
160 	struct scan_chan_list_params *scan_ch_param;
161 	struct channel_param *chan_p;
162 	struct ch_params ch_params = {0};
163 
164 	len = sizeof(struct channel_param) * chan_list->numChan +
165 		offsetof(struct scan_chan_list_params, ch_param[0]);
166 	scan_ch_param = qdf_mem_malloc(len);
167 	if (!scan_ch_param)
168 		return QDF_STATUS_E_NOMEM;
169 
170 	qdf_mem_zero(scan_ch_param, len);
171 	wma_debug("no of channels = %d", chan_list->numChan);
172 	chan_p = &scan_ch_param->ch_param[0];
173 	scan_ch_param->nallchans = chan_list->numChan;
174 	scan_ch_param->max_bw_support_present = true;
175 	wma_handle->saved_chan.num_channels = chan_list->numChan;
176 	wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en,
177 		  chan_list->vht_en, chan_list->vht_24_en);
178 
179 	for (i = 0; i < chan_list->numChan; ++i) {
180 		chan_p->mhz = chan_list->chanParam[i].freq;
181 		chan_p->cfreq1 = chan_p->mhz;
182 		chan_p->cfreq2 = 0;
183 		wma_handle->saved_chan.ch_freq_list[i] =
184 					chan_list->chanParam[i].freq;
185 
186 		if (chan_list->chanParam[i].dfsSet) {
187 			chan_p->is_chan_passive = 1;
188 			chan_p->dfs_set = 1;
189 		}
190 
191 		if (chan_list->chanParam[i].nan_disabled)
192 			chan_p->nan_disabled = 1;
193 
194 		if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) {
195 			chan_p->phy_mode = MODE_11G;
196 			if (chan_list->vht_en && chan_list->vht_24_en)
197 				chan_p->allow_vht = 1;
198 		} else {
199 			chan_p->phy_mode = MODE_11A;
200 			if (chan_list->vht_en &&
201 			    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
202 				chan_p->allow_vht = 1;
203 		}
204 
205 		if (chan_list->ht_en &&
206 		    !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz)))
207 			chan_p->allow_ht = 1;
208 
209 		if (chan_list->he_en)
210 			chan_p->allow_he = 1;
211 
212 		if (chan_list->eht_en)
213 			chan_p->allow_eht = 1;
214 
215 		if (chan_list->chanParam[i].half_rate)
216 			chan_p->half_rate = 1;
217 		else if (chan_list->chanParam[i].quarter_rate)
218 			chan_p->quarter_rate = 1;
219 
220 		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz) &&
221 		    wlan_reg_is_6ghz_psc_chan_freq(chan_p->mhz))
222 			chan_p->psc_channel = 1;
223 
224 		/*TODO: Set WMI_SET_CHANNEL_MIN_POWER */
225 		/*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */
226 		/*TODO: WMI_SET_CHANNEL_REG_CLASSID */
227 		chan_p->maxregpower = chan_list->chanParam[i].pwr;
228 
229 		wma_update_ch_list_11be_params(&ch_params);
230 
231 		wlan_reg_set_channel_params_for_pwrmode(wma_handle->pdev,
232 							chan_p->mhz, 0,
233 							&ch_params,
234 							REG_CURRENT_PWR_MODE);
235 
236 		chan_p->max_bw_supported =
237 		     wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width);
238 		chan_p++;
239 	}
240 
241 	qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle,
242 				scan_ch_param);
243 
244 	if (QDF_IS_STATUS_ERROR(qdf_status))
245 		wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID");
246 
247 	qdf_mem_free(scan_ch_param);
248 
249 	return qdf_status;
250 }
251 
252 /**
253  * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving
254  * @wma_handle: wma handle
255  * @vdev_id: vdev id
256  * @reason: disconnection reason from fw
257  *
258  * Return: None
259  */
wma_handle_disconnect_reason(tp_wma_handle wma_handle,uint32_t vdev_id,uint32_t reason)260 static void wma_handle_disconnect_reason(tp_wma_handle wma_handle,
261 					 uint32_t vdev_id, uint32_t reason)
262 {
263 	tpDeleteStaContext del_sta_ctx;
264 
265 	del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext));
266 	if (!del_sta_ctx)
267 		return;
268 
269 	del_sta_ctx->vdev_id = vdev_id;
270 	del_sta_ctx->reasonCode = reason;
271 	wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND,
272 		     (void *)del_sta_ctx, 0);
273 }
274 
275 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
276 QDF_STATUS
cm_handle_auth_offload(struct auth_offload_event * auth_event)277 cm_handle_auth_offload(struct auth_offload_event *auth_event)
278 {
279 	QDF_STATUS status;
280 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
281 	struct mac_context *mac_ctx;
282 
283 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
284 	if (!mac_ctx || !wma) {
285 		QDF_ASSERT(0);
286 		return QDF_STATUS_E_FAILURE;
287 	}
288 
289 	cds_host_diag_log_work(&wma->roam_preauth_wl,
290 			       WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION,
291 			       WIFI_POWER_EVENT_WAKELOCK_WOW);
292 
293 	qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl,
294 			       WMA_ROAM_HO_WAKE_LOCK_DURATION);
295 
296 	lim_sae_auth_cleanup_retry(mac_ctx, auth_event->vdev_id);
297 	wlan_cm_set_sae_auth_ta(mac_ctx->pdev,
298 				auth_event->vdev_id,
299 				auth_event->ta);
300 
301 	wlan_cm_store_mlo_roam_peer_address(mac_ctx->pdev, auth_event);
302 
303 	status =
304 		wlan_cm_update_offload_ssid_from_candidate(mac_ctx->pdev,
305 							   auth_event->vdev_id,
306 							   &auth_event->ap_bssid);
307 
308 	if (QDF_IS_STATUS_ERROR(status)) {
309 		wma_err_rl("Set offload ssid failed %d", status);
310 		return QDF_STATUS_E_FAILURE;
311 	}
312 
313 	status = wma->csr_roam_auth_event_handle_cb(mac_ctx, auth_event->vdev_id,
314 						    auth_event->ap_bssid,
315 						    auth_event->akm);
316 	if (QDF_IS_STATUS_ERROR(status)) {
317 		wma_err_rl("Trigger pre-auth failed");
318 		return QDF_STATUS_E_FAILURE;
319 	}
320 	return QDF_STATUS_SUCCESS;
321 }
322 
323 QDF_STATUS
cm_handle_disconnect_reason(struct vdev_disconnect_event_data * data)324 cm_handle_disconnect_reason(struct vdev_disconnect_event_data *data)
325 {
326 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
327 
328 	if (!wma) {
329 		QDF_ASSERT(0);
330 		return QDF_STATUS_E_FAILURE;
331 	}
332 	switch (data->reason) {
333 	case CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT:
334 		wma_handle_disconnect_reason(wma, data->vdev_id,
335 			HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT);
336 		break;
337 	case CM_DISCONNECT_REASON_MOVE_TO_CELLULAR:
338 		wma_handle_disconnect_reason(wma, data->vdev_id,
339 			HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
340 		break;
341 	default:
342 		return QDF_STATUS_SUCCESS;
343 	}
344 
345 	return QDF_STATUS_SUCCESS;
346 }
347 
348 QDF_STATUS
cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp * data)349 cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data)
350 {
351 	struct scheduler_msg sme_msg = {0};
352 
353 	sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT;
354 	sme_msg.bodyptr = data;
355 
356 	if (scheduler_post_message(QDF_MODULE_ID_WMA,
357 				   QDF_MODULE_ID_SME,
358 				   QDF_MODULE_ID_SME, &sme_msg)) {
359 		wma_err("Failed to post msg to SME");
360 		qdf_mem_free(sme_msg.bodyptr);
361 		return -EINVAL;
362 	}
363 
364 	return QDF_STATUS_SUCCESS;
365 }
366 
367 #endif
368 
369 /**
370  * wma_process_set_pdev_ie_req() - process the pdev set IE req
371  * @wma: Pointer to wma handle
372  * @ie_params: Pointer to IE data.
373  *
374  * Sends the WMI req to set the IE to FW.
375  *
376  * Return: None
377  */
wma_process_set_pdev_ie_req(tp_wma_handle wma,struct set_ie_param * ie_params)378 void wma_process_set_pdev_ie_req(tp_wma_handle wma,
379 				 struct set_ie_param *ie_params)
380 {
381 	if (ie_params->ie_type == DOT11_HT_IE)
382 		wma_process_set_pdev_ht_ie_req(wma, ie_params);
383 	if (ie_params->ie_type == DOT11_VHT_IE)
384 		wma_process_set_pdev_vht_ie_req(wma, ie_params);
385 
386 	qdf_mem_free(ie_params->ie_ptr);
387 }
388 
389 /**
390  * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW
391  * @wma: Pointer to wma handle
392  * @ie_params: Pointer to IE data.
393  * @nss: Nss values to prepare the HT IE.
394  *
395  * Sends the WMI req to set the HT IE to FW.
396  *
397  * Return: None
398  */
wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,struct set_ie_param * ie_params)399 void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,
400 				    struct set_ie_param *ie_params)
401 {
402 	QDF_STATUS status;
403 	wmi_pdev_set_ht_ie_cmd_fixed_param *cmd;
404 	wmi_buf_t buf;
405 	uint16_t len;
406 	uint16_t ie_len_pad;
407 	uint8_t *buf_ptr;
408 
409 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
410 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
411 	len += ie_len_pad;
412 
413 	buf = wmi_buf_alloc(wma->wmi_handle, len);
414 	if (!buf)
415 		return;
416 
417 	cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf);
418 	WMITLV_SET_HDR(&cmd->tlv_header,
419 		       WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param,
420 		       WMITLV_GET_STRUCT_TLVLEN(
421 			       wmi_pdev_set_ht_ie_cmd_fixed_param));
422 	cmd->reserved0 = 0;
423 	cmd->ie_len = ie_params->ie_len;
424 	cmd->tx_streams = ie_params->nss;
425 	cmd->rx_streams = ie_params->nss;
426 	wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss);
427 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
428 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
429 	if (ie_params->ie_len) {
430 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
431 			     (uint8_t *)ie_params->ie_ptr,
432 			     ie_params->ie_len);
433 	}
434 
435 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
436 				      WMI_PDEV_SET_HT_CAP_IE_CMDID);
437 	if (QDF_IS_STATUS_ERROR(status))
438 		wmi_buf_free(buf);
439 }
440 
441 /**
442  * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW
443  * @wma: Pointer to wma handle
444  * @ie_params: Pointer to IE data.
445  * @nss: Nss values to prepare the VHT IE.
446  *
447  * Sends the WMI req to set the VHT IE to FW.
448  *
449  * Return: None
450  */
wma_process_set_pdev_vht_ie_req(tp_wma_handle wma,struct set_ie_param * ie_params)451 void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma,
452 				     struct set_ie_param *ie_params)
453 {
454 	QDF_STATUS status;
455 	wmi_pdev_set_vht_ie_cmd_fixed_param *cmd;
456 	wmi_buf_t buf;
457 	uint16_t len;
458 	uint16_t ie_len_pad;
459 	uint8_t *buf_ptr;
460 
461 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
462 	ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t));
463 	len += ie_len_pad;
464 
465 	buf = wmi_buf_alloc(wma->wmi_handle, len);
466 	if (!buf)
467 		return;
468 
469 	cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf);
470 	WMITLV_SET_HDR(&cmd->tlv_header,
471 		       WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param,
472 		       WMITLV_GET_STRUCT_TLVLEN(
473 					wmi_pdev_set_vht_ie_cmd_fixed_param));
474 	cmd->reserved0 = 0;
475 	cmd->ie_len = ie_params->ie_len;
476 	cmd->tx_streams = ie_params->nss;
477 	cmd->rx_streams = ie_params->nss;
478 	wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss);
479 	buf_ptr = (uint8_t *)cmd + sizeof(*cmd);
480 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
481 	if (ie_params->ie_len) {
482 		qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
483 			     (uint8_t *)ie_params->ie_ptr, ie_params->ie_len);
484 	}
485 
486 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
487 				      WMI_PDEV_SET_VHT_CAP_IE_CMDID);
488 	if (QDF_IS_STATUS_ERROR(status))
489 		wmi_buf_free(buf);
490 }
491 
492 #define MAX_VDEV_ROAM_SCAN_PARAMS 2
493 /* params being sent:
494  * wmi_vdev_param_bmiss_first_bcnt
495  * wmi_vdev_param_bmiss_final_bcnt
496  */
497 
498 /**
499  * wma_roam_scan_bmiss_cnt() - set bmiss count to fw
500  * @wma_handle: wma handle
501  * @first_bcnt: first bmiss count
502  * @final_bcnt: final bmiss count
503  * @vdev_id: vdev id
504  *
505  * set first & final biss count to fw.
506  *
507  * Return: QDF status
508  */
wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle,A_INT32 first_bcnt,A_UINT32 final_bcnt,uint32_t vdev_id)509 QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle,
510 				   A_INT32 first_bcnt,
511 				   A_UINT32 final_bcnt, uint32_t vdev_id)
512 {
513 	QDF_STATUS status = QDF_STATUS_SUCCESS;
514 	struct dev_set_param setparam[MAX_VDEV_ROAM_SCAN_PARAMS] = {};
515 	uint8_t index = 0;
516 
517 	wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt);
518 
519 	status = mlme_check_index_setparam(setparam,
520 					   wmi_vdev_param_bmiss_first_bcnt,
521 					   first_bcnt, index++,
522 					   MAX_VDEV_ROAM_SCAN_PARAMS);
523 	if (QDF_IS_STATUS_ERROR(status)) {
524 		wma_err("failed to set wmi_vdev_param_bmiss_first_bcnt");
525 		goto error;
526 	}
527 	status = mlme_check_index_setparam(setparam,
528 					   wmi_vdev_param_bmiss_final_bcnt,
529 					   final_bcnt, index++,
530 					   MAX_VDEV_ROAM_SCAN_PARAMS);
531 	if (QDF_IS_STATUS_ERROR(status)) {
532 		wma_err("failed to set wmi_vdev_param_bmiss_final_bcnt");
533 		goto error;
534 	}
535 	status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM,
536 						     vdev_id, setparam, index);
537 	if (QDF_IS_STATUS_ERROR(status))
538 		wma_err("Failed to set BMISS FIRST and FINAL vdev set params");
539 error:
540 	return status;
541 }
542 
543 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
544 void
wma_send_roam_preauth_status(tp_wma_handle wma_handle,struct wmi_roam_auth_status_params * params)545 wma_send_roam_preauth_status(tp_wma_handle wma_handle,
546 			     struct wmi_roam_auth_status_params *params)
547 {
548 	QDF_STATUS status;
549 	struct wmi_unified *wmi_handle;
550 
551 	if (wma_validate_handle(wma_handle))
552 		return;
553 
554 	wmi_handle = wma_handle->wmi_handle;
555 	if (wmi_validate_handle(wmi_handle))
556 		return;
557 
558 	status = wmi_unified_send_roam_preauth_status(wmi_handle, params);
559 	if (QDF_IS_STATUS_ERROR(status))
560 		wma_err("failed to send disconnect roam preauth status");
561 }
562 #endif
563 
564 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
565 /**
566  * wma_delete_bss_peer() Delete bss peer/s for Non ML interface
567  * @wma: Global WMA Handle
568  * @vdev_id: vdev id
569  *
570  * This function will perform cleanup of the peer corresponds
571  * to given vdev_id
572  *
573  * Return: QDF status
574  */
575 static
wma_delete_bss_peer(tp_wma_handle wma,uint8_t vdev_id)576 QDF_STATUS wma_delete_bss_peer(tp_wma_handle wma,
577 			       uint8_t vdev_id)
578 {
579 	tDeleteStaParams *del_sta_params;
580 
581 	del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
582 	if (!del_sta_params)
583 		return QDF_STATUS_E_NOMEM;
584 
585 	del_sta_params->smesessionId = vdev_id;
586 	wma_delete_sta(wma, del_sta_params);
587 	wma_delete_bss(wma, vdev_id);
588 
589 	return QDF_STATUS_SUCCESS;
590 }
591 
592 #ifdef WLAN_FEATURE_11BE_MLO
593 /**
594  * wma_delete_all_peers() - Delete all bss peer/s
595  * @wma: Global WMA Handle
596  * @vdev_id: vdev id
597  * @del_sta_params: parameters required for del sta request
598  *
599  * This function will perform deleting of all the link peers
600  * after self roaming.
601  *
602  * Return: None
603  */
604 static QDF_STATUS
wma_delete_all_peers(tp_wma_handle wma,uint8_t vdev_id)605 wma_delete_all_peers(tp_wma_handle wma,
606 		     uint8_t vdev_id)
607 {
608 	struct wlan_objmgr_vdev *vdev;
609 	struct wlan_mlo_dev_context *mlo_dev_ctx;
610 	uint8_t i;
611 	uint8_t link_vdev_id;
612 	tDeleteStaParams *del_sta_params;
613 	QDF_STATUS status = QDF_STATUS_SUCCESS;
614 	struct qdf_mac_addr bssid;
615 	struct qdf_mac_addr *mld_addr;
616 
617 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id,
618 						    WLAN_MLME_OBJMGR_ID);
619 	if (!vdev) {
620 		mlme_err("vdev object is NULL for vdev %d", vdev_id);
621 		return QDF_STATUS_E_NULL_VALUE;
622 	}
623 
624 	mlo_dev_ctx = vdev->mlo_dev_ctx;
625 	if (!mlo_dev_ctx) {
626 		mld_addr =
627 		    (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
628 		/* It's not a ML interface*/
629 		if (qdf_is_macaddr_zero(mld_addr)) {
630 			mlme_debug("Non-ML STA vdev_id: %d", vdev_id);
631 			status = wma_delete_bss_peer(wma, vdev_id);
632 			goto end;
633 		}
634 
635 		mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id);
636 		status = QDF_STATUS_E_NULL_VALUE;
637 		goto end;
638 	}
639 
640 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
641 		if (!mlo_dev_ctx->wlan_vdev_list[i])
642 			continue;
643 
644 		if (QDF_IS_STATUS_ERROR(wlan_vdev_get_bss_peer_mac(
645 			mlo_dev_ctx->wlan_vdev_list[i],
646 			&bssid))) {
647 			pe_debug("bss peer is not present on vdev id %d, no need to cleanup",
648 				 wlan_vdev_get_id(
649 				 mlo_dev_ctx->wlan_vdev_list[i]));
650 			continue;
651 		}
652 
653 		del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params));
654 		if (!del_sta_params) {
655 			status = QDF_STATUS_E_NOMEM;
656 			goto end;
657 		}
658 		lim_mlo_roam_peer_disconn_del(mlo_dev_ctx->wlan_vdev_list[i]);
659 		qdf_mem_zero(del_sta_params, sizeof(*del_sta_params));
660 		link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]);
661 		if (link_vdev_id == WLAN_INVALID_VDEV_ID) {
662 			mlme_err("invalid vdev id");
663 			status = QDF_STATUS_E_INVAL;
664 			goto end;
665 		}
666 		del_sta_params->smesessionId = link_vdev_id;
667 		wma_delete_sta(wma, del_sta_params);
668 		wma_delete_bss(wma, link_vdev_id);
669 	}
670 
671 end:
672 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
673 	return status;
674 }
675 #else
676 static inline  QDF_STATUS
wma_delete_all_peers(tp_wma_handle wma,uint8_t vdev_id)677 wma_delete_all_peers(tp_wma_handle wma,
678 		     uint8_t vdev_id)
679 {
680 	return wma_delete_bss_peer(wma, vdev_id);
681 }
682 #endif
683 /**
684  * wma_roam_update_vdev() - Update the STA and BSS
685  * @wma: Global WMA Handle
686  * @roam_synch_ind_ptr: Information needed for roam sync propagation
687  *
688  * This function will perform all the vdev related operations with
689  * respect to the self sta and the peer after roaming and completes
690  * the roam synch propagation with respect to WMA layer.
691  *
692  * Return: QDF_STATUS
693  */
694 static QDF_STATUS
wma_roam_update_vdev(tp_wma_handle wma,struct roam_offload_synch_ind * roam_synch_ind_ptr,uint8_t roamed_vdev_id)695 wma_roam_update_vdev(tp_wma_handle wma,
696 		     struct roam_offload_synch_ind *roam_synch_ind_ptr,
697 		     uint8_t roamed_vdev_id)
698 {
699 	tAddStaParams *add_sta_params;
700 	uint8_t vdev_id, *bssid;
701 	int32_t uc_cipher, cipher_cap;
702 	bool is_assoc_peer = false;
703 	struct qdf_mac_addr mac_addr;
704 	QDF_STATUS status = QDF_STATUS_SUCCESS;
705 
706 	vdev_id = roamed_vdev_id;
707 	wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss;
708 
709 	/* update channel width */
710 	wma->interfaces[vdev_id].chan_width = roam_synch_ind_ptr->chan_width;
711 	/* Fill link freq from roam_synch_ind */
712 	if (is_multi_link_roam(roam_synch_ind_ptr))
713 		wma->interfaces[vdev_id].ch_freq =
714 			mlo_roam_get_chan_freq(vdev_id, roam_synch_ind_ptr);
715 	else
716 		wma->interfaces[vdev_id].ch_freq =
717 			roam_synch_ind_ptr->chan_freq;
718 
719 	add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params));
720 	if (!add_sta_params)
721 		return QDF_STATUS_E_INVAL;
722 
723 	if (is_multi_link_roam(roam_synch_ind_ptr))
724 		mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind_ptr,
725 					  &mac_addr);
726 	else
727 		mac_addr = roam_synch_ind_ptr->bssid;
728 
729 	qdf_mem_zero(add_sta_params, sizeof(*add_sta_params));
730 
731 	/* With self roaming on multi link AP, as the same
732 	 * peer already exists, new peer creation fails
733 	 * To handle this delete all link peers,
734 	 * while doing roam sync on first link.
735 	 */
736 	if (!is_multi_link_roam(roam_synch_ind_ptr) ||
737 	    wlan_vdev_mlme_get_is_mlo_link(wma->psoc, vdev_id) ||
738 	    mlo_get_single_link_ml_roaming(wma->psoc, vdev_id)) {
739 		status = wma_delete_all_peers(wma, vdev_id);
740 		if (QDF_IS_STATUS_ERROR(status))
741 			goto end;
742 	}
743 
744 	add_sta_params->staType = STA_ENTRY_SELF;
745 	add_sta_params->smesessionId = vdev_id;
746 	qdf_mem_copy(&add_sta_params->bssId, &mac_addr, QDF_MAC_ADDR_SIZE);
747 	add_sta_params->assocId = roam_synch_ind_ptr->aid;
748 
749 	bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev);
750 	if (!bssid) {
751 		wma_err("Failed to get bssid for vdev_%d", vdev_id);
752 		return QDF_STATUS_E_INVAL;
753 	}
754 
755 	is_assoc_peer = wlan_vdev_mlme_get_is_mlo_vdev(wma->psoc, vdev_id);
756 	if (is_multi_link_roam(roam_synch_ind_ptr)) {
757 		status = wma_create_peer(wma, mac_addr.bytes,
758 					 WMI_PEER_TYPE_DEFAULT, vdev_id,
759 					 roam_synch_ind_ptr->bssid.bytes,
760 					 is_assoc_peer);
761 	} else {
762 		status = wma_create_peer(wma, mac_addr.bytes,
763 					 WMI_PEER_TYPE_DEFAULT, vdev_id, NULL,
764 					 is_assoc_peer);
765 	}
766 
767 	if (QDF_IS_STATUS_ERROR(status)) {
768 		wma_err("Failed to create peer " QDF_MAC_ADDR_FMT,
769 			QDF_MAC_ADDR_REF(mac_addr.bytes));
770 		goto end;
771 	}
772 
773 	if (is_multi_link_roam(roam_synch_ind_ptr)) {
774 		status = lim_roam_mlo_create_peer(wma->mac_context,
775 						  roam_synch_ind_ptr, vdev_id,
776 						  mac_addr.bytes);
777 
778 		/* The created peer will be destroyed on HO failure cleanup */
779 		if (QDF_IS_STATUS_ERROR(status)) {
780 			wma_err("Failed to attach MLO peer " QDF_MAC_ADDR_FMT,
781 				QDF_MAC_ADDR_REF(mac_addr.bytes));
782 			goto end;
783 		}
784 	}
785 
786 	if (wlan_vdev_mlme_get_opmode(wma->interfaces[vdev_id].vdev) ==
787 								QDF_STA_MODE)
788 		wlan_cdp_set_peer_freq(wma->psoc, mac_addr.bytes,
789 				       wma->interfaces[vdev_id].ch_freq,
790 				       vdev_id);
791 
792 	/* Update new peer's uc cipher */
793 	uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
794 					   WLAN_CRYPTO_PARAM_UCAST_CIPHER);
795 	cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev,
796 					   WLAN_CRYPTO_PARAM_CIPHER_CAP);
797 	wma_set_peer_ucast_cipher(mac_addr.bytes, uc_cipher,
798 				  cipher_cap);
799 	wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params);
800 	wma_add_sta(wma, add_sta_params);
801 	qdf_mem_copy(bssid, mac_addr.bytes,
802 		     QDF_MAC_ADDR_SIZE);
803 	lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id,
804 				      roam_synch_ind_ptr);
805 end:
806 	qdf_mem_free(add_sta_params);
807 	return status;
808 }
809 
wma_update_phymode_on_roam(tp_wma_handle wma,struct qdf_mac_addr * bssid,wmi_channel * chan,struct wma_txrx_node * iface)810 static void wma_update_phymode_on_roam(tp_wma_handle wma,
811 				       struct qdf_mac_addr *bssid,
812 				       wmi_channel *chan,
813 				       struct wma_txrx_node *iface)
814 {
815 	enum wlan_phymode bss_phymode;
816 	struct wlan_channel *des_chan;
817 	struct wlan_channel *bss_chan;
818 	struct vdev_mlme_obj *vdev_mlme;
819 	uint8_t channel;
820 	struct wlan_objmgr_pdev *pdev = NULL;
821 	qdf_freq_t sec_ch_2g_freq = 0;
822 	struct ch_params ch_params = {0};
823 
824 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
825 	if (!vdev_mlme)
826 		return;
827 
828 	pdev = wlan_vdev_get_pdev(vdev_mlme->vdev);
829 
830 	channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq);
831 	if (chan)
832 		bss_phymode =
833 			wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan));
834 	else
835 		wma_get_phy_mode_cb(iface->ch_freq,
836 				    iface->chan_width, &bss_phymode);
837 
838 	/* Update vdev mlme channel info after roaming */
839 	des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev);
840 	bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev);
841 	des_chan->ch_phymode = bss_phymode;
842 	des_chan->ch_width = iface->chan_width;
843 	if (chan) {
844 		des_chan->ch_freq = chan->mhz;
845 		ch_params.ch_width = des_chan->ch_width;
846 		if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq) &&
847 		    des_chan->ch_width == CH_WIDTH_40MHZ &&
848 		    chan->band_center_freq1) {
849 			if (des_chan->ch_freq < chan->band_center_freq1)
850 				sec_ch_2g_freq = des_chan->ch_freq + 20;
851 			else
852 				sec_ch_2g_freq = des_chan->ch_freq - 20;
853 		}
854 		wlan_reg_set_channel_params_for_pwrmode(pdev, des_chan->ch_freq,
855 							sec_ch_2g_freq,
856 							&ch_params,
857 							REG_CURRENT_PWR_MODE);
858 		if (ch_params.ch_width != des_chan->ch_width ||
859 		    ch_params.mhz_freq_seg0 != chan->band_center_freq1 ||
860 		    ch_params.mhz_freq_seg1 != chan->band_center_freq2)
861 			wma_err("ch mismatch host & fw bw (%d %d) seg0 (%d, %d) seg1 (%d, %d)",
862 				ch_params.ch_width, des_chan->ch_width,
863 				ch_params.mhz_freq_seg0,
864 				chan->band_center_freq1,
865 				ch_params.mhz_freq_seg1,
866 				chan->band_center_freq2);
867 		des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0;
868 		des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1;
869 		des_chan->ch_width = ch_params.ch_width;
870 	} else {
871 		wma_err("LFR3: invalid chan");
872 	}
873 	qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel));
874 
875 	/* Till conversion is not done in WMI we need to fill fw phy mode */
876 	vdev_mlme->mgmt.generic.phy_mode = wmi_host_to_fw_phymode(bss_phymode);
877 
878 	/* update new phymode to peer */
879 	wma_objmgr_set_peer_mlme_phymode(wma, bssid->bytes, bss_phymode);
880 
881 	wma_debug("LFR3: new phymode %d freq %d (bw %d, %d %d)",
882 		  bss_phymode, des_chan->ch_freq, des_chan->ch_width,
883 		  des_chan->ch_cfreq1, des_chan->ch_cfreq2);
884 }
885 
886 /**
887  * wma_set_ric_req() - set ric request element
888  * @wma: wma handle
889  * @msg: message
890  * @is_add_ts: is addts required
891  *
892  * This function sets ric request element for 11r roaming.
893  *
894  * Return: none
895  */
wma_set_ric_req(tp_wma_handle wma,void * msg,uint8_t is_add_ts)896 void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts)
897 {
898 	if (!wma) {
899 		wma_err("wma handle is NULL");
900 		return;
901 	}
902 
903 	wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts);
904 }
905 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */
906 
907 #ifdef FEATURE_RSSI_MONITOR
wma_set_rssi_monitoring(tp_wma_handle wma,struct rssi_monitor_param * req)908 QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma,
909 				   struct rssi_monitor_param *req)
910 {
911 	if (!wma) {
912 		wma_err("wma handle is NULL");
913 		return QDF_STATUS_E_INVAL;
914 	}
915 
916 	return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req);
917 }
918 
919 /**
920  * wma_rssi_breached_event_handler() - rssi breached event handler
921  * @handle: wma handle
922  * @cmd_param_info: event handler data
923  * @len: length of @cmd_param_info
924  *
925  * Return: 0 on success; error number otherwise
926  */
wma_rssi_breached_event_handler(void * handle,u_int8_t * cmd_param_info,u_int32_t len)927 int wma_rssi_breached_event_handler(void *handle,
928 				u_int8_t  *cmd_param_info, u_int32_t len)
929 {
930 	WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf;
931 	wmi_rssi_breach_event_fixed_param  *event;
932 	struct rssi_breach_event  rssi;
933 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
934 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
935 
936 	if (!mac || !wma) {
937 		wma_err("Invalid mac/wma context");
938 		return -EINVAL;
939 	}
940 	if (!mac->sme.rssi_threshold_breached_cb) {
941 		wma_err("Callback not registered");
942 		return -EINVAL;
943 	}
944 	param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info;
945 	if (!param_buf) {
946 		wma_err("Invalid rssi breached event");
947 		return -EINVAL;
948 	}
949 	event = param_buf->fixed_param;
950 
951 	rssi.request_id = event->request_id;
952 	rssi.session_id = event->vdev_id;
953 	if (wmi_service_enabled(wma->wmi_handle,
954 				wmi_service_hw_db2dbm_support))
955 		rssi.curr_rssi = event->rssi;
956 	else
957 		rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
958 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes);
959 
960 	wma_debug("req_id: %u vdev_id: %d curr_rssi: %d",
961 		 rssi.request_id, rssi.session_id, rssi.curr_rssi);
962 	wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT,
963 		  QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes));
964 
965 	mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi);
966 	wma_debug("Invoke HDD rssi breached callback");
967 	return 0;
968 }
969 #endif /* FEATURE_RSSI_MONITOR */
970 
wma_pre_chan_switch_setup(uint8_t vdev_id)971 QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id)
972 {
973 	QDF_STATUS status = QDF_STATUS_SUCCESS;
974 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
975 	struct wma_txrx_node *intr;
976 	uint16_t beacon_interval_ori;
977 	bool restart;
978 	uint16_t reduced_beacon_interval;
979 	struct vdev_mlme_obj *mlme_obj;
980 	struct wlan_objmgr_vdev *vdev;
981 
982 	if (!wma) {
983 		pe_err("wma is NULL");
984 		return QDF_STATUS_E_FAILURE;
985 	}
986 	intr = &wma->interfaces[vdev_id];
987 	if (!intr) {
988 		pe_err("wma txrx node is NULL");
989 		return QDF_STATUS_E_FAILURE;
990 	}
991 	vdev = intr->vdev;
992 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
993 	if (!mlme_obj) {
994 		pe_err("vdev component object is NULL");
995 		return QDF_STATUS_E_FAILURE;
996 	}
997 
998 	restart =
999 		wma_get_channel_switch_in_progress(intr);
1000 	if (restart && intr->beacon_filter_enabled)
1001 		wma_remove_beacon_filter(wma, &intr->beacon_filter);
1002 
1003 	reduced_beacon_interval =
1004 		wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval;
1005 	if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) {
1006 
1007 
1008 		/* Reduce the beacon interval just before the channel switch.
1009 		 * This would help in reducing the downtime on the STA side
1010 		 * (which is waiting for beacons from the AP to resume back
1011 		 * transmission). Switch back the beacon_interval to its
1012 		 * original value after the channel switch based on the
1013 		 * timeout. This would ensure there are atleast some beacons
1014 		 * sent with increased frequency.
1015 		 */
1016 
1017 		wma_debug("Changing beacon interval to %d",
1018 			 reduced_beacon_interval);
1019 
1020 		/* Add a timer to reset the beacon interval back*/
1021 		beacon_interval_ori = mlme_obj->proto.generic.beacon_interval;
1022 		mlme_obj->proto.generic.beacon_interval =
1023 			reduced_beacon_interval;
1024 		if (wma_fill_beacon_interval_reset_req(wma,
1025 			vdev_id,
1026 			beacon_interval_ori,
1027 			RESET_BEACON_INTERVAL_TIMEOUT)) {
1028 
1029 			wma_debug("Failed to fill beacon interval reset req");
1030 		}
1031 	}
1032 
1033 	status = wma_vdev_pre_start(vdev_id, restart);
1034 
1035 	return status;
1036 }
1037 
wma_post_chan_switch_setup(uint8_t vdev_id)1038 QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id)
1039 {
1040 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
1041 	struct wma_txrx_node *intr;
1042 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
1043 	struct wlan_channel *des_chan;
1044 	cdp_config_param_type val;
1045 
1046 	if (!wma) {
1047 		pe_err("wma is NULL");
1048 		return QDF_STATUS_E_FAILURE;
1049 	}
1050 	intr = &wma->interfaces[vdev_id];
1051 	if (!intr) {
1052 		pe_err("wma txrx node is NULL");
1053 		return QDF_STATUS_E_FAILURE;
1054 	}
1055 	/*
1056 	 * Record monitor mode channel here in case HW
1057 	 * indicate RX PPDU TLV with invalid channel number.
1058 	 */
1059 	if (intr->type == WMI_VDEV_TYPE_MONITOR) {
1060 		des_chan = intr->vdev->vdev_mlme.des_chan;
1061 		val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee;
1062 		cdp_txrx_set_pdev_param(soc,
1063 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
1064 					CDP_MONITOR_CHANNEL, val);
1065 		val.cdp_pdev_param_mon_freq = des_chan->ch_freq;
1066 		cdp_txrx_set_pdev_param(soc,
1067 					wlan_objmgr_pdev_get_pdev_id(wma->pdev),
1068 					CDP_MONITOR_FREQUENCY, val);
1069 	}
1070 	return QDF_STATUS_SUCCESS;
1071 }
1072 
1073 #ifdef FEATURE_WLAN_ESE
1074 /**
1075  * wma_plm_start() - plm start request
1076  * @wma: wma handle
1077  * @params: plm request parameters
1078  *
1079  * This function request FW to start PLM.
1080  *
1081  * Return: QDF status
1082  */
wma_plm_start(tp_wma_handle wma,struct plm_req_params * params)1083 static QDF_STATUS wma_plm_start(tp_wma_handle wma,
1084 				struct plm_req_params *params)
1085 {
1086 	QDF_STATUS status;
1087 
1088 	wma_debug("PLM Start");
1089 
1090 	status = wmi_unified_plm_start_cmd(wma->wmi_handle, params);
1091 	if (QDF_IS_STATUS_ERROR(status))
1092 		return status;
1093 
1094 	wma->interfaces[params->vdev_id].plm_in_progress = true;
1095 
1096 	wma_debug("Plm start request sent successfully for vdev %d",
1097 		 params->vdev_id);
1098 
1099 	return status;
1100 }
1101 
1102 /**
1103  * wma_plm_stop() - plm stop request
1104  * @wma: wma handle
1105  * @params: plm request parameters
1106  *
1107  * This function request FW to stop PLM.
1108  *
1109  * Return: QDF status
1110  */
wma_plm_stop(tp_wma_handle wma,struct plm_req_params * params)1111 static QDF_STATUS wma_plm_stop(tp_wma_handle wma,
1112 			       struct plm_req_params *params)
1113 {
1114 	QDF_STATUS status;
1115 
1116 	if (!wma->interfaces[params->vdev_id].plm_in_progress) {
1117 		wma_err("No active plm req found, skip plm stop req");
1118 		return QDF_STATUS_E_FAILURE;
1119 	}
1120 
1121 	wma_debug("PLM Stop");
1122 
1123 	status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params);
1124 	if (QDF_IS_STATUS_ERROR(status))
1125 		return status;
1126 
1127 	wma->interfaces[params->vdev_id].plm_in_progress = false;
1128 
1129 	wma_debug("Plm stop request sent successfully for vdev %d",
1130 		 params->vdev_id);
1131 
1132 	return status;
1133 }
1134 
1135 /**
1136  * wma_config_plm() - config PLM
1137  * @wma: wma handle
1138  * @params: plm request parameters
1139  *
1140  * Return: none
1141  */
wma_config_plm(tp_wma_handle wma,struct plm_req_params * params)1142 void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params)
1143 {
1144 	QDF_STATUS ret;
1145 
1146 	if (!params || !wma)
1147 		return;
1148 
1149 	if (params->enable)
1150 		ret = wma_plm_start(wma, params);
1151 	else
1152 		ret = wma_plm_stop(wma, params);
1153 
1154 	if (ret)
1155 		wma_err("PLM %s failed %d",
1156 			params->enable ? "start" : "stop", ret);
1157 }
1158 #endif
1159 
1160 #ifdef FEATURE_WLAN_EXTSCAN
1161 /**
1162  * wma_extscan_wow_event_callback() - extscan wow event callback
1163  * @handle: WMA handle
1164  * @event: event buffer
1165  * @len: length of @event buffer
1166  *
1167  * In wow case, the wow event is followed by the payload of the event
1168  * which generated the wow event.
1169  * payload is 4 bytes of length followed by event buffer. the first 4 bytes
1170  * of event buffer is common tlv header, which is a combination
1171  * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to
1172  * identify the event which triggered wow event.
1173  * Payload is extracted and converted into generic tlv structure before
1174  * being passed to this function.
1175  *
1176  * @Return: Errno
1177  */
wma_extscan_wow_event_callback(void * handle,void * event,uint32_t len)1178 int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len)
1179 {
1180 	uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event));
1181 
1182 	switch (tag) {
1183 	case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param:
1184 		return wma_extscan_start_stop_event_handler(handle, event, len);
1185 
1186 	case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param:
1187 		return wma_extscan_operations_event_handler(handle, event, len);
1188 
1189 	case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param:
1190 		return wma_extscan_table_usage_event_handler(handle, event,
1191 							     len);
1192 
1193 	case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param:
1194 		return wma_extscan_cached_results_event_handler(handle, event,
1195 								len);
1196 
1197 	case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param:
1198 		return wma_extscan_change_results_event_handler(handle, event,
1199 								len);
1200 
1201 	case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param:
1202 		return wma_extscan_hotlist_match_event_handler(handle,	event,
1203 							       len);
1204 
1205 	case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param:
1206 		return wma_extscan_capabilities_event_handler(handle, event,
1207 							      len);
1208 
1209 	default:
1210 		wma_err("Unknown tag: %d", tag);
1211 		return 0;
1212 	}
1213 }
1214 
1215 /**
1216  * wma_register_extscan_event_handler() - register extscan event handler
1217  * @wma_handle: wma handle
1218  *
1219  * This function register extscan related event handlers.
1220  *
1221  * Return: none
1222  */
wma_register_extscan_event_handler(tp_wma_handle wma_handle)1223 void wma_register_extscan_event_handler(tp_wma_handle wma_handle)
1224 {
1225 	if (wma_validate_handle(wma_handle))
1226 		return;
1227 
1228 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1229 					   wmi_extscan_start_stop_event_id,
1230 					   wma_extscan_start_stop_event_handler,
1231 					   WMA_RX_SERIALIZER_CTX);
1232 
1233 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1234 					wmi_extscan_capabilities_event_id,
1235 					wma_extscan_capabilities_event_handler,
1236 					WMA_RX_SERIALIZER_CTX);
1237 
1238 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1239 				wmi_extscan_hotlist_match_event_id,
1240 				wma_extscan_hotlist_match_event_handler,
1241 				WMA_RX_SERIALIZER_CTX);
1242 
1243 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1244 				wmi_extscan_wlan_change_results_event_id,
1245 				wma_extscan_change_results_event_handler,
1246 				WMA_RX_SERIALIZER_CTX);
1247 
1248 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1249 				wmi_extscan_operation_event_id,
1250 				wma_extscan_operations_event_handler,
1251 				WMA_RX_SERIALIZER_CTX);
1252 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1253 				wmi_extscan_table_usage_event_id,
1254 				wma_extscan_table_usage_event_handler,
1255 				WMA_RX_SERIALIZER_CTX);
1256 
1257 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1258 				wmi_extscan_cached_results_event_id,
1259 				wma_extscan_cached_results_event_handler,
1260 				WMA_RX_SERIALIZER_CTX);
1261 
1262 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
1263 			wmi_passpoint_match_event_id,
1264 			wma_passpoint_match_event_handler,
1265 			WMA_RX_SERIALIZER_CTX);
1266 }
1267 
1268 /**
1269  * wma_extscan_start_stop_event_handler() -  extscan start/stop event handler
1270  * @handle: wma handle
1271  * @cmd_param_info: event buffer
1272  * @len: data length
1273  *
1274  * This function handles different extscan related commands
1275  * like start/stop/get results etc and indicate to upper layers.
1276  *
1277  * Return: 0 for success or error code.
1278  */
wma_extscan_start_stop_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1279 int wma_extscan_start_stop_event_handler(void *handle,
1280 					 uint8_t *cmd_param_info,
1281 					 uint32_t len)
1282 {
1283 	WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf;
1284 	wmi_extscan_start_stop_event_fixed_param *event;
1285 	struct sir_extscan_generic_response   *extscan_ind;
1286 	uint16_t event_type;
1287 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1288 
1289 	if (!mac)
1290 		return -EINVAL;
1291 
1292 	if (!mac->sme.ext_scan_ind_cb) {
1293 		wma_err("Callback not registered");
1294 		return -EINVAL;
1295 	}
1296 	param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *)
1297 		    cmd_param_info;
1298 	if (!param_buf) {
1299 		wma_err("Invalid extscan event");
1300 		return -EINVAL;
1301 	}
1302 	event = param_buf->fixed_param;
1303 	extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind));
1304 	if (!extscan_ind)
1305 		return -ENOMEM;
1306 
1307 	switch (event->command) {
1308 	case WMI_EXTSCAN_START_CMDID:
1309 		event_type = eSIR_EXTSCAN_START_RSP;
1310 		extscan_ind->status = event->status;
1311 		extscan_ind->request_id = event->request_id;
1312 		break;
1313 	case WMI_EXTSCAN_STOP_CMDID:
1314 		event_type = eSIR_EXTSCAN_STOP_RSP;
1315 		extscan_ind->status = event->status;
1316 		extscan_ind->request_id = event->request_id;
1317 		break;
1318 	case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID:
1319 		extscan_ind->status = event->status;
1320 		extscan_ind->request_id = event->request_id;
1321 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1322 			event_type =
1323 				eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP;
1324 		else
1325 			event_type =
1326 				eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP;
1327 		break;
1328 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID:
1329 		extscan_ind->status = event->status;
1330 		extscan_ind->request_id = event->request_id;
1331 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1332 			event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP;
1333 		else
1334 			event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP;
1335 		break;
1336 	case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID:
1337 		extscan_ind->status = event->status;
1338 		extscan_ind->request_id = event->request_id;
1339 		event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP;
1340 		break;
1341 	case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID:
1342 		extscan_ind->status = event->status;
1343 		extscan_ind->request_id = event->request_id;
1344 		if (event->mode == WMI_EXTSCAN_MODE_STOP)
1345 			event_type =
1346 				eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP;
1347 		else
1348 			event_type =
1349 				eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP;
1350 		break;
1351 	default:
1352 		wma_err("Unknown event(%d) from target", event->status);
1353 		qdf_mem_free(extscan_ind);
1354 		return -EINVAL;
1355 	}
1356 	mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind);
1357 	wma_debug("sending event to umac for requestid %u with status %d",
1358 		 extscan_ind->request_id, extscan_ind->status);
1359 	qdf_mem_free(extscan_ind);
1360 	return 0;
1361 }
1362 
1363 /**
1364  * wma_extscan_operations_event_handler() - extscan operation event handler
1365  * @handle: wma handle
1366  * @cmd_param_info: event buffer
1367  * @len: length
1368  *
1369  * This function handles different operations related event and indicate
1370  * upper layers with appropriate callback.
1371  *
1372  * Return: 0 for success or error code.
1373  */
wma_extscan_operations_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1374 int wma_extscan_operations_event_handler(void *handle,
1375 					 uint8_t *cmd_param_info,
1376 					 uint32_t len)
1377 {
1378 	tp_wma_handle wma = (tp_wma_handle) handle;
1379 	WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf;
1380 	wmi_extscan_operation_event_fixed_param *oprn_event;
1381 	tSirExtScanOnScanEventIndParams *oprn_ind;
1382 	uint32_t cnt;
1383 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1384 
1385 	if (!mac)
1386 		return -EINVAL;
1387 
1388 	if (!mac->sme.ext_scan_ind_cb) {
1389 		wma_err("Callback not registered");
1390 		return -EINVAL;
1391 	}
1392 	param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *)
1393 		    cmd_param_info;
1394 	if (!param_buf) {
1395 		wma_err("Invalid scan operation event");
1396 		return -EINVAL;
1397 	}
1398 	oprn_event = param_buf->fixed_param;
1399 	oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind));
1400 	if (!oprn_ind)
1401 		return -ENOMEM;
1402 
1403 	oprn_ind->requestId = oprn_event->request_id;
1404 
1405 	switch (oprn_event->event) {
1406 	case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT:
1407 		oprn_ind->status = 0;
1408 		goto exit_handler;
1409 	case WMI_EXTSCAN_CYCLE_STARTED_EVENT:
1410 		wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT");
1411 
1412 		if (oprn_event->num_buckets > param_buf->num_bucket_id) {
1413 			wma_err("FW mesg num_buk %d more than TLV hdr %d",
1414 				 oprn_event->num_buckets,
1415 				 param_buf->num_bucket_id);
1416 			qdf_mem_free(oprn_ind);
1417 			return -EINVAL;
1418 		}
1419 
1420 		cds_host_diag_log_work(&wma->extscan_wake_lock,
1421 				       WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION,
1422 				       WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
1423 		qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock,
1424 				      WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION);
1425 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT;
1426 		oprn_ind->status = 0;
1427 		oprn_ind->buckets_scanned = 0;
1428 		for (cnt = 0; cnt < oprn_event->num_buckets; cnt++)
1429 			oprn_ind->buckets_scanned |=
1430 				(1 << param_buf->bucket_id[cnt]);
1431 		wma_debug("num_buckets %u request_id %u buckets_scanned %u",
1432 			oprn_event->num_buckets, oprn_ind->requestId,
1433 			oprn_ind->buckets_scanned);
1434 		break;
1435 	case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT:
1436 		wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT");
1437 		qdf_wake_lock_release(&wma->extscan_wake_lock,
1438 				      WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
1439 		oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT;
1440 		oprn_ind->status = 0;
1441 		/* Set bucket scanned mask to zero on cycle complete */
1442 		oprn_ind->buckets_scanned = 0;
1443 		break;
1444 	case WMI_EXTSCAN_BUCKET_STARTED_EVENT:
1445 		wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT");
1446 		oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT;
1447 		oprn_ind->status = 0;
1448 		goto exit_handler;
1449 	case WMI_EXTSCAN_THRESHOLD_NUM_SCANS:
1450 		wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS");
1451 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS;
1452 		oprn_ind->status = 0;
1453 		break;
1454 	case WMI_EXTSCAN_THRESHOLD_PERCENT:
1455 		wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT");
1456 		oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT;
1457 		oprn_ind->status = 0;
1458 		break;
1459 	default:
1460 		wma_err("Unknown event(%d) from target", oprn_event->event);
1461 		qdf_mem_free(oprn_ind);
1462 		return -EINVAL;
1463 	}
1464 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1465 				eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind);
1466 	wma_debug("sending scan progress event to hdd");
1467 exit_handler:
1468 	qdf_mem_free(oprn_ind);
1469 	return 0;
1470 }
1471 
1472 /**
1473  * wma_extscan_table_usage_event_handler() - extscan table usage event handler
1474  * @handle: wma handle
1475  * @cmd_param_info: event buffer
1476  * @len: length
1477  *
1478  * This function handles table usage related event and indicate
1479  * upper layers with appropriate callback.
1480  *
1481  * Return: 0 for success or error code.
1482  */
wma_extscan_table_usage_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1483 int wma_extscan_table_usage_event_handler(void *handle,
1484 					  uint8_t *cmd_param_info,
1485 					  uint32_t len)
1486 {
1487 	WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf;
1488 	wmi_extscan_table_usage_event_fixed_param *event;
1489 	tSirExtScanResultsAvailableIndParams *tbl_usg_ind;
1490 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1491 
1492 	if (!mac)
1493 		return -EINVAL;
1494 
1495 	if (!mac->sme.ext_scan_ind_cb) {
1496 		wma_err("Callback not registered");
1497 		return -EINVAL;
1498 	}
1499 	param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *)
1500 		    cmd_param_info;
1501 	if (!param_buf) {
1502 		wma_err("Invalid table usage event");
1503 		return -EINVAL;
1504 	}
1505 	event = param_buf->fixed_param;
1506 	tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind));
1507 	if (!tbl_usg_ind)
1508 		return -ENOMEM;
1509 
1510 	tbl_usg_ind->requestId = event->request_id;
1511 	tbl_usg_ind->numResultsAvailable = event->entries_in_use;
1512 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1513 				eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND,
1514 				tbl_usg_ind);
1515 	wma_debug("sending scan_res available event to hdd");
1516 	qdf_mem_free(tbl_usg_ind);
1517 	return 0;
1518 }
1519 
1520 /**
1521  * wma_extscan_capabilities_event_handler() - extscan capabilities event handler
1522  * @handle: wma handle
1523  * @cmd_param_info: event buffer
1524  * @len: length
1525  *
1526  * This function handles capabilities event and indicate
1527  * upper layers with registered callback.
1528  *
1529  * Return: 0 for success or error code.
1530  */
wma_extscan_capabilities_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1531 int wma_extscan_capabilities_event_handler(void *handle,
1532 					   uint8_t *cmd_param_info,
1533 					   uint32_t len)
1534 {
1535 	WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf;
1536 	wmi_extscan_capabilities_event_fixed_param *event;
1537 	wmi_extscan_cache_capabilities *src_cache;
1538 	wmi_extscan_hotlist_monitor_capabilities *src_hotlist;
1539 	wmi_extscan_wlan_change_monitor_capabilities *src_change;
1540 	struct ext_scan_capabilities_response  *dest_capab;
1541 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1542 
1543 	if (!mac)
1544 		return -EINVAL;
1545 
1546 	if (!mac->sme.ext_scan_ind_cb) {
1547 		wma_err("Callback not registered");
1548 		return -EINVAL;
1549 	}
1550 	param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *)
1551 		    cmd_param_info;
1552 	if (!param_buf) {
1553 		wma_err("Invalid capabilities event");
1554 		return -EINVAL;
1555 	}
1556 	event = param_buf->fixed_param;
1557 	src_cache = param_buf->extscan_cache_capabilities;
1558 	src_hotlist = param_buf->hotlist_capabilities;
1559 	src_change = param_buf->wlan_change_capabilities;
1560 
1561 	if (!src_cache || !src_hotlist || !src_change) {
1562 		wma_err("Invalid capabilities list");
1563 		return -EINVAL;
1564 	}
1565 	dest_capab = qdf_mem_malloc(sizeof(*dest_capab));
1566 	if (!dest_capab)
1567 		return -ENOMEM;
1568 
1569 	dest_capab->requestId = event->request_id;
1570 	dest_capab->max_scan_buckets = src_cache->max_buckets;
1571 	dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size;
1572 	dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan;
1573 	dest_capab->max_scan_reporting_threshold =
1574 		src_cache->max_table_usage_threshold;
1575 
1576 	dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries;
1577 	dest_capab->max_rssi_sample_size =
1578 					src_change->max_rssi_averaging_samples;
1579 	dest_capab->max_bssid_history_entries =
1580 		src_change->max_rssi_history_entries;
1581 	dest_capab->max_significant_wifi_change_aps =
1582 		src_change->max_wlan_change_entries;
1583 	dest_capab->max_hotlist_ssids =
1584 				event->num_extscan_hotlist_ssid;
1585 	dest_capab->max_number_epno_networks =
1586 				event->num_epno_networks;
1587 	dest_capab->max_number_epno_networks_by_ssid =
1588 				event->num_epno_networks;
1589 	dest_capab->max_number_of_allow_listed_ssid =
1590 				event->num_roam_ssid_whitelist;
1591 	dest_capab->max_number_of_deny_listed_bssid =
1592 				event->num_roam_bssid_blacklist;
1593 	dest_capab->status = 0;
1594 
1595 	wma_debug("request_id: %u status: %d",
1596 		 dest_capab->requestId, dest_capab->status);
1597 
1598 	wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d",
1599 		 dest_capab->max_scan_buckets,
1600 		 dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size,
1601 		 dest_capab->max_ap_cache_per_scan);
1602 	wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d",
1603 		 dest_capab->max_scan_reporting_threshold,
1604 		 dest_capab->max_rssi_sample_size,
1605 		 dest_capab->max_bssid_history_entries,
1606 		 dest_capab->max_significant_wifi_change_aps);
1607 
1608 	wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d",
1609 		 dest_capab->max_hotlist_ssids,
1610 		 dest_capab->max_number_epno_networks,
1611 		 dest_capab->max_number_epno_networks_by_ssid);
1612 	wma_debug("max_number_of_allow_listed_ssid: %d, max_number_of_deny_listed_bssid: %d",
1613 		  dest_capab->max_number_of_allow_listed_ssid,
1614 		  dest_capab->max_number_of_deny_listed_bssid);
1615 
1616 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1617 				eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab);
1618 	qdf_mem_free(dest_capab);
1619 	return 0;
1620 }
1621 
1622 /**
1623  * wma_extscan_hotlist_match_event_handler() - hotlist match event handler
1624  * @handle: wma handle
1625  * @cmd_param_info: event buffer
1626  * @len: length
1627  *
1628  * This function handles hotlist match event and indicate
1629  * upper layers with registered callback.
1630  *
1631  * Return: 0 for success or error code.
1632  */
wma_extscan_hotlist_match_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1633 int wma_extscan_hotlist_match_event_handler(void *handle,
1634 					    uint8_t *cmd_param_info,
1635 					    uint32_t len)
1636 {
1637 	WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf;
1638 	wmi_extscan_hotlist_match_event_fixed_param *event;
1639 	struct extscan_hotlist_match *dest_hotlist;
1640 	tSirWifiScanResult *dest_ap;
1641 	wmi_extscan_wlan_descriptor *src_hotlist;
1642 	uint32_t numap;
1643 	int j, ap_found = 0;
1644 	uint32_t buf_len;
1645 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1646 
1647 	if (!mac)
1648 		return -EINVAL;
1649 
1650 	if (!mac->sme.ext_scan_ind_cb) {
1651 		wma_err("Callback not registered");
1652 		return -EINVAL;
1653 	}
1654 	param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *)
1655 		    cmd_param_info;
1656 	if (!param_buf) {
1657 		wma_err("Invalid hotlist match event");
1658 		return -EINVAL;
1659 	}
1660 	event = param_buf->fixed_param;
1661 	src_hotlist = param_buf->hotlist_match;
1662 	numap = event->total_entries;
1663 
1664 	if (!src_hotlist || !numap) {
1665 		wma_err("Hotlist AP's list invalid");
1666 		return -EINVAL;
1667 	}
1668 	if (numap > param_buf->num_hotlist_match) {
1669 		wma_err("Invalid no of total enteries %d", numap);
1670 		return -EINVAL;
1671 	}
1672 	if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) {
1673 		wma_err("Total Entries %u greater than max", numap);
1674 		numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES;
1675 	}
1676 
1677 	buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) +
1678 		  WMI_TLV_HDR_SIZE +
1679 		  (numap * sizeof(wmi_extscan_wlan_descriptor));
1680 
1681 	if (buf_len > len) {
1682 		wma_err("Invalid buf len from FW %d numap %d", len, numap);
1683 		return -EINVAL;
1684 	}
1685 
1686 	dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) +
1687 				      sizeof(*dest_ap) * numap);
1688 	if (!dest_hotlist)
1689 		return -ENOMEM;
1690 
1691 	dest_ap = &dest_hotlist->ap[0];
1692 	dest_hotlist->numOfAps = numap;
1693 	dest_hotlist->requestId = event->config_request_id;
1694 
1695 	if (event->first_entry_index +
1696 		event->num_entries_in_page < event->total_entries)
1697 		dest_hotlist->moreData = 1;
1698 	else
1699 		dest_hotlist->moreData = 0;
1700 
1701 	wma_debug("Hotlist match: requestId: %u numOfAps: %d",
1702 		 dest_hotlist->requestId, dest_hotlist->numOfAps);
1703 
1704 	/*
1705 	 * Currently firmware sends only one bss information in-case
1706 	 * of both hotlist ap found and lost.
1707 	 */
1708 	for (j = 0; j < numap; j++) {
1709 		dest_ap->rssi = 0;
1710 		dest_ap->channel = src_hotlist->channel;
1711 		dest_ap->ts = src_hotlist->tstamp;
1712 		ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE;
1713 		dest_ap->rtt = src_hotlist->rtt;
1714 		dest_ap->rtt_sd = src_hotlist->rtt_sd;
1715 		dest_ap->beaconPeriod = src_hotlist->beacon_interval;
1716 		dest_ap->capability = src_hotlist->capabilities;
1717 		dest_ap->ieLength = src_hotlist->ie_length;
1718 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
1719 					   dest_ap->bssid.bytes);
1720 		if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
1721 			wma_err("Invalid SSID len %d, truncating",
1722 				src_hotlist->ssid.ssid_len);
1723 			src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN;
1724 		}
1725 		qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid,
1726 			     src_hotlist->ssid.ssid_len);
1727 		dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
1728 		dest_ap++;
1729 		src_hotlist++;
1730 	}
1731 	dest_hotlist->ap_found = ap_found;
1732 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
1733 				eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist);
1734 	wma_debug("sending hotlist match event to hdd");
1735 	qdf_mem_free(dest_hotlist);
1736 	return 0;
1737 }
1738 
1739 /** wma_extscan_find_unique_scan_ids() - find unique scan ids
1740  * @cmd_param_info: event data.
1741  *
1742  * This utility function parses the input bss table of information
1743  * and find the unique number of scan ids
1744  *
1745  * Return: 0 on success; error number otherwise
1746  */
wma_extscan_find_unique_scan_ids(const u_int8_t * cmd_param_info)1747 static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info)
1748 {
1749 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1750 	wmi_extscan_cached_results_event_fixed_param  *event;
1751 	wmi_extscan_wlan_descriptor  *src_hotlist;
1752 	wmi_extscan_rssi_info  *src_rssi;
1753 	int prev_scan_id, scan_ids_cnt, i;
1754 
1755 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1756 						cmd_param_info;
1757 	event = param_buf->fixed_param;
1758 	src_hotlist = param_buf->bssid_list;
1759 	src_rssi = param_buf->rssi_list;
1760 
1761 	/* Find the unique number of scan_id's for grouping */
1762 	prev_scan_id = src_rssi->scan_cycle_id;
1763 	scan_ids_cnt = 1;
1764 	for (i = 1; i < param_buf->num_rssi_list; i++) {
1765 		src_rssi++;
1766 
1767 		if (prev_scan_id != src_rssi->scan_cycle_id) {
1768 			scan_ids_cnt++;
1769 			prev_scan_id = src_rssi->scan_cycle_id;
1770 		}
1771 	}
1772 
1773 	return scan_ids_cnt;
1774 }
1775 
1776 /** wma_fill_num_results_per_scan_id() - fill number of bss per scan id
1777  * @cmd_param_info: event data.
1778  * @scan_id_group: pointer to scan id group.
1779  *
1780  * This utility function parses the input bss table of information
1781  * and finds how many bss are there per unique scan id.
1782  *
1783  * Return: 0 on success; error number otherwise
1784  */
wma_fill_num_results_per_scan_id(const u_int8_t * cmd_param_info,struct extscan_cached_scan_result * scan_id_group)1785 static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info,
1786 			struct extscan_cached_scan_result *scan_id_group)
1787 {
1788 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1789 	wmi_extscan_cached_results_event_fixed_param  *event;
1790 	wmi_extscan_wlan_descriptor  *src_hotlist;
1791 	wmi_extscan_rssi_info  *src_rssi;
1792 	struct extscan_cached_scan_result *t_scan_id_grp;
1793 	int i, prev_scan_id;
1794 
1795 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1796 						cmd_param_info;
1797 	event = param_buf->fixed_param;
1798 	src_hotlist = param_buf->bssid_list;
1799 	src_rssi = param_buf->rssi_list;
1800 	t_scan_id_grp = scan_id_group;
1801 
1802 	prev_scan_id = src_rssi->scan_cycle_id;
1803 
1804 	t_scan_id_grp->scan_id = src_rssi->scan_cycle_id;
1805 	t_scan_id_grp->flags = src_rssi->flags;
1806 	t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned;
1807 	t_scan_id_grp->num_results = 1;
1808 	for (i = 1; i < param_buf->num_rssi_list; i++) {
1809 		src_rssi++;
1810 		if (prev_scan_id == src_rssi->scan_cycle_id) {
1811 			t_scan_id_grp->num_results++;
1812 		} else {
1813 			t_scan_id_grp++;
1814 			prev_scan_id = t_scan_id_grp->scan_id =
1815 				src_rssi->scan_cycle_id;
1816 			t_scan_id_grp->flags = src_rssi->flags;
1817 			t_scan_id_grp->buckets_scanned =
1818 				src_rssi->buckets_scanned;
1819 			t_scan_id_grp->num_results = 1;
1820 		}
1821 	}
1822 	return 0;
1823 }
1824 
1825 /** wma_group_num_bss_to_scan_id() - group bss to scan id table
1826  * @cmd_param_info: event data.
1827  * @cached_result: pointer to cached table.
1828  *
1829  * This function reads the bss information from the format
1830  * ------------------------------------------------------------------------
1831  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags |
1832  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags |
1833  * ........................................................................
1834  * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags |
1835  * ------------------------------------------------------------------------
1836  *
1837  * and converts it into the below format and store it
1838  *
1839  * ------------------------------------------------------------------------
1840  * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1
1841  * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2
1842  * ......................
1843  * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn
1844  * ------------------------------------------------------------------------
1845  *
1846  * Return: 0 on success; error number otherwise
1847  */
wma_group_num_bss_to_scan_id(const u_int8_t * cmd_param_info,struct extscan_cached_scan_results * cached_result)1848 static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info,
1849 			struct extscan_cached_scan_results *cached_result)
1850 {
1851 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1852 	wmi_extscan_cached_results_event_fixed_param  *event;
1853 	wmi_extscan_wlan_descriptor  *src_hotlist;
1854 	wmi_extscan_rssi_info  *src_rssi;
1855 	struct extscan_cached_scan_results *t_cached_result;
1856 	struct extscan_cached_scan_result *t_scan_id_grp;
1857 	int i, j;
1858 	uint32_t total_scan_num_results = 0;
1859 	tSirWifiScanResult *ap;
1860 
1861 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1862 						cmd_param_info;
1863 	event = param_buf->fixed_param;
1864 	src_hotlist = param_buf->bssid_list;
1865 	src_rssi = param_buf->rssi_list;
1866 	t_cached_result = cached_result;
1867 	t_scan_id_grp = &t_cached_result->result[0];
1868 
1869 	for (i = 0; i < t_cached_result->num_scan_ids; i++) {
1870 		total_scan_num_results += t_scan_id_grp->num_results;
1871 		t_scan_id_grp++;
1872 	}
1873 
1874 	if (total_scan_num_results > param_buf->num_bssid_list) {
1875 		wma_err("total_scan_num_results %d, num_bssid_list %d",
1876 			total_scan_num_results,
1877 			param_buf->num_bssid_list);
1878 		return -EINVAL;
1879 	}
1880 
1881 	t_scan_id_grp = &t_cached_result->result[0];
1882 	wma_debug("num_scan_ids:%d",
1883 			t_cached_result->num_scan_ids);
1884 	for (i = 0; i < t_cached_result->num_scan_ids; i++) {
1885 		wma_debug("num_results:%d", t_scan_id_grp->num_results);
1886 		t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results *
1887 						sizeof(*ap));
1888 		if (!t_scan_id_grp->ap)
1889 			return -ENOMEM;
1890 
1891 		ap = &t_scan_id_grp->ap[0];
1892 		for (j = 0; j < t_scan_id_grp->num_results; j++) {
1893 			ap->channel = src_hotlist->channel;
1894 			ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp);
1895 			ap->rtt = src_hotlist->rtt;
1896 			ap->rtt_sd = src_hotlist->rtt_sd;
1897 			ap->beaconPeriod = src_hotlist->beacon_interval;
1898 			ap->capability = src_hotlist->capabilities;
1899 			ap->ieLength = src_hotlist->ie_length;
1900 
1901 			/* Firmware already applied noise floor adjustment and
1902 			 * due to WMI interface "UINT32 rssi", host driver
1903 			 * receives a positive value, hence convert to
1904 			 * signed char to get the absolute rssi.
1905 			 */
1906 			ap->rssi = (signed char) src_rssi->rssi;
1907 			WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
1908 						   ap->bssid.bytes);
1909 
1910 			if (src_hotlist->ssid.ssid_len >
1911 			    WLAN_SSID_MAX_LEN) {
1912 				wma_debug("Invalid SSID len %d, truncating",
1913 					 src_hotlist->ssid.ssid_len);
1914 				src_hotlist->ssid.ssid_len =
1915 						WLAN_SSID_MAX_LEN;
1916 			}
1917 			qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid,
1918 					src_hotlist->ssid.ssid_len);
1919 			ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
1920 			ap++;
1921 			src_rssi++;
1922 			src_hotlist++;
1923 		}
1924 		t_scan_id_grp++;
1925 	}
1926 	return 0;
1927 }
1928 
1929 /**
1930  * wma_extscan_cached_results_event_handler() - cached results event handler
1931  * @handle: wma handle
1932  * @cmd_param_info: event buffer
1933  * @len: length of @cmd_param_info
1934  *
1935  * This function handles cached results event and indicate
1936  * cached results to upper layer.
1937  *
1938  * Return: 0 for success or error code.
1939  */
wma_extscan_cached_results_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)1940 int wma_extscan_cached_results_event_handler(void *handle,
1941 					     uint8_t *cmd_param_info,
1942 					     uint32_t len)
1943 {
1944 	WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
1945 	wmi_extscan_cached_results_event_fixed_param *event;
1946 	struct extscan_cached_scan_results *dest_cachelist;
1947 	struct extscan_cached_scan_result *dest_result;
1948 	struct extscan_cached_scan_results empty_cachelist;
1949 	wmi_extscan_wlan_descriptor *src_hotlist;
1950 	wmi_extscan_rssi_info *src_rssi;
1951 	int i, moredata, scan_ids_cnt, buf_len, status;
1952 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
1953 	uint32_t total_len;
1954 	bool excess_data = false;
1955 
1956 	if (!mac) {
1957 		wma_err("Invalid mac");
1958 		return -EINVAL;
1959 	}
1960 	if (!mac->sme.ext_scan_ind_cb) {
1961 		wma_err("Callback not registered");
1962 		return -EINVAL;
1963 	}
1964 	param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
1965 		    cmd_param_info;
1966 	if (!param_buf) {
1967 		wma_err("Invalid cached results event");
1968 		return -EINVAL;
1969 	}
1970 	event = param_buf->fixed_param;
1971 	src_hotlist = param_buf->bssid_list;
1972 	src_rssi = param_buf->rssi_list;
1973 	wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d",
1974 		 event->total_entries,
1975 		 event->first_entry_index,
1976 		 event->num_entries_in_page);
1977 
1978 	if (!src_hotlist || !src_rssi || !event->num_entries_in_page) {
1979 		wma_warn("Cached results empty, send 0 results");
1980 		goto noresults;
1981 	}
1982 
1983 	if (event->num_entries_in_page >
1984 	    (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) ||
1985 	    event->num_entries_in_page > param_buf->num_bssid_list) {
1986 		wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d",
1987 			 event->num_entries_in_page, param_buf->num_bssid_list);
1988 		return -EINVAL;
1989 	} else {
1990 		total_len = sizeof(*event) +
1991 			(event->num_entries_in_page * sizeof(*src_hotlist));
1992 	}
1993 	for (i = 0; i < event->num_entries_in_page; i++) {
1994 		if (src_hotlist[i].ie_length >
1995 		    WMI_SVC_MSG_MAX_SIZE - total_len) {
1996 			excess_data = true;
1997 			break;
1998 		} else {
1999 			total_len += src_hotlist[i].ie_length;
2000 			wma_debug("total len IE: %d", total_len);
2001 		}
2002 
2003 		if (src_hotlist[i].number_rssi_samples >
2004 		    (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) {
2005 			excess_data = true;
2006 			break;
2007 		} else {
2008 			total_len += (src_hotlist[i].number_rssi_samples *
2009 					sizeof(*src_rssi));
2010 			wma_debug("total len RSSI samples: %d", total_len);
2011 		}
2012 	}
2013 	if (excess_data) {
2014 		wma_err("excess data in WMI event");
2015 		return -EINVAL;
2016 	}
2017 
2018 	if (event->first_entry_index +
2019 	    event->num_entries_in_page < event->total_entries)
2020 		moredata = 1;
2021 	else
2022 		moredata = 0;
2023 
2024 	dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist));
2025 	if (!dest_cachelist)
2026 		return -ENOMEM;
2027 
2028 	qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist));
2029 	dest_cachelist->request_id = event->request_id;
2030 	dest_cachelist->more_data = moredata;
2031 
2032 	scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info);
2033 	wma_debug("scan_ids_cnt %d", scan_ids_cnt);
2034 	dest_cachelist->num_scan_ids = scan_ids_cnt;
2035 
2036 	buf_len = sizeof(*dest_result) * scan_ids_cnt;
2037 	dest_cachelist->result = qdf_mem_malloc(buf_len);
2038 	if (!dest_cachelist->result) {
2039 		qdf_mem_free(dest_cachelist);
2040 		return -ENOMEM;
2041 	}
2042 
2043 	dest_result = dest_cachelist->result;
2044 	wma_fill_num_results_per_scan_id(cmd_param_info, dest_result);
2045 
2046 	status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist);
2047 	if (!status)
2048 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2049 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
2050 				dest_cachelist);
2051 	else
2052 		wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback");
2053 
2054 	dest_result = dest_cachelist->result;
2055 	for (i = 0; i < dest_cachelist->num_scan_ids; i++) {
2056 		if (dest_result->ap)
2057 		qdf_mem_free(dest_result->ap);
2058 		dest_result++;
2059 	}
2060 	qdf_mem_free(dest_cachelist->result);
2061 	qdf_mem_free(dest_cachelist);
2062 	return status;
2063 
2064 noresults:
2065 	empty_cachelist.request_id = event->request_id;
2066 	empty_cachelist.more_data = 0;
2067 	empty_cachelist.num_scan_ids = 0;
2068 
2069 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2070 				eSIR_EXTSCAN_CACHED_RESULTS_IND,
2071 				&empty_cachelist);
2072 	return 0;
2073 }
2074 
2075 /**
2076  * wma_extscan_change_results_event_handler() - change results event handler
2077  * @handle: wma handle
2078  * @cmd_param_info: event buffer
2079  * @len: length
2080  *
2081  * This function handles change results event and indicate
2082  * change results to upper layer.
2083  *
2084  * Return: 0 for success or error code.
2085  */
wma_extscan_change_results_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)2086 int wma_extscan_change_results_event_handler(void *handle,
2087 					     uint8_t *cmd_param_info,
2088 					     uint32_t len)
2089 {
2090 	WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf;
2091 	wmi_extscan_wlan_change_results_event_fixed_param *event;
2092 	tSirWifiSignificantChangeEvent *dest_chglist;
2093 	tSirWifiSignificantChange *dest_ap;
2094 	wmi_extscan_wlan_change_result_bssid *src_chglist;
2095 
2096 	uint32_t numap;
2097 	int i, k;
2098 	uint8_t *src_rssi;
2099 	int count = 0;
2100 	int moredata;
2101 	uint32_t rssi_num = 0;
2102 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2103 	uint32_t buf_len;
2104 	bool excess_data = false;
2105 
2106 	if (!mac) {
2107 		wma_err("Invalid mac");
2108 		return -EINVAL;
2109 	}
2110 	if (!mac->sme.ext_scan_ind_cb) {
2111 		wma_err("Callback not registered");
2112 		return -EINVAL;
2113 	}
2114 	param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *)
2115 		    cmd_param_info;
2116 	if (!param_buf) {
2117 		wma_err("Invalid change monitor event");
2118 		return -EINVAL;
2119 	}
2120 	event = param_buf->fixed_param;
2121 	src_chglist = param_buf->bssid_signal_descriptor_list;
2122 	src_rssi = param_buf->rssi_list;
2123 	numap = event->num_entries_in_page;
2124 
2125 	if (!src_chglist || !numap) {
2126 		wma_err("Results invalid");
2127 		return -EINVAL;
2128 	}
2129 	if (numap > param_buf->num_bssid_signal_descriptor_list) {
2130 		wma_err("Invalid num of entries in page: %d", numap);
2131 		return -EINVAL;
2132 	}
2133 	for (i = 0; i < numap; i++) {
2134 		if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) {
2135 			wma_err("Invalid num of rssi samples %d numap %d rssi_num %d",
2136 				 src_chglist->num_rssi_samples,
2137 				 numap, rssi_num);
2138 			return -EINVAL;
2139 		}
2140 		rssi_num += src_chglist->num_rssi_samples;
2141 		src_chglist++;
2142 	}
2143 	src_chglist = param_buf->bssid_signal_descriptor_list;
2144 
2145 	if (event->first_entry_index +
2146 	    event->num_entries_in_page < event->total_entries) {
2147 		moredata = 1;
2148 	} else {
2149 		moredata = 0;
2150 	}
2151 
2152 	do {
2153 		if (event->num_entries_in_page >
2154 			(WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/
2155 			sizeof(*src_chglist)) {
2156 			excess_data = true;
2157 			break;
2158 		} else {
2159 			buf_len =
2160 				sizeof(*event) + (event->num_entries_in_page *
2161 						sizeof(*src_chglist));
2162 		}
2163 		if (rssi_num >
2164 			(WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) {
2165 			excess_data = true;
2166 			break;
2167 		}
2168 	} while (0);
2169 
2170 	if (excess_data) {
2171 		wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d",
2172 			numap, rssi_num);
2173 		QDF_ASSERT(0);
2174 		return -EINVAL;
2175 	}
2176 	dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) +
2177 				      sizeof(*dest_ap) * numap +
2178 				      sizeof(int32_t) * rssi_num);
2179 	if (!dest_chglist)
2180 		return -ENOMEM;
2181 
2182 	dest_ap = &dest_chglist->ap[0];
2183 	for (i = 0; i < numap; i++) {
2184 		dest_ap->channel = src_chglist->channel;
2185 		WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid,
2186 					   dest_ap->bssid.bytes);
2187 		dest_ap->numOfRssi = src_chglist->num_rssi_samples;
2188 		if (dest_ap->numOfRssi) {
2189 			if ((dest_ap->numOfRssi + count) >
2190 			    param_buf->num_rssi_list) {
2191 				wma_err("Invalid num in rssi list: %d",
2192 					dest_ap->numOfRssi);
2193 				qdf_mem_free(dest_chglist);
2194 				return -EINVAL;
2195 			}
2196 			for (k = 0; k < dest_ap->numOfRssi; k++) {
2197 				dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM +
2198 						   src_rssi[count++];
2199 			}
2200 		}
2201 		dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap +
2202 					dest_ap->numOfRssi * sizeof(int32_t) +
2203 					sizeof(*dest_ap));
2204 		src_chglist++;
2205 	}
2206 	dest_chglist->requestId = event->request_id;
2207 	dest_chglist->moreData = moredata;
2208 	dest_chglist->numResults = numap;
2209 
2210 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2211 			eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND,
2212 			dest_chglist);
2213 	wma_debug("sending change monitor results");
2214 	qdf_mem_free(dest_chglist);
2215 	return 0;
2216 }
2217 
2218 /**
2219  * wma_passpoint_match_event_handler() - passpoint match found event handler
2220  * @handle: WMA handle
2221  * @cmd_param_info: event data
2222  * @len: event data length
2223  *
2224  * This is the passpoint match found event handler; it reads event data from
2225  * @cmd_param_info and fill in the destination buffer and sends indication
2226  * up layer.
2227  *
2228  * Return: 0 on success; error number otherwise
2229  */
wma_passpoint_match_event_handler(void * handle,uint8_t * cmd_param_info,uint32_t len)2230 int wma_passpoint_match_event_handler(void *handle,
2231 				     uint8_t  *cmd_param_info,
2232 				     uint32_t len)
2233 {
2234 	WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf;
2235 	wmi_passpoint_event_hdr  *event;
2236 	struct wifi_passpoint_match  *dest_match;
2237 	tSirWifiScanResult      *dest_ap;
2238 	uint8_t *buf_ptr;
2239 	uint32_t buf_len = 0;
2240 	bool excess_data = false;
2241 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
2242 
2243 	if (!mac) {
2244 		wma_err("Invalid mac");
2245 		return -EINVAL;
2246 	}
2247 	if (!mac->sme.ext_scan_ind_cb) {
2248 		wma_err("Callback not registered");
2249 		return -EINVAL;
2250 	}
2251 
2252 	param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info;
2253 	if (!param_buf) {
2254 		wma_err("Invalid passpoint match event");
2255 		return -EINVAL;
2256 	}
2257 	event = param_buf->fixed_param;
2258 	buf_ptr = (uint8_t *)param_buf->fixed_param;
2259 
2260 	do {
2261 		if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) {
2262 			excess_data = true;
2263 			break;
2264 		} else {
2265 			buf_len = event->ie_length;
2266 		}
2267 
2268 		if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) {
2269 			excess_data = true;
2270 			break;
2271 		} else {
2272 			buf_len += event->anqp_length;
2273 		}
2274 
2275 	} while (0);
2276 
2277 	if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) ||
2278 	    buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) ||
2279 	    (event->ie_length + event->anqp_length) > param_buf->num_bufp) {
2280 		wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u",
2281 			event->ie_length, event->anqp_length,
2282 			param_buf->num_bufp);
2283 		return -EINVAL;
2284 	}
2285 
2286 	if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) {
2287 		wma_debug("Invalid ssid len %d, truncating",
2288 			 event->ssid.ssid_len);
2289 		event->ssid.ssid_len = WLAN_SSID_MAX_LEN;
2290 	}
2291 
2292 	dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len);
2293 	if (!dest_match)
2294 		return -EINVAL;
2295 
2296 	dest_ap = &dest_match->ap;
2297 	dest_match->request_id = 0;
2298 	dest_match->id = event->id;
2299 	dest_match->anqp_len = event->anqp_length;
2300 	wma_info("passpoint match: id: %u anqp length %u",
2301 		 dest_match->id, dest_match->anqp_len);
2302 
2303 	dest_ap->channel = event->channel_mhz;
2304 	dest_ap->ts = event->timestamp;
2305 	dest_ap->rtt = event->rtt;
2306 	dest_ap->rssi = event->rssi;
2307 	dest_ap->rtt_sd = event->rtt_sd;
2308 	dest_ap->beaconPeriod = event->beacon_period;
2309 	dest_ap->capability = event->capability;
2310 	dest_ap->ieLength = event->ie_length;
2311 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes);
2312 	qdf_mem_copy(dest_ap->ssid, event->ssid.ssid,
2313 				event->ssid.ssid_len);
2314 	dest_ap->ssid[event->ssid.ssid_len] = '\0';
2315 	qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) +
2316 			WMI_TLV_HDR_SIZE, dest_ap->ieLength);
2317 	qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) +
2318 			WMI_TLV_HDR_SIZE + dest_ap->ieLength,
2319 			dest_match->anqp_len);
2320 
2321 	mac->sme.ext_scan_ind_cb(mac->hdd_handle,
2322 				eSIR_PASSPOINT_NETWORK_FOUND_IND,
2323 				dest_match);
2324 	wma_debug("sending passpoint match event to hdd");
2325 	qdf_mem_free(dest_match);
2326 	return 0;
2327 }
2328 
wma_start_extscan(tp_wma_handle wma,struct wifi_scan_cmd_req_params * params)2329 QDF_STATUS wma_start_extscan(tp_wma_handle wma,
2330 			     struct wifi_scan_cmd_req_params *params)
2331 {
2332 	QDF_STATUS status;
2333 	struct wmi_unified *wmi_handle;
2334 
2335 	if (wma_validate_handle(wma))
2336 		return QDF_STATUS_E_INVAL;
2337 
2338 	wmi_handle = wma->wmi_handle;
2339 	if (wmi_validate_handle(wmi_handle))
2340 		return QDF_STATUS_E_INVAL;
2341 
2342 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2343 		wma_err("extscan not enabled");
2344 		return QDF_STATUS_E_FAILURE;
2345 	}
2346 
2347 	if (!params) {
2348 		wma_err("NULL param");
2349 		return QDF_STATUS_E_NOMEM;
2350 	}
2351 
2352 	status = wmi_unified_start_extscan_cmd(wmi_handle, params);
2353 	if (QDF_IS_STATUS_SUCCESS(status))
2354 		wma->interfaces[params->vdev_id].extscan_in_progress = true;
2355 
2356 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2357 
2358 	return status;
2359 }
2360 
wma_stop_extscan(tp_wma_handle wma,struct extscan_stop_req_params * params)2361 QDF_STATUS wma_stop_extscan(tp_wma_handle wma,
2362 			    struct extscan_stop_req_params *params)
2363 {
2364 	QDF_STATUS status;
2365 	struct wmi_unified *wmi_handle;
2366 
2367 	if (wma_validate_handle(wma))
2368 		return QDF_STATUS_E_INVAL;
2369 
2370 	wmi_handle = wma->wmi_handle;
2371 	if (wmi_validate_handle(wmi_handle))
2372 		return QDF_STATUS_E_INVAL;
2373 
2374 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2375 		wma_err("extscan not enabled");
2376 		return QDF_STATUS_E_FAILURE;
2377 	}
2378 
2379 	status = wmi_unified_stop_extscan_cmd(wmi_handle, params);
2380 	if (QDF_IS_STATUS_ERROR(status))
2381 		return status;
2382 
2383 	wma->interfaces[params->vdev_id].extscan_in_progress = false;
2384 	wma_debug("Extscan stop request sent successfully for vdev %d",
2385 		 params->vdev_id);
2386 
2387 	return status;
2388 }
2389 
wma_extscan_start_hotlist_monitor(tp_wma_handle wma,struct extscan_bssid_hotlist_set_params * params)2390 QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
2391 			struct extscan_bssid_hotlist_set_params *params)
2392 {
2393 	struct wmi_unified *wmi_handle;
2394 
2395 	if (wma_validate_handle(wma))
2396 		return QDF_STATUS_E_INVAL;
2397 
2398 	wmi_handle = wma->wmi_handle;
2399 	if (wmi_validate_handle(wmi_handle))
2400 		return QDF_STATUS_E_INVAL;
2401 
2402 	if (!params) {
2403 		wma_err("Invalid params");
2404 		return QDF_STATUS_E_INVAL;
2405 	}
2406 
2407 	return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle,
2408 							     params);
2409 }
2410 
wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,struct extscan_bssid_hotlist_reset_params * params)2411 QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,
2412 		    struct extscan_bssid_hotlist_reset_params *params)
2413 {
2414 	struct wmi_unified *wmi_handle;
2415 
2416 	if (wma_validate_handle(wma))
2417 		return QDF_STATUS_E_INVAL;
2418 
2419 	wmi_handle = wma->wmi_handle;
2420 	if (wmi_validate_handle(wmi_handle))
2421 		return QDF_STATUS_E_INVAL;
2422 
2423 	if (!params) {
2424 		wma_err("Invalid params");
2425 		return QDF_STATUS_E_INVAL;
2426 	}
2427 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2428 		wma_err("extscan not enabled");
2429 		return QDF_STATUS_E_FAILURE;
2430 	}
2431 
2432 	return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle,
2433 							    params);
2434 }
2435 
2436 QDF_STATUS
wma_extscan_start_change_monitor(tp_wma_handle wma,struct extscan_set_sig_changereq_params * params)2437 wma_extscan_start_change_monitor(tp_wma_handle wma,
2438 			struct extscan_set_sig_changereq_params *params)
2439 {
2440 	QDF_STATUS status;
2441 	struct wmi_unified *wmi_handle;
2442 
2443 	if (wma_validate_handle(wma))
2444 		return QDF_STATUS_E_INVAL;
2445 
2446 	wmi_handle = wma->wmi_handle;
2447 	if (wmi_validate_handle(wmi_handle))
2448 		return QDF_STATUS_E_INVAL;
2449 
2450 	if (!params) {
2451 		wma_err("NULL params");
2452 		return QDF_STATUS_E_NOMEM;
2453 	}
2454 
2455 	status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle,
2456 							      params);
2457 	return status;
2458 }
2459 
wma_extscan_stop_change_monitor(tp_wma_handle wma,struct extscan_capabilities_reset_params * params)2460 QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma,
2461 			struct extscan_capabilities_reset_params *params)
2462 {
2463 	struct wmi_unified *wmi_handle;
2464 
2465 	if (wma_validate_handle(wma))
2466 		return QDF_STATUS_E_INVAL;
2467 
2468 	wmi_handle = wma->wmi_handle;
2469 	if (wmi_validate_handle(wmi_handle))
2470 		return QDF_STATUS_E_INVAL;
2471 
2472 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2473 		wma_err("ext scan not enabled");
2474 		return QDF_STATUS_E_FAILURE;
2475 	}
2476 
2477 	return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle,
2478 							   params);
2479 }
2480 
2481 QDF_STATUS
wma_extscan_get_cached_results(tp_wma_handle wma,struct extscan_cached_result_params * params)2482 wma_extscan_get_cached_results(tp_wma_handle wma,
2483 			       struct extscan_cached_result_params *params)
2484 {
2485 	struct wmi_unified *wmi_handle;
2486 
2487 	if (wma_validate_handle(wma))
2488 		return QDF_STATUS_E_INVAL;
2489 
2490 	wmi_handle = wma->wmi_handle;
2491 	if (wmi_validate_handle(wmi_handle))
2492 		return QDF_STATUS_E_INVAL;
2493 
2494 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2495 		wma_err("extscan not enabled");
2496 		return QDF_STATUS_E_FAILURE;
2497 	}
2498 
2499 	return wmi_unified_extscan_get_cached_results_cmd(wmi_handle,
2500 							  params);
2501 }
2502 
2503 QDF_STATUS
wma_extscan_get_capabilities(tp_wma_handle wma,struct extscan_capabilities_params * params)2504 wma_extscan_get_capabilities(tp_wma_handle wma,
2505 			     struct extscan_capabilities_params *params)
2506 {
2507 	struct wmi_unified *wmi_handle;
2508 
2509 	if (wma_validate_handle(wma))
2510 		return QDF_STATUS_E_INVAL;
2511 
2512 	wmi_handle = wma->wmi_handle;
2513 	if (wmi_validate_handle(wmi_handle))
2514 		return QDF_STATUS_E_INVAL;
2515 
2516 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2517 		wma_err("extscan not enabled");
2518 		return QDF_STATUS_E_FAILURE;
2519 	}
2520 
2521 	return wmi_unified_extscan_get_capabilities_cmd(wmi_handle,
2522 							params);
2523 }
2524 
wma_set_epno_network_list(tp_wma_handle wma,struct wifi_enhanced_pno_params * req)2525 QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma,
2526 				     struct wifi_enhanced_pno_params *req)
2527 {
2528 	QDF_STATUS status;
2529 	struct wmi_unified *wmi_handle;
2530 
2531 	wma_debug("Enter");
2532 
2533 	if (wma_validate_handle(wma))
2534 		return QDF_STATUS_E_FAILURE;
2535 
2536 	wmi_handle = wma->wmi_handle;
2537 	if (wmi_validate_handle(wmi_handle))
2538 		return QDF_STATUS_E_FAILURE;
2539 
2540 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2541 		wma_err("extscan not enabled");
2542 		return QDF_STATUS_E_NOSUPPORT;
2543 	}
2544 
2545 	status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req);
2546 	wma_debug("Exit, vdev %d, status %d", req->vdev_id, status);
2547 
2548 	return status;
2549 }
2550 
2551 QDF_STATUS
wma_set_passpoint_network_list(tp_wma_handle wma,struct wifi_passpoint_req_param * params)2552 wma_set_passpoint_network_list(tp_wma_handle wma,
2553 			       struct wifi_passpoint_req_param *params)
2554 {
2555 	QDF_STATUS status;
2556 	struct wmi_unified *wmi_handle;
2557 
2558 	wma_debug("Enter");
2559 
2560 	if (wma_validate_handle(wma))
2561 		return QDF_STATUS_E_FAILURE;
2562 
2563 	wmi_handle = wma->wmi_handle;
2564 	if (wmi_validate_handle(wmi_handle))
2565 		return QDF_STATUS_E_FAILURE;
2566 
2567 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2568 		wma_err("extscan not enabled");
2569 		return QDF_STATUS_E_NOSUPPORT;
2570 	}
2571 
2572 	status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle,
2573 							    params);
2574 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2575 
2576 	return status;
2577 }
2578 
2579 QDF_STATUS
wma_reset_passpoint_network_list(tp_wma_handle wma,struct wifi_passpoint_req_param * params)2580 wma_reset_passpoint_network_list(tp_wma_handle wma,
2581 				 struct wifi_passpoint_req_param *params)
2582 {
2583 	QDF_STATUS status;
2584 	struct wmi_unified *wmi_handle;
2585 
2586 	wma_debug("Enter");
2587 
2588 	if (wma_validate_handle(wma))
2589 		return QDF_STATUS_E_FAILURE;
2590 
2591 	wmi_handle = wma->wmi_handle;
2592 	if (wmi_validate_handle(wmi_handle))
2593 		return QDF_STATUS_E_FAILURE;
2594 
2595 	if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) {
2596 		wma_err("extscan not enabled");
2597 		return QDF_STATUS_E_NOSUPPORT;
2598 	}
2599 
2600 	status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle,
2601 							      params);
2602 	wma_debug("Exit, vdev %d, status %d", params->vdev_id, status);
2603 
2604 	return status;
2605 }
2606 
2607 #endif
2608 
wma_scan_probe_setoui(tp_wma_handle wma,struct scan_mac_oui * set_oui)2609 QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma,
2610 				 struct scan_mac_oui *set_oui)
2611 {
2612 	struct wmi_unified *wmi_handle;
2613 
2614 	if (wma_validate_handle(wma))
2615 		return QDF_STATUS_E_INVAL;
2616 
2617 	wmi_handle = wma->wmi_handle;
2618 	if (wmi_validate_handle(wmi_handle))
2619 		return QDF_STATUS_E_INVAL;
2620 
2621 	if (!wma_is_vdev_valid(set_oui->vdev_id)) {
2622 		wma_err("vdev_id: %d is not active", set_oui->vdev_id);
2623 		return QDF_STATUS_E_INVAL;
2624 	}
2625 
2626 	return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui);
2627 }
2628 
2629 /**
2630  * wma_roam_better_ap_handler() - better ap event handler
2631  * @wma: wma handle
2632  * @vdev_id: vdev id
2633  *
2634  * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome.
2635  * This event means roam algorithm in Rome has found a better matching
2636  * candidate AP. The indication is sent to SME.
2637  *
2638  * Return: none
2639  */
wma_roam_better_ap_handler(tp_wma_handle wma,uint32_t vdev_id)2640 void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id)
2641 {
2642 	struct scheduler_msg msg = {0};
2643 	QDF_STATUS status;
2644 	struct cm_host_roam_start_ind *ind;
2645 
2646 	ind = qdf_mem_malloc(sizeof(*ind));
2647 	if (!ind)
2648 		return;
2649 
2650 	ind->pdev = wma->pdev;
2651 	ind->vdev_id = vdev_id;
2652 	msg.bodyptr = ind;
2653 	msg.callback = wlan_cm_host_roam_start;
2654 	wma_debug("Posting ROam start ind to connection manager, vdev %d",
2655 		  vdev_id);
2656 	status = scheduler_post_message(QDF_MODULE_ID_WMA,
2657 					QDF_MODULE_ID_OS_IF,
2658 					QDF_MODULE_ID_SCAN, &msg);
2659 
2660 	if (QDF_IS_STATUS_ERROR(status))
2661 		qdf_mem_free(msg.bodyptr);
2662 }
2663 
2664 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
2665 /**
2666  * wma_invalid_roam_reason_handler() - Handle Invalid roam notification
2667  * @wma: wma handle
2668  * @vdev_id: vdev id
2669  * @op_code: Operation to be done by the callback
2670  *
2671  * This function calls pe and csr callbacks with proper op_code
2672  *
2673  * Return: None
2674  */
wma_invalid_roam_reason_handler(tp_wma_handle wma_handle,uint32_t vdev_id,enum cm_roam_notif notif)2675 static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle,
2676 					    uint32_t vdev_id,
2677 					    enum cm_roam_notif notif)
2678 {
2679 	struct roam_offload_synch_ind *roam_synch_data;
2680 	enum sir_roam_op_code op_code;
2681 
2682 	if (notif == CM_ROAM_NOTIF_ROAM_START) {
2683 		op_code = SIR_ROAMING_START;
2684 	} else if (notif == CM_ROAM_NOTIF_ROAM_ABORT) {
2685 		op_code = SIR_ROAMING_ABORT;
2686 		lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2687 	} else {
2688 		wma_debug("Invalid notif %d", notif);
2689 		return;
2690 	}
2691 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2692 	if (!roam_synch_data)
2693 		return;
2694 
2695 	roam_synch_data->roamed_vdev_id = vdev_id;
2696 	if (notif != CM_ROAM_NOTIF_ROAM_START)
2697 		wma_handle->pe_roam_synch_cb(wma_handle->mac_context,
2698 					     roam_synch_data->roamed_vdev_id,
2699 					     roam_synch_data, 0, op_code);
2700 
2701 	if (notif == CM_ROAM_NOTIF_ROAM_START)
2702 		cm_fw_roam_start_req(wma_handle->psoc, vdev_id);
2703 	else
2704 		cm_fw_roam_abort_req(wma_handle->psoc, vdev_id);
2705 
2706 	qdf_mem_free(roam_synch_data);
2707 }
2708 
wma_handle_roam_sync_timeout(tp_wma_handle wma_handle,struct roam_sync_timeout_timer_info * info)2709 void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle,
2710 				  struct roam_sync_timeout_timer_info *info)
2711 {
2712 	wma_invalid_roam_reason_handler(wma_handle, info->vdev_id,
2713 					CM_ROAM_NOTIF_ROAM_ABORT);
2714 }
2715 
cm_invalid_roam_reason_handler(uint32_t vdev_id,enum cm_roam_notif notif,uint32_t reason)2716 void cm_invalid_roam_reason_handler(uint32_t vdev_id, enum cm_roam_notif notif,
2717 				    uint32_t reason)
2718 {
2719 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2720 
2721 	if (!wma_handle) {
2722 		QDF_ASSERT(0);
2723 		return;
2724 	}
2725 	wma_invalid_roam_reason_handler(wma_handle, vdev_id, notif);
2726 
2727 	if (notif == CM_ROAM_NOTIF_SCAN_START ||
2728 	    notif == CM_ROAM_NOTIF_SCAN_END)
2729 		cm_report_roam_rt_stats(wma_handle->psoc, vdev_id,
2730 					ROAM_RT_STATS_TYPE_SCAN_STATE,
2731 					NULL, notif, 0, reason);
2732 }
2733 #endif
2734 
2735 static void
wma_handle_roam_reason_invoke_roam_fail(tp_wma_handle wma_handle,uint8_t vdev_id,uint32_t notif_params)2736 wma_handle_roam_reason_invoke_roam_fail(tp_wma_handle wma_handle,
2737 					uint8_t vdev_id, uint32_t notif_params)
2738 {
2739 	struct roam_offload_synch_ind *roam_synch_data;
2740 
2741 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2742 	if (!roam_synch_data)
2743 		return;
2744 
2745 	lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2746 	roam_synch_data->roamed_vdev_id = vdev_id;
2747 	cm_fw_roam_invoke_fail(wma_handle->psoc, vdev_id);
2748 	wlan_cm_update_roam_states(wma_handle->psoc, vdev_id,
2749 				   notif_params,
2750 				   ROAM_INVOKE_FAIL_REASON);
2751 	qdf_mem_free(roam_synch_data);
2752 }
2753 
wma_handle_roam_reason_btm(uint8_t vdev_id)2754 static void wma_handle_roam_reason_btm(uint8_t vdev_id)
2755 {
2756 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2757 
2758 	if (!wma_handle) {
2759 		QDF_ASSERT(0);
2760 		return;
2761 	}
2762 	/*
2763 	 * This event is received from firmware if firmware is unable to
2764 	 * find candidate AP after roam scan and BTM request from AP
2765 	 * has disassoc imminent bit set.
2766 	 */
2767 	wma_debug("Kickout due to btm request");
2768 	wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, vdev_id, NULL);
2769 	wma_handle_disconnect_reason(wma_handle, vdev_id,
2770 			HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT);
2771 }
2772 
wma_handle_roam_reason_bmiss(uint8_t vdev_id,uint32_t rssi)2773 static void wma_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi)
2774 {
2775 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2776 
2777 	if (!wma_handle) {
2778 		QDF_ASSERT(0);
2779 		return;
2780 	}
2781 	/*
2782 	 * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so
2783 	 * avoid using CSR/PE structure directly
2784 	 */
2785 	wma_debug("Beacon Miss for vdevid %x", vdev_id);
2786 	mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi);
2787 	wma_beacon_miss_handler(wma_handle, vdev_id, rssi);
2788 	wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, vdev_id, NULL);
2789 }
2790 
wma_handle_roam_reason_better_ap(uint8_t vdev_id,uint32_t rssi)2791 static void wma_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi)
2792 {
2793 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2794 
2795 	if (!wma_handle) {
2796 		QDF_ASSERT(0);
2797 		return;
2798 	}
2799 	/*
2800 	 * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context,
2801 	 * so avoid using CSR/PE structure directly.
2802 	 */
2803 	wma_debug("Better AP found for vdevid %x, rssi %d", vdev_id, rssi);
2804 	mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev,
2805 				       false);
2806 	wma_roam_better_ap_handler(wma_handle, vdev_id);
2807 }
2808 
wma_handle_roam_reason_suitable_ap(uint8_t vdev_id,uint32_t rssi)2809 static void wma_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi)
2810 {
2811 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2812 
2813 	if (!wma_handle) {
2814 		QDF_ASSERT(0);
2815 		return;
2816 	}
2817 	/*
2818 	 * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ
2819 	 * context, so avoid using CSR/PE structure directly.
2820 	 */
2821 	mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev,
2822 				       true);
2823 	mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi);
2824 	wma_debug("Bmiss scan AP found for vdevid %x, rssi %d", vdev_id, rssi);
2825 	wma_roam_better_ap_handler(wma_handle, vdev_id);
2826 }
2827 
2828 static void
wma_update_pdev_hw_mode_trans_ind(tp_wma_handle wma,struct cm_hw_mode_trans_ind * trans_ind)2829 wma_update_pdev_hw_mode_trans_ind(tp_wma_handle wma,
2830 				  struct cm_hw_mode_trans_ind *trans_ind)
2831 {
2832 	uint32_t i;
2833 
2834 	/* Store the vdev-mac map in WMA and send to policy manager */
2835 	for (i = 0; i < trans_ind->num_vdev_mac_entries; i++)
2836 		wma_update_intf_hw_mode_params(
2837 				trans_ind->vdev_mac_map[i].vdev_id,
2838 				trans_ind->vdev_mac_map[i].mac_id,
2839 				trans_ind->new_hw_mode_index);
2840 
2841 	wma->old_hw_mode_index = trans_ind->old_hw_mode_index;
2842 	wma->new_hw_mode_index = trans_ind->new_hw_mode_index;
2843 	policy_mgr_update_new_hw_mode_index(wma->psoc,
2844 					    trans_ind->new_hw_mode_index);
2845 	policy_mgr_update_old_hw_mode_index(wma->psoc,
2846 					    trans_ind->old_hw_mode_index);
2847 
2848 	wma_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d",
2849 		  wma->old_hw_mode_index, wma->new_hw_mode_index);
2850 }
2851 
2852 static void
wma_handle_hw_mode_trans_ind(tp_wma_handle wma_handle,struct cm_hw_mode_trans_ind * hw_mode_trans_ind)2853 wma_handle_hw_mode_trans_ind(tp_wma_handle wma_handle,
2854 			     struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2855 {
2856 	struct scheduler_msg sme_msg = {0};
2857 	QDF_STATUS status;
2858 
2859 	if (hw_mode_trans_ind) {
2860 		wma_update_pdev_hw_mode_trans_ind(wma_handle,
2861 						  hw_mode_trans_ind);
2862 		wma_debug("Update HW mode");
2863 		sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND;
2864 		sme_msg.bodyptr = hw_mode_trans_ind;
2865 
2866 		status = scheduler_post_message(QDF_MODULE_ID_WMA,
2867 						QDF_MODULE_ID_SME,
2868 						QDF_MODULE_ID_SME, &sme_msg);
2869 		if (QDF_IS_STATUS_ERROR(status))
2870 			qdf_mem_free(hw_mode_trans_ind);
2871 	} else {
2872 		wma_debug("hw_mode transition fixed param is NULL");
2873 	}
2874 }
2875 
cm_rso_cmd_status_event_handler(uint8_t vdev_id,enum cm_roam_notif notif)2876 int cm_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif)
2877 {
2878 	return wma_rso_cmd_status_event_handler(vdev_id, notif);
2879 }
2880 
2881 void
cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id,uint32_t notif_params,struct cm_hw_mode_trans_ind * trans_ind)2882 cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id,	uint32_t notif_params,
2883 				       struct cm_hw_mode_trans_ind *trans_ind)
2884 {
2885 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2886 
2887 	if (!wma_handle) {
2888 		QDF_ASSERT(0);
2889 		return;
2890 	}
2891 	wma_handle_hw_mode_trans_ind(wma_handle, trans_ind);
2892 	wma_handle_roam_reason_invoke_roam_fail(wma_handle, vdev_id,
2893 						notif_params);
2894 	cm_report_roam_rt_stats(wma_handle->psoc, vdev_id,
2895 				ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON,
2896 				NULL, notif_params, 0, 0);
2897 }
2898 
2899 void
cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind * trans_ind)2900 cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind *trans_ind)
2901 {
2902 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2903 	struct cm_hw_mode_trans_ind *trans_ind_data;
2904 
2905 	if (!wma_handle) {
2906 		wma_err("invalid wma handle");
2907 		return;
2908 	}
2909 	trans_ind_data = qdf_mem_malloc(sizeof(*trans_ind_data));
2910 	if (!trans_ind_data)
2911 		return;
2912 	qdf_mem_copy(trans_ind_data, trans_ind, sizeof(*trans_ind_data));
2913 	wma_handle_hw_mode_trans_ind(wma_handle, trans_ind_data);
2914 }
2915 
2916 static void
wma_handle_roam_reason_deauth(uint8_t vdev_id,uint32_t notif_params,uint32_t notif_params1,uint8_t * deauth_disassoc_frame)2917 wma_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params,
2918 			      uint32_t notif_params1,
2919 			      uint8_t *deauth_disassoc_frame)
2920 {
2921 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2922 	struct roam_offload_synch_ind *roam_synch_data;
2923 
2924 	if (!wma_handle) {
2925 		QDF_ASSERT(0);
2926 		return;
2927 	}
2928 	wma_debug("Received disconnect roam event reason:%d", notif_params);
2929 	wma_handle->pe_disconnect_cb(wma_handle->mac_context,
2930 				     vdev_id,
2931 				     deauth_disassoc_frame, notif_params1,
2932 				     notif_params);
2933 	roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data));
2934 	if (!roam_synch_data)
2935 		return;
2936 
2937 	roam_synch_data->roamed_vdev_id = vdev_id;
2938 	qdf_mem_free(roam_synch_data);
2939 }
2940 
cm_handle_roam_reason_deauth(uint8_t vdev_id,uint32_t notif_params,uint8_t * deauth_disassoc_frame,uint32_t frame_len)2941 void cm_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params,
2942 				  uint8_t *deauth_disassoc_frame,
2943 				  uint32_t frame_len)
2944 {
2945 	wma_handle_roam_reason_deauth(vdev_id, notif_params, frame_len,
2946 				      deauth_disassoc_frame);
2947 }
2948 
cm_handle_roam_reason_btm(uint8_t vdev_id)2949 void cm_handle_roam_reason_btm(uint8_t vdev_id)
2950 {
2951 	wma_handle_roam_reason_btm(vdev_id);
2952 }
2953 
cm_handle_roam_reason_bmiss(uint8_t vdev_id,uint32_t rssi)2954 void cm_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi)
2955 {
2956 	wma_handle_roam_reason_bmiss(vdev_id, rssi);
2957 }
2958 
cm_handle_roam_reason_better_ap(uint8_t vdev_id,uint32_t rssi)2959 void cm_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi)
2960 {
2961 	wma_handle_roam_reason_better_ap(vdev_id, rssi);
2962 }
2963 
cm_handle_roam_reason_suitable_ap(uint8_t vdev_id,uint32_t rssi)2964 void cm_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi)
2965 {
2966 	wma_handle_roam_reason_suitable_ap(vdev_id, rssi);
2967 }
2968 
2969 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
2970 static void
wma_handle_roam_reason_ho_failed(uint8_t vdev_id,struct qdf_mac_addr bssid,struct cm_hw_mode_trans_ind * hw_mode_trans_ind)2971 wma_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid,
2972 				 struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2973 {
2974 	tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
2975 
2976 	if (!wma_handle) {
2977 		QDF_ASSERT(0);
2978 		return;
2979 	}
2980 	/*
2981 	 * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context,
2982 	 * so avoid using CSR/PE structure directly.
2983 	 */
2984 	wma_err("LFR3:Hand-Off Failed for vdevid %x", vdev_id);
2985 	wma_debug("mac addr to avoid " QDF_MAC_ADDR_FMT,
2986 		  QDF_MAC_ADDR_REF(bssid.bytes));
2987 	wma_handle_hw_mode_trans_ind(wma_handle, hw_mode_trans_ind);
2988 	cm_fw_ho_fail_req(wma_handle->psoc, vdev_id, bssid);
2989 	lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id);
2990 }
2991 
2992 void
cm_handle_roam_reason_ho_failed(uint8_t vdev_id,struct qdf_mac_addr bssid,struct cm_hw_mode_trans_ind * hw_mode_trans_ind)2993 cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid,
2994 				struct cm_hw_mode_trans_ind *hw_mode_trans_ind)
2995 {
2996 	wma_handle_roam_reason_ho_failed(vdev_id, bssid, hw_mode_trans_ind);
2997 }
2998 #endif
2999 
3000 #ifdef FEATURE_LFR_SUBNET_DETECTION
wma_set_gateway_params(tp_wma_handle wma,struct gateway_update_req_param * req)3001 QDF_STATUS wma_set_gateway_params(tp_wma_handle wma,
3002 				  struct gateway_update_req_param *req)
3003 {
3004 	if (wma_validate_handle(wma))
3005 		return QDF_STATUS_E_INVAL;
3006 
3007 	return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req);
3008 }
3009 #endif /* FEATURE_LFR_SUBNET_DETECTION */
3010 
3011 /**
3012  * wma_ht40_stop_obss_scan() - ht40 obss stop scan
3013  * @wma: WMA handle
3014  * @vdev_id: vdev identifier
3015  *
3016  * Return: Return QDF_STATUS, otherwise appropriate failure code
3017  */
wma_ht40_stop_obss_scan(tp_wma_handle wma,int32_t vdev_id)3018 QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id)
3019 {
3020 	QDF_STATUS status;
3021 	wmi_buf_t buf;
3022 	wmi_obss_scan_disable_cmd_fixed_param *cmd;
3023 	int len = sizeof(*cmd);
3024 
3025 	buf = wmi_buf_alloc(wma->wmi_handle, len);
3026 	if (!buf)
3027 		return QDF_STATUS_E_NOMEM;
3028 
3029 	wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id);
3030 
3031 	cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf);
3032 	WMITLV_SET_HDR(&cmd->tlv_header,
3033 		WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param,
3034 		WMITLV_GET_STRUCT_TLVLEN(
3035 			wmi_obss_scan_disable_cmd_fixed_param));
3036 
3037 	cmd->vdev_id = vdev_id;
3038 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3039 				      WMI_OBSS_SCAN_DISABLE_CMDID);
3040 	if (QDF_IS_STATUS_ERROR(status))
3041 		wmi_buf_free(buf);
3042 
3043 	return status;
3044 }
3045 
3046 /**
3047  * wma_send_ht40_obss_scanind() - ht40 obss start scan indication
3048  * @wma: WMA handle
3049  * @req: start scan request
3050  *
3051  * Return: Return QDF_STATUS, otherwise appropriate failure code
3052  */
wma_send_ht40_obss_scanind(tp_wma_handle wma,struct obss_ht40_scanind * req)3053 QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma,
3054 				struct obss_ht40_scanind *req)
3055 {
3056 	QDF_STATUS status;
3057 	wmi_buf_t buf;
3058 	wmi_obss_scan_enable_cmd_fixed_param *cmd;
3059 	int len = 0;
3060 	uint8_t *buf_ptr, i;
3061 	uint8_t *channel_list;
3062 	uint32_t *chan_freq_list;
3063 
3064 	len += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
3065 
3066 	len += WMI_TLV_HDR_SIZE;
3067 	len += qdf_roundup(sizeof(uint8_t) * req->channel_count,
3068 				sizeof(uint32_t));
3069 
3070 	len += WMI_TLV_HDR_SIZE;
3071 	len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
3072 
3073 	/* length calculation for chan_freqs */
3074 	len += WMI_TLV_HDR_SIZE;
3075 	len += sizeof(uint32_t) * req->channel_count;
3076 
3077 	wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d",
3078 		 len, req->bss_id, req->channel_count, req->iefield_len);
3079 
3080 	wma_debug("scantype %d active_time %d passive %d Obss interval %d",
3081 		 req->scan_type, req->obss_active_dwelltime,
3082 		 req->obss_passive_dwelltime,
3083 		 req->obss_width_trigger_interval);
3084 
3085 	buf = wmi_buf_alloc(wma->wmi_handle, len);
3086 	if (!buf)
3087 		return QDF_STATUS_E_NOMEM;
3088 
3089 	cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf);
3090 	WMITLV_SET_HDR(&cmd->tlv_header,
3091 		WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param,
3092 		WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param));
3093 
3094 	buf_ptr = (uint8_t *) cmd;
3095 
3096 	cmd->vdev_id = req->bss_id;
3097 	cmd->scan_type = req->scan_type;
3098 	cmd->obss_scan_active_dwell =
3099 		req->obss_active_dwelltime;
3100 	cmd->obss_scan_passive_dwell =
3101 		req->obss_passive_dwelltime;
3102 	cmd->bss_channel_width_trigger_scan_interval =
3103 		req->obss_width_trigger_interval;
3104 	cmd->bss_width_channel_transition_delay_factor =
3105 		req->bsswidth_ch_trans_delay;
3106 	cmd->obss_scan_active_total_per_channel =
3107 		req->obss_active_total_per_channel;
3108 	cmd->obss_scan_passive_total_per_channel =
3109 		req->obss_passive_total_per_channel;
3110 	cmd->obss_scan_activity_threshold =
3111 		req->obss_activity_threshold;
3112 
3113 	cmd->channel_len = req->channel_count;
3114 	cmd->forty_mhz_intolerant =  req->fortymhz_intolerent;
3115 	cmd->current_operating_class = req->current_operatingclass;
3116 	cmd->ie_len = req->iefield_len;
3117 
3118 	buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param);
3119 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
3120 		qdf_roundup(req->channel_count, sizeof(uint32_t)));
3121 
3122 	buf_ptr += WMI_TLV_HDR_SIZE;
3123 	channel_list = (uint8_t *) buf_ptr;
3124 
3125 	for (i = 0; i < req->channel_count; i++) {
3126 		channel_list[i] =
3127 		  wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]);
3128 		wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]);
3129 	}
3130 
3131 	buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count,
3132 				sizeof(uint32_t));
3133 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
3134 			qdf_roundup(1, sizeof(uint32_t)));
3135 	buf_ptr += WMI_TLV_HDR_SIZE;
3136 
3137 	buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t));
3138 
3139 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
3140 		       sizeof(uint32_t) * req->channel_count);
3141 	buf_ptr += WMI_TLV_HDR_SIZE;
3142 
3143 	chan_freq_list = (uint32_t *)buf_ptr;
3144 	for (i = 0; i < req->channel_count; i++) {
3145 		chan_freq_list[i] = req->chan_freq_list[i];
3146 		wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]);
3147 	}
3148 
3149 	buf_ptr += sizeof(uint32_t) * req->channel_count;
3150 
3151 	status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
3152 				      WMI_OBSS_SCAN_ENABLE_CMDID);
3153 	if (QDF_IS_STATUS_ERROR(status))
3154 		wmi_buf_free(buf);
3155 
3156 	return status;
3157 }
3158 
3159 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
cm_roam_update_vdev(struct wlan_objmgr_vdev * vdev,struct roam_offload_synch_ind * sync_ind)3160 QDF_STATUS cm_roam_update_vdev(struct wlan_objmgr_vdev *vdev,
3161 			       struct roam_offload_synch_ind *sync_ind)
3162 {
3163 	QDF_STATUS status;
3164 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3165 	struct qdf_mac_addr *self_mac_addr;
3166 	uint8_t vdev_id;
3167 
3168 	if (!wma)
3169 		return QDF_STATUS_E_INVAL;
3170 
3171 	vdev_id = wlan_vdev_get_id(vdev);
3172 
3173 	status = wma_roam_update_vdev(wma, sync_ind, vdev_id);
3174 	if (QDF_IS_STATUS_ERROR(status)) {
3175 		wma_debug("VDEV update failed for roam on %d", vdev_id);
3176 		return status;
3177 	}
3178 
3179 	if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
3180 		self_mac_addr =
3181 			(struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev);
3182 		goto update_deflink;
3183 	}
3184 
3185 	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
3186 	    wlan_vdev_mlme_is_mlo_link_vdev(vdev))
3187 		return QDF_STATUS_SUCCESS;
3188 
3189 	self_mac_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
3190 
3191 update_deflink:
3192 	/* Set the assoc vdev as DP deflink after roaming */
3193 	wlan_dp_update_def_link(wma->psoc, self_mac_addr, vdev);
3194 
3195 	return QDF_STATUS_SUCCESS;
3196 }
3197 
3198 QDF_STATUS
cm_roam_pe_sync_callback(struct roam_offload_synch_ind * sync_ind,uint8_t vdev_id,uint16_t ie_len)3199 cm_roam_pe_sync_callback(struct roam_offload_synch_ind *sync_ind,
3200 			 uint8_t vdev_id, uint16_t ie_len)
3201 {
3202 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3203 	struct pe_session *pe_session;
3204 	bool new_link_session = false;
3205 	QDF_STATUS status;
3206 
3207 	if (!wma)
3208 		return QDF_STATUS_E_INVAL;
3209 
3210 	pe_session = pe_find_session_by_vdev_id(wma->mac_context, vdev_id);
3211 	if (!pe_session) {
3212 		new_link_session = true;
3213 		/* Legacy to MLO roaming: create new pe session */
3214 		status = lim_create_and_fill_link_session(wma->mac_context,
3215 							  vdev_id,
3216 							  sync_ind, ie_len);
3217 
3218 		if (QDF_IS_STATUS_ERROR(status)) {
3219 			wma_err("MLO ROAM: pe session creation failed vdev id %d",
3220 				vdev_id);
3221 			return status;
3222 		}
3223 	}
3224 	status = wma->pe_roam_synch_cb(wma->mac_context,
3225 				vdev_id, sync_ind, ie_len,
3226 				SIR_ROAM_SYNCH_PROPAGATION);
3227 
3228 	/* delete newly added pe session in case of failure */
3229 	if (new_link_session && QDF_IS_STATUS_ERROR(status)) {
3230 		pe_session = pe_find_session_by_vdev_id(wma->mac_context,
3231 							vdev_id);
3232 		if (pe_session)
3233 			pe_delete_session(wma->mac_context, pe_session);
3234 	}
3235 	return status;
3236 }
3237 
cm_update_phymode_on_roam(uint8_t vdev_id,struct roam_offload_synch_ind * sync_ind)3238 void cm_update_phymode_on_roam(uint8_t vdev_id,
3239 			       struct roam_offload_synch_ind *sync_ind)
3240 {
3241 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
3242 	struct qdf_mac_addr link_bssid;
3243 	wmi_channel link_chan;
3244 
3245 	if (!wma)
3246 		return;
3247 
3248 	if (is_multi_link_roam(sync_ind)) {
3249 		mlo_roam_get_bssid_chan_for_link(vdev_id, sync_ind,
3250 						 &link_bssid,
3251 						 &link_chan);
3252 		wma_update_phymode_on_roam(wma, &link_bssid,
3253 					   &link_chan,
3254 					   &wma->interfaces[vdev_id]);
3255 	} else {
3256 		wma_update_phymode_on_roam(wma, &sync_ind->bssid,
3257 					   &sync_ind->chan,
3258 					   &wma->interfaces[vdev_id]);
3259 	}
3260 }
3261 
3262 enum wlan_phymode
wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode)3263 wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode)
3264 {
3265 	return wma_fw_to_host_phymode(phymode);
3266 }
3267 #endif
3268 
3269 QDF_STATUS
wlan_update_peer_phy_mode(struct wlan_channel * des_chan,struct wlan_objmgr_vdev * vdev)3270 wlan_update_peer_phy_mode(struct wlan_channel *des_chan,
3271 			  struct wlan_objmgr_vdev *vdev)
3272 {
3273 	return wma_update_bss_peer_phy_mode(des_chan, vdev);
3274 }
3275