1 /*
2  * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <osdep.h>
21 #include "wmi.h"
22 #include "wmi_unified_priv.h"
23 
24 /**
25  * send_reset_passpoint_network_list_cmd_tlv() - reset passpoint network list
26  * @wmi_handle: wmi handle
27  * @req: passpoint network request structure
28  *
29  * This function sends down WMI command with network id set to wildcard id.
30  * firmware shall clear all the config entries
31  *
32  * Return: QDF_STATUS enumeration
33  */
send_reset_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle,struct wifi_passpoint_req_param * req)34 static QDF_STATUS send_reset_passpoint_network_list_cmd_tlv
35 					(wmi_unified_t wmi_handle,
36 					struct wifi_passpoint_req_param *req)
37 {
38 	wmi_passpoint_config_cmd_fixed_param *cmd;
39 	wmi_buf_t buf;
40 	uint32_t len;
41 	int ret;
42 
43 	len = sizeof(*cmd);
44 	buf = wmi_buf_alloc(wmi_handle, len);
45 	if (!buf) {
46 		wmi_err("Failed allocate wmi buffer");
47 		return QDF_STATUS_E_NOMEM;
48 	}
49 
50 	cmd = (wmi_passpoint_config_cmd_fixed_param *) wmi_buf_data(buf);
51 
52 	WMITLV_SET_HDR(&cmd->tlv_header,
53 			WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param,
54 			WMITLV_GET_STRUCT_TLVLEN(
55 			wmi_passpoint_config_cmd_fixed_param));
56 	cmd->id = WMI_PASSPOINT_NETWORK_ID_WILDCARD;
57 
58 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
59 				   WMI_PASSPOINT_LIST_CONFIG_CMDID);
60 	if (ret) {
61 		wmi_err("Failed to send reset passpoint network list wmi cmd");
62 		wmi_buf_free(buf);
63 		return QDF_STATUS_E_FAILURE;
64 	}
65 
66 	return QDF_STATUS_SUCCESS;
67 }
68 
69 /**
70  * send_set_passpoint_network_list_cmd_tlv() - set passpoint network list
71  * @wmi_handle: wmi handle
72  * @req: passpoint network request structure
73  *
74  * This function reads the incoming @req and fill in the destination
75  * WMI structure and send down the passpoint configs down to the firmware
76  *
77  * Return: QDF_STATUS enumeration
78  */
send_set_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle,struct wifi_passpoint_req_param * req)79 static QDF_STATUS send_set_passpoint_network_list_cmd_tlv
80 					(wmi_unified_t wmi_handle,
81 					struct wifi_passpoint_req_param *req)
82 {
83 	wmi_passpoint_config_cmd_fixed_param *cmd;
84 	u_int8_t i, j, *bytes;
85 	wmi_buf_t buf;
86 	uint32_t len;
87 	int ret;
88 
89 	len = sizeof(*cmd);
90 	for (i = 0; i < req->num_networks; i++) {
91 		buf = wmi_buf_alloc(wmi_handle, len);
92 		if (!buf) {
93 			wmi_err("Failed allocate wmi buffer");
94 			return QDF_STATUS_E_NOMEM;
95 		}
96 
97 		cmd = (wmi_passpoint_config_cmd_fixed_param *)
98 				wmi_buf_data(buf);
99 
100 		WMITLV_SET_HDR(&cmd->tlv_header,
101 			WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param,
102 			WMITLV_GET_STRUCT_TLVLEN(
103 			wmi_passpoint_config_cmd_fixed_param));
104 		cmd->id = req->networks[i].id;
105 		wmi_debug("network id: %u", cmd->id);
106 		qdf_mem_copy(cmd->realm, req->networks[i].realm,
107 			strlen(req->networks[i].realm) + 1);
108 		wmi_debug("realm: %s", cmd->realm);
109 		for (j = 0; j < PASSPOINT_ROAMING_CONSORTIUM_ID_NUM; j++) {
110 			bytes = (uint8_t *) &req->networks[i].roaming_consortium_ids[j];
111 			wmi_debug("index: %d rcids: %02x %02x %02x %02x %02x %02x %02x %02x",
112 				j, bytes[0], bytes[1], bytes[2], bytes[3],
113 				bytes[4], bytes[5], bytes[6], bytes[7]);
114 
115 			qdf_mem_copy(&cmd->roaming_consortium_ids[j],
116 				&req->networks[i].roaming_consortium_ids[j],
117 				PASSPOINT_ROAMING_CONSORTIUM_ID_LEN);
118 		}
119 		qdf_mem_copy(cmd->plmn, req->networks[i].plmn,
120 				PASSPOINT_PLMN_ID_LEN);
121 		wmi_debug("plmn: %02x:%02x:%02x",
122 			 cmd->plmn[0], cmd->plmn[1], cmd->plmn[2]);
123 
124 		ret = wmi_unified_cmd_send(wmi_handle, buf, len,
125 					   WMI_PASSPOINT_LIST_CONFIG_CMDID);
126 		if (ret) {
127 			wmi_err("Failed to send set passpoint network list wmi cmd");
128 			wmi_buf_free(buf);
129 			return QDF_STATUS_E_FAILURE;
130 		}
131 	}
132 
133 	return QDF_STATUS_SUCCESS;
134 }
135 
136 /** send_set_epno_network_list_cmd_tlv() - set epno network list
137  * @wmi_handle: wmi handle
138  * @req: epno config params request structure
139  *
140  * This function reads the incoming epno config request structure
141  * and constructs the WMI message to the firmware.
142  *
143  * Returns: 0 on success, error number otherwise
144  */
send_set_epno_network_list_cmd_tlv(wmi_unified_t wmi_handle,struct wifi_enhanced_pno_params * req)145 static QDF_STATUS send_set_epno_network_list_cmd_tlv(wmi_unified_t wmi_handle,
146 		struct wifi_enhanced_pno_params *req)
147 {
148 	wmi_nlo_config_cmd_fixed_param *cmd;
149 	nlo_configured_parameters *nlo_list;
150 	enlo_candidate_score_params *cand_score_params;
151 	u_int8_t i, *buf_ptr;
152 	wmi_buf_t buf;
153 	uint32_t len;
154 	QDF_STATUS ret;
155 
156 	/* Fixed Params */
157 	len = sizeof(*cmd);
158 	if (req->num_networks) {
159 		/* TLV place holder for array of structures
160 		 * then each nlo_configured_parameters(nlo_list) TLV.
161 		 */
162 		len += WMI_TLV_HDR_SIZE;
163 		len += (sizeof(nlo_configured_parameters)
164 			    * QDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS));
165 		/* TLV for array of uint32 channel_list */
166 		len += WMI_TLV_HDR_SIZE;
167 		/* TLV for nlo_channel_prediction_cfg */
168 		len += WMI_TLV_HDR_SIZE;
169 		/* TLV for candidate score params */
170 		len += sizeof(enlo_candidate_score_params);
171 	}
172 
173 	buf = wmi_buf_alloc(wmi_handle, len);
174 	if (!buf) {
175 		wmi_err("Failed allocate wmi buffer");
176 		return QDF_STATUS_E_NOMEM;
177 	}
178 
179 	cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf);
180 
181 	buf_ptr = (u_int8_t *) cmd;
182 	WMITLV_SET_HDR(&cmd->tlv_header,
183 		       WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param,
184 		       WMITLV_GET_STRUCT_TLVLEN(
185 			       wmi_nlo_config_cmd_fixed_param));
186 	cmd->vdev_id = req->vdev_id;
187 
188 	/* set flag to reset if num of networks are 0 */
189 	cmd->flags = (req->num_networks == 0 ?
190 		WMI_NLO_CONFIG_ENLO_RESET : WMI_NLO_CONFIG_ENLO);
191 
192 	buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param);
193 
194 	cmd->no_of_ssids = QDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS);
195 	wmi_debug("SSID count: %d flags: %d",
196 		 cmd->no_of_ssids, cmd->flags);
197 
198 	/* Fill nlo_config only when num_networks are non zero */
199 	if (cmd->no_of_ssids) {
200 		/* Fill networks */
201 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
202 			cmd->no_of_ssids * sizeof(nlo_configured_parameters));
203 		buf_ptr += WMI_TLV_HDR_SIZE;
204 
205 		nlo_list = (nlo_configured_parameters *) buf_ptr;
206 		for (i = 0; i < cmd->no_of_ssids; i++) {
207 			WMITLV_SET_HDR(&nlo_list[i].tlv_header,
208 				WMITLV_TAG_ARRAY_BYTE,
209 				WMITLV_GET_STRUCT_TLVLEN(
210 				nlo_configured_parameters));
211 			/* Copy ssid and it's length */
212 			nlo_list[i].ssid.valid = true;
213 			nlo_list[i].ssid.ssid.ssid_len =
214 				req->networks[i].ssid.length;
215 			qdf_mem_copy(nlo_list[i].ssid.ssid.ssid,
216 				     req->networks[i].ssid.ssid,
217 				     nlo_list[i].ssid.ssid.ssid_len);
218 			wmi_debug("index: %d ssid: " QDF_SSID_FMT " len: %d", i,
219 				  QDF_SSID_REF(nlo_list[i].ssid.ssid.ssid_len,
220 					       nlo_list[i].ssid.ssid.ssid),
221 				  nlo_list[i].ssid.ssid.ssid_len);
222 
223 			/* Copy pno flags */
224 			nlo_list[i].bcast_nw_type.valid = true;
225 			nlo_list[i].bcast_nw_type.bcast_nw_type =
226 					req->networks[i].flags;
227 			wmi_debug("PNO flags: %u",
228 				 nlo_list[i].bcast_nw_type.bcast_nw_type);
229 
230 			/* Copy auth bit field */
231 			nlo_list[i].auth_type.valid = true;
232 			nlo_list[i].auth_type.auth_type =
233 					req->networks[i].auth_bit_field;
234 			wmi_debug("Auth bit field: %u",
235 				 nlo_list[i].auth_type.auth_type);
236 		}
237 
238 		buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters);
239 		/* Fill the channel list */
240 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
241 		buf_ptr += WMI_TLV_HDR_SIZE;
242 
243 		/* Fill prediction_param */
244 		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
245 		buf_ptr += WMI_TLV_HDR_SIZE;
246 
247 		/* Fill epno candidate score params */
248 		cand_score_params = (enlo_candidate_score_params *) buf_ptr;
249 		WMITLV_SET_HDR(buf_ptr,
250 			WMITLV_TAG_STRUC_enlo_candidate_score_param,
251 			WMITLV_GET_STRUCT_TLVLEN(enlo_candidate_score_params));
252 		cand_score_params->min5GHz_rssi =
253 			req->min_5ghz_rssi;
254 		cand_score_params->min24GHz_rssi =
255 			req->min_24ghz_rssi;
256 		cand_score_params->initial_score_max =
257 			req->initial_score_max;
258 		cand_score_params->current_connection_bonus =
259 			req->current_connection_bonus;
260 		cand_score_params->same_network_bonus =
261 			req->same_network_bonus;
262 		cand_score_params->secure_bonus =
263 			req->secure_bonus;
264 		cand_score_params->band5GHz_bonus =
265 			req->band_5ghz_bonus;
266 		buf_ptr += sizeof(enlo_candidate_score_params);
267 	}
268 
269 	ret = wmi_unified_cmd_send(wmi_handle, buf, len,
270 			WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
271 	if (QDF_IS_STATUS_ERROR(ret)) {
272 		wmi_err("Failed to send nlo wmi cmd");
273 		wmi_buf_free(buf);
274 		return QDF_STATUS_E_INVAL;
275 	}
276 
277 	wmi_debug("set ePNO list request sent successfully for vdev %d",
278 		 req->vdev_id);
279 
280 	return ret;
281 }
282 
283 /**
284  * send_extscan_get_capabilities_cmd_tlv() - extscan get capabilities
285  * @wmi_handle: wmi handle
286  * @pgetcapab: get capabilities params
287  *
288  * This function send request to fw to get extscan capabilities.
289  *
290  * Return: QDF status
291  */
send_extscan_get_capabilities_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_capabilities_params * pgetcapab)292 static QDF_STATUS send_extscan_get_capabilities_cmd_tlv(wmi_unified_t wmi_handle,
293 		    struct extscan_capabilities_params *pgetcapab)
294 {
295 	wmi_extscan_get_capabilities_cmd_fixed_param *cmd;
296 	wmi_buf_t wmi_buf;
297 	uint32_t len;
298 	uint8_t *buf_ptr;
299 
300 	len = sizeof(*cmd);
301 	wmi_buf = wmi_buf_alloc(wmi_handle, len);
302 	if (!wmi_buf) {
303 		wmi_err("wmi_buf_alloc failed");
304 		return QDF_STATUS_E_NOMEM;
305 	}
306 	buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
307 
308 	cmd = (wmi_extscan_get_capabilities_cmd_fixed_param *) buf_ptr;
309 	WMITLV_SET_HDR(&cmd->tlv_header,
310 	       WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param,
311 	       WMITLV_GET_STRUCT_TLVLEN
312 	       (wmi_extscan_get_capabilities_cmd_fixed_param));
313 
314 	cmd->request_id = pgetcapab->request_id;
315 
316 	if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len,
317 				 WMI_EXTSCAN_GET_CAPABILITIES_CMDID)) {
318 		wmi_err("Failed to send extscan get capabilities cmd");
319 		wmi_buf_free(wmi_buf);
320 		return QDF_STATUS_E_FAILURE;
321 	}
322 	return QDF_STATUS_SUCCESS;
323 }
324 
325 /**
326  * send_extscan_get_cached_results_cmd_tlv() - extscan get cached results
327  * @wmi_handle: wmi handle
328  * @pcached_results: cached results parameters
329  *
330  * This function send request to fw to get cached results.
331  *
332  * Return: QDF status
333  */
send_extscan_get_cached_results_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_cached_result_params * pcached_results)334 static QDF_STATUS send_extscan_get_cached_results_cmd_tlv(wmi_unified_t wmi_handle,
335 		  struct extscan_cached_result_params *pcached_results)
336 {
337 	wmi_extscan_get_cached_results_cmd_fixed_param *cmd;
338 	wmi_buf_t wmi_buf;
339 	uint32_t len;
340 	uint8_t *buf_ptr;
341 
342 	len = sizeof(*cmd);
343 	wmi_buf = wmi_buf_alloc(wmi_handle, len);
344 	if (!wmi_buf) {
345 		wmi_err("wmi_buf_alloc failed");
346 		return QDF_STATUS_E_NOMEM;
347 	}
348 	buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
349 
350 	cmd = (wmi_extscan_get_cached_results_cmd_fixed_param *) buf_ptr;
351 	WMITLV_SET_HDR(&cmd->tlv_header,
352 		WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param,
353 		WMITLV_GET_STRUCT_TLVLEN
354 		(wmi_extscan_get_cached_results_cmd_fixed_param));
355 
356 	cmd->request_id = pcached_results->request_id;
357 	cmd->vdev_id = pcached_results->vdev_id;
358 	cmd->control_flags = pcached_results->flush;
359 
360 	if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len,
361 				 WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID)) {
362 		wmi_err("failed to  command", __func__);
363 		wmi_buf_free(wmi_buf);
364 		return QDF_STATUS_E_FAILURE;
365 	}
366 	return QDF_STATUS_SUCCESS;
367 }
368 
369 /**
370  * send_extscan_stop_change_monitor_cmd_tlv() - send stop change monitor cmd
371  * @wmi_handle: wmi handle
372  * @reset_req: Reset change request params
373  *
374  * This function sends stop change monitor request to fw.
375  *
376  * Return: QDF status
377  */
send_extscan_stop_change_monitor_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_capabilities_reset_params * reset_req)378 static QDF_STATUS send_extscan_stop_change_monitor_cmd_tlv
379 			(wmi_unified_t wmi_handle,
380 			struct extscan_capabilities_reset_params *reset_req)
381 {
382 	wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd;
383 	wmi_buf_t wmi_buf;
384 	uint32_t len;
385 	uint8_t *buf_ptr;
386 	int change_list = 0;
387 
388 	len = sizeof(*cmd);
389 
390 	/* reset significant change tlv is set to 0 */
391 	len += WMI_TLV_HDR_SIZE;
392 	len += change_list * sizeof(wmi_extscan_wlan_change_bssid_param);
393 	wmi_buf = wmi_buf_alloc(wmi_handle, len);
394 	if (!wmi_buf) {
395 		wmi_err("wmi_buf_alloc failed");
396 		return QDF_STATUS_E_NOMEM;
397 	}
398 	buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
399 
400 	cmd = (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *)
401 		buf_ptr;
402 	WMITLV_SET_HDR(&cmd->tlv_header,
403 	WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param,
404 		WMITLV_GET_STRUCT_TLVLEN
405 		(wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param));
406 
407 	cmd->request_id = reset_req->request_id;
408 	cmd->vdev_id = reset_req->vdev_id;
409 	cmd->mode = 0;
410 
411 	buf_ptr += sizeof(*cmd);
412 	WMITLV_SET_HDR(buf_ptr,
413 		       WMITLV_TAG_ARRAY_STRUC,
414 		       change_list *
415 		       sizeof(wmi_extscan_wlan_change_bssid_param));
416 	buf_ptr += WMI_TLV_HDR_SIZE + (change_list *
417 				       sizeof
418 				       (wmi_extscan_wlan_change_bssid_param));
419 
420 	if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len,
421 			 WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) {
422 		wmi_err("Failed to send extscan change monitor cmd");
423 		wmi_buf_free(wmi_buf);
424 		return QDF_STATUS_E_FAILURE;
425 	}
426 	return QDF_STATUS_SUCCESS;
427 }
428 
429 /**
430  * wmi_get_buf_extscan_change_monitor_cmd() - fill change monitor request
431  * @wmi_handle: wmi handle
432  * @psigchange: change monitor request params
433  * @buf: wmi buffer
434  * @buf_len: buffer length
435  *
436  * This function fills elements of change monitor request buffer.
437  *
438  * Return: QDF status
439  */
wmi_get_buf_extscan_change_monitor_cmd(wmi_unified_t wmi_handle,struct extscan_set_sig_changereq_params * psigchange,wmi_buf_t * buf,int * buf_len)440 static QDF_STATUS wmi_get_buf_extscan_change_monitor_cmd
441 			(wmi_unified_t wmi_handle,
442 			struct extscan_set_sig_changereq_params
443 			*psigchange, wmi_buf_t *buf, int *buf_len)
444 {
445 	wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd;
446 	wmi_extscan_wlan_change_bssid_param *dest_chglist;
447 	uint8_t *buf_ptr;
448 	int j;
449 	int len = sizeof(*cmd);
450 	uint32_t numap = psigchange->num_ap;
451 	struct ap_threshold_params *src_ap = psigchange->ap;
452 
453 	if (!numap || (numap > WMI_WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS)) {
454 		wmi_err("Invalid number of bssid's");
455 		return QDF_STATUS_E_INVAL;
456 	}
457 	len += WMI_TLV_HDR_SIZE;
458 	len += numap * sizeof(wmi_extscan_wlan_change_bssid_param);
459 
460 	*buf = wmi_buf_alloc(wmi_handle, len);
461 	if (!*buf) {
462 		wmi_err("Failed to allocate memory for change monitor cmd");
463 		return QDF_STATUS_E_FAILURE;
464 	}
465 	buf_ptr = (uint8_t *) wmi_buf_data(*buf);
466 	cmd =
467 		(wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *)
468 		buf_ptr;
469 	WMITLV_SET_HDR(&cmd->tlv_header,
470 	WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param,
471 	       WMITLV_GET_STRUCT_TLVLEN
472 	       (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param));
473 
474 	cmd->request_id = psigchange->request_id;
475 	cmd->vdev_id = psigchange->vdev_id;
476 	cmd->total_entries = numap;
477 	cmd->mode = 1;
478 	cmd->num_entries_in_page = numap;
479 	cmd->lost_ap_scan_count = psigchange->lostap_sample_size;
480 	cmd->max_rssi_samples = psigchange->rssi_sample_size;
481 	cmd->rssi_averaging_samples = psigchange->rssi_sample_size;
482 	cmd->max_out_of_range_count = psigchange->min_breaching;
483 
484 	buf_ptr += sizeof(*cmd);
485 	WMITLV_SET_HDR(buf_ptr,
486 		       WMITLV_TAG_ARRAY_STRUC,
487 		       numap * sizeof(wmi_extscan_wlan_change_bssid_param));
488 	dest_chglist = (wmi_extscan_wlan_change_bssid_param *)
489 		       (buf_ptr + WMI_TLV_HDR_SIZE);
490 
491 	for (j = 0; j < numap; j++) {
492 		WMITLV_SET_HDR(dest_chglist,
493 		       WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
494 		       WMITLV_GET_STRUCT_TLVLEN
495 		       (wmi_extscan_wlan_change_bssid_param));
496 
497 		dest_chglist->lower_rssi_limit = src_ap->low;
498 		dest_chglist->upper_rssi_limit = src_ap->high;
499 		WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes,
500 					   &dest_chglist->bssid);
501 
502 		wmi_debug("min_rssi: %d", dest_chglist->lower_rssi_limit);
503 		dest_chglist++;
504 		src_ap++;
505 	}
506 	buf_ptr += WMI_TLV_HDR_SIZE +
507 		   (numap * sizeof(wmi_extscan_wlan_change_bssid_param));
508 	*buf_len = len;
509 	return QDF_STATUS_SUCCESS;
510 }
511 
512 /**
513  * send_extscan_start_change_monitor_cmd_tlv() - send start change monitor cmd
514  * @wmi_handle: wmi handle
515  * @psigchange: change monitor request params
516  *
517  * This function sends start change monitor request to fw.
518  *
519  * Return: QDF status
520  */
send_extscan_start_change_monitor_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_set_sig_changereq_params * psigchange)521 static QDF_STATUS send_extscan_start_change_monitor_cmd_tlv
522 			(wmi_unified_t wmi_handle,
523 			struct extscan_set_sig_changereq_params *
524 			psigchange)
525 {
526 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
527 	wmi_buf_t buf;
528 	int len;
529 
530 
531 	qdf_status = wmi_get_buf_extscan_change_monitor_cmd(wmi_handle,
532 			     psigchange, &buf,
533 			     &len);
534 	if (qdf_status != QDF_STATUS_SUCCESS) {
535 		wmi_err("Failed to get buffer for change monitor cmd");
536 		return QDF_STATUS_E_FAILURE;
537 	}
538 	if (!buf) {
539 		wmi_err("Failed to get buffer");
540 		return QDF_STATUS_E_FAILURE;
541 	}
542 	if (wmi_unified_cmd_send(wmi_handle, buf, len,
543 		 WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) {
544 		wmi_err("Failed to send command");
545 		wmi_buf_free(buf);
546 		return QDF_STATUS_E_FAILURE;
547 	}
548 	return QDF_STATUS_SUCCESS;
549 }
550 
551 /**
552  * send_extscan_stop_hotlist_monitor_cmd_tlv() - stop hotlist monitor
553  * @wmi_handle: wmi handle
554  * @photlist_reset: hotlist reset params
555  *
556  * This function configures hotlist monitor to stop in fw.
557  *
558  * Return: QDF status
559  */
send_extscan_stop_hotlist_monitor_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_bssid_hotlist_reset_params * photlist_reset)560 static QDF_STATUS send_extscan_stop_hotlist_monitor_cmd_tlv
561 		(wmi_unified_t wmi_handle,
562 		struct extscan_bssid_hotlist_reset_params *photlist_reset)
563 {
564 	wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd;
565 	wmi_buf_t wmi_buf;
566 	uint32_t len;
567 	uint8_t *buf_ptr;
568 	int hotlist_entries = 0;
569 
570 	len = sizeof(*cmd);
571 
572 	/* reset bssid hotlist with tlv set to 0 */
573 	len += WMI_TLV_HDR_SIZE;
574 	len += hotlist_entries * sizeof(wmi_extscan_hotlist_entry);
575 
576 	wmi_buf = wmi_buf_alloc(wmi_handle, len);
577 	if (!wmi_buf) {
578 		wmi_err("wmi_buf_alloc failed");
579 		return QDF_STATUS_E_NOMEM;
580 	}
581 
582 	buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
583 	cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *)
584 	      buf_ptr;
585 	WMITLV_SET_HDR(&cmd->tlv_header,
586 	WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param,
587 	WMITLV_GET_STRUCT_TLVLEN
588 	(wmi_extscan_configure_hotlist_monitor_cmd_fixed_param));
589 
590 	cmd->request_id = photlist_reset->request_id;
591 	cmd->vdev_id = photlist_reset->vdev_id;
592 	cmd->mode = 0;
593 
594 	buf_ptr += sizeof(*cmd);
595 	WMITLV_SET_HDR(buf_ptr,
596 		       WMITLV_TAG_ARRAY_STRUC,
597 		       hotlist_entries * sizeof(wmi_extscan_hotlist_entry));
598 	buf_ptr += WMI_TLV_HDR_SIZE +
599 		   (hotlist_entries * sizeof(wmi_extscan_hotlist_entry));
600 
601 	if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len,
602 				WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) {
603 		wmi_err("Failed to send extscan cfg hotlist cmd");
604 		wmi_buf_free(wmi_buf);
605 		return QDF_STATUS_E_FAILURE;
606 	}
607 	return QDF_STATUS_SUCCESS;
608 }
609 
610 /**
611  * send_stop_extscan_cmd_tlv() - stop extscan command to fw.
612  * @wmi_handle: wmi handle
613  * @pstopcmd: stop scan command request params
614  *
615  * This function sends stop extscan request to fw.
616  *
617  * Return: CDF Status.
618  */
send_stop_extscan_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_stop_req_params * pstopcmd)619 static QDF_STATUS send_stop_extscan_cmd_tlv(wmi_unified_t wmi_handle,
620 			  struct extscan_stop_req_params *pstopcmd)
621 {
622 	wmi_extscan_stop_cmd_fixed_param *cmd;
623 	wmi_buf_t wmi_buf;
624 	uint32_t len;
625 	uint8_t *buf_ptr;
626 
627 	len = sizeof(*cmd);
628 	wmi_buf = wmi_buf_alloc(wmi_handle, len);
629 	if (!wmi_buf) {
630 		wmi_err("wmi_buf_alloc failed");
631 		return QDF_STATUS_E_NOMEM;
632 	}
633 	buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
634 	cmd = (wmi_extscan_stop_cmd_fixed_param *) buf_ptr;
635 	WMITLV_SET_HDR(&cmd->tlv_header,
636 		       WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param,
637 		       WMITLV_GET_STRUCT_TLVLEN
638 			       (wmi_extscan_stop_cmd_fixed_param));
639 
640 	cmd->request_id = pstopcmd->request_id;
641 	cmd->vdev_id = pstopcmd->vdev_id;
642 
643 	if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len,
644 				 WMI_EXTSCAN_STOP_CMDID)) {
645 		wmi_err("Failed to send extscan stop cmd");
646 		wmi_buf_free(wmi_buf);
647 		return QDF_STATUS_E_FAILURE;
648 	}
649 
650 	return QDF_STATUS_SUCCESS;
651 }
652 
653 /**
654  * wmi_get_buf_extscan_start_cmd() - Fill extscan start request
655  * @wmi_handle: wmi handle
656  * @pstart: scan command request params
657  * @buf: event buffer
658  * @buf_len: length of buffer
659  *
660  * This function fills individual elements of extscan request and
661  * TLV for buckets, channel list.
662  *
663  * Return: CDF Status.
664  */
665 static
wmi_get_buf_extscan_start_cmd(wmi_unified_t wmi_handle,struct wifi_scan_cmd_req_params * pstart,wmi_buf_t * buf,int * buf_len)666 QDF_STATUS wmi_get_buf_extscan_start_cmd(wmi_unified_t wmi_handle,
667 			 struct wifi_scan_cmd_req_params *pstart,
668 			 wmi_buf_t *buf, int *buf_len)
669 {
670 	wmi_extscan_start_cmd_fixed_param *cmd;
671 	wmi_extscan_bucket *dest_blist;
672 	wmi_extscan_bucket_channel *dest_clist;
673 	struct wifi_scan_bucket_params *src_bucket = pstart->buckets;
674 	struct wifi_scan_channelspec_params *src_channel = src_bucket->channels;
675 	struct wifi_scan_channelspec_params save_channel[WMI_WLAN_EXTSCAN_MAX_CHANNELS];
676 
677 	uint8_t *buf_ptr;
678 	int i, k, count = 0;
679 	int len = sizeof(*cmd);
680 	int nbuckets = pstart->num_buckets;
681 	int nchannels = 0;
682 
683 	/* These TLV's are are NULL by default */
684 	uint32_t ie_len_with_pad = 0;
685 	int num_ssid = 0;
686 	int num_bssid = 0;
687 	int ie_len = 0;
688 
689 	uint32_t base_period = pstart->base_period;
690 
691 	/* TLV placeholder for ssid_list (NULL) */
692 	len += WMI_TLV_HDR_SIZE;
693 	len += num_ssid * sizeof(wmi_ssid);
694 
695 	/* TLV placeholder for bssid_list (NULL) */
696 	len += WMI_TLV_HDR_SIZE;
697 	len += num_bssid * sizeof(wmi_mac_addr);
698 
699 	/* TLV placeholder for ie_data (NULL) */
700 	len += WMI_TLV_HDR_SIZE;
701 	len += ie_len * sizeof(uint32_t);
702 
703 	/* TLV placeholder for bucket */
704 	len += WMI_TLV_HDR_SIZE;
705 	len += nbuckets * sizeof(wmi_extscan_bucket);
706 
707 	/* TLV channel placeholder */
708 	len += WMI_TLV_HDR_SIZE;
709 	for (i = 0; i < nbuckets; i++) {
710 		nchannels += src_bucket->num_channels;
711 		src_bucket++;
712 	}
713 
714 	wmi_debug("Total buckets: %d total #of channels is %d",
715 		 nbuckets, nchannels);
716 	len += nchannels * sizeof(wmi_extscan_bucket_channel);
717 	/* Allocate the memory */
718 	*buf = wmi_buf_alloc(wmi_handle, len);
719 	if (!*buf) {
720 		wmi_err("Failed to allocate memory for start extscan cmd");
721 		return QDF_STATUS_E_NOMEM;
722 	}
723 	buf_ptr = (uint8_t *) wmi_buf_data(*buf);
724 	cmd = (wmi_extscan_start_cmd_fixed_param *) buf_ptr;
725 	WMITLV_SET_HDR(&cmd->tlv_header,
726 		       WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param,
727 		       WMITLV_GET_STRUCT_TLVLEN
728 			       (wmi_extscan_start_cmd_fixed_param));
729 
730 	cmd->request_id = pstart->request_id;
731 	cmd->vdev_id = pstart->vdev_id;
732 	cmd->base_period = pstart->base_period;
733 	cmd->num_buckets = nbuckets;
734 	cmd->configuration_flags = 0;
735 	if (pstart->configuration_flags & WMI_EXTSCAN_LP_EXTENDED_BATCHING)
736 		cmd->configuration_flags |= WMI_EXTSCAN_EXTENDED_BATCHING_EN;
737 	wmi_debug("configuration_flags: 0x%x", cmd->configuration_flags);
738 #ifdef FEATURE_WLAN_EXTSCAN
739 	cmd->min_rest_time = WMI_EXTSCAN_REST_TIME;
740 	cmd->max_rest_time = WMI_EXTSCAN_REST_TIME;
741 	cmd->max_scan_time = WMI_EXTSCAN_MAX_SCAN_TIME;
742 	cmd->burst_duration = WMI_EXTSCAN_BURST_DURATION;
743 #endif
744 
745 	/* The max dwell time is retrieved from the first channel
746 	 * of the first bucket and kept common for all channels.
747 	 */
748 	cmd->min_dwell_time_active = pstart->min_dwell_time_active;
749 	cmd->max_dwell_time_active = pstart->max_dwell_time_active;
750 	cmd->min_dwell_time_passive = pstart->min_dwell_time_passive;
751 	cmd->max_dwell_time_passive = pstart->max_dwell_time_passive;
752 	cmd->max_bssids_per_scan_cycle = pstart->max_ap_per_scan;
753 	cmd->max_table_usage = pstart->report_threshold_percent;
754 	cmd->report_threshold_num_scans = pstart->report_threshold_num_scans;
755 
756 	cmd->repeat_probe_time = cmd->max_dwell_time_active /
757 					WMI_SCAN_NPROBES_DEFAULT;
758 	cmd->probe_delay = 0;
759 	cmd->probe_spacing_time = 0;
760 	cmd->idle_time = 0;
761 	cmd->scan_ctrl_flags = WMI_SCAN_ADD_BCAST_PROBE_REQ |
762 			       WMI_SCAN_ADD_CCK_RATES |
763 			       WMI_SCAN_ADD_OFDM_RATES |
764 			       WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ |
765 			       WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
766 	WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags,
767 			pstart->extscan_adaptive_dwell_mode);
768 	cmd->scan_priority = WMI_SCAN_PRIORITY_VERY_LOW;
769 	cmd->num_ssids = 0;
770 	cmd->num_bssid = 0;
771 	cmd->ie_len = 0;
772 	cmd->n_probes = (cmd->repeat_probe_time > 0) ?
773 			cmd->max_dwell_time_active / cmd->repeat_probe_time : 0;
774 
775 	buf_ptr += sizeof(*cmd);
776 	WMITLV_SET_HDR(buf_ptr,
777 		       WMITLV_TAG_ARRAY_FIXED_STRUC,
778 		       num_ssid * sizeof(wmi_ssid));
779 	buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid * sizeof(wmi_ssid));
780 
781 	WMITLV_SET_HDR(buf_ptr,
782 		       WMITLV_TAG_ARRAY_FIXED_STRUC,
783 		       num_bssid * sizeof(wmi_mac_addr));
784 	buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid * sizeof(wmi_mac_addr));
785 
786 	ie_len_with_pad = 0;
787 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
788 			  ie_len_with_pad);
789 	buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad;
790 
791 	WMITLV_SET_HDR(buf_ptr,
792 		       WMITLV_TAG_ARRAY_STRUC,
793 		       nbuckets * sizeof(wmi_extscan_bucket));
794 	dest_blist = (wmi_extscan_bucket *)
795 		     (buf_ptr + WMI_TLV_HDR_SIZE);
796 	src_bucket = pstart->buckets;
797 
798 	/* Retrieve scanning information from each bucket and
799 	 * channels and send it to the target
800 	 */
801 	for (i = 0; i < nbuckets; i++) {
802 		WMITLV_SET_HDR(dest_blist,
803 		      WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
804 		      WMITLV_GET_STRUCT_TLVLEN(wmi_extscan_bucket));
805 
806 		dest_blist->bucket_id = src_bucket->bucket;
807 		dest_blist->base_period_multiplier =
808 			src_bucket->period / base_period;
809 		dest_blist->min_period = src_bucket->period;
810 		dest_blist->max_period = src_bucket->max_period;
811 		dest_blist->exp_backoff = src_bucket->exponent;
812 		dest_blist->exp_max_step_count = src_bucket->step_count;
813 		dest_blist->channel_band = src_bucket->band;
814 		dest_blist->num_channels = src_bucket->num_channels;
815 		dest_blist->notify_extscan_events = 0;
816 
817 		if (src_bucket->report_events &
818 					WMI_EXTSCAN_REPORT_EVENTS_EACH_SCAN)
819 			dest_blist->notify_extscan_events =
820 					WMI_EXTSCAN_CYCLE_COMPLETED_EVENT |
821 					WMI_EXTSCAN_CYCLE_STARTED_EVENT;
822 
823 		if (src_bucket->report_events &
824 				WMI_EXTSCAN_REPORT_EVENTS_FULL_RESULTS) {
825 			dest_blist->forwarding_flags =
826 				WMI_EXTSCAN_FORWARD_FRAME_TO_HOST;
827 			dest_blist->notify_extscan_events |=
828 				WMI_EXTSCAN_BUCKET_COMPLETED_EVENT |
829 				WMI_EXTSCAN_CYCLE_STARTED_EVENT |
830 				WMI_EXTSCAN_CYCLE_COMPLETED_EVENT;
831 		} else {
832 			dest_blist->forwarding_flags =
833 				WMI_EXTSCAN_NO_FORWARDING;
834 		}
835 
836 		if (src_bucket->report_events &
837 					WMI_EXTSCAN_REPORT_EVENTS_NO_BATCH)
838 			dest_blist->configuration_flags = 0;
839 		else
840 			dest_blist->configuration_flags =
841 				WMI_EXTSCAN_BUCKET_CACHE_RESULTS;
842 
843 		wmi_debug("ntfy_extscan_events:%u cfg_flags:%u fwd_flags:%u",
844 			  dest_blist->notify_extscan_events,
845 			  dest_blist->configuration_flags,
846 			  dest_blist->forwarding_flags);
847 
848 		dest_blist->min_dwell_time_active =
849 				   src_bucket->min_dwell_time_active;
850 		dest_blist->max_dwell_time_active =
851 				   src_bucket->max_dwell_time_active;
852 		dest_blist->min_dwell_time_passive =
853 				   src_bucket->min_dwell_time_passive;
854 		dest_blist->max_dwell_time_passive =
855 				   src_bucket->max_dwell_time_passive;
856 		src_channel = src_bucket->channels;
857 
858 		/* save the channel info to later populate
859 		 * the  channel TLV
860 		 */
861 		for (k = 0; k < src_bucket->num_channels; k++) {
862 			save_channel[count++].channel = src_channel->channel;
863 			src_channel++;
864 		}
865 		dest_blist++;
866 		src_bucket++;
867 	}
868 	buf_ptr += WMI_TLV_HDR_SIZE + (nbuckets * sizeof(wmi_extscan_bucket));
869 	WMITLV_SET_HDR(buf_ptr,
870 		       WMITLV_TAG_ARRAY_STRUC,
871 		       nchannels * sizeof(wmi_extscan_bucket_channel));
872 	dest_clist = (wmi_extscan_bucket_channel *)
873 		     (buf_ptr + WMI_TLV_HDR_SIZE);
874 
875 	/* Active or passive scan is based on the bucket dwell time
876 	 * and channel specific active,passive scans are not
877 	 * supported yet
878 	 */
879 	for (i = 0; i < nchannels; i++) {
880 		WMITLV_SET_HDR(dest_clist,
881 		WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param,
882 			   WMITLV_GET_STRUCT_TLVLEN
883 			   (wmi_extscan_bucket_channel));
884 		dest_clist->channel = save_channel[i].channel;
885 		dest_clist++;
886 	}
887 	buf_ptr += WMI_TLV_HDR_SIZE +
888 		   (nchannels * sizeof(wmi_extscan_bucket_channel));
889 	*buf_len = len;
890 	return QDF_STATUS_SUCCESS;
891 }
892 
893 /**
894  * send_start_extscan_cmd_tlv() - start extscan command to fw.
895  * @wmi_handle: wmi handle
896  * @pstart: scan command request params
897  *
898  * This function sends start extscan request to fw.
899  *
900  * Return: CDF Status.
901  */
send_start_extscan_cmd_tlv(wmi_unified_t wmi_handle,struct wifi_scan_cmd_req_params * pstart)902 static QDF_STATUS send_start_extscan_cmd_tlv(wmi_unified_t wmi_handle,
903 			  struct wifi_scan_cmd_req_params *pstart)
904 {
905 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
906 	wmi_buf_t buf;
907 	int len;
908 
909 	/* Fill individual elements of extscan request and
910 	 * TLV for buckets, channel list.
911 	 */
912 	qdf_status = wmi_get_buf_extscan_start_cmd(wmi_handle,
913 			     pstart, &buf, &len);
914 	if (qdf_status != QDF_STATUS_SUCCESS) {
915 		wmi_err("Failed to get buffer for ext scan cmd");
916 		return QDF_STATUS_E_FAILURE;
917 	}
918 	if (!buf) {
919 		wmi_err("Failed to get buffer for current extscan info");
920 		return QDF_STATUS_E_FAILURE;
921 	}
922 	if (wmi_unified_cmd_send(wmi_handle, buf,
923 				 len, WMI_EXTSCAN_START_CMDID)) {
924 		wmi_err("Failed to send extscan start cmd");
925 		wmi_buf_free(buf);
926 		return QDF_STATUS_E_FAILURE;
927 	}
928 
929 	return QDF_STATUS_SUCCESS;
930 }
931 
932 /** wmi_get_hotlist_entries_per_page() - hotlist entries per page
933  * @wmi_handle: wmi handle.
934  * @cmd: size of command structure.
935  * @per_entry_size: per entry size.
936  *
937  * This utility function calculates how many hotlist entries can
938  * fit in one page.
939  *
940  * Return: number of entries
941  */
wmi_get_hotlist_entries_per_page(wmi_unified_t wmi_handle,size_t cmd_size,size_t per_entry_size)942 static inline int wmi_get_hotlist_entries_per_page
943 				(wmi_unified_t wmi_handle,
944 				size_t cmd_size,
945 				size_t per_entry_size)
946 {
947 	uint32_t avail_space = 0;
948 	int num_entries = 0;
949 	uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle);
950 
951 	/* Calculate number of hotlist entries that can
952 	 * be passed in wma message request.
953 	 */
954 	avail_space = max_msg_len - cmd_size;
955 	num_entries = avail_space / per_entry_size;
956 	return num_entries;
957 }
958 
959 /**
960  * send_extscan_start_hotlist_monitor_cmd_tlv() - start hotlist monitor
961  * @wmi_handle: wmi handle
962  * @params: hotlist params
963  *
964  * This function configures hotlist monitor to start in fw.
965  *
966  * Return: QDF status
967  */
send_extscan_start_hotlist_monitor_cmd_tlv(wmi_unified_t wmi_handle,struct extscan_bssid_hotlist_set_params * params)968 static QDF_STATUS send_extscan_start_hotlist_monitor_cmd_tlv
969 			(wmi_unified_t wmi_handle,
970 			struct extscan_bssid_hotlist_set_params *params)
971 {
972 	wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd = NULL;
973 	wmi_extscan_hotlist_entry *dest_hotlist;
974 	struct ap_threshold_params *src_ap = params->ap;
975 	wmi_buf_t buf;
976 	uint8_t *buf_ptr;
977 
978 	int j, index = 0;
979 	int cmd_len = 0;
980 	int num_entries;
981 	int min_entries = 0;
982 	uint32_t numap = params->num_ap;
983 	int len = sizeof(*cmd);
984 
985 	len += WMI_TLV_HDR_SIZE;
986 	cmd_len = len;
987 
988 	num_entries = wmi_get_hotlist_entries_per_page(wmi_handle,
989 							cmd_len,
990 							sizeof(*dest_hotlist));
991 	/* setbssid hotlist expects the bssid list
992 	 * to be non zero value
993 	 */
994 	if (!numap || (numap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS)) {
995 		wmi_err("Invalid number of APs: %d", numap);
996 		return QDF_STATUS_E_INVAL;
997 	}
998 
999 	/* Split the hot list entry pages and send multiple command
1000 	 * requests if the buffer reaches the maximum request size
1001 	 */
1002 	while (index < numap) {
1003 		min_entries = QDF_MIN(num_entries, numap);
1004 		len += min_entries * sizeof(wmi_extscan_hotlist_entry);
1005 		buf = wmi_buf_alloc(wmi_handle, len);
1006 		if (!buf) {
1007 			wmi_err("wmi_buf_alloc failed");
1008 			return QDF_STATUS_E_FAILURE;
1009 		}
1010 		buf_ptr = (uint8_t *) wmi_buf_data(buf);
1011 		cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *)
1012 		      buf_ptr;
1013 		WMITLV_SET_HDR(&cmd->tlv_header,
1014 			       WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param,
1015 			       WMITLV_GET_STRUCT_TLVLEN
1016 				       (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param));
1017 
1018 		/* Multiple requests are sent until the num_entries_in_page
1019 		 * matches the total_entries
1020 		 */
1021 		cmd->request_id = params->request_id;
1022 		cmd->vdev_id = params->vdev_id;
1023 		cmd->total_entries = numap;
1024 		cmd->mode = 1;
1025 		cmd->num_entries_in_page = min_entries;
1026 		cmd->lost_ap_scan_count = params->lost_ap_sample_size;
1027 		cmd->first_entry_index = index;
1028 
1029 		wmi_debug("vdev id:%d total_entries: %d num_entries: %d lost_ap_sample_size: %d",
1030 			 cmd->vdev_id, cmd->total_entries,
1031 			 cmd->num_entries_in_page,
1032 			 cmd->lost_ap_scan_count);
1033 
1034 		buf_ptr += sizeof(*cmd);
1035 		WMITLV_SET_HDR(buf_ptr,
1036 			       WMITLV_TAG_ARRAY_STRUC,
1037 			       min_entries * sizeof(wmi_extscan_hotlist_entry));
1038 		dest_hotlist = (wmi_extscan_hotlist_entry *)
1039 			       (buf_ptr + WMI_TLV_HDR_SIZE);
1040 
1041 		/* Populate bssid, channel info and rssi
1042 		 * for the bssid's that are sent as hotlists.
1043 		 */
1044 		for (j = 0; j < min_entries; j++) {
1045 			WMITLV_SET_HDR(dest_hotlist,
1046 				       WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
1047 				       WMITLV_GET_STRUCT_TLVLEN
1048 					       (wmi_extscan_hotlist_entry));
1049 
1050 			dest_hotlist->min_rssi = src_ap->low;
1051 			WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes,
1052 						   &dest_hotlist->bssid);
1053 
1054 			wmi_debug("channel:%d min_rssi %d",
1055 				 dest_hotlist->channel,
1056 				 dest_hotlist->min_rssi);
1057 			wmi_debug("bssid mac_addr31to0: 0x%x, mac_addr47to32: 0x%x",
1058 				dest_hotlist->bssid.mac_addr31to0,
1059 				dest_hotlist->bssid.mac_addr47to32);
1060 			dest_hotlist++;
1061 			src_ap++;
1062 		}
1063 		buf_ptr += WMI_TLV_HDR_SIZE +
1064 			   (min_entries * sizeof(wmi_extscan_hotlist_entry));
1065 
1066 		if (wmi_unified_cmd_send(wmi_handle, buf, len,
1067 				WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) {
1068 			wmi_err("Failed to send extscan cfg hotlist monitor cmd");
1069 			wmi_buf_free(buf);
1070 			return QDF_STATUS_E_FAILURE;
1071 		}
1072 		index = index + min_entries;
1073 		num_entries = numap - min_entries;
1074 		len = cmd_len;
1075 	}
1076 	return QDF_STATUS_SUCCESS;
1077 }
1078 
wmi_extscan_attach_tlv(wmi_unified_t wmi_handle)1079 void wmi_extscan_attach_tlv(wmi_unified_t wmi_handle)
1080 {
1081 	struct wmi_ops *ops = wmi_handle->ops;
1082 	ops->send_reset_passpoint_network_list_cmd =
1083 				send_reset_passpoint_network_list_cmd_tlv;
1084 	ops->send_set_passpoint_network_list_cmd =
1085 				send_set_passpoint_network_list_cmd_tlv;
1086 	ops->send_set_epno_network_list_cmd =
1087 				send_set_epno_network_list_cmd_tlv;
1088 	ops->send_extscan_get_capabilities_cmd =
1089 				 send_extscan_get_capabilities_cmd_tlv;
1090 	ops->send_extscan_get_cached_results_cmd =
1091 				send_extscan_get_cached_results_cmd_tlv;
1092 	ops->send_extscan_stop_change_monitor_cmd =
1093 				send_extscan_stop_change_monitor_cmd_tlv;
1094 	ops->send_extscan_start_change_monitor_cmd =
1095 				send_extscan_start_change_monitor_cmd_tlv;
1096 	ops->send_extscan_stop_hotlist_monitor_cmd =
1097 				send_extscan_stop_hotlist_monitor_cmd_tlv;
1098 	ops->send_extscan_start_hotlist_monitor_cmd =
1099 				send_extscan_start_hotlist_monitor_cmd_tlv;
1100 	ops->send_stop_extscan_cmd = send_stop_extscan_cmd_tlv;
1101 	ops->send_start_extscan_cmd = send_start_extscan_cmd_tlv;
1102 }
1103