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