1 /* 2 * BSS table 3 * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "utils/eloop.h" 13 #include "common/ieee802_11_defs.h" 14 #include "drivers/driver.h" 15 #include "eap_peer/eap.h" 16 #include "rsn_supp/wpa.h" 17 #include "wpa_supplicant_i.h" 18 #include "config.h" 19 #include "notify.h" 20 #include "scan.h" 21 #include "bssid_ignore.h" 22 #include "bss.h" 23 24 static void wpa_bss_set_hessid(struct wpa_bss *bss) 25 { 26 #ifdef CONFIG_INTERWORKING 27 const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING); 28 if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) { 29 os_memset(bss->hessid, 0, ETH_ALEN); 30 return; 31 } 32 if (ie[1] == 7) 33 os_memcpy(bss->hessid, ie + 3, ETH_ALEN); 34 else 35 os_memcpy(bss->hessid, ie + 5, ETH_ALEN); 36 #endif /* CONFIG_INTERWORKING */ 37 } 38 39 40 /** 41 * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry 42 * Returns: Allocated ANQP data structure or %NULL on failure 43 * 44 * The allocated ANQP data structure has its users count set to 1. It may be 45 * shared by multiple BSS entries and each shared entry is freed with 46 * wpa_bss_anqp_free(). 47 */ 48 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void) 49 { 50 struct wpa_bss_anqp *anqp; 51 anqp = os_zalloc(sizeof(*anqp)); 52 if (anqp == NULL) 53 return NULL; 54 #ifdef CONFIG_INTERWORKING 55 dl_list_init(&anqp->anqp_elems); 56 #endif /* CONFIG_INTERWORKING */ 57 anqp->users = 1; 58 return anqp; 59 } 60 61 62 /** 63 * wpa_bss_anqp_clone - Clone an ANQP data structure 64 * @anqp: ANQP data structure from wpa_bss_anqp_alloc() 65 * Returns: Cloned ANQP data structure or %NULL on failure 66 */ 67 static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) 68 { 69 struct wpa_bss_anqp *n; 70 71 n = os_zalloc(sizeof(*n)); 72 if (n == NULL) 73 return NULL; 74 75 #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) 76 #ifdef CONFIG_INTERWORKING 77 dl_list_init(&n->anqp_elems); 78 ANQP_DUP(capability_list); 79 ANQP_DUP(venue_name); 80 ANQP_DUP(network_auth_type); 81 ANQP_DUP(roaming_consortium); 82 ANQP_DUP(ip_addr_type_availability); 83 ANQP_DUP(nai_realm); 84 ANQP_DUP(anqp_3gpp); 85 ANQP_DUP(domain_name); 86 ANQP_DUP(fils_realm_info); 87 #endif /* CONFIG_INTERWORKING */ 88 #ifdef CONFIG_HS20 89 ANQP_DUP(hs20_capability_list); 90 ANQP_DUP(hs20_operator_friendly_name); 91 ANQP_DUP(hs20_wan_metrics); 92 ANQP_DUP(hs20_connection_capability); 93 ANQP_DUP(hs20_operating_class); 94 ANQP_DUP(hs20_osu_providers_list); 95 ANQP_DUP(hs20_operator_icon_metadata); 96 ANQP_DUP(hs20_osu_providers_nai_list); 97 #endif /* CONFIG_HS20 */ 98 #undef ANQP_DUP 99 100 return n; 101 } 102 103 104 /** 105 * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry 106 * @bss: BSS entry 107 * Returns: 0 on success, -1 on failure 108 * 109 * This function ensures the specific BSS entry has an ANQP data structure that 110 * is not shared with any other BSS entry. 111 */ 112 int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss) 113 { 114 struct wpa_bss_anqp *anqp; 115 116 if (bss->anqp && bss->anqp->users > 1) { 117 /* allocated, but shared - clone an unshared copy */ 118 anqp = wpa_bss_anqp_clone(bss->anqp); 119 if (anqp == NULL) 120 return -1; 121 anqp->users = 1; 122 bss->anqp->users--; 123 bss->anqp = anqp; 124 return 0; 125 } 126 127 if (bss->anqp) 128 return 0; /* already allocated and not shared */ 129 130 /* not allocated - allocate a new storage area */ 131 bss->anqp = wpa_bss_anqp_alloc(); 132 return bss->anqp ? 0 : -1; 133 } 134 135 136 /** 137 * wpa_bss_anqp_free - Free an ANQP data structure 138 * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone() 139 */ 140 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) 141 { 142 #ifdef CONFIG_INTERWORKING 143 struct wpa_bss_anqp_elem *elem; 144 #endif /* CONFIG_INTERWORKING */ 145 146 if (anqp == NULL) 147 return; 148 149 anqp->users--; 150 if (anqp->users > 0) { 151 /* Another BSS entry holds a pointer to this ANQP info */ 152 return; 153 } 154 155 #ifdef CONFIG_INTERWORKING 156 wpabuf_free(anqp->capability_list); 157 wpabuf_free(anqp->venue_name); 158 wpabuf_free(anqp->network_auth_type); 159 wpabuf_free(anqp->roaming_consortium); 160 wpabuf_free(anqp->ip_addr_type_availability); 161 wpabuf_free(anqp->nai_realm); 162 wpabuf_free(anqp->anqp_3gpp); 163 wpabuf_free(anqp->domain_name); 164 wpabuf_free(anqp->fils_realm_info); 165 166 while ((elem = dl_list_first(&anqp->anqp_elems, 167 struct wpa_bss_anqp_elem, list))) { 168 dl_list_del(&elem->list); 169 wpabuf_free(elem->payload); 170 os_free(elem); 171 } 172 #endif /* CONFIG_INTERWORKING */ 173 #ifdef CONFIG_HS20 174 wpabuf_free(anqp->hs20_capability_list); 175 wpabuf_free(anqp->hs20_operator_friendly_name); 176 wpabuf_free(anqp->hs20_wan_metrics); 177 wpabuf_free(anqp->hs20_connection_capability); 178 wpabuf_free(anqp->hs20_operating_class); 179 wpabuf_free(anqp->hs20_osu_providers_list); 180 wpabuf_free(anqp->hs20_operator_icon_metadata); 181 wpabuf_free(anqp->hs20_osu_providers_nai_list); 182 #endif /* CONFIG_HS20 */ 183 184 os_free(anqp); 185 } 186 187 188 static struct wpa_connect_work * 189 wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 190 { 191 struct wpa_radio_work *work; 192 struct wpa_connect_work *cwork; 193 194 work = radio_work_pending(wpa_s, "sme-connect"); 195 if (!work) 196 work = radio_work_pending(wpa_s, "connect"); 197 if (!work) 198 return NULL; 199 200 cwork = work->ctx; 201 if (cwork->bss != bss) 202 return NULL; 203 204 return cwork; 205 } 206 207 208 static void wpa_bss_update_pending_connect(struct wpa_connect_work *cwork, 209 struct wpa_bss *new_bss) 210 { 211 wpa_printf(MSG_DEBUG, 212 "Update BSS pointer for the pending connect radio work"); 213 cwork->bss = new_bss; 214 if (!new_bss) 215 cwork->bss_removed = 1; 216 } 217 218 219 void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 220 const char *reason) 221 { 222 struct wpa_connect_work *cwork; 223 224 if (wpa_s->last_scan_res) { 225 unsigned int i; 226 for (i = 0; i < wpa_s->last_scan_res_used; i++) { 227 if (wpa_s->last_scan_res[i] == bss) { 228 os_memmove(&wpa_s->last_scan_res[i], 229 &wpa_s->last_scan_res[i + 1], 230 (wpa_s->last_scan_res_used - i - 1) 231 * sizeof(struct wpa_bss *)); 232 wpa_s->last_scan_res_used--; 233 break; 234 } 235 } 236 } 237 cwork = wpa_bss_check_pending_connect(wpa_s, bss); 238 if (cwork) 239 wpa_bss_update_pending_connect(cwork, NULL); 240 dl_list_del(&bss->list); 241 dl_list_del(&bss->list_id); 242 wpa_s->num_bss--; 243 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR 244 " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid), 245 wpa_ssid_txt(bss->ssid, bss->ssid_len), reason); 246 wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id); 247 wpa_bss_anqp_free(bss->anqp); 248 os_free(bss); 249 } 250 251 252 /** 253 * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID 254 * @wpa_s: Pointer to wpa_supplicant data 255 * @bssid: BSSID, or %NULL to match any BSSID 256 * @ssid: SSID 257 * @ssid_len: Length of @ssid 258 * Returns: Pointer to the BSS entry or %NULL if not found 259 */ 260 struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, 261 const u8 *ssid, size_t ssid_len) 262 { 263 struct wpa_bss *bss; 264 265 if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid)) 266 return NULL; 267 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 268 if ((!bssid || ether_addr_equal(bss->bssid, bssid)) && 269 bss->ssid_len == ssid_len && 270 os_memcmp(bss->ssid, ssid, ssid_len) == 0) 271 return bss; 272 } 273 return NULL; 274 } 275 276 277 void calculate_update_time(const struct os_reltime *fetch_time, 278 unsigned int age_ms, 279 struct os_reltime *update_time) 280 { 281 os_time_t usec; 282 283 update_time->sec = fetch_time->sec; 284 update_time->usec = fetch_time->usec; 285 update_time->sec -= age_ms / 1000; 286 usec = (age_ms % 1000) * 1000; 287 if (update_time->usec < usec) { 288 update_time->sec--; 289 update_time->usec += 1000000; 290 } 291 update_time->usec -= usec; 292 } 293 294 295 static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, 296 struct os_reltime *fetch_time) 297 { 298 dst->flags = src->flags; 299 os_memcpy(dst->bssid, src->bssid, ETH_ALEN); 300 dst->freq = src->freq; 301 dst->max_cw = src->max_cw; 302 dst->beacon_int = src->beacon_int; 303 dst->caps = src->caps; 304 dst->qual = src->qual; 305 dst->noise = src->noise; 306 dst->level = src->level; 307 dst->tsf = src->tsf; 308 dst->beacon_newer = src->beacon_newer; 309 dst->est_throughput = src->est_throughput; 310 dst->snr = src->snr; 311 312 calculate_update_time(fetch_time, src->age, &dst->last_update); 313 } 314 315 316 static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s, 317 struct wpa_bss *bss) 318 { 319 #ifdef CONFIG_WPS 320 struct wpa_ssid *ssid; 321 struct wpabuf *wps_ie; 322 int pbc = 0, ret; 323 324 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); 325 if (!wps_ie) 326 return 0; 327 328 if (wps_is_selected_pbc_registrar(wps_ie)) { 329 pbc = 1; 330 } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { 331 wpabuf_free(wps_ie); 332 return 0; 333 } 334 335 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 336 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) 337 continue; 338 if (ssid->ssid_len && 339 (ssid->ssid_len != bss->ssid_len || 340 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0)) 341 continue; 342 343 if (pbc) 344 ret = eap_is_wps_pbc_enrollee(&ssid->eap); 345 else 346 ret = eap_is_wps_pin_enrollee(&ssid->eap); 347 wpabuf_free(wps_ie); 348 return ret; 349 } 350 wpabuf_free(wps_ie); 351 #endif /* CONFIG_WPS */ 352 353 return 0; 354 } 355 356 357 static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s, 358 struct wpa_bss *bss) 359 { 360 #ifdef CONFIG_P2P 361 u8 addr[ETH_ALEN]; 362 363 if (ether_addr_equal(bss->bssid, wpa_s->pending_join_iface_addr)) 364 return true; 365 if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) && 366 p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 && 367 ether_addr_equal(addr, wpa_s->pending_join_dev_addr)) 368 return true; 369 #endif /* CONFIG_P2P */ 370 return false; 371 } 372 373 374 static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 375 { 376 struct wpa_ssid *ssid; 377 378 if (is_p2p_pending_bss(wpa_s, bss)) 379 return 1; 380 381 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 382 if (ssid->ssid == NULL || ssid->ssid_len == 0) 383 continue; 384 if (ssid->ssid_len == bss->ssid_len && 385 os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0) 386 return 1; 387 } 388 389 return 0; 390 } 391 392 393 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 394 { 395 int i; 396 397 if (bss == wpa_s->current_bss) 398 return 1; 399 400 if (bss == wpa_s->ml_connect_probe_bss) 401 return 1; 402 403 #ifdef CONFIG_WNM 404 if (bss == wpa_s->wnm_target_bss) 405 return 1; 406 #endif /* CONFIG_WNM */ 407 408 if (wpa_s->current_bss && 409 (bss->ssid_len != wpa_s->current_bss->ssid_len || 410 os_memcmp(bss->ssid, wpa_s->current_bss->ssid, 411 bss->ssid_len) != 0)) 412 return 0; /* SSID has changed */ 413 414 if (!is_zero_ether_addr(bss->bssid) && 415 (ether_addr_equal(bss->bssid, wpa_s->bssid) || 416 ether_addr_equal(bss->bssid, wpa_s->pending_bssid))) 417 return 1; 418 419 if (!wpa_s->valid_links) 420 return 0; 421 422 for_each_link(wpa_s->valid_links, i) { 423 if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid)) 424 return 1; 425 } 426 427 return 0; 428 } 429 430 431 static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) 432 { 433 struct wpa_bss *bss; 434 435 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 436 if (!wpa_bss_known(wpa_s, bss) && 437 !wpa_bss_is_wps_candidate(wpa_s, bss)) { 438 wpa_bss_remove(wpa_s, bss, __func__); 439 return 0; 440 } 441 } 442 443 return -1; 444 } 445 446 447 static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) 448 { 449 struct wpa_bss *bss; 450 451 /* 452 * Remove the oldest entry that does not match with any configured 453 * network. 454 */ 455 if (wpa_bss_remove_oldest_unknown(wpa_s) == 0) 456 return 0; 457 458 /* 459 * Remove the oldest entry that isn't currently in use. 460 */ 461 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 462 if (!wpa_bss_in_use(wpa_s, bss)) { 463 wpa_bss_remove(wpa_s, bss, __func__); 464 return 0; 465 } 466 } 467 468 return -1; 469 } 470 471 472 static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, 473 const u8 *ssid, size_t ssid_len, 474 struct wpa_scan_res *res, 475 struct os_reltime *fetch_time) 476 { 477 struct wpa_bss *bss; 478 char extra[100]; 479 const u8 *ml_ie; 480 char *pos, *end; 481 int ret = 0; 482 const u8 *mld_addr; 483 484 bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); 485 if (bss == NULL) 486 return NULL; 487 bss->id = wpa_s->bss_next_id++; 488 bss->last_update_idx = wpa_s->bss_update_idx; 489 wpa_bss_copy_res(bss, res, fetch_time); 490 os_memcpy(bss->ssid, ssid, ssid_len); 491 bss->ssid_len = ssid_len; 492 bss->ie_len = res->ie_len; 493 bss->beacon_ie_len = res->beacon_ie_len; 494 os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); 495 wpa_bss_set_hessid(bss); 496 497 os_memset(bss->mld_addr, 0, ETH_ALEN); 498 ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); 499 if (ml_ie) { 500 mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1); 501 if (mld_addr) 502 os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); 503 } 504 505 if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count && 506 wpa_bss_remove_oldest(wpa_s) != 0) { 507 wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d " 508 "because all BSSes are in use. We should normally " 509 "not get here!", (int) wpa_s->num_bss + 1); 510 wpa_s->conf->bss_max_count = wpa_s->num_bss + 1; 511 } 512 513 dl_list_add_tail(&wpa_s->bss, &bss->list); 514 dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); 515 wpa_s->num_bss++; 516 517 extra[0] = '\0'; 518 pos = extra; 519 end = pos + sizeof(extra); 520 if (!is_zero_ether_addr(bss->hessid)) 521 ret = os_snprintf(pos, end - pos, " HESSID " MACSTR, 522 MAC2STR(bss->hessid)); 523 524 if (!is_zero_ether_addr(bss->mld_addr) && 525 !os_snprintf_error(end - pos, ret)) { 526 pos += ret; 527 ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR, 528 MAC2STR(bss->mld_addr)); 529 } 530 531 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR 532 " SSID '%s' freq %d%s", 533 bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len), 534 bss->freq, extra); 535 wpas_notify_bss_added(wpa_s, bss->bssid, bss->id); 536 return bss; 537 } 538 539 540 static int are_ies_equal(const struct wpa_bss *old, 541 const struct wpa_scan_res *new_res, u32 ie) 542 { 543 const u8 *old_ie, *new_ie; 544 struct wpabuf *old_ie_buff = NULL; 545 struct wpabuf *new_ie_buff = NULL; 546 int new_ie_len, old_ie_len, ret, is_multi; 547 548 switch (ie) { 549 case WPA_IE_VENDOR_TYPE: 550 old_ie = wpa_bss_get_vendor_ie(old, ie); 551 new_ie = wpa_scan_get_vendor_ie(new_res, ie); 552 is_multi = 0; 553 break; 554 case WPS_IE_VENDOR_TYPE: 555 old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie); 556 new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie); 557 is_multi = 1; 558 break; 559 case WLAN_EID_RSN: 560 case WLAN_EID_SUPP_RATES: 561 case WLAN_EID_EXT_SUPP_RATES: 562 old_ie = wpa_bss_get_ie(old, ie); 563 new_ie = wpa_scan_get_ie(new_res, ie); 564 is_multi = 0; 565 break; 566 default: 567 wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__); 568 return 0; 569 } 570 571 if (is_multi) { 572 /* in case of multiple IEs stored in buffer */ 573 old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL; 574 new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL; 575 old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0; 576 new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0; 577 } else { 578 /* in case of single IE */ 579 old_ie_len = old_ie ? old_ie[1] + 2 : 0; 580 new_ie_len = new_ie ? new_ie[1] + 2 : 0; 581 } 582 583 if (!old_ie || !new_ie) 584 ret = !old_ie && !new_ie; 585 else 586 ret = (old_ie_len == new_ie_len && 587 os_memcmp(old_ie, new_ie, old_ie_len) == 0); 588 589 wpabuf_free(old_ie_buff); 590 wpabuf_free(new_ie_buff); 591 592 return ret; 593 } 594 595 596 static u32 wpa_bss_compare_res(const struct wpa_bss *old, 597 const struct wpa_scan_res *new_res) 598 { 599 u32 changes = 0; 600 int caps_diff = old->caps ^ new_res->caps; 601 602 if (old->freq != new_res->freq) 603 changes |= WPA_BSS_FREQ_CHANGED_FLAG; 604 605 if (old->level != new_res->level) 606 changes |= WPA_BSS_SIGNAL_CHANGED_FLAG; 607 608 if (caps_diff & IEEE80211_CAP_PRIVACY) 609 changes |= WPA_BSS_PRIVACY_CHANGED_FLAG; 610 611 if (caps_diff & IEEE80211_CAP_IBSS) 612 changes |= WPA_BSS_MODE_CHANGED_FLAG; 613 614 if (old->ie_len == new_res->ie_len && 615 os_memcmp(wpa_bss_ie_ptr(old), new_res + 1, old->ie_len) == 0) 616 return changes; 617 changes |= WPA_BSS_IES_CHANGED_FLAG; 618 619 if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE)) 620 changes |= WPA_BSS_WPAIE_CHANGED_FLAG; 621 622 if (!are_ies_equal(old, new_res, WLAN_EID_RSN)) 623 changes |= WPA_BSS_RSNIE_CHANGED_FLAG; 624 625 if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE)) 626 changes |= WPA_BSS_WPS_CHANGED_FLAG; 627 628 if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) || 629 !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES)) 630 changes |= WPA_BSS_RATES_CHANGED_FLAG; 631 632 return changes; 633 } 634 635 636 void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, 637 const struct wpa_bss *bss) 638 { 639 if (changes & WPA_BSS_FREQ_CHANGED_FLAG) 640 wpas_notify_bss_freq_changed(wpa_s, bss->id); 641 642 if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG) 643 wpas_notify_bss_signal_changed(wpa_s, bss->id); 644 645 if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG) 646 wpas_notify_bss_privacy_changed(wpa_s, bss->id); 647 648 if (changes & WPA_BSS_MODE_CHANGED_FLAG) 649 wpas_notify_bss_mode_changed(wpa_s, bss->id); 650 651 if (changes & WPA_BSS_WPAIE_CHANGED_FLAG) 652 wpas_notify_bss_wpaie_changed(wpa_s, bss->id); 653 654 if (changes & WPA_BSS_RSNIE_CHANGED_FLAG) 655 wpas_notify_bss_rsnie_changed(wpa_s, bss->id); 656 657 if (changes & WPA_BSS_WPS_CHANGED_FLAG) 658 wpas_notify_bss_wps_changed(wpa_s, bss->id); 659 660 if (changes & WPA_BSS_IES_CHANGED_FLAG) 661 wpas_notify_bss_ies_changed(wpa_s, bss->id); 662 663 if (changes & WPA_BSS_RATES_CHANGED_FLAG) 664 wpas_notify_bss_rates_changed(wpa_s, bss->id); 665 666 wpas_notify_bss_seen(wpa_s, bss->id); 667 } 668 669 670 static struct wpa_bss * 671 wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, 672 struct wpa_scan_res *res, struct os_reltime *fetch_time) 673 { 674 u32 changes; 675 676 if (bss->last_update_idx == wpa_s->bss_update_idx) { 677 struct os_reltime update_time; 678 679 /* 680 * Some drivers (e.g., cfg80211) include multiple BSS entries 681 * for the same BSS if that BSS's channel changes. The BSS list 682 * implementation in wpa_supplicant does not do that and we need 683 * to filter out the obsolete results here to make sure only the 684 * most current BSS information remains in the table. 685 */ 686 wpa_printf(MSG_DEBUG, "BSS: " MACSTR 687 " has multiple entries in the scan results - select the most current one", 688 MAC2STR(bss->bssid)); 689 calculate_update_time(fetch_time, res->age, &update_time); 690 wpa_printf(MSG_DEBUG, 691 "Previous last_update: %u.%06u (freq %d%s)", 692 (unsigned int) bss->last_update.sec, 693 (unsigned int) bss->last_update.usec, 694 bss->freq, 695 (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : ""); 696 wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)", 697 (unsigned int) update_time.sec, 698 (unsigned int) update_time.usec, 699 res->freq, 700 (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : ""); 701 if ((bss->flags & WPA_BSS_ASSOCIATED) || 702 (!(res->flags & WPA_SCAN_ASSOCIATED) && 703 !os_reltime_before(&bss->last_update, &update_time))) { 704 wpa_printf(MSG_DEBUG, 705 "Ignore this BSS entry since the previous update looks more current"); 706 return bss; 707 } 708 wpa_printf(MSG_DEBUG, 709 "Accept this BSS entry since it looks more current than the previous update"); 710 } 711 712 changes = wpa_bss_compare_res(bss, res); 713 if (changes & WPA_BSS_FREQ_CHANGED_FLAG) 714 wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d", 715 MAC2STR(bss->bssid), bss->freq, res->freq); 716 bss->scan_miss_count = 0; 717 bss->last_update_idx = wpa_s->bss_update_idx; 718 wpa_bss_copy_res(bss, res, fetch_time); 719 /* Move the entry to the end of the list */ 720 dl_list_del(&bss->list); 721 #ifdef CONFIG_P2P 722 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && 723 !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE) && 724 !(changes & WPA_BSS_FREQ_CHANGED_FLAG)) { 725 /* 726 * This can happen when non-P2P station interface runs a scan 727 * without P2P IE in the Probe Request frame. P2P GO would reply 728 * to that with a Probe Response that does not include P2P IE. 729 * Do not update the IEs in this BSS entry to avoid such loss of 730 * information that may be needed for P2P operations to 731 * determine group information. 732 */ 733 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for " 734 MACSTR " since that would remove P2P IE information", 735 MAC2STR(bss->bssid)); 736 } else 737 #endif /* CONFIG_P2P */ 738 if (bss->ie_len + bss->beacon_ie_len >= 739 res->ie_len + res->beacon_ie_len) { 740 os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); 741 bss->ie_len = res->ie_len; 742 bss->beacon_ie_len = res->beacon_ie_len; 743 } else { 744 struct wpa_bss *nbss; 745 struct dl_list *prev = bss->list_id.prev; 746 struct wpa_connect_work *cwork; 747 unsigned int i; 748 bool update_current_bss = wpa_s->current_bss == bss; 749 bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss; 750 751 cwork = wpa_bss_check_pending_connect(wpa_s, bss); 752 753 for (i = 0; i < wpa_s->last_scan_res_used; i++) { 754 if (wpa_s->last_scan_res[i] == bss) 755 break; 756 } 757 758 dl_list_del(&bss->list_id); 759 nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + 760 res->beacon_ie_len); 761 if (nbss) { 762 if (i != wpa_s->last_scan_res_used) 763 wpa_s->last_scan_res[i] = nbss; 764 765 if (update_current_bss) 766 wpa_s->current_bss = nbss; 767 768 if (update_ml_probe_bss) 769 wpa_s->ml_connect_probe_bss = nbss; 770 771 if (cwork) 772 wpa_bss_update_pending_connect(cwork, nbss); 773 774 bss = nbss; 775 os_memcpy(bss->ies, res + 1, 776 res->ie_len + res->beacon_ie_len); 777 bss->ie_len = res->ie_len; 778 bss->beacon_ie_len = res->beacon_ie_len; 779 } 780 dl_list_add(prev, &bss->list_id); 781 } 782 if (changes & WPA_BSS_IES_CHANGED_FLAG) { 783 const u8 *ml_ie, *mld_addr; 784 785 wpa_bss_set_hessid(bss); 786 os_memset(bss->mld_addr, 0, ETH_ALEN); 787 ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); 788 if (ml_ie) { 789 mld_addr = get_basic_mle_mld_addr(&ml_ie[3], 790 ml_ie[1] - 1); 791 if (mld_addr) 792 os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); 793 } 794 } 795 dl_list_add_tail(&wpa_s->bss, &bss->list); 796 797 notify_bss_changes(wpa_s, changes, bss); 798 799 return bss; 800 } 801 802 803 /** 804 * wpa_bss_update_start - Start a BSS table update from scan results 805 * @wpa_s: Pointer to wpa_supplicant data 806 * 807 * This function is called at the start of each BSS table update round for new 808 * scan results. The actual scan result entries are indicated with calls to 809 * wpa_bss_update_scan_res() and the update round is finished with a call to 810 * wpa_bss_update_end(). 811 */ 812 void wpa_bss_update_start(struct wpa_supplicant *wpa_s) 813 { 814 wpa_s->bss_update_idx++; 815 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u", 816 wpa_s->bss_update_idx); 817 wpa_s->last_scan_res_used = 0; 818 } 819 820 821 /** 822 * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result 823 * @wpa_s: Pointer to wpa_supplicant data 824 * @res: Scan result 825 * @fetch_time: Time when the result was fetched from the driver 826 * 827 * This function updates a BSS table entry (or adds one) based on a scan result. 828 * This is called separately for each scan result between the calls to 829 * wpa_bss_update_start() and wpa_bss_update_end(). 830 */ 831 void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, 832 struct wpa_scan_res *res, 833 struct os_reltime *fetch_time) 834 { 835 const u8 *ssid, *p2p, *mesh; 836 struct wpa_bss *bss; 837 838 if (wpa_s->conf->ignore_old_scan_res) { 839 struct os_reltime update; 840 calculate_update_time(fetch_time, res->age, &update); 841 if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) { 842 struct os_reltime age; 843 os_reltime_sub(&wpa_s->scan_trigger_time, &update, 844 &age); 845 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " 846 "table entry that is %u.%06u seconds older " 847 "than our scan trigger", 848 (unsigned int) age.sec, 849 (unsigned int) age.usec); 850 return; 851 } 852 } 853 854 ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); 855 if (ssid == NULL) { 856 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for " 857 MACSTR, MAC2STR(res->bssid)); 858 return; 859 } 860 if (ssid[1] > SSID_MAX_LEN) { 861 wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for " 862 MACSTR, MAC2STR(res->bssid)); 863 return; 864 } 865 866 p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE); 867 #ifdef CONFIG_P2P 868 if (p2p == NULL && 869 wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { 870 /* 871 * If it's a P2P specific interface, then don't update 872 * the scan result without a P2P IE. 873 */ 874 wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR 875 " update for P2P interface", MAC2STR(res->bssid)); 876 return; 877 } 878 #endif /* CONFIG_P2P */ 879 if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN && 880 os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) 881 return; /* Skip P2P listen discovery results here */ 882 883 /* TODO: add option for ignoring BSSes we are not interested in 884 * (to save memory) */ 885 886 mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID); 887 if (mesh && mesh[1] <= SSID_MAX_LEN) 888 ssid = mesh; 889 890 bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); 891 if (bss == NULL) 892 bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time); 893 else { 894 bss = wpa_bss_update(wpa_s, bss, res, fetch_time); 895 if (wpa_s->last_scan_res) { 896 unsigned int i; 897 for (i = 0; i < wpa_s->last_scan_res_used; i++) { 898 if (bss == wpa_s->last_scan_res[i]) { 899 /* Already in the list */ 900 return; 901 } 902 } 903 } 904 } 905 906 if (bss == NULL) 907 return; 908 if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) { 909 struct wpa_bss **n; 910 unsigned int siz; 911 if (wpa_s->last_scan_res_size == 0) 912 siz = 32; 913 else 914 siz = wpa_s->last_scan_res_size * 2; 915 n = os_realloc_array(wpa_s->last_scan_res, siz, 916 sizeof(struct wpa_bss *)); 917 if (n == NULL) 918 return; 919 wpa_s->last_scan_res = n; 920 wpa_s->last_scan_res_size = siz; 921 } 922 923 if (wpa_s->last_scan_res) 924 wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss; 925 } 926 927 928 static int wpa_bss_included_in_scan(const struct wpa_bss *bss, 929 const struct scan_info *info) 930 { 931 int found; 932 size_t i; 933 934 if (info == NULL) 935 return 1; 936 937 if (info->num_freqs) { 938 found = 0; 939 for (i = 0; i < info->num_freqs; i++) { 940 if (bss->freq == info->freqs[i]) { 941 found = 1; 942 break; 943 } 944 } 945 if (!found) 946 return 0; 947 } 948 949 if (info->num_ssids) { 950 found = 0; 951 for (i = 0; i < info->num_ssids; i++) { 952 const struct wpa_driver_scan_ssid *s = &info->ssids[i]; 953 if ((s->ssid == NULL || s->ssid_len == 0) || 954 (s->ssid_len == bss->ssid_len && 955 os_memcmp(s->ssid, bss->ssid, bss->ssid_len) == 956 0)) { 957 found = 1; 958 break; 959 } 960 } 961 if (!found) 962 return 0; 963 } 964 965 return 1; 966 } 967 968 969 /** 970 * wpa_bss_update_end - End a BSS table update from scan results 971 * @wpa_s: Pointer to wpa_supplicant data 972 * @info: Information about scan parameters 973 * @new_scan: Whether this update round was based on a new scan 974 * 975 * This function is called at the end of each BSS table update round for new 976 * scan results. The start of the update was indicated with a call to 977 * wpa_bss_update_start(). 978 */ 979 void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, 980 int new_scan) 981 { 982 struct wpa_bss *bss, *n; 983 984 os_get_reltime(&wpa_s->last_scan); 985 if ((info && info->aborted) || !new_scan) 986 return; /* do not expire entries without new scan */ 987 988 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 989 if (wpa_bss_in_use(wpa_s, bss)) 990 continue; 991 if (!wpa_bss_included_in_scan(bss, info)) 992 continue; /* expire only BSSes that were scanned */ 993 if (bss->last_update_idx < wpa_s->bss_update_idx) 994 bss->scan_miss_count++; 995 if (bss->scan_miss_count >= 996 wpa_s->conf->bss_expiration_scan_count) { 997 wpa_bss_remove(wpa_s, bss, "no match in scan"); 998 } 999 } 1000 1001 wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu", 1002 wpa_s->last_scan_res_used, wpa_s->last_scan_res_size); 1003 } 1004 1005 1006 /** 1007 * wpa_bss_flush_by_age - Flush old BSS entries 1008 * @wpa_s: Pointer to wpa_supplicant data 1009 * @age: Maximum entry age in seconds 1010 * 1011 * Remove BSS entries that have not been updated during the last @age seconds. 1012 */ 1013 void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) 1014 { 1015 struct wpa_bss *bss, *n; 1016 struct os_reltime t; 1017 1018 if (dl_list_empty(&wpa_s->bss)) 1019 return; 1020 1021 os_get_reltime(&t); 1022 1023 if (t.sec < age) 1024 return; /* avoid underflow; there can be no older entries */ 1025 1026 t.sec -= age; 1027 1028 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 1029 if (wpa_bss_in_use(wpa_s, bss)) 1030 continue; 1031 1032 if (wpa_s->reassoc_same_ess && 1033 wpa_s->wpa_state != WPA_COMPLETED && 1034 wpa_s->last_ssid && 1035 bss->ssid_len == wpa_s->last_ssid->ssid_len && 1036 os_memcmp(bss->ssid, wpa_s->last_ssid->ssid, 1037 bss->ssid_len) == 0) 1038 continue; 1039 1040 if (os_reltime_before(&bss->last_update, &t)) { 1041 wpa_bss_remove(wpa_s, bss, __func__); 1042 } else 1043 break; 1044 } 1045 } 1046 1047 1048 /** 1049 * wpa_bss_init - Initialize BSS table 1050 * @wpa_s: Pointer to wpa_supplicant data 1051 * Returns: 0 on success, -1 on failure 1052 * 1053 * This prepares BSS table lists and timer for periodic updates. The BSS table 1054 * is deinitialized with wpa_bss_deinit() once not needed anymore. 1055 */ 1056 int wpa_bss_init(struct wpa_supplicant *wpa_s) 1057 { 1058 dl_list_init(&wpa_s->bss); 1059 dl_list_init(&wpa_s->bss_id); 1060 return 0; 1061 } 1062 1063 1064 /** 1065 * wpa_bss_flush - Flush all unused BSS entries 1066 * @wpa_s: Pointer to wpa_supplicant data 1067 */ 1068 void wpa_bss_flush(struct wpa_supplicant *wpa_s) 1069 { 1070 struct wpa_bss *bss, *n; 1071 1072 wpa_s->clear_driver_scan_cache = 1; 1073 1074 if (wpa_s->bss.next == NULL) 1075 return; /* BSS table not yet initialized */ 1076 1077 dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { 1078 if (wpa_bss_in_use(wpa_s, bss)) 1079 continue; 1080 wpa_bss_remove(wpa_s, bss, __func__); 1081 } 1082 } 1083 1084 1085 /** 1086 * wpa_bss_deinit - Deinitialize BSS table 1087 * @wpa_s: Pointer to wpa_supplicant data 1088 */ 1089 void wpa_bss_deinit(struct wpa_supplicant *wpa_s) 1090 { 1091 wpa_bss_flush(wpa_s); 1092 } 1093 1094 1095 /** 1096 * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID 1097 * @wpa_s: Pointer to wpa_supplicant data 1098 * @bssid: BSSID 1099 * Returns: Pointer to the BSS entry or %NULL if not found 1100 */ 1101 struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, 1102 const u8 *bssid) 1103 { 1104 struct wpa_bss *bss; 1105 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) 1106 return NULL; 1107 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { 1108 if (ether_addr_equal(bss->bssid, bssid)) 1109 return bss; 1110 } 1111 return NULL; 1112 } 1113 1114 1115 /** 1116 * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID 1117 * @wpa_s: Pointer to wpa_supplicant data 1118 * @bssid: BSSID 1119 * Returns: Pointer to the BSS entry or %NULL if not found 1120 * 1121 * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to 1122 * find the entry that has the most recent update. This can help in finding the 1123 * correct entry in cases where the SSID of the AP may have changed recently 1124 * (e.g., in WPS reconfiguration cases). 1125 */ 1126 struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, 1127 const u8 *bssid) 1128 { 1129 struct wpa_bss *bss, *found = NULL; 1130 if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) 1131 return NULL; 1132 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { 1133 if (!ether_addr_equal(bss->bssid, bssid)) 1134 continue; 1135 if (found == NULL || 1136 os_reltime_before(&found->last_update, &bss->last_update)) 1137 found = bss; 1138 } 1139 return found; 1140 } 1141 1142 1143 #ifdef CONFIG_P2P 1144 /** 1145 * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr 1146 * @wpa_s: Pointer to wpa_supplicant data 1147 * @dev_addr: P2P Device Address of the GO 1148 * Returns: Pointer to the BSS entry or %NULL if not found 1149 * 1150 * This function tries to find the entry that has the most recent update. This 1151 * can help in finding the correct entry in cases where the SSID of the P2P 1152 * Device may have changed recently. 1153 */ 1154 struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s, 1155 const u8 *dev_addr) 1156 { 1157 struct wpa_bss *bss, *found = NULL; 1158 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { 1159 u8 addr[ETH_ALEN]; 1160 if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, 1161 addr) != 0 || 1162 !ether_addr_equal(addr, dev_addr)) 1163 continue; 1164 if (!found || 1165 os_reltime_before(&found->last_update, &bss->last_update)) 1166 found = bss; 1167 } 1168 return found; 1169 } 1170 #endif /* CONFIG_P2P */ 1171 1172 1173 /** 1174 * wpa_bss_get_id - Fetch a BSS table entry based on identifier 1175 * @wpa_s: Pointer to wpa_supplicant data 1176 * @id: Unique identifier (struct wpa_bss::id) assigned for the entry 1177 * Returns: Pointer to the BSS entry or %NULL if not found 1178 */ 1179 struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id) 1180 { 1181 struct wpa_bss *bss; 1182 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 1183 if (bss->id == id) 1184 return bss; 1185 } 1186 return NULL; 1187 } 1188 1189 1190 /** 1191 * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range 1192 * @wpa_s: Pointer to wpa_supplicant data 1193 * @idf: Smallest allowed identifier assigned for the entry 1194 * @idf: Largest allowed identifier assigned for the entry 1195 * Returns: Pointer to the BSS entry or %NULL if not found 1196 * 1197 * This function is similar to wpa_bss_get_id() but allows a BSS entry with the 1198 * smallest id value to be fetched within the specified range without the 1199 * caller having to know the exact id. 1200 */ 1201 struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s, 1202 unsigned int idf, unsigned int idl) 1203 { 1204 struct wpa_bss *bss; 1205 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 1206 if (bss->id >= idf && bss->id <= idl) 1207 return bss; 1208 } 1209 return NULL; 1210 } 1211 1212 1213 /** 1214 * wpa_bss_get_ie - Fetch a specified information element from a BSS entry 1215 * @bss: BSS table entry 1216 * @ie: Information element identitifier (WLAN_EID_*) 1217 * Returns: Pointer to the information element (id field) or %NULL if not found 1218 * 1219 * This function returns the first matching information element in the BSS 1220 * entry. 1221 */ 1222 const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) 1223 { 1224 return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie); 1225 } 1226 1227 1228 /** 1229 * wpa_bss_get_ie_beacon - Fetch a specified information element from a BSS entry 1230 * @bss: BSS table entry 1231 * @ie: Information element identitifier (WLAN_EID_*) 1232 * Returns: Pointer to the information element (id field) or %NULL if not found 1233 * 1234 * This function returns the first matching information element in the BSS 1235 * entry. 1236 * 1237 * This function is like wpa_bss_get_ie(), but uses IE buffer only from Beacon 1238 * frames instead of either Beacon or Probe Response frames. 1239 */ 1240 const u8 * wpa_bss_get_ie_beacon(const struct wpa_bss *bss, u8 ie) 1241 { 1242 const u8 *ies; 1243 1244 if (bss->beacon_ie_len == 0) 1245 return NULL; 1246 1247 ies = wpa_bss_ie_ptr(bss); 1248 ies += bss->ie_len; 1249 return get_ie(ies, bss->beacon_ie_len, ie); 1250 } 1251 1252 1253 /** 1254 * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry 1255 * @bss: BSS table entry 1256 * @ext: Information element extension identifier (WLAN_EID_EXT_*) 1257 * Returns: Pointer to the information element (id field) or %NULL if not found 1258 * 1259 * This function returns the first matching information element in the BSS 1260 * entry. 1261 */ 1262 const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext) 1263 { 1264 return get_ie_ext(wpa_bss_ie_ptr(bss), bss->ie_len, ext); 1265 } 1266 1267 1268 /** 1269 * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry 1270 * @bss: BSS table entry 1271 * @vendor_type: Vendor type (four octets starting the IE payload) 1272 * Returns: Pointer to the information element (id field) or %NULL if not found 1273 * 1274 * This function returns the first matching information element in the BSS 1275 * entry. 1276 */ 1277 const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) 1278 { 1279 const u8 *ies; 1280 const struct element *elem; 1281 1282 ies = wpa_bss_ie_ptr(bss); 1283 1284 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) { 1285 if (elem->datalen >= 4 && 1286 vendor_type == WPA_GET_BE32(elem->data)) 1287 return &elem->id; 1288 } 1289 1290 return NULL; 1291 } 1292 1293 1294 /** 1295 * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry 1296 * @bss: BSS table entry 1297 * @vendor_type: Vendor type (four octets starting the IE payload) 1298 * Returns: Pointer to the information element (id field) or %NULL if not found 1299 * 1300 * This function returns the first matching information element in the BSS 1301 * entry. 1302 * 1303 * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only 1304 * from Beacon frames instead of either Beacon or Probe Response frames. 1305 */ 1306 const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss, 1307 u32 vendor_type) 1308 { 1309 const u8 *ies; 1310 const struct element *elem; 1311 1312 if (bss->beacon_ie_len == 0) 1313 return NULL; 1314 1315 ies = wpa_bss_ie_ptr(bss); 1316 ies += bss->ie_len; 1317 1318 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, 1319 bss->beacon_ie_len) { 1320 if (elem->datalen >= 4 && 1321 vendor_type == WPA_GET_BE32(elem->data)) 1322 return &elem->id; 1323 } 1324 1325 return NULL; 1326 } 1327 1328 1329 /** 1330 * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry 1331 * @bss: BSS table entry 1332 * @vendor_type: Vendor type (four octets starting the IE payload) 1333 * Returns: Pointer to the information element payload or %NULL if not found 1334 * 1335 * This function returns concatenated payload of possibly fragmented vendor 1336 * specific information elements in the BSS entry. The caller is responsible for 1337 * freeing the returned buffer. 1338 */ 1339 struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, 1340 u32 vendor_type) 1341 { 1342 struct wpabuf *buf; 1343 const u8 *end, *pos; 1344 1345 buf = wpabuf_alloc(bss->ie_len); 1346 if (buf == NULL) 1347 return NULL; 1348 1349 pos = wpa_bss_ie_ptr(bss); 1350 end = pos + bss->ie_len; 1351 1352 while (end - pos > 1) { 1353 u8 ie, len; 1354 1355 ie = pos[0]; 1356 len = pos[1]; 1357 if (len > end - pos - 2) 1358 break; 1359 pos += 2; 1360 if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 && 1361 vendor_type == WPA_GET_BE32(pos)) 1362 wpabuf_put_data(buf, pos + 4, len - 4); 1363 pos += len; 1364 } 1365 1366 if (wpabuf_len(buf) == 0) { 1367 wpabuf_free(buf); 1368 buf = NULL; 1369 } 1370 1371 return buf; 1372 } 1373 1374 1375 /** 1376 * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry 1377 * @bss: BSS table entry 1378 * @vendor_type: Vendor type (four octets starting the IE payload) 1379 * Returns: Pointer to the information element payload or %NULL if not found 1380 * 1381 * This function returns concatenated payload of possibly fragmented vendor 1382 * specific information elements in the BSS entry. The caller is responsible for 1383 * freeing the returned buffer. 1384 * 1385 * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only 1386 * from Beacon frames instead of either Beacon or Probe Response frames. 1387 */ 1388 struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, 1389 u32 vendor_type) 1390 { 1391 struct wpabuf *buf; 1392 const u8 *end, *pos; 1393 1394 buf = wpabuf_alloc(bss->beacon_ie_len); 1395 if (buf == NULL) 1396 return NULL; 1397 1398 pos = wpa_bss_ie_ptr(bss); 1399 pos += bss->ie_len; 1400 end = pos + bss->beacon_ie_len; 1401 1402 while (end - pos > 1) { 1403 u8 id, len; 1404 1405 id = *pos++; 1406 len = *pos++; 1407 if (len > end - pos) 1408 break; 1409 if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 && 1410 vendor_type == WPA_GET_BE32(pos)) 1411 wpabuf_put_data(buf, pos + 4, len - 4); 1412 pos += len; 1413 } 1414 1415 if (wpabuf_len(buf) == 0) { 1416 wpabuf_free(buf); 1417 buf = NULL; 1418 } 1419 1420 return buf; 1421 } 1422 1423 1424 /** 1425 * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS 1426 * @bss: BSS table entry 1427 * Returns: Maximum legacy rate in units of 500 kbps 1428 */ 1429 int wpa_bss_get_max_rate(const struct wpa_bss *bss) 1430 { 1431 int rate = 0; 1432 const u8 *ie; 1433 int i; 1434 1435 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 1436 for (i = 0; ie && i < ie[1]; i++) { 1437 if ((ie[i + 2] & 0x7f) > rate) 1438 rate = ie[i + 2] & 0x7f; 1439 } 1440 1441 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 1442 for (i = 0; ie && i < ie[1]; i++) { 1443 if ((ie[i + 2] & 0x7f) > rate) 1444 rate = ie[i + 2] & 0x7f; 1445 } 1446 1447 return rate; 1448 } 1449 1450 1451 /** 1452 * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS 1453 * @bss: BSS table entry 1454 * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps) 1455 * Returns: number of legacy TX rates or -1 on failure 1456 * 1457 * The caller is responsible for freeing the returned buffer with os_free() in 1458 * case of success. 1459 */ 1460 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) 1461 { 1462 const u8 *ie, *ie2; 1463 int i, j; 1464 unsigned int len; 1465 u8 *r; 1466 1467 ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 1468 ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 1469 1470 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0); 1471 1472 r = os_malloc(len); 1473 if (!r) 1474 return -1; 1475 1476 for (i = 0; ie && i < ie[1]; i++) 1477 r[i] = ie[i + 2] & 0x7f; 1478 1479 for (j = 0; ie2 && j < ie2[1]; j++) 1480 r[i + j] = ie2[j + 2] & 0x7f; 1481 1482 *rates = r; 1483 return len; 1484 } 1485 1486 1487 #ifdef CONFIG_FILS 1488 const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss) 1489 { 1490 const u8 *ie; 1491 1492 if (bss) { 1493 ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); 1494 if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7)) 1495 return ie + 4; 1496 } 1497 1498 return NULL; 1499 } 1500 #endif /* CONFIG_FILS */ 1501 1502 1503 int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab) 1504 { 1505 if (!bss) 1506 return 0; 1507 return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB), 1508 capab); 1509 } 1510 1511 1512 static void 1513 wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, 1514 struct wpa_bss *bss, u8 mbssid_idx, 1515 const struct ieee80211_neighbor_ap_info *ap_info, 1516 size_t len, u16 *seen, u16 *missing, 1517 struct wpa_ssid *ssid) 1518 { 1519 const u8 *pos, *end; 1520 const u8 *mld_params; 1521 u8 count, mld_params_offset; 1522 u8 i, type, link_id; 1523 1524 count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1; 1525 type = ap_info->tbtt_info_hdr & RNR_TBTT_INFO_HDR_TYPE_MSK; 1526 1527 /* MLD information is at offset 13 or at start */ 1528 if (type == 0 && ap_info->tbtt_info_len >= RNR_TBTT_INFO_MLD_LEN) { 1529 /* MLD info is appended */ 1530 mld_params_offset = RNR_TBTT_INFO_LEN; 1531 } else { 1532 /* TODO: Support NSTR AP */ 1533 return; 1534 } 1535 1536 pos = (const u8 *) ap_info; 1537 end = pos + len; 1538 pos += sizeof(*ap_info); 1539 1540 for (i = 0; i < count; i++) { 1541 u8 bss_params; 1542 1543 if (end - pos < ap_info->tbtt_info_len) 1544 break; 1545 1546 bss_params = pos[1 + ETH_ALEN + 4]; 1547 mld_params = pos + mld_params_offset; 1548 1549 link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK; 1550 if (link_id >= MAX_NUM_MLD_LINKS) 1551 return; 1552 1553 if (*mld_params != mbssid_idx) { 1554 wpa_printf(MSG_DEBUG, 1555 "MLD: Reported link not part of MLD"); 1556 } else if (!(BIT(link_id) & *seen)) { 1557 struct wpa_bss *neigh_bss; 1558 1559 if (ssid && ssid->ssid_len) 1560 neigh_bss = wpa_bss_get(wpa_s, pos + 1, 1561 ssid->ssid, 1562 ssid->ssid_len); 1563 else 1564 neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1); 1565 1566 *seen |= BIT(link_id); 1567 wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", 1568 *mld_params, link_id); 1569 1570 if (!neigh_bss) { 1571 *missing |= BIT(link_id); 1572 } else if ((!ssid || 1573 (bss_params & (RNR_BSS_PARAM_SAME_SSID | 1574 RNR_BSS_PARAM_CO_LOCATED)) || 1575 wpa_scan_res_match(wpa_s, 0, neigh_bss, 1576 ssid, 1, 0)) && 1577 !wpa_bssid_ignore_is_listed( 1578 wpa_s, neigh_bss->bssid)) { 1579 struct mld_link *l; 1580 1581 bss->valid_links |= BIT(link_id); 1582 l = &bss->mld_links[link_id]; 1583 os_memcpy(l->bssid, pos + 1, ETH_ALEN); 1584 l->freq = neigh_bss->freq; 1585 l->disabled = mld_params[2] & 1586 RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED; 1587 } 1588 } 1589 1590 pos += ap_info->tbtt_info_len; 1591 } 1592 } 1593 1594 1595 /** 1596 * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element 1597 * @wpa_s: Pointer to wpa_supplicant data 1598 * @bss: BSS table entry 1599 * @mld_addr: AP MLD address (or %NULL) 1600 * @link_info: Array to store link information (or %NULL), 1601 * should be initialized and #MAX_NUM_MLD_LINKS elements long 1602 * @missing_links: Result bitmask of links that were not discovered (or %NULL) 1603 * @ssid: Target SSID (or %NULL) 1604 * @ap_mld_id: On return would hold the corresponding AP MLD ID (or %NULL) 1605 * Returns: 0 on success or -1 for non-MLD or parsing failures 1606 * 1607 * Parses the Basic Multi-Link element of the BSS into @link_info using the scan 1608 * information stored in the wpa_supplicant data to fill in information for 1609 * links where possible. The @missing_links out parameter will contain any links 1610 * for which no corresponding BSS was found. 1611 */ 1612 int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, 1613 struct wpa_bss *bss, 1614 u8 *ap_mld_addr, 1615 u16 *missing_links, 1616 struct wpa_ssid *ssid, 1617 u8 *ap_mld_id) 1618 { 1619 struct ieee802_11_elems elems; 1620 struct wpabuf *mlbuf; 1621 const struct element *elem; 1622 u8 mbssid_idx = 0; 1623 size_t ml_ie_len; 1624 const struct ieee80211_eht_ml *eht_ml; 1625 const struct eht_ml_basic_common_info *ml_basic_common_info; 1626 u8 i, link_id; 1627 const u16 control_mask = 1628 MULTI_LINK_CONTROL_TYPE_MASK | 1629 BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | 1630 BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | 1631 BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; 1632 const u16 control = 1633 MULTI_LINK_CONTROL_TYPE_BASIC | 1634 BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | 1635 BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | 1636 BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; 1637 u16 missing = 0; 1638 u16 seen; 1639 const u8 *ies_pos = wpa_bss_ie_ptr(bss); 1640 size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; 1641 int ret = -1; 1642 struct mld_link *l; 1643 1644 if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) == 1645 ParseFailed) { 1646 wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements"); 1647 return ret; 1648 } 1649 1650 mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true); 1651 if (!mlbuf) { 1652 wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element"); 1653 return ret; 1654 } 1655 1656 ml_ie_len = wpabuf_len(mlbuf); 1657 1658 if (ssid) { 1659 struct wpa_ie_data ie; 1660 1661 if (!elems.rsn_ie || 1662 wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len, 1663 &ie)) { 1664 wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element"); 1665 goto out; 1666 } 1667 1668 if (!(ie.capabilities & WPA_CAPABILITY_MFPC) || 1669 wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) { 1670 wpa_dbg(wpa_s, MSG_DEBUG, 1671 "MLD: No management frame protection"); 1672 goto out; 1673 } 1674 1675 ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | 1676 WPA_KEY_MGMT_PSK_SHA256); 1677 if (!(ie.key_mgmt & ssid->key_mgmt)) { 1678 wpa_dbg(wpa_s, MSG_DEBUG, 1679 "MLD: No valid key management"); 1680 goto out; 1681 } 1682 } 1683 1684 /* 1685 * for ext ID + 2 control + common info len + MLD address + 1686 * link info 1687 */ 1688 if (ml_ie_len < 2UL + 1UL + ETH_ALEN + 1UL) 1689 goto out; 1690 1691 eht_ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf); 1692 if ((le_to_host16(eht_ml->ml_control) & control_mask) != control) { 1693 wpa_printf(MSG_DEBUG, 1694 "MLD: Unexpected Multi-Link element control=0x%x (mask 0x%x expected 0x%x)", 1695 le_to_host16(eht_ml->ml_control), control_mask, 1696 control); 1697 goto out; 1698 } 1699 1700 ml_basic_common_info = 1701 (const struct eht_ml_basic_common_info *) eht_ml->variable; 1702 1703 /* Common info length should be valid */ 1704 if (ml_basic_common_info->len < ETH_ALEN + 1UL) 1705 goto out; 1706 1707 /* Get the MLD address and MLD link ID */ 1708 if (ap_mld_addr) 1709 os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr, 1710 ETH_ALEN); 1711 1712 link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK; 1713 1714 bss->mld_link_id = link_id; 1715 seen = bss->valid_links = BIT(link_id); 1716 1717 l = &bss->mld_links[link_id]; 1718 os_memcpy(l->bssid, bss->bssid, ETH_ALEN); 1719 l->freq = bss->freq; 1720 1721 1722 /* 1723 * The AP MLD ID in the RNR corresponds to the MBSSID index, see 1724 * IEEE P802.11be/D4.0, 9.4.2.169.2 (Neighbor AP Information field). 1725 * 1726 * For the transmitting BSSID it is clear that both the MBSSID index 1727 * and the AP MLD ID in the RNR are zero. 1728 * 1729 * For nontransmitted BSSIDs we will have a BSS generated from the 1730 * MBSSID element(s) using inheritance rules. Included in the elements 1731 * is the MBSSID Index Element. The RNR is copied from the Beacon/Probe 1732 * Response frame that was send by the transmitting BSSID. As such, the 1733 * reported AP MLD ID in the RNR will match the value in the MBSSID 1734 * Index Element. 1735 */ 1736 elem = (const struct element *) 1737 wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX); 1738 if (elem && elem->datalen >= 1) 1739 mbssid_idx = elem->data[0]; 1740 1741 for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, 1742 wpa_bss_ie_ptr(bss), 1743 bss->ie_len ? bss->ie_len : bss->beacon_ie_len) { 1744 const struct ieee80211_neighbor_ap_info *ap_info; 1745 const u8 *pos = elem->data; 1746 size_t len = elem->datalen; 1747 1748 /* RNR IE may contain more than one Neighbor AP Info */ 1749 while (sizeof(*ap_info) <= len) { 1750 size_t ap_info_len = sizeof(*ap_info); 1751 u8 count; 1752 1753 ap_info = (const struct ieee80211_neighbor_ap_info *) 1754 pos; 1755 count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1; 1756 ap_info_len += count * ap_info->tbtt_info_len; 1757 1758 if (ap_info_len > len) 1759 goto out; 1760 1761 wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx, 1762 ap_info, len, &seen, 1763 &missing, ssid); 1764 1765 pos += ap_info_len; 1766 len -= ap_info_len; 1767 } 1768 } 1769 1770 wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)", 1771 bss->valid_links, missing); 1772 1773 for_each_link(bss->valid_links, i) { 1774 wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR, 1775 i, MAC2STR(bss->mld_links[i].bssid)); 1776 } 1777 1778 if (missing_links) 1779 *missing_links = missing; 1780 1781 if (ap_mld_id) 1782 *ap_mld_id = mbssid_idx; 1783 1784 ret = 0; 1785 out: 1786 wpabuf_free(mlbuf); 1787 return ret; 1788 } 1789 1790 1791 /* 1792 * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element 1793 * @wpa_s: Pointer to wpa_supplicant data 1794 * @bss: BSS table entry 1795 * Returns: The bitmap of links that are going to be removed 1796 */ 1797 u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s, 1798 struct wpa_bss *bss) 1799 { 1800 struct ieee802_11_elems elems; 1801 struct wpabuf *mlbuf; 1802 const u8 *pos = wpa_bss_ie_ptr(bss); 1803 size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; 1804 const struct ieee80211_eht_ml *ml; 1805 u16 removed_links = 0; 1806 u8 ml_common_len; 1807 1808 if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed) 1809 return 0; 1810 1811 if (!elems.reconf_mle || !elems.reconf_mle_len) 1812 return 0; 1813 1814 mlbuf = ieee802_11_defrag(elems.reconf_mle, elems.reconf_mle_len, true); 1815 if (!mlbuf) 1816 return 0; 1817 1818 ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf); 1819 len = wpabuf_len(mlbuf); 1820 1821 if (len < sizeof(*ml)) 1822 goto out; 1823 1824 ml_common_len = 1; 1825 if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR) 1826 ml_common_len += ETH_ALEN; 1827 1828 if (len < sizeof(*ml) + ml_common_len) { 1829 wpa_printf(MSG_DEBUG, 1830 "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)", 1831 len, sizeof(*ml) + ml_common_len); 1832 goto out; 1833 } 1834 1835 pos = ml->variable + ml_common_len; 1836 len -= sizeof(*ml) + ml_common_len; 1837 1838 while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) { 1839 size_t sub_elem_len = *(pos + 1); 1840 1841 if (2 + sub_elem_len > len) { 1842 wpa_printf(MSG_DEBUG, 1843 "MLD: Invalid link info len: %zu %zu", 1844 2 + sub_elem_len, len); 1845 goto out; 1846 } 1847 1848 if (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) { 1849 const struct ieee80211_eht_per_sta_profile *sta_prof = 1850 (const struct ieee80211_eht_per_sta_profile *) 1851 (pos + 2); 1852 u16 control = le_to_host16(sta_prof->sta_control); 1853 u8 link_id; 1854 1855 link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK; 1856 removed_links |= BIT(link_id); 1857 } 1858 1859 pos += 2 + sub_elem_len; 1860 len -= 2 + sub_elem_len; 1861 } 1862 1863 wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x", 1864 removed_links); 1865 out: 1866 wpabuf_free(mlbuf); 1867 return removed_links; 1868 } 1869