]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/p2p_supplicant.c
P2P: Update D-Bus network object semantics during group formation
[thirdparty/hostap.git] / wpa_supplicant / p2p_supplicant.c
index f082eeff7a6cf7db450670fd274a1f957b70b2e1..3287df01458495df6fe89727563d48aeddd8ef50 100644 (file)
 #include "p2p_supplicant.h"
 
 
+/*
+ * How many times to try to scan to find the GO before giving up on join
+ * request.
+ */
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+
+
 static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
 static struct wpa_supplicant *
 wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
@@ -55,7 +62,7 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 {
        size_t i;
 
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return;
 
        wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS)",
@@ -74,7 +81,9 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 }
 
 
-static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
+static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+                        unsigned int num_req_dev_types,
+                        const u8 *req_dev_types)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_driver_scan_params params;
@@ -82,6 +91,9 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
        struct wpabuf *wps_ie, *ies;
        int social_channels[] = { 2412, 2437, 2462, 0, 0 };
 
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        os_memset(&params, 0, sizeof(params));
 
        /* P2P Wildcard SSID */
@@ -91,7 +103,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq)
 
        wpa_s->wps->dev.p2p = 1;
        wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+                                       WPS_REQ_ENROLLEE,
+                                       num_req_dev_types, req_dev_types);
        if (wps_ie == NULL)
                return -1;
 
@@ -144,7 +157,7 @@ static void p2p_rx_action_mlme(void *ctx, const u8 *buf, size_t len, int freq)
        const struct ieee80211_mgmt *mgmt;
        size_t hdr_len;
 
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
                return;
        mgmt = (const struct ieee80211_mgmt *) buf;
        hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
@@ -173,6 +186,31 @@ static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
 }
 
 
+static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
+                                                 const u8 *ssid,
+                                                 size_t ssid_len, int *go)
+{
+       struct wpa_ssid *s;
+
+       for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               for (s = wpa_s->conf->ssid; s; s = s->next) {
+                       if (s->disabled != 0 || !s->p2p_group ||
+                           s->ssid_len != ssid_len ||
+                           os_memcmp(ssid, s->ssid, ssid_len) != 0)
+                               continue;
+                       if (s->mode == WPAS_MODE_P2P_GO &&
+                           s != wpa_s->current_ssid)
+                               continue;
+                       if (go)
+                               *go = s->mode == WPAS_MODE_P2P_GO;
+                       return wpa_s;
+               }
+       }
+
+       return NULL;
+}
+
+
 static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
 {
        struct wpa_ssid *ssid;
@@ -229,6 +267,10 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
        }
        wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
                wpa_s->ifname, gtype, reason);
+
+       if (ssid)
+               wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
        if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
                struct wpa_global *global;
                char *ifname;
@@ -253,7 +295,15 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                int id = ssid->id;
                if (ssid == wpa_s->current_ssid)
                        wpa_s->current_ssid = NULL;
-               wpas_notify_network_removed(wpa_s, ssid);
+               /*
+                * Networks objects created during any P2P activities are not
+                * exposed out as they might/will confuse certain non-P2P aware
+                * applications since these network objects won't behave like
+                * regular ones.
+                *
+                * Likewise, we don't send out network removed signals for such
+                * network objects.
+                */
                wpa_config_remove_network(wpa_s->conf, id);
                wpa_supplicant_clear_status(wpa_s);
        } else {
@@ -326,9 +376,9 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
-                                           struct wpa_ssid *ssid,
-                                           const u8 *go_dev_addr)
+static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
+                                          struct wpa_ssid *ssid,
+                                          const u8 *go_dev_addr)
 {
        struct wpa_ssid *s;
        int changed = 0;
@@ -357,7 +407,17 @@ static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
                changed = 1;
                s = wpa_config_add_network(wpa_s->conf);
                if (s == NULL)
-                       return;
+                       return -1;
+
+               /*
+                * Instead of network_added we emit persistent_group_added
+                * notification. Also to keep the defense checks in
+                * persistent_group obj registration method, we set the
+                * relevant flags in s to designate it as a persistent group.
+                */
+               s->p2p_group = 1;
+               s->p2p_persistent_group = 1;
+               wpas_notify_persistent_group_added(wpa_s, s);
                wpa_config_set_network_defaults(s);
        }
 
@@ -371,6 +431,7 @@ static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
        s->key_mgmt = WPA_KEY_MGMT_PSK;
        s->proto = WPA_PROTO_RSN;
        s->pairwise_cipher = WPA_CIPHER_CCMP;
+       s->export_keys = 1;
        if (ssid->passphrase) {
                os_free(s->passphrase);
                s->passphrase = os_strdup(ssid->passphrase);
@@ -396,6 +457,8 @@ static void wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
        }
 #endif /* CONFIG_NO_CONFIG_WRITE */
+
+       return s->id;
 }
 
 
@@ -407,6 +470,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        int client;
        int persistent;
        u8 go_dev_addr[ETH_ALEN];
+       int network_id = -1;
 
        /*
         * This callback is likely called for the main interface. Update wpa_s
@@ -415,6 +479,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
         */
        if (wpa_s->global->p2p_group_formation)
                wpa_s = wpa_s->global->p2p_group_formation;
+       wpa_s->global->p2p_group_formation = NULL;
        wpa_s->p2p_in_provisioning = 0;
 
        if (!success) {
@@ -450,6 +515,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                ssid_txt = "";
                client = wpa_s->p2p_group_interface ==
                        P2P_GROUP_INTERFACE_CLIENT;
+               os_memset(go_dev_addr, 0, ETH_ALEN);
        }
 
        wpa_s->show_group_started = 0;
