161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* 261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * wpa_supplicant - WNM 3f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. 461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * See README for more details. 761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/includes.h" 1061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/common.h" 1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "common/ieee802_11_defs.h" 13f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt#include "common/wpa_ctrl.h" 1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "rsn_supp/wpa.h" 15a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "wpa_supplicant_i.h" 16a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "driver_i.h" 17a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "scan.h" 1844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "ctrl_iface.h" 1944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "bss.h" 2044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "wnm_sta.h" 2161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define MAX_TFS_IE_LEN 1024 2344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#define WNM_MAX_NEIGHBOR_REPORT 10 2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* get the TFS IE from driver */ 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 *buf_len, enum wnm_oper oper) 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* set the TFS IE to driver */ 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *addr, u8 *buf, u16 *buf_len, 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper oper) 4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); 4461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* MLME-SLEEPMODE.request */ 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 49a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 action, u16 intval, struct wpabuf *tfs_req) 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct ieee80211_mgmt *mgmt; 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int res; 5361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t len; 5461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie; 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *wnmtfs_ie; 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 wnmsleep_ie_len; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WNM_SLEEP_TFS_REQ_IE_NONE; 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 61a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 62a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "action=%s to " MACSTR, 63a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt action == 0 ? "enter" : "exit", 64a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid)); 65a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 6661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* WNM-Sleep Mode IE */ 6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmsleep_ie == NULL) 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->len = wnmsleep_ie_len - 2; 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type = action; 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 75a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->intval = host_to_le16(intval); 76a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 77a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmsleep_ie, wnmsleep_ie_len); 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* TFS IE(s) */ 80a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfs_req) { 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = wpabuf_len(tfs_req); 82a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_malloc(wnmtfs_ie_len); 83a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 84a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 85a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 86a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 87a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 88a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else { 89a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 90a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 91a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 92a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 93a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 94a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 95a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfs_oper)) { 96a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = 0; 97a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 98a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = NULL; 99a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 10061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 101a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmtfs_ie, wnmtfs_ie_len); 10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (mgmt == NULL) { 10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "WNM-Sleep Request action frame"); 108a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 109a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WLAN_FC_STYPE_ACTION); 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 120a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len); 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* copy TFS IE here */ 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmtfs_ie_len > 0) { 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmtfs_ie_len; 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt &mgmt->u.action.category, len, 0); 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (res < 0) 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", action, intval); 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmsleep_ie); 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmtfs_ie); 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(mgmt); 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return res; 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 147a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 148a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *tfsresp_ie_start, 149a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *tfsresp_ie_end) 150a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 151a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 152a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->bssid, NULL, NULL); 153a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* remove GTK/IGTK ?? */ 154a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 155a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* set the TFS Resp IE(s) */ 156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfsresp_ie_start && tfsresp_ie_end && 157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end - tfsresp_ie_start >= 0) { 158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u16 tfsresp_ie_len; 159a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start; 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pass the TFS Resp IE(s) to driver for processing */ 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start, 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt &tfsresp_ie_len, 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_TFS_RESP_IE_SET)) 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 169a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 171a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 172a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *frm, u16 key_len_total) 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *ptr, *end; 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 gtk_len; 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt NULL, NULL); 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Install GTK/IGTK */ 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* point to key data field */ 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr = (u8 *) frm + 1 + 1 + 2; 185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = ptr + key_len_total; 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt while (ptr + 1 < end) { 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr + 2 + ptr[1] > end) { 190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "length"); 192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (end > ptr) { 193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr, end - ptr); 195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 196a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 197a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 198a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 199a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + 5) { 200a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len = *(ptr + 4); 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + gtk_len || 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len < 5 || gtk_len > 32) { 207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key( 212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->wpa, 213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_GTK, 214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr); 215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 13 + gtk_len; 216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W 217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key(wpa_s->wpa, 224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_IGTK, ptr); 225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 10 + WPA_IGTK_LEN; 226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */ 227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else 228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; /* skip the loop */ 229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 23361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 23461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *frm, int len) 23561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 23661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data | 23861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * WNM-Sleep Mode IE | TFS Response IE 23961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 24061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *pos = (u8 *) frm; /* point to action field */ 24161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 key_len_total = le_to_host16(*((u16 *)(frm+2))); 24261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie = NULL; 24361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* multiple TFS Resp IE (assuming consecutive) */ 24461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *tfsresp_ie_start = NULL; 24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *tfsresp_ie_end = NULL; 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d", 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt frm[0], frm[1], key_len_total); 24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += 4 + key_len_total; 250a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos > frm + len) { 251a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 252a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 253a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (pos - frm < len) { 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 ie_len = *(pos + 1); 256a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 2 + ie_len > frm + len) { 257a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 258a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 259a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 260a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*pos == WLAN_EID_WNMSLEEP) 26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = (struct wnm_sleep_element *) pos; 26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else if (*pos == WLAN_EID_TFS_RESP) { 26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!tfsresp_ie_start) 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_start = pos; 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_end = pos; 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += ie_len + 2; 27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!wnmsleep_ie) { 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 277a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 278a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "frame (action=%d, intval=%d)", 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 282a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 283a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 284a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end); 285a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 286a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 292a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 295a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 30344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 30444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int i; 30544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 30644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 30744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info); 30844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str); 30944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can); 31044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur); 31144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bearing); 31244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 31344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap); 31444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 31544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 31644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 31744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 31844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = NULL; 31944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 32044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 32344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, u8 elen, const u8 *pos) 32444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 32544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt switch (id) { 32644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_TSF: 32744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2 + 2) { 32844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 32944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 33044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 33144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); 33244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->tsf_info == NULL) 33344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 33444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->tsf_info->present = 1; 33544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->tsf_info->tsf_offset, pos, 2); 33644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2); 33744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 33844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 33944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 34044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 34144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "country string"); 34244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 34444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->con_coun_str = 34544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct condensed_country_string)); 34644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->con_coun_str == NULL) 34744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->con_coun_str->present = 1; 34944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->con_coun_str->country_string, pos, 2); 35044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 35244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 1) { 35344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 35444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "candidate"); 35544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 35744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_tran_can = 35844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct bss_transition_candidate)); 35944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bss_tran_can == NULL) 36044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_tran_can->present = 1; 36244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_tran_can->preference = pos[0]; 36344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 36544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 12) { 36644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination " 36744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "duration"); 36844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 37044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_term_dur = 37144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct bss_termination_duration)); 37244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bss_term_dur == NULL) 37344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_term_dur->present = 1; 37544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bss_term_dur->duration, pos, 12); 37644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BEARING: 37844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 8) { 37944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 38044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "bearing"); 38144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 38344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bearing = os_zalloc(sizeof(struct bearing)); 38444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bearing == NULL) 38544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bearing->present = 1; 38744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bearing->bearing, pos, 8); 38844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MEASUREMENT_PILOT: 39044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 39144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 39244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "pilot"); 39344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 39544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 39644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->meas_pilot == NULL) 39744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->present = 1; 39944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->measurement_pilot = pos[0]; 40044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->num_vendor_specific = pos[1]; 40144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2); 40244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 40444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 4) { 40544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 40644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "capabilities"); 40744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 40944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->rrm_cap = 41044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct rrm_enabled_capabilities)); 41144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->rrm_cap == NULL) 41244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->rrm_cap->present = 1; 41444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->rrm_cap->capabilities, pos, 4); 41544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MULTIPLE_BSSID: 41744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 41844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 41944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 42144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 42244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->mul_bssid == NULL) 42344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->present = 1; 42544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->max_bssid_indicator = pos[0]; 42644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->num_vendor_specific = pos[1]; 42744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2); 42844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 43044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 43144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 43444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt const u8 *pos, u8 len, 43544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *rep) 43644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 43744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 left = len; 43844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (left < 13) { 44044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 44144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 44244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 44344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 44444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid, pos, ETH_ALEN); 44544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4); 44644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->regulatory_class = *(pos + 10); 44744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->channel_number = *(pos + 11); 44844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->phy_type = *(pos + 12); 44944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 13; 45144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 13; 45244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (left >= 2) { 45444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, elen; 45544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt id = *pos++; 45744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt elen = *pos++; 45844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report_elem(rep, id, elen, pos); 45944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 2 + elen; 46044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += elen; 46144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 46244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 46344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 46444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 46544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, 46644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_scan_results *scan_res, 46744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *neigh_rep, 46844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 num_neigh_rep, u8 *bssid_to_connect) 46944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 47044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 i, j; 47244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (scan_res == NULL || num_neigh_rep == 0) 47444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 47544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < num_neigh_rep; i++) { 47744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (j = 0; j < scan_res->num; j++) { 47844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Check for a better RSSI AP */ 47944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (os_memcmp(scan_res->res[j]->bssid, 48044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt neigh_rep[i].bssid, ETH_ALEN) == 0 && 48144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt scan_res->res[j]->level > 48244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->current_bss->level) { 48344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Got a BSSID with better RSSI value */ 48444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(bssid_to_connect, neigh_rep[i].bssid, 48544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ETH_ALEN); 48644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 1; 48744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 48844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 48944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 49044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 49144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 49244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 49344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 49444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 495f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtstatic void wnm_send_bss_transition_mgmt_resp( 496f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt struct wpa_supplicant *wpa_s, u8 dialog_token, 497f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status, u8 delay, 498f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt const u8 *target_bssid) 499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 500a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 buf[1000], *pos; 501a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ieee80211_mgmt *mgmt; 502a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 503a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 504a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 505a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "to " MACSTR " dialog_token=%u status=%u delay=%d", 506a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid), dialog_token, status, delay); 507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 513a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 514a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WLAN_FC_STYPE_ACTION); 515a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 516a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.status_code = status; 519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_resp.variable; 521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (target_bssid) { 522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(pos, target_bssid, ETH_ALEN); 523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += ETH_ALEN; 524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt &mgmt->u.action.category, len, 0); 531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 53444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_scan_response(struct wpa_supplicant *wpa_s, 53544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_scan_results *scan_res) 53644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 53744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 bssid[ETH_ALEN]; 53844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 53944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (scan_res == NULL) { 54044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "Scan result is NULL"); 54144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt goto send_bss_resp_fail; 54244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 54344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 54444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Compare the Neighbor Report and scan results */ 54544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (compare_scan_neighbor_results(wpa_s, scan_res, 54644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements, 54744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report, 54844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt bssid) == 1) { 54944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Associate to the network */ 55044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_bss *bss; 55144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 55244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 55344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt bss = wpa_bss_get_bssid(wpa_s, bssid); 55444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (!bss) { 55544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " 55644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "BSS table"); 55744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt goto send_bss_resp_fail; 55844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 55944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 56044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Send the BSS Management Response - Accept */ 56144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 56244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 56344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 564f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_ACCEPT, 56544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 0, NULL); 56644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 56744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 56844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->reassociate = 1; 56944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_connect(wpa_s, bss, ssid); 57044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 57144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 57244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 57344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 57444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Send reject response for all the failures */ 57544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtsend_bss_resp_fail: 57644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 57744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 57844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 57944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 580f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_REJECT_UNSPECIFIED, 58144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 0, NULL); 58244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 58344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 58444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 58544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 58644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 587a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 588a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, const u8 *end, 589a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int reply) 590a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 591a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 5 > end) 592a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 593a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 59444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token = pos[0]; 59544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_mode = pos[1]; 59644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 59744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_validity_interval = pos[4]; 59844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_reply = reply; 599a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 600a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "dialog_token=%u request_mode=0x%x " 602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "disassoc_timer=%u validity_interval=%u", 60344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 60444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval); 60544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 5; 60744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 608f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 60944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (pos + 12 > end) { 61044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 61144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 61244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 61344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 614a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 12; /* BSS Termination Duration */ 61544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 61644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 617f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 618a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char url[256]; 619f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt unsigned int beacon_int; 620f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 1 > end || pos + 1 + pos[0] > end) { 622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "Management Request (URL)"); 624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 626a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(url, pos + 1, pos[0]); 627a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt url[pos[0]] = '\0'; 62844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 1 + pos[0]; 629f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 630f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->current_bss) 631f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt beacon_int = wpa_s->current_bss->beacon_int; 632f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else 633f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt beacon_int = 100; /* best guess */ 634f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 635f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 636f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_sm_pmf_enabled(wpa_s->wpa), 637f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 639a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 640f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 641a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 64244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 64344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 644a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* TODO: mark current BSS less preferred for 645a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * selection */ 646a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 647a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 648a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 649a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 651f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 65244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 65344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 65444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 65544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = os_zalloc( 65644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WNM_MAX_NEIGHBOR_REPORT * 65744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt sizeof(struct neighbor_report)); 65844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_neighbor_report_elements == NULL) 65944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 66044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 66144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (pos + 2 <= end && 66244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 66344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt { 66444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 tag = *pos++; 66544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 len = *pos++; 66644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 66744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 66844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt tag); 66944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (pos + len > end) { 67044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 67144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 67244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 67344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report( 67444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s, pos, len, 67544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &wpa_s->wnm_neighbor_report_elements[ 67644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report]); 67744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 67844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += len; 67944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report++; 68044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 68144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 68244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->scan_res_handler = wnm_scan_response; 68344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 68444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } else if (reply) { 685f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status; 686f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 687f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_ACCEPT; 688f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else { 689f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 690f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_REJECT_UNSPECIFIED; 691f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt } 69244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 69344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 694f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status, 0, NULL); 695a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 696a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 697a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 698a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 69944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtint wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 70044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 query_reason) 70144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 70244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 buf[1000], *pos; 70344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct ieee80211_mgmt *mgmt; 70444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt size_t len; 70544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int ret; 70644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 70744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 70844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MACSTR " query_reason=%u", 70944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MAC2STR(wpa_s->bssid), query_reason); 71044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 71144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 71244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 71344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 71444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 71544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 71644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 71744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WLAN_FC_STYPE_ACTION); 71844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 71944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 72044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.dialog_token = 0; 72144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 72244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_query.variable; 72344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 72444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 72544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 72644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 72744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 72844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &mgmt->u.action.category, len, 0); 72944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 73044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return ret; 73144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 73244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 73344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 73461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 73561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct rx_action *action) 73661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 737a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 738a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 act; 739a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 740a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (action->data == NULL || action->len == 0) 741a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 742a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 743a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = action->data; 744a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = pos + action->len; 745a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act = *pos++; 746a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 747a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 748a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act, MAC2STR(action->sa)); 749a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wpa_s->wpa_state < WPA_ASSOCIATED || 750a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) { 751a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 752a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "frame"); 753a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 754a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 75561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 75661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (act) { 757a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case WNM_BSS_TRANS_MGMT_REQ: 758a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 759a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt !(action->da[0] & 0x01)); 760a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 76161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WNM_SLEEP_MODE_RESP: 76261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); 76361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 76544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "WNM: Unknown request"); 76661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 76761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 76861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 769