xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/wifi_pos/src/os_if_wifi_pos.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
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: wlan_hdd_wifi_pos.c
22  * This file defines the important functions pertinent to wifi positioning
23  * component's os_if layer.
24  */
25 
26 #include "qdf_platform.h"
27 #include "qdf_module.h"
28 #include "wlan_nlink_srv.h"
29 #include "wlan_ptt_sock_svc.h"
30 #include "wlan_nlink_common.h"
31 #include "os_if_wifi_pos.h"
32 #include <wlan_lmac_if_def.h>
33 #include "wifi_pos_api.h"
34 #include "wlan_cfg80211.h"
35 #include "wlan_objmgr_psoc_obj.h"
36 #include "wlan_osif_priv.h"
37 #ifdef CNSS_GENL
38 #ifdef CONFIG_CNSS_OUT_OF_TREE
39 #include "cnss_nl.h"
40 #else
41 #include <net/cnss_nl.h>
42 #endif
43 #include "linux/genetlink.h"
44 #include "wifi_pos_utils_pub.h"
45 #endif
46 
47 #ifdef CNSS_GENL
48 #define WLAN_CLD80211_MAX_SIZE SKB_WITH_OVERHEAD(8192UL)
49 
50 #define CLD80211_ATTR_CMD 4
51 #define CLD80211_ATTR_CMD_TAG_DATA 5
52 #define CLD80211_ATTR_MAX 5
53 
54 static const uint32_t
55 cap_resp_sub_attr_len[CLD80211_SUB_ATTR_CAPS_MAX + 1] = {
56 	[CLD80211_SUB_ATTR_CAPS_OEM_TARGET_SIGNATURE] =
57 				OEM_TARGET_SIGNATURE_LEN,
58 	[CLD80211_SUB_ATTR_CAPS_OEM_TARGET_TYPE] = sizeof(uint32_t),
59 	[CLD80211_SUB_ATTR_CAPS_OEM_FW_VERSION] = sizeof(uint32_t),
60 	[CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_MAJOR] = sizeof(uint8_t),
61 	[CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_MINOR] = sizeof(uint8_t),
62 	[CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_PATCH] = sizeof(uint8_t),
63 	[CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_BUILD] = sizeof(uint8_t),
64 	[CLD80211_SUB_ATTR_CAPS_ALLOWED_DWELL_TIME_MIN] = sizeof(uint16_t),
65 	[CLD80211_SUB_ATTR_CAPS_ALLOWED_DWELL_TIME_MAX] = sizeof(uint16_t),
66 	[CLD80211_SUB_ATTR_CAPS_CURRENT_DWELL_TIME_MIN] = sizeof(uint16_t),
67 	[CLD80211_SUB_ATTR_CAPS_CURRENT_DWELL_TIME_MAX] = sizeof(uint16_t),
68 	[CLD80211_SUB_ATTR_CAPS_SUPPORTED_BANDS] = sizeof(uint16_t),
69 	[CLD80211_SUB_ATTR_CAPS_USER_DEFINED_CAPS] =
70 				sizeof(struct wifi_pos_user_defined_caps),
71 };
72 
73 static const uint32_t
74 peer_status_sub_attr_len[CLD80211_SUB_ATTR_PEER_MAX + 1] = {
75 	[CLD80211_SUB_ATTR_PEER_MAC_ADDR] = ETH_ALEN,
76 	[CLD80211_SUB_ATTR_PEER_STATUS] = sizeof(uint8_t),
77 	[CLD80211_SUB_ATTR_PEER_VDEV_ID] = sizeof(uint8_t),
78 	[CLD80211_SUB_ATTR_PEER_CAPABILITY] = sizeof(uint32_t),
79 	[CLD80211_SUB_ATTR_PEER_RESERVED] = sizeof(uint32_t),
80 	[CLD80211_SUB_ATTR_PEER_CHAN_INFO] =
81 				sizeof(struct wifi_pos_ch_info_rsp),
82 };
83 
84 static const uint32_t
85 ch_resp_sub_attr_len[CLD80211_SUB_ATTR_CH_MAX + 1] = {
86 	[CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN] = sizeof(uint32_t),
87 	[CLD80211_SUB_ATTR_CH_LIST] = sizeof(uint32_t),
88 	[CLD80211_SUB_ATTR_CH_CHAN_ID] = sizeof(uint32_t),
89 	[CLD80211_SUB_ATTR_CH_MHZ] = sizeof(uint32_t),
90 	[CLD80211_SUB_ATTR_CH_BAND_CF_1] = sizeof(uint32_t),
91 	[CLD80211_SUB_ATTR_CH_BAND_CF_2] = sizeof(uint32_t),
92 	[CLD80211_SUB_ATTR_CH_INFO] = sizeof(uint32_t),
93 	[CLD80211_SUB_ATTR_CH_REG_INFO_1] = sizeof(uint32_t),
94 	[CLD80211_SUB_ATTR_CH_REG_INFO_2] = sizeof(uint32_t),
95 };
96 #endif
97 
98 static int map_wifi_pos_cmd_to_ani_msg_rsp(
99 		enum wifi_pos_cmd_ids cmd)
100 {
101 	switch (cmd) {
102 	case WIFI_POS_CMD_REGISTRATION:
103 		return ANI_MSG_APP_REG_RSP;
104 	case WIFI_POS_CMD_SET_CAPS:
105 		return ANI_MSG_SET_OEM_CAP_RSP;
106 	case WIFI_POS_CMD_GET_CAPS:
107 		return ANI_MSG_GET_OEM_CAP_RSP;
108 	case WIFI_POS_CMD_GET_CH_INFO:
109 		return ANI_MSG_CHANNEL_INFO_RSP;
110 	case WIFI_POS_CMD_OEM_DATA:
111 		return ANI_MSG_OEM_DATA_RSP;
112 	case WIFI_POS_CMD_ERROR:
113 		return ANI_MSG_OEM_ERROR;
114 	case WIFI_POS_PEER_STATUS_IND:
115 		return ANI_MSG_PEER_STATUS_IND;
116 	default:
117 		osif_err("response message is invalid :%d", cmd);
118 		return -EINVAL;
119 	}
120 }
121 
122 static enum wifi_pos_cmd_ids
123 map_ani_msg_req_to_wifi_pos_cmd(uint32_t cmd)
124 {
125 	switch (cmd) {
126 	case ANI_MSG_APP_REG_REQ:
127 		return WIFI_POS_CMD_REGISTRATION;
128 	case ANI_MSG_SET_OEM_CAP_REQ:
129 		return WIFI_POS_CMD_SET_CAPS;
130 	case ANI_MSG_GET_OEM_CAP_REQ:
131 		return WIFI_POS_CMD_GET_CAPS;
132 	case ANI_MSG_CHANNEL_INFO_REQ:
133 		return WIFI_POS_CMD_GET_CH_INFO;
134 	case ANI_MSG_OEM_DATA_REQ:
135 		return WIFI_POS_CMD_OEM_DATA;
136 	default:
137 		osif_err("ani req is invalid :%d", cmd);
138 		return WIFI_POS_CMD_INVALID;
139 	}
140 }
141 
142 #ifdef CNSS_GENL
143 static enum wifi_pos_cmd_ids
144 map_cld_vendor_sub_cmd_to_wifi_pos_cmd(
145 		enum cld80211_vendor_sub_cmds cmd)
146 {
147 	switch (cmd) {
148 	case CLD80211_VENDOR_SUB_CMD_REGISTRATION:
149 		return WIFI_POS_CMD_REGISTRATION;
150 	case CLD80211_VENDOR_SUB_CMD_SET_CAPS:
151 		return WIFI_POS_CMD_SET_CAPS;
152 	case CLD80211_VENDOR_SUB_CMD_GET_CAPS:
153 		return WIFI_POS_CMD_GET_CAPS;
154 	case CLD80211_VENDOR_SUB_CMD_GET_CH_INFO:
155 		return WIFI_POS_CMD_GET_CH_INFO;
156 	case CLD80211_VENDOR_SUB_CMD_OEM_DATA:
157 		return WIFI_POS_CMD_OEM_DATA;
158 	default:
159 		osif_err("cld vendor subcmd is invalid :%d", cmd);
160 		return WIFI_POS_CMD_INVALID;
161 	}
162 }
163 
164 static enum cld80211_vendor_sub_cmds
165 map_wifi_pos_cmd_to_cld_vendor_sub_cmd(
166 		enum wifi_pos_cmd_ids cmd)
167 {
168 	switch (cmd) {
169 	case WIFI_POS_CMD_REGISTRATION:
170 		return CLD80211_VENDOR_SUB_CMD_REGISTRATION;
171 	case WIFI_POS_CMD_SET_CAPS:
172 		return CLD80211_VENDOR_SUB_CMD_SET_CAPS;
173 	case WIFI_POS_CMD_GET_CAPS:
174 		return CLD80211_VENDOR_SUB_CMD_GET_CAPS;
175 	case WIFI_POS_CMD_GET_CH_INFO:
176 		return CLD80211_VENDOR_SUB_CMD_GET_CH_INFO;
177 	case WIFI_POS_CMD_OEM_DATA:
178 		return CLD80211_VENDOR_SUB_CMD_OEM_DATA;
179 	case WIFI_POS_CMD_ERROR:
180 		return ANI_MSG_OEM_ERROR;
181 	case WIFI_POS_PEER_STATUS_IND:
182 		return ANI_MSG_PEER_STATUS_IND;
183 	default:
184 		osif_err("response message is invalid :%d", cmd);
185 		return CLD80211_VENDOR_SUB_CMD_INVALID;
186 	}
187 }
188 
189 static void os_if_wifi_pos_send_peer_nl_status(uint32_t pid, uint8_t *buf)
190 {
191 	void *hdr;
192 	int flags = GFP_KERNEL;
193 	struct sk_buff *msg = NULL;
194 	struct nlattr *nest1, *nest2, *nest3;
195 	struct wifi_pos_peer_status_info *peer_info;
196 	struct wifi_pos_ch_info_rsp *chan_info;
197 
198 	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
199 	if (!msg) {
200 		osif_err("alloc_skb failed");
201 		return;
202 	}
203 
204 	peer_info = (struct wifi_pos_peer_status_info *)buf;
205 	chan_info = &peer_info->peer_chan_info;
206 
207 	nla_put_u32(msg, CLD80211_ATTR_CMD,
208 			 CLD80211_VENDOR_SUB_CMD_PEER_STATUS_IND);
209 	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
210 	if (!nest2) {
211 		osif_err("nla_nest_start failed");
212 		dev_kfree_skb(msg);
213 		return;
214 	}
215 
216 	nla_put(msg, CLD80211_SUB_ATTR_PEER_MAC_ADDR,
217 			ETH_ALEN, peer_info->peer_mac_addr);
218 	nla_put_u8(msg, CLD80211_SUB_ATTR_PEER_STATUS,
219 						peer_info->peer_status);
220 	nla_put_u8(msg, CLD80211_SUB_ATTR_PEER_VDEV_ID,
221 						peer_info->vdev_id);
222 	nla_put_u32(msg, CLD80211_SUB_ATTR_PEER_CAPABILITY,
223 						peer_info->peer_capability);
224 	nla_put_u32(msg, CLD80211_SUB_ATTR_PEER_RESERVED,
225 							peer_info->reserved0);
226 	nest3 = nla_nest_start(msg, CLD80211_SUB_ATTR_PEER_CHAN_INFO);
227 	if (!nest3) {
228 		osif_err("nla_nest_start failed");
229 		dev_kfree_skb(msg);
230 		return;
231 	}
232 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_CHAN_ID,
233 			chan_info->chan_id);
234 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_MHZ, chan_info->mhz);
235 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_1,
236 			chan_info->band_center_freq1);
237 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_2,
238 			chan_info->band_center_freq2);
239 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_INFO, chan_info->info);
240 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_1,
241 			chan_info->reg_info_1);
242 	nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_2,
243 			chan_info->reg_info_2);
244 
245 	nla_nest_end(msg, nest3);
246 	nla_nest_end(msg, nest2);
247 
248 	osif_debug("sending oem rsp: type: %d to pid (%d)",
249 		    CLD80211_VENDOR_SUB_CMD_PEER_STATUS_IND, pid);
250 
251 	cld80211_oem_send_reply(msg, hdr, nest1, flags);
252 }
253 
254 static void os_if_send_cap_nl_resp(uint32_t pid, uint8_t *buf)
255 {
256 	void *hdr;
257 	int flags = GFP_KERNEL;
258 	struct sk_buff *msg = NULL;
259 	struct nlattr *nest1, *nest2;
260 	struct wifi_pos_oem_get_cap_rsp *cap_rsp;
261 
262 	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
263 	if (!msg) {
264 		osif_err("alloc_skb failed");
265 		return;
266 	}
267 
268 	nla_put_u32(msg, CLD80211_ATTR_CMD,
269 	map_wifi_pos_cmd_to_cld_vendor_sub_cmd(WIFI_POS_CMD_GET_CAPS));
270 
271 	cap_rsp = (struct wifi_pos_oem_get_cap_rsp *)(buf);
272 	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
273 
274 	if (!nest2) {
275 		osif_err("nla_nest_start failed");
276 		dev_kfree_skb(msg);
277 		return;
278 	}
279 
280 	nla_put(msg, CLD80211_SUB_ATTR_CAPS_OEM_TARGET_SIGNATURE,
281 		OEM_TARGET_SIGNATURE_LEN, OEM_TARGET_SIGNATURE);
282 	nla_put_u32(msg, CLD80211_SUB_ATTR_CAPS_OEM_TARGET_TYPE,
283 		    cap_rsp->driver_cap.oem_target_type);
284 	nla_put_u32(msg, CLD80211_SUB_ATTR_CAPS_OEM_FW_VERSION,
285 		    cap_rsp->driver_cap.oem_fw_version);
286 	nla_put_u8(msg, CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_MAJOR,
287 		   cap_rsp->driver_cap.driver_version.major);
288 	nla_put_u8(msg, CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_MINOR,
289 		   cap_rsp->driver_cap.driver_version.minor);
290 	nla_put_u8(msg, CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_PATCH,
291 		   cap_rsp->driver_cap.driver_version.patch);
292 	nla_put_u8(msg, CLD80211_SUB_ATTR_CAPS_DRIVER_VERSION_BUILD,
293 		   cap_rsp->driver_cap.driver_version.build);
294 	nla_put_u16(msg, CLD80211_SUB_ATTR_CAPS_ALLOWED_DWELL_TIME_MIN,
295 		    cap_rsp->driver_cap.allowed_dwell_time_min);
296 	nla_put_u16(msg, CLD80211_SUB_ATTR_CAPS_ALLOWED_DWELL_TIME_MAX,
297 		    cap_rsp->driver_cap.allowed_dwell_time_max);
298 	nla_put_u16(msg, CLD80211_SUB_ATTR_CAPS_CURRENT_DWELL_TIME_MIN,
299 		    cap_rsp->driver_cap.curr_dwell_time_min);
300 	nla_put_u16(msg, CLD80211_SUB_ATTR_CAPS_CURRENT_DWELL_TIME_MAX,
301 		    cap_rsp->driver_cap.curr_dwell_time_max);
302 	nla_put_u16(msg, CLD80211_SUB_ATTR_CAPS_SUPPORTED_BANDS,
303 		    cap_rsp->driver_cap.supported_bands);
304 	nla_put(msg, CLD80211_SUB_ATTR_CAPS_USER_DEFINED_CAPS,
305 		sizeof(struct wifi_pos_user_defined_caps),
306 		&cap_rsp->user_defined_cap);
307 	nla_nest_end(msg, nest2);
308 
309 	osif_debug("sending oem rsp: type: %d to pid (%d)",
310 		    CLD80211_VENDOR_SUB_CMD_GET_CAPS, pid);
311 
312 	cld80211_oem_send_reply(msg, hdr, nest1, flags);
313 }
314 
315 static void
316 os_if_get_chan_nl_resp_len(uint32_t *chan_info, uint32_t *attr_headers)
317 {
318 	uint32_t i;
319 	struct nlattr more_data;
320 	struct nlattr attr_tag_data;
321 	struct nlattr cld80211_subattr_ch_list;
322 	struct nlattr chan_iter;
323 
324 	*attr_headers = NLA_ALIGN(sizeof(attr_tag_data));
325 	*attr_headers += NLA_ALIGN(sizeof(more_data));
326 	*attr_headers += nla_total_size(
327 		ch_resp_sub_attr_len[CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN]);
328 	*attr_headers += sizeof(cld80211_subattr_ch_list);
329 
330 	*chan_info = NLA_ALIGN(sizeof(chan_iter));
331 	i = CLD80211_SUB_ATTR_CH_LIST;
332 	for (; i <= CLD80211_SUB_ATTR_CH_MAX; i++)
333 		*chan_info += nla_total_size(ch_resp_sub_attr_len[i]);
334 }
335 
336 static uint8_t os_if_get_max_chan_nl_resp(uint8_t chan_num)
337 {
338 	struct nlattr vendor_data;
339 	struct nlattr attr_cmd;
340 	uint32_t chan_info = 0, attr_headers = 0;
341 	uint32_t chan_info_msg_len, chan_allow = 0;
342 
343 	os_if_get_chan_nl_resp_len(&chan_info, &attr_headers);
344 	attr_headers += NLA_ALIGN(sizeof(vendor_data));
345 	attr_headers += NLA_ALIGN(sizeof(attr_cmd));
346 
347 	chan_info_msg_len = WLAN_CLD80211_MAX_SIZE;
348 	chan_info_msg_len -= WIFIPOS_RESERVE_BYTES;
349 	chan_info_msg_len -= attr_headers;
350 
351 	chan_allow = chan_info_msg_len / chan_info;
352 
353 	if (chan_num > chan_allow)
354 		return chan_allow;
355 	else
356 		return chan_num;
357 }
358 
359 static int
360 os_if_create_ch_nl_resp(uint32_t pid, uint8_t *buf, uint16_t num_chan,
361 			bool is_frag)
362 {
363 	void *hdr;
364 	int i;
365 	int flags = GFP_KERNEL;
366 	struct sk_buff *msg = NULL;
367 	struct nlattr *nest1, *nest2;
368 	struct nlattr *nest3, *nest4;
369 	struct wifi_pos_ch_info_rsp *channel_rsp;
370 
371 	channel_rsp = (struct wifi_pos_ch_info_rsp *)buf;
372 
373 	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
374 	if (!msg) {
375 		osif_err("alloc_skb failed");
376 		return -EPERM;
377 	}
378 
379 	nla_put_u32(msg, CLD80211_ATTR_CMD,
380 		    CLD80211_VENDOR_SUB_CMD_GET_CH_INFO);
381 
382 	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
383 	if (!nest2)
384 		goto fail;
385 
386 	if (is_frag)
387 		nla_put_flag(msg, CLD80211_SUB_ATTR_CH_MORE_DATA);
388 
389 	nla_put_u32(msg, CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN, num_chan);
390 
391 	nest3 = nla_nest_start(msg, CLD80211_SUB_ATTR_CH_LIST);
392 	if (!nest3)
393 		goto fail;
394 	for (i = 0; i < num_chan; i++) {
395 		nest4 = nla_nest_start(msg, i);
396 		if (!nest4)
397 			goto fail;
398 
399 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_CHAN_ID,
400 			    channel_rsp->chan_id);
401 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_MHZ, channel_rsp->mhz);
402 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_1,
403 			    channel_rsp->band_center_freq1);
404 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_2,
405 			    channel_rsp->band_center_freq2);
406 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_INFO, channel_rsp->info);
407 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_1,
408 			    channel_rsp->reg_info_1);
409 		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_2,
410 			    channel_rsp->reg_info_2);
411 		nla_nest_end(msg, nest4);
412 		channel_rsp++;
413 	}
414 
415 	nla_nest_end(msg, nest3);
416 	nla_nest_end(msg, nest2);
417 
418 	osif_debug("sending oem rsp: type: %d to pid (%d)",
419 		   CLD80211_VENDOR_SUB_CMD_GET_CH_INFO, pid);
420 
421 	cld80211_oem_send_reply(msg, hdr, nest1, flags);
422 	return 0;
423 
424 fail:
425 	osif_err("failed to fill CHAN_RESP attributes");
426 	dev_kfree_skb(msg);
427 	return -EPERM;
428 }
429 
430 static void os_if_send_chan_nl_resp(uint32_t pid, uint8_t *buf)
431 {
432 	int err;
433 	uint8_t check_chans = 0;
434 	uint8_t  *chnk_ptr, chan_allow = 0;
435 	bool resp_frag = false;
436 
437 	check_chans = buf[0];
438 	chnk_ptr = &buf[1];
439 
440 	do {
441 		chan_allow = os_if_get_max_chan_nl_resp(check_chans);
442 
443 		if (check_chans > chan_allow)
444 			resp_frag = true;
445 		else
446 			resp_frag = false;
447 		check_chans -= chan_allow;
448 
449 		err = os_if_create_ch_nl_resp(pid, chnk_ptr,
450 					      chan_allow, resp_frag);
451 		if (err) {
452 			osif_err("failed to alloc memory for ch_nl_resp");
453 			return;
454 		}
455 		chnk_ptr += (sizeof(struct wifi_pos_ch_info_rsp) *
456 				      chan_allow);
457 	} while (resp_frag);
458 }
459 
460 static int
461 os_if_create_oemdata_resp(uint32_t pid, uint8_t *buf, bool frag_resp,
462 			  uint32_t chnk_len)
463 {
464 	void *hdr;
465 	int flags = GFP_KERNEL;
466 	struct sk_buff *msg = NULL;
467 	struct nlattr *nest1, *nest2;
468 
469 	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
470 	if (!msg) {
471 		osif_err("alloc_skb failed");
472 		return -EPERM;
473 	}
474 
475 	nla_put_u32(msg, CLD80211_ATTR_CMD, CLD80211_VENDOR_SUB_CMD_OEM_DATA);
476 
477 	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
478 	if (!nest2)
479 		goto fail;
480 
481 	if (frag_resp)
482 		nla_put_flag(msg, CLD80211_SUB_ATTR_OEM_MORE_DATA);
483 
484 	nla_put(msg, CLD80211_SUB_ATTR_BINARY_DATA, chnk_len, buf);
485 
486 	nla_nest_end(msg, nest2);
487 	osif_debug("sending oem rsp: type: %d to pid (%d)",
488 		   CLD80211_VENDOR_SUB_CMD_OEM_DATA, pid);
489 	cld80211_oem_send_reply(msg, hdr, nest1, flags);
490 	return 0;
491 
492 fail:
493 	osif_err("failed to fill CHAN_RESP attributes");
494 	dev_kfree_skb(msg);
495 	return -EPERM;
496 }
497 
498 static void
499 os_if_send_oem_data_nl_resp(uint32_t pid, uint8_t *buf,
500 			    uint32_t buf_len)
501 {
502 	int err;
503 	uint32_t attr_len;
504 	uint32_t chnk_len, remain_len;
505 	uint8_t *chnk_ptr;
506 	bool frag_resp = false;
507 
508 	struct nlattr vendor_data;
509 	struct nlattr attr_cmd;
510 	struct nlattr attr_tag_data;
511 	struct nlattr cld80211_subattr_bindata;
512 	struct nlattr more_data;
513 
514 	attr_len = WIFIPOS_RESERVE_BYTES;
515 	attr_len += NLMSG_ALIGN(sizeof(vendor_data));
516 	attr_len += NLMSG_ALIGN(sizeof(attr_cmd));
517 	attr_len += NLMSG_ALIGN(sizeof(attr_tag_data));
518 	attr_len += NLMSG_ALIGN(sizeof(more_data));
519 
520 	chnk_ptr = buf;
521 	chnk_len = buf_len;
522 	remain_len = buf_len;
523 	do {
524 		if (attr_len + nla_total_size(chnk_len) >
525 		    WLAN_CLD80211_MAX_SIZE) {
526 			frag_resp = true;
527 
528 			chnk_len = WLAN_CLD80211_MAX_SIZE - (attr_len +
529 					sizeof(cld80211_subattr_bindata));
530 		} else {
531 			frag_resp = false;
532 		}
533 
534 		remain_len -= chnk_len;
535 
536 		err = os_if_create_oemdata_resp(pid, chnk_ptr,
537 						frag_resp, chnk_len);
538 		if (err) {
539 			osif_err("failed to alloc memory for oem_nl_resp");
540 			return;
541 		}
542 		chnk_ptr += chnk_len;
543 		chnk_len = remain_len;
544 	} while (frag_resp);
545 }
546 
547 static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
548 			       enum wifi_pos_cmd_ids cmd, uint32_t len)
549 {
550 	switch (cmd) {
551 	case WIFI_POS_CMD_GET_CAPS:
552 		os_if_send_cap_nl_resp(pid, buf);
553 		break;
554 	case WIFI_POS_CMD_GET_CH_INFO:
555 		os_if_send_chan_nl_resp(pid, buf);
556 		break;
557 	case WIFI_POS_CMD_OEM_DATA:
558 		os_if_send_oem_data_nl_resp(pid, buf, len);
559 		break;
560 	case WIFI_POS_PEER_STATUS_IND:
561 		os_if_wifi_pos_send_peer_nl_status(pid, buf);
562 		break;
563 	default:
564 		osif_err("response message is invalid :%d", cmd);
565 	}
566 }
567 #else
568 static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
569 			       enum wifi_pos_cmd_ids cmd, uint32_t len)
570 {
571 }
572 #endif
573 
574 /**
575  * os_if_wifi_pos_send_rsp() - send oem registration response
576  *
577  * This function sends oem message to registered application process
578  *
579  * Return:  none
580  */
581 static void os_if_wifi_pos_send_rsp(struct wlan_objmgr_psoc *psoc, uint32_t pid,
582 				    enum wifi_pos_cmd_ids cmd, uint32_t buf_len,
583 				    uint8_t *buf)
584 {
585 	tAniMsgHdr *aniHdr;
586 	struct sk_buff *skb = NULL;
587 	struct nlmsghdr *nlh;
588 
589 	/* OEM msg is always to a specific process and cannot be a broadcast */
590 	if (pid == 0) {
591 		osif_err("invalid dest pid");
592 		return;
593 	}
594 
595 	if (ucfg_wifi_pos_is_nl_rsp(psoc)) {
596 		os_if_send_nl_resp(pid, buf, cmd, buf_len);
597 	} else {
598 		skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len),
599 				GFP_ATOMIC);
600 		if (!skb) {
601 			osif_alert("alloc_skb failed");
602 			return;
603 		}
604 
605 		nlh = (struct nlmsghdr *)skb->data;
606 		nlh->nlmsg_pid = 0;     /* from kernel */
607 		nlh->nlmsg_flags = 0;
608 		nlh->nlmsg_seq = 0;
609 		nlh->nlmsg_type = WLAN_NL_MSG_OEM;
610 		nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + buf_len);
611 
612 		aniHdr = NLMSG_DATA(nlh);
613 		aniHdr->type = map_wifi_pos_cmd_to_ani_msg_rsp(cmd);
614 		qdf_mem_copy(&aniHdr[1], buf, buf_len);
615 		aniHdr->length = buf_len;
616 
617 		skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len));
618 		osif_debug("sending oem rsp: type: %d len(%d) to pid (%d)",
619 			   aniHdr->type, buf_len, pid);
620 		nl_srv_ucast_oem(skb, pid, MSG_DONTWAIT);
621 	}
622 }
623 
624 #ifdef CNSS_GENL
625 static int
626 wifi_pos_parse_nla_oemdata_req(uint32_t len, uint8_t *buf,
627 			       struct wifi_pos_req_msg *req)
628 {
629 	struct nlattr *tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX + 1];
630 
631 	if (wlan_cfg80211_nla_parse(tb_oem_data,
632 				    CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX,
633 				    (struct nlattr *)buf, len, NULL)) {
634 		osif_err("invalid data in request");
635 		return OEM_ERR_INVALID_MESSAGE_TYPE;
636 	}
637 
638 	if (!tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]) {
639 		osif_err("CLD80211_SUB_ATTR_MSG_OEM_DATA_FW not present");
640 		return OEM_ERR_INVALID_MESSAGE_TYPE;
641 	}
642 	req->buf_len = nla_len(
643 				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
644 	req->buf = nla_data(
645 				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
646 
647 	return 0;
648 }
649 
650 static int  wifi_pos_parse_nla_req(const void *data, int len, int pid,
651 		    struct wifi_pos_req_msg *req)
652 {
653 	uint8_t *msg;
654 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
655 	uint32_t msg_len;
656 
657 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
658 		osif_err("invalid data in request");
659 		return OEM_ERR_INVALID_MESSAGE_TYPE;
660 	}
661 
662 	req->pid = pid;
663 	req->msg_type = map_cld_vendor_sub_cmd_to_wifi_pos_cmd(
664 				nla_get_u32(tb[CLD80211_ATTR_CMD]));
665 	req->rsp_version = WIFI_POS_RSP_V2_NL;
666 
667 	if (tb[CLD80211_ATTR_CMD_TAG_DATA]) {
668 		msg_len = nla_len(tb[CLD80211_ATTR_CMD_TAG_DATA]);
669 		msg = nla_data(tb[CLD80211_ATTR_CMD_TAG_DATA]);
670 
671 		if (req->msg_type == WIFI_POS_CMD_OEM_DATA) {
672 			if (wifi_pos_parse_nla_oemdata_req(msg_len, msg, req)) {
673 				osif_err("parsing oemdata req failed");
674 				return OEM_ERR_INVALID_MESSAGE_LENGTH;
675 			}
676 		} else {
677 			req->buf_len = msg_len;
678 			req->buf = msg;
679 		}
680 	}
681 	if (tb[CLD80211_ATTR_META_DATA])
682 		osif_err("meta data dropped. Apps can use CLD80211_ATTR_CMD_TAG_DATA sub attrs");
683 
684 	return 0;
685 }
686 
687 static int  wifi_pos_parse_ani_req(const void *data, int len, int pid,
688 		    struct wifi_pos_req_msg *req)
689 {
690 	tAniMsgHdr *msg_hdr;
691 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
692 	uint32_t msg_len, id, nl_field_info_size, expected_field_info_size;
693 	struct wifi_pos_field_info *field_info;
694 
695 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
696 		osif_err("invalid data in request");
697 		return OEM_ERR_INVALID_MESSAGE_TYPE;
698 	}
699 
700 	msg_len = nla_len(tb[CLD80211_ATTR_DATA]);
701 	if (msg_len < sizeof(*msg_hdr)) {
702 		osif_err("Insufficient length for msg_hdr: %u", msg_len);
703 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
704 	}
705 
706 	msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]);
707 	req->msg_type = map_ani_msg_req_to_wifi_pos_cmd(
708 				(uint32_t)msg_hdr->type);
709 	req->rsp_version = WIFI_POS_RSP_V1_FLAT_MEMORY;
710 
711 	if (msg_len < sizeof(*msg_hdr) + msg_hdr->length) {
712 		osif_err("Insufficient length for msg_hdr buffer: %u",
713 			 msg_len);
714 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
715 	}
716 
717 	req->buf_len = msg_hdr->length;
718 	req->buf = (uint8_t *)&msg_hdr[1];
719 	req->pid = pid;
720 
721 	id = CLD80211_ATTR_META_DATA;
722 	if (!tb[id])
723 		return 0;
724 
725 	nl_field_info_size = nla_len(tb[id]);
726 	if (nl_field_info_size < sizeof(*field_info)) {
727 		osif_err("Insufficient length for field_info_buf: %u",
728 			 nl_field_info_size);
729 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
730 	}
731 
732 	field_info = nla_data(tb[id]);
733 	if (!field_info->count) {
734 		osif_debug("field_info->count is zero, ignoring META_DATA");
735 		return 0;
736 	}
737 
738 	if ((field_info->count - 1) >
739 	    ((UINT_MAX - sizeof(*field_info)) /
740 	    sizeof(struct wifi_pos_field))) {
741 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
742 	}
743 
744 	expected_field_info_size = sizeof(*field_info) +
745 		(field_info->count - 1) * sizeof(struct wifi_pos_field);
746 
747 	if (nl_field_info_size < expected_field_info_size) {
748 		osif_err("Insufficient len for total no.of %u fields",
749 			 field_info->count);
750 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
751 	}
752 
753 	req->field_info_buf = field_info;
754 	req->field_info_buf_len = nl_field_info_size;
755 
756 	return 0;
757 }
758 
759 
760 static int  wifi_pos_parse_req(const void *data, int len, int pid,
761 		    struct wifi_pos_req_msg *req)
762 {
763 	int status = 0;
764 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
765 
766 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
767 		osif_err("invalid data in request");
768 		return OEM_ERR_INVALID_MESSAGE_TYPE;
769 	}
770 
771 	if (tb[CLD80211_ATTR_DATA]) {
772 		status = wifi_pos_parse_ani_req(data, len, pid, req);
773 	} else if (tb[CLD80211_ATTR_CMD]) {
774 		status = wifi_pos_parse_nla_req(data, len, pid, req);
775 	} else {
776 		osif_err("Valid CLD80211 ATTR not present");
777 		return OEM_ERR_INVALID_MESSAGE_TYPE;
778 	}
779 	return status;
780 }
781 #else
782 static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req,
783 			      struct wlan_objmgr_psoc **psoc)
784 {
785 	/* SKB->data contains NL msg */
786 	/* NLMSG_DATA(nlh) contains ANI msg */
787 	struct nlmsghdr *nlh;
788 	tAniMsgHdr *msg_hdr;
789 	size_t field_info_len;
790 	int interface_len;
791 	char *interface = NULL;
792 	uint8_t pdev_id = 0;
793 	uint32_t tgt_pdev_id = 0;
794 	uint8_t i;
795 	uint32_t offset;
796 	QDF_STATUS status;
797 
798 	nlh = (struct nlmsghdr *)skb->data;
799 	if (!nlh) {
800 		osif_err("Netlink header null");
801 		return OEM_ERR_NULL_MESSAGE_HEADER;
802 	}
803 
804 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr))) {
805 		osif_err("nlmsg_len(%d) and msg_hdr_size(%zu) mismatch",
806 			 nlh->nlmsg_len, sizeof(*msg_hdr));
807 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
808 	}
809 
810 	msg_hdr = NLMSG_DATA(nlh);
811 	if (!msg_hdr) {
812 		osif_err("Message header null");
813 		return OEM_ERR_NULL_MESSAGE_HEADER;
814 	}
815 
816 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length)) {
817 		osif_err("nlmsg_len(%d) and animsg_len(%d) mismatch",
818 			 nlh->nlmsg_len, msg_hdr->length);
819 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
820 	}
821 
822 	req->msg_type = map_ani_msg_req_to_wifi_pos_cmd(
823 				(uint32_t)msg_hdr->type);
824 	req->rsp_version = WIFI_POS_RSP_V1_FLAT_MEMORY;
825 	req->buf_len = msg_hdr->length;
826 	req->buf = (uint8_t *)&msg_hdr[1];
827 	req->pid = nlh->nlmsg_pid;
828 	req->field_info_buf = NULL;
829 	req->field_info_buf_len = 0;
830 
831 	field_info_len = nlh->nlmsg_len -
832 		(NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length +
833 			      sizeof(struct wifi_pos_interface)));
834 	if (field_info_len) {
835 		req->field_info_buf =
836 			(struct wifi_pos_field_info *)(req->buf + req->buf_len);
837 		req->field_info_buf_len = sizeof(struct wifi_pos_field_info);
838 	}
839 
840 	interface_len = nlh->nlmsg_len -
841 		(NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length +
842 			      req->field_info_buf_len));
843 
844 	if (interface_len) {
845 		interface = (char *)(req->buf + req->buf_len +
846 				     req->field_info_buf_len);
847 		req->interface.length = *interface;
848 
849 		if (req->interface.length > sizeof(req->interface.dev_name)) {
850 			osif_err("interface length exceeds array length");
851 			return OEM_ERR_INVALID_MESSAGE_LENGTH;
852 		}
853 
854 		qdf_mem_copy(req->interface.dev_name,
855 			     (interface + sizeof(uint8_t)),
856 			     req->interface.length);
857 
858 		status = ucfg_wifi_psoc_get_pdev_id_by_dev_name(
859 				req->interface.dev_name, &pdev_id, psoc);
860 		if (QDF_IS_STATUS_ERROR(status)) {
861 			osif_err("failed to get pdev_id and psoc");
862 			return OEM_ERR_NULL_CONTEXT;
863 		}
864 
865 		status = wifi_pos_convert_host_pdev_id_to_target(
866 				*psoc, pdev_id, &tgt_pdev_id);
867 		if (QDF_IS_STATUS_ERROR(status)) {
868 			osif_err("failed to get target pdev_id");
869 			return OEM_ERR_NULL_CONTEXT;
870 		}
871 
872 		for (i = 0;
873 		     (req->field_info_buf && (i < req->field_info_buf->count));
874 		     i++) {
875 			if (req->field_info_buf->fields[i].id ==
876 					META_DATA_PDEV) {
877 				offset = req->field_info_buf->fields[i].offset;
878 				*((uint32_t *)&req->buf[offset]) = tgt_pdev_id;
879 			}
880 		}
881 	}
882 
883 	return 0;
884 }
885 #endif
886 
887 /**
888  * __os_if_wifi_pos_callback() - callback registered with NL service socket to
889  * process wifi pos request
890  * @skb: request message sk_buff
891  *
892  * Return: status of operation
893  */
894 #ifdef CNSS_GENL
895 static void __os_if_wifi_pos_callback(const void *data, int data_len,
896 				      void *ctx, int pid)
897 {
898 	uint8_t err;
899 	QDF_STATUS status;
900 	struct wifi_pos_req_msg req = {0};
901 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
902 
903 	osif_debug("enter: pid %d", pid);
904 	if (!psoc) {
905 		osif_err("global psoc object not registered yet.");
906 		return;
907 	}
908 
909 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
910 	err = wifi_pos_parse_req(data, data_len, pid, &req);
911 	if (err) {
912 		os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
913 					WIFI_POS_CMD_ERROR, sizeof(err), &err);
914 		status = QDF_STATUS_E_INVAL;
915 		goto release_psoc_ref;
916 	}
917 
918 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
919 	if (QDF_IS_STATUS_ERROR(status))
920 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
921 			 status);
922 
923 release_psoc_ref:
924 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
925 }
926 
927 static void os_if_wifi_pos_callback(const void *data, int data_len,
928 				    void *ctx, int pid)
929 {
930 	struct qdf_op_sync *op_sync;
931 
932 	if (qdf_op_protect(&op_sync))
933 		return;
934 
935 	__os_if_wifi_pos_callback(data, data_len, ctx, pid);
936 	qdf_op_unprotect(op_sync);
937 }
938 #else
939 static int __os_if_wifi_pos_callback(struct sk_buff *skb)
940 {
941 	uint8_t err;
942 	QDF_STATUS status;
943 	struct wifi_pos_req_msg req = {0};
944 	struct wlan_objmgr_psoc *psoc = NULL;
945 
946 	osif_debug("enter");
947 
948 	err = wifi_pos_parse_req(skb, &req, &psoc);
949 	if (err) {
950 		osif_err("wifi_pos_parse_req failed");
951 		return -EINVAL;
952 	}
953 
954 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
955 
956 	if (err) {
957 		os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
958 					WIFI_POS_CMD_ERROR, sizeof(err), &err);
959 		status = QDF_STATUS_E_INVAL;
960 		goto release_psoc_ref;
961 	}
962 
963 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
964 	if (QDF_IS_STATUS_ERROR(status))
965 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
966 			 status);
967 
968 release_psoc_ref:
969 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
970 
971 	return qdf_status_to_os_return(status);
972 }
973 
974 static int os_if_wifi_pos_callback(struct sk_buff *skb)
975 {
976 	struct qdf_op_sync *op_sync;
977 	int err;
978 
979 	if (qdf_op_protect(&op_sync))
980 		return -EINVAL;
981 
982 	err = __os_if_wifi_pos_callback(skb);
983 	qdf_op_unprotect(op_sync);
984 
985 	return err;
986 }
987 #endif
988 
989 #ifdef CNSS_GENL
990 int os_if_wifi_pos_register_nl(void)
991 {
992 	int ret = register_cld_cmd_cb(WLAN_NL_MSG_OEM,
993 				os_if_wifi_pos_callback, NULL);
994 	if (ret)
995 		osif_err("register_cld_cmd_cb failed");
996 
997 	return ret;
998 }
999 #else
1000 int os_if_wifi_pos_register_nl(void)
1001 {
1002 	return nl_srv_register(WLAN_NL_MSG_OEM, os_if_wifi_pos_callback);
1003 }
1004 #endif /* CNSS_GENL */
1005 qdf_export_symbol(os_if_wifi_pos_register_nl);
1006 
1007 #ifdef CNSS_GENL
1008 int os_if_wifi_pos_deregister_nl(void)
1009 {
1010 	int ret = deregister_cld_cmd_cb(WLAN_NL_MSG_OEM);
1011 	if (ret)
1012 		osif_err("deregister_cld_cmd_cb failed");
1013 
1014 	return ret;
1015 }
1016 #else
1017 int os_if_wifi_pos_deregister_nl(void)
1018 {
1019 	return 0;
1020 }
1021 #endif /* CNSS_GENL */
1022 
1023 void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac,
1024 				uint8_t peer_status,
1025 				uint8_t peer_timing_meas_cap,
1026 				uint8_t session_id,
1027 				struct wifi_pos_ch_info *chan_info,
1028 				enum QDF_OPMODE dev_mode)
1029 {
1030 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
1031 	struct wifi_pos_peer_status_info *peer_info;
1032 
1033 	if (!psoc) {
1034 		osif_err("global wifi_pos psoc object not registered");
1035 		return;
1036 	}
1037 
1038 	if (!wifi_pos_is_app_registered(psoc) ||
1039 			wifi_pos_get_app_pid(psoc) == 0) {
1040 		osif_debug("app is not registered or pid is invalid");
1041 		return;
1042 	}
1043 
1044 	peer_info = qdf_mem_malloc(sizeof(*peer_info));
1045 	if (!peer_info)
1046 		return;
1047 
1048 	qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes,
1049 		     sizeof(peer_mac->bytes));
1050 	peer_info->peer_status = peer_status;
1051 	peer_info->vdev_id = session_id;
1052 	peer_info->peer_capability = peer_timing_meas_cap;
1053 	peer_info->reserved0 = 0;
1054 	/* Set 0th bit of reserved0 for STA mode */
1055 	if (QDF_STA_MODE == dev_mode)
1056 		peer_info->reserved0 |= 0x01;
1057 
1058 	if (chan_info) {
1059 		peer_info->peer_chan_info.chan_id = chan_info->chan_id;
1060 		peer_info->peer_chan_info.reserved0 = 0;
1061 		peer_info->peer_chan_info.mhz = chan_info->mhz;
1062 		peer_info->peer_chan_info.band_center_freq1 =
1063 			chan_info->band_center_freq1;
1064 		peer_info->peer_chan_info.band_center_freq2 =
1065 			chan_info->band_center_freq2;
1066 		peer_info->peer_chan_info.info = chan_info->info;
1067 		peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
1068 		peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
1069 	}
1070 
1071 	os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
1072 				WIFI_POS_PEER_STATUS_IND,
1073 				sizeof(*peer_info), (uint8_t *)peer_info);
1074 	qdf_mem_free(peer_info);
1075 }
1076 
1077 int os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
1078 				   struct wifi_pos_driver_caps *caps)
1079 {
1080 	if (!psoc || !caps) {
1081 		osif_err("psoc or caps buffer is null");
1082 		return -EINVAL;
1083 	}
1084 
1085 	return qdf_status_to_os_return(wifi_pos_populate_caps(psoc, caps));
1086 }
1087 
1088 #if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT)
1089 QDF_STATUS
1090 os_if_wifi_pos_initiate_pasn_auth(struct wlan_objmgr_vdev *vdev,
1091 				  struct wlan_pasn_request *pasn_peer,
1092 				  uint8_t num_pasn_peers,
1093 				  bool is_initiate_pasn)
1094 {
1095 	struct net_device *netdev;
1096 	struct vdev_osif_priv *osif_priv;
1097 	struct sk_buff *skb;
1098 	struct nlattr *attr, *nest_attr;
1099 	enum qca_wlan_vendor_pasn_action action;
1100 	int i;
1101 	int index = QCA_NL80211_VENDOR_SUBCMD_PASN_AUTH_STATUS_INDEX;
1102 	uint16_t record_size;
1103 	uint32_t len;
1104 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1105 
1106 	osif_priv  = wlan_vdev_get_ospriv(vdev);
1107 	if (!osif_priv) {
1108 		osif_err("OSIF priv is NULL");
1109 		return QDF_STATUS_E_FAILURE;
1110 	}
1111 
1112 	netdev = osif_priv->wdev->netdev;
1113 
1114 	len = NLMSG_HDRLEN;
1115 	/* QCA_WLAN_VENDOR_ATTR_PASN_ACTION */
1116 	len += nla_total_size(sizeof(u32));
1117 
1118 	/*
1119 	 * size of nest containing
1120 	 * QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR
1121 	 * QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR
1122 	 */
1123 	record_size = nla_total_size(2 * nla_total_size(ETH_ALEN));
1124 
1125 	/* QCA_WLAN_VENDOR_ATTR_PASN_PEERS nest */
1126 	len += nla_total_size(num_pasn_peers * record_size);
1127 
1128 	skb = wlan_cfg80211_vendor_event_alloc(osif_priv->wdev->wiphy,
1129 					       osif_priv->wdev, len,
1130 					       index, GFP_ATOMIC);
1131 	if (!skb)
1132 		return QDF_STATUS_E_NOMEM;
1133 
1134 	action = is_initiate_pasn ?
1135 		 QCA_WLAN_VENDOR_PASN_ACTION_AUTH :
1136 		 QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT;
1137 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_PASN_ACTION, action)) {
1138 		osif_err("NLA put failed");
1139 		goto nla_put_failure;
1140 	}
1141 
1142 	attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEERS);
1143 	if (!attr) {
1144 		osif_err("NLA nest failed");
1145 		status = QDF_STATUS_E_FAILURE;
1146 		goto nla_put_failure;
1147 	}
1148 
1149 	for (i = 0; i < num_pasn_peers; i++) {
1150 		osif_debug("PASN peer_mac[%d]: " QDF_MAC_ADDR_FMT " src_mac: " QDF_MAC_ADDR_FMT,
1151 			   i, QDF_MAC_ADDR_REF(pasn_peer[i].peer_mac.bytes),
1152 			   QDF_MAC_ADDR_REF(pasn_peer[i].self_mac.bytes));
1153 		nest_attr = nla_nest_start(skb, i);
1154 		if (!nest_attr) {
1155 			osif_err("NLA nest failed for iter:%d", i);
1156 			status = QDF_STATUS_E_FAILURE;
1157 			goto nla_put_failure;
1158 		}
1159 
1160 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR,
1161 			    ETH_ALEN, pasn_peer[i].peer_mac.bytes)) {
1162 			osif_err("NLA put failed");
1163 			status = QDF_STATUS_E_FAILURE;
1164 			goto nla_put_failure;
1165 		}
1166 
1167 		if (!qdf_is_macaddr_zero(&pasn_peer[i].self_mac) &&
1168 		    nla_put(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR,
1169 			    ETH_ALEN, pasn_peer[i].self_mac.bytes)) {
1170 			osif_err("NLA put failed");
1171 			status = QDF_STATUS_E_FAILURE;
1172 			goto nla_put_failure;
1173 		}
1174 
1175 		nla_nest_end(skb, nest_attr);
1176 	}
1177 	nla_nest_end(skb, attr);
1178 
1179 	osif_debug("action:%d num_pasn_peers:%d", action, num_pasn_peers);
1180 
1181 	wlan_cfg80211_vendor_event(skb, GFP_ATOMIC);
1182 
1183 	return status;
1184 
1185 nla_put_failure:
1186 	wlan_cfg80211_vendor_free_skb(skb);
1187 
1188 	return status;
1189 }
1190 #endif /* WIFI_POS_CONVERGED && WLAN_FEATURE_RTT_11AZ_SUPPORT */
1191