P2P: Support dedicated P2P_DEVICE without separate group interface
authorLior David <qca_liord@qca.qualcomm.com>
Sun, 24 Jan 2016 15:36:49 +0000 (17:36 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 27 Feb 2016 17:37:19 +0000 (19:37 +0200)
Add support for drivers with dedicated P2P_DEVICE interface, but without
group interface concurrency (only a single netdev is used). With such
devices, wpa_supplicant tried to use the p2p_dev interface instead of
the group interface and most P2P operations failed. Extend
wpa_supplicant to use the primary interface instead of a separate group
interface in such cases.

Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wpa_supplicant.c

index cfe5fff..ff52098 100644 (file)
@@ -800,6 +800,8 @@ grp_owner:
                s = wpas_p2p_get_persistent_go(wpa_s);
                if (!s && !go_wpa_s && p2p_no_group_iface) {
                        p2p_set_intended_addr(wpa_s->global->p2p,
+                                             wpa_s->p2p_mgmt ?
+                                             wpa_s->parent->own_addr :
                                              wpa_s->own_addr);
                } else if (!s && !go_wpa_s) {
                        if (wpas_p2p_add_group_interface(wpa_s,
@@ -949,6 +951,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
+       /*
+        * The primary interface was used for P2P group operations, so
+        * need to reset its p2pdev.
+        */
+       wpa_s->p2pdev = wpa_s->parent;
+
        if (!wpa_s->p2p_go_group_formation_completed) {
                wpa_s->global->p2p_group_formation = NULL;
                wpa_s->p2p_in_provisioning = 0;
@@ -1976,6 +1984,23 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
 }
 
 
+static void wpas_p2p_clone_config_dh(struct wpa_supplicant *dst,
+                                    const struct wpa_supplicant *src)
+{
+       struct wpa_config *d;
+       const struct wpa_config *s;
+
+       d = dst->conf;
+       s = src->conf;
+
+       if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
+           !d->wps_nfc_dh_privkey && !d->wps_nfc_dh_pubkey) {
+               d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
+               d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
+       }
+}
+
+
 static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
                                      char *ifname, size_t len)
 {
@@ -2159,6 +2184,7 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s)
 static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       struct wpa_supplicant *group_wpa_s;
 
        if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
@@ -2211,7 +2237,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        }
 
        if (wpa_s->create_p2p_iface) {
-               struct wpa_supplicant *group_wpa_s =
+               group_wpa_s =
                        wpas_p2p_init_group_interface(wpa_s, res->role_go);
                if (group_wpa_s == NULL) {
                        wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -2220,31 +2246,27 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
                        wpas_p2p_group_formation_failed(wpa_s, 1);
                        return;
                }
-               if (group_wpa_s != wpa_s) {
-                       os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
-                                 sizeof(group_wpa_s->p2p_pin));
-                       group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
-               }
                os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
                wpa_s->pending_interface_name[0] = '\0';
-               group_wpa_s->p2p_in_provisioning = 1;
-
-               if (res->role_go) {
-                       wpas_start_wps_go(group_wpa_s, res, 1);
-               } else {
-                       os_get_reltime(&group_wpa_s->scan_min_time);
-                       wpas_start_wps_enrollee(group_wpa_s, res);
-               }
        } else {
-               wpa_s->p2p_in_provisioning = 1;
-               wpa_s->global->p2p_group_formation = wpa_s;
+               group_wpa_s = wpa_s->parent;
+               wpa_s->global->p2p_group_formation = group_wpa_s;
+               if (group_wpa_s != wpa_s)
+                       wpas_p2p_clone_config_dh(group_wpa_s, wpa_s);
+       }
 
-               if (res->role_go) {
-                       wpas_start_wps_go(wpa_s, res, 1);
-               } else {
-                       os_get_reltime(&wpa_s->scan_min_time);
-                       wpas_start_wps_enrollee(ctx, res);
-               }
+       group_wpa_s->p2p_in_provisioning = 1;
+       group_wpa_s->p2pdev = wpa_s;
+       if (group_wpa_s != wpa_s) {
+               os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
+                         sizeof(group_wpa_s->p2p_pin));
+               group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+       }
+       if (res->role_go) {
+               wpas_start_wps_go(group_wpa_s, res, 1);
+       } else {
+               os_get_reltime(&group_wpa_s->scan_min_time);
+               wpas_start_wps_enrollee(group_wpa_s, res);
        }
 
        wpa_s->p2p_long_listen = 0;
@@ -2903,7 +2925,11 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
                                   "invitation");
                        return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
                }
-               os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
+               if (wpa_s->p2p_mgmt)
+                       os_memcpy(group_bssid, wpa_s->parent->own_addr,
+                                 ETH_ALEN);
+               else
+                       os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN);
        } else if (s->mode == WPAS_MODE_P2P_GO) {
                *go = 1;
                if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0)
@@ -3733,6 +3759,7 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
        wpa_s->pending_interface_name[0] = '\0';
        return 0;
 }
@@ -4514,8 +4541,7 @@ static void wpas_p2p_deinit_global(struct wpa_global *global)
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
-       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
-           wpa_s->conf->p2p_no_group_iface)
+       if (wpa_s->conf->p2p_no_group_iface)
                return 0; /* separate interface disabled per configuration */
        if (wpa_s->drv_flags &
            (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
@@ -5397,7 +5423,10 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
                if_addr = wpa_s->pending_interface_addr;
        } else {
-               if_addr = wpa_s->own_addr;
+               if (wpa_s->p2p_mgmt)
+                       if_addr = wpa_s->parent->own_addr;
+               else
+                       if_addr = wpa_s->own_addr;
                os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
        }
 
@@ -5943,9 +5972,20 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
        struct wpa_supplicant *group_wpa_s;
 
        if (!wpas_p2p_create_iface(wpa_s)) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
-                       "operations");
+               if (wpa_s->p2p_mgmt) {
+                       /*
+                        * We may be called on the p2p_dev interface which
+                        * cannot be used for group operations, so always use
+                        * the primary interface.
+                        */
+                       wpa_s->parent->p2pdev = wpa_s;
+                       wpa_s = wpa_s->parent;
+               }
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "P2P: Use primary interface for group operations");
                wpa_s->p2p_first_connection_timeout = 0;
+               if (wpa_s != wpa_s->p2pdev)
+                       wpas_p2p_clone_config_dh(wpa_s, wpa_s->p2pdev);
                return wpa_s;
        }
 
@@ -6745,7 +6785,9 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                                return -1;
                        }
                        bssid = wpa_s->pending_interface_addr;
-               } else
+               } else if (wpa_s->p2p_mgmt)
+                       bssid = wpa_s->parent->own_addr;
+               else
                        bssid = wpa_s->own_addr;
        } else {
                role = P2P_INVITE_ROLE_CLIENT;
@@ -8671,7 +8713,9 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
                }
 
                if_addr = wpa_s->pending_interface_addr;
-       } else
+       } else if (wpa_s->p2p_mgmt)
+               if_addr = wpa_s->parent->own_addr;
+       else
                if_addr = wpa_s->own_addr;
 
        wpa_s->p2p_nfc_tag_enabled = enabled;
index 27c428a..6b9c957 100644 (file)
@@ -4840,6 +4840,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        iface = global->ifaces;
        while (iface) {
+               if (iface->p2pdev == wpa_s)
+                       iface->p2pdev = iface->parent;
                if (iface == wpa_s || iface->parent != wpa_s) {
                        iface = iface->next;
                        continue;