xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/dispatcher/src/wlan_scan_utils_api.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
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: Defines scan utility functions
21  */
22 
23 #include <wlan_cmn.h>
24 #include <wlan_scan_ucfg_api.h>
25 #include <wlan_scan_utils_api.h>
26 #include <../../core/src/wlan_scan_cache_db.h>
27 #include <../../core/src/wlan_scan_main.h>
28 
29 const char*
30 util_scan_get_ev_type_name(enum scan_event_type type)
31 {
32 	static const char * const event_name[] = {
33 		[SCAN_EVENT_TYPE_STARTED] = "STARTED",
34 		[SCAN_EVENT_TYPE_COMPLETED] = "COMPLETED",
35 		[SCAN_EVENT_TYPE_BSS_CHANNEL] = "HOME_CHANNEL",
36 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL] = "FOREIGN_CHANNEL",
37 		[SCAN_EVENT_TYPE_DEQUEUED] = "DEQUEUED",
38 		[SCAN_EVENT_TYPE_PREEMPTED] = "PREEMPTED",
39 		[SCAN_EVENT_TYPE_START_FAILED] = "START_FAILED",
40 		[SCAN_EVENT_TYPE_RESTARTED] = "RESTARTED",
41 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_EXIT] = "FOREIGN_CHANNEL_EXIT",
42 		[SCAN_EVENT_TYPE_SUSPENDED] = "SUSPENDED",
43 		[SCAN_EVENT_TYPE_RESUMED] = "RESUMED",
44 		[SCAN_EVENT_TYPE_NLO_COMPLETE] = "NLO_COMPLETE",
45 		[SCAN_EVENT_TYPE_NLO_MATCH] = "NLO_MATCH",
46 		[SCAN_EVENT_TYPE_INVALID] = "INVALID",
47 		[SCAN_EVENT_TYPE_GPIO_TIMEOUT] = "GPIO_TIMEOUT",
48 		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_START] =
49 			"RADIO_MEASUREMENT_START",
50 		[SCAN_EVENT_TYPE_RADIO_MEASUREMENT_END] =
51 			"RADIO_MEASUREMENT_END",
52 		[SCAN_EVENT_TYPE_BSSID_MATCH] = "BSSID_MATCH",
53 		[SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF] =
54 			"FOREIGN_CHANNEL_GET_NF",
55 	};
56 
57 	if (type >= SCAN_EVENT_TYPE_MAX)
58 		return "UNKNOWN";
59 
60 	return event_name[type];
61 }
62 
63 
64 const char*
65 util_scan_get_ev_reason_name(enum scan_completion_reason reason)
66 {
67 	static const char * const reason_name[] = {
68 		[SCAN_REASON_NONE] = "NONE",
69 		[SCAN_REASON_COMPLETED] = "COMPLETED",
70 		[SCAN_REASON_CANCELLED] = "CANCELLED",
71 		[SCAN_REASON_PREEMPTED] = "PREEMPTED",
72 		[SCAN_REASON_TIMEDOUT] = "TIMEDOUT",
73 		[SCAN_REASON_INTERNAL_FAILURE] = "INTERNAL_FAILURE",
74 		[SCAN_REASON_SUSPENDED] = "SUSPENDED",
75 		[SCAN_REASON_RUN_FAILED] = "RUN_FAILED",
76 		[SCAN_REASON_TERMINATION_FUNCTION] = "TERMINATION_FUNCTION",
77 		[SCAN_REASON_MAX_OFFCHAN_RETRIES] = "MAX_OFFCHAN_RETRIES",
78 	};
79 
80 	if (reason >= SCAN_REASON_MAX)
81 		return "UNKNOWN";
82 
83 	return reason_name[reason];
84 }
85 
86 qdf_time_t
87 util_get_last_scan_time(struct wlan_objmgr_vdev *vdev)
88 {
89 	uint8_t pdev_id;
90 	struct wlan_scan_obj *scan_obj;
91 
92 	if (!vdev) {
93 		scm_warn("null vdev");
94 		QDF_ASSERT(0);
95 		return 0;
96 	}
97 	pdev_id = wlan_scan_vdev_get_pdev_id(vdev);
98 	scan_obj = wlan_vdev_get_scan_obj(vdev);
99 
100 	return scan_obj->pdev_info[pdev_id].last_scan_time;
101 }
102 
103 enum wlan_band util_scan_scm_chan_to_band(uint32_t chan)
104 {
105 	if (WLAN_CHAN_IS_2GHZ(chan))
106 		return WLAN_BAND_2_4_GHZ;
107 
108 	return WLAN_BAND_5_GHZ;
109 }
110 
111 bool util_is_scan_entry_match(
112 	struct scan_cache_entry *entry1,
113 	struct scan_cache_entry *entry2)
114 {
115 
116 	if (entry1->cap_info.wlan_caps.ess !=
117 	   entry2->cap_info.wlan_caps.ess)
118 		return false;
119 
120 	if (entry1->cap_info.wlan_caps.ess &&
121 	   !qdf_mem_cmp(entry1->bssid.bytes,
122 	   entry2->bssid.bytes, QDF_MAC_ADDR_SIZE) &&
123 	   util_scan_scm_chan_to_band(
124 	   entry1->channel.chan_idx) ==
125 	   util_scan_scm_chan_to_band(entry2->channel.chan_idx)) {
126 		/* Check for BSS */
127 		if (util_is_ssid_match(
128 		   &entry1->ssid, &entry2->ssid))
129 			return true;
130 	} else if (entry1->cap_info.wlan_caps.ibss &&
131 	   (entry1->channel.chan_idx ==
132 	   entry2->channel.chan_idx)) {
133 		/*
134 		 * Same channel cannot have same SSID for
135 		 * different IBSS, so no need to check BSSID
136 		 */
137 		if (util_is_ssid_match(
138 		   &entry1->ssid, &entry2->ssid))
139 			return true;
140 	} else if (!entry1->cap_info.wlan_caps.ibss &&
141 	   !entry1->cap_info.wlan_caps.ess &&
142 	   !qdf_mem_cmp(entry1->bssid.bytes,
143 	   entry2->bssid.bytes, QDF_MAC_ADDR_SIZE)) {
144 		/* In case of P2P devices, ess and ibss will be set to zero */
145 		return true;
146 	}
147 
148 	return false;
149 }
150 
151 static bool util_is_pureg_rate(uint8_t *rates, uint8_t nrates)
152 {
153 	static const uint8_t g_rates[] = {12, 18, 24, 36, 48, 72, 96, 108};
154 	bool pureg = false;
155 	uint8_t i, j;
156 
157 	for (i = 0; i < nrates; i++) {
158 		for (j = 0; j < QDF_ARRAY_SIZE(g_rates); j++) {
159 			if (WLAN_RV(rates[i]) == g_rates[j]) {
160 				pureg = true;
161 				break;
162 			}
163 		}
164 		if (pureg)
165 			break;
166 	}
167 
168 	return pureg;
169 }
170 static enum wlan_phymode
171 util_scan_get_phymode_5g(struct scan_cache_entry *scan_params)
172 {
173 	enum wlan_phymode phymode = WLAN_PHYMODE_AUTO;
174 	uint16_t ht_cap = 0;
175 	struct htcap_cmn_ie *htcap;
176 	struct wlan_ie_htinfo_cmn *htinfo;
177 	struct wlan_ie_vhtop *vhtop;
178 
179 	htcap = (struct htcap_cmn_ie *)
180 		util_scan_entry_htcap(scan_params);
181 	htinfo = (struct wlan_ie_htinfo_cmn *)
182 		util_scan_entry_htinfo(scan_params);
183 	vhtop = (struct wlan_ie_vhtop *)
184 		util_scan_entry_vhtop(scan_params);
185 
186 	if (!(htcap && htinfo))
187 		return WLAN_PHYMODE_11A;
188 
189 	if (htcap)
190 		ht_cap = le16toh(htcap->hc_cap);
191 
192 	if (util_scan_entry_vhtcap(scan_params) && vhtop) {
193 		switch (vhtop->vht_op_chwidth) {
194 		case WLAN_VHTOP_CHWIDTH_2040:
195 			if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
196 			   (htinfo->hi_extchoff ==
197 			   WLAN_HTINFO_EXTOFFSET_ABOVE))
198 				phymode = WLAN_PHYMODE_11AC_VHT40PLUS;
199 			else if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
200 			   (htinfo->hi_extchoff ==
201 			   WLAN_HTINFO_EXTOFFSET_BELOW))
202 				phymode = WLAN_PHYMODE_11AC_VHT40MINUS;
203 			else
204 				phymode = WLAN_PHYMODE_11AC_VHT20;
205 			break;
206 		case WLAN_VHTOP_CHWIDTH_80:
207 			if (WLAN_IS_REVSIG_VHT80_80(vhtop))
208 				phymode = WLAN_PHYMODE_11AC_VHT80_80;
209 			else if (WLAN_IS_REVSIG_VHT160(vhtop))
210 				phymode = WLAN_PHYMODE_11AC_VHT160;
211 			else
212 				phymode = WLAN_PHYMODE_11AC_VHT80;
213 			break;
214 		case WLAN_VHTOP_CHWIDTH_160:
215 			phymode = WLAN_PHYMODE_11AC_VHT160;
216 			break;
217 		case WLAN_VHTOP_CHWIDTH_80_80:
218 			phymode = WLAN_PHYMODE_11AC_VHT80_80;
219 			break;
220 		default:
221 			scm_err("bad channel: %d",
222 					vhtop->vht_op_chwidth);
223 			break;
224 		}
225 	} else if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
226 	   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_ABOVE))
227 		phymode = WLAN_PHYMODE_11NA_HT40PLUS;
228 	else if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
229 	   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_BELOW))
230 		phymode = WLAN_PHYMODE_11NA_HT40MINUS;
231 	else
232 		phymode = WLAN_PHYMODE_11NA_HT20;
233 
234 	return phymode;
235 }
236 
237 static enum wlan_phymode
238 util_scan_get_phymode_2g(struct scan_cache_entry *scan_params)
239 {
240 	enum wlan_phymode phymode = WLAN_PHYMODE_AUTO;
241 	uint16_t ht_cap = 0;
242 	struct htcap_cmn_ie *htcap;
243 	struct wlan_ie_htinfo_cmn *htinfo;
244 	struct wlan_ie_vhtop *vhtop;
245 
246 	htcap = (struct htcap_cmn_ie *)
247 		util_scan_entry_htcap(scan_params);
248 	htinfo = (struct wlan_ie_htinfo_cmn *)
249 		util_scan_entry_htinfo(scan_params);
250 	vhtop = (struct wlan_ie_vhtop *)
251 		util_scan_entry_vhtop(scan_params);
252 
253 	if (htcap)
254 		ht_cap = le16toh(htcap->hc_cap);
255 
256 	if (htcap && htinfo) {
257 		if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
258 		   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_ABOVE))
259 			phymode = WLAN_PHYMODE_11NG_HT40PLUS;
260 		else if ((ht_cap & WLAN_HTCAP_C_CHWIDTH40) &&
261 		   (htinfo->hi_extchoff == WLAN_HTINFO_EXTOFFSET_BELOW))
262 			phymode = WLAN_PHYMODE_11NG_HT40MINUS;
263 		else
264 			phymode = WLAN_PHYMODE_11NG_HT20;
265 	} else if (util_scan_entry_xrates(scan_params)) {
266 		/* only 11G stations will have more than 8 rates */
267 		phymode = WLAN_PHYMODE_11G;
268 	} else {
269 		/* Some mischievous g-only APs do not set extended rates */
270 		if (util_scan_entry_rates(scan_params)) {
271 			if (util_is_pureg_rate(&scan_params->ie_list.rates[2],
272 			   scan_params->ie_list.rates[1]))
273 				phymode = WLAN_PHYMODE_11G;
274 			else
275 				phymode = WLAN_PHYMODE_11B;
276 		} else {
277 			phymode = WLAN_PHYMODE_11B;
278 		}
279 	}
280 
281 	return phymode;
282 }
283 
284 static QDF_STATUS
285 util_scan_parse_chan_switch_wrapper_ie(struct scan_cache_entry *scan_params,
286 	struct ie_header *sub_ie, qdf_size_t sub_ie_len)
287 {
288 	/* Walk through to check nothing is malformed */
289 	while (sub_ie_len >= sizeof(struct ie_header)) {
290 		/* At least one more header is present */
291 		sub_ie_len -= sizeof(struct ie_header);
292 
293 		if (sub_ie->ie_len == 0) {
294 			sub_ie += 1;
295 			continue;
296 		}
297 		if (sub_ie_len < sub_ie->ie_len) {
298 			scm_err("Incomplete corrupted IE:%x",
299 				WLAN_ELEMID_CHAN_SWITCH_WRAP);
300 			return QDF_STATUS_E_INVAL;
301 		}
302 		switch (sub_ie->ie_id) {
303 		case WLAN_ELEMID_COUNTRY:
304 			scan_params->ie_list.country = (uint8_t *)sub_ie;
305 			break;
306 		case WLAN_ELEMID_WIDE_BAND_CHAN_SWITCH:
307 			scan_params->ie_list.widebw = (uint8_t *)sub_ie;
308 			break;
309 		case WLAN_ELEMID_VHT_TX_PWR_ENVLP:
310 			scan_params->ie_list.txpwrenvlp = (uint8_t *)sub_ie;
311 			break;
312 		}
313 		/* Consume sub info element */
314 		sub_ie_len -= sub_ie->ie_len;
315 		/* go to next Sub IE */
316 		sub_ie = (struct ie_header *)
317 			(((uint8_t *) sub_ie) +
318 			sizeof(struct ie_header) + sub_ie->ie_len);
319 	}
320 
321 	return QDF_STATUS_SUCCESS;
322 }
323 
324 bool
325 util_scan_is_hidden_ssid(struct ie_ssid *ssid)
326 {
327 	uint8_t i;
328 
329 	/*
330 	 * We flag this as Hidden SSID if the Length is 0
331 	 * of the SSID only contains 0's
332 	 */
333 	if (!ssid || !ssid->ssid_len)
334 		return true;
335 
336 	for (i = 0; i < ssid->ssid_len; i++)
337 		if (ssid->ssid[i] != 0)
338 			return false;
339 
340 	/* All 0's */
341 	return true;
342 }
343 
344 static QDF_STATUS
345 util_scan_parse_extn_ie(struct scan_cache_entry *scan_params,
346 	struct ie_header *ie)
347 {
348 	struct extn_ie_header *extn_ie = (struct extn_ie_header *) ie;
349 
350 	switch (extn_ie->ie_extn_id) {
351 	case WLAN_EXTN_ELEMID_SRP:
352 		scan_params->ie_list.srp   = (uint8_t *)ie;
353 		break;
354 	case WLAN_EXTN_ELEMID_HECAP:
355 		scan_params->ie_list.hecap = (uint8_t *)ie;
356 		break;
357 	case WLAN_EXTN_ELEMID_HEOP:
358 		scan_params->ie_list.heop  = (uint8_t *)ie;
359 		break;
360 	case WLAN_EXTN_ELEMID_ESP:
361 		scan_params->ie_list.esp = (uint8_t *)ie;
362 		break;
363 	default:
364 		break;
365 	}
366 	return QDF_STATUS_SUCCESS;
367 }
368 
369 static QDF_STATUS
370 util_scan_parse_vendor_ie(struct scan_cache_entry *scan_params,
371 	struct ie_header *ie)
372 {
373 	if (scan_params->ie_list.vendor == NULL)
374 		scan_params->ie_list.vendor = (uint8_t *)ie;
375 
376 	if (is_wpa_oui((uint8_t *)ie)) {
377 		scan_params->ie_list.wpa = (uint8_t *)ie;
378 	} else if (is_wps_oui((uint8_t *)ie)) {
379 		scan_params->ie_list.wps = (uint8_t *)ie;
380 		/* WCN IE should be a subset of WPS IE */
381 		if (is_wcn_oui((uint8_t *)ie))
382 			scan_params->ie_list.wcn = (uint8_t *)ie;
383 	} else if (is_wme_param((uint8_t *)ie)) {
384 		scan_params->ie_list.wmeparam = (uint8_t *)ie;
385 	} else if (is_wme_info((uint8_t *)ie)) {
386 		scan_params->ie_list.wmeinfo = (uint8_t *)ie;
387 	} else if (is_atheros_oui((uint8_t *)ie)) {
388 		scan_params->ie_list.athcaps = (uint8_t *)ie;
389 	} else if (is_atheros_extcap_oui((uint8_t *)ie)) {
390 		scan_params->ie_list.athextcaps = (uint8_t *)ie;
391 	} else if (is_sfa_oui((uint8_t *)ie)) {
392 		scan_params->ie_list.sfa = (uint8_t *)ie;
393 	} else if (is_p2p_oui((uint8_t *)ie)) {
394 		scan_params->ie_list.p2p = (uint8_t *)ie;
395 	} else if (is_qca_son_oui((uint8_t *)ie,
396 				  QCA_OUI_WHC_AP_INFO_SUBTYPE)) {
397 		scan_params->ie_list.sonadv = (uint8_t *)ie;
398 	} else if (is_ht_cap((uint8_t *)ie)) {
399 		/* we only care if there isn't already an HT IE (ANA) */
400 		if (scan_params->ie_list.htcap == NULL) {
401 			if (ie->ie_len != (WLAN_VENDOR_HT_IE_OFFSET_LEN +
402 					   sizeof(struct htcap_cmn_ie)))
403 				return QDF_STATUS_E_INVAL;
404 			scan_params->ie_list.htcap =
405 			 (uint8_t *)&(((struct wlan_vendor_ie_htcap *)ie)->ie);
406 		}
407 	} else if (is_ht_info((uint8_t *)ie)) {
408 		/* we only care if there isn't already an HT IE (ANA) */
409 		if (scan_params->ie_list.htinfo == NULL) {
410 			if (ie->ie_len != WLAN_VENDOR_HT_IE_OFFSET_LEN +
411 					  sizeof(struct wlan_ie_htinfo_cmn))
412 				return QDF_STATUS_E_INVAL;
413 			scan_params->ie_list.htinfo =
414 			  (uint8_t *)&(((struct wlan_vendor_ie_htinfo *)
415 			  ie)->hi_ie);
416 		}
417 	} else if (is_interop_vht((uint8_t *)ie) &&
418 	    !(scan_params->ie_list.vhtop)) {
419 		uint8_t *vendor_ie = (uint8_t *)(ie);
420 
421 		if (ie->ie_len < ((WLAN_VENDOR_VHTCAP_IE_OFFSET +
422 				 sizeof(struct wlan_ie_vhtcaps)) -
423 				 sizeof(struct ie_header)))
424 			return QDF_STATUS_E_INVAL;
425 		vendor_ie = ((uint8_t *)(ie)) + WLAN_VENDOR_VHTCAP_IE_OFFSET;
426 		if (vendor_ie[1] != (sizeof(struct wlan_ie_vhtcaps)) -
427 				      sizeof(struct ie_header))
428 			return QDF_STATUS_E_INVAL;
429 		/* location where Interop Vht Cap IE and VHT OP IE Present */
430 		scan_params->ie_list.vhtcap = (((uint8_t *)(ie)) +
431 						WLAN_VENDOR_VHTCAP_IE_OFFSET);
432 		if (ie->ie_len > ((WLAN_VENDOR_VHTCAP_IE_OFFSET +
433 				 sizeof(struct wlan_ie_vhtcaps)) -
434 				 sizeof(struct ie_header)) &&
435 		    ie->ie_len < ((WLAN_VENDOR_VHTOP_IE_OFFSET +
436 				  sizeof(struct wlan_ie_vhtop)) -
437 				  sizeof(struct ie_header)))
438 			return QDF_STATUS_E_INVAL;
439 		vendor_ie = ((uint8_t *)(ie)) + WLAN_VENDOR_VHTOP_IE_OFFSET;
440 		if (vendor_ie[1] != (sizeof(struct wlan_ie_vhtop) -
441 				     sizeof(struct ie_header)))
442 			return QDF_STATUS_E_INVAL;
443 		scan_params->ie_list.vhtop = (((uint8_t *)(ie)) +
444 						WLAN_VENDOR_VHTOP_IE_OFFSET);
445 	} else if (is_bwnss_oui((uint8_t *)ie)) {
446 		/*
447 		 * Bandwidth-NSS map has sub-type & version.
448 		 * hence copy data just after version byte
449 		 */
450 		scan_params->ie_list.bwnss_map = (((uint8_t *)ie) + 8);
451 	} else if (is_mbo_oce_oui((uint8_t *)ie)) {
452 		scan_params->ie_list.mbo_oce = (uint8_t *)ie;
453 	}
454 	return QDF_STATUS_SUCCESS;
455 }
456 
457 static QDF_STATUS
458 util_scan_populate_bcn_ie_list(struct scan_cache_entry *scan_params)
459 {
460 	struct ie_header *ie, *sub_ie;
461 	uint32_t ie_len, sub_ie_len;
462 	QDF_STATUS status;
463 
464 	ie_len = util_scan_entry_ie_len(scan_params);
465 	ie = (struct ie_header *)
466 		  util_scan_entry_ie_data(scan_params);
467 
468 	while (ie_len >= sizeof(struct ie_header)) {
469 		ie_len -= sizeof(struct ie_header);
470 
471 		if (!ie->ie_len) {
472 			ie += 1;
473 			continue;
474 		}
475 
476 		if (ie_len < ie->ie_len) {
477 			scm_err("Incomplete corrupted IE:%x",
478 				ie->ie_id);
479 			return QDF_STATUS_E_INVAL;
480 		}
481 
482 		switch (ie->ie_id) {
483 		case WLAN_ELEMID_SSID:
484 			if (ie->ie_len > (sizeof(struct ie_ssid) -
485 					  sizeof(struct ie_header)))
486 				return QDF_STATUS_E_INVAL;
487 			scan_params->ie_list.ssid = (uint8_t *)ie;
488 			break;
489 		case WLAN_ELEMID_RATES:
490 			if (ie->ie_len > WLAN_SUPPORTED_RATES_IE_MAX_LEN)
491 				return QDF_STATUS_E_INVAL;
492 			scan_params->ie_list.rates = (uint8_t *)ie;
493 			break;
494 		case WLAN_ELEMID_DSPARMS:
495 			if (ie->ie_len != WLAN_DS_PARAM_IE_MAX_LEN)
496 				return QDF_STATUS_E_INVAL;
497 			scan_params->ie_list.ds_param = (uint8_t *)ie;
498 			scan_params->channel.chan_idx =
499 				((struct ds_ie *)ie)->cur_chan;
500 			break;
501 		case WLAN_ELEMID_TIM:
502 			if (ie->ie_len < WLAN_TIM_IE_MIN_LENGTH)
503 				return QDF_STATUS_E_INVAL;
504 			scan_params->ie_list.tim = (uint8_t *)ie;
505 			scan_params->dtim_period =
506 				((struct wlan_tim_ie *)ie)->tim_period;
507 			break;
508 		case WLAN_ELEMID_COUNTRY:
509 			if (ie->ie_len < WLAN_COUNTRY_IE_MIN_LEN)
510 				return QDF_STATUS_E_INVAL;
511 			scan_params->ie_list.country = (uint8_t *)ie;
512 			break;
513 		case WLAN_ELEMID_QBSS_LOAD:
514 			if (ie->ie_len != sizeof(struct qbss_load_ie) -
515 					  sizeof(struct ie_header))
516 				return QDF_STATUS_E_INVAL;
517 			scan_params->ie_list.qbssload = (uint8_t *)ie;
518 			break;
519 		case WLAN_ELEMID_CHANSWITCHANN:
520 			if (ie->ie_len != WLAN_CSA_IE_MAX_LEN)
521 				return QDF_STATUS_E_INVAL;
522 			scan_params->ie_list.csa = (uint8_t *)ie;
523 			break;
524 		case WLAN_ELEMID_IBSSDFS:
525 			if (ie->ie_len < WLAN_IBSSDFS_IE_MIN_LEN)
526 				return QDF_STATUS_E_INVAL;
527 			scan_params->ie_list.ibssdfs = (uint8_t *)ie;
528 			break;
529 		case WLAN_ELEMID_QUIET:
530 			if (ie->ie_len != WLAN_QUIET_IE_MAX_LEN)
531 				return QDF_STATUS_E_INVAL;
532 			scan_params->ie_list.quiet = (uint8_t *)ie;
533 			break;
534 		case WLAN_ELEMID_ERP:
535 			if (ie->ie_len != (sizeof(struct erp_ie) -
536 					    sizeof(struct ie_header)))
537 				return QDF_STATUS_E_INVAL;
538 			scan_params->erp = ((struct erp_ie *)ie)->value;
539 			break;
540 		case WLAN_ELEMID_HTCAP_ANA:
541 			if (ie->ie_len != sizeof(struct htcap_cmn_ie))
542 				return QDF_STATUS_E_INVAL;
543 			scan_params->ie_list.htcap =
544 				(uint8_t *)&(((struct htcap_ie *)ie)->ie);
545 			break;
546 		case WLAN_ELEMID_RSN:
547 			if (ie->ie_len < WLAN_RSN_IE_MIN_LEN)
548 				return QDF_STATUS_E_INVAL;
549 			scan_params->ie_list.rsn = (uint8_t *)ie;
550 			break;
551 		case WLAN_ELEMID_XRATES:
552 			scan_params->ie_list.xrates = (uint8_t *)ie;
553 			break;
554 		case WLAN_ELEMID_EXTCHANSWITCHANN:
555 			if (ie->ie_len != WLAN_XCSA_IE_MAX_LEN)
556 				return QDF_STATUS_E_INVAL;
557 			scan_params->ie_list.xcsa = (uint8_t *)ie;
558 			break;
559 		case WLAN_ELEMID_SECCHANOFFSET:
560 			if (ie->ie_len != WLAN_SECCHANOFF_IE_MAX_LEN)
561 				return QDF_STATUS_E_INVAL;
562 			scan_params->ie_list.secchanoff = (uint8_t *)ie;
563 			break;
564 		case WLAN_ELEMID_HTINFO_ANA:
565 			if (ie->ie_len != sizeof(struct wlan_ie_htinfo_cmn))
566 				return QDF_STATUS_E_INVAL;
567 			scan_params->ie_list.htinfo =
568 			  (uint8_t *)&(((struct wlan_ie_htinfo *) ie)->hi_ie);
569 			scan_params->channel.chan_idx =
570 			  ((struct wlan_ie_htinfo_cmn *)
571 			  (scan_params->ie_list.htinfo))->hi_ctrlchannel;
572 			break;
573 		case WLAN_ELEMID_WAPI:
574 			if (ie->ie_len < WLAN_WAPI_IE_MIN_LEN)
575 				return QDF_STATUS_E_INVAL;
576 			scan_params->ie_list.wapi = (uint8_t *)ie;
577 			break;
578 		case WLAN_ELEMID_XCAPS:
579 			if (ie->ie_len > WLAN_EXTCAP_IE_MAX_LEN)
580 				return QDF_STATUS_E_INVAL;
581 			scan_params->ie_list.extcaps = (uint8_t *)ie;
582 			break;
583 		case WLAN_ELEMID_VHTCAP:
584 			if (ie->ie_len != (sizeof(struct wlan_ie_vhtcaps) -
585 					   sizeof(struct ie_header)))
586 				return QDF_STATUS_E_INVAL;
587 			scan_params->ie_list.vhtcap = (uint8_t *)ie;
588 			break;
589 		case WLAN_ELEMID_VHTOP:
590 			if (ie->ie_len != (sizeof(struct wlan_ie_vhtop) -
591 					   sizeof(struct ie_header)))
592 				return QDF_STATUS_E_INVAL;
593 			scan_params->ie_list.vhtop = (uint8_t *)ie;
594 			break;
595 		case WLAN_ELEMID_OP_MODE_NOTIFY:
596 			if (ie->ie_len != WLAN_OPMODE_IE_MAX_LEN)
597 				return QDF_STATUS_E_INVAL;
598 				scan_params->ie_list.opmode = (uint8_t *)ie;
599 			break;
600 		case WLAN_ELEMID_MOBILITY_DOMAIN:
601 			if (ie->ie_len != WLAN_MOBILITY_DOMAIN_IE_MAX_LEN)
602 				return QDF_STATUS_E_INVAL;
603 			scan_params->ie_list.mdie = (uint8_t *)ie;
604 			break;
605 		case WLAN_ELEMID_VENDOR:
606 			status = util_scan_parse_vendor_ie(scan_params,
607 							   ie);
608 			if (QDF_IS_STATUS_ERROR(status))
609 				return status;
610 			break;
611 		case WLAN_ELEMID_CHAN_SWITCH_WRAP:
612 			scan_params->ie_list.cswrp = (uint8_t *)ie;
613 			/* Go to next sub IE */
614 			sub_ie = (struct ie_header *)
615 			(((uint8_t *)ie) + sizeof(struct ie_header));
616 			sub_ie_len = ie->ie_len;
617 			status =
618 				util_scan_parse_chan_switch_wrapper_ie(
619 					scan_params, sub_ie, sub_ie_len);
620 			if (QDF_IS_STATUS_ERROR(status)) {
621 				scm_err("failed to parse chan_switch_wrapper_ie");
622 				return status;
623 			}
624 			break;
625 		case WLAN_ELEMID_FILS_INDICATION:
626 			if (ie->ie_len < WLAN_FILS_INDICATION_IE_MIN_LEN)
627 				return QDF_STATUS_E_INVAL;
628 			scan_params->ie_list.fils_indication = (uint8_t *)ie;
629 			break;
630 		case WLAN_ELEMID_EXTN_ELEM:
631 			status = util_scan_parse_extn_ie(scan_params, ie);
632 			if (QDF_IS_STATUS_ERROR(status))
633 				return status;
634 			break;
635 		default:
636 			break;
637 		}
638 
639 		/* Consume info element */
640 		ie_len -= ie->ie_len;
641 		/* Go to next IE */
642 		ie = (struct ie_header *)
643 			(((uint8_t *) ie) +
644 			sizeof(struct ie_header) +
645 			ie->ie_len);
646 	}
647 
648 	return QDF_STATUS_SUCCESS;
649 }
650 
651 /**
652  * util_scan_update_esp_data: update ESP params from beacon/probe response
653  * @esp_information: pointer to wlan_esp_information
654  * @scan_entry: new received entry
655  *
656  * The Estimated Service Parameters element is
657  * used by a AP to provide information to another STA which
658  * can then use the information as input to an algorithm to
659  * generate an estimate of throughput between the two STAs.
660  * The ESP Information List field contains from 1 to 4 ESP
661  * Information fields(each field 24 bits), each corresponding
662  * to an access category for which estimated service parameters
663  * information is provided.
664  *
665  * Return: None
666  */
667 static void util_scan_update_esp_data(struct wlan_esp_ie *esp_information,
668 		struct scan_cache_entry *scan_entry)
669 {
670 
671 	uint8_t *data;
672 	int i = 0;
673 	uint64_t total_elements;
674 	struct wlan_esp_info *esp_info;
675 	struct wlan_esp_ie *esp_ie;
676 
677 	esp_ie = (struct wlan_esp_ie *)
678 		util_scan_entry_esp_info(scan_entry);
679 
680 	total_elements  = esp_ie->esp_len;
681 	data = (uint8_t *)esp_ie + 3;
682 	do_div(total_elements, ESP_INFORMATION_LIST_LENGTH);
683 
684 	if (total_elements > MAX_ESP_INFORMATION_FIELD) {
685 		scm_err("No of Air time fractions are greater than supported");
686 		return;
687 	}
688 
689 	for (i = 0; i < total_elements; i++) {
690 		esp_info = (struct wlan_esp_info *)data;
691 		if (esp_info->access_category == ESP_AC_BK) {
692 			qdf_mem_copy(&esp_information->esp_info_AC_BK,
693 					data, 3);
694 			data = data + ESP_INFORMATION_LIST_LENGTH;
695 			continue;
696 		}
697 		if (esp_info->access_category == ESP_AC_BE) {
698 			qdf_mem_copy(&esp_information->esp_info_AC_BE,
699 					data, 3);
700 			data = data + ESP_INFORMATION_LIST_LENGTH;
701 			continue;
702 		}
703 		if (esp_info->access_category == ESP_AC_VI) {
704 			qdf_mem_copy(&esp_information->esp_info_AC_VI,
705 					data, 3);
706 			data = data + ESP_INFORMATION_LIST_LENGTH;
707 			continue;
708 		}
709 		if (esp_info->access_category == ESP_AC_VO) {
710 			qdf_mem_copy(&esp_information->esp_info_AC_VO,
711 					data, 3);
712 			data = data + ESP_INFORMATION_LIST_LENGTH;
713 			break;
714 		}
715 	}
716 }
717 
718 /**
719  * util_scan_scm_update_bss_with_esp_dataa: calculate estimated air time
720  * fraction
721  * @scan_entry: new received entry
722  *
723  * This function process all Access category ESP params and provide
724  * best effort air time fraction.
725  * If best effort is not available, it will choose VI, VO and BK in sequence
726  *
727  */
728 static void util_scan_scm_update_bss_with_esp_data(
729 		struct scan_cache_entry *scan_entry)
730 {
731 	uint8_t air_time_fraction = 0;
732 	struct wlan_esp_ie esp_information;
733 
734 	if (!scan_entry->ie_list.esp)
735 		return;
736 
737 	util_scan_update_esp_data(&esp_information, scan_entry);
738 
739 	/*
740 	 * If the ESP metric is transmitting multiple airtime fractions, then
741 	 * follow the sequence AC_BE, AC_VI, AC_VO, AC_BK and pick whichever is
742 	 * the first one available
743 	 */
744 	if (esp_information.esp_info_AC_BE.access_category
745 			== ESP_AC_BE)
746 		air_time_fraction =
747 			esp_information.esp_info_AC_BE.
748 			estimated_air_fraction;
749 	else if (esp_information.esp_info_AC_VI.access_category
750 			== ESP_AC_VI)
751 		air_time_fraction =
752 			esp_information.esp_info_AC_VI.
753 			estimated_air_fraction;
754 	else if (esp_information.esp_info_AC_VO.access_category
755 			== ESP_AC_VO)
756 		air_time_fraction =
757 			esp_information.esp_info_AC_VO.
758 			estimated_air_fraction;
759 	else if (esp_information.esp_info_AC_BK.access_category
760 			== ESP_AC_BK)
761 		air_time_fraction =
762 			esp_information.esp_info_AC_BK.
763 				estimated_air_fraction;
764 	scan_entry->air_time_fraction = air_time_fraction;
765 }
766 
767 /**
768  * util_scan_scm_calc_nss_supported_by_ap() - finds out nss from AP
769  * @scan_entry: new received entry
770  *
771  * Return: number of nss advertised by AP
772  */
773 static int util_scan_scm_calc_nss_supported_by_ap(
774 		struct scan_cache_entry *scan_params)
775 {
776 	struct htcap_cmn_ie *htcap;
777 	struct wlan_ie_vhtcaps *vhtcaps;
778 	uint8_t rx_mcs_map;
779 
780 	htcap = (struct htcap_cmn_ie *)
781 		util_scan_entry_htcap(scan_params);
782 	vhtcaps = (struct wlan_ie_vhtcaps *)
783 		util_scan_entry_vhtcap(scan_params);
784 	if (vhtcaps) {
785 		rx_mcs_map = vhtcaps->rx_mcs_map;
786 		if ((rx_mcs_map & 0xC0) != 0xC0)
787 			return 4;
788 
789 		if ((rx_mcs_map & 0x30) != 0x30)
790 			return 3;
791 
792 		if ((rx_mcs_map & 0x0C) != 0x0C)
793 			return 2;
794 	} else if (htcap) {
795 		if (htcap->mcsset[3])
796 			return 4;
797 
798 		if (htcap->mcsset[2])
799 			return 3;
800 
801 		if (htcap->mcsset[1])
802 			return 2;
803 
804 	}
805 	return 1;
806 }
807 
808 qdf_list_t *
809 util_scan_unpack_beacon_frame(uint8_t *frame,
810 	qdf_size_t frame_len, uint32_t frm_subtype,
811 	struct mgmt_rx_event_params *rx_param)
812 {
813 	struct wlan_frame_hdr *hdr;
814 	struct wlan_bcn_frame *bcn;
815 	QDF_STATUS status;
816 	struct ie_ssid *ssid;
817 	struct scan_cache_entry *scan_entry;
818 	struct qbss_load_ie *qbss_load;
819 	qdf_list_t *scan_list;
820 	struct scan_cache_node *scan_node;
821 
822 	scan_list = qdf_mem_malloc(sizeof(*scan_list));
823 	if (!scan_list) {
824 		scm_err("failed to allocate scan_list");
825 		return NULL;
826 	}
827 	qdf_list_create(scan_list, MAX_SCAN_CACHE_SIZE);
828 
829 	scan_entry = qdf_mem_malloc(sizeof(*scan_entry));
830 	if (!scan_entry) {
831 		scm_err("failed to allocate memory for scan_entry");
832 		qdf_mem_free(scan_list);
833 		return NULL;
834 	}
835 	scan_entry->raw_frame.ptr =
836 			qdf_mem_malloc(frame_len);
837 	if (!scan_entry->raw_frame.ptr) {
838 		scm_err("failed to allocate memory for frame");
839 		qdf_mem_free(scan_entry);
840 		qdf_mem_free(scan_list);
841 		return NULL;
842 	}
843 
844 	bcn = (struct wlan_bcn_frame *)
845 			   (frame + sizeof(*hdr));
846 	hdr = (struct wlan_frame_hdr *)frame;
847 
848 	/* update timestamp in nanoseconds needed by kernel layers */
849 	scan_entry->boottime_ns = qdf_get_monotonic_boottime_ns();
850 
851 	scan_entry->frm_subtype = frm_subtype;
852 	qdf_mem_copy(scan_entry->bssid.bytes,
853 		hdr->i_addr3, QDF_MAC_ADDR_SIZE);
854 	/* Scr addr */
855 	qdf_mem_copy(scan_entry->mac_addr.bytes,
856 		hdr->i_addr2, QDF_MAC_ADDR_SIZE);
857 	scan_entry->seq_num =
858 		(le16toh(*(uint16_t *)hdr->i_seq) >> WLAN_SEQ_SEQ_SHIFT);
859 
860 	scan_entry->rssi_raw = rx_param->rssi;
861 	scan_entry->avg_rssi = WLAN_RSSI_IN(scan_entry->rssi_raw);
862 	scan_entry->tsf_delta = rx_param->tsf_delta;
863 
864 	/* Copy per chain rssi to scan entry */
865 	qdf_mem_copy(scan_entry->per_chain_snr, rx_param->rssi_ctl,
866 		     WLAN_MGMT_TXRX_HOST_MAX_ANTENNA);
867 
868 	/* store jiffies */
869 	scan_entry->rrm_parent_tsf = (u_int32_t) qdf_system_ticks();
870 
871 	scan_entry->bcn_int = le16toh(bcn->beacon_interval);
872 
873 	/*
874 	 * In case if the beacon dosnt have
875 	 * valid beacon interval falback to def
876 	 */
877 	if (!scan_entry->bcn_int)
878 		scan_entry->bcn_int = 100;
879 	scan_entry->cap_info.value = le16toh(bcn->capability.value);
880 	qdf_mem_copy(scan_entry->tsf_info.data,
881 		bcn->timestamp, 8);
882 	scan_entry->erp = ERP_NON_ERP_PRESENT;
883 
884 	scan_entry->scan_entry_time =
885 		qdf_mc_timer_get_system_time();
886 
887 	scan_entry->raw_frame.len = frame_len;
888 	qdf_mem_copy(scan_entry->raw_frame.ptr,
889 		frame, frame_len);
890 	status = util_scan_populate_bcn_ie_list(scan_entry);
891 	if (QDF_IS_STATUS_ERROR(status)) {
892 		scm_err("failed to parse beacon IE");
893 		qdf_mem_free(scan_entry->raw_frame.ptr);
894 		qdf_mem_free(scan_entry);
895 		qdf_mem_free(scan_list);
896 		return NULL;
897 	}
898 
899 	if (!scan_entry->ie_list.rates) {
900 		qdf_mem_free(scan_entry->raw_frame.ptr);
901 		qdf_mem_free(scan_entry);
902 		qdf_mem_free(scan_list);
903 		return NULL;
904 	}
905 
906 	ssid = (struct ie_ssid *)
907 		scan_entry->ie_list.ssid;
908 
909 	if (ssid && (ssid->ssid_len > WLAN_SSID_MAX_LEN)) {
910 		qdf_mem_free(scan_entry->raw_frame.ptr);
911 		qdf_mem_free(scan_entry);
912 		qdf_mem_free(scan_list);
913 		return NULL;
914 	}
915 
916 	if (scan_entry->ie_list.p2p)
917 		scan_entry->is_p2p = true;
918 
919 	/* If no channel info is present in beacon use meta channel */
920 	if (!scan_entry->channel.chan_idx) {
921 		scan_entry->channel.chan_idx =
922 				rx_param->channel;
923 	} else if (rx_param->channel !=
924 	   scan_entry->channel.chan_idx) {
925 		scan_entry->channel_mismatch = true;
926 	}
927 
928 	if (util_scan_is_hidden_ssid(ssid)) {
929 		scan_entry->ie_list.ssid = NULL;
930 	} else {
931 		qdf_mem_copy(scan_entry->ssid.ssid,
932 				ssid->ssid, WLAN_SSID_MAX_LEN);
933 		scan_entry->ssid.length = ssid->ssid_len;
934 		scan_entry->hidden_ssid_timestamp =
935 			scan_entry->scan_entry_time;
936 	}
937 
938 	if (WLAN_CHAN_IS_5GHZ(scan_entry->channel.chan_idx))
939 		scan_entry->phy_mode = util_scan_get_phymode_5g(scan_entry);
940 	else
941 		scan_entry->phy_mode = util_scan_get_phymode_2g(scan_entry);
942 
943 	scan_entry->nss = util_scan_scm_calc_nss_supported_by_ap(scan_entry);
944 	util_scan_scm_update_bss_with_esp_data(scan_entry);
945 	qbss_load = (struct qbss_load_ie *)
946 			util_scan_entry_qbssload(scan_entry);
947 	if (qbss_load)
948 		scan_entry->qbss_chan_load = qbss_load->qbss_chan_load;
949 
950 	scan_node = qdf_mem_malloc(sizeof(*scan_node));
951 	if (!scan_node) {
952 		qdf_mem_free(scan_entry->raw_frame.ptr);
953 		qdf_mem_free(scan_entry);
954 		qdf_mem_free(scan_list);
955 		return NULL;
956 	}
957 
958 	scan_node->entry = scan_entry;
959 	qdf_list_insert_front(scan_list, &scan_node->node);
960 
961 	/* TODO calculate channel struct */
962 	return scan_list;
963 }
964 
965 QDF_STATUS
966 util_scan_entry_update_mlme_info(struct wlan_objmgr_pdev *pdev,
967 	struct scan_cache_entry *scan_entry)
968 {
969 
970 	if (!pdev || !scan_entry) {
971 		scm_err("pdev 0x%pK, scan_entry: 0x%pK", pdev, scan_entry);
972 		return QDF_STATUS_E_INVAL;
973 	}
974 
975 	return scm_update_scan_mlme_info(pdev, scan_entry);
976 }
977