P2P: Add automatic GO Negotiation vs. join-a-group selection
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 13 Apr 2012 13:04:36 +0000 (16:04 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 13 Apr 2012 13:04:36 +0000 (16:04 +0300)
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 <jouni@qca.qualcomm.com>

wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new_handlers_p2p.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index 3ddae95..0dd2d58 100644 (file)
@@ -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;
index 62930c7..ad3cc11 100644 (file)
@@ -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) {
index 9d31fdb..6cef40c 100644 (file)
@@ -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;
        }
index 8f8e635..c15e42a 100644 (file)
@@ -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,
index a494c49..b25116e 100644 (file)
@@ -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;