Merge "[Security bug fix] Added peer address check"
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index a1f8ae9..3c55c5a 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -592,6 +592,7 @@
 ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
 {
 	struct ieee802_1x_kay_peer *peer;
+	struct os_reltime now;
 
 	peer = os_zalloc(sizeof(*peer));
 	if (!peer) {
@@ -601,7 +602,8 @@
 
 	os_memcpy(peer->mi, mi, MI_LEN);
 	peer->mn = mn;
-	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+	os_get_reltime(&now);
+	peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 	peer->sak_used = false;
 	peer->missing_sak_use_count = 0;
 
@@ -678,6 +680,7 @@
 {
 	struct ieee802_1x_kay_peer *peer;
 	struct receive_sc *rxsc;
+	struct os_reltime now;
 
 	peer = ieee802_1x_kay_get_potential_peer(participant, mi);
 	if (!peer)
@@ -690,7 +693,8 @@
 	os_memcpy(&peer->sci, &participant->current_peer_sci,
 		  sizeof(peer->sci));
 	peer->mn = mn;
-	peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+	os_get_reltime(&now);
+	peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 
 	wpa_printf(MSG_DEBUG, "KaY: Move potential peer to live peer");
 	ieee802_1x_kay_dump_peer(peer);
@@ -873,13 +877,15 @@
 		peer = ieee802_1x_kay_get_peer_sci(participant,
 						   &body->actor_sci);
 		if (peer) {
-			time_t new_expire;
+			os_time_t new_expire;
+			struct os_reltime now;
 
 			wpa_printf(MSG_WARNING,
 				   "KaY: duplicated SCI detected - maybe active attacker or peer selected new MI - ignore MKPDU");
 			/* Reduce timeout to speed up this process but left the
 			 * chance for old one to prove aliveness. */
-			new_expire = time(NULL) + MKA_HELLO_TIME * 1.5 / 1000;
+			os_get_reltime(&now);
+			new_expire = now.sec + MKA_HELLO_TIME * 1.5 / 1000;
 			if (peer->expire > new_expire)
 				peer->expire = new_expire;
 			return NULL;
@@ -2130,6 +2136,7 @@
 	unsigned int key_len;
 	u8 *key;
 	struct macsec_ciphersuite *cs;
+	struct os_reltime now;
 
 	/* check condition for generating a fresh SAK:
 	 * must have one live peer
@@ -2150,7 +2157,8 @@
 	 * here only check first item and ingore
 	 *   && (!dl_list_empty(&participant->potential_peers))) {
 	 */
-	if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
+	os_get_reltime(&now);
+	if ((now.sec - kay->dist_time) < MKA_LIFE_TIME / 1000) {
 		wpa_printf(MSG_ERROR,
 			   "KaY: Life time has not elapsed since prior SAK distributed");
 		return -1;
@@ -2244,7 +2252,7 @@
 	if (kay->dist_an > 3)
 		kay->dist_an = 0;
 
-	kay->dist_time = time(NULL);
+	kay->dist_time = now.sec;
 
 	return 0;
 
@@ -2548,17 +2556,19 @@
 	struct ieee802_1x_mka_participant *participant;
 	struct ieee802_1x_kay *kay;
 	struct ieee802_1x_kay_peer *peer, *pre_peer;
-	time_t now = time(NULL);
+	struct os_reltime now;
 	bool lp_changed;
 	struct receive_sc *rxsc, *pre_rxsc;
 	struct transmit_sa *txsa, *pre_txsa;
 
+	os_get_reltime(&now);
+
 	participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
 	kay = participant->kay;
 	wpa_printf(MSG_DEBUG, "KaY: Participant timer (ifname=%s)",
 		   kay->if_name);
 	if (participant->cak_life) {
-		if (now > participant->cak_life)
+		if (now.sec > participant->cak_life)
 			goto delete_mka;
 	}
 
@@ -2566,7 +2576,7 @@
 	 * when the MKA life elapsed since its creating */
 	if (participant->mka_life) {
 		if (dl_list_empty(&participant->live_peers)) {
-			if (now > participant->mka_life)
+			if (now.sec > participant->mka_life)
 				goto delete_mka;
 		} else {
 			participant->mka_life = 0;
@@ -2576,7 +2586,7 @@
 	lp_changed = false;
 	dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
 			      struct ieee802_1x_kay_peer, list) {
-		if (now > peer->expire) {
+		if (now.sec > peer->expire) {
 			wpa_printf(MSG_DEBUG, "KaY: Live peer removed");
 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
 				    sizeof(peer->mi));
@@ -2634,7 +2644,7 @@
 
 	dl_list_for_each_safe(peer, pre_peer, &participant->potential_peers,
 			      struct ieee802_1x_kay_peer, list) {
-		if (now > peer->expire) {
+		if (now.sec > peer->expire) {
 			wpa_printf(MSG_DEBUG, "KaY: Potential peer removed");
 			wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
 				    sizeof(peer->mi));
@@ -3371,11 +3381,14 @@
 				return -1;
 			}
 		} else {
+			struct os_reltime now;
+
+			os_get_reltime(&now);
 			peer->missing_sak_use_count = 0;
 
 			/* Only update live peer watchdog after successful
 			 * decode of all parameter sets */
-			peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+			peer->expire = now.sec + MKA_LIFE_TIME / 1000;
 		}
 	} else {
 		/* MKPDU is from new or potential peer */
@@ -3674,8 +3687,12 @@
 	os_memcpy(participant->cak.key, cak->key, cak->len);
 	wpa_hexdump_key(MSG_DEBUG, "KaY: CAK", participant->cak.key,
 			participant->cak.len);
-	if (life)
-		participant->cak_life = life + time(NULL);
+	if (life) {
+		struct os_reltime now;
+		os_get_reltime(&now);
+
+		participant->cak_life = life + now.sec;
+	}
 
 	switch (mode) {
 	case EAP_EXCHANGE:
@@ -3783,7 +3800,10 @@
 	 * some peer appears.
 	 */
 	if (mode != PSK) {
-		participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+		struct os_reltime now;
+		os_get_reltime(&now);
+
+		participant->mka_life = MKA_LIFE_TIME / 1000 + now.sec +
 			usecs / 1000000;
 	}
 	participant->mode = mode;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 11cf7b7..525679f 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -213,7 +213,7 @@
 	u32 dist_kn;
 	u32 rcvd_keys;
 	u8 dist_an;
-	time_t dist_time;
+	os_time_t dist_time;
 
 	u8 mka_version;
 	u8 algo_agility[4];
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index 7a04169..e4650b5 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -45,7 +45,7 @@
 	struct ieee802_1x_mka_sci sci;
 	u8 mi[MI_LEN];
 	u32 mn;
-	time_t expire;
+	os_time_t expire;
 	bool is_key_server;
 	u8 key_server_priority;
 	bool macsec_desired;
@@ -135,8 +135,8 @@
 	struct ieee802_1x_mka_peer_id current_peer_id;
 	struct ieee802_1x_mka_sci current_peer_sci;
 
-	time_t cak_life;
-	time_t mka_life;
+	os_time_t cak_life;
+	os_time_t mka_life;
 	bool to_dist_sak;
 	bool to_use_sak;
 	bool new_sak;
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index 45dbaec..694357f 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -23,13 +23,7 @@
 #include "driver_i.h"
 }
 
-#define P2P_MAX_JOIN_SCAN_ATTEMPTS 3
-// Wait time before triggering the single channel scan to discover Auto GO.
-// Use a shorter wait time when the given frequency is GO operating frequency.
-// The idea is to quickly finish scans and return the status to application.
-#define P2P_JOIN_SINGLE_CHANNEL_SCAN_INTERVAL_USECS 200000
-// Wait time before triggering the multiple channel scan to discover Auto GO.
-#define P2P_JOIN_MULTIPLE_CHANNEL_SCAN_INTERVAL_USECS 1000000
+#define P2P_JOIN_LIMIT 3
 
 namespace {
 const char kConfigMethodStrPbc[] = "pbc";
@@ -99,138 +93,6 @@
 	return 1;
 }
 
-static int setBandScanFreqsList(
-	struct wpa_supplicant *wpa_s,
-	enum hostapd_hw_mode hw_mode,
-	bool exclude_dfs,
-	struct wpa_driver_scan_params *params)
-{
-	struct hostapd_hw_modes *mode;
-	int count, i;
-
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
-	if (mode == NULL || !mode->num_channels) {
-		wpa_printf(MSG_ERROR,
-			"P2P: No channels supported in this hw_mode: %d", hw_mode);
-		return -1;
-	}
-
-	/*
-	 * Allocate memory for frequency array, allocate one extra
-	 * slot for the zero-terminator.
-	 */
-	params->freqs = (int *) os_calloc(mode->num_channels + 1, sizeof(int));
-	if (params->freqs == NULL) {
-		return -ENOMEM;
-	}
-	for (count = 0, i = 0; i < mode->num_channels; i++) {
-		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) {
-			continue;
-		}
-		if (exclude_dfs && (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)) {
-			continue;
-		}
-		params->freqs[count++] = mode->channels[i].freq;
-	}
-	if (!count && params->freqs) {
-		wpa_printf(MSG_ERROR,
-			"P2P: All channels(exclude_dfs: %d) are disabled in this hw_mode: %d",
-			exclude_dfs, hw_mode);
-		os_free(params->freqs);
-		return -1;
-	}
-	return 0;
-}
-
-static int setScanFreq(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params,
-	int freq, int operating_freq)
-{
-	int frequency = operating_freq ? operating_freq : freq;
-	if (disabled_freq(wpa_s, frequency)) {
-		wpa_printf(MSG_ERROR,
-				"P2P: freq %d is not supported for a client.", frequency);
-		return -1;
-	}
-	/*
-	 * Allocate memory for frequency array, with one extra
-	 * slot for the zero-terminator.
-	 */
-	params->freqs = new int[2] {frequency, 0};
-	return 0;
-}
-
-/**
- * setP2pCliOptimizedScanFreqsList - Fill the frequencies to scan in Scan
- * parameters.
- * @wpa_s: Pointer to wpa_supplicant data
- * @params: Pointer to Scan parameters.
- * @freq: Frequency/Band requested to scan by the application, possible values are,
- *		0 - All the frequencies - full scan
- *		2 - Frequencies in 2.4GHz
- *		5 - Frequencies in 5GHz
- *		- Valid frequency
- * @operating_freq: Frequency of BSS if found in scan cache
- * Returns: Pointer to the BSS entry or %NULL if not found
- */
-static int setP2pCliOptimizedScanFreqsList(struct wpa_supplicant *wpa_s,
-	struct wpa_driver_scan_params *params, int freq, int operating_freq)
-{
-	int ret;
-	/* If BSS is found in scan cache, first scan its operating frequency */
-	if (!wpa_s->p2p_join_scan_count && operating_freq) {
-		ret = setScanFreq(wpa_s, params, freq, operating_freq);
-		if (!ret) {
-			return ret;
-		}
-	}
-
-	/* Empty freq params means scan all the frequencies */
-	if (freq == 0) {
-		return 0;
-	}
-	else if (freq == 2 || freq == 5) {
-		/* Scan the frequencies in the band */
-		enum hostapd_hw_mode mode;
-		int ret;
-		if (wpa_s->hw.modes == NULL) {
-			wpa_printf(MSG_DEBUG,
-				   "P2P: Unknown what %dG channels the driver supports.", freq);
-			return 0;
-		}
-		mode = freq == 5 ? HOSTAPD_MODE_IEEE80211A : HOSTAPD_MODE_IEEE80211G;
-		if (wpa_s->p2p_join_scan_count < 2) {
-			// scan all non DFS channels in the first two attempts
-			ret = setBandScanFreqsList(wpa_s, mode, true, params);
-			if (ret < 0 && (-ENOMEM != ret)) {
-				// try to scan all channels before returning error
-				ret = setBandScanFreqsList(wpa_s, mode, false, params);
-			}
-		} else {
-			// scan all channels
-			ret = setBandScanFreqsList(wpa_s, mode, false, params);
-		}
-		return ret;
-	} else {
-		/* Scan the frequency requested by the application */
-		ret = setScanFreq(wpa_s, params, freq, 0);
-		return ret;
-	}
-	return 0;
-}
-
-/**
- * getP2pJoinScanInterval - Get the delay in triggering the scan to discover
- * Auto GO.
- */
-static int getP2pJoinScanIntervalUsecs(int freq)
-{
-	if (freq == 5 || freq == 2 || freq == 0) {
-		return P2P_JOIN_MULTIPLE_CHANNEL_SCAN_INTERVAL_USECS;
-	} else {
-		return P2P_JOIN_SINGLE_CHANNEL_SCAN_INTERVAL_USECS;
-	}
-}
-
 /*
  * isAnyEtherAddr - match any ether address
  *
@@ -241,56 +103,9 @@
 	return (a[0] == 2) && !(a[1] | a[2] | a[3] | a[4] | a[5]);
 }
 
-/**
- * findBssBySsid - Fetch a BSS table entry based on SSID and optional BSSID.
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID, 02:00:00:00:00:00 matches any bssid
- * @ssid: SSID
- * @ssid_len: Length of @ssid
- * Returns: Pointer to the BSS entry or %NULL if not found
- */
-struct wpa_bss* findBssBySsid(
-	struct wpa_supplicant *wpa_s, const u8 *bssid,
-	const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_bss *bss;
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if ((isAnyEtherAddr(bssid) ||
-			os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) &&
-			bss->ssid_len == ssid_len &&
-			os_memcmp(bss->ssid, ssid, ssid_len) == 0)
-			return bss;
-	}
-	return NULL;
-}
-
-/**
- * findBssBySsidFromAnyInterface - Fetch a BSS table entry based on SSID and optional BSSID
- * by iterating through all the interfaces.
- * @head: Head of Pointer to wpa_supplicant data
- * @bssid: BSSID, 02:00:00:00:00:00 matches any bssid
- * @ssid: SSID
- * @ssid_len: Length of @ssid
- * Returns: Pointer to the BSS entry or %NULL if not found
- */
-struct wpa_bss* findBssBySsidFromAnyInterface(
-	struct wpa_supplicant *head, const u8 *bssid,
-	const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_supplicant *wpa_s;
-	struct wpa_bss *bss = NULL;
-	for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) {
-		bss = findBssBySsid(wpa_s, bssid, ssid, ssid_len);
-		if (bss != NULL) {
-			return bss;
-		}
-	}
-	return bss;
-}
-
 struct wpa_ssid* addGroupClientNetwork(
 	struct wpa_supplicant* wpa_s,
-	uint8_t *group_owner_bssid,
+	const uint8_t *group_owner_bssid,
 	const std::vector<uint8_t>& ssid,
 	const std::string& passphrase)
 {
@@ -304,22 +119,18 @@
 	// set P2p network defaults
 	wpa_network->p2p_group = 1;
 	wpa_network->mode = wpas_mode::WPAS_MODE_INFRA;
-
-	wpa_network->auth_alg = WPA_AUTH_ALG_OPEN;
-	wpa_network->key_mgmt = WPA_KEY_MGMT_PSK;
-	wpa_network->proto = WPA_PROTO_RSN;
-	wpa_network->pairwise_cipher = WPA_CIPHER_CCMP;
-	wpa_network->group_cipher = WPA_CIPHER_CCMP;
 	wpa_network->disabled = 2;
 
 	// set necessary fields
-	os_memcpy(wpa_network->bssid, group_owner_bssid, ETH_ALEN);
-	wpa_network->bssid_set = 1;
+	if (!isAnyEtherAddr(group_owner_bssid)) {
+		os_memcpy(wpa_network->bssid, group_owner_bssid, ETH_ALEN);
+		wpa_network->bssid_set = 1;
+	}
 
 	wpa_network->ssid = (uint8_t *)os_malloc(ssid.size());
 	if (wpa_network->ssid == NULL) {
 		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
-		return  NULL;
+		return NULL;
 	}
 	memcpy(wpa_network->ssid, ssid.data(), ssid.size());
 	wpa_network->ssid_len = ssid.size();
@@ -328,7 +139,7 @@
 	wpa_network->passphrase = dup_binstr(passphrase.c_str(), passphrase.length());
 	if (wpa_network->passphrase == NULL) {
 		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
-		return  NULL;
+		return NULL;
 	}
 	wpa_config_update_psk(wpa_network);
 
@@ -336,13 +147,6 @@
 
 }
 
-void joinScanWrapper(void *eloop_ctx, void *timeout_ctx)
-{
-	if (pending_join_scan_callback) {
-		pending_join_scan_callback();
-	}
-}
-
 void scanResJoinWrapper(
 	struct wpa_supplicant *wpa_s,
 	struct wpa_scan_results *scan_res)
@@ -358,85 +162,6 @@
 	}
 }
 
-int joinScanReq(
-	struct wpa_supplicant* wpa_s,
-	const std::vector<uint8_t>& ssid,
-	int freq, int operating_freq)
-{
-	int ret;
-	struct wpa_driver_scan_params params;
-	struct wpabuf *ies;
-	size_t ielen;
-	unsigned int bands;
-
-	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
-		wpa_printf(MSG_ERROR,
-			"P2P: P2P interface is gone, cancel join scan");
-		return -ENXIO;
-	}
-
-	os_memset(&params, 0, sizeof(params));
-	if (ssid.size() > 0) {
-		params.ssids[0].ssid = ssid.data();
-		params.ssids[0].ssid_len = ssid.size();
-	} else {
-		params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
-		params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
-	}
-	wpa_printf(MSG_DEBUG, "Scan SSID %s for join with frequency %d"
-		"BSS operating_freq from scan cache %d",
-		wpa_ssid_txt(params.ssids[0].ssid, params.ssids[0].ssid_len), freq, operating_freq);
-
-	/* Construct an optimized p2p scan channel list */
-	ret = setP2pCliOptimizedScanFreqsList(wpa_s, &params, freq, operating_freq);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR,
-				   "Failed to set frequency in p2p scan params, error = %d", ret);
-		return -1;
-	}
-
-	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
-	ies = wpabuf_alloc(ielen);
-	if (ies == NULL) {
-		if (params.freqs) {
-			os_free(params.freqs);
-		}
-		return -1;
-	}
-
-	bands = wpas_get_bands(wpa_s, params.freqs);
-	p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
-
-	params.p2p_probe = 1;
-	params.extra_ies = (u8 *) wpabuf_head(ies);
-	params.extra_ies_len = wpabuf_len(ies);
-	if (wpa_s->clear_driver_scan_cache) {
-		wpa_printf(MSG_DEBUG,
-			"Request driver to clear scan cache due to local BSS flush");
-		params.only_new_results = 1;
-	}
-
-	ret = wpa_drv_scan(wpa_s, &params);
-	if (!ret) {
-		os_get_reltime(&wpa_s->scan_trigger_time);
-		if (wpa_s->scan_res_handler) {
-			wpa_printf(MSG_DEBUG, "Replace current running scan result handler");
-		}
-		wpa_s->p2p_join_scan_count++;
-		wpa_s->scan_res_handler = scanResJoinWrapper;
-		wpa_s->own_scan_requested = 1;
-		wpa_s->clear_driver_scan_cache = 0;
-	}
-
-	if (params.freqs) {
-		os_free(params.freqs);
-	}
-
-	wpabuf_free(ies);
-
-	return ret;
-}
-
 static bool is6GhzAllowed(struct wpa_supplicant *wpa_s) {
 	if (!wpa_s->global->p2p) return false;
 	return wpa_s->global->p2p->allow_6ghz;
@@ -444,9 +169,10 @@
 
 int joinGroup(
 	struct wpa_supplicant* wpa_s,
-	uint8_t *group_owner_bssid,
+	const uint8_t *group_owner_bssid,
 	const std::vector<uint8_t>& ssid,
-	const std::string& passphrase)
+	const std::string& passphrase,
+	uint32_t freq)
 {
 	int ret = 0;
 	int he = wpa_s->conf->p2p_go_he;
@@ -467,8 +193,8 @@
 	wpa_network->temporary = 1;
 
 	if (wpas_p2p_group_add_persistent(
-		wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
-		CONF_OPER_CHWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
+		wpa_s, wpa_network, 0, 0, freq, 0, ht40, vht,
+		CONF_OPER_CHWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s), P2P_JOIN_LIMIT)) {
 		ret = -1;
 	}
 
