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