P2P: Maintain list of per-client PSKs for persistent groups
authorJouni Malinen <j@w1.fi>
Sun, 1 Sep 2013 10:40:33 +0000 (13:40 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 1 Sep 2013 18:35:10 +0000 (21:35 +0300)
Record all generated per-client PSKs in the persistent group network
block and configure these for the GO Authenticator whenever re-starting
the persistent group. This completes per-client PSK support for
persistent groups.

Signed-hostap: Jouni Malinen <j@w1.fi>

src/ap/hostapd.h
src/ap/wps_hostapd.c
wpa_supplicant/ap.c
wpa_supplicant/config.c
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/config_winreg.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index cae4756..dbf1b52 100644 (file)
@@ -204,6 +204,11 @@ struct hostapd_data {
        void (*setup_complete_cb)(void *ctx);
        void *setup_complete_cb_ctx;
 
+       void (*new_psk_cb)(void *ctx, const u8 *mac_addr,
+                          const u8 *p2p_dev_addr, const u8 *psk,
+                          size_t psk_len);
+       void *new_psk_cb_ctx;
+
 #ifdef CONFIG_P2P
        struct p2p_data *p2p;
        struct p2p_group *p2p_group;
index 85eae35..eb300f1 100644 (file)
@@ -125,6 +125,11 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
        os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
        os_memcpy(p->psk, psk, PMK_LEN);
 
+       if (hapd->new_psk_cb) {
+               hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
+                                psk, psk_len);
+       }
+
        p->next = ssid->wpa_psk;
        ssid->wpa_psk = p;
 
index 99c6d8a..c2fb215 100644 (file)
@@ -367,6 +367,19 @@ static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
 }
 
 
+#ifdef CONFIG_P2P
+static void ap_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+                         const u8 *psk, size_t psk_len)
+{
+
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL)
+               return;
+       wpas_p2p_new_psk_cb(wpa_s, mac_addr, p2p_dev_addr, psk, psk_len);
+}
+#endif /* CONFIG_P2P */
+
+
 static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 {
 #ifdef CONFIG_P2P
@@ -571,6 +584,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
                hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
 #ifdef CONFIG_P2P
+               hapd_iface->bss[i]->new_psk_cb = ap_new_psk_cb;
+               hapd_iface->bss[i]->new_psk_cb_ctx = wpa_s;
                hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
                hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
                                                                    ssid);
index a35be51..d666c91 100644 (file)
@@ -1372,6 +1372,60 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
 }
 #endif /* NO_CONFIG_WRITE */
 
+
+static int wpa_config_parse_psk_list(const struct parse_data *data,
+                                    struct wpa_ssid *ssid, int line,
+                                    const char *value)
+{
+       struct psk_list_entry *p;
+       const char *pos;
+
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return -1;
+
+       pos = value;
+       if (os_strncmp(pos, "P2P-", 4) == 0) {
+               p->p2p = 1;
+               pos += 4;
+       }
+
+       if (hwaddr_aton(pos, p->addr)) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+       pos += 17;
+       if (*pos != '-') {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+       pos++;
+
+       if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+
+       dl_list_add(&ssid->psk_list, &p->list);
+
+       return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk_list(const struct parse_data *data,
+                                       struct wpa_ssid *ssid)
+{
+       return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
 #endif /* CONFIG_P2P */
 
 /* Helper macros for network block parser */
@@ -1539,6 +1593,7 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
        { FUNC(p2p_client_list) },
+       { FUNC(psk_list) },
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_HT_OVERRIDES
        { INT_RANGE(disable_ht, 0, 1) },
@@ -1731,6 +1786,8 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
  */
 void wpa_config_free_ssid(struct wpa_ssid *ssid)
 {
+       struct psk_list_entry *psk;
+
        os_free(ssid->ssid);
        os_free(ssid->passphrase);
        os_free(ssid->ext_psk);
@@ -1745,6 +1802,11 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
 #ifdef CONFIG_HT_OVERRIDES
        os_free(ssid->ht_mcs);
 #endif /* CONFIG_HT_OVERRIDES */
+       while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
+                                   list))) {
+               dl_list_del(&psk->list);
+               os_free(psk);
+       }
        os_free(ssid);
 }
 
@@ -1908,6 +1970,7 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
        if (ssid == NULL)
                return NULL;
        ssid->id = id;
+       dl_list_init(&ssid->psk_list);
        if (last)
                last->next = ssid;
        else
index d03de0b..a2791eb 100644 (file)
@@ -158,6 +158,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
        ssid = os_zalloc(sizeof(*ssid));
        if (ssid == NULL)
                return NULL;
+       dl_list_init(&ssid->psk_list);
        ssid->id = id;
 
        wpa_config_set_network_defaults(ssid);
@@ -604,6 +605,7 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
 
 
 #ifdef CONFIG_P2P