@@ -477,27 +203,6 @@
 	return ret;
 }
 
-void notifyGroupJoinFailure(
-	struct wpa_supplicant* wpa_s)
-{
-	u8 zero_addr[ETH_ALEN] = {0};
-	std::vector<uint8_t> ssid = {'D', 'I', 'R', 'E','C', 'T', '-'};
-	std::string passphrase = "";
-	struct wpa_ssid *wpa_network = addGroupClientNetwork(
-		wpa_s, zero_addr, ssid, passphrase);
-	if (wpa_network) {
-		wpa_network->temporary = 1;
-		wpas_notify_p2p_group_formation_failure(wpa_s, "Failed to find the group.");
-		wpas_notify_p2p_group_removed(
-			wpa_s, wpa_network, "client");
-		wpa_config_remove_network(
-			wpa_s->conf, wpa_network->id);
-	} else {
-		wpa_printf(MSG_ERROR,
-			"P2P: Cannot construct a network.");
-	}
-}
-
 void scanResJoinIgnore(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) {
 	wpa_printf(MSG_DEBUG, "P2P: Ignore group join scan results.");
 
@@ -1901,7 +1606,7 @@
 	} else if (ssid->disabled == 2) {
 		if (wpas_p2p_group_add_persistent(
 			wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
-			CONF_OPER_CHWIDTH_USE_HT, he, edmg, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
+			CONF_OPER_CHWIDTH_USE_HT, he, edmg, NULL, 0, 0, is6GhzAllowed(wpa_s), 0)) {
 			return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
 		} else {
 			return ndk::ScopedAStatus::ok();
@@ -1956,77 +1661,7 @@
 	// The rest is for group join.
 	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND before group join.");
 	wpas_p2p_stop_find(wpa_s);
-
-	if (pending_scan_res_join_callback != NULL) {
-		wpa_printf(MSG_WARNING, "P2P: Renew scan result callback with new request.");
-	}
-
-	pending_join_scan_callback =
-		[wpa_s, ssid, peer_address, freq]() {
-		if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
-			return;
-		}
-		int operating_freq = 0;
-		struct wpa_bss *bss = findBssBySsidFromAnyInterface(
-			wpa_s->global->ifaces, peer_address.data(), ssid.data(), ssid.size());
-		if (bss != NULL) {
-			wpa_printf(MSG_DEBUG, "P2P: Found Group owner " MACSTR "in scan cache",
-				MAC2STR(bss->bssid));
-			operating_freq = bss->freq;
-		}
-
-		int ret = joinScanReq(wpa_s, ssid, freq, operating_freq);
-		// for BUSY case, the scan might be occupied by WiFi.
-		// Do not give up immediately, but try again later.
-		if (-EBUSY == ret) {
-			// re-schedule this join scan
-			eloop_cancel_timeout(joinScanWrapper, wpa_s, NULL);
-			eloop_register_timeout(0, P2P_JOIN_SINGLE_CHANNEL_SCAN_INTERVAL_USECS,
-					joinScanWrapper, wpa_s, NULL);
-		} else if (0 != ret) {
-			notifyGroupJoinFailure(wpa_s);
-			pending_scan_res_join_callback = NULL;
-		}
-	};
-
-	pending_scan_res_join_callback = [wpa_s, ssid, passphrase, peer_address, freq, this]() {
-		if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
-			return;
-		}
-
-		wpa_printf(MSG_DEBUG, "P2P: Scan results received for join (reinvoke).");
-
-		struct wpa_bss *bss = findBssBySsid(
-			wpa_s, peer_address.data(), ssid.data(), ssid.size());
-		if (bss) {
-			if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
-				wpa_printf(MSG_ERROR, "P2P: Failed to join a group.");
-			}
-			// no need to notify group join failure here,
-			// it will be handled by wpas_p2p_group_add_persistent
-			// called in joinGroup.
-			pending_scan_res_join_callback = NULL;
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Join scan count %d.", wpa_s->p2p_join_scan_count);
-		eloop_cancel_timeout(joinScanWrapper, wpa_s, NULL);
-		if (wpa_s->p2p_join_scan_count < P2P_MAX_JOIN_SCAN_ATTEMPTS) {
-			wpa_printf(MSG_DEBUG, "P2P: Try join again later.");
-			eloop_register_timeout(0, getP2pJoinScanIntervalUsecs(freq),
-				joinScanWrapper, wpa_s, this);
-			return;
-		}
-
-		wpa_printf(MSG_ERROR, "P2P: Failed to find the group with "
-			"network name %s - stop join attempt",
-			wpa_ssid_txt(ssid.data(), ssid.size()));
-		notifyGroupJoinFailure(wpa_s);
-		pending_scan_res_join_callback = NULL;
-	};
-
-	wpa_s->p2p_join_scan_count = 0;
-	pending_join_scan_callback();
-	if (pending_scan_res_join_callback == NULL) {
+	if (joinGroup(wpa_s, peer_address.data(), ssid, passphrase, freq)) {
 		return createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
 			"Failed to start scan.");
 	}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index a3da86c..dcc28be 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -240,7 +240,7 @@
 /**
  * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
  * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID
+ * @bssid: BSSID, or %NULL to match any BSSID
  * @ssid: SSID
  * @ssid_len: Length of @ssid
  * Returns: Pointer to the BSS entry or %NULL if not found
@@ -252,7 +252,8 @@
 	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
 		return NULL;
 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+		if ((!bssid ||
+		     os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) &&
 		    bss->ssid_len == ssid_len &&
 		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
 			return bss;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7118cab..314d741 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6879,7 +6879,7 @@
 	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
 					     vht_center_freq2, 0, ht40, vht,
 					     vht_chwidth, he, edmg,
-					     NULL, 0, 0, allow_6ghz);
+					     NULL, 0, 0, allow_6ghz, 0);
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index de79178..370aee2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -355,6 +355,7 @@
 	char *pg_object_path = NULL;
 	int persistent_group = 0;
 	int freq = 0;
+	int retry_limit = 0;
 	char *iface = NULL;
 	unsigned int group_id = 0;
 	struct wpa_ssid *ssid;
@@ -376,6 +377,11 @@
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
+		} else if (os_strcmp(entry.key, "retry_limit") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
+			retry_limit = entry.int32_value;
+			if (retry_limit <= 0)
+				goto inv_args_clear;
 		} else if (os_strcmp(entry.key, "persistent_group_object") ==
 			   0 &&
 			   entry.type == DBUS_TYPE_OBJECT_PATH)
@@ -426,7 +432,7 @@
 
 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
 						  0, 0, 0, 0, NULL, 0, 0,
-						  false)) {
+						  false, retry_limit)) {
 			reply = wpas_dbus_error_unknown_error(
 				message,
 				"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index aa01245..b066d62 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2409,6 +2409,9 @@
 			if (res == 1)
 				return 0;
 
+			if (wpas_p2p_retry_limit_exceeded(wpa_s)) {
+				return 0;
+			}
 			if (wpa_s->p2p_in_provisioning ||
 			    wpa_s->show_group_started ||
 			    wpa_s->p2p_in_invitation) {
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0bfb962..ab1555e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -365,9 +365,9 @@
 		wpa_printf(MSG_DEBUG,
 			   "P2P: Exclude 6 GHz channels - update the scan frequency list");
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
-					0);
+					false, false);
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
-					0);
+					false, false);
 	}
 	ret = wpa_drv_scan(wpa_s, params);
 	if (ret == 0)
@@ -996,6 +996,7 @@
 	}
 
 	wpa_s->p2p_in_invitation = 0;
+	wpa_s->p2p_retry_limit = 0;
 	eloop_cancel_timeout(wpas_p2p_move_go, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
 
@@ -1390,6 +1391,7 @@
 		wpa_s->p2p_in_provisioning = 0;
 	}
 	wpa_s->p2p_in_invitation = 0;
+	wpa_s->p2p_retry_limit = 0;
 	wpa_s->group_formation_reported = 1;
 
 	if (!success) {
@@ -2407,6 +2409,21 @@
 }
 
 
+bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->p2p_in_invitation || !wpa_s->p2p_retry_limit ||
+	    wpa_s->p2p_in_invitation <= wpa_s->p2p_retry_limit) {
+		return false;
+	}
+	wpa_printf(MSG_DEBUG, "P2P: Group join retry limit exceeded");
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+			     wpa_s->p2pdev, NULL);
+	eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+			       wpa_s->p2pdev, NULL);
+	return true;
+}
+
+
 static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -3292,7 +3309,7 @@
 				wpa_s->conf->p2p_go_he,
 				wpa_s->conf->p2p_go_edmg, NULL,
 				go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
-				1, is_p2p_allow_6ghz(wpa_s->global->p2p));
+				1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0);
 		} else if (bssid) {
 			wpa_s->user_initiated_pd = 0;
 			wpa_msg_global(wpa_s, MSG_INFO,
@@ -3522,7 +3539,7 @@
 				      ssid->mode == WPAS_MODE_P2P_GO ?
 				      P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
 				      0, 1,
-				      is_p2p_allow_6ghz(wpa_s->global->p2p));
+				      is_p2p_allow_6ghz(wpa_s->global->p2p), 0);
 }
 
 
@@ -4602,7 +4619,7 @@
 					persistent_go->mode ==
 					WPAS_MODE_P2P_GO ?
 					P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
-					0, 0, false);
+					0, 0, false, 0);
 			} else if (response_done) {
 				wpas_p2p_group_add(wpa_s, 1, freq,
 						   0, 0, 0, 0, 0, 0, false);
@@ -4725,7 +4742,7 @@
 			NULL,
 			persistent_go->mode == WPAS_MODE_P2P_GO ?
 			P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0,
-			is_p2p_allow_6ghz(wpa_s->global->p2p));
+			is_p2p_allow_6ghz(wpa_s->global->p2p), 0);
 	} else {
 		wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0,
 				   is_p2p_allow_6ghz(wpa_s->global->p2p));
@@ -5543,9 +5560,9 @@
 		wpa_printf(MSG_DEBUG,
 			   "P2P: 6 GHz disabled - update the scan frequency list");
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params,
-					0);
+					false, false);
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params,
-					0);
+					false, false);
 	}
 
 	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -6954,7 +6971,7 @@
 
 static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
 				 struct wpa_ssid *params, int addr_allocated,
-				 int freq, int force_scan)
+				 int freq, int force_scan, int retry_limit)
 {
 	struct wpa_ssid *ssid;
 	int other_iface_found = 0;
@@ -6997,8 +7014,14 @@
 	if (params->passphrase)
 		ssid->passphrase = os_strdup(params->passphrase);
 
+	if (params->bssid_set) {
+		ssid->bssid_set = 1;
+		os_memcpy(ssid->bssid, params->bssid, ETH_ALEN);
+	}
+
 	wpa_s->show_group_started = 1;
 	wpa_s->p2p_in_invitation = 1;
+	wpa_s->p2p_retry_limit = retry_limit;
 	wpa_s->p2p_invite_go_freq = freq;
 	wpa_s->p2p_go_group_formation_completed = 0;
 	wpa_s->global->p2p_group_formation = wpa_s;
@@ -7042,7 +7065,7 @@
 				  int edmg,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan,
-				  bool allow_6ghz)
+				  bool allow_6ghz, int retry_limit)
 {
 	struct p2p_go_neg_results params;
 	int go = 0, freq;
@@ -7111,7 +7134,7 @@
 		}
 
 		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq,
-					     force_scan);
+					     force_scan, retry_limit);
 	} else {
 		return -1;
 	}
@@ -7867,6 +7890,7 @@
 		wpa_s->global->p2p_group_formation = NULL;
 		wpa_s->p2p_in_provisioning = 0;
 		wpa_s->p2p_in_invitation = 0;
+		wpa_s->p2p_retry_limit = 0;
 	}
 
 	os_memset(go_dev_addr, 0, ETH_ALEN);
@@ -8696,6 +8720,7 @@
 		wpa_s->global->p2p_group_formation = NULL;
 		wpa_s->p2p_in_provisioning = 0;
 		wpa_s->p2p_in_invitation = 0;
+		wpa_s->p2p_retry_limit = 0;
 	}
 	wpa_s->global->p2p_go_wait_client.sec = 0;
 	if (addr == NULL)
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 5a869e7..949044a 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -52,7 +52,7 @@
 				  int max_oper_chwidth, int he, int edmg,
 				  const struct p2p_channels *channels,
 				  int connection_timeout, int force_scan,
-				  bool allow_6ghz);
+				  bool allow_6ghz, int retry_limit);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 				       struct wpa_ssid *ssid);
 enum wpas_p2p_prov_disc_use {
@@ -206,6 +206,7 @@
 int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
 int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
 void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
+bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s);
 void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s);
 void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index ee90aac..faa97e0 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -444,16 +444,63 @@
 
 	if (params->freqs == NULL && wpa_s->p2p_in_invitation) {
 		/*
+		 * Perform a single-channel scan if the GO has already been
+		 * discovered on another non-P2P interface. Note that a scan
+		 * initiated by a P2P interface (e.g. the device interface)
+		 * should already have sufficient IEs and scan results will be
+		 * fetched on interface creation in that case.
+		 */
+		if (wpa_s->p2p_in_invitation == 1 && wpa_s->current_ssid) {
+			struct wpa_supplicant *ifs;
+			struct wpa_bss *bss = NULL;
+			struct wpa_ssid *ssid = wpa_s->current_ssid;
+			u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL;
+			dl_list_for_each(ifs, &wpa_s->radio->ifaces,
+					 struct wpa_supplicant, radio_list) {
+				bss = wpa_bss_get(ifs, bssid, ssid->ssid,
+						  ssid->ssid_len);
+				if (bss)
+					break;
+			}
+			if (bss && !disabled_freq(wpa_s, bss->freq)) {
+				params->freqs = os_calloc(2, sizeof(int));
+				if (params->freqs)
+					params->freqs[0] = bss->freq;
+			}
+		}
+		/*
 		 * Optimize scan based on GO information during persistent
 		 * group reinvocation
 		 */