@@ -484,8 +550,12 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        }
 
        if (persistent)
-               wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
-                                               go_dev_addr);
+               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+                                                            ssid, go_dev_addr);
+       if (network_id < 0)
+               network_id = ssid->id;
+       if (!client)
+               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 }
 
 
@@ -569,9 +639,11 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
                                           "driver to remain on channel (%u "
                                           "MHz) for Action Frame TX",
                                           wpa_s->pending_action_freq);
-                       } else
+                       } else {
+                               wpa_s->off_channel_freq = 0;
                                wpa_s->roc_waiting_drv_freq =
                                        wpa_s->pending_action_freq;
+                       }
                }
                return;
        }
@@ -579,7 +651,7 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
        wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
                   MACSTR " using interface %s",
                   MAC2STR(wpa_s->pending_action_dst), iface->ifname);
-       res = wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+       res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
                                  wpa_s->pending_action_dst,
                                  wpa_s->pending_action_src,
                                  wpa_s->pending_action_bssid,
@@ -605,7 +677,9 @@ void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
                                const u8 *data, size_t data_len,
                                enum p2p_send_action_result result)
 {
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+               return;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return;
 
        if (wpa_s->pending_action_tx == NULL) {
@@ -670,6 +744,20 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
        wpa_s->pending_action_freq = freq;
 
+       if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               struct wpa_supplicant *iface;
+
+               iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+               wpa_s->action_tx_wait_time = wait_time;
+
+               return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+                                       wait_time, wpa_s->pending_action_dst,
+                                       wpa_s->pending_action_src,
+                                       wpa_s->pending_action_bssid,
+                                       wpabuf_head(wpa_s->pending_action_tx),
+                                       wpabuf_len(wpa_s->pending_action_tx));
+       }
+
        if (freq) {
                struct wpa_supplicant *tx_iface;
                tx_iface = wpas_get_tx_interface(wpa_s, src);
@@ -709,6 +797,7 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
                           "Frame TX", freq);
                return -1;
        }
+       wpa_s->off_channel_freq = 0;
        wpa_s->roc_waiting_drv_freq = freq;
 
        return 0;
@@ -721,7 +810,11 @@ static void wpas_send_action_done(void *ctx)
        wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
        wpabuf_free(wpa_s->pending_action_tx);
        wpa_s->pending_action_tx = NULL;
-       if (wpa_s->off_channel_freq) {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               if (wpa_s->action_tx_wait_time)
+                       wpa_drv_send_action_cancel_wait(wpa_s);
+               wpa_s->off_channel_freq = 0;
+       } else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
                wpa_s->off_channel_freq = 0;
                wpa_s->roc_waiting_drv_freq = 0;
@@ -768,10 +861,13 @@ static void p2p_go_configured(void *ctx, void *data)
        struct wpa_supplicant *wpa_s = ctx;
        struct p2p_go_neg_results *params = data;
        struct wpa_ssid *ssid;
+       int network_id = -1;
 
        ssid = wpa_s->current_ssid;
        if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
                wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
+               if (wpa_s->global->p2p_group_formation == wpa_s)
+                       wpa_s->global->p2p_group_formation = NULL;
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
                        "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
                        "go_dev_addr=" MACSTR "%s",
@@ -781,10 +877,14 @@ static void p2p_go_configured(void *ctx, void *data)
                        params->passphrase ? params->passphrase : "",
                        MAC2STR(wpa_s->parent->own_addr),
                        params->persistent_group ? " [PERSISTENT]" : "");
+
                if (params->persistent_group)
-                       wpas_p2p_store_persistent_group(
+                       network_id = wpas_p2p_store_persistent_group(
                                wpa_s->parent, ssid,
                                wpa_s->parent->own_addr);
+               if (network_id < 0)
+                       network_id = ssid->id;
+               wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
                wpas_p2p_cross_connect_setup(wpa_s);
                wpas_p2p_set_group_idle_timeout(wpa_s);
                return;
@@ -798,7 +898,8 @@ static void p2p_go_configured(void *ctx, void *data)
                return;
        }
        if (params->wps_method == WPS_PBC)
-               wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr);
+               wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
+                                         NULL);
        else if (wpa_s->p2p_pin[0])
                wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
                                          wpa_s->p2p_pin, NULL, 0);
@@ -841,7 +942,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        wpa_s->ap_configured_cb = p2p_go_configured;
        wpa_s->ap_configured_cb_ctx = wpa_s;
        wpa_s->ap_configured_cb_data = wpa_s->go_params;
-       wpa_s->connect_without_scan = 1;
+       wpa_s->connect_without_scan = ssid;
        wpa_s->reassociate = 1;
        wpa_s->disconnected = 0;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -863,10 +964,14 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
        C(model_name);
        C(model_number);
        C(serial_number);
-       C(device_type);
        C(config_methods);
 #undef C
 
+       os_memcpy(d->device_type, s->device_type, WPS_DEV_TYPE_LEN);
+       os_memcpy(d->sec_device_type, s->sec_device_type,
+                 sizeof(d->sec_device_type));
+       d->num_sec_device_types = s->num_sec_device_types;
+
        d->p2p_group_idle = s->p2p_group_idle;
        d->p2p_intra_bss = s->p2p_intra_bss;
 }
@@ -889,8 +994,14 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
-       os_snprintf(ifname, sizeof(ifname), "%s-p2p-%d", wpa_s->ifname,
+       os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
                    wpa_s->p2p_group_idx);
+       if (os_strlen(ifname) >= IFNAMSIZ &&
+           os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+               /* Try to avoid going over the IFNAMSIZ length limit */
+               os_snprintf(ifname, sizeof(ifname), "p2p-%d",
+                           wpa_s->p2p_group_idx);
+       }
        force_ifname[0] = '\0';
 
        wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
