]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
mesh: Add MESH_PMKSA_GET/ADD commands
authorMasashi Honma <masashi.honma@gmail.com>
Mon, 2 Jan 2017 10:32:07 +0000 (19:32 +0900)
committerJouni Malinen <j@w1.fi>
Sat, 14 Jan 2017 16:07:46 +0000 (18:07 +0200)
These commnds 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') also.

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 re-store
the PMKSA cache into wpa_supplicant. By using re-stored PMKSA cache,
wpa_supplicant can skip commit message creation which can use
significant 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@gmail.com>
13 files changed:
src/ap/ctrl_iface_ap.c
src/ap/ctrl_iface_ap.h
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/mesh_rsn.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 3680fda3153f5197fc14a0a69eeaf6d70c34ca56..a760e3a009278a163af37f0c48e8e57400f15f3f 100644 (file)
@@ -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 */
index 4f996800f1326a37da347212ff2a1b4633b4e5a2..3b61cac35c3de526b7c1dc684e533b705c158987 100644 (file)
@@ -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 */
index d610e7e5b0057cd9ff20e87adaa17b4cff4462dc..bce5abf98932eb920d75b6282b300fe33a928589 100644 (file)
@@ -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 Supplicant, 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 == NULL)
+               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,70 @@ 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 */
index d8d9c5a25c0e42286e3162dea738df74dc2fe0e5..bd1b672374a74317f926da28b2e7692b1fd4bcaf 100644 (file)
@@ -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 */
index 43e3558a4f33d629b12c5c9f596cc1c113ac5eff..4d4b23748120e69ba4ab310ffd1efb3db1b2eee4 100644 (file)
@@ -3850,6 +3850,58 @@ 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)
+{
+       int ret;
+
+       if (!wpa_auth || !wpa_auth->pmksa)
+               return -1;
+
+       ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
+       if (ret < 0)
+               wpa_printf(MSG_DEBUG,
+                          "RSN: Failed to store external PMKSA cache for "
+                          MACSTR, MAC2STR(entry->spa));
+
+       return ret;
+}
+
+#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)
index 743f2e6f5a0893c5ecf1849dd36a4af1725e2efe..f383ab0a0adc0350542c603128721640f18e5b36 100644 (file)
@@ -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);
index c594c7ebf4bb4b85f5b5f9804271855a9dee66f1..608d3550fb1d30a93394ff6b5d4b69d28261e99a 100644 (file)
@@ -1437,6 +1437,43 @@ 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)
+{
+       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_zalloc(sizeof(struct external_pmksa_cache));
+       if (!entry)
+               return -1;
+
+       entry->pmksa_cache = pmksa_cache;
+
+       dl_list_add(&wpa_s->mesh_external_pmksa_cache, &entry->list);
+
+       return 0;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
 #endif /* CONFIG_CTRL_IFACE */
 
 
index 5a59ddcc1c93e22a8df6edf3df805cc86cf207ab..3fa656f7b5b3a6d61740dfe9d8370dce18e3c78b 100644 (file)
@@ -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);
index 10c9e71a81b11cc45a6d0d41c4f3288c77eff22a..aa1211c2a6779767079a095c31ffa1003a4826dc 100644 (file)
@@ -9114,6 +9114,40 @@ 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 */
 
 
@@ -9198,6 +9232,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))
index b1cf1385d97aeccbe8b112474d2ac2860e4748ef..065fa0814134e2f4cf975d945ad04085b3d3d04b 100644 (file)
@@ -224,6 +224,9 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
        struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
        const u8 *ie;
        size_t ie_len;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+       struct external_pmksa_cache *entry;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 
        mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
        if (mesh_rsn == NULL)
@@ -242,6 +245,22 @@ struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
 
        bss->wpa_auth = mesh_rsn->auth;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+       while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+                                    struct external_pmksa_cache,
+                                    list)) != NULL) {
+               int ret;
+
+               ret = wpa_auth_pmksa_add_entry(bss->wpa_auth,
+                                              entry->pmksa_cache);
+               dl_list_del(&entry->list);
+               os_free(entry);
+
+               if (ret < 0)
+                       return NULL;
+       }
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
        ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
        conf->rsn_ie = (u8 *) ie;
        conf->rsn_ie_len = ie_len;
index 77038cadbad60e91cfeb8713b47ee3be6272366d..538d5ccdc2ec3013da52dd78ef6858f0e8641ac8 100644 (file)
@@ -348,6 +348,23 @@ 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 +2909,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,
index ae62bd63b09af99fada9622fecd575eb3d1e19fa..bc59c6760990843ac190ab3a01bec9f5738f6fd8 100644 (file)
@@ -586,6 +586,22 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpabuf_free(wpa_s->lci);
        wpa_s->lci = NULL;
        wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       {
+               struct external_pmksa_cache *entry;
+
+               while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+                                            struct external_pmksa_cache,
+                                            list)) != NULL) {
+                       dl_list_del(&entry->list);
+                       os_free(entry->pmksa_cache);
+                       os_free(entry);
+               }
+       }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 }
 
 
@@ -4977,6 +4993,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_external_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
index 576f141b15b9b970cb89a9eb2fb389893dfd48b8..2fb32e28fe1b500c938d5588b6aacf5ff23e3091 100644 (file)
@@ -461,6 +461,11 @@ struct beacon_rep_data {
 };
 
 
+struct external_pmksa_cache {
+       struct dl_list list;
+       void *pmksa_cache;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -791,6 +796,10 @@ 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 external_pmksa_cache::list */
+       struct dl_list mesh_external_pmksa_cache;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
 #endif /* CONFIG_MESH */
 
        unsigned int off_channel_freq;