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 "rsn_supp/wpa.h"
14 #include "wpa_supplicant_i.h"
17 #define MAX_TFS_IE_LEN 1024
20 /* get the TFS IE from driver */
21 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant
*wpa_s
, u8
*buf
,
22 u16
*buf_len
, enum wnm_oper oper
)
24 wpa_printf(MSG_DEBUG
, "%s: TFS get operation %d", __func__
, oper
);
26 return wpa_drv_wnm_oper(wpa_s
, oper
, wpa_s
->bssid
, buf
, buf_len
);
30 /* set the TFS IE to driver */
31 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant
*wpa_s
,
32 const u8
*addr
, u8
*buf
, u16
*buf_len
,
35 wpa_printf(MSG_DEBUG
, "%s: TFS set operation %d", __func__
, oper
);
37 return wpa_drv_wnm_oper(wpa_s
, oper
, addr
, buf
, buf_len
);
41 /* MLME-SLEEPMODE.request */
42 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant
*wpa_s
,
43 u8 action
, u16 intval
, struct wpabuf
*tfs_req
)
45 struct ieee80211_mgmt
*mgmt
;
48 struct wnm_sleep_element
*wnmsleep_ie
;
51 u16 wnmtfs_ie_len
; /* possibly multiple IE(s) */
52 enum wnm_oper tfs_oper
= action
== 0 ? WNM_SLEEP_TFS_REQ_IE_ADD
:
53 WNM_SLEEP_TFS_REQ_IE_NONE
;
55 wpa_printf(MSG_DEBUG
, "WNM: Request to send WNM-Sleep Mode Request "
56 "action=%s to " MACSTR
,
57 action
== 0 ? "enter" : "exit",
58 MAC2STR(wpa_s
->bssid
));
60 /* WNM-Sleep Mode IE */
61 wnmsleep_ie_len
= sizeof(struct wnm_sleep_element
);
62 wnmsleep_ie
= os_zalloc(sizeof(struct wnm_sleep_element
));
63 if (wnmsleep_ie
== NULL
)
65 wnmsleep_ie
->eid
= WLAN_EID_WNMSLEEP
;
66 wnmsleep_ie
->len
= wnmsleep_ie_len
- 2;
67 wnmsleep_ie
->action_type
= action
;
68 wnmsleep_ie
->status
= WNM_STATUS_SLEEP_ACCEPT
;
69 wnmsleep_ie
->intval
= host_to_le16(intval
);
70 wpa_hexdump(MSG_DEBUG
, "WNM: WNM-Sleep Mode element",
71 (u8
*) wnmsleep_ie
, wnmsleep_ie_len
);
75 wnmtfs_ie_len
= wpabuf_len(tfs_req
);
76 wnmtfs_ie
= os_malloc(wnmtfs_ie_len
);
77 if (wnmtfs_ie
== NULL
) {
81 os_memcpy(wnmtfs_ie
, wpabuf_head(tfs_req
), wnmtfs_ie_len
);
83 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
84 if (wnmtfs_ie
== NULL
) {
88 if (ieee80211_11_get_tfs_ie(wpa_s
, wnmtfs_ie
, &wnmtfs_ie_len
,
95 wpa_hexdump(MSG_DEBUG
, "WNM: TFS Request element",
96 (u8
*) wnmtfs_ie
, wnmtfs_ie_len
);
98 mgmt
= os_zalloc(sizeof(*mgmt
) + wnmsleep_ie_len
+ wnmtfs_ie_len
);
100 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
101 "WNM-Sleep Request action frame");
105 os_memcpy(mgmt
->da
, wpa_s
->bssid
, ETH_ALEN
);
106 os_memcpy(mgmt
->sa
, wpa_s
->own_addr
, ETH_ALEN
);
107 os_memcpy(mgmt
->bssid
, wpa_s
->bssid
, ETH_ALEN
);
108 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
109 WLAN_FC_STYPE_ACTION
);
110 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
111 mgmt
->u
.action
.u
.wnm_sleep_req
.action
= WNM_SLEEP_MODE_REQ
;
112 mgmt
->u
.action
.u
.wnm_sleep_req
.dialogtoken
= 1;
113 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
, wnmsleep_ie
,
115 /* copy TFS IE here */
116 if (wnmtfs_ie_len
> 0) {
117 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
+
118 wnmsleep_ie_len
, wnmtfs_ie
, wnmtfs_ie_len
);
121 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_req
) + wnmsleep_ie_len
+
124 res
= wpa_drv_send_action(wpa_s
, wpa_s
->assoc_freq
, 0, wpa_s
->bssid
,
125 wpa_s
->own_addr
, wpa_s
->bssid
,
126 &mgmt
->u
.action
.category
, len
, 0);
128 wpa_printf(MSG_DEBUG
, "Failed to send WNM-Sleep Request "
129 "(action=%d, intval=%d)", action
, intval
);
131 os_free(wnmsleep_ie
);
139 static void wnm_sleep_mode_enter_success(struct wpa_supplicant
*wpa_s
,
140 u8
*tfsresp_ie_start
,
143 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
144 wpa_s
->bssid
, NULL
, NULL
);
145 /* remove GTK/IGTK ?? */
147 /* set the TFS Resp IE(s) */
148 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
149 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
151 tfsresp_ie_len
= (tfsresp_ie_end
+ tfsresp_ie_end
[1] + 2) -
153 wpa_printf(MSG_DEBUG
, "TFS Resp IE(s) found");
154 /* pass the TFS Resp IE(s) to driver for processing */
155 if (ieee80211_11_set_tfs_ie(wpa_s
, wpa_s
->bssid
,
158 WNM_SLEEP_TFS_RESP_IE_SET
))
159 wpa_printf(MSG_DEBUG
, "WNM: Fail to set TFS Resp IE");
164 static void wnm_sleep_mode_exit_success(struct wpa_supplicant
*wpa_s
,
165 const u8
*frm
, u16 key_len_total
)
170 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
, wpa_s
->bssid
,
173 /* Install GTK/IGTK */
175 /* point to key data field */
176 ptr
= (u8
*) frm
+ 1 + 1 + 2;
177 end
= ptr
+ key_len_total
;
178 wpa_hexdump_key(MSG_DEBUG
, "WNM: Key Data", ptr
, key_len_total
);
180 while (ptr
+ 1 < end
) {
181 if (ptr
+ 2 + ptr
[1] > end
) {
182 wpa_printf(MSG_DEBUG
, "WNM: Invalid Key Data element "
185 wpa_hexdump(MSG_DEBUG
, "WNM: Remaining data",
190 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
191 if (ptr
[1] < 11 + 5) {
192 wpa_printf(MSG_DEBUG
, "WNM: Too short GTK "
196 gtk_len
= *(ptr
+ 4);
197 if (ptr
[1] < 11 + gtk_len
||
198 gtk_len
< 5 || gtk_len
> 32) {
199 wpa_printf(MSG_DEBUG
, "WNM: Invalid GTK "
203 wpa_wnmsleep_install_key(
205 WNM_SLEEP_SUBELEM_GTK
,
208 #ifdef CONFIG_IEEE80211W
209 } else if (*ptr
== WNM_SLEEP_SUBELEM_IGTK
) {
210 if (ptr
[1] < 2 + 6 + WPA_IGTK_LEN
) {
211 wpa_printf(MSG_DEBUG
, "WNM: Too short IGTK "
215 wpa_wnmsleep_install_key(wpa_s
->wpa
,
216 WNM_SLEEP_SUBELEM_IGTK
, ptr
);
217 ptr
+= 10 + WPA_IGTK_LEN
;
218 #endif /* CONFIG_IEEE80211W */
220 break; /* skip the loop */
225 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant
*wpa_s
,
226 const u8
*frm
, int len
)
229 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
230 * WNM-Sleep Mode IE | TFS Response IE
232 u8
*pos
= (u8
*) frm
; /* point to action field */
233 u16 key_len_total
= le_to_host16(*((u16
*)(frm
+2)));
234 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
235 /* multiple TFS Resp IE (assuming consecutive) */
236 u8
*tfsresp_ie_start
= NULL
;
237 u8
*tfsresp_ie_end
= NULL
;
239 wpa_printf(MSG_DEBUG
, "action=%d token = %d key_len_total = %d",
240 frm
[0], frm
[1], key_len_total
);
241 pos
+= 4 + key_len_total
;
242 if (pos
> frm
+ len
) {
243 wpa_printf(MSG_INFO
, "WNM: Too short frame for Key Data field");
246 while (pos
- frm
< len
) {
247 u8 ie_len
= *(pos
+ 1);
248 if (pos
+ 2 + ie_len
> frm
+ len
) {
249 wpa_printf(MSG_INFO
, "WNM: Invalid IE len %u", ie_len
);
252 wpa_hexdump(MSG_DEBUG
, "WNM: Element", pos
, 2 + ie_len
);
253 if (*pos
== WLAN_EID_WNMSLEEP
)
254 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
255 else if (*pos
== WLAN_EID_TFS_RESP
) {
256 if (!tfsresp_ie_start
)
257 tfsresp_ie_start
= pos
;
258 tfsresp_ie_end
= pos
;
260 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
265 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
269 if (wnmsleep_ie
->status
== WNM_STATUS_SLEEP_ACCEPT
||
270 wnmsleep_ie
->status
== WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE
) {
271 wpa_printf(MSG_DEBUG
, "Successfully recv WNM-Sleep Response "
272 "frame (action=%d, intval=%d)",
273 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
274 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_ENTER
) {
275 wnm_sleep_mode_enter_success(wpa_s
, tfsresp_ie_start
,
277 } else if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
) {
278 wnm_sleep_mode_exit_success(wpa_s
, frm
, key_len_total
);
281 wpa_printf(MSG_DEBUG
, "Reject recv WNM-Sleep Response frame "
282 "(action=%d, intval=%d)",
283 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
284 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_ENTER
)
285 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_FAIL
,
286 wpa_s
->bssid
, NULL
, NULL
);
287 else if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
)
288 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_FAIL
,
289 wpa_s
->bssid
, NULL
, NULL
);
294 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
295 struct rx_action
*action
)
297 u8
*pos
= (u8
*) action
->data
; /* point to action field */
299 /* u8 dialog_token = *pos++; */
302 case WNM_SLEEP_MODE_RESP
:
303 ieee802_11_rx_wnmsleep_resp(wpa_s
, action
->data
, action
->len
);