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 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
131 /* multiple TFS Resp IE (assuming consecutive) */
132 u8
*tfsresp_ie_start
= NULL
;
133 u8
*tfsresp_ie_end
= NULL
;
134 u16 tfsresp_ie_len
= 0;
136 wpa_printf(MSG_DEBUG
, "action=%d token = %d key_len_total = %d",
137 frm
[0], frm
[1], key_len_total
);
138 pos
+= 4 + key_len_total
;
139 while (pos
- frm
< len
) {
140 u8 ie_len
= *(pos
+ 1);
141 if (*pos
== WLAN_EID_WNMSLEEP
)
142 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
143 else if (*pos
== WLAN_EID_TFS_RESP
) {
144 if (!tfsresp_ie_start
)
145 tfsresp_ie_start
= pos
;
146 tfsresp_ie_end
= pos
;
148 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
153 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
157 if (wnmsleep_ie
->status
== WNM_STATUS_SLEEP_ACCEPT
) {
158 wpa_printf(MSG_DEBUG
, "Successfully recv WNM-Sleep Response "
159 "frame (action=%d, intval=%d)",
160 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
161 if (wnmsleep_ie
->action_type
== 0) {
162 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
163 wpa_s
->bssid
, NULL
, NULL
);
164 /* remove GTK/IGTK ?? */
166 /* set the TFS Resp IE(s) */
167 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
168 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
169 tfsresp_ie_len
= (tfsresp_ie_end
+
170 tfsresp_ie_end
[1] + 2) -
172 wpa_printf(MSG_DEBUG
, "TFS Resp IE(s) found");
174 * pass the TFS Resp IE(s) to driver for
177 if (ieee80211_11_set_tfs_ie(
181 WNM_SLEEP_TFS_RESP_IE_SET
))
182 wpa_printf(MSG_DEBUG
, "Fail to set "
185 } else if (wnmsleep_ie
->action_type
== 1) {
186 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
,
187 wpa_s
->bssid
, NULL
, NULL
);
188 /* Install GTK/IGTK */
190 /* point to key data field */
191 u8
*ptr
= (u8
*) frm
+ 1 + 1 + 2;
192 while (ptr
< (u8
*) frm
+ 4 + key_len_total
) {
193 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
194 gtk_len
= *(ptr
+ 4);
195 wpa_wnmsleep_install_key(
197 WNM_SLEEP_SUBELEM_GTK
,
200 #ifdef CONFIG_IEEE80211W
202 WNM_SLEEP_SUBELEM_IGTK
) {
203 wpa_wnmsleep_install_key(
205 WNM_SLEEP_SUBELEM_IGTK
,
207 ptr
+= 10 + WPA_IGTK_LEN
;
208 #endif /* CONFIG_IEEE80211W */
210 break; /* skip the loop */
215 wpa_printf(MSG_DEBUG
, "Reject recv WNM-Sleep Response frame "
216 "(action=%d, intval=%d)",
217 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
218 if (wnmsleep_ie
->action_type
== 0)
219 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_FAIL
,
220 wpa_s
->bssid
, NULL
, NULL
);
221 else if (wnmsleep_ie
->action_type
== 1)
222 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_FAIL
,
223 wpa_s
->bssid
, NULL
, NULL
);
228 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
229 struct rx_action
*action
)
231 u8
*pos
= (u8
*) action
->data
; /* point to action field */
233 /* u8 dialog_token = *pos++; */
236 case WNM_SLEEP_MODE_RESP
:
237 ieee802_11_rx_wnmsleep_resp(wpa_s
, action
->data
, action
->len
);
244 #endif /* CONFIG_IEEE80211V */