P2PS: Add intended iface address during PD for persistent group
[mech_eap.git] / wpa_supplicant / p2p_supplicant.c
index 7a8a46a..220f2d7 100644 (file)
@@ -126,6 +126,8 @@ static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
 static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
                                        enum wpa_driver_if_type type);
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+                                           int already_deleted);
 
 
 /*
@@ -191,7 +193,11 @@ static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
 {
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return;
-       if (wpa_s->parent->conf->p2p_ignore_shared_freq &&
+
+       /* Use the wpa_s used to control the P2P Device operation */
+       wpa_s = wpa_s->global->p2p_init_wpa_s;
+
+       if (wpa_s->conf->p2p_ignore_shared_freq &&
            freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
            wpas_p2p_num_unused_channels(wpa_s) > 0) {
                wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration",
@@ -600,7 +606,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
         */
        go_wpa_s = wpas_p2p_get_go_group(wpa_s);
        persistent_go = wpas_p2p_get_persistent_go(wpa_s);
-       p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
+       p2p_no_group_iface = !wpas_p2p_create_iface(wpa_s);
 
        wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
                   go_wpa_s, persistent_go);
@@ -1109,13 +1115,14 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
        u8 *n;
        size_t i;
        int found = 0;
+       struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
 
        ssid = wpa_s->current_ssid;
        if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
            !ssid->p2p_persistent_group)
                return;
 
-       for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+       for (s = p2p_wpa_s->conf->ssid; s; s = s->next) {
                if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
                        continue;
 
@@ -1174,8 +1181,8 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
                          0xff, ETH_ALEN);
        }
 
-       if (wpa_s->parent->conf->update_config &&
-           wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+       if (p2p_wpa_s->conf->update_config &&
+           wpa_config_write(p2p_wpa_s->confname, p2p_wpa_s->conf))
                wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
 }
 
@@ -1226,7 +1233,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
 
 
 static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
-                                          int success)
+                                          int success, int already_deleted)
 {
        struct wpa_ssid *ssid;
        int client;
@@ -1251,6 +1258,8 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        if (!success) {
                wpa_msg_global(wpa_s->parent, MSG_INFO,
                               P2P_EVENT_GROUP_FORMATION_FAILURE);
+               if (already_deleted)
+                       return;
                wpas_p2p_group_delete(wpa_s,
                                      P2P_GROUP_REMOVAL_FORMATION_FAILED);
                return;
@@ -1869,6 +1878,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
                d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
                d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
        }
+       d->p2p_cli_probe = s->p2p_cli_probe;
 }
 
 
@@ -2014,17 +2024,18 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
-       wpas_p2p_group_formation_failed(wpa_s);
+       wpas_p2p_group_formation_failed(wpa_s, 0);
 }
 
 
-void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+                                           int already_deleted)
 {
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                             wpa_s->parent, NULL);
        if (wpa_s->global->p2p)
                p2p_group_formation_failed(wpa_s->global->p2p);
-       wpas_group_formation_completed(wpa_s, 0);
+       wpas_group_formation_completed(wpa_s, 0, already_deleted);
 }
 
 
@@ -2105,7 +2116,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
                        wpas_p2p_remove_pending_group_interface(wpa_s);
                        eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
                                             wpa_s, NULL);
-                       wpas_p2p_group_formation_failed(wpa_s);
+                       wpas_p2p_group_formation_failed(wpa_s, 1);
                        return;
                }
                if (group_wpa_s != wpa_s) {
@@ -2141,13 +2152,15 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 }
 
 
-static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id,
+                              u8 go_intent)
 {
        struct wpa_supplicant *wpa_s = ctx;
        wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
-                      " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+                      " dev_passwd_id=%u go_intent=%u", MAC2STR(src),
+                      dev_passwd_id, go_intent);
 
-       wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+       wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id, go_intent);
 }
 
 
@@ -2248,6 +2261,7 @@ static void wpas_find_stopped(void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
        wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+       wpas_notify_p2p_find_stopped(wpa_s);
 }
 
 
@@ -2376,15 +2390,24 @@ static void wpas_stop_listen(void *ctx)
                wpa_s->roc_waiting_drv_freq = 0;
        }
        wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
-       wpa_drv_probe_req_report(wpa_s, 0);
+
+       /*
+        * Don't cancel Probe Request RX reporting for a connected P2P Client
+        * handling Probe Request frames.
+        */
+       if (!wpa_s->p2p_cli_probe)
+               wpa_drv_probe_req_report(wpa_s, 0);
+
        wpas_p2p_listen_work_done(wpa_s);
 }
 
 
-static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
+static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
+                               unsigned int freq)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+       return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
+                                freq);
 }
 
 