-		if (wpa_s->p2p_in_invitation < 5 &&
+		if (params->freqs == NULL && wpa_s->p2p_in_invitation < 5 &&
 		    wpa_s->p2p_invite_go_freq > 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
-				wpa_s->p2p_invite_go_freq);
-			params->freqs = os_calloc(2, sizeof(int));
-			if (params->freqs)
-				params->freqs[0] = wpa_s->p2p_invite_go_freq;
+			if (wpa_s->p2p_invite_go_freq == 2 ||
+			    wpa_s->p2p_invite_go_freq == 5) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred band %d GHz during invitation",
+					wpa_s->p2p_invite_go_freq);
+				enum hostapd_hw_mode mode;
+				if (wpa_s->hw.modes == NULL)
+					return;
+				mode = wpa_s->p2p_invite_go_freq == 5 ?
+				       HOSTAPD_MODE_IEEE80211A :
+				       HOSTAPD_MODE_IEEE80211G;
+				if (wpa_s->p2p_in_invitation <= 2)
+					wpa_add_scan_freqs_list(wpa_s, mode,
+								params, false,
+								true);
+				if (params->freqs == NULL ||
+				    (params->freqs && params->freqs[0] == 0))
+					wpa_add_scan_freqs_list(wpa_s, mode,
+								params, false,
+								false);
+			} else {
+				wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
+					wpa_s->p2p_invite_go_freq);
+				params->freqs = os_calloc(2, sizeof(int));
+				if (params->freqs)
+					params->freqs[0] =
+					    wpa_s->p2p_invite_go_freq;
+			}
 		}
 		wpa_s->p2p_in_invitation++;
 		if (wpa_s->p2p_in_invitation > 20) {
@@ -465,6 +512,7 @@
 			 */
 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation");
 			wpa_s->p2p_in_invitation = 0;
+			wpa_s->p2p_retry_limit = 0;
 		}
 	}
 #endif /* CONFIG_P2P */
