OSDN Git Service

Accumulative patch from commit cc03d0fef3bf5913f8e11b7e998c10bf36a3c07f
[android-x86/external-wpa_supplicant_8.git] / wpa_supplicant / p2p_supplicant.c
index 94a8658..3e02099 100644 (file)
 #endif /* P2P_MAX_INITIAL_CONN_WAIT */
 
 #ifndef P2P_CONCURRENT_SEARCH_DELAY
-#ifdef ANDROID_P2P
-#define P2P_CONCURRENT_SEARCH_DELAY 0
-#else
 #define P2P_CONCURRENT_SEARCH_DELAY 500
-#endif
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
 
 enum p2p_group_removal_reason {
@@ -82,9 +78,7 @@ enum p2p_group_removal_reason {
 #endif
 };
 
-#ifdef ANDROID_P2P
-static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
-#endif
+
 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,
@@ -95,31 +89,14 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
                         const u8 *dev_addr, enum p2p_wps_method wps_method,
                         int auto_join);
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
-                                           void *timeout_ctx);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
                                        int group_added);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 
-#ifdef ANDROID_P2P
-static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s)
-{
-       struct wpa_supplicant *iface = NULL;
-
-       for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
-               if(iface->scanning  || iface->wpa_state == WPA_SCANNING) {
-                       wpa_printf(MSG_DEBUG, "P2P: Scan in progress on %s,"
-                       "defer P2P SEARCH", iface->ifname);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-#endif
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
                                      struct wpa_scan_results *scan_res)
@@ -135,7 +112,7 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
        for (i = 0; i < scan_res->num; i++) {
                struct wpa_scan_res *bss = scan_res->res[i];
                if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
-                                        bss->freq, bss->level,
+                                        bss->freq, bss->age, bss->level,
                                         (const u8 *) (bss + 1),
                                         bss->ie_len) > 0)
                        break;
@@ -166,7 +143,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                        wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
                                   "pending station mode scan to be "
                                   "completed on interface %s", ifs->ifname);
-                       wpa_s->p2p_cb_on_scan_complete = 1;
+                       wpa_s->global->p2p_cb_on_scan_complete = 1;
                        wpa_supplicant_req_scan(ifs, 0, 0);
                        return 1;
                }
@@ -223,10 +200,13 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        wpabuf_free(ies);
 
        if (ret) {
-               if (wpa_s->scanning ||
-                   wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
-                       wpa_s->p2p_cb_on_scan_complete = 1;
-                       ret = 1;
+               for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+                       if (ifs->scanning ||
+                           ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
+                               wpa_s->global->p2p_cb_on_scan_complete = 1;
+                               ret = 1;
+                               break;
+                       }
                }
        } else
                wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
@@ -283,24 +263,21 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
        const char *reason;
 
        ssid = wpa_s->current_ssid;
-#ifdef ANDROID_P2P
-       if ((ssid == NULL) && (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
-#else
        if (ssid == NULL) {
-#endif
                /*
                 * The current SSID was not known, but there may still be a
-                * pending P2P group interface waiting for provisioning.
+                * pending P2P group interface waiting for provisioning or a
+                * P2P group that is trying to reconnect.
                 */
                ssid = wpa_s->conf->ssid;
                while (ssid) {
-                       if (ssid->p2p_group &&
-                           (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
-                            (ssid->key_mgmt & WPA_KEY_MGMT_WPS)))
+                       if (ssid->p2p_group && ssid->disabled != 2)
                                break;
                        ssid = ssid->next;
                }
-               if (ssid == NULL) {
+               if (ssid == NULL &&
+                       wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
+               {
                        wpa_printf(MSG_ERROR, "P2P: P2P group interface "
                                   "not found");
                        return -1;
@@ -399,6 +376,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
                wpa_config_remove_network(wpa_s->conf, id);
                wpa_supplicant_clear_status(wpa_s);
                wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_s->sta_scan_pending = 0;
        } else {
                wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
                           "found");
@@ -698,6 +676,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
 #ifdef ANDROID_P2P
                /* For client Second phase of Group formation (4-way handshake) can be still pending
                 * So we need to restore wpa_s->global->p2p_group_formation */
+               wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
                wpa_s->global->p2p_group_formation = wpa_s;
 #endif
 
@@ -766,19 +745,13 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
        if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
            wpa_s->pending_pd_before_join &&
            (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
-            os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+            os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+           wpa_s->p2p_fallback_to_go_neg) {
                wpa_s->pending_pd_before_join = 0;
-               if (wpa_s->p2p_fallback_to_go_neg) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
-                               "during p2p_connect-auto");
-                       wpas_p2p_fallback_to_go_neg(wpa_s, 0);
-                       return;
-               }
-
-               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
-                          "join-existing-group operation (no ACK for PD "
-                          "Req)");
-               wpas_p2p_join_start(wpa_s);
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+                       "during p2p_connect-auto");
+               wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+               return;
        }
 }
 
