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