P2P: Maintain list of per-client PSKs for persistent groups

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>
This commit is contained in:
Jouni Malinen 2013-09-01 13:40:33 +03:00
parent 759fd76b7f
commit 01a57fe420
11 changed files with 277 additions and 2 deletions

View file

@ -204,6 +204,11 @@ struct hostapd_data {
void (*setup_complete_cb)(void *ctx); void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_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 #ifdef CONFIG_P2P
struct p2p_data *p2p; struct p2p_data *p2p;
struct p2p_group *p2p_group; struct p2p_group *p2p_group;

View 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->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN); 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; p->next = ssid->wpa_psk;
ssid->wpa_psk = p; ssid->wpa_psk = p;

View 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) static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
{ {
#ifdef CONFIG_P2P #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 = ap_sta_authorized_cb;
hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s; hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
#ifdef CONFIG_P2P #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 = wpa_s->global->p2p;
hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s, hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
ssid); ssid);

View file

@ -1372,6 +1372,60 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
} }
#endif /* NO_CONFIG_WRITE */ #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 */ #endif /* CONFIG_P2P */
/* Helper macros for network block parser */ /* Helper macros for network block parser */
@ -1539,6 +1593,7 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
{ FUNC(p2p_client_list) }, { FUNC(p2p_client_list) },
{ FUNC(psk_list) },
#endif /* CONFIG_P2P */ #endif /* CONFIG_P2P */
#ifdef CONFIG_HT_OVERRIDES #ifdef CONFIG_HT_OVERRIDES
{ INT_RANGE(disable_ht, 0, 1) }, { 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) void wpa_config_free_ssid(struct wpa_ssid *ssid)
{ {
struct psk_list_entry *psk;
os_free(ssid->ssid); os_free(ssid->ssid);
os_free(ssid->passphrase); os_free(ssid->passphrase);
os_free(ssid->ext_psk); os_free(ssid->ext_psk);
@ -1745,6 +1802,11 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
#ifdef CONFIG_HT_OVERRIDES #ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs); os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */ #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); os_free(ssid);
} }
@ -1908,6 +1970,7 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
if (ssid == NULL) if (ssid == NULL)
return NULL; return NULL;
ssid->id = id; ssid->id = id;
dl_list_init(&ssid->psk_list);
if (last) if (last)
last->next = ssid; last->next = ssid;
else else

View file

