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/wpa_supplicant_i.h"
15 #include "../wpa_supplicant/driver_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
,
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 /* WNM-Sleep Mode IE */
57 wnmsleep_ie_len
= sizeof(struct wnm_sleep_element
);
58 wnmsleep_ie
= os_zalloc(sizeof(struct wnm_sleep_element
));
59 if (wnmsleep_ie
== NULL
)
61 wnmsleep_ie
->eid
= WLAN_EID_WNMSLEEP
;
62 wnmsleep_ie
->len
= wnmsleep_ie_len
- 2;
63 wnmsleep_ie
->action_type
= action
;
64 wnmsleep_ie
->status
= WNM_STATUS_SLEEP_ACCEPT
;
65 wnmsleep_ie
->intval
= intval
;
68 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
69 if (wnmtfs_ie
== NULL
) {
73 if (ieee80211_11_get_tfs_ie(wpa_s
, wnmtfs_ie
, &wnmtfs_ie_len
,
80 mgmt
= os_zalloc(sizeof(*mgmt
) + wnmsleep_ie_len
+ wnmtfs_ie_len
);
82 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
83 "WNM-Sleep Request action frame");
87 os_memcpy(mgmt
->da
, wpa_s
->bssid
, ETH_ALEN
);
88 os_memcpy(mgmt
->sa
, wpa_s
->own_addr
, ETH_ALEN
);
89 os_memcpy(mgmt
->bssid
, wpa_s
->bssid
, ETH_ALEN
);
90 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
91 WLAN_FC_STYPE_ACTION
);
92 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
93 mgmt
->u
.action
.u
.wnm_sleep_req
.action
= WNM_SLEEP_MODE_REQ
;
94 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
, wnmsleep_ie
,
96 /* copy TFS IE here */
97 if (wnmtfs_ie_len
> 0) {
98 os_memcpy(mgmt
->u
.action
.u
.wnm_sleep_req
.variable
+
99 wnmsleep_ie_len
, wnmtfs_ie
, wnmtfs_ie_len
);
102 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_req
) + wnmsleep_ie_len
+
105 res
= wpa_drv_send_action(wpa_s
, wpa_s
->assoc_freq
, 0, wpa_s
->bssid
,
106 wpa_s
->own_addr
, wpa_s
->bssid
,
107 &mgmt
->u
.action
.category
, len
, 0);
109 wpa_printf(MSG_DEBUG
, "Failed to send WNM-Sleep Request "
110 "(action=%d, intval=%d)", action
, intval
);
112 os_free(wnmsleep_ie
);
120 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant
*wpa_s
,
121 const u8
*frm
, int len
)
124 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
125 * WNM-Sleep Mode IE | TFS Response IE
127 u8
*pos
= (u8
*) frm
; /* point to action field */
128 u16 key_len_total
= le_to_host16(*((u16
*)(frm
+2)));
130 #ifdef CONFIG_IEEE80211W
132 #endif /* CONFIG_IEEE80211W */
133 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
134 /* multiple TFS Resp IE (assuming consecutive) */
135 u8
*tfsresp_ie_start
= NULL
;
136 u8
*tfsresp_ie_end
= NULL
;
137 u16 tfsresp_ie_len
= 0;
139 wpa_printf(MSG_DEBUG
, "action=%d token = %d key_len_total = %d",
140 frm
[0], frm
[1], key_len_total
);
141 pos
+= 4 + key_len_total
;
142 while (pos
- frm
< len
) {
143 u8 ie_len
= *(pos
+ 1);
144 if (*pos
== WLAN_EID_WNMSLEEP
)
145 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
146 else if (*pos
== WLAN_EID_TFS_RESP
) {
147 if (!tfsresp_ie_start
)
148 tfsresp_ie_start
= pos
;
149 tfsresp_ie_end
= pos
;
151 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
156 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
160 if (wnmsleep_ie
->status
== WNM_STATUS_SLEEP_ACCEPT
) {
161 wpa_printf(MSG_DEBUG
, "Successfully recv WNM-Sleep Response "
162 "frame (action=%d, intval=%d)",
163 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
164 if (wnmsleep_ie
->action_type
== 0) {
165 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
166 wpa_s
->bssid
, NULL
, NULL
);
167 /* remove GTK/IGTK ?? */
169 /* set the TFS Resp IE(s) */
170 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
171 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
172 tfsresp_ie_len
= (tfsresp_ie_end
+
173 tfsresp_ie_end
[1] + 2) -
175 wpa_printf(MSG_DEBUG
, "TFS Resp IE(s) found");
177 * pass the TFS Resp IE(s) to driver for
180 if (ieee80211_11_set_tfs_ie(
184 WNM_SLEEP_TFS_RESP_IE_SET
))
185 wpa_printf(MSG_DEBUG
, "Fail to set "
188 } else if (wnmsleep_ie
->action_type
== 1) {
189 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
,
190 wpa_s
->bssid
, NULL
, NULL
);
191 /* Install GTK/IGTK */
193 /* point to key data field */
194 u8
*ptr
= (u8
*) frm
+ 1 + 1 + 2;
195 while (ptr
< (u8
*) frm
+ 4 + key_len_total
) {
196 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
197 gtk_len
= *(ptr
+ 4);
198 wpa_wnmsleep_install_key(
200 WNM_SLEEP_SUBELEM_GTK
,
203 #ifdef CONFIG_IEEE80211W
205 WNM_SLEEP_SUBELEM_IGTK
) {
206 igtk_len
= WPA_IGTK_LEN
;
207 wpa_wnmsleep_install_key(
209 WNM_SLEEP_SUBELEM_IGTK
,
211 ptr
+= 10 + WPA_IGTK_LEN
;
212 #endif /* CONFIG_IEEE80211W */
214 break; /* skip the loop */
219 wpa_printf(MSG_DEBUG
, "Reject recv WNM-Sleep Response frame "
220 "(action=%d, intval=%d)",
221 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
222 if (wnmsleep_ie
->action_type
== 0)
223 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_FAIL
,
224 wpa_s
->bssid
, NULL
, NULL
);
225 else if (wnmsleep_ie
->action_type
== 1)
226 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_FAIL
,
227 wpa_s
->bssid
, NULL
, NULL
);
232 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
233 struct rx_action
*action
)
235 u8
*pos
= (u8
*) action
->data
; /* point to action field */
237 /* u8 dialog_token = *pos++; */
240 case WNM_SLEEP_MODE_RESP
:
241 ieee802_11_rx_wnmsleep_resp(wpa_s
, action
->data
, action
->len
);
248 #endif /* CONFIG_IEEE80211V */