xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/utils/src/wlan_utility.c (revision a175314c51a4ce5cec2835cc8a8c7dc0c1810915)
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 
30 uint32_t wlan_chan_to_freq(uint8_t chan)
31 {
32 	/* ch 0 - ch 13 */
33 	if (chan < WLAN_24_GHZ_CHANNEL_14)
34 		return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
35 	else if (chan == WLAN_24_GHZ_CHANNEL_14)
36 		return WLAN_CHAN_14_FREQ;
37 	else if (chan < WLAN_24_GHZ_CHANNEL_27)
38 		/* ch 15 - ch 26 */
39 		return WLAN_CHAN_15_FREQ +
40 		  (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ;
41 	else if (chan == WLAN_5_GHZ_CHANNEL_170)
42 		return WLAN_CHAN_170_FREQ;
43 	else
44 		return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ;
45 }
46 
47 uint8_t wlan_freq_to_chan(uint32_t freq)
48 {
49 	uint8_t chan;
50 
51 	if (freq > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ)
52 		chan = ((freq - WLAN_24_GHZ_BASE_FREQ) /
53 			WLAN_CHAN_SPACING_5MHZ);
54 	else if (freq == WLAN_CHAN_14_FREQ)
55 		chan = WLAN_24_GHZ_CHANNEL_14;
56 	else if ((freq > WLAN_24_GHZ_BASE_FREQ) &&
57 		(freq < WLAN_5_GHZ_BASE_FREQ))
58 		chan = (((freq - WLAN_CHAN_15_FREQ) /
59 			WLAN_CHAN_SPACING_20MHZ) +
60 			WLAN_24_GHZ_CHANNEL_15);
61 	else
62 		chan = (freq - WLAN_5_GHZ_BASE_FREQ) /
63 			WLAN_CHAN_SPACING_5MHZ;
64 
65 	return chan;
66 }
67 
68 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len)
69 {
70 	uint8_t elen;
71 
72 	while (ie_len) {
73 		if (ie_len < 2)
74 			return false;
75 
76 		elen = ie[1];
77 		ie_len -= 2;
78 		ie += 2;
79 		if (elen > ie_len)
80 			return false;
81 
82 		ie_len -= elen;
83 		ie += elen;
84 	}
85 
86 	return true;
87 }
88 
89 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid,
90 						     const uint8_t *oui,
91 						     uint8_t oui_size,
92 						     const uint8_t *ie,
93 						     uint16_t ie_len)
94 {
95 	int32_t left = ie_len;
96 	const uint8_t *ptr = ie;
97 	uint8_t elem_id, elem_len;
98 
99 	while (left >= 2) {
100 		elem_id  = ptr[0];
101 		elem_len = ptr[1];
102 		left -= 2;
103 
104 		if (elem_len > left)
105 			return NULL;
106 
107 		if (eid == elem_id) {
108 			/* if oui is not provide eid match is enough */
109 			if (!oui)
110 				return ptr;
111 
112 			/*
113 			 * if oui is provided and oui_size is more than left
114 			 * bytes, then we cannot have match
115 			 */
116 			if (oui_size > left)
117 				return NULL;
118 
119 			if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0)
120 				return ptr;
121 		}
122 
123 		left -= elem_len;
124 		ptr += (elem_len + 2);
125 	}
126 
127 	return NULL;
128 }
129 
130 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid,
131 					const uint8_t *ie,
132 					int ie_len)
133 {
134 	return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len);
135 }
136 
137 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui,
138 					       uint8_t oui_size,
139 					       const uint8_t *ie,
140 					       uint16_t ie_len)
141 {
142 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR,
143 					      oui, oui_size, ie, ie_len);
144 }
145 
146 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui,
147 					       uint8_t oui_size,
148 					       const uint8_t *ie,
149 					       uint16_t ie_len)
150 {
151 	return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT,
152 					      oui, oui_size, ie, ie_len);
153 }
154 
155 bool wlan_is_emulation_platform(uint32_t phy_version)
156 {
157 	if ((phy_version == 0xABC0) || (phy_version == 0xABC1) ||
158 		(phy_version == 0xABC2) || (phy_version == 0xABC3) ||
159 		(phy_version == 0xFFFF) || (phy_version == 0xABCD))
160 		return true;
161 
162 	return false;
163 }
164 
165 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc,
166 				      uint8_t vdev_id,
167 				      wlan_objmgr_ref_dbgid dbg_id)
168 {
169 	struct wlan_objmgr_vdev *vdev;
170 	struct wlan_objmgr_pdev *pdev = NULL;
171 	uint32_t pdev_id = WLAN_INVALID_PDEV_ID;
172 
173 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
174 						    vdev_id, dbg_id);
175 
176 	if (vdev) {
177 		pdev = wlan_vdev_get_pdev(vdev);
178 		if (pdev)
179 			pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
180 		wlan_objmgr_vdev_release_ref(vdev, dbg_id);
181 	}
182 
183 	return pdev_id;
184 }
185 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id);
186 
187 static void wlan_util_get_vdev_by_ifname_cb(struct wlan_objmgr_psoc *psoc,
188 					    void *obj, void *arg)
189 {
190 	struct wlan_objmgr_vdev *vdev = obj;
191 	struct wlan_find_vdev_filter *filter = arg;
192 
193 	if (filter->found_vdev)
194 		return;
195 
196 	wlan_vdev_obj_lock(vdev);
197 	if (!qdf_str_cmp(vdev->vdev_nif.osdev->wdev->netdev->name,
198 			 filter->ifname)) {
199 		filter->found_vdev = vdev;
200 	}
201 	wlan_vdev_obj_unlock(vdev);
202 }
203 
204 struct wlan_objmgr_vdev *wlan_util_get_vdev_by_ifname(
205 				struct wlan_objmgr_psoc *psoc, char *ifname,
206 				wlan_objmgr_ref_dbgid ref_id)
207 {
208 	QDF_STATUS status;
209 	struct wlan_find_vdev_filter filter = {0};
210 
211 	filter.ifname = ifname;
212 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
213 				     wlan_util_get_vdev_by_ifname_cb,
214 				     &filter, 0, ref_id);
215 
216 	if (!filter.found_vdev)
217 		return NULL;
218 
219 	status = wlan_objmgr_vdev_try_get_ref(filter.found_vdev, ref_id);
220 	if (QDF_IS_STATUS_ERROR(status))
221 		return NULL;
222 
223 	return filter.found_vdev;
224 }
225 
226 /**
227  * wlan_util_vdev_get_if_name() - get vdev's interface name
228  * @vdev: VDEV object
229  *
230  * API to get vdev's interface name
231  *
232  * Return:
233  * @id: vdev's interface name
234  */
235 uint8_t *wlan_util_vdev_get_if_name(struct wlan_objmgr_vdev *vdev)
236 {
237 	uint8_t *name;
238 	struct vdev_osif_priv *osif_priv;
239 
240 	wlan_vdev_obj_lock(vdev);
241 
242 	osif_priv = wlan_vdev_get_ospriv(vdev);
243 	if (!osif_priv) {
244 		wlan_vdev_obj_unlock(vdev);
245 		return NULL;
246 	}
247 
248 	if (!osif_priv->wdev) {
249 		wlan_vdev_obj_unlock(vdev);
250 		return NULL;
251 	}
252 
253 	name = osif_priv->wdev->netdev->name;
254 	wlan_vdev_obj_unlock(vdev);
255 
256 	return name;
257 }
258 qdf_export_symbol(wlan_util_vdev_get_if_name);
259 
260 static void wlan_vap_active(struct wlan_objmgr_pdev *pdev,
261 			void *object,
262 			void *arg)
263 {
264 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
265 	uint8_t *flag = (uint8_t *)arg;
266 
267 	wlan_vdev_obj_lock(vdev);
268 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_RUN) ||
269 		(wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_DFS_WAIT)) {
270 		*flag = 1;
271 	}
272 	wlan_vdev_obj_unlock(vdev);
273 }
274 
275 QDF_STATUS wlan_util_is_vap_active(struct wlan_objmgr_pdev *pdev,
276 				   wlan_objmgr_ref_dbgid dbg_id)
277 {
278 	uint8_t flag = 0;
279 
280 	if (!pdev)
281 		return QDF_STATUS_E_INVAL;
282 
283 	wlan_objmgr_pdev_iterate_obj_list(pdev,
284 				WLAN_VDEV_OP,
285 				wlan_vap_active,
286 				&flag, 0, dbg_id);
287 
288 	if (flag == 1)
289 		return QDF_STATUS_SUCCESS;
290 
291 	return QDF_STATUS_E_INVAL;
292 }
293