1 /* 2 * hostapd - WNM 3 * Copyright (c) 2011-2014, 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 "utils/eloop.h" 13 #include "common/ieee802_11_defs.h" 14 #include "common/wpa_ctrl.h" 15 #include "common/ocv.h" 16 #include "ap/hostapd.h" 17 #include "ap/sta_info.h" 18 #include "ap/ap_config.h" 19 #include "ap/ap_drv_ops.h" 20 #include "ap/wpa_auth.h" 21 #include "mbo_ap.h" 22 #include "wnm_ap.h" 23 24 #define MAX_TFS_IE_LEN 1024 25 26 27 /* get the TFS IE from driver */ 28 static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr, 29 u8 *buf, u16 *buf_len, enum wnm_oper oper) 30 { 31 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 32 33 return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len); 34 } 35 36 37 /* set the TFS IE to driver */ 38 static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr, 39 u8 *buf, u16 *buf_len, enum wnm_oper oper) 40 { 41 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 42 43 return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len); 44 } 45 46 47 static const u8 * wnm_ap_get_own_addr(struct hostapd_data *hapd, 48 struct sta_info *sta) 49 { 50 const u8 *own_addr = hapd->own_addr; 51 52 #ifdef CONFIG_IEEE80211BE 53 if (hapd->conf->mld_ap && (!sta || ap_sta_is_mld(hapd, sta))) 54 own_addr = hapd->mld->mld_addr; 55 #endif /* CONFIG_IEEE80211BE */ 56 57 return own_addr; 58 } 59 60 61 /* MLME-SLEEPMODE.response */ 62 static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 63 const u8 *addr, u8 dialog_token, 64 u8 action_type, u16 intval) 65 { 66 struct ieee80211_mgmt *mgmt; 67 int res; 68 size_t len; 69 size_t gtk_elem_len = 0; 70 size_t igtk_elem_len = 0; 71 size_t bigtk_elem_len = 0; 72 struct wnm_sleep_element wnmsleep_ie; 73 u8 *wnmtfs_ie, *oci_ie; 74 u8 wnmsleep_ie_len, oci_ie_len; 75 u16 wnmtfs_ie_len; 76 u8 *pos; 77 struct sta_info *sta; 78 enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ? 79 WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE; 80 const u8 *own_addr; 81 82 sta = ap_get_sta(hapd, addr); 83 if (sta == NULL) { 84 wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 85 return -EINVAL; 86 } 87 88 /* WNM-Sleep Mode IE */ 89 os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element)); 90 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 91 wnmsleep_ie.eid = WLAN_EID_WNMSLEEP; 92 wnmsleep_ie.len = wnmsleep_ie_len - 2; 93 wnmsleep_ie.action_type = action_type; 94 wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT; 95 wnmsleep_ie.intval = host_to_le16(intval); 96 97 /* TFS IE(s) */ 98 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 99 if (wnmtfs_ie == NULL) 100 return -1; 101 if (ieee80211_11_get_tfs_ie(hapd, addr, 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 oci_ie = NULL; 109 oci_ie_len = 0; 110 #ifdef CONFIG_OCV 111 if (action_type == WNM_SLEEP_MODE_EXIT && 112 wpa_auth_uses_ocv(sta->wpa_sm)) { 113 struct wpa_channel_info ci; 114 115 if (hostapd_drv_channel_info(hapd, &ci) != 0) { 116 wpa_printf(MSG_WARNING, 117 "Failed to get channel info for OCI element in WNM-Sleep Mode frame"); 118 os_free(wnmtfs_ie); 119 return -1; 120 } 121 #ifdef CONFIG_TESTING_OPTIONS 122 if (hapd->conf->oci_freq_override_wnm_sleep) { 123 wpa_printf(MSG_INFO, 124 "TEST: Override OCI frequency %d -> %u MHz", 125 ci.frequency, 126 hapd->conf->oci_freq_override_wnm_sleep); 127 ci.frequency = hapd->conf->oci_freq_override_wnm_sleep; 128 } 129 #endif /* CONFIG_TESTING_OPTIONS */ 130 131 oci_ie_len = OCV_OCI_EXTENDED_LEN; 132 oci_ie = os_zalloc(oci_ie_len); 133 if (!oci_ie) { 134 wpa_printf(MSG_WARNING, 135 "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame"); 136 os_free(wnmtfs_ie); 137 return -1; 138 } 139 140 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) { 141 os_free(wnmtfs_ie); 142 os_free(oci_ie); 143 return -1; 144 } 145 } 146 #endif /* CONFIG_OCV */ 147 148 #define MAX_GTK_SUBELEM_LEN 45 149 #define MAX_IGTK_SUBELEM_LEN 26 150 #define MAX_BIGTK_SUBELEM_LEN 26 151 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + 152 MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN + 153 MAX_BIGTK_SUBELEM_LEN + 154 oci_ie_len); 155 if (mgmt == NULL) { 156 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 157 "WNM-Sleep Response action frame"); 158 res = -1; 159 goto fail; 160 } 161 162 own_addr = wnm_ap_get_own_addr(hapd, sta); 163 164 os_memcpy(mgmt->da, addr, ETH_ALEN); 165 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 166 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 167 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 168 WLAN_FC_STYPE_ACTION); 169 mgmt->u.action.category = WLAN_ACTION_WNM; 170 mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP; 171 mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token; 172 pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable; 173 /* add key data if MFP is enabled */ 174 if (!wpa_auth_uses_mfp(sta->wpa_sm) || 175 hapd->conf->wnm_sleep_mode_no_keys || 176 action_type != WNM_SLEEP_MODE_EXIT) { 177 mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0; 178 } else { 179 gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos); 180 pos += gtk_elem_len; 181 wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d", 182 (int) gtk_elem_len); 183 res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos); 184 if (res < 0) 185 goto fail; 186 igtk_elem_len = res; 187 pos += igtk_elem_len; 188 wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d", 189 (int) igtk_elem_len); 190 if (hapd->conf->beacon_prot && 191 (hapd->iface->drv_flags & 192 WPA_DRIVER_FLAGS_BEACON_PROTECTION)) { 193 res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos); 194 if (res < 0) 195 goto fail; 196 bigtk_elem_len = res; 197 pos += bigtk_elem_len; 198 wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d", 199 (int) bigtk_elem_len); 200 } 201 202 WPA_PUT_LE16((u8 *) 203 &mgmt->u.action.u.wnm_sleep_resp.keydata_len, 204 gtk_elem_len + igtk_elem_len + bigtk_elem_len); 205 } 206 os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len); 207 /* copy TFS IE here */ 208 pos += wnmsleep_ie_len; 209 if (wnmtfs_ie) { 210 os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len); 211 pos += wnmtfs_ie_len; 212 } 213 #ifdef CONFIG_OCV 214 /* copy OCV OCI here */ 215 if (oci_ie_len > 0) 216 os_memcpy(pos, oci_ie, oci_ie_len); 217 #endif /* CONFIG_OCV */ 218 219 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len + 220 igtk_elem_len + bigtk_elem_len + 221 wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len; 222 223 /* In driver, response frame should be forced to sent when STA is in 224 * PS mode */ 225 res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 226 mgmt->da, &mgmt->u.action.category, len); 227 228 if (!res) { 229 wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response " 230 "frame"); 231 232 /* when entering wnmsleep 233 * 1. pause the node in driver 234 * 2. mark the node so that AP won't update GTK/IGTK/BIGTK 235 * during WNM Sleep 236 */ 237 if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && 238 wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { 239 sta->flags |= WLAN_STA_WNM_SLEEP_MODE; 240 hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM, 241 addr, NULL, NULL); 242 wpa_set_wnmsleep(sta->wpa_sm, 1); 243 } 244 /* when exiting wnmsleep 245 * 1. unmark the node 246 * 2. start GTK/IGTK/BIGTK update if MFP is not used 247 * 3. unpause the node in driver 248 */ 249 if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT || 250 wnmsleep_ie.status == 251 WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) && 252 wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) { 253 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 254 wpa_set_wnmsleep(sta->wpa_sm, 0); 255 hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM, 256 addr, NULL, NULL); 257 if (!wpa_auth_uses_mfp(sta->wpa_sm) || 258 hapd->conf->wnm_sleep_mode_no_keys) 259 wpa_wnmsleep_rekey_gtk(sta->wpa_sm); 260 } 261 } else 262 wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame"); 263 264 #undef MAX_GTK_SUBELEM_LEN 265 #undef MAX_IGTK_SUBELEM_LEN 266 #undef MAX_BIGTK_SUBELEM_LEN 267 fail: 268 os_free(wnmtfs_ie); 269 os_free(oci_ie); 270 os_free(mgmt); 271 return res; 272 } 273 274 275 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, 276 const u8 *addr, const u8 *frm, int len) 277 { 278 /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */ 279 const u8 *pos = frm; 280 u8 dialog_token; 281 struct wnm_sleep_element *wnmsleep_ie = NULL; 282 /* multiple TFS Req IE (assuming consecutive) */ 283 u8 *tfsreq_ie_start = NULL; 284 u8 *tfsreq_ie_end = NULL; 285 u16 tfsreq_ie_len = 0; 286 #ifdef CONFIG_OCV 287 struct sta_info *sta; 288 const u8 *oci_ie = NULL; 289 u8 oci_ie_len = 0; 290 #endif /* CONFIG_OCV */ 291 292 if (!hapd->conf->wnm_sleep_mode) { 293 wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from " 294 MACSTR " since WNM-Sleep Mode is disabled", 295 MAC2STR(addr)); 296 return; 297 } 298 299 if (len < 1) { 300 wpa_printf(MSG_DEBUG, 301 "WNM: Ignore too short WNM-Sleep Mode Request from " 302 MACSTR, MAC2STR(addr)); 303 return; 304 } 305 306 dialog_token = *pos++; 307 while (pos + 1 < frm + len) { 308 u8 ie_len = pos[1]; 309 if (pos + 2 + ie_len > frm + len) 310 break; 311 if (*pos == WLAN_EID_WNMSLEEP && 312 ie_len >= (int) sizeof(*wnmsleep_ie) - 2) 313 wnmsleep_ie = (struct wnm_sleep_element *) pos; 314 else if (*pos == WLAN_EID_TFS_REQ) { 315 if (!tfsreq_ie_start) 316 tfsreq_ie_start = (u8 *) pos; 317 tfsreq_ie_end = (u8 *) pos; 318 #ifdef CONFIG_OCV 319 } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 && 320 pos[2] == WLAN_EID_EXT_OCV_OCI) { 321 oci_ie = pos + 3; 322 oci_ie_len = ie_len - 1; 323 #endif /* CONFIG_OCV */ 324 } else 325 wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized", 326 *pos); 327 pos += ie_len + 2; 328 } 329 330 if (!wnmsleep_ie) { 331 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 332 return; 333 } 334 335 #ifdef CONFIG_OCV 336 sta = ap_get_sta(hapd, addr); 337 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT && 338 sta && wpa_auth_uses_ocv(sta->wpa_sm)) { 339 struct wpa_channel_info ci; 340 341 if (hostapd_drv_channel_info(hapd, &ci) != 0) { 342 wpa_printf(MSG_WARNING, 343 "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame"); 344 return; 345 } 346 347 if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci, 348 channel_width_to_int(ci.chanwidth), 349 ci.seg1_idx) != OCI_SUCCESS) { 350 wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s", 351 ocv_errorstr); 352 return; 353 } 354 } 355 #endif /* CONFIG_OCV */ 356 357 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER && 358 tfsreq_ie_start && tfsreq_ie_end && 359 tfsreq_ie_end - tfsreq_ie_start >= 0) { 360 tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) - 361 tfsreq_ie_start; 362 wpa_printf(MSG_DEBUG, "TFS Req IE(s) found"); 363 /* pass the TFS Req IE(s) to driver for processing */ 364 if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, 365 &tfsreq_ie_len, 366 WNM_SLEEP_TFS_REQ_IE_SET)) 367 wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE"); 368 } 369 370 ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token, 371 wnmsleep_ie->action_type, 372 le_to_host16(wnmsleep_ie->intval)); 373 374 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 375 /* clear the tfs after sending the resp frame */ 376 ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, 377 &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL); 378 } 379 } 380 381 382 static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, 383 const u8 *addr, 384 u8 dialog_token) 385 { 386 struct ieee80211_mgmt *mgmt; 387 const u8 *own_addr; 388 struct sta_info *sta; 389 size_t len; 390 u8 *pos; 391 int res; 392 393 mgmt = os_zalloc(sizeof(*mgmt)); 394 if (mgmt == NULL) 395 return -1; 396 397 sta = ap_get_sta(hapd, addr); 398 own_addr = wnm_ap_get_own_addr(hapd, sta); 399 400 os_memcpy(mgmt->da, addr, ETH_ALEN); 401 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 402 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 403 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 404 WLAN_FC_STYPE_ACTION); 405 mgmt->u.action.category = WLAN_ACTION_WNM; 406 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 407 mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; 408 mgmt->u.action.u.bss_tm_req.req_mode = 0; 409 mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); 410 mgmt->u.action.u.bss_tm_req.validity_interval = 1; 411 pos = mgmt->u.action.u.bss_tm_req.variable; 412 413 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " 414 MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " 415 "validity_interval=%u", 416 MAC2STR(addr), dialog_token, 417 mgmt->u.action.u.bss_tm_req.req_mode, 418 le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer), 419 mgmt->u.action.u.bss_tm_req.validity_interval); 420 421 len = pos - &mgmt->u.action.category; 422 res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 423 mgmt->da, &mgmt->u.action.category, len); 424 os_free(mgmt); 425 return res; 426 } 427 428 429 static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, 430 const u8 *addr, const u8 *frm, 431 size_t len) 432 { 433 u8 dialog_token, reason; 434 const u8 *pos, *end; 435 int enabled = hapd->conf->bss_transition; 436 char *hex = NULL; 437 size_t hex_len; 438 439 #ifdef CONFIG_MBO 440 if (hapd->conf->mbo_enabled) 441 enabled = 1; 442 #endif /* CONFIG_MBO */ 443 if (!enabled) { 444 wpa_printf(MSG_DEBUG, 445 "Ignore BSS Transition Management Query from " 446 MACSTR 447 " since BSS Transition Management is disabled", 448 MAC2STR(addr)); 449 return; 450 } 451 452 if (len < 2) { 453 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from " 454 MACSTR, MAC2STR(addr)); 455 return; 456 } 457 458 pos = frm; 459 end = pos + len; 460 dialog_token = *pos++; 461 reason = *pos++; 462 463 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from " 464 MACSTR " dialog_token=%u reason=%u", 465 MAC2STR(addr), dialog_token, reason); 466 467 wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", 468 pos, end - pos); 469 470 hex_len = 2 * (end - pos) + 1; 471 if (hex_len > 1) { 472 hex = os_malloc(hex_len); 473 if (hex) 474 wpa_snprintf_hex(hex, hex_len, pos, end - pos); 475 } 476 wpa_msg(hapd->msg_ctx, MSG_INFO, 477 BSS_TM_QUERY MACSTR " reason=%u%s%s", 478 MAC2STR(addr), reason, hex ? " neighbor=" : "", hex); 479 os_free(hex); 480 481 ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); 482 } 483 484 485 void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx) 486 { 487 struct hostapd_data *hapd = eloop_ctx; 488 struct sta_info *sta = timeout_ctx; 489 490 if (sta->agreed_to_steer) { 491 wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR, 492 hapd->conf->iface, MAC2STR(sta->addr)); 493 sta->agreed_to_steer = 0; 494 } 495 } 496 497 498 static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, 499 const u8 *addr, const u8 *frm, 500 size_t len) 501 { 502 u8 dialog_token, status_code, bss_termination_delay; 503 const u8 *pos, *end; 504 int enabled = hapd->conf->bss_transition; 505 struct sta_info *sta; 506 507 #ifdef CONFIG_MBO 508 if (hapd->conf->mbo_enabled) 509 enabled = 1; 510 #endif /* CONFIG_MBO */ 511 if (!enabled) { 512 wpa_printf(MSG_DEBUG, 513 "Ignore BSS Transition Management Response from " 514 MACSTR 515 " since BSS Transition Management is disabled", 516 MAC2STR(addr)); 517 return; 518 } 519 520 if (len < 3) { 521 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from " 522 MACSTR, MAC2STR(addr)); 523 return; 524 } 525 526 pos = frm; 527 end = pos + len; 528 dialog_token = *pos++; 529 status_code = *pos++; 530 bss_termination_delay = *pos++; 531 532 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from " 533 MACSTR " dialog_token=%u status_code=%u " 534 "bss_termination_delay=%u", MAC2STR(addr), dialog_token, 535 status_code, bss_termination_delay); 536 537 sta = ap_get_sta(hapd, addr); 538 if (!sta) { 539 wpa_printf(MSG_DEBUG, "Station " MACSTR 540 " not found for received BSS TM Response", 541 MAC2STR(addr)); 542 return; 543 } 544 545 if (status_code == WNM_BSS_TM_ACCEPT) { 546 if (end - pos < ETH_ALEN) { 547 wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); 548 return; 549 } 550 sta->agreed_to_steer = 1; 551 eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); 552 eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer, 553 hapd, sta); 554 wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR, 555 MAC2STR(pos)); 556 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR 557 " status_code=%u bss_termination_delay=%u target_bssid=" 558 MACSTR, 559 MAC2STR(addr), status_code, bss_termination_delay, 560 MAC2STR(pos)); 561 pos += ETH_ALEN; 562 } else { 563 sta->agreed_to_steer = 0; 564 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR 565 " status_code=%u bss_termination_delay=%u", 566 MAC2STR(addr), status_code, bss_termination_delay); 567 } 568 569 wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", 570 pos, end - pos); 571 } 572 573 574 static void wnm_beacon_protection_failure(struct hostapd_data *hapd, 575 const u8 *addr) 576 { 577 struct sta_info *sta; 578 579 if (!hapd->conf->beacon_prot || 580 !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION)) 581 return; 582 583 sta = ap_get_sta(hapd, addr); 584 if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { 585 wpa_printf(MSG_DEBUG, "Station " MACSTR 586 " not found for received WNM-Notification Request", 587 MAC2STR(addr)); 588 return; 589 } 590 591 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 592 HOSTAPD_LEVEL_INFO, 593 "Beacon protection failure reported"); 594 wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter=" 595 MACSTR, MAC2STR(addr)); 596 } 597 598 599 static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd, 600 const u8 *addr, const u8 *buf, 601 size_t len) 602 { 603 u8 dialog_token, type; 604 605 if (len < 2) 606 return; 607 dialog_token = *buf++; 608 type = *buf++; 609 len -= 2; 610 611 wpa_printf(MSG_DEBUG, 612 "WNM: Received WNM Notification Request frame from " 613 MACSTR " (dialog_token=%u type=%u)", 614 MAC2STR(addr), dialog_token, type); 615 wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements", 616 buf, len); 617 switch (type) { 618 case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE: 619 wnm_beacon_protection_failure(hapd, addr); 620 break; 621 case WNM_NOTIF_TYPE_VENDOR_SPECIFIC: 622 mbo_ap_wnm_notification_req(hapd, addr, buf, len); 623 break; 624 } 625 } 626 627 628 static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd, 629 const u8 *addr, const u8 *buf, 630 size_t len) 631 { 632 u8 dialog_token; 633 char *hex; 634 size_t hex_len; 635 636 if (!hapd->conf->coloc_intf_reporting) { 637 wpa_printf(MSG_DEBUG, 638 "WNM: Ignore unexpected Collocated Interference Report from " 639 MACSTR, MAC2STR(addr)); 640 return; 641 } 642 643 if (len < 1) { 644 wpa_printf(MSG_DEBUG, 645 "WNM: Ignore too short Collocated Interference Report from " 646 MACSTR, MAC2STR(addr)); 647 return; 648 } 649 dialog_token = *buf++; 650 len--; 651 652 wpa_printf(MSG_DEBUG, 653 "WNM: Received Collocated Interference Report frame from " 654 MACSTR " (dialog_token=%u)", 655 MAC2STR(addr), dialog_token); 656 wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements", 657 buf, len); 658 659 hex_len = 2 * len + 1; 660 hex = os_malloc(hex_len); 661 if (!hex) 662 return; 663 wpa_snprintf_hex(hex, hex_len, buf, len); 664 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s", 665 MAC2STR(addr), dialog_token, hex); 666 os_free(hex); 667 } 668 669 670 671 static const char * wnm_event_type2str(enum wnm_event_report_type wtype) 672 { 673 #define W2S(wtype) case WNM_EVENT_TYPE_ ## wtype: return #wtype; 674 switch (wtype) { 675 W2S(TRANSITION) 676 W2S(RSNA) 677 W2S(P2P_LINK) 678 W2S(WNM_LOG) 679 W2S(BSS_COLOR_COLLISION) 680 W2S(BSS_COLOR_IN_USE) 681 } 682 return "UNKNOWN"; 683 #undef W2S 684 } 685 686 687 static void ieee802_11_rx_wnm_event_report(struct hostapd_data *hapd, 688 const u8 *addr, const u8 *buf, 689 size_t len) 690 { 691 struct sta_info *sta; 692 u8 dialog_token; 693 struct wnm_event_report_element *report_ie; 694 const u8 *pos = buf, *end = buf + len; 695 const size_t fixed_field_len = 3; /* Event Token/Type/Report Status */ 696 #ifdef CONFIG_IEEE80211AX 697 const size_t tsf_len = 8; 698 u8 color; 699 u64 bitmap; 700 #endif /* CONFIG_IEEE80211AX */ 701 702 if (end - pos < 1 + 2) { 703 wpa_printf(MSG_DEBUG, 704 "WNM: Ignore too short WNM Event Report frame from " 705 MACSTR, MAC2STR(addr)); 706 return; 707 } 708 709 dialog_token = *pos++; 710 report_ie = (struct wnm_event_report_element *) pos; 711 712 if (end - pos < 2 + report_ie->len || 713 report_ie->len < fixed_field_len) { 714 wpa_printf(MSG_DEBUG, 715 "WNM: Ignore truncated WNM Event Report frame from " 716 MACSTR, MAC2STR(addr)); 717 return; 718 } 719 720 if (report_ie->eid != WLAN_EID_EVENT_REPORT || 721 report_ie->status != WNM_STATUS_SUCCESSFUL) 722 return; 723 724 wpa_printf(MSG_DEBUG, "WNM: Received WNM Event Report frame from " 725 MACSTR " dialog_token=%u event_token=%u type=%d (%s)", 726 MAC2STR(addr), dialog_token, report_ie->token, 727 report_ie->type, wnm_event_type2str(report_ie->type)); 728 729 pos += 2 + fixed_field_len; 730 wpa_hexdump(MSG_MSGDUMP, "WNM: Event Report", pos, end - pos); 731 732 sta = ap_get_sta(hapd, addr); 733 if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { 734 wpa_printf(MSG_DEBUG, "Station " MACSTR 735 " not found for received WNM Event Report", 736 MAC2STR(addr)); 737 return; 738 } 739 740 switch (report_ie->type) { 741 #ifdef CONFIG_IEEE80211AX 742 case WNM_EVENT_TYPE_BSS_COLOR_COLLISION: 743 if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) 744 return; 745 if (report_ie->len < 746 fixed_field_len + tsf_len + 8) { 747 wpa_printf(MSG_DEBUG, 748 "WNM: Too short BSS color collision event report from " 749 MACSTR, MAC2STR(addr)); 750 return; 751 } 752 bitmap = WPA_GET_LE64(report_ie->u.bss_color_collision.color_bitmap); 753 wpa_printf(MSG_DEBUG, 754 "WNM: BSS color collision bitmap 0x%llx reported by " 755 MACSTR, (unsigned long long) bitmap, MAC2STR(addr)); 756 hostapd_switch_color(hapd->iface->bss[0], bitmap); 757 break; 758 case WNM_EVENT_TYPE_BSS_COLOR_IN_USE: 759 if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) 760 return; 761 if (report_ie->len < fixed_field_len + tsf_len + 1) { 762 wpa_printf(MSG_DEBUG, 763 "WNM: Too short BSS color in use event report from " 764 MACSTR, MAC2STR(addr)); 765 return; 766 } 767 color = report_ie->u.bss_color_in_use.color; 768 if (color > 63) { 769 wpa_printf(MSG_DEBUG, 770 "WNM: Invalid BSS color %u report from " 771 MACSTR, color, MAC2STR(addr)); 772 return; 773 } 774 if (color == 0) { 775 wpa_printf(MSG_DEBUG, 776 "WNM: BSS color use report canceled by " 777 MACSTR, MAC2STR(addr)); 778 /* TODO: Clear stored color from the collision bitmap 779 * if there are no other users for it. */ 780 return; 781 } 782 wpa_printf(MSG_DEBUG, "WNM: BSS color %u use report by " 783 MACSTR, color, MAC2STR(addr)); 784 hapd->color_collision_bitmap |= 1ULL << color; 785 break; 786 #endif /* CONFIG_IEEE80211AX */ 787 default: 788 wpa_printf(MSG_DEBUG, 789 "WNM Event Report type=%d (%s) not supported", 790 report_ie->type, 791 wnm_event_type2str(report_ie->type)); 792 break; 793 } 794 } 795 796 797 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, 798 const struct ieee80211_mgmt *mgmt, size_t len) 799 { 800 u8 action; 801 const u8 *payload; 802 size_t plen; 803 804 if (len < IEEE80211_HDRLEN + 2) 805 return -1; 806 807 payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 808 action = *payload++; 809 plen = len - IEEE80211_HDRLEN - 2; 810 811 switch (action) { 812 case WNM_EVENT_REPORT: 813 ieee802_11_rx_wnm_event_report(hapd, mgmt->sa, payload, 814 plen); 815 return 0; 816 case WNM_BSS_TRANS_MGMT_QUERY: 817 ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, 818 plen); 819 return 0; 820 case WNM_BSS_TRANS_MGMT_RESP: 821 ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, 822 plen); 823 return 0; 824 case WNM_SLEEP_MODE_REQ: 825 ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen); 826 return 0; 827 case WNM_NOTIFICATION_REQ: 828 ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload, 829 plen); 830 return 0; 831 case WNM_COLLOCATED_INTERFERENCE_REPORT: 832 ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload, 833 plen); 834 return 0; 835 } 836 837 wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, 838 action, MAC2STR(mgmt->sa)); 839 return -1; 840 } 841 842 843 int wnm_send_disassoc_imminent(struct hostapd_data *hapd, 844 struct sta_info *sta, int disassoc_timer) 845 { 846 u8 buf[1000], *pos; 847 struct ieee80211_mgmt *mgmt; 848 const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); 849 850 os_memset(buf, 0, sizeof(buf)); 851 mgmt = (struct ieee80211_mgmt *) buf; 852 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 853 WLAN_FC_STYPE_ACTION); 854 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 855 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 856 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 857 mgmt->u.action.category = WLAN_ACTION_WNM; 858 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 859 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 860 mgmt->u.action.u.bss_tm_req.req_mode = 861 WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 862 mgmt->u.action.u.bss_tm_req.disassoc_timer = 863 host_to_le16(disassoc_timer); 864 mgmt->u.action.u.bss_tm_req.validity_interval = 0; 865 866 pos = mgmt->u.action.u.bss_tm_req.variable; 867 868 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " 869 MACSTR, disassoc_timer, MAC2STR(sta->addr)); 870 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { 871 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 872 "Management Request frame"); 873 return -1; 874 } 875 876 return 0; 877 } 878 879 880 static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta, 881 int disassoc_timer) 882 { 883 int timeout, beacon_int; 884 885 /* 886 * Prevent STA from reconnecting using cached PMKSA to force 887 * full authentication with the authentication server (which may 888 * decide to reject the connection), 889 */ 890 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 891 892 beacon_int = hapd->iconf->beacon_int; 893 if (beacon_int < 1) 894 beacon_int = 100; /* best guess */ 895 /* Calculate timeout in ms based on beacon_int in TU */ 896 timeout = disassoc_timer * beacon_int * 128 / 125; 897 wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR 898 " set to %d ms", MAC2STR(sta->addr), timeout); 899 900 sta->timeout_next = STA_DISASSOC_FROM_CLI; 901 eloop_cancel_timeout(ap_handle_timer, hapd, sta); 902 eloop_register_timeout(timeout / 1000, 903 timeout % 1000 * 1000, 904 ap_handle_timer, hapd, sta); 905 } 906 907 908 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, 909 struct sta_info *sta, const char *url, 910 int disassoc_timer) 911 { 912 u8 buf[1000], *pos; 913 struct ieee80211_mgmt *mgmt; 914 size_t url_len; 915 const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); 916 917 os_memset(buf, 0, sizeof(buf)); 918 mgmt = (struct ieee80211_mgmt *) buf; 919 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 920 WLAN_FC_STYPE_ACTION); 921 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 922 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 923 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 924 mgmt->u.action.category = WLAN_ACTION_WNM; 925 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 926 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 927 mgmt->u.action.u.bss_tm_req.req_mode = 928 WNM_BSS_TM_REQ_DISASSOC_IMMINENT | 929 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 930 mgmt->u.action.u.bss_tm_req.disassoc_timer = 931 host_to_le16(disassoc_timer); 932 mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; 933 934 pos = mgmt->u.action.u.bss_tm_req.variable; 935 936 /* Session Information URL */ 937 url_len = os_strlen(url); 938 if (url_len > 255) 939 return -1; 940 *pos++ = url_len; 941 os_memcpy(pos, url, url_len); 942 pos += url_len; 943 944 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { 945 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 946 "Management Request frame"); 947 return -1; 948 } 949 950 if (disassoc_timer) { 951 /* send disassociation frame after time-out */ 952 set_disassoc_timer(hapd, sta, disassoc_timer); 953 } 954 955 return 0; 956 } 957 958 959 int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, 960 u8 req_mode, int disassoc_timer, u8 valid_int, 961 const u8 *bss_term_dur, u8 dialog_token, 962 const char *url, const u8 *nei_rep, size_t nei_rep_len, 963 const u8 *mbo_attrs, size_t mbo_len) 964 { 965 u8 *buf, *pos; 966 struct ieee80211_mgmt *mgmt; 967 size_t url_len; 968 const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); 969 970 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " 971 MACSTR 972 " req_mode=0x%x disassoc_timer=%d valid_int=0x%x dialog_token=%u", 973 MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int, 974 dialog_token); 975 buf = os_zalloc(1000 + nei_rep_len + mbo_len); 976 if (buf == NULL) 977 return -1; 978 mgmt = (struct ieee80211_mgmt *) buf; 979 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 980 WLAN_FC_STYPE_ACTION); 981 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 982 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 983 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 984 mgmt->u.action.category = WLAN_ACTION_WNM; 985 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 986 mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; 987 mgmt->u.action.u.bss_tm_req.req_mode = req_mode; 988 mgmt->u.action.u.bss_tm_req.disassoc_timer = 989 host_to_le16(disassoc_timer); 990 mgmt->u.action.u.bss_tm_req.validity_interval = valid_int; 991 992 pos = mgmt->u.action.u.bss_tm_req.variable; 993 994 if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) && 995 bss_term_dur) { 996 os_memcpy(pos, bss_term_dur, 12); 997 pos += 12; 998 } 999 1000 if (url) { 1001 /* Session Information URL */ 1002 url_len = os_strlen(url); 1003 if (url_len > 255) { 1004 os_free(buf); 1005 return -1; 1006 } 1007 1008 *pos++ = url_len; 1009 os_memcpy(pos, url, url_len); 1010 pos += url_len; 1011 } 1012 1013 if (nei_rep) { 1014 os_memcpy(pos, nei_rep, nei_rep_len); 1015 pos += nei_rep_len; 1016 } 1017 1018 if (mbo_len > 0) { 1019 pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs, 1020 mbo_len); 1021 } 1022 1023 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { 1024 wpa_printf(MSG_DEBUG, 1025 "Failed to send BSS Transition Management Request frame"); 1026 os_free(buf); 1027 return -1; 1028 } 1029 os_free(buf); 1030 1031 if (disassoc_timer) { 1032 #ifdef CONFIG_IEEE80211BE 1033 if (ap_sta_is_mld(hapd, sta)) { 1034 int i; 1035 unsigned int links = 0; 1036 1037 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { 1038 if (sta->mld_info.links[i].valid) 1039 links++; 1040 } 1041 1042 if (links > 1) { 1043 wpa_printf(MSG_DEBUG, 1044 "WNM: Only terminating one link - other links remains associated for " 1045 MACSTR, 1046 MAC2STR(sta->mld_info.common_info.mld_addr)); 1047 return 0; 1048 } 1049 } 1050 #endif /* CONFIG_IEEE80211BE */ 1051 1052 /* send disassociation frame after time-out */ 1053 set_disassoc_timer(hapd, sta, disassoc_timer); 1054 } 1055 1056 return 0; 1057 } 1058 1059 1060 int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, 1061 unsigned int auto_report, unsigned int timeout) 1062 { 1063 u8 buf[100], *pos; 1064 struct ieee80211_mgmt *mgmt; 1065 u8 dialog_token = 1; 1066 const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); 1067 1068 if (auto_report > 3 || timeout > 63) 1069 return -1; 1070 os_memset(buf, 0, sizeof(buf)); 1071 mgmt = (struct ieee80211_mgmt *) buf; 1072 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1073 WLAN_FC_STYPE_ACTION); 1074 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 1075 os_memcpy(mgmt->sa, own_addr, ETH_ALEN); 1076 os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); 1077 mgmt->u.action.category = WLAN_ACTION_WNM; 1078 mgmt->u.action.u.coloc_intf_req.action = 1079 WNM_COLLOCATED_INTERFERENCE_REQ; 1080 mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token; 1081 mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2); 1082 pos = &mgmt->u.action.u.coloc_intf_req.req_info; 1083 pos++; 1084 1085 wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to " 1086 MACSTR " (dialog_token=%u auto_report=%u timeout=%u)", 1087 MAC2STR(sta->addr), dialog_token, auto_report, timeout); 1088 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { 1089 wpa_printf(MSG_DEBUG, 1090 "WNM: Failed to send Collocated Interference Request frame"); 1091 return -1; 1092 } 1093 1094 return 0; 1095 } 1096