[automerger skipped] Merge ab/6749736 in stage. am: 3ff082d40b -s ours am: 243eb46396 -s ours am: 465d05a71c -s ours

am skip reason: Change-Id I97316678d08ab460eccd8bf54fa6642f2c6b4fee with SHA-1 20da6d1e43 is in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/external/wpa_supplicant_8/+/12804412

Change-Id: I4e697007341e4afdbc1c27ff15a5b9bbe1373e6f
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index f2b15d3..58b0d16 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1153,6 +1153,7 @@
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.1
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.2
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.3
 LOCAL_SHARED_LIBRARIES += libbase libhidlbase libutils
 LOCAL_STATIC_LIBRARIES += libhostapd_hidl
 endif
@@ -1195,7 +1196,7 @@
 LOCAL_CPPFLAGS := $(L_CPPFLAGS)
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.2
+HIDL_INTERFACE_VERSION = 1.3
 LOCAL_SRC_FILES := \
     hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
     hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
@@ -1203,6 +1204,7 @@
     android.hardware.wifi.hostapd@1.0 \
     android.hardware.wifi.hostapd@1.1 \
     android.hardware.wifi.hostapd@1.2 \
+    android.hardware.wifi.hostapd@1.3 \
     libbase \
     libhidlbase \
     libutils \
diff --git a/hostapd/android.config b/hostapd/android.config
index cd54efc..bf21fc6 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -25,9 +25,13 @@
 #LIBS += -L$(LIBNL)/lib
 CONFIG_LIBNL20=y
 
+# BCM vendor extensions to nl80211
+ifeq ($(BOARD_WLAN_DEVICE),bcmdhd)
+CONFIG_DRIVER_NL80211_BRCM=y
+else
 # QCA vendor extensions to nl80211
 CONFIG_DRIVER_NL80211_QCA=y
-
+endif
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -231,3 +235,7 @@
 # be completely removed in a future release.
 CONFIG_WEP=y
 
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+CONFIG_INTERWORKING=y
diff --git a/hostapd/android.hardware.wifi.hostapd.xml b/hostapd/android.hardware.wifi.hostapd.xml
index 4dc1701..c688d3e 100644
--- a/hostapd/android.hardware.wifi.hostapd.xml
+++ b/hostapd/android.hardware.wifi.hostapd.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.wifi.hostapd</name>
         <transport>hwbinder</transport>
-        <version>1.2</version>
+        <version>1.3</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
diff --git a/hostapd/hidl/1.2/hidl.cpp b/hostapd/hidl/1.3/hidl.cpp
similarity index 93%
rename from hostapd/hidl/1.2/hidl.cpp
rename to hostapd/hidl/1.3/hidl.cpp
index 4bde312..68e4d86 100644
--- a/hostapd/hidl/1.2/hidl.cpp
+++ b/hostapd/hidl/1.3/hidl.cpp
@@ -22,8 +22,8 @@
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_2::IHostapd;
-using android::hardware::wifi::hostapd::V1_2::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_3::IHostapd;
+using android::hardware::wifi::hostapd::V1_3::implementation::Hostapd;
 
 // This file is a bridge between the hostapd code written in 'C' and the HIDL
 // interface in C++. So, using "C" style static globals here!
diff --git a/hostapd/hidl/1.2/hidl.h b/hostapd/hidl/1.3/hidl.h
similarity index 100%
rename from hostapd/hidl/1.2/hidl.h
rename to hostapd/hidl/1.3/hidl.h
diff --git a/hostapd/hidl/1.2/hidl_return_util.h b/hostapd/hidl/1.3/hidl_return_util.h
similarity index 96%
rename from hostapd/hidl/1.2/hidl_return_util.h
rename to hostapd/hidl/1.3/hidl_return_util.h
index 81742f8..6d50348 100644
--- a/hostapd/hidl/1.2/hidl_return_util.h
+++ b/hostapd/hidl/1.3/hidl_return_util.h
@@ -16,7 +16,7 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_return_util {
 
@@ -35,7 +35,7 @@
 }
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.2/hostapd.cpp b/hostapd/hidl/1.3/hostapd.cpp
similarity index 71%
rename from hostapd/hidl/1.2/hostapd.cpp
rename to hostapd/hidl/1.3/hostapd.cpp
index 7789ed6..b68ddc7 100644
--- a/hostapd/hidl/1.2/hostapd.cpp
+++ b/hostapd/hidl/1.3/hostapd.cpp
@@ -19,6 +19,7 @@
 
 extern "C"
 {
+#include "common/wpa_ctrl.h"
 #include "utils/eloop.h"
 }
 
@@ -33,7 +34,9 @@
 using android::base::RemoveFileIfExists;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_2::IHostapd;
+using android::hardware::wifi::hostapd::V1_3::IHostapd;
+using android::hardware::wifi::hostapd::V1_3::Generation;
+using android::hardware::wifi::hostapd::V1_3::Bandwidth;
 
 std::string WriteHostapdConfig(
     const std::string& interface_name, const std::string& config)
