1 /*
2  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-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 /**
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 
map_wifi_pos_cmd_to_ani_msg_rsp(enum wifi_pos_cmd_ids cmd)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
map_ani_msg_req_to_wifi_pos_cmd(uint32_t cmd)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
map_cld_vendor_sub_cmd_to_wifi_pos_cmd(enum cld80211_vendor_sub_cmds cmd)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
map_wifi_pos_cmd_to_cld_vendor_sub_cmd(enum wifi_pos_cmd_ids cmd)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 
os_if_wifi_pos_send_peer_nl_status(uint32_t pid,uint8_t * buf)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 
os_if_send_cap_nl_resp(uint32_t pid,uint8_t * buf)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
os_if_get_chan_nl_resp_len(uint32_t * chan_info,uint32_t * attr_headers)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 
os_if_get_max_chan_nl_resp(uint8_t chan_num)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
os_if_create_ch_nl_resp(uint32_t pid,uint8_t * buf,uint16_t num_chan,bool is_frag)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 
os_if_send_chan_nl_resp(uint32_t pid,uint8_t * buf)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
os_if_create_oemdata_resp(uint32_t pid,uint8_t * buf,bool frag_resp,uint32_t chnk_len)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
os_if_send_oem_data_nl_resp(uint32_t pid,uint8_t * buf,uint32_t buf_len)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 
os_if_send_nl_resp(uint32_t pid,uint8_t * buf,enum wifi_pos_cmd_ids cmd,uint32_t len)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
os_if_send_nl_resp(uint32_t pid,uint8_t * buf,enum wifi_pos_cmd_ids cmd,uint32_t len)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  * @psoc: soc object
577  * @pid: registering process ID
578  * @cmd: OEM command
579  * @buf_len: length of the OEM message in @buf
580  * @buf: OEM message
581  *
582  * This function sends oem message to registered application process
583  *
584  * Return:  none
585  */
os_if_wifi_pos_send_rsp(struct wlan_objmgr_psoc * psoc,uint32_t pid,enum wifi_pos_cmd_ids cmd,uint32_t buf_len,uint8_t * buf)586 static void os_if_wifi_pos_send_rsp(struct wlan_objmgr_psoc *psoc, uint32_t pid,
587 				    enum wifi_pos_cmd_ids cmd, uint32_t buf_len,
588 				    uint8_t *buf)
589 {
590 	tAniMsgHdr *aniHdr;
591 	struct sk_buff *skb = NULL;
592 	struct nlmsghdr *nlh;
593 
594 	/* OEM msg is always to a specific process and cannot be a broadcast */
595 	if (pid == 0) {
596 		osif_err("invalid dest pid");
597 		return;
598 	}
599 
600 	if (ucfg_wifi_pos_is_nl_rsp(psoc)) {
601 		os_if_send_nl_resp(pid, buf, cmd, buf_len);
602 	} else {
603 		skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len),
604 				GFP_ATOMIC);
605 		if (!skb) {
606 			osif_alert("alloc_skb failed");
607 			return;
608 		}
609 
610 		nlh = (struct nlmsghdr *)skb->data;
611 		nlh->nlmsg_pid = 0;     /* from kernel */
612 		nlh->nlmsg_flags = 0;
613 		nlh->nlmsg_seq = 0;
614 		nlh->nlmsg_type = WLAN_NL_MSG_OEM;
615 		nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + buf_len);
616 
617 		aniHdr = NLMSG_DATA(nlh);
618 		aniHdr->type = map_wifi_pos_cmd_to_ani_msg_rsp(cmd);
619 		qdf_mem_copy(&aniHdr[1], buf, buf_len);
620 		aniHdr->length = buf_len;
621 
622 		skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len));
623 		osif_debug("sending oem rsp: type: %d len(%d) to pid (%d)",
624 			   aniHdr->type, buf_len, pid);
625 		nl_srv_ucast_oem(skb, pid, MSG_DONTWAIT);
626 	}
627 }
628 
629 #ifdef CNSS_GENL
630 static int
wifi_pos_parse_nla_oemdata_req(uint32_t len,uint8_t * buf,struct wifi_pos_req_msg * req)631 wifi_pos_parse_nla_oemdata_req(uint32_t len, uint8_t *buf,
632 			       struct wifi_pos_req_msg *req)
633 {
634 	struct nlattr *tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX + 1];
635 
636 	if (wlan_cfg80211_nla_parse(tb_oem_data,
637 				    CLD80211_SUB_ATTR_MSG_OEM_DATA_REQ_MAX,
638 				    (struct nlattr *)buf, len, NULL)) {
639 		osif_err("invalid data in request");
640 		return OEM_ERR_INVALID_MESSAGE_TYPE;
641 	}
642 
643 	if (!tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]) {
644 		osif_err("CLD80211_SUB_ATTR_MSG_OEM_DATA_FW not present");
645 		return OEM_ERR_INVALID_MESSAGE_TYPE;
646 	}
647 	req->buf_len = nla_len(
648 				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
649 	req->buf = nla_data(
650 				tb_oem_data[CLD80211_SUB_ATTR_MSG_OEM_DATA_FW]);
651 
652 	return 0;
653 }
654 
wifi_pos_parse_nla_req(const void * data,int len,int pid,struct wifi_pos_req_msg * req)655 static int  wifi_pos_parse_nla_req(const void *data, int len, int pid,
656 		    struct wifi_pos_req_msg *req)
657 {
658 	uint8_t *msg;
659 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
660 	uint32_t msg_len;
661 
662 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
663 		osif_err("invalid data in request");
664 		return OEM_ERR_INVALID_MESSAGE_TYPE;
665 	}
666 
667 	req->pid = pid;
668 	req->msg_type = map_cld_vendor_sub_cmd_to_wifi_pos_cmd(
669 				nla_get_u32(tb[CLD80211_ATTR_CMD]));
670 	req->rsp_version = WIFI_POS_RSP_V2_NL;
671 
672 	if (tb[CLD80211_ATTR_CMD_TAG_DATA]) {
673 		msg_len = nla_len(tb[CLD80211_ATTR_CMD_TAG_DATA]);
674 		msg = nla_data(tb[CLD80211_ATTR_CMD_TAG_DATA]);
675 
676 		if (req->msg_type == WIFI_POS_CMD_OEM_DATA) {
677 			if (wifi_pos_parse_nla_oemdata_req(msg_len, msg, req)) {
678 				osif_err("parsing oemdata req failed");
679 				return OEM_ERR_INVALID_MESSAGE_LENGTH;
680 			}
681 		} else {
682 			req->buf_len = msg_len;
683 			req->buf = msg;
684 		}
685 	}
686 	if (tb[CLD80211_ATTR_META_DATA])
687 		osif_err("meta data dropped. Apps can use CLD80211_ATTR_CMD_TAG_DATA sub attrs");
688 
689 	return 0;
690 }
691 
wifi_pos_parse_ani_req(const void * data,int len,int pid,struct wifi_pos_req_msg * req)692 static int  wifi_pos_parse_ani_req(const void *data, int len, int pid,
693 		    struct wifi_pos_req_msg *req)
694 {
695 	tAniMsgHdr *msg_hdr;
696 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
697 	uint32_t msg_len, id, nl_field_info_size, expected_field_info_size;
698 	struct wifi_pos_field_info *field_info;
699 
700 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
701 		osif_err("invalid data in request");
702 		return OEM_ERR_INVALID_MESSAGE_TYPE;
703 	}
704 
705 	msg_len = nla_len(tb[CLD80211_ATTR_DATA]);
706 	if (msg_len < sizeof(*msg_hdr)) {
707 		osif_err("Insufficient length for msg_hdr: %u", msg_len);
708 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
709 	}
710 
711 	msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]);
712 	req->msg_type = map_ani_msg_req_to_wifi_pos_cmd(
713 				(uint32_t)msg_hdr->type);
714 	req->rsp_version = WIFI_POS_RSP_V1_FLAT_MEMORY;
715 
716 	if (msg_len < sizeof(*msg_hdr) + msg_hdr->length) {
717 		osif_err("Insufficient length for msg_hdr buffer: %u",
718 			 msg_len);
719 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
720 	}
721 
722 	req->buf_len = msg_hdr->length;
723 	req->buf = (uint8_t *)&msg_hdr[1];
724 	req->pid = pid;
725 
726 	id = CLD80211_ATTR_META_DATA;
727 	if (!tb[id])
728 		return 0;
729 
730 	nl_field_info_size = nla_len(tb[id]);
731 	if (nl_field_info_size < sizeof(*field_info)) {
732 		osif_err("Insufficient length for field_info_buf: %u",
733 			 nl_field_info_size);
734 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
735 	}
736 
737 	field_info = nla_data(tb[id]);
738 	if (!field_info->count) {
739 		osif_debug("field_info->count is zero, ignoring META_DATA");
740 		return 0;
741 	}
742 
743 	if ((field_info->count - 1) >
744 	    ((UINT_MAX - sizeof(*field_info)) /
745 	    sizeof(struct wifi_pos_field))) {
746 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
747 	}
748 
749 	expected_field_info_size = sizeof(*field_info) +
750 		(field_info->count - 1) * sizeof(struct wifi_pos_field);
751 
752 	if (nl_field_info_size < expected_field_info_size) {
753 		osif_err("Insufficient len for total no.of %u fields",
754 			 field_info->count);
755 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
756 	}
757 
758 	req->field_info_buf = field_info;
759 	req->field_info_buf_len = nl_field_info_size;
760 
761 	return 0;
762 }
763 
764 
wifi_pos_parse_req(const void * data,int len,int pid,struct wifi_pos_req_msg * req)765 static int  wifi_pos_parse_req(const void *data, int len, int pid,
766 		    struct wifi_pos_req_msg *req)
767 {
768 	int status = 0;
769 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
770 
771 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
772 		osif_err("invalid data in request");
773 		return OEM_ERR_INVALID_MESSAGE_TYPE;
774 	}
775 
776 	if (tb[CLD80211_ATTR_DATA]) {
777 		status = wifi_pos_parse_ani_req(data, len, pid, req);
778 	} else if (tb[CLD80211_ATTR_CMD]) {
779 		status = wifi_pos_parse_nla_req(data, len, pid, req);
780 	} else {
781 		osif_err("Valid CLD80211 ATTR not present");
782 		return OEM_ERR_INVALID_MESSAGE_TYPE;
783 	}
784 	return status;
785 }
786 #else
wifi_pos_parse_req(struct sk_buff * skb,struct wifi_pos_req_msg * req,struct wlan_objmgr_psoc ** psoc)787 static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req,
788 			      struct wlan_objmgr_psoc **psoc)
789 {
790 	/* SKB->data contains NL msg */
791 	/* NLMSG_DATA(nlh) contains ANI msg */
792 	struct nlmsghdr *nlh;
793 	tAniMsgHdr *msg_hdr;
794 	size_t field_info_len;
795 	int interface_len;
796 	char *interface = NULL;
797 	uint8_t pdev_id = 0;
798 	uint32_t tgt_pdev_id = 0;
799 	uint8_t i;
800 	uint32_t offset;
801 	QDF_STATUS status;
802 
803 	nlh = (struct nlmsghdr *)skb->data;
804 	if (!nlh) {
805 		osif_err("Netlink header null");
806 		return OEM_ERR_NULL_MESSAGE_HEADER;
807 	}
808 
809 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr))) {
810 		osif_err("nlmsg_len(%d) and msg_hdr_size(%zu) mismatch",
811 			 nlh->nlmsg_len, sizeof(*msg_hdr));
812 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
813 	}
814 
815 	msg_hdr = NLMSG_DATA(nlh);
816 	if (!msg_hdr) {
817 		osif_err("Message header null");
818 		return OEM_ERR_NULL_MESSAGE_HEADER;
819 	}
820 
821 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length)) {
822 		osif_err("nlmsg_len(%d) and animsg_len(%d) mismatch",
823 			 nlh->nlmsg_len, msg_hdr->length);
824 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
825 	}
826 
827 	req->msg_type = map_ani_msg_req_to_wifi_pos_cmd(
828 				(uint32_t)msg_hdr->type);
829 	req->rsp_version = WIFI_POS_RSP_V1_FLAT_MEMORY;
830 	req->buf_len = msg_hdr->length;
831 	req->buf = (uint8_t *)&msg_hdr[1];
832 	req->pid = nlh->nlmsg_pid;
833 	req->field_info_buf = NULL;
834 	req->field_info_buf_len = 0;
835 
836 	field_info_len = nlh->nlmsg_len -
837 		(NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length +
838 			      sizeof(struct wifi_pos_interface)));
839 	if (field_info_len) {
840 		req->field_info_buf =
841 			(struct wifi_pos_field_info *)(req->buf + req->buf_len);
842 		req->field_info_buf_len = sizeof(struct wifi_pos_field_info);
843 	}
844 
845 	interface_len = nlh->nlmsg_len -
846 		(NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length +
847 			      req->field_info_buf_len));
848 
849 	if (interface_len) {
850 		interface = (char *)(req->buf + req->buf_len +
851 				     req->field_info_buf_len);
852 		req->interface.length = *interface;
853 
854 		if (req->interface.length > sizeof(req->interface.dev_name)) {
855 			osif_err("interface length exceeds array length");
856 			return OEM_ERR_INVALID_MESSAGE_LENGTH;
857 		}
858 
859 		qdf_mem_copy(req->interface.dev_name,
860 			     (interface + sizeof(uint8_t)),
861 			     req->interface.length);
862 
863 		status = ucfg_wifi_psoc_get_pdev_id_by_dev_name(
864 				req->interface.dev_name, &pdev_id, psoc);
865 		if (QDF_IS_STATUS_ERROR(status)) {
866 			osif_err("failed to get pdev_id and psoc");
867 			return OEM_ERR_NULL_CONTEXT;
868 		}
869 
870 		status = wifi_pos_convert_host_pdev_id_to_target(
871 				*psoc, pdev_id, &tgt_pdev_id);
872 		if (QDF_IS_STATUS_ERROR(status)) {
873 			osif_err("failed to get target pdev_id");
874 			return OEM_ERR_NULL_CONTEXT;
875 		}
876 
877 		for (i = 0;
878 		     (req->field_info_buf && (i < req->field_info_buf->count));
879 		     i++) {
880 			if (req->field_info_buf->fields[i].id ==
881 					META_DATA_PDEV) {
882 				offset = req->field_info_buf->fields[i].offset;
883 				*((uint32_t *)&req->buf[offset]) = tgt_pdev_id;
884 			}
885 		}
886 	}
887 
888 	return 0;
889 }
890 #endif
891 
892 #ifdef CNSS_GENL
893 /**
894  * __os_if_wifi_pos_callback() - callback registered with NL service socket to
895  * process wifi pos request
896  * @data: request message buffer
897  * @data_len: length of @data
898  * @ctx: context registered with the dispatcher (unused)
899  * @pid: caller process ID
900  *
901  * Return: status of operation
902  */
__os_if_wifi_pos_callback(const void * data,int data_len,void * ctx,int pid)903 static void __os_if_wifi_pos_callback(const void *data, int data_len,
904 				      void *ctx, int pid)
905 {
906 	uint8_t err;
907 	QDF_STATUS status;
908 	struct wifi_pos_req_msg req = {0};
909 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
910 
911 	osif_debug("enter: pid %d", pid);
912 	if (!psoc) {
913 		osif_err("global psoc object not registered yet.");
914 		return;
915 	}
916 
917 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
918 	err = wifi_pos_parse_req(data, data_len, pid, &req);
919 	if (err) {
920 		os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
921 					WIFI_POS_CMD_ERROR, sizeof(err), &err);
922 		status = QDF_STATUS_E_INVAL;
923 		goto release_psoc_ref;
924 	}
925 
926 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
927 	if (QDF_IS_STATUS_ERROR(status))
928 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
929 			 status);
930 
931 release_psoc_ref:
932 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
933 }
934 
os_if_wifi_pos_callback(const void * data,int data_len,void * ctx,int pid)935 static void os_if_wifi_pos_callback(const void *data, int data_len,
936 				    void *ctx, int pid)
937 {
938 	struct qdf_op_sync *op_sync;
939 
940 	if (qdf_op_protect(&op_sync))
941 		return;
942 
943 	__os_if_wifi_pos_callback(data, data_len, ctx, pid);
944 	qdf_op_unprotect(op_sync);
945 }
946 #else
947 /**
948  * __os_if_wifi_pos_callback() - callback registered with NL service socket to
949  * process wifi pos request
950  * @skb: request message sk_buff
951  *
952  * Return: status of operation
953  */
__os_if_wifi_pos_callback(struct sk_buff * skb)954 static int __os_if_wifi_pos_callback(struct sk_buff *skb)
955 {
956 	uint8_t err;
957 	QDF_STATUS status;
958 	struct wifi_pos_req_msg req = {0};
959 	struct wlan_objmgr_psoc *psoc = NULL;
960 
961 	osif_debug("enter");
962 
963 	err = wifi_pos_parse_req(skb, &req, &psoc);
964 	if (err) {
965 		osif_err("wifi_pos_parse_req failed");
966 		return -EINVAL;
967 	}
968 
969 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
970 
971 	if (err) {
972 		os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
973 					WIFI_POS_CMD_ERROR, sizeof(err), &err);
974 		status = QDF_STATUS_E_INVAL;
975 		goto release_psoc_ref;
976 	}
977 
978 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
979 	if (QDF_IS_STATUS_ERROR(status))
980 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
981 			 status);
982 
983 release_psoc_ref:
984 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
985 
986 	return qdf_status_to_os_return(status);
987 }
988 
os_if_wifi_pos_callback(struct sk_buff * skb)989 static int os_if_wifi_pos_callback(struct sk_buff *skb)
990 {
991 	struct qdf_op_sync *op_sync;
992 	int err;
993 
994 	if (qdf_op_protect(&op_sync))
995 		return -EINVAL;
996 
997 	err = __os_if_wifi_pos_callback(skb);
998 	qdf_op_unprotect(op_sync);
999 
1000 	return err;
1001 }
1002 #endif
1003 
1004 #ifdef CNSS_GENL
os_if_wifi_pos_register_nl(void)1005 int os_if_wifi_pos_register_nl(void)
1006 {
1007 	int ret = register_cld_cmd_cb(WLAN_NL_MSG_OEM,
1008 				os_if_wifi_pos_callback, NULL);
1009 	if (ret)
1010 		osif_err("register_cld_cmd_cb failed");
1011 
1012 	return ret;
1013 }
1014 #else
os_if_wifi_pos_register_nl(void)1015 int os_if_wifi_pos_register_nl(void)
1016 {
1017 	return nl_srv_register(WLAN_NL_MSG_OEM, os_if_wifi_pos_callback);
1018 }
1019 #endif /* CNSS_GENL */
1020 qdf_export_symbol(os_if_wifi_pos_register_nl);
1021 
1022 #ifdef CNSS_GENL
os_if_wifi_pos_deregister_nl(void)1023 int os_if_wifi_pos_deregister_nl(void)
1024 {
1025 	int ret = deregister_cld_cmd_cb(WLAN_NL_MSG_OEM);
1026 	if (ret)
1027 		osif_err("deregister_cld_cmd_cb failed");
1028 
1029 	return ret;
1030 }
1031 #else
os_if_wifi_pos_deregister_nl(void)1032 int os_if_wifi_pos_deregister_nl(void)
1033 {
1034 	return 0;
1035 }
1036 #endif /* CNSS_GENL */
1037 
os_if_wifi_pos_send_peer_status(struct qdf_mac_addr * peer_mac,uint8_t peer_status,uint8_t peer_timing_meas_cap,uint8_t session_id,struct wifi_pos_ch_info * chan_info,enum QDF_OPMODE dev_mode)1038 void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac,
1039 				uint8_t peer_status,
1040 				uint8_t peer_timing_meas_cap,
1041 				uint8_t session_id,
1042 				struct wifi_pos_ch_info *chan_info,
1043 				enum QDF_OPMODE dev_mode)
1044 {
1045 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
1046 	struct wifi_pos_peer_status_info *peer_info;
1047 
1048 	if (!psoc) {
1049 		osif_err("global wifi_pos psoc object not registered");
1050 		return;
1051 	}
1052 
1053 	if (!wifi_pos_is_app_registered(psoc) ||
1054 			wifi_pos_get_app_pid(psoc) == 0) {
1055 		osif_debug("app is not registered or pid is invalid");
1056 		return;
1057 	}
1058 
1059 	peer_info = qdf_mem_malloc(sizeof(*peer_info));
1060 	if (!peer_info)
1061 		return;
1062 
1063 	qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes,
1064 		     sizeof(peer_mac->bytes));
1065 	peer_info->peer_status = peer_status;
1066 	peer_info->vdev_id = session_id;
1067 	peer_info->peer_capability = peer_timing_meas_cap;
1068 	peer_info->reserved0 = 0;
1069 	/* Set 0th bit of reserved0 for STA mode */
1070 	if (QDF_STA_MODE == dev_mode)
1071 		peer_info->reserved0 |= 0x01;
1072 
1073 	if (chan_info) {
1074 		peer_info->peer_chan_info.chan_id = chan_info->chan_id;
1075 		peer_info->peer_chan_info.reserved0 = 0;
1076 		peer_info->peer_chan_info.mhz = chan_info->mhz;
1077 		peer_info->peer_chan_info.band_center_freq1 =
1078 			chan_info->band_center_freq1;
1079 		peer_info->peer_chan_info.band_center_freq2 =
1080 			chan_info->band_center_freq2;
1081 		peer_info->peer_chan_info.info = chan_info->info;
1082 		peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
1083 		peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
1084 	}
1085 
1086 	os_if_wifi_pos_send_rsp(psoc, wifi_pos_get_app_pid(psoc),
1087 				WIFI_POS_PEER_STATUS_IND,
1088 				sizeof(*peer_info), (uint8_t *)peer_info);
1089 	qdf_mem_free(peer_info);
1090 }
1091 
os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc * psoc,struct wifi_pos_driver_caps * caps)1092 int os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
1093 				   struct wifi_pos_driver_caps *caps)
1094 {
1095 	if (!psoc || !caps) {
1096 		osif_err("psoc or caps buffer is null");
1097 		return -EINVAL;
1098 	}
1099 
1100 	return qdf_status_to_os_return(wifi_pos_populate_caps(psoc, caps));
1101 }
1102 
1103 #if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT)
1104 QDF_STATUS
os_if_wifi_pos_initiate_pasn_auth(struct wlan_objmgr_vdev * vdev,struct wlan_pasn_request * pasn_peer,uint8_t num_pasn_peers,bool is_initiate_pasn)1105 os_if_wifi_pos_initiate_pasn_auth(struct wlan_objmgr_vdev *vdev,
1106 				  struct wlan_pasn_request *pasn_peer,
1107 				  uint8_t num_pasn_peers,
1108 				  bool is_initiate_pasn)
1109 {
1110 	struct net_device *netdev;
1111 	struct vdev_osif_priv *osif_priv;
1112 	struct sk_buff *skb;
1113 	struct nlattr *attr, *nest_attr;
1114 	enum qca_wlan_vendor_pasn_action action;
1115 	int i;
1116 	int index = QCA_NL80211_VENDOR_SUBCMD_PASN_AUTH_STATUS_INDEX;
1117 	uint16_t record_size;
1118 	uint32_t len;
1119 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1120 
1121 	osif_priv  = wlan_vdev_get_ospriv(vdev);
1122 	if (!osif_priv) {
1123 		osif_err("OSIF priv is NULL");
1124 		return QDF_STATUS_E_FAILURE;
1125 	}
1126 
1127 	netdev = osif_priv->wdev->netdev;
1128 
1129 	len = NLMSG_HDRLEN;
1130 	/* QCA_WLAN_VENDOR_ATTR_PASN_ACTION */
1131 	len += nla_total_size(sizeof(u32));
1132 
1133 	/*
1134 	 * size of nest containing
1135 	 * QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR
1136 	 * QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR
1137 	 */
1138 	record_size = nla_total_size(2 * nla_total_size(ETH_ALEN));
1139 
1140 	/* QCA_WLAN_VENDOR_ATTR_PASN_PEERS nest */
1141 	len += nla_total_size(num_pasn_peers * record_size);
1142 
1143 	skb = wlan_cfg80211_vendor_event_alloc(osif_priv->wdev->wiphy,
1144 					       osif_priv->wdev, len,
1145 					       index, GFP_ATOMIC);
1146 	if (!skb)
1147 		return QDF_STATUS_E_NOMEM;
1148 
1149 	action = is_initiate_pasn ?
1150 		 QCA_WLAN_VENDOR_PASN_ACTION_AUTH :
1151 		 QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT;
1152 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_PASN_ACTION, action)) {
1153 		osif_err("NLA put failed");
1154 		goto nla_put_failure;
1155 	}
1156 
1157 	attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEERS);
1158 	if (!attr) {
1159 		osif_err("NLA nest failed");
1160 		status = QDF_STATUS_E_FAILURE;
1161 		goto nla_put_failure;
1162 	}
1163 
1164 	for (i = 0; i < num_pasn_peers; i++) {
1165 		osif_debug("PASN peer_mac[%d]: " QDF_MAC_ADDR_FMT " src_mac: " QDF_MAC_ADDR_FMT,
1166 			   i, QDF_MAC_ADDR_REF(pasn_peer[i].peer_mac.bytes),
1167 			   QDF_MAC_ADDR_REF(pasn_peer[i].self_mac.bytes));
1168 		nest_attr = nla_nest_start(skb, i);
1169 		if (!nest_attr) {
1170 			osif_err("NLA nest failed for iter:%d", i);
1171 			status = QDF_STATUS_E_FAILURE;
1172 			goto nla_put_failure;
1173 		}
1174 
1175 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR,
1176 			    ETH_ALEN, pasn_peer[i].peer_mac.bytes)) {
1177 			osif_err("NLA put failed");
1178 			status = QDF_STATUS_E_FAILURE;
1179 			goto nla_put_failure;
1180 		}
1181 
1182 		if (!qdf_is_macaddr_zero(&pasn_peer[i].self_mac) &&
1183 		    nla_put(skb, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR,
1184 			    ETH_ALEN, pasn_peer[i].self_mac.bytes)) {
1185 			osif_err("NLA put failed");
1186 			status = QDF_STATUS_E_FAILURE;
1187 			goto nla_put_failure;
1188 		}
1189 
1190 		nla_nest_end(skb, nest_attr);
1191 	}
1192 	nla_nest_end(skb, attr);
1193 
1194 	osif_debug("action:%d num_pasn_peers:%d", action, num_pasn_peers);
1195 
1196 	wlan_cfg80211_vendor_event(skb, GFP_ATOMIC);
1197 
1198 	return status;
1199 
1200 nla_put_failure:
1201 	wlan_cfg80211_vendor_free_skb(skb);
1202 
1203 	return status;
1204 }
1205 #endif /* WIFI_POS_CONVERGED && WLAN_FEATURE_RTT_11AZ_SUPPORT */
1206