xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/utils/src/wlan_utility.c (revision 1f55ed1a9f5050d8da228aa8dd3fff7c0242aa71)
1 /*
2  * Copyright (c) 2017-2018 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: This file contains definition for mandatory legacy API
21  */
22 
23 #include "qdf_str.h"
24 #include "wlan_utility.h"
25 #include <wlan_cmn.h>
26 #include "wlan_osif_priv.h"
27 #include <net/cfg80211.h>
28 #include <qdf_module.h>
29 #include <wlan_vdev_mlme_api.h>
30 
31 uint32_t wlan_chan_to_freq(uint8_t chan)
32 {
33 	/* ch 0 - ch 13 */
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 > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ)
53 		chan = ((freq - WLAN_24_GHZ_BASE_FREQ) /
54 			WLAN_CHAN_SPACING_5MHZ);
55 	else if (freq == WLAN_CHAN_14_FREQ)
56 		chan = WLAN_24_GHZ_CHANNEL_14;
57 	else if ((freq > WLAN_24_GHZ_BASE_FREQ) &&
58 		(freq < WLAN_5_GHZ_BASE_FREQ))
59 		chan = (((freq - WLAN_CHAN_15_FREQ) /
60 			WLAN_CHAN_SPACING_20MHZ) +
61 			WLAN_24_GHZ_CHANNEL_15);
62 	else
63 		chan = (freq - WLAN_5_GHZ_BASE_FREQ) /
64 			WLAN_CHAN_SPACING_5MHZ;
65 
66 	return chan;
67 }
68 
69 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len)
70 {
71 	uint8_t elen;
72 
73 	while (ie_len) {
74 		if (ie_len < 2)
75 			return false;
76 
77 		elen = ie[1];
78 		ie_len -= 2;
79 		ie += 2;
80 		if (elen > ie_len)
81 			return false;
82 
83 		ie_len -= elen;
84 		ie += elen;
85 	}
86 
87 	return true;
88 }
89 
90 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,
91 						     const uint8_t *oui,
92 						     uint8_t oui_size,
93 						     const uint8_t *ie,
94 						     uint16_t ie_len)
95 {
96 	int32_t left = ie_len;
97 	const uint8_t *ptr = ie;
98 	uint8_t elem_id, elem_len;
99 
100 	while (left >= 2) {
101 		elem_id  = ptr[0];
102 		elem_len = ptr[1];
103 		left -= 2;
104 
105 		if (elem_len > left)
106 			return NULL;
107 
108 		if (eid == elem_id) {
109 			/* if oui is not provide eid match is enough */
110 			if (!oui)
111 				return ptr;
112 
113 			/*
114 			 * if oui is provided and oui_size is more than left
115 			 * bytes, then we cannot have match
116 			 */
117 			if (oui_size > left)
118 				return NULL;
119 
120 			if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0)
121 				return ptr;
122 		}
123 
124 		left -= elem_len;
125 		ptr += (elem_len + 2);
126 	}
127 
128 	return NULL;
129 }
130 
131 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid,
132 					const uint8_t *ie,
133 					int ie_len)
134 {
135 	return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len);
136 }
137 
138 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui,
139 					       uint8_t oui_size,
140 					       const uint8_t *ie,
141 					       uint16_t ie_len)
142 {
143 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR,
144 					      oui, oui_size, ie, ie_len);
145 }
146 
147 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui,
148 					       uint8_t oui_size,
149 					       const uint8_t *ie,
150 					       uint16_t ie_len)
151 {
152 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT,
153 					      oui, oui_size, ie, ie_len);
154 }
155 
156 bool wlan_is_emulation_platform(uint32_t phy_version)
157 {
158 	if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
159 		(phy_version == 0xABC2) || (phy_version == 0xABC3) ||
160 		(phy_version == 0xFFFF) || (phy_version == 0xABCD))
161 		return true;
162 
163 	return false;
164 }
165 
166 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc,
167 				      uint8_t vdev_id,
168 				      wlan_objmgr_ref_dbgid dbg_id)
169 {
170 	struct wlan_objmgr_vdev *vdev;
171 	struct wlan_objmgr_pdev *pdev = NULL;
172 	uint32_t pdev_id = WLAN_INVALID_PDEV_ID;
173 
174 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
175 						    vdev_id, dbg_id);
176 
177 	if (vdev) {
178 		pdev = wlan_vdev_get_pdev(vdev);
179 		if (pdev)
180 			pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
181 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
182 	}
183 
184 	return pdev_id;
185 }
186 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id);
187 
188 static void wlan_util_get_vdev_by_ifname_cb(struct wlan_objmgr_psoc *psoc,
189 					    void *obj, void *arg)
190 {
191 	struct wlan_objmgr_vdev *vdev = obj;
192 	struct wlan_find_vdev_filter *filter = arg;
193 
194 	if (filter->found_vdev)
195 		return;
196 
197 	wlan_vdev_obj_lock(vdev);
198 	if (!qdf_str_cmp(vdev->vdev_nif.osdev->wdev->netdev->name,
199 			 filter->ifname)) {
200 		filter->found_vdev = vdev;
201 	}
202 	wlan_vdev_obj_unlock(vdev);
203 }
204 
205 struct wlan_objmgr_vdev *wlan_util_get_vdev_by_ifname(
206 				struct wlan_objmgr_psoc *psoc, char *ifname,
207 				wlan_objmgr_ref_dbgid ref_id)
208 {
209 	QDF_STATUS status;
210 	struct wlan_find_vdev_filter filter = {0};
211 
212 	filter.ifname = ifname;
213 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
214 				     wlan_util_get_vdev_by_ifname_cb,
215 				     &filter, 0, ref_id);
216 
217 	if (!filter.found_vdev)
218 		return NULL;
219 
220 	status = wlan_objmgr_vdev_try_get_ref(filter.found_vdev, ref_id);
221 	if (QDF_IS_STATUS_ERROR(status))
222 		return NULL;
223 
224 	return filter.found_vdev;
225 }
226 
227 /**
228  * wlan_util_vdev_get_if_name() - get vdev's interface name
229  * @vdev: VDEV object
230  *
231  * API to get vdev's interface name
232  *
233  * Return:
234  * @id: vdev's interface name
235  */
236 uint8_t *wlan_util_vdev_get_if_name(struct wlan_objmgr_vdev *vdev)
237 {
238 	uint8_t *name;
239 	struct vdev_osif_priv *osif_priv;
240 
241 	wlan_vdev_obj_lock(vdev);
242 
243 	osif_priv = wlan_vdev_get_ospriv(vdev);
244 	if (!osif_priv) {
245 		wlan_vdev_obj_unlock(vdev);
246 		return NULL;
247 	}
248 
249 	if (!osif_priv->wdev) {
250 		wlan_vdev_obj_unlock(vdev);
251 		return NULL;
252 	}
253 
254 	name = osif_priv->wdev->netdev->name;
255 	wlan_vdev_obj_unlock(vdev);
256 
257 	return name;
258 }
259 qdf_export_symbol(wlan_util_vdev_get_if_name);
260 
261 #ifdef CMN_VDEV_MLME_SM_ENABLE
262 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
263 			     void *arg)
264 {
265 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
266 	uint8_t *flag = (uint8_t *)arg;
267 
268 	wlan_vdev_obj_lock(vdev);
269 	if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS)
270 		*flag = 1;
271 
272 	wlan_vdev_obj_unlock(vdev);
273 }
274 
275 bool wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
276 {
277 	bool ret_val = false;
278 
279 	if (wlan_vdev_allow_connect_n_tx(vdev) == QDF_STATUS_SUCCESS)
280 		ret_val = true;
281 
282 	return ret_val;
283 }
284 
285 qdf_export_symbol(wlan_vdev_is_up);
286 #else
287 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object,
288 			     void *arg)
289 {
290 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
291 	uint8_t *flag = (uint8_t *)arg;
292 
293 	wlan_vdev_obj_lock(vdev);
294 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_RUN) ||
295 		(wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_DFS_WAIT))
296 		*flag = 1;
297 
298 	wlan_vdev_obj_unlock(vdev);
299 }
300 
301 bool wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev)
302 {
303 	bool ret_val = false;
304 
305 	wlan_vdev_obj_lock(vdev);
306 	if (wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_RUN)
307 		ret_val = true;
308 
309 	wlan_vdev_obj_unlock(vdev);
310 
311 	return ret_val;
312 }
313 
314 qdf_export_symbol(wlan_vdev_is_up);
315 #endif
316 
317 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev,
318 				    wlan_objmgr_ref_dbgid dbg_id)
319 {
320 	uint8_t flag = 0;
321 
322 	if (!pdev)
323 		return QDF_STATUS_E_INVAL;
324 
325 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active,
326 					  &flag, 0, dbg_id);
327 
328 	if (flag == 1)
329 		return QDF_STATUS_SUCCESS;
330 
331 	return QDF_STATUS_E_INVAL;
332 }
333 
334 #ifdef CMN_VDEV_MLME_SM_ENABLE
335 void wlan_util_change_map_index(uint32_t *map, uint8_t id, uint8_t set)
336 {
337 	uint8_t map_index = 0;
338 	uint8_t map_entry_size = 32;
339 	uint8_t adjust_index = 0;
340 
341 	/*
342 	 * Derive map_index and adjust_index to find actual DWORD
343 	 * the id map is present
344 	 */
345 	while ((id - adjust_index) >= map_entry_size) {
346 		map_index++;
347 		adjust_index = map_index * map_entry_size;
348 	}
349 	if (set)
350 		map[map_index] |= (1 << (id - adjust_index));
351 	else
352 		map[map_index] &= ~(1 << (id - adjust_index));
353 }
354 
355 bool wlan_util_map_index_is_set(uint32_t *map, uint8_t id)
356 {
357 	uint8_t map_index = 0;
358 	uint8_t map_entry_size = 32;
359 	uint8_t adjust_index = 0;
360 
361 	/*
362 	 * Derive map_index and adjust_index to find actual DWORD
363 	 * the id map is present
364 	 */
365 	while ((id - adjust_index) >= map_entry_size) {
366 		map_index++;
367 		adjust_index = map_index * map_entry_size;
368 	}
369 	if (map[map_index] & (1 << (id - adjust_index)))
370 		return true;
371 
372 	return false;
373 }
374 
375 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev,
376 					  void *object, void *arg)
377 {
378 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
379 	uint32_t *vdev_id_map = (uint32_t *)arg;
380 	uint8_t id = 0;
381 	struct wlan_objmgr_psoc *psoc;
382 
383 	psoc = wlan_pdev_get_psoc(pdev);
384 	if (!psoc)
385 		return;
386 
387 	wlan_vdev_obj_lock(vdev);
388 	if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) {
389 		id = wlan_vdev_get_id(vdev);
390 		/* Invalid vdev id */
391 		if (id >= wlan_psoc_get_max_vdev_count(psoc))
392 			return;
393 
394 		wlan_util_change_map_index(vdev_id_map, id, 1);
395 	}
396 
397 	wlan_vdev_obj_unlock(vdev);
398 }
399 
400 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev,
401 					       uint32_t *vdev_id_map,
402 					       wlan_objmgr_ref_dbgid dbg_id)
403 {
404 	if (!pdev)
405 		return QDF_STATUS_E_INVAL;
406 
407 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
408 					  wlan_vdev_chan_change_pending,
409 					  vdev_id_map, 0, dbg_id);
410 
411 	return QDF_STATUS_SUCCESS;
412 }
413 
414 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2)
415 {
416 	if (!qdf_mem_cmp(chan1, chan2, sizeof(struct wlan_channel)))
417 		return QDF_STATUS_SUCCESS;
418 
419 	return QDF_STATUS_E_FAILURE;
420 }
421 
422 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev,	void *object,
423 				 void *arg)
424 {
425 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
426 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
427 
428 	if (ch_filter->flag)
429 		return;
430 
431 	wlan_vdev_obj_lock(comp_vdev);
432 	wlan_vdev_obj_lock(ch_filter->vdev);
433 
434 	if (wlan_vdev_chan_config_valid(ch_filter->vdev) == QDF_STATUS_SUCCESS)
435 		if (wlan_chan_eq(wlan_vdev_mlme_get_des_chan(comp_vdev),
436 				 wlan_vdev_mlme_get_des_chan(ch_filter->vdev))
437 				 != QDF_STATUS_SUCCESS)
438 			ch_filter->flag = 1;
439 
440 	wlan_vdev_obj_unlock(ch_filter->vdev);
441 	wlan_vdev_obj_unlock(comp_vdev);
442 }
443 
444 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
445 					      struct wlan_objmgr_vdev *vdev,
446 					      wlan_objmgr_ref_dbgid dbg_id)
447 {
448 	struct wlan_vdev_ch_check_filter ch_filter;
449 
450 	if (!pdev)
451 		return QDF_STATUS_E_INVAL;
452 
453 	ch_filter.flag = 0;
454 	ch_filter.vdev = vdev;
455 
456 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
457 					  wlan_pdev_chan_match, &ch_filter, 0,
458 					  dbg_id);
459 
460 	if (ch_filter.flag == 0)
461 		return QDF_STATUS_SUCCESS;
462 
463 	return QDF_STATUS_E_FAILURE;
464 }
465 #endif
466 
467 void
468 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr,
469 			 int8_t *rssi)
470 {
471 	uint32_t snr;
472 
473 	if (db2dbm_enabled) {
474 		if (TGT_IS_VALID_RSSI(bcn_snr))
475 			*rssi = bcn_snr;
476 		else if (TGT_IS_VALID_RSSI(dat_snr))
477 			*rssi = dat_snr;
478 		else
479 			*rssi = TGT_NOISE_FLOOR_DBM;
480 	} else {
481 		if (TGT_IS_VALID_SNR(bcn_snr))
482 			snr = bcn_snr;
483 		else if (TGT_IS_VALID_SNR(dat_snr))
484 			snr = dat_snr;
485 		else
486 			snr = TGT_INVALID_SNR;
487 
488 		/* Get the absolute rssi value from the current rssi value */
489 		*rssi = snr + TGT_NOISE_FLOOR_DBM;
490 	}
491 }
492