@@ -899,7 +1010,7 @@ static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
 
        wpa_s->pending_interface_type = type;
        if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname,
-                          wpa_s->pending_interface_addr) < 0) {
+                          wpa_s->pending_interface_addr, NULL) < 0) {
                wpa_printf(MSG_ERROR, "P2P: Failed to create new group "
                           "interface");
                return -1;
@@ -987,6 +1098,8 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
        wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
        if (wpa_s->global->p2p)
                p2p_group_formation_failed(wpa_s->global->p2p);
+       else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               wpa_drv_p2p_group_formation_failed(wpa_s);
        wpas_group_formation_completed(wpa_s, 0);
 }
 
@@ -995,7 +1108,7 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       if (wpa_s->off_channel_freq) {
+       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
                wpa_s->off_channel_freq = 0;
                wpa_s->roc_waiting_drv_freq = 0;
@@ -1004,11 +1117,13 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        if (res->status) {
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
                        res->status);
+               wpas_notify_p2p_go_neg_completed(wpa_s, res->status);
                wpas_p2p_remove_pending_group_interface(wpa_s);
                return;
        }
 
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+       wpas_notify_p2p_go_neg_completed(wpa_s, P2P_SC_SUCCESS);
 
        if (wpa_s->create_p2p_iface) {
                struct wpa_supplicant *group_wpa_s =
@@ -1055,22 +1170,37 @@ 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
                " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+
+       wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
 }
 
 
-void wpas_dev_found(void *ctx, const u8 *addr, const u8 *dev_addr,
-                   const u8 *pri_dev_type, const char *dev_name,
-                   u16 config_methods, u8 dev_capab, u8 group_capab)
+void wpas_dev_found(void *ctx, const u8 *addr,
+                   const struct p2p_peer_info *info,
+                   int new_device)
 {
        struct wpa_supplicant *wpa_s = ctx;
        char devtype[WPS_DEV_TYPE_BUFSIZE];
+
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
                " p2p_dev_addr=" MACSTR
                " pri_dev_type=%s name='%s' config_methods=0x%x "
                "dev_capab=0x%x group_capab=0x%x",
-               MAC2STR(addr), MAC2STR(dev_addr),
-               wps_dev_type_bin2str(pri_dev_type, devtype, sizeof(devtype)),
-               dev_name, config_methods, dev_capab, group_capab);
+               MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+               wps_dev_type_bin2str(info->pri_dev_type, devtype,
+                                    sizeof(devtype)),
+               info->device_name, info->config_methods,
+               info->dev_capab, info->group_capab);
+
+       wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
+}
+
+
+static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpas_notify_p2p_device_lost(wpa_s, dev_addr);
 }
 
 
@@ -1098,6 +1228,7 @@ static int wpas_start_listen(void *ctx, unsigned int freq,
                wpa_s->pending_listen_freq = 0;
                return -1;
        }
+       wpa_s->off_channel_freq = 0;
        wpa_s->roc_waiting_drv_freq = freq;
 
        return 0;
@@ -1112,6 +1243,7 @@ static void wpas_stop_listen(void *ctx)
                wpa_s->off_channel_freq = 0;
                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);
 }
 
@@ -1374,6 +1506,7 @@ static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
                        break;
                wpabuf_put_str(resp, usrv->service);
        }
+       os_free(str);
 
        if (count == 0) {
                wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
@@ -1487,6 +1620,9 @@ void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
        }
 
 done:
+       wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+                                  update_indic, tlvs, tlvs_len);
+
        wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
 
        wpabuf_free(resp);
@@ -1553,12 +1689,18 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
 
                pos = tlv_end;
        }
+
+       wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
 }
 
 
 void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
                           const struct wpabuf *tlvs)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return (void *) wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return NULL;
        return p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
 }
 
@@ -1585,6 +1727,10 @@ void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
 
 int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_sd_cancel_request(wpa_s, (u64) req);
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
        return p2p_sd_cancel_request(wpa_s->global->p2p, req);
 }
 
@@ -1593,6 +1739,13 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
                          const u8 *dst, u8 dialog_token,
                          const struct wpabuf *resp_tlvs)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
+                                       resp_tlvs);
+               return;
+       }
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
        p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
                        resp_tlvs);
 }
@@ -1600,7 +1753,12 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
 
 void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
 {
-       p2p_sd_service_update(wpa_s->global->p2p);
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_service_update(wpa_s);
+               return;
+       }
+       if (wpa_s->global->p2p)
+               p2p_sd_service_update(wpa_s->global->p2p);
 }
 
 
@@ -1715,10 +1873,11 @@ int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
 
 
 static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
-                                        const u8 *peer, const char *params)
+                                        const u8 *peer, const char *params,
+                                        unsigned int generated_pin)
 {
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
-               MAC2STR(peer), wps_generate_pin(), params);
+               MAC2STR(peer), generated_pin, params);
 }
 
 
@@ -1739,6 +1898,7 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
        char devtype[WPS_DEV_TYPE_BUFSIZE];
        char params[200];
        u8 empty_dev_type[8];
+       unsigned int generated_pin = 0;
 
        if (pri_dev_type == NULL) {
                os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
@@ -1753,27 +1913,40 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
                    dev_name, supp_config_methods, dev_capab, group_capab);
        params[sizeof(params) - 1] = '\0';
 
