wpa_supplicant: Add changes to support QoS policy AIDL APIs

Add implementation for the QoS policies AIDL API requests and callbacks.

Bug: 191426881
Test: m
Change-Id: Id282577a23408e2297626b0f259d31fa30975f64
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index eb38497..1add3df 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -1001,3 +1001,35 @@
 		AuxiliarySupplicantEventCode::OPEN_SSL_FAILURE,
 		reason_string);
 }
+
+void wpas_aidl_notify_qos_policy_reset(
+	struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+	wpa_printf(
+		MSG_DEBUG, "Notifying Qos Policy Reset");
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	aidl_manager->notifyQosPolicyReset(wpa_s);
+}
+
+void wpas_aidl_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
+	struct dscp_policy_data *policies, int num_policies)
+{
+	if (!wpa_s || !policies)
+		return;
+
+	wpa_printf(
+		MSG_DEBUG, "Notifying Qos Policy Request");
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	aidl_manager->notifyQosPolicyRequest(wpa_s, policies, num_policies);
+}
+
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index fcd462b..d9ab7bd 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -139,6 +139,9 @@
 		const char *reason_string);
 	void wpas_aidl_notify_open_ssl_failure(struct wpa_supplicant *wpa_s,
 		const char *reason_string);
+	void wpas_aidl_notify_qos_policy_reset(struct wpa_supplicant *wpa_s);
+	void wpas_aidl_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
+		struct dscp_policy_data *policies, int num_policies);
 #else   // CONFIG_CTRL_IFACE_AIDL
 static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -308,6 +311,11 @@
 void wpas_aidl_notify_open_ssl_failure(struct wpa_supplicant *wpa_s,
 	const char *reason_string)
 {}
+static void wpas_aidl_notify_qos_policy_reset(struct wpa_supplicant *wpa_s) {}
+static void wpas_aidl_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
+						struct dscp_policy_data *policies,
+						int num_policies)
+{}
 #endif  // CONFIG_CTRL_IFACE_AIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index 9124570..ac7b8e8 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -15,6 +15,7 @@
 #include "misc_utils.h"
 #include <android/binder_process.h>
 #include <android/binder_manager.h>
+#include <aidl/android/hardware/wifi/supplicant/IpVersion.h>
 
 extern "C" {
 #include "scan.h"
@@ -2331,6 +2332,136 @@
 		ifname, network_id, method, sta_network_callbacks_map_);
 }
 
