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 27849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */ 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* get the TFS IE from driver */ 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 *buf_len, enum wnm_oper oper) 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* set the TFS IE to driver */ 4061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 41d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *addr, const u8 *buf, u16 buf_len, 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper oper) 4361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 44d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt u16 len = buf_len; 45d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 4761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 48d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* MLME-SLEEPMODE.request */ 5361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 54a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 action, u16 intval, struct wpabuf *tfs_req) 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct ieee80211_mgmt *mgmt; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int res; 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t len; 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie; 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *wnmtfs_ie; 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 wnmsleep_ie_len; 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WNM_SLEEP_TFS_REQ_IE_NONE; 6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 66a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 67a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "action=%s to " MACSTR, 68a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt action == 0 ? "enter" : "exit", 69a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid)); 70a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* WNM-Sleep Mode IE */ 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmsleep_ie == NULL) 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->len = wnmsleep_ie_len - 2; 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type = action; 7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 80a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->intval = host_to_le16(intval); 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 82a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmsleep_ie, wnmsleep_ie_len); 8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* TFS IE(s) */ 85a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfs_req) { 86a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = wpabuf_len(tfs_req); 87a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_malloc(wnmtfs_ie_len); 88a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 89a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 90a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 91a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 92a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 93a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else { 94a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 95a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 96a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 97a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 98a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 99a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 100a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfs_oper)) { 101a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = 0; 102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 103a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = NULL; 104a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 106a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 107a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmtfs_ie, wnmtfs_ie_len); 10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (mgmt == NULL) { 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "WNM-Sleep Request action frame"); 113a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 114a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WLAN_FC_STYPE_ACTION); 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 125a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len); 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* copy TFS IE here */ 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmtfs_ie_len > 0) { 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmtfs_ie_len; 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt &mgmt->u.action.category, len, 0); 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (res < 0) 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", action, intval); 143b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt else 144b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt wpa_s->wnmsleep_used = 1; 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmsleep_ie); 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmtfs_ie); 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(mgmt); 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return res; 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 154a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 155d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start, 156d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end) 157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 159a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->bssid, NULL, NULL); 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* remove GTK/IGTK ?? */ 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* set the TFS Resp IE(s) */ 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfsresp_ie_start && tfsresp_ie_end && 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end - tfsresp_ie_start >= 0) { 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u16 tfsresp_ie_len; 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start; 168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 169a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pass the TFS Resp IE(s) to driver for processing */ 170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 171a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start, 172d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt tfsresp_ie_len, 173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_TFS_RESP_IE_SET)) 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *frm, u16 key_len_total) 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *ptr, *end; 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 gtk_len; 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt NULL, NULL); 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Install GTK/IGTK */ 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* point to key data field */ 191fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ptr = (u8 *) frm + 1 + 2; 192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = ptr + key_len_total; 193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 19517de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { 19617de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen wpa_msg(wpa_s, MSG_INFO, 19717de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); 19817de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen return; 19917de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen } 20017de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen 201d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - ptr > 1) { 202d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ptr[1] > end - ptr) { 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "length"); 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (end > ptr) { 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr, end - ptr); 208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + 5) { 213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len = *(ptr + 4); 218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + gtk_len || 219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len < 5 || gtk_len > 32) { 220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key( 225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->wpa, 226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_GTK, 227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr); 228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 13 + gtk_len; 229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W 230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 234a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key(wpa_s->wpa, 237a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_IGTK, ptr); 238a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 10 + WPA_IGTK_LEN; 239a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */ 240a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else 241a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; /* skip the loop */ 242a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 243a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 244a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 245a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *frm, int len) 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 25021de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * WNM-Sleep Mode IE | TFS Response IE 25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 253d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *pos = frm; /* point to payload after the action field */ 25421de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt u16 key_len_total; 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie = NULL; 25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* multiple TFS Resp IE (assuming consecutive) */ 257d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start = NULL; 258d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end = NULL; 259fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t left; 26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 261b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt if (!wpa_s->wnmsleep_used) { 262b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt wpa_printf(MSG_DEBUG, 263b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association"); 264b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt return; 265b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt } 266b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt 26721de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt if (len < 3) 26821de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt return; 26921de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt key_len_total = WPA_GET_LE16(frm + 1); 27021de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt 271fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 272fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt frm[0], key_len_total); 273fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt left = len - 3; 274fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (key_len_total > left) { 275a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 276a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 277a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 278fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt pos += 3 + key_len_total; 279d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (pos - frm + 1 < len) { 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 ie_len = *(pos + 1); 281d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ie_len > frm + len - pos) { 282a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 283a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 284a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 285a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 286d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = (struct wnm_sleep_element *) pos; 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else if (*pos == WLAN_EID_TFS_RESP) { 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!tfsresp_ie_start) 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_start = pos; 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_end = pos; 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += ie_len + 2; 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!wnmsleep_ie) { 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 30161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 302a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 303a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "frame (action=%d, intval=%d)", 30661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 307a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 308a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 309a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end); 310a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 311a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", 31661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 317a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 31961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 320a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 32744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 32844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 32944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int i; 33044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 33144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 33244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 33344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 33444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 33544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 33621de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 33744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 33844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = NULL; 33944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 34044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 34144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 34244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 34344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, u8 elen, const u8 *pos) 34444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 34544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt switch (id) { 34644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_TSF: 34744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2 + 2) { 34844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 34944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 351fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_offset = WPA_GET_LE16(pos); 352fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->beacon_int = WPA_GET_LE16(pos + 2); 353fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_present = 1; 35444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 35644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 35744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 35844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "country string"); 35944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 361fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->country, pos, 2); 362fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->country_present = 1; 36344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 36544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 1) { 36644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 36744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "candidate"); 36844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 370fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference = pos[0]; 371fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference_present = 1; 37244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 374fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_tsf = WPA_GET_LE64(pos); 375fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_dur = WPA_GET_LE16(pos + 8); 376fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_present = 1; 37744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BEARING: 37944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 8) { 38044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 38144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "bearing"); 38244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 384fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing = WPA_GET_LE16(pos); 385fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->distance = WPA_GET_LE32(pos + 2); 386fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rel_height = WPA_GET_LE16(pos + 2 + 4); 387fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing_present = 1; 38844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MEASUREMENT_PILOT: 390f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 39144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 39244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "pilot"); 39344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 395f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->meas_pilot); 39644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 39744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->meas_pilot == NULL) 39844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->measurement_pilot = pos[0]; 400f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->meas_pilot->subelem_len = elen - 1; 401f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 40244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 404f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 5) { 40544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 40644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "capabilities"); 40744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 409fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->rm_capab, pos, 5); 410fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rm_capab_present = 1; 41144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MULTIPLE_BSSID: 413f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 41444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 41544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 417f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->mul_bssid); 41844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 41944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->mul_bssid == NULL) 42044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->max_bssid_indicator = pos[0]; 422f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->mul_bssid->subelem_len = elen - 1; 423f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 42444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 42644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 42744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 42844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 429fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) 430fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 431fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 432fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const char *country = NULL; 433b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt int freq; 434fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 435fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss) { 436fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); 437fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 438fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (elem && elem[1] >= 2) 439fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt country = (const char *) (elem + 2); 440fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 441fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 442b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = ieee80211_chan_to_freq(country, op_class, chan); 443b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt if (freq <= 0 && op_class == 0) { 444b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt /* 445b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * Some APs do not advertise correct operating class 446b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * information. Try to determine the most likely operating 447b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * frequency based on the channel number. 448b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt */ 449b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt if (chan >= 1 && chan <= 13) 450b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 2407 + chan * 5; 451b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt else if (chan == 14) 452b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 2484; 453b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt else if (chan >= 36 && chan <= 169) 454b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 5000 + chan * 5; 455b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt } 456b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt return freq; 457fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 458fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 459fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 46044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 46144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt const u8 *pos, u8 len, 46244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *rep) 46344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 46444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 left = len; 46544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 46644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (left < 13) { 46744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 46844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 46944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 47044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid, pos, ETH_ALEN); 472fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); 47344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->regulatory_class = *(pos + 10); 47444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->channel_number = *(pos + 11); 47544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->phy_type = *(pos + 12); 47644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 13; 47844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 13; 47944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 48044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (left >= 2) { 48144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, elen; 48244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 48344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt id = *pos++; 48444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt elen = *pos++; 485f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 486f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= 2; 487f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen > left) { 488f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, 489f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt "WNM: Truncated neighbor report subelement"); 490f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt break; 491f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 49244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report_elem(rep, id, elen, pos); 493f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= elen; 49444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += elen; 49544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 496fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 497fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, 498fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->channel_number); 49944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 50044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 50144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 502fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct wpa_bss * 503849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtcompare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs) 50444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 50544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 506fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 i; 507fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 508fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *target; 50944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 510fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) 5114ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt return NULL; 51244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 513fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 514fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(wpa_s->bssid), bss->level); 515fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 516fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 517fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 518fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 519fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 520fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->preference_present && nei->preference == 0) { 521fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 522fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 523fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 524fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 525fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 526fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target = wpa_bss_get_bssid(wpa_s, nei->bssid); 527fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!target) { 528fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 529fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) not found in scan results", 530fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 531fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 532fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 533fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 534fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 535fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 536849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (age_secs) { 537849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct os_reltime now; 538849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 539849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (os_get_reltime(&now) == 0 && 540849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_reltime_expired(&now, &target->last_update, 541849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt age_secs)) { 542849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 543849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Candidate BSS is more than %ld seconds old", 544849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt age_secs); 545849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 546849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 547849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 548849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 549fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss->ssid_len != target->ssid_len || 550fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 551fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 552fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * TODO: Could consider allowing transition to another 553fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * ESS if PMF was enabled for the association. 554fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 555fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 556fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) in different ESS", 557fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 558fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 559fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 560fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 561fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 562fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 563e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt if (wpa_s->current_ssid && 564e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 565abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt 1, 0)) { 566e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 567e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt " (pref %d) does not match the current network profile", 568e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt MAC2STR(nei->bssid), 569e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt nei->preference_present ? nei->preference : 570e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt -1); 571e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt continue; 572e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt } 573e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt 57457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { 57557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 57657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "MBO: Candidate BSS " MACSTR 57757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt " retry delay is not over yet", 57857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(nei->bssid)); 57957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt continue; 58057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 58157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 582fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (target->level < bss->level && target->level < -80) { 583fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 584fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) does not have sufficient signal level (%d)", 585fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 586fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 587fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1, 588fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target->level); 589fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 59044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 591fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 592fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 593fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Found an acceptable preferred transition candidate BSS " 594fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " (RSSI %d)", 595fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), target->level); 596fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return target; 59744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 59844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 599fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return NULL; 60044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 60144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 60244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 60357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) 60457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 60557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *ie_a, *ie_b; 60657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 60757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!a || !b) 60857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 60957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 61057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_a = wpa_bss_get_ie(a, eid); 61157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_b = wpa_bss_get_ie(b, eid); 61257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 61357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) 61457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 61557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 61657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; 61757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 61857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 61957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 62157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 62257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u32 info = 0; 62357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; 62557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* 62757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * Leave the security and key scope bits unset to indicate that the 62857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * security information is not available. 62957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 63057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 63157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) 63257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 63357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_QOS) 63457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_QOS; 63557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_APSD) 63657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_APSD; 63757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) 63857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_RM; 63957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) 64057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_DELAYED_BA; 64157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) 64257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_IMM_BA; 64357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) 64457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; 64557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) 64657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_HT; 64757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 64857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return info; 64957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 65057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 65157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 65257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, 65357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 op_class, u8 chan, u8 phy_type, u8 pref) 65457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 65557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 *pos = buf; 65657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 65757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (len < 18) { 65857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 65957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Not enough room for Neighbor Report element"); 66057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -1; 66157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 66257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 66357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = WLAN_EID_NEIGHBOR_REPORT; 66457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* length: 13 for basic neighbor report + 3 for preference subelement */ 66557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = 16; 66657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_memcpy(pos, bssid, ETH_ALEN); 66757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += ETH_ALEN; 66857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt WPA_PUT_LE32(pos, bss_info); 66957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += 4; 67057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = op_class; 67157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = chan; 67257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = phy_type; 67357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; 67457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = 1; 67557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = pref; 67657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 67757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 67857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 67957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 68057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, 68157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_bss *bss, u8 *buf, size_t len, 68257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 pref) 68357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 68457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *ie; 68557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 op_class, chan; 68657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int sec_chan = 0, vht = 0; 68757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt enum phy_type phy_type; 68857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u32 info; 68957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct ieee80211_ht_operation *ht_oper = NULL; 69057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct ieee80211_vht_operation *vht_oper = NULL; 69157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 69257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); 69357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ie && ie[1] >= 2) { 69457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 69557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 69657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 69757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sec_chan = 1; 69857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt else if (ht_oper->ht_param & 69957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 70057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sec_chan = -1; 70157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 70257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 70357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); 70457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ie && ie[1] >= 1) { 70557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 70657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 70757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || 70857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || 70957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) 71057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht = vht_oper->vht_op_info_chwidth; 71157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 71257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 71357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, 71457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt &chan) == NUM_HOSTAPD_MODES) { 71557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 71657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Cannot determine operating class and channel"); 71757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -2; 71857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 71957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 72057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), 72157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt (vht_oper != NULL)); 72257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (phy_type == PHY_TYPE_UNSPECIFIED) { 72357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 72457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Cannot determine BSS phy type for Neighbor Report"); 72557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -2; 72657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 72757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 72857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info = wnm_get_bss_info(wpa_s, bss); 72957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 73057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, 73157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt phy_type, pref); 73257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 73357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 73457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 73557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) 73657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 73757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 *pos = buf; 73857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt unsigned int i, pref = 255; 73957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct os_reltime now; 74057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 74157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 74257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!ssid) 74357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 74457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 74557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* 74657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * TODO: Define when scan results are no longer valid for the candidate 74757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * list. 74857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 74957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_get_reltime(&now); 75057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) 75157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 75257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 75357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 75457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Add candidate list to BSS Transition Management Response frame"); 75557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { 75657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_bss *bss = wpa_s->last_scan_res[i]; 75757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int res; 75857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 759abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { 76057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); 76157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (res == -2) 76257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt continue; /* could not build entry for BSS */ 76357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (res < 0) 76457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; /* no more room for candidates */ 76557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (pref == 1) 76657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 76757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 76857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += res; 76957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt len -= res; 77057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 77157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 77257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 77357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 77457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: BSS Transition Management Response candidate list", 77557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt buf, pos - buf); 77657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 77757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 77857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 77957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 78057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 781f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtstatic void wnm_send_bss_transition_mgmt_resp( 782f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt struct wpa_supplicant *wpa_s, u8 dialog_token, 783f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status, u8 delay, 784f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt const u8 *target_bssid) 785a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 78657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 buf[2000], *pos; 787a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ieee80211_mgmt *mgmt; 788a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 789fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int res; 790a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 791a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 792a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "to " MACSTR " dialog_token=%u status=%u delay=%d", 793a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid), dialog_token, status, delay); 794fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss) { 795fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 796fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Current BSS not known - drop response"); 797fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 798fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 799a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 800a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 801a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 802a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 803a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 804a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 805a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 806a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WLAN_FC_STYPE_ACTION); 807a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 808a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 809a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 810a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.status_code = status; 811a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 812a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_resp.variable; 813a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (target_bssid) { 814a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(pos, target_bssid, ETH_ALEN); 815a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += ETH_ALEN; 816fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } else if (status == WNM_BSS_TM_ACCEPT) { 817fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* 818fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * P802.11-REVmc clarifies that the Target BSSID field is always 819fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * present when status code is zero, so use a fake value here if 820fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * no BSSID is yet known. 821fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt */ 822fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memset(pos, 0, ETH_ALEN); 823fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt pos += ETH_ALEN; 824a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 825a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 82657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (status == WNM_BSS_TM_ACCEPT) 82757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 82857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 82957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 83057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (status != WNM_BSS_TM_ACCEPT) { 83157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wpas_mbo_ie_bss_trans_reject( 83257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_s, pos, buf + sizeof(buf) - pos, 83357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MBO_TRANSITION_REJECT_REASON_UNSPECIFIED); 83457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 83557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 83657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 837a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 838a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 839fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 840fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 841fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &mgmt->u.action.category, len, 0); 842fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (res < 0) { 843fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 844fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Failed to send BSS Transition Management Response"); 845fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 846a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 847a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 848a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 849849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, 850849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_bss *bss, struct wpa_ssid *ssid, 851849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int after_new_scan) 852849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 853849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, 854849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Transition to BSS " MACSTR 855849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt " based on BSS Transition Management Request (old BSSID " 856849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt MACSTR " after_new_scan=%d)", 857849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan); 858849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 859849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Send the BSS Management Response - Accept */ 860849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (wpa_s->wnm_reply) { 861849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_s->wnm_reply = 0; 862849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 863849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Sending successful BSS Transition Management Response"); 864849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 865849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_s->wnm_dialog_token, 866849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt WNM_BSS_TM_ACCEPT, 867849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 0, bss->bssid); 868849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 869849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 870849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (bss == wpa_s->current_bss) { 871849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 872849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Already associated with the preferred candidate"); 873849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wnm_deallocate_memory(wpa_s); 874849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 875849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 876849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 877849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_s->reassociate = 1; 878849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Issuing connect"); 879849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_supplicant_connect(wpa_s, bss, ssid); 880849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wnm_deallocate_memory(wpa_s); 881849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 882849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 883849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 884fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 88544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 886fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss; 887fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 888fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 88944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 890fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 891fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 892fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 893849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, 894849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Process scan results for BSS Transition Management"); 895fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 896fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &wpa_s->scan_trigger_time)) { 897fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 898fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 899fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 900fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 901fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 902fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss || 903fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 904fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ETH_ALEN) != 0) { 905fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 906fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 90744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 90844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 90944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Compare the Neighbor Report and scan results */ 910849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt bss = compare_scan_neighbor_results(wpa_s, 0); 911fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) { 912fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 913fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 914fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto send_bss_resp_fail; 915fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 91644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 917fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Associate to the network */ 918849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wnm_bss_tm_connect(wpa_s, bss, ssid, 1); 919fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 920fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 921fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtsend_bss_resp_fail: 922fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!reply_on_fail) 923fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 924fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 925fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Send reject response for all the failures */ 926fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 92744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 928fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_reply = 0; 92944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 93044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 931fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status, 0, NULL); 93244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 933fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 934fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 935fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 936fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 937fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 938fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 939fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int cand_pref_compar(const void *a, const void *b) 940fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 941fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *aa = a; 942fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *bb = b; 943fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 944fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present && !bb->preference_present) 945fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 946fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present) 947fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 948fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bb->preference_present) 949fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 950fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference > aa->preference) 951fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 952fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference < aa->preference) 953fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 954fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 955fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 956fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 957fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 958fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 959fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 960fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 961fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 962fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt qsort(wpa_s->wnm_neighbor_report_elements, 963fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 964fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt cand_pref_compar); 965fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 966fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 967fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 968fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 969fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 970fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 971fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 972fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 973fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 974fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 975fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 976fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 977fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 978fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 979fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "%u: " MACSTR 980fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 981fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt i, MAC2STR(nei->bssid), nei->bssid_info, 982fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->regulatory_class, 983fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->channel_number, nei->phy_type, 984fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : -1, 985fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->freq); 986fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 987fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 988fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 989fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 990fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int chan_supported(struct wpa_supplicant *wpa_s, int freq) 991fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 992fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 993fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 994fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->hw.num_modes; i++) { 995fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 996fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int j; 997fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 998fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (j = 0; j < mode->num_channels; j++) { 999fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_channel_data *chan; 1000fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1001fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt chan = &mode->channels[j]; 1002fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan->freq == freq && 1003fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt !(chan->flag & HOSTAPD_CHAN_DISABLED)) 1004fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 1005fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1006fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1007fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1008fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 1009fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 1010fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1011fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1012fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 1013fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 1014fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int *freqs; 1015fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int num_freqs = 0; 1016fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 1017fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1018fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 1019fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1020fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1021fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->hw.modes == NULL) 1022fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1023fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1024fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(wpa_s->next_scan_freqs); 1025fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = NULL; 1026fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1027fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 1028fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (freqs == NULL) 1029fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1030fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1031fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1032fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 1033fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1034fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 1035fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->freq <= 0) { 1036fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1037fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Unknown neighbor operating frequency for " 1038fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " - scan all channels", 1039fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 1040fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 1041fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1042fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1043fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan_supported(wpa_s, nei->freq)) 1044fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt add_freq(freqs, &num_freqs, nei->freq); 1045fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1046fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1047fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (num_freqs == 0) { 1048fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 1049fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1050fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1051fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1052fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1053fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Scan %d frequencies based on transition candidate list", 1054fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt num_freqs); 1055fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = freqs; 105644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 105744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 105844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1059849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) 1060849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 1061849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_scan_results *scan_res; 1062849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_bss *bss; 1063849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 1064849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 i, found = 0; 1065849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt size_t j; 1066849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1067849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, 1068849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Fetch current scan results from the driver for checking transition candidates"); 1069849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt scan_res = wpa_drv_get_scan_results2(wpa_s); 1070849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!scan_res) { 1071849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); 1072849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 1073849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1074849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1075849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (scan_res->fetch_time.sec == 0) 1076849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_get_reltime(&scan_res->fetch_time); 1077849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1078849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt filter_scan_res(wpa_s, scan_res); 1079849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1080849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 1081849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct neighbor_report *nei; 1082849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1083849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 1084849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (nei->preference_present && nei->preference == 0) 1085849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 1086849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1087849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt for (j = 0; j < scan_res->num; j++) { 1088849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_scan_res *res; 1089849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *ssid_ie; 1090849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1091849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt res = scan_res->res[j]; 1092849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || 1093849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt res->age > WNM_SCAN_RESULT_AGE * 1000) 1094849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 1095849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt bss = wpa_s->current_bss; 1096849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); 1097849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (bss && ssid_ie && 1098849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt (bss->ssid_len != ssid_ie[1] || 1099849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_memcmp(bss->ssid, ssid_ie + 2, 1100849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt bss->ssid_len) != 0)) 1101849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 1102849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1103849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Potential candidate found */ 1104849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt found = 1; 1105849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt scan_snr(res); 1106849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt scan_est_throughput(wpa_s, res); 1107849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_bss_update_scan_res(wpa_s, res, 1108849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt &scan_res->fetch_time); 1109849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1110849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1111849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1112849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_scan_results_free(scan_res); 1113849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!found) { 1114849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, 1115849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: No transition candidate matches existing scan results"); 1116849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 1117849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1118849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1119849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE); 1120849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!bss) { 1121849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, 1122849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "WNM: Comparison of scan results against transition candidates did not find matches"); 1123849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 1124849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 1125849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1126849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Associate to the network */ 1127849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wnm_bss_tm_connect(wpa_s, bss, ssid, 0); 1128849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 1; 1129849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 1130849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1131849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1132a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1133a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, const u8 *end, 1134a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int reply) 1135a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 1136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int beacon_int; 1137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 valid_int; 113857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 113957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *vendor; 114057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 1141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1142d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 5) 1143a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1144a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->current_bss) 1146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = wpa_s->current_bss->beacon_int; 1147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else 1148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = 100; /* best guess */ 1149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 115044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token = pos[0]; 115144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_mode = pos[1]; 115244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_int = pos[4]; 115444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_reply = reply; 1155a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "dialog_token=%u request_mode=0x%x " 1158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "disassoc_timer=%u validity_interval=%u", 115944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1160fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_dissoc_timer, valid_int); 116144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1162aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) 1163aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt if (wpa_s->reject_btm_req_reason) { 1164aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt wpa_printf(MSG_INFO, 1165aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", 1166aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt wpa_s->reject_btm_req_reason); 1167aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 1168aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt wpa_s->wnm_dialog_token, 1169aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt wpa_s->reject_btm_req_reason, 1170aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt 0, NULL); 1171aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt return; 1172aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt } 1173aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ 1174aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt 1175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 5; 117644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1177f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1178d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 12) { 117944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 118044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 118144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 118244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 12; /* BSS Termination Duration */ 118444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 118544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1186f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char url[256]; 1188f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 1189d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 1 || 1 + pos[0] > end - pos) { 1190a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "Management Request (URL)"); 1192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1194a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(url, pos + 1, pos[0]); 1195a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt url[pos[0]] = '\0'; 119644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 1 + pos[0]; 1197f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 1198f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1199f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_sm_pmf_enabled(wpa_s->wpa), 1200f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1201a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1203f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 120544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 120644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* TODO: mark current BSS less preferred for 1208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * selection */ 1209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 1211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 121457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 121557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 121657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vendor) 121757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 121857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 121957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 1220f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1221fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int valid_ms; 1222fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 122344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1224fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 1225fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = os_calloc( 1226fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WNM_MAX_NEIGHBOR_REPORT, 122744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt sizeof(struct neighbor_report)); 122844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_neighbor_report_elements == NULL) 122944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 123044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1231d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos >= 2 && 123244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 123344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt { 123444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 tag = *pos++; 123544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 len = *pos++; 123644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 123744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 123844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt tag); 1239d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (len > end - pos) { 124044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 124144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 124244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 1243f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1244f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt struct neighbor_report *rep; 1245f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep = &wpa_s->wnm_neighbor_report_elements[ 1246f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_s->wnm_num_neighbor_report]; 1247f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wnm_parse_neighbor_report(wpa_s, pos, len, rep); 12489c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s->wnm_num_neighbor_report++; 1249f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 125044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 125144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += len; 125244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 12539c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 12549c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if (!wpa_s->wnm_num_neighbor_report) { 12559c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_printf(MSG_DEBUG, 12569c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt "WNM: Candidate list included bit is set, but no candidates found"); 12579c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wnm_send_bss_transition_mgmt_resp( 12589c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s, wpa_s->wnm_dialog_token, 12599c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 12609c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 0, NULL); 12619c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt return; 12629c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt } 12639c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 1264fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_sort_cand_list(wpa_s); 1265fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_dump_cand_list(wpa_s); 1266fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms = valid_int * beacon_int * 128 / 125; 1267fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1268fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms); 1269fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&wpa_s->wnm_cand_valid_until); 1270fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1271fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1272fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += 1273fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec / 1000000; 1274fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec %= 1000000; 1275fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1276fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1277849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 1278849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Fetch the latest scan results from the kernel and check for 1279849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * candidates based on those results first. This can help in 1280849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * finding more up-to-date information should the driver has 1281849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * done some internal scanning operations after the last scan 1282849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * result update in wpa_supplicant. 1283849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 1284849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (wnm_fetch_scan_results(wpa_s) > 0) 1285849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 1286849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1287849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 1288849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Try to use previously received scan results, if they are 1289849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * recent enough to use for a connection. 1290849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 1291fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->last_scan_res_used > 0) { 1292fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct os_reltime now; 1293fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1294fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&now); 1295fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1296fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1297fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Try to use recent scan results"); 1298fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wnm_scan_process(wpa_s, 0) > 0) 1299fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1300fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1301fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: No match in previous scan results - try a new scan"); 1302fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1303fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 130444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1305fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_set_scan_freqs(wpa_s); 13069c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if (wpa_s->wnm_num_neighbor_report == 1) { 13079c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt os_memcpy(wpa_s->next_scan_bssid, 13089c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s->wnm_neighbor_report_elements[0].bssid, 13099c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt ETH_ALEN); 13109c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_printf(MSG_DEBUG, 13119c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt "WNM: Scan only for a specific BSSID since there is only a single candidate " 13129c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 13139c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt } 131444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 131544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } else if (reply) { 1316f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status; 1317f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1318f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_ACCEPT; 1319f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else { 1320f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1321f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1322f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt } 132344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 132444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 1325f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status, 0, NULL); 1326a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1327a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 1328a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1329a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 133044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtint wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 133157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 query_reason, int cand_list) 133244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 133357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 buf[2000], *pos; 133444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct ieee80211_mgmt *mgmt; 133544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt size_t len; 133644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int ret; 133744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 133844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 133957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MACSTR " query_reason=%u%s", 134057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(wpa_s->bssid), query_reason, 134157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt cand_list ? " candidate list" : ""); 134244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 134344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 134444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 134544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 134644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 134744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 134844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 134944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WLAN_FC_STYPE_ACTION); 135044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 135144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 1352fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt mgmt->u.action.u.bss_tm_query.dialog_token = 1; 135344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 135444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_query.variable; 135544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 135657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (cand_list) 135757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 135857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 135944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 136044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 136144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 136244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 136344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &mgmt->u.action.category, len, 0); 136444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 136544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return ret; 136644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 136744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 136844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1369f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1370f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *data, 1371f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int len) 1372f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1373f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end, *next; 1374f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 ie, ie_len; 1375f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1376f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = data; 1377f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = data + len; 1378f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1379d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos > 1) { 1380f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie = *pos++; 1381f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_len = *pos++; 1382f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1383f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie, ie_len); 1384f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len > end - pos) { 1385f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1386f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 1387f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1388f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1389f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt next = pos + ie_len; 1390f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len < 4) { 1391f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1392f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1393f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1394f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1395f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos), pos[3]); 1396f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1397f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20 1398f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1399f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 1400f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1401f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Subscription Remediation subelement */ 1402f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1403f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1404f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1405f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 osu_method; 1406f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1407f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1408f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 1409f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1410f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1411f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1412f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url_len == 0) { 1413f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1414f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = NULL; 1415f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = 1; 1416f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } else { 1417d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len + 1 > ie_end - pos) { 1418f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1419f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len, 1420f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt (int) (ie_end - pos)); 1421f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1422f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1423f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1424f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1425f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1426f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1427f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1428f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = pos[url_len]; 1429f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1430f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_subscription_remediation(wpa_s, url, 1431f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method); 1432f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1433f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1434f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1435f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1436f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1437f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1438f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 1439f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1440f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1441f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1442f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1443f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 code; 1444f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u16 reauth_delay; 1445f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1446f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1447f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1448f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code = *pos++; 1449f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay = WPA_GET_LE16(pos); 1450f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 2; 1451f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1452f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1453f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Imminent - Reason Code %u " 1454f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Re-Auth Delay %u URL Length %u", 1455f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code, reauth_delay, url_len); 1456d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len > ie_end - pos) 1457f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1458f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1459f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1460f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1461f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1462f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1463f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_deauth_imminent_notice(wpa_s, code, 1464f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay, url); 1465f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1466f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1467f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1468f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1469f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */ 1470f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1471f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1472f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1473f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1474f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1475f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1476f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1477f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *frm, int len) 1478f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1479f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end; 1480f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 dialog_token, type; 1481f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1482f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Dialog Token [1] | Type [1] | Subelements */ 1483f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1484f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (len < 2 || sa == NULL) 1485f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1486f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = frm + len; 1487f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = frm; 1488f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token = *pos++; 1489f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt type = *pos++; 1490f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1491f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1492f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "(dialog_token %u type %u sa " MACSTR ")", 1493f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token, type, MAC2STR(sa)); 1494f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1495f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos, end - pos); 1496f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1497f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED || 1498f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1499f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1500f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "from our AP - ignore it"); 1501f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1502f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1503f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1504f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt switch (type) { 1505f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 1: 1506f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1507f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1508f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt default: 1509f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1510f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "WNM-Notification type %u", type); 1511f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1512f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1513f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1514f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1515f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 151661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1517fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 151861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 1519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 1520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 act; 1521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1522fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (len < IEEE80211_HDRLEN + 2) 1523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1525623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act = *pos++; 1527fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt end = ((const u8 *) mgmt) + len; 1528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1530fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt act, MAC2STR(mgmt->sa)); 1531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wpa_s->wpa_state < WPA_ASSOCIATED || 1532fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "frame"); 1535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 153761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 153861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (act) { 1539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case WNM_BSS_TRANS_MGMT_REQ: 1540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1541fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt !(mgmt->da[0] & 0x01)); 1542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 154361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WNM_SLEEP_MODE_RESP: 1544fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 154561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 1546f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case WNM_NOTIFICATION_REQ: 1547f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1548f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 154961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 155044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "WNM: Unknown request"); 155161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 155261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 155361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 1554