@@ -218,11 +221,11 @@
     const IHostapd::IfaceParams& iface_params,
     const IHostapd::NetworkParams& nw_params)
 {
-	if (nw_params.V1_0.ssid.size() >
+	if (nw_params.V1_2.V1_0.ssid.size() >
 	    static_cast<uint32_t>(
 		IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
 		wpa_printf(
-		    MSG_ERROR, "Invalid SSID size: %zu", nw_params.V1_0.ssid.size());
+		    MSG_ERROR, "Invalid SSID size: %zu", nw_params.V1_2.V1_0.ssid.size());
 		return "";
 	}
 
@@ -230,20 +233,20 @@
 	std::stringstream ss;
 	ss << std::hex;
 	ss << std::setfill('0');
-	for (uint8_t b : nw_params.V1_0.ssid) {
+	for (uint8_t b : nw_params.V1_2.V1_0.ssid) {
 		ss << std::setw(2) << static_cast<unsigned int>(b);
 	}
 	const std::string ssid_as_string = ss.str();
 
 	// Encryption config string
 	std::string encryption_config_as_string;
-	switch (nw_params.encryptionType) {
+	switch (nw_params.V1_2.encryptionType) {
 	case IHostapd::EncryptionType::NONE:
 		// no security params
 		break;
 	case IHostapd::EncryptionType::WPA:
 		if (!validatePassphrase(
-		    nw_params.passphrase.size(),
+		    nw_params.V1_2.passphrase.size(),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
 				WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
@@ -254,11 +257,11 @@
 		    "wpa=3\n"
 		    "wpa_pairwise=TKIP CCMP\n"
 		    "wpa_passphrase=%s",
-		    nw_params.passphrase.c_str());
+		    nw_params.V1_2.passphrase.c_str());
 		break;
 	case IHostapd::EncryptionType::WPA2:
 		if (!validatePassphrase(
-		    nw_params.passphrase.size(),
+		    nw_params.V1_2.passphrase.size(),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
 				WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
@@ -269,11 +272,11 @@
 		    "wpa=2\n"
 		    "rsn_pairwise=CCMP\n"
 		    "wpa_passphrase=%s",
-		    nw_params.passphrase.c_str());
+		    nw_params.V1_2.passphrase.c_str());
 		break;
 	case IHostapd::EncryptionType::WPA3_SAE_TRANSITION:
 		if (!validatePassphrase(
-		    nw_params.passphrase.size(),
+		    nw_params.V1_2.passphrase.size(),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
 				WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
 		    static_cast<uint32_t>(IHostapd::ParamSizeLimits::
@@ -288,11 +291,11 @@
 		    "sae_require_mfp=1\n"
 		    "wpa_passphrase=%s\n"
 		    "sae_password=%s",
-		    nw_params.passphrase.c_str(),
-		    nw_params.passphrase.c_str());
+		    nw_params.V1_2.passphrase.c_str(),
+		    nw_params.V1_2.passphrase.c_str());
 		break;
 	case IHostapd::EncryptionType::WPA3_SAE:
-		if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) {
+		if (!validatePassphrase(nw_params.V1_2.passphrase.size(), 1, -1)) {
 			return "";
 		}
 		encryption_config_as_string = StringPrintf(
@@ -302,7 +305,7 @@
 		    "ieee80211w=2\n"
 		    "sae_require_mfp=2\n"
 		    "sae_password=%s",
-		    nw_params.passphrase.c_str());
+		    nw_params.V1_2.passphrase.c_str());
 		break;
 	default:
 		wpa_printf(MSG_ERROR, "Unknown encryption type");
@@ -396,6 +399,18 @@
 	}
 #endif /* CONFIG_IEEE80211AX */
 
+#ifdef CONFIG_INTERWORKING
+	std::string access_network_params_as_string;
+	if (nw_params.isMetered) {
+		access_network_params_as_string = StringPrintf(
+		    "interworking=1\n"
+		    "access_network_type=2\n"); // CHARGEABLE_PUBLIC_NETWORK
+	} else {
+	    access_network_params_as_string = StringPrintf(
+		    "interworking=0\n");
+	}
+#endif /* CONFIG_INTERWORKING */
+
 	return StringPrintf(
 	    "interface=%s\n"
 	    "driver=nl80211\n"
@@ -412,6 +427,9 @@
 	    "%s\n"
 	    "ignore_broadcast_ssid=%d\n"
 	    "wowlan_triggers=any\n"
+#ifdef CONFIG_INTERWORKING
+	    "%s\n"
+#endif /* CONFIG_INTERWORKING */
 	    "%s\n",
 	    iface_params.V1_1.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
 	    channel_config_as_string.c_str(),
@@ -419,7 +437,56 @@
 	    iface_params.V1_1.V1_0.hwModeParams.enable80211AC ? 1 : 0,
 	    he_params_as_string.c_str(),
 	    hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
-	    nw_params.V1_0.isHidden ? 1 : 0, encryption_config_as_string.c_str());
+	    nw_params.V1_2.V1_0.isHidden ? 1 : 0,
+#ifdef CONFIG_INTERWORKING
+            access_network_params_as_string.c_str(),
+#endif /* CONFIG_INTERWORKING */
+            encryption_config_as_string.c_str());
+}
+
+Generation getGeneration(hostapd_hw_modes *current_mode)
+{
+	wpa_printf(MSG_DEBUG, "getGeneration hwmode=%d, ht_enabled=%d, vht_enabled=%d",
+		   current_mode->mode, current_mode->ht_capab != 0,
+		   current_mode->vht_capab != 0);
+	switch (current_mode->mode) {
+	case HOSTAPD_MODE_IEEE80211B:
+		return Generation::WIFI_STANDARD_LEGACY;
+	case HOSTAPD_MODE_IEEE80211G:
+		return current_mode->ht_capab == 0 ?
+		       Generation::WIFI_STANDARD_LEGACY : Generation::WIFI_STANDARD_11N;
+	case HOSTAPD_MODE_IEEE80211A:
+		return current_mode->vht_capab == 0 ?
+		       Generation::WIFI_STANDARD_11N : Generation::WIFI_STANDARD_11AC;
+        // TODO: b/162484222 miss HOSTAPD_MODE_IEEE80211AX definition.
+	default:
+		return Generation::WIFI_STANDARD_UNKNOWN;
+	}
+}
+
+Bandwidth getBandwidth(struct hostapd_config *iconf)
+{
+	wpa_printf(MSG_DEBUG, "getBandwidth %d, isHT=%d, isHT40=%d",
+		   iconf->vht_oper_chwidth, iconf->ieee80211n,
+		   iconf->secondary_channel);
+	switch (iconf->vht_oper_chwidth) {
+	case CHANWIDTH_80MHZ:
+		return Bandwidth::WIFI_BANDWIDTH_80;
+	case CHANWIDTH_80P80MHZ:
+		return Bandwidth::WIFI_BANDWIDTH_80P80;
+		break;
+	case CHANWIDTH_160MHZ:
+		return Bandwidth::WIFI_BANDWIDTH_160;
+		break;
+	case CHANWIDTH_USE_HT:
+		if (iconf->ieee80211n) {
+			return iconf->secondary_channel != 0 ?
+				Bandwidth::WIFI_BANDWIDTH_40 : Bandwidth::WIFI_BANDWIDTH_20;
+		}
+		return Bandwidth::WIFI_BANDWIDTH_20_NOHT;
+	default:
+		return Bandwidth::WIFI_BANDWIDTH_INVALID;
+	}
 }
 
 // hostapd core functions accept "C" style function pointers, so use global
@@ -440,13 +507,43 @@
 		on_setup_complete_internal_callback = nullptr;
 	}
 }
+
+// Callback to be invoked on hotspot client connection/disconnection
+std::function<void(struct hostapd_data*, const u8 *mac_addr, int authorized,
+		   const u8 *p2p_dev_addr)> on_sta_authorized_internal_callback;
+void onAsyncStaAuthorizedCb(void* ctx, const u8 *mac_addr, int authorized,
+			    const u8 *p2p_dev_addr)
+{
+	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+	if (on_sta_authorized_internal_callback) {
+		on_sta_authorized_internal_callback(iface_hapd, mac_addr,
+			authorized, p2p_dev_addr);
+	}
+}
+
+std::function<void(struct hostapd_data*, int level,
+                   enum wpa_msg_type type, const char *txt,
+                   size_t len)> on_wpa_msg_internal_callback;
+
+void onAsyncWpaEventCb(void *ctx, int level,
+                   enum wpa_msg_type type, const char *txt,
+                   size_t len)
+{
+	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+	if (on_wpa_msg_internal_callback) {
+		on_wpa_msg_internal_callback(iface_hapd, level,
+					       type, txt, len);
+	}
+}
+
+
 }  // namespace
 
 namespace android {
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::call;
 using namespace android::hardware::wifi::hostapd::V1_0;
@@ -473,7 +570,8 @@
 }
 
 Return<void> Hostapd::addAccessPoint_1_2(
-    const IfaceParams& iface_params, const NetworkParams& nw_params,
+    const V1_2::IHostapd::IfaceParams& iface_params,
+    const V1_2::IHostapd::NetworkParams& nw_params,
     addAccessPoint_1_2_cb _hidl_cb)
 {
 	return call(
@@ -481,6 +579,16 @@
 	    nw_params);
 }
 
+Return<void> Hostapd::addAccessPoint_1_3(
+    const V1_3::IHostapd::IfaceParams& iface_params,
+    const V1_3::IHostapd::NetworkParams& nw_params,
+    addAccessPoint_1_3_cb _hidl_cb)
+{
+        return call(
+            this, &Hostapd::addAccessPointInternal_1_3, _hidl_cb, iface_params,
+            nw_params);
+}
+
 Return<void> Hostapd::removeAccessPoint(
     const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
 {
@@ -502,6 +610,13 @@
 	    this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
 }
 
+Return<void> Hostapd::registerCallback_1_3(
+    const sp<V1_3::IHostapdCallback>& callback, registerCallback_1_3_cb _hidl_cb)
+{
+	return call(
+	    this, &Hostapd::registerCallbackInternal_1_3, _hidl_cb, callback);
+}
+
 Return<void> Hostapd::forceClientDisconnect(
     const hidl_string& iface_name, const hidl_array<uint8_t, 6>& client_address,
     V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb)
@@ -512,7 +627,7 @@
 }
 
 Return<void> Hostapd::setDebugParams(
-    DebugLevel level, setDebugParams_cb _hidl_cb)
+     V1_2::DebugLevel level, setDebugParams_cb _hidl_cb)
 {
 	return call(
 	    this, &Hostapd::setDebugParamsInternal, _hidl_cb, level);
@@ -532,25 +647,32 @@
 	return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
 }
 
