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