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
wlan_hdd_transport_mode_cfg(struct wlan_objmgr_pdev * pdev,uint8_t vdev_id,uint32_t pid,enum qca_wlan_vendor_cfr_data_transport_modes tx_mode)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
wlan_cfg80211_cfr_set_group_config(struct wlan_objmgr_vdev * vdev,struct nlattr * tb[])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
convert_vendor_cfr_capture_type(enum qca_wlan_vendor_cfr_capture_type type)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
wlan_cfg80211_cfr_set_config(struct wlan_objmgr_vdev * vdev,struct nlattr * tb[])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
hdd_stop_enh_cfr(struct wlan_objmgr_vdev * vdev)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
hdd_cfr_disconnect(struct wlan_objmgr_vdev * vdev)372 QDF_STATUS hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev)
373 {
374 return hdd_stop_enh_cfr(vdev);
375 }
376
377 static int
wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter * adapter,struct nlattr ** tb)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
wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter * adapter,struct nlattr ** tb)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
wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter * adapter,struct nlattr ** tb)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
convert_capture_bw(enum nl80211_chan_width capture_bw)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
wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter * adapter,struct nlattr ** tb)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
wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter * adapter,struct nlattr ** tb)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
wlan_cfg80211_peer_cfr_capture_cfg(struct wiphy * wiphy,struct hdd_adapter * adapter,const void * data,int data_len)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
__wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)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
wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)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