@@ -847,15 +820,28 @@ static void p2p_go_configured(void *ctx, void *data)
                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",
-                       wpa_s->ifname,
-                       wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
-                       ssid->frequency,
-                       params->passphrase ? params->passphrase : "",
-                       MAC2STR(wpa_s->global->p2p_dev_addr),
-                       params->persistent_group ? " [PERSISTENT]" : "");
+               if (os_strlen(params->passphrase) > 0) {
+                       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                               "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                               "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+                               wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                               ssid->frequency, params->passphrase,
+                               MAC2STR(wpa_s->global->p2p_dev_addr),
+                               params->persistent_group ? " [PERSISTENT]" :
+                               "");
+               } else {
+                       char psk[65];
+                       wpa_snprintf_hex(psk, sizeof(psk), params->psk,
+                                        sizeof(params->psk));
+                       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+                               "%s GO ssid=\"%s\" freq=%d psk=%s "
+                               "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+                               wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                               ssid->frequency, psk,
+                               MAC2STR(wpa_s->global->p2p_dev_addr),
+                               params->persistent_group ? " [PERSISTENT]" :
+                               "");
+               }
 
                if (params->persistent_group)
                        network_id = wpas_p2p_store_persistent_group(
@@ -881,7 +867,7 @@ static void p2p_go_configured(void *ctx, void *data)
                                          params->peer_device_addr);
        else if (wpa_s->p2p_pin[0])
                wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
-                                         wpa_s->p2p_pin, NULL, 0);
+                                         wpa_s->p2p_pin, NULL, 0, 0);
        os_free(wpa_s->go_params);
        wpa_s->go_params = NULL;
 }
@@ -893,12 +879,18 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
 {
        struct wpa_ssid *ssid;
 
-       if (wpas_copy_go_neg_results(wpa_s, params) < 0)
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO");
+       if (wpas_copy_go_neg_results(wpa_s, params) < 0) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation "
+                       "results");
                return;
+       }
 
        ssid = wpa_config_add_network(wpa_s->conf);
-       if (ssid == NULL)
+       if (ssid == NULL) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
                return;
+       }
 
        wpa_s->show_group_started = 0;
 
@@ -919,7 +911,21 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        ssid->key_mgmt = WPA_KEY_MGMT_PSK;
        ssid->proto = WPA_PROTO_RSN;
        ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-       ssid->passphrase = os_strdup(params->passphrase);
+       if (os_strlen(params->passphrase) > 0) {
+               ssid->passphrase = os_strdup(params->passphrase);
+               if (ssid->passphrase == NULL) {
+                       wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
+                               "passphrase for GO");
+                       wpa_config_remove_network(wpa_s->conf, ssid->id);
+                       return;
+               }
+       } else
+               ssid->passphrase = NULL;
+       ssid->psk_set = params->psk_set;
+       if (ssid->psk_set)
+               os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
+       else if (ssid->passphrase)
+               wpa_config_update_psk(ssid);
        ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
 
        wpa_s->ap_configured_cb = p2p_go_configured;
@@ -928,6 +934,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
        wpa_s->connect_without_scan = ssid;
        wpa_s->reassociate = 1;
        wpa_s->disconnected = 0;
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to "
+               "start GO)");
        wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
@@ -1185,16 +1193,26 @@ void wpas_dev_found(void *ctx, const u8 *addr,
 #ifndef CONFIG_NO_STDOUT_DEBUG
        struct wpa_supplicant *wpa_s = ctx;
        char devtype[WPS_DEV_TYPE_BUFSIZE];
-
+#define WFD_DEV_INFO_SIZE 9
+       char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
+       os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
+#ifdef CONFIG_WIFI_DISPLAY
+       if (info->wfd_subelems) {
+               wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
+                                       wpabuf_head(info->wfd_subelems),
+                                       WFD_DEV_INFO_SIZE);
+       }
+#endif /* CONFIG_WIFI_DISPLAY */
        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",
