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" 21f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#include "hs20_supplicant.h" 2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define MAX_TFS_IE_LEN 1024 2444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#define WNM_MAX_NEIGHBOR_REPORT 10 2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* get the TFS IE from driver */ 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 *buf_len, enum wnm_oper oper) 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* set the TFS IE to driver */ 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *addr, u8 *buf, u16 *buf_len, 4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper oper) 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* MLME-SLEEPMODE.request */ 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 50a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 action, u16 intval, struct wpabuf *tfs_req) 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct ieee80211_mgmt *mgmt; 5361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int res; 5461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t len; 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie; 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *wnmtfs_ie; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 wnmsleep_ie_len; 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WNM_SLEEP_TFS_REQ_IE_NONE; 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 62a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 63a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "action=%s to " MACSTR, 64a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt action == 0 ? "enter" : "exit", 65a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid)); 66a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* WNM-Sleep Mode IE */ 6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmsleep_ie == NULL) 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->len = wnmsleep_ie_len - 2; 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type = action; 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 76a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->intval = host_to_le16(intval); 77a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 78a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmsleep_ie, wnmsleep_ie_len); 7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* TFS IE(s) */ 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfs_req) { 82a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = wpabuf_len(tfs_req); 83a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_malloc(wnmtfs_ie_len); 84a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 85a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 86a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 87a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 88a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 89a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else { 90a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 91a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 92a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 93a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 94a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 95a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 96a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfs_oper)) { 97a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = 0; 98a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 99a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = NULL; 100a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 103a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmtfs_ie, wnmtfs_ie_len); 10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (mgmt == NULL) { 10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "WNM-Sleep Request action frame"); 109a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 110a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WLAN_FC_STYPE_ACTION); 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 121a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len); 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* copy TFS IE here */ 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmtfs_ie_len > 0) { 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmtfs_ie_len; 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt &mgmt->u.action.category, len, 0); 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (res < 0) 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", action, intval); 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmsleep_ie); 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmtfs_ie); 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(mgmt); 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return res; 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 148a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 149a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *tfsresp_ie_start, 150a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *tfsresp_ie_end) 151a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 152a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 153a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->bssid, NULL, NULL); 154a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* remove GTK/IGTK ?? */ 155a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* set the TFS Resp IE(s) */ 157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfsresp_ie_start && tfsresp_ie_end && 158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end - tfsresp_ie_start >= 0) { 159a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u16 tfsresp_ie_len; 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start; 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pass the TFS Resp IE(s) to driver for processing */ 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start, 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt &tfsresp_ie_len, 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_TFS_RESP_IE_SET)) 168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 169a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 171a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 172a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *frm, u16 key_len_total) 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *ptr, *end; 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 gtk_len; 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt NULL, NULL); 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Install GTK/IGTK */ 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* point to key data field */ 185fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ptr = (u8 *) frm + 1 + 2; 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = ptr + key_len_total; 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt while (ptr + 1 < end) { 190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr + 2 + ptr[1] > end) { 191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "length"); 193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (end > ptr) { 194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr, end - ptr); 196a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 197a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 198a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 199a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 200a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + 5) { 201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len = *(ptr + 4); 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + gtk_len || 207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len < 5 || gtk_len > 32) { 208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key( 213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->wpa, 214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_GTK, 215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr); 216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 13 + gtk_len; 217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W 218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key(wpa_s->wpa, 225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_IGTK, ptr); 226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 10 + WPA_IGTK_LEN; 227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */ 228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else 229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; /* skip the loop */ 230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 23461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 23561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *frm, int len) 23661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 23821de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 23961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * WNM-Sleep Mode IE | TFS Response IE 24061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 241fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt u8 *pos = (u8 *) frm; /* point to payload after the action field */ 24221de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt u16 key_len_total; 24361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie = NULL; 24461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* multiple TFS Resp IE (assuming consecutive) */ 24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *tfsresp_ie_start = NULL; 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *tfsresp_ie_end = NULL; 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 24821de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt if (len < 3) 24921de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt return; 25021de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt key_len_total = WPA_GET_LE16(frm + 1); 25121de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt 252fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 253fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt frm[0], key_len_total); 254fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt pos += 3 + key_len_total; 255a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos > frm + len) { 256a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 257a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 258a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (pos - frm < len) { 26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 ie_len = *(pos + 1); 261a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 2 + ie_len > frm + len) { 262a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 263a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 264a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 265a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (*pos == WLAN_EID_WNMSLEEP) 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = (struct wnm_sleep_element *) pos; 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else if (*pos == WLAN_EID_TFS_RESP) { 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!tfsresp_ie_start) 27061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_start = pos; 27161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_end = pos; 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += ie_len + 2; 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!wnmsleep_ie) { 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 282a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 283a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "frame (action=%d, intval=%d)", 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 287a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 288a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 289a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end); 290a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 291a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 297a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 300a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 30261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 30744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 30844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 30944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int i; 31044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 31144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 31244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info); 31344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str); 31444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can); 31544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur); 31644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].bearing); 31744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 31844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap); 31944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 32044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 32144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32221de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 32344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 32444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = NULL; 32544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 32644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 32944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, u8 elen, const u8 *pos) 33044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 33144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt switch (id) { 33244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_TSF: 33344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2 + 2) { 33444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 33544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 33644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 337f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->tsf_info); 33844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); 33944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->tsf_info == NULL) 34044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->tsf_info->tsf_offset, pos, 2); 34244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2); 34344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 34544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 34644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 34744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "country string"); 34844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 350f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->con_coun_str); 35144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->con_coun_str = 35244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct condensed_country_string)); 35344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->con_coun_str == NULL) 35444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->con_coun_str->country_string, pos, 2); 35644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 35844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 1) { 35944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 36044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "candidate"); 36144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 363f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->bss_tran_can); 36444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_tran_can = 36544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct bss_transition_candidate)); 36644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bss_tran_can == NULL) 36744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_tran_can->preference = pos[0]; 36944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 371f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 10) { 37244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination " 37344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "duration"); 37444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 376f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->bss_term_dur); 37744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bss_term_dur = 37844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct bss_termination_duration)); 37944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bss_term_dur == NULL) 38044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 381f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->bss_term_dur->duration, pos, 10); 38244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BEARING: 38444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 8) { 38544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 38644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "bearing"); 38744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 389f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->bearing); 39044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->bearing = os_zalloc(sizeof(struct bearing)); 39144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->bearing == NULL) 39244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bearing->bearing, pos, 8); 39444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MEASUREMENT_PILOT: 396f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 39744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 39844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "pilot"); 39944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 401f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->meas_pilot); 40244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 40344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->meas_pilot == NULL) 40444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->measurement_pilot = pos[0]; 406f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->meas_pilot->subelem_len = elen - 1; 407f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 40844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 410f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 5) { 41144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 41244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "capabilities"); 41344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 415f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->rrm_cap); 41644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->rrm_cap = 41744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_zalloc(sizeof(struct rrm_enabled_capabilities)); 41844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->rrm_cap == NULL) 41944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 420f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->rrm_cap->capabilities, pos, 5); 42144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MULTIPLE_BSSID: 423f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 42444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 42544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 427f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->mul_bssid); 42844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 42944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->mul_bssid == NULL) 43044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 43144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->max_bssid_indicator = pos[0]; 432f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->mul_bssid->subelem_len = elen - 1; 433f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 43444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 43544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 43644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 43744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 44044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt const u8 *pos, u8 len, 44144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *rep) 44244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 44344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 left = len; 44444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 44544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (left < 13) { 44644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 44744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 44844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 44944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid, pos, ETH_ALEN); 45144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4); 45244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->regulatory_class = *(pos + 10); 45344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->channel_number = *(pos + 11); 45444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->phy_type = *(pos + 12); 45544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 13; 45744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 13; 45844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (left >= 2) { 46044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, elen; 46144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 46244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt id = *pos++; 46344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt elen = *pos++; 464f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 465f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= 2; 466f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen > left) { 467f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, 468f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt "WNM: Truncated neighbor report subelement"); 469f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt break; 470f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 47144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report_elem(rep, id, elen, pos); 472f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= elen; 47344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += elen; 47444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 47544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 47644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, 47944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_scan_results *scan_res, 48044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *neigh_rep, 48144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 num_neigh_rep, u8 *bssid_to_connect) 48244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 48344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 48444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 i, j; 48544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 4867d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt if (scan_res == NULL || num_neigh_rep == 0 || !wpa_s->current_bss) 48744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 48844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 489fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 4907d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt MAC2STR(wpa_s->bssid), wpa_s->current_bss->level); 491fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 49244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < num_neigh_rep; i++) { 49344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (j = 0; j < scan_res->num; j++) { 49444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Check for a better RSSI AP */ 49544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (os_memcmp(scan_res->res[j]->bssid, 49644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt neigh_rep[i].bssid, ETH_ALEN) == 0 && 49744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt scan_res->res[j]->level > 49844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->current_bss->level) { 49944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Got a BSSID with better RSSI value */ 50044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(bssid_to_connect, neigh_rep[i].bssid, 50144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ETH_ALEN); 502fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR 503fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt " with better scan RSSI %d", 504fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt MAC2STR(scan_res->res[j]->bssid), 505fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt scan_res->res[j]->level); 50644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 1; 50744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 508fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR 509fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt " RSSI %d", j, 510fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt MAC2STR(scan_res->res[j]->bssid), 511fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt scan_res->res[j]->level); 51244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 51344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 51444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 51544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 51644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 51744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 51844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 519f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtstatic void wnm_send_bss_transition_mgmt_resp( 520f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt struct wpa_supplicant *wpa_s, u8 dialog_token, 521f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status, u8 delay, 522f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt const u8 *target_bssid) 523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 buf[1000], *pos; 525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ieee80211_mgmt *mgmt; 526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "to " MACSTR " dialog_token=%u status=%u delay=%d", 530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid), dialog_token, status, delay); 531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 537a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 538a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WLAN_FC_STYPE_ACTION); 539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 541a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.status_code = status; 543a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 544a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_resp.variable; 545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (target_bssid) { 546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(pos, target_bssid, ETH_ALEN); 547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += ETH_ALEN; 548fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } else if (status == WNM_BSS_TM_ACCEPT) { 549fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* 550fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * P802.11-REVmc clarifies that the Target BSSID field is always 551fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * present when status code is zero, so use a fake value here if 552fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * no BSSID is yet known. 553fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt */ 554fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memset(pos, 0, ETH_ALEN); 555fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt pos += ETH_ALEN; 556a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 557a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt &mgmt->u.action.category, len, 0); 563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 56644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_scan_response(struct wpa_supplicant *wpa_s, 56744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_scan_results *scan_res) 56844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 56944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 bssid[ETH_ALEN]; 57044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 57144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (scan_res == NULL) { 57244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "Scan result is NULL"); 57344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt goto send_bss_resp_fail; 57444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 57544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 57644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Compare the Neighbor Report and scan results */ 57744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (compare_scan_neighbor_results(wpa_s, scan_res, 57844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements, 57944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report, 58044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt bssid) == 1) { 58144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Associate to the network */ 58244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_bss *bss; 58344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 58444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 58544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt bss = wpa_bss_get_bssid(wpa_s, bssid); 58644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (!bss) { 58744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " 58844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "BSS table"); 58944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt goto send_bss_resp_fail; 59044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 59144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 59244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Send the BSS Management Response - Accept */ 59344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 59444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 59544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 596f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_ACCEPT, 597fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 0, bssid); 59844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 59944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 60044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->reassociate = 1; 60144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_connect(wpa_s, bss, ssid); 60244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 60344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 60444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 60544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 60644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Send reject response for all the failures */ 60744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtsend_bss_resp_fail: 60844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 60944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 61044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 61144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 612f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_REJECT_UNSPECIFIED, 61344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 0, NULL); 61444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 61544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 61644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 61744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 61844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 620a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, const u8 *end, 621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int reply) 622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 5 > end) 624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 62644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token = pos[0]; 62744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_mode = pos[1]; 62844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 62944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_validity_interval = pos[4]; 63044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_reply = reply; 631a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 632a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 633a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "dialog_token=%u request_mode=0x%x " 634a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "disassoc_timer=%u validity_interval=%u", 63544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 63644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval); 63744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 5; 63944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 640f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 64144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (pos + 12 > end) { 64244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 64344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 64444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 64544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 646a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 12; /* BSS Termination Duration */ 64744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 64844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 649f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char url[256]; 651f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt unsigned int beacon_int; 652f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 653a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (pos + 1 > end || pos + 1 + pos[0] > end) { 654a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 655a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "Management Request (URL)"); 656a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 657a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 658a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(url, pos + 1, pos[0]); 659a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt url[pos[0]] = '\0'; 66044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 1 + pos[0]; 661f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 662f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->current_bss) 663f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt beacon_int = wpa_s->current_bss->beacon_int; 664f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else 665f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt beacon_int = 100; /* best guess */ 666f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 667f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 668f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_sm_pmf_enabled(wpa_s->wpa), 669f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 670a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 671a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 672f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 673a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 67444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 67544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 676a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* TODO: mark current BSS less preferred for 677a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * selection */ 678a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 679a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 680a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 681a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 682a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 683f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 68444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 68544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 68644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 68744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = os_zalloc( 68844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WNM_MAX_NEIGHBOR_REPORT * 68944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt sizeof(struct neighbor_report)); 69044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_neighbor_report_elements == NULL) 69144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 69244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 69344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (pos + 2 <= end && 69444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 69544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt { 69644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 tag = *pos++; 69744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 len = *pos++; 69844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 69944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 70044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt tag); 70144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (pos + len > end) { 70244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 70344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 70444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 705f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (tag == WLAN_EID_NEIGHBOR_REPORT) { 706f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt struct neighbor_report *rep; 707f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep = &wpa_s->wnm_neighbor_report_elements[ 708f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_s->wnm_num_neighbor_report]; 709f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wnm_parse_neighbor_report(wpa_s, pos, len, rep); 710f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 71144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 71244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += len; 71344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report++; 71444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 71544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 71644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->scan_res_handler = wnm_scan_response; 71744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 71844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } else if (reply) { 719f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status; 720f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 721f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_ACCEPT; 722f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else { 723f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 724f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_REJECT_UNSPECIFIED; 725f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt } 72644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 72744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 728f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status, 0, NULL); 729a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 730a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 731a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 732a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 73344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtint wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 73444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 query_reason) 73544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 73644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 buf[1000], *pos; 73744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct ieee80211_mgmt *mgmt; 73844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt size_t len; 73944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int ret; 74044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 74144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 74244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MACSTR " query_reason=%u", 74344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MAC2STR(wpa_s->bssid), query_reason); 74444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 74544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 74644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 74744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 74844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 74944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 75044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 75144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WLAN_FC_STYPE_ACTION); 75244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 75344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 754fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt mgmt->u.action.u.bss_tm_query.dialog_token = 1; 75544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 75644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_query.variable; 75744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 75844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 75944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 76044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 76144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 76244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &mgmt->u.action.category, len, 0); 76344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 76444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return ret; 76544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 76644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 76744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 768f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 769f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *data, 770f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int len) 771f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 772f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end, *next; 773f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 ie, ie_len; 774f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 775f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = data; 776f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = data + len; 777f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 778f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt while (pos + 1 < end) { 779f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie = *pos++; 780f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_len = *pos++; 781f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 782f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie, ie_len); 783f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len > end - pos) { 784f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 785f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 786f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 787f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 788f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt next = pos + ie_len; 789f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len < 4) { 790f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 791f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 792f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 793f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 794f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos), pos[3]); 795f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 796f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20 797f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 798f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 799f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_SUB_REM_NEEDED) { 800f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Subscription Remediation subelement */ 801f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 802f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 803f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 804f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 osu_method; 805f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 806f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 807f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 808f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 809f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 810f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 811f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url_len == 0) { 812f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 813f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = NULL; 814f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = 1; 815f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } else { 816f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (pos + url_len + 1 > ie_end) { 817f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 818f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len, 819f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt (int) (ie_end - pos)); 820f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 821f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 822f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 823f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 824f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 825f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 826f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 827f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = pos[url_len]; 828f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 829f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_subscription_remediation(wpa_s, url, 830f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method); 831f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 832f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 833f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 834f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 835f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 836f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 837f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 838f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 839f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 840f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 841f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 842f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 code; 843f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u16 reauth_delay; 844f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 845f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 846f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 847f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code = *pos++; 848f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay = WPA_GET_LE16(pos); 849f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 2; 850f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 851f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 852f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Imminent - Reason Code %u " 853f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Re-Auth Delay %u URL Length %u", 854f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code, reauth_delay, url_len); 855f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (pos + url_len > ie_end) 856f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 857f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 858f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 859f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 860f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 861f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 862f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_deauth_imminent_notice(wpa_s, code, 863f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay, url); 864f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 865f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 866f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 867f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 868f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */ 869f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 870f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 871f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 872f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 873f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 874f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 875f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 876f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *frm, int len) 877f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 878f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end; 879f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 dialog_token, type; 880f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 881f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Dialog Token [1] | Type [1] | Subelements */ 882f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 883f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (len < 2 || sa == NULL) 884f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 885f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = frm + len; 886f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = frm; 887f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token = *pos++; 888f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt type = *pos++; 889f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 890f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 891f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "(dialog_token %u type %u sa " MACSTR ")", 892f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token, type, MAC2STR(sa)); 893f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 894f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos, end - pos); 895f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 896f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED || 897f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 898f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 899f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "from our AP - ignore it"); 900f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 901f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 902f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 903f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt switch (type) { 904f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 1: 905f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 906f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 907f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt default: 908f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 909f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "WNM-Notification type %u", type); 910f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 911f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 912f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 913f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 914f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 91561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 916fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 91761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 918a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 919a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 act; 920a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 921fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (len < IEEE80211_HDRLEN + 2) 922a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 923a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 924623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 925a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act = *pos++; 926fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt end = ((const u8 *) mgmt) + len; 927a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 928a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 929fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt act, MAC2STR(mgmt->sa)); 930a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wpa_s->wpa_state < WPA_ASSOCIATED || 931fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 932a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 933a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "frame"); 934a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 935a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 93661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 93761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (act) { 938a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case WNM_BSS_TRANS_MGMT_REQ: 939a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 940fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt !(mgmt->da[0] & 0x01)); 941a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 94261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WNM_SLEEP_MODE_RESP: 943fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 94461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 945f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case WNM_NOTIFICATION_REQ: 946f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 947f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 94861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 94944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "WNM: Unknown request"); 95061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 95161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 95261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 953