3 * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
23 #define MAX_TFS_IE_LEN 1024
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
)
30 wpa_printf(MSG_DEBUG
, "%s: TFS get operation %d", __func__
, oper
);
32 return hostapd_drv_wnm_oper(hapd
, oper
, addr
, buf
, buf_len
);
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
)
40 wpa_printf(MSG_DEBUG
, "%s: TFS set operation %d", __func__
, oper
);
42 return hostapd_drv_wnm_oper(hapd
, oper
, addr
, buf
, buf_len
);
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
)
51 struct ieee80211_mgmt
*mgmt
;
54 size_t gtk_elem_len
= 0;
55 size_t igtk_elem_len
= 0;
56 struct wnm_sleep_element wnmsleep_ie
;
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
;
65 sta
= ap_get_sta(hapd
, addr
);
67 wpa_printf(MSG_DEBUG
, "%s: station not found", __func__
);
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
);
81 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
82 if (wnmtfs_ie
== NULL
)
84 if (ieee80211_11_get_tfs_ie(hapd
, addr
, wnmtfs_ie
, &wnmtfs_ie_len
,
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
);
96 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
97 "WNM-Sleep Response action frame");
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;
116 gtk_elem_len
= wpa_wnmsleep_gtk_subelem(sta
->wpa_sm
, pos
);
118 wpa_printf(MSG_DEBUG
, "Pass 4, gtk_len = %d",
120 #ifdef CONFIG_IEEE80211W
121 res
= wpa_wnmsleep_igtk_subelem(sta
->wpa_sm
, pos
);
125 pos
+= igtk_elem_len
;
126 wpa_printf(MSG_DEBUG
, "Pass 4 igtk_len = %d",
127 (int) igtk_elem_len
);
128 #endif /* CONFIG_IEEE80211W */
131 &mgmt
->u
.action
.u
.wnm_sleep_resp
.keydata_len
,
132 gtk_elem_len
+ igtk_elem_len
);
134 os_memcpy(pos
, &wnmsleep_ie
, wnmsleep_ie_len
);
135 /* copy TFS IE here */
136 pos
+= wnmsleep_ie_len
;
138 os_memcpy(pos
, wnmtfs_ie
, wnmtfs_ie_len
);
140 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_resp
) + gtk_elem_len
+
141 igtk_elem_len
+ wnmsleep_ie_len
+ wnmtfs_ie_len
;
143 /* In driver, response frame should be forced to sent when STA is in
145 res
= hostapd_drv_send_action(hapd
, hapd
->iface
->freq
, 0,
146 mgmt
->da
, &mgmt
->u
.action
.category
, len
);
149 wpa_printf(MSG_DEBUG
, "Successfully send WNM-Sleep Response "
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
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
,
162 wpa_set_wnmsleep(sta
->wpa_sm
, 1);
164 /* when exiting wnmsleep
166 * 2. start GTK/IGTK update if MFP is not used
167 * 3. unpause the node in driver
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
,
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
);
182 wpa_printf(MSG_DEBUG
, "Fail to send WNM-Sleep Response frame");
184 #undef MAX_GTK_SUBELEM_LEN
185 #undef MAX_IGTK_SUBELEM_LEN
193 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data
*hapd
,
194 const u8
*addr
, const u8
*frm
, int len
)
196 /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
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;
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",
212 dialog_token
= *pos
++;
213 while (pos
+ 1 < frm
+ len
) {
215 if (pos
+ 2 + ie_len
> frm
+ len
)
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
;
225 wpa_printf(MSG_DEBUG
, "WNM: EID %d not recognized",
231 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
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) -
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
,
244 WNM_SLEEP_TFS_REQ_IE_SET
))
245 wpa_printf(MSG_DEBUG
, "Fail to set TFS Req IE");
248 ieee802_11_send_wnmsleep_resp(hapd
, addr
, dialog_token
,
249 wnmsleep_ie
->action_type
,
250 le_to_host16(wnmsleep_ie
->intval
));
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
);
260 static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data
*hapd
,
264 struct ieee80211_mgmt
*mgmt
;
269 mgmt
= os_zalloc(sizeof(*mgmt
));
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
;
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
);
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
);
301 static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data
*hapd
,
302 const u8
*addr
, const u8
*frm
,
305 u8 dialog_token
, reason
;
307 int enabled
= hapd
->conf
->bss_transition
;
310 if (hapd
->conf
->mbo_enabled
)
312 #endif /* CONFIG_MBO */
314 wpa_printf(MSG_DEBUG
,
315 "Ignore BSS Transition Management Query from "
317 " since BSS Transition Management is disabled",
323 wpa_printf(MSG_DEBUG
, "WNM: Ignore too short BSS Transition Management Query from "
324 MACSTR
, MAC2STR(addr
));
330 dialog_token
= *pos
++;
333 wpa_printf(MSG_DEBUG
, "WNM: BSS Transition Management Query from "
334 MACSTR
" dialog_token=%u reason=%u",
335 MAC2STR(addr
), dialog_token
, reason
);
337 wpa_hexdump(MSG_DEBUG
, "WNM: BSS Transition Candidate List Entries",
340 ieee802_11_send_bss_trans_mgmt_request(hapd
, addr
, dialog_token
);
344 void ap_sta_reset_steer_flag_timer(void *eloop_ctx
, void *timeout_ctx
)
346 struct hostapd_data
*hapd
= eloop_ctx
;
347 struct sta_info
*sta
= timeout_ctx
;
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;
357 static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data
*hapd
,
358 const u8
*addr
, const u8
*frm
,
361 u8 dialog_token
, status_code
, bss_termination_delay
;
363 int enabled
= hapd
->conf
->bss_transition
;
364 struct sta_info
*sta
;
367 if (hapd
->conf
->mbo_enabled
)
369 #endif /* CONFIG_MBO */
371 wpa_printf(MSG_DEBUG
,
372 "Ignore BSS Transition Management Response from "
374 " since BSS Transition Management is disabled",
380 wpa_printf(MSG_DEBUG
, "WNM: Ignore too short BSS Transition Management Response from "
381 MACSTR
, MAC2STR(addr
));
387 dialog_token
= *pos
++;
388 status_code
= *pos
++;
389 bss_termination_delay
= *pos
++;
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
);
396 sta
= ap_get_sta(hapd
, addr
);
398 wpa_printf(MSG_DEBUG
, "Station " MACSTR
399 " not found for received BSS TM Response",
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");
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
,
413 wpa_printf(MSG_DEBUG
, "WNM: Target BSSID: " MACSTR
,
415 wpa_msg(hapd
->msg_ctx
, MSG_INFO
, BSS_TM_RESP MACSTR
416 " status_code=%u bss_termination_delay=%u target_bssid="
418 MAC2STR(addr
), status_code
, bss_termination_delay
,
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
);
428 wpa_hexdump(MSG_DEBUG
, "WNM: BSS Transition Candidate List Entries",
433 static void ieee802_11_rx_wnm_notification_req(struct hostapd_data
*hapd
,
434 const u8
*addr
, const u8
*buf
,
437 u8 dialog_token
, type
;
441 dialog_token
= *buf
++;
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",
451 if (type
== WLAN_EID_VENDOR_SPECIFIC
)
452 mbo_ap_wnm_notification_req(hapd
, addr
, buf
, len
);
456 static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data
*hapd
,
457 const u8
*addr
, const u8
*buf
,
464 if (!hapd
->conf
->coloc_intf_reporting
) {
465 wpa_printf(MSG_DEBUG
,
466 "WNM: Ignore unexpected Collocated Interference Report from "
467 MACSTR
, MAC2STR(addr
));
472 wpa_printf(MSG_DEBUG
,
473 "WNM: Ignore too short Collocated Interference Report from "
474 MACSTR
, MAC2STR(addr
));
477 dialog_token
= *buf
++;
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",
487 hex_len
= 2 * len
+ 1;
488 hex
= os_malloc(hex_len
);
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
);
498 int ieee802_11_rx_wnm_action_ap(struct hostapd_data
*hapd
,
499 const struct ieee80211_mgmt
*mgmt
, size_t len
)
505 if (len
< IEEE80211_HDRLEN
+ 2)
508 payload
= ((const u8
*) mgmt
) + IEEE80211_HDRLEN
+ 1;
510 plen
= len
- IEEE80211_HDRLEN
- 2;
513 case WNM_BSS_TRANS_MGMT_QUERY
:
514 ieee802_11_rx_bss_trans_mgmt_query(hapd
, mgmt
->sa
, payload
,
517 case WNM_BSS_TRANS_MGMT_RESP
:
518 ieee802_11_rx_bss_trans_mgmt_resp(hapd
, mgmt
->sa
, payload
,
521 case WNM_SLEEP_MODE_REQ
:
522 ieee802_11_rx_wnmsleep_req(hapd
, mgmt
->sa
, payload
, plen
);
524 case WNM_NOTIFICATION_REQ
:
525 ieee802_11_rx_wnm_notification_req(hapd
, mgmt
->sa
, payload
,
528 case WNM_COLLOCATED_INTERFERENCE_REPORT
:
529 ieee802_11_rx_wnm_coloc_intf_report(hapd
, mgmt
->sa
, payload
,
534 wpa_printf(MSG_DEBUG
, "WNM: Unsupported WNM Action %u from " MACSTR
,
535 action
, MAC2STR(mgmt
->sa
));
540 int wnm_send_disassoc_imminent(struct hostapd_data
*hapd
,
541 struct sta_info
*sta
, int disassoc_timer
)
544 struct ieee80211_mgmt
*mgmt
;
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;
562 pos
= mgmt
->u
.action
.u
.bss_tm_req
.variable
;
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");
576 static void set_disassoc_timer(struct hostapd_data
*hapd
, struct sta_info
*sta
,
579 int timeout
, beacon_int
;
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),
586 wpa_auth_pmksa_remove(hapd
->wpa_auth
, sta
->addr
);
588 beacon_int
= hapd
->iconf
->beacon_int
;
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
);
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
);
604 int wnm_send_ess_disassoc_imminent(struct hostapd_data
*hapd
,
605 struct sta_info
*sta
, const char *url
,
609 struct ieee80211_mgmt
*mgmt
;
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;
629 pos
= mgmt
->u
.action
.u
.bss_tm_req
.variable
;
631 /* Session Information URL */
632 url_len
= os_strlen(url
);
636 os_memcpy(pos
, url
, url_len
);
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");
645 if (disassoc_timer
) {
646 /* send disassociation frame after time-out */
647 set_disassoc_timer(hapd
, sta
, disassoc_timer
);
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
)
661 struct ieee80211_mgmt
*mgmt
;
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
);
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
;
684 pos
= mgmt
->u
.action
.u
.bss_tm_req
.variable
;
686 if ((req_mode
& WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED
) &&
688 os_memcpy(pos
, bss_term_dur
, 12);
693 /* Session Information URL */
694 url_len
= os_strlen(url
);
701 os_memcpy(pos
, url
, url_len
);
706 os_memcpy(pos
, nei_rep
, nei_rep_len
);
711 pos
+= mbo_add_ie(pos
, buf
+ sizeof(buf
) - pos
, mbo_attrs
,
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");
723 if (disassoc_timer
) {
724 /* send disassociation frame after time-out */
725 set_disassoc_timer(hapd
, sta
, disassoc_timer
);
732 int wnm_send_coloc_intf_req(struct hostapd_data
*hapd
, struct sta_info
*sta
,
733 unsigned int auto_report
, unsigned int timeout
)
736 struct ieee80211_mgmt
*mgmt
;
739 if (auto_report
> 3 || timeout
> 63)
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
;
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");