+               "dev_capab=0x%x group_capab=0x%x%s%s",
                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);
+               info->dev_capab, info->group_capab,
+               wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
        wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
@@ -1263,6 +1281,135 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
 }
 
 
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+                                      u8 **spos, const u8 *end)
+{
+       while (*spos < end) {
+               u8 val = ((*spos)[0] & 0xc0) >> 6;
+               int len;
+
+               if (val == 1 || val == 2) {
+                       /* These are reserved values in RFC 1035 */
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+                                  "sequence starting with 0x%x", val);
+                       return -1;
+               }
+
+               if (val == 3) {
+                       u16 offset;
+                       u8 *spos_tmp;
+
+                       /* Offset */
+                       if (*spos + 2 > end) {
+                               wpa_printf(MSG_DEBUG, "P2P: No room for full "
+                                          "DNS offset field");
+                               return -1;
+                       }
+
+                       offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+                       if (offset >= *spos - start) {
+                               wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+                                          "pointer offset %u", offset);
+                               return -1;
+                       }
+
+                       (*spos) += 2;
+                       spos_tmp = start + offset;
+                       return p2p_sd_dns_uncompress_label(upos, uend, start,
+                                                          &spos_tmp,
+                                                          *spos - 2);
+               }
+
+               /* Label */
+               len = (*spos)[0] & 0x3f;
+               if (len == 0)
+                       return 0;
+
+               (*spos)++;
+               if (*spos + len > end) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+                                  "sequence - no room for label with length "
+                                  "%u", len);
+                       return -1;
+               }
+
+               if (*upos + len + 2 > uend)
+                       return -2;
+
+               os_memcpy(*upos, *spos, len);
+               *spos += len;
+               *upos += len;
+               (*upos)[0] = '.';
+               (*upos)++;
+               (*upos)[0] = '\0';
+       }
+
+       return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+                                size_t msg_len, size_t offset)
+{
+       /* 27-octet in-memory packet from P2P specification */
+       const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+               "\x04_udp\xC0\x11\x00\x0C\x00\x01";
+       u8 *tmp, *end, *spos;
+       char *upos, *uend;
+       int ret = 0;
+
+       if (buf_len < 2)
+               return -1;
+       if (offset > msg_len)
+               return -1;
+
+       tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+       if (tmp == NULL)
+               return -1;
+       spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+       end = spos + msg_len;
+       spos += offset;
+
+       os_memset(tmp, 0, DNS_HEADER_LEN);
+       os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+       os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+       upos = buf;
+       uend = buf + buf_len;
+
+       ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+       if (ret) {
+               os_free(tmp);
+               return ret;
+       }
+
+       if (upos == buf) {
+               upos[0] = '.';
+               upos[1] = '\0';
+       } else if (upos[-1] == '.')
+               upos[-1] = '\0';
+
+       os_free(tmp);
+       return 0;
+}
+
+
 static struct p2p_srv_bonjour *
 wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
                             const struct wpabuf *query)
@@ -1353,13 +1500,40 @@ static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
 }
 
 
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+                              size_t query_len)
+{
+       char str_rx[256], str_srv[256];
+
+       if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+               return 0; /* Too short to include DNS Type and Version */
+       if (os_memcmp(query + query_len - 3,
+                     wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+                     3) != 0)
+               return 0; /* Mismatch in DNS Type or Version */
+       if (query_len == wpabuf_len(bsrv->query) &&
+           os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+               return 1; /* Binary match */
+
+       if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+                                 0))
+               return 0; /* Failed to uncompress query */
+       if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+                                 wpabuf_head(bsrv->query),
+                                 wpabuf_len(bsrv->query) - 3, 0))
+               return 0; /* Failed to uncompress service */
+
+       return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
 static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
                                struct wpabuf *resp, u8 srv_trans_id,
                                const u8 *query, size_t query_len)
 {
        struct p2p_srv_bonjour *bsrv;
-       struct wpabuf buf;
        u8 *len_pos;
+       int matches = 0;
 
        wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
                          query, query_len);