-HostapdStatus Hostapd::addAccessPointInternal_1_2(
-    const IfaceParams& iface_params, const NetworkParams& nw_params)
+V1_2::HostapdStatus Hostapd::addAccessPointInternal_1_2(
+    const V1_2::IHostapd::IfaceParams& iface_params,
+    const V1_2::IHostapd::NetworkParams& nw_params) {
+	return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addAccessPointInternal_1_3(
+    const V1_2::IHostapd::IfaceParams& iface_params,
+    const V1_3::IHostapd::NetworkParams& nw_params)
 {
 	if (hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str())) {
 		wpa_printf(
 		    MSG_ERROR, "Interface %s already present",
 		    iface_params.V1_1.V1_0.ifaceName.c_str());
-		return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
+		return {V1_2::HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
 	}
 	const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
 	if (conf_params.empty()) {
 		wpa_printf(MSG_ERROR, "Failed to create config params");
-		return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
+		return {V1_2::HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
 	}
 	const auto conf_file_path =
 	    WriteHostapdConfig(iface_params.V1_1.V1_0.ifaceName, conf_params);
 	if (conf_file_path.empty()) {
 		wpa_printf(MSG_ERROR, "Failed to write config file");
-		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+		return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	std::string add_iface_param_str = StringPrintf(
 	    "%s config=%s", iface_params.V1_1.V1_0.ifaceName.c_str(),
@@ -561,7 +683,7 @@
 		wpa_printf(
 		    MSG_ERROR, "Adding interface %s failed",
 		    add_iface_param_str.c_str());
-		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+		return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
 	struct hostapd_data* iface_hapd =
 	    hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str());
@@ -581,15 +703,55 @@
 			    }
 		    }
 	    };
+
+	// Rgegister for new client connect/disconnect indication.
+	on_sta_authorized_internal_callback =
+	    [this](struct hostapd_data* iface_hapd, const u8 *mac_addr,
+		   int authorized, const u8 *p2p_dev_addr) {
+		wpa_printf(MSG_DEBUG, "notify client " MACSTR " %s",
+			   MAC2STR(mac_addr),
+			   (authorized) ? "Connected" : "Disconnected");
+
+		for (const auto &callback : callbacks_) {
+		    // TODO: The iface need to separate to iface and ap instance
+		    // identify for AP+AP case.
+		    callback->onConnectedClientsChanged(iface_hapd->conf->iface,
+			    iface_hapd->conf->iface, mac_addr, authorized);
+		}
+	    };
+
+	// Register for wpa_event which used to get channel switch event
+	on_wpa_msg_internal_callback =
+	    [this](struct hostapd_data* iface_hapd, int level,
+		   enum wpa_msg_type type, const char *txt,
+		   size_t len) {
+		wpa_printf(MSG_DEBUG, "Receive wpa msg : %s", txt);
+		if (os_strncmp(txt, WPA_EVENT_CHANNEL_SWITCH,
+			       strlen(WPA_EVENT_CHANNEL_SWITCH)) == 0) {
+		    for (const auto &callback : callbacks_) {
+			callback->onApInstanceInfoChanged(
+				iface_hapd->conf->iface, iface_hapd->conf->iface,
+				iface_hapd->iface->freq, getBandwidth(iface_hapd->iconf),
+				getGeneration(iface_hapd->iface->current_mode),
+				iface_hapd->own_addr);
+		    }
+		}
+	    };
+
+	// Setup callback
 	iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
 	iface_hapd->setup_complete_cb_ctx = iface_hapd;
+	iface_hapd->sta_authorized_cb = onAsyncStaAuthorizedCb;
+	iface_hapd->sta_authorized_cb_ctx = iface_hapd;
+	wpa_msg_register_cb(onAsyncWpaEventCb);
+
 	if (hostapd_enable_iface(iface_hapd->iface) < 0) {
 		wpa_printf(
 		    MSG_ERROR, "Enabling interface %s failed",
 		    iface_params.V1_1.V1_0.ifaceName.c_str());
-		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+		return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
 	}
-	return {HostapdStatusCode::SUCCESS, ""};
+	return {V1_2::HostapdStatusCode::SUCCESS, ""};
 }
 
 V1_0::HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
