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