Merge changes from topic "qos-r3-hal-impl" into main

* changes:
  Move downlink-specific QoS processing into an if-block.
  Add method to convert from AIDL QosCharacteristics type to the supplicant equivalent.
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index cc7af8c..dbe7b29 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -3686,3 +3686,50 @@
 
 	return ieee802_11_defrag_data(data, len, true);
 }
+
+
+unsigned int is_ap_t2lm_negotiation_supported(const u8 *mle, size_t mle_len)
+{
+	u16 ml_control;
+	u16 mld_capabilities;
+	size_t offset =
+		2 /* Multi Link Control */ +
+		1 /* Common Info Length field */ +
+		ETH_ALEN /* MLD MAC Address field */;
+
+	if(!mle || mle_len < offset)
+	    return 0;
+
+	ml_control = WPA_GET_LE16(mle);
+	wpa_printf(MSG_DEBUG, "%s: ML control field 0x%x", __func__, ml_control);
+
+	if (!(ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA)) {
+	    wpa_printf(MSG_DEBUG, "MLD capabilities not present");
+	    return 0;
+	}
+
+	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID)
+	    offset++;
+
+	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT)
+	    offset++;
+
+	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO)
+	    offset += 2;
+
+	if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA)
+	    offset += 2;
+
+	if (mle_len < (offset + 2)) {
+	    wpa_printf(MSG_ERROR, "Not suffcient length for MLD capabilities");
+	    return 0;
+	}
+
+	mld_capabilities = WPA_GET_LE16(mle + offset);
+	wpa_printf(MSG_DEBUG, "MLD capabilities 0x%x", mld_capabilities);
+	if(!(mld_capabilities &
+	     EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK))
+	    return 0;
+
+	return 1;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 854857e..6f4fe80 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -373,4 +373,5 @@
 enum chan_width get_sta_operation_chan_width(enum chan_width ap_operation_chan_width,
 					     struct supported_chan_width sta_supported_width);
 
+unsigned int is_ap_t2lm_negotiation_supported(const u8 *mle, size_t mle_len);
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/pae/aidl/aidl_psk.cpp b/src/pae/aidl/aidl_psk.cpp
index 67afef0..53f4f4f 100644
--- a/src/pae/aidl/aidl_psk.cpp
+++ b/src/pae/aidl/aidl_psk.cpp
@@ -74,6 +74,7 @@
 	if (pskPlugin == NULL)
 		return -ENODEV;
 
+        n++;
 	n = n * 8;
 	if (n < 8)
 		return -ENODEV;
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index e3f7532..a4c2c36 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -1881,6 +1881,7 @@
 		}
 		capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
 		capa.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
+		capa.apTidToLinkMapNegotiationSupported = wpa_s->ap_t2lm_negotiation_support;
 	} else {
 		capa.technology = WifiTechnology::UNKNOWN;
 		capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
@@ -2520,11 +2521,46 @@
 }
 
 ::ndk::ScopedAStatus StaIface::configureMscsInternal(const MscsParams& params) {
-	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct robust_av_data *robust_av = &wpa_s->robust_av;
+	os_memset(robust_av, 0, sizeof(struct robust_av_data));
+
+	if (params.upLimit < 0 || params.upLimit > 7) {
+		wpa_printf(MSG_ERROR, "Invalid MSCS params - upLimit=%d", params.upLimit);
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+	if (params.streamTimeoutUs < 0 || params.streamTimeoutUs > 60000000 /* 60 sec */) {
+		wpa_printf(MSG_ERROR, "Invalid MSCS params - streamTimeoutUs=%d", params.streamTimeoutUs);
+		return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+	}
+
+	robust_av->request_type = SCS_REQ_ADD;
+	robust_av->up_bitmap = params.upBitmap;
+	robust_av->up_limit = params.upLimit;
+	robust_av->stream_timeout = params.streamTimeoutUs;
+	robust_av->frame_classifier[0] = params.frameClassifierMask;  // single type-4 frame classifier mask
+	robust_av->frame_classifier_len = 1;
+
+	int status = wpas_send_mscs_req(wpa_s);
+	wpa_printf(MSG_INFO, "MSCS add request status: %d", status);
+
+	// Mark config as invalid to avoid retransmitting automatically.
+	robust_av->valid_config = false;
+	return ndk::ScopedAStatus::ok();
 }
 
 ::ndk::ScopedAStatus StaIface::disableMscsInternal() {
-	return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	struct robust_av_data *robust_av = &wpa_s->robust_av;
+	os_memset(robust_av, 0, sizeof(struct robust_av_data));
+
+	robust_av->request_type = SCS_REQ_REMOVE;
+	robust_av->valid_config = false;
+
+	int status = wpas_send_mscs_req(wpa_s);
+	wpa_printf(MSG_INFO, "MSCS remove request status: %d", status);
+
+	return ndk::ScopedAStatus::ok();
 }
 
 /**
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7c23727..fc93305 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3351,6 +3351,9 @@
 			}
 			if (req_elems.rrm_enabled)
 				wpa_s->rrm.rrm_used = 1;
+			wpa_s->ap_t2lm_negotiation_support =
+				is_ap_t2lm_negotiation_supported(resp_elems.basic_mle,
+				resp_elems.basic_mle_len);
 		}
 	}
 
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4b13f3e..0890110 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -986,6 +986,7 @@
 	unsigned int connection_channel_bandwidth:5;
 	unsigned int disable_mbo_oce:1;
 	unsigned int connection_11b_only:1;
+	unsigned int ap_t2lm_negotiation_support:1;
 
 	struct os_reltime last_mac_addr_change;
 	enum wpas_mac_addr_style last_mac_addr_style;