xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/utils/src/wlan_utility.c (revision 8ddef7dd9a290d4a9b1efd5d3efacf51d78a1a0d)
1 /*
2  * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: This file contains definition for mandatory legacy API
19  */
20 
21 #include "qdf_str.h"
22 #include "wlan_utility.h"
23 #include <wlan_cmn.h>
24 #include "wlan_osif_priv.h"
25 #include <net/cfg80211.h>
26 #include <qdf_module.h>
27 #include <wlan_vdev_mlme_api.h>
28 
29 uint32_t wlan_chan_to_freq(uint8_t chan)
30 {
31 	/* ch 0 - ch 13 */
32 	if (chan < WLAN_24_GHZ_CHANNEL_14)
33 		return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
34 	else if (chan == WLAN_24_GHZ_CHANNEL_14)
35 		return WLAN_CHAN_14_FREQ;
36 	else if (chan < WLAN_24_GHZ_CHANNEL_27)
37 		/* ch 15 - ch 26 */
38 		return WLAN_CHAN_15_FREQ +
39 		  (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ;
40 	else if (chan == WLAN_5_GHZ_CHANNEL_170)
41 		return WLAN_CHAN_170_FREQ;
42 	else
43 		return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
44 }
45 
46 uint8_t wlan_freq_to_chan(uint32_t freq)
47 {
48 	uint8_t chan;
49 
50 	if (freq > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ)
51 		chan = ((freq - WLAN_24_GHZ_BASE_FREQ) /
52 			WLAN_CHAN_SPACING_5MHZ);
53 	else if (freq == WLAN_CHAN_14_FREQ)
54 		chan = WLAN_24_GHZ_CHANNEL_14;
55 	else if ((freq > WLAN_24_GHZ_BASE_FREQ) &&
56 		(freq < WLAN_5_GHZ_BASE_FREQ))
57 		chan = (((freq - WLAN_CHAN_15_FREQ) /
58 			WLAN_CHAN_SPACING_20MHZ) +
59 			WLAN_24_GHZ_CHANNEL_15);
60 	else
61 		chan = (freq - WLAN_5_GHZ_BASE_FREQ) /
62 			WLAN_CHAN_SPACING_5MHZ;
63 
64 	return chan;
65 }
66 
67 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len)
68 {
69 	uint8_t elen;
70 
71 	while (ie_len) {
72 		if (ie_len < 2)
73 			return false;
74 
75 		elen = ie[1];
76 		ie_len -= 2;
77 		ie += 2;
78 		if (elen > ie_len)
79 			return false;
80 
81 		ie_len -= elen;
82 		ie += elen;
83 	}
84 
85 	return true;
86 }
87 
88 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,
89 						     const uint8_t *oui,
90 						     uint8_t oui_size,
91 						     const uint8_t *ie,
92 						     uint16_t ie_len)
93 {
94 	int32_t left = ie_len;
95 	const uint8_t *ptr = ie;
96 	uint8_t elem_id, elem_len;
97 
98 	while (left >= 2) {
99 		elem_id  = ptr[0];
100 		elem_len = ptr[1];
101 		left -= 2;
102 
103 		if (elem_len > left)
104 			return NULL;
105 
106 		if (eid == elem_id) {
107 			/* if oui is not provide eid match is enough */
108 			if (!oui)
109 				return ptr;
110 
111 			/*
112 			 * if oui is provided and oui_size is more than left
113 			 * bytes, then we cannot have match
114 			 */
115 			if (oui_size > left)
116 				return NULL;
117 
118 			if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0)
119 				return ptr;
120 		}
121 
122 		left -= elem_len;
123 		ptr += (elem_len + 2);
124 	}
125 
126 	return NULL;
127 }
128 
129 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid,
130 					const uint8_t *ie,
131 					int ie_len)
132 {
133 	return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len);
134 }
135 
136 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui,
137 					       uint8_t oui_size,
138 					       const uint8_t *ie,
139 					       uint16_t ie_len)
140 {
141 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR,
142 					      oui, oui_size, ie, ie_len);
143 }
144 
145 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui,
146 					       uint8_t oui_size,
147 					       const uint8_t *ie,
148 					       uint16_t ie_len)
149 {
150 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT,
151 					      oui, oui_size, ie, ie_len);
152 }
153 
154 bool wlan_is_emulation_platform(uint32_t phy_version)
155 {
156 	if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
157 		(phy_version == 0xABC2) || (phy_version == 0xABC3) ||
158 		(phy_version == 0xFFFF) || (phy_version == 0xABCD))
159 		return true;
160 
161 	return false;
162 }
163 
164 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc,
165 				      uint8_t vdev_id,
166 				      wlan_objmgr_ref_dbgid dbg_id)
167 {
168 	struct wlan_objmgr_vdev *vdev;
169 	struct wlan_objmgr_pdev *pdev = NULL;
170 	uint32_t pdev_id = WLAN_INVALID_PDEV_ID;
171 
172 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
173 						    vdev_id, dbg_id);
174 
175 	if (vdev) {
176 		pdev = wlan_vdev_get_pdev(vdev);
177 		if (pdev)
178 			pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
179 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
180 	}
181 
182 	return pdev_id;
183 }
184 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id);
185 
186 static void wlan_util_get_vdev_by_ifname_cb(struct wlan_objmgr_psoc *psoc,
187 					    void *obj, void *arg)
188 {
189 	struct wlan_objmgr_vdev *vdev = obj;
190 	struct wlan_find_vdev_filter *filter = arg;
191 
192 	if (filter->found_vdev)
193 		return;
194 
195 	wlan_vdev_obj_lock(vdev);
196 	if (!qdf_str_cmp(vdev->vdev_nif.osdev->wdev->netdev->name,
197 			 filter->ifname)) {
198 		filter->found_vdev = vdev;
199 	}
200 	wlan_vdev_obj_unlock(vdev);
201 }
202 
203 struct wlan_objmgr_vdev *wlan_util_get_vdev_by_ifname(
204 				struct wlan_objmgr_psoc *psoc, char *ifname,
205 				wlan_objmgr_ref_dbgid ref_id)
206 {
207 	QDF_STATUS status;
208 	struct wlan_find_vdev_filter filter = {0};
209 
210 	filter.ifname = ifname;
211 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
212 				     wlan_util_get_vdev_by_ifname_cb,
213 				     &filter, 0, ref_id);
214 
215 	if (!filter.found_vdev)
216 		return NULL;
217 
218 	status = wlan_objmgr_vdev_try_get_ref(filter.found_vdev, ref_id);
219 	if (QDF_IS_STATUS_ERROR(status))
220 		return NULL;
221 
222 	return filter.found_vdev;
223 }
224 
225 /**
226  * wlan_util_vdev_get_if_name() - get vdev's interface name
227  * @vdev: VDEV object
228  *
229  * API to get vdev's interface name
230  *
231  * Return:
232  * @id: vdev's interface name
233  */
234 uint8_t *wlan_util_vdev_get_if_name(struct wlan_objmgr_vdev *vdev)
235 {
236 	uint8_t *name;
237 	struct vdev_osif_priv *osif_priv;
238 
239 	wlan_vdev_obj_lock(vdev);
240 
241 	osif_priv = wlan_vdev_get_ospriv(vdev);
242 	if (!osif_priv) {
243 		wlan_vdev_obj_unlock(vdev);
244 		return NULL;
245 	}
246 
247 	if (!osif_priv->wdev) {
248 		wlan_vdev_obj_unlock(vdev);
249 		return NULL;
250 	}
251 
252 	name = osif_priv->wdev->netdev->name;
253 	wlan_vdev_obj_unlock(vdev);
254 
255 	return name;
256 }
257 qdf_export_symbol(wlan_util_vdev_get_if_name);
258 
259 #ifdef CMN_VDEV_MLME_SM_ENABLE
260 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
261 			     void *arg)
262 {
263 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
264 	uint8_t *flag = (uint8_t *)arg;
265 
266 	wlan_vdev_obj_lock(vdev);
267 	if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
268 		*flag = 1;
269 
270 	wlan_vdev_obj_unlock(vdev);
271 }
272 
273 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
274 {
275 	return wlan_vdev_allow_connect_n_tx(vdev);
276 }
277 
278 qdf_export_symbol(wlan_vdev_is_up);
279 #else
280 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
281 			     void *arg)
282 {
283 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
284 	uint8_t *flag = (uint8_t *)arg;
285 
286 	wlan_vdev_obj_lock(vdev);
287 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_RUN) ||
288 		(wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_DFS_WAIT))
289 		*flag = 1;
290 
291 	wlan_vdev_obj_unlock(vdev);
292 }
293 
294 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
295 {
296 	QDF_STATUS is_up = QDF_STATUS_E_FAILURE;
297 
298 	wlan_vdev_obj_lock(vdev);
299 	if (wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_RUN)
300 		is_up = QDF_STATUS_SUCCESS;
301 
302 	wlan_vdev_obj_unlock(vdev);
303 
304 	return is_up;
305 }
306 
307 qdf_export_symbol(wlan_vdev_is_up);
308 #endif
309 
310 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev,
311 				    wlan_objmgr_ref_dbgid dbg_id)
312 {
313 	uint8_t flag = 0;
314 
315 	if (!pdev)
316 		return QDF_STATUS_E_INVAL;
317 
318 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active,
319 					  &flag, 0, dbg_id);
320 
321 	if (flag == 1)
322 		return QDF_STATUS_SUCCESS;
323 
324 	return QDF_STATUS_E_INVAL;
325 }
326 
327 #ifdef CMN_VDEV_MLME_SM_ENABLE
328 void wlan_util_change_map_index(unsigned long *map, uint8_t id, uint8_t set)
329 {
330 	if (set)
331 		qdf_set_bit(id, map);
332 	else
333 		qdf_clear_bit(id, map);
334 }
335 
336 bool wlan_util_map_index_is_set(unsigned long *map, uint8_t id)
337 {
338 	return qdf_test_bit(id, map);
339 }
340 
341 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev,
342 					  void *object, void *arg)
343 {
344 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
345 	unsigned long *vdev_id_map = (unsigned long *)arg;
346 	uint8_t id = 0;
347 	struct wlan_objmgr_psoc *psoc;
348 
349 	psoc = wlan_pdev_get_psoc(pdev);
350 	if (!psoc)
351 		return;
352 
353 	wlan_vdev_obj_lock(vdev);
354 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
355 		id = wlan_vdev_get_id(vdev);
356 		/* Invalid vdev id */
357 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
358 			wlan_vdev_obj_unlock(vdev);
359 			return;
360 		}
361 
362 		wlan_util_change_map_index(vdev_id_map, id, 1);
363 	}
364 
365 	wlan_vdev_obj_unlock(vdev);
366 }
367 
368 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev,
369 					       unsigned long *vdev_id_map,
370 					       wlan_objmgr_ref_dbgid dbg_id)
371 {
372 	if (!pdev)
373 		return QDF_STATUS_E_INVAL;
374 
375 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
376 					  wlan_vdev_chan_change_pending,
377 					  vdev_id_map, 0, dbg_id);
378 
379 	return QDF_STATUS_SUCCESS;
380 }
381 
382 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
383 {
384 	if ((chan1->ch_ieee == chan2->ch_ieee) &&
385 	    (chan1->ch_freq_seg2 == chan2->ch_freq_seg2))
386 		return QDF_STATUS_SUCCESS;
387 
388 	return QDF_STATUS_E_FAILURE;
389 }
390 
391 void wlan_chan_copy(struct wlan_channel *tgt, struct wlan_channel *src)
392 {
393 	qdf_mem_copy(tgt, src, sizeof(struct wlan_channel));
394 }
395 
396 struct wlan_channel *wlan_vdev_get_active_channel(struct wlan_objmgr_vdev *vdev)
397 {
398 	struct wlan_channel *comp_vdev_chan = NULL;
399 
400 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
401 		/* compare with BSS channel, when vdev is active, since desired
402 		 * channel gets update, if channel is triggered in another path
403 		 */
404 		if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
405 			comp_vdev_chan = wlan_vdev_mlme_get_bss_chan(vdev);
406 		else
407 			comp_vdev_chan = wlan_vdev_mlme_get_des_chan(vdev);
408 	}
409 
410 	return comp_vdev_chan;
411 }
412 
413 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
414 				 void *arg)
415 {
416 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
417 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
418 	struct wlan_channel *vdev_chan;
419 	struct wlan_channel *iter_vdev_chan;
420 
421 	if (ch_filter->flag)
422 		return;
423 
424 	if (comp_vdev == ch_filter->vdev)
425 		return;
426 
427 	wlan_vdev_obj_lock(comp_vdev);
428 	wlan_vdev_obj_lock(ch_filter->vdev);
429 
430 	vdev_chan = wlan_vdev_get_active_channel(comp_vdev);
431 	if (vdev_chan) {
432 		iter_vdev_chan = wlan_vdev_mlme_get_des_chan(
433 							ch_filter->vdev);
434 		if (wlan_chan_eq(vdev_chan, iter_vdev_chan)
435 						!= QDF_STATUS_SUCCESS) {
436 			ch_filter->flag = 1;
437 
438 			qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
439 				     wlan_vdev_get_id(comp_vdev),
440 				     vdev_chan->ch_ieee,
441 				     vdev_chan->ch_phymode);
442 			qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
443 				     vdev_chan->ch_flags, vdev_chan->ch_flagext,
444 				     vdev_chan->ch_freq_seg1,
445 				     vdev_chan->ch_freq_seg2);
446 
447 			qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
448 				     wlan_vdev_get_id(ch_filter->vdev),
449 				     iter_vdev_chan->ch_ieee,
450 				     iter_vdev_chan->ch_phymode);
451 			qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d",
452 				     iter_vdev_chan->ch_flags,
453 				     iter_vdev_chan->ch_flagext,
454 				     iter_vdev_chan->ch_freq_seg1,
455 				     iter_vdev_chan->ch_freq_seg2);
456 		}
457 	}
458 
459 	wlan_vdev_obj_unlock(ch_filter->vdev);
460 	wlan_vdev_obj_unlock(comp_vdev);
461 }
462 
463 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
464 					      struct wlan_objmgr_vdev *vdev,
465 					      wlan_objmgr_ref_dbgid dbg_id)
466 {
467 	struct wlan_vdev_ch_check_filter ch_filter;
468 
469 	if (!pdev)
470 		return QDF_STATUS_E_INVAL;
471 
472 	if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_CHAN_CONCURRENCY))
473 		return QDF_STATUS_SUCCESS;
474 
475 	if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == QDF_STATUS_SUCCESS) {
476 		ch_filter.flag = 0;
477 		ch_filter.vdev = vdev;
478 
479 		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
480 						  wlan_pdev_chan_match,
481 						  &ch_filter, 0, dbg_id);
482 
483 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
484 
485 		if (ch_filter.flag == 0)
486 			return QDF_STATUS_SUCCESS;
487 	}
488 
489 	return QDF_STATUS_E_FAILURE;
490 }
491 
492 static void wlan_vdev_restart_progress(struct wlan_objmgr_pdev *pdev,
493 				       void *object, void *arg)
494 {
495 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
496 	uint8_t *flag = (uint8_t *)arg;
497 
498 	wlan_vdev_obj_lock(vdev);
499 	if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS)
500 		*flag = 1;
501 
502 	wlan_vdev_obj_unlock(vdev);
503 }
504 
505 QDF_STATUS wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev *pdev,
506 					      wlan_objmgr_ref_dbgid dbg_id)
507 {
508 	uint8_t flag = 0;
509 
510 	if (!pdev)
511 		return QDF_STATUS_E_INVAL;
512 
513 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
514 					  wlan_vdev_restart_progress,
515 					  &flag, 0, dbg_id);
516 
517 	if (flag == 1)
518 		return QDF_STATUS_SUCCESS;
519 
520 	return QDF_STATUS_E_INVAL;
521 }
522 
523 static void wlan_vdev_scan_allowed(struct wlan_objmgr_pdev *pdev, void *object,
524 				   void *arg)
525 {
526 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
527 	uint8_t *flag = (uint8_t *)arg;
528 
529 	wlan_vdev_obj_lock(vdev);
530 	if (wlan_vdev_mlme_is_scan_allowed(vdev) != QDF_STATUS_SUCCESS)
531 		*flag = 1;
532 
533 	wlan_vdev_obj_unlock(vdev);
534 }
535 
536 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev,
537 					  wlan_objmgr_ref_dbgid dbg_id)
538 {
539 	uint8_t flag = 0;
540 
541 	if (!pdev)
542 		return QDF_STATUS_E_INVAL;
543 
544 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
545 					  wlan_vdev_scan_allowed,
546 					  &flag, 0, dbg_id);
547 
548 	if (flag == 1)
549 		return QDF_STATUS_E_FAILURE;
550 
551 	return QDF_STATUS_SUCCESS;
552 }
553 #else
554 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev,
555 					  wlan_objmgr_ref_dbgid dbg_id)
556 {
557 	return QDF_STATUS_SUCCESS;
558 }
559 #endif
560 
561 void
562 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr,
563 			 int8_t *rssi)
564 {
565 	uint32_t snr;
566 
567 	if (db2dbm_enabled) {
568 		if (TGT_IS_VALID_RSSI(bcn_snr))
569 			*rssi = bcn_snr;
570 		else if (TGT_IS_VALID_RSSI(dat_snr))
571 			*rssi = dat_snr;
572 		else
573 			*rssi = TGT_NOISE_FLOOR_DBM;
574 	} else {
575 		if (TGT_IS_VALID_SNR(bcn_snr))
576 			snr = bcn_snr;
577 		else if (TGT_IS_VALID_SNR(dat_snr))
578 			snr = dat_snr;
579 		else
580 			snr = TGT_INVALID_SNR;
581 
582 		/* Get the absolute rssi value from the current rssi value */
583 		*rssi = snr + TGT_NOISE_FLOOR_DBM;
584 	}
585 }
586