@@ -609,8 +771,14 @@
 V1_0::HostapdStatus Hostapd::registerCallbackInternal(
     const sp<V1_1::IHostapdCallback>& callback)
 {
+	return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::registerCallbackInternal_1_3(
+    const sp<V1_3::IHostapdCallback>& callback)
+{
 	callbacks_.push_back(callback);
-	return {V1_0::HostapdStatusCode::SUCCESS, ""};
+	return {V1_2::HostapdStatusCode::SUCCESS, ""};
 }
 
 V1_2::HostapdStatus Hostapd::forceClientDisconnectInternal(const std::string& iface_name,
@@ -635,14 +803,14 @@
 	return {V1_2::HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, ""};
 }
 
-V1_2::HostapdStatus Hostapd::setDebugParamsInternal(DebugLevel level)
+V1_2::HostapdStatus Hostapd::setDebugParamsInternal(V1_2::DebugLevel level)
 {
 	wpa_debug_level = static_cast<uint32_t>(level);
 	return {V1_2::HostapdStatusCode::SUCCESS, ""};
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.2/hostapd.h b/hostapd/hidl/1.3/hostapd.h
similarity index 74%
rename from hostapd/hidl/1.2/hostapd.h
rename to hostapd/hidl/1.3/hostapd.h
index ca6c32e..059e24a 100644
--- a/hostapd/hidl/1.2/hostapd.h
+++ b/hostapd/hidl/1.3/hostapd.h
@@ -14,8 +14,8 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
-#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapdCallback.h>
 
 extern "C"
 {
@@ -30,7 +30,7 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::hostapd::V1_0;
 
@@ -39,7 +39,7 @@
  * object is used core for global control operations on
  * hostapd.
  */
-class Hostapd : public V1_2::IHostapd
+class Hostapd : public V1_3::IHostapd
 {
 public:
 	Hostapd(hapd_interfaces* interfaces);
@@ -53,8 +53,13 @@
 	    const V1_1::IHostapd::IfaceParams& iface_params,
 	    const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
 	Return<void> addAccessPoint_1_2(
-	    const V1_2::IHostapd::IfaceParams& iface_params, const NetworkParams& nw_params,
+	    const V1_2::IHostapd::IfaceParams& iface_params,
+	    const V1_2::IHostapd::NetworkParams& nw_params,
 	    addAccessPoint_1_2_cb _hidl_cb) override;
+	Return<void> addAccessPoint_1_3(
+	    const V1_2::IHostapd::IfaceParams& iface_params,
+	    const V1_3::IHostapd::NetworkParams& nw_params,
+	    addAccessPoint_1_3_cb _hidl_cb) override;
 	Return<void> removeAccessPoint(
 	    const hidl_string& iface_name,
 	    removeAccessPoint_cb _hidl_cb) override;
@@ -62,12 +67,15 @@
 	Return<void> registerCallback(
 	    const sp<V1_1::IHostapdCallback>& callback,
 	    registerCallback_cb _hidl_cb) override;
+	Return<void> registerCallback_1_3(
+	    const sp<V1_3::IHostapdCallback>& callback,
+	    registerCallback_1_3_cb _hidl_cb) override;
 	Return<void>forceClientDisconnect(
 	    const hidl_string& iface_name,
 	    const hidl_array<uint8_t, 6>& client_address,
 	    V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb) override;
 	Return<void> setDebugParams(
-	    DebugLevel level, setDebugParams_cb _hidl_cb) override;
+	    V1_2::DebugLevel level, setDebugParams_cb _hidl_cb) override;
 private:
 	// Corresponding worker functions for the HIDL methods.
 	V1_0::HostapdStatus addAccessPointInternal(
@@ -79,22 +87,27 @@
 	V1_2::HostapdStatus addAccessPointInternal_1_2(
 	    const V1_2::IHostapd::IfaceParams& IfaceParams,
 	    const V1_2::IHostapd::NetworkParams& nw_params);
+	V1_2::HostapdStatus addAccessPointInternal_1_3(
+	    const V1_2::IHostapd::IfaceParams& IfaceParams,
+	    const V1_3::IHostapd::NetworkParams& nw_params);
 	V1_0::HostapdStatus removeAccessPointInternal(const std::string& iface_name);
 	V1_0::HostapdStatus registerCallbackInternal(
 	    const sp<V1_1::IHostapdCallback>& callback);
+	V1_2::HostapdStatus registerCallbackInternal_1_3(
+	    const sp<V1_3::IHostapdCallback>& callback);
 	V1_2::HostapdStatus forceClientDisconnectInternal(
 	    const std::string& iface_name,
 	    const std::array<uint8_t, 6>& client_address,
 	    V1_2::Ieee80211ReasonCode reason_code);
-	V1_2::HostapdStatus setDebugParamsInternal(DebugLevel level);
+	V1_2::HostapdStatus setDebugParamsInternal(V1_2::DebugLevel level);
 	// Raw pointer to the global structure maintained by the core.
 	struct hapd_interfaces* interfaces_;
 	// Callbacks registered.
-	std::vector<sp<V1_1::IHostapdCallback>> callbacks_;
+	std::vector<sp<V1_3::IHostapdCallback>> callbacks_;
 	DISALLOW_COPY_AND_ASSIGN(Hostapd);
 };
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index 512ca0d..7cc45bd 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -15,6 +15,7 @@
     interface android.hardware.wifi.hostapd@1.0::IHostapd default
     interface android.hardware.wifi.hostapd@1.1::IHostapd default
     interface android.hardware.wifi.hostapd@1.2::IHostapd default
+    interface android.hardware.wifi.hostapd@1.3::IHostapd default
     class main
     capabilities NET_ADMIN NET_RAW
     user wifi
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
new file mode 100644
index 0000000..cb5b348
--- /dev/null
+++ b/src/common/brcm_vendor.h
@@ -0,0 +1,65 @@
+/*
+ * Broadcom Corporation OUI and vendor specific assignments
+ * Copyright (c) 2015, Broadcom Corporation.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BRCM_VENDOR_H
+#define BRCM_VENDOR_H
+
+/*
+ * This file is a registry of identifier assignments from the Broadcom
+ * OUI 00:10:18 for purposes other than MAC address assignment. New identifiers
+ * can be assigned through normal review process for changes to the upstream
+ * hostap.git repository.
+ */
+
+#define OUI_BRCM  0x001018
+
+/**
+ * enum brcm_nl80211_vendor_subcmds - BRCM nl80211 vendor command identifiers
+ *
+ * @BRCM_VENDOR_SUBCMD_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_SUBCMD_PRIV_STR: String command/event
+ */
+enum brcm_nl80211_vendor_subcmds {
+	BRCM_VENDOR_SUBCMD_UNSPEC		= 0,
+	BRCM_VENDOR_SCMD_ACS			= 9,
+	BRCM_VENDOR_SCMD_MAX			= 10
+};
+
+/**
+ * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
+ *
+ * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
+ *
+ * @BRCM_VENDOR_EVENT_PRIV_STR: String command/event
+ */
+enum brcm_nl80211_vendor_events {
+        BRCM_VENDOR_EVENT_UNSPEC,
+	BRCM_VENDOR_EVENT_ACS			= 42,
+	BRCM_VENDOR_EVENT_LAST			= 44
+};
+
+enum wl_vendor_attr_acs_offload {
+	BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+	BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ,
+	BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ,
+	BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+	BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
+
+	BRCM_VENDOR_ATTR_ACS_HW_MODE,
+	BRCM_VENDOR_ATTR_ACS_HT_ENABLED,
+	BRCM_VENDOR_ATTR_ACS_HT40_ENABLED,
+	BRCM_VENDOR_ATTR_ACS_VHT_ENABLED,
+	BRCM_VENDOR_ATTR_ACS_CHWIDTH,
+	BRCM_VENDOR_ATTR_ACS_CH_LIST,
+	BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+
+	BRCM_VENDOR_ATTR_ACS_LAST
+};
+#endif /* BRCM_VENDOR_H */
+
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 92960e2..6859787 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1421,7 +1421,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/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 51674f0..5a760ff 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -37,7 +37,9 @@
 #include "radiotap_iter.h"
 #include "rfkill.h"
 #include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 #ifndef NETLINK_CAP_ACK
 #define NETLINK_CAP_ACK 10
@@ -1200,6 +1202,10 @@
 			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
 					     NULL);
 		}
+	} else if (ifi->ifi_flags & IFF_UP) {
+		/* Re-read MAC address as it may have changed */
+		nl80211_refresh_mac(drv, ifi->ifi_index, 1);
+		return;
 	}
 
 	/*
@@ -3033,6 +3039,98 @@
 	return num_suites;
 }
 
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static int wpa_driver_do_broadcom_acs(void *priv, struct drv_acs_params
+	*params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *data;
+	int  freq_list_len;
+	int  ret = 0;
+	do {
+		freq_list_len =
+			int_array_len(params->freq_list);
+		wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d",
+				__FUNCTION__, freq_list_len);
+		msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+		if (!msg) {
+			wpa_printf(MSG_ERROR, "%s: *errof, no memory for msg", __FUNCTION__);
+			return ret;
+		}
+		if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_ID",
+					__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+
+		if ((nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_ACS))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_SUBCMD",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if (!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, NL80211_ATTR_VENDOR_DATA", __FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HW_MODE",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED, params->ht_enabled))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT_ENABLED",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, params->ht40_enabled))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if ((nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, params->vht_enabled))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		if ((nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width))) {
+			wpa_printf(MSG_ERROR, "%s: *errof, BRCM_VENDOR_ATTR_ACS_CHWIDTH",
+				__FUNCTION__);
+			nlmsg_free(msg);
+			return ret;
+		}
+		wpa_printf(MSG_DEBUG, "%s: ht40=%d, ch_width=%d\n",
+			__FUNCTION__, params->ht40_enabled, params->ch_width);
+		if ((freq_list_len > 0)	&& (nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,
+				sizeof(int) * freq_list_len, params->freq_list))) {
+			wpa_printf(MSG_ERROR, "%s: *error, BRCM_VENDOR_ATTR_ACS_FREQ_LIST,"
+				"list_len=%d\n", __FUNCTION__, freq_list_len);
+			nlmsg_free(msg);
+			return ret;
+		}
+		nla_nest_end(msg, data);
+		wpa_printf(MSG_DEBUG, "nl80211: ACS Params: HW_MODE: %d HT: %d HT40:"
+			" %d VHT: %d BW: %d\n",
+			params->hw_mode, params->ht_enabled, params->ht40_enabled,
+			params->vht_enabled, params->ch_width);
+		ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+		if (ret) {
+			wpa_printf(MSG_ERROR, "nl80211:	Failed to invoke vendor"
+				" driver ACS function: %s\n",
+				strerror(errno));
+		}
+	} while (0);
+	return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 #ifdef CONFIG_DRIVER_NL80211_QCA
 static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
@@ -11637,6 +11735,9 @@
 	.add_sta_node = nl80211_add_sta_node,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 	.configure_data_frame_filters = nl80211_configure_data_frame_filters,
+#if defined(CONFIG_DRIVER_NL80211_BRCM)
+	.do_acs = wpa_driver_do_broadcom_acs,
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 	.get_ext_capab = nl80211_get_ext_capab,
 	.update_connect_params = nl80211_update_connection_params,
 	.send_external_auth_status = nl80211_send_external_auth_status,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 3e8dcef..435df11 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -17,7 +17,9 @@
 #include "common/qca-vendor.h"
 #include "common/qca-vendor-attr.h"
 #include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
 {
@@ -992,7 +994,21 @@
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 				}
 			}
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+			if (vinfo->vendor_id == OUI_BRCM) {
+				wpa_printf(MSG_MSGDUMP, "vendor:%x cmd:0x%x\n",
+						vinfo->vendor_id, vinfo->subcmd);
+				switch (vinfo->subcmd) {
+					case BRCM_VENDOR_SCMD_ACS:
+						drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+						drv->capa.flags |=
+							WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
+						break;
+					default:
+						break;
+				}
+			}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
 				   vinfo->vendor_id, vinfo->subcmd);
 		}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 6a2de1f..0454d29 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -18,7 +18,9 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "driver_nl80211.h"
-
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 
 static const char * nl80211_command_to_string(enum nl80211_commands cmd)
 {
@@ -1705,7 +1707,96 @@
 	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
 }
 
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data
+	*drv, const u8 *data, size_t len)
+{
+	struct nlattr *tb[BRCM_VENDOR_ATTR_ACS_LAST + 1];
+	union wpa_event_data event;
 
+	wpa_printf(MSG_DEBUG, "nl80211: vendor ACS channel selection vendor even received");
+
+	if (nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr*) data, len, NULL)
+		|| (!tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ])
+			|| (!tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ])) {
+			return;
+		}
+
+	os_memset(&event, 0, sizeof(event));
+	if (tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]) {
+		event.acs_selected_channels.pri_freq =
+				nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]);
+	}
+
+	wpa_printf(MSG_MSGDUMP, "got pri_freq=%d\n",
+		event.acs_selected_channels.pri_freq );
+
+	if (tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]) {
+		event.acs_selected_channels.sec_freq =
+			nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]);
+	}
+
+	wpa_printf(MSG_MSGDUMP, "got sec_freq=%d\n",
+		event.acs_selected_channels.sec_freq );
+	if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) {
+		event.acs_selected_channels.vht_seg0_center_ch =
+			nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+	}
+
+	if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) {
+		event.acs_selected_channels.vht_seg1_center_ch =
+			nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+	}
+	if (tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]) {
+		event.acs_selected_channels.ch_width =
+			nla_get_u16(tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]);
+	}
+	if (tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]) {
+		event.acs_selected_channels.hw_mode =
+		nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]);
+		if ((event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES)
+			|| (event.acs_selected_channels.hw_mode
+				== HOSTAPD_MODE_IEEE80211ANY)) {
+			wpa_printf(MSG_ERROR, "nl80211: Invalid hw_mode %d in ACS selection event",
+				event.acs_selected_channels.hw_mode);
+			return;
+		}
+	}
+
+	wpa_printf(MSG_INFO, "nl80211: ACS Results: PCH: %d SCH: %d BW: %d"
+		" VHT0: %d VHT1: %d HW_MODE: %d",
+		event.acs_selected_channels.pri_freq,
+		event.acs_selected_channels.sec_freq,
+		event.acs_selected_channels.ch_width,
+		event.acs_selected_channels.vht_seg0_center_ch,
+		event.acs_selected_channels.vht_seg1_center_ch,
+		event.acs_selected_channels.hw_mode);
+	wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED,
+		&event);
+	return;
+}
+
+static void nl80211_vendor_event_brcm( struct wpa_driver_nl80211_data *drv,
+	u32 subcmd, u8 *data, size_t len)
+{
+	union wpa_event_data event;
+        const struct nlattr *iter;
+        int rem = len;
+
+	wpa_printf(MSG_MSGDUMP, "got vendor event %d", subcmd);
+	memset(&event, 0, sizeof(event));
+	switch (subcmd) {
+	case BRCM_VENDOR_EVENT_ACS:
+		wpa_printf(MSG_DEBUG, "nl80211: Received VENDOR_EVENT_ACS");
+		brcm_nl80211_acs_select_ch(drv, data, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event %u", subcmd);
+		break;
+	}
+
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 #ifdef CONFIG_DRIVER_NL80211_QCA
 
 static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
@@ -2267,6 +2358,11 @@
 	case OUI_QCA:
 		nl80211_vendor_event_qca(drv, subcmd, data, len);
 		break;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+	case OUI_BRCM:
+	        nl80211_vendor_event_brcm(drv, subcmd, data, len);
+	        break;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
 		break;
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 55a98ef..a03d4a0 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -26,6 +26,10 @@
 CONFIG_LIBNL3_ROUTE=y
 endif
 
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
+
 ifdef CONFIG_DRIVER_MACSEC_QCA
 DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
 DRV_OBJS += ../src/drivers/driver_macsec_qca.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 5a32a24..10eab6a 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -41,6 +41,9 @@
 ifdef CONFIG_DRIVER_NL80211_QCA
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
 endif
+ifdef CONFIG_DRIVER_NL80211_BRCM
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
+endif
 NEED_SME=y
 NEED_AP_MLME=y
 NEED_NETLINK=y
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 8631775..5cc9c65 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1504,7 +1504,7 @@
 ifdef CONFIG_CTRL_IFACE_HIDL
 WPA_SUPPLICANT_USE_HIDL=y
 L_CFLAGS += -DCONFIG_HIDL -DCONFIG_CTRL_IFACE_HIDL
-HIDL_INTERFACE_VERSION := 1.3
+HIDL_INTERFACE_VERSION := 1.4
 endif
 
 ifdef CONFIG_READLINE
@@ -1757,9 +1757,10 @@
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.1
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.2
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.3
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.4
 LOCAL_SHARED_LIBRARIES += libhidlbase libutils libbase
 LOCAL_STATIC_LIBRARIES += libwpa_hidl
-LOCAL_VINTF_FRAGMENTS := hidl/$(HIDL_INTERFACE_VERSION)/manifest.xml
+LOCAL_VINTF_FRAGMENTS := hidl/$(HIDL_INTERFACE_VERSION)/android.hardware.wifi.supplicant.xml
 ifeq ($(WIFI_HIDL_UNIFIED_SUPPLICANT_SERVICE_RC_ENTRY), true)
 LOCAL_INIT_RC=hidl/$(HIDL_INTERFACE_VERSION)/android.hardware.wifi.supplicant-service.rc
 endif
@@ -1825,6 +1826,7 @@
     android.hardware.wifi.supplicant@1.1 \
     android.hardware.wifi.supplicant@1.2 \
     android.hardware.wifi.supplicant@1.3 \
+    android.hardware.wifi.supplicant@1.4 \
     libbase \
     libhidlbase \
     libutils \
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7b68ebe..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
diff --git a/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc
similarity index 90%
rename from wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc
rename to wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc
index 3cf2500..71318d4 100644
--- a/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc
+++ b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant-service.rc
@@ -9,6 +9,7 @@
     interface android.hardware.wifi.supplicant@1.1::ISupplicant default
     interface android.hardware.wifi.supplicant@1.2::ISupplicant default
     interface android.hardware.wifi.supplicant@1.3::ISupplicant default
+    interface android.hardware.wifi.supplicant@1.4::ISupplicant default
     class main
     socket wpa_wlan0 dgram 660 wifi wifi
     disabled
diff --git a/wpa_supplicant/hidl/1.3/manifest.xml b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml
similarity index 89%
rename from wpa_supplicant/hidl/1.3/manifest.xml
rename to wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml
index 33e4fd4..772096c 100644
--- a/wpa_supplicant/hidl/1.3/manifest.xml
+++ b/wpa_supplicant/hidl/1.4/android.hardware.wifi.supplicant.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.wifi.supplicant</name>
         <transport>hwbinder</transport>
-        <version>1.3</version>
+        <version>1.4</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/wpa_supplicant/hidl/1.3/hidl.cpp b/wpa_supplicant/hidl/1.4/hidl.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.3/hidl.cpp
rename to wpa_supplicant/hidl/1.4/hidl.cpp
index 310e56c..c664e15 100644
--- a/wpa_supplicant/hidl/1.3/hidl.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl.cpp
@@ -28,7 +28,7 @@
 using android::hardware::wifi::supplicant::V1_3::DppFailureCode;
 using android::hardware::wifi::supplicant::V1_3::DppProgressCode;
 using android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
-using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_4::implementation::HidlManager;
 
 static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code);
 static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code);
diff --git a/wpa_supplicant/hidl/1.3/hidl.h b/wpa_supplicant/hidl/1.4/hidl.h
similarity index 100%
rename from wpa_supplicant/hidl/1.3/hidl.h
rename to wpa_supplicant/hidl/1.4/hidl.h
diff --git a/wpa_supplicant/hidl/1.3/hidl_constants.h b/wpa_supplicant/hidl/1.4/hidl_constants.h
similarity index 100%
rename from wpa_supplicant/hidl/1.3/hidl_constants.h
rename to wpa_supplicant/hidl/1.4/hidl_constants.h
diff --git a/wpa_supplicant/hidl/1.3/hidl_i.h b/wpa_supplicant/hidl/1.4/hidl_i.h
similarity index 100%
rename from wpa_supplicant/hidl/1.3/hidl_i.h
rename to wpa_supplicant/hidl/1.4/hidl_i.h
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.cpp b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
similarity index 97%
rename from wpa_supplicant/hidl/1.3/hidl_manager.cpp
rename to wpa_supplicant/hidl/1.4/hidl_manager.cpp
index 2734e98..5e74f48 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
@@ -400,7 +400,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicantStaIfaceCallback;
 
@@ -1236,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
@@ -1279,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");
@@ -1386,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,
@@ -1402,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,
@@ -1572,7 +1570,7 @@
  * @param ifname Interface name
  * @param code Status code
  */
