summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/wpa_supplicant/src/ap/ap_drv_ops.c15
-rw-r--r--external/wpa_supplicant/src/ap/ap_drv_ops.h7
-rw-r--r--external/wpa_supplicant/src/ap/ieee802_11.c358
-rw-r--r--external/wpa_supplicant/src/ap/sta_info.c6
-rw-r--r--external/wpa_supplicant/src/ap/sta_info.h3
-rw-r--r--external/wpa_supplicant/src/ap/wpa_auth.c36
-rw-r--r--external/wpa_supplicant/src/ap/wpa_auth.h3
-rw-r--r--external/wpa_supplicant/src/ap/wpa_auth_ft.c11
-rw-r--r--external/wpa_supplicant/src/ap/wpa_auth_i.h1
-rw-r--r--external/wpa_supplicant/src/common/qca-vendor.h3
-rw-r--r--external/wpa_supplicant/src/common/wpa_common.h13
-rw-r--r--external/wpa_supplicant/src/drivers/driver.h23
-rw-r--r--external/wpa_supplicant/src/drivers/driver_nl80211.c70
-rw-r--r--external/wpa_supplicant/src/drivers/driver_nl80211_capa.c16
-rw-r--r--external/wpa_supplicant/src/rsn_supp/tdls.c39
-rw-r--r--external/wpa_supplicant/src/rsn_supp/wpa.c241
-rw-r--r--external/wpa_supplicant/src/rsn_supp/wpa.h1
-rw-r--r--external/wpa_supplicant/src/rsn_supp/wpa_ft.c8
-rw-r--r--external/wpa_supplicant/src/rsn_supp/wpa_i.h15
-rw-r--r--external/wpa_supplicant/wpa_supplicant/config.c2
-rw-r--r--external/wpa_supplicant/wpa_supplicant/config.h11
-rw-r--r--external/wpa_supplicant/wpa_supplicant/config_file.c3
-rw-r--r--external/wpa_supplicant/wpa_supplicant/ctrl_iface.c1
-rw-r--r--external/wpa_supplicant/wpa_supplicant/events.c1
-rw-r--r--external/wpa_supplicant/wpa_supplicant/wnm_sta.c37
-rw-r--r--external/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h3
-rw-r--r--external/wpa_supplicant/wpa_supplicant/wpas_glue.c1
27 files changed, 759 insertions, 169 deletions
diff --git a/external/wpa_supplicant/src/ap/ap_drv_ops.c b/external/wpa_supplicant/src/ap/ap_drv_ops.c
index 34104e1e..cce15ce8 100644
--- a/external/wpa_supplicant/src/ap/ap_drv_ops.c
+++ b/external/wpa_supplicant/src/ap/ap_drv_ops.c
@@ -36,6 +36,11 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
if (flags & WLAN_STA_MFP) {
res |= WPA_STA_MFP;
}
+ if (flags & WLAN_STA_AUTH)
+ res |= WPA_STA_AUTHENTICATED;
+ if (flags & WLAN_STA_ASSOC)
+ res |= WPA_STA_ASSOCIATED;
+
return res;
}
@@ -351,7 +356,13 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, int reassoc, u1
return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr, reassoc, status, ie, len);
}
-int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, u32 flags, u8 qosinfo, u8 vht_opmode)
+int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid,
+ u16 capability, const u8 *supp_rates,
+ size_t supp_rates_len, u16 listen_interval,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set)
{
struct hostapd_sta_add_params params;
@@ -375,6 +386,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capa
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
+ params.support_p2p_ps = supp_p2p_ps;
+ params.set = set;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
diff --git a/external/wpa_supplicant/src/ap/ap_drv_ops.h b/external/wpa_supplicant/src/ap/ap_drv_ops.h
index 20a09fbe..80f243bf 100644
--- a/external/wpa_supplicant/src/ap/ap_drv_ops.h
+++ b/external/wpa_supplicant/src/ap/ap_drv_ops.h
@@ -27,7 +27,12 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, int
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds, const u8 *addr, int aid, int val);
-int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, u32 flags, u8 qosinfo, u8 vht_opmode);
+int hostapd_sta_add(struct hostapd_data *hapd, const u8 *addr, u16 aid,
+ u16 capability, const u8 *supp_rates, size_t supp_rates_len,
+ u16 listen_interval, const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set);
+
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, size_t elem_len);
int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
diff --git a/external/wpa_supplicant/src/ap/ieee802_11.c b/external/wpa_supplicant/src/ap/ieee802_11.c
index 99780baa..1a6fdff6 100644
--- a/external/wpa_supplicant/src/ap/ieee802_11.c
+++ b/external/wpa_supplicant/src/ap/ieee802_11.c
@@ -240,16 +240,20 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, u16
return 0;
}
-static void send_auth_reply(struct hostapd_data *hapd, const u8 *dst, const u8 *bssid, u16 auth_alg, u16 auth_transaction, u16 resp, const u8 *ies, size_t ies_len)
+static int send_auth_reply(struct hostapd_data *hapd,
+ const u8 *dst, const u8 *bssid,
+ u16 auth_alg, u16 auth_transaction, u16 resp,
+ const u8 *ies, size_t ies_len)
{
struct ieee80211_mgmt *reply;
u8 *buf;
size_t rlen;
-
+ int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
buf = os_zalloc(rlen);
if (buf == NULL) {
- return;
+ return -1;
}
reply = (struct ieee80211_mgmt *)buf;
@@ -268,10 +272,14 @@ static void send_auth_reply(struct hostapd_data *hapd, const u8 *dst, const u8 *
wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", MAC2STR(dst), auth_alg, auth_transaction, resp, (unsigned long)ies_len);
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) {
- wpa_printf(MSG_INFO, "send_auth_reply: send");
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
}
+ else
+ reply_res = WLAN_STATUS_SUCCESS;
os_free(buf);
+
+ return reply_res;
}
#ifdef CONFIG_IEEE80211R
@@ -279,18 +287,26 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, u16
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int reply_res;
+
+ reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ auth_transaction, status, ies, ies_len);
- send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction, status, ies, ies_len);
-
- if (status != WLAN_STATUS_SUCCESS) {
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL) {
return;
}
- sta = ap_get_sta(hapd, dst);
- if (sta == NULL) {
+ if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
+ status != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
return;
}
+ if (status != WLAN_STATUS_SUCCESS)
+ return;
+
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
sta->flags |= WLAN_STA_AUTH;
mlme_authenticate_indication(hapd, sta);
@@ -342,33 +358,41 @@ static struct wpabuf *auth_build_sae_confirm(struct hostapd_data *hapd, struct s
static int auth_sae_send_commit(struct hostapd_data *hapd, struct sta_info *sta, const u8 *bssid, int update)
{
struct wpabuf *data;
-
+ int reply_res;
+
data = auth_build_sae_commit(hapd, sta, update);
if (data == NULL) {
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS, wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data));
+
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
static int auth_sae_send_confirm(struct hostapd_data *hapd, struct sta_info *sta, const u8 *bssid)
{
struct wpabuf *data;
-
+ int reply_res;
+
data = auth_build_sae_confirm(hapd, sta);
if (data == NULL) {
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS, wpabuf_head(data), wpabuf_len(data));
+ reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ wpabuf_len(data));
+
wpabuf_free(data);
- return WLAN_STATUS_SUCCESS;
+ return reply_res;
}
static int use_sae_anti_clogging(struct hostapd_data *hapd)
@@ -658,17 +682,22 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, const u8
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, size_t len, u16 auth_transaction, u16 status_code)
{
- u16 resp = WLAN_STATUS_SUCCESS;
+ int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
if (!sta->sae) {
- if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS) {
- return;
+ if (auth_transaction != 1 ||
+ status_code != WLAN_STATUS_SUCCESS) {
+ resp = -1;
+ goto remove_sta;
}
+
sta->sae = os_zalloc(sizeof(*sta->sae));
- if (sta->sae == NULL) {
- return;
+ if (!sta->sae) {
+ resp = -1;
+ goto remove_sta;
}
+
sta->sae->state = SAE_NOTHING;
sta->sae->sync = 0;
}
@@ -697,7 +726,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, con
sta->sae->tmp->anti_clogging_token = wpabuf_alloc_copy(pos, end - pos);
if (sta->sae->tmp->anti_clogging_token == NULL) {
wpa_printf(MSG_ERROR, "SAE: Failed to alloc for anti-clogging token");
- return;
+
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
}
/*
@@ -707,9 +738,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, con
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR, "SAE: Failed to send commit message");
- return;
+
+ goto remove_sta;
}
sta->sae->state = SAE_COMMITTED;
sta->sae->sync = 0;
@@ -718,18 +751,21 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, con
}
if (status_code != WLAN_STATUS_SUCCESS) {
- return;
+ goto remove_sta;
}
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable, ((const u8 *)mgmt) + len - mgmt->u.auth.variable, &token, &token_len, hapd->conf->sae_groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message from " MACSTR " due to reflection attack", MAC2STR(sta->addr));
- return;
+ goto remove_sta;
}
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " "incorrect token from " MACSTR, MAC2STR(sta->addr));
- return;
+
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
+
}
if (resp != WLAN_STATUS_SUCCESS) {
@@ -750,7 +786,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, con
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "SAE authentication (RX confirm, status=%u)", status_code);
if (status_code != WLAN_STATUS_SUCCESS) {
- return;
+ goto remove_sta;
}
if (sta->sae->state >= SAE_CONFIRMED || !(hapd->conf->mesh & MESH_ENABLED)) {
if (sae_check_confirm(sta->sae, mgmt->u.auth.variable, ((u8 *)mgmt) + len - mgmt->u.auth.variable) < 0) {
@@ -762,7 +798,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, con
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "unexpected SAE authentication transaction %u (status=%u)", auth_transaction, status_code);
if (status_code != WLAN_STATUS_SUCCESS) {
- return;
+ goto remove_sta;
}
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
@@ -771,6 +807,13 @@ reply:
if (resp != WLAN_STATUS_SUCCESS) {
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, auth_transaction, resp, data ? wpabuf_head(data) : (u8 *)"", data ? wpabuf_len(data) : 0);
}
+remove_sta:
+ if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+ status_code != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+
wpabuf_free(data);
}
@@ -815,7 +858,7 @@ static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
struct sta_info *sta = NULL;
- int res;
+ int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
@@ -962,6 +1005,46 @@ static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *
ap_sta_no_session_timeout(hapd, sta);
}
+ /*
+ * If the driver supports full AP client state, add a station to the
+ * driver before sending authentication reply to make sure the driver
+ * has resources, and not to go through the entire authentication and
+ * association handshake, and fail it at the end.
+ *
+ * If this is not the first transaction, in a multi-step authentication
+ * algorithm, the station already exists in the driver
+ * (sta->added_unassoc = 1) so skip it.
+ *
+ * In mesh mode, the station was already added to the driver when the
+ * NEW_PEER_CANDIDATE event is received.
+ */
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+ !(sta->added_unassoc)) {
+ /*
+ * If a station that is already associated to the AP, is trying
+ * to authenticate again, remove the STA entry, in order to make
+ * sure the STA PS state gets cleared and configuration gets
+ * updated. To handle this, station's added_unassoc flag is
+ * cleared once the station has completed association.
+ */
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
+ WLAN_STA_AUTHORIZED);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0, 0, 0, 0,
+ NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ sta->added_unassoc = 1;
+ }
+
switch (auth_alg) {
case WLAN_AUTH_OPEN:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (open system)");
@@ -1020,7 +1103,15 @@ fail:
os_free(radius_cui);
hostapd_free_psk_list(psk);
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, auth_transaction + 1, resp, resp_ies, resp_ies_len);
+ reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ auth_transaction + 1, resp, resp_ies,
+ resp_ies_len);
+
+ if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
+ reply_res != WLAN_STATUS_SUCCESS)) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
@@ -1394,7 +1485,78 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, u16 reason_co
}
}
-static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, u16 status_code, int reassoc, const u8 *ies, size_t ies_len)
+
+static int add_associated_sta(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct ieee80211_ht_capabilities ht_cap;
+ struct ieee80211_vht_capabilities vht_cap;
+ int set = 1;
+
+ /*
+ * Remove the STA entry to ensure the STA PS state gets cleared and
+ * configuration gets updated. This is relevant for cases, such as
+ * FT-over-the-DS, where a station re-associates back to the same AP but
+ * skips the authentication flow, or if working with a driver that
+ * does not support full AP client state.
+ *
+ * Skip this if the STA has already completed FT reassociation and the
+ * TK has been configured since the TX/RX PN must not be reset to 0 for
+ * the same key.
+ */
+
+ if (!sta->added_unassoc &&
+ (!(sta->flags & WLAN_STA_AUTHORIZED) ||
+ !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
+ set = 0;
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (sta->flags & WLAN_STA_HT)
+ hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
+#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (sta->flags & WLAN_STA_VHT)
+ hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
+
+ /*
+ * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
+ * will be set when the ACK frame for the (Re)Association Response frame
+ * is processed (TX status driver event).
+ */
+ if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+ sta->supported_rates, sta->supported_rates_len,
+ sta->listen_interval,
+ sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+ sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+ sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
+ sta->vht_opmode, sta->p2p_ie ? 1 : 0,
+ set)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
+ "Could not %s STA to kernel driver",
+ set ? "set" : "add");
+
+ if (sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+
+ return -1;
+ }
+
+ sta->added_unassoc = 0;
+
+ return 0;
+}
+
+
+static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
+ u16 status_code, int reassoc, const u8 *ies,
+ size_t ies_len)
{
int send_len;
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
@@ -1505,13 +1667,15 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, u16
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", strerror(errno));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ return WLAN_STATUS_SUCCESS;
}
static void handle_assoc(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS;
+ u16 resp = WLAN_STATUS_SUCCESS, reply_res;
const u8 *pos;
int left, i;
struct sta_info *sta;
@@ -1555,6 +1719,13 @@ static void handle_assoc(struct hostapd_data *hapd, const struct ieee80211_mgmt
#ifdef CONFIG_IEEE80211R
if (sta && sta->auth_alg == WLAN_AUTH_FT && (sta->flags & WLAN_STA_AUTH) == 0) {
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " "prior to authentication since it is using " "over-the-DS FT", MAC2STR(mgmt->sa));
+
+ /*
+ * Mark station as authenticated, to avoid adding station
+ * entry in the driver as associated and not authenticated
+ */
+ sta->flags |= WLAN_STA_AUTH;
+
} else
#endif /* CONFIG_IEEE80211R */
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
@@ -1661,7 +1832,38 @@ static void handle_assoc(struct hostapd_data *hapd, const struct ieee80211_mgmt
sta->timeout_next = STA_NULLFUNC;
fail:
- send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+ /*
+ * In case of a successful response, add the station to the driver.
+ * Otherwise, the kernel may ignore Data frames before we process the
+ * ACK frame (TX status). In case of a failure, this station will be
+ * removed.
+ *
+ * Note that this is not compliant with the IEEE 802.11 standard that
+ * states that a non-AP station should transition into the
+ * authenticated/associated state only after the station acknowledges
+ * the (Re)Association Response frame. However, still do this as:
+ *
+ * 1. In case the station does not acknowledge the (Re)Association
+ * Response frame, it will be removed.
+ * 2. Data frames will be dropped in the kernel until the station is
+ * set into authorized state, and there are no significant known
+ * issues with processing other non-Data Class 3 frames during this
+ * window.
+ */
+ if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta))
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+ reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+ /*
+ * Remove the station in case tranmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if ((reply_res != WLAN_STATUS_SUCCESS &&
+ resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
static void handle_disassoc(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len)
@@ -1697,6 +1899,7 @@ static void handle_disassoc(struct hostapd_data *hapd, const struct ieee80211_mg
}
ap_sta_ip6addr_del(hapd, sta);
hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
if (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC) {
sta->timeout_next = STA_DEAUTH;
@@ -1982,29 +2185,39 @@ static void handle_auth_cb(struct hostapd_data *hapd, const struct ieee80211_mgm
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
- if (!ok) {
- hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "did not acknowledge authentication response");
- return;
- }
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)", (unsigned long)len);
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+ MAC2STR(mgmt->da));
return;
}
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
+
+ if (!ok) {
+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "did not acknowledge authentication response");
+ goto fail;
+ }
- sta = ap_get_sta(hapd, mgmt->da);
- if (!sta) {
- wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found", MAC2STR(mgmt->da));
- return;
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)", (unsigned long)len);
+ goto fail;
}
if (status_code == WLAN_STATUS_SUCCESS && ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "authenticated");
sta->flags |= WLAN_STA_AUTH;
+ if (sta->added_unassoc)
+ hostapd_set_sta_flags(hapd, sta);
+ return;
+ }
+
+fail:
+ if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
}
@@ -2030,13 +2243,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, const struct ieee80211_mg
u16 status;
struct sta_info *sta;
int new_assoc = 1;
- struct ieee80211_ht_capabilities ht_cap;
- struct ieee80211_vht_capabilities vht_cap;
-
- if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : sizeof(mgmt->u.assoc_resp))) {
- wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)", reassoc, (unsigned long)len);
- return;
- }
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2044,16 +2250,30 @@ static void handle_assoc_cb(struct hostapd_data *hapd, const struct ieee80211_mg
return;
}
- if (!ok) {
- hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response");
- sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+ sizeof(mgmt->u.assoc_resp))) {
+ wpa_printf(MSG_INFO,
+ "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
+ reassoc, (unsigned long) len);
+ hostapd_drv_sta_remove(hapd, sta->addr);
return;
+
}
- if (reassoc) {
+ if (reassoc)
status = le_to_host16(mgmt->u.reassoc_resp.status_code);
- } else {
+ else
status = le_to_host16(mgmt->u.assoc_resp.status_code);
+
+
+ if (!ok) {
+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response");
+ sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+ /* The STA is added only in case of SUCCESS */
+ if (status == WLAN_STATUS_SUCCESS)
+ hostapd_drv_sta_remove(hapd, sta->addr);
+
+ return ;
}
if (status != WLAN_STATUS_SUCCESS) {
@@ -2089,32 +2309,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, const struct ieee80211_mg
sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
- /*
- * Remove the STA entry in order to make sure the STA PS state gets
- * cleared and configuration gets updated in case of reassociation back
- * to the same AP.
- */
- hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifdef CONFIG_IEEE80211N
- if (sta->flags & WLAN_STA_HT) {
- hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
- }
-#endif /* CONFIG_IEEE80211N */
-#ifdef CONFIG_IEEE80211AC
- if (sta->flags & WLAN_STA_VHT) {
- hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
- }
-#endif /* CONFIG_IEEE80211AC */
-
- if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, sta->supported_rates, sta->supported_rates_len, sta->listen_interval, sta->flags & WLAN_STA_HT ? &ht_cap : NULL, sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, sta->flags, sta->qosinfo, sta->vht_opmode)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not add STA to kernel driver");
-
- ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_DISASSOC_AP_BUSY);
-
- return;
- }
-
if (sta->flags & WLAN_STA_WDS) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
diff --git a/external/wpa_supplicant/src/ap/sta_info.c b/external/wpa_supplicant/src/ap/sta_info.c
index e0bbe26b..842bf641 100644
--- a/external/wpa_supplicant/src/ap/sta_info.c
+++ b/external/wpa_supplicant/src/ap/sta_info.c
@@ -166,8 +166,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
}
ap_sta_ip6addr_del(hapd, sta);
- if (!hapd->iface->driver_ap_teardown && !(sta->flags & WLAN_STA_PREAUTH)) {
+ if (!hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH)) {
hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
#ifndef CONFIG_NO_VLAN
@@ -178,6 +180,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
*/
if (hapd->iface->driver_ap_teardown && !(sta->flags & WLAN_STA_PREAUTH)) {
hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
}
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
}
@@ -578,6 +581,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR " from kernel driver.", MAC2STR(sta->addr));
return -1;
}
+ sta->added_unassoc = 0;
return 0;
}
diff --git a/external/wpa_supplicant/src/ap/sta_info.h b/external/wpa_supplicant/src/ap/sta_info.h
index 9d7fd42e..27330592 100644
--- a/external/wpa_supplicant/src/ap/sta_info.h
+++ b/external/wpa_supplicant/src/ap/sta_info.h
@@ -85,7 +85,8 @@ struct sta_info {
unsigned int hs20_deauth_requested: 1;
unsigned int session_timeout_set: 1;
unsigned int radius_das_match: 1;
-
+ unsigned int added_unassoc:1;
+
u16 auth_alg;
enum {
diff --git a/external/wpa_supplicant/src/ap/wpa_auth.c b/external/wpa_supplicant/src/ap/wpa_auth.c
index 6d461a1d..d4187e82 100644
--- a/external/wpa_supplicant/src/ap/wpa_auth.c
+++ b/external/wpa_supplicant/src/ap/wpa_auth.c
@@ -1483,6 +1483,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
#else /* CONFIG_IEEE80211R */
break;
#endif /* CONFIG_IEEE80211R */
+ case WPA_DRV_STA_REMOVED:
+ sm->tk_already_set = FALSE;
+ return 0;
}
#ifdef CONFIG_IEEE80211R
@@ -1615,6 +1618,20 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
sm->TimeoutCtr = 0;
}
+static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
+{
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to get random data for ANonce");
+ sm->Disconnect = TRUE;
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
+ WPA_NONCE_LEN);
+ sm->TimeoutCtr = 0;
+ return 0;
+}
+
SM_STATE(WPA_PTK, INITPMK)
{
u8 msk[2 * PMK_LEN];
@@ -2086,10 +2103,14 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, AUTHENTICATION);
} else if (sm->ReAuthenticationRequest) {
SM_ENTER(WPA_PTK, AUTHENTICATION2);
- } else if (sm->PTKRequest) {
- SM_ENTER(WPA_PTK, PTKSTART);
- } else
- switch (sm->wpa_ptk_state) {
+ }
+ else if (sm->PTKRequest) {
+ if (wpa_auth_sm_ptk_update(sm) < 0)
+ SM_ENTER(WPA_PTK, DISCONNECTED);
+ else
+ SM_ENTER(WPA_PTK, PTKSTART);
+ } else switch (sm->wpa_ptk_state) {
+
case WPA_PTK_INITIALIZE:
break;
case WPA_PTK_DISCONNECT:
@@ -2782,6 +2803,13 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
return sm->wpa;
}
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
+{
+ if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+ return 0;
+ return sm->tk_already_set;
+}
+
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, struct rsn_pmksa_cache_entry *entry)
{
if (sm == NULL || sm->pmksa != entry) {
diff --git a/external/wpa_supplicant/src/ap/wpa_auth.h b/external/wpa_supplicant/src/ap/wpa_auth.h
index 0d434f9e..1708367d 100644
--- a/external/wpa_supplicant/src/ap/wpa_auth.h
+++ b/external/wpa_supplicant/src/ap/wpa_auth.h
@@ -227,7 +227,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len);
typedef enum {
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
- WPA_REAUTH_EAPOL, WPA_ASSOC_FT
+ WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
} wpa_event;
void wpa_remove_ptk(struct wpa_state_machine *sm);
int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
@@ -240,6 +240,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry *wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
diff --git a/external/wpa_supplicant/src/ap/wpa_auth_ft.c b/external/wpa_supplicant/src/ap/wpa_auth_ft.c
index fe153ee1..0a78d183 100644
--- a/external/wpa_supplicant/src/ap/wpa_auth_ft.c
+++ b/external/wpa_supplicant/src/ap/wpa_auth_ft.c
@@ -705,7 +705,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip " "PTK configuration", sm->pairwise);
return;
}
-
+ if (sm->tk_already_set) {
+ /* Must avoid TK reconfiguration to prevent clearing of TX/RX
+ * PN in the driver */
+ wpa_printf(MSG_DEBUG,
+ "FT: Do not re-install same PTK to the driver");
+ return;
+ }
+
/* FIX: add STA entry to kernel/driver here? The set_key will fail
* most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called
@@ -718,6 +725,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE;
+ sm->tk_already_set = TRUE;
}
static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, u8 **resp_ies, size_t *resp_ies_len)
@@ -805,6 +813,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, const u8 *ies,
sm->pairwise = pairwise;
sm->PTK_valid = TRUE;
+ sm->tk_already_set = FALSE;
wpa_ft_install_ptk(sm);
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 2 + FT_R1KH_ID_LEN + 200;
diff --git a/external/wpa_supplicant/src/ap/wpa_auth_i.h b/external/wpa_supplicant/src/ap/wpa_auth_i.h
index 78051032..610152e3 100644
--- a/external/wpa_supplicant/src/ap/wpa_auth_i.h
+++ b/external/wpa_supplicant/src/ap/wpa_auth_i.h
@@ -63,6 +63,7 @@ struct wpa_state_machine {
struct wpa_ptk PTK;
Boolean PTK_valid;
Boolean pairwise_set;
+ Boolean tk_already_set;
int keycount;
Boolean Pair;
struct wpa_key_replay_counter {
diff --git a/external/wpa_supplicant/src/common/qca-vendor.h b/external/wpa_supplicant/src/common/qca-vendor.h
index f8fe63c0..d0bca743 100644
--- a/external/wpa_supplicant/src/common/qca-vendor.h
+++ b/external/wpa_supplicant/src/common/qca-vendor.h
@@ -242,11 +242,14 @@ enum qca_wlan_vendor_acs_hw_mode {
* after roaming, rather than having the user space wpa_supplicant do it.
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
* band selection based on channel selection results.
+ * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
+ * simultaneous off-channel operations.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
+ QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
diff --git a/external/wpa_supplicant/src/common/wpa_common.h b/external/wpa_supplicant/src/common/wpa_common.h
index 8f78eaeb..b1abefc2 100644
--- a/external/wpa_supplicant/src/common/wpa_common.h
+++ b/external/wpa_supplicant/src/common/wpa_common.h
@@ -207,8 +207,21 @@ struct wpa_ptk {
size_t kck_len;
size_t kek_len;
size_t tk_len;
+ int installed; /* 1 if key has already been installed to driver */
};
+struct wpa_gtk {
+ u8 gtk[WPA_GTK_MAX_LEN];
+ size_t gtk_len;
+};
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk {
+ u8 igtk[WPA_IGTK_MAX_LEN];
+ size_t igtk_len;
+};
+#endif /* CONFIG_IEEE80211W */
+
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
* 0x01 0x00 (version; little endian)
diff --git a/external/wpa_supplicant/src/drivers/driver.h b/external/wpa_supplicant/src/drivers/driver.h
index 97074626..2fcd5409 100644
--- a/external/wpa_supplicant/src/drivers/driver.h
+++ b/external/wpa_supplicant/src/drivers/driver.h
@@ -1213,8 +1213,16 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
/** Driver supports automatic band selection */
#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
+ /** Driver supports simultaneous off-channel operations */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
+/** Driver supports full AP client state */
+#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
+
u64 flags;
+#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
+ (drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
+
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
unsigned int smps_modes;
@@ -1336,6 +1344,7 @@ struct hostapd_sta_add_params {
size_t supp_channels_len;
const u8 *supp_oper_classes;
size_t supp_oper_classes_len;
+ int support_p2p_ps;
};
struct mac_address {
@@ -1430,6 +1439,7 @@ struct wpa_bss_params {
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
#define WPA_STA_AUTHENTICATED BIT(5)
+#define WPA_STA_ASSOCIATED BIT(6)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -2277,12 +2287,17 @@ struct wpa_driver_ops {
* @params: Station parameters
* Returns: 0 on success, -1 on failure
*
- * This function is used to add a station entry to the driver once the
- * station has completed association. This is only used if the driver
+ * This function is used to add or set (params->set 1) a station
+ * entry in the driver. Adding STA entries is used only if the driver
* does not take care of association processing.
*
- * With TDLS, this function is also used to add or set (params->set 1)
- * TDLS peer entries.
+ * With drivers that don't support full AP client state, this function
+ * is used to add a station entry to the driver once the station has
+ * completed association.
+ *
+ * With TDLS, this function is used to add or set (params->set 1)
+ * TDLS peer entries (even with drivers that do not support full AP
+ * client state).
*/
int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
diff --git a/external/wpa_supplicant/src/drivers/driver_nl80211.c b/external/wpa_supplicant/src/drivers/driver_nl80211.c
index 31e6df82..8397866d 100644
--- a/external/wpa_supplicant/src/drivers/driver_nl80211.c
+++ b/external/wpa_supplicant/src/drivers/driver_nl80211.c
@@ -3270,6 +3270,9 @@ static u32 sta_flags_nl80211(int flags)
if (flags & WPA_STA_AUTHENTICATED) {
f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
}
+ if (flags & WPA_STA_ASSOCIATED)
+ f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+
return f;
}
@@ -3317,7 +3320,19 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params
goto fail;
}
- if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
+
+ /*
+ * Set the below properties only in one of the following cases:
+ * 1. New station is added, already associated.
+ * 2. Set WPA_STA_TDLS_PEER station.
+ * 3. Set an already added unassociated station, if driver supports
+ * full AP client state. (Set these properties after station became
+ * associated will be rejected by the driver).
+ */
+ if (!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ (params->set && FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
+ (params->flags & WPA_STA_ASSOCIATED))) {
+
wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates, params->supp_rates_len);
wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, params->supp_rates) || nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability)) {
@@ -3344,7 +3359,14 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params
goto fail;
}
}
+ if (is_ap_interface(drv->nlmode) &&
+ nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
+ params->support_p2p_ps ?
+ NL80211_P2P_PS_SUPPORTED :
+ NL80211_P2P_PS_UNSUPPORTED))
+ goto fail;
}
+
if (!params->set) {
if (params->aid) {
wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
@@ -3355,9 +3377,13 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params
/*
* cfg80211 validates that AID is non-zero, so we have
* to make this a non-zero value for the TDLS case where
- * a dummy STA entry is used for now.
+ * a dummy STA entry is used for now and for a station
+ * that is still not associated.
*/
- wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)");
+ wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
+ (params->flags & WPA_STA_TDLS_PEER) ?
+ "TDLS" : "UNASSOC_STA");
+
if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1)) {
goto fail;
}
@@ -3371,6 +3397,15 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params
if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid)) {
goto fail;
}
+ } else if (FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags) &&
+ (params->flags & WPA_STA_ASSOCIATED)) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid) ||
+ nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval))
+ goto fail;
}
if (params->vht_opmode_enabled) {
@@ -3397,6 +3432,35 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params
os_memset(&upd, 0, sizeof(upd));
upd.set = sta_flags_nl80211(params->flags);
upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
+ /*
+ * If the driver doesn't support full AP client state, ignore ASSOC/AUTH
+ * flags, as nl80211 driver moves a new station, by default, into
+ * associated state.
+ *
+ * On the other hand, if the driver supports that feature and the
+ * station is added in unauthenticated state, set the
+ * authenticated/associated bits in the mask to prevent moving this
+ * station to associated state before it is actually associated.
+ *
+ * This is irrelevant for mesh mode where the station is added to the
+ * driver as authenticated already, and ASSOCIATED isn't part of the
+ * nl80211 API.
+ */
+ if (!is_mesh_interface(drv->nlmode)) {
+ if (!FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore ASSOC/AUTH flags since driver doesn't support full AP client state");
+ upd.mask &= ~(BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED));
+ } else if (!params->set &&
+ !(params->flags & WPA_STA_TDLS_PEER)) {
+ if (!(params->flags & WPA_STA_AUTHENTICATED))
+ upd.mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (!(params->flags & WPA_STA_ASSOCIATED))
+ upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ }
+ }
+
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x", upd.set, upd.mask);
if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
goto fail;
diff --git a/external/wpa_supplicant/src/drivers/driver_nl80211_capa.c b/external/wpa_supplicant/src/drivers/driver_nl80211_capa.c
index ba83558c..1a10a89d 100644
--- a/external/wpa_supplicant/src/drivers/driver_nl80211_capa.c
+++ b/external/wpa_supplicant/src/drivers/driver_nl80211_capa.c
@@ -430,6 +430,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info, struct nlattr
if (flags & NL80211_FEATURE_HT_IBSS) {
capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
}
+
+ if (flags & NL80211_FEATURE_FULL_AP_CLIENT_STATE)
+ capa->flags |= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
}
static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa, struct nlattr *tb)
@@ -793,6 +796,9 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info)) {
drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
}
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+
}
int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
@@ -872,6 +878,16 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
qca_nl80211_check_dfs_capa(drv);
qca_nl80211_get_features(drv);
+ /*
+ * To enable offchannel simultaneous support in wpa_supplicant, the
+ * underlying driver needs to support the same along with offchannel TX.
+ * Offchannel TX support is needed since remain_on_channel and
+ * action_tx use some common data structures and hence cannot be
+ * scheduled simultaneously.
+ */
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+
return 0;
}
diff --git a/external/wpa_supplicant/src/rsn_supp/tdls.c b/external/wpa_supplicant/src/rsn_supp/tdls.c
index a3fda4d9..98b7670a 100644
--- a/external/wpa_supplicant/src/rsn_supp/tdls.c
+++ b/external/wpa_supplicant/src/rsn_supp/tdls.c
@@ -108,6 +108,7 @@ struct wpa_tdls_peer {
u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
} tpk;
int tpk_set;
+ int tk_set; /* TPK-TK configured to the driver */
int tpk_success;
int tpk_in_progress;
@@ -182,6 +183,20 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
u8 rsc[6];
enum wpa_alg alg;
+ if (peer->tk_set) {
+ /*
+ * This same TPK-TK has already been configured to the driver
+ * and this new configuration attempt (likely due to an
+ * unexpected retransmitted frame) would result in clearing
+ * the TX/RX sequence number which can break security, so must
+ * not allow that to happen.
+ */
+ wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
+ " has already been configured to the driver - do not reconfigure",
+ MAC2STR(peer->addr));
+ return -1;
+ }
+
os_memset(rsc, 0, 6);
switch (peer->cipher) {
@@ -197,10 +212,14 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
return -1;
}
+ wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
+ MAC2STR(peer->addr));
+
if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " "driver");
return -1;
}
+ peer->tk_set = 1;
return 0;
}
@@ -594,7 +613,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->cipher = 0;
peer->qos_info = 0;
peer->wmm_capable = 0;
- peer->tpk_set = peer->tpk_success = 0;
+ peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
peer->chan_switch_enabled = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
@@ -1032,6 +1051,7 @@ skip_rsnie:
wpa_tdls_peer_free(sm, peer);
return -1;
}
+ peer->tk_set = 0; /* A new nonce results in a new TK */
wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", peer->inonce, WPA_NONCE_LEN);
os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
@@ -1536,6 +1556,19 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, i
return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid, peer->capability, peer->supp_rates, peer->supp_rates_len, peer->ht_capabilities, peer->vht_capabilities, peer->qos_info, peer->wmm_capable, peer->ext_capab, peer->ext_capab_len, peer->supp_channels, peer->supp_channels_len, peer->supp_oper_classes, peer->supp_oper_classes_len);
}
+static int tdls_nonce_set(const u8 *nonce)
+{
+ int i;
+
+ for (i = 0; i < WPA_NONCE_LEN; i++) {
+ if (nonce[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len)
{
struct wpa_tdls_peer *peer;
@@ -1776,7 +1809,8 @@ skip_rsn:
peer->rsnie_i_len = kde.rsn_ie_len;
peer->cipher = cipher;
- if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 ||
+ !tdls_nonce_set(peer->inonce)) {
/*
* There is no point in updating the RNonce for every obtained
* TPK M1 frame (e.g., retransmission due to timeout) with the
@@ -1790,6 +1824,7 @@ skip_rsn:
wpa_msg(sm->ctx->ctx, MSG_WARNING, "TDLS: Failed to get random data for responder nonce");
goto error;
}
+ peer->tk_set = 0; /* A new nonce results in a new TK */
}
#if 0
/* get version info from RSNIE received from Peer */
diff --git a/external/wpa_supplicant/src/rsn_supp/wpa.c b/external/wpa_supplicant/src/rsn_supp/wpa.c
index d8578d6a..7f17ec3d 100644
--- a/external/wpa_supplicant/src/rsn_supp/wpa.c
+++ b/external/wpa_supplicant/src/rsn_supp/wpa.c
@@ -1,6 +1,7 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright(c) 2015 Intel Deutschland GmbH
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +23,8 @@
#include "wpa_ie.h"
#include "peerkey.h"
+static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
/**
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -33,9 +36,13 @@
* @msg: EAPOL-Key message
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: >= 0 on success, < 0 on failure
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic)
+int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+ int ver, const u8 *dest, u16 proto,
+ u8 *msg, size_t msg_len, u8 *key_mic)
{
+ int ret = -1;
#ifdef CONFIG_SUPPLICANT_EXCESS_LOG
size_t mic_len = wpa_mic_len(sm->key_mgmt);
#endif
@@ -59,10 +66,12 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, int ve
wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
- wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+// wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+ ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
out:
os_free(msg);
+ return ret;
}
/**
@@ -268,7 +277,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, const unsigned char *src_ad
* @wpa_ie: WPA/RSN IE
* @wpa_ie_len: Length of the WPA/RSN IE
* @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
*/
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, int ver, const u8 *nonce, const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ptk *ptk)
{
@@ -345,9 +354,8 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, cons
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL, rbuf, rlen, key_mic);
-
- return 0;
+ return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
++ ETH_P_EAPOL, rbuf, rlen, key_mic);
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
@@ -421,7 +429,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char
os_memset(buf, 0, sizeof(buf));
}
sm->tptk_set = 1;
-
+
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
@@ -444,7 +452,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char
}
#endif /* CONFIG_P2P */
- if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, kde, kde_len, ptk)) {
+ if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
+ kde, kde_len, ptk) < 0) {
goto failed;
}
@@ -509,7 +518,12 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, const struct wpa_eapol_
int keylen, rsclen;
enum wpa_alg alg;
const u8 *key_rsc;
- u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ if (sm->ptk.installed) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Do not re-install same PTK to the driver");
+ return 0;
+ }
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Installing PTK to the driver");
@@ -541,7 +555,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, const struct wpa_eapol_
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
-
+ sm->ptk.installed = 1;
+
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, sm, NULL);
@@ -576,11 +591,24 @@ struct wpa_gtk_data {
int gtk_len;
};
-static int wpa_supplicant_install_gtk(struct wpa_sm *sm, const struct wpa_gtk_data *gd, const u8 *key_rsc)
+static int wpa_supplicant_install_gtk(struct wpa_sm *sm, const struct wpa_gtk_data *gd,
+ const u8 *key_rsc, int wnm_sleep)
{
const u8 *_gtk = gd->gtk;
u8 gtk_buf[32];
+ /* Detect possible key reinstallation */
+ if ((sm->gtk.gtk_len == (size_t) gd->gtk_len &&
+ os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) ||
+ (sm->gtk_wnm_sleep.gtk_len == (size_t) gd->gtk_len &&
+ os_memcmp(sm->gtk_wnm_sleep.gtk, gd->gtk,
+ sm->gtk_wnm_sleep.gtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
+ gd->keyidx, gd->tx, gd->gtk_len);
+ return 0;
+ }
+
wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", gd->keyidx, gd->tx, gd->gtk_len);
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
@@ -604,6 +632,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, const struct wpa_gtk_da
}
os_memset(gtk_buf, 0, sizeof(gtk_buf));
+ if (wnm_sleep) {
+ sm->gtk_wnm_sleep.gtk_len = gd->gtk_len;
+ os_memcpy(sm->gtk_wnm_sleep.gtk, gd->gtk,
+ sm->gtk_wnm_sleep.gtk_len);
+ } else {
+ sm->gtk.gtk_len = gd->gtk_len;
+ os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
+ }
+
return 0;
}
@@ -621,10 +658,40 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, int tx)
return tx;
}
+static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm,
+ const u8 *rsc)
+{
+ int rsclen;
+
+ if (!sm->wpa_rsc_relaxation)
+ return 0;
+
+ rsclen = wpa_cipher_rsc_len(sm->group_cipher);
+
+ /*
+ * Try to detect RSC (endian) corruption issue where the AP sends
+ * the RSC bytes in EAPOL-Key message in the wrong order, both if
+ * it's actually a 6-byte field (as it should be) and if it treats
+ * it as an 8-byte field.
+ * An AP model known to have this bug is the Sapido RB-1632.
+ */
+ if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0",
+ rsc[0], rsc[1], rsc[2], rsc[3],
+ rsc[4], rsc[5], rsc[6], rsc[7]);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol_key *key, const u8 *gtk, size_t gtk_len, int key_info)
{
struct wpa_gtk_data gd;
-
+ const u8 *key_rsc;
/*
* IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
* GTK KDE format:
@@ -648,7 +715,14 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol
os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
- if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, gtk_len, gtk_len, &gd.key_rsc_len, &gd.alg) || wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
+ key_rsc = key->key_rsc;
+ if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+ key_rsc = null_rsc;
+
+
+ if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+ (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, gtk_len, gtk_len, &gd.key_rsc_len, &gd.alg) ||
+ wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Failed to install GTK");
os_memset(&gd, 0, sizeof(gd));
return -1;
@@ -659,6 +733,58 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol
return 0;
}
+#ifdef CONFIG_IEEE80211W
+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
+ const struct wpa_igtk_kde *igtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(igtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->igtk.igtk_len == len &&
+ os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) ||
+ (sm->igtk_wnm_sleep.igtk_len == len &&
+ os_memcmp(sm->igtk_wnm_sleep.igtk, igtk->igtk,
+ sm->igtk_wnm_sleep.igtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+ keyidx, MAC2STR(igtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
+ if (keyidx > 4095) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid IGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, igtk->pn, sizeof(igtk->pn),
+ igtk->igtk, len) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure IGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->igtk_wnm_sleep.igtk_len = len;
+ os_memcpy(sm->igtk_wnm_sleep.igtk, igtk->igtk,
+ sm->igtk_wnm_sleep.igtk_len);
+ } else {
+ sm->igtk.igtk_len = len;
+ os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
@@ -669,23 +795,15 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie)
if (ie->igtk) {
size_t len;
const struct wpa_igtk_kde *igtk;
- u16 keyidx;
+
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) {
return -1;
}
igtk = (const struct wpa_igtk_kde *)ie->igtk;
- keyidx = WPA_GET_LE16(igtk->keyid);
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " "pn %02x%02x%02x%02x%02x%02x", keyidx, MAC2STR(igtk->pn));
- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
- if (keyidx > 4095) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Invalid IGTK KeyID %d", keyidx);
- return -1;
- }
- if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), broadcast_ether_addr, keyidx, 0, igtk->pn, sizeof(igtk->pn), igtk->igtk, len) < 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to configure IGTK to the driver");
- return -1;
- }
+
+ if (wpa_supplicant_install_igtk(sm, igtk, 0) < 0)
+ return -1;
}
return 0;
@@ -865,7 +983,7 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, const unsigned char *sr
* @ver: Version bits from EAPOL-Key Key Info
* @key_info: Key Info
* @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
+ * Returns: >= 0 on success, < 0 on failure
*/
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, u16 ver, u16 key_info, struct wpa_ptk *ptk)
{
@@ -901,9 +1019,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, cons
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL, rbuf, rlen, key_mic);
- return 0;
+ return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
+
}
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, const struct wpa_eapol_key *key, u16 ver, const u8 *key_data, size_t key_data_len)
@@ -957,7 +1076,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, const struct wpa_ea
}
#endif /* CONFIG_P2P */
- if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, &sm->ptk)) {
+ if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
+ &sm->ptk) < 0) {
goto failed;
}
@@ -1140,9 +1260,8 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, const struct wpa_eapol_
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid, ETH_P_EAPOL, rbuf, rlen, key_mic);
-
- return 0;
+ return wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver,
+ sm->bssid, ETH_P_EAPOL, rbuf, rlen, key_mic);
}
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, const u8 *key_data, size_t key_data_len, u16 ver)
@@ -1150,6 +1269,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, const unsigned char
u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
+ const u8 *key_rsc;
if (!sm->msg_3_of_4_ok) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group Key Handshake started prior to completion of 4-way handshake");
@@ -1175,7 +1295,12 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, const unsigned char
goto failed;
}
- if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) || wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) {
+ key_rsc = key->key_rsc;
+ if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+ key_rsc = null_rsc;
+
+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
+ wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0) {
goto failed;
}
os_memset(&gd, 0, sizeof(gd));
@@ -1749,7 +1874,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
*/
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
{
- int clear_ptk = 1;
+ int clear_keys = 1;
if (sm == NULL) {
return;
@@ -1776,11 +1901,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
/* Prepare for the next transition */
wpa_ft_prepare_auth_request(sm, NULL);
- clear_ptk = 0;
+ clear_keys = 0;
}
#endif /* CONFIG_IEEE80211R */
- if (clear_ptk) {
+ if (clear_keys) {
/*
* IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
* this is not part of a Fast BSS Transition.
@@ -1790,7 +1915,14 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
sm->tptk_set = 0;
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+ os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
+#ifdef CONFIG_IEEE80211W
+ os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+ os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
+#endif /* CONFIG_IEEE80211W */
}
+
#ifdef CONFIG_TDLS
wpa_tdls_assoc(sm);
#endif /* CONFIG_TDLS */
@@ -1820,7 +1952,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
-
+#ifdef CONFIG_IEEE80211R
+ sm->ft_reassoc_completed = 0;
+#endif /* CONFIG_IEEE80211R */
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
@@ -1936,6 +2070,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
}
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
+ sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
} else {
sm->network_ctx = NULL;
sm->peerkey_enabled = 0;
@@ -1946,6 +2081,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
+ sm->wpa_rsc_relaxation = 0;
}
}
@@ -2292,6 +2428,12 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+ os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
+#ifdef CONFIG_IEEE80211W
+ os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+ os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
+#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
@@ -2349,7 +2491,8 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
os_memcpy(gd.gtk, buf + 13, gd.gtk_len);
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", gd.gtk, gd.gtk_len);
- if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+
+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) {
os_memset(&gd, 0, sizeof(gd));
wpa_printf(MSG_DEBUG, "Failed to install the GTK in " "WNM mode");
return -1;
@@ -2357,24 +2500,10 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
os_memset(&gd, 0, sizeof(gd));
#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
- struct wpa_igtk_kde igd;
- u16 keyidx;
-
- os_memset(&igd, 0, sizeof(igd));
- keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
- os_memcpy(igd.keyid, buf + 2, 2);
- os_memcpy(igd.pn, buf + 4, 6);
-
- keyidx = WPA_GET_LE16(igd.keyid);
- os_memcpy(igd.igtk, buf + 10, keylen);
-
- wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", igd.igtk, keylen);
- if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), broadcast_ether_addr, keyidx, 0, igd.pn, sizeof(igd.pn), igd.igtk, keylen) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " "WNM mode");
- os_memset(&igd, 0, sizeof(igd));
- return -1;
- }
- os_memset(&igd, 0, sizeof(igd));
+ const struct wpa_igtk_kde *igtk;
+ igtk = (const struct wpa_igtk_kde *) (buf + 2);
+ if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
+ return -1;
#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
diff --git a/external/wpa_supplicant/src/rsn_supp/wpa.h b/external/wpa_supplicant/src/rsn_supp/wpa.h
index 1586da6b..93fc5992 100644
--- a/external/wpa_supplicant/src/rsn_supp/wpa.h
+++ b/external/wpa_supplicant/src/rsn_supp/wpa.h
@@ -77,6 +77,7 @@ struct rsn_supp_config {
size_t ssid_len;
int wpa_ptk_rekey;
int p2p;
+ int wpa_rsc_relaxation;
};
#ifndef CONFIG_NO_WPA
diff --git a/external/wpa_supplicant/src/rsn_supp/wpa_ft.c b/external/wpa_supplicant/src/rsn_supp/wpa_ft.c
index d9fe1fb8..2333eabd 100644
--- a/external/wpa_supplicant/src/rsn_supp/wpa_ft.c
+++ b/external/wpa_supplicant/src/rsn_supp/wpa_ft.c
@@ -134,6 +134,7 @@ static u8 *wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, const u8 *anonce,
u16 capab;
sm->ft_completed = 0;
+ sm->ft_reassoc_completed = 0;
buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 2 + sm->r0kh_id_len + ric_ies_len + 100;
buf = os_zalloc(buf_len);
@@ -596,6 +597,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_le
return -1;
}
+ if (sm->ft_reassoc_completed) {
+ wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
+ return 0;
+ }
+
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1;
@@ -675,6 +681,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_le
return -1;
}
+ sm->ft_reassoc_completed = 1;
+
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) {
return -1;
}
diff --git a/external/wpa_supplicant/src/rsn_supp/wpa_i.h b/external/wpa_supplicant/src/rsn_supp/wpa_i.h
index 6659e427..53369538 100644
--- a/external/wpa_supplicant/src/rsn_supp/wpa_i.h
+++ b/external/wpa_supplicant/src/rsn_supp/wpa_i.h
@@ -30,6 +30,12 @@ struct wpa_sm {
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
int rx_replay_counter_set;
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+ struct wpa_gtk gtk;
+ struct wpa_gtk gtk_wnm_sleep;
+#ifdef CONFIG_IEEE80211W
+ struct wpa_igtk igtk;
+ struct wpa_igtk igtk_wnm_sleep;
+#endif /* CONFIG_IEEE80211W */
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -60,7 +66,8 @@ struct wpa_sm {
size_t ssid_len;
int wpa_ptk_rekey;
int p2p;
-
+ int wpa_rsc_relaxation;
+
u8 own_addr[ETH_ALEN];
const char *ifname;
const char *bridge_ifname;
@@ -121,6 +128,7 @@ struct wpa_sm {
size_t r0kh_id_len;
u8 r1kh_id[FT_R1KH_ID_LEN];
int ft_completed;
+ int ft_reassoc_completed;
int over_the_ds_in_progress;
u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
int set_ptk_after_assoc;
@@ -305,7 +313,10 @@ static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm, const u8 *pmk, size
return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
}
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic);
+int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+ int ver, const u8 *dest, u16 proto,
+ u8 *msg, size_t msg_len, u8 *key_mic);
+
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, int ver, const u8 *nonce, const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ptk *ptk);
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, const struct wpa_eapol_key *key, u16 ver, u16 key_info, struct wpa_ptk *ptk);
diff --git a/external/wpa_supplicant/wpa_supplicant/config.c b/external/wpa_supplicant/wpa_supplicant/config.c
index 9a08e6aa..9d80de7a 100644
--- a/external/wpa_supplicant/wpa_supplicant/config.c
+++ b/external/wpa_supplicant/wpa_supplicant/config.c
@@ -3390,6 +3390,7 @@ struct wpa_config *wpa_config_alloc_empty(const char *ctrl_interface, const char
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
+ config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
if (ctrl_interface) {
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -4016,6 +4017,7 @@ static const struct global_parse_data global_fields[] = {
{INT(passive_scan), 0},
{INT(reassoc_same_bss_optim), 0},
{INT(wps_priority), 0},
+ { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
};
#undef FUNC
diff --git a/external/wpa_supplicant/wpa_supplicant/config.h b/external/wpa_supplicant/wpa_supplicant/config.h
index 6f62a81b..c962a5df 100644
--- a/external/wpa_supplicant/wpa_supplicant/config.h
+++ b/external/wpa_supplicant/wpa_supplicant/config.h
@@ -34,6 +34,7 @@
#define DEFAULT_KEY_MGMT_OFFLOAD 1
#define DEFAULT_CERT_IN_CB 1
#define DEFAULT_P2P_GO_CTWINDOW 0
+#define DEFAULT_WPA_RSC_RELAXATION 1
#include "config_ssid.h"
#include "wps/wps.h"
@@ -1182,6 +1183,16 @@ struct wpa_config {
* by executing the WPS protocol.
*/
int wps_priority;
+
+ /**
+ * wpa_rsc_relaxation - RSC relaxation on GTK installation
+ *
+ * Values:
+ * 0 - use the EAPOL-Key RSC value on GTK installation
+ * 1 - use the null RSC if a bogus RSC value is detected in message 3
+ * of 4-Way Handshake or message 1 of Group Key Handshake.
+ */
+ int wpa_rsc_relaxation;
};
/* Prototypes for common functions from config.c */
diff --git a/external/wpa_supplicant/wpa_supplicant/config_file.c b/external/wpa_supplicant/wpa_supplicant/config_file.c
index 66b3f5ef..6572169c 100644
--- a/external/wpa_supplicant/wpa_supplicant/config_file.c
+++ b/external/wpa_supplicant/wpa_supplicant/config_file.c
@@ -1331,6 +1331,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_priority) {
fprintf(f, "wps_priority=%d\n", config->wps_priority);
}
+ if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION)
+ fprintf(f, "wpa_rsc_relaxation=%d\n",
+ config->wpa_rsc_relaxation);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/external/wpa_supplicant/wpa_supplicant/ctrl_iface.c b/external/wpa_supplicant/wpa_supplicant/ctrl_iface.c
index b9e28979..142650f3 100644
--- a/external/wpa_supplicant/wpa_supplicant/ctrl_iface.c
+++ b/external/wpa_supplicant/wpa_supplicant/ctrl_iface.c
@@ -6641,6 +6641,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
}
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->wnmsleep_used = 0;
}
static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
diff --git a/external/wpa_supplicant/wpa_supplicant/events.c b/external/wpa_supplicant/wpa_supplicant/events.c
index a98d7310..58680e5f 100644
--- a/external/wpa_supplicant/wpa_supplicant/events.c
+++ b/external/wpa_supplicant/wpa_supplicant/events.c
@@ -302,6 +302,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpa_s->key_mgmt = 0;
wpas_rrm_reset(wpa_s);
+ wpa_s->wnmsleep_used = 0;
}
static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
diff --git a/external/wpa_supplicant/wpa_supplicant/wnm_sta.c b/external/wpa_supplicant/wpa_supplicant/wnm_sta.c
index bb56c99a..1a0b90e2 100644
--- a/external/wpa_supplicant/wpa_supplicant/wnm_sta.c
+++ b/external/wpa_supplicant/wpa_supplicant/wnm_sta.c
@@ -33,11 +33,14 @@ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, u16 *b
}
/* set the TFS IE to driver */
-static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, const u8 *addr, u8 *buf, u16 *buf_len, enum wnm_oper oper)
+static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *buf, u16 buf_len,
+ enum wnm_oper oper)
{
+ u16 len = buf_len;
wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
- return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
}
/* MLME-SLEEPMODE.request */
@@ -117,7 +120,9 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 in
if (res < 0) {
wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " "(action=%d, intval=%d)", action, intval);
}
-
+ else
+ wpa_s->wnmsleep_used = 1;
+
os_free(wnmsleep_ie);
os_free(wnmtfs_ie);
os_free(mgmt);
@@ -125,7 +130,9 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 in
return res;
}
-static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, u8 *tfsresp_ie_start, u8 *tfsresp_ie_end)
+static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
+ const u8 *tfsresp_ie_start,
+ const u8 *tfsresp_ie_end)
{
wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, wpa_s->bssid, NULL, NULL);
/* remove GTK/IGTK ?? */
@@ -136,7 +143,10 @@ static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, u8 *tfsre
tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - tfsresp_ie_start;
wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
/* pass the TFS Resp IE(s) to driver for processing */
- if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, tfsresp_ie_start, &tfsresp_ie_len, WNM_SLEEP_TFS_RESP_IE_SET)) {
+ if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
+ tfsresp_ie_start,
+ tfsresp_ie_len,
+ WNM_SLEEP_TFS_RESP_IE_SET)) {
wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
}
}
@@ -197,14 +207,20 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, const u8 *
* Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
* WNM-Sleep Mode IE | TFS Response IE
*/
- u8 *pos = (u8 *)frm; /* point to payload after the action field */
+ const u8 *pos = frm; /* point to payload after the action field */
u16 key_len_total;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Resp IE (assuming consecutive) */
- u8 *tfsresp_ie_start = NULL;
- u8 *tfsresp_ie_end = NULL;
+ const u8 *tfsresp_ie_start = NULL;
+ const u8 *tfsresp_ie_end = NULL;
size_t left;
+ if (!wpa_s->wnmsleep_used) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested");
+ return;
+ }
+
if (len < 3) {
return;
}
@@ -242,7 +258,10 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, const u8 *
return;
}
- if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
+ wpa_s->wnmsleep_used = 0;
+
+ if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
+ wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " "frame (action=%d, intval=%d)", wnmsleep_ie->action_type, wnmsleep_ie->intval);
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, tfsresp_ie_end);
diff --git a/external/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h b/external/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h
index a55b203a..16ea29ac 100644
--- a/external/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h
+++ b/external/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h
@@ -648,7 +648,8 @@ struct wpa_supplicant {
unsigned int reattach: 1; /* reassociation to the same BSS requested */
unsigned int mac_addr_changed: 1;
unsigned int added_vif: 1;
-
+ unsigned int wnmsleep_used:1;
+
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
diff --git a/external/wpa_supplicant/wpa_supplicant/wpas_glue.c b/external/wpa_supplicant/wpa_supplicant/wpas_glue.c
index f9ce49f4..8aff7664 100644
--- a/external/wpa_supplicant/wpa_supplicant/wpas_glue.c
+++ b/external/wpa_supplicant/wpa_supplicant/wpas_glue.c
@@ -993,6 +993,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, struct wpa
}
}
#endif /* CONFIG_P2P */
+ conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}