Merge "wifi: Add info callback"
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index b158077..71baf9b 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1411,7 +1411,8 @@
 
 static int is_11b(u8 rate)
 {
-	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16
+		|| rate == 0x82 || rate == 0x84 || rate == 0x8b || rate == 0x96;
 }
 
 
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 5cc9c65..ed20fb3 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -68,6 +68,10 @@
 L_CFLAGS += -DCONFIG_NO_ROAMING
 endif
 
+ifeq ($(WIFI_UPDATE_SUPPLICANT_MAC_ADDR), enabled)
+L_CFLAGS += -DFEATURE_UPDATE_STA_MAC_ADDR
+endif
+
 # Use Android specific directory for control interface sockets
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\"
 L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\"
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index e2cae4b..6b33ee3 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2621,6 +2621,8 @@
 					   data->assoc_info.resp_ies_len,
 					   &resp_elems, 0) != ParseFailed) {
 			wpa_s->connection_set = 1;
+			wpa_s->connection_11b_only = supp_rates_11b_only(&req_elems) ||
+				supp_rates_11b_only(&resp_elems);
 			wpa_s->connection_ht = req_elems.ht_capabilities &&
 				resp_elems.ht_capabilities;
 			/* Do not include subset of VHT on 2.4 GHz vendor
@@ -4365,8 +4367,8 @@
 			data->assoc_reject.timeout_reason ?
 			data->assoc_reject.timeout_reason : "");
 	wpa_s->assoc_status_code = data->assoc_reject.status_code;
-	wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
-	wpas_notify_assoc_status_code(wpa_s);
+	wpas_notify_assoc_status_code(wpa_s,
+				      bssid, data->assoc_reject.timed_out);
 
 #ifdef CONFIG_OWE
 	if (data->assoc_reject.status_code ==
diff --git a/wpa_supplicant/hidl/1.4/hidl.cpp b/wpa_supplicant/hidl/1.4/hidl.cpp
index 6788efe..c664e15 100644
--- a/wpa_supplicant/hidl/1.4/hidl.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl.cpp
@@ -282,7 +282,8 @@
 	hidl_manager->notifyDisconnectReason(wpa_s);
 }
 
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s)
+void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
+    const u8 *bssid, u8 timed_out)
 {
 	if (!wpa_s)
 		return;
@@ -295,7 +296,7 @@
 	if (!hidl_manager)
 		return;
 
-	hidl_manager->notifyAssocReject(wpa_s);
+	hidl_manager->notifyAssocReject(wpa_s, bssid, timed_out);
 }
 
 void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
diff --git a/wpa_supplicant/hidl/1.4/hidl.h b/wpa_supplicant/hidl/1.4/hidl.h
index 304a4d6..bf03bf9 100644
--- a/wpa_supplicant/hidl/1.4/hidl.h
+++ b/wpa_supplicant/hidl/1.4/hidl.h
@@ -50,7 +50,8 @@
 	    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
 	    const char *url);
 	void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
-	void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
+	void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
+	    const u8 *bssid, u8 timed_out);
 	void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
 	void wpas_hidl_notify_wps_event_fail(
@@ -164,7 +165,8 @@
     struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
 {}
 static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
+    const u8 *bssid, u8 timed_out) {}
 static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
 static void wpas_hidl_notify_wps_event_fail(
     struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.cpp b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
index 0548be9..5e74f48 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
@@ -969,8 +969,12 @@
  *
  * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
  * the network is present.
+ * @param bssid bssid of AP that rejected the association.
+ * @param timed_out flag to indicate failure is due to timeout
+ * (auth, assoc, ...) rather than explicit rejection response from the AP.
  */
-void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s)
+void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s,
+    const u8 *bssid, u8 timed_out)
 {
 	if (!wpa_s)
 		return;
@@ -979,19 +983,13 @@
 	    sta_iface_object_map_.end())
 		return;
 
-	const u8 *bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid)) {
-		bssid = wpa_s->pending_bssid;
-	}
-
 	callWithEachStaIfaceCallback(
 	    wpa_s->ifname,
 	    std::bind(
 		&ISupplicantStaIfaceCallback::onAssociationRejected,
 		std::placeholders::_1, bssid,
 		static_cast<ISupplicantStaIfaceCallback::StatusCode>(
-		    wpa_s->assoc_status_code),
-		wpa_s->assoc_timed_out == 1));
+		    wpa_s->assoc_status_code), timed_out == 1));
 }
 
 void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
@@ -1238,9 +1236,8 @@
 		return;
 
 	// For group notifications, need to use the parent iface for callbacks.
-	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
+	struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+	if (!wpa_s)
 		return;
 
 	uint32_t hidl_freq = wpa_group_s->current_bss
