From acc247b260817aac89121f46f444be8278085726 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 24 Oct 2011 17:29:37 +0300 Subject: [PATCH] P2P: Advertise Persistent Reconnect group capability The persistent_reconnect configuration parameter was used to decide whether to accept invitation to re-establish a persistent group. However, this was not being advertised in the Group Capability bitmap. Add the Persistent Reconnect bit based on this configuration to GO Negotiation frames and Beacon/Probe Response frames from the GO. --- src/p2p/p2p.c | 38 ++++++++++++++++++++++++--------- src/p2p/p2p.h | 14 ++++++++++-- src/p2p/p2p_go_neg.c | 17 ++++++++++++--- src/p2p/p2p_group.c | 5 ++++- src/p2p/p2p_i.h | 1 + wpa_supplicant/p2p_supplicant.c | 12 ++++++++++- 6 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index f7e047ecf..404b2cdc8 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1029,6 +1029,26 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq) } +static void p2p_set_dev_persistent(struct p2p_device *dev, + int persistent_group) +{ + switch (persistent_group) { + case 0: + dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP | + P2P_DEV_PREFER_PERSISTENT_RECONN); + break; + case 1: + dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; + dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN; + break; + case 2: + dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP | + P2P_DEV_PREFER_PERSISTENT_RECONN; + break; + } +} + + int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, @@ -1086,10 +1106,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, dev->connect_reqs = 0; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; - if (persistent_group) - dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; - else - dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; + p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1159,10 +1176,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, dev->flags &= ~P2P_DEV_USER_REJECTED; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; - if (persistent_group) - dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; - else - dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; + p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1273,8 +1287,12 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN); res.wps_method = peer->wps_method; - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) - res.persistent_group = 1; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + res.persistent_group = 2; + else + res.persistent_group = 1; + } if (go) { /* Setup AP mode for WPS provisioning */ diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 31e83d5ff..3d97136f9 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -120,6 +120,9 @@ struct p2p_go_neg_results { /** * persistent_group - Whether the group should be made persistent + * 0 = not persistent + * 1 = persistent group without persistent reconnect + * 2 = persistent group with persistent reconnect */ int persistent_group; @@ -846,7 +849,9 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout); * @go_intent: Local GO intent value (1..15) * @own_interface_addr: Intended interface address to use with the group * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create a persistent group + * @persistent_group: Whether to create a persistent group (0 = no, 1 = + * persistent group without persistent reconnect, 2 = persistent group with + * persistent reconnect) * Returns: 0 on success, -1 on failure */ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, @@ -862,7 +867,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, * @go_intent: Local GO intent value (1..15) * @own_interface_addr: Intended interface address to use with the group * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create a persistent group + * @persistent_group: Whether to create a persistent group (0 = no, 1 = + * persistent group without persistent reconnect, 2 = persistent group with + * persistent reconnect) * Returns: 0 on success, -1 on failure * * This is like p2p_connect(), but the actual group negotiation is not @@ -1164,6 +1171,9 @@ struct p2p_group; struct p2p_group_config { /** * persistent_group - Whether the group is persistent + * 0 = not a persistent group + * 1 = persistent group without persistent reconnect + * 2 = persistent group with persistent reconnect */ int persistent_group; diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index b506a80b9..eb85f51c7 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -152,8 +152,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, len = p2p_buf_add_ie_hdr(buf); group_capab = 0; - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) @@ -242,8 +245,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p_buf_add_status(buf, status); group_capab = 0; if (peer && peer->go_state == LOCAL_GO) { - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= + P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) @@ -673,8 +680,12 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, p2p_buf_add_status(buf, status); group_capab = 0; if (peer->go_state == LOCAL_GO) { - if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) + group_capab |= + P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index cc2542dcd..e0f0c5604 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -147,8 +147,11 @@ static void p2p_group_add_common_ies(struct p2p_group *group, dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; - if (group->cfg->persistent_group) + if (group->cfg->persistent_group) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; + if (group->cfg->persistent_group == 2) + group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; + } if (group->p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; if (group->group_formation) diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 0e7313686..7ee6e07d5 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -89,6 +89,7 @@ struct p2p_device { #define P2P_DEV_FORCE_FREQ BIT(13) #define P2P_DEV_PD_FOR_JOIN BIT(14) #define P2P_DEV_REPORTED_ONCE BIT(15) +#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16) unsigned int flags; int status; /* enum p2p_status_code */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 58cc8e788..55e84a132 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -756,6 +756,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->p2p_group_idle = s->p2p_group_idle; d->p2p_intra_bss = s->p2p_intra_bss; + d->persistent_reconnect = s->persistent_reconnect; } @@ -2376,6 +2377,9 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group) { + if (persistent_group && wpa_s->conf->persistent_reconnect) + persistent_group = 2; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method, go_intent, own_interface_addr, @@ -2394,6 +2398,9 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group) { + if (persistent_group && wpa_s->conf->persistent_reconnect) + persistent_group = 2; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) return -1; @@ -3210,7 +3217,10 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, if (cfg == NULL) return NULL; - cfg->persistent_group = persistent_group; + if (persistent_group && wpa_s->conf->persistent_reconnect) + cfg->persistent_group = 2; + else if (persistent_group) + cfg->persistent_group = 1; os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN); if (wpa_s->max_stations && wpa_s->max_stations < wpa_s->conf->max_num_sta)