xref: /wlan-dirver/qca-wifi-host-cmn/umac/wifi_pos/src/wifi_pos_main.c (revision 7630cc90f02e8e853426e72adcbd746fb48d2d89)
1 /*
2  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 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: wifi_pos_main.c
22  * This file defines the important functions pertinent to
23  * wifi positioning to initialize and de-initialize the component.
24  */
25 #include <wlan_lmac_if_def.h>
26 #include "target_if_wifi_pos.h"
27 #include "wifi_pos_oem_interface_i.h"
28 #include "wifi_pos_utils_i.h"
29 #include "wifi_pos_api.h"
30 #include "wifi_pos_main_i.h"
31 #include "wifi_pos_ucfg_i.h"
32 #include "wlan_objmgr_cmn.h"
33 #include "wlan_objmgr_global_obj.h"
34 #include "wlan_objmgr_psoc_obj.h"
35 #include "wlan_objmgr_pdev_obj.h"
36 #include "wlan_objmgr_vdev_obj.h"
37 #include "wlan_ptt_sock_svc.h"
38 #include "target_if.h"
39 #include "wlan_objmgr_peer_obj.h"
40 
41 #ifndef CNSS_GENL
42 #include <wlan_objmgr_global_obj_i.h>
43 #endif
44 
45 #include "wlan_reg_services_api.h"
46 /* forward declartion */
47 struct regulatory_channel;
48 
49 #define REG_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \
50 	reg_info_1 &= 0xff00ffff;           \
51 	reg_info_1 |= ((val & 0xff) << 16); \
52 } while (0)
53 
54 /* max tx power is in 1 dBm units */
55 #define REG_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \
56 	reg_info_2 &= 0xffff00ff;              \
57 	reg_info_2 |= ((val & 0xff) << 8);     \
58 } while (0)
59 
60 /* channel info consists of 6 bits of channel mode */
61 
62 #define REG_SET_CHANNEL_MODE(reg_channel, val) do { \
63 	(reg_channel)->info &= 0xffffffc0;            \
64 	(reg_channel)->info |= (val);                 \
65 } while (0)
66 
67 /*
68  * obj mgr api to iterate over vdevs does not provide a direct array or vdevs,
69  * rather takes a callback that is called for every vdev. wifi pos needs to
70  * store device mode and vdev id of all active vdevs and provide this info to
71  * user space as part of APP registration response. due to this, vdev_idx is
72  * used to identify how many vdevs have been populated by obj manager API.
73  */
74 static uint32_t vdev_idx;
75 
76 /**
77  * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg
78  * @psoc: psoc object
79  *
80  * Return: status of operation
81  */
82 static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
83 {
84 	/* this is TBD */
85 	return true;
86 }
87 
88 #ifdef CNSS_GENL
89 static uint8_t *
90 wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
91 			  struct app_reg_rsp_vdev_info *vdevs_info)
92 {
93 	uint32_t *nl_sign;
94 	uint8_t *resp_buf;
95 	struct wifi_app_reg_rsp *app_reg_rsp;
96 
97 	/*
98 	 * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp
99 	 * to indicate NLA type response is supported for OEM request
100 	 * commands.
101 	 */
102 	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
103 			+ sizeof(uint8_t) + ENHNC_FLAGS_LEN;
104 	resp_buf = qdf_mem_malloc(*rsp_len);
105 	if (!resp_buf)
106 		return NULL;
107 
108 	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
109 	app_reg_rsp->num_inf = vdev_idx;
110 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
111 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
112 
113 	nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx];
114 	*nl_sign |= NL_ENABLE_OEM_REQ_RSP;
115 
116 	return resp_buf;
117 }
118 
119 /**
120  * wifi_pos_get_host_pdev_id: Get host pdev_id
121  * @psoc: Pointer to psoc object
122  * @tgt_pdev_id: target_pdev_id
123  * @host_pdev_id: host pdev_id
124  *
125  * Return: QDF_STATUS_SUCCESS in case of success, error codes in case of failure
126  */
127 static QDF_STATUS wifi_pos_get_host_pdev_id(
128 		struct wlan_objmgr_psoc *psoc, uint32_t tgt_pdev_id,
129 		uint32_t *host_pdev_id)
130 {
131 	/* pdev_id in FW starts from 1. So convert it to
132 	 * host id by decrementing it.
133 	 * zero has special meaning due to backward
134 	 * compatibility. Dont change it.
135 	 */
136 	if (tgt_pdev_id)
137 		*host_pdev_id = tgt_pdev_id - 1;
138 	else
139 		*host_pdev_id = tgt_pdev_id;
140 
141 	return QDF_STATUS_SUCCESS;
142 }
143 #else
144 static uint8_t *
145 wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
146 			  struct app_reg_rsp_vdev_info *vdevs_info)
147 {
148 	uint8_t *resp_buf;
149 	struct wifi_app_reg_rsp *app_reg_rsp;
150 
151 	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
152 			+ sizeof(uint8_t);
153 	resp_buf = qdf_mem_malloc(*rsp_len);
154 	if (!resp_buf)
155 		return NULL;
156 
157 	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
158 	app_reg_rsp->num_inf = vdev_idx;
159 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
160 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
161 
162 	return resp_buf;
163 }
164 
165 static QDF_STATUS wifi_pos_get_host_pdev_id(
166 		struct wlan_objmgr_psoc *psoc, uint32_t tgt_pdev_id,
167 		uint32_t *host_pdev_id)
168 {
169 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
170 
171 	tx_ops = wifi_pos_get_tx_ops(psoc);
172 	if (!tx_ops) {
173 		qdf_print("tx ops null");
174 		return QDF_STATUS_E_NULL_VALUE;
175 	}
176 
177 	if (!tx_ops->wifi_pos_convert_pdev_id_target_to_host) {
178 		wifi_pos_err("wifi_pos_convert_pdev_id_target_to_host is null");
179 		return QDF_STATUS_E_NULL_VALUE;
180 	}
181 
182 	return tx_ops->wifi_pos_convert_pdev_id_target_to_host(
183 			psoc, tgt_pdev_id, host_pdev_id);
184 }
185 #endif
186 
187 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
188 					struct wifi_pos_req_msg *req)
189 {
190 	uint8_t idx;
191 	uint32_t sub_type = 0;
192 	uint32_t channel_mhz = 0;
193 	uint32_t host_pdev_id = 0, tgt_pdev_id = 0;
194 	uint32_t offset;
195 	struct oem_data_req data_req;
196 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
197 	struct wlan_objmgr_pdev *pdev;
198 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
199 				wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
200 	QDF_STATUS status;
201 	uint8_t err;
202 
203 
204 	if (!wifi_pos_obj) {
205 		wifi_pos_err("wifi_pos priv obj is null");
206 		return QDF_STATUS_E_INVAL;
207 	}
208 
209 	wifi_pos_debug("Received data req pid(%d), len(%d)",
210 			req->pid, req->buf_len);
211 
212 	/* look for fields */
213 	if (req->field_info_buf)
214 		for (idx = 0; idx < req->field_info_buf->count; idx++) {
215 			offset = req->field_info_buf->fields[idx].offset;
216 			/*
217 			 * replace following reads with read_api based on
218 			 * length
219 			 */
220 			if (req->field_info_buf->fields[idx].id ==
221 					META_DATA_SUB_TYPE) {
222 				sub_type = *((uint32_t *)&req->buf[offset]);
223 				continue;
224 			}
225 
226 			if (req->field_info_buf->fields[idx].id ==
227 					META_DATA_CHANNEL_MHZ) {
228 				channel_mhz = *((uint32_t *)&req->buf[offset]);
229 				continue;
230 			}
231 
232 			if (req->field_info_buf->fields[idx].id ==
233 					META_DATA_PDEV) {
234 				tgt_pdev_id = *((uint32_t *)&req->buf[offset]);
235 				status = wifi_pos_get_host_pdev_id(
236 						psoc, tgt_pdev_id,
237 						&host_pdev_id);
238 				if (QDF_IS_STATUS_ERROR(status)) {
239 					wifi_pos_err("failed to get host pdev_id, tgt_pdev_id = %d",
240 						     tgt_pdev_id);
241 					return QDF_STATUS_E_INVAL;
242 				}
243 				continue;
244 			}
245 		}
246 
247 	switch (sub_type) {
248 	case TARGET_OEM_CAPABILITY_REQ:
249 		/* TBD */
250 		break;
251 	case TARGET_OEM_CONFIGURE_LCR:
252 		/* TBD */
253 		break;
254 	case TARGET_OEM_CONFIGURE_LCI:
255 		/* TBD */
256 		break;
257 	case TARGET_OEM_MEASUREMENT_REQ:
258 		/* TBD */
259 		break;
260 	case TARGET_OEM_CONFIGURE_FTMRR:
261 		wifi_pos_debug("FTMRR request");
262 		if (wifi_pos_obj->wifi_pos_send_action)
263 			wifi_pos_obj->wifi_pos_send_action(psoc, sub_type,
264 							   req->buf,
265 							   req->buf_len);
266 		break;
267 	case TARGET_OEM_CONFIGURE_WRU:
268 		wifi_pos_debug("WRU request");
269 		if (wifi_pos_obj->wifi_pos_send_action)
270 			wifi_pos_obj->wifi_pos_send_action(psoc, sub_type,
271 							   req->buf,
272 							   req->buf_len);
273 		break;
274 	default:
275 		wifi_pos_debug("invalid sub type or not passed");
276 
277 		tx_ops = wifi_pos_get_tx_ops(psoc);
278 		if (!tx_ops) {
279 			wifi_pos_err("tx ops null");
280 			return QDF_STATUS_E_INVAL;
281 		}
282 
283 		pdev = wlan_objmgr_get_pdev_by_id(psoc, host_pdev_id,
284 						  WLAN_WIFI_POS_CORE_ID);
285 		if (!pdev) {
286 			wifi_pos_err("pdev null");
287 			return QDF_STATUS_E_INVAL;
288 		}
289 
290 		status = ucfg_wifi_pos_measurement_request_notification(
291 				pdev, req);
292 		if (QDF_IS_STATUS_ERROR(status)) {
293 			err = OEM_ERR_REQUEST_REJECTED;
294 			wifi_pos_obj->wifi_pos_send_rsp(
295 					psoc, wifi_pos_get_app_pid(psoc),
296 					WIFI_POS_CMD_ERROR, sizeof(err), &err);
297 			wlan_objmgr_pdev_release_ref(pdev,
298 						     WLAN_WIFI_POS_CORE_ID);
299 			return QDF_STATUS_E_INVAL;
300 		}
301 
302 		data_req.data_len = req->buf_len;
303 		data_req.data = req->buf;
304 		tx_ops->data_req_tx(pdev, &data_req);
305 		wlan_objmgr_pdev_release_ref(pdev,
306 					     WLAN_WIFI_POS_CORE_ID);
307 		break;
308 	}
309 
310 	return QDF_STATUS_SUCCESS;
311 }
312 
313 static QDF_STATUS wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc,
314 					struct wifi_pos_req_msg *req)
315 {
316 	int error_code;
317 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
318 				wifi_pos_get_psoc_priv_obj(psoc);
319 	struct wifi_pos_user_defined_caps *caps =
320 				(struct wifi_pos_user_defined_caps *)req->buf;
321 
322 	if (!wifi_pos_obj) {
323 		wifi_pos_err("wifi_pos priv obj is null");
324 		return QDF_STATUS_E_INVAL;
325 	}
326 
327 	wifi_pos_debug("Received set cap req pid(%d), len(%d)",
328 			req->pid, req->buf_len);
329 
330 	wifi_pos_obj->ftm_rr = caps->ftm_rr;
331 	wifi_pos_obj->lci_capability = caps->lci_capability;
332 	error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS);
333 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
334 					WIFI_POS_CMD_SET_CAPS,
335 					sizeof(error_code),
336 					(uint8_t *)&error_code);
337 
338 	return QDF_STATUS_SUCCESS;
339 }
340 
341 static QDF_STATUS wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc,
342 					struct wifi_pos_req_msg *req)
343 {
344 	struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } };
345 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
346 					wifi_pos_get_psoc_priv_obj(psoc);
347 
348 	if (!wifi_pos_obj) {
349 		wifi_pos_err("wifi_pos priv obj is null");
350 		return QDF_STATUS_E_INVAL;
351 	}
352 
353 	wifi_pos_debug("Received get cap req pid(%d), len(%d)",
354 		       req->pid, req->buf_len);
355 
356 	wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap);
357 	cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr;
358 	cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability;
359 
360 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
361 					WIFI_POS_CMD_GET_CAPS,
362 					sizeof(cap_rsp),
363 					(uint8_t *)&cap_rsp);
364 
365 	return QDF_STATUS_SUCCESS;
366 }
367 
368 QDF_STATUS wifi_pos_send_report_resp(struct wlan_objmgr_psoc *psoc,
369 				     int req_id, uint8_t *dest_mac,
370 				     int err_code)
371 {
372 	struct wifi_pos_err_msg_report err_report = {0};
373 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
374 					wifi_pos_get_psoc_priv_obj(psoc);
375 
376 	if (!wifi_pos_obj) {
377 		wifi_pos_err("wifi_pos priv obj is null");
378 		return QDF_STATUS_E_INVAL;
379 	}
380 
381 	err_report.msg_tag_len = OEM_MSG_RSP_HEAD_TAG_ID << 16;
382 	err_report.msg_tag_len |= (sizeof(err_report) -
383 				   sizeof(err_report.err_rpt)) & 0x0000FFFF;
384 	err_report.msg_subtype = TARGET_OEM_ERROR_REPORT_RSP;
385 	err_report.req_id = req_id & 0xFFFF;
386 	err_report.req_id |= ((err_code & 0xFF) << 16);
387 	err_report.req_id |= (0x1 << 24);
388 	err_report.time_left = 0xFFFFFFFF;
389 	err_report.err_rpt.tag_len = OEM_MEAS_RSP_HEAD_TAG_ID << 16;
390 	err_report.err_rpt.tag_len |=
391 				(sizeof(struct wifi_pos_err_rpt)) & 0x0000FFFF;
392 	memcpy(&err_report.err_rpt.dest_mac, dest_mac, QDF_MAC_ADDR_SIZE);
393 
394 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
395 			WIFI_POS_CMD_OEM_DATA,
396 			sizeof(err_report),
397 			(uint8_t *)&err_report);
398 
399 	return QDF_STATUS_SUCCESS;
400 }
401 
402 static QDF_STATUS wifi_pos_get_vht_ch_width(struct wlan_objmgr_psoc *psoc,
403 					    enum phy_ch_width *ch_width)
404 {
405 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
406 
407 	tx_ops = wifi_pos_get_tx_ops(psoc);
408 	if (!tx_ops) {
409 		qdf_print("tx ops null");
410 		return QDF_STATUS_E_NULL_VALUE;
411 	}
412 
413 	if (!tx_ops->wifi_pos_get_vht_ch_width) {
414 		wifi_pos_err("wifi pos get vht ch width is null");
415 		return QDF_STATUS_E_NULL_VALUE;
416 	}
417 
418 	return tx_ops->wifi_pos_get_vht_ch_width(
419 			psoc, ch_width);
420 }
421 
422 static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc,
423 					struct wlan_objmgr_pdev *pdev,
424 					uint16_t freq,
425 					struct wifi_pos_channel_power *chan)
426 {
427 	struct ch_params ch_params = {0};
428 	uint16_t sec_ch_2g = 0;
429 	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
430 		wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
431 	uint32_t phy_mode;
432 	QDF_STATUS status;
433 
434 	if (!wifi_pos_psoc) {
435 		wifi_pos_err("wifi_pos priv obj is null");
436 		return;
437 	}
438 
439 	status = wifi_pos_get_vht_ch_width(psoc, &ch_params.ch_width);
440 
441 	if (QDF_IS_STATUS_ERROR(status)) {
442 		wifi_pos_err("can not get vht ch width");
443 		return;
444 	}
445 
446 	wlan_reg_set_channel_params_for_pwrmode(pdev, freq, sec_ch_2g,
447 						&ch_params,
448 						REG_CURRENT_PWR_MODE);
449 	chan->band_center_freq1 = ch_params.mhz_freq_seg0;
450 
451 	if (wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq) {
452 		wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq(
453 				freq, ch_params.ch_width, &phy_mode);
454 		chan->phy_mode = phy_mode;
455 	}
456 }
457 
458 /**
459  * wifi_pos_get_valid_channels: Get the list of valid channels from the
460  * given channel list
461  * @chan_freqs: Channel frequencies to be validated
462  * @num_ch: NUmber of channels in the channel list to be validated
463  * @valid_channel_list: Pointer to valid channel list
464  *
465  * Return: Number of valid channels in the given list
466  */
467 static uint32_t wifi_pos_get_valid_channels(qdf_freq_t *chan_freqs,
468 					    uint32_t num_ch,
469 					    qdf_freq_t *valid_channel_list)
470 {
471 	uint32_t i, num_valid_channels = 0;
472 
473 	for (i = 0; i < num_ch; i++) {
474 		enum channel_enum ch_enum;
475 
476 		ch_enum = wlan_reg_get_chan_enum_for_freq(chan_freqs[i]);
477 		if (reg_is_chan_enum_invalid(ch_enum))
478 			continue;
479 		valid_channel_list[num_valid_channels++] = chan_freqs[i];
480 	}
481 	return num_valid_channels;
482 }
483 
484 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
485 				   void *obj, void *arg)
486 {
487 	QDF_STATUS status;
488 	uint8_t num_channels;
489 	struct wlan_objmgr_pdev *pdev = obj;
490 	struct wifi_pos_channel_list *chan_list = arg;
491 	struct channel_power *ch_info = NULL;
492 	struct wifi_pos_channel_power *wifi_pos_ch;
493 	int i;
494 	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
495 		wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
496 
497 	if (!wifi_pos_psoc) {
498 		wifi_pos_err("wifi_pos priv obj is null");
499 		return;
500 	}
501 
502 	if (!chan_list) {
503 		wifi_pos_err("wifi_pos priv arg is null");
504 		return;
505 	}
506 
507 	wifi_pos_ch = &chan_list->chan_info[chan_list->num_channels];
508 
509 	ch_info = (struct channel_power *)qdf_mem_malloc(
510 			sizeof(*ch_info) * NUM_CHANNELS);
511 	if (!ch_info) {
512 		wifi_pos_err("ch_info is null");
513 		return;
514 	}
515 
516 	status = wlan_reg_get_channel_list_with_power_for_freq(pdev, ch_info,
517 							       &num_channels);
518 
519 	if (QDF_IS_STATUS_ERROR(status)) {
520 		wifi_pos_err("Failed to get valid channel list");
521 		qdf_mem_free(ch_info);
522 		return;
523 	}
524 
525 	if ((chan_list->num_channels + num_channels) > NUM_CHANNELS) {
526 		wifi_pos_err("Invalid number of channels");
527 		qdf_mem_free(ch_info);
528 		return;
529 	}
530 
531 	for (i = 0; i < num_channels; i++) {
532 		wifi_pos_ch[i].ch_power.center_freq = ch_info[i].center_freq;
533 		wifi_pos_ch[i].ch_power.chan_num = ch_info[i].chan_num;
534 		wifi_pos_ch[i].ch_power.tx_power = ch_info[i].tx_power;
535 		wifi_pos_ch[i].is_dfs_chan =
536 			wlan_reg_is_dfs_for_freq(pdev, ch_info[i].center_freq);
537 		wifi_update_channel_bw_info(
538 				psoc, pdev,
539 				ch_info[i].center_freq, &wifi_pos_ch[i]);
540 	}
541 
542 	if (wifi_pos_psoc->wifi_pos_get_max_fw_phymode_for_channels) {
543 		status = wifi_pos_psoc->wifi_pos_get_max_fw_phymode_for_channels(
544 				pdev, wifi_pos_ch, num_channels);
545 		if (QDF_IS_STATUS_ERROR(status)) {
546 			wifi_pos_err("Failed to get phymode");
547 			qdf_mem_free(ch_info);
548 			return;
549 		}
550 	}
551 
552 	chan_list->num_channels += num_channels;
553 	qdf_mem_free(ch_info);
554 }
555 
556 #ifdef CNSS_GENL
557 static bool wifi_pos_is_resp_version_valid(uint32_t rsp_version)
558 {
559 	return (rsp_version == WIFI_POS_RSP_V2_NL) ? true : false;
560 }
561 
562 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
563 				 struct wifi_pos_channel_list *chan_list)
564 {
565 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
566 				     wifi_pos_pdev_iterator,
567 				     chan_list, true, WLAN_WIFI_POS_CORE_ID);
568 	wifi_pos_debug("num channels: %d", chan_list->num_channels);
569 }
570 
571 #else
572 static bool wifi_pos_is_resp_version_valid(uint32_t rsp_version)
573 {
574 	return ((rsp_version == WIFI_POS_RSP_V2_NL) ||
575 		(rsp_version == WIFI_POS_RSP_V1_FLAT_MEMORY)) ?
576 		true : false;
577 }
578 
579 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
580 				 struct wifi_pos_channel_list *chan_list)
581 {
582 	uint8_t index;
583 
584 	for (index = 0; index < WLAN_OBJMGR_MAX_DEVICES; index++) {
585 		if (g_umac_glb_obj->psoc[index]) {
586 			wlan_objmgr_iterate_obj_list(
587 					g_umac_glb_obj->psoc[index],
588 					WLAN_PDEV_OP, wifi_pos_pdev_iterator,
589 					chan_list, true, WLAN_WIFI_POS_CORE_ID);
590 		}
591 	}
592 
593 	wifi_pos_notice("num channels: %d", chan_list->num_channels);
594 }
595 #endif
596 
597 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
598 					struct wifi_pos_req_msg *req)
599 {
600 	uint8_t idx;
601 	uint8_t *buf = NULL;
602 	uint32_t len, i, freq;
603 	qdf_freq_t *chan_freqs = NULL;
604 	bool oem_6g_support_disable;
605 	uint8_t *channels = req->buf;
606 	struct wlan_objmgr_pdev *pdev;
607 	uint32_t num_ch = req->buf_len;
608 	qdf_freq_t valid_channel_list[NUM_CHANNELS];
609 	uint32_t num_valid_channels = 0;
610 	struct wifi_pos_ch_info_rsp *ch_info;
611 	struct wifi_pos_channel_list *ch_list = NULL;
612 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
613 					wifi_pos_get_psoc_priv_obj(psoc);
614 	QDF_STATUS ret_val;
615 	struct wifi_pos_channel_power *ch;
616 
617 	if (!wifi_pos_obj) {
618 		wifi_pos_err("wifi_pos priv obj is null");
619 		return QDF_STATUS_E_INVAL;
620 	}
621 
622 	wifi_pos_debug("Received ch info req pid(%d), len(%d)",
623 			req->pid, req->buf_len);
624 
625 	/* get first pdev since we need that only for freq and dfs state */
626 	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_WIFI_POS_CORE_ID);
627 	if (!pdev) {
628 		wifi_pos_err("pdev get API failed");
629 		return QDF_STATUS_E_INVAL;
630 	}
631 	if (num_ch > NUM_CHANNELS) {
632 		wifi_pos_err("Invalid number of channels");
633 		ret_val = QDF_STATUS_E_INVAL;
634 		goto cleanup;
635 	}
636 
637 	chan_freqs = qdf_mem_malloc(NUM_CHANNELS * (sizeof(*chan_freqs)));
638 	if (!chan_freqs) {
639 		ret_val = QDF_STATUS_E_NOMEM;
640 		goto cleanup;
641 	}
642 
643 	ch_list = qdf_mem_malloc(sizeof(*ch_list));
644 	if (!ch_list) {
645 		ret_val = QDF_STATUS_E_NOMEM;
646 		goto cleanup;
647 	}
648 
649 	ch = ch_list->chan_info;
650 
651 	if ((num_ch == 0) &&
652 	    wifi_pos_is_resp_version_valid(req->rsp_version)) {
653 		wifi_pos_get_ch_info(psoc, ch_list);
654 		qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
655 		oem_6g_support_disable = wifi_pos_obj->oem_6g_support_disable;
656 		qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
657 
658 		/* ch_list has the frequencies in order of 2.4g, 5g & 6g */
659 		for (i = 0; i < ch_list->num_channels; i++) {
660 			freq = ch[i].ch_power.center_freq;
661 			if (oem_6g_support_disable &&
662 			    WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
663 				continue;
664 			num_valid_channels++;
665 		}
666 	} else {
667 		for (i = 0; i < NUM_CHANNELS; i++)
668 			chan_freqs[i] =
669 			    wlan_reg_chan_band_to_freq(pdev, channels[i],
670 						       BIT(REG_BAND_5G) |
671 						       BIT(REG_BAND_2G));
672 		/* v1 has ch_list with frequencies in order of 2.4g, 5g only */
673 		num_valid_channels = wifi_pos_get_valid_channels(
674 							chan_freqs, num_ch,
675 							 valid_channel_list);
676 		for (i = 0; i < num_valid_channels; i++) {
677 			ch[i].ch_power.center_freq = valid_channel_list[i];
678 			ch[i].ch_power.chan_num = wlan_reg_freq_to_chan(
679 					pdev, ch[i].ch_power.center_freq);
680 			ch[i].ch_power.tx_power =
681 				wlan_reg_get_channel_reg_power_for_freq(
682 						pdev,
683 						ch[i].ch_power.center_freq);
684 			ch[i].is_dfs_chan = wlan_reg_is_dfs_for_freq(
685 						pdev,
686 						ch[i].ch_power.center_freq);
687 
688 			wifi_update_channel_bw_info(psoc, pdev,
689 						    ch[i].ch_power.center_freq,
690 						    &ch[i]);
691 		}
692 	}
693 
694 	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) *
695 			num_valid_channels;
696 	buf = qdf_mem_malloc(len);
697 	if (!buf) {
698 		ret_val = QDF_STATUS_E_NOMEM;
699 		goto cleanup;
700 	}
701 
702 	/* First byte of message body will have num of channels */
703 	buf[0] = num_valid_channels;
704 	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
705 	for (idx = 0; idx < num_valid_channels; idx++) {
706 		ch_info[idx].reserved0 = 0;
707 		ch_info[idx].chan_id = ch[idx].ch_power.chan_num;
708 		ch_info[idx].mhz = ch[idx].ch_power.center_freq;
709 		ch_info[idx].band_center_freq1 = ch[idx].band_center_freq1;
710 		ch_info[idx].band_center_freq2 = 0;
711 		ch_info[idx].info = 0;
712 
713 		REG_SET_CHANNEL_REG_POWER(ch_info[idx].reg_info_1,
714 					  ch[idx].ch_power.tx_power);
715 		REG_SET_CHANNEL_MAX_TX_POWER(ch_info[idx].reg_info_2,
716 					     ch[idx].ch_power.tx_power);
717 
718 		if (ch[idx].is_dfs_chan)
719 			WIFI_POS_SET_DFS(ch_info[idx].info);
720 
721 		if (ch[idx].phy_mode)
722 			REG_SET_CHANNEL_MODE(&ch_info[idx], ch[idx].phy_mode);
723 	}
724 
725 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
726 					WIFI_POS_CMD_GET_CH_INFO,
727 					len, buf);
728 	ret_val = QDF_STATUS_SUCCESS;
729 
730 cleanup:
731 	qdf_mem_free(buf);
732 	qdf_mem_free(ch_list);
733 	qdf_mem_free(chan_freqs);
734 	wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
735 
736 	return ret_val;
737 }
738 
739 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc,
740 				   void *vdev, void *arg)
741 {
742 	struct app_reg_rsp_vdev_info *vdev_info = arg;
743 
744 	vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev);
745 	vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev);
746 	vdev_idx++;
747 }
748 
749 #ifdef CNSS_GENL
750 static void wifi_pos_get_vdev_list(struct wlan_objmgr_psoc *psoc,
751 				   struct app_reg_rsp_vdev_info *vdevs_info)
752 {
753 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
754 				     wifi_pos_vdev_iterator,
755 				     vdevs_info, true, WLAN_WIFI_POS_CORE_ID);
756 }
757 #else
758 /* For WIN, WIFI POS command registration is called only for the first
759  * PSOC. Hence, iterate through all the PSOCs and send the vdev list
760  * to LOWI.
761  */
762 static void wifi_pos_get_vdev_list(struct wlan_objmgr_psoc *psoc,
763 				   struct app_reg_rsp_vdev_info *vdevs_info)
764 {
765 	uint8_t index;
766 
767 	for (index = 0; index < WLAN_OBJMGR_MAX_DEVICES; index++) {
768 		if (g_umac_glb_obj->psoc[index]) {
769 			wlan_objmgr_iterate_obj_list(
770 					g_umac_glb_obj->psoc[index],
771 					WLAN_VDEV_OP, wifi_pos_vdev_iterator,
772 					vdevs_info, true,
773 					WLAN_WIFI_POS_CORE_ID);
774 		}
775 	}
776 }
777 #endif
778 
779 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
780 					struct wifi_pos_req_msg *req)
781 {
782 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
783 	uint8_t err = 0, *app_reg_rsp;
784 	uint32_t rsp_len;
785 	char *sign_str = NULL;
786 	struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
787 								= { { 0 } };
788 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
789 			wifi_pos_get_psoc_priv_obj(psoc);
790 
791 	if (!wifi_pos_obj) {
792 		wifi_pos_err("wifi_pos priv obj is null");
793 		return QDF_STATUS_E_INVAL;
794 	}
795 
796 	wifi_pos_debug("Received App Req Req pid(%d), len(%d)",
797 			req->pid, req->buf_len);
798 
799 	sign_str = (char *)req->buf;
800 	/* Registration request is only allowed for QTI Application */
801 	if ((OEM_APP_SIGNATURE_LEN != req->buf_len) ||
802 		(strncmp(sign_str, OEM_APP_SIGNATURE_STR,
803 			 OEM_APP_SIGNATURE_LEN))) {
804 		wifi_pos_err("Invalid signature pid(%d)", req->pid);
805 		ret = QDF_STATUS_E_PERM;
806 		err = OEM_ERR_INVALID_SIGNATURE;
807 		goto app_reg_failed;
808 	}
809 
810 	wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid);
811 	qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
812 	wifi_pos_obj->is_app_registered = true;
813 	wifi_pos_obj->app_pid = req->pid;
814 	qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
815 
816 	vdev_idx = 0;
817 
818 	wifi_pos_get_vdev_list(psoc, vdevs_info);
819 
820 	app_reg_rsp = wifi_pos_prepare_reg_resp(&rsp_len, vdevs_info);
821 	if (!app_reg_rsp) {
822 		ret = QDF_STATUS_E_NOMEM;
823 		err = OEM_ERR_NULL_CONTEXT;
824 		goto app_reg_failed;
825 	}
826 
827 	if (!vdev_idx)
828 		wifi_pos_debug("no active vdev");
829 
830 	vdev_idx = 0;
831 	wifi_pos_obj->wifi_pos_send_rsp(psoc, req->pid,
832 					WIFI_POS_CMD_REGISTRATION,
833 					rsp_len, (uint8_t *)app_reg_rsp);
834 
835 	qdf_mem_free(app_reg_rsp);
836 	return ret;
837 
838 app_reg_failed:
839 
840 	wifi_pos_obj->wifi_pos_send_rsp(psoc, req->pid, WIFI_POS_CMD_ERROR,
841 					sizeof(err), &err);
842 	return ret;
843 }
844 
845 /**
846  * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req
847  * @wmi_msg: wmi type request msg
848  *
849  * Return: status of operation
850  */
851 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc,
852 					struct wifi_pos_req_msg *req)
853 {
854 	wifi_pos_debug("enter: msg_type: %d", req->msg_type);
855 	switch (req->msg_type) {
856 	case WIFI_POS_CMD_REGISTRATION:
857 		return wifi_pos_process_app_reg_req(psoc, req);
858 	case WIFI_POS_CMD_OEM_DATA:
859 		return wifi_pos_process_data_req(psoc, req);
860 	case WIFI_POS_CMD_GET_CH_INFO:
861 		return wifi_pos_process_ch_info_req(psoc, req);
862 	case WIFI_POS_CMD_SET_CAPS:
863 		return wifi_pos_process_set_cap_req(psoc, req);
864 	case WIFI_POS_CMD_GET_CAPS:
865 		return wifi_pos_process_get_cap_req(psoc, req);
866 	default:
867 		wifi_pos_err("invalid request type");
868 		break;
869 	}
870 	return 0;
871 }
872 
873 /**
874  * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV
875  * type req
876  * @wmi_msg: wmi type request msg
877  *
878  * Return: status of operation
879  */
880 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc,
881 					    struct wifi_pos_req_msg *req)
882 {
883 	return QDF_STATUS_SUCCESS;
884 }
885 
886 QDF_STATUS wifi_pos_convert_host_pdev_id_to_target(
887 		struct wlan_objmgr_psoc *psoc, uint32_t host_pdev_id,
888 		uint32_t *target_pdev_id)
889 {
890 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
891 
892 	tx_ops = wifi_pos_get_tx_ops(psoc);
893 	if (!tx_ops) {
894 		wifi_pos_err("tx_ops is null");
895 		return QDF_STATUS_E_NULL_VALUE;
896 	}
897 
898 	if (!tx_ops->wifi_pos_convert_pdev_id_host_to_target) {
899 		wifi_pos_err("wifi_pos_convert_pdev_id_host_to_target is null");
900 		return QDF_STATUS_E_NULL_VALUE;
901 	}
902 
903 	return tx_ops->wifi_pos_convert_pdev_id_host_to_target(
904 			psoc, host_pdev_id, target_pdev_id);
905 }
906 
907 QDF_STATUS wifi_pos_psoc_obj_created_notification(
908 		struct wlan_objmgr_psoc *psoc, void *arg_list)
909 {
910 	QDF_STATUS status;
911 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj;
912 
913 	/*
914 	 * this is for WIN, if they have multiple psoc, we dont want to create
915 	 * multiple priv object. Since there is just one LOWI app registered to
916 	 * one driver, avoid 2nd private object with another psoc.
917 	 */
918 	if (wifi_pos_get_psoc()) {
919 		wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object");
920 		return QDF_STATUS_SUCCESS;
921 	} else {
922 		wifi_pos_debug("setting global pos object");
923 		wifi_pos_set_psoc(psoc);
924 	}
925 
926 	/* initialize wifi-pos psoc priv object */
927 	wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj));
928 	if (!wifi_pos_obj) {
929 		wifi_pos_clear_psoc();
930 		return QDF_STATUS_E_NOMEM;
931 	}
932 
933 	qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock);
934 	/* Register TLV or non-TLV callbacks depending on target fw version */
935 	if (wifi_pos_get_tlv_support(psoc))
936 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback;
937 	else
938 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback;
939 
940 	/*
941 	 * MGMT Rx is not handled in this phase since wifi pos only uses few
942 	 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are
943 	 * used for 80211k. That part is not yet converged and still follows
944 	 * legacy MGMT Rx to work. Action frame in new TXRX can be registered
945 	 * at per ACTION Frame type granularity only.
946 	 */
947 
948 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
949 						WLAN_UMAC_COMP_WIFI_POS,
950 						wifi_pos_obj,
951 						QDF_STATUS_SUCCESS);
952 
953 	if (QDF_IS_STATUS_ERROR(status)) {
954 		wifi_pos_err("obj attach with psoc failed with status: %d",
955 				status);
956 		qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
957 		qdf_mem_free(wifi_pos_obj);
958 		wifi_pos_clear_psoc();
959 	}
960 
961 	return status;
962 }
963 
964 QDF_STATUS  wifi_pos_psoc_obj_destroyed_notification(
965 		struct wlan_objmgr_psoc *psoc, void *arg_list)
966 {
967 	QDF_STATUS status;
968 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL;
969 
970 	if (wifi_pos_get_psoc() == psoc) {
971 		wifi_pos_debug("deregistering wifi_pos_psoc object");
972 		wifi_pos_clear_psoc();
973 	} else {
974 		wifi_pos_warn("un-related PSOC closed. do nothing");
975 		return QDF_STATUS_SUCCESS;
976 	}
977 
978 	wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc);
979 	if (!wifi_pos_obj) {
980 		wifi_pos_err("wifi_pos_obj is NULL");
981 		return QDF_STATUS_E_FAULT;
982 	}
983 
984 	target_if_wifi_pos_deinit_dma_rings(psoc);
985 
986 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
987 						WLAN_UMAC_COMP_WIFI_POS,
988 						wifi_pos_obj);
989 	if (status != QDF_STATUS_SUCCESS)
990 		wifi_pos_err("wifi_pos_obj detach failed");
991 
992 	wifi_pos_debug("wifi_pos_obj deleted with status %d", status);
993 	qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
994 	qdf_mem_free(wifi_pos_obj);
995 
996 	return status;
997 }
998 
999 #if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT)
1000 void
1001 wifi_pos_init_11az_context(struct wifi_pos_vdev_priv_obj *vdev_pos_obj)
1002 {
1003 	struct wifi_pos_11az_context *pasn_context;
1004 	uint8_t i;
1005 
1006 	pasn_context = &vdev_pos_obj->pasn_context;
1007 	for (i = 0; i < WLAN_MAX_11AZ_PEERS; i++) {
1008 		qdf_set_macaddr_broadcast(
1009 				&pasn_context->secure_peer_list[i].peer_mac);
1010 		qdf_set_macaddr_broadcast(
1011 				&pasn_context->secure_peer_list[i].self_mac);
1012 		pasn_context->secure_peer_list[i].force_self_mac_usage = false;
1013 		pasn_context->secure_peer_list[i].control_flags = 0;
1014 		qdf_set_macaddr_broadcast(
1015 				&pasn_context->unsecure_peer_list[i].peer_mac);
1016 		qdf_set_macaddr_broadcast(&pasn_context->failed_peer_list[i]);
1017 	}
1018 
1019 	pasn_context->num_secure_peers = 0;
1020 	pasn_context->num_unsecure_peers = 0;
1021 	pasn_context->num_failed_peers = 0;
1022 }
1023 #endif
1024 
1025 QDF_STATUS
1026 wifi_pos_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
1027 				   void *arg_list)
1028 {
1029 	struct wifi_pos_vdev_priv_obj *vdev_pos_obj;
1030 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
1031 
1032 	vdev_pos_obj = qdf_mem_malloc(sizeof(*vdev_pos_obj));
1033 	if (!vdev_pos_obj)
1034 		return QDF_STATUS_E_NOMEM;
1035 
1036 	status = wlan_objmgr_vdev_component_obj_attach(vdev,
1037 						       WLAN_UMAC_COMP_WIFI_POS,
1038 						       vdev_pos_obj,
1039 						       QDF_STATUS_SUCCESS);
1040 	if (QDF_IS_STATUS_ERROR(status)) {
1041 		qdf_mem_free(vdev_pos_obj);
1042 		wifi_pos_err("Wifi pos vdev attach failed");
1043 		return status;
1044 	}
1045 
1046 	wifi_pos_init_11az_context(vdev_pos_obj);
1047 
1048 	return status;
1049 }
1050 
1051 QDF_STATUS
1052 wifi_pos_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
1053 				     void *arg_list)
1054 {
1055 	struct wifi_pos_vdev_priv_obj *vdev_pos_obj;
1056 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
1057 
1058 	vdev_pos_obj = wifi_pos_get_vdev_priv_obj(vdev);
1059 	if (!vdev_pos_obj) {
1060 		wifi_pos_err("Wifi pos vdev priv obj is null");
1061 		return QDF_STATUS_E_FAILURE;
1062 	}
1063 
1064 	status = wlan_objmgr_vdev_component_obj_detach(vdev,
1065 						       WLAN_UMAC_COMP_WIFI_POS,
1066 						       vdev_pos_obj);
1067 	if (QDF_IS_STATUS_ERROR(status))
1068 		wifi_pos_err("Detach vdev private obj failed");
1069 
1070 	qdf_mem_free(vdev_pos_obj);
1071 
1072 	return status;
1073 }
1074 
1075 QDF_STATUS
1076 wifi_pos_peer_object_created_notification(struct wlan_objmgr_peer *peer,
1077 					  void *arg)
1078 {
1079 	struct wlan_wifi_pos_peer_priv_obj *peer_priv;
1080 	QDF_STATUS status;
1081 
1082 	if (!peer) {
1083 		wifi_pos_err("Peer is NULL");
1084 		return QDF_STATUS_E_NULL_VALUE;
1085 	}
1086 
1087 	peer_priv = qdf_mem_malloc(sizeof(*peer_priv));
1088 	if (!peer_priv)
1089 		return QDF_STATUS_E_NOMEM;
1090 
1091 	status = wlan_objmgr_peer_component_obj_attach(peer,
1092 						       WLAN_UMAC_COMP_WIFI_POS,
1093 						       (void *)peer_priv,
1094 						       QDF_STATUS_SUCCESS);
1095 	if (QDF_IS_STATUS_ERROR(status)) {
1096 		wifi_pos_err("unable to attach peer_priv obj to peer obj");
1097 		qdf_mem_free(peer_priv);
1098 	}
1099 
1100 	return status;
1101 }
1102 
1103 QDF_STATUS
1104 wifi_pos_peer_object_destroyed_notification(struct wlan_objmgr_peer *peer,
1105 					    void *arg)
1106 {
1107 	struct wlan_wifi_pos_peer_priv_obj *peer_priv;
1108 	QDF_STATUS status;
1109 
1110 	if (!peer) {
1111 		wifi_pos_err("Peer is NULL");
1112 		return QDF_STATUS_E_NULL_VALUE;
1113 	}
1114 
1115 	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
1116 							  WLAN_UMAC_COMP_WIFI_POS);
1117 	if (!peer_priv) {
1118 		wifi_pos_err("peer MLME component object is NULL");
1119 		return QDF_STATUS_E_FAILURE;
1120 	}
1121 
1122 	status = wlan_objmgr_peer_component_obj_detach(peer,
1123 						       WLAN_UMAC_COMP_WIFI_POS,
1124 						       (void *)peer_priv);
1125 	if (QDF_IS_STATUS_ERROR(status))
1126 		wifi_pos_err("unable to dettach peer_priv obj to peer obj");
1127 
1128 	qdf_mem_free(peer_priv);
1129 
1130 	return status;
1131 }
1132 
1133 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc,
1134 			     struct oem_data_rsp *oem_rsp)
1135 {
1136 	uint32_t len;
1137 	uint8_t *data;
1138 	uint32_t app_pid;
1139 	struct wifi_pos_psoc_priv_obj *priv;
1140 	wifi_pos_send_rsp_handler wifi_pos_send_rsp;
1141 
1142 	priv = wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
1143 	if (!priv) {
1144 		wifi_pos_err("private object is NULL");
1145 		return -EINVAL;
1146 	}
1147 
1148 	qdf_spin_lock_bh(&priv->wifi_pos_lock);
1149 	app_pid = priv->app_pid;
1150 	wifi_pos_send_rsp = priv->wifi_pos_send_rsp;
1151 	qdf_spin_unlock_bh(&priv->wifi_pos_lock);
1152 
1153 	len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len;
1154 	if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE ||
1155 			oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) {
1156 		wifi_pos_err("invalid length of Oem Data response");
1157 		return -EINVAL;
1158 	}
1159 
1160 	if (!wifi_pos_send_rsp) {
1161 		wifi_pos_err("invalid response handler");
1162 		return -EINVAL;
1163 	}
1164 
1165 	wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid);
1166 
1167 	if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) {
1168 		/* stitch togther the msg data_1 + CIR/CFR + data_2 */
1169 		data = qdf_mem_malloc(len);
1170 		if (!data)
1171 			return -ENOMEM;
1172 
1173 		qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1);
1174 		qdf_mem_copy(&data[oem_rsp->rsp_len_1],
1175 			     oem_rsp->vaddr, oem_rsp->dma_len);
1176 		qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len],
1177 			     oem_rsp->data_2, oem_rsp->rsp_len_2);
1178 
1179 		wifi_pos_send_rsp(psoc, app_pid, WIFI_POS_CMD_OEM_DATA, len,
1180 				  data);
1181 		qdf_mem_free(data);
1182 	} else {
1183 		wifi_pos_send_rsp(psoc, app_pid, WIFI_POS_CMD_OEM_DATA,
1184 				  oem_rsp->rsp_len_1, oem_rsp->data_1);
1185 	}
1186 
1187 	return 0;
1188 }
1189 
1190 void wifi_pos_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
1191 {
1192 	struct wlan_lmac_if_wifi_pos_rx_ops *wifi_pos_rx_ops;
1193 
1194 	wifi_pos_rx_ops = &rx_ops->wifi_pos_rx_ops;
1195 	wifi_pos_rx_ops->oem_rsp_event_rx = wifi_pos_oem_rsp_handler;
1196 }
1197 
1198 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
1199 			   struct wifi_pos_driver_caps *caps)
1200 {
1201 	uint16_t i, count = 0;
1202 	uint32_t freq;
1203 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
1204 					wifi_pos_get_psoc_priv_obj(psoc);
1205 	struct wifi_pos_channel_list *ch_list = NULL;
1206 
1207 	wifi_pos_debug("Enter");
1208 	if (!wifi_pos_obj) {
1209 		wifi_pos_err("wifi_pos_obj is null");
1210 		return QDF_STATUS_E_NULL_VALUE;
1211 	}
1212 
1213 	ch_list = qdf_mem_malloc(sizeof(*ch_list));
1214 	if (!ch_list)
1215 		return QDF_STATUS_E_NOMEM;
1216 
1217 	strlcpy(caps->oem_target_signature,
1218 		OEM_TARGET_SIGNATURE,
1219 		OEM_TARGET_SIGNATURE_LEN);
1220 	caps->oem_target_type = wifi_pos_obj->oem_target_type;
1221 	caps->oem_fw_version = wifi_pos_obj->oem_fw_version;
1222 	caps->driver_version.major = wifi_pos_obj->driver_version.major;
1223 	caps->driver_version.minor = wifi_pos_obj->driver_version.minor;
1224 	caps->driver_version.patch = wifi_pos_obj->driver_version.patch;
1225 	caps->driver_version.build = wifi_pos_obj->driver_version.build;
1226 	caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min;
1227 	caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max;
1228 	caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min;
1229 	caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max;
1230 	caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc);
1231 	wifi_pos_get_ch_info(psoc, ch_list);
1232 
1233 	/* copy valid channels list to caps */
1234 	for (i = 0; i < ch_list->num_channels; i++) {
1235 		freq = ch_list->chan_info[i].ch_power.center_freq;
1236 		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
1237 			continue;
1238 		caps->channel_list[count++] =
1239 			ch_list->chan_info[i].ch_power.chan_num;
1240 	}
1241 	caps->num_channels = count;
1242 	qdf_mem_free(ch_list);
1243 	return QDF_STATUS_SUCCESS;
1244 }
1245