@@ -1281,9 +1278,8 @@
 		return;
 
 	// For group notifications, need to use the parent iface for callbacks.
-	struct wpa_supplicant *wpa_s = wpa_group_s->parent;
-	if (p2p_iface_object_map_.find(wpa_s->ifname) ==
-	    p2p_iface_object_map_.end())
+	struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+	if (!wpa_s)
 		return;
 
 	bool hidl_is_go = (std::string(role) == "GO");
@@ -1388,15 +1384,15 @@
 }
 
 void HidlManager::notifyApStaAuthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+    struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr)
 {
-	if (!wpa_s || !wpa_s->parent || !sta)
+	if (!wpa_group_s || !wpa_group_s->parent || !sta)
 		return;
-	if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
-	    p2p_iface_object_map_.end())
+	wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+	if (!wpa_s)
 		return;
 	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname,
+	    wpa_s->ifname,
 	    std::bind(
 		&ISupplicantP2pIfaceCallback::onStaAuthorized,
 		std::placeholders::_1, sta,
@@ -1404,16 +1400,16 @@
 }
 
 void HidlManager::notifyApStaDeauthorized(
-    struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+    struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr)
 {
-	if (!wpa_s || !wpa_s->parent || !sta)
+	if (!wpa_group_s || !wpa_group_s->parent || !sta)
 		return;
-	if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
-	    p2p_iface_object_map_.end())
+	wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s);
+	if (!wpa_s)
 		return;
 
 	callWithEachP2pIfaceCallback(
-	    wpa_s->parent->ifname,
+	    wpa_s->ifname,
 	    std::bind(
 		&ISupplicantP2pIfaceCallback::onStaDeauthorized,
 		std::placeholders::_1, sta,
@@ -1978,6 +1974,35 @@
 }
 
 /**
+ * Finds the correct |wpa_supplicant| object for P2P notifications
+ *
+ * @param wpa_s the |wpa_supplicant| that triggered the P2P event.
+ * @return appropriate |wpa_supplicant| object or NULL if not found.
+ */
+struct wpa_supplicant *HidlManager::getTargetP2pIfaceForGroup(
+	    struct wpa_supplicant *wpa_group_s)
+{
+	if (!wpa_group_s || !wpa_group_s->parent)
+		return NULL;
+
+	struct wpa_supplicant *target_wpa_s = wpa_group_s->parent;
+	if (p2p_iface_object_map_.find(target_wpa_s->ifname) !=
+	    p2p_iface_object_map_.end())
+		return target_wpa_s;
+
+	// try P2P device if available
+	if (!target_wpa_s->p2pdev || !target_wpa_s->p2pdev->p2p_mgmt)
+		return NULL;
+
+	target_wpa_s = target_wpa_s->p2pdev;
+	if (p2p_iface_object_map_.find(target_wpa_s->ifname) !=
+	    p2p_iface_object_map_.end())
+		return target_wpa_s;
+
+	return NULL;
+}
+
+/**
  * Removes the provided |ISupplicantCallback| hidl object reference
  * from our global callback list.
  *
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.h b/wpa_supplicant/hidl/1.4/hidl_manager.h
index 98e51d6..e024427 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.h
@@ -83,7 +83,8 @@
 	    struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
 	    const char *url);
 	void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
-	void notifyAssocReject(struct wpa_supplicant *wpa_s);
+	void notifyAssocReject(struct wpa_supplicant *wpa_s,
+	    const u8 *bssid, u8 timed_out);
 	void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
 	void notifyBssidChanged(struct wpa_supplicant *wpa_s);
 	void notifyWpsEventFail(
@@ -184,6 +185,8 @@
 	HidlManager(const HidlManager &) = default;
 	HidlManager &operator=(const HidlManager &) = default;
 
+	struct wpa_supplicant *getTargetP2pIfaceForGroup(
+	    struct wpa_supplicant *wpa_s);
 	void removeSupplicantCallbackHidlObject(
 	    const android::sp<ISupplicantCallback> &callback);
 	void removeP2pIfaceCallbackHidlObject(
diff --git a/wpa_supplicant/hidl/1.4/p2p_iface.cpp b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
index ece1c04..8f4416c 100644
--- a/wpa_supplicant/hidl/1.4/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
@@ -1083,8 +1083,9 @@
 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
 	const char* pin =
 	    pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
+	bool auto_join = !join_existing_group;
 	int new_pin = wpas_p2p_connect(
-	    wpa_s, peer_address.data(), pin, wps_method, persistent, false,
+	    wpa_s, peer_address.data(), pin, wps_method, persistent, auto_join,
 	    join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
 	    vht, CHANWIDTH_USE_HT, he, 0, nullptr, 0);
 	if (new_pin < 0) {
diff --git a/wpa_supplicant/hidl/1.4/sta_iface.cpp b/wpa_supplicant/hidl/1.4/sta_iface.cpp
index b47c5fa..7f476b1 100644
--- a/wpa_supplicant/hidl/1.4/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_iface.cpp
@@ -35,9 +35,10 @@
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
 using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
 using android::hardware::wifi::supplicant::V1_3::WifiTechnology;
+using android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using android::hardware::wifi::supplicant::V1_4::LegacyMode;
 using android::hardware::wifi::supplicant::V1_4::implementation::HidlManager;
 
 constexpr uint32_t kMaxAnqpElems = 100;
@@ -765,6 +766,14 @@
 	    &StaIface::getConnectionCapabilitiesInternal, _hidl_cb);
 }
 
+Return<void> StaIface::getConnectionCapabilities_1_4(
+    getConnectionCapabilities_1_4_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_UNKNOWN,
+	    &StaIface::getConnectionCapabilitiesInternal_1_4, _hidl_cb);
+}
+
 SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
 {
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
@@ -1421,49 +1430,64 @@
 #endif
 }
 
-std::pair<SupplicantStatus, ConnectionCapabilities>
+std::pair<SupplicantStatus, android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities>
 StaIface::getConnectionCapabilitiesInternal()
 {
+  struct android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities capa;
+	return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, capa};
+}
+
+std::pair<SupplicantStatus, ConnectionCapabilities>
+StaIface::getConnectionCapabilitiesInternal_1_4()
+{
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	struct ConnectionCapabilities capa;
 
 	if (wpa_s->connection_set) {
+		capa.legacyMode = LegacyMode::UNKNOWN;
 		if (wpa_s->connection_he) {
-			capa.technology = WifiTechnology::HE;
+			capa.V1_3.technology = WifiTechnology::HE;
 		} else if (wpa_s->connection_vht) {
-			capa.technology = WifiTechnology::VHT;
+			capa.V1_3.technology = WifiTechnology::VHT;
 		} else if (wpa_s->connection_ht) {
-			capa.technology = WifiTechnology::HT;
+			capa.V1_3.technology = WifiTechnology::HT;
 		} else {
-			capa.technology = WifiTechnology::LEGACY;
+			capa.V1_3.technology = WifiTechnology::LEGACY;
+			if (wpas_freq_to_band(wpa_s->assoc_freq) == BAND_2_4_GHZ) {
+				capa.legacyMode = (wpa_s->connection_11b_only) ? LegacyMode::B_MODE
+						: LegacyMode::G_MODE; 
+			} else {
+				capa.legacyMode = LegacyMode::A_MODE;
+			}
 		}
 		switch (wpa_s->connection_channel_bandwidth) {
 		case CHAN_WIDTH_20:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
 			break;
 		case CHAN_WIDTH_40:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
 			break;
 		case CHAN_WIDTH_80:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
 			break;
 		case CHAN_WIDTH_160:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
 			break;
 		case CHAN_WIDTH_80P80:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
 			break;
 		default:
-			capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+			capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
 			break;
 		}
-		capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
-		capa.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
+		capa.V1_3.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
+		capa.V1_3.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
 	} else {
-		capa.technology = WifiTechnology::UNKNOWN;
-		capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
-		capa.maxNumberTxSpatialStreams = 1;
-		capa.maxNumberRxSpatialStreams = 1;
+		capa.V1_3.technology = WifiTechnology::UNKNOWN;
+		capa.V1_3.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+		capa.V1_3.maxNumberTxSpatialStreams = 1;
+		capa.V1_3.maxNumberRxSpatialStreams = 1;
+		capa.legacyMode = LegacyMode::UNKNOWN;
 	}
 	return {{SupplicantStatusCode::SUCCESS, ""}, capa};
 }
diff --git a/wpa_supplicant/hidl/1.4/sta_iface.h b/wpa_supplicant/hidl/1.4/sta_iface.h
index 8338459..1b8584d 100644
--- a/wpa_supplicant/hidl/1.4/sta_iface.h
+++ b/wpa_supplicant/hidl/1.4/sta_iface.h
@@ -15,7 +15,7 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
 
@@ -44,7 +44,7 @@
  * object is used for control operations on a specific interface
  * controlled by wpa_supplicant.
  */
-class StaIface : public V1_3::ISupplicantStaIface
+class StaIface : public V1_4::ISupplicantStaIface
 {
 public:
 	StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -189,6 +189,8 @@
 	Return<void> stopDppInitiator(stopDppInitiator_cb _hidl_cb) override;
 	Return<void> getConnectionCapabilities(
 	    getConnectionCapabilities_cb _hidl_cb) override;
+	Return<void> getConnectionCapabilities_1_4(
+	    getConnectionCapabilities_1_4_cb _hidl_cb) override;
 	Return<void> getWpaDriverCapabilities(
 	    getWpaDriverCapabilities_cb _hidl_cb) override;
 	Return<void> setMboCellularDataStatus(bool available,
@@ -283,6 +285,8 @@
 			uint32_t own_bootstrap_id);
 	SupplicantStatus stopDppInitiatorInternal();
 	std::pair<SupplicantStatus, V1_3::ConnectionCapabilities> getConnectionCapabilitiesInternal();
+	std::pair<SupplicantStatus, V1_4::ConnectionCapabilities>
+			getConnectionCapabilitiesInternal_1_4();
 	std::pair<SupplicantStatus, uint32_t> getWpaDriverCapabilitiesInternal();
 	SupplicantStatus setMboCellularDataStatusInternal(bool available);
 	std::pair<SupplicantStatus, uint32_t> getKeyMgmtCapabilitiesInternal_1_3();
diff --git a/wpa_supplicant/hidl/1.4/sta_network.cpp b/wpa_supplicant/hidl/1.4/sta_network.cpp
index fa4edc1..d5c7f87 100644
--- a/wpa_supplicant/hidl/1.4/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_network.cpp
@@ -1863,6 +1863,11 @@
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	wpa_s->scan_min_time.sec = 0;
 	wpa_s->scan_min_time.usec = 0;
+#ifdef FEATURE_UPDATE_STA_MAC_ADDR
+	// Make sure that the supplicant is updated to the latest
+	// MAC address, which might have changed due to MAC randomization.
+	wpa_supplicant_update_mac_addr(wpa_s);
+#endif
 	wpa_supplicant_select_network(wpa_s, wpa_ssid);
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 56eb62a..16e747f 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -148,14 +148,15 @@
 }
 
 
-void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid, u8 timed_out)
 {
 	if (wpa_s->p2p_mgmt)
 		return;
 
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
 
-	wpas_hidl_notify_assoc_reject(wpa_s);
+	wpas_hidl_notify_assoc_reject(wpa_s, bssid, timed_out);
 }
 
 void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s) {
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index e9e39ee..0e7991b 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -28,7 +28,8 @@
 			       enum wpa_states old_state);
 void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
