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