@@ -2825,6 +2848,7 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
                                        const u8 *peer, int inv)
 {
        size_t i;
+       struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
 
        if (ssid == NULL)
                return;
@@ -2854,8 +2878,8 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
                   ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
                   (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
        ssid->num_p2p_clients--;
-       if (wpa_s->parent->conf->update_config &&
-           wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+       if (p2p_wpa_s->conf->update_config &&
+           wpa_config_write(p2p_wpa_s->confname, p2p_wpa_s->conf))
                wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
 }
 
@@ -3107,6 +3131,7 @@ static const struct p2p_oper_class_map op_class[] = {
 #endif
        { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
        { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+       { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
        { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
        { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
        { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
@@ -3296,7 +3321,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
                        if (o->mode != HOSTAPD_MODE_IEEE80211A ||
-                           o->bw == BW20 || ch != channel)
+                           (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
+                           ch != channel)
                                continue;
                        ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
                        if (ret == ALLOWED)
@@ -3446,14 +3472,12 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
                iface.confname = wpa_s->confname;
                iface.ctrl_interface = wpa_s->conf->ctrl_interface;
        }
-       iface.conf_p2p_dev = NULL;
 
        p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
        if (!p2pdev_wpa_s) {
                wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
                return -1;
        }
-       wpa_s->p2p_dev = p2pdev_wpa_s;
 
        wpa_s->pending_interface_name[0] = '\0';
        return 0;
@@ -3484,7 +3508,8 @@ static void wpas_presence_resp(void *ctx, const u8 *src, u8 status,
 
 static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
                                     size_t ssid_len, u8 *go_dev_addr,
-                                    u8 *ret_ssid, size_t *ret_ssid_len)
+                                    u8 *ret_ssid, size_t *ret_ssid_len,
+                                    u8 *intended_iface_addr)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_ssid *s;
@@ -3494,6 +3519,19 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
                os_memcpy(ret_ssid, s->ssid, s->ssid_len);
                *ret_ssid_len = s->ssid_len;
                os_memcpy(go_dev_addr, s->bssid, ETH_ALEN);
+
+               if (s->mode != WPAS_MODE_P2P_GO) {
+                       os_memset(intended_iface_addr, 0, ETH_ALEN);
+               } else if (wpas_p2p_create_iface(wpa_s)) {
+                       if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO))
+                               return 0;
+
+                       os_memcpy(intended_iface_addr,
+                                 wpa_s->pending_interface_addr, ETH_ALEN);
+               } else {
+                       os_memcpy(intended_iface_addr, wpa_s->own_addr,
+                                 ETH_ALEN);
+               }
                return 1;
        }
 
@@ -3714,16 +3752,26 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
        }
 
        if (conncap == P2PS_SETUP_GROUP_OWNER) {
-               const char *go_ifname = NULL;
+               /*
+                * We need to copy the interface name. Simply saving a
+                * pointer isn't enough, since if we use pending_interface_name
+                * it will be overwritten when the group is added.
+                */
+               char go_ifname[100];
+
+               go_ifname[0] = '\0';
                if (!go_wpa_s) {
                        wpa_s->global->pending_p2ps_group = 1;
 
-                       if (wpa_s->conf->p2p_no_group_iface)
-                               go_ifname = wpa_s->ifname;
+                       if (!wpas_p2p_create_iface(wpa_s))
+                               os_memcpy(go_ifname, wpa_s->ifname,
+                                         sizeof(go_ifname));
                        else if (wpa_s->pending_interface_name[0])
-                               go_ifname = wpa_s->pending_interface_name;
+                               os_memcpy(go_ifname,
+                                         wpa_s->pending_interface_name,
+                                         sizeof(go_ifname));
 
-                       if (!go_ifname) {
+                       if (!go_ifname[0]) {
                                wpas_p2ps_prov_complete(
                                        wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
                                        dev, adv_mac, ses_mac,
@@ -3753,7 +3801,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
                                        MAC2STR(dev));
                        }
                } else if (passwd_id == DEV_PW_P2PS_DEFAULT) {
-                       go_ifname = go_wpa_s->ifname;
+                       os_memcpy(go_ifname, go_wpa_s->ifname,
+                                 sizeof(go_ifname));
 
                        wpa_dbg(go_wpa_s, MSG_DEBUG,
                                "P2P: Setting PIN-1 For " MACSTR, MAC2STR(dev));
@@ -4402,10 +4451,25 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                               wpa_s->pending_join_iface_addr);
        }
        if (bss) {
+               u8 dev_addr[ETH_ALEN];
+
                freq = bss->freq;
                wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
                           "from BSS table: %d MHz (SSID %s)", freq,
                           wpa_ssid_txt(bss->ssid, bss->ssid_len));
+               if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+                                      dev_addr) == 0 &&
+                   os_memcmp(wpa_s->pending_join_dev_addr,
+                             wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
+                   os_memcmp(dev_addr, wpa_s->pending_join_dev_addr,
+                             ETH_ALEN) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "P2P: Update target GO device address based on BSS entry: " MACSTR " (was " MACSTR ")",
+                                  MAC2STR(dev_addr),
+                                  MAC2STR(wpa_s->pending_join_dev_addr));
+                       os_memcpy(wpa_s->pending_join_dev_addr, dev_addr,
+                                 ETH_ALEN);
+               }
        }
        if (freq > 0) {
                u16 method;
@@ -5218,6 +5282,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                    wpa_s->conf->p2p_oper_reg_class == 116 ||
                    wpa_s->conf->p2p_oper_reg_class == 117 ||
                    wpa_s->conf->p2p_oper_reg_class == 124 ||
+                   wpa_s->conf->p2p_oper_reg_class == 125 ||
                    wpa_s->conf->p2p_oper_reg_class == 126 ||
                    wpa_s->conf->p2p_oper_reg_class == 127) &&
                   freq_included(channels,
@@ -5482,6 +5547,23 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
            go == (ssid->mode == WPAS_MODE_P2P_GO)) {
                wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is "
                           "already running");
+               if (go == 0 &&
+                   eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                        wpa_s->parent, NULL)) {
+                       /*
+                        * This can happen if Invitation Response frame was lost
+                        * and the peer (GO of a persistent group) tries to
+                        * invite us again. Reschedule the timeout to avoid
+                        * terminating the wait for the connection too early
+                        * since we now know that the peer is still trying to
+                        * invite us instead of having already started the GO.
+                        */
+                       wpa_printf(MSG_DEBUG,
+                                  "P2P: Reschedule group formation timeout since peer is still trying to invite us");
+                       eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+                                              wpas_p2p_group_formation_timeout,
+                                              wpa_s->parent, NULL);
+               }
                return 0;
        }
 