@@ -1375,39 +1549,52 @@ static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       if (wpabuf_tailroom(resp) < 5)
-               return;
-       /* Length (to be filled) */
-       len_pos = wpabuf_put(resp, 2);
-       wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-       wpabuf_put_u8(resp, srv_trans_id);
+       dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+                        struct p2p_srv_bonjour, list) {
+               if (!match_bonjour_query(bsrv, query, query_len))
+                       continue;
+
+               if (wpabuf_tailroom(resp) <
+                   5 + query_len + wpabuf_len(bsrv->resp))
+                       return;
+
+               matches++;
+
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+               wpabuf_put_u8(resp, srv_trans_id);
+
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+                                 wpabuf_head(bsrv->resp),
+                                 wpabuf_len(bsrv->resp));
 
-       wpabuf_set(&buf, query, query_len);
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
-       if (bsrv == NULL) {
+               /* Response Data */
+               wpabuf_put_data(resp, query, query_len); /* Key */
+               wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+               WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+       }
+
+       if (matches == 0) {
                wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
                           "available");
+               if (wpabuf_tailroom(resp) < 5)
+                       return;
+
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+               wpabuf_put_u8(resp, srv_trans_id);
 
                /* Status Code */
                wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
                /* Response Data: empty */
                WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
                             2);
-               return;
        }
-
-       /* Status Code */
-       wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
-                         wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
-       if (wpabuf_tailroom(resp) >=
-           wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
-               /* Response Data */
-               wpabuf_put_buf(resp, bsrv->query); /* Key */
-               wpabuf_put_buf(resp, bsrv->resp); /* Value */
-       }
-       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
 }
 
 
@@ -1968,14 +2155,6 @@ int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
 {
        struct p2p_srv_bonjour *bsrv;
 
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
-       if (bsrv) {
-               wpabuf_free(query);
-               wpabuf_free(bsrv->resp);
-               bsrv->resp = resp;
-               return 0;
-       }
-
        bsrv = os_zalloc(sizeof(*bsrv));
        if (bsrv == NULL)
                return -1;
@@ -2180,6 +2359,15 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
                return;
        }
 
+       if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
+               wpa_s->pending_pd_before_join = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation (no ACK for PD "
+                          "Req attempts)");
+               wpas_p2p_join_start(wpa_s);
+               return;
+       }
+
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
                " p2p_dev_addr=" MACSTR " status=%d",
                MAC2STR(peer), status);
@@ -2306,9 +2494,11 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                           " was accepted; op_freq=%d MHz",
                           MAC2STR(sa), op_freq);
                if (s) {
+                       int go = s->mode == WPAS_MODE_P2P_GO;
                        wpas_p2p_group_add_persistent(
-                               wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
+                               wpa_s, s, go, go ? op_freq : 0, 0);
                } else if (bssid) {
+                       wpa_s->user_initiated_pd = 0;
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
                                      wpa_s->p2p_wps_method, 0);
                }
@@ -2373,8 +2563,28 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
                return;
        }
 
+       /*
+        * The peer could have missed our ctrl::ack frame for Invitation
+        * Response and continue retransmitting the frame. To reduce the
+        * likelihood of the peer not getting successful TX status for the
+        * Invitation Response frame, wait a short time here before starting
+        * the persistent group so that we will remain on the current channel to
+        * acknowledge any possible retransmission from the peer.
+        */
+#ifndef ANDROID_P2P
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
+               "starting persistent group");
+       os_sleep(0, 50000);
+#else
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 100 ms wait on current channel before "
+               "starting persistent group");
+       os_sleep(0, 100000);
+#endif
+
        wpas_p2p_group_add_persistent(wpa_s, ssid,
-                                     ssid->mode == WPAS_MODE_P2P_GO, 0, 0);
+                                     ssid->mode == WPAS_MODE_P2P_GO,
+                                     wpa_s->p2p_persistent_go_freq,
+                                     wpa_s->p2p_go_ht40);
 }
 
 