-       if (config_methods & WPS_CONFIG_DISPLAY)
-               wpas_prov_disc_local_display(wpa_s, peer, params);
-       else if (config_methods & WPS_CONFIG_KEYPAD)
+       if (config_methods & WPS_CONFIG_DISPLAY) {
+               generated_pin = wps_generate_pin();
+               wpas_prov_disc_local_display(wpa_s, peer, params,
+                                            generated_pin);
+       } else if (config_methods & WPS_CONFIG_KEYPAD)
                wpas_prov_disc_local_keypad(wpa_s, peer, params);
        else if (config_methods & WPS_CONFIG_PUSHBUTTON)
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
                        "%s", MAC2STR(peer), params);
+
+       wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
+                                           P2P_PROV_DISC_SUCCESS,
+                                           config_methods, generated_pin);
 }
 
 
 void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 {
        struct wpa_supplicant *wpa_s = ctx;
+       unsigned int generated_pin = 0;
+
        if (config_methods & WPS_CONFIG_DISPLAY)
                wpas_prov_disc_local_keypad(wpa_s, peer, "");
-       else if (config_methods & WPS_CONFIG_KEYPAD)
-               wpas_prov_disc_local_display(wpa_s, peer, "");
-       else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+       else if (config_methods & WPS_CONFIG_KEYPAD) {
+               generated_pin = wps_generate_pin();
+               wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
+       } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
                        MAC2STR(peer));
 
+       wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+                                           P2P_PROV_DISC_SUCCESS,
+                                           config_methods, generated_pin);
+
        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)) {
@@ -1785,6 +1958,16 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 }
 
 
+void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+                        enum p2p_prov_disc_status status)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+                                           status, 0, 0);
+}
+
+
 static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
                                  const u8 *go_dev_addr, const u8 *ssid,
                                  size_t ssid_len, int *go, u8 *group_bssid,
@@ -1794,6 +1977,7 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
        struct wpa_ssid *s;
        u8 cur_bssid[ETH_ALEN];
        int res;
+       struct wpa_supplicant *grp;
 
        if (!persistent_group) {
                wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
@@ -1813,6 +1997,15 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
                return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
        }
 
+       grp = wpas_get_p2p_group(wpa_s, ssid, ssid_len, go);
+       if (grp) {
+               wpa_printf(MSG_DEBUG, "P2P: Accept invitation to already "
+                          "running persistent group");
+               if (*go)
+                       os_memcpy(group_bssid, grp->own_addr, ETH_ALEN);
+               goto accept_inv;
+       }
+
        if (!wpa_s->conf->persistent_reconnect)
                return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
 
@@ -1941,6 +2134,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
                        "status=%d ", status);
        }
+       wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
 
        if (wpa_s->pending_invite_ssid_id == -1)
                return; /* Invitation to active group */