@@ -5696,7 +5778,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        if (wpa_s->global->p2p)
                p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
-       wpas_group_formation_completed(wpa_s, 1);
+       wpas_group_formation_completed(wpa_s, 1, 0);
 }
 
 
@@ -5972,7 +6054,8 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
                          const u8 *dst, const u8 *bssid,
-                         const u8 *ie, size_t ie_len, int ssi_signal)
+                         const u8 *ie, size_t ie_len,
+                         unsigned int rx_freq, int ssi_signal)
 {
        if (wpa_s->global->p2p_disabled)
                return 0;
@@ -5980,7 +6063,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
                return 0;
 
        switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
-                                ie, ie_len)) {
+                                ie, ie_len, rx_freq)) {
        case P2P_PREQ_NOT_P2P:
                wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
                                 ssi_signal);
@@ -6712,7 +6795,7 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
                   "session overlap");
        if (wpa_s != wpa_s->parent)
                wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
-       wpas_p2p_group_formation_failed(wpa_s);
+       wpas_p2p_group_formation_failed(wpa_s, 0);
        return 1;
 }
 
@@ -6822,7 +6905,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                                             wpa_s->parent, NULL);
                        if (wpa_s->p2p_in_provisioning) {
-                               wpas_group_formation_completed(wpa_s, 0);
+                               wpas_group_formation_completed(wpa_s, 0, 0);
                                break;
                        }
                        wpas_p2p_group_delete(wpa_s,
@@ -6832,7 +6915,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
                                   wpa_s->ifname);
                        found = 1;
-                       wpas_p2p_group_formation_failed(wpa_s);
+                       wpas_p2p_group_formation_failed(wpa_s, 0);
                }
        }
 
@@ -7028,7 +7111,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
                         */
                        if (wpa_s->global->p2p)
                                p2p_wps_success_cb(wpa_s->global->p2p, addr);
-                       wpas_group_formation_completed(wpa_s, 1);
+                       wpas_group_formation_completed(wpa_s, 1, 0);
                }
        }
        if (!wpa_s->p2p_go_group_formation_completed) {
@@ -7053,7 +7136,7 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
 
        if (wpa_s->global->p2p_group_formation)
                group = wpa_s->global->p2p_group_formation;
-       wpa_s = wpa_s->parent;
+       wpa_s = wpa_s->global->p2p_init_wpa_s;
        offchannel_send_action_done(wpa_s);
        if (group_added)
                ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
@@ -7308,16 +7391,17 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
 {
        struct wpa_ssid *s;
        struct wpa_supplicant *w;
+       struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove client " MACSTR, MAC2STR(peer));
 
        /* Remove from any persistent group */
-       for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+       for (s = p2p_wpa_s->conf->ssid; s; s = s->next) {
                if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
                        continue;
                if (!iface_addr)
-                       wpas_remove_persistent_peer(wpa_s, s, peer, 0);
-               wpas_p2p_remove_psk(wpa_s->parent, s, peer, iface_addr);
+                       wpas_remove_persistent_peer(p2p_wpa_s, s, peer, 0);
+               wpas_p2p_remove_psk(p2p_wpa_s, s, peer, iface_addr);
        }
 
        /* Remove from any operating group */