@@ -2513,7 +2723,6 @@ struct p2p_oper_class_map {
 
 static struct p2p_oper_class_map op_class[] = {
        { 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 },
@@ -2802,11 +3011,17 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 
        p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
 
+       p2p.max_listen = wpa_s->max_remain_on_chan;
+
 #ifdef ANDROID_P2P
-       if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+       if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
                p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
-       else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT)
+               wpa_printf(MSG_DEBUG, "P2P: Multi channel concurrency support");
+       } else {
+       // Add support for WPA_DRIVER_FLAGS_P2P_CONCURRENT
                p2p.p2p_concurrency = P2P_SINGLE_CHANNEL_CONCURRENT;
+               wpa_printf(MSG_DEBUG, "P2P: Single channel concurrency support");
+       }
 #endif
 
        global->p2p = p2p_init(&p2p);
@@ -2847,7 +3062,6 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
        wpa_s->go_params = NULL;
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-       eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
        wpa_s->p2p_long_listen = 0;
        eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
        eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
@@ -2908,6 +3122,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
+       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 |
             WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
@@ -2928,7 +3144,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                                 enum p2p_wps_method wps_method,
                                 int go_intent, const u8 *own_interface_addr,
                                 unsigned int force_freq, int persistent_group,
-                                struct wpa_ssid *ssid)
+                                struct wpa_ssid *ssid, unsigned int pref_freq)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -2950,7 +3166,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                           go_intent, own_interface_addr, force_freq,
                           persistent_group, ssid ? ssid->ssid : NULL,
                           ssid ? ssid->ssid_len : 0,
-                          wpa_s->p2p_pd_before_go_neg);
+                          wpa_s->p2p_pd_before_go_neg, pref_freq);
 }
 
 
@@ -2959,7 +3175,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
                                enum p2p_wps_method wps_method,
                                int go_intent, const u8 *own_interface_addr,
                                unsigned int force_freq, int persistent_group,
-                               struct wpa_ssid *ssid)
+                               struct wpa_ssid *ssid, unsigned int pref_freq)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -2970,7 +3186,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
        return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
                             go_intent, own_interface_addr, force_freq,
                             persistent_group, ssid ? ssid->ssid : NULL,
-                            ssid ? ssid->ssid_len : 0);
+                            ssid ? ssid->ssid_len : 0, pref_freq);
 }
 
 
@@ -2997,21 +3213,6 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_supplicant *wpa_s = eloop_ctx;
-       if (!wpa_s->pending_pd_before_join)
-               return;
-       /*
-        * Provision Discovery Response may have been lost - try to connect
-        * anyway since we do not need any information from this PD.
-        */
-       wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
-                  "try to connect anyway");
-       wpas_p2p_join_start(wpa_s);
-}
-
-
 static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 {
        struct wpa_supplicant *iface;
@@ -3129,7 +3330,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr,
                                      wpa_s->pending_pd_config_methods, join,
-                                     0) < 0) {
+                                     0, wpa_s->user_initiated_pd) < 0) {
                        wpa_s->p2p_auto_pd = 0;
                        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
                                " p2p_dev_addr=" MACSTR " status=N/A",
@@ -3239,25 +3440,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr, method, 1,
-                                     freq) < 0) {
+                                     freq, wpa_s->user_initiated_pd) < 0) {
                        wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
                                   "Discovery Request before joining an "
                                   "existing group");
                        wpa_s->pending_pd_before_join = 0;
                        goto start;
                }
-
-               /*
-                * Actual join operation will be started from the Action frame
-                * TX status callback (if no ACK is received) or when the
-                * Provision Discovery Response is received. Use a short
-                * timeout as a backup mechanism should the Provision Discovery
-                * Response be lost for any reason.
-                */
-               eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
-                                    NULL);
-               eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
-                                      wpa_s, NULL);
                return;
        }
 
@@ -3384,7 +3573,6 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        struct p2p_go_neg_results res;
        struct wpa_bss *bss;
 
-       eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
        group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
        if (group == NULL)
                return -1;
@@ -3392,6 +3580,15 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
                os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
                          sizeof(group->p2p_pin));
                group->p2p_wps_method = wpa_s->p2p_wps_method;
+       } else {
+               /*
+                * Need to mark the current interface for p2p_group_formation
+                * when a separate group interface is not used. This is needed
+                * to allow p2p_cancel stop a pending p2p_connect-join.
+                * wpas_p2p_init_group_interface() addresses this for the case
+                * where a separate group interface is used.
+                */
+               wpa_s->global->p2p_group_formation = wpa_s;
        }
 
        group->p2p_in_provisioning = 1;