@@ -2022,12 +2216,14 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 }
 
 
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan)
+static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
        int i;
 
        for (i = 0; i < mode->num_channels; i++) {
                if (mode->channels[i].chan == chan) {
+                       if (flags)
+                               *flags = mode->channels[i].flag;
                        return !(mode->channels[i].flag &
                                 (HOSTAPD_CHAN_DISABLED |
                                  HOSTAPD_CHAN_PASSIVE_SCAN |
@@ -2046,6 +2242,7 @@ struct p2p_oper_class_map {
        u8 min_chan;
        u8 max_chan;
        u8 inc;
+       enum { BW20, BW40PLUS, BW40MINUS } bw;
 };
 
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
@@ -2055,19 +2252,19 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
        u16 num_modes, flags;
        int cla, op;
        struct p2p_oper_class_map op_class[] = {
-               { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1 },
-               { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1 },
-               { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4 },
-               { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4 },
-#if 0 /* TODO: 40 MHz channels */
-               { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1 },
-               { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1 },
-               { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8 },
-               { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8 },
-               { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8 },
-               { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8 },
+               { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
+               { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
+#if 0 /* Do not enable HT40 on 2 GHz for now */
+               { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
+               { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
 #endif
-               { -1, 0, 0, 0, 0 }
+               { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
+               { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 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 },
+               { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+               { -1, 0, 0, 0, 0, BW20 }
        };
 
        modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
@@ -2089,7 +2286,16 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
                if (mode == NULL)
                        continue;
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
-                       if (!has_channel(mode, ch))
+                       int flag;
+                       if (!has_channel(mode, ch, &flag))
+                               continue;
+                       if (o->bw == BW40MINUS &&
+                           (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
+                            !has_channel(mode, ch - 4, NULL)))
+                               continue;
+                       if (o->bw == BW40PLUS &&
+                           (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
+                            !has_channel(mode, ch + 4, NULL)))
                                continue;
                        if (reg == NULL) {
                                wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2161,6 +2367,25 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        if (global->p2p)
                return 0;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               struct p2p_params params;
+
+               wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
+               os_memset(&params, 0, sizeof(params));
+               params.dev_name = wpa_s->conf->device_name;
+               os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
+                         WPS_DEV_TYPE_LEN);
+               params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+               os_memcpy(params.sec_dev_type,
+                         wpa_s->conf->sec_device_type,
+                         params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+
+               if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
+                       return -1;
+
+               return 0;
+       }
+
        os_memset(&p2p, 0, sizeof(p2p));
        p2p.msg_ctx = wpa_s;
        p2p.cb_ctx = wpa_s;
@@ -2170,6 +2395,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        p2p.go_neg_completed = wpas_go_neg_completed;
        p2p.go_neg_req_rx = wpas_go_neg_req_rx;
        p2p.dev_found = wpas_dev_found;
+       p2p.dev_lost = wpas_dev_lost;
        p2p.start_listen = wpas_start_listen;
        p2p.stop_listen = wpas_stop_listen;
        p2p.send_probe_resp = wpas_send_probe_resp;
@@ -2177,6 +2403,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        p2p.sd_response = wpas_sd_response;
        p2p.prov_disc_req = wpas_prov_disc_req;
        p2p.prov_disc_resp = wpas_prov_disc_resp;
+       p2p.prov_disc_fail = wpas_prov_disc_fail;
        p2p.invitation_process = wpas_invitation_process;
        p2p.invitation_received = wpas_invitation_received;
        p2p.invitation_result = wpas_invitation_result;
@@ -2185,6 +2412,14 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
        os_memcpy(p2p.dev_addr, wpa_s->own_addr, ETH_ALEN);
        p2p.dev_name = wpa_s->conf->device_name;
+       p2p.manufacturer = wpa_s->conf->manufacturer;
+       p2p.model_name = wpa_s->conf->model_name;
+       p2p.model_number = wpa_s->conf->model_number;
+       p2p.serial_number = wpa_s->conf->serial_number;
+       if (wpa_s->wps) {
+               os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
+               p2p.config_methods = wpa_s->wps->config_methods;
+       }
 
        if (wpa_s->conf->p2p_listen_reg_class &&
            wpa_s->conf->p2p_listen_channel) {
@@ -2199,28 +2434,33 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                os_get_random((u8 *) &r, sizeof(r));
                p2p.channel = 1 + (r % 3) * 5;
        }
+       wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
 
        if (wpa_s->conf->p2p_oper_reg_class &&
            wpa_s->conf->p2p_oper_channel) {
                p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;
                p2p.op_channel = wpa_s->conf->p2p_oper_channel;
+               p2p.cfg_op_channel = 1;
+               wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
+
        } else {
                p2p.op_reg_class = 81;
                /*
-                * For initial tests, pick the operation channel randomly.
-                * TODO: Use scan results (etc.) to select the best channel.
+                * Use random operation channel from (1, 6, 11) if no other
+                * preference is indicated.
                 */
                os_get_random((u8 *) &r, sizeof(r));
-               p2p.op_channel = 1 + r % 11;
+               p2p.op_channel = 1 + (r % 3) * 5;
+               p2p.cfg_op_channel = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
        }
-       wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d  "
-                  "Own preferred operation channel: %d",
-                  p2p.channel, p2p.op_channel);
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
                os_memcpy(p2p.country, wpa_s->conf->country, 2);
                p2p.country[2] = 0x04;
        } else
-               os_memcpy(p2p.country, "US\x04", 3);
+               os_memcpy(p2p.country, "XX\x04", 3);
 
        if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
                wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
@@ -2228,26 +2468,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                return -1;
        }
 
-       if (wpa_s->conf->device_type &&
-           wps_dev_type_str2bin(wpa_s->conf->device_type, p2p.pri_dev_type) <
-           0) {
-               wpa_printf(MSG_ERROR, "P2P: Invalid device_type");
-               return -1;
-       }
+       os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
+                 WPS_DEV_TYPE_LEN);
 
-       for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
-               if (wpa_s->conf->sec_device_type[i] == NULL)
-                       continue;
-               if (wps_dev_type_str2bin(
-                           wpa_s->conf->sec_device_type[i],
-                           p2p.sec_dev_type[p2p.num_sec_dev_types]) < 0) {
-                       wpa_printf(MSG_ERROR, "P2P: Invalid sec_device_type");
-                       return -1;
-               }
-               p2p.num_sec_dev_types++;
-               if (p2p.num_sec_dev_types == P2P_SEC_DEVICE_TYPES)
-                       break;
-       }
+       p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+       os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type,
+                 p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN);
 
        p2p.concurrent_operations = !!(wpa_s->drv_flags &
                                       WPA_DRIVER_FLAGS_P2P_CONCURRENT);
@@ -2269,6 +2495,13 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        if (global->p2p == NULL)
                return -1;
 
+       for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+               if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+                       continue;
+               p2p_add_wps_vendor_extension(
+                       global->p2p, wpa_s->conf->wps_vendor_ext[i]);
+       }
+
        return 0;
 }
 
@@ -2354,7 +2587,9 @@ 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_P2P_DEDICATED_INTERFACE)
+       if (wpa_s->drv_flags &
+           (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
+            WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
                return 1; /* P2P group requires a new interface in every case
                           */
        if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT))
@@ -2373,6 +2608,12 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                                 int go_intent, const u8 *own_interface_addr,
                                 unsigned int force_freq, int persistent_group)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
+                                          go_intent, own_interface_addr,
+                                          force_freq, persistent_group);
+       }
+
        return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
                           go_intent, own_interface_addr, force_freq,
                           persistent_group);
@@ -2385,17 +2626,37 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
                                int go_intent, const u8 *own_interface_addr,
                                unsigned int force_freq, int persistent_group)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
        return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
                             go_intent, own_interface_addr, force_freq,
                             persistent_group);
 }
 
 
+static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->p2p_join_scan_count++;
+       wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d",
+                  wpa_s->p2p_join_scan_count);
+       if (wpa_s->p2p_join_scan_count > P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to find GO " MACSTR
+                          " for join operationg - stop join attempt",
+                          MAC2STR(wpa_s->pending_join_iface_addr));
+               eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_GROUP_FORMATION_FAILURE);
+       }
+}
+
+
 static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                   struct wpa_scan_results *scan_res)
 {
        struct wpa_bss *bss;
        int freq;
+       u8 iface_addr[ETH_ALEN];
 
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
@@ -2410,6 +2671,23 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
        freq = p2p_get_oper_freq(wpa_s->global->p2p,
                                 wpa_s->pending_join_iface_addr);
+       if (freq < 0 &&
+           p2p_get_interface_addr(wpa_s->global->p2p,
+                                  wpa_s->pending_join_dev_addr,
+                                  iface_addr) == 0 &&
+           os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
+       {
+               wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
+                          "address for join from " MACSTR " to " MACSTR
+                          " based on newly discovered P2P peer entry",
+                          MAC2STR(wpa_s->pending_join_iface_addr),
+                          MAC2STR(iface_addr));
+               os_memcpy(wpa_s->pending_join_iface_addr, iface_addr,
+                         ETH_ALEN);
+
+               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);
@@ -2462,8 +2740,11 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "P2P: Target BSS/GO not yet in BSS table - "
-                  "cannot send Provision Discovery Request");
+       wpa_printf(MSG_DEBUG, "P2P: Failed to find BSS/GO - try again later");
+       eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+       eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+       wpas_p2p_check_join_scan_limit(wpa_s);
+       return;
 
 start:
        /* Start join operation immediately */
