xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/utils/src/wlan_utility.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
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 	if (chan == 0 )
32 		return 0;
33 
34 	if (chan < WLAN_24_GHZ_CHANNEL_14)
35 		return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
36 	else if (chan == WLAN_24_GHZ_CHANNEL_14)
37 		return WLAN_CHAN_14_FREQ;
38 	else if (chan < WLAN_24_GHZ_CHANNEL_27)
39 		/* ch 15 - ch 26 */
40 		return WLAN_CHAN_15_FREQ +
41 		  (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ;
42 	else if (chan == WLAN_5_GHZ_CHANNEL_170)
43 		return WLAN_CHAN_170_FREQ;
44 	else
45 		return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
46 }
47 
48 uint8_t wlan_freq_to_chan(uint32_t freq)
49 {
50 	uint8_t chan;
51 
52 	if (freq == 0)
53 		return 0;
54 
55 	if (freq > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ)
56 		chan = ((freq - WLAN_24_GHZ_BASE_FREQ) /
57 			WLAN_CHAN_SPACING_5MHZ);
58 	else if (freq == WLAN_CHAN_14_FREQ)
59 		chan = WLAN_24_GHZ_CHANNEL_14;
60 	else if ((freq > WLAN_24_GHZ_BASE_FREQ) &&
61 		(freq < WLAN_5_GHZ_BASE_FREQ))
62 		chan = (((freq - WLAN_CHAN_15_FREQ) /
63 			WLAN_CHAN_SPACING_20MHZ) +
64 			WLAN_24_GHZ_CHANNEL_15);
65 	else
66 		chan = (freq - WLAN_5_GHZ_BASE_FREQ) /
67 			WLAN_CHAN_SPACING_5MHZ;
68 
69 	return chan;
70 }
71 
72 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len)
73 {
74 	uint8_t elen;
75 
76 	while (ie_len) {
77 		if (ie_len < 2)
78 			return false;
79 
80 		elen = ie[1];
81 		ie_len -= 2;
82 		ie += 2;
83 		if (elen > ie_len)
84 			return false;
85 
86 		ie_len -= elen;
87 		ie += elen;
88 	}
89 
90 	return true;
91 }
92 
93 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,
94 						     const uint8_t *oui,
95 						     uint8_t oui_size,
96 						     const uint8_t *ie,
97 						     uint16_t ie_len)
98 {
99 	int32_t left = ie_len;
100 	const uint8_t *ptr = ie;
101 	uint8_t elem_id, elem_len;
102 
103 	while (left >= 2) {
104 		elem_id  = ptr[0];
105 		elem_len = ptr[1];
106 		left -= 2;
107 
108 		if (elem_len > left)
109 			return NULL;
110 
111 		if (eid == elem_id) {
112 			/* if oui is not provide eid match is enough */
113 			if (!oui)
114 				return ptr;
115 
116 			/*
117 			 * if oui is provided and oui_size is more than left
118 			 * bytes, then we cannot have match
119 			 */
120 			if (oui_size > left)
121 				return NULL;
122 
123 			if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0)
124 				return ptr;
125 		}
126 
127 		left -= elem_len;
128 		ptr += (elem_len + 2);
129 	}
130 
131 	return NULL;
132 }
133 
134 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid,
135 					const uint8_t *ie,
136 					int ie_len)
137 {
138 	return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len);
139 }
140 
141 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui,
142 					       uint8_t oui_size,
143 					       const uint8_t *ie,
144 					       uint16_t ie_len)
145 {
146 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR,
147 					      oui, oui_size, ie, ie_len);
148 }
149 
150 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui,
151 					       uint8_t oui_size,
152 					       const uint8_t *ie,
153 					       uint16_t ie_len)
154 {
155 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT,
156 					      oui, oui_size, ie, ie_len);
157 }
158 
159 bool wlan_is_emulation_platform(uint32_t phy_version)
160 {
161 	if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
162 		(phy_version == 0xABC2) || (phy_version == 0xABC3) ||
163 		(phy_version == 0xFFFF) || (phy_version == 0xABCD))
164 		return true;
165 
166 	return false;
167 }
168 
169 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc,
170 				      uint8_t vdev_id,
171 				      wlan_objmgr_ref_dbgid dbg_id)
172 {
173 	struct wlan_objmgr_vdev *vdev;
174 	struct wlan_objmgr_pdev *pdev = NULL;
175 	uint32_t pdev_id = WLAN_INVALID_PDEV_ID;
176 
177 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
178 						    vdev_id, dbg_id);
179 
180 	if (vdev) {
181 		pdev = wlan_vdev_get_pdev(vdev);
182 		if (pdev)
183 			pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
184 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
185 	}
186 
187 	return pdev_id;
188 }
189 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id);
190 
191 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
192 			     void *arg)
193 {
194 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
195 	uint8_t *flag = (uint8_t *)arg;
196 
197 	wlan_vdev_obj_lock(vdev);
198 	if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
199 		*flag = 1;
200 
201 	wlan_vdev_obj_unlock(vdev);
202 }
203 
204 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
205 {
206 	return wlan_vdev_allow_connect_n_tx(vdev);
207 }
208 qdf_export_symbol(wlan_vdev_is_up);
209 
210 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev,
211 				    wlan_objmgr_ref_dbgid dbg_id)
212 {
213 	uint8_t flag = 0;
214 
215 	if (!pdev)
216 		return QDF_STATUS_E_INVAL;
217 
218 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active,
219 					  &flag, 0, dbg_id);
220 
221 	if (flag == 1)
222 		return QDF_STATUS_SUCCESS;
223 
224 	return QDF_STATUS_E_INVAL;
225 }
226 
227 qdf_export_symbol(wlan_util_is_vdev_active);
228 
229 void wlan_util_change_map_index(unsigned long *map, uint8_t id, uint8_t set)
230 {
231 	if (set)
232 		qdf_set_bit(id, map);
233 	else
234 		qdf_clear_bit(id, map);
235 }
236 
237 bool wlan_util_map_index_is_set(unsigned long *map, uint8_t id)
238 {
239 	return qdf_test_bit(id, map);
240 }
241 
242 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev,
243 					  void *object, void *arg)
244 {
245 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
246 	unsigned long *vdev_id_map = (unsigned long *)arg;
247 	uint8_t id = 0;
248 	struct wlan_objmgr_psoc *psoc;
249 
250 	psoc = wlan_pdev_get_psoc(pdev);
251 	if (!psoc)
252 		return;
253 
254 	wlan_vdev_obj_lock(vdev);
255 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
256 		id = wlan_vdev_get_id(vdev);
257 		/* Invalid vdev id */
258 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
259 			wlan_vdev_obj_unlock(vdev);
260 			return;
261 		}
262 
263 		wlan_util_change_map_index(vdev_id_map, id, 1);
264 	}
265 
266 	wlan_vdev_obj_unlock(vdev);
267 }
268 
269 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev,
270 					       unsigned long *vdev_id_map,
271 					       wlan_objmgr_ref_dbgid dbg_id)
272 {
273 	if (!pdev)
274 		return QDF_STATUS_E_INVAL;
275 
276 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
277 					  wlan_vdev_chan_change_pending,
278 					  vdev_id_map, 0, dbg_id);
279 
280 	return QDF_STATUS_SUCCESS;
281 }
282 
283 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
284 {
285 	if ((chan1->ch_ieee == chan2->ch_ieee) &&
286 	    (chan1->ch_freq_seg2 == chan2->ch_freq_seg2))
287 		return QDF_STATUS_SUCCESS;
288 
289 	return QDF_STATUS_E_FAILURE;
290 }
291 
292 void wlan_chan_copy(struct wlan_channel *tgt, struct wlan_channel *src)
293 {
294 	qdf_mem_copy(tgt, src, sizeof(struct wlan_channel));
295 }
296 
297 struct wlan_channel *wlan_vdev_get_active_channel(struct wlan_objmgr_vdev *vdev)
298 {
299 	struct wlan_channel *comp_vdev_chan = NULL;
300 
301 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
302 		/* compare with BSS channel, when vdev is active, since desired
303 		 * channel gets update, if channel is triggered in another path
304 		 */
305 		if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
306 			comp_vdev_chan = wlan_vdev_mlme_get_bss_chan(vdev);
307 		else
308 			comp_vdev_chan = wlan_vdev_mlme_get_des_chan(vdev);
309 	}
310 
311 	return comp_vdev_chan;
312 }
313 
314 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
315 				 void *arg)
316 {
317 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
318 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
319 	struct wlan_channel vdev_chan, *chan;
320 	struct wlan_channel *iter_vdev_chan;
321 
322 	if (ch_filter->flag)
323 		return;
324 
325 	if (comp_vdev == ch_filter->vdev)
326 		return;
327 
328 	wlan_vdev_obj_lock(comp_vdev);
329 	chan = wlan_vdev_get_active_channel(comp_vdev);
330 	if (!chan) {
331 		wlan_vdev_obj_unlock(comp_vdev);
332 		return;
333 	}
334 	wlan_chan_copy(&vdev_chan, chan);
335 	wlan_vdev_obj_unlock(comp_vdev);
336 
337 	wlan_vdev_obj_lock(ch_filter->vdev);
338 	iter_vdev_chan = wlan_vdev_mlme_get_des_chan(ch_filter->vdev);
339 	if (wlan_chan_eq(&vdev_chan, iter_vdev_chan)
340 		!= QDF_STATUS_SUCCESS) {
341 		ch_filter->flag = 1;
342 		qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
343 			     wlan_vdev_get_id(comp_vdev),
344 			     vdev_chan.ch_ieee,
345 			     vdev_chan.ch_phymode);
346 		qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
347 			     vdev_chan.ch_flags, vdev_chan.ch_flagext,
348 			     vdev_chan.ch_freq_seg1,
349 			     vdev_chan.ch_freq_seg2);
350 		qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
351 			     wlan_vdev_get_id(ch_filter->vdev),
352 			     iter_vdev_chan->ch_ieee,
353 			     iter_vdev_chan->ch_phymode);
354 		qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d",
355 			     iter_vdev_chan->ch_flags,
356 			     iter_vdev_chan->ch_flagext,
357 			     iter_vdev_chan->ch_freq_seg1,
358 			     iter_vdev_chan->ch_freq_seg2);
359 	}
360 	wlan_vdev_obj_unlock(ch_filter->vdev);
361 }
362 
363 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
364 					      struct wlan_objmgr_vdev *vdev,
365 					      wlan_objmgr_ref_dbgid dbg_id)
366 {
367 	struct wlan_vdev_ch_check_filter ch_filter;
368 
369 	if (!pdev)
370 		return QDF_STATUS_E_INVAL;
371 
372 	if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_CHAN_CONCURRENCY))
373 		return QDF_STATUS_SUCCESS;
374 
375 	if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == QDF_STATUS_SUCCESS) {
376 		ch_filter.flag = 0;
377 		ch_filter.vdev = vdev;
378 
379 		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
380 						  wlan_pdev_chan_match,
381 						  &ch_filter, 0, dbg_id);
382 
383 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
384 
385 		if (ch_filter.flag == 0)
386 			return QDF_STATUS_SUCCESS;
387 	}
388 
389 	return QDF_STATUS_E_FAILURE;
390 }
391 
392 static void wlan_vdev_restart_progress(struct wlan_objmgr_pdev *pdev,
393 				       void *object, void *arg)
394 {
395 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
396 	uint8_t *flag = (uint8_t *)arg;
397 
398 	wlan_vdev_obj_lock(vdev);
399 	if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS)
400 		*flag = 1;
401 
402 	wlan_vdev_obj_unlock(vdev);
403 }
404 
405 QDF_STATUS wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev *pdev,
406 					      wlan_objmgr_ref_dbgid dbg_id)
407 {
408 	uint8_t flag = 0;
409 
410 	if (!pdev)
411 		return QDF_STATUS_E_INVAL;
412 
413 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
414 					  wlan_vdev_restart_progress,
415 					  &flag, 0, dbg_id);
416 
417 	if (flag == 1)
418 		return QDF_STATUS_SUCCESS;
419 
420 	return QDF_STATUS_E_INVAL;
421 }
422 
423 static void wlan_vdev_scan_allowed(struct wlan_objmgr_pdev *pdev, void *object,
424 				   void *arg)
425 {
426 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
427 	uint8_t *flag = (uint8_t *)arg;
428 
429 	wlan_vdev_obj_lock(vdev);
430 	if (wlan_vdev_mlme_is_scan_allowed(vdev) != QDF_STATUS_SUCCESS)
431 		*flag = 1;
432 
433 	wlan_vdev_obj_unlock(vdev);
434 }
435 
436 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev,
437 					  wlan_objmgr_ref_dbgid dbg_id)
438 {
439 	uint8_t flag = 0;
440 
441 	if (!pdev)
442 		return QDF_STATUS_E_INVAL;
443 
444 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
445 					  wlan_vdev_scan_allowed,
446 					  &flag, 0, dbg_id);
447 
448 	if (flag == 1)
449 		return QDF_STATUS_E_FAILURE;
450 
451 	return QDF_STATUS_SUCCESS;
452 }
453 
454 void
455 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr,
456 			 int8_t *rssi)
457 {
458 	uint32_t snr;
459 
460 	if (db2dbm_enabled) {
461 		if (TGT_IS_VALID_RSSI(bcn_snr))
462 			*rssi = bcn_snr;
463 		else if (TGT_IS_VALID_RSSI(dat_snr))
464 			*rssi = dat_snr;
465 		else
466 			*rssi = TGT_NOISE_FLOOR_DBM;
467 	} else {
468 		if (TGT_IS_VALID_SNR(bcn_snr))
469 			snr = bcn_snr;
470 		else if (TGT_IS_VALID_SNR(dat_snr))
471 			snr = dat_snr;
472 		else
473 			snr = TGT_INVALID_SNR;
474 
475 		/* Get the absolute rssi value from the current rssi value */
476 		*rssi = snr + TGT_NOISE_FLOOR_DBM;
477 	}
478 }
479 
480 /**
481  * wlan_util_get_mode_specific_peer_count - This api gives vdev mode specific
482  * peer count`
483  * @pdev: PDEV object
484  * @object: vdev object
485  * @arg: argument passed by caller
486  *
487  * Return: void
488  */
489 static void
490 wlan_util_get_mode_specific_peer_count(struct wlan_objmgr_pdev *pdev,
491 				       void *object, void *arg)
492 {
493 	struct wlan_objmgr_vdev *vdev = object;
494 	uint16_t temp_count = 0;
495 	struct wlan_op_mode_peer_count *count = arg;
496 
497 	wlan_vdev_obj_lock(vdev);
498 	if (wlan_vdev_mlme_get_opmode(vdev) == count->opmode) {
499 		temp_count = wlan_vdev_get_peer_count(vdev);
500 		/* Decrement the self peer count */
501 		if (temp_count > 1)
502 			count->peer_count += (temp_count - 1);
503 	}
504 	wlan_vdev_obj_unlock(vdev);
505 }
506 
507 uint16_t wlan_util_get_peer_count_for_mode(struct wlan_objmgr_pdev *pdev,
508 					   enum QDF_OPMODE mode)
509 {
510 	struct wlan_op_mode_peer_count count;
511 
512 	count.opmode = mode;
513 	count.peer_count = 0;
514 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
515 				wlan_util_get_mode_specific_peer_count, &count,
516 				0, WLAN_OBJMGR_ID);
517 
518 	return count.peer_count;
519 }
520 
521