1 /* 2 * wpa_supplicant - WNM 3 * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. 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 "common/ieee802_11_defs.h" 13 #include "common/ieee802_11_common.h" 14 #include "common/wpa_ctrl.h" 15 #include "rsn_supp/wpa.h" 16 #include "wpa_supplicant_i.h" 17 #include "driver_i.h" 18 #include "scan.h" 19 #include "ctrl_iface.h" 20 #include "bss.h" 21 #include "wnm_sta.h" 22 #include "hs20_supplicant.h" 23 24 #define MAX_TFS_IE_LEN 1024 25 #define WNM_MAX_NEIGHBOR_REPORT 10 26 27 #define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ 28 29 /* get the TFS IE from driver */ 30 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 31 u16 *buf_len, enum wnm_oper oper) 32 { 33 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 34 35 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 36 } 37 38 39 /* set the TFS IE to driver */ 40 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 41 const u8 *addr, const u8 *buf, u16 buf_len, 42 enum wnm_oper oper) 43 { 44 u16 len = buf_len; 45 46 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 47 48 return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 49 } 50 51 52 /* MLME-SLEEPMODE.request */ 53 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 54 u8 action, u16 intval, struct wpabuf *tfs_req) 55 { 56 struct ieee80211_mgmt *mgmt; 57 int res; 58 size_t len; 59 struct wnm_sleep_element *wnmsleep_ie; 60 u8 *wnmtfs_ie; 61 u8 wnmsleep_ie_len; 62 u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 63 enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 64 WNM_SLEEP_TFS_REQ_IE_NONE; 65 66 wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 67 "action=%s to " MACSTR, 68 action == 0 ? "enter" : "exit", 69 MAC2STR(wpa_s->bssid)); 70 71 /* WNM-Sleep Mode IE */ 72 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 73 wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 74 if (wnmsleep_ie == NULL) 75 return -1; 76 wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 77 wnmsleep_ie->len = wnmsleep_ie_len - 2; 78 wnmsleep_ie->action_type = action; 79 wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 80 wnmsleep_ie->intval = host_to_le16(intval); 81 wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 82 (u8 *) wnmsleep_ie, wnmsleep_ie_len); 83 84 /* TFS IE(s) */ 85 if (tfs_req) { 86 wnmtfs_ie_len = wpabuf_len(tfs_req); 87 wnmtfs_ie = os_malloc(wnmtfs_ie_len); 88 if (wnmtfs_ie == NULL) { 89 os_free(wnmsleep_ie); 90 return -1; 91 } 92 os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 93 } else { 94 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 95 if (wnmtfs_ie == NULL) { 96 os_free(wnmsleep_ie); 97 return -1; 98 } 99 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 100 tfs_oper)) { 101 wnmtfs_ie_len = 0; 102 os_free(wnmtfs_ie); 103 wnmtfs_ie = NULL; 104 } 105 } 106 wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 107 (u8 *) wnmtfs_ie, wnmtfs_ie_len); 108 109 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 110 if (mgmt == NULL) { 111 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 112 "WNM-Sleep Request action frame"); 113 os_free(wnmsleep_ie); 114 os_free(wnmtfs_ie); 115 return -1; 116 } 117 118 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 119 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 120 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 121 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 122 WLAN_FC_STYPE_ACTION); 123 mgmt->u.action.category = WLAN_ACTION_WNM; 124 mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 125 mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 126 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 127 wnmsleep_ie_len); 128 /* copy TFS IE here */ 129 if (wnmtfs_ie_len > 0) { 130 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 131 wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 132 } 133 134 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 135 wnmtfs_ie_len; 136 137 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 138 wpa_s->own_addr, wpa_s->bssid, 139 &mgmt->u.action.category, len, 0); 140 if (res < 0) 141 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 142 "(action=%d, intval=%d)", action, intval); 143 else 144 wpa_s->wnmsleep_used = 1; 145 146 os_free(wnmsleep_ie); 147 os_free(wnmtfs_ie); 148 os_free(mgmt); 149 150 return res; 151 } 152 153 154 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 155 const u8 *tfsresp_ie_start, 156 const u8 *tfsresp_ie_end) 157 { 158 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 159 wpa_s->bssid, NULL, NULL); 160 /* remove GTK/IGTK ?? */ 161 162 /* set the TFS Resp IE(s) */ 163 if (tfsresp_ie_start && tfsresp_ie_end && 164 tfsresp_ie_end - tfsresp_ie_start >= 0) { 165 u16 tfsresp_ie_len; 166 tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 167 tfsresp_ie_start; 168 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 169 /* pass the TFS Resp IE(s) to driver for processing */ 170 if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 171 tfsresp_ie_start, 172 tfsresp_ie_len, 173 WNM_SLEEP_TFS_RESP_IE_SET)) 174 wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 175 } 176 } 177 178 179 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 180 const u8 *frm, u16 key_len_total) 181 { 182 u8 *ptr, *end; 183 u8 gtk_len; 184 185 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 186 NULL, NULL); 187 188 /* Install GTK/IGTK */ 189 190 /* point to key data field */ 191 ptr = (u8 *) frm + 1 + 2; 192 end = ptr + key_len_total; 193 wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 194 195 if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { 196 wpa_msg(wpa_s, MSG_INFO, 197 "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); 198 return; 199 } 200 201 while (end - ptr > 1) { 202 if (2 + ptr[1] > end - ptr) { 203 wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 204 "length"); 205 if (end > ptr) { 206 wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 207 ptr, end - ptr); 208 } 209 break; 210 } 211 if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 212 if (ptr[1] < 11 + 5) { 213 wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 214 "subelem"); 215 break; 216 } 217 gtk_len = *(ptr + 4); 218 if (ptr[1] < 11 + gtk_len || 219 gtk_len < 5 || gtk_len > 32) { 220 wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 221 "subelem"); 222 break; 223 } 224 wpa_wnmsleep_install_key( 225 wpa_s->wpa, 226 WNM_SLEEP_SUBELEM_GTK, 227 ptr); 228 ptr += 13 + gtk_len; 229 #ifdef CONFIG_IEEE80211W 230 } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 231 if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 232 wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 233 "subelem"); 234 break; 235 } 236 wpa_wnmsleep_install_key(wpa_s->wpa, 237 WNM_SLEEP_SUBELEM_IGTK, ptr); 238 ptr += 10 + WPA_IGTK_LEN; 239 #endif /* CONFIG_IEEE80211W */ 240 } else 241 break; /* skip the loop */ 242 } 243 } 244 245 246 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 247 const u8 *frm, int len) 248 { 249 /* 250 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 251 * WNM-Sleep Mode IE | TFS Response IE 252 */ 253 const u8 *pos = frm; /* point to payload after the action field */ 254 u16 key_len_total; 255 struct wnm_sleep_element *wnmsleep_ie = NULL; 256 /* multiple TFS Resp IE (assuming consecutive) */ 257 const u8 *tfsresp_ie_start = NULL; 258 const u8 *tfsresp_ie_end = NULL; 259 size_t left; 260 261 if (!wpa_s->wnmsleep_used) { 262 wpa_printf(MSG_DEBUG, 263 "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested"); 264 return; 265 } 266 267 if (len < 3) 268 return; 269 key_len_total = WPA_GET_LE16(frm + 1); 270 271 wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 272 frm[0], key_len_total); 273 left = len - 3; 274 if (key_len_total > left) { 275 wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 276 return; 277 } 278 pos += 3 + key_len_total; 279 while (pos - frm + 1 < len) { 280 u8 ie_len = *(pos + 1); 281 if (2 + ie_len > frm + len - pos) { 282 wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 283 break; 284 } 285 wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 286 if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) 287 wnmsleep_ie = (struct wnm_sleep_element *) pos; 288 else if (*pos == WLAN_EID_TFS_RESP) { 289 if (!tfsresp_ie_start) 290 tfsresp_ie_start = pos; 291 tfsresp_ie_end = pos; 292 } else 293 wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 294 pos += ie_len + 2; 295 } 296 297 if (!wnmsleep_ie) { 298 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 299 return; 300 } 301 302 wpa_s->wnmsleep_used = 0; 303 304 if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 305 wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 306 wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 307 "frame (action=%d, intval=%d)", 308 wnmsleep_ie->action_type, wnmsleep_ie->intval); 309 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 310 wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 311 tfsresp_ie_end); 312 } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 313 wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 314 } 315 } else { 316 wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 317 "(action=%d, intval=%d)", 318 wnmsleep_ie->action_type, wnmsleep_ie->intval); 319 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 320 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 321 wpa_s->bssid, NULL, NULL); 322 else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 323 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 324 wpa_s->bssid, NULL, NULL); 325 } 326 } 327 328 329 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 330 { 331 int i; 332 333 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 334 os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 335 os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 336 } 337 338 wpa_s->wnm_num_neighbor_report = 0; 339 os_free(wpa_s->wnm_neighbor_report_elements); 340 wpa_s->wnm_neighbor_report_elements = NULL; 341 } 342 343 344 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 345 u8 id, u8 elen, const u8 *pos) 346 { 347 switch (id) { 348 case WNM_NEIGHBOR_TSF: 349 if (elen < 2 + 2) { 350 wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 351 break; 352 } 353 rep->tsf_offset = WPA_GET_LE16(pos); 354 rep->beacon_int = WPA_GET_LE16(pos + 2); 355 rep->tsf_present = 1; 356 break; 357 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 358 if (elen < 2) { 359 wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 360 "country string"); 361 break; 362 } 363 os_memcpy(rep->country, pos, 2); 364 rep->country_present = 1; 365 break; 366 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 367 if (elen < 1) { 368 wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 369 "candidate"); 370 break; 371 } 372 rep->preference = pos[0]; 373 rep->preference_present = 1; 374 break; 375 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 376 rep->bss_term_tsf = WPA_GET_LE64(pos); 377 rep->bss_term_dur = WPA_GET_LE16(pos + 8); 378 rep->bss_term_present = 1; 379 break; 380 case WNM_NEIGHBOR_BEARING: 381 if (elen < 8) { 382 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 383 "bearing"); 384 break; 385 } 386 rep->bearing = WPA_GET_LE16(pos); 387 rep->distance = WPA_GET_LE32(pos + 2); 388 rep->rel_height = WPA_GET_LE16(pos + 2 + 4); 389 rep->bearing_present = 1; 390 break; 391 case WNM_NEIGHBOR_MEASUREMENT_PILOT: 392 if (elen < 1) { 393 wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 394 "pilot"); 395 break; 396 } 397 os_free(rep->meas_pilot); 398 rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 399 if (rep->meas_pilot == NULL) 400 break; 401 rep->meas_pilot->measurement_pilot = pos[0]; 402 rep->meas_pilot->subelem_len = elen - 1; 403 os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 404 break; 405 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 406 if (elen < 5) { 407 wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 408 "capabilities"); 409 break; 410 } 411 os_memcpy(rep->rm_capab, pos, 5); 412 rep->rm_capab_present = 1; 413 break; 414 case WNM_NEIGHBOR_MULTIPLE_BSSID: 415 if (elen < 1) { 416 wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 417 break; 418 } 419 os_free(rep->mul_bssid); 420 rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 421 if (rep->mul_bssid == NULL) 422 break; 423 rep->mul_bssid->max_bssid_indicator = pos[0]; 424 rep->mul_bssid->subelem_len = elen - 1; 425 os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 426 break; 427 } 428 } 429 430 431 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) 432 { 433 struct wpa_bss *bss = wpa_s->current_bss; 434 const char *country = NULL; 435 int freq; 436 437 if (bss) { 438 const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); 439 440 if (elem && elem[1] >= 2) 441 country = (const char *) (elem + 2); 442 } 443 444 freq = ieee80211_chan_to_freq(country, op_class, chan); 445 if (freq <= 0 && op_class == 0) { 446 /* 447 * Some APs do not advertise correct operating class 448 * information. Try to determine the most likely operating 449 * frequency based on the channel number. 450 */ 451 if (chan >= 1 && chan <= 13) 452 freq = 2407 + chan * 5; 453 else if (chan == 14) 454 freq = 2484; 455 else if (chan >= 36 && chan <= 169) 456 freq = 5000 + chan * 5; 457 } 458 return freq; 459 } 460 461 462 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 463 const u8 *pos, u8 len, 464 struct neighbor_report *rep) 465 { 466 u8 left = len; 467 468 if (left < 13) { 469 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 470 return; 471 } 472 473 os_memcpy(rep->bssid, pos, ETH_ALEN); 474 rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); 475 rep->regulatory_class = *(pos + 10); 476 rep->channel_number = *(pos + 11); 477 rep->phy_type = *(pos + 12); 478 479 pos += 13; 480 left -= 13; 481 482 while (left >= 2) { 483 u8 id, elen; 484 485 id = *pos++; 486 elen = *pos++; 487 wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 488 left -= 2; 489 if (elen > left) { 490 wpa_printf(MSG_DEBUG, 491 "WNM: Truncated neighbor report subelement"); 492 break; 493 } 494 wnm_parse_neighbor_report_elem(rep, id, elen, pos); 495 left -= elen; 496 pos += elen; 497 } 498 499 rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, 500 rep->channel_number); 501 } 502 503 504 static struct wpa_bss * 505 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) 506 { 507 508 u8 i; 509 struct wpa_bss *bss = wpa_s->current_bss; 510 struct wpa_bss *target; 511 512 if (!bss) 513 return NULL; 514 515 wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 516 MAC2STR(wpa_s->bssid), bss->level); 517 518 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 519 struct neighbor_report *nei; 520 521 nei = &wpa_s->wnm_neighbor_report_elements[i]; 522 if (nei->preference_present && nei->preference == 0) { 523 wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 524 MAC2STR(nei->bssid)); 525 continue; 526 } 527 528 target = wpa_bss_get_bssid(wpa_s, nei->bssid); 529 if (!target) { 530 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 531 " (pref %d) not found in scan results", 532 MAC2STR(nei->bssid), 533 nei->preference_present ? nei->preference : 534 -1); 535 continue; 536 } 537 538 if (age_secs) { 539 struct os_reltime now; 540 541 if (os_get_reltime(&now) == 0 && 542 os_reltime_expired(&now, &target->last_update, 543 age_secs)) { 544 wpa_printf(MSG_DEBUG, 545 "Candidate BSS is more than %ld seconds old", 546 age_secs); 547 continue; 548 } 549 } 550 551 if (bss->ssid_len != target->ssid_len || 552 os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 553 /* 554 * TODO: Could consider allowing transition to another 555 * ESS if PMF was enabled for the association. 556 */ 557 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 558 " (pref %d) in different ESS", 559 MAC2STR(nei->bssid), 560 nei->preference_present ? nei->preference : 561 -1); 562 continue; 563 } 564 565 if (wpa_s->current_ssid && 566 !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 567 1)) { 568 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 569 " (pref %d) does not match the current network profile", 570 MAC2STR(nei->bssid), 571 nei->preference_present ? nei->preference : 572 -1); 573 continue; 574 } 575 576 if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { 577 wpa_printf(MSG_DEBUG, 578 "MBO: Candidate BSS " MACSTR 579 " retry delay is not over yet", 580 MAC2STR(nei->bssid)); 581 continue; 582 } 583 584 if (target->level < bss->level && target->level < -80) { 585 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 586 " (pref %d) does not have sufficient signal level (%d)", 587 MAC2STR(nei->bssid), 588 nei->preference_present ? nei->preference : 589 -1, 590 target->level); 591 continue; 592 } 593 594 wpa_printf(MSG_DEBUG, 595 "WNM: Found an acceptable preferred transition candidate BSS " 596 MACSTR " (RSSI %d)", 597 MAC2STR(nei->bssid), target->level); 598 return target; 599 } 600 601 return NULL; 602 } 603 604 605 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) 606 { 607 const u8 *ie_a, *ie_b; 608 609 if (!a || !b) 610 return 0; 611 612 ie_a = wpa_bss_get_ie(a, eid); 613 ie_b = wpa_bss_get_ie(b, eid); 614 615 if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) 616 return 0; 617 618 return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; 619 } 620 621 622 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 623 { 624 u32 info = 0; 625 626 info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; 627 628 /* 629 * Leave the security and key scope bits unset to indicate that the 630 * security information is not available. 631 */ 632 633 if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) 634 info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 635 if (bss->caps & WLAN_CAPABILITY_QOS) 636 info |= NEI_REP_BSSID_INFO_QOS; 637 if (bss->caps & WLAN_CAPABILITY_APSD) 638 info |= NEI_REP_BSSID_INFO_APSD; 639 if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) 640 info |= NEI_REP_BSSID_INFO_RM; 641 if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) 642 info |= NEI_REP_BSSID_INFO_DELAYED_BA; 643 if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) 644 info |= NEI_REP_BSSID_INFO_IMM_BA; 645 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) 646 info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; 647 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) 648 info |= NEI_REP_BSSID_INFO_HT; 649 650 return info; 651 } 652 653 654 static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, 655 u8 op_class, u8 chan, u8 phy_type, u8 pref) 656 { 657 u8 *pos = buf; 658 659 if (len < 18) { 660 wpa_printf(MSG_DEBUG, 661 "WNM: Not enough room for Neighbor Report element"); 662 return -1; 663 } 664 665 *pos++ = WLAN_EID_NEIGHBOR_REPORT; 666 /* length: 13 for basic neighbor report + 3 for preference subelement */ 667 *pos++ = 16; 668 os_memcpy(pos, bssid, ETH_ALEN); 669 pos += ETH_ALEN; 670 WPA_PUT_LE32(pos, bss_info); 671 pos += 4; 672 *pos++ = op_class; 673 *pos++ = chan; 674 *pos++ = phy_type; 675 *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; 676 *pos++ = 1; 677 *pos++ = pref; 678 return pos - buf; 679 } 680 681 682 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, 683 struct wpa_bss *bss, u8 *buf, size_t len, 684 u8 pref) 685 { 686 const u8 *ie; 687 u8 op_class, chan; 688 int sec_chan = 0, vht = 0; 689 enum phy_type phy_type; 690 u32 info; 691 struct ieee80211_ht_operation *ht_oper = NULL; 692 struct ieee80211_vht_operation *vht_oper = NULL; 693 694 ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); 695 if (ie && ie[1] >= 2) { 696 ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 697 698 if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 699 sec_chan = 1; 700 else if (ht_oper->ht_param & 701 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 702 sec_chan = -1; 703 } 704 705 ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); 706 if (ie && ie[1] >= 1) { 707 vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 708 709 if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || 710 vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || 711 vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) 712 vht = vht_oper->vht_op_info_chwidth; 713 } 714 715 if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, 716 &chan) == NUM_HOSTAPD_MODES) { 717 wpa_printf(MSG_DEBUG, 718 "WNM: Cannot determine operating class and channel"); 719 return -2; 720 } 721 722 phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), 723 (vht_oper != NULL)); 724 if (phy_type == PHY_TYPE_UNSPECIFIED) { 725 wpa_printf(MSG_DEBUG, 726 "WNM: Cannot determine BSS phy type for Neighbor Report"); 727 return -2; 728 } 729 730 info = wnm_get_bss_info(wpa_s, bss); 731 732 return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, 733 phy_type, pref); 734 } 735 736 737 static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) 738 { 739 u8 *pos = buf; 740 unsigned int i, pref = 255; 741 struct os_reltime now; 742 struct wpa_ssid *ssid = wpa_s->current_ssid; 743 744 if (!ssid) 745 return 0; 746 747 /* 748 * TODO: Define when scan results are no longer valid for the candidate 749 * list. 750 */ 751 os_get_reltime(&now); 752 if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) 753 return 0; 754 755 wpa_printf(MSG_DEBUG, 756 "WNM: Add candidate list to BSS Transition Management Response frame"); 757 for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { 758 struct wpa_bss *bss = wpa_s->last_scan_res[i]; 759 int res; 760 761 if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) { 762 res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); 763 if (res == -2) 764 continue; /* could not build entry for BSS */ 765 if (res < 0) 766 break; /* no more room for candidates */ 767 if (pref == 1) 768 break; 769 770 pos += res; 771 len -= res; 772 } 773 } 774 775 wpa_hexdump(MSG_DEBUG, 776 "WNM: BSS Transition Management Response candidate list", 777 buf, pos - buf); 778 779 return pos - buf; 780 } 781 782 783 static void wnm_send_bss_transition_mgmt_resp( 784 struct wpa_supplicant *wpa_s, u8 dialog_token, 785 enum bss_trans_mgmt_status_code status, u8 delay, 786 const u8 *target_bssid) 787 { 788 u8 buf[2000], *pos; 789 struct ieee80211_mgmt *mgmt; 790 size_t len; 791 int res; 792 793 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 794 "to " MACSTR " dialog_token=%u status=%u delay=%d", 795 MAC2STR(wpa_s->bssid), dialog_token, status, delay); 796 if (!wpa_s->current_bss) { 797 wpa_printf(MSG_DEBUG, 798 "WNM: Current BSS not known - drop response"); 799 return; 800 } 801 802 mgmt = (struct ieee80211_mgmt *) buf; 803 os_memset(&buf, 0, sizeof(buf)); 804 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 805 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 806 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 807 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 808 WLAN_FC_STYPE_ACTION); 809 mgmt->u.action.category = WLAN_ACTION_WNM; 810 mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 811 mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 812 mgmt->u.action.u.bss_tm_resp.status_code = status; 813 mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 814 pos = mgmt->u.action.u.bss_tm_resp.variable; 815 if (target_bssid) { 816 os_memcpy(pos, target_bssid, ETH_ALEN); 817 pos += ETH_ALEN; 818 } else if (status == WNM_BSS_TM_ACCEPT) { 819 /* 820 * P802.11-REVmc clarifies that the Target BSSID field is always 821 * present when status code is zero, so use a fake value here if 822 * no BSSID is yet known. 823 */ 824 os_memset(pos, 0, ETH_ALEN); 825 pos += ETH_ALEN; 826 } 827 828 if (status == WNM_BSS_TM_ACCEPT) 829 pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 830 831 #ifdef CONFIG_MBO 832 if (status != WNM_BSS_TM_ACCEPT) { 833 pos += wpas_mbo_ie_bss_trans_reject( 834 wpa_s, pos, buf + sizeof(buf) - pos, 835 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED); 836 } 837 #endif /* CONFIG_MBO */ 838 839 len = pos - (u8 *) &mgmt->u.action.category; 840 841 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 842 wpa_s->own_addr, wpa_s->bssid, 843 &mgmt->u.action.category, len, 0); 844 if (res < 0) { 845 wpa_printf(MSG_DEBUG, 846 "WNM: Failed to send BSS Transition Management Response"); 847 } 848 } 849 850 851 static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, 852 struct wpa_bss *bss, struct wpa_ssid *ssid, 853 int after_new_scan) 854 { 855 wpa_dbg(wpa_s, MSG_DEBUG, 856 "WNM: Transition to BSS " MACSTR 857 " based on BSS Transition Management Request (old BSSID " 858 MACSTR " after_new_scan=%d)", 859 MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); 860 861 /* Send the BSS Management Response - Accept */ 862 if (wpa_s->wnm_reply) { 863 wpa_s->wnm_reply = 0; 864 wpa_printf(MSG_DEBUG, 865 "WNM: Sending successful BSS Transition Management Response"); 866 wnm_send_bss_transition_mgmt_resp(wpa_s, 867 wpa_s->wnm_dialog_token, 868 WNM_BSS_TM_ACCEPT, 869 0, bss->bssid); 870 } 871 872 if (bss == wpa_s->current_bss) { 873 wpa_printf(MSG_DEBUG, 874 "WNM: Already associated with the preferred candidate"); 875 wnm_deallocate_memory(wpa_s); 876 return; 877 } 878 879 wpa_s->reassociate = 1; 880 wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); 881 wpa_supplicant_connect(wpa_s, bss, ssid); 882 wnm_deallocate_memory(wpa_s); 883 } 884 885 886 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 887 { 888 struct wpa_bss *bss; 889 struct wpa_ssid *ssid = wpa_s->current_ssid; 890 enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 891 892 if (!wpa_s->wnm_neighbor_report_elements) 893 return 0; 894 895 wpa_dbg(wpa_s, MSG_DEBUG, 896 "WNM: Process scan results for BSS Transition Management"); 897 if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 898 &wpa_s->scan_trigger_time)) { 899 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 900 wnm_deallocate_memory(wpa_s); 901 return 0; 902 } 903 904 if (!wpa_s->current_bss || 905 os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 906 ETH_ALEN) != 0) { 907 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 908 return 0; 909 } 910 911 /* Compare the Neighbor Report and scan results */ 912 bss = compare_scan_neighbor_results(wpa_s, 0); 913 if (!bss) { 914 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 915 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 916 goto send_bss_resp_fail; 917 } 918 919 /* Associate to the network */ 920 wnm_bss_tm_connect(wpa_s, bss, ssid, 1); 921 return 1; 922 923 send_bss_resp_fail: 924 if (!reply_on_fail) 925 return 0; 926 927 /* Send reject response for all the failures */ 928 929 if (wpa_s->wnm_reply) { 930 wpa_s->wnm_reply = 0; 931 wnm_send_bss_transition_mgmt_resp(wpa_s, 932 wpa_s->wnm_dialog_token, 933 status, 0, NULL); 934 } 935 wnm_deallocate_memory(wpa_s); 936 937 return 0; 938 } 939 940 941 static int cand_pref_compar(const void *a, const void *b) 942 { 943 const struct neighbor_report *aa = a; 944 const struct neighbor_report *bb = b; 945 946 if (!aa->preference_present && !bb->preference_present) 947 return 0; 948 if (!aa->preference_present) 949 return 1; 950 if (!bb->preference_present) 951 return -1; 952 if (bb->preference > aa->preference) 953 return 1; 954 if (bb->preference < aa->preference) 955 return -1; 956 return 0; 957 } 958 959 960 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 961 { 962 if (!wpa_s->wnm_neighbor_report_elements) 963 return; 964 qsort(wpa_s->wnm_neighbor_report_elements, 965 wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 966 cand_pref_compar); 967 } 968 969 970 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 971 { 972 unsigned int i; 973 974 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 975 if (!wpa_s->wnm_neighbor_report_elements) 976 return; 977 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 978 struct neighbor_report *nei; 979 980 nei = &wpa_s->wnm_neighbor_report_elements[i]; 981 wpa_printf(MSG_DEBUG, "%u: " MACSTR 982 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 983 i, MAC2STR(nei->bssid), nei->bssid_info, 984 nei->regulatory_class, 985 nei->channel_number, nei->phy_type, 986 nei->preference_present ? nei->preference : -1, 987 nei->freq); 988 } 989 } 990 991 992 static int chan_supported(struct wpa_supplicant *wpa_s, int freq) 993 { 994 unsigned int i; 995 996 for (i = 0; i < wpa_s->hw.num_modes; i++) { 997 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 998 int j; 999 1000 for (j = 0; j < mode->num_channels; j++) { 1001 struct hostapd_channel_data *chan; 1002 1003 chan = &mode->channels[j]; 1004 if (chan->freq == freq && 1005 !(chan->flag & HOSTAPD_CHAN_DISABLED)) 1006 return 1; 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 1014 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 1015 { 1016 int *freqs; 1017 int num_freqs = 0; 1018 unsigned int i; 1019 1020 if (!wpa_s->wnm_neighbor_report_elements) 1021 return; 1022 1023 if (wpa_s->hw.modes == NULL) 1024 return; 1025 1026 os_free(wpa_s->next_scan_freqs); 1027 wpa_s->next_scan_freqs = NULL; 1028 1029 freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 1030 if (freqs == NULL) 1031 return; 1032 1033 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1034 struct neighbor_report *nei; 1035 1036 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1037 if (nei->freq <= 0) { 1038 wpa_printf(MSG_DEBUG, 1039 "WNM: Unknown neighbor operating frequency for " 1040 MACSTR " - scan all channels", 1041 MAC2STR(nei->bssid)); 1042 os_free(freqs); 1043 return; 1044 } 1045 if (chan_supported(wpa_s, nei->freq)) 1046 add_freq(freqs, &num_freqs, nei->freq); 1047 } 1048 1049 if (num_freqs == 0) { 1050 os_free(freqs); 1051 return; 1052 } 1053 1054 wpa_printf(MSG_DEBUG, 1055 "WNM: Scan %d frequencies based on transition candidate list", 1056 num_freqs); 1057 wpa_s->next_scan_freqs = freqs; 1058 } 1059 1060 1061 static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) 1062 { 1063 struct wpa_scan_results *scan_res; 1064 struct wpa_bss *bss; 1065 struct wpa_ssid *ssid = wpa_s->current_ssid; 1066 u8 i, found = 0; 1067 size_t j; 1068 1069 wpa_dbg(wpa_s, MSG_DEBUG, 1070 "WNM: Fetch current scan results from the driver for checking transition candidates"); 1071 scan_res = wpa_drv_get_scan_results2(wpa_s); 1072 if (!scan_res) { 1073 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); 1074 return 0; 1075 } 1076 1077 if (scan_res->fetch_time.sec == 0) 1078 os_get_reltime(&scan_res->fetch_time); 1079 1080 filter_scan_res(wpa_s, scan_res); 1081 1082 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1083 struct neighbor_report *nei; 1084 1085 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1086 if (nei->preference_present && nei->preference == 0) 1087 continue; 1088 1089 for (j = 0; j < scan_res->num; j++) { 1090 struct wpa_scan_res *res; 1091 const u8 *ssid_ie; 1092 1093 res = scan_res->res[j]; 1094 if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || 1095 res->age > WNM_SCAN_RESULT_AGE * 1000) 1096 continue; 1097 bss = wpa_s->current_bss; 1098 ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); 1099 if (bss && ssid_ie && 1100 (bss->ssid_len != ssid_ie[1] || 1101 os_memcmp(bss->ssid, ssid_ie + 2, 1102 bss->ssid_len) != 0)) 1103 continue; 1104 1105 /* Potential candidate found */ 1106 found = 1; 1107 scan_snr(res); 1108 scan_est_throughput(wpa_s, res); 1109 wpa_bss_update_scan_res(wpa_s, res, 1110 &scan_res->fetch_time); 1111 } 1112 } 1113 1114 wpa_scan_results_free(scan_res); 1115 if (!found) { 1116 wpa_dbg(wpa_s, MSG_DEBUG, 1117 "WNM: No transition candidate matches existing scan results"); 1118 return 0; 1119 } 1120 1121 bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE); 1122 if (!bss) { 1123 wpa_dbg(wpa_s, MSG_DEBUG, 1124 "WNM: Comparison of scan results against transition candidates did not find matches"); 1125 return 0; 1126 } 1127 1128 /* Associate to the network */ 1129 wnm_bss_tm_connect(wpa_s, bss, ssid, 0); 1130 return 1; 1131 } 1132 1133 1134 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1135 const u8 *pos, const u8 *end, 1136 int reply) 1137 { 1138 unsigned int beacon_int; 1139 u8 valid_int; 1140 #ifdef CONFIG_MBO 1141 const u8 *vendor; 1142 #endif /* CONFIG_MBO */ 1143 1144 if (end - pos < 5) 1145 return; 1146 1147 if (wpa_s->current_bss) 1148 beacon_int = wpa_s->current_bss->beacon_int; 1149 else 1150 beacon_int = 100; /* best guess */ 1151 1152 wpa_s->wnm_dialog_token = pos[0]; 1153 wpa_s->wnm_mode = pos[1]; 1154 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1155 valid_int = pos[4]; 1156 wpa_s->wnm_reply = reply; 1157 1158 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1159 "dialog_token=%u request_mode=0x%x " 1160 "disassoc_timer=%u validity_interval=%u", 1161 wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1162 wpa_s->wnm_dissoc_timer, valid_int); 1163 1164 #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) 1165 if (wpa_s->reject_btm_req_reason) { 1166 wpa_printf(MSG_INFO, 1167 "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", 1168 wpa_s->reject_btm_req_reason); 1169 wnm_send_bss_transition_mgmt_resp(wpa_s, 1170 wpa_s->wnm_dialog_token, 1171 wpa_s->reject_btm_req_reason, 1172 0, NULL); 1173 return; 1174 } 1175 #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ 1176 1177 pos += 5; 1178 1179 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1180 if (end - pos < 12) { 1181 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 1182 return; 1183 } 1184 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1185 pos += 12; /* BSS Termination Duration */ 1186 } 1187 1188 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1189 char url[256]; 1190 1191 if (end - pos < 1 || 1 + pos[0] > end - pos) { 1192 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1193 "Management Request (URL)"); 1194 return; 1195 } 1196 os_memcpy(url, pos + 1, pos[0]); 1197 url[pos[0]] = '\0'; 1198 pos += 1 + pos[0]; 1199 1200 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1201 wpa_sm_pmf_enabled(wpa_s->wpa), 1202 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1203 } 1204 1205 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1206 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 1207 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 1208 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1209 /* TODO: mark current BSS less preferred for 1210 * selection */ 1211 wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1212 wpa_supplicant_req_scan(wpa_s, 0, 0); 1213 } 1214 } 1215 1216 #ifdef CONFIG_MBO 1217 vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 1218 if (vendor) 1219 wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 1220 #endif /* CONFIG_MBO */ 1221 1222 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1223 unsigned int valid_ms; 1224 1225 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1226 wnm_deallocate_memory(wpa_s); 1227 wpa_s->wnm_neighbor_report_elements = os_calloc( 1228 WNM_MAX_NEIGHBOR_REPORT, 1229 sizeof(struct neighbor_report)); 1230 if (wpa_s->wnm_neighbor_report_elements == NULL) 1231 return; 1232 1233 while (end - pos >= 2 && 1234 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 1235 { 1236 u8 tag = *pos++; 1237 u8 len = *pos++; 1238 1239 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 1240 tag); 1241 if (len > end - pos) { 1242 wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 1243 return; 1244 } 1245 if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1246 struct neighbor_report *rep; 1247 rep = &wpa_s->wnm_neighbor_report_elements[ 1248 wpa_s->wnm_num_neighbor_report]; 1249 wnm_parse_neighbor_report(wpa_s, pos, len, rep); 1250 wpa_s->wnm_num_neighbor_report++; 1251 } 1252 1253 pos += len; 1254 } 1255 1256 if (!wpa_s->wnm_num_neighbor_report) { 1257 wpa_printf(MSG_DEBUG, 1258 "WNM: Candidate list included bit is set, but no candidates found"); 1259 wnm_send_bss_transition_mgmt_resp( 1260 wpa_s, wpa_s->wnm_dialog_token, 1261 WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 1262 0, NULL); 1263 return; 1264 } 1265 1266 wnm_sort_cand_list(wpa_s); 1267 wnm_dump_cand_list(wpa_s); 1268 valid_ms = valid_int * beacon_int * 128 / 125; 1269 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1270 valid_ms); 1271 os_get_reltime(&wpa_s->wnm_cand_valid_until); 1272 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1273 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1274 wpa_s->wnm_cand_valid_until.sec += 1275 wpa_s->wnm_cand_valid_until.usec / 1000000; 1276 wpa_s->wnm_cand_valid_until.usec %= 1000000; 1277 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1278 1279 /* 1280 * Fetch the latest scan results from the kernel and check for 1281 * candidates based on those results first. This can help in 1282 * finding more up-to-date information should the driver has 1283 * done some internal scanning operations after the last scan 1284 * result update in wpa_supplicant. 1285 */ 1286 if (wnm_fetch_scan_results(wpa_s) > 0) 1287 return; 1288 1289 /* 1290 * Try to use previously received scan results, if they are 1291 * recent enough to use for a connection. 1292 */ 1293 if (wpa_s->last_scan_res_used > 0) { 1294 struct os_reltime now; 1295 1296 os_get_reltime(&now); 1297 if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1298 wpa_printf(MSG_DEBUG, 1299 "WNM: Try to use recent scan results"); 1300 if (wnm_scan_process(wpa_s, 0) > 0) 1301 return; 1302 wpa_printf(MSG_DEBUG, 1303 "WNM: No match in previous scan results - try a new scan"); 1304 } 1305 } 1306 1307 wnm_set_scan_freqs(wpa_s); 1308 if (wpa_s->wnm_num_neighbor_report == 1) { 1309 os_memcpy(wpa_s->next_scan_bssid, 1310 wpa_s->wnm_neighbor_report_elements[0].bssid, 1311 ETH_ALEN); 1312 wpa_printf(MSG_DEBUG, 1313 "WNM: Scan only for a specific BSSID since there is only a single candidate " 1314 MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 1315 } 1316 wpa_supplicant_req_scan(wpa_s, 0, 0); 1317 } else if (reply) { 1318 enum bss_trans_mgmt_status_code status; 1319 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1320 status = WNM_BSS_TM_ACCEPT; 1321 else { 1322 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1323 status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1324 } 1325 wnm_send_bss_transition_mgmt_resp(wpa_s, 1326 wpa_s->wnm_dialog_token, 1327 status, 0, NULL); 1328 } 1329 } 1330 1331 1332 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 1333 u8 query_reason, int cand_list) 1334 { 1335 u8 buf[2000], *pos; 1336 struct ieee80211_mgmt *mgmt; 1337 size_t len; 1338 int ret; 1339 1340 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 1341 MACSTR " query_reason=%u%s", 1342 MAC2STR(wpa_s->bssid), query_reason, 1343 cand_list ? " candidate list" : ""); 1344 1345 mgmt = (struct ieee80211_mgmt *) buf; 1346 os_memset(&buf, 0, sizeof(buf)); 1347 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 1348 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 1349 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 1350 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1351 WLAN_FC_STYPE_ACTION); 1352 mgmt->u.action.category = WLAN_ACTION_WNM; 1353 mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 1354 mgmt->u.action.u.bss_tm_query.dialog_token = 1; 1355 mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 1356 pos = mgmt->u.action.u.bss_tm_query.variable; 1357 1358 if (cand_list) 1359 pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 1360 1361 len = pos - (u8 *) &mgmt->u.action.category; 1362 1363 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1364 wpa_s->own_addr, wpa_s->bssid, 1365 &mgmt->u.action.category, len, 0); 1366 1367 return ret; 1368 } 1369 1370 1371 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1372 const u8 *sa, const u8 *data, 1373 int len) 1374 { 1375 const u8 *pos, *end, *next; 1376 u8 ie, ie_len; 1377 1378 pos = data; 1379 end = data + len; 1380 1381 while (end - pos > 1) { 1382 ie = *pos++; 1383 ie_len = *pos++; 1384 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1385 ie, ie_len); 1386 if (ie_len > end - pos) { 1387 wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1388 "subelement"); 1389 break; 1390 } 1391 next = pos + ie_len; 1392 if (ie_len < 4) { 1393 pos = next; 1394 continue; 1395 } 1396 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1397 WPA_GET_BE24(pos), pos[3]); 1398 1399 #ifdef CONFIG_HS20 1400 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1401 WPA_GET_BE24(pos) == OUI_WFA && 1402 pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1403 /* Subscription Remediation subelement */ 1404 const u8 *ie_end; 1405 u8 url_len; 1406 char *url; 1407 u8 osu_method; 1408 1409 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1410 "subelement"); 1411 ie_end = pos + ie_len; 1412 pos += 4; 1413 url_len = *pos++; 1414 if (url_len == 0) { 1415 wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1416 url = NULL; 1417 osu_method = 1; 1418 } else { 1419 if (url_len + 1 > ie_end - pos) { 1420 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1421 url_len, 1422 (int) (ie_end - pos)); 1423 break; 1424 } 1425 url = os_malloc(url_len + 1); 1426 if (url == NULL) 1427 break; 1428 os_memcpy(url, pos, url_len); 1429 url[url_len] = '\0'; 1430 osu_method = pos[url_len]; 1431 } 1432 hs20_rx_subscription_remediation(wpa_s, url, 1433 osu_method); 1434 os_free(url); 1435 pos = next; 1436 continue; 1437 } 1438 1439 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1440 WPA_GET_BE24(pos) == OUI_WFA && 1441 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1442 const u8 *ie_end; 1443 u8 url_len; 1444 char *url; 1445 u8 code; 1446 u16 reauth_delay; 1447 1448 ie_end = pos + ie_len; 1449 pos += 4; 1450 code = *pos++; 1451 reauth_delay = WPA_GET_LE16(pos); 1452 pos += 2; 1453 url_len = *pos++; 1454 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1455 "Imminent - Reason Code %u " 1456 "Re-Auth Delay %u URL Length %u", 1457 code, reauth_delay, url_len); 1458 if (url_len > ie_end - pos) 1459 break; 1460 url = os_malloc(url_len + 1); 1461 if (url == NULL) 1462 break; 1463 os_memcpy(url, pos, url_len); 1464 url[url_len] = '\0'; 1465 hs20_rx_deauth_imminent_notice(wpa_s, code, 1466 reauth_delay, url); 1467 os_free(url); 1468 pos = next; 1469 continue; 1470 } 1471 #endif /* CONFIG_HS20 */ 1472 1473 pos = next; 1474 } 1475 } 1476 1477 1478 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1479 const u8 *sa, const u8 *frm, int len) 1480 { 1481 const u8 *pos, *end; 1482 u8 dialog_token, type; 1483 1484 /* Dialog Token [1] | Type [1] | Subelements */ 1485 1486 if (len < 2 || sa == NULL) 1487 return; 1488 end = frm + len; 1489 pos = frm; 1490 dialog_token = *pos++; 1491 type = *pos++; 1492 1493 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1494 "(dialog_token %u type %u sa " MACSTR ")", 1495 dialog_token, type, MAC2STR(sa)); 1496 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1497 pos, end - pos); 1498 1499 if (wpa_s->wpa_state != WPA_COMPLETED || 1500 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1501 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1502 "from our AP - ignore it"); 1503 return; 1504 } 1505 1506 switch (type) { 1507 case 1: 1508 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1509 break; 1510 default: 1511 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1512 "WNM-Notification type %u", type); 1513 break; 1514 } 1515 } 1516 1517 1518 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1519 const struct ieee80211_mgmt *mgmt, size_t len) 1520 { 1521 const u8 *pos, *end; 1522 u8 act; 1523 1524 if (len < IEEE80211_HDRLEN + 2) 1525 return; 1526 1527 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1528 act = *pos++; 1529 end = ((const u8 *) mgmt) + len; 1530 1531 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1532 act, MAC2STR(mgmt->sa)); 1533 if (wpa_s->wpa_state < WPA_ASSOCIATED || 1534 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1535 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1536 "frame"); 1537 return; 1538 } 1539 1540 switch (act) { 1541 case WNM_BSS_TRANS_MGMT_REQ: 1542 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1543 !(mgmt->da[0] & 0x01)); 1544 break; 1545 case WNM_SLEEP_MODE_RESP: 1546 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 1547 break; 1548 case WNM_NOTIFICATION_REQ: 1549 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1550 break; 1551 default: 1552 wpa_printf(MSG_ERROR, "WNM: Unknown request"); 1553 break; 1554 } 1555 } 1556