@@ -3458,7 +3655,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     int go_intent, int freq, int persistent_id, int pd,
                     int ht40)
 {
-       int force_freq = 0, oper_freq = 0;
+       int force_freq = 0, pref_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
        int ret = 0;
        enum wpa_driver_if_type iftype;
@@ -3524,6 +3721,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                                   wpa_s->p2p_auto_started.sec,
                                   wpa_s->p2p_auto_started.usec);
                }
+               wpa_s->user_initiated_pd = 1;
                if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
                                  auto_join) < 0)
                        return -1;
@@ -3571,6 +3769,13 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                           "(%u MHz) not available for P2P - try to use "
                           "another channel", oper_freq);
                force_freq = 0;
+       } else if (oper_freq > 0 &&
+                  (wpa_s->drv_flags &
+                   WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+                          "are already using (%u MHz) on another interface",
+                          oper_freq);
+               pref_freq = oper_freq;
        } else if (oper_freq > 0) {
                wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
                           "channel we are already using (%u MHz) on another "
@@ -3598,15 +3803,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        if (auth) {
                if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
                                         go_intent, if_addr,
-                                        force_freq, persistent_group, ssid) <
-                   0)
+                                        force_freq, persistent_group, ssid,
+                                        pref_freq) < 0)
                        return -1;
                return ret;
        }
 
        if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
                                  go_intent, if_addr, force_freq,
-                                 persistent_group, ssid) < 0) {
+                                 persistent_group, ssid, pref_freq) < 0) {
                if (wpa_s->create_p2p_iface)
                        wpas_p2p_remove_pending_group_interface(wpa_s);
                return -1;
@@ -3665,12 +3870,12 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 {
        wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
                   "(p2p_long_listen=%d ms pending_action_tx=%p)",
-                  wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+                  wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
        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)
+       if (offchannel_pending_action_tx(wpa_s))
                return;
        if (wpa_s->p2p_long_listen > 0)
                wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
@@ -3812,18 +4017,27 @@ 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))
+       if (!wpas_p2p_create_iface(wpa_s)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
+                       "operations");
                return wpa_s;
+       }
 
        if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
-                                        WPA_IF_P2P_CLIENT) < 0)
+                                        WPA_IF_P2P_CLIENT) < 0) {
+               wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to add group interface");
                return NULL;
+       }
        group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
        if (group_wpa_s == NULL) {
+               wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to initialize group "
+                       "interface");
                wpas_p2p_remove_pending_group_interface(wpa_s);
                return NULL;
        }
 
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
+               group_wpa_s->ifname);
        return group_wpa_s;
 }
 
@@ -3849,7 +4063,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 
        /* Make sure we are not running find during connection establishment */
        wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
-       wpas_p2p_stop_find(wpa_s);
+       wpas_p2p_stop_find_oper(wpa_s);
 
        if (freq == 2) {
                wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
@@ -3980,7 +4194,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
        }
 
        /* Make sure we are not running find during connection establishment */
-       wpas_p2p_stop_find(wpa_s);
+       wpas_p2p_stop_find_oper(wpa_s);
 
        wpa_s->p2p_fallback_to_go_neg = 0;
 
@@ -3994,14 +4208,18 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
 
        params.role_go = 1;
-       if (ssid->passphrase == NULL ||
-           os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
-               wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
-                          "group");
-               return -1;
+       params.psk_set = ssid->psk_set;
+       if (params.psk_set)
+               os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
+       if (ssid->passphrase) {
+               if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
+                       wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
+                                  "persistent group");
+                       return -1;
+               }
+               os_strlcpy(params.passphrase, ssid->passphrase,
+                          sizeof(params.passphrase));
        }
-       os_strlcpy(params.passphrase, ssid->passphrase,
-                  sizeof(params.passphrase));
        os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
        params.ssid_len = ssid->ssid_len;
        params.persistent_group = 1;
@@ -4203,7 +4421,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
        return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
                                 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
-                                0);
+                                0, 1);
 }
 
 
@@ -4216,13 +4434,12 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
 
 static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
 {
-       if (!wpa_s->pending_action_tx)
+       if (!offchannel_pending_action_tx(wpa_s))
                return;
 
        wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
                   "operation request");
