diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index b37d9f729..06cc349b8 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -2867,7 +2867,8 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr, if (!drv->p2p) return -1; return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent, - own_interface_addr, force_freq, persistent_group); + own_interface_addr, force_freq, persistent_group, + NULL, 0); } diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 474dd73ce..2f5a0a0fe 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1172,7 +1172,8 @@ static void p2p_set_dev_persistent(struct p2p_device *dev, 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, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + const u8 *force_ssid, size_t force_ssid_len) { struct p2p_device *dev; @@ -1186,7 +1187,6 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, if (p2p_prepare_channel(p2p, force_freq) < 0) return -1; - p2p->ssid_set = 0; dev = p2p_get_device(p2p, peer_addr); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, @@ -1219,6 +1219,15 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, */ } + p2p->ssid_set = 0; + if (force_ssid) { + wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID", + force_ssid, force_ssid_len); + os_memcpy(p2p->ssid, force_ssid, force_ssid_len); + p2p->ssid_len = force_ssid_len; + p2p->ssid_set = 1; + } + dev->flags &= ~P2P_DEV_NOT_YET_READY; dev->flags &= ~P2P_DEV_USER_REJECTED; dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; @@ -1270,7 +1279,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + const u8 *force_ssid, size_t force_ssid_len) { struct p2p_device *dev; @@ -1292,6 +1302,15 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, return -1; } + p2p->ssid_set = 0; + if (force_ssid) { + wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID", + force_ssid, force_ssid_len); + os_memcpy(p2p->ssid, force_ssid, force_ssid_len); + p2p->ssid_len = force_ssid_len; + p2p->ssid_set = 1; + } + dev->flags &= ~P2P_DEV_NOT_YET_READY; dev->flags &= ~P2P_DEV_USER_REJECTED; dev->go_neg_req_sent = 0; diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index a4d425690..44162f686 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -877,12 +877,16 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout); * @persistent_group: Whether to create a persistent group (0 = no, 1 = * persistent group without persistent reconnect, 2 = persistent group with * persistent reconnect) + * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate + * a new SSID + * @force_ssid_len: Length of $force_ssid buffer * Returns: 0 on success, -1 on failure */ 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, - unsigned int force_freq, int persistent_group); + unsigned int force_freq, int persistent_group, + const u8 *force_ssid, size_t force_ssid_len); /** * p2p_authorize - Authorize P2P group formation (GO negotiation) @@ -895,6 +899,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, * @persistent_group: Whether to create a persistent group (0 = no, 1 = * persistent group without persistent reconnect, 2 = persistent group with * persistent reconnect) + * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate + * a new SSID + * @force_ssid_len: Length of $force_ssid buffer * Returns: 0 on success, -1 on failure * * This is like p2p_connect(), but the actual group negotiation is not @@ -903,7 +910,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group); + unsigned int force_freq, int persistent_group, + const u8 *force_ssid, size_t force_ssid_len); /** * p2p_reject - Reject peer device (explicitly block connection attempts) diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index cd28aaec4..090b3a9f1 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -118,7 +118,8 @@ out whether the peer device is operating as a GO and if so, use join-a-group style PD instead of GO Negotiation style PD. p2p_connect [display|keypad] - [persistent] [join|auth] [go_intent=<0..15>] [freq=] + [persistent|persistent=] [join|auth] + [go_intent=<0..15>] [freq=] Start P2P group formation with a discovered P2P peer. This includes optional group owner negotiation, group interface setup, provisioning, @@ -131,7 +132,12 @@ the command return code), PIN# means that a pre-selected PIN can be used (e.g., 12345670). [display|keypad] is used with PIN method to specify which PIN is used (display=dynamically generated random PIN from local display, keypad=PIN entered from peer display). "persistent" -parameter can be used to request a persistent group to be formed. +parameter can be used to request a persistent group to be formed. The +"persistent=" alternative can be used to pre-populate +SSID/passphrase configuration based on a previously used persistent +group where this device was the GO. The previously used parameters will +then be used if the local end becomes the GO in GO Negotiation (which +can be forced with go_intent=15). "join" indicates that this is a command to join an existing group as a client. It skips the GO Negotiation part. This will send a Provision diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index e51846bfe..6745be6c5 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2855,14 +2855,15 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, enum p2p_wps_method wps_method; int new_pin; int ret; - int persistent_group; + int persistent_group, persistent_id = -1; int join; int auth; int automatic; int go_intent = -1; int freq = 0; - /* <"pbc" | "pin" | PIN> [label|display|keypad] [persistent] + /* <"pbc" | "pin" | PIN> [label|display|keypad] + * [persistent|persistent=] * [join] [auth] [go_intent=<0..15>] [freq=] */ if (hwaddr_aton(cmd, addr)) @@ -2874,6 +2875,19 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, pos++; persistent_group = os_strstr(pos, " persistent") != NULL; + pos2 = os_strstr(pos, " persistent="); + if (pos2) { + struct wpa_ssid *ssid; + persistent_id = atoi(pos2 + 12); + ssid = wpa_config_get_network(wpa_s->conf, persistent_id); + if (ssid == NULL || ssid->disabled != 2 || + ssid->mode != WPAS_MODE_P2P_GO) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " + "SSID id=%d for persistent P2P group (GO)", + persistent_id); + return -1; + } + } join = os_strstr(pos, " join") != NULL; auth = os_strstr(pos, " auth") != NULL; automatic = os_strstr(pos, " auto") != NULL; @@ -2912,7 +2926,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, - auth, go_intent, freq); + auth, go_intent, freq, persistent_id); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index badec75b2..89ad4840f 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -509,7 +509,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, - go_intent, freq); + go_intent, freq, -1); if (new_pin >= 0) { char npin[9]; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 3ff2e179f..65c399a50 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -987,6 +987,20 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS); wpas_notify_p2p_go_neg_completed(wpa_s, res); + if (res->role_go && wpa_s->p2p_persistent_id >= 0) { + struct wpa_ssid *ssid; + ssid = wpa_config_get_network(wpa_s->conf, + wpa_s->p2p_persistent_id); + if (ssid && ssid->disabled == 2 && + ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) { + size_t len = os_strlen(ssid->passphrase); + wpa_printf(MSG_DEBUG, "P2P: Override passphrase based " + "on requested persistent group"); + os_memcpy(res->passphrase, ssid->passphrase, len); + res->passphrase[len] = '\0'; + } + } + if (wpa_s->create_p2p_iface) { struct wpa_supplicant *group_wpa_s = wpas_p2p_init_group_interface(wpa_s, res->role_go); @@ -2559,7 +2573,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + struct wpa_ssid *ssid) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -2572,7 +2587,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, - persistent_group); + persistent_group, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0); } @@ -2580,7 +2596,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group) + unsigned int force_freq, int persistent_group, + struct wpa_ssid *ssid) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -2590,7 +2607,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, - persistent_group); + persistent_group, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0); } @@ -2745,7 +2763,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, wpa_s->p2p_go_intent, - wpa_s->p2p_connect_freq); + wpa_s->p2p_connect_freq, + wpa_s->p2p_persistent_id); return; } @@ -3012,6 +3031,8 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) * initiating Group Owner negotiation * @go_intent: GO Intent or -1 to use default * @freq: Frequency for the group or 0 for auto-selection + * @persistent_id: Persistent group credentials to use for forcing GO + * parameters or -1 to generate new values (SSID/passphrase) * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported @@ -3019,17 +3040,25 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int auto_join, int join, int auth, - int go_intent, int freq) + int go_intent, int freq, int persistent_id) { int force_freq = 0, oper_freq = 0; u8 bssid[ETH_ALEN]; int ret = 0; enum wpa_driver_if_type iftype; const u8 *if_addr; + struct wpa_ssid *ssid = NULL; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + if (persistent_id >= 0) { + ssid = wpa_config_get_network(wpa_s->conf, persistent_id); + if (ssid == NULL || ssid->disabled != 2 || + ssid->mode != WPAS_MODE_P2P_GO) + return -1; + } + if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; @@ -3038,6 +3067,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_wps_method = wps_method; wpa_s->p2p_persistent_group = !!persistent_group; + wpa_s->p2p_persistent_id = persistent_id; wpa_s->p2p_go_intent = go_intent; wpa_s->p2p_connect_freq = freq; @@ -3149,14 +3179,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (auth) { if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, - force_freq, persistent_group) < 0) + force_freq, persistent_group, ssid) < + 0) return -1; return ret; } if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, - persistent_group) < 0) { + persistent_group, ssid) < 0) { if (wpa_s->create_p2p_iface) wpas_p2p_remove_pending_group_interface(wpa_s); return -1; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 42c849b07..9779aaac0 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -20,7 +20,7 @@ void wpas_p2p_deinit_global(struct wpa_global *global); int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int auto_join, int join, - int auth, int go_intent, int freq); + int auth, int go_intent, int freq, int persistent_id); void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration); void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 354c5ccf0..1f8e79d02 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -515,6 +515,7 @@ struct wpa_supplicant { unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; + int p2p_persistent_id; int p2p_go_intent; int p2p_connect_freq; struct os_time p2p_auto_started;