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(&params.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(&params.ta[0]));
134 	}
135 
136 	if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK]) {
137 		nla_memcpy(&params.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(&params.ta_mask[0]));
142 	}
143 
144 	if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA]) {
145 		nla_memcpy(&params.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(&params.ra[0]));
150 	}
151 
152 	if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK]) {
153 		nla_memcpy(&params.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(&params.ra_mask[0]));
158 	}
159 
160 	if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ta) ||
161 	    !qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ra) ||
162 	    !qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ta_mask) ||
163 	    !qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ra_mask)) {
164 		hdd_debug("set tara config");
165 		ucfg_cfr_set_tara_config(vdev, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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