@@ -2487,7 +2768,7 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 
        wpa_s->wps->dev.p2p = 1;
        wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+                                       WPS_REQ_ENROLLEE, 0, NULL);
        if (wps_ie == NULL) {
                wpas_p2p_scan_res_join(wpa_s, NULL);
                return;
@@ -2524,6 +2805,7 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
                           "try again later");
                eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
                eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+               wpas_p2p_check_join_scan_limit(wpa_s);
        }
 }
 
@@ -2542,6 +2824,7 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
        /* Make sure we are not running find during connection establishment */
        wpas_p2p_stop_find(wpa_s);
 
+       wpa_s->p2p_join_scan_count = 0;
        wpas_p2p_join_scan(wpa_s, NULL);
        return 0;
 }
@@ -2608,6 +2891,9 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        int ret = 0;
        enum wpa_driver_if_type iftype;
 
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        if (go_intent < 0)
                go_intent = wpa_s->conf->p2p_go_intent;
 
@@ -2757,6 +3043,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
                                   unsigned int freq, unsigned int duration)
 {
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
        wpa_s->roc_waiting_drv_freq = 0;
        wpa_s->off_channel_freq = freq;
        wpas_send_action_cb(wpa_s, NULL);
@@ -2775,6 +3063,9 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
        if (timeout > wpa_s->max_remain_on_chan)
                timeout = wpa_s->max_remain_on_chan;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_listen(wpa_s, timeout);
+
        return p2p_listen(wpa_s->global->p2p, timeout);
 }
 
@@ -2792,18 +3083,20 @@ 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)",
+                  "(p2p_long_listen=%d ms pending_action_tx=%p)",
                   wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
        wpa_s->off_channel_freq = 0;
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
        if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
                return; /* P2P module started a new operation */
        if (wpa_s->pending_action_tx)
                return;
        if (wpa_s->p2p_long_listen > 0)
-               wpa_s->p2p_long_listen -= 5;
+               wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
        if (wpa_s->p2p_long_listen > 0) {
                wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
-               wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen * 1000);
+               wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
        }
 }
 
@@ -2831,8 +3124,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
                while (wpa_s) {
                        prev = wpa_s;
                        wpa_s = wpa_s->next;
-                       prev->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
-                       wpas_p2p_group_delete(prev);
+                       wpas_p2p_disconnect(prev);
                }
                return 0;
        }
@@ -2842,13 +3134,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
                        break;
        }
 
-       if (wpa_s == NULL)
-               return -1;
-
-       wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
-       wpas_p2p_group_delete(wpa_s);
-
-       return 0;
+       return wpas_p2p_disconnect(wpa_s);
 }
 
 
@@ -2861,16 +3147,48 @@ static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 
        os_memset(params, 0, sizeof(*params));
        params->role_go = 1;
-       params->freq = 2412;
-       if (freq)
+       if (freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
+                          "frequency %d MHz", freq);
                params->freq = freq;
-       else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
-                wpa_s->conf->p2p_oper_channel >= 1 &&
-                wpa_s->conf->p2p_oper_channel <= 11)
+       else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
+                  wpa_s->conf->p2p_oper_channel >= 1 &&
+                  wpa_s->conf->p2p_oper_channel <= 11) {
                params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
-       else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
-                wpa_s->conf->p2p_oper_reg_class == 118)
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
+                  wpa_s->conf->p2p_oper_reg_class == 124) {
                params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_overall_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_overall_freq)) {
+               params->freq = wpa_s->best_overall_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_24_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_24_freq)) {
+               params->freq = wpa_s->best_24_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_5_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_5_freq)) {
+               params->freq = wpa_s->best_5_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
+                          "channel %d MHz", params->freq);
+       } else {
+               params->freq = 2412;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
+                          "known)", params->freq);
+       }
+
        if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
            wpa_s->assoc_freq && !freq) {
                wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
@@ -2923,6 +3241,49 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
                       int freq)
 {
        struct p2p_go_neg_results params;
+       unsigned int r;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       if (freq == 2) {
+               wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+                          "band");
+               if (wpa_s->best_24_freq > 0 &&
+                   p2p_supported_freq(wpa_s->global->p2p,
+                                      wpa_s->best_24_freq)) {
+                       freq = wpa_s->best_24_freq;
+                       wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+                                  "channel: %d MHz", freq);
+               } else {
+                       os_get_random((u8 *) &r, sizeof(r));
+                       freq = 2412 + (r % 3) * 25;
+                       wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+                                  "channel: %d MHz", freq);
+               }
+       }
+
+       if (freq == 5) {
+               wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+                          "band");
+               if (wpa_s->best_5_freq > 0 &&
+                   p2p_supported_freq(wpa_s->global->p2p,
+                                      wpa_s->best_5_freq)) {
+                       freq = wpa_s->best_5_freq;
+                       wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+                                  "channel: %d MHz", freq);
+               } else {
+                       os_get_random((u8 *) &r, sizeof(r));
+                       freq = 5180 + (r % 4) * 20;
+                       if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                               wpa_printf(MSG_DEBUG, "P2P: Could not select "
+                                          "5 GHz channel for P2P group");
+                               return -1;
+                       }
+                       wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+                                  "channel: %d MHz", freq);
+               }
+       }
 
        if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
                wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
