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 wpa_dbg(wpa_s, MSG_DEBUG, 1101 "WNM: Transition to BSS " MACSTR 1102 " based on BSS Transition Management Request (old BSSID " 1103 MACSTR " after_new_scan=%d)", 1104 MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); 1105 1106 /* Send the BSS Management Response - Accept */ 1107 if (wpa_s->wnm_reply) { 1108 wpa_s->wnm_reply = 0; 1109 wpa_printf(MSG_DEBUG, 1110 "WNM: Sending successful BSS Transition Management Response"); 1111 wnm_send_bss_transition_mgmt_resp( 1112 wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, 1113 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1114 bss->bssid); 1115 } 1116 1117 if (bss == wpa_s->current_bss) { 1118 wpa_printf(MSG_DEBUG, 1119 "WNM: Already associated with the preferred candidate"); 1120 wnm_deallocate_memory(wpa_s); 1121 return; 1122 } 1123 1124 wpa_s->reassociate = 1; 1125 wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); 1126 wpa_supplicant_connect(wpa_s, bss, ssid); 1127 wnm_deallocate_memory(wpa_s); 1128 } 1129 1130 1131 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 1132 { 1133 struct wpa_bss *bss; 1134 struct wpa_ssid *ssid = wpa_s->current_ssid; 1135 enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1136 enum mbo_transition_reject_reason reason = 1137 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; 1138 1139 if (!wpa_s->wnm_neighbor_report_elements) 1140 return 0; 1141 1142 wpa_dbg(wpa_s, MSG_DEBUG, 1143 "WNM: Process scan results for BSS Transition Management"); 1144 if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 1145 &wpa_s->scan_trigger_time)) { 1146 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 1147 wnm_deallocate_memory(wpa_s); 1148 return 0; 1149 } 1150 1151 if (!wpa_s->current_bss || 1152 os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 1153 ETH_ALEN) != 0) { 1154 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 1155 return 0; 1156 } 1157 1158 /* Compare the Neighbor Report and scan results */ 1159 bss = compare_scan_neighbor_results(wpa_s, 0, &reason); 1160 if (!bss) { 1161 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 1162 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 1163 goto send_bss_resp_fail; 1164 } 1165 1166 /* Associate to the network */ 1167 wnm_bss_tm_connect(wpa_s, bss, ssid, 1); 1168 return 1; 1169 1170 send_bss_resp_fail: 1171 if (!reply_on_fail) 1172 return 0; 1173 1174 /* Send reject response for all the failures */ 1175 1176 if (wpa_s->wnm_reply) { 1177 wpa_s->wnm_reply = 0; 1178 wnm_send_bss_transition_mgmt_resp(wpa_s, 1179 wpa_s->wnm_dialog_token, 1180 status, reason, 0, NULL); 1181 } 1182 wnm_deallocate_memory(wpa_s); 1183 1184 return 0; 1185 } 1186 1187 1188 static int cand_pref_compar(const void *a, const void *b) 1189 { 1190 const struct neighbor_report *aa = a; 1191 const struct neighbor_report *bb = b; 1192 1193 if (!aa->preference_present && !bb->preference_present) 1194 return 0; 1195 if (!aa->preference_present) 1196 return 1; 1197 if (!bb->preference_present) 1198 return -1; 1199 if (bb->preference > aa->preference) 1200 return 1; 1201 if (bb->preference < aa->preference) 1202 return -1; 1203 return 0; 1204 } 1205 1206 1207 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 1208 { 1209 if (!wpa_s->wnm_neighbor_report_elements) 1210 return; 1211 qsort(wpa_s->wnm_neighbor_report_elements, 1212 wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 1213 cand_pref_compar); 1214 } 1215 1216 1217 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 1218 { 1219 unsigned int i; 1220 1221 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 1222 if (!wpa_s->wnm_neighbor_report_elements) 1223 return; 1224 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1225 struct neighbor_report *nei; 1226 1227 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1228 wpa_printf(MSG_DEBUG, "%u: " MACSTR 1229 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 1230 i, MAC2STR(nei->bssid), nei->bssid_info, 1231 nei->regulatory_class, 1232 nei->channel_number, nei->phy_type, 1233 nei->preference_present ? nei->preference : -1, 1234 nei->freq); 1235 } 1236 } 1237 1238 1239 static int chan_supported(struct wpa_supplicant *wpa_s, int freq) 1240 { 1241 unsigned int i; 1242 1243 for (i = 0; i < wpa_s->hw.num_modes; i++) { 1244 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 1245 int j; 1246 1247 for (j = 0; j < mode->num_channels; j++) { 1248 struct hostapd_channel_data *chan; 1249 1250 chan = &mode->channels[j]; 1251 if (chan->freq == freq && 1252 !(chan->flag & HOSTAPD_CHAN_DISABLED)) 1253 return 1; 1254 } 1255 } 1256 1257 return 0; 1258 } 1259 1260 1261 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 1262 { 1263 int *freqs; 1264 int num_freqs = 0; 1265 unsigned int i; 1266 1267 if (!wpa_s->wnm_neighbor_report_elements) 1268 return; 1269 1270 if (wpa_s->hw.modes == NULL) 1271 return; 1272 1273 os_free(wpa_s->next_scan_freqs); 1274 wpa_s->next_scan_freqs = NULL; 1275 1276 freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 1277 if (freqs == NULL) 1278 return; 1279 1280 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1281 struct neighbor_report *nei; 1282 1283 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1284 if (nei->freq <= 0) { 1285 wpa_printf(MSG_DEBUG, 1286 "WNM: Unknown neighbor operating frequency for " 1287 MACSTR " - scan all channels", 1288 MAC2STR(nei->bssid)); 1289 os_free(freqs); 1290 return; 1291 } 1292 if (chan_supported(wpa_s, nei->freq)) 1293 add_freq(freqs, &num_freqs, nei->freq); 1294 } 1295 1296 if (num_freqs == 0) { 1297 os_free(freqs); 1298 return; 1299 } 1300 1301 wpa_printf(MSG_DEBUG, 1302 "WNM: Scan %d frequencies based on transition candidate list", 1303 num_freqs); 1304 wpa_s->next_scan_freqs = freqs; 1305 } 1306 1307 1308 static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) 1309 { 1310 struct wpa_scan_results *scan_res; 1311 struct wpa_bss *bss; 1312 struct wpa_ssid *ssid = wpa_s->current_ssid; 1313 u8 i, found = 0; 1314 size_t j; 1315 1316 wpa_dbg(wpa_s, MSG_DEBUG, 1317 "WNM: Fetch current scan results from the driver for checking transition candidates"); 1318 scan_res = wpa_drv_get_scan_results2(wpa_s); 1319 if (!scan_res) { 1320 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); 1321 return 0; 1322 } 1323 1324 if (scan_res->fetch_time.sec == 0) 1325 os_get_reltime(&scan_res->fetch_time); 1326 1327 filter_scan_res(wpa_s, scan_res); 1328 1329 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1330 struct neighbor_report *nei; 1331 1332 nei = &wpa_s->wnm_neighbor_report_elements[i]; 1333 if (nei->preference_present && nei->preference == 0) 1334 continue; 1335 1336 for (j = 0; j < scan_res->num; j++) { 1337 struct wpa_scan_res *res; 1338 const u8 *ssid_ie; 1339 1340 res = scan_res->res[j]; 1341 if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || 1342 res->age > WNM_SCAN_RESULT_AGE * 1000) 1343 continue; 1344 bss = wpa_s->current_bss; 1345 ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); 1346 if (bss && ssid_ie && ssid_ie[1] && 1347 (bss->ssid_len != ssid_ie[1] || 1348 os_memcmp(bss->ssid, ssid_ie + 2, 1349 bss->ssid_len) != 0)) 1350 continue; /* Skip entries for other ESSs */ 1351 1352 /* Potential candidate found */ 1353 found = 1; 1354 scan_snr(res); 1355 scan_est_throughput(wpa_s, res); 1356 wpa_bss_update_scan_res(wpa_s, res, 1357 &scan_res->fetch_time); 1358 } 1359 } 1360 1361 wpa_scan_results_free(scan_res); 1362 if (!found) { 1363 wpa_dbg(wpa_s, MSG_DEBUG, 1364 "WNM: No transition candidate matches existing scan results"); 1365 return 0; 1366 } 1367 1368 bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); 1369 if (!bss) { 1370 wpa_dbg(wpa_s, MSG_DEBUG, 1371 "WNM: Comparison of scan results against transition candidates did not find matches"); 1372 return 0; 1373 } 1374 1375 /* Associate to the network */ 1376 wnm_bss_tm_connect(wpa_s, bss, ssid, 0); 1377 return 1; 1378 } 1379 1380 1381 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1382 const u8 *pos, const u8 *end, 1383 int reply) 1384 { 1385 unsigned int beacon_int; 1386 u8 valid_int; 1387 #ifdef CONFIG_MBO 1388 const u8 *vendor; 1389 #endif /* CONFIG_MBO */ 1390 1391 if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm) 1392 return; 1393 1394 if (end - pos < 5) 1395 return; 1396 1397 #ifdef CONFIG_MBO 1398 wpa_s->wnm_mbo_trans_reason_present = 0; 1399 wpa_s->wnm_mbo_transition_reason = 0; 1400 #endif /* CONFIG_MBO */ 1401 1402 if (wpa_s->current_bss) 1403 beacon_int = wpa_s->current_bss->beacon_int; 1404 else 1405 beacon_int = 100; /* best guess */ 1406 1407 wpa_s->wnm_dialog_token = pos[0]; 1408 wpa_s->wnm_mode = pos[1]; 1409 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1410 valid_int = pos[4]; 1411 wpa_s->wnm_reply = reply; 1412 1413 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1414 "dialog_token=%u request_mode=0x%x " 1415 "disassoc_timer=%u validity_interval=%u", 1416 wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1417 wpa_s->wnm_dissoc_timer, valid_int); 1418 1419 #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) 1420 if (wpa_s->reject_btm_req_reason) { 1421 wpa_printf(MSG_INFO, 1422 "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", 1423 wpa_s->reject_btm_req_reason); 1424 wnm_send_bss_transition_mgmt_resp( 1425 wpa_s, wpa_s->wnm_dialog_token, 1426 wpa_s->reject_btm_req_reason, 1427 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1428 return; 1429 } 1430 #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ 1431 1432 pos += 5; 1433 1434 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1435 if (end - pos < 12) { 1436 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 1437 return; 1438 } 1439 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1440 pos += 12; /* BSS Termination Duration */ 1441 } 1442 1443 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1444 char url[256]; 1445 1446 if (end - pos < 1 || 1 + pos[0] > end - pos) { 1447 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1448 "Management Request (URL)"); 1449 return; 1450 } 1451 os_memcpy(url, pos + 1, pos[0]); 1452 url[pos[0]] = '\0'; 1453 pos += 1 + pos[0]; 1454 1455 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1456 wpa_sm_pmf_enabled(wpa_s->wpa), 1457 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1458 } 1459 1460 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1461 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 1462 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 1463 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1464 /* TODO: mark current BSS less preferred for 1465 * selection */ 1466 wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1467 wpa_supplicant_req_scan(wpa_s, 0, 0); 1468 } 1469 } 1470 1471 #ifdef CONFIG_MBO 1472 vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 1473 if (vendor) 1474 wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 1475 #endif /* CONFIG_MBO */ 1476 1477 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1478 unsigned int valid_ms; 1479 1480 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1481 wnm_deallocate_memory(wpa_s); 1482 wpa_s->wnm_neighbor_report_elements = os_calloc( 1483 WNM_MAX_NEIGHBOR_REPORT, 1484 sizeof(struct neighbor_report)); 1485 if (wpa_s->wnm_neighbor_report_elements == NULL) 1486 return; 1487 1488 while (end - pos >= 2 && 1489 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 1490 { 1491 u8 tag = *pos++; 1492 u8 len = *pos++; 1493 1494 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 1495 tag); 1496 if (len > end - pos) { 1497 wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 1498 return; 1499 } 1500 if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1501 struct neighbor_report *rep; 1502 rep = &wpa_s->wnm_neighbor_report_elements[ 1503 wpa_s->wnm_num_neighbor_report]; 1504 wnm_parse_neighbor_report(wpa_s, pos, len, rep); 1505 wpa_s->wnm_num_neighbor_report++; 1506 #ifdef CONFIG_MBO 1507 if (wpa_s->wnm_mbo_trans_reason_present && 1508 wpa_s->wnm_num_neighbor_report == 1) { 1509 rep->is_first = 1; 1510 wpa_printf(MSG_DEBUG, 1511 "WNM: First transition candidate is " 1512 MACSTR, MAC2STR(rep->bssid)); 1513 } 1514 #endif /* CONFIG_MBO */ 1515 } 1516 1517 pos += len; 1518 } 1519 1520 if (!wpa_s->wnm_num_neighbor_report) { 1521 wpa_printf(MSG_DEBUG, 1522 "WNM: Candidate list included bit is set, but no candidates found"); 1523 wnm_send_bss_transition_mgmt_resp( 1524 wpa_s, wpa_s->wnm_dialog_token, 1525 WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 1526 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, 1527 NULL); 1528 return; 1529 } 1530 1531 wnm_sort_cand_list(wpa_s); 1532 wnm_dump_cand_list(wpa_s); 1533 valid_ms = valid_int * beacon_int * 128 / 125; 1534 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1535 valid_ms); 1536 os_get_reltime(&wpa_s->wnm_cand_valid_until); 1537 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1538 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1539 wpa_s->wnm_cand_valid_until.sec += 1540 wpa_s->wnm_cand_valid_until.usec / 1000000; 1541 wpa_s->wnm_cand_valid_until.usec %= 1000000; 1542 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1543 1544 /* 1545 * Fetch the latest scan results from the kernel and check for 1546 * candidates based on those results first. This can help in 1547 * finding more up-to-date information should the driver has 1548 * done some internal scanning operations after the last scan 1549 * result update in wpa_supplicant. 1550 */ 1551 if (wnm_fetch_scan_results(wpa_s) > 0) 1552 return; 1553 1554 /* 1555 * Try to use previously received scan results, if they are 1556 * recent enough to use for a connection. 1557 */ 1558 if (wpa_s->last_scan_res_used > 0) { 1559 struct os_reltime now; 1560 1561 os_get_reltime(&now); 1562 if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1563 wpa_printf(MSG_DEBUG, 1564 "WNM: Try to use recent scan results"); 1565 if (wnm_scan_process(wpa_s, 0) > 0) 1566 return; 1567 wpa_printf(MSG_DEBUG, 1568 "WNM: No match in previous scan results - try a new scan"); 1569 } 1570 } 1571 1572 wnm_set_scan_freqs(wpa_s); 1573 if (wpa_s->wnm_num_neighbor_report == 1) { 1574 os_memcpy(wpa_s->next_scan_bssid, 1575 wpa_s->wnm_neighbor_report_elements[0].bssid, 1576 ETH_ALEN); 1577 wpa_printf(MSG_DEBUG, 1578 "WNM: Scan only for a specific BSSID since there is only a single candidate " 1579 MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 1580 } 1581 wpa_supplicant_req_scan(wpa_s, 0, 0); 1582 } else if (reply) { 1583 enum bss_trans_mgmt_status_code status; 1584 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1585 status = WNM_BSS_TM_ACCEPT; 1586 else { 1587 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1588 status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1589 } 1590 wnm_send_bss_transition_mgmt_resp( 1591 wpa_s, wpa_s->wnm_dialog_token, status, 1592 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); 1593 } 1594 } 1595 1596 1597 #define BTM_QUERY_MIN_SIZE 4 1598 1599 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 1600 u8 query_reason, 1601 const char *btm_candidates, 1602 int cand_list) 1603 { 1604 struct wpabuf *buf; 1605 int ret; 1606 1607 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 1608 MACSTR " query_reason=%u%s", 1609 MAC2STR(wpa_s->bssid), query_reason, 1610 cand_list ? " candidate list" : ""); 1611 1612 buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE); 1613 if (!buf) 1614 return -1; 1615 1616 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1617 wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY); 1618 wpabuf_put_u8(buf, 1); 1619 wpabuf_put_u8(buf, query_reason); 1620 1621 if (cand_list) 1622 wnm_add_cand_list(wpa_s, &buf); 1623 1624 if (btm_candidates) { 1625 const size_t max_len = 1000; 1626 1627 ret = wpabuf_resize(&buf, max_len); 1628 if (ret < 0) { 1629 wpabuf_free(buf); 1630 return ret; 1631 } 1632 1633 ret = ieee802_11_parse_candidate_list(btm_candidates, 1634 wpabuf_put(buf, 0), 1635 max_len); 1636 if (ret < 0) { 1637 wpabuf_free(buf); 1638 return ret; 1639 } 1640 1641 wpabuf_put(buf, ret); 1642 } 1643 1644 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1645 wpa_s->own_addr, wpa_s->bssid, 1646 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1647 1648 wpabuf_free(buf); 1649 return ret; 1650 } 1651 1652 1653 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1654 const u8 *sa, const u8 *data, 1655 int len) 1656 { 1657 const u8 *pos, *end, *next; 1658 u8 ie, ie_len; 1659 1660 pos = data; 1661 end = data + len; 1662 1663 while (end - pos > 1) { 1664 ie = *pos++; 1665 ie_len = *pos++; 1666 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1667 ie, ie_len); 1668 if (ie_len > end - pos) { 1669 wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1670 "subelement"); 1671 break; 1672 } 1673 next = pos + ie_len; 1674 if (ie_len < 4) { 1675 pos = next; 1676 continue; 1677 } 1678 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1679 WPA_GET_BE24(pos), pos[3]); 1680 1681 #ifdef CONFIG_HS20 1682 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1683 WPA_GET_BE24(pos) == OUI_WFA && 1684 pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1685 /* Subscription Remediation subelement */ 1686 const u8 *ie_end; 1687 u8 url_len; 1688 char *url; 1689 u8 osu_method; 1690 1691 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1692 "subelement"); 1693 ie_end = pos + ie_len; 1694 pos += 4; 1695 url_len = *pos++; 1696 if (url_len == 0) { 1697 wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1698 url = NULL; 1699 osu_method = 1; 1700 } else { 1701 if (url_len + 1 > ie_end - pos) { 1702 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1703 url_len, 1704 (int) (ie_end - pos)); 1705 break; 1706 } 1707 url = os_malloc(url_len + 1); 1708 if (url == NULL) 1709 break; 1710 os_memcpy(url, pos, url_len); 1711 url[url_len] = '\0'; 1712 osu_method = pos[url_len]; 1713 } 1714 hs20_rx_subscription_remediation(wpa_s, url, 1715 osu_method); 1716 os_free(url); 1717 pos = next; 1718 continue; 1719 } 1720 1721 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1722 WPA_GET_BE24(pos) == OUI_WFA && 1723 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1724 const u8 *ie_end; 1725 u8 url_len; 1726 char *url; 1727 u8 code; 1728 u16 reauth_delay; 1729 1730 ie_end = pos + ie_len; 1731 pos += 4; 1732 code = *pos++; 1733 reauth_delay = WPA_GET_LE16(pos); 1734 pos += 2; 1735 url_len = *pos++; 1736 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1737 "Imminent - Reason Code %u " 1738 "Re-Auth Delay %u URL Length %u", 1739 code, reauth_delay, url_len); 1740 if (url_len > ie_end - pos) 1741 break; 1742 url = os_malloc(url_len + 1); 1743 if (url == NULL) 1744 break; 1745 os_memcpy(url, pos, url_len); 1746 url[url_len] = '\0'; 1747 hs20_rx_deauth_imminent_notice(wpa_s, code, 1748 reauth_delay, url); 1749 os_free(url); 1750 pos = next; 1751 continue; 1752 } 1753 1754 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1755 WPA_GET_BE24(pos) == OUI_WFA && 1756 pos[3] == HS20_WNM_T_C_ACCEPTANCE) { 1757 const u8 *ie_end; 1758 u8 url_len; 1759 char *url; 1760 1761 ie_end = pos + ie_len; 1762 pos += 4; 1763 url_len = *pos++; 1764 wpa_printf(MSG_DEBUG, 1765 "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)", 1766 url_len); 1767 if (url_len > ie_end - pos) 1768 break; 1769 url = os_malloc(url_len + 1); 1770 if (!url) 1771 break; 1772 os_memcpy(url, pos, url_len); 1773 url[url_len] = '\0'; 1774 hs20_rx_t_c_acceptance(wpa_s, url); 1775 os_free(url); 1776 pos = next; 1777 continue; 1778 } 1779 #endif /* CONFIG_HS20 */ 1780 1781 pos = next; 1782 } 1783 } 1784 1785 1786 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1787 const u8 *sa, const u8 *frm, int len) 1788 { 1789 const u8 *pos, *end; 1790 u8 dialog_token, type; 1791 1792 /* Dialog Token [1] | Type [1] | Subelements */ 1793 1794 if (len < 2 || sa == NULL) 1795 return; 1796 end = frm + len; 1797 pos = frm; 1798 dialog_token = *pos++; 1799 type = *pos++; 1800 1801 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1802 "(dialog_token %u type %u sa " MACSTR ")", 1803 dialog_token, type, MAC2STR(sa)); 1804 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1805 pos, end - pos); 1806 1807 if (wpa_s->wpa_state != WPA_COMPLETED || 1808 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1809 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1810 "from our AP - ignore it"); 1811 return; 1812 } 1813 1814 switch (type) { 1815 case 1: 1816 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1817 break; 1818 default: 1819 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1820 "WNM-Notification type %u", type); 1821 break; 1822 } 1823 } 1824 1825 1826 static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s, 1827 const u8 *sa, const u8 *frm, 1828 int len) 1829 { 1830 u8 dialog_token, req_info, auto_report, timeout; 1831 1832 if (!wpa_s->conf->coloc_intf_reporting) 1833 return; 1834 1835 /* Dialog Token [1] | Request Info [1] */ 1836 1837 if (len < 2) 1838 return; 1839 dialog_token = frm[0]; 1840 req_info = frm[1]; 1841 auto_report = req_info & 0x03; 1842 timeout = req_info >> 2; 1843 1844 wpa_dbg(wpa_s, MSG_DEBUG, 1845 "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")", 1846 dialog_token, auto_report, timeout, MAC2STR(sa)); 1847 1848 if (dialog_token == 0) 1849 return; /* only nonzero values are used for request */ 1850 1851 if (wpa_s->wpa_state != WPA_COMPLETED || 1852 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1853 wpa_dbg(wpa_s, MSG_DEBUG, 1854 "WNM: Collocated Interference Request frame not from current AP - ignore it"); 1855 return; 1856 } 1857 1858 wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u", 1859 dialog_token, auto_report, timeout); 1860 wpa_s->coloc_intf_dialog_token = dialog_token; 1861 wpa_s->coloc_intf_auto_report = auto_report; 1862 wpa_s->coloc_intf_timeout = timeout; 1863 } 1864 1865 1866 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1867 const struct ieee80211_mgmt *mgmt, size_t len) 1868 { 1869 const u8 *pos, *end; 1870 u8 act; 1871 1872 if (len < IEEE80211_HDRLEN + 2) 1873 return; 1874 1875 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1876 act = *pos++; 1877 end = ((const u8 *) mgmt) + len; 1878 1879 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1880 act, MAC2STR(mgmt->sa)); 1881 if (wpa_s->wpa_state < WPA_ASSOCIATED || 1882 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1883 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1884 "frame"); 1885 return; 1886 } 1887 1888 switch (act) { 1889 case WNM_BSS_TRANS_MGMT_REQ: 1890 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1891 !(mgmt->da[0] & 0x01)); 1892 break; 1893 case WNM_SLEEP_MODE_RESP: 1894 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 1895 break; 1896 case WNM_NOTIFICATION_REQ: 1897 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1898 break; 1899 case WNM_COLLOCATED_INTERFERENCE_REQ: 1900 ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos, 1901 end - pos); 1902 break; 1903 default: 1904 wpa_printf(MSG_ERROR, "WNM: Unknown request"); 1905 break; 1906 } 1907 } 1908 1909 1910 int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, 1911 const struct wpabuf *elems) 1912 { 1913 struct wpabuf *buf; 1914 int ret; 1915 1916 if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems) 1917 return -1; 1918 1919 wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to " 1920 MACSTR " (dialog token %u)", 1921 MAC2STR(wpa_s->bssid), dialog_token); 1922 1923 buf = wpabuf_alloc(3 + wpabuf_len(elems)); 1924 if (!buf) 1925 return -1; 1926 1927 wpabuf_put_u8(buf, WLAN_ACTION_WNM); 1928 wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT); 1929 wpabuf_put_u8(buf, dialog_token); 1930 wpabuf_put_buf(buf, elems); 1931 1932 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 1933 wpa_s->own_addr, wpa_s->bssid, 1934 wpabuf_head_u8(buf), wpabuf_len(buf), 0); 1935 wpabuf_free(buf); 1936 return ret; 1937 } 1938 1939 1940 void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, 1941 struct wpabuf *elems) 1942 { 1943 wpabuf_free(wpa_s->coloc_intf_elems); 1944 if (elems && wpabuf_len(elems) == 0) { 1945 wpabuf_free(elems); 1946 elems = NULL; 1947 } 1948 wpa_s->coloc_intf_elems = elems; 1949 1950 if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems && 1951 wpa_s->coloc_intf_dialog_token && 1952 (wpa_s->coloc_intf_auto_report == 1 || 1953 wpa_s->coloc_intf_auto_report == 3)) { 1954 /* TODO: Check that there has not been less than 1955 * wpa_s->coloc_intf_timeout * 200 TU from the last report. 1956 */ 1957 wnm_send_coloc_intf_report(wpa_s, 1958 wpa_s->coloc_intf_dialog_token, 1959 wpa_s->coloc_intf_elems); 1960 } 1961 } 1962 1963 1964 void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) 1965 { 1966 #ifdef CONFIG_WNM 1967 wpa_s->coloc_intf_dialog_token = 0; 1968 wpa_s->coloc_intf_auto_report = 0; 1969 #endif /* CONFIG_WNM */ 1970 } 1971