From b31be3a0fd58b38e669d804aa082b1039408566f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 13 Apr 2012 16:04:36 +0300 Subject: [PATCH] P2P: Add automatic GO Negotiation vs. join-a-group selection p2p_connect command can now be used with an optional "auto" parameter to request wpa_supplicant to determine automatically whether to use join-a-group operation (if the peer is operating as a GO) or group formation. This makes it easier for external programs to handle connection type selection by offloading this to wpa_supplicant. The previously used p2p_connect join commands can be replaced with p2p_connect auto to use this new mechanism. Signed-hostap: Jouni Malinen --- wpa_supplicant/ctrl_iface.c | 6 +- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2 +- wpa_supplicant/p2p_supplicant.c | 81 ++++++++++++++++++--- wpa_supplicant/p2p_supplicant.h | 4 +- wpa_supplicant/wpa_supplicant_i.h | 5 ++ 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 3ddae959c..0dd2d5895 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2858,6 +2858,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, int persistent_group; int join; int auth; + int automatic; int go_intent = -1; int freq = 0; @@ -2875,6 +2876,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, persistent_group = os_strstr(pos, " persistent") != NULL; join = os_strstr(pos, " join") != NULL; auth = os_strstr(pos, " auth") != NULL; + automatic = os_strstr(pos, " auto") != NULL; pos2 = os_strstr(pos, " go_intent="); if (pos2) { @@ -2909,8 +2911,8 @@ 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, join, auth, go_intent, - freq); + persistent_group, automatic, join, + auth, go_intent, freq); 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 62930c7a3..ad3cc1137 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -508,7 +508,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, goto inv_args; new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, - persistent_group, join, authorize_only, + persistent_group, 0, join, authorize_only, go_intent, freq); if (new_pin >= 0) { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 9d31fdbb9..6cef40c13 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -55,7 +55,8 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, - const u8 *dev_addr, enum p2p_wps_method wps_method); + const u8 *dev_addr, enum p2p_wps_method wps_method, + int auto_join); static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s); @@ -1969,7 +1970,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0); } else if (bssid) { wpas_p2p_join(wpa_s, bssid, go_dev_addr, - wpa_s->p2p_wps_method); + wpa_s->p2p_wps_method, 0); } return; } @@ -2647,6 +2648,31 @@ static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq) } +static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, + const u8 *peer_dev_addr) +{ + struct wpa_bss *bss; + int updated; + + bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr); + if (bss == NULL) + return 0; + if (bss->last_update_idx < wpa_s->bss_update_idx) { + wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the " + "last scan"); + return 0; + } + + updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update); + wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " + "%ld.%06ld (%supdated in last scan)", + bss->last_update.sec, bss->last_update.usec, + updated ? "": "not "); + + return updated; +} + + static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { @@ -2659,12 +2685,29 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (wpa_s->global->p2p_disabled) return; - wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join", - scan_res ? (int) scan_res->num : -1); + wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin", + scan_res ? (int) scan_res->num : -1, + wpa_s->p2p_auto_join ? "auto_" : ""); if (scan_res) wpas_p2p_scan_res_handler(wpa_s, scan_res); + 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 " + "running a GO -> use GO Negotiation"); + wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, + 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); + return; + } + + wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO -> try " + "to join the group"); + } + freq = p2p_get_oper_freq(wpa_s->global->p2p, wpa_s->pending_join_iface_addr); if (freq < 0 && @@ -2836,12 +2879,15 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, - const u8 *dev_addr, enum p2p_wps_method wps_method) + const u8 *dev_addr, enum p2p_wps_method wps_method, + int auto_join) { wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface " - MACSTR " dev " MACSTR ")", - MAC2STR(iface_addr), MAC2STR(dev_addr)); + MACSTR " dev " MACSTR ")%s", + MAC2STR(iface_addr), MAC2STR(dev_addr), + auto_join ? " (auto_join)" : ""); + 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); wpa_s->pending_join_wps_method = wps_method; @@ -2912,6 +2958,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) * @peer_addr: Address of the peer P2P Device * @pin: PIN to use during provisioning or %NULL to indicate PBC mode * @persistent_group: Whether to create a persistent group + * @auto_join: Whether to select join vs. GO Negotiation automatically * @join: Whether to join an existing group (as a client) instead of starting * Group Owner negotiation; @peer_addr is BSSID in that case * @auth: Whether to only authorize the connection instead of doing that and @@ -2924,8 +2971,8 @@ 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 join, int auth, int go_intent, - int freq) + int persistent_group, int auto_join, int join, int auth, + int go_intent, int freq) { int force_freq = 0, oper_freq = 0; u8 bssid[ETH_ALEN]; @@ -2943,6 +2990,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_long_listen = 0; wpa_s->p2p_wps_method = wps_method; + wpa_s->p2p_persistent_group = !!persistent_group; + wpa_s->p2p_go_intent = go_intent; + wpa_s->p2p_connect_freq = freq; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -2955,7 +3005,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } else wpa_s->p2p_pin[0] = '\0'; - if (join) { + if (join || auto_join) { u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN]; if (auth) { wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to " @@ -2971,8 +3021,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, p2p_get_dev_addr(wpa_s->global->p2p, peer_addr, dev_addr); } - if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) < - 0) + if (auto_join) { + os_get_time(&wpa_s->p2p_auto_started); + wpa_printf(MSG_DEBUG, "P2P: Auto join started at " + "%ld.%06ld", + wpa_s->p2p_auto_started.sec, + wpa_s->p2p_auto_started.usec); + } + if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method, + auto_join) < 0) return -1; return ret; } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 8f8e635b3..c15e42a0c 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -19,8 +19,8 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s); 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 join, int auth, int go_intent, - int freq); + int persistent_group, int auto_join, int join, + int auth, int go_intent, int freq); 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 a494c49de..b25116e17 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -508,6 +508,11 @@ struct wpa_supplicant { } removal_reason; unsigned int p2p_cb_on_scan_complete:1; + unsigned int p2p_auto_join:1; + unsigned int p2p_persistent_group:1; + int p2p_go_intent; + int p2p_connect_freq; + struct os_time p2p_auto_started; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid;