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
== 0 ? WNM_SLEEP_TFS_RESP_IE_ADD
:
60 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
) || action_type
!= 1){
108 mgmt
->u
.action
.u
.wnm_sleep_resp
.keydata_len
= 0;
110 gtk_elem_len
= wpa_wnmsleep_gtk_subelem(sta
->wpa_sm
, pos
);
112 wpa_printf(MSG_DEBUG
, "Pass 4, gtk_len = %d",
114 #ifdef CONFIG_IEEE80211W
115 res
= wpa_wnmsleep_igtk_subelem(sta
->wpa_sm
, pos
);
122 pos
+= igtk_elem_len
;
123 wpa_printf(MSG_DEBUG
, "Pass 4 igtk_len = %d",
124 (int) igtk_elem_len
);
125 #endif /* CONFIG_IEEE80211W */
128 &mgmt
->u
.action
.u
.wnm_sleep_resp
.keydata_len
,
129 gtk_elem_len
+ igtk_elem_len
);
131 os_memcpy(pos
, &wnmsleep_ie
, wnmsleep_ie_len
);
132 /* copy TFS IE here */
133 pos
+= wnmsleep_ie_len
;
134 os_memcpy(pos
, wnmtfs_ie
, wnmtfs_ie_len
);
136 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_resp
) + gtk_elem_len
+
137 igtk_elem_len
+ wnmsleep_ie_len
+ wnmtfs_ie_len
;
139 /* In driver, response frame should be forced to sent when STA is in
141 res
= hostapd_drv_send_action(hapd
, hapd
->iface
->freq
, 0,
142 mgmt
->da
, &mgmt
->u
.action
.category
, len
);
145 wpa_printf(MSG_DEBUG
, "Successfully send WNM-Sleep Response "
148 /* when entering wnmsleep
149 * 1. pause the node in driver
150 * 2. mark the node so that AP won't update GTK/IGTK during
153 if (wnmsleep_ie
.status
== WNM_STATUS_SLEEP_ACCEPT
&&
154 wnmsleep_ie
.action_type
== 0) {
155 hostapd_drv_wnm_oper(hapd
, WNM_SLEEP_ENTER_CONFIRM
,
157 wpa_set_wnmsleep(sta
->wpa_sm
, 1);
159 /* when exiting wnmsleep
161 * 2. start GTK/IGTK update if MFP is not used
162 * 3. unpause the node in driver
164 if (wnmsleep_ie
.status
== WNM_STATUS_SLEEP_ACCEPT
&&
165 wnmsleep_ie
.action_type
== 1) {
166 wpa_set_wnmsleep(sta
->wpa_sm
, 0);
167 hostapd_drv_wnm_oper(hapd
, WNM_SLEEP_EXIT_CONFIRM
,
169 if (wpa_auth_uses_mfp(sta
->wpa_sm
) && action_type
== 1)
170 wpa_wnmsleep_rekey_gtk(sta
->wpa_sm
);
173 wpa_printf(MSG_DEBUG
, "Fail to send WNM-Sleep Response frame");
175 #undef MAX_GTK_SUBELEM_LEN
176 #undef MAX_IGTK_SUBELEM_LEN
183 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data
*hapd
,
184 const u8
*addr
, const u8
*frm
, int len
)
186 /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
189 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
190 /* multiple TFS Req IE (assuming consecutive) */
191 u8
*tfsreq_ie_start
= NULL
;
192 u8
*tfsreq_ie_end
= NULL
;
193 u16 tfsreq_ie_len
= 0;
195 dialog_token
= *pos
++;
196 while (pos
+ 1 < frm
+ len
) {
198 if (pos
+ 2 + ie_len
> frm
+ len
)
200 if (*pos
== WLAN_EID_WNMSLEEP
)
201 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
202 else if (*pos
== WLAN_EID_TFS_REQ
) {
203 if (!tfsreq_ie_start
)
204 tfsreq_ie_start
= (u8
*) pos
;
205 tfsreq_ie_end
= (u8
*) pos
;
207 wpa_printf(MSG_DEBUG
, "WNM: EID %d not recognized",
213 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
217 if (wnmsleep_ie
->action_type
== 0 && tfsreq_ie_start
&&
218 tfsreq_ie_end
&& tfsreq_ie_end
- tfsreq_ie_start
>= 0) {
219 tfsreq_ie_len
= (tfsreq_ie_end
+ tfsreq_ie_end
[1] + 2) -
221 wpa_printf(MSG_DEBUG
, "TFS Req IE(s) found");
222 /* pass the TFS Req IE(s) to driver for processing */
223 if (ieee80211_11_set_tfs_ie(hapd
, addr
, tfsreq_ie_start
,
225 WNM_SLEEP_TFS_REQ_IE_SET
))
226 wpa_printf(MSG_DEBUG
, "Fail to set TFS Req IE");
229 ieee802_11_send_wnmsleep_resp(hapd
, addr
, dialog_token
,
230 wnmsleep_ie
->action_type
,
231 wnmsleep_ie
->intval
);
233 if (wnmsleep_ie
->action_type
== 1) {
234 /* clear the tfs after sending the resp frame */
235 ieee80211_11_set_tfs_ie(hapd
, addr
, tfsreq_ie_start
,
236 &tfsreq_ie_len
, WNM_SLEEP_TFS_IE_DEL
);
241 int ieee802_11_rx_wnm_action_ap(struct hostapd_data
*hapd
,
242 struct rx_action
*action
)
244 if (action
->len
< 1 || action
->data
== NULL
)
247 switch (action
->data
[0]) {
248 case WNM_SLEEP_MODE_REQ
:
249 ieee802_11_rx_wnmsleep_req(hapd
, action
->sa
, action
->data
+ 1,
254 wpa_printf(MSG_DEBUG
, "WNM: Unsupported WNM Action %u from " MACSTR
,
255 action
->data
[0], MAC2STR(action
->sa
));