@ -158,6 +158,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
ssid = os_zalloc(sizeof(*ssid)); ssid = os_zalloc(sizeof(*ssid));
if (ssid == NULL) if (ssid == NULL)
return NULL; return NULL;
dl_list_init(&ssid->psk_list);
ssid->id = id; ssid->id = id;
wpa_config_set_network_defaults(ssid); 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 #ifdef CONFIG_P2P
static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid) static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
{ {
char *value = wpa_config_get(ssid, "p2p_client_list"); 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); fprintf(f, "\tp2p_client_list=%s\n", value);
os_free(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 */ #endif /* CONFIG_P2P */
@ -696,6 +712,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(id_str); STR(id_str);
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
write_p2p_client_list(f, ssid); write_p2p_client_list(f, ssid);
write_psk_list(f, ssid);
#endif /* CONFIG_P2P */ #endif /* CONFIG_P2P */
INT(dtim_period); INT(dtim_period);
INT(beacon_int); INT(beacon_int);

View file

@ -1,6 +1,6 @@
/* /*
* WPA Supplicant / Network configuration structures * 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. * This software may be distributed under the terms of the BSD license.
* See README for more details. * See README for more details.
@ -10,6 +10,7 @@
#define CONFIG_SSID_H #define CONFIG_SSID_H
#include "common/defs.h" #include "common/defs.h"
#include "utils/list.h"
#include "eap_peer/eap_config.h" #include "eap_peer/eap_config.h"
#define MAX_SSID_LEN 32 #define MAX_SSID_LEN 32
@ -33,6 +34,13 @@
#define DEFAULT_AMPDU_FACTOR -1 /* no change */ #define DEFAULT_AMPDU_FACTOR -1 /* no change */
#define DEFAULT_AMPDU_DENSITY -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 * struct wpa_ssid - Network configuration data
* *
@ -455,6 +463,11 @@ struct wpa_ssid {
#define P2P_MAX_STORED_CLIENTS 100 #define P2P_MAX_STORED_CLIENTS 100
#endif /* P2P_MAX_STORED_CLIENTS */ #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) * p2p_group - Network generated as a P2P group (used internally)
*/ */

View file

@ -302,6 +302,7 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
RegCloseKey(nhk); RegCloseKey(nhk);
return NULL; return NULL;
} }
dl_list_init(&ssid->psk_list);
ssid->id = id; ssid->id = id;
wpa_config_set_network_defaults(ssid); wpa_config_set_network_defaults(ssid);

View file

@ -600,6 +600,11 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
s->ssid_len = ssid->ssid_len; s->ssid_len = ssid->ssid_len;
os_memcpy(s->ssid, ssid->ssid, s->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 #ifndef CONFIG_NO_CONFIG_WRITE
if (changed && wpa_s->conf->update_config && if (changed && wpa_s->conf->update_config &&
@ -775,6 +780,10 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
if (persistent) if (persistent)
network_id = wpas_p2p_store_persistent_group(wpa_s->parent, network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
ssid, go_dev_addr); ssid, go_dev_addr);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
}
if (network_id < 0 && ssid) if (network_id < 0 && ssid)
network_id = ssid->id; network_id = ssid->id;
if (!client) { 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) static void p2p_go_configured(void *ctx, void *data)
{ {
struct wpa_supplicant *wpa_s = ctx; struct wpa_supplicant *wpa_s = ctx;
@ -918,10 +965,12 @@ static void p2p_go_configured(void *ctx, void *data)
" [PERSISTENT]" : ""); " [PERSISTENT]" : "");
} }
if (params->persistent_group) if (params->persistent_group) {
network_id = wpas_p2p_store_persistent_group( network_id = wpas_p2p_store_persistent_group(
wpa_s->parent, ssid, wpa_s->parent, ssid,
wpa_s->global->p2p_dev_addr); wpa_s->global->p2p_dev_addr);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
if (network_id < 0) if (network_id < 0)
network_id = ssid->id; network_id = ssid->id;
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); 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; return -1;
} }
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
if (go_intent < 0) if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent; 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) if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1; 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 */ /* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND"); wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s); wpas_p2p_stop_find_oper(wpa_s);
@ -4515,6 +4570,9 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
return 0; 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 */ /* Make sure we are not running find during connection establishment */
wpas_p2p_stop_find_oper(wpa_s); 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 || (ssid_len != s->ssid_len ||
os_memcmp(ssid, s->ssid, ssid_len) != 0)) os_memcmp(ssid, s->ssid, ssid_len) != 0))
continue; continue;
if (addr == NULL) {
if (s->mode == WPAS_MODE_P2P_GO)
return s;
continue;
}
if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0) if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
return s; /* peer is GO in the persistent group */ return s; /* peer is GO in the persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL) 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)); 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 */
}

View 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, int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel); struct hostapd_hw_modes *mode, u8 channel);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); 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 #ifdef CONFIG_P2P
void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s); void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);

View file

@ -3480,6 +3480,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
os_free(global->params.override_ctrl_interface); os_free(global->params.override_ctrl_interface);
os_free(global->p2p_disallow_freq); os_free(global->p2p_disallow_freq);
os_free(global->add_psk);
os_free(global); os_free(global);
wpa_debug_close_syslog(); wpa_debug_close_syslog();

View file

@ -272,6 +272,8 @@ struct wpa_global {
#define MAX_WFD_SUBELEMS 10 #define MAX_WFD_SUBELEMS 10
struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS]; struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
#endif /* CONFIG_WIFI_DISPLAY */ #endif /* CONFIG_WIFI_DISPLAY */
struct psk_list_entry *add_psk; /* From group formation */
}; };