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 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 * @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 */ 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 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 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 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 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 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 */ 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 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 */ 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 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 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 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 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 1032 int os_if_wifi_pos_deregister_nl(void) 1033 { 1034 return 0; 1035 } 1036 #endif /* CNSS_GENL */ 1037 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 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 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