-void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code)
+void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, V1_3::DppSuccessCode code)
 {
 	std::string hidl_ifname = wpa_s->ifname;
 
@@ -1846,7 +1844,7 @@
  */
 int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
     const std::string &ifname, int network_id,
-    android::sp<ISupplicantStaNetwork> *network_object)
+    android::sp<V1_3::ISupplicantStaNetwork> *network_object)
 {
 	if (ifname.empty() || network_id < 0 || !network_object)
 		return 1;
@@ -1976,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.
  *
@@ -2211,7 +2238,7 @@
 	    ifname, network_id, method, sta_network_callbacks_map_);
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.h b/wpa_supplicant/hidl/1.4/hidl_manager.h
similarity index 91%
rename from wpa_supplicant/hidl/1.3/hidl_manager.h
rename to wpa_supplicant/hidl/1.4/hidl_manager.h
index b40d303..e024427 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.h
@@ -38,7 +38,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicant;
 using V1_0::ISupplicantP2pIface;
@@ -134,7 +134,7 @@
 	void notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
 			struct wpa_ssid *config);
 	void notifyDppConfigSent(struct wpa_supplicant *wpa_s);
-	void notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code);
+	void notifyDppSuccess(struct wpa_supplicant *wpa_s, V1_3::DppSuccessCode code);
 	void notifyDppFailure(struct wpa_supplicant *wpa_s,
 			android::hardware::wifi::supplicant::V1_3::DppFailureCode code);
 	void notifyDppFailure(struct wpa_supplicant *wpa_s,
@@ -163,7 +163,7 @@
 	    android::sp<ISupplicantP2pNetwork> *network_object);
 	int getStaNetworkHidlObjectByIfnameAndNetworkId(
 	    const std::string &ifname, int network_id,
-	    android::sp<ISupplicantStaNetwork> *network_object);
+	    android::sp<V1_3::ISupplicantStaNetwork> *network_object);
 	int addSupplicantCallbackHidlObject(
 	    const android::sp<ISupplicantCallback> &callback);
 	int addP2pIfaceCallbackHidlObject(
@@ -185,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(
@@ -339,51 +341,51 @@
     "Debug level value mismatch");
 
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
 	WPA_KEY_MGMT_NONE,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
 	WPA_KEY_MGMT_PSK,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
 	WPA_KEY_MGMT_IEEE8021X,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
 	WPA_KEY_MGMT_IEEE8021X_NO_WPA,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
 	WPA_KEY_MGMT_FT_IEEE8021X,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
 	WPA_KEY_MGMT_FT_PSK,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
 	WPA_KEY_MGMT_OSEN,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
 	WPA_KEY_MGMT_SAE,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
 	WPA_KEY_MGMT_IEEE8021X_SUITE_B_192,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
 	WPA_KEY_MGMT_OWE,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
 	WPA_KEY_MGMT_PSK_SHA256,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
 	WPA_KEY_MGMT_IEEE8021X_SHA256,
     "KeyMgmt value mismatch");
 static_assert(
@@ -395,15 +397,15 @@
 	WPA_KEY_MGMT_WAPI_CERT,
     "KeyMgmt value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::WPA) ==
 	WPA_PROTO_WPA,
     "Proto value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::RSN) ==
 	WPA_PROTO_RSN,
     "Proto value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::ProtoMask::OSEN) ==
 	WPA_PROTO_OSEN,
     "Proto value mismatch");
 static_assert(
@@ -411,35 +413,35 @@
 	WPA_PROTO_WAPI,
     "Proto value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
 	WPA_AUTH_ALG_OPEN,
     "AuthAlg value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
 	WPA_AUTH_ALG_SHARED,
     "AuthAlg value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
 	WPA_AUTH_ALG_LEAP,
     "AuthAlg value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
 	WPA_CIPHER_WEP40,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
 	WPA_CIPHER_WEP104,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
 	WPA_CIPHER_TKIP,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
 	WPA_CIPHER_CCMP,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
+    static_cast<uint32_t>(V1_2::ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
 	WPA_CIPHER_GCMP_256,
     "GroupCipher value mismatch");
 static_assert(
@@ -448,24 +450,24 @@
     "GroupCipher value mismatch");
 static_assert(
     static_cast<uint32_t>(
-	ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
+	V1_0::ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
 	WPA_CIPHER_GTK_NOT_USED,
     "GroupCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
 	WPA_CIPHER_NONE,
     "PairwiseCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
 	WPA_CIPHER_TKIP,
     "PairwiseCipher value mismatch");
 static_assert(
-    static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
+    static_cast<uint32_t>(V1_0::ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
 	WPA_CIPHER_CCMP,
     "PairwiseCipher value mismatch");
 static_assert(
     static_cast<uint32_t>(
-	ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
+	V1_2::ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
 	WPA_CIPHER_GCMP_256,
     "PairwiseCipher value mismatch");
 static_assert(
@@ -761,7 +763,7 @@
 	P2P_PROV_DISC_INFO_UNAVAILABLE,
     "P2P status code value mismatch");
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/hidl_return_util.h b/wpa_supplicant/hidl/1.4/hidl_return_util.h
similarity index 98%
rename from wpa_supplicant/hidl/1.3/hidl_return_util.h
rename to wpa_supplicant/hidl/1.4/hidl_return_util.h
index 4c1f919..d285164 100644
--- a/wpa_supplicant/hidl/1.3/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.4/hidl_return_util.h
@@ -14,7 +14,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_return_util {
 using V1_0::SupplicantStatusCode;
@@ -94,7 +94,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/iface_config_utils.cpp b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.3/iface_config_utils.cpp
rename to wpa_supplicant/hidl/1.4/iface_config_utils.cpp
index 31370a6..b10523a 100644
--- a/wpa_supplicant/hidl/1.3/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
@@ -81,7 +81,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_config_utils {
 SupplicantStatus setWpsDeviceName(
@@ -176,7 +176,7 @@
 }
 }  // namespace iface_config_utils
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/iface_config_utils.h b/wpa_supplicant/hidl/1.4/iface_config_utils.h
similarity index 97%
rename from wpa_supplicant/hidl/1.3/iface_config_utils.h
rename to wpa_supplicant/hidl/1.4/iface_config_utils.h
index 822d7ac..a94feb5 100644
--- a/wpa_supplicant/hidl/1.3/iface_config_utils.h
+++ b/wpa_supplicant/hidl/1.4/iface_config_utils.h
@@ -30,7 +30,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_config_utils {
 SupplicantStatus setWpsDeviceName(
@@ -51,7 +51,7 @@
     struct wpa_supplicant* wpa_s, bool useExternalSim);
 }  // namespace iface_config_utils
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/misc_utils.h b/wpa_supplicant/hidl/1.4/misc_utils.h
similarity index 98%
rename from wpa_supplicant/hidl/1.3/misc_utils.h
rename to wpa_supplicant/hidl/1.4/misc_utils.h
index b95b1ee..6e69d4c 100644
--- a/wpa_supplicant/hidl/1.3/misc_utils.h
+++ b/wpa_supplicant/hidl/1.4/misc_utils.h
@@ -27,7 +27,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace misc_utils {
 using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
@@ -103,7 +103,7 @@
 }
 }  // namespace misc_utils
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.3/p2p_iface.cpp
rename to wpa_supplicant/hidl/1.4/p2p_iface.cpp
index ffa9b6a..8f4416c 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
@@ -406,7 +406,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using V1_0::SupplicantStatusCode;
@@ -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) {
@@ -1853,7 +1854,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.h b/wpa_supplicant/hidl/1.4/p2p_iface.h
similarity index 99%
rename from wpa_supplicant/hidl/1.3/p2p_iface.h
rename to wpa_supplicant/hidl/1.4/p2p_iface.h
index 608dbd4..882fad1 100644
--- a/wpa_supplicant/hidl/1.3/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.h
@@ -34,7 +34,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::SupplicantNetworkId;
 using V1_0::SupplicantStatus;
@@ -321,7 +321,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_network.cpp b/wpa_supplicant/hidl/1.4/p2p_network.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.3/p2p_network.cpp
rename to wpa_supplicant/hidl/1.4/p2p_network.cpp
index c87e4c0..cba2fdd 100644
--- a/wpa_supplicant/hidl/1.3/p2p_network.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_network.cpp
@@ -20,7 +20,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using V1_0::SupplicantStatusCode;
@@ -250,7 +250,7 @@
 	    (struct wpa_global *)wpa_global_, ifname_.c_str());
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/p2p_network.h b/wpa_supplicant/hidl/1.4/p2p_network.h
similarity index 98%
rename from wpa_supplicant/hidl/1.3/p2p_network.h
rename to wpa_supplicant/hidl/1.4/p2p_network.h
index 8c134b0..94e3763 100644
--- a/wpa_supplicant/hidl/1.3/p2p_network.h
+++ b/wpa_supplicant/hidl/1.4/p2p_network.h
@@ -26,7 +26,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicantP2pNetwork;
 using V1_0::ISupplicantP2pNetworkCallback;
@@ -96,7 +96,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.4/sta_iface.cpp
similarity index 95%
rename from wpa_supplicant/hidl/1.3/sta_iface.cpp
rename to wpa_supplicant/hidl/1.4/sta_iface.cpp
index b738ff7..7f476b1 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_iface.cpp
@@ -35,10 +35,11 @@
 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_3::implementation::HidlManager;
+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;
 constexpr char kGetMacAddress[] = "MACADDR";
@@ -223,7 +224,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using V1_0::ISupplicantStaIfaceCallback;
@@ -742,7 +743,7 @@
 std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
 StaIface::addNetworkInternal()
 {
-	android::sp<ISupplicantStaNetwork> network;
+	android::sp<V1_3::ISupplicantStaNetwork> network;
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
 	if (!ssid) {
@@ -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();
@@ -781,7 +790,7 @@
 std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
 StaIface::getNetworkInternal(SupplicantNetworkId id)
 {
-	android::sp<ISupplicantStaNetwork> network;
+	android::sp<V1_3::ISupplicantStaNetwork> network;
 	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
 	struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
 	if (!ssid) {
@@ -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};
 }
@@ -1479,9 +1503,9 @@
 	 * transition + Cellular steering. 11v is a default feature in
 	 * supplicant. And cellular steering is handled in framework.
 	 */
-	mask |= WpaDriverCapabilitiesMask::MBO;
+	mask |= V1_3::WpaDriverCapabilitiesMask::MBO;
 	if (wpa_s->enable_oce & OCE_STA) {
-		mask |= WpaDriverCapabilitiesMask::OCE;
+		mask |= V1_3::WpaDriverCapabilitiesMask::OCE;
 	}
 #endif
 
@@ -1535,7 +1559,7 @@
 	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.h b/wpa_supplicant/hidl/1.4/sta_iface.h
similarity index 96%
rename from wpa_supplicant/hidl/1.3/sta_iface.h
rename to wpa_supplicant/hidl/1.4/sta_iface.h
index ba06e5a..1b8584d 100644
--- a/wpa_supplicant/hidl/1.3/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>
 
@@ -33,7 +33,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicantNetwork;
 using android::hardware::wifi::supplicant::V1_2::DppAkm;
@@ -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,
@@ -282,7 +284,9 @@
 	SupplicantStatus startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
 			uint32_t own_bootstrap_id);
 	SupplicantStatus stopDppInitiatorInternal();
-	std::pair<SupplicantStatus, ConnectionCapabilities> getConnectionCapabilitiesInternal();
+	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();
@@ -300,7 +304,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.4/sta_network.cpp
similarity index 96%
rename from wpa_supplicant/hidl/1.3/sta_network.cpp
rename to wpa_supplicant/hidl/1.4/sta_network.cpp
index 5f3b491..a87c9eb 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_network.cpp
@@ -22,6 +22,7 @@
 using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 using ISupplicantStaNetworkV1_2 = android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
 using ISupplicantStaNetworkV1_3 = android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using ISupplicantStaNetworkV1_4 = android::hardware::wifi::supplicant::V1_4::ISupplicantStaNetwork;
 
 constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
 
@@ -60,7 +61,8 @@
      static_cast<uint32_t>(
 	 ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) |
      static_cast<uint32_t>(ISupplicantStaNetworkV1_2::GroupCipherMask::GCMP_256) |
-     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::GroupCipherMask::SMS4));
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::GroupCipherMask::SMS4) |
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_4::GroupCipherMask::GCMP_128));
 constexpr uint32_t kAllowedPairwisewCipherMask =
     (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
      static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
@@ -68,7 +70,8 @@
      static_cast<uint32_t>(
 	 ISupplicantStaNetworkV1_2::PairwiseCipherMask::GCMP_256) |
      static_cast<uint32_t>(
-	 ISupplicantStaNetworkV1_3::PairwiseCipherMask::SMS4));
+	 ISupplicantStaNetworkV1_3::PairwiseCipherMask::SMS4) |
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_4::PairwiseCipherMask::GCMP_128));
 constexpr uint32_t kAllowedGroupMgmtCipherMask =
 	(static_cast<uint32_t>(
 			ISupplicantStaNetworkV1_2::GroupMgmtCipherMask::BIP_GMAC_128) |
@@ -104,7 +107,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using V1_0::SupplicantStatusCode;
@@ -409,6 +412,13 @@
 	    &StaNetwork::setWapiCertSuiteInternal, _hidl_cb, suite);
 }
 