@@ -2958,7 +3319,6 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
        ssid = wpa_config_add_network(wpa_s->conf);
        if (ssid == NULL)
                return -1;
-       wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
        ssid->temporary = 1;
        ssid->proto = WPA_PROTO_RSN;
@@ -2967,13 +3327,13 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
        ssid->key_mgmt = WPA_KEY_MGMT_PSK;
        ssid->ssid = os_malloc(params->ssid_len);
        if (ssid->ssid == NULL) {
-               wpas_notify_network_removed(wpa_s, ssid);
                wpa_config_remove_network(wpa_s->conf, ssid->id);
                return -1;
        }
        os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
        ssid->ssid_len = params->ssid_len;
        ssid->p2p_group = 1;
+       ssid->export_keys = 1;
        if (params->psk_set) {
                os_memcpy(ssid->psk, params->psk, 32);
                ssid->psk_set = 1;
@@ -2994,12 +3354,20 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                                  int freq)
 {
        struct p2p_go_neg_results params;
+       int go = 0;
 
        if (ssid->disabled != 2 || ssid->ssid == NULL)
                return -1;
 
-       wpa_s->p2p_long_listen = 0;
-       eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+       if (wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go) &&
+           go == (ssid->mode == WPAS_MODE_P2P_GO)) {
+               wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is "
+                          "already running");
+               return 0;
+       }
+
+       /* Make sure we are not running find during connection establishment */
+       wpas_p2p_stop_find(wpa_s);
 
        if (ssid->mode == WPAS_MODE_INFRA)
                return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
@@ -3072,6 +3440,11 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        struct p2p_group *group;
        struct p2p_group_config *cfg;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return NULL;
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return NULL;
+
        cfg = os_zalloc(sizeof(*cfg));
        if (cfg == NULL)
                return NULL;
@@ -3110,6 +3483,8 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                             NULL);
        if (wpa_s->global->p2p)
                p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
+       else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               wpa_drv_wps_success_cb(wpa_s, peer_addr);
        wpas_group_formation_completed(wpa_s, 1);
 }
 
@@ -3129,7 +3504,12 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        else
                return -1;
 
-       if (wpa_s->global->p2p == NULL)
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
+                                                config_methods);
+       }
+
+       if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
                return -1;
 
        return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
@@ -3157,12 +3537,20 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
 
 
 int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
-                 enum p2p_discovery_type type)
+                 enum p2p_discovery_type type,
+                 unsigned int num_req_dev_types, const u8 *req_dev_types)
 {
        wpas_p2p_clear_pending_action_tx(wpa_s);
        wpa_s->p2p_long_listen = 0;
 
-       return p2p_find(wpa_s->global->p2p, timeout, type);
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_find(wpa_s, timeout, type);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
+       return p2p_find(wpa_s->global->p2p, timeout, type,
+                       num_req_dev_types, req_dev_types);
 }
 
 
@@ -3170,9 +3558,16 @@ 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_long_listen_timeout, wpa_s, NULL);
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
-       p2p_stop_find(wpa_s->global->p2p);
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+               wpa_drv_p2p_stop_find(wpa_s);
+               return;
+       }
+
+       if (wpa_s->global->p2p)
+               p2p_stop_find(wpa_s->global->p2p);
 
        wpas_p2p_remove_pending_group_interface(wpa_s);
 }
@@ -3189,6 +3584,9 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
 {
        int res;
 
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        wpas_p2p_clear_pending_action_tx(wpa_s);
 
        if (timeout == 0) {
@@ -3204,7 +3602,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
 
        res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
        if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
-               wpa_s->p2p_long_listen = timeout;
+               wpa_s->p2p_long_listen = timeout * 1000;
                eloop_register_timeout(timeout, 0,
                                       wpas_p2p_long_listen_timeout,
                                       wpa_s, NULL);
@@ -3284,6 +3682,12 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 {
        wpa_s->p2p_long_listen = 0;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_reject(wpa_s, addr);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        return p2p_reject(wpa_s->global->p2p, addr);
 }
 
@@ -3319,6 +3723,14 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        wpa_s->pending_invite_ssid_id = ssid->id;
 
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+                                         ssid->ssid, ssid->ssid_len,
+                                         go_dev_addr, 1);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
                          ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
 }
@@ -3366,7 +3778,15 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
                    !is_zero_ether_addr(wpa_s->go_dev_addr))
                        go_dev_addr = wpa_s->go_dev_addr;
        }
-       wpa_s->pending_invite_ssid_id = -1;
+       wpa_s->parent->pending_invite_ssid_id = -1;
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+                                         ssid->ssid, ssid->ssid_len,
+                                         go_dev_addr, 0);
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
 
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
                          ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
@@ -3379,6 +3799,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        struct wpa_ssid *ssid = wpa_s->current_ssid;
        const char *ssid_txt;
        u8 go_dev_addr[ETH_ALEN];
+       int network_id = -1;
        int persistent;
 
        if (!wpa_s->show_group_started || !ssid)
@@ -3417,14 +3838,22 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        }
 
        if (persistent)