-void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
+void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid, u8 timed_out);
 void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
 void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index b0bea61..2d33810 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -4925,6 +4925,15 @@
 				       MAC2STR(wpa_s->pending_join_dev_addr));
 			return;
 		}
+		if (wpa_s->p2p_fallback_to_go_neg) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Join operating "
+				"failed - fall back to GO Negotiation");
+			wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
+				       P2P_EVENT_FALLBACK_TO_GO_NEG
+				       "reason=join-failed");
+			wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+			return;
+		}
 		wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
 			       P2P_EVENT_GROUP_FORMATION_FAILURE);
 		wpas_notify_p2p_group_formation_failure(wpa_s, "");
@@ -9383,6 +9392,12 @@
 	/* Stop the AP functionality */
 	/* TODO: Should do this in a way that does not indicated to possible
 	 * P2P Clients in the group that the group is terminated. */
+	/* If this action occurs before a group is started, the callback should be
+	 * preserved, or GROUP-STARTED event would be lost. If this action occurs after
+	 * a group is started, these poiners are all NULL and harmless. */
+	void (*ap_configured_cb)(void *ctx, void *data) = wpa_s->ap_configured_cb;
+	void *ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;;
+	void *ap_configured_cb_data = wpa_s->ap_configured_cb_data;
 	wpa_supplicant_ap_deinit(wpa_s);
 
 	/* Reselect the GO frequency */
@@ -9406,6 +9421,9 @@
 		return;
 	}
 
+	wpa_s->ap_configured_cb = ap_configured_cb;
+	wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
+	wpa_s->ap_configured_cb_data = ap_configured_cb_data;
 	/* Update the frequency */
 	current_ssid->frequency = params.freq;
 	wpa_s->connect_without_scan = current_ssid;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9a9ed8d..7c792b3 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -779,6 +779,7 @@
 	unsigned int connection_max_nss_tx:4;
 	unsigned int connection_channel_bandwidth:5;
 	unsigned int disable_mbo_oce:1;
+	unsigned int connection_11b_only:1;
 
 	struct os_reltime last_mac_addr_change;
 	int last_mac_addr_style;
@@ -1064,8 +1065,6 @@
 
 	/* WLAN_STATUS_* status codes from (Re)Association Response frame. */
 	u16 assoc_status_code;
-	/* Indicates if the previous association request timed out. */
-	u8 assoc_timed_out;
 
 	struct ext_password_data *ext_pw;