+Return<void> StaNetwork::setEdmg(bool enable, setEdmg_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setEdmgInternal, _hidl_cb, enable);
+}
+
 Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
 {
 	return validateAndCall(
@@ -637,6 +647,13 @@
 	    &StaNetwork::getWapiCertSuiteInternal, _hidl_cb);
 }
 
+Return<void> StaNetwork::getEdmg(getEdmg_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getEdmgInternal, _hidl_cb);
+}
+
 Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
 {
 	return validateAndCall(
@@ -822,7 +839,7 @@
 }
 
 Return<void> StaNetwork::setOcsp(
-    OcspType ocspType, setOcsp_cb _hidl_cb) {
+    V1_3::OcspType ocspType, setOcsp_cb _hidl_cb) {
 	return validateAndCall(
 	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
 	    &StaNetwork::setOcspInternal, _hidl_cb, ocspType);
@@ -928,6 +945,38 @@
 	    &StaNetwork::setEapErpInternal, _hidl_cb, enable);
 }
 
+Return<void> StaNetwork::setGroupCipher_1_4(
+    uint32_t group_cipher_mask, setGroupCipher_1_4_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setGroupCipher_1_4Internal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::getGroupCipher_1_4(getGroupCipher_1_4_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getGroupCipher_1_4Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPairwiseCipher_1_4(
+    uint32_t pairwise_cipher_mask, setPairwiseCipher_1_4_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setPairwiseCipher_1_4Internal, _hidl_cb,
+	    pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::getPairwiseCipher_1_4(
+    getPairwiseCipher_1_4_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::getPairwiseCipher_1_4Internal, _hidl_cb);
+}
+
 std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -1028,6 +1077,14 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus StaNetwork::setEdmgInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->enable_edmg = enable ? 1 : 0;
+	resetInternalStateAfterParamsUpdate();
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
 {
 	return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
@@ -1794,6 +1851,13 @@
 	return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
 }
 
+std::pair<SupplicantStatus, bool> StaNetwork::getEdmgInternal()
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	return {{SupplicantStatusCode::SUCCESS, ""},
+		(wpa_ssid->enable_edmg == 1)};
+}
+
 std::pair<SupplicantStatus, std::vector<uint8_t>>
 StaNetwork::getWpsNfcConfigurationTokenInternal()
 {
@@ -2130,9 +2194,9 @@
 		wpa_ssid->group_mgmt_cipher & kAllowedGroupMgmtCipherMask};
 }
 
