1 /* 2 * wpa_supplicant - WNM 3 * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 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" 16 17 #define MAX_TFS_IE_LEN 1024 18 19 #ifdef CONFIG_IEEE80211V 20 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) 24 { 25 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 26 27 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 28 } 29 30 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, 34 enum wnm_oper oper) 35 { 36 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 37 38 return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); 39 } 40 41 42 /* MLME-SLEEPMODE.request */ 43 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 44 u8 action, u8 intval) 45 { 46 struct ieee80211_mgmt *mgmt; 47 int res; 48 size_t len; 49 struct wnm_sleep_element *wnmsleep_ie; 50 u8 *wnmtfs_ie; 51 u8 wnmsleep_ie_len; 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; 55 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) 60 return -1; 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; 66 67 /* TFS IE(s) */ 68 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 69 if (wnmtfs_ie == NULL) { 70 os_free(wnmsleep_ie); 71 return -1; 72 } 73 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 74 tfs_oper)) { 75 wnmtfs_ie_len = 0; 76 os_free(wnmtfs_ie); 77 wnmtfs_ie = NULL; 78 } 79 80 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 81 if (mgmt == NULL) { 82 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 83 "WNM-Sleep Request action frame"); 84 return -1; 85 } 86 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, 95 wnmsleep_ie_len); 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); 100 } 101 102 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 103 wnmtfs_ie_len; 104 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); 108 if (res < 0) 109 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 110 "(action=%d, intval=%d)", action, intval); 111 112 os_free(wnmsleep_ie); 113 os_free(wnmtfs_ie); 114 os_free(mgmt); 115 116 return res; 117 } 118 119 120 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 121 const u8 *frm, int len) 122 { 123 /* 124 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data | 125 * WNM-Sleep Mode IE | TFS Response IE 126 */ 127 u8 *pos = (u8 *) frm; /* point to action field */ 128 u16 key_len_total = le_to_host16(*((u16 *)(frm+2))); 129 u8 gtk_len; 130 #ifdef CONFIG_IEEE80211W 131 u8 igtk_len; 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; 138 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; 150 } else 151 wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 152 pos += ie_len + 2; 153 } 154 155 if (!wnmsleep_ie) { 156 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 157 return; 158 } 159 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 ?? */ 168 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) - 174 tfsresp_ie_start; 175 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 176 /* 177 * pass the TFS Resp IE(s) to driver for 178 * processing 179 */ 180 if (ieee80211_11_set_tfs_ie( 181 wpa_s, wpa_s->bssid, 182 tfsresp_ie_start, 183 &tfsresp_ie_len, 184 WNM_SLEEP_TFS_RESP_IE_SET)) 185 wpa_printf(MSG_DEBUG, "Fail to set " 186 "TFS Resp IE"); 187 } 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 */ 192 do { 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( 199 wpa_s->wpa, 200 WNM_SLEEP_SUBELEM_GTK, 201 ptr); 202 ptr += 13 + gtk_len; 203 #ifdef CONFIG_IEEE80211W 204 } else if (*ptr == 205 WNM_SLEEP_SUBELEM_IGTK) { 206 igtk_len = WPA_IGTK_LEN; 207 wpa_wnmsleep_install_key( 208 wpa_s->wpa, 209 WNM_SLEEP_SUBELEM_IGTK, 210 ptr); 211 ptr += 10 + WPA_IGTK_LEN; 212 #endif /* CONFIG_IEEE80211W */ 213 } else 214 break; /* skip the loop */ 215 } 216 } while(0); 217 } 218 } else { 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); 228 } 229 } 230 231 232 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 233 struct rx_action *action) 234 { 235 u8 *pos = (u8 *) action->data; /* point to action field */ 236 u8 act = *pos++; 237 /* u8 dialog_token = *pos++; */ 238 239 switch (act) { 240 case WNM_SLEEP_MODE_RESP: 241 ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); 242 break; 243 default: 244 break; 245 } 246 } 247 248 #endif /* CONFIG_IEEE80211V */ 249