hidl: Add support to connect to FILS enabled APs using ERP

Add hidl support to configure FILS key_mgmt types and ERP while adding
configurations for FILS enabled APs. When ERP is enabled, the ERP keys
will be generated while connecting to FILS enabled APs and the ERP keys
will be used to make faster future connections with FILS enabled APs.
Also add support to add/flush Higher Layer Packets(HLPs) which can be
sent to AP through association request frame.

Bug: 143259898
Test: Basic wifi sanity test.
Test: VTS test.
Change-Id: Iddffa6b3bec3883562f04b2636c2c6f9fb5d6f90
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 63c8eb3..d05141f 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -506,7 +506,10 @@
 CONFIG_MBO=y
 
 # Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-#CONFIG_FILS=y
+CONFIG_FILS=y
+
+# EAP Re-authentication protocol
+CONFIG_ERP=y
 
 # Support RSN on IBSS networks
 # This is needed to be able to use mode=1 network profile with proto=RSN and
diff --git a/wpa_supplicant/hidl/1.3/hidl_manager.cpp b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
index 120f2d3..f019c94 100644
--- a/wpa_supplicant/hidl/1.3/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
@@ -700,13 +700,22 @@
 	} else {
 		bssid = wpa_s->bssid;
 	}
-	callWithEachStaIfaceCallback(
-	    wpa_s->ifname, std::bind(
-			       &ISupplicantStaIfaceCallback::onStateChanged,
-			       std::placeholders::_1,
-			       static_cast<ISupplicantStaIfaceCallback::State>(
-				   wpa_s->wpa_state),
-			       bssid, hidl_network_id, hidl_ssid));
+	bool fils_hlp_sent =
+		(wpa_auth_alg_fils(wpa_s->auth_alg) &&
+		 !dl_list_empty(&wpa_s->fils_hlp_req) &&
+		 (wpa_s->wpa_state == WPA_COMPLETED)) ? true : false;
+
+	// Invoke the |onStateChanged_1_3| method on all registered callbacks.
+	const std::function<
+		Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+		func = std::bind(
+			&V1_3::ISupplicantStaIfaceCallback::onStateChanged_1_3,
+			std::placeholders::_1,
+			static_cast<ISupplicantStaIfaceCallback::State>(
+				wpa_s->wpa_state),
+				bssid, hidl_network_id, hidl_ssid,
+				fils_hlp_sent);
+	callWithEachStaIfaceCallbackDerived(wpa_s->ifname, func);
 	return 0;
 }
 
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.cpp b/wpa_supplicant/hidl/1.3/sta_iface.cpp
index 60456f3..4e5a517 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_iface.cpp
@@ -205,6 +205,14 @@
 	mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
 	mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
 #endif /* CONFIG_WAPI_INTERFACE */
+#ifdef CONFIG_FILS
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+		mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256;
+	}
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+		mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384;
+	}
+#endif /* CONFIG_FILS */
 	return mask;
 }
 
@@ -258,6 +266,22 @@
 	    &StaIface::removeNetworkInternal, _hidl_cb, id);
 }
 
+Return<void> StaIface::filsHlpFlushRequest(filsHlpFlushRequest_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::filsHlpFlushRequestInternal, _hidl_cb);
+}
+
+Return<void> StaIface::filsHlpAddRequest(
+    const hidl_array<uint8_t, 6> &dst_mac, const hidl_vec<uint8_t> &pkt,
+    filsHlpAddRequest_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::filsHlpAddRequestInternal, _hidl_cb, dst_mac, pkt);
+}
+
 Return<void> StaIface::getNetwork(
     SupplicantNetworkId id, getNetwork_cb _hidl_cb)
 {
@@ -672,6 +696,48 @@
 	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
 }
 
+SupplicantStatus StaIface::filsHlpFlushRequestInternal()
+{
+#ifdef CONFIG_FILS
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+
+	wpas_flush_fils_hlp_req(wpa_s);
+	return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
+SupplicantStatus StaIface::filsHlpAddRequestInternal(
+    const std::array<uint8_t, 6> &dst_mac, const std::vector<uint8_t> &pkt)
+{
+#ifdef CONFIG_FILS
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct fils_hlp_req *req;
+
+	if (!pkt.size())
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+
+
+	req = (struct fils_hlp_req *)os_zalloc(sizeof(*req));
+	if (!req)
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+
+	os_memcpy(req->dst, dst_mac.data(), ETH_ALEN);
+
+	req->pkt = wpabuf_alloc_copy(pkt.data(), pkt.size());
+	if (!req->pkt) {
+		os_free(req);
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+
+	dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
+	return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
 std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
 StaIface::addNetworkInternal()
 {
diff --git a/wpa_supplicant/hidl/1.3/sta_iface.h b/wpa_supplicant/hidl/1.3/sta_iface.h
index 958bdc5..ba06e5a 100644
--- a/wpa_supplicant/hidl/1.3/sta_iface.h
+++ b/wpa_supplicant/hidl/1.3/sta_iface.h
@@ -17,7 +17,7 @@
 
 #include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
 
 extern "C"
 {
@@ -70,6 +70,11 @@
 	Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
 	Return<void> removeNetwork(
 	    SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
+	Return<void> filsHlpFlushRequest(
+	    filsHlpFlushRequest_cb _hidl_cb) override;
+	Return<void> filsHlpAddRequest(
+	    const hidl_array<uint8_t, 6>& dst_mac, const hidl_vec<uint8_t>& pkt,
+	    filsHlpAddRequest_cb _hidl_cb) override;
 	Return<void> getNetwork(
 	    SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
 	Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
@@ -197,6 +202,10 @@
 	std::pair<SupplicantStatus, IfaceType> getTypeInternal();
 	std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
 	addNetworkInternal();
+	SupplicantStatus filsHlpFlushRequestInternal();
+	SupplicantStatus filsHlpAddRequestInternal(
+	    const std::array<uint8_t, 6>& dst_mac,
+	    const std::vector<uint8_t>& pkt);
 	SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
 	std::pair<SupplicantStatus, sp<ISupplicantNetwork>> getNetworkInternal(
 	    SupplicantNetworkId id);
diff --git a/wpa_supplicant/hidl/1.3/sta_network.cpp b/wpa_supplicant/hidl/1.3/sta_network.cpp
index c807c52..d6f85c5 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_network.cpp
@@ -39,7 +39,9 @@
      static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::WPA_PSK_SHA256) |
      static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::WPA_EAP_SHA256) |
      static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::WAPI_PSK) |
-     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::WAPI_CERT));
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::WAPI_CERT) |
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::FILS_SHA256) |
+     static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::FILS_SHA384));
 constexpr uint32_t kAllowedProtoMask =
     (static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
      static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
@@ -918,6 +920,13 @@
 	    &StaNetwork::setAuthAlgInternal, _hidl_cb, auth_alg_mask);
 }
 
+Return<void> StaNetwork::setEapErp(bool enable, setEapErp_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+	    &StaNetwork::setEapErpInternal, _hidl_cb, enable);
+}
+
 std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -2388,6 +2397,22 @@
 		key_mgmt_mask &= ~WPA_KEY_MGMT_FT_IEEE8021X;
 	}
 }
+
+/**
+ * Helper function to enable erp keys generation while connecting to FILS
+ * enabled APs.
+ */
+SupplicantStatus StaNetwork::setEapErpInternal(bool enable)
+{
+#ifdef CONFIG_FILS
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->eap.erp = enable ? 1 : 0;
+	return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+	return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
 }  // namespace implementation
 }  // namespace V1_3
 }  // namespace supplicant
diff --git a/wpa_supplicant/hidl/1.3/sta_network.h b/wpa_supplicant/hidl/1.3/sta_network.h
index 279b327..2a847a6 100644
--- a/wpa_supplicant/hidl/1.3/sta_network.h
+++ b/wpa_supplicant/hidl/1.3/sta_network.h
@@ -255,6 +255,7 @@
 	Return<void> setAuthAlg_1_3(uint32_t auth_alg_mask,
 			std::function<void(const SupplicantStatus &status)> _hidl_cb)
 					override;
+	Return<void> setEapErp(bool enable, setEapErp_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -409,6 +410,7 @@
 	    const char* hexdump_prefix);
 	void setFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
 	void resetFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
+	SupplicantStatus setEapErpInternal(bool enable);
 
 	// Reference to the global wpa_struct. This is assumed to be valid
 	// for the lifetime of the process.