WPS 2.0: Provide (Re)Association Response WPS IE to driver
[libeap.git] / wpa_supplicant / p2p_supplicant.c
index 60a3c66..da90c28 100644 (file)
@@ -22,6 +22,7 @@
 #include "wps/wps_i.h"
 #include "p2p/p2p.h"
 #include "ap/hostapd.h"
+#include "ap/p2p_hostapd.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "ap.h"
@@ -44,6 +45,7 @@ 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);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -200,6 +202,12 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                gtype = "client";
        } else
                gtype = "GO";
+       if (wpa_s->cross_connect_in_use) {
+               wpa_s->cross_connect_in_use = 0;
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                       wpa_s->ifname, wpa_s->cross_connect_uplink);
+       }
        wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s",
                wpa_s->ifname, gtype);
        if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -437,17 +445,21 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                char psk[65];
                wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" psk=%s go_dev_addr=" MACSTR "%s",
-                       wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+                       "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
+                       "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+                       MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
+               wpas_p2p_cross_connect_setup(wpa_s);
        } else {
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
-                       wpa_s->ifname, ssid_txt,
+                       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency,
                        ssid && ssid->passphrase ? ssid->passphrase : "",
                        MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
+               wpas_p2p_cross_connect_setup(wpa_s);
        }
 
        if (persistent)
@@ -465,6 +477,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
 
        without_roc = wpa_s->pending_action_without_roc;
        wpa_s->pending_action_without_roc = 0;
+       wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
+                  "pending_action_tx=%p)",
+                  without_roc, wpa_s->pending_action_tx);
 
        if (wpa_s->pending_action_tx == NULL)
                return;
@@ -599,8 +614,9 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        struct wpa_supplicant *wpa_s = ctx;
 
        wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
-                  " src=" MACSTR " bssid=" MACSTR,
-                  freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
+                  " src=" MACSTR " bssid=" MACSTR " len=%d",
+                  freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+                  (int) len);
 
        if (wpa_s->pending_action_tx) {
                wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
@@ -608,8 +624,11 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
                wpabuf_free(wpa_s->pending_action_tx);
        }
        wpa_s->pending_action_tx = wpabuf_alloc(len);
-       if (wpa_s->pending_action_tx == NULL)
+       if (wpa_s->pending_action_tx == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
+                          "TX buffer (len=%llu)", (unsigned long long) len);
                return -1;
+       }
        wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
        os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
        os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
@@ -617,7 +636,8 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        wpa_s->pending_action_freq = freq;
 
        if (wpa_s->off_channel_freq == freq || freq == 0) {
-               /* Already on requested channel; send immediately */
+               wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
+                          "send Action frame immediately");
                /* TODO: Would there ever be need to extend the current
                 * duration on the channel? */
                wpa_s->pending_action_without_roc = 1;
@@ -680,6 +700,8 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
                                    struct p2p_go_neg_results *res)
 {
+       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
+                         res->ssid, res->ssid_len);
        wpa_supplicant_ap_deinit(wpa_s);
        wpas_copy_go_neg_results(wpa_s, res);
        if (res->wps_method == WPS_PBC)
@@ -705,10 +727,11 @@ static void p2p_go_configured(void *ctx, void *data)
        if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
                wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
+                       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
                        wpa_s->ifname,
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                       ssid->frequency,
                        params->passphrase ? params->passphrase : "",
                        MAC2STR(wpa_s->parent->own_addr),
                        params->persistent_group ? " [PERSISTENT]" : "");
@@ -716,6 +739,7 @@ static void p2p_go_configured(void *ctx, void *data)
                        wpas_p2p_store_persistent_group(
                                wpa_s->parent, ssid,
                                wpa_s->parent->own_addr);
+               wpas_p2p_cross_connect_setup(wpa_s);
                return;
        }
 
@@ -961,17 +985,17 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
-       /* TODO: add peer Config Timeout */
-       eloop_register_timeout(15, 0, wpas_p2p_group_formation_timeout, wpa_s,
-                              NULL);
+       eloop_register_timeout(15 + res->peer_config_timeout / 100,
+                              (res->peer_config_timeout % 100) * 10000,
+                              wpas_p2p_group_formation_timeout, wpa_s, NULL);
 }
 
 
-void wpas_go_neg_req_rx(void *ctx, const u8 *src)
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR,
-               MAC2STR(src));
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+               " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
 }
 
 
@@ -997,7 +1021,7 @@ static int wpas_start_listen(void *ctx, unsigned int freq,
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie);
+       wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
 
        if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
                wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
@@ -1690,6 +1714,15 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
        else if (config_methods & WPS_CONFIG_PUSHBUTTON)
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
                        MAC2STR(peer));
+
+       if (wpa_s->pending_pd_before_join &&
+           (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+            os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+               wpa_s->pending_pd_before_join = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation");
+               wpas_p2p_join_start(wpa_s);
+       }
 }
 
 
