xref: /wlan-dirver/qca-wifi-host-cmn/umac/regulatory/core/src/reg_offload_11d_scan.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
1 /*
2  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: Add 11d utility functions
21  */
22 
23 #include <wlan_cmn.h>
24 #include <reg_services_public_struct.h>
25 #include <wlan_scan_public_structs.h>
26 #include <wlan_scan_ucfg_api.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include "reg_priv_objs.h"
29 #include "reg_utils.h"
30 #include "reg_services_common.h"
31 #include "reg_offload_11d_scan.h"
32 #include "reg_host_11d.h"
33 
34 #ifdef TARGET_11D_SCAN
35 
36 QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev,
37 			       uint8_t *country)
38 {
39 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
40 	struct set_country country_code;
41 	struct wlan_objmgr_psoc *psoc;
42 	struct cc_regdmn_s rd;
43 	QDF_STATUS status;
44 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
45 	uint8_t pdev_id;
46 	uint8_t phy_id;
47 
48 	if (!country) {
49 		reg_err("Null country code");
50 		return QDF_STATUS_E_INVAL;
51 	}
52 
53 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
54 
55 	psoc = wlan_pdev_get_psoc(pdev);
56 	psoc_priv_obj = reg_get_psoc_obj(psoc);
57 	if (!psoc_priv_obj) {
58 		reg_err("Null psoc reg component");
59 		return QDF_STATUS_E_INVAL;
60 	}
61 
62 	if (!qdf_mem_cmp(psoc_priv_obj->cur_country, country, REG_ALPHA2_LEN)) {
63 		if (psoc_priv_obj->cc_src == SOURCE_11D) {
64 			reg_debug("same country");
65 			return QDF_STATUS_SUCCESS;
66 		}
67 	}
68 
69 	reg_info("set new 11d country:%c%c to fW",
70 		 country[0], country[1]);
71 
72 	qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1);
73 	country_code.pdev_id = pdev_id;
74 
75 	tx_ops = reg_get_psoc_tx_ops(psoc);
76 	if (tx_ops->get_phy_id_from_pdev_id)
77 		tx_ops->get_phy_id_from_pdev_id(psoc, pdev_id, &phy_id);
78 	else
79 		phy_id = pdev_id;
80 
81 	psoc_priv_obj->new_11d_ctry_pending[phy_id] = true;
82 
83 	if (psoc_priv_obj->offload_enabled) {
84 		tx_ops = reg_get_psoc_tx_ops(psoc);
85 		if (tx_ops->set_country_code) {
86 			tx_ops->set_country_code(psoc, &country_code);
87 		} else {
88 			reg_err("country set fw handler not present");
89 			psoc_priv_obj->new_11d_ctry_pending[phy_id] = false;
90 			return QDF_STATUS_E_FAULT;
91 		}
92 		status = QDF_STATUS_SUCCESS;
93 	} else {
94 		qdf_mem_copy(rd.cc.alpha, country, REG_ALPHA2_LEN + 1);
95 		rd.flags = ALPHA_IS_SET;
96 		reg_program_chan_list(pdev, &rd);
97 		status = QDF_STATUS_SUCCESS;
98 	}
99 
100 	return status;
101 }
102 
103 /**
104  * reg_send_11d_flush_cbk() - release 11d psoc reference
105  * @msg: Pointer to scheduler message.
106  *
107  * Return: QDF_STATUS
108  */
109 static QDF_STATUS reg_send_11d_flush_cbk(struct scheduler_msg *msg)
110 {
111 	struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr;
112 	struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc;
113 
114 	wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
115 	qdf_mem_free(scan_msg_11d);
116 
117 	return QDF_STATUS_SUCCESS;
118 }
119 
120 /**
121  * reg_send_11d_msg_cbk() - Send start/stop 11d scan message.
122  * @msg: Pointer to scheduler message.
123  *
124  * Return: QDF_STATUS
125  */
126 static QDF_STATUS reg_send_11d_msg_cbk(struct scheduler_msg *msg)
127 {
128 	struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr;
129 	struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc;
130 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
131 	struct reg_start_11d_scan_req start_req;
132 	struct reg_stop_11d_scan_req stop_req;
133 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
134 
135 	tx_ops = reg_get_psoc_tx_ops(psoc);
136 
137 	psoc_priv_obj = reg_get_psoc_obj(psoc);
138 	if (!psoc_priv_obj) {
139 		reg_err("Null psoc priv obj");
140 		goto end;
141 	}
142 
143 	if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) {
144 		psoc_priv_obj->enable_11d_supp = false;
145 		reg_err("Invalid vdev");
146 		goto end;
147 	}
148 
149 	if (scan_msg_11d->enable_11d_supp) {
150 		start_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
151 		start_req.scan_period_msec = psoc_priv_obj->scan_11d_interval;
152 		start_req.start_interval_msec = 0;
153 		reg_debug("sending start msg");
154 		tx_ops->start_11d_scan(psoc, &start_req);
155 	} else {
156 		stop_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
157 		reg_debug("sending stop msg");
158 		tx_ops->stop_11d_scan(psoc, &stop_req);
159 	}
160 
161 end:
162 	qdf_mem_free(scan_msg_11d);
163 	wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
164 	return QDF_STATUS_SUCCESS;
165 }
166 
167 /**
168  * reg_sched_11d_msg() - Schedules 11d scan message.
169  * @scan_msg_11d: 11d scan message
170  */
171 static QDF_STATUS reg_sched_11d_msg(struct reg_11d_scan_msg *scan_msg_11d)
172 {
173 	struct scheduler_msg msg = {0};
174 	QDF_STATUS status;
175 
176 	status = wlan_objmgr_psoc_try_get_ref(scan_msg_11d->psoc,
177 					      WLAN_REGULATORY_SB_ID);
178 	if (QDF_IS_STATUS_ERROR(status)) {
179 		reg_err("error taking psoc ref cnt");
180 		return status;
181 	}
182 
183 	msg.bodyptr = scan_msg_11d;
184 	msg.callback = reg_send_11d_msg_cbk;
185 	msg.flush_callback = reg_send_11d_flush_cbk;
186 
187 	status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
188 					QDF_MODULE_ID_REGULATORY,
189 					QDF_MODULE_ID_TARGET_IF, &msg);
190 	if (QDF_IS_STATUS_ERROR(status))
191 		wlan_objmgr_psoc_release_ref(scan_msg_11d->psoc,
192 					     WLAN_REGULATORY_SB_ID);
193 
194 	return status;
195 }
196 
197 void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc)
198 {
199 	bool temp_11d_support;
200 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
201 	bool world_mode;
202 	struct reg_11d_scan_msg *scan_msg_11d;
203 
204 	psoc_priv_obj = reg_get_psoc_obj(psoc);
205 	if (!psoc_priv_obj) {
206 		reg_err("Null reg psoc private obj");
207 		return;
208 	}
209 
210 	if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) {
211 		psoc_priv_obj->enable_11d_supp = false;
212 		reg_err("Invalid vdev");
213 		return;
214 	}
215 
216 	world_mode = reg_is_world_alpha2(psoc_priv_obj->cur_country);
217 
218 	temp_11d_support = psoc_priv_obj->enable_11d_supp;
219 	if ((psoc_priv_obj->enable_11d_in_world_mode) && (world_mode))
220 		psoc_priv_obj->enable_11d_supp = true;
221 	else if (((psoc_priv_obj->user_ctry_set) &&
222 		  (psoc_priv_obj->user_ctry_priority)) ||
223 		 (psoc_priv_obj->master_vdev_cnt))
224 		psoc_priv_obj->enable_11d_supp = false;
225 	else
226 		psoc_priv_obj->enable_11d_supp =
227 			psoc_priv_obj->enable_11d_supp_original;
228 
229 	reg_debug("inside 11d state machine:tmp %d 11d_supp %d org %d set %d pri %d cnt %d vdev %d",
230 		  temp_11d_support,
231 		  psoc_priv_obj->enable_11d_supp,
232 		  psoc_priv_obj->enable_11d_supp_original,
233 		  psoc_priv_obj->user_ctry_set,
234 		  psoc_priv_obj->user_ctry_priority,
235 		  psoc_priv_obj->master_vdev_cnt,
236 		  psoc_priv_obj->vdev_id_for_11d_scan);
237 
238 	if (temp_11d_support != psoc_priv_obj->enable_11d_supp) {
239 		if (psoc_priv_obj->is_11d_offloaded) {
240 			scan_msg_11d = qdf_mem_malloc(sizeof(*scan_msg_11d));
241 			if (!scan_msg_11d)
242 				return;
243 			scan_msg_11d->psoc = psoc;
244 			scan_msg_11d->enable_11d_supp =
245 						psoc_priv_obj->enable_11d_supp;
246 			reg_sched_11d_msg(scan_msg_11d);
247 		} else {
248 			reg_11d_host_scan(psoc_priv_obj);
249 		}
250 	}
251 }
252 
253 QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev)
254 {
255 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
256 	struct wlan_objmgr_pdev *parent_pdev;
257 	struct wlan_objmgr_psoc *parent_psoc;
258 	uint32_t vdev_id;
259 	enum QDF_OPMODE op_mode;
260 	uint8_t i;
261 
262 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
263 
264 	parent_pdev = wlan_vdev_get_pdev(vdev);
265 	parent_psoc = wlan_pdev_get_psoc(parent_pdev);
266 
267 	psoc_priv_obj = reg_get_psoc_obj(parent_psoc);
268 	if (!psoc_priv_obj) {
269 		reg_err("reg psoc private obj is NULL");
270 		return QDF_STATUS_E_FAULT;
271 	}
272 
273 	if ((op_mode == QDF_STA_MODE) ||
274 	    (op_mode == QDF_P2P_DEVICE_MODE) ||
275 	    (op_mode == QDF_P2P_CLIENT_MODE)) {
276 		vdev_id = wlan_vdev_get_id(vdev);
277 		if (!psoc_priv_obj->vdev_cnt_11d) {
278 			psoc_priv_obj->vdev_id_for_11d_scan = vdev_id;
279 			reg_debug("running 11d state machine, opmode %d",
280 				  op_mode);
281 			reg_run_11d_state_machine(parent_psoc);
282 		}
283 
284 		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
285 			if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID) {
286 				psoc_priv_obj->vdev_ids_11d[i] = vdev_id;
287 				break;
288 			}
289 		}
290 		psoc_priv_obj->vdev_cnt_11d++;
291 	}
292 
293 	if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) {
294 		reg_debug("running 11d state machine, opmode %d", op_mode);
295 		psoc_priv_obj->master_vdev_cnt++;
296 		reg_run_11d_state_machine(parent_psoc);
297 	}
298 
299 	return QDF_STATUS_SUCCESS;
300 }
301 
302 QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev)
303 {
304 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
305 	struct wlan_objmgr_pdev *parent_pdev;
306 	struct wlan_objmgr_psoc *parent_psoc;
307 	enum QDF_OPMODE op_mode;
308 	uint32_t vdev_id;
309 	uint8_t i;
310 
311 	if (!vdev) {
312 		reg_err("NULL vdev");
313 		return QDF_STATUS_E_INVAL;
314 	}
315 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
316 
317 	parent_pdev = wlan_vdev_get_pdev(vdev);
318 	parent_psoc = wlan_pdev_get_psoc(parent_pdev);
319 
320 	psoc_priv_obj = reg_get_psoc_obj(parent_psoc);
321 	if (!psoc_priv_obj) {
322 		reg_err("NULL reg psoc private obj");
323 		return QDF_STATUS_E_FAULT;
324 	}
325 
326 	if ((op_mode == QDF_P2P_GO_MODE) || (op_mode == QDF_SAP_MODE)) {
327 		psoc_priv_obj->master_vdev_cnt--;
328 		reg_debug("run 11d state machine, deleted opmode %d",
329 			  op_mode);
330 		reg_run_11d_state_machine(parent_psoc);
331 		return QDF_STATUS_SUCCESS;
332 	}
333 
334 	if ((op_mode == QDF_STA_MODE) || (op_mode == QDF_P2P_DEVICE_MODE) ||
335 	    (op_mode == QDF_P2P_CLIENT_MODE)) {
336 		vdev_id = wlan_vdev_get_id(vdev);
337 		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
338 			if (psoc_priv_obj->vdev_ids_11d[i] == vdev_id) {
339 				psoc_priv_obj->vdev_ids_11d[i] =
340 					INVALID_VDEV_ID;
341 				psoc_priv_obj->vdev_cnt_11d--;
342 				break;
343 			}
344 		}
345 
346 		if (psoc_priv_obj->vdev_id_for_11d_scan != vdev_id)
347 			return QDF_STATUS_SUCCESS;
348 
349 		if (!psoc_priv_obj->vdev_cnt_11d) {
350 			psoc_priv_obj->vdev_id_for_11d_scan = INVALID_VDEV_ID;
351 			psoc_priv_obj->enable_11d_supp = false;
352 			return QDF_STATUS_SUCCESS;
353 		}
354 
355 		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
356 			if (psoc_priv_obj->vdev_ids_11d[i] == INVALID_VDEV_ID)
357 				continue;
358 			psoc_priv_obj->vdev_id_for_11d_scan =
359 				psoc_priv_obj->vdev_ids_11d[i];
360 			psoc_priv_obj->enable_11d_supp = false;
361 			reg_debug("running 11d state machine, vdev %d",
362 				  psoc_priv_obj->vdev_id_for_11d_scan);
363 			reg_run_11d_state_machine(parent_psoc);
364 			break;
365 		}
366 	}
367 
368 	return QDF_STATUS_SUCCESS;
369 }
370 
371 bool reg_is_11d_scan_inprogress(struct wlan_objmgr_psoc *psoc)
372 {
373 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
374 
375 	psoc_priv_obj = reg_get_psoc_obj(psoc);
376 	if (!psoc_priv_obj) {
377 		reg_err("NULL reg psoc private obj");
378 		return false;
379 	}
380 
381 	return psoc_priv_obj->enable_11d_supp;
382 }
383 
384 QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
385 				    uint8_t *country)
386 {
387 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
388 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
389 	struct set_country country_code;
390 	uint8_t pdev_id;
391 	uint8_t ctr;
392 
393 	psoc_priv_obj = reg_get_psoc_obj(psoc);
394 	if (!psoc_priv_obj) {
395 		reg_err("NULL reg psoc private obj");
396 
397 		return QDF_STATUS_E_FAILURE;
398 	}
399 
400 	/*
401 	 * Need firmware to send channel list event
402 	 * for all phys. Therefore set pdev_id to 0xFF
403 	 */
404 	pdev_id = 0xFF;
405 	for (ctr = 0; ctr < psoc_priv_obj->num_phy; ctr++)
406 		psoc_priv_obj->new_11d_ctry_pending[ctr] = true;
407 
408 	qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1);
409 	country_code.pdev_id = pdev_id;
410 
411 	if (psoc_priv_obj->offload_enabled) {
412 		tx_ops = reg_get_psoc_tx_ops(psoc);
413 		if (tx_ops->set_country_code) {
414 			tx_ops->set_country_code(psoc, &country_code);
415 		} else {
416 			reg_err("NULL country set handler");
417 			for (ctr = 0; ctr < psoc_priv_obj->num_phy; ctr++)
418 				psoc_priv_obj->new_11d_ctry_pending[ctr] =
419 					false;
420 			return QDF_STATUS_E_FAULT;
421 		}
422 	}
423 
424 	return QDF_STATUS_SUCCESS;
425 }
426 
427 bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
428 {
429 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
430 
431 	psoc_priv_obj = reg_get_psoc_obj(psoc);
432 	if (!psoc_priv_obj) {
433 		reg_err("NULL reg psoc private obj");
434 		return QDF_STATUS_E_FAILURE;
435 	}
436 
437 	return (psoc_priv_obj->enable_11d_supp &&
438 		!psoc_priv_obj->is_11d_offloaded);
439 }
440 
441 QDF_STATUS reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc, bool val)
442 {
443 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
444 
445 	psoc_priv_obj = reg_get_psoc_obj(psoc);
446 	if (!psoc_priv_obj) {
447 		reg_err("NULL psoc reg component");
448 		return QDF_STATUS_E_FAILURE;
449 	}
450 
451 	psoc_priv_obj->is_11d_offloaded = val;
452 	reg_debug("set is_11d_offloaded %d", val);
453 	return QDF_STATUS_SUCCESS;
454 }
455 
456 bool reg_is_11d_offloaded(struct wlan_objmgr_psoc *psoc)
457 {
458 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
459 
460 	psoc_priv_obj = reg_get_psoc_obj(psoc);
461 	if (!psoc_priv_obj) {
462 		reg_err("NULL reg psoc private obj");
463 		return false;
464 	}
465 
466 	return psoc_priv_obj->is_11d_offloaded;
467 }
468 #endif
469