On Tue, Dec 27, 2016 at 12:49:09PM +0900, Masashi Honma wrote: > These commnds are mesh version of PMKSA_GET/ADD commands. So the usage > and security risk is similar to them. Refer > Commit 3459381dd260e15e7bf768a75cb0b799cc1db33a ('External persistent > storage for PMKSA cache entries') also. ... This looks like a reasonable thing to add, but there are some issues in the current patch especially as far as the correct location of adding the PMKSA cache entries for a new mesh network is concerned (per-peer-STA function vs. initialization time) and as far as memory management is concerned (couple of memory leaks). I did some cleanup while reviewing this and added "FIX" comments to the places that did not look correct to me. Outcome of that is below. Please take a look at the FIX comments and update the patch to address the identified issues (or describe why there is no issue). From: Masashi Honma <masashi.honma@xxxxxxxxx> Subject: [PATCH] mesh: Add MESH_PMKSA_GET/ADD commands These commands are mesh version of PMKSA_GET/ADD commands. So the usage and security risk is similar to them. Refer to commit 3459381dd260e15e7bf768a75cb0b799cc1db33a ('External persistent storage for PMKSA cache entries') for more details. The MESH_PMKSA_GET command requires peer MAC address or "any" as an argument and outputs appropriate stored PMKSA cache. And the MESH_PMKSA_ADD command receives an output of MESH_PMKSA_GET and restore the PMKSA cache into wpa_supplicant. By using restored PMKSA cache, wpa_supplicant can skip SAE commit message creation which spends CPU resources. The output of the MESH_PMKSA_GET command uses the following format: <BSSID> <PMKID> <PMK> <expiration in seconds> The example of MESH_PMKSA_ADD command is this. MESH_PMKSA_ADD 02:00:00:00:03:00 231dc1c9fa2eed0354ea49e8ff2cc2dc cb0f6c9cab358a8146488566ca155421ab4f3ea4a6de2120050c149b797018fe 42930 MESH_PMKSA_ADD 02:00:00:00:04:00 d7e595916611640d3e4e8eac02909c3c eb414a33c74831275f25c2357b3c12e3d8bd2f2aab6cf781d6ade706be71321a 43180 This functionality is disabled by default and can be enabled with CONFIG_PMKSA_CACHE_EXTERNAL=y build configuration option. Signed-off-by: Masashi Honma <masashi.honma@xxxxxxxxx> --- src/ap/ctrl_iface_ap.c | 57 +++++++++++++++++ src/ap/ctrl_iface_ap.h | 3 + src/ap/pmksa_cache_auth.c | 126 +++++++++++++++++++++++++++++++++++++- src/ap/pmksa_cache_auth.h | 9 +++ src/ap/wpa_auth.c | 44 +++++++++++++ src/ap/wpa_auth.h | 7 +++ wpa_supplicant/ap.c | 39 ++++++++++++ wpa_supplicant/ap.h | 3 + wpa_supplicant/ctrl_iface.c | 41 +++++++++++++ wpa_supplicant/mesh_rsn.c | 25 ++++++++ wpa_supplicant/wpa_cli.c | 26 ++++++++ wpa_supplicant/wpa_supplicant.c | 26 ++++++++ wpa_supplicant/wpa_supplicant_i.h | 8 +++ 13 files changed, 411 insertions(+), 3 deletions(-) diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 3680fda..a760e3a 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -639,3 +639,60 @@ void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd) { wpa_auth_pmksa_flush(hapd->wpa_auth); } + + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + +int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd, + const u8 *addr, char *buf, size_t len) +{ + return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len); +} + + +void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd) +{ + u8 spa[ETH_ALEN]; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN_MAX]; + char *pos; + int expiration; + + /* + * Entry format: + * <BSSID> <PMKID> <PMK> <expiration in seconds> + */ + + if (hwaddr_aton(cmd, spa)) + return NULL; + + pos = os_strchr(cmd, ' '); + if (!pos) + return NULL; + pos++; + + if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0) + return NULL; + + pos = os_strchr(pos, ' '); + if (!pos) + return NULL; + pos++; + + if (hexstr2bin(pos, pmk, PMK_LEN) < 0) + return NULL; + + pos = os_strchr(pos, ' '); + if (!pos) + return NULL; + pos++; + + if (sscanf(pos, "%d", &expiration) != 1) + return NULL; + + return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index 4f99680..3b61cac 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -32,5 +32,8 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd); int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf, size_t len); void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd); +int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd, + const u8 *addr, char *buf, size_t len); +void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd); #endif /* CTRL_IFACE_AP_H */ diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index d610e7e..9c3d9c7 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -282,7 +282,42 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, int session_timeout, struct eapol_state_machine *eapol, int akmp) { - struct rsn_pmksa_cache_entry *entry, *pos; + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len, + aa, spa, session_timeout, eapol, + akmp); + + if (pmksa_cache_auth_add_entry(pmksa, entry) < 0) + return NULL; + + return entry; +} + + +/** + * pmksa_cache_auth_create_entry - Create a PMKSA cache entry + * @pmk: The new pairwise master key + * @pmk_len: PMK length in bytes, usually PMK_LEN (32) + * @pmkid: Calculated PMKID + * @kck: Key confirmation key or %NULL if not yet derived + * @kck_len: KCK length in bytes + * @aa: Authenticator address + * @spa: Supplicant address + * @session_timeout: Session timeout + * @eapol: Pointer to EAPOL state machine data + * @akmp: WPA_KEY_MGMT_* used in key derivation + * Returns: Pointer to the added PMKSA cache entry or %NULL on error + * + * This function creates a PMKSA entry. + */ +struct rsn_pmksa_cache_entry * +pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid, + const u8 *kck, size_t kck_len, const u8 *aa, + const u8 *spa, int session_timeout, + struct eapol_state_machine *eapol, int akmp) +{ + struct rsn_pmksa_cache_entry *entry; struct os_reltime now; if (pmk_len > PMK_LEN_MAX) @@ -315,9 +350,30 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, os_memcpy(entry->spa, spa, ETH_ALEN); pmksa_cache_from_eapol_data(entry, eapol); + return entry; +} + + +/** + * pmksa_cache_auth_add_entry - Add a PMKSA cache entry + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() + * @entry: Pointer to PMKSA cache entry + * + * This function adds PMKSA cache entry to the PMKSA cache. If an old entry is + * already in the cache for the same STA, this entry will be replaced with the + * new entry. PMKID will be calculated based on the PMK. + */ +int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry) +{ + struct rsn_pmksa_cache_entry *pos; + + if (!entry) + return -1; + /* Replace an old entry for the same STA (if found) with the new entry */ - pos = pmksa_cache_auth_get(pmksa, spa, NULL); + pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL); if (pos) pmksa_cache_free_entry(pmksa, pos); @@ -331,7 +387,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, pmksa_cache_link_entry(pmksa, entry); - return entry; + return 0; } @@ -605,3 +661,67 @@ int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) } return pos - buf; } + + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH +/** + * pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() + * @addr: MAC address of the peer (NULL means any) + * @buf: Buffer for the list + * @len: Length of the buffer + * Returns: Number of bytes written to buffer + * + * This function is used to generate a text format representation of the + * current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store + * in external storage. + */ +int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr, + char *buf, size_t len) +{ + int ret; + char *pos, *end; + struct rsn_pmksa_cache_entry *entry; + struct os_reltime now; + + pos = buf; + end = buf + len; + os_get_reltime(&now); + + /* + * Entry format: + * <BSSID> <PMKID> <PMK> <expiration in seconds> + */ + for (entry = pmksa->pmksa; entry; entry = entry->next) { + if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0) + continue; + + ret = os_snprintf(pos, end - pos, MACSTR " ", + MAC2STR(entry->spa)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid, + PMKID_LEN); + + ret = os_snprintf(pos, end - pos, " "); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + pos += wpa_snprintf_hex(pos, end - pos, entry->pmk, + entry->pmk_len); + + ret = os_snprintf(pos, end - pos, " %d\n", + (int) (entry->expiration - now.sec)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + return pos - buf; +} +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h index d8d9c5a..bd1b672 100644 --- a/src/ap/pmksa_cache_auth.h +++ b/src/ap/pmksa_cache_auth.h @@ -53,6 +53,13 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, int session_timeout, struct eapol_state_machine *eapol, int akmp); struct rsn_pmksa_cache_entry * +pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid, + const u8 *kck, size_t kck_len, const u8 *aa, + const u8 *spa, int session_timeout, + struct eapol_state_machine *eapol, int akmp); +int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry); +struct rsn_pmksa_cache_entry * pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, const struct rsn_pmksa_cache_entry *old_entry, const u8 *aa, const u8 *pmkid); @@ -65,5 +72,7 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa, struct radius_das_attrs *attr); int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa); +int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr, + char *buf, size_t len); #endif /* PMKSA_CACHE_H */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 43e3558..219ab47 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -3850,6 +3850,50 @@ void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth) } +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + +int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr, + char *buf, size_t len) +{ + if (!wpa_auth || !wpa_auth->pmksa) + return 0; + + return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len); +} + + +struct rsn_pmksa_cache_entry * +wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk, + const u8 *pmkid, int expiration) +{ + struct rsn_pmksa_cache_entry *entry; + struct os_reltime now; + + entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa, + spa, 0, NULL, WPA_KEY_MGMT_SAE); + if (!entry) + return NULL; + + os_get_reltime(&now); + entry->expiration = now.sec + expiration; + return entry; +} + + +int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth, + struct rsn_pmksa_cache_entry *entry) +{ + if (!wpa_auth || !wpa_auth->pmksa) + return -1; + + return pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid) diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 743f2e6..f383ab0 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -302,6 +302,13 @@ 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); +int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr, + char *buf, size_t len); +struct rsn_pmksa_cache_entry * +wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk, + const u8 *pmkid, int expiration); +int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth, + struct rsn_pmksa_cache_entry *entry); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 5afb772..44061d3 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1436,6 +1436,45 @@ void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s) if (wpa_s->ifmsh) hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]); } + + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + +int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr, + char *buf, size_t len) +{ + if (!wpa_s->ifmsh) + return -1; + return hostapd_ctrl_iface_pmksa_list_mesh(wpa_s->ifmsh->bss[0], addr, + &buf[0], len); +} + + +int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd) +{ + struct external_pmksa_cache *entry; + void *pmksa_cache; + + pmksa_cache = hostapd_ctrl_iface_pmksa_create_entry(wpa_s->own_addr, + cmd); + if (!pmksa_cache) + return -1; + + entry = os_malloc(sizeof(struct external_pmksa_cache)); + if (!entry) + return -1; + + entry->pmksa_cache = pmksa_cache; + + dl_list_add(&wpa_s->mesh_ext_pmksa_cache, &entry->list); + + return 0; +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + #endif /* CONFIG_CTRL_IFACE */ diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 5a59ddc..3fa656f 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -85,6 +85,9 @@ int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s); int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len); void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s); +int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr, + char *buf, size_t len); +int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd); void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, struct dfs_event *radar); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index be178d7..0505e8e 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8982,6 +8982,39 @@ fail: return ret; } + +#ifdef CONFIG_MESH + +static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, + size_t buflen) +{ + u8 spa[ETH_ALEN]; + + if (!wpa_s->ifmsh) + return -1; + + if (os_strcasecmp(cmd, "any") == 0) + return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen); + + if (hwaddr_aton(cmd, spa)) + return -1; + return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen); +} + + +static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s, + char *cmd) +{ + /* + * We do not check mesh interface existance because PMKSA should be + * stored before wpa_s->ifmsh creation to suppress commit message + * creation. + */ + return wpas_ap_pmksa_cache_add_external(wpa_s, cmd); +} + +#endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ @@ -9066,6 +9099,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) { if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0) reply_len = -1; +#ifdef CONFIG_MESH + } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) { + reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15, + reply, reply_size); + } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) { + if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0) + reply_len = -1; +#endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index b1cf138..868714a 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -320,6 +320,9 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, struct rsn_pmksa_cache_entry *pmksa; unsigned int rnd; int ret; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + struct external_pmksa_cache *entry; +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ if (!ssid) { wpa_msg(wpa_s, MSG_DEBUG, @@ -333,6 +336,28 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, return -1; } +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + /* FIX: Why is this loop here? This function is called for a specific + * STA while the loop here adds PMKSA cache entries for all STAs. + * Shouldn't this addition be done when starting the mesh rather than + * when going through a STA-specific SAE initialization? */ + while ((entry = dl_list_last(&wpa_s->mesh_ext_pmksa_cache, + struct external_pmksa_cache, + list)) != NULL) { + if (wpa_auth_pmksa_add_entry(hapd->wpa_auth, + entry->pmksa_cache) < 0) { + wpa_msg(wpa_s, MSG_DEBUG, + "AUTH: Failed to store external PMKSA cache"); + /* FIX: Wouldn't this lost the last reference to + * entry->pmksa_cache and by doing so, leak memory? + */ + return -1; + } + dl_list_del(&entry->list); + os_free(entry); + } +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL); if (pmksa) { if (!sta->wpa_sm) diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 1b74729..d164d8b 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -348,6 +348,24 @@ static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv); } + +#ifdef CONFIG_MESH + +static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv); +} + + +static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv); +} + +#endif /* CONFIG_MESH */ + #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ @@ -2892,6 +2910,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL, cli_cmd_flag_sensitive, "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" }, +#ifdef CONFIG_MESH + { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL, + cli_cmd_flag_none, + "<peer MAC address | any> = fetch all stored mesh PMKSA cache entries" }, + { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL, + cli_cmd_flag_sensitive, + "<BSSID> <PMKID> <PMK> <expiration in seconds> = store mesh PMKSA cache entry from external storage" }, +#endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ { "reassociate", wpa_cli_cmd_reassociate, NULL, cli_cmd_flag_none, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 214b9b3..e2d04f3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -585,6 +585,26 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpabuf_free(wpa_s->lci); wpa_s->lci = NULL; + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + { + struct external_pmksa_cache *entry; + + while ((entry = dl_list_last(&wpa_s->mesh_ext_pmksa_cache, + struct external_pmksa_cache, + list)) != NULL) { + /* FIX: free entry->pmksa_cache (need pmksa_cache_auth.c + * changes to do that, e.g., by allowing + * _pmksa_cache_free_entry() to be called from here or + * maybe more likely by adding a new wrapper function + * for this special external cache case). */ + dl_list_del(&entry->list); + os_free(entry); + } + } +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ } @@ -4976,6 +4996,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, if (wpa_bss_init(wpa_s) < 0) return -1; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL +#ifdef CONFIG_MESH + dl_list_init(&wpa_s->mesh_ext_pmksa_cache); +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + /* * Set Wake-on-WLAN triggers, if configured. * Note: We don't restore/remove the triggers on shutdown (it doesn't diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index f03d51a..5dfa3b4 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -446,6 +446,11 @@ struct wpa_bss_tmp_disallowed { struct os_reltime disallowed_until; }; +struct external_pmksa_cache { + struct dl_list list; + void *pmksa_cache; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -776,6 +781,9 @@ struct wpa_supplicant { unsigned int mesh_if_created:1; unsigned int mesh_ht_enabled:1; unsigned int mesh_vht_enabled:1; +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + struct dl_list mesh_ext_pmksa_cache; +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ #endif /* CONFIG_MESH */ unsigned int off_channel_freq; -- 2.7.4 -- Jouni Malinen PGP id EFC895FA _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap