xref: /wlan-driver/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_epcs_api.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name 
17*5113495bSYour Name /*
18*5113495bSYour Name  * DOC: contains EPCS (Emergency Preparedness Communications Service)
19*5113495bSYour Name  * related functionality
20*5113495bSYour Name  */
21*5113495bSYour Name #include <wlan_cmn.h>
22*5113495bSYour Name #include <wlan_cm_public_struct.h>
23*5113495bSYour Name #include "wlan_epcs_api.h"
24*5113495bSYour Name #include <wlan_mlo_epcs.h>
25*5113495bSYour Name #include "wlan_cm_api.h"
26*5113495bSYour Name #include "wlan_mlo_mgr_roam.h"
27*5113495bSYour Name #include "wlan_cmn_ieee80211.h"
28*5113495bSYour Name #include "dot11f.h"
29*5113495bSYour Name 
30*5113495bSYour Name #define EPCS_MIN_DIALOG_TOKEN         1
31*5113495bSYour Name #define EPCS_MAX_DIALOG_TOKEN         0xFF
32*5113495bSYour Name 
33*5113495bSYour Name static struct ac_param_record default_epcs_edca[] = {
34*5113495bSYour Name #ifndef ANI_LITTLE_BIT_ENDIAN
35*5113495bSYour Name 	/* The txop is multiple of 32us units */
36*5113495bSYour Name 	{0x07, 0x95, 79 /* 2.528ms */},
37*5113495bSYour Name 	{0x03, 0x95, 79 /* 2.528ms */},
38*5113495bSYour Name 	{0x02, 0x54, 128 /* 4.096ms */},
39*5113495bSYour Name 	{0x02, 0x43, 65 /* 2.080ms */}
40*5113495bSYour Name #else
41*5113495bSYour Name 	{0x70, 0x59, 79 /* 2.528ms */},
42*5113495bSYour Name 	{0x30, 0x59, 79 /* 2.528ms */},
43*5113495bSYour Name 	{0x20, 0x45, 128 /* 4.096ms */},
44*5113495bSYour Name 	{0x20, 0x34, 65 /* 2.080ms */}
45*5113495bSYour Name #endif
46*5113495bSYour Name };
47*5113495bSYour Name 
48*5113495bSYour Name static
epcs_get_event_str(enum wlan_epcs_evt event)49*5113495bSYour Name const char *epcs_get_event_str(enum wlan_epcs_evt event)
50*5113495bSYour Name {
51*5113495bSYour Name 	if (event > WLAN_EPCS_EV_ACTION_FRAME_MAX)
52*5113495bSYour Name 		return "";
53*5113495bSYour Name 
54*5113495bSYour Name 	switch (event) {
55*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_REQ);
56*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_RESP);
57*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_REQ);
58*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_RESP);
59*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN);
60*5113495bSYour Name 	CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN);
61*5113495bSYour Name 	default:
62*5113495bSYour Name 		return "Unknown";
63*5113495bSYour Name 	}
64*5113495bSYour Name }
65*5113495bSYour Name 
66*5113495bSYour Name static uint8_t
epcs_gen_dialog_token(struct wlan_mlo_peer_epcs_info * epcs_info)67*5113495bSYour Name epcs_gen_dialog_token(struct wlan_mlo_peer_epcs_info *epcs_info)
68*5113495bSYour Name {
69*5113495bSYour Name 	if (!epcs_info)
70*5113495bSYour Name 		return 0;
71*5113495bSYour Name 
72*5113495bSYour Name 	if (epcs_info->self_gen_dialog_token == EPCS_MAX_DIALOG_TOKEN)
73*5113495bSYour Name 		/* wrap is ok */
74*5113495bSYour Name 		epcs_info->self_gen_dialog_token = EPCS_MIN_DIALOG_TOKEN;
75*5113495bSYour Name 	else
76*5113495bSYour Name 		epcs_info->self_gen_dialog_token += 1;
77*5113495bSYour Name 
78*5113495bSYour Name 	mlme_debug("gen dialog token %d", epcs_info->self_gen_dialog_token);
79*5113495bSYour Name 	return epcs_info->self_gen_dialog_token;
80*5113495bSYour Name }
81*5113495bSYour Name 
epcs_update_ac_value(tSirMacEdcaParamRecord * edca,struct ac_param_record * epcs)82*5113495bSYour Name static void epcs_update_ac_value(tSirMacEdcaParamRecord *edca,
83*5113495bSYour Name 				 struct ac_param_record *epcs)
84*5113495bSYour Name {
85*5113495bSYour Name 	edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK;
86*5113495bSYour Name 	edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK;
87*5113495bSYour Name 	edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK;
88*5113495bSYour Name 	edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK;
89*5113495bSYour Name 
90*5113495bSYour Name 	edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK;
91*5113495bSYour Name 	edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK;
92*5113495bSYour Name 
93*5113495bSYour Name 	edca->txoplimit = epcs->txop_limit;
94*5113495bSYour Name 	mlme_debug("edca rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
95*5113495bSYour Name 		   edca->aci.rsvd, edca->aci.aci, edca->aci.acm,
96*5113495bSYour Name 		   edca->aci.aifsn, edca->cw.max, edca->cw.min);
97*5113495bSYour Name }
98*5113495bSYour Name 
epcs_update_mu_ac_value(tSirMacEdcaParamRecord * edca,struct muac_param_record * epcs)99*5113495bSYour Name static void epcs_update_mu_ac_value(tSirMacEdcaParamRecord *edca,
100*5113495bSYour Name 				    struct muac_param_record *epcs)
101*5113495bSYour Name {
102*5113495bSYour Name 	edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK;
103*5113495bSYour Name 	edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK;
104*5113495bSYour Name 	edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK;
105*5113495bSYour Name 	edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK;
106*5113495bSYour Name 
107*5113495bSYour Name 	edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK;
108*5113495bSYour Name 	edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK;
109*5113495bSYour Name 
110*5113495bSYour Name 	edca->txoplimit = epcs->mu_edca_timer;
111*5113495bSYour Name 	mlme_debug("muac rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
112*5113495bSYour Name 		   edca->aci.rsvd, edca->aci.aci, edca->aci.acm,
113*5113495bSYour Name 		   edca->aci.aifsn, edca->cw.max, edca->cw.min);
114*5113495bSYour Name }
115*5113495bSYour Name 
116*5113495bSYour Name static QDF_STATUS
epcs_update_def_edca_param(struct wlan_objmgr_vdev * vdev)117*5113495bSYour Name epcs_update_def_edca_param(struct wlan_objmgr_vdev *vdev)
118*5113495bSYour Name {
119*5113495bSYour Name 	int i;
120*5113495bSYour Name 	struct mac_context *mac_ctx;
121*5113495bSYour Name 	tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0};
122*5113495bSYour Name 
123*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
124*5113495bSYour Name 	if (!mac_ctx)
125*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
126*5113495bSYour Name 
127*5113495bSYour Name 	for (i = 0; i < QCA_WLAN_AC_ALL; i++) {
128*5113495bSYour Name 		epcs_update_ac_value(&edca[i], &default_epcs_edca[i]);
129*5113495bSYour Name 		edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i];
130*5113495bSYour Name 	}
131*5113495bSYour Name 
132*5113495bSYour Name 	mlme_debug("using default edca info");
133*5113495bSYour Name 	return lim_send_epcs_update_edca_params(vdev, edca, false);
134*5113495bSYour Name }
135*5113495bSYour Name 
136*5113495bSYour Name static QDF_STATUS
epcs_update_edca_param(struct wlan_objmgr_vdev * vdev,struct edca_ie * edca_ie)137*5113495bSYour Name epcs_update_edca_param(struct wlan_objmgr_vdev *vdev,
138*5113495bSYour Name 		       struct edca_ie *edca_ie)
139*5113495bSYour Name {
140*5113495bSYour Name 	struct mac_context *mac_ctx;
141*5113495bSYour Name 	struct ac_param_record *ac_record;
142*5113495bSYour Name 	tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0};
143*5113495bSYour Name 	int i;
144*5113495bSYour Name 
145*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
146*5113495bSYour Name 	if (!mac_ctx)
147*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
148*5113495bSYour Name 
149*5113495bSYour Name 	if (edca_ie->ie != DOT11F_EID_EDCAPARAMSET ||
150*5113495bSYour Name 	    edca_ie->len != DOT11F_IE_EDCAPARAMSET_MIN_LEN) {
151*5113495bSYour Name 		mlme_debug("edca info is not valid or not exist");
152*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
153*5113495bSYour Name 	}
154*5113495bSYour Name 
155*5113495bSYour Name 	ac_record = edca_ie->ac_record;
156*5113495bSYour Name 	for (i = 0; i < QCA_WLAN_AC_ALL; i++) {
157*5113495bSYour Name 		epcs_update_ac_value(&edca[i], &ac_record[i]);
158*5113495bSYour Name 		edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i];
159*5113495bSYour Name 	}
160*5113495bSYour Name 
161*5113495bSYour Name 	return lim_send_epcs_update_edca_params(vdev, edca, false);
162*5113495bSYour Name }
163*5113495bSYour Name 
164*5113495bSYour Name static QDF_STATUS
epcs_update_ven_wmm_param(struct wlan_objmgr_vdev * vdev,uint8_t * ven_wme_ie)165*5113495bSYour Name epcs_update_ven_wmm_param(struct wlan_objmgr_vdev *vdev, uint8_t *ven_wme_ie)
166*5113495bSYour Name {
167*5113495bSYour Name 	struct mac_context *mac_ctx;
168*5113495bSYour Name 	tDot11fIEWMMParams wmm_para = {0};
169*5113495bSYour Name 	tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0};
170*5113495bSYour Name 	uint32_t status;
171*5113495bSYour Name 
172*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
173*5113495bSYour Name 	if (!mac_ctx)
174*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
175*5113495bSYour Name 
176*5113495bSYour Name 	status = dot11f_unpack_ie_wmm_params(mac_ctx,
177*5113495bSYour Name 					     ven_wme_ie + WMM_VENDOR_HEADER_LEN,
178*5113495bSYour Name 					     DOT11F_IE_WMMPARAMS_MIN_LEN,
179*5113495bSYour Name 					     &wmm_para, false);
180*5113495bSYour Name 	if (status != DOT11F_PARSE_SUCCESS) {
181*5113495bSYour Name 		mlme_debug("EPCS parsing wmm ie error");
182*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
183*5113495bSYour Name 	}
184*5113495bSYour Name 
185*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].aci.rsvd = wmm_para.unused1;
186*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].aci.aci = wmm_para.acbe_aci;
187*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].aci.acm = wmm_para.acbe_acm;
188*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].aci.aifsn = wmm_para.acbe_aifsn;
189*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].cw.max = wmm_para.acbe_acwmax;
190*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].cw.min = wmm_para.acbe_acwmin;
191*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].txoplimit = wmm_para.acbe_txoplimit;
192*5113495bSYour Name 	edca[QCA_WLAN_AC_BE].no_ack =
193*5113495bSYour Name 				mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BE];
194*5113495bSYour Name 	mlme_debug("WMM BE aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
195*5113495bSYour Name 		   edca[QCA_WLAN_AC_BE].aci.aci,
196*5113495bSYour Name 		   edca[QCA_WLAN_AC_BE].aci.acm,
197*5113495bSYour Name 		   edca[QCA_WLAN_AC_BE].aci.aifsn,
198*5113495bSYour Name 		   edca[QCA_WLAN_AC_BE].cw.max,
199*5113495bSYour Name 		   edca[QCA_WLAN_AC_BE].cw.min);
200*5113495bSYour Name 
201*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].aci.rsvd = wmm_para.unused2;
202*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].aci.aci = wmm_para.acbk_aci;
203*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].aci.acm = wmm_para.acbk_acm;
204*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].aci.aifsn = wmm_para.acbk_aifsn;
205*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].cw.max = wmm_para.acbk_acwmax;
206*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].cw.min = wmm_para.acbk_acwmin;
207*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].txoplimit = wmm_para.acbk_txoplimit;
208*5113495bSYour Name 	edca[QCA_WLAN_AC_BK].no_ack =
209*5113495bSYour Name 				mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BK];
210*5113495bSYour Name 	mlme_debug("WMM BK aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
211*5113495bSYour Name 		   edca[QCA_WLAN_AC_BK].aci.aci,
212*5113495bSYour Name 		   edca[QCA_WLAN_AC_BK].aci.acm,
213*5113495bSYour Name 		   edca[QCA_WLAN_AC_BK].aci.aifsn,
214*5113495bSYour Name 		   edca[QCA_WLAN_AC_BK].cw.max,
215*5113495bSYour Name 		   edca[QCA_WLAN_AC_BK].cw.min);
216*5113495bSYour Name 
217*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].aci.rsvd = wmm_para.unused3;
218*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].aci.aci = wmm_para.acvi_aci;
219*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].aci.acm = wmm_para.acvi_acm;
220*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].aci.aifsn = wmm_para.acvi_aifsn;
221*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].cw.max = wmm_para.acvi_acwmax;
222*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].cw.min = wmm_para.acvi_acwmin;
223*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].txoplimit = wmm_para.acvi_txoplimit;
224*5113495bSYour Name 	edca[QCA_WLAN_AC_VI].no_ack =
225*5113495bSYour Name 				mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VI];
226*5113495bSYour Name 	mlme_debug("WMM VI aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
227*5113495bSYour Name 		   edca[QCA_WLAN_AC_VI].aci.aci,
228*5113495bSYour Name 		   edca[QCA_WLAN_AC_VI].aci.acm,
229*5113495bSYour Name 		   edca[QCA_WLAN_AC_VI].aci.aifsn,
230*5113495bSYour Name 		   edca[QCA_WLAN_AC_VI].cw.max,
231*5113495bSYour Name 		   edca[QCA_WLAN_AC_VI].cw.min);
232*5113495bSYour Name 
233*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].aci.rsvd = wmm_para.unused4;
234*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].aci.aci = wmm_para.acvo_aci;
235*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].aci.acm = wmm_para.acvo_acm;
236*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].aci.aifsn = wmm_para.acvo_aifsn;
237*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].cw.max = wmm_para.acvo_acwmax;
238*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].cw.min = wmm_para.acvo_acwmin;
239*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].txoplimit = wmm_para.acvo_txoplimit;
240*5113495bSYour Name 	edca[QCA_WLAN_AC_VO].no_ack =
241*5113495bSYour Name 				mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VO];
242*5113495bSYour Name 	mlme_debug("WMM VO aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d",
243*5113495bSYour Name 		   edca[QCA_WLAN_AC_VO].aci.aci,
244*5113495bSYour Name 		   edca[QCA_WLAN_AC_VO].aci.acm,
245*5113495bSYour Name 		   edca[QCA_WLAN_AC_VO].aci.aifsn,
246*5113495bSYour Name 		   edca[QCA_WLAN_AC_VO].cw.max,
247*5113495bSYour Name 		   edca[QCA_WLAN_AC_VO].cw.min);
248*5113495bSYour Name 
249*5113495bSYour Name 	return lim_send_epcs_update_edca_params(vdev, edca, false);
250*5113495bSYour Name }
251*5113495bSYour Name 
252*5113495bSYour Name static QDF_STATUS
epcs_update_mu_edca_param(struct wlan_objmgr_vdev * vdev,struct muedca_ie * muedca)253*5113495bSYour Name epcs_update_mu_edca_param(struct wlan_objmgr_vdev *vdev,
254*5113495bSYour Name 			  struct muedca_ie *muedca)
255*5113495bSYour Name {
256*5113495bSYour Name 	struct mac_context *mac_ctx;
257*5113495bSYour Name 	struct muac_param_record *mu_record;
258*5113495bSYour Name 	tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0};
259*5113495bSYour Name 	int i;
260*5113495bSYour Name 
261*5113495bSYour Name 	if (muedca->elem_id != DOT11F_EID_MU_EDCA_PARAM_SET ||
262*5113495bSYour Name 	    muedca->elem_len != (DOT11F_IE_MU_EDCA_PARAM_SET_MIN_LEN + 1)) {
263*5113495bSYour Name 		mlme_debug("mu edca info for epcs is not valid or not exist");
264*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
265*5113495bSYour Name 	}
266*5113495bSYour Name 
267*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
268*5113495bSYour Name 	if (!mac_ctx)
269*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
270*5113495bSYour Name 
271*5113495bSYour Name 	mu_record = muedca->mu_record;
272*5113495bSYour Name 	for (i = 0; i < QCA_WLAN_AC_ALL; i++) {
273*5113495bSYour Name 		epcs_update_mu_ac_value(&edca[i], &mu_record[i]);
274*5113495bSYour Name 		edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i];
275*5113495bSYour Name 	}
276*5113495bSYour Name 
277*5113495bSYour Name 	return lim_send_epcs_update_edca_params(vdev, edca, true);
278*5113495bSYour Name }
279*5113495bSYour Name 
280*5113495bSYour Name static QDF_STATUS
epcs_restore_edca_param(struct wlan_objmgr_vdev * vdev)281*5113495bSYour Name epcs_restore_edca_param(struct wlan_objmgr_vdev *vdev)
282*5113495bSYour Name {
283*5113495bSYour Name 	struct wlan_objmgr_vdev *link_vdev;
284*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx;
285*5113495bSYour Name 	int i;
286*5113495bSYour Name 
287*5113495bSYour Name 	if (!vdev)
288*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
289*5113495bSYour Name 
290*5113495bSYour Name 	mlo_dev_ctx = vdev->mlo_dev_ctx;
291*5113495bSYour Name 	if (!mlo_dev_ctx)
292*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
293*5113495bSYour Name 
294*5113495bSYour Name 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
295*5113495bSYour Name 		link_vdev = mlo_dev_ctx->wlan_vdev_list[i];
296*5113495bSYour Name 		if (!link_vdev)
297*5113495bSYour Name 			continue;
298*5113495bSYour Name 		lim_send_epcs_restore_edca_params(link_vdev);
299*5113495bSYour Name 	}
300*5113495bSYour Name 
301*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
302*5113495bSYour Name }
303*5113495bSYour Name 
epcs_handle_rx_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,void * event_data,uint32_t len)304*5113495bSYour Name static QDF_STATUS epcs_handle_rx_req(struct wlan_objmgr_vdev *vdev,
305*5113495bSYour Name 				     struct wlan_objmgr_peer *peer,
306*5113495bSYour Name 				     void *event_data, uint32_t len)
307*5113495bSYour Name {
308*5113495bSYour Name 	struct wlan_mlo_peer_context *ml_peer;
309*5113495bSYour Name 	struct wlan_mlo_peer_epcs_info *epcs_info;
310*5113495bSYour Name 	struct wlan_epcs_info epcs_req = {0};
311*5113495bSYour Name 	struct wlan_action_frame_args args;
312*5113495bSYour Name 	struct ml_pa_info *edca_info;
313*5113495bSYour Name 	struct ml_pa_partner_link_info *link;
314*5113495bSYour Name 	struct wlan_objmgr_vdev *link_vdev;
315*5113495bSYour Name 	uint32_t i;
316*5113495bSYour Name 	QDF_STATUS status;
317*5113495bSYour Name 
318*5113495bSYour Name 	if (!vdev || !peer)
319*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
320*5113495bSYour Name 
321*5113495bSYour Name 	ml_peer = peer->mlo_peer_ctx;
322*5113495bSYour Name 	if (!ml_peer)
323*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
324*5113495bSYour Name 
325*5113495bSYour Name 	epcs_info = &ml_peer->epcs_info;
326*5113495bSYour Name 	if (epcs_info->state == EPCS_ENABLE) {
327*5113495bSYour Name 		mlme_err("EPCS has been enable, ignore the req.");
328*5113495bSYour Name 		return QDF_STATUS_E_ALREADY;
329*5113495bSYour Name 	}
330*5113495bSYour Name 
331*5113495bSYour Name 	status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len);
332*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
333*5113495bSYour Name 		mlme_err("Unable to parse EPCS request action frame");
334*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
335*5113495bSYour Name 	}
336*5113495bSYour Name 
337*5113495bSYour Name 	epcs_info->self_gen_dialog_token = epcs_req.dialog_token;
338*5113495bSYour Name 	edca_info = &epcs_req.pa_info;
339*5113495bSYour Name 	for (i = 0; i < edca_info->num_links; i++) {
340*5113495bSYour Name 		link = &edca_info->link_info[i];
341*5113495bSYour Name 		link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id,
342*5113495bSYour Name 						    WLAN_MLO_MGR_ID);
343*5113495bSYour Name 		if (!link_vdev)
344*5113495bSYour Name 			continue;
345*5113495bSYour Name 
346*5113495bSYour Name 		if (link->edca_ie_present)
347*5113495bSYour Name 			epcs_update_edca_param(link_vdev, &link->edca);
348*5113495bSYour Name 		else if (link->ven_wme_ie_present)
349*5113495bSYour Name 			epcs_update_ven_wmm_param(link_vdev,
350*5113495bSYour Name 						  &link->ven_wme_ie_bytes[0]);
351*5113495bSYour Name 		else
352*5113495bSYour Name 			epcs_update_def_edca_param(link_vdev);
353*5113495bSYour Name 
354*5113495bSYour Name 		if (link->muedca_ie_present)
355*5113495bSYour Name 			epcs_update_mu_edca_param(link_vdev, &link->muedca);
356*5113495bSYour Name 
357*5113495bSYour Name 		wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID);
358*5113495bSYour Name 	}
359*5113495bSYour Name 
360*5113495bSYour Name 	args.category = ACTION_CATEGORY_PROTECTED_EHT;
361*5113495bSYour Name 	args.action = EHT_EPCS_RESPONSE;
362*5113495bSYour Name 	args.arg1 = epcs_info->self_gen_dialog_token;
363*5113495bSYour Name 	args.arg2 = QDF_STATUS_SUCCESS;
364*5113495bSYour Name 
365*5113495bSYour Name 	status = lim_send_epcs_action_rsp_frame(vdev,
366*5113495bSYour Name 						wlan_peer_get_macaddr(peer),
367*5113495bSYour Name 						&args);
368*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
369*5113495bSYour Name 		mlme_err("Send EPCS response frame error");
370*5113495bSYour Name 		epcs_restore_edca_param(vdev);
371*5113495bSYour Name 	} else {
372*5113495bSYour Name 		epcs_info->state = EPCS_ENABLE;
373*5113495bSYour Name 		mlme_debug("EPCS (responder) state: Teardown -> Enable");
374*5113495bSYour Name 	}
375*5113495bSYour Name 
376*5113495bSYour Name 	return status;
377*5113495bSYour Name }
378*5113495bSYour Name 
epcs_handle_rx_resp(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,void * event_data,uint32_t len)379*5113495bSYour Name static QDF_STATUS epcs_handle_rx_resp(struct wlan_objmgr_vdev *vdev,
380*5113495bSYour Name 				      struct wlan_objmgr_peer *peer,
381*5113495bSYour Name 				      void *event_data, uint32_t len)
382*5113495bSYour Name {
383*5113495bSYour Name 	struct wlan_mlo_peer_context *ml_peer;
384*5113495bSYour Name 	struct wlan_mlo_peer_epcs_info *epcs_info;
385*5113495bSYour Name 	struct wlan_epcs_info epcs_rsp = {0};
386*5113495bSYour Name 	struct ml_pa_info *edca_info;
387*5113495bSYour Name 	struct ml_pa_partner_link_info *link;
388*5113495bSYour Name 	struct wlan_objmgr_vdev *link_vdev;
389*5113495bSYour Name 	uint32_t i;
390*5113495bSYour Name 	QDF_STATUS status;
391*5113495bSYour Name 
392*5113495bSYour Name 	if (!vdev || !peer)
393*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
394*5113495bSYour Name 
395*5113495bSYour Name 	ml_peer = peer->mlo_peer_ctx;
396*5113495bSYour Name 	if (!ml_peer)
397*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
398*5113495bSYour Name 
399*5113495bSYour Name 	epcs_info = &ml_peer->epcs_info;
400*5113495bSYour Name 	if (epcs_info->state == EPCS_ENABLE) {
401*5113495bSYour Name 		mlme_err("EPCS has been enable, ignore the rsp.");
402*5113495bSYour Name 		return QDF_STATUS_E_ALREADY;
403*5113495bSYour Name 	}
404*5113495bSYour Name 
405*5113495bSYour Name 	status = wlan_mlo_parse_epcs_action_frame(&epcs_rsp, event_data, len);
406*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
407*5113495bSYour Name 		mlme_err("Unable to parse EPCS response action frame");
408*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
409*5113495bSYour Name 	}
410*5113495bSYour Name 
411*5113495bSYour Name 	if (epcs_info->self_gen_dialog_token != epcs_rsp.dialog_token) {
412*5113495bSYour Name 		mlme_err("epcs rsp dialog token %d does not match",
413*5113495bSYour Name 			 epcs_rsp.dialog_token);
414*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
415*5113495bSYour Name 	}
416*5113495bSYour Name 
417*5113495bSYour Name 	if (epcs_rsp.status) {
418*5113495bSYour Name 		mlme_err("epcs rsp status error %d", epcs_rsp.status);
419*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
420*5113495bSYour Name 	}
421*5113495bSYour Name 
422*5113495bSYour Name 	edca_info = &epcs_rsp.pa_info;
423*5113495bSYour Name 	for (i = 0; i < edca_info->num_links; i++) {
424*5113495bSYour Name 		link = &edca_info->link_info[i];
425*5113495bSYour Name 		link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id,
426*5113495bSYour Name 						    WLAN_MLO_MGR_ID);
427*5113495bSYour Name 		if (!link_vdev)
428*5113495bSYour Name 			continue;
429*5113495bSYour Name 
430*5113495bSYour Name 		if (link->edca_ie_present)
431*5113495bSYour Name 			epcs_update_edca_param(link_vdev, &link->edca);
432*5113495bSYour Name 		else if (link->ven_wme_ie_present)
433*5113495bSYour Name 			epcs_update_ven_wmm_param(link_vdev,
434*5113495bSYour Name 						  &link->ven_wme_ie_bytes[0]);
435*5113495bSYour Name 		else
436*5113495bSYour Name 			epcs_update_def_edca_param(link_vdev);
437*5113495bSYour Name 
438*5113495bSYour Name 		if (link->muedca_ie_present)
439*5113495bSYour Name 			epcs_update_mu_edca_param(link_vdev, &link->muedca);
440*5113495bSYour Name 
441*5113495bSYour Name 		wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID);
442*5113495bSYour Name 	}
443*5113495bSYour Name 
444*5113495bSYour Name 	epcs_info->state = EPCS_ENABLE;
445*5113495bSYour Name 	mlme_debug("EPCS (initiator) state: Teardown -> Enable");
446*5113495bSYour Name 
447*5113495bSYour Name 	return status;
448*5113495bSYour Name }
449*5113495bSYour Name 
epcs_handle_rx_teardown(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,void * event_data,uint32_t len)450*5113495bSYour Name static QDF_STATUS epcs_handle_rx_teardown(struct wlan_objmgr_vdev *vdev,
451*5113495bSYour Name 					  struct wlan_objmgr_peer *peer,
452*5113495bSYour Name 					  void *event_data, uint32_t len)
453*5113495bSYour Name {
454*5113495bSYour Name 	struct wlan_mlo_peer_context *ml_peer;
455*5113495bSYour Name 	struct wlan_mlo_peer_epcs_info *epcs_info;
456*5113495bSYour Name 	struct wlan_epcs_info epcs_req = {0};
457*5113495bSYour Name 	struct mac_context *mac_ctx;
458*5113495bSYour Name 	QDF_STATUS status;
459*5113495bSYour Name 
460*5113495bSYour Name 	if (!vdev || !peer)
461*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
462*5113495bSYour Name 
463*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
464*5113495bSYour Name 	if (!mac_ctx)
465*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
466*5113495bSYour Name 
467*5113495bSYour Name 	ml_peer = peer->mlo_peer_ctx;
468*5113495bSYour Name 	if (!ml_peer)
469*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
470*5113495bSYour Name 
471*5113495bSYour Name 	epcs_info = &ml_peer->epcs_info;
472*5113495bSYour Name 	if (epcs_info->state == EPCS_DOWN) {
473*5113495bSYour Name 		mlme_err("EPCS has been down, ignore the teardown req.");
474*5113495bSYour Name 		return QDF_STATUS_E_ALREADY;
475*5113495bSYour Name 	}
476*5113495bSYour Name 
477*5113495bSYour Name 	status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len);
478*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
479*5113495bSYour Name 		mlme_err("Unable to parse EPCS teardown action frame");
480*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
481*5113495bSYour Name 	}
482*5113495bSYour Name 
483*5113495bSYour Name 	epcs_restore_edca_param(vdev);
484*5113495bSYour Name 
485*5113495bSYour Name 	epcs_info->state = EPCS_DOWN;
486*5113495bSYour Name 	mlme_debug("EPCS state: Enale -> Teardown.");
487*5113495bSYour Name 
488*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
489*5113495bSYour Name }
490*5113495bSYour Name 
epcs_handle_tx_req(struct wlan_objmgr_vdev * vdev)491*5113495bSYour Name static QDF_STATUS epcs_handle_tx_req(struct wlan_objmgr_vdev *vdev)
492*5113495bSYour Name {
493*5113495bSYour Name 	struct wlan_mlo_peer_context *ml_peer;
494*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
495*5113495bSYour Name 	struct wlan_action_frame_args args;
496*5113495bSYour Name 	struct wlan_mlo_peer_epcs_info *epcs_info;
497*5113495bSYour Name 	QDF_STATUS status;
498*5113495bSYour Name 
499*5113495bSYour Name 	if (!vdev)
500*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
501*5113495bSYour Name 
502*5113495bSYour Name 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
503*5113495bSYour Name 	if (!peer)
504*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
505*5113495bSYour Name 
506*5113495bSYour Name 	ml_peer = peer->mlo_peer_ctx;
507*5113495bSYour Name 	if (!ml_peer) {
508*5113495bSYour Name 		status = QDF_STATUS_E_NULL_VALUE;
509*5113495bSYour Name 		goto release_peer;
510*5113495bSYour Name 	}
511*5113495bSYour Name 
512*5113495bSYour Name 	epcs_info = &ml_peer->epcs_info;
513*5113495bSYour Name 	if (epcs_info->state == EPCS_ENABLE) {
514*5113495bSYour Name 		mlme_err("EPCS has been enable, ignore the req cmd.");
515*5113495bSYour Name 		status = QDF_STATUS_E_ALREADY;
516*5113495bSYour Name 		goto release_peer;
517*5113495bSYour Name 	}
518*5113495bSYour Name 
519*5113495bSYour Name 	args.category = ACTION_CATEGORY_PROTECTED_EHT;
520*5113495bSYour Name 	args.action = EHT_EPCS_REQUEST;
521*5113495bSYour Name 	args.arg1 = epcs_gen_dialog_token(epcs_info);
522*5113495bSYour Name 
523*5113495bSYour Name 	status = lim_send_epcs_action_req_frame(vdev,
524*5113495bSYour Name 						wlan_peer_get_macaddr(peer),
525*5113495bSYour Name 						&args);
526*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
527*5113495bSYour Name 		mlme_err("Failed to send EPCS action request frame");
528*5113495bSYour Name 
529*5113495bSYour Name release_peer:
530*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
531*5113495bSYour Name 
532*5113495bSYour Name 	return status;
533*5113495bSYour Name }
534*5113495bSYour Name 
epcs_handle_tx_teardown(struct wlan_objmgr_vdev * vdev)535*5113495bSYour Name static QDF_STATUS epcs_handle_tx_teardown(struct wlan_objmgr_vdev *vdev)
536*5113495bSYour Name {
537*5113495bSYour Name 	struct wlan_mlo_peer_context *ml_peer;
538*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
539*5113495bSYour Name 	struct wlan_action_frame_args args;
540*5113495bSYour Name 	struct wlan_mlo_peer_epcs_info *epcs_info;
541*5113495bSYour Name 	QDF_STATUS status;
542*5113495bSYour Name 
543*5113495bSYour Name 	if (!vdev)
544*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
545*5113495bSYour Name 
546*5113495bSYour Name 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID);
547*5113495bSYour Name 	if (!peer)
548*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
549*5113495bSYour Name 
550*5113495bSYour Name 	ml_peer = peer->mlo_peer_ctx;
551*5113495bSYour Name 	if (!ml_peer) {
552*5113495bSYour Name 		status = QDF_STATUS_E_NULL_VALUE;
553*5113495bSYour Name 		goto release_peer;
554*5113495bSYour Name 	}
555*5113495bSYour Name 
556*5113495bSYour Name 	epcs_info = &ml_peer->epcs_info;
557*5113495bSYour Name 	if (epcs_info->state == EPCS_DOWN) {
558*5113495bSYour Name 		mlme_err("EPCS has been down, ignore the teardwon cmd.");
559*5113495bSYour Name 		status = QDF_STATUS_E_ALREADY;
560*5113495bSYour Name 		goto release_peer;
561*5113495bSYour Name 	}
562*5113495bSYour Name 
563*5113495bSYour Name 	args.category = ACTION_CATEGORY_PROTECTED_EHT;
564*5113495bSYour Name 	args.action = EHT_EPCS_TEARDOWN;
565*5113495bSYour Name 
566*5113495bSYour Name 	status =
567*5113495bSYour Name 	    lim_send_epcs_action_teardown_frame(vdev,
568*5113495bSYour Name 						wlan_peer_get_macaddr(peer),
569*5113495bSYour Name 						&args);
570*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
571*5113495bSYour Name 		mlme_err("Failed to send EPCS tear down frame");
572*5113495bSYour Name 	} else {
573*5113495bSYour Name 		epcs_restore_edca_param(vdev);
574*5113495bSYour Name 		epcs_info->state = EPCS_DOWN;
575*5113495bSYour Name 		mlme_debug("EPCS state: Enale -> Teardown.");
576*5113495bSYour Name 	}
577*5113495bSYour Name 
578*5113495bSYour Name release_peer:
579*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
580*5113495bSYour Name 
581*5113495bSYour Name 	return status;
582*5113495bSYour Name }
583*5113495bSYour Name 
epcs_deliver_event(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,enum wlan_epcs_evt event,void * event_data,uint32_t len)584*5113495bSYour Name static QDF_STATUS epcs_deliver_event(struct wlan_objmgr_vdev *vdev,
585*5113495bSYour Name 				     struct wlan_objmgr_peer *peer,
586*5113495bSYour Name 				     enum wlan_epcs_evt event,
587*5113495bSYour Name 				     void *event_data, uint32_t len)
588*5113495bSYour Name {
589*5113495bSYour Name 	QDF_STATUS status;
590*5113495bSYour Name 
591*5113495bSYour Name 	mlme_debug("EPCS event received: %s(%d)",
592*5113495bSYour Name 		   epcs_get_event_str(event), event);
593*5113495bSYour Name 
594*5113495bSYour Name 	switch (event) {
595*5113495bSYour Name 	case WLAN_EPCS_EV_ACTION_FRAME_RX_REQ:
596*5113495bSYour Name 		status = epcs_handle_rx_req(vdev, peer, event_data, len);
597*5113495bSYour Name 		break;
598*5113495bSYour Name 	case WLAN_EPCS_EV_ACTION_FRAME_RX_RESP:
599*5113495bSYour Name 		status = epcs_handle_rx_resp(vdev, peer, event_data, len);
600*5113495bSYour Name 		break;
601*5113495bSYour Name 	case WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN:
602*5113495bSYour Name 		status = epcs_handle_rx_teardown(vdev, peer, event_data, len);
603*5113495bSYour Name 		break;
604*5113495bSYour Name 	default:
605*5113495bSYour Name 		status = QDF_STATUS_E_FAILURE;
606*5113495bSYour Name 		mlme_err("Unhandled EPCS event");
607*5113495bSYour Name 	}
608*5113495bSYour Name 
609*5113495bSYour Name 	return status;
610*5113495bSYour Name }
611*5113495bSYour Name 
wlan_epcs_deliver_event(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_peer * peer,enum wlan_epcs_evt event,void * event_data,uint32_t len)612*5113495bSYour Name QDF_STATUS wlan_epcs_deliver_event(struct wlan_objmgr_vdev *vdev,
613*5113495bSYour Name 				   struct wlan_objmgr_peer *peer,
614*5113495bSYour Name 				   enum wlan_epcs_evt event,
615*5113495bSYour Name 				   void *event_data, uint32_t len)
616*5113495bSYour Name {
617*5113495bSYour Name 	return epcs_deliver_event(vdev, peer, event, event_data, len);
618*5113495bSYour Name }
619*5113495bSYour Name 
epcs_deliver_cmd(struct wlan_objmgr_vdev * vdev,enum wlan_epcs_evt event)620*5113495bSYour Name static QDF_STATUS epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev,
621*5113495bSYour Name 				   enum wlan_epcs_evt event)
622*5113495bSYour Name {
623*5113495bSYour Name 	QDF_STATUS status;
624*5113495bSYour Name 
625*5113495bSYour Name 	mlme_debug("EPCS cmd received: %s(%d)",
626*5113495bSYour Name 		   epcs_get_event_str(event), event);
627*5113495bSYour Name 
628*5113495bSYour Name 	switch (event) {
629*5113495bSYour Name 	case WLAN_EPCS_EV_ACTION_FRAME_TX_REQ:
630*5113495bSYour Name 		status = epcs_handle_tx_req(vdev);
631*5113495bSYour Name 		break;
632*5113495bSYour Name 	case WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN:
633*5113495bSYour Name 		status = epcs_handle_tx_teardown(vdev);
634*5113495bSYour Name 		break;
635*5113495bSYour Name 	default:
636*5113495bSYour Name 		status = QDF_STATUS_E_FAILURE;
637*5113495bSYour Name 		mlme_err("Unhandled EPCS cmd");
638*5113495bSYour Name 	}
639*5113495bSYour Name 
640*5113495bSYour Name 	return status;
641*5113495bSYour Name }
642*5113495bSYour Name 
wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev * vdev,enum wlan_epcs_evt event)643*5113495bSYour Name QDF_STATUS wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev,
644*5113495bSYour Name 				 enum wlan_epcs_evt event)
645*5113495bSYour Name {
646*5113495bSYour Name 	if (!vdev)
647*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
648*5113495bSYour Name 
649*5113495bSYour Name 	if (!wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev))) {
650*5113495bSYour Name 		mlme_info("EPCS has been disabled");
651*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
652*5113495bSYour Name 	}
653*5113495bSYour Name 
654*5113495bSYour Name 	return epcs_deliver_cmd(vdev, event);
655*5113495bSYour Name }
656*5113495bSYour Name 
wlan_epcs_set_config(struct wlan_objmgr_vdev * vdev,uint8_t flag)657*5113495bSYour Name QDF_STATUS wlan_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag)
658*5113495bSYour Name {
659*5113495bSYour Name 	struct mac_context *mac_ctx;
660*5113495bSYour Name 
661*5113495bSYour Name 	mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
662*5113495bSYour Name 	if (!mac_ctx)
663*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
664*5113495bSYour Name 
665*5113495bSYour Name 	if (!vdev)
666*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
667*5113495bSYour Name 
668*5113495bSYour Name 	if (flag)
669*5113495bSYour Name 		wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), true);
670*5113495bSYour Name 	else
671*5113495bSYour Name 		wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), false);
672*5113495bSYour Name 
673*5113495bSYour Name 	return lim_send_eht_caps_ie(mac_ctx, QDF_STA_MODE,
674*5113495bSYour Name 				    wlan_vdev_get_id(vdev));
675*5113495bSYour Name }
676*5113495bSYour Name 
wlan_epcs_get_config(struct wlan_objmgr_vdev * vdev)677*5113495bSYour Name bool wlan_epcs_get_config(struct wlan_objmgr_vdev *vdev)
678*5113495bSYour Name {
679*5113495bSYour Name 	bool epcs_flag;
680*5113495bSYour Name 
681*5113495bSYour Name 	if (!vdev)
682*5113495bSYour Name 		return false;
683*5113495bSYour Name 
684*5113495bSYour Name 	epcs_flag = wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev));
685*5113495bSYour Name 	mlme_debug("EPCS %s", epcs_flag ? "Enabled" : "Disabled");
686*5113495bSYour Name 
687*5113495bSYour Name 	return epcs_flag;
688*5113495bSYour Name }
689