P2P: Fix P2P IE generation for AssocReq when BSS info is not available
[libeap.git] / wpa_supplicant / p2p_supplicant.c
index b257654..93c23e3 100644 (file)
@@ -45,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,
@@ -201,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) {
@@ -441,6 +448,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                        "%s GO ssid=\"%s\" psk=%s go_dev_addr=" MACSTR "%s",
                        wpa_s->ifname, ssid_txt, 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="
@@ -449,6 +457,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                        ssid && ssid->passphrase ? ssid->passphrase : "",
                        MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
+               wpas_p2p_cross_connect_setup(wpa_s);
        }
 
        if (persistent)
@@ -717,6 +726,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;
        }
 
@@ -968,11 +978,11 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 }
 
 
-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);
 }
 
 
@@ -2150,7 +2160,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 =
@@ -2491,7 +2501,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,
@@ -2499,10 +2509,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;
@@ -3005,6 +3019,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,
@@ -3307,3 +3323,135 @@ int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
        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;
+       }
+}