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