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