wnm_sta.c revision 9c17526f86859e2b6aebac0ed4f2561601816103
161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* 261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * wpa_supplicant - WNM 3f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. 461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * 561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * See README for more details. 761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/includes.h" 1061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "utils/common.h" 1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "common/ieee802_11_defs.h" 13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_common.h" 14f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt#include "common/wpa_ctrl.h" 1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "rsn_supp/wpa.h" 16a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "wpa_supplicant_i.h" 17a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "driver_i.h" 18a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#include "scan.h" 1944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "ctrl_iface.h" 2044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "bss.h" 2144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#include "wnm_sta.h" 22f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#include "hs20_supplicant.h" 2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define MAX_TFS_IE_LEN 1024 2544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt#define WNM_MAX_NEIGHBOR_REPORT 10 2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* get the TFS IE from driver */ 2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 *buf_len, enum wnm_oper oper) 3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* set the TFS IE to driver */ 3961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 40d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *addr, const u8 *buf, u16 buf_len, 4161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper oper) 4261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 43d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt u16 len = buf_len; 44d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 4561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 4661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 47d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len); 4861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 4961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 5161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/* MLME-SLEEPMODE.request */ 5261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 53a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 action, u16 intval, struct wpabuf *tfs_req) 5461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 5561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct ieee80211_mgmt *mgmt; 5661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt int res; 5761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt size_t len; 5861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie; 5961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 *wnmtfs_ie; 6061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 wnmsleep_ie_len; 6161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WNM_SLEEP_TFS_REQ_IE_NONE; 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 65a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 66a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "action=%s to " MACSTR, 67a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt action == 0 ? "enter" : "exit", 68a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid)); 69a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* WNM-Sleep Mode IE */ 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmsleep_ie == NULL) 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->len = wnmsleep_ie_len - 2; 7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type = action; 7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 79a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->intval = host_to_le16(intval); 80a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 81a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmsleep_ie, wnmsleep_ie_len); 8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* TFS IE(s) */ 84a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfs_req) { 85a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = wpabuf_len(tfs_req); 86a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_malloc(wnmtfs_ie_len); 87a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 88a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 89a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 90a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 91a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 92a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else { 93a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 94a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmtfs_ie == NULL) { 95a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 96a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return -1; 97a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 98a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 99a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfs_oper)) { 100a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie_len = 0; 101a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 102a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmtfs_ie = NULL; 103a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 105a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 106a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (u8 *) wnmtfs_ie, wnmtfs_ie_len); 10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (mgmt == NULL) { 11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "WNM-Sleep Request action frame"); 112a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmsleep_ie); 113a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_free(wnmtfs_ie); 11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return -1; 11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt WLAN_FC_STYPE_ACTION); 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 124a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len); 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* copy TFS IE here */ 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (wnmtfs_ie_len > 0) { 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmtfs_ie_len; 13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt &mgmt->u.action.category, len, 0); 13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (res < 0) 14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", action, intval); 142b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt else 143b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt wpa_s->wnmsleep_used = 1; 14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmsleep_ie); 14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(wnmtfs_ie); 14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt os_free(mgmt); 14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return res; 15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 153a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 154d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start, 155d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end) 156a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 157a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 158a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->bssid, NULL, NULL); 159a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* remove GTK/IGTK ?? */ 160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 161a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* set the TFS Resp IE(s) */ 162a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tfsresp_ie_start && tfsresp_ie_end && 163a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end - tfsresp_ie_start >= 0) { 164a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u16 tfsresp_ie_len; 165a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 166a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start; 167a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 168a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pass the TFS Resp IE(s) to driver for processing */ 169a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_start, 171d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt tfsresp_ie_len, 172a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_TFS_RESP_IE_SET)) 173a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 174a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 175a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 176a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 177a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 178a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 179a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *frm, u16 key_len_total) 180a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 181a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 *ptr, *end; 182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 gtk_len; 183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt NULL, NULL); 186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 187a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Install GTK/IGTK */ 188a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 189a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* point to key data field */ 190fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ptr = (u8 *) frm + 1 + 2; 191a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt end = ptr + key_len_total; 192a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 193a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 19417de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { 19517de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen wpa_msg(wpa_s, MSG_INFO, 19617de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); 19717de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen return; 19817de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen } 19917de68dac9fe4e739d32bbe6ec5962da31bc2dbdJouni Malinen 200d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - ptr > 1) { 201d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ptr[1] > end - ptr) { 202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 203a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "length"); 204a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (end > ptr) { 205a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 206a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr, end - ptr); 207a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 208a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 209a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 210a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 211a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + 5) { 212a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 213a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 214a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 215a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 216a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len = *(ptr + 4); 217a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 11 + gtk_len || 218a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt gtk_len < 5 || gtk_len > 32) { 219a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 220a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 221a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 222a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 223a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key( 224a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_s->wpa, 225a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_GTK, 226a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr); 227a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 13 + gtk_len; 228a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W 229a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 230a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 231a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 232a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "subelem"); 233a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 234a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 235a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_wnmsleep_install_key(wpa_s->wpa, 236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WNM_SLEEP_SUBELEM_IGTK, ptr); 237a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ptr += 10 + WPA_IGTK_LEN; 238a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */ 239a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else 240a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; /* skip the loop */ 241a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 242a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 243a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 244a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const u8 *frm, int len) 24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* 24921de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * WNM-Sleep Mode IE | TFS Response IE 25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */ 252d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *pos = frm; /* point to payload after the action field */ 25321de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt u16 key_len_total; 25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct wnm_sleep_element *wnmsleep_ie = NULL; 25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* multiple TFS Resp IE (assuming consecutive) */ 256d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_start = NULL; 257d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt const u8 *tfsresp_ie_end = NULL; 258fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t left; 25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 260b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt if (!wpa_s->wnmsleep_used) { 261b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt wpa_printf(MSG_DEBUG, 262b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association"); 263b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt return; 264b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt } 265b70d0bbd90f638aa38da542e337c312309200e87Dmitry Shmidt 26621de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt if (len < 3) 26721de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt return; 26821de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt key_len_total = WPA_GET_LE16(frm + 1); 26921de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt 270fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 271fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt frm[0], key_len_total); 272fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt left = len - 3; 273fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (key_len_total > left) { 274a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 275a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 276a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 277fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt pos += 3 + key_len_total; 278d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (pos - frm + 1 < len) { 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt u8 ie_len = *(pos + 1); 280d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (2 + ie_len > frm + len - pos) { 281a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 282a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 283a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 284a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 285d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4) 28661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie = (struct wnm_sleep_element *) pos; 28761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt else if (*pos == WLAN_EID_TFS_RESP) { 28861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!tfsresp_ie_start) 28961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_start = pos; 29061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt tfsresp_ie_end = pos; 29161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else 29261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 29361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt pos += ie_len + 2; 29461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 29561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 29661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!wnmsleep_ie) { 29761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 29861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return; 29961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 30061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 301a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 302a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 30361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 30461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "frame (action=%d, intval=%d)", 30561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 306a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 307a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 308a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tfsresp_ie_end); 309a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 310a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 31161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 31261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } else { 31361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 31461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt "(action=%d, intval=%d)", 31561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wnmsleep_ie->action_type, wnmsleep_ie->intval); 316a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 31761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 31861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 319a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 32061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 32161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt wpa_s->bssid, NULL, NULL); 32261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 32644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtvoid wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 32744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 32844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int i; 32944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 33044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 33144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 33244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 33344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 33444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 33521de214b4ba4271ca20843f3b8fba9f1501b2a89Dmitry Shmidt wpa_s->wnm_num_neighbor_report = 0; 33644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_free(wpa_s->wnm_neighbor_report_elements); 33744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = NULL; 33844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 33944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 34044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 34144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 34244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, u8 elen, const u8 *pos) 34344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 34444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt switch (id) { 34544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_TSF: 34644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2 + 2) { 34744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 34844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 34944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 350fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_offset = WPA_GET_LE16(pos); 351fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->beacon_int = WPA_GET_LE16(pos + 2); 352fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->tsf_present = 1; 35344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 35544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 2) { 35644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 35744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "country string"); 35844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 35944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 360fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->country, pos, 2); 361fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->country_present = 1; 36244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 36444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 1) { 36544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 36644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "candidate"); 36744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 36844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 369fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference = pos[0]; 370fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->preference_present = 1; 37144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 373fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_tsf = WPA_GET_LE64(pos); 374fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_dur = WPA_GET_LE16(pos + 8); 375fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bss_term_present = 1; 37644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 37744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_BEARING: 37844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (elen < 8) { 37944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 38044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "bearing"); 38144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 383fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing = WPA_GET_LE16(pos); 384fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->distance = WPA_GET_LE32(pos + 2); 385fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rel_height = WPA_GET_LE16(pos + 2 + 4); 386fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bearing_present = 1; 38744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 38844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MEASUREMENT_PILOT: 389f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 39044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 39144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "pilot"); 39244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 394f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->meas_pilot); 39544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 39644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->meas_pilot == NULL) 39744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 39844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->meas_pilot->measurement_pilot = pos[0]; 399f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->meas_pilot->subelem_len = elen - 1; 400f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 40144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 403f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 5) { 40444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 40544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "capabilities"); 40644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 40744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 408fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(rep->rm_capab, pos, 5); 409fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->rm_capab_present = 1; 41044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt case WNM_NEIGHBOR_MULTIPLE_BSSID: 412f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen < 1) { 41344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 41444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 41544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 416f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_free(rep->mul_bssid); 41744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 41844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (rep->mul_bssid == NULL) 41944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->mul_bssid->max_bssid_indicator = pos[0]; 421f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep->mul_bssid->subelem_len = elen - 1; 422f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 42344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt break; 42444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 42544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 42644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 42744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 428fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) 429fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 430fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 431fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const char *country = NULL; 432b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt int freq; 433fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 434fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss) { 435fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); 436fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 437fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (elem && elem[1] >= 2) 438fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt country = (const char *) (elem + 2); 439fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 440fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 441b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = ieee80211_chan_to_freq(country, op_class, chan); 442b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt if (freq <= 0 && op_class == 0) { 443b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt /* 444b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * Some APs do not advertise correct operating class 445b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * information. Try to determine the most likely operating 446b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt * frequency based on the channel number. 447b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt */ 448b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt if (chan >= 1 && chan <= 13) 449b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 2407 + chan * 5; 450b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt else if (chan == 14) 451b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 2484; 452b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt else if (chan >= 36 && chan <= 169) 453b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt freq = 5000 + chan * 5; 454b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt } 455b97e428f8acf1ecb93f38f8d0063d2f2fd0bc36eDmitry Shmidt return freq; 456fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 457fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 458fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 45944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtstatic void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 46044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt const u8 *pos, u8 len, 46144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct neighbor_report *rep) 46244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 46344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 left = len; 46444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 46544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (left < 13) { 46644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 46744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 46844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 46944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(rep->bssid, pos, ETH_ALEN); 471fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); 47244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->regulatory_class = *(pos + 10); 47344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->channel_number = *(pos + 11); 47444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt rep->phy_type = *(pos + 12); 47544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 13; 47744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt left -= 13; 47844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 47944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt while (left >= 2) { 48044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 id, elen; 48144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 48244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt id = *pos++; 48344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt elen = *pos++; 484f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 485f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= 2; 486f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (elen > left) { 487f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_printf(MSG_DEBUG, 488f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt "WNM: Truncated neighbor report subelement"); 489f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt break; 490f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 49144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_parse_neighbor_report_elem(rep, id, elen, pos); 492f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt left -= elen; 49344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += elen; 49444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 495fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 496fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, 497fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt rep->channel_number); 49844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 49944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 50044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 501fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct wpa_bss * 502fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtcompare_scan_neighbor_results(struct wpa_supplicant *wpa_s) 50344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 50444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 505fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 i; 506fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss = wpa_s->current_bss; 507fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *target; 50844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 509fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) 51044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return 0; 51144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 512fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 513fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(wpa_s->bssid), bss->level); 514fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 515fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 516fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 517fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 518fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 519fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->preference_present && nei->preference == 0) { 520fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, 521fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 522fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 523fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 524fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 525fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target = wpa_bss_get_bssid(wpa_s, nei->bssid); 526fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!target) { 527fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 528fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) not found in scan results", 529fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 530fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 531fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 532fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 533fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 534fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 535fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss->ssid_len != target->ssid_len || 536fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { 537fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* 538fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * TODO: Could consider allowing transition to another 539fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * ESS if PMF was enabled for the association. 540fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */ 541fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 542fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) in different ESS", 543fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 544fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 545fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1); 546fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 547fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 548fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 54957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { 55057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 55157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "MBO: Candidate BSS " MACSTR 55257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt " retry delay is not over yet", 55357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(nei->bssid)); 55457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt continue; 55557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 55657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 557fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (target->level < bss->level && target->level < -80) { 558fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR 559fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " (pref %d) does not have sufficient signal level (%d)", 560fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), 561fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : 562fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt -1, 563fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt target->level); 564fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt continue; 56544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 566fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 567fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 568fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Found an acceptable preferred transition candidate BSS " 569fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " (RSSI %d)", 570fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid), target->level); 571fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return target; 57244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 57344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 574fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return NULL; 57544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 57644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 57744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 57857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid) 57957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 58057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *ie_a, *ie_b; 58157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 58257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!a || !b) 58357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 58457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 58557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_a = wpa_bss_get_ie(a, eid); 58657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_b = wpa_bss_get_ie(b, eid); 58757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 58857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!ie_a || !ie_b || ie_a[1] != ie_b[1]) 58957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 59057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 59157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return os_memcmp(ie_a, ie_b, ie_a[1]) == 0; 59257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 59357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 59457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 59557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 59657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 59757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u32 info = 0; 59857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 59957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH; 60057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 60157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* 60257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * Leave the security and key scope bits unset to indicate that the 60357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * security information is not available. 60457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 60557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 60657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT) 60757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; 60857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_QOS) 60957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_QOS; 61057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_APSD) 61157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_APSD; 61257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT) 61357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_RM; 61457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK) 61557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_DELAYED_BA; 61657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK) 61757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_IMM_BA; 61857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN)) 61957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN; 62057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP)) 62157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info |= NEI_REP_BSSID_INFO_HT; 62257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return info; 62457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 62557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 62757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info, 62857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 op_class, u8 chan, u8 phy_type, u8 pref) 62957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 63057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 *pos = buf; 63157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 63257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (len < 18) { 63357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 63457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Not enough room for Neighbor Report element"); 63557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -1; 63657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 63757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 63857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = WLAN_EID_NEIGHBOR_REPORT; 63957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* length: 13 for basic neighbor report + 3 for preference subelement */ 64057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = 16; 64157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_memcpy(pos, bssid, ETH_ALEN); 64257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += ETH_ALEN; 64357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt WPA_PUT_LE32(pos, bss_info); 64457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += 4; 64557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = op_class; 64657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = chan; 64757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = phy_type; 64857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE; 64957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = 1; 65057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos++ = pref; 65157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 65257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 65357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 65457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 65557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, 65657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_bss *bss, u8 *buf, size_t len, 65757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 pref) 65857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 65957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *ie; 66057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 op_class, chan; 66157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int sec_chan = 0, vht = 0; 66257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt enum phy_type phy_type; 66357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u32 info; 66457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct ieee80211_ht_operation *ht_oper = NULL; 66557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct ieee80211_vht_operation *vht_oper = NULL; 66657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 66757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); 66857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ie && ie[1] >= 2) { 66957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 67057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 67157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 67257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sec_chan = 1; 67357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt else if (ht_oper->ht_param & 67457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 67557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sec_chan = -1; 67657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 67757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 67857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); 67957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ie && ie[1] >= 1) { 68057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 68157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 68257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || 68357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || 68457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) 68557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vht = vht_oper->vht_op_info_chwidth; 68657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 68757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 68857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, 68957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt &chan) == NUM_HOSTAPD_MODES) { 69057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 69157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Cannot determine operating class and channel"); 69257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -2; 69357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 69457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 69557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), 69657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt (vht_oper != NULL)); 69757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (phy_type == PHY_TYPE_UNSPECIFIED) { 69857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 69957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Cannot determine BSS phy type for Neighbor Report"); 70057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return -2; 70157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 70257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 70357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info = wnm_get_bss_info(wpa_s, bss); 70457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 70557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, 70657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt phy_type, pref); 70757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 70857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 70957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 71057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) 71157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 71257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 *pos = buf; 71357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt unsigned int i, pref = 255; 71457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct os_reltime now; 71557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 71657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 71757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!ssid) 71857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 71957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 72057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* 72157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * TODO: Define when scan results are no longer valid for the candidate 72257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * list. 72357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 72457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_get_reltime(&now); 72557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) 72657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 72757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 72857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 72957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: Add candidate list to BSS Transition Management Response frame"); 73057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { 73157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct wpa_bss *bss = wpa_s->last_scan_res[i]; 73257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int res; 73357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 73457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) { 73557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); 73657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (res == -2) 73757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt continue; /* could not build entry for BSS */ 73857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (res < 0) 73957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; /* no more room for candidates */ 74057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (pref == 1) 74157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 74257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 74357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += res; 74457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt len -= res; 74557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 74657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 74757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 74857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 74957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "WNM: BSS Transition Management Response candidate list", 75057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt buf, pos - buf); 75157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 75257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 75357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 75457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 75557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 756f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidtstatic void wnm_send_bss_transition_mgmt_resp( 757f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt struct wpa_supplicant *wpa_s, u8 dialog_token, 758f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status, u8 delay, 759f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt const u8 *target_bssid) 760a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 76157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 buf[2000], *pos; 762a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ieee80211_mgmt *mgmt; 763a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt size_t len; 764fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int res; 765a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 766a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 767a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "to " MACSTR " dialog_token=%u status=%u delay=%d", 768a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt MAC2STR(wpa_s->bssid), dialog_token, status, delay); 769fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss) { 770fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 771fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Current BSS not known - drop response"); 772fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 773fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 774a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 775a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 776a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 777a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 778a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 779a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 780a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 781a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt WLAN_FC_STYPE_ACTION); 782a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 783a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 784a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 785a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.status_code = status; 786a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 787a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_resp.variable; 788a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (target_bssid) { 789a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(pos, target_bssid, ETH_ALEN); 790a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += ETH_ALEN; 791fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt } else if (status == WNM_BSS_TM_ACCEPT) { 792fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt /* 793fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * P802.11-REVmc clarifies that the Target BSSID field is always 794fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * present when status code is zero, so use a fake value here if 795fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt * no BSSID is yet known. 796fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt */ 797fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memset(pos, 0, ETH_ALEN); 798fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt pos += ETH_ALEN; 799a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 800a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 80157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (status == WNM_BSS_TM_ACCEPT) 80257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 80357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 80457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 80557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (status != WNM_BSS_TM_ACCEPT) { 80657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wpas_mbo_ie_bss_trans_reject( 80757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_s, pos, buf + sizeof(buf) - pos, 80857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MBO_TRANSITION_REJECT_REASON_UNSPECIFIED); 80957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 81057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 81157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 812a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 813a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 814fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 815fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 816fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &mgmt->u.action.category, len, 0); 817fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (res < 0) { 818fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 819fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Failed to send BSS Transition Management Response"); 820fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 821a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 822a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 823a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 824fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) 82544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 826fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_bss *bss; 827fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct wpa_ssid *ssid = wpa_s->current_ssid; 828fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; 82944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 830fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 831fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 832fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 833fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (os_reltime_before(&wpa_s->wnm_cand_valid_until, 834fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt &wpa_s->scan_trigger_time)) { 835fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); 836fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 837fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 838fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 839fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 840fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->current_bss || 841fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, 842fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt ETH_ALEN) != 0) { 843fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); 844fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 84544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 84644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 84744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt /* Compare the Neighbor Report and scan results */ 848fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt bss = compare_scan_neighbor_results(wpa_s); 849fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bss) { 850fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); 851fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; 852fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt goto send_bss_resp_fail; 853fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 85444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 855fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Associate to the network */ 856fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Send the BSS Management Response - Accept */ 857fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->wnm_reply) { 858fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_reply = 0; 859fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 86044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 861f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt WNM_BSS_TM_ACCEPT, 862fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 0, bss->bssid); 863fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 86444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 865fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bss == wpa_s->current_bss) { 866fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 867fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Already associated with the preferred candidate"); 868d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt wnm_deallocate_memory(wpa_s); 869fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 87044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 87144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 872fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->reassociate = 1; 873fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_supplicant_connect(wpa_s, bss, ssid); 87444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_deallocate_memory(wpa_s); 875fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 876fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 877fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtsend_bss_resp_fail: 878fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!reply_on_fail) 879fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 880fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 881fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Send reject response for all the failures */ 882fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 88344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_reply) { 884fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_reply = 0; 88544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 88644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 887fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt status, 0, NULL); 88844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 889fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 890fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 891fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 892fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 893fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 894fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 895fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int cand_pref_compar(const void *a, const void *b) 896fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 897fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *aa = a; 898fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt const struct neighbor_report *bb = b; 899fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 900fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present && !bb->preference_present) 901fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 902fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!aa->preference_present) 903fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 904fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!bb->preference_present) 905fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 906fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference > aa->preference) 907fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 908fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (bb->preference < aa->preference) 909fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 910fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 911fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 912fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 913fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 914fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) 915fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 916fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 917fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 918fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt qsort(wpa_s->wnm_neighbor_report_elements, 919fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), 920fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt cand_pref_compar); 921fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 922fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 923fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 924fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) 925fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 926fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 927fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 928fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); 929fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 930fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 931fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 932fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 933fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 934fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 935fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "%u: " MACSTR 936fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", 937fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt i, MAC2STR(nei->bssid), nei->bssid_info, 938fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->regulatory_class, 939fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->channel_number, nei->phy_type, 940fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->preference_present ? nei->preference : -1, 941fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei->freq); 942fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 943fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 944fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 945fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 946fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int chan_supported(struct wpa_supplicant *wpa_s, int freq) 947fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 948fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 949fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 950fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->hw.num_modes; i++) { 951fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 952fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int j; 953fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 954fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (j = 0; j < mode->num_channels; j++) { 955fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct hostapd_channel_data *chan; 956fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 957fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt chan = &mode->channels[j]; 958fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan->freq == freq && 959fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt !(chan->flag & HOSTAPD_CHAN_DISABLED)) 960fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 1; 961fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 962fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 963fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 964fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return 0; 965fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 966fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 967fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 968fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) 969fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 970fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int *freqs; 971fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt int num_freqs = 0; 972fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int i; 973fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 974fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!wpa_s->wnm_neighbor_report_elements) 975fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 976fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 977fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->hw.modes == NULL) 978fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 979fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 980fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(wpa_s->next_scan_freqs); 981fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = NULL; 982fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 983fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); 984fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (freqs == NULL) 985fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 986fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 987fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 988fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct neighbor_report *nei; 989fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 990fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt nei = &wpa_s->wnm_neighbor_report_elements[i]; 991fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (nei->freq <= 0) { 992fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 993fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Unknown neighbor operating frequency for " 994fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MACSTR " - scan all channels", 995fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt MAC2STR(nei->bssid)); 996fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 997fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 998fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 999fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (chan_supported(wpa_s, nei->freq)) 1000fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt add_freq(freqs, &num_freqs, nei->freq); 1001fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1002fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1003fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (num_freqs == 0) { 1004fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_free(freqs); 1005fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1006fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1007fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1008fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1009fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Scan %d frequencies based on transition candidate list", 1010fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt num_freqs); 1011fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->next_scan_freqs = freqs; 101244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 101344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 101444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1015a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 1016a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, const u8 *end, 1017a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int reply) 1018a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 1019fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int beacon_int; 1020fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 valid_int; 102157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 102257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *vendor; 102357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 1024fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1025d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 5) 1026a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1027a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1028fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->current_bss) 1029fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = wpa_s->current_bss->beacon_int; 1030fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt else 1031fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt beacon_int = 100; /* best guess */ 1032fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 103344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token = pos[0]; 103444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_mode = pos[1]; 103544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 1036fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_int = pos[4]; 103744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_reply = reply; 1038a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1039a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 1040a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "dialog_token=%u request_mode=0x%x " 1041a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "disassoc_timer=%u validity_interval=%u", 104244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 1043fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_dissoc_timer, valid_int); 104444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1045a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 5; 104644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1047f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 1048d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 12) { 104944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 105044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 105144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 105244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 1053a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt pos += 12; /* BSS Termination Duration */ 105444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 105544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1056f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 1057a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char url[256]; 1058f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 1059d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (end - pos < 1 || 1 + pos[0] > end - pos) { 1060a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 1061a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "Management Request (URL)"); 1062a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1063a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1064a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt os_memcpy(url, pos + 1, pos[0]); 1065a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt url[pos[0]] = '\0'; 106644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += 1 + pos[0]; 1067f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt 1068f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 1069f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_sm_pmf_enabled(wpa_s->wpa), 1070f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 1071a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1072a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1073f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 1074a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 107544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 107644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 1077a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* TODO: mark current BSS less preferred for 1078a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt * selection */ 1079a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 1080a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 1081a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1082a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1083a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 108457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#ifdef CONFIG_MBO 108557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); 108657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (vendor) 108757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); 108857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#endif /* CONFIG_MBO */ 108957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 1090f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 1091fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt unsigned int valid_ms; 1092fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 109344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 1094fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_deallocate_memory(wpa_s); 1095fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_neighbor_report_elements = os_calloc( 1096fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt WNM_MAX_NEIGHBOR_REPORT, 109744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt sizeof(struct neighbor_report)); 109844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt if (wpa_s->wnm_neighbor_report_elements == NULL) 109944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 110044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1101d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos >= 2 && 110244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 110344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt { 110444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 tag = *pos++; 110544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt u8 len = *pos++; 110644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 110744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 110844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt tag); 1109d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (len > end - pos) { 111044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 111144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return; 111244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 1113f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt if (tag == WLAN_EID_NEIGHBOR_REPORT) { 1114f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt struct neighbor_report *rep; 1115f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt rep = &wpa_s->wnm_neighbor_report_elements[ 1116f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wpa_s->wnm_num_neighbor_report]; 1117f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt wnm_parse_neighbor_report(wpa_s, pos, len, rep); 11189c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s->wnm_num_neighbor_report++; 1119f940fbdc849eba19de7b63a74ced85e550bf4572Dmitry Shmidt } 112044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 112144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos += len; 112244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } 11239c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 11249c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if (!wpa_s->wnm_num_neighbor_report) { 11259c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_printf(MSG_DEBUG, 11269c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt "WNM: Candidate list included bit is set, but no candidates found"); 11279c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wnm_send_bss_transition_mgmt_resp( 11289c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s, wpa_s->wnm_dialog_token, 11299c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, 11309c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 0, NULL); 11319c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt return; 11329c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt } 11339c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt 1134fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_sort_cand_list(wpa_s); 1135fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_dump_cand_list(wpa_s); 1136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms = valid_int * beacon_int * 128 / 125; 1137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", 1138fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt valid_ms); 1139fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&wpa_s->wnm_cand_valid_until); 1140fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; 1141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; 1142fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.sec += 1143fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec / 1000000; 1144fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_s->wnm_cand_valid_until.usec %= 1000000; 1145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); 1146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wpa_s->last_scan_res_used > 0) { 1148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct os_reltime now; 1149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 1150fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_get_reltime(&now); 1151fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { 1152fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: Try to use recent scan results"); 1154fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (wnm_scan_process(wpa_s, 0) > 0) 1155fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return; 1156fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 1157fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "WNM: No match in previous scan results - try a new scan"); 1158fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 1159fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 116044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1161fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wnm_set_scan_freqs(wpa_s); 11629c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt if (wpa_s->wnm_num_neighbor_report == 1) { 11639c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt os_memcpy(wpa_s->next_scan_bssid, 11649c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_s->wnm_neighbor_report_elements[0].bssid, 11659c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt ETH_ALEN); 11669c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt wpa_printf(MSG_DEBUG, 11679c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt "WNM: Scan only for a specific BSSID since there is only a single candidate " 11689c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt MACSTR, MAC2STR(wpa_s->next_scan_bssid)); 11699c17526f86859e2b6aebac0ed4f2561601816103Dmitry Shmidt } 117044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_supplicant_req_scan(wpa_s, 0, 0); 117144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt } else if (reply) { 1172f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt enum bss_trans_mgmt_status_code status; 1173f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 1174f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_ACCEPT; 1175f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt else { 1176f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 1177f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status = WNM_BSS_TM_REJECT_UNSPECIFIED; 1178f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt } 117944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wnm_send_bss_transition_mgmt_resp(wpa_s, 118044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->wnm_dialog_token, 1181f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt status, 0, NULL); 1182a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 1183a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 1184a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1185a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 118644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidtint wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 118757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 query_reason, int cand_list) 118844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt{ 118957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 buf[2000], *pos; 119044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt struct ieee80211_mgmt *mgmt; 119144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt size_t len; 119244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt int ret; 119344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 119444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 119557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MACSTR " query_reason=%u%s", 119657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(wpa_s->bssid), query_reason, 119757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt cand_list ? " candidate list" : ""); 119844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 119944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt = (struct ieee80211_mgmt *) buf; 120044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memset(&buf, 0, sizeof(buf)); 120144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 120244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 120344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 120444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 120544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt WLAN_FC_STYPE_ACTION); 120644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.category = WLAN_ACTION_WNM; 120744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 1208fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt mgmt->u.action.u.bss_tm_query.dialog_token = 1; 120944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 121044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt pos = mgmt->u.action.u.bss_tm_query.variable; 121144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 121257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (cand_list) 121357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos); 121457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 121544c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt len = pos - (u8 *) &mgmt->u.action.category; 121644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 121744c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 121844c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 121944c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt &mgmt->u.action.category, len, 0); 122044c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 122144c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt return ret; 122244c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt} 122344c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 122444c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt 1225f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 1226f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *data, 1227f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt int len) 1228f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1229f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end, *next; 1230f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 ie, ie_len; 1231f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1232f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = data; 1233f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = data + len; 1234f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1235d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt while (end - pos > 1) { 1236f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie = *pos++; 1237f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_len = *pos++; 1238f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 1239f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie, ie_len); 1240f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len > end - pos) { 1241f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 1242f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 1243f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1244f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1245f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt next = pos + ie_len; 1246f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie_len < 4) { 1247f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1248f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1249f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1250f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 1251f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos), pos[3]); 1252f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1253f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_HS20 1254f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 1255f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 1256f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_SUB_REM_NEEDED) { 1257f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Subscription Remediation subelement */ 1258f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1259f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1260f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1261f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 osu_method; 1262f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1263f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 1264f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "subelement"); 1265f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1266f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1267f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1268f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url_len == 0) { 1269f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 1270f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = NULL; 1271f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = 1; 1272f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } else { 1273d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len + 1 > ie_end - pos) { 1274f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 1275f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len, 1276f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt (int) (ie_end - pos)); 1277f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1278f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1279f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1280f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1281f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1282f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1283f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1284f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method = pos[url_len]; 1285f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1286f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_subscription_remediation(wpa_s, url, 1287f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt osu_method); 1288f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1289f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1290f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1291f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1292f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1293f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 1294f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt WPA_GET_BE24(pos) == OUI_WFA && 1295f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 1296f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *ie_end; 1297f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 url_len; 1298f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt char *url; 1299f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 code; 1300f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u16 reauth_delay; 1301f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1302f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ie_end = pos + ie_len; 1303f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 4; 1304f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code = *pos++; 1305f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay = WPA_GET_LE16(pos); 1306f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos += 2; 1307f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url_len = *pos++; 1308f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 1309f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Imminent - Reason Code %u " 1310f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "Re-Auth Delay %u URL Length %u", 1311f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt code, reauth_delay, url_len); 1312d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (url_len > ie_end - pos) 1313f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1314f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url = os_malloc(url_len + 1); 1315f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (url == NULL) 1316f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1317f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcpy(url, pos, url_len); 1318f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt url[url_len] = '\0'; 1319f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt hs20_rx_deauth_imminent_notice(wpa_s, code, 1320f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt reauth_delay, url); 1321f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_free(url); 1322f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1323f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt continue; 1324f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1325f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_HS20 */ 1326f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1327f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = next; 1328f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1329f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1330f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1331f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1332f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidtstatic void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 1333f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *sa, const u8 *frm, int len) 1334f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt{ 1335f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt const u8 *pos, *end; 1336f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt u8 dialog_token, type; 1337f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1338f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt /* Dialog Token [1] | Type [1] | Subelements */ 1339f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1340f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (len < 2 || sa == NULL) 1341f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1342f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt end = frm + len; 1343f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos = frm; 1344f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token = *pos++; 1345f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt type = *pos++; 1346f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1347f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 1348f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "(dialog_token %u type %u sa " MACSTR ")", 1349f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt dialog_token, type, MAC2STR(sa)); 1350f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 1351f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt pos, end - pos); 1352f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1353f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED || 1354f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 1355f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 1356f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "from our AP - ignore it"); 1357f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt return; 1358f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1359f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1360f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt switch (type) { 1361f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case 1: 1362f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 1363f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1364f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt default: 1365f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 1366f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt "WNM-Notification type %u", type); 1367f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 1368f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt } 1369f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt} 1370f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 1371f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt 137261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 1373fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt const struct ieee80211_mgmt *mgmt, size_t len) 137461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 1375a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt const u8 *pos, *end; 1376a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt u8 act; 1377a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1378fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (len < IEEE80211_HDRLEN + 2) 1379a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1380a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1381623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 1382a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt act = *pos++; 1383fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt end = ((const u8 *) mgmt) + len; 1384a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 1385a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 1386fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt act, MAC2STR(mgmt->sa)); 1387a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (wpa_s->wpa_state < WPA_ASSOCIATED || 1388fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1389a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 1390a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt "frame"); 1391a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 1392a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 139361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 139461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt switch (act) { 1395a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt case WNM_BSS_TRANS_MGMT_REQ: 1396a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 1397fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt !(mgmt->da[0] & 0x01)); 1398a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 139961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case WNM_SLEEP_MODE_RESP: 1400fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 140161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 1402f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt case WNM_NOTIFICATION_REQ: 1403f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 1404f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt break; 140561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt default: 140644c957860ca714a86357591f39aff0bfa904c743Dmitry Shmidt wpa_printf(MSG_ERROR, "WNM: Unknown request"); 140761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 140861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 140961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 1410