Browse Source

qcacld-3.0: Trigger MSCS action frame

Add logic to send MSCS action frame to AP based on
voice tx packet.

Change-Id: I272addfcb60e459043426950d00ba5957b594505
CRs-Fixed: 2791796
Abhinav Kumar 4 years ago
parent
commit
c526619159

+ 3 - 0
Kbuild

@@ -3400,6 +3400,9 @@ cppflags-$(CONFIG_ADAPTIVE_11R) += -DWLAN_ADAPTIVE_11R
 #Flag to enable/disable sae single pmk feature feature
 cppflags-$(CONFIG_SAE_SINGLE_PMK) += -DWLAN_SAE_SINGLE_PMK
 
+#Flag to enable/disable mscs feature
+cppflags-$(CONFIG_FEATURE_MSCS) += -DWLAN_FEATURE_MSCS
+
 #Flag to enable NUD tracking
 cppflags-$(CONFIG_WLAN_NUD_TRACKING) += -DWLAN_NUD_TRACKING
 

+ 92 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -144,6 +144,94 @@ struct wlan_mlme_roam {
 #endif
 };
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * struct tclas_mask - TCLAS Mask Elements for mscs request
+ * @classifier_type: specifies the type of classifier parameters
+ * in TCLAS element. Currently driver supports classifier type = 4 only.
+ * @classifier_mask: Mask for tclas elements. For example, if
+ * classifier type = 4, value of classifier mask is 0x5F.
+ * @info: information of classifier type
+ */
+struct tclas_mask {
+	uint8_t classifier_type;
+	uint8_t classifier_mask;
+	union {
+		struct {
+			uint8_t version;
+			union {
+				struct {
+					uint8_t source[4];
+					uint8_t dest[4];
+					uint16_t src_port;
+					uint16_t dest_port;
+					uint8_t dscp;
+					uint8_t proto;
+					uint8_t reserved;
+				} ip_v4_params;
+				struct {
+					uint8_t source[16];
+					uint8_t dest[16];
+					uint16_t src_port;
+					uint16_t dest_port;
+					uint8_t DSCP;
+					uint8_t next_header;
+					uint8_t flow_label[3];
+				} ip_v6_params;
+			} params;
+		} ip_params; /* classifier_type = 4 */
+	} info;
+};
+
+/**
+ * enum scs_request_type - scs request type to peer
+ * @SCS_REQ_ADD: To set mscs parameters
+ * @SCS_REQ_REMOVE: Remove mscs parameters
+ * @SCS_REQ_CHANGE: Update mscs parameters
+ */
+enum scs_request_type {
+	SCS_REQ_ADD = 0,
+	SCS_REQ_REMOVE = 1,
+	SCS_REQ_CHANGE = 2,
+};
+
+/**
+ * struct descriptor_element - mscs Descriptor element
+ * @request_type: mscs request type defined in enum scs_request_type
+ * @user_priority_control: To set user priority of tx packet
+ * @stream_timeout: minimum timeout value, in TUs, for maintaining
+ * variable user priority in the MSCS list.
+ * @tclas_mask: to specify how incoming MSDUs are classified into
+ * streams in MSCS
+ * @status_code: status of mscs request
+ */
+struct descriptor_element {
+	uint8_t request_type;
+	uint16_t user_priority_control;
+	uint64_t stream_timeout;
+	struct tclas_mask tclas_mask;
+	uint8_t status_code;
+};
+
+/**
+ * struct mscs_req_info - mscs request information
+ * @vdev_id: session id
+ * @bssid: peer bssid
+ * @dialog_token: Token number of mscs req action frame
+ * @dec: mscs Descriptor element defines information about
+ * the parameters used to classify streams
+ * @is_mscs_req_sent: To Save mscs req request if any (only
+ * one can be outstanding at any time)
+ */
+struct mscs_req_info {
+	uint8_t vdev_id;
+	struct qdf_mac_addr bssid;
+	uint8_t dialog_token;
+	struct descriptor_element dec;
+	bool is_mscs_req_sent;
+};
+#endif
+
 /**
  * struct mlme_legacy_priv - VDEV MLME legacy priv object
  * @chan_switch_in_progress: flag to indicate that channel switch is in progress
@@ -170,6 +258,7 @@ struct wlan_mlme_roam {
  * @fils_con_info: Pointer to fils connection info from csr roam profile
  * @opr_rate_set: operational rates set
  * @ext_opr_rate_set: extended operational rates set
+ * @mscs_req_info: Information related to mscs request
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -197,6 +286,9 @@ struct mlme_legacy_priv {
 #endif
 	struct mlme_cfg_str opr_rate_set;
 	struct mlme_cfg_str ext_opr_rate_set;
+#ifdef WLAN_FEATURE_MSCS
+	struct mscs_req_info mscs_req_info;
+#endif
 };
 
 

+ 31 - 0
components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h

@@ -64,6 +64,37 @@ QDF_STATUS mlme_unregister_vdev_mgr_ops(struct vdev_mlme_obj *vdev_mlme);
 QDF_STATUS mlme_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev,
 					       bool val);
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * mlme_set_is_mscs_req_sent() - set mscs frame req flag
+ * @vdev: vdev pointer
+ * @val: value to be set
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val);
+
+/**
+ * mlme_get_is_mscs_req_sent() - get mscs frame req flag
+ * @vdev: vdev pointer
+ *
+ * Return: value of mscs flag
+ */
+bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev);
+#else
+static inline
+QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline
+bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+#endif
+
 /**
  * mlme_is_chan_switch_in_progress() - get mlme priv restart in progress
  * @vdev: vdev pointer

+ 30 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -588,6 +588,36 @@ QDF_STATUS mlme_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_MSCS
+QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->mscs_req_info.is_mscs_req_sent = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return false;
+	}
+
+	return mlme_priv->mscs_req_info.is_mscs_req_sent;
+}
+#endif
+
 bool mlme_is_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev)
 {
 	struct mlme_legacy_priv *mlme_priv;

+ 3 - 0
configs/default_defconfig

@@ -300,6 +300,9 @@ CONFIG_ADAPTIVE_11R := y
 #Flag to enable sae single pmk feature
 CONFIG_SAE_SINGLE_PMK := y
 
+#Flag to enable mscs feature
+CONFIG_FEATURE_MSCS := y
+
 #Flag to enable FILS Feature (11ai)
 CONFIG_WLAN_FEATURE_FILS := y
 ifneq ($(CONFIG_QCA_CLD_WLAN),)

+ 60 - 0
core/hdd/inc/hdd_dp_cfg.h

@@ -353,6 +353,65 @@
 
 #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
 
+#ifdef WLAN_FEATURE_MSCS
+/*
+ * <ini>
+ * mscs_pkt_threshold - Voice pkt count threshold
+ *
+ * @Min: 0
+ * @Max: 10000
+ * @Default: 1200
+ *
+ * This ini specifies the Voice pkt count threshold to
+ * Send MSCS action frame to AP
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_VO_PKT_COUNT_THRESHOLD \
+		CFG_INI_UINT( \
+		"mscs_pkt_threshold", \
+		0, \
+		10000, \
+		1200, \
+		CFG_VALUE_OR_DEFAULT, \
+		"Voice pkt count threshold")
+
+/*
+ * <ini>
+ * mscs_voice_interval - mscs voice interval in sec
+ *
+ * @Min: 0
+ * @Max: 300
+ * @Default: 30
+ *
+ * This ini specifies the mscs voice interval to
+ * monitor voice tx packet count to send MSCS action frame
+ *
+ * Related: mscs_pkt_threshold
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_MSCS_VOICE_INTERVAL \
+		CFG_INI_UINT( \
+		"mscs_voice_interval", \
+		0, \
+		300, \
+		30, \
+		CFG_VALUE_OR_DEFAULT, \
+		"mscs voice interval")
+
+#define CFG_MSCS_FEATURE_ALL \
+		CFG(CFG_VO_PKT_COUNT_THRESHOLD) \
+		CFG(CFG_MSCS_VOICE_INTERVAL)
+
+#else
+#define CFG_MSCS_FEATURE_ALL
+#endif
+
 #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH
 /*
  * <ini>
@@ -1445,6 +1504,7 @@
 	CFG(CFG_DP_RX_WAKELOCK_TIMEOUT) \
 	CFG(CFG_DP_NUM_DP_RX_THREADS) \
 	CFG(CFG_DP_HTC_WMI_CREDIT_CNT) \
+	CFG_MSCS_FEATURE_ALL \
 	CFG_DP_ENABLE_FASTPATH_ALL \
 	CFG_HDD_DP_BUS_BANDWIDTH \
 	CFG_DP_DRIVER_TCP_DELACK \

+ 5 - 0
core/hdd/inc/wlan_hdd_cfg.h

@@ -175,6 +175,11 @@ struct hdd_config {
 	bool enable_latency_crit_clients;
 #endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/
 
+#ifdef WLAN_FEATURE_MSCS
+	uint32_t mscs_pkt_threshold;
+	uint32_t mscs_voice_interval;
+#endif /* WLAN_FEATURE_MSCS */
+
 #ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK
 	bool del_ack_enable;
 	uint32_t del_ack_threshold_high;