+
 static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
 {
        char *value = wpa_config_get(ssid, "p2p_client_list");
@@ -612,6 +614,20 @@ static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
        fprintf(f, "\tp2p_client_list=%s\n", value);
        os_free(value);
 }
+
+
+static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
+{
+       struct psk_list_entry *psk;
+       char hex[32 * 2 + 1];
+
+       dl_list_for_each(psk, &ssid->psk_list, struct psk_list_entry, list) {
+               wpa_snprintf_hex(hex, sizeof(hex), psk->psk, sizeof(psk->psk));
+               fprintf(f, "\tpsk_list=%s" MACSTR "-%s\n",
+                       psk->p2p ? "P2P-" : "", MAC2STR(psk->addr), hex);
+       }
+}
+
 #endif /* CONFIG_P2P */
 
 
@@ -696,6 +712,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        STR(id_str);
 #ifdef CONFIG_P2P
        write_p2p_client_list(f, ssid);
+       write_psk_list(f, ssid);
 #endif /* CONFIG_P2P */
        INT(dtim_period);
        INT(beacon_int);
index 1340dce..3a44272 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Network configuration structures
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #define CONFIG_SSID_H
 
 #include "common/defs.h"
+#include "utils/list.h"
 #include "eap_peer/eap_config.h"
 
 #define MAX_SSID_LEN 32
 #define DEFAULT_AMPDU_FACTOR -1 /* no change */
 #define DEFAULT_AMPDU_DENSITY -1 /* no change */
 
+struct psk_list_entry {
+       struct dl_list list;
+       u8 addr[ETH_ALEN];
+       u8 psk[32];
+       u8 p2p;
+};
+
 /**
  * struct wpa_ssid - Network configuration data
  *
@@ -456,6 +464,11 @@ struct wpa_ssid {
 #endif /* P2P_MAX_STORED_CLIENTS */
 
        /**
+        * psk_list - Per-client PSKs (struct psk_list_entry)
+        */
+       struct dl_list psk_list;
+
+       /**
         * p2p_group - Network generated as a P2P group (used internally)
         */
        int p2p_group;
index 3cf3a91..1b5e237 100644 (file)
@@ -302,6 +302,7 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
                RegCloseKey(nhk);
                return NULL;
        }
+       dl_list_init(&ssid->psk_list);
        ssid->id = id;
 
        wpa_config_set_network_defaults(ssid);
index f8c8b0a..962236b 100644 (file)
@@ -600,6 +600,11 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
                s->ssid_len = ssid->ssid_len;
                os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
        }
+       if (ssid->mode == WPAS_MODE_P2P_GO && wpa_s->global->add_psk) {
+               dl_list_add(&s->psk_list, &wpa_s->global->add_psk->list);
+               wpa_s->global->add_psk = NULL;
+               changed = 1;
+       }
 
 #ifndef CONFIG_NO_CONFIG_WRITE
        if (changed && wpa_s->conf->update_config &&
@@ -775,6 +780,10 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        if (persistent)
                network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
                                                             ssid, go_dev_addr);
+       else {
+               os_free(wpa_s->global->add_psk);
+               wpa_s->global->add_psk = NULL;
+       }
        if (network_id < 0 && ssid)
                network_id = ssid->id;
        if (!client) {
@@ -879,6 +888,44 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s,
+                                 struct wpa_ssid *ssid)
+{
+       struct wpa_ssid *persistent;
+       struct psk_list_entry *psk;
+       struct hostapd_data *hapd;
+
+       if (!wpa_s->ap_iface)
+               return;
+
+       persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+                                            ssid->ssid_len);
+       if (persistent == NULL)
+               return;
+
+       hapd = wpa_s->ap_iface->bss[0];
+
+       dl_list_for_each(psk, &persistent->psk_list, struct psk_list_entry,
+                        list) {
+               struct hostapd_wpa_psk *hpsk;
+
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add persistent group PSK entry for "
+                       MACSTR " psk=%d",
+                       MAC2STR(psk->addr), psk->p2p);
+               hpsk = os_zalloc(sizeof(*hpsk));
+               if (hpsk == NULL)
+                       break;
+               os_memcpy(hpsk->psk, psk->psk, PMK_LEN);
+               if (psk->p2p)
+                       os_memcpy(hpsk->p2p_dev_addr, psk->addr, ETH_ALEN);
+               else
+                       os_memcpy(hpsk->addr, psk->addr, ETH_ALEN);
+               hpsk->next = hapd->conf->ssid.wpa_psk;
+               hapd->conf->ssid.wpa_psk = hpsk;
+       }
+}
+
+
 static void p2p_go_configured(void *ctx, void *data)
 {
        struct wpa_supplicant *wpa_s = ctx;
@@ -918,10 +965,12 @@ static void p2p_go_configured(void *ctx, void *data)
                                       " [PERSISTENT]" : "");
                }
 
