xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/utils/src/wlan_utility.c (revision dd4dc88b837a295134aa9869114a2efee0f4894b)
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_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
187 			     void *arg)
188 {
189 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
190 	uint8_t *flag = (uint8_t *)arg;
191 
192 	wlan_vdev_obj_lock(vdev);
193 	if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
194 		*flag = 1;
195 
196 	wlan_vdev_obj_unlock(vdev);
197 }
198 
199 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
200 {
201 	return wlan_vdev_allow_connect_n_tx(vdev);
202 }
203 qdf_export_symbol(wlan_vdev_is_up);
204 
205 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev,
206 				    wlan_objmgr_ref_dbgid dbg_id)
207 {
208 	uint8_t flag = 0;
209 
210 	if (!pdev)
211 		return QDF_STATUS_E_INVAL;
212 
213 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active,
214 					  &flag, 0, dbg_id);
215 
216 	if (flag == 1)
217 		return QDF_STATUS_SUCCESS;
218 
219 	return QDF_STATUS_E_INVAL;
220 }
221 
222 qdf_export_symbol(wlan_util_is_vdev_active);
223 
224 void wlan_util_change_map_index(unsigned long *map, uint8_t id, uint8_t set)
225 {
226 	if (set)
227 		qdf_set_bit(id, map);
228 	else
229 		qdf_clear_bit(id, map);
230 }
231 
232 bool wlan_util_map_index_is_set(unsigned long *map, uint8_t id)
233 {
234 	return qdf_test_bit(id, map);
235 }
236 
237 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev,
238 					  void *object, void *arg)
239 {
240 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
241 	unsigned long *vdev_id_map = (unsigned long *)arg;
242 	uint8_t id = 0;
243 	struct wlan_objmgr_psoc *psoc;
244 
245 	psoc = wlan_pdev_get_psoc(pdev);
246 	if (!psoc)
247 		return;
248 
249 	wlan_vdev_obj_lock(vdev);
250 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
251 		id = wlan_vdev_get_id(vdev);
252 		/* Invalid vdev id */
253 		if (id >= wlan_psoc_get_max_vdev_count(psoc)) {
254 			wlan_vdev_obj_unlock(vdev);
255 			return;
256 		}
257 
258 		wlan_util_change_map_index(vdev_id_map, id, 1);
259 	}
260 
261 	wlan_vdev_obj_unlock(vdev);
262 }
263 
264 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev,
265 					       unsigned long *vdev_id_map,
266 					       wlan_objmgr_ref_dbgid dbg_id)
267 {
268 	if (!pdev)
269 		return QDF_STATUS_E_INVAL;
270 
271 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
272 					  wlan_vdev_chan_change_pending,
273 					  vdev_id_map, 0, dbg_id);
274 
275 	return QDF_STATUS_SUCCESS;
276 }
277 
278 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
279 {
280 	if ((chan1->ch_ieee == chan2->ch_ieee) &&
281 	    (chan1->ch_freq_seg2 == chan2->ch_freq_seg2))
282 		return QDF_STATUS_SUCCESS;
283 
284 	return QDF_STATUS_E_FAILURE;
285 }
286 
287 void wlan_chan_copy(struct wlan_channel *tgt, struct wlan_channel *src)
288 {
289 	qdf_mem_copy(tgt, src, sizeof(struct wlan_channel));
290 }
291 
292 struct wlan_channel *wlan_vdev_get_active_channel(struct wlan_objmgr_vdev *vdev)
293 {
294 	struct wlan_channel *comp_vdev_chan = NULL;
295 
296 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
297 		/* compare with BSS channel, when vdev is active, since desired
298 		 * channel gets update, if channel is triggered in another path
299 		 */
300 		if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
301 			comp_vdev_chan = wlan_vdev_mlme_get_bss_chan(vdev);
302 		else
303 			comp_vdev_chan = wlan_vdev_mlme_get_des_chan(vdev);
304 	}
305 
306 	return comp_vdev_chan;
307 }
308 
309 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
310 				 void *arg)
311 {
312 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
313 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
314 	struct wlan_channel *vdev_chan;
315 	struct wlan_channel *iter_vdev_chan;
316 
317 	if (ch_filter->flag)
318 		return;
319 
320 	if (comp_vdev == ch_filter->vdev)
321 		return;
322 
323 	wlan_vdev_obj_lock(comp_vdev);
324 	wlan_vdev_obj_lock(ch_filter->vdev);
325 
326 	vdev_chan = wlan_vdev_get_active_channel(comp_vdev);
327 	if (vdev_chan) {
328 		iter_vdev_chan = wlan_vdev_mlme_get_des_chan(
329 							ch_filter->vdev);
330 		if (wlan_chan_eq(vdev_chan, iter_vdev_chan)
331 						!= QDF_STATUS_SUCCESS) {
332 			ch_filter->flag = 1;
333 
334 			qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
335 				     wlan_vdev_get_id(comp_vdev),
336 				     vdev_chan->ch_ieee,
337 				     vdev_chan->ch_phymode);
338 			qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
339 				     vdev_chan->ch_flags, vdev_chan->ch_flagext,
340 				     vdev_chan->ch_freq_seg1,
341 				     vdev_chan->ch_freq_seg2);
342 
343 			qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
344 				     wlan_vdev_get_id(ch_filter->vdev),
345 				     iter_vdev_chan->ch_ieee,
346 				     iter_vdev_chan->ch_phymode);
347 			qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d",
348 				     iter_vdev_chan->ch_flags,
349 				     iter_vdev_chan->ch_flagext,
350 				     iter_vdev_chan->ch_freq_seg1,
351 				     iter_vdev_chan->ch_freq_seg2);
352 		}
353 	}
354 
355 	wlan_vdev_obj_unlock(ch_filter->vdev);
356 	wlan_vdev_obj_unlock(comp_vdev);
357 }
358 
359 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
360 					      struct wlan_objmgr_vdev *vdev,
361 					      wlan_objmgr_ref_dbgid dbg_id)
362 {
363 	struct wlan_vdev_ch_check_filter ch_filter;
364 
365 	if (!pdev)
366 		return QDF_STATUS_E_INVAL;
367 
368 	if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_CHAN_CONCURRENCY))
369 		return QDF_STATUS_SUCCESS;
370 
371 	if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == QDF_STATUS_SUCCESS) {
372 		ch_filter.flag = 0;
373 		ch_filter.vdev = vdev;
374 
375 		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
376 						  wlan_pdev_chan_match,
377 						  &ch_filter, 0, dbg_id);
378 
379 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
380 
381 		if (ch_filter.flag == 0)
382 			return QDF_STATUS_SUCCESS;
383 	}
384 
385 	return QDF_STATUS_E_FAILURE;
386 }
387 
388 static void wlan_vdev_restart_progress(struct wlan_objmgr_pdev *pdev,
389 				       void *object, void *arg)
390 {
391 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
392 	uint8_t *flag = (uint8_t *)arg;
393 
394 	wlan_vdev_obj_lock(vdev);
395 	if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS)
396 		*flag = 1;
397 
398 	wlan_vdev_obj_unlock(vdev);
399 }
400 
401 QDF_STATUS wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev *pdev,
402 					      wlan_objmgr_ref_dbgid dbg_id)
403 {
404 	uint8_t flag = 0;
405 
406 	if (!pdev)
407 		return QDF_STATUS_E_INVAL;
408 
409 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
410 					  wlan_vdev_restart_progress,
411 					  &flag, 0, dbg_id);
412 
413 	if (flag == 1)
414 		return QDF_STATUS_SUCCESS;
415 
416 	return QDF_STATUS_E_INVAL;
417 }
418 
419 static void wlan_vdev_scan_allowed(struct wlan_objmgr_pdev *pdev, void *object,
420 				   void *arg)
421 {
422 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
423 	uint8_t *flag = (uint8_t *)arg;
424 
425 	wlan_vdev_obj_lock(vdev);
426 	if (wlan_vdev_mlme_is_scan_allowed(vdev) != QDF_STATUS_SUCCESS)
427 		*flag = 1;
428 
429 	wlan_vdev_obj_unlock(vdev);
430 }
431 
432 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev,
433 					  wlan_objmgr_ref_dbgid dbg_id)
434 {
435 	uint8_t flag = 0;
436 
437 	if (!pdev)
438 		return QDF_STATUS_E_INVAL;
439 
440 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
441 					  wlan_vdev_scan_allowed,
442 					  &flag, 0, dbg_id);
443 
444 	if (flag == 1)
445 		return QDF_STATUS_E_FAILURE;
446 
447 	return QDF_STATUS_SUCCESS;
448 }
449 
450 void
451 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr,
452 			 int8_t *rssi)
453 {
454 	uint32_t snr;
455 
456 	if (db2dbm_enabled) {
457 		if (TGT_IS_VALID_RSSI(bcn_snr))
458 			*rssi = bcn_snr;
459 		else if (TGT_IS_VALID_RSSI(dat_snr))
460 			*rssi = dat_snr;
461 		else
462 			*rssi = TGT_NOISE_FLOOR_DBM;
463 	} else {
464 		if (TGT_IS_VALID_SNR(bcn_snr))
465 			snr = bcn_snr;
466 		else if (TGT_IS_VALID_SNR(dat_snr))
467 			snr = dat_snr;
468 		else
469 			snr = TGT_INVALID_SNR;
470 
471 		/* Get the absolute rssi value from the current rssi value */
472 		*rssi = snr + TGT_NOISE_FLOOR_DBM;
473 	}
474 }
475 
476 /**
477  * wlan_util_get_mode_specific_peer_count - This api gives vdev mode specific
478  * peer count`
479  * @pdev: PDEV object
480  * @object: vdev object
481  * @arg: argument passed by caller
482  *
483  * Return: void
484  */
485 static void
486 wlan_util_get_mode_specific_peer_count(struct wlan_objmgr_pdev *pdev,
487 				       void *object, void *arg)
488 {
489 	struct wlan_objmgr_vdev *vdev = object;
490 	uint16_t temp_count = 0;
491 	struct wlan_op_mode_peer_count *count = arg;
492 
493 	wlan_vdev_obj_lock(vdev);
494 	if (wlan_vdev_mlme_get_opmode(vdev) == count->opmode) {
495 		temp_count = wlan_vdev_get_peer_count(vdev);
496 		/* Decrement the self peer count */
497 		if (temp_count > 1)
498 			count->peer_count += (temp_count - 1);
499 	}
500 	wlan_vdev_obj_unlock(vdev);
501 }
502 
503 uint16_t wlan_util_get_peer_count_for_mode(struct wlan_objmgr_pdev *pdev,
504 					   enum QDF_OPMODE mode)
505 {
506 	struct wlan_op_mode_peer_count count;
507 
508 	count.opmode = mode;
509 	count.peer_count = 0;
510 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
511 				wlan_util_get_mode_specific_peer_count, &count,
512 				0, WLAN_OBJMGR_ID);
513 
514 	return count.peer_count;
515 }
516 
517