-       wpabuf_free(wpa_s->pending_action_tx);
-       wpa_s->pending_action_tx = NULL;
+       offchannel_clear_pending_action_tx(wpa_s);
 }
 
 
@@ -4249,22 +4466,30 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
 }
 
 
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(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);
-       wpa_s->p2p_cb_on_scan_complete = 0;
+       wpa_s->global->p2p_cb_on_scan_complete = 0;
 
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
                wpa_drv_p2p_stop_find(wpa_s);
-               return;
+               return 1;
        }
 
        if (wpa_s->global->p2p)
                p2p_stop_find(wpa_s->global->p2p);
 
+       return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+       if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+               return;
        wpas_p2p_remove_pending_group_interface(wpa_s);
 }
 
@@ -4418,11 +4643,17 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 
 /* Invite to reinvoke a persistent group */
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                   struct wpa_ssid *ssid, const u8 *go_dev_addr)
+                   struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+                   int ht40)
 {
        enum p2p_invite_role role;
        u8 *bssid = NULL;
+#ifdef ANDROID_P2P
+       int force_freq = 0, oper_freq = 0;
+#endif
 
+       wpa_s->p2p_persistent_go_freq = freq;
+       wpa_s->p2p_go_ht40 = !!ht40;
        if (ssid->mode == WPAS_MODE_P2P_GO) {
                role = P2P_INVITE_ROLE_GO;
                if (peer_addr == NULL) {
@@ -4447,6 +4678,55 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        wpa_s->pending_invite_ssid_id = ssid->id;
 
+#ifdef ANDROID_P2P
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+           wpa_s->assoc_freq)
+               oper_freq = wpa_s->assoc_freq;
+       else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       if (freq > 0) {
+               if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                       wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+                                  "(%u MHz) is not supported for P2P uses",
+                                  freq);
+                       return -3;
+               }
+
+               if (oper_freq > 0 && freq != oper_freq &&
+                   !(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "on %u MHz while connected on another "
+                                  "channel (%u MHz)", freq, oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "requested channel (%u MHz)", freq);
+               force_freq = freq;
+       } else if (oper_freq > 0 &&
+                  !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
+               if (!(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "while connected on non-P2P supported "
+                                  "channel (%u MHz)", oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+                          "(%u MHz) not available for P2P - try to use "
+                          "another channel", oper_freq);
+               force_freq = 0;
+       } else if (oper_freq > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "channel we are already using (%u MHz) on another "
+                          "interface", oper_freq);
+               force_freq = oper_freq;
+       }
+#endif
        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,
@@ -4455,8 +4735,13 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+#ifdef ANDROID_P2P
+       return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+                         ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1);
+#else
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-                         ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
+                         ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+#endif
 }
 
 
@@ -4470,6 +4755,9 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
        struct wpa_ssid *ssid;
        int persistent;
 
+       wpa_s->p2p_persistent_go_freq = 0;
+       wpa_s->p2p_go_ht40 = 0;
+
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
                if (os_strcmp(wpa_s->ifname, ifname) == 0)
                        break;
@@ -4582,9 +4870,9 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
 
 done:
-       if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+       if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
            wpa_s->global->p2p != NULL) {
-               wpa_s->p2p_cb_on_scan_complete = 0;
+               wpa_s->global->p2p_cb_on_scan_complete = 0;
                if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
                                "continued after successful connection");
@@ -4630,8 +4918,15 @@ int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
 
 static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
 {
-       return wpa_s->current_ssid != NULL &&
-               wpa_s->current_ssid->p2p_group &&
+       if (wpa_s->current_ssid == NULL) {
+               /*
+                * current_ssid can be cleared when P2P client interface gets
+                * disconnected, so assume this interface was used as P2P
+                * client.
+                */
+               return 1;
+       }
+       return wpa_s->current_ssid->p2p_group &&
                wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
 }
 
@@ -5066,6 +5361,13 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
+                                    struct wpa_scan_results *scan_res)
+{
+       wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+}
+
+
 int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
 {
        struct wpa_global *global = wpa_s->global;
@@ -5089,6 +5391,18 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                found = 1;
        }
 