-               if (params->persistent_group)
+               if (params->persistent_group) {
                        network_id = wpas_p2p_store_persistent_group(
                                wpa_s->parent, ssid,
                                wpa_s->global->p2p_dev_addr);
+                       wpas_p2p_add_psk_list(wpa_s, ssid);
+               }
                if (network_id < 0)
                        network_id = ssid->id;
                wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
@@ -3970,6 +4019,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        return -1;
        }
 
+       os_free(wpa_s->global->add_psk);
+       wpa_s->global->add_psk = NULL;
+
        if (go_intent < 0)
                go_intent = wpa_s->conf->p2p_go_intent;
 
@@ -4424,6 +4476,9 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       os_free(wpa_s->global->add_psk);
+       wpa_s->global->add_psk = NULL;
+
        /* Make sure we are not running find during connection establishment */
        wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
        wpas_p2p_stop_find_oper(wpa_s);
@@ -4515,6 +4570,9 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
+       os_free(wpa_s->global->add_psk);
+       wpa_s->global->add_psk = NULL;
+
        /* Make sure we are not running find during connection establishment */
        wpas_p2p_stop_find_oper(wpa_s);
 
@@ -5843,6 +5901,11 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
                    (ssid_len != s->ssid_len ||
                     os_memcmp(ssid, s->ssid, ssid_len) != 0))
                        continue;
+               if (addr == NULL) {
+                       if (s->mode == WPAS_MODE_P2P_GO)
+                               return s;
+                       continue;
+               }
                if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
                        return s; /* peer is GO in the persistent group */
                if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
@@ -5966,3 +6029,90 @@ void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
                                          wpas_p2p_search_delay(wpa_s));
        }
 }
+
+
+void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
+                        const u8 *p2p_dev_addr,
+                        const u8 *psk, size_t psk_len)
+{
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       struct wpa_ssid *persistent;
+       struct psk_list_entry *p;
+
+       if (psk_len != sizeof(p->psk))
+               return;
+
+       if (p2p_dev_addr) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR
+                       " p2p_dev_addr=" MACSTR,
+                       MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
+               if (is_zero_ether_addr(p2p_dev_addr))
+                       p2p_dev_addr = NULL;
+       } else {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR,
+                       MAC2STR(mac_addr));
+       }
+
+       if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: new_psk_cb during group formation");
+               /* To be added to persistent group once created */
+               if (wpa_s->global->add_psk == NULL) {
+                       wpa_s->global->add_psk = os_zalloc(sizeof(*p));
+                       if (wpa_s->global->add_psk == NULL)
+                               return;
+               }
+               p = wpa_s->global->add_psk;
+               if (p2p_dev_addr) {
+                       p->p2p = 1;
+                       os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+               } else {
+                       p->p2p = 0;
+                       os_memcpy(p->addr, mac_addr, ETH_ALEN);
+               }
+               os_memcpy(p->psk, psk, psk_len);
+               return;
+       }
+
+       if (ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Ignore new_psk_cb on not-persistent GO");
+               return;
+       }
+
+       persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid,
+                                            ssid->ssid_len);
+       if (!persistent) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK");
+               return;
+       }
+
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return;
+       if (p2p_dev_addr) {
+               p->p2p = 1;
+               os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN);
+       } else {
+               p->p2p = 0;
+               os_memcpy(p->addr, mac_addr, ETH_ALEN);
+       }
+       os_memcpy(p->psk, psk, psk_len);
+
+       if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS) {
+               struct psk_list_entry *last;
+               last = dl_list_last(&persistent->psk_list,
+                                   struct psk_list_entry, list);
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for "
+                       MACSTR " (p2p=%u) to make room for a new one",
+                       MAC2STR(last->addr), last->p2p);
+               dl_list_del(&last->list);
+               os_free(last);
+       }
+
+       dl_list_add(&persistent->psk_list, &p->list);
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+       if (wpa_s->parent->conf->update_config &&
+           wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+               wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
index e7ddb85..f72d563 100644 (file)
@@ -152,6 +152,9 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                           struct hostapd_hw_modes *mode, u8 channel);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
+void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
+                        const u8 *p2p_dev_addr,
+                        const u8 *psk, size_t psk_len);
 
 #ifdef CONFIG_P2P
 void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
index 7bfbc0e..c274f3c 100644 (file)
@@ -3480,6 +3480,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.override_ctrl_interface);
 
        os_free(global->p2p_disallow_freq);
+       os_free(global->add_psk);
 
        os_free(global);
        wpa_debug_close_syslog();
index f808f49..ac22c31 100644 (file)
@@ -272,6 +272,8 @@ struct wpa_global {
 #define MAX_WFD_SUBELEMS 10
        struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
 #endif /* CONFIG_WIFI_DISPLAY */
+
+       struct psk_list_entry *add_psk; /* From group formation */
 };