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
19 #ifdef CONFIG_IEEE80211V
21 /* get the TFS IE from driver */
22 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant
*wpa_s
, u8
*buf
,
23 u16
*buf_len
, enum wnm_oper oper
)
25 wpa_printf(MSG_DEBUG
, "%s: TFS get operation %d", __func__
, oper
);
27 return wpa_drv_wnm_oper(wpa_s
, oper
, wpa_s
->bssid
, buf
, buf_len
);
31 /* set the TFS IE to driver */
32 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant
*wpa_s
,
33 const u8
*addr
, u8
*buf
, u16
*buf_len
,
36 wpa_printf(MSG_DEBUG
, "%s: TFS set operation %d", __func__
, oper
);
38 return wpa_drv_wnm_oper(wpa_s
, oper
, addr
, buf
, buf_len
);
42 /* MLME-SLEEPMODE.request */
43 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant
*wpa_s
,
44 u8 action
, u16 intval
, struct wpabuf
*tfs_req
)
46 struct ieee80211_mgmt
*mgmt
;
49 struct wnm_sleep_element
*wnmsleep_ie
;
52 u16 wnmtfs_ie_len
; /* possibly multiple IE(s) */
53 enum wnm_oper tfs_oper
= action
== 0 ? WNM_SLEEP_TFS_REQ_IE_ADD
:
54 WNM_SLEEP_TFS_REQ_IE_NONE
;
56 wpa_printf(MSG_DEBUG
, "WNM: Request to send WNM-Sleep Mode Request "
57 "action=%s to " MACSTR
,
58 action
== 0 ? "enter" : "exit",
59 MAC2STR(wpa_s
->bssid
));
61 /* WNM-Sleep Mode IE */
62 wnmsleep_ie_len
= sizeof(struct wnm_sleep_element
);
63 wnmsleep_ie
= os_zalloc(sizeof(struct wnm_sleep_element
));
64 if (wnmsleep_ie
== NULL
)
66 wnmsleep_ie
->eid
= WLAN_EID_WNMSLEEP
;
67 wnmsleep_ie
->len
= wnmsleep_ie_len
- 2;
68 wnmsleep_ie
->action_type
= action
;
69 wnmsleep_ie
->status
= WNM_STATUS_SLEEP_ACCEPT
;
70 wnmsleep_ie
->intval
= host_to_le16(intval
);
71 wpa_hexdump(MSG_DEBUG
, "WNM: WNM-Sleep Mode element",
72 (u8
*) wnmsleep_ie
, wnmsleep_ie_len
);
76 wnmtfs_ie_len
= wpabuf_len(tfs_req
);
77 wnmtfs_ie
= os_malloc(wnmtfs_ie_len
);
78 if (wnmtfs_ie
== NULL
) {
82 os_memcpy(wnmtfs_ie
, wpabuf_head(tfs_req
), wnmtfs_ie_len
);
84 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
85 if (wnmtfs_ie
== NULL
) {
89 if (ieee80211_11_get_tfs_ie(wpa_s
, wnmtfs_ie
, &wnmtfs_ie_len
,
96 wpa_hexdump(MSG_DEBUG
, "WNM: TFS Request element",
97 (u8
*) wnmtfs_ie
, wnmtfs_ie_len
);
99 mgmt
= os_zalloc(sizeof(*mgmt
) + wnmsleep_ie_len
+ wnmtfs_ie_len
);
101 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
102 "WNM-Sleep Request action frame");
106 os_memcpy(mgmt
->da
, wpa_s
->bssid
, ETH_ALEN
);
107 os_memcpy(mgmt
->sa
, wpa_s
->own_addr
, ETH_ALEN
);
108 os_memcpy(mgmt
->bssid
, wpa_s
->bssid
, ETH_ALEN
);
109 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
110 WLAN_FC_STYPE_ACTION
);
111 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
112 mgmt
->u
.action
.u
.wnm_sleep_req
.action
= WNM_SLEEP_MODE_REQ
;
113 mgmt
->u
.action
.u
.wnm_sleep_req
.dialogtoken
= 1;
114 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
, wnmsleep_ie
,
116 /* copy TFS IE here */
117 if (wnmtfs_ie_len
> 0) {
118 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
+
119 wnmsleep_ie_len
, wnmtfs_ie
, wnmtfs_ie_len
);
122 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_req
) + wnmsleep_ie_len
+
125 res
= wpa_drv_send_action(wpa_s
, wpa_s
->assoc_freq
, 0, wpa_s
->bssid
,
126 wpa_s
->own_addr
, wpa_s
->bssid
,
127 &mgmt
->u
.action
.category
, len
, 0);
129 wpa_printf(MSG_DEBUG
, "Failed to send WNM-Sleep Request "
130 "(action=%d, intval=%d)", action
, intval
);
132 os_free(wnmsleep_ie
);
140 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant
*wpa_s
,
141 const u8
*frm
, int len
)
144 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
145 * WNM-Sleep Mode IE | TFS Response IE
147 u8
*pos
= (u8
*) frm
; /* point to action field */
148 u16 key_len_total
= le_to_host16(*((u16
*)(frm
+2)));
150 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
151 /* multiple TFS Resp IE (assuming consecutive) */
152 u8
*tfsresp_ie_start
= NULL
;
153 u8
*tfsresp_ie_end
= NULL
;
154 u16 tfsresp_ie_len
= 0;
156 wpa_printf(MSG_DEBUG
, "action=%d token = %d key_len_total = %d",
157 frm
[0], frm
[1], key_len_total
);
158 pos
+= 4 + key_len_total
;
159 while (pos
- frm
< len
) {
160 u8 ie_len
= *(pos
+ 1);
161 if (*pos
== WLAN_EID_WNMSLEEP
)
162 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
163 else if (*pos
== WLAN_EID_TFS_RESP
) {
164 if (!tfsresp_ie_start
)
165 tfsresp_ie_start
= pos
;
166 tfsresp_ie_end
= pos
;
168 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
173 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
177 if (wnmsleep_ie
->status
== WNM_STATUS_SLEEP_ACCEPT
||
178 wnmsleep_ie
->status
== WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE
) {
179 wpa_printf(MSG_DEBUG
, "Successfully recv WNM-Sleep Response "
180 "frame (action=%d, intval=%d)",
181 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
182 if (wnmsleep_ie
->action_type
== 0) {
183 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
184 wpa_s
->bssid
, NULL
, NULL
);
185 /* remove GTK/IGTK ?? */
187 /* set the TFS Resp IE(s) */
188 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
189 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
190 tfsresp_ie_len
= (tfsresp_ie_end
+
191 tfsresp_ie_end
[1] + 2) -
193 wpa_printf(MSG_DEBUG
, "TFS Resp IE(s) found");
195 * pass the TFS Resp IE(s) to driver for
198 if (ieee80211_11_set_tfs_ie(
202 WNM_SLEEP_TFS_RESP_IE_SET
))
203 wpa_printf(MSG_DEBUG
, "Fail to set "
206 } else if (wnmsleep_ie
->action_type
== 1) {
207 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
,
208 wpa_s
->bssid
, NULL
, NULL
);
209 /* Install GTK/IGTK */
211 /* point to key data field */
212 u8
*ptr
= (u8
*) frm
+ 1 + 1 + 2;
213 while (ptr
< (u8
*) frm
+ 4 + key_len_total
) {
214 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
215 gtk_len
= *(ptr
+ 4);
216 wpa_wnmsleep_install_key(
218 WNM_SLEEP_SUBELEM_GTK
,
221 #ifdef CONFIG_IEEE80211W
223 WNM_SLEEP_SUBELEM_IGTK
) {
224 wpa_wnmsleep_install_key(
226 WNM_SLEEP_SUBELEM_IGTK
,
228 ptr
+= 10 + WPA_IGTK_LEN
;
229 #endif /* CONFIG_IEEE80211W */
231 break; /* skip the loop */
236 wpa_printf(MSG_DEBUG
, "Reject recv WNM-Sleep Response frame "
237 "(action=%d, intval=%d)",
238 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
239 if (wnmsleep_ie
->action_type
== 0)
240 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_FAIL
,
241 wpa_s
->bssid
, NULL
, NULL
);
242 else if (wnmsleep_ie
->action_type
== 1)
243 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_FAIL
,
244 wpa_s
->bssid
, NULL
, NULL
);
249 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
250 struct rx_action
*action
)
252 u8
*pos
= (u8
*) action
->data
; /* point to action field */
254 /* u8 dialog_token = *pos++; */
257 case WNM_SLEEP_MODE_RESP
:
258 ieee802_11_rx_wnmsleep_resp(wpa_s
, action
->data
, action
->len
);
265 #endif /* CONFIG_IEEE80211V */