+void AidlManager::notifyQosPolicyReset(
+	struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onQosPolicyReset,
+			std::placeholders::_1));
+}
+
+void AidlManager::notifyQosPolicyRequest(struct wpa_supplicant *wpa_s,
+	struct dscp_policy_data *policies, int num_policies)
+{
+	if (!wpa_s || !policies)
+		return;
+
+	std::vector<QosPolicyData> qosPolicyData;
+	uint32_t mask = 0;
+
+	for (int num = 0; num < num_policies; num++) {
+		QosPolicyData policy;
+		QosPolicyClassifierParams classifier_params;
+		QosPolicyClassifierParamsMask classifier_param_mask;
+		bool ip_ver4 = false;
+
+		if (policies[num].type4_param.ip_version == 4) {
+			classifier_params.ipVersion = IpVersion::VERSION_4;
+			ip_ver4 = true;
+		} else {
+			classifier_params.ipVersion = IpVersion::VERSION_6;
+			ip_ver4 = false;
+		}
+
+		// classifier_mask parameters are defined in IEEE Std 802.11-2020, Table 9-170
+		if (policies[num].type4_param.classifier_mask & BIT(1)) {
+			mask |= static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_IP);
+			if (ip_ver4) {
+				classifier_params.srcIp =
+					byteArrToVec((const uint8_t *)
+						&policies[num].type4_param.ip_params.v4.src_ip, 4);
+			} else {
+				classifier_params.srcIp =
+					byteArrToVec((const uint8_t *)
+						&policies[num].type4_param.ip_params.v6.src_ip, 16);
+			}
+		}
+		if (policies[num].type4_param.classifier_mask & BIT(2)) {
+			mask |= static_cast<uint32_t>(QosPolicyClassifierParamsMask::DST_IP);
+			if (ip_ver4){
+				classifier_params.dstIp =
+					byteArrToVec((const uint8_t *)
+						&policies[num].type4_param.ip_params.v4.dst_ip, 4);
+			} else {
+				classifier_params.dstIp =
+					byteArrToVec((const uint8_t *)
+						&policies[num].type4_param.ip_params.v6.dst_ip, 16);
+			}
+		}
+		if (policies[num].type4_param.classifier_mask & BIT(3)) {
+			mask |= static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_PORT);
+			if (ip_ver4){
+				classifier_params.srcPort =
+					policies[num].type4_param.ip_params.v4.src_port;
+			} else {
+				classifier_params.srcPort =
+					policies[num].type4_param.ip_params.v6.src_port;
+			}
+		}
+
+		if (policies[num].type4_param.classifier_mask & BIT(4)) {
+			mask |= static_cast<uint32_t>(
+				QosPolicyClassifierParamsMask::DST_PORT_RANGE);
+			if (ip_ver4) {
+				classifier_params.dstPortRange.startPort =
+					policies[num].type4_param.ip_params.v4.dst_port;
+				classifier_params.dstPortRange.endPort =
+					policies[num].type4_param.ip_params.v4.dst_port;
+			} else {
+				classifier_params.dstPortRange.startPort =
+					policies[num].type4_param.ip_params.v6.dst_port;
+				classifier_params.dstPortRange.endPort =
+					policies[num].type4_param.ip_params.v6.dst_port;
+			}
+		} else if (policies[num].port_range_info) {
+			mask |= static_cast<uint32_t>(
+				QosPolicyClassifierParamsMask::DST_PORT_RANGE);
+			classifier_params.dstPortRange.startPort = policies[num].start_port;
+			classifier_params.dstPortRange.endPort = policies[num].end_port;
+		}
+		if (policies[num].type4_param.classifier_mask & BIT(6)) {
+			mask |= static_cast<uint32_t>(
+				QosPolicyClassifierParamsMask::PROTOCOL_NEXT_HEADER);
+			if (ip_ver4) {
+				classifier_params.protocolNextHdr = static_cast<ProtocolNextHeader>(
+					policies[num].type4_param.ip_params.v4.protocol);
+			} else {
+				classifier_params.protocolNextHdr = static_cast<ProtocolNextHeader>(
+					policies[num].type4_param.ip_params.v6.next_header);
+			}
+		}
+		if (policies[num].type4_param.classifier_mask & BIT(7)) {
+			mask |= static_cast<uint32_t>(QosPolicyClassifierParamsMask::FLOW_LABEL);
+			classifier_params.flowLabelIpv6 =
+				byteArrToVec(policies[num].type4_param.ip_params.v6.flow_label, 3);
+		}
+		if (policies[num].domain_name_len != 0) {
+			mask |= static_cast<uint32_t>(QosPolicyClassifierParamsMask::DOMAIN_NAME);
+			classifier_params.domainName =
+				misc_utils::charBufToString(
+					reinterpret_cast<const char *>(policies[num].domain_name));
+		}
+
+		classifier_params.classifierParamMask =
+			static_cast<QosPolicyClassifierParamsMask>(mask);
+		policy.policyId = policies[num].policy_id;
+		policy.requestType = static_cast<QosPolicyRequestType>(policies[num].req_type);
+		policy.dscp = policies[num].dscp;
+		policy.classifierParams = classifier_params;
+
+		qosPolicyData.push_back(policy);
+	}
+
+	callWithEachStaIfaceCallback(
+		misc_utils::charBufToString(wpa_s->ifname), std::bind(
+			&ISupplicantStaIfaceCallback::onQosPolicyRequest,
+			std::placeholders::_1, wpa_s->dscp_req_dialog_token, qosPolicyData));
+}
+
 }  // namespace supplicant
 }  // namespace wifi
 }  // namespace hardware
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index 15f8e28..6acacf5 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -153,6 +153,10 @@
 	void notifyAuxiliaryEvent(struct wpa_supplicant *wpa_s,
 			AuxiliarySupplicantEventCode event_code,
 			const char *reason_string);
