wnm_sta.c revision d80a401aed31d06f261efd19223cf55d1a2a8228
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" 13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_common.h" 14f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt#include "common/wpa_ctrl.h" 1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "rsn_supp/wpa.h" 16a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "wpa_supplicant_i.h" 17a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "driver_i.h" 18a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "scan.h" 1944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "ctrl_iface.h" 2044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "bss.h" 2144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "wnm_sta.h" 22f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#include "hs20_supplicant.h" 2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define MAX_TFS_IE_LEN 1024 2544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#define WNM_MAX_NEIGHBOR_REPORT 10 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* get the TFS IE from driver */ 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 *buf_len, enum wnm_oper oper) 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* set the TFS IE to driver */ 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 40d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *addr, const u8 *buf, u16 buf_len, 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper oper) 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 43d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt u16 len = buf_len; 44d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* MLME-SLEEPMODE.request */ 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 53a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 action, u16 intval, struct wpabuf *tfs_req) 5461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct ieee80211_mgmt *mgmt; 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int res; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t len; 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie; 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *wnmtfs_ie; 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 wnmsleep_ie_len; 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WNM_SLEEP_TFS_REQ_IE_NONE; 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 65a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 66a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "action=%s to " MACSTR, 67a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt action == 0 ? "enter" : "exit", 68a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid)); 69a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* WNM-Sleep Mode IE */ 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmsleep_ie == NULL) 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->len = wnmsleep_ie_len - 2; 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type = action; 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 79a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->intval = host_to_le16(intval); 80a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmsleep_ie, wnmsleep_ie_len); 8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* TFS IE(s) */ 84a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfs_req) { 85a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = wpabuf_len(tfs_req); 86a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_malloc(wnmtfs_ie_len); 87a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 88a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 89a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 90a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 91a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 92a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else { 93a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 94a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 95a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 96a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 97a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 98a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 99a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfs_oper)) { 100a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = 0; 101a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = NULL; 103a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 105a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 106a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmtfs_ie, wnmtfs_ie_len); 10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (mgmt == NULL) { 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "WNM-Sleep Request action frame"); 112a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 113a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WLAN_FC_STYPE_ACTION); 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 124a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len); 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* copy TFS IE here */ 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmtfs_ie_len > 0) { 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmtfs_ie_len; 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt &mgmt->u.action.category, len, 0); 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (res < 0) 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", action, intval); 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmsleep_ie); 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmtfs_ie); 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(mgmt); 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return res; 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 151a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 152d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start, 153d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end) 154a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 155a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->bssid, NULL, NULL); 157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* remove GTK/IGTK ?? */ 158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 159a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* set the TFS Resp IE(s) */ 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfsresp_ie_start && tfsresp_ie_end && 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end - tfsresp_ie_start >= 0) { 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u16 tfsresp_ie_len; 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start; 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pass the TFS Resp IE(s) to driver for processing */ 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start, 169d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt tfsresp_ie_len, 170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_TFS_RESP_IE_SET)) 171a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 172a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *frm, u16 key_len_total) 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *ptr, *end; 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 gtk_len; 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt NULL, NULL); 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Install GTK/IGTK */ 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* point to key data field */ 188fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ptr = (u8 *) frm + 1 + 2; 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = ptr + key_len_total; 190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 192d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - ptr > 1) { 193d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ptr[1] > end - ptr) { 194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "length"); 196a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (end > ptr) { 197a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 198a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr, end - ptr); 199a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 200a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + 5) { 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len = *(ptr + 4); 209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + gtk_len || 210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len < 5 || gtk_len > 32) { 211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key( 216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->wpa, 217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_GTK, 218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr); 219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 13 + gtk_len; 220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W 221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key(wpa_s->wpa, 228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_IGTK, ptr); 229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 10 + WPA_IGTK_LEN; 230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */ 231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else 232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; /* skip the loop */ 233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 234a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 23861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *frm, int len) 23961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 24061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 24121de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 24261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * WNM-Sleep Mode IE | TFS Response IE 24361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 244d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *pos = frm; /* point to payload after the action field */ 24521de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt u16 key_len_total; 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie = NULL; 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* multiple TFS Resp IE (assuming consecutive) */ 248d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start = NULL; 249d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end = NULL; 250fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t left; 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 25221de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt if (len < 3) 25321de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt return; 25421de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt key_len_total = WPA_GET_LE16(frm + 1); 25521de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt 256fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 257fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt frm[0], key_len_total); 258fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt left = len - 3; 259fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (key_len_total > left) { 260a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 261a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 262a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 263fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt pos += 3 + key_len_total; 264d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (pos - frm + 1 < len) { 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 ie_len = *(pos + 1); 266d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ie_len > frm + len - pos) { 267a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 268a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 269a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 270a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 271d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) 27261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = (struct wnm_sleep_element *) pos; 27361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else if (*pos == WLAN_EID_TFS_RESP) { 27461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!tfsresp_ie_start) 27561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_start = pos; 27661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_end = pos; 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += ie_len + 2; 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!wnmsleep_ie) { 28361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 28461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 28561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 287a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 288a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "frame (action=%d, intval=%d)", 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 292a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 293a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 294a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end); 295a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 296a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 302a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 305a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 30761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 30861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 30961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 31061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 31244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 31344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 31444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int i; 31544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 31644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 31744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 31844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 31944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 32044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32121de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 32244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 32344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = NULL; 32444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 32544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 32744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 32844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, u8 elen, const u8 *pos) 32944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 33044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt switch (id) { 33144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_TSF: 33244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2 + 2) { 33344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 33444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 33544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 336fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_offset = WPA_GET_LE16(pos); 337fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->beacon_int = WPA_GET_LE16(pos + 2); 338fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_present = 1; 33944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 34144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 34244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 34344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "country string"); 34444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 346fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->country, pos, 2); 347fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->country_present = 1; 34844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 35044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 1) { 35144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 35244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "candidate"); 35344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 355fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference = pos[0]; 356fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference_present = 1; 35744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 359fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_tsf = WPA_GET_LE64(pos); 360fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_dur = WPA_GET_LE16(pos + 8); 361fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_present = 1; 36244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BEARING: 36444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 8) { 36544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 36644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "bearing"); 36744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 369fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing = WPA_GET_LE16(pos); 370fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->distance = WPA_GET_LE32(pos + 2); 371fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rel_height = WPA_GET_LE16(pos + 2 + 4); 372fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing_present = 1; 37344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MEASUREMENT_PILOT: 375f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 37644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 37744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "pilot"); 37844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 380f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->meas_pilot); 38144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 38244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->meas_pilot == NULL) 38344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->measurement_pilot = pos[0]; 385f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->meas_pilot->subelem_len = elen - 1; 386f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 38744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 389f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 5) { 39044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 39144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "capabilities"); 39244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 394fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->rm_capab, pos, 5); 395fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rm_capab_present = 1; 39644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MULTIPLE_BSSID: 398f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 39944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 40044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 402f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->mul_bssid); 40344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 40444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->mul_bssid == NULL) 40544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->max_bssid_indicator = pos[0]; 407f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->mul_bssid->subelem_len = elen - 1; 408f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 40944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 41144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 41244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 41344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 414fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) 415fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 416fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 417fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const char *country = NULL; 418fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 419fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss) { 420fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); 421fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 422fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (elem && elem[1] >= 2) 423fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt country = (const char *) (elem + 2); 424fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 425fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 426fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return ieee80211_chan_to_freq(country, op_class, chan); 427fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 428fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 429fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 43044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 43144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt const u8 *pos, u8 len, 43244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *rep) 43344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 43444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 left = len; 43544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 43644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (left < 13) { 43744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 43844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 43944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 44044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 44144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid, pos, ETH_ALEN); 442fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); 44344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->regulatory_class = *(pos + 10); 44444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->channel_number = *(pos + 11); 44544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->phy_type = *(pos + 12); 44644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 44744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 13; 44844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 13; 44944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (left >= 2) { 45144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, elen; 45244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 45344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt id = *pos++; 45444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt elen = *pos++; 455f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 456f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= 2; 457f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen > left) { 458f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, 459f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt "WNM: Truncated neighbor report subelement"); 460f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt break; 461f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 46244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report_elem(rep, id, elen, pos); 463f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= elen; 46444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += elen; 46544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 466fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 467fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, 468fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->channel_number); 46944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 47044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 472fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct wpa_bss * 473fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtcompare_scan_neighbor_results(struct wpa_supplicant *wpa_s) 47444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 47544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 476fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 i; 477fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 478fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *target; 47944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 480fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) 48144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 48244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 483fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 484fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(wpa_s->bssid), bss->level); 485fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 486fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 487fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 488fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 489fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 490fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->preference_present && nei->preference == 0) { 491fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 492fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 493fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 494fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 495fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 496fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target = wpa_bss_get_bssid(wpa_s, nei->bssid); 497fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!target) { 498fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 499fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) not found in scan results", 500fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 501fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 502fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 503fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 504fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 505fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 506fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss->ssid_len != target->ssid_len || 507fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 508fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 509fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * TODO: Could consider allowing transition to another 510fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * ESS if PMF was enabled for the association. 511fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 512fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 513fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) in different ESS", 514fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 515fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 516fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 517fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 518fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 519fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 520fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (target->level < bss->level && target->level < -80) { 521fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 522fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) does not have sufficient signal level (%d)", 523fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 524fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 525fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1, 526fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target->level); 527fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 52844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 529fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 530fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 531fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Found an acceptable preferred transition candidate BSS " 532fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " (RSSI %d)", 533fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), target->level); 534fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return target; 53544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 53644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 537fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return NULL; 53844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 53944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 54044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 541f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtstatic void wnm_send_bss_transition_mgmt_resp( 542f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt struct wpa_supplicant *wpa_s, u8 dialog_token, 543f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status, u8 delay, 544f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt const u8 *target_bssid) 545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 buf[1000], *pos; 547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ieee80211_mgmt *mgmt; 548a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 549fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int res; 550a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 551a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 552a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "to " MACSTR " dialog_token=%u status=%u delay=%d", 553a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid), dialog_token, status, delay); 554fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss) { 555fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 556fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Current BSS not known - drop response"); 557fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 558fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WLAN_FC_STYPE_ACTION); 567a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 569a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 570a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.status_code = status; 571a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 572a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_resp.variable; 573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (target_bssid) { 574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(pos, target_bssid, ETH_ALEN); 575a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += ETH_ALEN; 576fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } else if (status == WNM_BSS_TM_ACCEPT) { 577fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* 578fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * P802.11-REVmc clarifies that the Target BSSID field is always 579fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * present when status code is zero, so use a fake value here if 580fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * no BSSID is yet known. 581fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt */ 582fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memset(pos, 0, ETH_ALEN); 583fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt pos += ETH_ALEN; 584a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 585a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 586a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 587a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 588fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 589fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 590fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &mgmt->u.action.category, len, 0); 591fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (res < 0) { 592fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 593fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Failed to send BSS Transition Management Response"); 594fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 596a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 597a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 598fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 59944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 600fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss; 601fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 602fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 60344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 604fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 605fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 606fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 607fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 608fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &wpa_s->scan_trigger_time)) { 609fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 610fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 611fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 612fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 613fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 614fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss || 615fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 616fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ETH_ALEN) != 0) { 617fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 618fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 61944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 62044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 62144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Compare the Neighbor Report and scan results */ 622fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bss = compare_scan_neighbor_results(wpa_s); 623fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) { 624fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 625fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 626fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto send_bss_resp_fail; 627fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 62844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 629fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Associate to the network */ 630fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Send the BSS Management Response - Accept */ 631fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->wnm_reply) { 632fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_reply = 0; 633fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 63444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 635f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_ACCEPT, 636fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0, bss->bssid); 637fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 63844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 639fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss == wpa_s->current_bss) { 640fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 641fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Already associated with the preferred candidate"); 642d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt wnm_deallocate_memory(wpa_s); 643fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 64444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 64544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 646fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->reassociate = 1; 647fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_supplicant_connect(wpa_s, bss, ssid); 64844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 649fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 650fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 651fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtsend_bss_resp_fail: 652fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!reply_on_fail) 653fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 654fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 655fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Send reject response for all the failures */ 656fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 65744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 658fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_reply = 0; 65944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 66044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 661fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status, 0, NULL); 66244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 663fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 664fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 665fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 666fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 667fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 668fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 669fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int cand_pref_compar(const void *a, const void *b) 670fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 671fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *aa = a; 672fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *bb = b; 673fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 674fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present && !bb->preference_present) 675fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 676fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present) 677fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 678fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bb->preference_present) 679fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 680fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference > aa->preference) 681fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 682fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference < aa->preference) 683fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 684fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 685fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 686fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 687fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 688fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 689fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 690fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 691fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 692fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt qsort(wpa_s->wnm_neighbor_report_elements, 693fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 694fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt cand_pref_compar); 695fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 696fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 697fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 698fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 699fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 700fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 701fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 702fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 703fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 704fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 705fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 706fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 707fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 708fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 709fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "%u: " MACSTR 710fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 711fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt i, MAC2STR(nei->bssid), nei->bssid_info, 712fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->regulatory_class, 713fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->channel_number, nei->phy_type, 714fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : -1, 715fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->freq); 716fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 717fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 718fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 719fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 720fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int chan_supported(struct wpa_supplicant *wpa_s, int freq) 721fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 722fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 723fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 724fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->hw.num_modes; i++) { 725fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 726fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int j; 727fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 728fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (j = 0; j < mode->num_channels; j++) { 729fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_channel_data *chan; 730fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 731fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt chan = &mode->channels[j]; 732fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan->freq == freq && 733fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt !(chan->flag & HOSTAPD_CHAN_DISABLED)) 734fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 735fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 736fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 737fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 738fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 739fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 740fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 741fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 742fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 743fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 744fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int *freqs; 745fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int num_freqs = 0; 746fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 747fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 748fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 749fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 750fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 751fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->hw.modes == NULL) 752fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 753fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 754fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(wpa_s->next_scan_freqs); 755fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = NULL; 756fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 757fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 758fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (freqs == NULL) 759fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 760fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 761fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 762fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 763fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 764fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 765fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->freq <= 0) { 766fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 767fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Unknown neighbor operating frequency for " 768fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " - scan all channels", 769fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 770fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 771fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 772fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 773fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan_supported(wpa_s, nei->freq)) 774fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt add_freq(freqs, &num_freqs, nei->freq); 775fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 776fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 777fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (num_freqs == 0) { 778fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 779fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 780fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 781fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 782fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 783fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Scan %d frequencies based on transition candidate list", 784fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt num_freqs); 785fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = freqs; 78644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 78744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 78844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 789a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 790a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, const u8 *end, 791a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int reply) 792a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 793fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int beacon_int; 794fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 valid_int; 795fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 796d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 5) 797a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 798a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 799fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->current_bss) 800fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = wpa_s->current_bss->beacon_int; 801fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else 802fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = 100; /* best guess */ 803fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 80444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token = pos[0]; 80544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_mode = pos[1]; 80644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 807fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_int = pos[4]; 80844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_reply = reply; 809a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 810a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 811a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "dialog_token=%u request_mode=0x%x " 812a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "disassoc_timer=%u validity_interval=%u", 81344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 814fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_dissoc_timer, valid_int); 81544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 816a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 5; 81744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 818f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 819d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 12) { 82044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 82144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 82244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 82344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 824a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 12; /* BSS Termination Duration */ 82544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 82644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 827f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 828a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char url[256]; 829f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 830d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 1 || 1 + pos[0] > end - pos) { 831a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 832a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "Management Request (URL)"); 833a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 834a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 835a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(url, pos + 1, pos[0]); 836a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt url[pos[0]] = '\0'; 83744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 1 + pos[0]; 838f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 839f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 840f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_sm_pmf_enabled(wpa_s->wpa), 841f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 842a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 843a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 844f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 845a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 84644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 84744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 848a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* TODO: mark current BSS less preferred for 849a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * selection */ 850a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 851a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 852a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 853a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 854a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 855f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 856fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int valid_ms; 857fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 85844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 859fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 860fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = os_calloc( 861fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WNM_MAX_NEIGHBOR_REPORT, 86244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt sizeof(struct neighbor_report)); 86344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_neighbor_report_elements == NULL) 86444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 86544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 866d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos >= 2 && 86744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 86844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt { 86944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 tag = *pos++; 87044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 len = *pos++; 87144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 87244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 87344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt tag); 874d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (len > end - pos) { 87544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 87644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 87744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 878f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (tag == WLAN_EID_NEIGHBOR_REPORT) { 879f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt struct neighbor_report *rep; 880f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep = &wpa_s->wnm_neighbor_report_elements[ 881f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_s->wnm_num_neighbor_report]; 882f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wnm_parse_neighbor_report(wpa_s, pos, len, rep); 883f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 88444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 88544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += len; 88644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report++; 88744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 888fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_sort_cand_list(wpa_s); 889fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_dump_cand_list(wpa_s); 890fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms = valid_int * beacon_int * 128 / 125; 891fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 892fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms); 893fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&wpa_s->wnm_cand_valid_until); 894fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 895fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 896fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += 897fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec / 1000000; 898fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec %= 1000000; 899fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 900fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 901fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->last_scan_res_used > 0) { 902fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct os_reltime now; 903fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 904fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&now); 905fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 906fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 907fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Try to use recent scan results"); 908fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wnm_scan_process(wpa_s, 0) > 0) 909fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 910fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 911fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: No match in previous scan results - try a new scan"); 912fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 913fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 91444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 915fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_set_scan_freqs(wpa_s); 91644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 91744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } else if (reply) { 918f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status; 919f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 920f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_ACCEPT; 921f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else { 922f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 923f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_REJECT_UNSPECIFIED; 924f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt } 92544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 92644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 927f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status, 0, NULL); 928a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 929a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 930a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 931a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 93244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtint wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 93344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 query_reason) 93444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 93544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 buf[1000], *pos; 93644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct ieee80211_mgmt *mgmt; 93744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt size_t len; 93844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int ret; 93944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 94044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 94144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MACSTR " query_reason=%u", 94244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt MAC2STR(wpa_s->bssid), query_reason); 94344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 94444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 94544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 94644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 94744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 94844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 94944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 95044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WLAN_FC_STYPE_ACTION); 95144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 95244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 953fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt mgmt->u.action.u.bss_tm_query.dialog_token = 1; 95444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 95544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_query.variable; 95644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 95744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 95844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 95944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 96044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 96144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &mgmt->u.action.category, len, 0); 96244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 96344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return ret; 96444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 96544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 96644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 967f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 968f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *data, 969f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int len) 970f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 971f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end, *next; 972f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 ie, ie_len; 973f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 974f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = data; 975f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = data + len; 976f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 977d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos > 1) { 978f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie = *pos++; 979f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_len = *pos++; 980f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 981f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie, ie_len); 982f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len > end - pos) { 983f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 984f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 985f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 986f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 987f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt next = pos + ie_len; 988f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len < 4) { 989f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 990f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 991f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 992f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 993f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos), pos[3]); 994f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 995f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20 996f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 997f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 998f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_SUB_REM_NEEDED) { 999f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Subscription Remediation subelement */ 1000f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1001f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1002f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1003f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 osu_method; 1004f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1005f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1006f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 1007f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1008f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1009f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1010f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url_len == 0) { 1011f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1012f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = NULL; 1013f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = 1; 1014f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } else { 1015d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len + 1 > ie_end - pos) { 1016f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1017f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len, 1018f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt (int) (ie_end - pos)); 1019f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1020f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1021f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1022f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1023f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1024f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1025f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1026f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = pos[url_len]; 1027f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1028f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_subscription_remediation(wpa_s, url, 1029f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method); 1030f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1031f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1032f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1033f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1034f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1035f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1036f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 1037f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1038f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1039f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1040f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1041f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 code; 1042f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u16 reauth_delay; 1043f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1044f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1045f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1046f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code = *pos++; 1047f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay = WPA_GET_LE16(pos); 1048f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 2; 1049f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1050f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1051f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Imminent - Reason Code %u " 1052f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Re-Auth Delay %u URL Length %u", 1053f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code, reauth_delay, url_len); 1054d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len > ie_end - pos) 1055f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1056f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1057f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1058f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1059f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1060f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1061f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_deauth_imminent_notice(wpa_s, code, 1062f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay, url); 1063f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1064f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1065f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1066f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1067f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */ 1068f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1069f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1070f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1071f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1072f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1073f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1074f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1075f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *frm, int len) 1076f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1077f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end; 1078f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 dialog_token, type; 1079f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1080f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Dialog Token [1] | Type [1] | Subelements */ 1081f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1082f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (len < 2 || sa == NULL) 1083f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1084f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = frm + len; 1085f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = frm; 1086f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token = *pos++; 1087f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt type = *pos++; 1088f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1089f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1090f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "(dialog_token %u type %u sa " MACSTR ")", 1091f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token, type, MAC2STR(sa)); 1092f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1093f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos, end - pos); 1094f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1095f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED || 1096f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1097f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1098f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "from our AP - ignore it"); 1099f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1102f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt switch (type) { 1103f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 1: 1104f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1105f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1106f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt default: 1107f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1108f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "WNM-Notification type %u", type); 1109f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1110f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1111f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1112f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1113f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 111461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1115fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 111661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 1117a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 1118a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 act; 1119a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1120fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (len < IEEE80211_HDRLEN + 2) 1121a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1122a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1123623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1124a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act = *pos++; 1125fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt end = ((const u8 *) mgmt) + len; 1126a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1127a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1128fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt act, MAC2STR(mgmt->sa)); 1129a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wpa_s->wpa_state < WPA_ASSOCIATED || 1130fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1131a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1132a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "frame"); 1133a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1134a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 113561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 113661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (act) { 1137a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case WNM_BSS_TRANS_MGMT_REQ: 1138a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1139fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt !(mgmt->da[0] & 0x01)); 1140a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 114161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WNM_SLEEP_MODE_RESP: 1142fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 114361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 1144f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case WNM_NOTIFICATION_REQ: 1145f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1146f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 114761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 114844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "WNM: Unknown request"); 114961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 115061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 115161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 1152