3 * Copyright (c) 2011-2012, 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 "common/ieee802_11_defs.h"
13 #include "ap/hostapd.h"
14 #include "ap/sta_info.h"
15 #include "ap/ap_config.h"
16 #include "ap/ap_drv_ops.h"
17 #include "ap/wpa_auth.h"
20 #define MAX_TFS_IE_LEN 1024
23 /* get the TFS IE from driver */
24 static int ieee80211_11_get_tfs_ie(struct hostapd_data
*hapd
, const u8
*addr
,
25 u8
*buf
, u16
*buf_len
, enum wnm_oper oper
)
27 wpa_printf(MSG_DEBUG
, "%s: TFS get operation %d", __func__
, oper
);
29 return hostapd_drv_wnm_oper(hapd
, oper
, addr
, buf
, buf_len
);
33 /* set the TFS IE to driver */
34 static int ieee80211_11_set_tfs_ie(struct hostapd_data
*hapd
, const u8
*addr
,
35 u8
*buf
, u16
*buf_len
, enum wnm_oper oper
)
37 wpa_printf(MSG_DEBUG
, "%s: TFS set operation %d", __func__
, oper
);
39 return hostapd_drv_wnm_oper(hapd
, oper
, addr
, buf
, buf_len
);
43 /* MLME-SLEEPMODE.response */
44 static int ieee802_11_send_wnmsleep_resp(struct hostapd_data
*hapd
,
45 const u8
*addr
, u8 dialog_token
,
46 u8 action_type
, u16 intval
)
48 struct ieee80211_mgmt
*mgmt
;
51 size_t gtk_elem_len
= 0;
52 size_t igtk_elem_len
= 0;
53 struct wnm_sleep_element wnmsleep_ie
;
59 enum wnm_oper tfs_oper
= action_type
== WNM_SLEEP_MODE_ENTER
?
60 WNM_SLEEP_TFS_RESP_IE_ADD
: WNM_SLEEP_TFS_RESP_IE_NONE
;
62 sta
= ap_get_sta(hapd
, addr
);
64 wpa_printf(MSG_DEBUG
, "%s: station not found", __func__
);
68 /* WNM-Sleep Mode IE */
69 os_memset(&wnmsleep_ie
, 0, sizeof(struct wnm_sleep_element
));
70 wnmsleep_ie_len
= sizeof(struct wnm_sleep_element
);
71 wnmsleep_ie
.eid
= WLAN_EID_WNMSLEEP
;
72 wnmsleep_ie
.len
= wnmsleep_ie_len
- 2;
73 wnmsleep_ie
.action_type
= action_type
;
74 wnmsleep_ie
.status
= WNM_STATUS_SLEEP_ACCEPT
;
75 wnmsleep_ie
.intval
= intval
;
78 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
79 if (wnmtfs_ie
== NULL
)
81 if (ieee80211_11_get_tfs_ie(hapd
, addr
, wnmtfs_ie
, &wnmtfs_ie_len
,
88 #define MAX_GTK_SUBELEM_LEN 45
89 #define MAX_IGTK_SUBELEM_LEN 26
90 mgmt
= os_zalloc(sizeof(*mgmt
) + wnmsleep_ie_len
+
91 MAX_GTK_SUBELEM_LEN
+ MAX_IGTK_SUBELEM_LEN
);
93 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
94 "WNM-Sleep Response action frame");
97 os_memcpy(mgmt
->da
, addr
, ETH_ALEN
);
98 os_memcpy(mgmt
->sa
, hapd
->own_addr
, ETH_ALEN
);
99 os_memcpy(mgmt
->bssid
, hapd
->own_addr
, ETH_ALEN
);
100 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
101 WLAN_FC_STYPE_ACTION
);
102 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
103 mgmt
->u
.action
.u
.wnm_sleep_resp
.action
= WNM_SLEEP_MODE_RESP
;
104 mgmt
->u
.action
.u
.wnm_sleep_resp
.dialogtoken
= dialog_token
;
105 pos
= (u8
*)mgmt
->u
.action
.u
.wnm_sleep_resp
.variable
;
106 /* add key data if MFP is enabled */
107 if (!wpa_auth_uses_mfp(sta
->wpa_sm
) ||
108 action_type
!= WNM_SLEEP_MODE_EXIT
) {
109 mgmt
->u
.action
.u
.wnm_sleep_resp
.keydata_len
= 0;
111 gtk_elem_len
= wpa_wnmsleep_gtk_subelem(sta
->wpa_sm
, pos
);
113 wpa_printf(MSG_DEBUG
, "Pass 4, gtk_len = %d",
115 #ifdef CONFIG_IEEE80211W
116 res
= wpa_wnmsleep_igtk_subelem(sta
->wpa_sm
, pos
);
123 pos
+= igtk_elem_len
;
124 wpa_printf(MSG_DEBUG
, "Pass 4 igtk_len = %d",
125 (int) igtk_elem_len
);
126 #endif /* CONFIG_IEEE80211W */
129 &mgmt
->u
.action
.u
.wnm_sleep_resp
.keydata_len
,
130 gtk_elem_len
+ igtk_elem_len
);
132 os_memcpy(pos
, &wnmsleep_ie
, wnmsleep_ie_len
);
133 /* copy TFS IE here */
134 pos
+= wnmsleep_ie_len
;
136 os_memcpy(pos
, wnmtfs_ie
, wnmtfs_ie_len
);
138 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_resp
) + gtk_elem_len
+
139 igtk_elem_len
+ wnmsleep_ie_len
+ wnmtfs_ie_len
;
141 /* In driver, response frame should be forced to sent when STA is in
143 res
= hostapd_drv_send_action(hapd
, hapd
->iface
->freq
, 0,
144 mgmt
->da
, &mgmt
->u
.action
.category
, len
);
147 wpa_printf(MSG_DEBUG
, "Successfully send WNM-Sleep Response "
150 /* when entering wnmsleep
151 * 1. pause the node in driver
152 * 2. mark the node so that AP won't update GTK/IGTK during
155 if (wnmsleep_ie
.status
== WNM_STATUS_SLEEP_ACCEPT
&&
156 wnmsleep_ie
.action_type
== WNM_SLEEP_MODE_ENTER
) {
157 hostapd_drv_wnm_oper(hapd
, WNM_SLEEP_ENTER_CONFIRM
,
159 wpa_set_wnmsleep(sta
->wpa_sm
, 1);
161 /* when exiting wnmsleep
163 * 2. start GTK/IGTK update if MFP is not used
164 * 3. unpause the node in driver
166 if ((wnmsleep_ie
.status
== WNM_STATUS_SLEEP_ACCEPT
||
167 wnmsleep_ie
.status
==
168 WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE
) &&
169 wnmsleep_ie
.action_type
== WNM_SLEEP_MODE_EXIT
) {
170 wpa_set_wnmsleep(sta
->wpa_sm
, 0);
171 hostapd_drv_wnm_oper(hapd
, WNM_SLEEP_EXIT_CONFIRM
,
173 if (!wpa_auth_uses_mfp(sta
->wpa_sm
))
174 wpa_wnmsleep_rekey_gtk(sta
->wpa_sm
);
177 wpa_printf(MSG_DEBUG
, "Fail to send WNM-Sleep Response frame");
179 #undef MAX_GTK_SUBELEM_LEN
180 #undef MAX_IGTK_SUBELEM_LEN
187 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data
*hapd
,
188 const u8
*addr
, const u8
*frm
, int len
)
190 /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
193 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
194 /* multiple TFS Req IE (assuming consecutive) */
195 u8
*tfsreq_ie_start
= NULL
;
196 u8
*tfsreq_ie_end
= NULL
;
197 u16 tfsreq_ie_len
= 0;
199 dialog_token
= *pos
++;
200 while (pos
+ 1 < frm
+ len
) {
202 if (pos
+ 2 + ie_len
> frm
+ len
)
204 if (*pos
== WLAN_EID_WNMSLEEP
)
205 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
206 else if (*pos
== WLAN_EID_TFS_REQ
) {
207 if (!tfsreq_ie_start
)
208 tfsreq_ie_start
= (u8
*) pos
;
209 tfsreq_ie_end
= (u8
*) pos
;
211 wpa_printf(MSG_DEBUG
, "WNM: EID %d not recognized",
217 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
221 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_ENTER
&&
222 tfsreq_ie_start
&& tfsreq_ie_end
&&
223 tfsreq_ie_end
- tfsreq_ie_start
>= 0) {
224 tfsreq_ie_len
= (tfsreq_ie_end
+ tfsreq_ie_end
[1] + 2) -
226 wpa_printf(MSG_DEBUG
, "TFS Req IE(s) found");
227 /* pass the TFS Req IE(s) to driver for processing */
228 if (ieee80211_11_set_tfs_ie(hapd
, addr
, tfsreq_ie_start
,
230 WNM_SLEEP_TFS_REQ_IE_SET
))
231 wpa_printf(MSG_DEBUG
, "Fail to set TFS Req IE");
234 ieee802_11_send_wnmsleep_resp(hapd
, addr
, dialog_token
,
235 wnmsleep_ie
->action_type
,
236 wnmsleep_ie
->intval
);
238 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
) {
239 /* clear the tfs after sending the resp frame */
240 ieee80211_11_set_tfs_ie(hapd
, addr
, tfsreq_ie_start
,
241 &tfsreq_ie_len
, WNM_SLEEP_TFS_IE_DEL
);
246 int ieee802_11_rx_wnm_action_ap(struct hostapd_data
*hapd
,
247 struct rx_action
*action
)
249 if (action
->len
< 1 || action
->data
== NULL
)
252 switch (action
->data
[0]) {
253 case WNM_BSS_TRANS_MGMT_QUERY
:
254 wpa_printf(MSG_DEBUG
, "WNM: BSS Transition Management Query");
257 case WNM_BSS_TRANS_MGMT_RESP
:
258 wpa_printf(MSG_DEBUG
, "WNM: BSS Transition Management "
262 case WNM_SLEEP_MODE_REQ
:
263 ieee802_11_rx_wnmsleep_req(hapd
, action
->sa
, action
->data
+ 1,
268 wpa_printf(MSG_DEBUG
, "WNM: Unsupported WNM Action %u from " MACSTR
,
269 action
->data
[0], MAC2STR(action
->sa
));