AIDL: Implement QoS SCS policy stub APIs
Add implementation for QoS SCS policy APIs and callbacks:
- addQosPolicyRequestForScs
- removeQosPolicyForScs
- removeAllQosPoliciesForScs
- onQosPolicyResponseForScs
Bug: 236182432
Test: m
Change-Id: Ie6c66e2e6783c20c8754ce9e7bfdd31eacc4f29e
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index b4518bf..614d66d 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -1073,3 +1073,17 @@
return aidl_manager->getCertificate(alias, value);
}
+
+void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
+ unsigned int count, int **scs_resp)
+{
+ if (!wpa_s || !count || !scs_resp)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying Qos Policy SCS Response");
+ aidl_manager->notifyQosPolicyScsResponse(wpa_s, count, scs_resp);
+}
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index f963e61..f4afc7e 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -146,6 +146,8 @@
void wpas_aidl_notify_qos_policy_request(struct wpa_supplicant *wpa_s,
struct dscp_policy_data *policies, int num_policies);
ssize_t wpas_aidl_get_certificate(const char* alias, uint8_t** value);
+ void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
+ unsigned int count, int **scs_resp);
#else // CONFIG_CTRL_IFACE_AIDL
static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -332,6 +334,8 @@
{
return -1;
}
+static void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
+ unsigned int count, int **scs_resp) {}
#endif // CONFIG_CTRL_IFACE_AIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index 5c36301..d7987e6 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -2609,6 +2609,64 @@
return -1;
}
+QosPolicyScsResponseStatusCode getQosPolicyScsResponseStatusCode(int scsResponseCode)
+{
+ QosPolicyScsResponseStatusCode status = QosPolicyScsResponseStatusCode::TIMEOUT;
+ /* Status code as per Ieee802.11-2020 Table 9-50—Status codes */
+ switch (scsResponseCode) {
+ case 0: /* SUCCESS */
+ status = QosPolicyScsResponseStatusCode::SUCCESS;
+ break;
+ case 37: /* REQUEST_DECLINED */
+ status = QosPolicyScsResponseStatusCode::TCLAS_REQUEST_DECLINED;
+ break;
+ case 56: /* REQUESTED_TCLAS_NOT_SUPPORTED */
+ case 80: /* REQUESTED_TCLAS_NOT_SUPPORTED */
+ status = QosPolicyScsResponseStatusCode::TCLAS_NOT_SUPPORTED_BY_AP;
+ break;
+ case 57: /* INSUFFICIENT_TCLAS_PROCESSING_RESOURCES */
+ status = QosPolicyScsResponseStatusCode::TCLAS_INSUFFICIENT_RESOURCES;
+ break;
+ case 81: /* TCLAS_RESOURCES_EXHAUSTED */
+ status = QosPolicyScsResponseStatusCode::TCLAS_RESOURCES_EXHAUSTED;
+ break;
+ case 128: /* TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS */
+ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS;
+ break;
+ case 129: /* TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT */
+ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT;
+ break;
+ case 97: /* TCLAS_PROCESSING_TERMINATED */
+ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED;
+ break;
+ default:
+ status = QosPolicyScsResponseStatusCode::TIMEOUT;
+ break;
+ return status;
+ }
+ return status;
+}
+
+void AidlManager::notifyQosPolicyScsResponse(struct wpa_supplicant *wpa_s,
+ unsigned int count, int **scs_resp)
+{
+ if (!wpa_s || !count || !scs_resp)
+ return;
+
+ std::vector<QosPolicyScsResponseStatus> scsResponses;
+
+ for (int i = 0; i < count; i++) {
+ QosPolicyScsResponseStatus resp;
+ resp.policyId = scs_resp[0][i] & 0xFF;
+ resp.qosPolicyScsResponseStatusCode = getQosPolicyScsResponseStatusCode(scs_resp[1][i]);
+ scsResponses.push_back(resp);
+ }
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onQosPolicyResponseForScs,
+ std::placeholders::_1, scsResponses));
+}
+
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index 223f4b2..2173a0d 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -164,6 +164,8 @@
struct dscp_policy_data *policies,
int num_policies);
ssize_t getCertificate(const char* alias, uint8_t** value);
+ void notifyQosPolicyScsResponse(struct wpa_supplicant *wpa_s,
+ unsigned int count, int **scs_resp);
// 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 674b30c..fba4d30 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -2085,19 +2085,350 @@
return {results, ndk::ScopedAStatus::ok()};
}
+static int set_type4_frame_classifier(QosPolicyScsData qos_policy_data,
+ struct type4_params *param)
+{
+ u8 classifier_mask = 0;
+ int ret;
+ char addr[INET6_ADDRSTRLEN];
+ uint32_t inMask = static_cast<uint32_t>(qos_policy_data.classifierParams.classifierParamMask);
+ if (qos_policy_data.classifierParams.ipVersion ==
+ IpVersion::VERSION_4) {
+ param->ip_version = IPV4;
+ } else if (qos_policy_data.classifierParams.ipVersion ==
+ IpVersion::VERSION_6) {
+ param->ip_version = IPV6;
+ } else {
+ wpa_printf(MSG_ERROR, "IP version missing/invalid");
+ return -1;
+ }
+
+ /* Classifier Mask - bit 0 = Ip Version */
+ classifier_mask |= BIT(0);
+
+ if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_IP)) {
+ if (param->ip_version == IPV4) {
+ if (qos_policy_data.classifierParams.srcIp.size() !=
+ sizeof(param->ip_params.v4.src_ip)) {
+ wpa_printf(MSG_ERROR, "Invalid source IP");
+ return -1;
+ }
+ os_memcpy(addr, qos_policy_data.classifierParams.srcIp.data(), 4);
+ ret = inet_pton(AF_INET, addr,
+ ¶m->ip_params.v4.src_ip);
+ } else {
+ if (qos_policy_data.classifierParams.srcIp.size() !=
+ sizeof(param->ip_params.v6.src_ip)) {
+ wpa_printf(MSG_ERROR, "Invalid source IP");
+ return -1;
+ }
+ os_memcpy(addr, qos_policy_data.classifierParams.srcIp.data(), 16);
+ ret = inet_pton(AF_INET6, addr,
+ ¶m->ip_params.v6.src_ip);
+ }
+ if (ret != 1) {
+ wpa_printf(MSG_ERROR,
+ "Error converting src IP address to binary ret=%d",
+ ret);
+ return -1;
+ }
+
+ /* Classifier Mask - bit 1 = Source IP Address */
+ classifier_mask |= BIT(1);
+ }
+
+ if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DST_IP)) {
+ if (param->ip_version == IPV4) {
+ if (qos_policy_data.classifierParams.dstIp.size() !=
+ sizeof(param->ip_params.v4.dst_ip)) {
+ wpa_printf(MSG_ERROR, "Invalid destination IP");
+ return -1;
+ }
+ os_memcpy(addr, qos_policy_data.classifierParams.dstIp.data(), 4);
+ ret = inet_pton(AF_INET, addr,
+ ¶m->ip_params.v4.dst_ip);
+ } else {
+ if (qos_policy_data.classifierParams.dstIp.size() !=
+ sizeof(param->ip_params.v6.dst_ip)) {
+ wpa_printf(MSG_ERROR, "Invalid destination IP");
+ return -1;
+ }
+ os_memcpy(addr, qos_policy_data.classifierParams.dstIp.data(), 16);
+ ret = inet_pton(AF_INET6, addr,
+ ¶m->ip_params.v6.dst_ip);
+ }
+
+ if (ret != 1) {
+ wpa_printf(MSG_ERROR,
+ "Error converting dst IP address to binary ret=%d",
+ ret);
+ return -1;
+ }
+
+ /* Classifier Mask - bit 2 = Destination IP Address */
+ classifier_mask |= BIT(2);
+ }
+
+ if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_PORT))
+ && (qos_policy_data.classifierParams.srcPort > 0)) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.src_port = qos_policy_data.classifierParams.srcPort;
+ else
+ param->ip_params.v6.src_port = qos_policy_data.classifierParams.srcPort;
+
+ /* Classifier Mask - bit 3 = Source Port */
+ classifier_mask |= BIT(3);
+ }
+
+ if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DST_PORT_RANGE))
+ && (qos_policy_data.classifierParams.dstPortRange.startPort > 0)) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.dst_port = qos_policy_data.classifierParams.dstPortRange.startPort;
+ else
+ param->ip_params.v6.dst_port = qos_policy_data.classifierParams.dstPortRange.startPort;
+
+ /* Classifier Mask - bit 4 = Destination Port range */
+ classifier_mask |= BIT(4);
+ }
+
+ if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DSCP))
+ && (qos_policy_data.classifierParams.dscp > 0)) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.dscp = qos_policy_data.classifierParams.dscp;
+ else
+ param->ip_params.v6.dscp = qos_policy_data.classifierParams.dscp;
+
+ /* Classifier Mask - bit 5 = DSCP */
+ classifier_mask |= BIT(5);
+ }
+
+ if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::PROTOCOL_NEXT_HEADER)) {
+ if (!((qos_policy_data.classifierParams.protocolNextHdr ==
+ ProtocolNextHeader::TCP) ||
+ (qos_policy_data.classifierParams.protocolNextHdr ==
+ ProtocolNextHeader::UDP) ||
+ (qos_policy_data.classifierParams.protocolNextHdr ==
+ ProtocolNextHeader::ESP))) {
+ wpa_printf(MSG_ERROR, "Invalid protocol");
+ return -1;
+ }
+ if (param->ip_version == IPV4) {
+ param->ip_params.v4.protocol =
+ (u8)qos_policy_data.classifierParams.protocolNextHdr;
+ } else {
+ param->ip_params.v6.next_header =
+ (u8)qos_policy_data.classifierParams.protocolNextHdr;
+ }
+
+ /* Classifier Mask - bit 6 = Protocol Number*/
+ classifier_mask |= BIT(6);
+ }
+
+ if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::FLOW_LABEL)) {
+ if (qos_policy_data.classifierParams.flowLabelIpv6.size() !=
+ sizeof(param->ip_params.v6.flow_label)) {
+ wpa_printf(MSG_ERROR, "Invalid flow label");
+ return -1;
+ }
+ os_memcpy(param->ip_params.v6.flow_label, qos_policy_data.classifierParams.flowLabelIpv6.data(),
+ sizeof(qos_policy_data.classifierParams.flowLabelIpv6));
+
+ /* Classifier Mask - bit 7 = flow level */
+ classifier_mask |= BIT(7);
+ }
+
+ param->classifier_mask = classifier_mask;
+ return 0;
+}
+
+static int scs_parse_type4(struct tclas_element *elem, QosPolicyScsData qos_policy_data)
+{
+ struct type4_params type4_param;
+ memset(&type4_param, 0, sizeof(type4_param));
+
+ if (set_type4_frame_classifier(qos_policy_data, &type4_param) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set frame_classifier 4");
+ return -1;
+ }
+
+ os_memcpy(&elem->frame_classifier.type4_param,
+ &type4_param, sizeof(struct type4_params));
+ return 0;
+}
+
+/**
+ * This is a request to the AP (if it supports the feature) to apply the QoS policy
+ * on traffic in the Downlink.
+ */
std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
StaIface::addQosPolicyRequestForScsInternal(const std::vector<QosPolicyScsData>& qosPolicyData)
{
- return {std::vector<QosPolicyScsRequestStatus>(),
- createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
+ struct scs_desc_elem desc_elem;
+ int user_priority, num_qos_policies;
+ unsigned int num_scs_ids = 0;
+ std::vector<QosPolicyScsRequestStatus> reports;
+
+ if (wpa_s->ongoing_scs_req) {
+ wpa_printf(MSG_ERROR, "AIDL: SCS Request already in queue");
+ return {std::vector<QosPolicyScsRequestStatus>(),
+ createStatus(SupplicantStatusCode::FAILURE_ONGOING_REQUEST)};
+ }
+ free_up_scs_desc(scs_data);
+
+ /**
+ * format:
+ * [scs_id=<decimal number>] [scs_up=<0-7>]
+ * [classifier params based on classifier type]
+ * [scs_id=<decimal number>] ...
+ */
+ num_qos_policies = qosPolicyData.size();
+ for (int i = 0; i < num_qos_policies; i++) {
+ struct scs_desc_elem *new_desc_elems;
+ struct active_scs_elem *active_scs_desc;
+ struct tclas_element *elem;
+ bool scsid_active = false;
+ QosPolicyScsRequestStatus status;
+
+ memset(&desc_elem, 0, sizeof(desc_elem));
+ desc_elem.scs_id = qosPolicyData[i].policyId;
+ status.policyId = desc_elem.scs_id;
+ desc_elem.request_type = SCS_REQ_ADD;
+ dl_list_for_each(active_scs_desc, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ if (desc_elem.scs_id == active_scs_desc->scs_id) {
+ scsid_active = true;
+ break;
+ }
+ }
+
+ if (scsid_active) {
+ wpa_printf(MSG_ERROR, "SCSID %d already active",
+ desc_elem.scs_id);
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::ALREADY_ACTIVE;
+ reports.push_back(status);
+ continue;
+ }
+
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::INVALID;
+ user_priority = qosPolicyData[i].userPriority;
+ if (user_priority < 0 || user_priority > 7) {
+ wpa_printf(MSG_ERROR,
+ "Intra-Access user priority invalid %d", user_priority);
+ reports.push_back(status);
+ continue;
+ }
+
+ desc_elem.intra_access_priority = user_priority;
+ desc_elem.scs_up_avail = true;
+
+ /**
+ * Supported classifier type 4.
+ */
+ desc_elem.tclas_elems = (struct tclas_element *) os_malloc(sizeof(struct tclas_element));
+ if (!desc_elem.tclas_elems) {
+ wpa_printf(MSG_ERROR,
+ "Classifier type4 failed with Bad malloc");
+ reports.push_back(status);
+ continue;
+ }
+
+ elem = desc_elem.tclas_elems;
+ memset(elem, 0, sizeof(struct tclas_element));
+ elem->classifier_type = 4;
+ if (scs_parse_type4(elem, qosPolicyData[i]) < 0) {
+ os_free(elem);
+ reports.push_back(status);
+ continue;
+ }
+
+ desc_elem.num_tclas_elem = 1;
+
+ /* Reallocate memory to scs_desc_elems to accomodate further policies */
+ new_desc_elems = static_cast<struct scs_desc_elem *>(os_realloc(scs_data->scs_desc_elems,
+ (num_scs_ids + 1) * sizeof(struct scs_desc_elem)));
+ if (!new_desc_elems) {
+ os_free(elem);
+ reports.push_back(status);
+ continue;
+ }
+
+ scs_data->scs_desc_elems = new_desc_elems;
+ os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_ids *
+ sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
+ num_scs_ids++;
+ scs_data->num_scs_desc = num_scs_ids;
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::SENT;
+ reports.push_back(status);
+ }
+ wpas_send_scs_req(wpa_s);
+ return {std::vector<QosPolicyScsRequestStatus>(reports),
+ ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
StaIface::removeQosPolicyForScsInternal(const std::vector<uint8_t>& scsPolicyIds)
{
- return {std::vector<QosPolicyScsRequestStatus>(),
- createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
+ struct scs_desc_elem desc_elem;
+ int count;
+ unsigned int num_scs_ids = 0;
+ std::vector<QosPolicyScsRequestStatus> reports;
+ struct active_scs_elem *scs_desc;
+
+ if (wpa_s->ongoing_scs_req) {
+ wpa_printf(MSG_ERROR, "AIDL: SCS Request already in queue");
+ return {std::vector<QosPolicyScsRequestStatus>(),
+ createStatus(SupplicantStatusCode::FAILURE_ONGOING_REQUEST)};
+ }
+ free_up_scs_desc(scs_data);
+
+ count = scsPolicyIds.size();
+ for (int i = 0; i < count; i++) {
+ struct scs_desc_elem *new_desc_elems;
+ QosPolicyScsRequestStatus status;
+ bool policy_id_exists = false;
+
+ memset(&desc_elem, 0, sizeof(desc_elem));
+ desc_elem.scs_id = scsPolicyIds[i];
+ status.policyId = scsPolicyIds[i];
+ desc_elem.request_type = SCS_REQ_REMOVE;
+ dl_list_for_each(scs_desc, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ if (desc_elem.scs_id == scs_desc->scs_id) {
+ policy_id_exists = true;
+ break;
+ }
+ }
+ if (policy_id_exists == false) {
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::NOT_EXIST;
+ reports.push_back(status);
+ continue;
+ }
+
+ new_desc_elems = static_cast<struct scs_desc_elem *>(os_realloc(scs_data->scs_desc_elems, (num_scs_ids + 1) *
+ sizeof(struct scs_desc_elem)));
+ if (!new_desc_elems) {
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::INVALID;
+ reports.push_back(status);
+ continue;
+ }
+
+ scs_data->scs_desc_elems = new_desc_elems;
+ os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_ids *
+ sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
+ num_scs_ids++;
+ scs_data->num_scs_desc = num_scs_ids;
+ status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::SENT;
+ reports.push_back(status);
+ }
+ wpas_send_scs_req(wpa_s);
+
+ return {std::vector<QosPolicyScsRequestStatus>(reports),
+ ndk::ScopedAStatus::ok()};
}
/**
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 23a5ad9..cd272e3 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -1377,3 +1377,12 @@
{
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SIGNAL_CHANGE);
}
+
+void wpas_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
+ unsigned int num_scs_resp, int **scs_resp)
+{
+ if (!wpa_s || !num_scs_resp || !scs_resp)
+ return;
+
+ wpas_aidl_notify_qos_policy_scs_response(wpa_s, num_scs_resp, scs_resp);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 914f950..84ef898 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -226,5 +226,7 @@
void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *entry);
void wpas_notify_signal_change(struct wpa_supplicant *wpa_s);
+void wpas_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
+ unsigned int num_scs_resp, int **scs_resp);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index a561891..ff648b2 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -599,8 +599,9 @@
size_t len)
{
u8 dialog_token;
- unsigned int i, count;
+ unsigned int i, count, num_active_scs, j = 0;
struct active_scs_elem *scs_desc, *prev;
+ int *scs_resp[2];
if (len < 2)
return;
@@ -632,6 +633,26 @@
return;
}
+ num_active_scs = dl_list_len(&wpa_s->active_scs_ids);
+ if (num_active_scs < count) {
+ wpa_printf(MSG_ERROR, "Unexpected number of SCS responses."
+ " Expected < %d, received %d", num_active_scs, count);
+ return;
+ }
+
+ scs_resp[0] = (int *) os_zalloc(num_active_scs);
+ if (!scs_resp[0]) {
+ wpa_printf(MSG_ERROR, "Failed to allocate memory for scs_resp");
+ return;
+ }
+
+ scs_resp[1] = (int *) os_zalloc(num_active_scs);
+ if (!scs_resp[1]) {
+ os_free(scs_resp[0]);
+ wpa_printf(MSG_ERROR, "Failed to allocate memory for scs_resp");
+ return;
+ }
+
for (i = 0; i < count; i++) {
u8 id;
u16 status;
@@ -664,6 +685,8 @@
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
" SCSID=%u status_code=%u", MAC2STR(src), id, status);
+ scs_resp[0][j] = id;
+ scs_resp[1][j++] = status;
}
eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
@@ -676,10 +699,17 @@
WPA_EVENT_SCS_RESULT "bssid=" MACSTR
" SCSID=%u status_code=response_not_received",
MAC2STR(src), scs_desc->scs_id);
+ if (j < num_active_scs) {
+ scs_resp[0][j] = scs_desc->scs_id;
+ scs_resp[1][j++] = -1; /* TIMEOUT indicator for AIDL */
+ }
dl_list_del(&scs_desc->list);
os_free(scs_desc);
}
}
+ wpas_notify_qos_policy_scs_response(wpa_s, j, scs_resp);
+ os_free(scs_resp[0]);
+ os_free(scs_resp[1]);
}