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 "config.h" 17 #include "wpa_supplicant_i.h" 18 #include "driver_i.h" 19 #include "scan.h" 20 #include "ctrl_iface.h" 21 #include "bss.h" 22 #include "wnm_sta.h" 23 #include "hs20_supplicant.h" 24 25 #define MAX_TFS_IE_LEN 1024 26 #define WNM_MAX_NEIGHBOR_REPORT 10 27 28 #define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ 29 30 /* get the TFS IE from driver */ 31 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 32 u16 *buf_len, enum wnm_oper oper) 33 { 34 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 35 36 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 37 } 38 39 40 /* set the TFS IE to driver */ 41 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 42 const u8 *addr, const u8 *buf, u16 buf_len, 43 enum wnm_oper oper) 44 { 45 u16 len = buf_len; 46 47 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 48 49 return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 50 } 51 52 53 /* MLME-SLEEPMODE.request */ 54 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 55 u8 action, u16 intval, struct wpabuf *tfs_req) 56 { 57 struct ieee80211_mgmt *mgmt; 58 int res; 59 size_t len; 60 struct wnm_sleep_element *wnmsleep_ie; 61 u8 *wnmtfs_ie; 62 u8 wnmsleep_ie_len; 63 u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 64 enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 65 WNM_SLEEP_TFS_REQ_IE_NONE; 66 67 wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 68 "action=%s to " MACSTR, 69 action == 0 ? "enter" : "exit", 70 MAC2STR(wpa_s->bssid)); 71 72 /* WNM-Sleep Mode IE */ 73 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 74 wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 75 if (wnmsleep_ie == NULL) 76 return -1; 77 wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 78 wnmsleep_ie->len = wnmsleep_ie_len - 2; 79 wnmsleep_ie->action_type = action; 80 wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 81 wnmsleep_ie->intval = host_to_le16(intval); 82 wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 83 (u8 *) wnmsleep_ie, wnmsleep_ie_len); 84 85 /* TFS IE(s) */ 86 if (tfs_req) { 87 wnmtfs_ie_len = wpabuf_len(tfs_req); 88 wnmtfs_ie = os_memdup(wpabuf_head(tfs_req), wnmtfs_ie_len); 89 if (wnmtfs_ie == NULL) { 90 os_free(wnmsleep_ie); 91 return -1; 92 } 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 void wnm_clear_acceptable(struct wpa_supplicant *wpa_s) 505 { 506 unsigned int i; 507 508 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) 509 wpa_s->wnm_neighbor_report_elements[i].acceptable = 0; 510 } 511 512 513 static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) 514 { 515 unsigned int i; 516 struct neighbor_report *nei; 517 518 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 519 nei = &wpa_s->wnm_neighbor_report_elements[i]; 520 if (nei->acceptable) 521 return wpa_bss_get_bssid(wpa_s, nei->bssid); 522 } 523 524 return NULL; 525 } 526 527 528 #ifdef CONFIG_MBO 529 static struct wpa_bss * 530 get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, 531 enum mbo_transition_reject_reason *reason) 532 { 533 struct wpa_bss *target = NULL; 534 struct wpa_bss_trans_info params; 535 struct wpa_bss_candidate_info *info = NULL; 536 struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements; 537 u8 *first_candidate_bssid = NULL, *pos; 538 unsigned int i; 539 540 params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason; 541 params.n_candidates = 0; 542 params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN); 543 if (!params.bssid) 544 return NULL; 545 546 pos = params.bssid; 547 for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) { 548 if (nei->is_first) 549 first_candidate_bssid = nei->bssid; 550 if (!nei->acceptable) 551 continue; 552 os_memcpy(pos, nei->bssid, ETH_ALEN); 553 pos += ETH_ALEN; 554 params.n_candidates++; 555 } 556 557 if (!params.n_candidates) 558 goto end; 559 560 info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms); 561 if (!info) { 562 /* If failed to get candidate BSS transition status from driver, 563 * get the first acceptable candidate from wpa_supplicant. 564 */ 565 target = wpa_bss_get_bssid(wpa_s, params.bssid); 566 goto end; 567 } 568 569 /* Get the first acceptable candidate from driver */ 570 for (i = 0; i < info->num; i++) { 571 if (info->candidates[i].is_accept) { 572 target = wpa_bss_get_bssid(wpa_s, 573 info->candidates[i].bssid); 574 goto end; 575 } 576 } 577 578 /* If Disassociation Imminent is set and driver rejects all the 579 * candidate select first acceptable candidate which has 580 * rssi > disassoc_imminent_rssi_threshold 581 */ 582 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 583 for (i = 0; i < info->num; i++) { 584 target = wpa_bss_get_bssid(wpa_s, 585 info->candidates[i].bssid); 586 if (target && 587 (target->level < 588 wpa_s->conf->disassoc_imminent_rssi_threshold)) 589 continue; 590 goto end; 591 } 592 } 593 594 /* While sending BTM reject use reason code of the first candidate 595 * received in BTM request frame 596 */ 597 if (reason) { 598 for (i = 0; i < info->num; i++) { 599 if (first_candidate_bssid && 600 os_memcmp(first_candidate_bssid, 601 info->candidates[i].bssid, ETH_ALEN) == 0) 602 { 603 *reason = info->candidates[i].reject_reason; 604 break; 605 } 606 } 607 } 608 609 target = NULL; 610 611 end: 612 os_free(params.bssid); 613 if (info) { 614 os_free(info->candidates); 615 os_free(info); 616 } 617 return target; 618 } 619 #endif /* CONFIG_MBO */ 620 621 622 static struct wpa_bss * 623 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, 624 enum mbo_transition_reject_reason *reason) 625 { 626 u8 i; 627 struct wpa_bss *bss = wpa_s->current_bss; 628 struct wpa_bss *target; 629 630 if (!bss) 631 return NULL; 632 633 wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 634 MAC2STR(wpa_s->bssid), bss->level); 635 636 wnm_clear_acceptable(wpa_s); 637 638 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 639 struct neighbor_report *nei; 640 641 nei = &wpa_s->wnm_neighbor_report_elements[i]; 642 if (nei->preference_present && nei->preference == 0) { 643 wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 644 MAC2STR(nei->bssid)); 645 continue; 646 } 647 648 target = wpa_bss_get_bssid(wpa_s, nei->bssid); 649 if (!target) { 650 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 651 " (pref %d) not found in scan results", 652 MAC2STR(nei->bssid), 653 nei->preference_present ? nei->preference : 654 -1); 655 continue; 656 } 657 658 if (age_secs) { 659 struct os_reltime now; 660 661 if (os_get_reltime(&now) == 0 && 662 os_reltime_expired(&now, &target->last_update, 663 age_secs)) { 664 wpa_printf(MSG_DEBUG, 665 "Candidate BSS is more than %ld seconds old", 666 age_secs); 667 continue; 668 } 669 } 670 671 if (bss->ssid_len != target->ssid_len || 672 os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 673 /* 674 * TODO: Could consider allowing transition to another 675 * ESS if PMF was enabled for the association. 676 */ 677 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 678 " (pref %d) in different ESS", 679 MAC2STR(nei->bssid), 680 nei->preference_present ? nei->preference : 681 -1); 682 continue; 683 } 684 685 if (wpa_s->current_ssid && 686 !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 687 1, 0)) { 688 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 689 " (pref %d) does not match the current network profile", 690 MAC2STR(nei->bssid), 691 nei->preference_present ? nei->preference : 692 -1); 693 continue; 694 } 695 696 if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { 697 wpa_printf(MSG_DEBUG, 698 "MBO: Candidate BSS " MACSTR 699 " retry delay is not over yet", 700 MAC2STR(nei->bssid)); 701 continue; 702 } 703 704 if (target->level < bss->level && target->level < -80) { 705 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 706 " (pref %d) does not have sufficient signal level (%d)", 707 MAC2STR(nei->bssid), 708 nei->preference_present ? nei->preference : 709 -1, 710 target->level); 711 continue; 712 } 713 714 nei->acceptable = 1; 715 } 716 717 #ifdef CONFIG_MBO 718 if (wpa_s->wnm_mbo_trans_reason_present) 719 target = get_mbo_transition_candidate(wpa_s, reason); 720 else 721 target = get_first_acceptable(wpa_s); 722 #else /* CONFIG_MBO */ 723 target = get_first_acceptable(wpa_s); 724 #endif /* CONFIG_MBO */ 725 726 if (target) { 727 wpa_printf(MSG_DEBUG, 728 "WNM: Found an acceptable preferred transition candidate BSS " 729 MACSTR " (RSSI %d)", 730 MAC2STR(target->bssid), target->level); 731 } 732 733 return target; 734 } 735 736 737 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) 738 { 739 const u8 *ie_a, *ie_b; 740 741 if (!a || !b) 742 return 0; 743 744 ie_a = wpa_bss_get_ie(a, eid); 745 ie_b = wpa_bss_get_ie(b, eid); 746 747 if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) 748 return 0; 749 750 return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; 751 } 752 753 754 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 755 { 756 u32 info = 0; 757 758 info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; 759 760 /* 761 * Leave the security and key scope bits unset to indicate that the 762 * security information is not available. 763 */ 764 765 if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) 766 info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 767 if (bss->caps & WLAN_CAPABILITY_QOS) 768 info |= NEI_REP_BSSID_INFO_QOS; 769 if (bss->caps & WLAN_CAPABILITY_APSD) 770 info |= NEI_REP_BSSID_INFO_APSD; 771 if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) 772 info |= NEI_REP_BSSID_INFO_RM; 773 if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) 774 info |= NEI_REP_BSSID_INFO_DELAYED_BA; 775 if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) 776 info |= NEI_REP_BSSID_INFO_IMM_BA; 777 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) 778 info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; 779 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) 780 info |= NEI_REP_BSSID_INFO_HT; 781 782 return info; 783 } 784 785 786 static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid, 787 u32 bss_info, u8 op_class, u8 chan, u8 phy_type, 788 u8 pref) 789 { 790 if (wpabuf_len(*buf) + 18 > 791 IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) { 792 wpa_printf(MSG_DEBUG, 793 "WNM: No room in frame for Neighbor Report element"); 794 return -1; 795 } 796 797 if (wpabuf_resize(buf, 18) < 0) { 798 wpa_printf(MSG_DEBUG, 799 "WNM: Failed to allocate memory for Neighbor Report element"); 800 return -1; 801 } 802 803 wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT); 804 /* length: 13 for basic neighbor report + 3 for preference subelement */ 805 wpabuf_put_u8(*buf, 16); 806 wpabuf_put_data(*buf, bssid, ETH_ALEN); 807 wpabuf_put_le32(*buf, bss_info); 808 wpabuf_put_u8(*buf, op_class); 809 wpabuf_put_u8(*buf, chan); 810 wpabuf_put_u8(*buf, phy_type); 811 wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE); 812 wpabuf_put_u8(*buf, 1); 813 wpabuf_put_u8(*buf, pref); 814 return 0; 815 } 816 817 818 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, 819 struct wpa_bss *bss, struct wpabuf **buf, 820 u8 pref) 821 { 822 const u8 *ie; 823 u8 op_class, chan; 824 int sec_chan = 0, vht = 0; 825 enum phy_type phy_type; 826 u32 info; 827 struct ieee80211_ht_operation *ht_oper = NULL; 828 struct ieee80211_vht_operation *vht_oper = NULL; 829 830 ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); 831 if (ie && ie[1] >= 2) { 832 ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 833 834 if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 835 sec_chan = 1; 836 else if (ht_oper->ht_param & 837 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 838 sec_chan = -1; 839 } 840 841 ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); 842 if (ie && ie[1] >= 1) { 843 vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 844 845 if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || 846 vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || 847 vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) 848 vht = vht_oper->vht_op_info_chwidth; 849 } 850 851 if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, 852 &chan) == NUM_HOSTAPD_MODES) { 853 wpa_printf(MSG_DEBUG, 854 "WNM: Cannot determine operating class and channel"); 855 return -2; 856 } 857 858 phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), 859 (vht_oper != NULL)); 860 if (phy_type == PHY_TYPE_UNSPECIFIED) { 861 wpa_printf(MSG_DEBUG, 862 "WNM: Cannot determine BSS phy type for Neighbor Report"); 863 return -2; 864 } 865 866 info = wnm_get_bss_info(wpa_s, bss); 867 868 return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type, 869 pref); 870 } 871 872 873 static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf) 874 { 875 unsigned int i, pref = 255; 876 struct os_reltime now; 877 struct wpa_ssid *ssid = wpa_s->current_ssid; 878 879 if (!ssid) 880 return; 881 882 /* 883 * TODO: Define when scan results are no longer valid for the candidate 884 * list. 885 */ 886 os_get_reltime(&now); 887 if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) 888 return; 889 890 wpa_printf(MSG_DEBUG, 891 "WNM: Add candidate list to BSS Transition Management Response frame"); 892 for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { 893 struct wpa_bss *bss = wpa_s->last_scan_res[i]; 894 int res; 895 896 if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { 897 res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--); 898 if (res == -2) 899 continue; /* could not build entry for BSS */ 900 if (res < 0) 901 break; /* no more room for candidates */ 902 if (pref == 1) 903 break; 904 } 905 } 906 907 wpa_hexdump_buf(MSG_DEBUG, 908 "WNM: BSS Transition Management Response candidate list", 909 *buf); 910 } 911 912 913 #define BTM_RESP_MIN_SIZE 5 + ETH_ALEN 914 915 static void wnm_send_bss_transition_mgmt_resp( 916 struct wpa_supplicant *wpa_s, u8 dialog_token, 917 enum bss_trans_mgmt_status_code status, 918 enum mbo_transition_reject_reason reason, 919 u8 delay, const u8 *target_bssid) 920 { 921 struct wpabuf *buf; 922 int res; 923 924 wpa_printf(MSG_DEBUG, 925 "WNM: Send BSS Transition Management Response to " MACSTR 926 " dialog_token=%u status=%u reason=%u delay=%d", 927 MAC2STR(wpa_s->bssid), dialog_token, status, reason, delay); 928 if (!wpa_s->current_bss) { 929 wpa_printf(MSG_DEBUG, 930 "WNM: Current BSS not known - drop response"); 931 return; 932 } 933 934 buf = wpabuf_alloc(BTM_RESP_MIN_SIZE); 935 if (!buf) { 936 wpa_printf(MSG_DEBUG, 937 "WNM: Failed to allocate memory for BTM response"); 938 return; 939 } 940 941 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 942 wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP); 943 wpabuf_put_u8(buf, dialog_token); 944 wpabuf_put_u8(buf, status); 945 wpabuf_put_u8(buf, delay); 946 if (target_bssid) { 947 wpabuf_put_data(buf, target_bssid, ETH_ALEN); 948 } else if (status == WNM_BSS_TM_ACCEPT) { 949 /* 950 * P802.11-REVmc clarifies that the Target BSSID field is always 951 * present when status code is zero, so use a fake value here if 952 * no BSSID is yet known. 953 */ 954 wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN); 955 } 956 957 if (status == WNM_BSS_TM_ACCEPT) 958 wnm_add_cand_list(wpa_s, &buf); 959 960 #ifdef CONFIG_MBO 961 if (status != WNM_BSS_TM_ACCEPT && 962 wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) { 963 u8 mbo[10]; 964 size_t ret; 965 966 ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo), 967 reason); 968 if (ret) { 969 if (wpabuf_resize(&buf, ret) < 0) { 970 wpabuf_free(buf); 971 wpa_printf(MSG_DEBUG, 972 "WNM: Failed to allocate memory for MBO IE"); 973 return; 974 } 975 976 wpabuf_put_data(buf, mbo, ret); 977 } 978 } 979 #endif /* CONFIG_MBO */ 980 981 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 982 wpa_s->own_addr, wpa_s->bssid, 983 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 984 if (res < 0) { 985 wpa_printf(MSG_DEBUG, 986 "WNM: Failed to send BSS Transition Management Response"); 987 } 988 989 wpabuf_free(buf); 990 } 991 992 993 static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, 994 struct wpa_bss *bss, struct wpa_ssid *ssid, 995 int after_new_scan) 996 { 997 wpa_dbg(wpa_s, MSG_DEBUG, 998 "WNM: Transition to BSS " MACSTR 999 " based on BSS Transition Management Request (old BSSID " 1000 MACSTR " after_new_scan=%d)", 1001 MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); 1002 1003 /* Send the BSS Management Response - Accept */ 1004 if (wpa_s->wnm_reply) { 1005 wpa_s->wnm_reply = 0; 1006 wpa_printf(MSG_DEBUG, 1007 "WNM: Sending successful BSS Transition Management Response"); 1008 wnm_send_bss_transition_mgmt_resp( 1009 wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, 1010 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1011 bss->bssid); 1012 } 1013 1014 if (bss == wpa_s->current_bss) { 1015 wpa_printf(MSG_DEBUG, 1016 "WNM: Already associated with the preferred candidate"); 1017 wnm_deallocate_memory(wpa_s); 1018 return; 1019 } 1020 1021 wpa_s->reassociate = 1; 1022 wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); 1023 wpa_supplicant_connect(wpa_s, bss, ssid); 1024 wnm_deallocate_memory(wpa_s); 1025 } 1026 1027 1028 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 1029 { 1030 struct wpa_bss *bss; 1031 struct wpa_ssid *ssid = wpa_s->current_ssid; 1032 enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1033 enum mbo_transition_reject_reason reason = 1034 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; 1035 1036 if (!wpa_s->wnm_neighbor_report_elements) 1037 return 0; 1038 1039 wpa_dbg(wpa_s, MSG_DEBUG, 1040 "WNM: Process scan results for BSS Transition Management"); 1041 if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 1042 &wpa_s->scan_trigger_time)) { 1043 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 1044 wnm_deallocate_memory(wpa_s); 1045 return 0; 1046 } 1047 1048 if (!wpa_s->current_bss || 1049 os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 1050 ETH_ALEN) != 0) { 1051 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 1052 return 0; 1053 } 1054 1055 /* Compare the Neighbor Report and scan results */ 1056 bss = compare_scan_neighbor_results(wpa_s, 0, &reason); 1057 if (!bss) { 1058 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 1059 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 1060 goto send_bss_resp_fail; 1061 } 1062 1063 /* Associate to the network */ 1064 wnm_bss_tm_connect(wpa_s, bss, ssid, 1); 1065 return 1; 1066 1067 send_bss_resp_fail: 1068 if (!reply_on_fail) 1069 return 0; 1070 1071 /* Send reject response for all the failures */ 1072 1073 if (wpa_s->wnm_reply) { 1074 wpa_s->wnm_reply = 0; 1075 wnm_send_bss_transition_mgmt_resp(wpa_s, 1076 wpa_s->wnm_dialog_token, 1077 status, reason, 0, NULL); 1078 } 1079 wnm_deallocate_memory(wpa_s); 1080 1081 return 0; 1082 } 1083 1084 1085 static int cand_pref_compar(const void *a, const void *b) 1086 { 1087 const struct neighbor_report *aa = a; 1088 const struct neighbor_report *bb = b; 1089 1090 if (!aa->preference_present && !bb->preference_present) 1091 return 0; 1092 if (!aa->preference_present) 1093 return 1; 1094 if (!bb->preference_present) 1095 return -1; 1096 if (bb->preference > aa->preference) 1097 return 1; 1098 if (bb->preference < aa->preference) 1099 return -1; 1100 return 0; 1101 } 1102 1103 1104 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 1105 { 1106 if (!wpa_s->wnm_neighbor_report_elements) 1107 return; 1108 qsort(wpa_s->wnm_neighbor_report_elements, 1109 wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 1110 cand_pref_compar); 1111 } 1112 1113 1114 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 1115 { 1116 unsigned int i; 1117 1118 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 1119 if (!wpa_s->wnm_neighbor_report_elements) 1120 return; 1121 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1122 struct neighbor_report *nei; 1123 1124 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1125 wpa_printf(MSG_DEBUG, "%u: " MACSTR 1126 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 1127 i, MAC2STR(nei->bssid), nei->bssid_info, 1128 nei->regulatory_class, 1129 nei->channel_number, nei->phy_type, 1130 nei->preference_present ? nei->preference : -1, 1131 nei->freq); 1132 } 1133 } 1134 1135 1136 static int chan_supported(struct wpa_supplicant *wpa_s, int freq) 1137 { 1138 unsigned int i; 1139 1140 for (i = 0; i < wpa_s->hw.num_modes; i++) { 1141 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 1142 int j; 1143 1144 for (j = 0; j < mode->num_channels; j++) { 1145 struct hostapd_channel_data *chan; 1146 1147 chan = &mode->channels[j]; 1148 if (chan->freq == freq && 1149 !(chan->flag & HOSTAPD_CHAN_DISABLED)) 1150 return 1; 1151 } 1152 } 1153 1154 return 0; 1155 } 1156 1157 1158 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 1159 { 1160 int *freqs; 1161 int num_freqs = 0; 1162 unsigned int i; 1163 1164 if (!wpa_s->wnm_neighbor_report_elements) 1165 return; 1166 1167 if (wpa_s->hw.modes == NULL) 1168 return; 1169 1170 os_free(wpa_s->next_scan_freqs); 1171 wpa_s->next_scan_freqs = NULL; 1172 1173 freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 1174 if (freqs == NULL) 1175 return; 1176 1177 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1178 struct neighbor_report *nei; 1179 1180 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1181 if (nei->freq <= 0) { 1182 wpa_printf(MSG_DEBUG, 1183 "WNM: Unknown neighbor operating frequency for " 1184 MACSTR " - scan all channels", 1185 MAC2STR(nei->bssid)); 1186 os_free(freqs); 1187 return; 1188 } 1189 if (chan_supported(wpa_s, nei->freq)) 1190 add_freq(freqs, &num_freqs, nei->freq); 1191 } 1192 1193 if (num_freqs == 0) { 1194 os_free(freqs); 1195 return; 1196 } 1197 1198 wpa_printf(MSG_DEBUG, 1199 "WNM: Scan %d frequencies based on transition candidate list", 1200 num_freqs); 1201 wpa_s->next_scan_freqs = freqs; 1202 } 1203 1204 1205 static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) 1206 { 1207 struct wpa_scan_results *scan_res; 1208 struct wpa_bss *bss; 1209 struct wpa_ssid *ssid = wpa_s->current_ssid; 1210 u8 i, found = 0; 1211 size_t j; 1212 1213 wpa_dbg(wpa_s, MSG_DEBUG, 1214 "WNM: Fetch current scan results from the driver for checking transition candidates"); 1215 scan_res = wpa_drv_get_scan_results2(wpa_s); 1216 if (!scan_res) { 1217 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); 1218 return 0; 1219 } 1220 1221 if (scan_res->fetch_time.sec == 0) 1222 os_get_reltime(&scan_res->fetch_time); 1223 1224 filter_scan_res(wpa_s, scan_res); 1225 1226 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1227 struct neighbor_report *nei; 1228 1229 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1230 if (nei->preference_present && nei->preference == 0) 1231 continue; 1232 1233 for (j = 0; j < scan_res->num; j++) { 1234 struct wpa_scan_res *res; 1235 const u8 *ssid_ie; 1236 1237 res = scan_res->res[j]; 1238 if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || 1239 res->age > WNM_SCAN_RESULT_AGE * 1000) 1240 continue; 1241 bss = wpa_s->current_bss; 1242 ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); 1243 if (bss && ssid_ie && 1244 (bss->ssid_len != ssid_ie[1] || 1245 os_memcmp(bss->ssid, ssid_ie + 2, 1246 bss->ssid_len) != 0)) 1247 continue; 1248 1249 /* Potential candidate found */ 1250 found = 1; 1251 scan_snr(res); 1252 scan_est_throughput(wpa_s, res); 1253 wpa_bss_update_scan_res(wpa_s, res, 1254 &scan_res->fetch_time); 1255 } 1256 } 1257 1258 wpa_scan_results_free(scan_res); 1259 if (!found) { 1260 wpa_dbg(wpa_s, MSG_DEBUG, 1261 "WNM: No transition candidate matches existing scan results"); 1262 return 0; 1263 } 1264 1265 bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); 1266 if (!bss) { 1267 wpa_dbg(wpa_s, MSG_DEBUG, 1268 "WNM: Comparison of scan results against transition candidates did not find matches"); 1269 return 0; 1270 } 1271 1272 /* Associate to the network */ 1273 wnm_bss_tm_connect(wpa_s, bss, ssid, 0); 1274 return 1; 1275 } 1276 1277 1278 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1279 const u8 *pos, const u8 *end, 1280 int reply) 1281 { 1282 unsigned int beacon_int; 1283 u8 valid_int; 1284 #ifdef CONFIG_MBO 1285 const u8 *vendor; 1286 #endif /* CONFIG_MBO */ 1287 1288 if (end - pos < 5) 1289 return; 1290 1291 #ifdef CONFIG_MBO 1292 wpa_s->wnm_mbo_trans_reason_present = 0; 1293 wpa_s->wnm_mbo_transition_reason = 0; 1294 #endif /* CONFIG_MBO */ 1295 1296 if (wpa_s->current_bss) 1297 beacon_int = wpa_s->current_bss->beacon_int; 1298 else 1299 beacon_int = 100; /* best guess */ 1300 1301 wpa_s->wnm_dialog_token = pos[0]; 1302 wpa_s->wnm_mode = pos[1]; 1303 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1304 valid_int = pos[4]; 1305 wpa_s->wnm_reply = reply; 1306 1307 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1308 "dialog_token=%u request_mode=0x%x " 1309 "disassoc_timer=%u validity_interval=%u", 1310 wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1311 wpa_s->wnm_dissoc_timer, valid_int); 1312 1313 #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) 1314 if (wpa_s->reject_btm_req_reason) { 1315 wpa_printf(MSG_INFO, 1316 "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", 1317 wpa_s->reject_btm_req_reason); 1318 wnm_send_bss_transition_mgmt_resp( 1319 wpa_s, wpa_s->wnm_dialog_token, 1320 wpa_s->reject_btm_req_reason, 1321 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1322 return; 1323 } 1324 #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ 1325 1326 pos += 5; 1327 1328 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1329 if (end - pos < 12) { 1330 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 1331 return; 1332 } 1333 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1334 pos += 12; /* BSS Termination Duration */ 1335 } 1336 1337 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1338 char url[256]; 1339 1340 if (end - pos < 1 || 1 + pos[0] > end - pos) { 1341 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1342 "Management Request (URL)"); 1343 return; 1344 } 1345 os_memcpy(url, pos + 1, pos[0]); 1346 url[pos[0]] = '\0'; 1347 pos += 1 + pos[0]; 1348 1349 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1350 wpa_sm_pmf_enabled(wpa_s->wpa), 1351 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1352 } 1353 1354 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1355 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 1356 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 1357 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1358 /* TODO: mark current BSS less preferred for 1359 * selection */ 1360 wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1361 wpa_supplicant_req_scan(wpa_s, 0, 0); 1362 } 1363 } 1364 1365 #ifdef CONFIG_MBO 1366 vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 1367 if (vendor) 1368 wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 1369 #endif /* CONFIG_MBO */ 1370 1371 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1372 unsigned int valid_ms; 1373 1374 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1375 wnm_deallocate_memory(wpa_s); 1376 wpa_s->wnm_neighbor_report_elements = os_calloc( 1377 WNM_MAX_NEIGHBOR_REPORT, 1378 sizeof(struct neighbor_report)); 1379 if (wpa_s->wnm_neighbor_report_elements == NULL) 1380 return; 1381 1382 while (end - pos >= 2 && 1383 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 1384 { 1385 u8 tag = *pos++; 1386 u8 len = *pos++; 1387 1388 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 1389 tag); 1390 if (len > end - pos) { 1391 wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 1392 return; 1393 } 1394 if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1395 struct neighbor_report *rep; 1396 rep = &wpa_s->wnm_neighbor_report_elements[ 1397 wpa_s->wnm_num_neighbor_report]; 1398 wnm_parse_neighbor_report(wpa_s, pos, len, rep); 1399 wpa_s->wnm_num_neighbor_report++; 1400 #ifdef CONFIG_MBO 1401 if (wpa_s->wnm_mbo_trans_reason_present && 1402 wpa_s->wnm_num_neighbor_report == 1) { 1403 rep->is_first = 1; 1404 wpa_printf(MSG_DEBUG, 1405 "WNM: First transition candidate is " 1406 MACSTR, MAC2STR(rep->bssid)); 1407 } 1408 #endif /* CONFIG_MBO */ 1409 } 1410 1411 pos += len; 1412 } 1413 1414 if (!wpa_s->wnm_num_neighbor_report) { 1415 wpa_printf(MSG_DEBUG, 1416 "WNM: Candidate list included bit is set, but no candidates found"); 1417 wnm_send_bss_transition_mgmt_resp( 1418 wpa_s, wpa_s->wnm_dialog_token, 1419 WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 1420 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1421 NULL); 1422 return; 1423 } 1424 1425 wnm_sort_cand_list(wpa_s); 1426 wnm_dump_cand_list(wpa_s); 1427 valid_ms = valid_int * beacon_int * 128 / 125; 1428 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1429 valid_ms); 1430 os_get_reltime(&wpa_s->wnm_cand_valid_until); 1431 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1432 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1433 wpa_s->wnm_cand_valid_until.sec += 1434 wpa_s->wnm_cand_valid_until.usec / 1000000; 1435 wpa_s->wnm_cand_valid_until.usec %= 1000000; 1436 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1437 1438 /* 1439 * Fetch the latest scan results from the kernel and check for 1440 * candidates based on those results first. This can help in 1441 * finding more up-to-date information should the driver has 1442 * done some internal scanning operations after the last scan 1443 * result update in wpa_supplicant. 1444 */ 1445 if (wnm_fetch_scan_results(wpa_s) > 0) 1446 return; 1447 1448 /* 1449 * Try to use previously received scan results, if they are 1450 * recent enough to use for a connection. 1451 */ 1452 if (wpa_s->last_scan_res_used > 0) { 1453 struct os_reltime now; 1454 1455 os_get_reltime(&now); 1456 if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1457 wpa_printf(MSG_DEBUG, 1458 "WNM: Try to use recent scan results"); 1459 if (wnm_scan_process(wpa_s, 0) > 0) 1460 return; 1461 wpa_printf(MSG_DEBUG, 1462 "WNM: No match in previous scan results - try a new scan"); 1463 } 1464 } 1465 1466 wnm_set_scan_freqs(wpa_s); 1467 if (wpa_s->wnm_num_neighbor_report == 1) { 1468 os_memcpy(wpa_s->next_scan_bssid, 1469 wpa_s->wnm_neighbor_report_elements[0].bssid, 1470 ETH_ALEN); 1471 wpa_printf(MSG_DEBUG, 1472 "WNM: Scan only for a specific BSSID since there is only a single candidate " 1473 MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 1474 } 1475 wpa_supplicant_req_scan(wpa_s, 0, 0); 1476 } else if (reply) { 1477 enum bss_trans_mgmt_status_code status; 1478 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1479 status = WNM_BSS_TM_ACCEPT; 1480 else { 1481 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1482 status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1483 } 1484 wnm_send_bss_transition_mgmt_resp( 1485 wpa_s, wpa_s->wnm_dialog_token, status, 1486 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1487 } 1488 } 1489 1490 1491 #define BTM_QUERY_MIN_SIZE 4 1492 1493 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 1494 u8 query_reason, 1495 const char *btm_candidates, 1496 int cand_list) 1497 { 1498 struct wpabuf *buf; 1499 int ret; 1500 1501 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 1502 MACSTR " query_reason=%u%s", 1503 MAC2STR(wpa_s->bssid), query_reason, 1504 cand_list ? " candidate list" : ""); 1505 1506 buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE); 1507 if (!buf) 1508 return -1; 1509 1510 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1511 wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY); 1512 wpabuf_put_u8(buf, 1); 1513 wpabuf_put_u8(buf, query_reason); 1514 1515 if (cand_list) 1516 wnm_add_cand_list(wpa_s, &buf); 1517 1518 if (btm_candidates) { 1519 const size_t max_len = 1000; 1520 1521 ret = wpabuf_resize(&buf, max_len); 1522 if (ret < 0) { 1523 wpabuf_free(buf); 1524 return ret; 1525 } 1526 1527 ret = ieee802_11_parse_candidate_list(btm_candidates, 1528 wpabuf_put(buf, 0), 1529 max_len); 1530 if (ret < 0) { 1531 wpabuf_free(buf); 1532 return ret; 1533 } 1534 1535 wpabuf_put(buf, ret); 1536 } 1537 1538 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1539 wpa_s->own_addr, wpa_s->bssid, 1540 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1541 1542 wpabuf_free(buf); 1543 return ret; 1544 } 1545 1546 1547 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1548 const u8 *sa, const u8 *data, 1549 int len) 1550 { 1551 const u8 *pos, *end, *next; 1552 u8 ie, ie_len; 1553 1554 pos = data; 1555 end = data + len; 1556 1557 while (end - pos > 1) { 1558 ie = *pos++; 1559 ie_len = *pos++; 1560 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1561 ie, ie_len); 1562 if (ie_len > end - pos) { 1563 wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1564 "subelement"); 1565 break; 1566 } 1567 next = pos + ie_len; 1568 if (ie_len < 4) { 1569 pos = next; 1570 continue; 1571 } 1572 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1573 WPA_GET_BE24(pos), pos[3]); 1574 1575 #ifdef CONFIG_HS20 1576 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1577 WPA_GET_BE24(pos) == OUI_WFA && 1578 pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1579 /* Subscription Remediation subelement */ 1580 const u8 *ie_end; 1581 u8 url_len; 1582 char *url; 1583 u8 osu_method; 1584 1585 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1586 "subelement"); 1587 ie_end = pos + ie_len; 1588 pos += 4; 1589 url_len = *pos++; 1590 if (url_len == 0) { 1591 wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1592 url = NULL; 1593 osu_method = 1; 1594 } else { 1595 if (url_len + 1 > ie_end - pos) { 1596 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1597 url_len, 1598 (int) (ie_end - pos)); 1599 break; 1600 } 1601 url = os_malloc(url_len + 1); 1602 if (url == NULL) 1603 break; 1604 os_memcpy(url, pos, url_len); 1605 url[url_len] = '\0'; 1606 osu_method = pos[url_len]; 1607 } 1608 hs20_rx_subscription_remediation(wpa_s, url, 1609 osu_method); 1610 os_free(url); 1611 pos = next; 1612 continue; 1613 } 1614 1615 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1616 WPA_GET_BE24(pos) == OUI_WFA && 1617 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1618 const u8 *ie_end; 1619 u8 url_len; 1620 char *url; 1621 u8 code; 1622 u16 reauth_delay; 1623 1624 ie_end = pos + ie_len; 1625 pos += 4; 1626 code = *pos++; 1627 reauth_delay = WPA_GET_LE16(pos); 1628 pos += 2; 1629 url_len = *pos++; 1630 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1631 "Imminent - Reason Code %u " 1632 "Re-Auth Delay %u URL Length %u", 1633 code, reauth_delay, url_len); 1634 if (url_len > ie_end - pos) 1635 break; 1636 url = os_malloc(url_len + 1); 1637 if (url == NULL) 1638 break; 1639 os_memcpy(url, pos, url_len); 1640 url[url_len] = '\0'; 1641 hs20_rx_deauth_imminent_notice(wpa_s, code, 1642 reauth_delay, url); 1643 os_free(url); 1644 pos = next; 1645 continue; 1646 } 1647 #endif /* CONFIG_HS20 */ 1648 1649 pos = next; 1650 } 1651 } 1652 1653 1654 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1655 const u8 *sa, const u8 *frm, int len) 1656 { 1657 const u8 *pos, *end; 1658 u8 dialog_token, type; 1659 1660 /* Dialog Token [1] | Type [1] | Subelements */ 1661 1662 if (len < 2 || sa == NULL) 1663 return; 1664 end = frm + len; 1665 pos = frm; 1666 dialog_token = *pos++; 1667 type = *pos++; 1668 1669 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1670 "(dialog_token %u type %u sa " MACSTR ")", 1671 dialog_token, type, MAC2STR(sa)); 1672 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1673 pos, end - pos); 1674 1675 if (wpa_s->wpa_state != WPA_COMPLETED || 1676 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1677 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1678 "from our AP - ignore it"); 1679 return; 1680 } 1681 1682 switch (type) { 1683 case 1: 1684 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1685 break; 1686 default: 1687 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1688 "WNM-Notification type %u", type); 1689 break; 1690 } 1691 } 1692 1693 1694 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1695 const struct ieee80211_mgmt *mgmt, size_t len) 1696 { 1697 const u8 *pos, *end; 1698 u8 act; 1699 1700 if (len < IEEE80211_HDRLEN + 2) 1701 return; 1702 1703 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1704 act = *pos++; 1705 end = ((const u8 *) mgmt) + len; 1706 1707 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1708 act, MAC2STR(mgmt->sa)); 1709 if (wpa_s->wpa_state < WPA_ASSOCIATED || 1710 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1711 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1712 "frame"); 1713 return; 1714 } 1715 1716 switch (act) { 1717 case WNM_BSS_TRANS_MGMT_REQ: 1718 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1719 !(mgmt->da[0] & 0x01)); 1720 break; 1721 case WNM_SLEEP_MODE_RESP: 1722 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 1723 break; 1724 case WNM_NOTIFICATION_REQ: 1725 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1726 break; 1727 default: 1728 wpa_printf(MSG_ERROR, "WNM: Unknown request"); 1729 break; 1730 } 1731 } 1732