diff --git a/Kbuild b/Kbuild
index 0f91594a9c0a..e84c8647e161 100644
--- a/Kbuild
+++ b/Kbuild
@@ -3369,6 +3369,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
diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h
index e161b9b33d32..0ebb5ebcca27 100644
--- a/components/mlme/core/inc/wlan_mlme_main.h
+++ b/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
};
diff --git a/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h b/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h
index bcc46424d65d..03910298a7ae 100644
--- a/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h
+++ b/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
diff --git a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
index 3fa16313d241..1c1b375fc8af 100644
--- a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c
+++ b/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;
diff --git a/configs/default_defconfig b/configs/default_defconfig
index e2a683150adb..554b861879c9 100644
--- a/configs/default_defconfig
+++ b/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),)
diff --git a/core/hdd/inc/hdd_dp_cfg.h b/core/hdd/inc/hdd_dp_cfg.h
index f65f35fce467..58d34a18170a 100644
--- a/core/hdd/inc/hdd_dp_cfg.h
+++ b/core/hdd/inc/hdd_dp_cfg.h
@@ -353,6 +353,65 @@
#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
+#ifdef WLAN_FEATURE_MSCS
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_VO_PKT_COUNT_THRESHOLD \
+ CFG_INI_UINT( \
+ "mscs_pkt_threshold", \
+ 0, \
+ 10000, \
+ 1200, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Voice pkt count threshold")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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
/*
*
@@ -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 \
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 76b602a28be7..b39bf067558b 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/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;
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 3d629419ec7b..41fcbce3ef66 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/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;
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 31c246e45f6c..1334c4c8599b 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -21014,6 +21014,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)
{
@@ -21025,6 +21047,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);
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 9516c2864ad7..16053aad5a51 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/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) {
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index 2e6f84afb9e7..e76db9bad531 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_tx_rx.c
@@ -3404,6 +3404,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
@@ -3607,6 +3631,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);
diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h
index cbe6e11aecd8..69ed5a0089ac 100644
--- a/core/mac/inc/wni_api.h
+++ b/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,
diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h
index cb3784cdf0d4..068fab32c8b9 100644
--- a/core/mac/src/include/parser_api.h
+++ b/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);
diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c
index 2c895f6a1aaf..6d984025d446 100644
--- a/core/mac/src/pe/lim/lim_process_message_queue.c
+++ b/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:
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index 4a9496d3f36b..933aa735d6fa 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/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);
diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c
index 50b248bc11af..0e6933c75a54 100644
--- a/core/mac/src/pe/lim/lim_send_management_frames.c
+++ b/core/mac/src/pe/lim/lim_send_management_frames.c
@@ -56,6 +56,7 @@
#include "lim_process_fils.h"
#include "wlan_utility.h"
#include
+#include
/**
*
@@ -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
diff --git a/core/mac/src/pe/lim/lim_types.h b/core/mac/src/pe/lim/lim_types.h
index 1d04e74ee052..fed50a994eaf 100644
--- a/core/mac/src/pe/lim/lim_types.h
+++ b/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
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index cc0245ea72f6..be1f31e056b9 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/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:
diff --git a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c
index b6e58d0cfe9c..86d83efb38d6 100644
--- a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c
+++ b/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);
diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c
index 1d20ed722aea..55966c92d317 100644
--- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c
+++ b/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)
{
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 3f7494e783e6..fd8fcf88e060 100644
--- a/core/sme/inc/sme_api.h
+++ b/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
diff --git a/core/sme/src/qos/sme_qos.c b/core/sme/src/qos/sme_qos.c
index 29ed5f5a85d0..d64fab5351a4 100644
--- a/core/sme/src/qos/sme_qos.c
+++ b/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.