@@ -709,7 +757,8 @@
 
 int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
 			    enum hostapd_hw_mode band,
-			    struct wpa_driver_scan_params *params, bool is_6ghz)
+			    struct wpa_driver_scan_params *params, bool is_6ghz,
+			    bool exclude_radar)
 {
 	/* Include only supported channels for the specified band */
 	struct hostapd_hw_modes *mode;
@@ -734,6 +783,8 @@
 	for (i = 0; i < mode->num_channels; i++) {
 		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
 			continue;
+		if (exclude_radar && (mode->channels[i].flag & HOSTAPD_CHAN_RADAR))
+			continue;
 		params->freqs[num_chans++] = mode->channels[i].freq;
 	}
 	params->freqs[num_chans] = 0;
@@ -752,13 +803,13 @@
 
 	if (wpa_s->setband_mask & WPA_SETBAND_5G)
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
-					false);
+					false, false);
 	if (wpa_s->setband_mask & WPA_SETBAND_2G)
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
-					false);
+					false, false);
 	if (wpa_s->setband_mask & WPA_SETBAND_6G)
 		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
-					true);
+					true, false);
 }
 
 
@@ -1375,9 +1426,9 @@
 		 * since the 6 GHz band is disabled for P2P uses. */
 		wpa_printf(MSG_DEBUG,
 			   "P2P: 6 GHz disabled - update the scan frequency list");
-		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params, false);
-		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params, false);
-		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD, &params, false);
+		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params, false, false);
+		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params, false, false);
+		wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD, &params, false, false);
 	}
 #endif /* CONFIG_P2P */
 
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index f826d91..52d2696 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -92,6 +92,7 @@
 int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
 			    enum hostapd_hw_mode band,
 			    struct wpa_driver_scan_params *params,
-			    bool is_6ghz);
+			    bool is_6ghz,
+			    bool exclude_radar);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index faec32b..e673a9c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1124,6 +1124,7 @@
 	int p2p_sd_over_ctrl_iface;
 	int p2p_in_provisioning;
 	int p2p_in_invitation;
+	int p2p_retry_limit;
 	int p2p_invite_go_freq;
 	int pending_invite_ssid_id;
 	int show_group_started;