+	void notifyQosPolicyReset(struct wpa_supplicant *wpa_s);
+	void notifyQosPolicyRequest(struct wpa_supplicant *wpa_s,
+			struct dscp_policy_data *policies,
+			int num_policies);
 
 	// Methods called from aidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index b4fbb24..7a07cc1 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -1871,6 +1871,8 @@
 
 ndk::ScopedAStatus StaIface::setQosPolicyFeatureEnabledInternal(bool enable)
 {
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	wpa_s->enable_dscp_policy_capa = enable ? 1 : 0;
 	return ndk::ScopedAStatus::ok();
 }
 
@@ -1878,11 +1880,51 @@
 	int32_t qos_policy_request_id, bool more_policies,
 	const std::vector<QosPolicyStatus>& qos_policy_status_list)
 {
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct dscp_resp_data resp_data;
+	int num_policies = qos_policy_status_list.size();
+
+	memset(&resp_data, 0, sizeof(resp_data));
+
+	resp_data.more = more_policies ? 1 : 0;
+	resp_data.policy = (struct dscp_policy_status *) malloc(
+		sizeof(struct dscp_policy_status) * num_policies);
+	if (num_policies && !resp_data.policy){
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+
+	resp_data.solicited = true;
+	wpa_s->dscp_req_dialog_token = qos_policy_request_id;
+
+	for (int i = 0; i < num_policies; i++) {
+		resp_data.policy[i].id = qos_policy_status_list.at(i).policyId;
+		resp_data.policy[i].status =
+			static_cast<uint8_t>(qos_policy_status_list.at(i).status);
+	}
+	resp_data.num_policies = num_policies;
+
+	if (wpas_send_dscp_response(wpa_s, &resp_data)) {
+		free(resp_data.policy);
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
+
+	free(resp_data.policy);
 	return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus StaIface::removeAllQosPoliciesInternal()
 {
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct dscp_resp_data resp_data;
+
+	memset(&resp_data, 0, sizeof(resp_data));
+	resp_data.reset = true;
+	resp_data.solicited = false;
+	wpa_s->dscp_req_dialog_token = 0;
+
+	if (wpas_send_dscp_response(wpa_s, &resp_data)) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	return ndk::ScopedAStatus::ok();
 }
 
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 72c6260..4c30518 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -1304,3 +1304,20 @@
 {
 	wpas_aidl_notify_open_ssl_failure(wpa_s, reason_string);
 }
+
+void wpas_notify_qos_policy_reset(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return;
+
+	wpas_aidl_notify_qos_policy_reset(wpa_s);
+}
+
+void wpas_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
+	struct dscp_policy_data *policies, int num_policies)
+{
+	if (!wpa_s || !policies)
+		return;
+
+	wpas_aidl_notify_qos_policy_request(wpa_s, policies, num_policies);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 8035749..f700017 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -214,5 +214,8 @@
 		const char *reason_string);
 void wpas_notify_open_ssl_failure(struct wpa_supplicant *wpa_s,
 		const char *reason_string);
+void wpas_notify_qos_policy_reset(struct wpa_supplicant *wpa_s);
+void wpas_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
+		struct dscp_policy_data *policies, int num_policies);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index 770c8fc..6110797 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -14,6 +14,7 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "bss.h"
+#include "notify.h"
 
 
 #define SCS_RESP_TIMEOUT 1
@@ -843,22 +844,6 @@
 }
 
 