+       if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
+               wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
+               wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
+               found = 1;
+       }
+
+       if (wpa_s->pending_pd_before_join) {
+               wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
+               wpa_s->pending_pd_before_join = 0;
+               found = 1;
+       }
+
        wpas_p2p_stop_find(wpa_s);
 
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
@@ -5102,6 +5416,10 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        found = 1;
                        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);
+                               break;
+                       }
                        wpas_p2p_group_delete(wpa_s,
                                              P2P_GROUP_REMOVAL_REQUESTED);
                        break;
@@ -5177,28 +5495,9 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
 
 int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
 {
-#ifdef ANDROID_P2P
-       struct wpa_supplicant *group = wpa_s;
-#endif
-
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return 0;
 
-#ifdef ANDROID_P2P
-       while (group && (group->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)) {
-               if(group->wpa_state == WPA_ASSOCIATED) {
-                       /* WPA_ASSOCIATED hasn't moved to WPA_COMPLETED. So it could be in WPS
-                        * or 4Way Hanshake phase. Avoid allowing scan during this time critical
-                        * phase
-                        */
-                       wpa_printf(MSG_ERROR, "P2P: WPS/4way handshake in Progress."
-                       " Defer SCAN ");
-                       return 1;
-               }
-               group = group->next;
-       }
-#endif
-
        return p2p_in_progress(wpa_s->global->p2p);
 }
 
@@ -5268,7 +5567,6 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
                                        int group_added)
 {
        struct wpa_supplicant *group = wpa_s;
-       eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
        if (wpa_s->global->p2p_group_formation)
                group = wpa_s->global->p2p_group_formation;
        wpa_s = wpa_s->parent;
@@ -5340,40 +5638,59 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
 }
 
 #ifdef ANDROID_P2P
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+       struct wpa_ssid *ssid)
 {
        struct wpa_supplicant *iface = NULL;
        struct p2p_data *p2p = wpa_s->global->p2p;
 
        for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
-               if((iface->p2p_group_interface) && (iface->current_ssid) &&
-                       (iface->current_ssid->frequency != freq)) {
-
-                       if (iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) {
-                                       /* Try to see whether we can move the GO. If it
-                                        * is not possible, remove the GO interface
-                                        */
-                                       if(wpa_drv_switch_channel(iface, freq) == 0) {
-                                                       wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
-                                                       iface->current_ssid->frequency = freq;
-                                                       continue;
-                                       }
+               if ((iface->current_ssid) &&
+                   (iface->current_ssid->frequency != freq) &&
+                   ((iface->p2p_group_interface) ||
+                    (iface->current_ssid->p2p_group))) {
+
+                       if ((iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO)  ||
+                           (iface->current_ssid->mode == WPAS_MODE_P2P_GO)) {
+                               /* Try to see whether we can move the GO. If it
+                                * is not possible, remove the GO interface
+                                */
+                               if (wpa_drv_switch_channel(iface, freq) == 0) {
+                                       wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
+                                       iface->current_ssid->frequency = freq;
+                                       continue;
+                               }
                        }
 
                        /* If GO cannot be moved or if the conflicting interface is a
                         * P2P Client, remove the interface depending up on the connection
                         * priority */
-                       if(!wpas_is_p2p_prioritized(wpa_s)) {
-                               /* STA connection has priority over existing 
+                       if(!wpas_is_p2p_prioritized(iface)) {
+                               /* STA connection has priority over existing
                                 * P2P connection. So remove the interface */
                                wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
                                                "concurrent mode frequency conflict");
                                wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+                               /* If connection in progress is p2p connection, do not proceed for the connection */
+                               if (wpa_s == iface)
+                                       return -1;
+                               else
+                                       /* If connection in progress is STA connection, proceed for the connection */
+                                       return 0;
                        } else {
-                               /* Existing connection has the priority. Disable the newly
-                 * selected network and let the application know about it.
-                                */
-                               return -1;
+                               /* P2p connection has priority, disable the STA network*/
+                               wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
+                               wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+                                       " id=%d", ssid->id);
+                               os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
+                               if (wpa_s == iface) {
+                                       /* p2p connection is in progress, continue connecting...*/
+                                       return 0;
+                               }
+                               else {
+                                       /* STA connection is in progress, do not allow to continue */
+                                       return -1;
+                               }
                        }
                }
        }