@@ -1802,7 +1835,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                if (s) {
                        wpas_p2p_group_add_persistent(
                                wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
-               } else {
+               } else if (bssid) {
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
                                      wpa_s->p2p_wps_method);
                }
@@ -1916,16 +1949,24 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 
                /* Operating class 81 - 2.4 GHz band channels 1..13 */
                p2p->channels.reg_class[cla].reg_class = 81;
+#if 0
                p2p->channels.reg_class[cla].channels = 13;
                for (i = 0; i < 13; i++)
                        p2p->channels.reg_class[cla].channel[i] = i + 1;
+#else
+               p2p->channels.reg_class[cla].channels = 11;
+               for (i = 0; i < 11; i++)
+                       p2p->channels.reg_class[cla].channel[i] = i + 1;
+#endif
                cla++;
 
+#if 0
                /* Operating class 82 - 2.4 GHz band channel 14 */
                p2p->channels.reg_class[cla].reg_class = 82;
                p2p->channels.reg_class[cla].channels = 1;
                p2p->channels.reg_class[cla].channel[0] = 14;
                cla++;
+#endif
 
 #if 0
                /* Operating class 83 - 2.4 GHz band channels 1..9; 40 MHz */
@@ -2149,7 +2190,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        p2p.concurrent_operations = !!(wpa_s->drv_flags &
                                       WPA_DRIVER_FLAGS_P2P_CONCURRENT);
 
-       p2p.max_peers = 100;
+       p2p.max_peers = wpa_s->max_stations ? wpa_s->max_stations : 100;
 
        if (wpa_s->conf->p2p_ssid_postfix) {
                p2p.ssid_postfix_len =
@@ -2160,6 +2201,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                          p2p.ssid_postfix_len);
        }
 
+       p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+
        global->p2p = p2p_init(&p2p);
        if (global->p2p == NULL)
                return -1;
@@ -2232,6 +2275,15 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
                os_free(ifname);
        }
 
+       /*
+        * Deinit GO data on any possibly remaining interface (if main
+        * interface is used as GO).
+        */
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s->ap_iface)
+                       wpas_p2p_group_deinit(wpa_s);
+       }
+
        p2p_deinit(global->p2p);
        global->p2p = NULL;
 }
@@ -2280,6 +2332,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                   struct wpa_scan_results *scan_res)
 {
        struct wpa_bss *bss;
+       int freq;
 
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
@@ -2292,14 +2345,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);
 
+       freq = p2p_get_oper_freq(wpa_s->global->p2p,
+                                wpa_s->pending_join_iface_addr);
+       if (freq >= 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from P2P peer table: %d MHz", freq);
+       }
        bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
        if (bss) {
+               freq = bss->freq;
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from BSS table: %d MHz", freq);
+       }
+       if (freq > 0) {
                u16 method;
 
                wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
                           "prior to joining an existing group (GO " MACSTR
                           " freq=%u MHz)",
-                          MAC2STR(wpa_s->pending_join_dev_addr), bss->freq);
+                          MAC2STR(wpa_s->pending_join_dev_addr), freq);
                wpa_s->pending_pd_before_join = 1;
 
                switch (wpa_s->pending_join_wps_method) {
@@ -2442,6 +2506,15 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        res.wps_method = wpa_s->pending_join_wps_method;
        wpas_start_wps_enrollee(group, &res);
 
+       /*
+        * Allow a longer timeout for join-a-running-group than normal 15
+        * second group formation timeout since the GO may not have authorized
+        * our connection yet.
+        */
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+       eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
+                              wpa_s, NULL);
+
        return 0;
 }
 
@@ -2490,7 +2563,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                wpa_s->p2p_pin[0] = '\0';
 
        if (join) {
-               u8 iface_addr[ETH_ALEN];
+               u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
                if (auth) {
                        wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
                                   "connect a running group from " MACSTR,
@@ -2498,10 +2571,14 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
                        return ret;
                }
+               os_memcpy(dev_addr, peer_addr, ETH_ALEN);
                if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
-                                          iface_addr) < 0)
+                                          iface_addr) < 0) {
                        os_memcpy(iface_addr, peer_addr, ETH_ALEN);
-               if (wpas_p2p_join(wpa_s, iface_addr, peer_addr, wps_method) <
+                       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)
                        return -1;
                return ret;
@@ -2618,6 +2695,9 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
                                          unsigned int freq)
 {
+       wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
+                  "(p2p_long_listen=%d pending_action_tx=%p)",
+                  wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
        wpa_s->off_channel_freq = 0;
        if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
                return; /* P2P module started a new operation */
@@ -2940,9 +3020,22 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
 }
 
 