-struct dscp_policy_data {
-	u8 policy_id;
-	u8 req_type;
-	u8 dscp;
-	bool dscp_info;
-	const u8 *frame_classifier;
-	u8 frame_classifier_len;
-	struct type4_params type4_param;
-	const u8 *domain_name;
-	u8 domain_name_len;
-	u16 start_port;
-	u16 end_port;
-	bool port_range_info;
-};
-
-
 static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy)
 {
 	u8 classifier_mask;
@@ -1062,7 +1047,7 @@
 }
 
 
-static void wpas_add_dscp_policy(struct wpa_supplicant *wpa_s,
+static int  wpas_add_dscp_policy(struct wpa_supplicant *wpa_s,
 				 struct dscp_policy_data *policy)
 {
 	int ip_ver = 0, res;
@@ -1147,10 +1132,11 @@
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
 		"add policy_id=%u dscp=%u ip_version=%d%s",
 		policy->policy_id, policy->dscp, ip_ver, policy_str);
-	return;
+	return 0;
 fail:
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "reject policy_id=%u",
 		policy->policy_id);
+	return -1;
 }
 
 
@@ -1231,6 +1217,9 @@
 	const u8 *qos_ie, *attr;
 	int more, reset;
 
+        struct dscp_policy_data *policies = NULL, *policies_temp;
+        int num_dscp_policies = 0;
+
 	if (!wpa_s->enable_dscp_policy_capa) {
 		wpa_printf(MSG_ERROR,
 			   "QM: Ignore DSCP Policy frame since the capability is not enabled");
@@ -1276,6 +1265,9 @@
 	more = buf[2] & DSCP_POLICY_CTRL_MORE;
 	reset = buf[2] & DSCP_POLICY_CTRL_RESET;
 
+        if (reset)
+                wpas_notify_qos_policy_reset(wpa_s);
+
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_start%s%s",
 		reset ? " clear_all" : "", more ? " more" : "");
 
@@ -1283,6 +1275,7 @@
 	rem_len = len - 3;
 	while (rem_len > 2) {
 		struct dscp_policy_data policy;
+		int res = 0;
 		int rem_attrs_len, ie_len;
 
 		ie_len = 2 + qos_ie[1];
@@ -1318,16 +1311,37 @@
 		}
 
 		if (policy.req_type == DSCP_POLICY_REQ_ADD)
-			wpas_add_dscp_policy(wpa_s, &policy);
+			res = wpas_add_dscp_policy(wpa_s, &policy);
 		else if (policy.req_type == DSCP_POLICY_REQ_REMOVE)
 			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
 				"remove policy_id=%u", policy.policy_id);
-		else
+		else {
 			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
 				"reject policy_id=%u", policy.policy_id);
+			res = -1;
+		}
+
+		if (res)
+			continue;
+
+		policies_temp = os_realloc(policies,
+					   (num_dscp_policies + 1)  *
+					   sizeof(struct dscp_policy_data));
+		if (!policies_temp)
+			goto fail;
+
+		policies = policies_temp;
+		policies[num_dscp_policies] = policy;
+		num_dscp_policies++;
 	}
 
+	wpas_notify_qos_policy_request(wpa_s, policies, num_dscp_policies);
+
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_end");
+
+fail:
+        os_free(policies);
+        return;
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9c2d9af..1d2c3e2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -681,6 +681,21 @@
 	enum scs_response_status status;
 };
 
+struct dscp_policy_data {
+	u8 policy_id;
+	u8 req_type;
+	u8 dscp;
+	bool dscp_info;
+	const u8 *frame_classifier;
+	u8 frame_classifier_len;
+	struct type4_params type4_param;
+	const u8 *domain_name;
+	u8 domain_name_len;
+	u16 start_port;
+	u16 end_port;
+	bool port_range_info;
+};
+
 
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface