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