-SupplicantStatus StaNetwork::setOcspInternal(OcspType ocspType) {
+SupplicantStatus StaNetwork::setOcspInternal(V1_3::OcspType ocspType) {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-	if (ocspType < OcspType::NONE || ocspType > OcspType::REQUIRE_ALL_CERTS_STATUS) {
+	if (ocspType < V1_3::OcspType::NONE || ocspType > V1_3::OcspType::REQUIRE_ALL_CERTS_STATUS) {
 		return{ SupplicantStatusCode::FAILURE_ARGS_INVALID, "" };
 	}
 	wpa_ssid->eap.cert.ocsp = (int) ocspType;
@@ -2142,11 +2206,11 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
-std::pair<SupplicantStatus, OcspType> StaNetwork::getOcspInternal()
+std::pair<SupplicantStatus, V1_3::OcspType> StaNetwork::getOcspInternal()
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	return {{SupplicantStatusCode::SUCCESS, ""},
-		(OcspType) wpa_ssid->eap.cert.ocsp};
+		(V1_3::OcspType) wpa_ssid->eap.cert.ocsp};
 }
 
 SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
@@ -2212,6 +2276,27 @@
 
 SupplicantStatus StaNetwork::setGroupCipher_1_3Internal(uint32_t group_cipher_mask)
 {
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_3Internal()
+{
+	return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
+}
+
+SupplicantStatus StaNetwork::setPairwiseCipher_1_3Internal(
+    uint32_t pairwise_cipher_mask)
+{
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_3Internal()
+{
+	return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
+}
+
+SupplicantStatus StaNetwork::setGroupCipher_1_4Internal(uint32_t group_cipher_mask)
+{
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	if (group_cipher_mask & ~kAllowedGroupCipherMask) {
 		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
@@ -2222,14 +2307,14 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_3Internal()
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_4Internal()
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	return {{SupplicantStatusCode::SUCCESS, ""},
 		wpa_ssid->group_cipher & kAllowedGroupCipherMask};
 }
 
-SupplicantStatus StaNetwork::setPairwiseCipher_1_3Internal(
+SupplicantStatus StaNetwork::setPairwiseCipher_1_4Internal(
     uint32_t pairwise_cipher_mask)
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
@@ -2243,7 +2328,7 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_3Internal()
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_4Internal()
 {
 	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
 	return {{SupplicantStatusCode::SUCCESS, ""},
@@ -2498,7 +2583,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/sta_network.h b/wpa_supplicant/hidl/1.4/sta_network.h
similarity index 93%
rename from wpa_supplicant/hidl/1.3/sta_network.h
rename to wpa_supplicant/hidl/1.4/sta_network.h
index 0057596..83b47d0 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.h
+++ b/wpa_supplicant/hidl/1.4/sta_network.h
@@ -15,7 +15,7 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaNetwork.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
 
 extern "C"
@@ -34,7 +34,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicantStaNetworkCallback;
 using V1_2::DppFailureCode;
@@ -45,7 +45,7 @@
  * object is used for control operations on a specific network
  * controlled by wpa_supplicant.
  */
-class StaNetwork : public V1_3::ISupplicantStaNetwork
+class StaNetwork : public V1_4::ISupplicantStaNetwork
 {
 public:
 	StaNetwork(
@@ -133,6 +133,7 @@
 	    const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
 	Return<void> setUpdateIdentifier(
 	    uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
+	Return<void> setEdmg(bool enable, setEdmg_cb _hidl_cb) override;
 	Return<void> getSsid(getSsid_cb _hidl_cb) override;
 	Return<void> getBssid(getBssid_cb _hidl_cb) override;
 	Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
@@ -172,6 +173,7 @@
 	Return<void> getIdStr(getIdStr_cb _hidl_cb) override;
 	Return<void> getWpsNfcConfigurationToken(
 	    getWpsNfcConfigurationToken_cb _hidl_cb) override;
+	Return<void> getEdmg(getEdmg_cb _hidl_cb) override;
 	Return<void> enable(bool no_connect, enable_cb _hidl_cb) override;
 	Return<void> disable(disable_cb _hidl_cb) override;
 	Return<void> select(select_cb _hidl_cb) override;
@@ -227,7 +229,7 @@
 	    const hidl_string& sae_password_id,
 	    setSaePasswordId_cb _hidl_cb) override;
 	Return<void> setOcsp(
-	    OcspType ocspType, setOcsp_cb _hidl_cb) override;
+	    V1_3::OcspType ocspType, setOcsp_cb _hidl_cb) override;
 	Return<void> getOcsp(
 	    getOcsp_cb _hidl_cb) override;
 	Return<void> setPmkCache(const hidl_vec<uint8_t>& serializedEntry,
@@ -256,6 +258,16 @@
 			std::function<void(const SupplicantStatus &status)> _hidl_cb)
 					override;
 	Return<void> setEapErp(bool enable, setEapErp_cb _hidl_cb) override;
+	Return<void> setPairwiseCipher_1_4(
+	    uint32_t pairwise_cipher_mask,
+	    setPairwiseCipher_1_4_cb _hidl_cb) override;
+	Return<void> getPairwiseCipher_1_4(
+	    getPairwiseCipher_1_4_cb _hidl_cb) override;
+	Return<void> setGroupCipher_1_4(
+	    uint32_t group_cipher_mask,
+	    setGroupCipher_1_4_cb _hidl_cb) override;
+	Return<void> getGroupCipher_1_4(
+	    getGroupCipher_1_4_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -305,6 +317,7 @@
 	SupplicantStatus setProactiveKeyCachingInternal(bool enable);
 	SupplicantStatus setIdStrInternal(const std::string& id_str);
 	SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
+	SupplicantStatus setEdmgInternal(bool enable);
 	std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
 	std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
 	std::pair<SupplicantStatus, bool> getScanSsidInternal();
@@ -345,6 +358,7 @@
 	std::pair<SupplicantStatus, std::string> getIdStrInternal();
 	std::pair<SupplicantStatus, std::vector<uint8_t>>
 	getWpsNfcConfigurationTokenInternal();
+	std::pair<SupplicantStatus, bool> getEdmgInternal();
 	SupplicantStatus enableInternal(bool no_connect);
 	SupplicantStatus disableInternal();
 	SupplicantStatus selectInternal();
@@ -372,8 +386,8 @@
 	    const std::string& sae_password_id);
 	SupplicantStatus setGroupMgmtCipherInternal(uint32_t group_mgmt_cipher_mask);
 	std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
-	SupplicantStatus setOcspInternal(OcspType ocspType);
-	std::pair<SupplicantStatus, OcspType> getOcspInternal();
+	SupplicantStatus setOcspInternal(V1_3::OcspType ocspType);
+	std::pair<SupplicantStatus, V1_3::OcspType> getOcspInternal();
 	SupplicantStatus setPmkCacheInternal(const std::vector<uint8_t>& serialziedEntry);
 	SupplicantStatus setWapiCertSuiteInternal(const std::string& suite);
 	std::pair<SupplicantStatus, std::string> getWapiCertSuiteInternal();
@@ -388,6 +402,11 @@
 	    uint32_t pairwise_cipher_mask);
 	SupplicantStatus setWapiPskInternal(const std::vector<uint8_t>& psk);
 	std::pair<SupplicantStatus, std::vector<uint8_t>> getWapiPskInternal();
+	std::pair<SupplicantStatus, uint32_t> getGroupCipher_1_4Internal();
+	SupplicantStatus setGroupCipher_1_4Internal(uint32_t group_cipher_mask);
+	std::pair<SupplicantStatus, uint32_t> getPairwiseCipher_1_4Internal();
+	SupplicantStatus setPairwiseCipher_1_4Internal(
+	    uint32_t pairwise_cipher_mask);
 
 	struct wpa_ssid* retrieveNetworkPtr();
 	struct wpa_supplicant* retrieveIfacePtr();
@@ -427,7 +446,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/supplicant.cpp b/wpa_supplicant/hidl/1.4/supplicant.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.3/supplicant.cpp
rename to wpa_supplicant/hidl/1.4/supplicant.cpp
index 50d2343..5fea68d 100644
--- a/wpa_supplicant/hidl/1.3/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.4/supplicant.cpp
@@ -156,7 +156,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using V1_0::SupplicantStatusCode;
@@ -417,7 +417,7 @@
 	return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/supplicant.h b/wpa_supplicant/hidl/1.4/supplicant.h
similarity index 95%
rename from wpa_supplicant/hidl/1.3/supplicant.h
rename to wpa_supplicant/hidl/1.4/supplicant.h
index 0c0ac72..8fd2033 100644
--- a/wpa_supplicant/hidl/1.3/supplicant.h
+++ b/wpa_supplicant/hidl/1.4/supplicant.h
@@ -13,7 +13,7 @@
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
 #include <android/hardware/wifi/supplicant/1.0/types.h>
-#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
 #include <android-base/macros.h>
 #include <hidl/Status.h>
 
@@ -29,7 +29,7 @@
 namespace hardware {
 namespace wifi {
 namespace supplicant {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using V1_0::ISupplicantCallback;
 using V1_0::ISupplicantIface;
@@ -39,7 +39,7 @@
  * object is used core for global control operations on
  * wpa_supplicant.
  */
-class Supplicant : public V1_3::ISupplicant
+class Supplicant : public V1_4::ISupplicant
 {
 public:
 	Supplicant(struct wpa_global* global);
@@ -93,7 +93,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 2f4682e..eb7c392 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, "");
@@ -9406,6 +9415,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 */
@@ -9429,6 +9444,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 98b317e..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;