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