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 "common/ocv.h" 16 #include "rsn_supp/wpa.h" 17 #include "config.h" 18 #include "wpa_supplicant_i.h" 19 #include "driver_i.h" 20 #include "scan.h" 21 #include "ctrl_iface.h" 22 #include "bss.h" 23 #include "wnm_sta.h" 24 #include "notify.h" 25 #include "hs20_supplicant.h" 26 27 #define MAX_TFS_IE_LEN 1024 28 #define WNM_MAX_NEIGHBOR_REPORT 10 29 30 #define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ 31 32 /* get the TFS IE from driver */ 33 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 34 u16 *buf_len, enum wnm_oper oper) 35 { 36 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 37 38 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 39 } 40 41 42 /* set the TFS IE to driver */ 43 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 44 const u8 *addr, const u8 *buf, u16 buf_len, 45 enum wnm_oper oper) 46 { 47 u16 len = buf_len; 48 49 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 50 51 return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 52 } 53 54 55 /* MLME-SLEEPMODE.request */ 56 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 57 u8 action, u16 intval, struct wpabuf *tfs_req) 58 { 59 struct ieee80211_mgmt *mgmt; 60 int res; 61 size_t len; 62 struct wnm_sleep_element *wnmsleep_ie; 63 u8 *wnmtfs_ie, *oci_ie; 64 u8 wnmsleep_ie_len, oci_ie_len; 65 u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 66 enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 67 WNM_SLEEP_TFS_REQ_IE_NONE; 68 69 wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 70 "action=%s to " MACSTR, 71 action == 0 ? "enter" : "exit", 72 MAC2STR(wpa_s->bssid)); 73 74 /* WNM-Sleep Mode IE */ 75 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 76 wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 77 if (wnmsleep_ie == NULL) 78 return -1; 79 wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 80 wnmsleep_ie->len = wnmsleep_ie_len - 2; 81 wnmsleep_ie->action_type = action; 82 wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 83 wnmsleep_ie->intval = host_to_le16(intval); 84 wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 85 (u8 *) wnmsleep_ie, wnmsleep_ie_len); 86 87 /* TFS IE(s) */ 88 if (tfs_req) { 89 wnmtfs_ie_len = wpabuf_len(tfs_req); 90 wnmtfs_ie = os_memdup(wpabuf_head(tfs_req), wnmtfs_ie_len); 91 if (wnmtfs_ie == NULL) { 92 os_free(wnmsleep_ie); 93 return -1; 94 } 95 } else { 96 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 97 if (wnmtfs_ie == NULL) { 98 os_free(wnmsleep_ie); 99 return -1; 100 } 101 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 102 tfs_oper)) { 103 wnmtfs_ie_len = 0; 104 os_free(wnmtfs_ie); 105 wnmtfs_ie = NULL; 106 } 107 } 108 wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 109 (u8 *) wnmtfs_ie, wnmtfs_ie_len); 110 111 oci_ie = NULL; 112 oci_ie_len = 0; 113 #ifdef CONFIG_OCV 114 if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) { 115 struct wpa_channel_info ci; 116 117 if (wpa_drv_channel_info(wpa_s, &ci) != 0) { 118 wpa_printf(MSG_WARNING, 119 "Failed to get channel info for OCI element in WNM-Sleep Mode frame"); 120 os_free(wnmsleep_ie); 121 os_free(wnmtfs_ie); 122 return -1; 123 } 124 #ifdef CONFIG_TESTING_OPTIONS 125 if (wpa_s->oci_freq_override_wnm_sleep) { 126 wpa_printf(MSG_INFO, 127 "TEST: Override OCI KDE frequency %d -> %d MHz", 128 ci.frequency, 129 wpa_s->oci_freq_override_wnm_sleep); 130 ci.frequency = wpa_s->oci_freq_override_wnm_sleep; 131 } 132 #endif /* CONFIG_TESTING_OPTIONS */ 133 134 oci_ie_len = OCV_OCI_EXTENDED_LEN; 135 oci_ie = os_zalloc(oci_ie_len); 136 if (!oci_ie) { 137 wpa_printf(MSG_WARNING, 138 "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame"); 139 os_free(wnmsleep_ie); 140 os_free(wnmtfs_ie); 141 return -1; 142 } 143 144 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) { 145 os_free(wnmsleep_ie); 146 os_free(wnmtfs_ie); 147 os_free(oci_ie); 148 return -1; 149 } 150 } 151 #endif /* CONFIG_OCV */ 152 153 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len + 154 oci_ie_len); 155 if (mgmt == NULL) { 156 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 157 "WNM-Sleep Request action frame"); 158 os_free(wnmsleep_ie); 159 os_free(wnmtfs_ie); 160 return -1; 161 } 162 163 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 164 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 165 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 166 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 167 WLAN_FC_STYPE_ACTION); 168 mgmt->u.action.category = WLAN_ACTION_WNM; 169 mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 170 mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 171 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 172 wnmsleep_ie_len); 173 /* copy TFS IE here */ 174 if (wnmtfs_ie_len > 0) { 175 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 176 wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 177 } 178 179 #ifdef CONFIG_OCV 180 /* copy OCV OCI here */ 181 if (oci_ie_len > 0) { 182 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 183 wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len); 184 } 185 #endif /* CONFIG_OCV */ 186 187 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 188 wnmtfs_ie_len + oci_ie_len; 189 190 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 191 wpa_s->own_addr, wpa_s->bssid, 192 &mgmt->u.action.category, len, 0); 193 if (res < 0) 194 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 195 "(action=%d, intval=%d)", action, intval); 196 else 197 wpa_s->wnmsleep_used = 1; 198 199 os_free(wnmsleep_ie); 200 os_free(wnmtfs_ie); 201 os_free(oci_ie); 202 os_free(mgmt); 203 204 return res; 205 } 206 207 208 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 209 const u8 *tfsresp_ie_start, 210 const u8 *tfsresp_ie_end) 211 { 212 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 213 wpa_s->bssid, NULL, NULL); 214 /* remove GTK/IGTK ?? */ 215 216 /* set the TFS Resp IE(s) */ 217 if (tfsresp_ie_start && tfsresp_ie_end && 218 tfsresp_ie_end - tfsresp_ie_start >= 0) { 219 u16 tfsresp_ie_len; 220 tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 221 tfsresp_ie_start; 222 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 223 /* pass the TFS Resp IE(s) to driver for processing */ 224 if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 225 tfsresp_ie_start, 226 tfsresp_ie_len, 227 WNM_SLEEP_TFS_RESP_IE_SET)) 228 wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 229 } 230 } 231 232 233 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 234 const u8 *frm, u16 key_len_total) 235 { 236 u8 *ptr, *end; 237 u8 gtk_len; 238 239 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 240 NULL, NULL); 241 242 /* Install GTK/IGTK */ 243 244 /* point to key data field */ 245 ptr = (u8 *) frm + 1 + 2; 246 end = ptr + key_len_total; 247 wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 248 249 if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { 250 wpa_msg(wpa_s, MSG_INFO, 251 "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); 252 return; 253 } 254 255 while (end - ptr > 1) { 256 if (2 + ptr[1] > end - ptr) { 257 wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 258 "length"); 259 if (end > ptr) { 260 wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 261 ptr, end - ptr); 262 } 263 break; 264 } 265 if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 266 if (ptr[1] < 11 + 5) { 267 wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 268 "subelem"); 269 break; 270 } 271 gtk_len = *(ptr + 4); 272 if (ptr[1] < 11 + gtk_len || 273 gtk_len < 5 || gtk_len > 32) { 274 wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 275 "subelem"); 276 break; 277 } 278 wpa_wnmsleep_install_key( 279 wpa_s->wpa, 280 WNM_SLEEP_SUBELEM_GTK, 281 ptr); 282 ptr += 13 + gtk_len; 283 } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 284 if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 285 wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 286 "subelem"); 287 break; 288 } 289 wpa_wnmsleep_install_key(wpa_s->wpa, 290 WNM_SLEEP_SUBELEM_IGTK, ptr); 291 ptr += 10 + WPA_IGTK_LEN; 292 } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) { 293 if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) { 294 wpa_printf(MSG_DEBUG, 295 "WNM: Too short BIGTK subelem"); 296 break; 297 } 298 wpa_wnmsleep_install_key(wpa_s->wpa, 299 WNM_SLEEP_SUBELEM_BIGTK, ptr); 300 ptr += 10 + WPA_BIGTK_LEN; 301 } else 302 break; /* skip the loop */ 303 } 304 } 305 306 307 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 308 const u8 *frm, int len) 309 { 310 /* 311 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 312 * WNM-Sleep Mode IE | TFS Response IE 313 */ 314 const u8 *pos = frm; /* point to payload after the action field */ 315 u16 key_len_total; 316 struct wnm_sleep_element *wnmsleep_ie = NULL; 317 /* multiple TFS Resp IE (assuming consecutive) */ 318 const u8 *tfsresp_ie_start = NULL; 319 const u8 *tfsresp_ie_end = NULL; 320 #ifdef CONFIG_OCV 321 const u8 *oci_ie = NULL; 322 u8 oci_ie_len = 0; 323 #endif /* CONFIG_OCV */ 324 size_t left; 325 326 if (!wpa_s->wnmsleep_used) { 327 wpa_printf(MSG_DEBUG, 328 "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested"); 329 return; 330 } 331 332 if (len < 3) 333 return; 334 key_len_total = WPA_GET_LE16(frm + 1); 335 336 wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 337 frm[0], key_len_total); 338 left = len - 3; 339 if (key_len_total > left) { 340 wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 341 return; 342 } 343 pos += 3 + key_len_total; 344 while (pos - frm + 1 < len) { 345 u8 ie_len = *(pos + 1); 346 if (2 + ie_len > frm + len - pos) { 347 wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 348 break; 349 } 350 wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 351 if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) 352 wnmsleep_ie = (struct wnm_sleep_element *) pos; 353 else if (*pos == WLAN_EID_TFS_RESP) { 354 if (!tfsresp_ie_start) 355 tfsresp_ie_start = pos; 356 tfsresp_ie_end = pos; 357 #ifdef CONFIG_OCV 358 } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 && 359 pos[2] == WLAN_EID_EXT_OCV_OCI) { 360 oci_ie = pos + 3; 361 oci_ie_len = ie_len - 1; 362 #endif /* CONFIG_OCV */ 363 } else 364 wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 365 pos += ie_len + 2; 366 } 367 368 if (!wnmsleep_ie) { 369 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 370 return; 371 } 372 373 #ifdef CONFIG_OCV 374 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT && 375 wpa_sm_ocv_enabled(wpa_s->wpa)) { 376 struct wpa_channel_info ci; 377 378 if (wpa_drv_channel_info(wpa_s, &ci) != 0) { 379 wpa_msg(wpa_s, MSG_WARNING, 380 "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame"); 381 return; 382 } 383 384 if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci, 385 channel_width_to_int(ci.chanwidth), 386 ci.seg1_idx) != OCI_SUCCESS) { 387 wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s", 388 ocv_errorstr); 389 return; 390 } 391 } 392 #endif /* CONFIG_OCV */ 393 394 wpa_s->wnmsleep_used = 0; 395 396 if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 397 wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 398 wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 399 "frame (action=%d, intval=%d)", 400 wnmsleep_ie->action_type, wnmsleep_ie->intval); 401 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 402 wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 403 tfsresp_ie_end); 404 } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 405 wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 406 } 407 } else { 408 wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 409 "(action=%d, intval=%d)", 410 wnmsleep_ie->action_type, wnmsleep_ie->intval); 411 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 412 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 413 wpa_s->bssid, NULL, NULL); 414 else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 415 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 416 wpa_s->bssid, NULL, NULL); 417 } 418 } 419 420 421 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 422 { 423 int i; 424 425 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 426 os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 427 os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 428 } 429 430 wpa_s->wnm_num_neighbor_report = 0; 431 os_free(wpa_s->wnm_neighbor_report_elements); 432 wpa_s->wnm_neighbor_report_elements = NULL; 433 434 wpabuf_free(wpa_s->coloc_intf_elems); 435 wpa_s->coloc_intf_elems = NULL; 436 } 437 438 439 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 440 u8 id, u8 elen, const u8 *pos) 441 { 442 switch (id) { 443 case WNM_NEIGHBOR_TSF: 444 if (elen < 2 + 2) { 445 wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 446 break; 447 } 448 rep->tsf_offset = WPA_GET_LE16(pos); 449 rep->beacon_int = WPA_GET_LE16(pos + 2); 450 rep->tsf_present = 1; 451 break; 452 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 453 if (elen < 2) { 454 wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 455 "country string"); 456 break; 457 } 458 os_memcpy(rep->country, pos, 2); 459 rep->country_present = 1; 460 break; 461 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 462 if (elen < 1) { 463 wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 464 "candidate"); 465 break; 466 } 467 rep->preference = pos[0]; 468 rep->preference_present = 1; 469 break; 470 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 471 if (elen < 10) { 472 wpa_printf(MSG_DEBUG, 473 "WNM: Too short BSS termination duration"); 474 break; 475 } 476 rep->bss_term_tsf = WPA_GET_LE64(pos); 477 rep->bss_term_dur = WPA_GET_LE16(pos + 8); 478 rep->bss_term_present = 1; 479 break; 480 case WNM_NEIGHBOR_BEARING: 481 if (elen < 8) { 482 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 483 "bearing"); 484 break; 485 } 486 rep->bearing = WPA_GET_LE16(pos); 487 rep->distance = WPA_GET_LE32(pos + 2); 488 rep->rel_height = WPA_GET_LE16(pos + 2 + 4); 489 rep->bearing_present = 1; 490 break; 491 case WNM_NEIGHBOR_MEASUREMENT_PILOT: 492 if (elen < 1) { 493 wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 494 "pilot"); 495 break; 496 } 497 os_free(rep->meas_pilot); 498 rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 499 if (rep->meas_pilot == NULL) 500 break; 501 rep->meas_pilot->measurement_pilot = pos[0]; 502 rep->meas_pilot->subelem_len = elen - 1; 503 os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 504 break; 505 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 506 if (elen < 5) { 507 wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 508 "capabilities"); 509 break; 510 } 511 os_memcpy(rep->rm_capab, pos, 5); 512 rep->rm_capab_present = 1; 513 break; 514 case WNM_NEIGHBOR_MULTIPLE_BSSID: 515 if (elen < 1) { 516 wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 517 break; 518 } 519 os_free(rep->mul_bssid); 520 rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 521 if (rep->mul_bssid == NULL) 522 break; 523 rep->mul_bssid->max_bssid_indicator = pos[0]; 524 rep->mul_bssid->subelem_len = elen - 1; 525 os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 526 break; 527 } 528 } 529 530 531 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) 532 { 533 struct wpa_bss *bss = wpa_s->current_bss; 534 const char *country = NULL; 535 int freq; 536 537 if (bss) { 538 const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); 539 540 if (elem && elem[1] >= 2) 541 country = (const char *) (elem + 2); 542 } 543 544 freq = ieee80211_chan_to_freq(country, op_class, chan); 545 if (freq <= 0 && op_class == 0) { 546 /* 547 * Some APs do not advertise correct operating class 548 * information. Try to determine the most likely operating 549 * frequency based on the channel number. 550 */ 551 if (chan >= 1 && chan <= 13) 552 freq = 2407 + chan * 5; 553 else if (chan == 14) 554 freq = 2484; 555 else if (chan >= 36 && chan <= 177) 556 freq = 5000 + chan * 5; 557 } 558 return freq; 559 } 560 561 562 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 563 const u8 *pos, u8 len, 564 struct neighbor_report *rep) 565 { 566 u8 left = len; 567 568 if (left < 13) { 569 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 570 return; 571 } 572 573 os_memcpy(rep->bssid, pos, ETH_ALEN); 574 rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); 575 rep->regulatory_class = *(pos + 10); 576 rep->channel_number = *(pos + 11); 577 rep->phy_type = *(pos + 12); 578 579 pos += 13; 580 left -= 13; 581 582 while (left >= 2) { 583 u8 id, elen; 584 585 id = *pos++; 586 elen = *pos++; 587 wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 588 left -= 2; 589 if (elen > left) { 590 wpa_printf(MSG_DEBUG, 591 "WNM: Truncated neighbor report subelement"); 592 break; 593 } 594 wnm_parse_neighbor_report_elem(rep, id, elen, pos); 595 left -= elen; 596 pos += elen; 597 } 598 599 rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, 600 rep->channel_number); 601 } 602 603 604 static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s) 605 { 606 unsigned int i; 607 608 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) 609 wpa_s->wnm_neighbor_report_elements[i].acceptable = 0; 610 } 611 612 613 static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) 614 { 615 unsigned int i; 616 struct neighbor_report *nei; 617 618 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 619 nei = &wpa_s->wnm_neighbor_report_elements[i]; 620 if (nei->acceptable) 621 return wpa_bss_get_bssid(wpa_s, nei->bssid); 622 } 623 624 return NULL; 625 } 626 627 628 #ifdef CONFIG_MBO 629 static struct wpa_bss * 630 get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, 631 enum mbo_transition_reject_reason *reason) 632 { 633 struct wpa_bss *target = NULL; 634 struct wpa_bss_trans_info params; 635 struct wpa_bss_candidate_info *info = NULL; 636 struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements; 637 u8 *first_candidate_bssid = NULL, *pos; 638 unsigned int i; 639 640 params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason; 641 params.n_candidates = 0; 642 params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN); 643 if (!params.bssid) 644 return NULL; 645 646 pos = params.bssid; 647 for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) { 648 if (nei->is_first) 649 first_candidate_bssid = nei->bssid; 650 if (!nei->acceptable) 651 continue; 652 os_memcpy(pos, nei->bssid, ETH_ALEN); 653 pos += ETH_ALEN; 654 params.n_candidates++; 655 } 656 657 if (!params.n_candidates) 658 goto end; 659 660 info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms); 661 if (!info) { 662 /* If failed to get candidate BSS transition status from driver, 663 * get the first acceptable candidate from wpa_supplicant. 664 */ 665 target = wpa_bss_get_bssid(wpa_s, params.bssid); 666 goto end; 667 } 668 669 /* Get the first acceptable candidate from driver */ 670 for (i = 0; i < info->num; i++) { 671 if (info->candidates[i].is_accept) { 672 target = wpa_bss_get_bssid(wpa_s, 673 info->candidates[i].bssid); 674 goto end; 675 } 676 } 677 678 /* If Disassociation Imminent is set and driver rejects all the 679 * candidate select first acceptable candidate which has 680 * rssi > disassoc_imminent_rssi_threshold 681 */ 682 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 683 for (i = 0; i < info->num; i++) { 684 target = wpa_bss_get_bssid(wpa_s, 685 info->candidates[i].bssid); 686 if (target && 687 (target->level < 688 wpa_s->conf->disassoc_imminent_rssi_threshold)) 689 continue; 690 goto end; 691 } 692 } 693 694 /* While sending BTM reject use reason code of the first candidate 695 * received in BTM request frame 696 */ 697 if (reason) { 698 for (i = 0; i < info->num; i++) { 699 if (first_candidate_bssid && 700 os_memcmp(first_candidate_bssid, 701 info->candidates[i].bssid, ETH_ALEN) == 0) 702 { 703 *reason = info->candidates[i].reject_reason; 704 break; 705 } 706 } 707 } 708 709 target = NULL; 710 711 end: 712 os_free(params.bssid); 713 if (info) { 714 os_free(info->candidates); 715 os_free(info); 716 } 717 return target; 718 } 719 #endif /* CONFIG_MBO */ 720 721 722 static struct wpa_bss * 723 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, 724 enum mbo_transition_reject_reason *reason) 725 { 726 u8 i; 727 struct wpa_bss *bss = wpa_s->current_bss; 728 struct wpa_bss *target; 729 730 if (!bss) 731 return NULL; 732 733 wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 734 MAC2STR(wpa_s->bssid), bss->level); 735 736 wnm_clear_acceptable(wpa_s); 737 738 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 739 struct neighbor_report *nei; 740 741 nei = &wpa_s->wnm_neighbor_report_elements[i]; 742 if (nei->preference_present && nei->preference == 0) { 743 wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 744 MAC2STR(nei->bssid)); 745 continue; 746 } 747 748 target = wpa_bss_get_bssid(wpa_s, nei->bssid); 749 if (!target) { 750 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 751 " (pref %d) not found in scan results", 752 MAC2STR(nei->bssid), 753 nei->preference_present ? nei->preference : 754 -1); 755 continue; 756 } 757 758 if (age_secs) { 759 struct os_reltime now; 760 761 if (os_get_reltime(&now) == 0 && 762 os_reltime_expired(&now, &target->last_update, 763 age_secs)) { 764 wpa_printf(MSG_DEBUG, 765 "Candidate BSS is more than %ld seconds old", 766 age_secs); 767 continue; 768 } 769 } 770 771 if (bss->ssid_len != target->ssid_len || 772 os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 773 /* 774 * TODO: Could consider allowing transition to another 775 * ESS if PMF was enabled for the association. 776 */ 777 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 778 " (pref %d) in different ESS", 779 MAC2STR(nei->bssid), 780 nei->preference_present ? nei->preference : 781 -1); 782 continue; 783 } 784 785 if (wpa_s->current_ssid && 786 !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 787 1, 0)) { 788 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 789 " (pref %d) does not match the current network profile", 790 MAC2STR(nei->bssid), 791 nei->preference_present ? nei->preference : 792 -1); 793 continue; 794 } 795 796 if (wpa_is_bss_tmp_disallowed(wpa_s, target)) { 797 wpa_printf(MSG_DEBUG, 798 "MBO: Candidate BSS " MACSTR 799 " retry delay is not over yet", 800 MAC2STR(nei->bssid)); 801 continue; 802 } 803 804 if (target->level < bss->level && target->level < -80) { 805 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 806 " (pref %d) does not have sufficient signal level (%d)", 807 MAC2STR(nei->bssid), 808 nei->preference_present ? nei->preference : 809 -1, 810 target->level); 811 continue; 812 } 813 814 nei->acceptable = 1; 815 } 816 817 #ifdef CONFIG_MBO 818 if (wpa_s->wnm_mbo_trans_reason_present) 819 target = get_mbo_transition_candidate(wpa_s, reason); 820 else 821 target = get_first_acceptable(wpa_s); 822 #else /* CONFIG_MBO */ 823 target = get_first_acceptable(wpa_s); 824 #endif /* CONFIG_MBO */ 825 826 if (target) { 827 wpa_printf(MSG_DEBUG, 828 "WNM: Found an acceptable preferred transition candidate BSS " 829 MACSTR " (RSSI %d)", 830 MAC2STR(target->bssid), target->level); 831 } 832 833 return target; 834 } 835 836 837 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) 838 { 839 const u8 *ie_a, *ie_b; 840 841 if (!a || !b) 842 return 0; 843 844 ie_a = wpa_bss_get_ie(a, eid); 845 ie_b = wpa_bss_get_ie(b, eid); 846 847 if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) 848 return 0; 849 850 return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; 851 } 852 853 854 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 855 { 856 u32 info = 0; 857 858 info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; 859 860 /* 861 * Leave the security and key scope bits unset to indicate that the 862 * security information is not available. 863 */ 864 865 if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) 866 info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 867 if (bss->caps & WLAN_CAPABILITY_QOS) 868 info |= NEI_REP_BSSID_INFO_QOS; 869 if (bss->caps & WLAN_CAPABILITY_APSD) 870 info |= NEI_REP_BSSID_INFO_APSD; 871 if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) 872 info |= NEI_REP_BSSID_INFO_RM; 873 if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) 874 info |= NEI_REP_BSSID_INFO_DELAYED_BA; 875 if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) 876 info |= NEI_REP_BSSID_INFO_IMM_BA; 877 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) 878 info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; 879 if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) 880 info |= NEI_REP_BSSID_INFO_HT; 881 882 return info; 883 } 884 885 886 static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid, 887 u32 bss_info, u8 op_class, u8 chan, u8 phy_type, 888 u8 pref) 889 { 890 if (wpabuf_len(*buf) + 18 > 891 IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) { 892 wpa_printf(MSG_DEBUG, 893 "WNM: No room in frame for Neighbor Report element"); 894 return -1; 895 } 896 897 if (wpabuf_resize(buf, 18) < 0) { 898 wpa_printf(MSG_DEBUG, 899 "WNM: Failed to allocate memory for Neighbor Report element"); 900 return -1; 901 } 902 903 wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT); 904 /* length: 13 for basic neighbor report + 3 for preference subelement */ 905 wpabuf_put_u8(*buf, 16); 906 wpabuf_put_data(*buf, bssid, ETH_ALEN); 907 wpabuf_put_le32(*buf, bss_info); 908 wpabuf_put_u8(*buf, op_class); 909 wpabuf_put_u8(*buf, chan); 910 wpabuf_put_u8(*buf, phy_type); 911 wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE); 912 wpabuf_put_u8(*buf, 1); 913 wpabuf_put_u8(*buf, pref); 914 return 0; 915 } 916 917 918 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, 919 struct wpa_bss *bss, struct wpabuf **buf, 920 u8 pref) 921 { 922 const u8 *ie; 923 u8 op_class, chan; 924 int sec_chan = 0, vht = 0; 925 enum phy_type phy_type; 926 u32 info; 927 struct ieee80211_ht_operation *ht_oper = NULL; 928 struct ieee80211_vht_operation *vht_oper = NULL; 929 930 ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); 931 if (ie && ie[1] >= 2) { 932 ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 933 934 if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 935 sec_chan = 1; 936 else if (ht_oper->ht_param & 937 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 938 sec_chan = -1; 939 } 940 941 ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); 942 if (ie && ie[1] >= 1) { 943 vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 944 945 if (vht_oper->vht_op_info_chwidth == CHANWIDTH_80MHZ || 946 vht_oper->vht_op_info_chwidth == CHANWIDTH_160MHZ || 947 vht_oper->vht_op_info_chwidth == CHANWIDTH_80P80MHZ) 948 vht = vht_oper->vht_op_info_chwidth; 949 } 950 951 if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, 952 &chan) == NUM_HOSTAPD_MODES) { 953 wpa_printf(MSG_DEBUG, 954 "WNM: Cannot determine operating class and channel"); 955 return -2; 956 } 957 958 phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), 959 (vht_oper != NULL)); 960 if (phy_type == PHY_TYPE_UNSPECIFIED) { 961 wpa_printf(MSG_DEBUG, 962 "WNM: Cannot determine BSS phy type for Neighbor Report"); 963 return -2; 964 } 965 966 info = wnm_get_bss_info(wpa_s, bss); 967 968 return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type, 969 pref); 970 } 971 972 973 static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf) 974 { 975 unsigned int i, pref = 255; 976 struct os_reltime now; 977 struct wpa_ssid *ssid = wpa_s->current_ssid; 978 979 if (!ssid) 980 return; 981 982 /* 983 * TODO: Define when scan results are no longer valid for the candidate 984 * list. 985 */ 986 os_get_reltime(&now); 987 if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) 988 return; 989 990 wpa_printf(MSG_DEBUG, 991 "WNM: Add candidate list to BSS Transition Management Response frame"); 992 for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { 993 struct wpa_bss *bss = wpa_s->last_scan_res[i]; 994 int res; 995 996 if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { 997 res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--); 998 if (res == -2) 999 continue; /* could not build entry for BSS */ 1000 if (res < 0) 1001 break; /* no more room for candidates */ 1002 if (pref == 1) 1003 break; 1004 } 1005 } 1006 1007 wpa_hexdump_buf(MSG_DEBUG, 1008 "WNM: BSS Transition Management Response candidate list", 1009 *buf); 1010 } 1011 1012 1013 #define BTM_RESP_MIN_SIZE 5 + ETH_ALEN 1014 1015 static void wnm_send_bss_transition_mgmt_resp( 1016 struct wpa_supplicant *wpa_s, u8 dialog_token, 1017 enum bss_trans_mgmt_status_code status, 1018 enum mbo_transition_reject_reason reason, 1019 u8 delay, const u8 *target_bssid) 1020 { 1021 struct wpabuf *buf; 1022 int res; 1023 1024 wpa_printf(MSG_DEBUG, 1025 "WNM: Send BSS Transition Management Response to " MACSTR 1026 " dialog_token=%u status=%u reason=%u delay=%d", 1027 MAC2STR(wpa_s->bssid), dialog_token, status, reason, delay); 1028 if (!wpa_s->current_bss) { 1029 wpa_printf(MSG_DEBUG, 1030 "WNM: Current BSS not known - drop response"); 1031 return; 1032 } 1033 1034 buf = wpabuf_alloc(BTM_RESP_MIN_SIZE); 1035 if (!buf) { 1036 wpa_printf(MSG_DEBUG, 1037 "WNM: Failed to allocate memory for BTM response"); 1038 return; 1039 } 1040 1041 wpa_s->bss_tm_status = status; 1042 wpas_notify_bss_tm_status(wpa_s); 1043 1044 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1045 wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP); 1046 wpabuf_put_u8(buf, dialog_token); 1047 wpabuf_put_u8(buf, status); 1048 wpabuf_put_u8(buf, delay); 1049 if (target_bssid) { 1050 wpabuf_put_data(buf, target_bssid, ETH_ALEN); 1051 } else if (status == WNM_BSS_TM_ACCEPT) { 1052 /* 1053 * P802.11-REVmc clarifies that the Target BSSID field is always 1054 * present when status code is zero, so use a fake value here if 1055 * no BSSID is yet known. 1056 */ 1057 wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN); 1058 } 1059 1060 if (status == WNM_BSS_TM_ACCEPT) 1061 wnm_add_cand_list(wpa_s, &buf); 1062 1063 #ifdef CONFIG_MBO 1064 if (status != WNM_BSS_TM_ACCEPT && 1065 wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) { 1066 u8 mbo[10]; 1067 size_t ret; 1068 1069 ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo), 1070 reason); 1071 if (ret) { 1072 if (wpabuf_resize(&buf, ret) < 0) { 1073 wpabuf_free(buf); 1074 wpa_printf(MSG_DEBUG, 1075 "WNM: Failed to allocate memory for MBO IE"); 1076 return; 1077 } 1078 1079 wpabuf_put_data(buf, mbo, ret); 1080 } 1081 } 1082 #endif /* CONFIG_MBO */ 1083 1084 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1085 wpa_s->own_addr, wpa_s->bssid, 1086 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1087 if (res < 0) { 1088 wpa_printf(MSG_DEBUG, 1089 "WNM: Failed to send BSS Transition Management Response"); 1090 } 1091 1092 wpabuf_free(buf); 1093 } 1094 1095 1096 static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, 1097 struct wpa_bss *bss, struct wpa_ssid *ssid, 1098 int after_new_scan) 1099 { 1100 struct wpa_radio_work *already_connecting; 1101 1102 wpa_dbg(wpa_s, MSG_DEBUG, 1103 "WNM: Transition to BSS " MACSTR 1104 " based on BSS Transition Management Request (old BSSID " 1105 MACSTR " after_new_scan=%d)", 1106 MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); 1107 1108 /* Send the BSS Management Response - Accept */ 1109 if (wpa_s->wnm_reply) { 1110 wpa_s->wnm_reply = 0; 1111 wpa_printf(MSG_DEBUG, 1112 "WNM: Sending successful BSS Transition Management Response"); 1113 wnm_send_bss_transition_mgmt_resp( 1114 wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, 1115 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1116 bss->bssid); 1117 } 1118 1119 if (bss == wpa_s->current_bss) { 1120 wpa_printf(MSG_DEBUG, 1121 "WNM: Already associated with the preferred candidate"); 1122 wnm_deallocate_memory(wpa_s); 1123 return; 1124 } 1125 1126 already_connecting = radio_work_pending(wpa_s, "sme-connect"); 1127 wpa_s->reassociate = 1; 1128 wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); 1129 wpa_supplicant_connect(wpa_s, bss, ssid); 1130 1131 /* 1132 * Indicate that a BSS transition is in progress so scan results that 1133 * come in before the 'sme-connect' radio work gets executed do not 1134 * override the original connection attempt. 1135 */ 1136 if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) 1137 wpa_s->bss_trans_mgmt_in_progress = true; 1138 wnm_deallocate_memory(wpa_s); 1139 } 1140 1141 1142 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 1143 { 1144 struct wpa_bss *bss; 1145 struct wpa_ssid *ssid = wpa_s->current_ssid; 1146 enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1147 enum mbo_transition_reject_reason reason = 1148 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; 1149 1150 if (!wpa_s->wnm_neighbor_report_elements) 1151 return 0; 1152 1153 wpa_dbg(wpa_s, MSG_DEBUG, 1154 "WNM: Process scan results for BSS Transition Management"); 1155 if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 1156 &wpa_s->scan_trigger_time)) { 1157 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 1158 wnm_deallocate_memory(wpa_s); 1159 return 0; 1160 } 1161 1162 if (!wpa_s->current_bss || 1163 os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 1164 ETH_ALEN) != 0) { 1165 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 1166 return 0; 1167 } 1168 1169 /* Compare the Neighbor Report and scan results */ 1170 bss = compare_scan_neighbor_results(wpa_s, 0, &reason); 1171 if (!bss) { 1172 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 1173 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 1174 goto send_bss_resp_fail; 1175 } 1176 1177 /* Associate to the network */ 1178 wnm_bss_tm_connect(wpa_s, bss, ssid, 1); 1179 return 1; 1180 1181 send_bss_resp_fail: 1182 if (!reply_on_fail) 1183 return 0; 1184 1185 /* Send reject response for all the failures */ 1186 1187 if (wpa_s->wnm_reply) { 1188 wpa_s->wnm_reply = 0; 1189 wnm_send_bss_transition_mgmt_resp(wpa_s, 1190 wpa_s->wnm_dialog_token, 1191 status, reason, 0, NULL); 1192 } 1193 wnm_deallocate_memory(wpa_s); 1194 1195 return 0; 1196 } 1197 1198 1199 static int cand_pref_compar(const void *a, const void *b) 1200 { 1201 const struct neighbor_report *aa = a; 1202 const struct neighbor_report *bb = b; 1203 1204 if (!aa->preference_present && !bb->preference_present) 1205 return 0; 1206 if (!aa->preference_present) 1207 return 1; 1208 if (!bb->preference_present) 1209 return -1; 1210 if (bb->preference > aa->preference) 1211 return 1; 1212 if (bb->preference < aa->preference) 1213 return -1; 1214 return 0; 1215 } 1216 1217 1218 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 1219 { 1220 if (!wpa_s->wnm_neighbor_report_elements) 1221 return; 1222 qsort(wpa_s->wnm_neighbor_report_elements, 1223 wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 1224 cand_pref_compar); 1225 } 1226 1227 1228 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 1229 { 1230 unsigned int i; 1231 1232 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 1233 if (!wpa_s->wnm_neighbor_report_elements) 1234 return; 1235 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1236 struct neighbor_report *nei; 1237 1238 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1239 wpa_printf(MSG_DEBUG, "%u: " MACSTR 1240 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 1241 i, MAC2STR(nei->bssid), nei->bssid_info, 1242 nei->regulatory_class, 1243 nei->channel_number, nei->phy_type, 1244 nei->preference_present ? nei->preference : -1, 1245 nei->freq); 1246 } 1247 } 1248 1249 1250 static int chan_supported(struct wpa_supplicant *wpa_s, int freq) 1251 { 1252 unsigned int i; 1253 1254 for (i = 0; i < wpa_s->hw.num_modes; i++) { 1255 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 1256 int j; 1257 1258 for (j = 0; j < mode->num_channels; j++) { 1259 struct hostapd_channel_data *chan; 1260 1261 chan = &mode->channels[j]; 1262 if (chan->freq == freq && 1263 !(chan->flag & HOSTAPD_CHAN_DISABLED)) 1264 return 1; 1265 } 1266 } 1267 1268 return 0; 1269 } 1270 1271 1272 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 1273 { 1274 int *freqs; 1275 int num_freqs = 0; 1276 unsigned int i; 1277 1278 if (!wpa_s->wnm_neighbor_report_elements) 1279 return; 1280 1281 if (wpa_s->hw.modes == NULL) 1282 return; 1283 1284 os_free(wpa_s->next_scan_freqs); 1285 wpa_s->next_scan_freqs = NULL; 1286 1287 freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 1288 if (freqs == NULL) 1289 return; 1290 1291 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1292 struct neighbor_report *nei; 1293 1294 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1295 if (nei->freq <= 0) { 1296 wpa_printf(MSG_DEBUG, 1297 "WNM: Unknown neighbor operating frequency for " 1298 MACSTR " - scan all channels", 1299 MAC2STR(nei->bssid)); 1300 os_free(freqs); 1301 return; 1302 } 1303 if (chan_supported(wpa_s, nei->freq)) 1304 add_freq(freqs, &num_freqs, nei->freq); 1305 } 1306 1307 if (num_freqs == 0) { 1308 os_free(freqs); 1309 return; 1310 } 1311 1312 wpa_printf(MSG_DEBUG, 1313 "WNM: Scan %d frequencies based on transition candidate list", 1314 num_freqs); 1315 wpa_s->next_scan_freqs = freqs; 1316 } 1317 1318 1319 static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) 1320 { 1321 struct wpa_scan_results *scan_res; 1322 struct wpa_bss *bss; 1323 struct wpa_ssid *ssid = wpa_s->current_ssid; 1324 u8 i, found = 0; 1325 size_t j; 1326 1327 wpa_dbg(wpa_s, MSG_DEBUG, 1328 "WNM: Fetch current scan results from the driver for checking transition candidates"); 1329 scan_res = wpa_drv_get_scan_results2(wpa_s); 1330 if (!scan_res) { 1331 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); 1332 return 0; 1333 } 1334 1335 if (scan_res->fetch_time.sec == 0) 1336 os_get_reltime(&scan_res->fetch_time); 1337 1338 filter_scan_res(wpa_s, scan_res); 1339 1340 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1341 struct neighbor_report *nei; 1342 1343 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1344 if (nei->preference_present && nei->preference == 0) 1345 continue; 1346 1347 for (j = 0; j < scan_res->num; j++) { 1348 struct wpa_scan_res *res; 1349 const u8 *ssid_ie; 1350 1351 res = scan_res->res[j]; 1352 if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || 1353 res->age > WNM_SCAN_RESULT_AGE * 1000) 1354 continue; 1355 bss = wpa_s->current_bss; 1356 ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); 1357 if (bss && ssid_ie && ssid_ie[1] && 1358 (bss->ssid_len != ssid_ie[1] || 1359 os_memcmp(bss->ssid, ssid_ie + 2, 1360 bss->ssid_len) != 0)) 1361 continue; /* Skip entries for other ESSs */ 1362 1363 /* Potential candidate found */ 1364 found = 1; 1365 scan_snr(res); 1366 scan_est_throughput(wpa_s, res); 1367 wpa_bss_update_scan_res(wpa_s, res, 1368 &scan_res->fetch_time); 1369 } 1370 } 1371 1372 wpa_scan_results_free(scan_res); 1373 if (!found) { 1374 wpa_dbg(wpa_s, MSG_DEBUG, 1375 "WNM: No transition candidate matches existing scan results"); 1376 return 0; 1377 } 1378 1379 bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); 1380 if (!bss) { 1381 wpa_dbg(wpa_s, MSG_DEBUG, 1382 "WNM: Comparison of scan results against transition candidates did not find matches"); 1383 return 0; 1384 } 1385 1386 /* Associate to the network */ 1387 wnm_bss_tm_connect(wpa_s, bss, ssid, 0); 1388 return 1; 1389 } 1390 1391 1392 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1393 const u8 *pos, const u8 *end, 1394 int reply) 1395 { 1396 unsigned int beacon_int; 1397 u8 valid_int; 1398 #ifdef CONFIG_MBO 1399 const u8 *vendor; 1400 #endif /* CONFIG_MBO */ 1401 1402 if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm) 1403 return; 1404 1405 if (end - pos < 5) 1406 return; 1407 1408 #ifdef CONFIG_MBO 1409 wpa_s->wnm_mbo_trans_reason_present = 0; 1410 wpa_s->wnm_mbo_transition_reason = 0; 1411 #endif /* CONFIG_MBO */ 1412 1413 if (wpa_s->current_bss) 1414 beacon_int = wpa_s->current_bss->beacon_int; 1415 else 1416 beacon_int = 100; /* best guess */ 1417 1418 wpa_s->wnm_dialog_token = pos[0]; 1419 wpa_s->wnm_mode = pos[1]; 1420 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1421 valid_int = pos[4]; 1422 wpa_s->wnm_reply = reply; 1423 1424 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1425 "dialog_token=%u request_mode=0x%x " 1426 "disassoc_timer=%u validity_interval=%u", 1427 wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1428 wpa_s->wnm_dissoc_timer, valid_int); 1429 1430 #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) 1431 if (wpa_s->reject_btm_req_reason) { 1432 wpa_printf(MSG_INFO, 1433 "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", 1434 wpa_s->reject_btm_req_reason); 1435 wnm_send_bss_transition_mgmt_resp( 1436 wpa_s, wpa_s->wnm_dialog_token, 1437 wpa_s->reject_btm_req_reason, 1438 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1439 return; 1440 } 1441 #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ 1442 1443 pos += 5; 1444 1445 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1446 if (end - pos < 12) { 1447 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 1448 return; 1449 } 1450 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1451 pos += 12; /* BSS Termination Duration */ 1452 } 1453 1454 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1455 char url[256]; 1456 1457 if (end - pos < 1 || 1 + pos[0] > end - pos) { 1458 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1459 "Management Request (URL)"); 1460 return; 1461 } 1462 os_memcpy(url, pos + 1, pos[0]); 1463 url[pos[0]] = '\0'; 1464 pos += 1 + pos[0]; 1465 1466 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1467 wpa_sm_pmf_enabled(wpa_s->wpa), 1468 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1469 } 1470 1471 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1472 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 1473 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 1474 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1475 /* TODO: mark current BSS less preferred for 1476 * selection */ 1477 wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1478 wpa_supplicant_req_scan(wpa_s, 0, 0); 1479 } 1480 } 1481 1482 #ifdef CONFIG_MBO 1483 vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 1484 if (vendor) 1485 wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 1486 #endif /* CONFIG_MBO */ 1487 1488 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1489 unsigned int valid_ms; 1490 1491 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1492 wnm_deallocate_memory(wpa_s); 1493 wpa_s->wnm_neighbor_report_elements = os_calloc( 1494 WNM_MAX_NEIGHBOR_REPORT, 1495 sizeof(struct neighbor_report)); 1496 if (wpa_s->wnm_neighbor_report_elements == NULL) 1497 return; 1498 1499 while (end - pos >= 2 && 1500 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 1501 { 1502 u8 tag = *pos++; 1503 u8 len = *pos++; 1504 1505 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 1506 tag); 1507 if (len > end - pos) { 1508 wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 1509 return; 1510 } 1511 if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1512 struct neighbor_report *rep; 1513 rep = &wpa_s->wnm_neighbor_report_elements[ 1514 wpa_s->wnm_num_neighbor_report]; 1515 wnm_parse_neighbor_report(wpa_s, pos, len, rep); 1516 wpa_s->wnm_num_neighbor_report++; 1517 #ifdef CONFIG_MBO 1518 if (wpa_s->wnm_mbo_trans_reason_present && 1519 wpa_s->wnm_num_neighbor_report == 1) { 1520 rep->is_first = 1; 1521 wpa_printf(MSG_DEBUG, 1522 "WNM: First transition candidate is " 1523 MACSTR, MAC2STR(rep->bssid)); 1524 } 1525 #endif /* CONFIG_MBO */ 1526 } 1527 1528 pos += len; 1529 } 1530 1531 if (!wpa_s->wnm_num_neighbor_report) { 1532 wpa_printf(MSG_DEBUG, 1533 "WNM: Candidate list included bit is set, but no candidates found"); 1534 wnm_send_bss_transition_mgmt_resp( 1535 wpa_s, wpa_s->wnm_dialog_token, 1536 WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 1537 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1538 NULL); 1539 return; 1540 } 1541 1542 wnm_sort_cand_list(wpa_s); 1543 wnm_dump_cand_list(wpa_s); 1544 valid_ms = valid_int * beacon_int * 128 / 125; 1545 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1546 valid_ms); 1547 os_get_reltime(&wpa_s->wnm_cand_valid_until); 1548 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1549 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1550 wpa_s->wnm_cand_valid_until.sec += 1551 wpa_s->wnm_cand_valid_until.usec / 1000000; 1552 wpa_s->wnm_cand_valid_until.usec %= 1000000; 1553 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1554 1555 /* 1556 * Fetch the latest scan results from the kernel and check for 1557 * candidates based on those results first. This can help in 1558 * finding more up-to-date information should the driver has 1559 * done some internal scanning operations after the last scan 1560 * result update in wpa_supplicant. 1561 */ 1562 if (wnm_fetch_scan_results(wpa_s) > 0) 1563 return; 1564 1565 /* 1566 * Try to use previously received scan results, if they are 1567 * recent enough to use for a connection. 1568 */ 1569 if (wpa_s->last_scan_res_used > 0) { 1570 struct os_reltime now; 1571 1572 os_get_reltime(&now); 1573 if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1574 wpa_printf(MSG_DEBUG, 1575 "WNM: Try to use recent scan results"); 1576 if (wnm_scan_process(wpa_s, 0) > 0) 1577 return; 1578 wpa_printf(MSG_DEBUG, 1579 "WNM: No match in previous scan results - try a new scan"); 1580 } 1581 } 1582 1583 wnm_set_scan_freqs(wpa_s); 1584 if (wpa_s->wnm_num_neighbor_report == 1) { 1585 os_memcpy(wpa_s->next_scan_bssid, 1586 wpa_s->wnm_neighbor_report_elements[0].bssid, 1587 ETH_ALEN); 1588 wpa_printf(MSG_DEBUG, 1589 "WNM: Scan only for a specific BSSID since there is only a single candidate " 1590 MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 1591 } 1592 wpa_supplicant_req_scan(wpa_s, 0, 0); 1593 } else if (reply) { 1594 enum bss_trans_mgmt_status_code status; 1595 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1596 status = WNM_BSS_TM_ACCEPT; 1597 else { 1598 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1599 status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1600 } 1601 wnm_send_bss_transition_mgmt_resp( 1602 wpa_s, wpa_s->wnm_dialog_token, status, 1603 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1604 } 1605 } 1606 1607 1608 #define BTM_QUERY_MIN_SIZE 4 1609 1610 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 1611 u8 query_reason, 1612 const char *btm_candidates, 1613 int cand_list) 1614 { 1615 struct wpabuf *buf; 1616 int ret; 1617 1618 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 1619 MACSTR " query_reason=%u%s", 1620 MAC2STR(wpa_s->bssid), query_reason, 1621 cand_list ? " candidate list" : ""); 1622 1623 buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE); 1624 if (!buf) 1625 return -1; 1626 1627 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1628 wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY); 1629 wpabuf_put_u8(buf, 1); 1630 wpabuf_put_u8(buf, query_reason); 1631 1632 if (cand_list) 1633 wnm_add_cand_list(wpa_s, &buf); 1634 1635 if (btm_candidates) { 1636 const size_t max_len = 1000; 1637 1638 ret = wpabuf_resize(&buf, max_len); 1639 if (ret < 0) { 1640 wpabuf_free(buf); 1641 return ret; 1642 } 1643 1644 ret = ieee802_11_parse_candidate_list(btm_candidates, 1645 wpabuf_put(buf, 0), 1646 max_len); 1647 if (ret < 0) { 1648 wpabuf_free(buf); 1649 return ret; 1650 } 1651 1652 wpabuf_put(buf, ret); 1653 } 1654 1655 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1656 wpa_s->own_addr, wpa_s->bssid, 1657 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1658 1659 wpabuf_free(buf); 1660 return ret; 1661 } 1662 1663 1664 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1665 const u8 *sa, const u8 *data, 1666 int len) 1667 { 1668 const u8 *pos, *end, *next; 1669 u8 ie, ie_len; 1670 1671 pos = data; 1672 end = data + len; 1673 1674 while (end - pos > 1) { 1675 ie = *pos++; 1676 ie_len = *pos++; 1677 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1678 ie, ie_len); 1679 if (ie_len > end - pos) { 1680 wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1681 "subelement"); 1682 break; 1683 } 1684 next = pos + ie_len; 1685 if (ie_len < 4) { 1686 pos = next; 1687 continue; 1688 } 1689 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1690 WPA_GET_BE24(pos), pos[3]); 1691 1692 #ifdef CONFIG_HS20 1693 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1694 WPA_GET_BE24(pos) == OUI_WFA && 1695 pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1696 /* Subscription Remediation subelement */ 1697 const u8 *ie_end; 1698 u8 url_len; 1699 char *url; 1700 u8 osu_method; 1701 1702 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1703 "subelement"); 1704 ie_end = pos + ie_len; 1705 pos += 4; 1706 url_len = *pos++; 1707 if (url_len == 0) { 1708 wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1709 url = NULL; 1710 osu_method = 1; 1711 } else { 1712 if (url_len + 1 > ie_end - pos) { 1713 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1714 url_len, 1715 (int) (ie_end - pos)); 1716 break; 1717 } 1718 url = os_malloc(url_len + 1); 1719 if (url == NULL) 1720 break; 1721 os_memcpy(url, pos, url_len); 1722 url[url_len] = '\0'; 1723 osu_method = pos[url_len]; 1724 } 1725 hs20_rx_subscription_remediation(wpa_s, url, 1726 osu_method); 1727 os_free(url); 1728 pos = next; 1729 continue; 1730 } 1731 1732 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1733 WPA_GET_BE24(pos) == OUI_WFA && 1734 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1735 const u8 *ie_end; 1736 u8 url_len; 1737 char *url; 1738 u8 code; 1739 u16 reauth_delay; 1740 1741 ie_end = pos + ie_len; 1742 pos += 4; 1743 code = *pos++; 1744 reauth_delay = WPA_GET_LE16(pos); 1745 pos += 2; 1746 url_len = *pos++; 1747 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1748 "Imminent - Reason Code %u " 1749 "Re-Auth Delay %u URL Length %u", 1750 code, reauth_delay, url_len); 1751 if (url_len > ie_end - pos) 1752 break; 1753 url = os_malloc(url_len + 1); 1754 if (url == NULL) 1755 break; 1756 os_memcpy(url, pos, url_len); 1757 url[url_len] = '\0'; 1758 hs20_rx_deauth_imminent_notice(wpa_s, code, 1759 reauth_delay, url); 1760 os_free(url); 1761 pos = next; 1762 continue; 1763 } 1764 1765 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1766 WPA_GET_BE24(pos) == OUI_WFA && 1767 pos[3] == HS20_WNM_T_C_ACCEPTANCE) { 1768 const u8 *ie_end; 1769 u8 url_len; 1770 char *url; 1771 1772 ie_end = pos + ie_len; 1773 pos += 4; 1774 url_len = *pos++; 1775 wpa_printf(MSG_DEBUG, 1776 "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)", 1777 url_len); 1778 if (url_len > ie_end - pos) 1779 break; 1780 url = os_malloc(url_len + 1); 1781 if (!url) 1782 break; 1783 os_memcpy(url, pos, url_len); 1784 url[url_len] = '\0'; 1785 hs20_rx_t_c_acceptance(wpa_s, url); 1786 os_free(url); 1787 pos = next; 1788 continue; 1789 } 1790 #endif /* CONFIG_HS20 */ 1791 1792 pos = next; 1793 } 1794 } 1795 1796 1797 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1798 const u8 *sa, const u8 *frm, int len) 1799 { 1800 const u8 *pos, *end; 1801 u8 dialog_token, type; 1802 1803 /* Dialog Token [1] | Type [1] | Subelements */ 1804 1805 if (len < 2 || sa == NULL) 1806 return; 1807 end = frm + len; 1808 pos = frm; 1809 dialog_token = *pos++; 1810 type = *pos++; 1811 1812 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1813 "(dialog_token %u type %u sa " MACSTR ")", 1814 dialog_token, type, MAC2STR(sa)); 1815 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1816 pos, end - pos); 1817 1818 if (wpa_s->wpa_state != WPA_COMPLETED || 1819 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1820 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1821 "from our AP - ignore it"); 1822 return; 1823 } 1824 1825 switch (type) { 1826 case 1: 1827 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1828 break; 1829 default: 1830 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1831 "WNM-Notification type %u", type); 1832 break; 1833 } 1834 } 1835 1836 1837 static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s, 1838 const u8 *sa, const u8 *frm, 1839 int len) 1840 { 1841 u8 dialog_token, req_info, auto_report, timeout; 1842 1843 if (!wpa_s->conf->coloc_intf_reporting) 1844 return; 1845 1846 /* Dialog Token [1] | Request Info [1] */ 1847 1848 if (len < 2) 1849 return; 1850 dialog_token = frm[0]; 1851 req_info = frm[1]; 1852 auto_report = req_info & 0x03; 1853 timeout = req_info >> 2; 1854 1855 wpa_dbg(wpa_s, MSG_DEBUG, 1856 "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")", 1857 dialog_token, auto_report, timeout, MAC2STR(sa)); 1858 1859 if (dialog_token == 0) 1860 return; /* only nonzero values are used for request */ 1861 1862 if (wpa_s->wpa_state != WPA_COMPLETED || 1863 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1864 wpa_dbg(wpa_s, MSG_DEBUG, 1865 "WNM: Collocated Interference Request frame not from current AP - ignore it"); 1866 return; 1867 } 1868 1869 wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u", 1870 dialog_token, auto_report, timeout); 1871 wpa_s->coloc_intf_dialog_token = dialog_token; 1872 wpa_s->coloc_intf_auto_report = auto_report; 1873 wpa_s->coloc_intf_timeout = timeout; 1874 } 1875 1876 1877 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1878 const struct ieee80211_mgmt *mgmt, size_t len) 1879 { 1880 const u8 *pos, *end; 1881 u8 act; 1882 1883 if (len < IEEE80211_HDRLEN + 2) 1884 return; 1885 1886 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1887 act = *pos++; 1888 end = ((const u8 *) mgmt) + len; 1889 1890 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1891 act, MAC2STR(mgmt->sa)); 1892 if (wpa_s->wpa_state < WPA_ASSOCIATED || 1893 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1894 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1895 "frame"); 1896 return; 1897 } 1898 1899 switch (act) { 1900 case WNM_BSS_TRANS_MGMT_REQ: 1901 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1902 !(mgmt->da[0] & 0x01)); 1903 break; 1904 case WNM_SLEEP_MODE_RESP: 1905 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 1906 break; 1907 case WNM_NOTIFICATION_REQ: 1908 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1909 break; 1910 case WNM_COLLOCATED_INTERFERENCE_REQ: 1911 ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos, 1912 end - pos); 1913 break; 1914 default: 1915 wpa_printf(MSG_ERROR, "WNM: Unknown request"); 1916 break; 1917 } 1918 } 1919 1920 1921 int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, 1922 const struct wpabuf *elems) 1923 { 1924 struct wpabuf *buf; 1925 int ret; 1926 1927 if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems) 1928 return -1; 1929 1930 wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to " 1931 MACSTR " (dialog token %u)", 1932 MAC2STR(wpa_s->bssid), dialog_token); 1933 1934 buf = wpabuf_alloc(3 + wpabuf_len(elems)); 1935 if (!buf) 1936 return -1; 1937 1938 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1939 wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT); 1940 wpabuf_put_u8(buf, dialog_token); 1941 wpabuf_put_buf(buf, elems); 1942 1943 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1944 wpa_s->own_addr, wpa_s->bssid, 1945 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1946 wpabuf_free(buf); 1947 return ret; 1948 } 1949 1950 1951 void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, 1952 struct wpabuf *elems) 1953 { 1954 wpabuf_free(wpa_s->coloc_intf_elems); 1955 if (elems && wpabuf_len(elems) == 0) { 1956 wpabuf_free(elems); 1957 elems = NULL; 1958 } 1959 wpa_s->coloc_intf_elems = elems; 1960 1961 if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems && 1962 wpa_s->coloc_intf_dialog_token && 1963 (wpa_s->coloc_intf_auto_report == 1 || 1964 wpa_s->coloc_intf_auto_report == 3)) { 1965 /* TODO: Check that there has not been less than 1966 * wpa_s->coloc_intf_timeout * 200 TU from the last report. 1967 */ 1968 wnm_send_coloc_intf_report(wpa_s, 1969 wpa_s->coloc_intf_dialog_token, 1970 wpa_s->coloc_intf_elems); 1971 } 1972 } 1973 1974 1975 void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) 1976 { 1977 #ifdef CONFIG_WNM 1978 wpa_s->coloc_intf_dialog_token = 0; 1979 wpa_s->coloc_intf_auto_report = 0; 1980 #endif /* CONFIG_WNM */ 1981 } 1982