-               wpas_p2p_store_persistent_group(wpa_s->parent, ssid,
-                                               go_dev_addr);
+               network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+                                                            ssid, go_dev_addr);
+       if (network_id < 0)
+               network_id = ssid->id;
+       wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
 }
 
 
 int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
                          u32 interval1, u32 duration2, u32 interval2)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        if (wpa_s->wpa_state < WPA_ASSOCIATED ||
            wpa_s->current_ssid == NULL ||
            wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
@@ -3439,6 +3868,12 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
 int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
                        unsigned int interval)
 {
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+               return -1;
+
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return -1;
+
        return p2p_ext_listen(wpa_s->global->p2p, period, interval);
 }
 
@@ -3479,7 +3914,9 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
                           u16 reason_code, const u8 *ie, size_t ie_len)
 {
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return;
 
        p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
@@ -3489,7 +3926,9 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
                             u16 reason_code, const u8 *ie, size_t ie_len)
 {
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+               return;
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return;
 
        p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
@@ -3509,37 +3948,37 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
                p2p_set_dev_name(p2p, wpa_s->conf->device_name);
 
-       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) {
-               u8 pri_dev_type[8];
-               if (wpa_s->conf->device_type) {
-                       if (wps_dev_type_str2bin(wpa_s->conf->device_type,
-                                                pri_dev_type) < 0) {
-                               wpa_printf(MSG_ERROR, "P2P: Invalid "
-                                          "device_type");
-                       } else
-                               p2p_set_pri_dev_type(p2p, pri_dev_type);
-               }
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
+               p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type);
+
+       if (wpa_s->wps &&
+           (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS))
+               p2p_set_config_methods(p2p, wpa_s->wps->config_methods);
+
+       if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID))
+               p2p_set_uuid(p2p, wpa_s->wps->uuid);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) {
+               p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer);
+               p2p_set_model_name(p2p, wpa_s->conf->model_name);
+               p2p_set_model_number(p2p, wpa_s->conf->model_number);
+               p2p_set_serial_number(p2p, wpa_s->conf->serial_number);
        }
 
-       if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
-               u8 sec_dev_type[P2P_SEC_DEVICE_TYPES][8];
-               size_t num = 0;
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE)
+               p2p_set_sec_dev_types(p2p,
+                                     (void *) wpa_s->conf->sec_device_type,
+                                     wpa_s->conf->num_sec_device_types);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) {
                int i;
-               for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
-                       if (wpa_s->conf->sec_device_type[i] == NULL)
-                               continue;
-                       if (wps_dev_type_str2bin(
-                                   wpa_s->conf->sec_device_type[i],
-                                   sec_dev_type[num]) < 0) {
-                               wpa_printf(MSG_ERROR, "P2P: Invalid "
-                                          "sec_device_type");
+               p2p_remove_wps_vendor_extensions(p2p);
+               for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+                       if (wpa_s->conf->wps_vendor_ext[i] == NULL)
                                continue;
-                       }
-                       num++;
-                       if (num == P2P_SEC_DEVICE_TYPES)
-                               break;
+                       p2p_add_wps_vendor_extension(
+                               p2p, wpa_s->conf->wps_vendor_ext[i]);
                }
-               p2p_set_sec_dev_types(p2p, (void *) sec_dev_type, num);
        }
 
        if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
@@ -3575,7 +4014,7 @@ int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
 
 int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
 {
-       if (wpa_s->global->p2p_disabled)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return -1;
@@ -3717,6 +4156,15 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
 
        wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
                   "session overlap");
+       if (wpa_s != wpa_s->parent)
+               wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
+
+       if (wpa_s->global->p2p)
+               p2p_group_formation_failed(wpa_s->global->p2p);
+
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                            wpa_s->parent, NULL);
+
        wpas_group_formation_completed(wpa_s, 0);
        return 1;
 }
@@ -3744,6 +4192,10 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
 {
        struct wpa_global *global = wpa_s->global;
        int found = 0;
+       const u8 *peer;
+
+       if (global->p2p == NULL)
+               return -1;
 
        wpa_printf(MSG_DEBUG, "P2P: Request to cancel group formation");
 
@@ -3751,6 +4203,13 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
            !is_zero_ether_addr(wpa_s->pending_interface_addr))
                found = 1;
 
+       peer = p2p_get_go_neg_peer(global->p2p);
+       if (peer) {
+               wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
+                          MACSTR, MAC2STR(peer));
+               p2p_unauthorize(global->p2p, peer);
+       }
+
        wpas_p2p_stop_find(wpa_s);
 
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
@@ -3762,6 +4221,8 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                                   "formation found - cancelling",
                                   wpa_s->ifname);
                        found = 1;
+                       eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                            wpa_s->parent, NULL);
                        wpas_p2p_group_delete(wpa_s);
                        break;
                }
@@ -3786,3 +4247,52 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
        wpas_p2p_group_delete(wpa_s);
 }
+
+
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+                                  int freq_24, int freq_5, int freq_overall)
+{
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+               return;
+       p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
+}
+
+
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
+{
+       u8 peer[ETH_ALEN];
+       struct p2p_data *p2p = wpa_s->global->p2p;
+
+       if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+               return -1;
+
+       if (hwaddr_aton(addr, peer))
+               return -1;
+
+       return p2p_unauthorize(p2p, peer);
+}
+
+
+/**
+ * wpas_p2p_disconnect - Disconnect from a P2P Group
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to disconnect from a group in which the local end is a P2P
+ * Client or to end a P2P Group in case the local end is the Group Owner. If a
+ * virtual network interface was created for this group, that interface will be
+ * removed. Otherwise, only the configured P2P group network will be removed
+ * from the interface.
+ */
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
+{
+
+       if (wpa_s == NULL)
+               return -1;
+
+       wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
+       wpas_p2p_group_delete(wpa_s);
+
+       return 0;
+}