+ 5 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1316,6 +1316,11 @@ struct hdd_adapter {
 	uint64_t prev_fwd_rx_packets;
 #endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/
 
+#ifdef WLAN_FEATURE_MSCS
+	unsigned long mscs_prev_tx_vo_pkts;
+	uint32_t mscs_counter;
+#endif /* WLAN_FEATURE_MSCS */
+
 #if  defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \
 				defined(QCA_HL_NETDEV_FLOW_CONTROL)
 	qdf_mc_timer_t tx_flow_control_timer;

+ 23 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -20929,6 +20929,28 @@ wlan_hdd_cfg80211_indicate_disconnect(struct hdd_adapter *adapter,
 }
 #endif
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * reset_mscs_params() - Reset mscs parameters
+ * @adapter: pointer to adapter structure
+ *
+ * Reset mscs parameters whils disconnection
+ *
+ * Return: None
+ */
+static void reset_mscs_params(struct hdd_adapter *adapter)
+{
+	mlme_set_is_mscs_req_sent(adapter->vdev, false);
+	adapter->mscs_counter = 0;
+}
+#else
+static inline
+void reset_mscs_params(struct hdd_adapter *adapter)
+{
+	return;
+}
+#endif
+
 int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason,
 			enum wlan_reason_code mac_reason)
 {
@@ -20940,6 +20962,7 @@ int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason,
 
 	/*stop tx queues */
 	hdd_debug("Disabling queues");
+	reset_mscs_params(adapter);
 	wlan_hdd_netif_queue_control(adapter,
 		WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, WLAN_CONTROL_PATH);
 

+ 39 - 0
core/hdd/src/wlan_hdd_main.c

@@ -10065,6 +10065,41 @@ void hdd_set_vdev_bundle_require_flag(uint16_t vdev_id,
 #endif
 
 #define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
+
+#ifdef WLAN_FEATURE_MSCS
+static
+void hdd_send_mscs_action_frame(struct hdd_context *hdd_ctx,
+				struct hdd_adapter *adapter)
+{
+	uint64_t mscs_vo_pkt_delta;
+	unsigned long tx_vo_pkts;
+
+	tx_vo_pkts = adapter->hdd_stats.tx_rx_stats.tx_classified_ac[SME_AC_VO];
+
+	if (!adapter->mscs_counter)
+		adapter->mscs_prev_tx_vo_pkts = tx_vo_pkts;
+
+	adapter->mscs_counter++;
+
+	if (adapter->mscs_counter * hdd_ctx->config->bus_bw_compute_interval >=
+	    hdd_ctx->config->mscs_voice_interval * 1000) {
+	    adapter->mscs_counter = 0;
+		mscs_vo_pkt_delta =
+				HDD_BW_GET_DIFF(tx_vo_pkts,
+						adapter->mscs_prev_tx_vo_pkts);
+		if (mscs_vo_pkt_delta > hdd_ctx->config->mscs_pkt_threshold &&
+		    !mlme_get_is_mscs_req_sent(adapter->vdev))
+			sme_send_mscs_action_frame(adapter->vdev_id);
+	}
+}
+#else
+static inline
+void hdd_send_mscs_action_frame(struct hdd_context *hdd_ctx,
+				struct hdd_adapter *adapter)
+{
+}
+#endif
+
 static void __hdd_bus_bw_work_handler(struct hdd_context *hdd_ctx)
 {
 	struct hdd_adapter *adapter = NULL, *con_sap_adapter = NULL;
@@ -10113,6 +10148,10 @@ static void __hdd_bus_bw_work_handler(struct hdd_context *hdd_ctx)
 		tx_bytes = HDD_BW_GET_DIFF(adapter->stats.tx_bytes,
 					   adapter->prev_tx_bytes);
 
+		if (adapter->device_mode == QDF_STA_MODE &&
+		   hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter)))
+			hdd_send_mscs_action_frame(hdd_ctx, adapter);
+
 		if (adapter->device_mode == QDF_SAP_MODE ||
 		    adapter->device_mode == QDF_P2P_GO_MODE ||
 		    adapter->device_mode == QDF_NDI_MODE) {

+ 25 - 0
core/hdd/src/wlan_hdd_tx_rx.c

@@ -3378,6 +3378,30 @@ static void hdd_ini_tx_flow_control(struct hdd_config *config,
 }
 #endif
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * hdd_ini_mscs_params() - Initialize INIs related to MSCS feature
+ * @config: pointer to hdd config
+ * @psoc: pointer to psoc obj
+ *
+ * Return: none
+ */
+static void hdd_ini_mscs_params(struct hdd_config *config,
+				struct wlan_objmgr_psoc *psoc)
+{
+	config->mscs_pkt_threshold =
+		cfg_get(psoc, CFG_VO_PKT_COUNT_THRESHOLD);
+	config->mscs_voice_interval =
+		cfg_get(psoc, CFG_MSCS_VOICE_INTERVAL);
+}
+
+#else
+static inline void hdd_ini_mscs_params(struct hdd_config *config,
+				       struct wlan_objmgr_psoc *psoc)
+{
+}
+#endif
+
 #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH
 /**
  * hdd_ini_tx_flow_control() - Initialize INIs concerned about bus bandwidth
@@ -3581,6 +3605,7 @@ void hdd_dp_cfg_update(struct wlan_objmgr_psoc *psoc,
 	hdd_ini_tx_flow_control(config, psoc);
 	hdd_ini_bus_bandwidth(config, psoc);
 	hdd_ini_tcp_settings(config, psoc);
+	hdd_ini_mscs_params(config, psoc);
 
 	hdd_ini_tcp_del_ack_settings(config, psoc);
 

+ 2 - 1
core/mac/inc/wni_api.h

@@ -67,8 +67,9 @@ enum eWniMsgTypes {
 	eWNI_SME_DELTS_REQ = SIR_SME_MSG_TYPES_BEGIN + 30,
 	eWNI_SME_DELTS_RSP = SIR_SME_MSG_TYPES_BEGIN + 31,
 	eWNI_SME_DELTS_IND = SIR_SME_MSG_TYPES_BEGIN + 32,
+	eWNI_SME_MSCS_REQ = SIR_SME_MSG_TYPES_BEGIN + 33,
 	/*
-	 * unused SIR_SME_MSG_TYPES_BEGIN + 33 to
+	 * unused SIR_SME_MSG_TYPES_BEGIN + 34 to
 	 * to SIR_SME_MSG_TYPES_BEGIN + 35
 	 */
 	eWNI_SME_ASSOC_IND_UPPER_LAYER = SIR_SME_MSG_TYPES_BEGIN + 36,

+ 7 - 0
core/mac/src/include/parser_api.h

@@ -34,6 +34,7 @@
 #include "dot11f.h"
 #include "lim_ft_defs.h"
 #include "lim_session.h"
+#include "wlan_mlme_main.h"
 
 #define COUNTRY_STRING_LENGTH    (3)
 #define COUNTRY_INFO_MAX_CHANNEL (84)
@@ -975,6 +976,12 @@ void populate_dot11f_tspec(struct mac_tspec_ie *pOld, tDot11fIETSPEC *pDot11f);
 void populate_dot11f_wmmtspec(struct mac_tspec_ie *pOld,
 			      tDot11fIEWMMTSPEC *pDot11f);
 
+#ifdef WLAN_FEATURE_MSCS
+void
+populate_dot11f_mscs_dec_element(struct mscs_req_info *mscs_req,
+				 tDot11fmscs_request_action_frame *dot11f);
+#endif
+
 QDF_STATUS
 populate_dot11f_tclas(struct mac_context *mac,
 		tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f);

+ 1 - 0
core/mac/src/pe/lim/lim_process_message_queue.c

@@ -1742,6 +1742,7 @@ static void lim_process_messages(struct mac_context *mac_ctx,
 	case eWNI_SME_DEAUTH_CNF:
 	case eWNI_SME_ASSOC_CNF:
 	case eWNI_SME_ADDTS_REQ:
+	case eWNI_SME_MSCS_REQ:
 	case eWNI_SME_DELTS_REQ:
 	case eWNI_SME_SESSION_UPDATE_PARAM:
 	case eWNI_SME_CHNG_MCC_BEACON_INTERVAL:

+ 62 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -3064,6 +3064,63 @@ send_failure_addts_rsp:
 			       smesessionId);
 }
 
+#ifdef WLAN_FEATURE_MSCS
+static void
+__lim_process_sme_mscs_req(struct mac_context *mac, uint32_t *msg_buf)
+{
+	struct qdf_mac_addr peer_mac;
+	struct mscs_req_info *mscs_req;
+	struct pe_session *pe_session;
+	uint8_t pe_session_id;
+
+	if (!msg_buf) {
+		pe_err("Buffer is Pointing to NULL");
+		return;
+	}
+
+	mscs_req = (struct mscs_req_info *) msg_buf;
+	pe_session = pe_find_session_by_bssid(mac, mscs_req->bssid.bytes,
+					      &pe_session_id);
+	if (!pe_session) {
+		pe_err("Session Does not exist for bssid: " QDF_MAC_ADDR_FMT,
+			QDF_MAC_ADDR_REF(mscs_req->bssid.bytes));
+		return;
+	}
+
+	if (!LIM_IS_STA_ROLE(pe_session)) {
+		pe_err("MSCS req received on AP - ignoring");
+		return;
+	}
+
+	if (QDF_IS_STATUS_ERROR(wlan_vdev_mlme_is_active(pe_session->vdev))) {
+		pe_err("mscs req in unexpected vdev SM state:%d",
+		       wlan_vdev_mlme_get_state(pe_session->vdev));
+		return;
+	}
+
+	if (mscs_req->is_mscs_req_sent) {
+		pe_err("MSCS req already sent");
+		return;
+	}
+
+	qdf_mem_copy(peer_mac.bytes, pe_session->bssId, QDF_MAC_ADDR_SIZE);
+
+	/* save the mscs request */
+	mscs_req->is_mscs_req_sent = true;
+
+	/* ship out the message now */
+	lim_send_mscs_req_action_frame(mac, peer_mac, mscs_req,
+				       pe_session);
+}
+#else
+static inline void
+__lim_process_sme_mscs_req(struct mac_context *mac, uint32_t *msg_buf)
+{
+	return;
+}
+
+#endif
+
 static void
 __lim_process_sme_delts_req(struct mac_context *mac, uint32_t *msg_buf)
 {
@@ -4651,6 +4708,11 @@ bool lim_process_sme_req_messages(struct mac_context *mac,
 		__lim_process_sme_addts_req(mac, msg_buf);
 		break;
 
+	case eWNI_SME_MSCS_REQ:
+		pe_debug("Received MSCS_REQ message");
+		__lim_process_sme_mscs_req(mac, msg_buf);
+		break;
+
 	case eWNI_SME_DELTS_REQ:
 		pe_debug("Received DELTS_REQ message");
 		__lim_process_sme_delts_req(mac, msg_buf);

+ 127 - 0
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -56,6 +56,7 @@
 #include "lim_process_fils.h"
 #include "wlan_utility.h"
 #include <wlan_mlme_api.h>
+#include <wlan_mlme_main.h>
 
 /**
  *
@@ -1093,6 +1094,132 @@ lim_send_addts_req_action_frame(struct mac_context *mac,
 			qdf_status);
 } /* End lim_send_addts_req_action_frame. */
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * lim_mscs_req_tx_complete_cnf()- Confirmation for mscs req sent over the air
+ * @context: pointer to global mac
+ * @buf: buffer
+ * @tx_complete : Sent status
+ * @params; tx completion params
+ *
+ * Return: This returns QDF_STATUS
+ */
+
+static QDF_STATUS lim_mscs_req_tx_complete_cnf(void *context, qdf_nbuf_t buf,
+					       uint32_t tx_complete,
+					       void *params)
+{
+	uint16_t mscs_ack_status;
+	uint16_t reason_code;
+
+	pe_debug("mscs req TX: %s (%d)",
+		 (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ?
+		      "success" : "fail", tx_complete);
+
+	if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) {
+		mscs_ack_status = ACKED;
+		reason_code = QDF_STATUS_SUCCESS;
+	} else {
+		mscs_ack_status = NOT_ACKED;
+		reason_code = QDF_STATUS_E_FAILURE;
+	}
+	if (buf)
+		qdf_nbuf_free(buf);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void lim_send_mscs_req_action_frame(struct mac_context *mac,
+				    struct qdf_mac_addr peer_mac,
+				    struct mscs_req_info *mscs_req,
+				    struct pe_session *pe_session)
+{
+	uint8_t *frame;
+	tDot11fmscs_request_action_frame mscs_req_frame;
+	uint32_t payload, bytes;
+	tpSirMacMgmtHdr peer_mac_hdr;
+	void *packet;
+	QDF_STATUS qdf_status;
+	tpSirMacMgmtHdr mac_hdr;
+
+	qdf_mem_zero(&mscs_req_frame, sizeof(mscs_req_frame));
+
+	mscs_req_frame.Action.action = MCSC_REQ;
+	mscs_req_frame.DialogToken.token = mscs_req->dialog_token;
+	mscs_req_frame.Category.category = ACTION_CATEGORY_RVS;
+	populate_dot11f_mscs_dec_element(mscs_req, &mscs_req_frame);
+	bytes = dot11f_get_packed_mscs_request_action_frameSize(mac,
+					&mscs_req_frame, &payload);
+	if (DOT11F_FAILED(bytes)) {
+		pe_err("Failed to calculate the packed size for an MSCS Request (0x%08x)",
+		       bytes);
+		/* We'll fall back on the worst case scenario: */
+		payload = sizeof(tDot11fmscs_request_action_frame);
+	} else if (DOT11F_WARNED(bytes)) {
+		pe_warn("There were warnings while calculating the packed size for MSCS Request (0x%08x)",
+			bytes);
+	}
+
+	bytes = payload + sizeof(struct qdf_mac_addr);
+
+	qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame,
+				      (void **)&packet);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		pe_err("Failed to allocate %d bytes for an mscs request",
+		       bytes);
+		return;
+	}
+	/* Paranoia: */
+	qdf_mem_zero(frame, bytes);
+
+	lim_populate_mac_header(mac, frame, SIR_MAC_MGMT_FRAME,
+				SIR_MAC_MGMT_ACTION,
+				peer_mac.bytes, pe_session->self_mac_addr);
+	peer_mac_hdr = (tpSirMacMgmtHdr) frame;
+
+	qdf_mem_copy(peer_mac.bytes, pe_session->bssId, QDF_MAC_ADDR_SIZE);
+
+	lim_set_protected_bit(mac, pe_session, peer_mac.bytes, peer_mac_hdr);
+
+	bytes = dot11f_pack_mscs_request_action_frame(mac, &mscs_req_frame,
+						      frame +
+						      sizeof(tSirMacMgmtHdr),
+						      payload, &payload);
+	if (DOT11F_FAILED(bytes)) {
+		pe_err("Failed to pack an mscs Request " "(0x%08x)", bytes);
+		cds_packet_free((void *)packet);
+			return; /* allocated! */
+	} else if (DOT11F_WARNED(bytes)) {
+			pe_warn("There were warnings while packing an mscs Request (0x%08x)",
+				bytes);
+	}
+
+	mac_hdr = (tpSirMacMgmtHdr) frame;
+
+	pe_debug("mscs req TX: vdev id: %d to "QDF_MAC_ADDR_FMT" seq num[%d], frame subtype:%d ",
+		 mscs_req->vdev_id, peer_mac.bytes, mac->mgmtSeqNum,
+		 mac_hdr->fc.subType);
+
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			   frame,
+			   (uint16_t)(sizeof(tSirMacMgmtHdr) + payload));
+	qdf_status =
+		wma_tx_frameWithTxComplete(mac, packet,
+			   (uint16_t) (sizeof(tSirMacMgmtHdr) + payload),
+			   TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7,
+			   lim_tx_complete, frame, lim_mscs_req_tx_complete_cnf,
+			   HAL_USE_PEER_STA_REQUESTED_MASK, pe_session->vdev_id,
+			   false, 0, RATEID_DEFAULT);
+	if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		mlme_set_is_mscs_req_sent(pe_session->vdev, true);
+	} else {
+		pe_err("Could not send an mscs Request (%X)", qdf_status);
+	}
+
+	/* Pkt will be freed up by the callback */
+} /* End lim_send_mscs_req_action_frame */
+#endif
+
 /**
  * lim_assoc_rsp_tx_complete() - Confirmation for assoc rsp OTA
  * @context: pointer to global mac

+ 18 - 0
core/mac/src/pe/lim/lim_types.h

@@ -642,6 +642,24 @@ void lim_send_delts_req_action_frame(struct mac_context *mac, tSirMacAddr peer,
 void lim_send_addts_req_action_frame(struct mac_context *mac, tSirMacAddr peerMacAddr,
 				     tSirAddtsReqInfo *addts, struct pe_session *);
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * lim_send_mscs_req_action_frame() - Send mscs req
+ * @mac_ctx: Handle for mac context
+ * @peer_mac: Mac address of requesting peer
+ * @mscs_req: mscs request buffer
+ * @pe_session: PE session id.
+ *
+ * Builds and sends mscs action frame to the peer.
+ *
+ * Return: void
+ */
+void lim_send_mscs_req_action_frame(struct mac_context *mac,
+				    struct qdf_mac_addr peer_mac,
+				    struct mscs_req_info *mscs_req,
+				    struct pe_session *pe_session);
+#endif
+
 /**
  * lim_send_assoc_rsp_mgmt_frame() - Send assoc response
  * @mac_ctx: Handle for mac context

+ 2 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -255,6 +255,8 @@ char *lim_msg_str(uint32_t msgType)
 		return "eWNI_SME_DEAUTH_CNF";
 	case eWNI_SME_ADDTS_REQ:
 		return "eWNI_SME_ADDTS_REQ";
+	case eWNI_SME_MSCS_REQ:
+		return "eWNI_SME_MSCS_REQ";
 	case eWNI_SME_ADDTS_RSP:
 		return "eWNI_SME_ADDTS_RSP";
 	case eWNI_SME_DELTS_REQ:

+ 1 - 0
core/mac/src/sys/legacy/src/utils/src/mac_trace.c

@@ -238,6 +238,7 @@ uint8_t *mac_trace_get_sme_msg_string(uint16_t sme_msg)
 		CASE_RETURN_STRING(eWNI_SME_DEAUTH_CNF);
 		CASE_RETURN_STRING(eWNI_SME_MIC_FAILURE_IND);
 		CASE_RETURN_STRING(eWNI_SME_ADDTS_REQ);
+		CASE_RETURN_STRING(eWNI_SME_MSCS_REQ);
 		CASE_RETURN_STRING(eWNI_SME_ADDTS_RSP);
 		CASE_RETURN_STRING(eWNI_SME_DELTS_REQ);
 		CASE_RETURN_STRING(eWNI_SME_DELTS_RSP);

+ 22 - 0
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -5057,6 +5057,28 @@ void populate_dot11f_tspec(struct mac_tspec_ie *pOld, tDot11fIETSPEC *pDot11f)
 
 } /* End populate_dot11f_tspec. */
 
