1 /* 2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: wlan_hdd_cfr.c 20 * 21 * WLAN Host Device Driver CFR capture Implementation 22 */ 23 24 #include <linux/version.h> 25 #include <linux/module.h> 26 #include <linux/kernel.h> 27 #include <net/cfg80211.h> 28 #include "wlan_hdd_includes.h" 29 #include "osif_sync.h" 30 #include "wlan_hdd_cfr.h" 31 #include "wlan_cfr_ucfg_api.h" 32 #include "wlan_hdd_object_manager.h" 33 #include "wlan_cmn.h" 34 #include "wlan_policy_mgr_ll_sap.h" 35 36 const struct nla_policy cfr_config_policy[ 37 QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1] = { 38 [QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR] = 39 VENDOR_NLA_POLICY_MAC_ADDR, 40 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE] = {.type = NLA_FLAG}, 41 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH] = {.type = NLA_U8}, 42 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY] = {.type = NLA_U32}, 43 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD] = {.type = NLA_U8}, 44 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION] = {.type = NLA_U8}, 45 [QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE] = { 46 .type = NLA_FLAG}, 47 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP] = { 48 .type = NLA_U32}, 49 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION] = {.type = NLA_U32}, 50 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL] = {.type = NLA_U32}, 51 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE] = {.type = NLA_U32}, 52 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK] = {.type = NLA_U64}, 53 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT] = { 54 .type = NLA_U32}, 55 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE] = { 56 .type = NLA_NESTED}, 57 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY] = { 58 .type = NLA_NESTED}, 59 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER] = {.type = NLA_U32}, 60 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA] = 61 VENDOR_NLA_POLICY_MAC_ADDR, 62 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA] = 63 VENDOR_NLA_POLICY_MAC_ADDR, 64 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK] = 65 VENDOR_NLA_POLICY_MAC_ADDR, 66 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK] = 67 VENDOR_NLA_POLICY_MAC_ADDR, 68 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS] = {.type = NLA_U32}, 69 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW] = {.type = NLA_U32}, 70 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER] = { 71 .type = NLA_U32}, 72 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER] = { 73 .type = NLA_U32}, 74 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER] = { 75 .type = NLA_U32}, 76 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE] = { 77 .type = NLA_U8}, 78 [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID] = { 79 .type = NLA_U32}, 80 }; 81 82 #ifdef WLAN_ENH_CFR_ENABLE 83 static void 84 wlan_hdd_transport_mode_cfg(struct wlan_objmgr_pdev *pdev, 85 uint8_t vdev_id, uint32_t pid, 86 enum qca_wlan_vendor_cfr_data_transport_modes tx_mode) 87 { 88 struct pdev_cfr *pa; 89 90 if (!pdev) { 91 hdd_err("failed to %s transport mode cb for cfr, pdev is NULL for vdev id %d", 92 tx_mode ? "register" : "deregister", vdev_id); 93 return; 94 } 95 96 pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); 97 if (!pa) { 98 hdd_err("cfr private obj is NULL for vdev id %d", vdev_id); 99 return; 100 } 101 pa->nl_cb.vdev_id = vdev_id; 102 pa->nl_cb.pid = pid; 103 if (tx_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS) 104 pa->nl_cb.cfr_nl_cb = hdd_cfr_data_send_nl_event; 105 else 106 pa->nl_cb.cfr_nl_cb = NULL; 107 } 108 109 #define DEFAULT_CFR_NSS 0xff 110 #define DEFAULT_CFR_BW 0xf 111 static QDF_STATUS 112 wlan_cfg80211_cfr_set_group_config(struct wlan_objmgr_vdev *vdev, 113 struct nlattr *tb[]) 114 { 115 struct cfr_wlanconfig_param params = { 0 }; 116 117 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]) { 118 params.grp_id = nla_get_u32(tb[ 119 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]); 120 hdd_debug("group_id %d", params.grp_id); 121 } 122 123 if (params.grp_id >= HDD_INVALID_GROUP_ID) { 124 hdd_err("invalid group id"); 125 return QDF_STATUS_E_INVAL; 126 } 127 128 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA]) { 129 nla_memcpy(¶ms.ta[0], 130 tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA], 131 QDF_MAC_ADDR_SIZE); 132 hdd_debug("ta " QDF_MAC_ADDR_FMT, 133 QDF_MAC_ADDR_REF(¶ms.ta[0])); 134 } 135 136 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK]) { 137 nla_memcpy(¶ms.ta_mask[0], 138 tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK], 139 QDF_MAC_ADDR_SIZE); 140 hdd_debug("ta_mask " QDF_MAC_ADDR_FMT, 141 QDF_MAC_ADDR_REF(¶ms.ta_mask[0])); 142 } 143 144 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA]) { 145 nla_memcpy(¶ms.ra[0], 146 tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA], 147 QDF_MAC_ADDR_SIZE); 148 hdd_debug("ra " QDF_MAC_ADDR_FMT, 149 QDF_MAC_ADDR_REF(¶ms.ra[0])); 150 } 151 152 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK]) { 153 nla_memcpy(¶ms.ra_mask[0], 154 tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK], 155 QDF_MAC_ADDR_SIZE); 156 hdd_debug("ra_mask " QDF_MAC_ADDR_FMT, 157 QDF_MAC_ADDR_REF(¶ms.ra_mask[0])); 158 } 159 160 if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ta) || 161 !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ra) || 162 !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ta_mask) || 163 !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ra_mask)) { 164 hdd_debug("set tara config"); 165 ucfg_cfr_set_tara_config(vdev, ¶ms); 166 } 167 168 params.nss = DEFAULT_CFR_NSS; 169 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]) { 170 params.nss = nla_get_u32(tb[ 171 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]); 172 hdd_debug("nss %d", params.nss); 173 } 174 175 params.bw = DEFAULT_CFR_BW; 176 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]) { 177 params.bw = nla_get_u32(tb[ 178 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]); 179 hdd_debug("bw %d", params.bw); 180 } 181 182 if (params.nss || params.bw) { 183 hdd_debug("set bw nss"); 184 ucfg_cfr_set_bw_nss(vdev, ¶ms); 185 } 186 187 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]) { 188 params.expected_mgmt_subtype = nla_get_u32(tb[ 189 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]); 190 hdd_debug("expected_mgmt_subtype %d(%x)", 191 params.expected_mgmt_subtype, 192 params.expected_mgmt_subtype); 193 } 194 195 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]) { 196 params.expected_ctrl_subtype = nla_get_u32(tb[ 197 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]); 198 hdd_debug("expected_mgmt_subtype %d(%x)", 199 params.expected_ctrl_subtype, 200 params.expected_ctrl_subtype); 201 } 202 203 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]) { 204 params.expected_data_subtype = nla_get_u32(tb[ 205 QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]); 206 hdd_debug("expected_mgmt_subtype %d(%x)", 207 params.expected_data_subtype, 208 params.expected_data_subtype); 209 } 210 211 if (!params.expected_mgmt_subtype || 212 !params.expected_ctrl_subtype || 213 !params.expected_data_subtype) { 214 hdd_debug("set frame type"); 215 ucfg_cfr_set_frame_type_subtype(vdev, ¶ms); 216 } 217 218 return QDF_STATUS_SUCCESS; 219 } 220 221 static enum capture_type convert_vendor_cfr_capture_type( 222 enum qca_wlan_vendor_cfr_capture_type type) 223 { 224 switch (type) { 225 case QCA_WLAN_VENDOR_CFR_DIRECT_FTM: 226 return RCC_DIRECTED_FTM_FILTER; 227 case QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: 228 return RCC_ALL_FTM_ACK_FILTER; 229 case QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: 230 return RCC_DIRECTED_NDPA_NDP_FILTER; 231 case QCA_WLAN_VENDOR_CFR_TA_RA: 232 return RCC_TA_RA_FILTER; 233 case QCA_WLAN_VENDOR_CFR_ALL_PACKET: 234 return RCC_NDPA_NDP_ALL_FILTER; 235 default: 236 hdd_err("invalid capture type"); 237 return RCC_DIS_ALL_MODE; 238 } 239 } 240 241 static int 242 wlan_cfg80211_cfr_set_config(struct wlan_objmgr_vdev *vdev, 243 struct nlattr *tb[]) 244 { 245 struct nlattr *group[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1]; 246 struct nlattr *group_list; 247 struct cfr_wlanconfig_param params = { 0 }; 248 enum capture_type type; 249 enum qca_wlan_vendor_cfr_capture_type vendor_capture_type; 250 int rem = 0; 251 int maxtype; 252 int attr; 253 uint64_t ul_mu_user_mask = 0; 254 255 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]) { 256 params.cap_dur = nla_get_u32(tb[ 257 QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]); 258 ucfg_cfr_set_capture_duration(vdev, ¶ms); 259 hdd_debug("params.cap_dur %d", params.cap_dur); 260 } 261 262 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]) { 263 params.cap_intvl = nla_get_u32(tb[ 264 QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]); 265 ucfg_cfr_set_capture_interval(vdev, ¶ms); 266 hdd_debug("params.cap_intvl %d", params.cap_intvl); 267 } 268 269 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]) { 270 vendor_capture_type = nla_get_u32(tb[ 271 QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]); 272 if ((vendor_capture_type < QCA_WLAN_VENDOR_CFR_DIRECT_FTM) || 273 (vendor_capture_type > QCA_WLAN_VENDOR_CFR_ALL_PACKET)) { 274 hdd_err_rl("invalid capture type %d", 275 vendor_capture_type); 276 return -EINVAL; 277 } 278 type = convert_vendor_cfr_capture_type(vendor_capture_type); 279 ucfg_cfr_set_rcc_mode(vdev, type, 1); 280 hdd_debug("type %d", type); 281 } 282 283 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]) { 284 ul_mu_user_mask = nla_get_u64(tb[ 285 QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]); 286 hdd_debug("ul_mu_user_mask_lower %d", 287 params.ul_mu_user_mask_lower); 288 } 289 290 if (ul_mu_user_mask) { 291 params.ul_mu_user_mask_lower = 292 (uint32_t)(ul_mu_user_mask & 0xffffffff); 293 params.ul_mu_user_mask_lower = 294 (uint32_t)(ul_mu_user_mask >> 32); 295 hdd_debug("set ul mu user mask"); 296 ucfg_cfr_set_ul_mu_user_mask(vdev, ¶ms); 297 } 298 299 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]) { 300 params.freeze_tlv_delay_cnt_thr = nla_get_u32(tb[ 301 QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]); 302 if (params.freeze_tlv_delay_cnt_thr) { 303 params.freeze_tlv_delay_cnt_en = 1; 304 ucfg_cfr_set_freeze_tlv_delay_cnt(vdev, ¶ms); 305 hdd_debug("freeze_tlv_delay_cnt_thr %d", 306 params.freeze_tlv_delay_cnt_thr); 307 } 308 } 309 310 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE]) { 311 maxtype = QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX; 312 attr = QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE; 313 nla_for_each_nested(group_list, tb[attr], rem) { 314 if (wlan_cfg80211_nla_parse(group, maxtype, 315 nla_data(group_list), 316 nla_len(group_list), 317 cfr_config_policy)) { 318 hdd_err("nla_parse failed for cfr config group"); 319 return -EINVAL; 320 } 321 wlan_cfg80211_cfr_set_group_config(vdev, group); 322 } 323 } 324 325 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]) { 326 uint8_t transport_mode = 0xff; 327 uint32_t pid = 0; 328 329 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID]) 330 pid = nla_get_u32(tb[ 331 QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID]); 332 else 333 hdd_debug("No PID received"); 334 335 transport_mode = nla_get_u8(tb[ 336 QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]); 337 338 hdd_debug("tx mode attr %d, pid %d", transport_mode, pid); 339 if (transport_mode == QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS || 340 transport_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS) { 341 wlan_hdd_transport_mode_cfg(vdev->vdev_objmgr.wlan_pdev, 342 vdev->vdev_objmgr.vdev_id, 343 pid, transport_mode); 344 } else { 345 hdd_debug("invalid transport mode %d for vdev id %d", 346 transport_mode, vdev->vdev_objmgr.vdev_id); 347 } 348 } 349 350 return 0; 351 } 352 353 static QDF_STATUS hdd_stop_enh_cfr(struct wlan_objmgr_vdev *vdev) 354 { 355 if (!ucfg_cfr_get_rcc_enabled(vdev)) 356 return QDF_STATUS_SUCCESS; 357 358 hdd_debug("cleanup rcc mode"); 359 wlan_objmgr_vdev_try_get_ref(vdev, WLAN_CFR_ID); 360 ucfg_cfr_set_rcc_mode(vdev, RCC_DIS_ALL_MODE, 0); 361 ucfg_cfr_subscribe_ppdu_desc(wlan_vdev_get_pdev(vdev), 362 false); 363 ucfg_cfr_committed_rcc_config(vdev); 364 ucfg_cfr_stop_indication(vdev); 365 ucfg_cfr_suspend(wlan_vdev_get_pdev(vdev)); 366 hdd_debug("stop indication done"); 367 wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); 368 369 return QDF_STATUS_SUCCESS; 370 } 371 372 QDF_STATUS hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev) 373 { 374 return hdd_stop_enh_cfr(vdev); 375 } 376 377 static int 378 wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter *adapter, 379 struct nlattr **tb) 380 { 381 struct cfr_wlanconfig_param params = { 0 }; 382 struct wlan_objmgr_vdev *vdev; 383 bool is_start_capture = false; 384 int ret = 0; 385 386 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]) { 387 is_start_capture = nla_get_flag(tb[ 388 QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]); 389 } 390 391 if (is_start_capture && 392 !tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]) { 393 hdd_err("Invalid group bitmap"); 394 return -EINVAL; 395 } 396 397 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); 398 if (!vdev) { 399 hdd_err("can't get vdev"); 400 return -EINVAL; 401 } 402 403 if (is_start_capture) { 404 ret = wlan_cfg80211_cfr_set_config(vdev, tb); 405 if (ret) { 406 hdd_err("set config failed"); 407 goto out; 408 } 409 params.en_cfg = nla_get_u32(tb[ 410 QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]); 411 hdd_debug("params.en_cfg %d", params.en_cfg); 412 ucfg_cfr_set_en_bitmap(vdev, ¶ms); 413 ucfg_cfr_resume(wlan_vdev_get_pdev(vdev)); 414 ucfg_cfr_subscribe_ppdu_desc(wlan_vdev_get_pdev(vdev), 415 true); 416 ucfg_cfr_committed_rcc_config(vdev); 417 } else { 418 hdd_stop_enh_cfr(vdev); 419 } 420 out: 421 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 422 return ret; 423 } 424 #else 425 static int 426 wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter *adapter, 427 struct nlattr **tb) 428 { 429 return 0; 430 } 431 #endif 432 433 #ifdef WLAN_CFR_ADRASTEA 434 static QDF_STATUS 435 wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, 436 struct nlattr **tb) 437 { 438 struct cfr_capture_params params = { 0 }; 439 struct wlan_objmgr_vdev *vdev; 440 struct wlan_objmgr_pdev *pdev; 441 struct wlan_objmgr_peer *peer; 442 struct wlan_objmgr_psoc *psoc; 443 struct qdf_mac_addr peer_addr; 444 bool is_start_capture = false; 445 QDF_STATUS status = QDF_STATUS_SUCCESS; 446 447 if (!tb[QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR]) { 448 hdd_err("peer mac addr not given"); 449 return QDF_STATUS_E_INVAL; 450 } 451 452 nla_memcpy(peer_addr.bytes, tb[QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR], 453 QDF_MAC_ADDR_SIZE); 454 455 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]) { 456 is_start_capture = nla_get_flag(tb[ 457 QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]); 458 } 459 460 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); 461 if (!vdev) { 462 hdd_err("can't get vdev"); 463 return -EINVAL; 464 } 465 466 pdev = wlan_vdev_get_pdev(vdev); 467 if (!pdev) { 468 hdd_err("failed to get pdev"); 469 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 470 return QDF_STATUS_E_INVAL; 471 } 472 473 psoc = wlan_vdev_get_psoc(vdev); 474 if (!psoc) { 475 hdd_err("Failed to get psoc"); 476 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 477 return QDF_STATUS_E_INVAL; 478 } 479 480 peer = wlan_objmgr_get_peer_by_mac(psoc, peer_addr.bytes, WLAN_CFR_ID); 481 if (!peer) { 482 hdd_err("No peer object found"); 483 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 484 return QDF_STATUS_E_INVAL; 485 } 486 487 if (is_start_capture) { 488 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY]) { 489 params.period = nla_get_u32(tb[ 490 QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY]); 491 hdd_debug("params.periodicity %d", params.period); 492 /* Set the periodic CFR */ 493 if (params.period) 494 ucfg_cfr_set_timer(pdev, params.period); 495 } 496 497 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD]) { 498 params.method = nla_get_u8(tb[ 499 QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD]); 500 /* Adrastea supports only QOS NULL METHOD */ 501 if (params.method != 502 QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL) { 503 hdd_err_rl("invalid capture method %d", 504 params.method); 505 status = QDF_STATUS_E_INVAL; 506 goto exit; 507 } 508 } 509 510 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH]) { 511 params.bandwidth = nla_get_u8(tb[ 512 QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH]); 513 /* Adrastea supports only 20Mhz bandwidth CFR capture */ 514 if (params.bandwidth != NL80211_CHAN_WIDTH_20_NOHT) { 515 hdd_err_rl("invalid capture bandwidth %d", 516 params.bandwidth); 517 status = QDF_STATUS_E_INVAL; 518 goto exit; 519 } 520 } 521 ucfg_cfr_start_capture(pdev, peer, ¶ms); 522 } else { 523 /* Disable the periodic CFR if enabled */ 524 if (ucfg_cfr_get_timer(pdev)) 525 ucfg_cfr_set_timer(pdev, 0); 526 527 /* Disable the peer CFR capture */ 528 ucfg_cfr_stop_capture(pdev, peer); 529 } 530 exit: 531 wlan_objmgr_peer_release_ref(peer, WLAN_CFR_ID); 532 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 533 534 return status; 535 } 536 #elif defined(WLAN_CFR_DBR) 537 static enum 538 phy_ch_width convert_capture_bw(enum nl80211_chan_width capture_bw) 539 { 540 switch (capture_bw) { 541 case NL80211_CHAN_WIDTH_20_NOHT: 542 case NL80211_CHAN_WIDTH_20: 543 return CH_WIDTH_20MHZ; 544 case NL80211_CHAN_WIDTH_40: 545 return CH_WIDTH_40MHZ; 546 case NL80211_CHAN_WIDTH_80: 547 return CH_WIDTH_80MHZ; 548 case NL80211_CHAN_WIDTH_80P80: 549 return CH_WIDTH_80P80MHZ; 550 case NL80211_CHAN_WIDTH_160: 551 return CH_WIDTH_160MHZ; 552 case NL80211_CHAN_WIDTH_5: 553 return CH_WIDTH_5MHZ; 554 case NL80211_CHAN_WIDTH_10: 555 return CH_WIDTH_10MHZ; 556 default: 557 hdd_err("invalid capture bw"); 558 return CH_WIDTH_INVALID; 559 } 560 } 561 562 static QDF_STATUS 563 wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, 564 struct nlattr **tb) 565 { 566 struct cfr_capture_params params = { 0 }; 567 struct wlan_objmgr_vdev *vdev; 568 struct wlan_objmgr_pdev *pdev; 569 struct wlan_objmgr_peer *peer; 570 struct wlan_objmgr_psoc *psoc; 571 struct qdf_mac_addr peer_addr; 572 bool is_start_capture = false; 573 QDF_STATUS status = QDF_STATUS_SUCCESS; 574 int id; 575 576 id = QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR; 577 if (!tb[id]) { 578 hdd_err("peer mac addr not given"); 579 return QDF_STATUS_E_INVAL; 580 } 581 582 nla_memcpy(peer_addr.bytes, tb[id], 583 QDF_MAC_ADDR_SIZE); 584 585 id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE; 586 if (tb[id]) 587 is_start_capture = nla_get_flag(tb[id]); 588 589 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); 590 if (!vdev) { 591 hdd_err("can't get vdev"); 592 return -EINVAL; 593 } 594 595 pdev = wlan_vdev_get_pdev(vdev); 596 if (!pdev) { 597 hdd_err("failed to get pdev"); 598 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 599 return QDF_STATUS_E_INVAL; 600 } 601 602 psoc = wlan_vdev_get_psoc(vdev); 603 if (!psoc) { 604 hdd_err("Failed to get psoc"); 605 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 606 return QDF_STATUS_E_INVAL; 607 } 608 609 peer = wlan_objmgr_get_peer_by_mac(psoc, peer_addr.bytes, WLAN_CFR_ID); 610 if (!peer) { 611 hdd_err("No peer object found"); 612 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 613 return QDF_STATUS_E_INVAL; 614 } 615 616 if (is_start_capture) { 617 id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY; 618 if (tb[id]) { 619 params.period = nla_get_u32(tb[id]); 620 hdd_debug("params.periodicity %d", params.period); 621 /* Set the periodic CFR */ 622 if (params.period) 623 ucfg_cfr_set_timer(pdev, params.period); 624 } 625 id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD; 626 if (tb[id]) { 627 params.method = nla_get_u8(tb[id]); 628 /* Adrastea supports only QOS NULL METHOD */ 629 if (params.method != 630 QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL) { 631 hdd_err_rl("invalid capture method %d", 632 params.method); 633 status = QDF_STATUS_E_INVAL; 634 goto exit; 635 } 636 } 637 id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH; 638 if (tb[id]) { 639 params.bandwidth = nla_get_u8(tb[id]); 640 params.bandwidth = convert_capture_bw(params.bandwidth); 641 if (params.bandwidth > NL80211_CHAN_WIDTH_80) { 642 hdd_err_rl("invalid capture bandwidth %d", 643 params.bandwidth); 644 status = QDF_STATUS_E_INVAL; 645 goto exit; 646 } 647 } 648 ucfg_cfr_start_capture(pdev, peer, ¶ms); 649 } else { 650 /* Disable the periodic CFR if enabled */ 651 if (ucfg_cfr_get_timer(pdev)) 652 ucfg_cfr_set_timer(pdev, 0); 653 654 /* Disable the peer CFR capture */ 655 ucfg_cfr_stop_capture(pdev, peer); 656 ucfg_cfr_stop_indication(vdev); 657 } 658 exit: 659 wlan_objmgr_peer_release_ref(peer, WLAN_CFR_ID); 660 hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); 661 662 return status; 663 } 664 665 #else 666 static QDF_STATUS 667 wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, 668 struct nlattr **tb) 669 { 670 return QDF_STATUS_E_NOSUPPORT; 671 } 672 #endif 673 674 static int 675 wlan_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, 676 struct hdd_adapter *adapter, 677 const void *data, 678 int data_len) 679 { 680 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1]; 681 uint8_t version = 0; 682 QDF_STATUS status; 683 684 if (wlan_cfg80211_nla_parse( 685 tb, 686 QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX, 687 data, 688 data_len, 689 cfr_config_policy)) { 690 hdd_err("Invalid ATTR"); 691 return -EINVAL; 692 } 693 694 if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]) { 695 version = nla_get_u8(tb[ 696 QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]); 697 hdd_debug("version %d", version); 698 if (version == LEGACY_CFR_VERSION) { 699 status = wlan_cfg80211_peer_cfr_capture_cfg_adrastea( 700 adapter, tb); 701 return qdf_status_to_os_return(status); 702 } else if (version != ENHANCED_CFR_VERSION) { 703 hdd_err("unsupported version"); 704 return -EFAULT; 705 } 706 } 707 708 return wlan_cfg80211_peer_enh_cfr_capture(adapter, tb); 709 } 710 711 static int __wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, 712 struct wireless_dev *wdev, 713 const void *data, 714 int data_len) 715 { 716 int ret; 717 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 718 struct net_device *dev = wdev->netdev; 719 struct hdd_adapter *adapter; 720 uint8_t ll_lt_sap_vdev_id; 721 722 hdd_enter(); 723 724 ret = wlan_hdd_validate_context(hdd_ctx); 725 if (ret) 726 return ret; 727 728 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 729 hdd_err("Command not allowed in FTM mode"); 730 return -EPERM; 731 } 732 733 adapter = WLAN_HDD_GET_PRIV_PTR(dev); 734 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) 735 return -EINVAL; 736 737 ll_lt_sap_vdev_id = 738 wlan_policy_mgr_get_ll_lt_sap_vdev_id(hdd_ctx->psoc); 739 if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) { 740 hdd_info_rl("LL_LT_SAP vdev %d present, cfr cmd not allowed", 741 ll_lt_sap_vdev_id); 742 return -EINVAL; 743 } 744 745 wlan_cfg80211_peer_cfr_capture_cfg(wiphy, adapter, 746 data, data_len); 747 748 hdd_exit(); 749 750 return ret; 751 } 752 753 int wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, 754 struct wireless_dev *wdev, 755 const void *data, 756 int data_len) 757 { 758 struct osif_psoc_sync *psoc_sync; 759 int errno; 760 761 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); 762 if (errno) 763 return errno; 764 765 errno = __wlan_hdd_cfg80211_peer_cfr_capture_cfg(wiphy, wdev, 766 data, data_len); 767 768 osif_psoc_sync_op_stop(psoc_sync); 769 770 return errno; 771 } 772