aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ap/hostapd.h1
-rw-r--r--src/ap/ieee802_11.c28
-rw-r--r--src/ap/ieee802_11.h1
-rw-r--r--src/ap/sta_info.h1
-rw-r--r--src/ap/wpa_auth.c28
-rw-r--r--src/ap/wpa_auth.h6
-rw-r--r--wpa_supplicant/ctrl_iface.c12
-rw-r--r--wpa_supplicant/mesh.c5
-rw-r--r--wpa_supplicant/mesh.h3
-rw-r--r--wpa_supplicant/mesh_mpm.c40
-rw-r--r--wpa_supplicant/mesh_mpm.h3
-rw-r--r--wpa_supplicant/mesh_rsn.c35
-rw-r--r--wpa_supplicant/wpa_cli.c2
13 files changed, 147 insertions, 18 deletions
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 60516ae..75a7c04 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -262,6 +262,7 @@ struct hostapd_data {
struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
+ u8 mesh_required_peer[ETH_ALEN];
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 134ae06..6a373c5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -554,6 +554,18 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
}
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->sae->state = SAE_ACCEPTED;
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk, sta->sae->pmkid);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *bssid, u8 auth_transaction)
{
@@ -676,13 +688,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
sae_set_retransmit_timer(hapd, sta);
} else {
- sta->flags |= WLAN_STA_AUTH;
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
- wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk, sta->sae->pmkid);
+ sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
@@ -691,6 +697,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
") doing reauthentication",
MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
} else {
if (sae_check_big_sync(sta))
return WLAN_STATUS_SUCCESS;
@@ -733,6 +740,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
sta->sae->sync = 0;
}
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ sta->mesh_sae_pmksa_caching = 0;
+ }
+
if (auth_transaction == 1) {
const u8 *token = NULL, *pos, *end;
size_t token_len = 0;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1a96b33..71b3b49 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -102,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_SAE */
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 70a59cc..3d9a928 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -183,6 +183,7 @@ struct sta_info {
#ifdef CONFIG_SAE
struct sae_data *sae;
+ unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index ad1a7bc..779a40d 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3375,6 +3375,34 @@ void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
}
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return NULL;
+ return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+}
+
+
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk)
+{
+ if (!sm)
+ return;
+
+ sm->pmksa = pmksa;
+ if (sm->pmksa->pmk)
+ os_memcpy(pmk, sm->pmksa->pmk, PMK_LEN);
+ if (sm->pmksa->pmkid) {
+ os_memcpy(pmkid, sm->pmksa->pmkid, PMKID_LEN);
+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed,
+ sm->pmksa->pmkid, PMKID_LEN);
+ }
+}
+
+
/*
* Remove and free the group from wpa_authenticator. This is triggered by a
* callback to make sure nobody is currently iterating the group list while it
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 1669766..0de8d97 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -301,6 +301,12 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
size_t len);
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 381d521..a79200b 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2744,11 +2744,21 @@ static int wpa_supplicant_ctrl_iface_mesh_peer_add(
struct wpa_supplicant *wpa_s, char *cmd)
{
u8 addr[ETH_ALEN];
+ int duration;
+ char *pos;
+
+ pos = os_strstr(cmd, " duration=");
+ if (pos) {
+ *pos = '\0';
+ duration = atoi(pos + 10);
+ } else {
+ duration = -1;
+ }
if (hwaddr_aton(cmd, addr))
return -1;
- return wpas_mesh_peer_add(wpa_s, addr);
+ return wpas_mesh_peer_add(wpa_s, addr, duration);
}
#endif /* CONFIG_MESH */
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index cdb5eb0..89b033b 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -605,7 +605,8 @@ int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
}
-int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr)
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
{
- return mesh_mpm_connect_peer(wpa_s, addr);
+ return mesh_mpm_connect_peer(wpa_s, addr, duration);
}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index b40ae6c..7317083 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -19,7 +19,8 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
size_t len);
int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
-int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index c470d10..c014eaf 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -14,6 +14,7 @@
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "mesh_mpm.h"
@@ -419,6 +420,7 @@ static void plink_timer(void *eloop_ctx, void *user_data)
struct sta_info *sta = user_data;
u16 reason = 0;
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
case PLINK_OPEN_RCVD:
@@ -448,6 +450,13 @@ static void plink_timer(void *eloop_ctx, void *user_data)
break;
case PLINK_HOLDING:
/* holding timer */
+
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+ " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ }
mesh_mpm_fsm_restart(wpa_s, sta);
break;
default:
@@ -512,7 +521,17 @@ int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
}
-int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
struct hostapd_data *hapd;
@@ -547,10 +566,14 @@ int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
return -1;
}
- if (conf->security == MESH_CONF_SEC_NONE)
+ if (conf->security == MESH_CONF_SEC_NONE) {
mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
- else
+ } else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
+ os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+ eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+ peer_add_timer, wpa_s, NULL);
+ }
return 0;
}
@@ -565,6 +588,7 @@ void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
hapd->num_plinks = 0;
hostapd_free_stas(hapd);
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
}
@@ -705,7 +729,9 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
if (!sta)
return;
- if (ssid && ssid->no_auto_peer) {
+ if (ssid && ssid->no_auto_peer &&
+ (is_zero_ether_addr(data->mesh_required_peer) ||
+ os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
MACSTR " because of no_auto_peer", MAC2STR(addr));
if (data->mesh_pending_auth) {
@@ -785,7 +811,10 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
hapd->num_plinks++;
sta->flags |= WLAN_STA_ASSOC;
+ sta->mesh_sae_pmksa_caching = 0;
+ eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+ peer_add_timer(wpa_s, NULL);
eloop_cancel_timeout(plink_timer, wpa_s, sta);
/* Send ctrl event */
@@ -1065,7 +1094,8 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
* open mesh, then go ahead and add the peer before proceeding.
*/
if (!sta && action_field == PLINK_OPEN &&
- !(mconf->security & MESH_CONF_SEC_AMPE))
+ (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+ wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
if (!sta) {
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index cbecd37..5fc1e61 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -19,7 +19,8 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
struct sta_info *sta,
enum mesh_plink_state state);
int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
-int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int duration);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 5d88274..7077cc6 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -291,6 +291,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct rsn_pmksa_cache_entry *pmksa;
unsigned int rnd;
int ret;
@@ -306,6 +307,29 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
return -1;
}
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+ if (pmksa) {
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to initialize RSN state machine");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "AUTH: Mesh PMKSA cache entry found for " MACSTR
+ " - try to use PMKSA caching instead of new SAE authentication",
+ MAC2STR(sta->addr));
+ wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+ sta->sae->pmkid, sta->sae->pmk);
+ sae_accept_sta(hapd, sta);
+ sta->mesh_sae_pmksa_caching = 1;
+ return 0;
+ }
+ sta->mesh_sae_pmksa_caching = 0;
+
if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
return -1;
@@ -514,6 +538,17 @@ int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
(elems->mic - 2) - cat };
+ if (!sta->sae) {
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+ wpa_printf(MSG_INFO,
+ "Mesh RSN: SAE is not prepared yet");
+ return -1;
+ }
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ }
+
if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
wpa_msg(wpa_s, MSG_DEBUG,
"Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index bd669e3..36a7a4e 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3229,7 +3229,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
"<addr> = Remove a mesh peer" },
{ "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
cli_cmd_flag_none,
- "<addr> = Add a mesh peer" },
+ "<addr> [duration=<seconds>] = Add a mesh peer" },
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,