+#ifdef WLAN_FEATURE_MSCS
+void
+populate_dot11f_mscs_dec_element(struct mscs_req_info *mscs_req,
+				 tDot11fmscs_request_action_frame *dot11f)
+{
+	dot11f->decriptor_element.request_type =
+			mscs_req->dec.request_type;
+	dot11f->decriptor_element.user_priority_control =
+			mscs_req->dec.user_priority_control;
+	dot11f->decriptor_element.stream_timeout =
+			mscs_req->dec.stream_timeout;
+	dot11f->decriptor_element.tclas_mask.classifier_type =
+			mscs_req->dec.tclas_mask.classifier_type;
+	dot11f->decriptor_element.tclas_mask.classifier_mask =
+			mscs_req->dec.tclas_mask.classifier_mask;
+
+	dot11f->decriptor_element.present = 1;
+	dot11f->decriptor_element.tclas_mask.present = 1;
+
+} /* End populate_dot11f_decriptor_element */
+#endif
+
 void populate_dot11f_wmmtspec(struct mac_tspec_ie *pOld,
 			      tDot11fIEWMMTSPEC *pDot11f)
 {

+ 12 - 0
core/sme/inc/sme_api.h

@@ -2749,6 +2749,18 @@ struct mac_context *sme_get_mac_context(void);
  */
 void sme_display_disconnect_stats(mac_handle_t mac_handle, uint8_t session_id);
 
+#ifdef WLAN_FEATURE_MSCS
+/**
+ * sme_send_mscs_action_frame() - Send MSCS action frame
+ * @vdev_id: sme vdev_id
+ *
+ * This function is used to send down the mscs request to PE
+ *
+ * Return: None
+ */
+void sme_send_mscs_action_frame(uint8_t vdev_id);
+#endif
+
 /**
  * sme_process_msg_callback() - process callback message from LIM
  * @mac: global mac context

+ 49 - 0
core/sme/src/qos/sme_qos.c

@@ -81,6 +81,14 @@
 /* The Dialog Token field shall be set [...] to a non-zero value */
 #define SME_QOS_MIN_DIALOG_TOKEN         1
 #define SME_QOS_MAX_DIALOG_TOKEN         0xFF
+
+#ifdef WLAN_FEATURE_MSCS
+#define MSCS_USER_PRIORITY               0x07C0
+#define MSCS_STREAM_TIMEOUT              60 /* in sec */
+#define MSCS_TCLAS_CLASSIFIER_MASK       0x5F
+#define MSCS_TCLAS_CLASSIFIER_TYPE       4
+#endif
+
 /* Type declarations */
 /* Enumeration of the various states in the QoS state m/c */
 enum sme_qos_states {
@@ -3813,6 +3821,47 @@ QDF_STATUS sme_qos_process_ft_reassoc_rsp_ev(struct mac_context *mac_ctx,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_MSCS
+void sme_send_mscs_action_frame(uint8_t vdev_id)
+{
+	struct mscs_req_info *mscs_req;
+	struct sme_qos_sessioninfo *qos_session;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS qdf_status;
+
+	qos_session = &sme_qos_cb.sessionInfo[vdev_id];
+	if (!qos_session) {
+		sme_debug("qos_session is NULL");
+		return;
+	}
+	mscs_req = qdf_mem_malloc(sizeof(*mscs_req));
+	if (!mscs_req)
+		return;
+
+	mscs_req->vdev_id = vdev_id;
+	qdf_mem_copy(&mscs_req->bssid.bytes[0],
+		     &qos_session->assocInfo.bss_desc->bssId[0],
+		     sizeof(struct qdf_mac_addr));
+
+	mscs_req->dialog_token = sme_qos_assign_dialog_token();
+	mscs_req->dec.request_type = SCS_REQ_ADD;
+	mscs_req->dec.user_priority_control = MSCS_USER_PRIORITY;
+	mscs_req->dec.stream_timeout = (MSCS_STREAM_TIMEOUT * 1000);
+	mscs_req->dec.tclas_mask.classifier_type = MSCS_TCLAS_CLASSIFIER_TYPE;
+	mscs_req->dec.tclas_mask.classifier_mask = MSCS_TCLAS_CLASSIFIER_MASK;
+
+	msg.type = eWNI_SME_MSCS_REQ;
+	msg.reserved = 0;
+	msg.bodyptr = mscs_req;
+	qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE,
+					    QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		sme_err("Fail to send mscs request to PE");
+		qdf_mem_free(mscs_req);
+	}
+}
+#endif
+
 /**
  * sme_qos_add_ts_req() - send ADDTS request.
  * @mac: Pointer to the global MAC parameter structure.