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 /* MLME-SLEEPMODE.response */ 48 static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 49 const u8 *addr, u8 dialog_token, 50 u8 action_type, u16 intval) 51 { 52 struct ieee80211_mgmt *mgmt; 53 int res; 54 size_t len; 55 size_t gtk_elem_len = 0; 56 size_t igtk_elem_len = 0; 57 struct wnm_sleep_element wnmsleep_ie; 58 u8 *wnmtfs_ie, *oci_ie; 59 u8 wnmsleep_ie_len, oci_ie_len; 60 u16 wnmtfs_ie_len; 61 u8 *pos; 62 struct sta_info *sta; 63 enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ? 64 WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE; 65 66 sta = ap_get_sta(hapd, addr); 67 if (sta == NULL) { 68 wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 69 return -EINVAL; 70 } 71 72 /* WNM-Sleep Mode IE */ 73 os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element)); 74 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 75 wnmsleep_ie.eid = WLAN_EID_WNMSLEEP; 76 wnmsleep_ie.len = wnmsleep_ie_len - 2; 77 wnmsleep_ie.action_type = action_type; 78 wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT; 79 wnmsleep_ie.intval = host_to_le16(intval); 80 81 /* TFS IE(s) */ 82 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 83 if (wnmtfs_ie == NULL) 84 return -1; 85 if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len, 86 tfs_oper)) { 87 wnmtfs_ie_len = 0; 88 os_free(wnmtfs_ie); 89 wnmtfs_ie = NULL; 90 } 91 92 oci_ie = NULL; 93 oci_ie_len = 0; 94 #ifdef CONFIG_OCV 95 if (action_type == WNM_SLEEP_MODE_EXIT && 96 wpa_auth_uses_ocv(sta->wpa_sm)) { 97 struct wpa_channel_info ci; 98 99 if (hostapd_drv_channel_info(hapd, &ci) != 0) { 100 wpa_printf(MSG_WARNING, 101 "Failed to get channel info for OCI element in WNM-Sleep Mode frame"); 102 os_free(wnmtfs_ie); 103 return -1; 104 } 105 106 oci_ie_len = OCV_OCI_EXTENDED_LEN; 107 oci_ie = os_zalloc(oci_ie_len); 108 if (!oci_ie) { 109 wpa_printf(MSG_WARNING, 110 "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame"); 111 os_free(wnmtfs_ie); 112 return -1; 113 } 114 115 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) { 116 os_free(wnmtfs_ie); 117 os_free(oci_ie); 118 return -1; 119 } 120 } 121 #endif /* CONFIG_OCV */ 122 123 #define MAX_GTK_SUBELEM_LEN 45 124 #define MAX_IGTK_SUBELEM_LEN 26 125 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + 126 MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN + 127 oci_ie_len); 128 if (mgmt == NULL) { 129 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 130 "WNM-Sleep Response action frame"); 131 res = -1; 132 goto fail; 133 } 134 os_memcpy(mgmt->da, addr, ETH_ALEN); 135 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 136 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 137 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 138 WLAN_FC_STYPE_ACTION); 139 mgmt->u.action.category = WLAN_ACTION_WNM; 140 mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP; 141 mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token; 142 pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable; 143 /* add key data if MFP is enabled */ 144 if (!wpa_auth_uses_mfp(sta->wpa_sm) || 145 hapd->conf->wnm_sleep_mode_no_keys || 146 action_type != WNM_SLEEP_MODE_EXIT) { 147 mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0; 148 } else { 149 gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos); 150 pos += gtk_elem_len; 151 wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d", 152 (int) gtk_elem_len); 153 #ifdef CONFIG_IEEE80211W 154 res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos); 155 if (res < 0) 156 goto fail; 157 igtk_elem_len = res; 158 pos += igtk_elem_len; 159 wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d", 160 (int) igtk_elem_len); 161 #endif /* CONFIG_IEEE80211W */ 162 163 WPA_PUT_LE16((u8 *) 164 &mgmt->u.action.u.wnm_sleep_resp.keydata_len, 165 gtk_elem_len + igtk_elem_len); 166 } 167 os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len); 168 /* copy TFS IE here */ 169 pos += wnmsleep_ie_len; 170 if (wnmtfs_ie) { 171 os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len); 172 pos += wnmtfs_ie_len; 173 } 174 #ifdef CONFIG_OCV 175 /* copy OCV OCI here */ 176 if (oci_ie_len > 0) 177 os_memcpy(pos, oci_ie, oci_ie_len); 178 #endif /* CONFIG_OCV */ 179 180 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len + 181 igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len; 182 183 /* In driver, response frame should be forced to sent when STA is in 184 * PS mode */ 185 res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 186 mgmt->da, &mgmt->u.action.category, len); 187 188 if (!res) { 189 wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response " 190 "frame"); 191 192 /* when entering wnmsleep 193 * 1. pause the node in driver 194 * 2. mark the node so that AP won't update GTK/IGTK during 195 * WNM Sleep 196 */ 197 if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && 198 wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { 199 sta->flags |= WLAN_STA_WNM_SLEEP_MODE; 200 hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM, 201 addr, NULL, NULL); 202 wpa_set_wnmsleep(sta->wpa_sm, 1); 203 } 204 /* when exiting wnmsleep 205 * 1. unmark the node 206 * 2. start GTK/IGTK update if MFP is not used 207 * 3. unpause the node in driver 208 */ 209 if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT || 210 wnmsleep_ie.status == 211 WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) && 212 wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) { 213 sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 214 wpa_set_wnmsleep(sta->wpa_sm, 0); 215 hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM, 216 addr, NULL, NULL); 217 if (!wpa_auth_uses_mfp(sta->wpa_sm) || 218 hapd->conf->wnm_sleep_mode_no_keys) 219 wpa_wnmsleep_rekey_gtk(sta->wpa_sm); 220 } 221 } else 222 wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame"); 223 224 #undef MAX_GTK_SUBELEM_LEN 225 #undef MAX_IGTK_SUBELEM_LEN 226 fail: 227 os_free(wnmtfs_ie); 228 os_free(oci_ie); 229 os_free(mgmt); 230 return res; 231 } 232 233 234 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, 235 const u8 *addr, const u8 *frm, int len) 236 { 237 /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */ 238 const u8 *pos = frm; 239 u8 dialog_token; 240 struct wnm_sleep_element *wnmsleep_ie = NULL; 241 /* multiple TFS Req IE (assuming consecutive) */ 242 u8 *tfsreq_ie_start = NULL; 243 u8 *tfsreq_ie_end = NULL; 244 u16 tfsreq_ie_len = 0; 245 #ifdef CONFIG_OCV 246 struct sta_info *sta; 247 const u8 *oci_ie = NULL; 248 u8 oci_ie_len = 0; 249 #endif /* CONFIG_OCV */ 250 251 if (!hapd->conf->wnm_sleep_mode) { 252 wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from " 253 MACSTR " since WNM-Sleep Mode is disabled", 254 MAC2STR(addr)); 255 return; 256 } 257 258 if (len < 1) { 259 wpa_printf(MSG_DEBUG, 260 "WNM: Ignore too short WNM-Sleep Mode Request from " 261 MACSTR, MAC2STR(addr)); 262 return; 263 } 264 265 dialog_token = *pos++; 266 while (pos + 1 < frm + len) { 267 u8 ie_len = pos[1]; 268 if (pos + 2 + ie_len > frm + len) 269 break; 270 if (*pos == WLAN_EID_WNMSLEEP && 271 ie_len >= (int) sizeof(*wnmsleep_ie) - 2) 272 wnmsleep_ie = (struct wnm_sleep_element *) pos; 273 else if (*pos == WLAN_EID_TFS_REQ) { 274 if (!tfsreq_ie_start) 275 tfsreq_ie_start = (u8 *) pos; 276 tfsreq_ie_end = (u8 *) pos; 277 #ifdef CONFIG_OCV 278 } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 && 279 pos[2] == WLAN_EID_EXT_OCV_OCI) { 280 oci_ie = pos + 3; 281 oci_ie_len = ie_len - 1; 282 #endif /* CONFIG_OCV */ 283 } else 284 wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized", 285 *pos); 286 pos += ie_len + 2; 287 } 288 289 if (!wnmsleep_ie) { 290 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 291 return; 292 } 293 294 #ifdef CONFIG_OCV 295 sta = ap_get_sta(hapd, addr); 296 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT && 297 sta && wpa_auth_uses_ocv(sta->wpa_sm)) { 298 struct wpa_channel_info ci; 299 300 if (hostapd_drv_channel_info(hapd, &ci) != 0) { 301 wpa_printf(MSG_WARNING, 302 "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame"); 303 return; 304 } 305 306 if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci, 307 channel_width_to_int(ci.chanwidth), 308 ci.seg1_idx) != 0) { 309 wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr); 310 return; 311 } 312 } 313 #endif /* CONFIG_OCV */ 314 315 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER && 316 tfsreq_ie_start && tfsreq_ie_end && 317 tfsreq_ie_end - tfsreq_ie_start >= 0) { 318 tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) - 319 tfsreq_ie_start; 320 wpa_printf(MSG_DEBUG, "TFS Req IE(s) found"); 321 /* pass the TFS Req IE(s) to driver for processing */ 322 if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, 323 &tfsreq_ie_len, 324 WNM_SLEEP_TFS_REQ_IE_SET)) 325 wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE"); 326 } 327 328 ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token, 329 wnmsleep_ie->action_type, 330 le_to_host16(wnmsleep_ie->intval)); 331 332 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 333 /* clear the tfs after sending the resp frame */ 334 ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start, 335 &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL); 336 } 337 } 338 339 340 static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, 341 const u8 *addr, 342 u8 dialog_token) 343 { 344 struct ieee80211_mgmt *mgmt; 345 size_t len; 346 u8 *pos; 347 int res; 348 349 mgmt = os_zalloc(sizeof(*mgmt)); 350 if (mgmt == NULL) 351 return -1; 352 os_memcpy(mgmt->da, addr, ETH_ALEN); 353 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 354 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 355 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 356 WLAN_FC_STYPE_ACTION); 357 mgmt->u.action.category = WLAN_ACTION_WNM; 358 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 359 mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; 360 mgmt->u.action.u.bss_tm_req.req_mode = 0; 361 mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); 362 mgmt->u.action.u.bss_tm_req.validity_interval = 1; 363 pos = mgmt->u.action.u.bss_tm_req.variable; 364 365 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " 366 MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " 367 "validity_interval=%u", 368 MAC2STR(addr), dialog_token, 369 mgmt->u.action.u.bss_tm_req.req_mode, 370 le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer), 371 mgmt->u.action.u.bss_tm_req.validity_interval); 372 373 len = pos - &mgmt->u.action.category; 374 res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, 375 mgmt->da, &mgmt->u.action.category, len); 376 os_free(mgmt); 377 return res; 378 } 379 380 381 static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, 382 const u8 *addr, const u8 *frm, 383 size_t len) 384 { 385 u8 dialog_token, reason; 386 const u8 *pos, *end; 387 int enabled = hapd->conf->bss_transition; 388 389 #ifdef CONFIG_MBO 390 if (hapd->conf->mbo_enabled) 391 enabled = 1; 392 #endif /* CONFIG_MBO */ 393 if (!enabled) { 394 wpa_printf(MSG_DEBUG, 395 "Ignore BSS Transition Management Query from " 396 MACSTR 397 " since BSS Transition Management is disabled", 398 MAC2STR(addr)); 399 return; 400 } 401 402 if (len < 2) { 403 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from " 404 MACSTR, MAC2STR(addr)); 405 return; 406 } 407 408 pos = frm; 409 end = pos + len; 410 dialog_token = *pos++; 411 reason = *pos++; 412 413 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from " 414 MACSTR " dialog_token=%u reason=%u", 415 MAC2STR(addr), dialog_token, reason); 416 417 wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", 418 pos, end - pos); 419 420 ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); 421 } 422 423 424 void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx) 425 { 426 struct hostapd_data *hapd = eloop_ctx; 427 struct sta_info *sta = timeout_ctx; 428 429 if (sta->agreed_to_steer) { 430 wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR, 431 hapd->conf->iface, MAC2STR(sta->addr)); 432 sta->agreed_to_steer = 0; 433 } 434 } 435 436 437 static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, 438 const u8 *addr, const u8 *frm, 439 size_t len) 440 { 441 u8 dialog_token, status_code, bss_termination_delay; 442 const u8 *pos, *end; 443 int enabled = hapd->conf->bss_transition; 444 struct sta_info *sta; 445 446 #ifdef CONFIG_MBO 447 if (hapd->conf->mbo_enabled) 448 enabled = 1; 449 #endif /* CONFIG_MBO */ 450 if (!enabled) { 451 wpa_printf(MSG_DEBUG, 452 "Ignore BSS Transition Management Response from " 453 MACSTR 454 " since BSS Transition Management is disabled", 455 MAC2STR(addr)); 456 return; 457 } 458 459 if (len < 3) { 460 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from " 461 MACSTR, MAC2STR(addr)); 462 return; 463 } 464 465 pos = frm; 466 end = pos + len; 467 dialog_token = *pos++; 468 status_code = *pos++; 469 bss_termination_delay = *pos++; 470 471 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from " 472 MACSTR " dialog_token=%u status_code=%u " 473 "bss_termination_delay=%u", MAC2STR(addr), dialog_token, 474 status_code, bss_termination_delay); 475 476 sta = ap_get_sta(hapd, addr); 477 if (!sta) { 478 wpa_printf(MSG_DEBUG, "Station " MACSTR 479 " not found for received BSS TM Response", 480 MAC2STR(addr)); 481 return; 482 } 483 484 if (status_code == WNM_BSS_TM_ACCEPT) { 485 if (end - pos < ETH_ALEN) { 486 wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); 487 return; 488 } 489 sta->agreed_to_steer = 1; 490 eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); 491 eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer, 492 hapd, sta); 493 wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR, 494 MAC2STR(pos)); 495 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR 496 " status_code=%u bss_termination_delay=%u target_bssid=" 497 MACSTR, 498 MAC2STR(addr), status_code, bss_termination_delay, 499 MAC2STR(pos)); 500 pos += ETH_ALEN; 501 } else { 502 sta->agreed_to_steer = 0; 503 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR 504 " status_code=%u bss_termination_delay=%u", 505 MAC2STR(addr), status_code, bss_termination_delay); 506 } 507 508 wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", 509 pos, end - pos); 510 } 511 512 513 static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd, 514 const u8 *addr, const u8 *buf, 515 size_t len) 516 { 517 u8 dialog_token, type; 518 519 if (len < 2) 520 return; 521 dialog_token = *buf++; 522 type = *buf++; 523 len -= 2; 524 525 wpa_printf(MSG_DEBUG, 526 "WNM: Received WNM Notification Request frame from " 527 MACSTR " (dialog_token=%u type=%u)", 528 MAC2STR(addr), dialog_token, type); 529 wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements", 530 buf, len); 531 if (type == WLAN_EID_VENDOR_SPECIFIC) 532 mbo_ap_wnm_notification_req(hapd, addr, buf, len); 533 } 534 535 536 static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd, 537 const u8 *addr, const u8 *buf, 538 size_t len) 539 { 540 u8 dialog_token; 541 char *hex; 542 size_t hex_len; 543 544 if (!hapd->conf->coloc_intf_reporting) { 545 wpa_printf(MSG_DEBUG, 546 "WNM: Ignore unexpected Collocated Interference Report from " 547 MACSTR, MAC2STR(addr)); 548 return; 549 } 550 551 if (len < 1) { 552 wpa_printf(MSG_DEBUG, 553 "WNM: Ignore too short Collocated Interference Report from " 554 MACSTR, MAC2STR(addr)); 555 return; 556 } 557 dialog_token = *buf++; 558 len--; 559 560 wpa_printf(MSG_DEBUG, 561 "WNM: Received Collocated Interference Report frame from " 562 MACSTR " (dialog_token=%u)", 563 MAC2STR(addr), dialog_token); 564 wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements", 565 buf, len); 566 567 hex_len = 2 * len + 1; 568 hex = os_malloc(hex_len); 569 if (!hex) 570 return; 571 wpa_snprintf_hex(hex, hex_len, buf, len); 572 wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s", 573 MAC2STR(addr), dialog_token, hex); 574 os_free(hex); 575 } 576 577 578 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, 579 const struct ieee80211_mgmt *mgmt, size_t len) 580 { 581 u8 action; 582 const u8 *payload; 583 size_t plen; 584 585 if (len < IEEE80211_HDRLEN + 2) 586 return -1; 587 588 payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 589 action = *payload++; 590 plen = len - IEEE80211_HDRLEN - 2; 591 592 switch (action) { 593 case WNM_BSS_TRANS_MGMT_QUERY: 594 ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, 595 plen); 596 return 0; 597 case WNM_BSS_TRANS_MGMT_RESP: 598 ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, 599 plen); 600 return 0; 601 case WNM_SLEEP_MODE_REQ: 602 ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen); 603 return 0; 604 case WNM_NOTIFICATION_REQ: 605 ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload, 606 plen); 607 return 0; 608 case WNM_COLLOCATED_INTERFERENCE_REPORT: 609 ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload, 610 plen); 611 return 0; 612 } 613 614 wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, 615 action, MAC2STR(mgmt->sa)); 616 return -1; 617 } 618 619 620 int wnm_send_disassoc_imminent(struct hostapd_data *hapd, 621 struct sta_info *sta, int disassoc_timer) 622 { 623 u8 buf[1000], *pos; 624 struct ieee80211_mgmt *mgmt; 625 626 os_memset(buf, 0, sizeof(buf)); 627 mgmt = (struct ieee80211_mgmt *) buf; 628 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 629 WLAN_FC_STYPE_ACTION); 630 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 631 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 632 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 633 mgmt->u.action.category = WLAN_ACTION_WNM; 634 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 635 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 636 mgmt->u.action.u.bss_tm_req.req_mode = 637 WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 638 mgmt->u.action.u.bss_tm_req.disassoc_timer = 639 host_to_le16(disassoc_timer); 640 mgmt->u.action.u.bss_tm_req.validity_interval = 0; 641 642 pos = mgmt->u.action.u.bss_tm_req.variable; 643 644 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " 645 MACSTR, disassoc_timer, MAC2STR(sta->addr)); 646 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 647 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 648 "Management Request frame"); 649 return -1; 650 } 651 652 return 0; 653 } 654 655 656 static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta, 657 int disassoc_timer) 658 { 659 int timeout, beacon_int; 660 661 /* 662 * Prevent STA from reconnecting using cached PMKSA to force 663 * full authentication with the authentication server (which may 664 * decide to reject the connection), 665 */ 666 wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 667 668 beacon_int = hapd->iconf->beacon_int; 669 if (beacon_int < 1) 670 beacon_int = 100; /* best guess */ 671 /* Calculate timeout in ms based on beacon_int in TU */ 672 timeout = disassoc_timer * beacon_int * 128 / 125; 673 wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR 674 " set to %d ms", MAC2STR(sta->addr), timeout); 675 676 sta->timeout_next = STA_DISASSOC_FROM_CLI; 677 eloop_cancel_timeout(ap_handle_timer, hapd, sta); 678 eloop_register_timeout(timeout / 1000, 679 timeout % 1000 * 1000, 680 ap_handle_timer, hapd, sta); 681 } 682 683 684 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, 685 struct sta_info *sta, const char *url, 686 int disassoc_timer) 687 { 688 u8 buf[1000], *pos; 689 struct ieee80211_mgmt *mgmt; 690 size_t url_len; 691 692 os_memset(buf, 0, sizeof(buf)); 693 mgmt = (struct ieee80211_mgmt *) buf; 694 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 695 WLAN_FC_STYPE_ACTION); 696 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 697 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 698 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 699 mgmt->u.action.category = WLAN_ACTION_WNM; 700 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 701 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 702 mgmt->u.action.u.bss_tm_req.req_mode = 703 WNM_BSS_TM_REQ_DISASSOC_IMMINENT | 704 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 705 mgmt->u.action.u.bss_tm_req.disassoc_timer = 706 host_to_le16(disassoc_timer); 707 mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; 708 709 pos = mgmt->u.action.u.bss_tm_req.variable; 710 711 /* Session Information URL */ 712 url_len = os_strlen(url); 713 if (url_len > 255) 714 return -1; 715 *pos++ = url_len; 716 os_memcpy(pos, url, url_len); 717 pos += url_len; 718 719 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 720 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 721 "Management Request frame"); 722 return -1; 723 } 724 725 if (disassoc_timer) { 726 /* send disassociation frame after time-out */ 727 set_disassoc_timer(hapd, sta, disassoc_timer); 728 } 729 730 return 0; 731 } 732 733 734 int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, 735 u8 req_mode, int disassoc_timer, u8 valid_int, 736 const u8 *bss_term_dur, const char *url, 737 const u8 *nei_rep, size_t nei_rep_len, 738 const u8 *mbo_attrs, size_t mbo_len) 739 { 740 u8 *buf, *pos; 741 struct ieee80211_mgmt *mgmt; 742 size_t url_len; 743 744 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " 745 MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x", 746 MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int); 747 buf = os_zalloc(1000 + nei_rep_len + mbo_len); 748 if (buf == NULL) 749 return -1; 750 mgmt = (struct ieee80211_mgmt *) buf; 751 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 752 WLAN_FC_STYPE_ACTION); 753 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 754 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 755 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 756 mgmt->u.action.category = WLAN_ACTION_WNM; 757 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 758 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 759 mgmt->u.action.u.bss_tm_req.req_mode = req_mode; 760 mgmt->u.action.u.bss_tm_req.disassoc_timer = 761 host_to_le16(disassoc_timer); 762 mgmt->u.action.u.bss_tm_req.validity_interval = valid_int; 763 764 pos = mgmt->u.action.u.bss_tm_req.variable; 765 766 if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) && 767 bss_term_dur) { 768 os_memcpy(pos, bss_term_dur, 12); 769 pos += 12; 770 } 771 772 if (url) { 773 /* Session Information URL */ 774 url_len = os_strlen(url); 775 if (url_len > 255) { 776 os_free(buf); 777 return -1; 778 } 779 780 *pos++ = url_len; 781 os_memcpy(pos, url, url_len); 782 pos += url_len; 783 } 784 785 if (nei_rep) { 786 os_memcpy(pos, nei_rep, nei_rep_len); 787 pos += nei_rep_len; 788 } 789 790 if (mbo_len > 0) { 791 pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs, 792 mbo_len); 793 } 794 795 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 796 wpa_printf(MSG_DEBUG, 797 "Failed to send BSS Transition Management Request frame"); 798 os_free(buf); 799 return -1; 800 } 801 os_free(buf); 802 803 if (disassoc_timer) { 804 /* send disassociation frame after time-out */ 805 set_disassoc_timer(hapd, sta, disassoc_timer); 806 } 807 808 return 0; 809 } 810 811 812 int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, 813 unsigned int auto_report, unsigned int timeout) 814 { 815 u8 buf[100], *pos; 816 struct ieee80211_mgmt *mgmt; 817 u8 dialog_token = 1; 818 819 if (auto_report > 3 || timeout > 63) 820 return -1; 821 os_memset(buf, 0, sizeof(buf)); 822 mgmt = (struct ieee80211_mgmt *) buf; 823 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 824 WLAN_FC_STYPE_ACTION); 825 os_memcpy(mgmt->da, sta->addr, ETH_ALEN); 826 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 827 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 828 mgmt->u.action.category = WLAN_ACTION_WNM; 829 mgmt->u.action.u.coloc_intf_req.action = 830 WNM_COLLOCATED_INTERFERENCE_REQ; 831 mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token; 832 mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2); 833 pos = &mgmt->u.action.u.coloc_intf_req.req_info; 834 pos++; 835 836 wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to " 837 MACSTR " (dialog_token=%u auto_report=%u timeout=%u)", 838 MAC2STR(sta->addr), dialog_token, auto_report, timeout); 839 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 840 wpa_printf(MSG_DEBUG, 841 "WNM: Failed to send Collocated Interference Request frame"); 842 return -1; 843 } 844 845 return 0; 846 } 847