+static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->pending_action_tx)
+               return;
+
+       wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
+                  "operation request");
+       wpabuf_free(wpa_s->pending_action_tx);
+       wpa_s->pending_action_tx = NULL;
+}
+
+
 int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
                  enum p2p_discovery_type type)
 {
+       wpas_p2p_clear_pending_action_tx(wpa_s);
        wpa_s->p2p_long_listen = 0;
 
        return p2p_find(wpa_s->global->p2p, timeout, type);
@@ -2951,6 +3044,7 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
 
 void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
 {
+       wpas_p2p_clear_pending_action_tx(wpa_s);
        wpa_s->p2p_long_listen = 0;
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
@@ -2971,6 +3065,8 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
 {
        int res;
 
+       wpas_p2p_clear_pending_action_tx(wpa_s);
+
        if (timeout == 0) {
                /*
                 * This is a request for unlimited Listen state. However, at
@@ -3004,6 +3100,8 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                return -1;
        if (wpa_s->global->p2p == NULL)
                return -1;
+       if (bss == NULL)
+               return -1;
 
        p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
        ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
@@ -3176,15 +3274,16 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
                char psk[65];
                wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s client ssid=\"%s\" psk=%s go_dev_addr=" MACSTR
-                       "%s",
-                       wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+                       "%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+                       MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+                       MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
        } else {
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s client ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
-                       wpa_s->ifname, ssid_txt,
+                       "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency,
                        ssid->passphrase ? ssid->passphrase : "",
                        MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
@@ -3244,6 +3343,9 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
        if (p2p == NULL)
                return;
 
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+               return;
+
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
                p2p_set_dev_name(p2p, wpa_s->conf->device_name);
 
@@ -3295,4 +3397,162 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
                                     os_strlen(wpa_s->conf->p2p_ssid_postfix) :
                                     0);
        }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
+               p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+}
+
+
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+                    int duration)
+{
+       if (!wpa_s->ap_iface)
+               return -1;
+       return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
+                                  duration);
+}
+
+
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
+{
+       if (wpa_s->global->p2p_disabled)
+               return -1;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
+       wpa_s->global->cross_connection = enabled;
+       p2p_set_cross_connect(wpa_s->global->p2p, enabled);
+
+       if (!enabled) {
+               struct wpa_supplicant *iface;
+
+               for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+               {
+                       if (iface->cross_connect_enabled == 0)
+                               continue;
+
+                       iface->cross_connect_enabled = 0;
+                       iface->cross_connect_in_use = 0;
+                       wpa_msg(iface->parent, MSG_INFO,
+                               P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                               iface->ifname, iface->cross_connect_uplink);
+               }
+       }
+
+       return 0;
+}
+
+
+static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
+{
+       struct wpa_supplicant *iface;
+
+       if (!uplink->global->cross_connection)
+               return;
+
+       for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+               if (!iface->cross_connect_enabled)
+                       continue;
+               if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+                   0)
+                       continue;
+               if (iface->ap_iface == NULL)
+                       continue;
+               if (iface->cross_connect_in_use)
+                       continue;
+
+               iface->cross_connect_in_use = 1;
+               wpa_msg(iface->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                       iface->ifname, iface->cross_connect_uplink);
+       }
+}
+
+
+static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
+{
+       struct wpa_supplicant *iface;
+
+       for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+               if (!iface->cross_connect_enabled)
+                       continue;
+               if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+                   0)
+                       continue;
+               if (!iface->cross_connect_in_use)
+                       continue;
+
+               wpa_msg(iface->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+                       iface->ifname, iface->cross_connect_uplink);
+               iface->cross_connect_in_use = 0;
+       }
+}
+
+
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->ap_iface || wpa_s->current_ssid == NULL ||
+           wpa_s->current_ssid->mode != WPAS_MODE_INFRA ||
+           wpa_s->cross_connect_disallowed)
+               wpas_p2p_disable_cross_connect(wpa_s);
+       else
+               wpas_p2p_enable_cross_connect(wpa_s);
+}
+
+
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+       wpas_p2p_disable_cross_connect(wpa_s);
+}
+
+
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_supplicant *iface;
+
+       if (!wpa_s->global->cross_connection)
+               return;
+
+       for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+               if (iface == wpa_s)
+                       continue;
+               if (iface->drv_flags &
+                   WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
+                       continue;
+               if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+                       continue;
+
+               wpa_s->cross_connect_enabled = 1;
+               os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname,
+                          sizeof(wpa_s->cross_connect_uplink));
+               wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from "
+                          "%s to %s whenever uplink is available",
+                          wpa_s->ifname, wpa_s->cross_connect_uplink);
+
+               if (iface->ap_iface || iface->current_ssid == NULL ||
+                   iface->current_ssid->mode != WPAS_MODE_INFRA ||
+                   iface->cross_connect_disallowed ||
+                   iface->wpa_state != WPA_COMPLETED)
+                       break;
+
+               wpa_s->cross_connect_in_use = 1;
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+                       wpa_s->ifname, wpa_s->cross_connect_uplink);
+               break;
+       }
+}
+
+
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
+           !wpa_s->p2p_in_provisioning)
+               return 0; /* not P2P client operation */
+
+       wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
+                  "session overlap");
+       wpas_group_formation_completed(wpa_s, 0);
+       return 1;
 }