From 0918c4bf3bd511405a59c7c5bf0d86e1ac7bb74c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 26 Apr 2012 17:13:03 +0300 Subject: [PATCH] P2P: Add p2p_prov_disc auto mechanism wpa_supplicant can now be requested to automatically figure out whether the indicated peer is operating as a GO and if so, use join-a-group style PD instead of pre-GO Negotiation PD. Signed-hostap: Jouni Malinen --- wpa_supplicant/README-P2P | 7 ++- wpa_supplicant/ctrl_iface.c | 11 +++- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 3 +- wpa_supplicant/p2p_supplicant.c | 66 ++++++++++++++++++--- wpa_supplicant/p2p_supplicant.h | 8 ++- wpa_supplicant/wpa_supplicant_i.h | 5 ++ 6 files changed, 86 insertions(+), 14 deletions(-) diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index db6e4aefa..cd28aaec4 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -101,7 +101,7 @@ Flush P2P peer table and state. Group Formation -p2p_prov_disc [join] +p2p_prov_disc [join|auto] Send P2P provision discovery request to the specified peer. The parameters for this command are the P2P device address of the peer and @@ -112,7 +112,10 @@ to enter a PIN that we display. The optional "join" parameter can be used to indicate that this command is requesting an already running GO to prepare for a new client. This is -mainly used with "display" to request it to display a PIN. +mainly used with "display" to request it to display a PIN. The "auto" +parameter can be used to request wpa_supplicant to automatically figure +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=] diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2158d51a0..e51846bfe 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2946,8 +2946,9 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) { u8 addr[ETH_ALEN]; char *pos; + enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG; - /* [join] */ + /* [join|auto] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -2957,8 +2958,12 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) return -1; pos++; - return wpas_p2p_prov_disc(wpa_s, addr, pos, - os_strstr(pos, "join") != NULL); + if (os_strstr(pos, " join") != NULL) + use = WPAS_P2P_PD_FOR_JOIN; + else if (os_strstr(pos, " auto") != NULL) + use = WPAS_P2P_PD_AUTO; + + return wpas_p2p_prov_disc(wpa_s, addr, pos, use); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 45e8a6978..badec75b2 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -692,7 +692,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message, os_strcmp(config_method, "pushbutton")) return wpas_dbus_error_invalid_args(message, NULL); - if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0) + if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, + WPAS_P2P_PD_FOR_GO_NEG) < 0) return wpas_dbus_error_unknown_error(message, "Failed to send provision discovery request"); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e80071154..3ff2e179f 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1821,6 +1821,7 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; + char params[20]; if (wpa_s->pending_pd_before_join && (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || @@ -1832,14 +1833,22 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) return; } + if (wpa_s->pending_pd_use == AUTO_PD_JOIN || + wpa_s->pending_pd_use == AUTO_PD_GO_NEG) + os_snprintf(params, sizeof(params), " peer_go=%d", + wpa_s->pending_pd_use == AUTO_PD_JOIN); + else + params[0] = '\0'; + if (config_methods & WPS_CONFIG_DISPLAY) - wpas_prov_disc_local_keypad(wpa_s, peer, ""); + wpas_prov_disc_local_keypad(wpa_s, peer, params); else if (config_methods & WPS_CONFIG_KEYPAD) { generated_pin = wps_generate_pin(); - wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin); + wpas_prov_disc_local_display(wpa_s, peer, params, + generated_pin); } else if (config_methods & WPS_CONFIG_PUSHBUTTON) - wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR, - MAC2STR(peer)); + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR + "%s", MAC2STR(peer), params); wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */, P2P_PROV_DISC_SUCCESS, @@ -2595,6 +2604,13 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) " for join operationg - stop join attempt", MAC2STR(wpa_s->pending_join_iface_addr)); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); + if (wpa_s->p2p_auto_pd) { + wpa_s->p2p_auto_pd = 0; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE + " p2p_dev_addr=" MACSTR " status=N/A", + MAC2STR(wpa_s->pending_join_dev_addr)); + return; + } wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); } @@ -2702,6 +2718,25 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (scan_res) wpas_p2p_scan_res_handler(wpa_s, scan_res); + if (wpa_s->p2p_auto_pd) { + int join = wpas_p2p_peer_go(wpa_s, + wpa_s->pending_join_dev_addr); + wpa_s->p2p_auto_pd = 0; + wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG; + wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d", + MAC2STR(wpa_s->pending_join_dev_addr), join); + if (p2p_prov_disc_req(wpa_s->global->p2p, + wpa_s->pending_join_dev_addr, + wpa_s->pending_pd_config_methods, join, + 0) < 0) { + wpa_s->p2p_auto_pd = 0; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE + " p2p_dev_addr=" MACSTR " status=N/A", + MAC2STR(wpa_s->pending_join_dev_addr)); + } + return; + } + if (wpa_s->p2p_auto_join) { if (!wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr)) { wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " @@ -2898,6 +2933,7 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, MAC2STR(iface_addr), MAC2STR(dev_addr), auto_join ? " (auto_join)" : ""); + wpa_s->p2p_auto_pd = 0; wpa_s->p2p_auto_join = !!auto_join; os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN); os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN); @@ -3666,10 +3702,12 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, - const char *config_method, int join) + const char *config_method, + enum wpas_p2p_prov_disc_use use) { u16 config_methods; + wpa_s->pending_pd_use = NORMAL_PD; if (os_strncmp(config_method, "display", 7) == 0) config_methods = WPS_CONFIG_DISPLAY; else if (os_strncmp(config_method, "keypad", 6) == 0) @@ -3682,16 +3720,30 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } + if (use == WPAS_P2P_PD_AUTO) { + os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN); + wpa_s->pending_pd_config_methods = config_methods; + wpa_s->p2p_auto_pd = 1; + wpa_s->p2p_auto_join = 0; + wpa_s->pending_pd_before_join = 0; + wpas_p2p_stop_find(wpa_s); + wpa_s->p2p_join_scan_count = 0; + wpas_p2p_join_scan(wpa_s, NULL); + return 0; + } + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr, - config_methods, join); + config_methods, + use == WPAS_P2P_PD_FOR_JOIN); } if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return -1; return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, - config_methods, join, 0); + config_methods, use == WPAS_P2P_PD_FOR_JOIN, + 0); } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index c15e42a0c..42c849b07 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -36,8 +36,14 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, int group_formation); void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int registrar); +enum wpas_p2p_prov_disc_use { + WPAS_P2P_PD_FOR_GO_NEG, + WPAS_P2P_PD_FOR_JOIN, + WPAS_P2P_PD_AUTO +}; int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, - const char *config_method, int join); + const char *config_method, + enum wpas_p2p_prov_disc_use use); void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data, size_t data_len, enum p2p_send_action_result result); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b25116e17..354c5ccf0 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -477,6 +477,10 @@ struct wpa_supplicant { int pending_join_wps_method; int p2p_join_scan_count; int force_long_sd; + u16 pending_pd_config_methods; + enum { + NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN + } pending_pd_use; /* * Whether cross connection is disallowed by the AP to which this @@ -509,6 +513,7 @@ struct wpa_supplicant { unsigned int p2p_cb_on_scan_complete:1; unsigned int p2p_auto_join:1; + unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; int p2p_go_intent; int p2p_connect_freq;