aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorMasashi Honma <masashi.honma@gmail.com>2016-03-09 09:16:14 (GMT)
committerJouni Malinen <j@w1.fi>2016-03-20 15:56:38 (GMT)
commit9f2cf23e2e0d8f5c28a403c44fad1f65705f884e (patch)
treef5c1126a33fcc3c59fc84edf9210ba22598ecdd6 /wpa_supplicant
parent4c522c7798d16cac0d59de8b23d8202fb9fa8a59 (diff)
downloadhostap-9f2cf23e2e0d8f5c28a403c44fad1f65705f884e.zip
hostap-9f2cf23e2e0d8f5c28a403c44fad1f65705f884e.tar.gz
hostap-9f2cf23e2e0d8f5c28a403c44fad1f65705f884e.tar.bz2
mesh: Add support for PMKSA caching
This patch add functionality of mesh SAE PMKSA caching. If the local STA already has peer's PMKSA entry in the cache, skip SAE authentication and start AMPE with the cached value. If the peer does not support PMKSA caching or does not have the local STA's PMKSA entry in the cache, AMPE will fail and the PMKSA cache entry of the peer will be removed. Then STA retries with ordinary SAE authentication. If the peer does not support PMKSA caching and the local STA uses no_auto_peer=1, the local STA can not retry SAE authentication because NEW_PEER_CANDIDATE event cannot start SAE authentication when no_auto_peer=1. So this patch extends MESH_PEER_ADD command to use duration(sec). Throughout the duration, the local STA can start SAE authentication triggered by NEW_PEER_CANDIDATE even though no_auto_peer=1. This commit requires commit 70c93963edefa37ef84b73efb9d04ea10268341c ('SAE: Fix PMKID calculation for PMKSA cache'). Without that commit, chosen PMK comparison will fail. Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
Diffstat (limited to 'wpa_supplicant')
-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
7 files changed, 89 insertions, 11 deletions
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,