xref: /wlan-driver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_epcs.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 APIs
19*5113495bSYour Name  */
20*5113495bSYour Name 
21*5113495bSYour Name #include <wlan_objmgr_pdev_obj.h>
22*5113495bSYour Name #include <wlan_objmgr_vdev_obj.h>
23*5113495bSYour Name #include <wlan_objmgr_peer_obj.h>
24*5113495bSYour Name #include <wlan_mlo_mgr_public_structs.h>
25*5113495bSYour Name #include <wlan_mlo_mgr_cmn.h>
26*5113495bSYour Name #include <qdf_util.h>
27*5113495bSYour Name #include <wlan_cm_api.h>
28*5113495bSYour Name #include <utils_mlo.h>
29*5113495bSYour Name #include <wlan_mlo_epcs.h>
30*5113495bSYour Name 
31*5113495bSYour Name /**
32*5113495bSYour Name  * wlan_mlo_is_node_epcs_authorized() - API to check mac address is
33*5113495bSYour Name  * EPCS authorized or not
34*5113495bSYour Name  * @ml_peer: pointer to mlo context of peer
35*5113495bSYour Name  *
36*5113495bSYour Name  * Return: QDF_STATUS
37*5113495bSYour Name  */
38*5113495bSYour Name static QDF_STATUS
wlan_mlo_is_node_epcs_authorized(struct wlan_mlo_peer_context * ml_peer)39*5113495bSYour Name wlan_mlo_is_node_epcs_authorized(struct wlan_mlo_peer_context *ml_peer)
40*5113495bSYour Name {
41*5113495bSYour Name 	struct wlan_mlo_dev_context *mlo_dev_ctx;
42*5113495bSYour Name 	struct wlan_epcs_context *epcs_ctx;
43*5113495bSYour Name 	enum QDF_OPMODE opmode;
44*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = NULL;
45*5113495bSYour Name 	int i;
46*5113495bSYour Name 
47*5113495bSYour Name 	if (!ml_peer) {
48*5113495bSYour Name 		epcs_err("ml_peer is null");
49*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
50*5113495bSYour Name 	}
51*5113495bSYour Name 
52*5113495bSYour Name 	mlo_dev_ctx = ml_peer->ml_dev;
53*5113495bSYour Name 	if (!mlo_dev_ctx) {
54*5113495bSYour Name 		epcs_err("mlo dev ctx is null");
55*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
56*5113495bSYour Name 	}
57*5113495bSYour Name 
58*5113495bSYour Name 	/* Get first valid vdev */
59*5113495bSYour Name 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
60*5113495bSYour Name 		if (!mlo_dev_ctx->wlan_vdev_list[i])
61*5113495bSYour Name 			continue;
62*5113495bSYour Name 
63*5113495bSYour Name 		vdev = mlo_dev_ctx->wlan_vdev_list[i];
64*5113495bSYour Name 		opmode = wlan_vdev_mlme_get_opmode(vdev);
65*5113495bSYour Name 		break;
66*5113495bSYour Name 	}
67*5113495bSYour Name 
68*5113495bSYour Name 	if (!vdev) {
69*5113495bSYour Name 		epcs_err("no valid vdev entry found");
70*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
71*5113495bSYour Name 	}
72*5113495bSYour Name 
73*5113495bSYour Name 	epcs_debug("ml peer type %d", opmode);
74*5113495bSYour Name 	if (opmode != QDF_SAP_MODE)
75*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
76*5113495bSYour Name 
77*5113495bSYour Name 	epcs_ctx = &mlo_dev_ctx->epcs_ctx;
78*5113495bSYour Name 	if (!epcs_ctx) {
79*5113495bSYour Name 		epcs_err("epcs info is null");
80*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
81*5113495bSYour Name 	}
82*5113495bSYour Name 
83*5113495bSYour Name 	epcs_dev_lock_acquire(epcs_ctx);
84*5113495bSYour Name 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
85*5113495bSYour Name 		if (epcs_ctx->authorize_info[i].valid &&
86*5113495bSYour Name 		    !qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
87*5113495bSYour Name 				 ml_peer->peer_mld_addr.bytes,
88*5113495bSYour Name 				 QDF_MAC_ADDR_SIZE)) {
89*5113495bSYour Name 			epcs_dev_lock_release(epcs_ctx);
90*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
91*5113495bSYour Name 		}
92*5113495bSYour Name 	}
93*5113495bSYour Name 	epcs_dev_lock_release(epcs_ctx);
94*5113495bSYour Name 
95*5113495bSYour Name 	return QDF_STATUS_E_INVAL;
96*5113495bSYour Name }
97*5113495bSYour Name 
98*5113495bSYour Name /**
99*5113495bSYour Name  * mlo_process_ml_priorityaccess_ie() - API to parse Priority access ML IE
100*5113495bSYour Name  * @ml_ie: Pointer to start of ML IE
101*5113495bSYour Name  * @ml_ie_len: Length of ML IE
102*5113495bSYour Name  * @priority_access_info: pointer to fill multi link priority access information
103*5113495bSYour Name  *
104*5113495bSYour Name  * Return: QDF_STATUS
105*5113495bSYour Name  */
106*5113495bSYour Name static QDF_STATUS
mlo_process_ml_priorityaccess_ie(uint8_t * ml_ie,qdf_size_t ml_ie_len,struct ml_pa_info * priority_access_info)107*5113495bSYour Name mlo_process_ml_priorityaccess_ie(uint8_t *ml_ie, qdf_size_t ml_ie_len,
108*5113495bSYour Name 				 struct ml_pa_info *priority_access_info)
109*5113495bSYour Name {
110*5113495bSYour Name 	uint8_t *ml_pa_ie = NULL;
111*5113495bSYour Name 	qdf_size_t ml_pa_ie_len = 0;
112*5113495bSYour Name 	QDF_STATUS status;
113*5113495bSYour Name 
114*5113495bSYour Name 	if (!ml_ie) {
115*5113495bSYour Name 		mlo_err("NULL ml_ie");
116*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
117*5113495bSYour Name 	}
118*5113495bSYour Name 
119*5113495bSYour Name 	if (!priority_access_info) {
120*5113495bSYour Name 		mlo_err("NULL priority_access_info");
121*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
122*5113495bSYour Name 	}
123*5113495bSYour Name 
124*5113495bSYour Name 	status = util_find_mlie_by_variant(ml_ie,
125*5113495bSYour Name 					   ml_ie_len,
126*5113495bSYour Name 					   &ml_pa_ie,
127*5113495bSYour Name 					   &ml_pa_ie_len,
128*5113495bSYour Name 					   WLAN_ML_VARIANT_PRIORITYACCESS);
129*5113495bSYour Name 
130*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status) || !ml_pa_ie) {
131*5113495bSYour Name 		mlo_debug("ML IE for reconfig variant not found");
132*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
133*5113495bSYour Name 	}
134*5113495bSYour Name 	epcs_debug("PAV ML IE with length %zu is present", ml_pa_ie_len);
135*5113495bSYour Name 
136*5113495bSYour Name 	status = util_get_pav_mlie_link_info(ml_pa_ie, ml_pa_ie_len,
137*5113495bSYour Name 					     priority_access_info);
138*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
139*5113495bSYour Name 		mlo_err("Unable to get sta link info from ML PAV IE");
140*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
141*5113495bSYour Name 	}
142*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
143*5113495bSYour Name }
144*5113495bSYour Name 
145*5113495bSYour Name /**
146*5113495bSYour Name  * wlan_mlo_parse_epcs_request_action_frame() - API to parse EPCS request action
147*5113495bSYour Name  * frame.
148*5113495bSYour Name  * @epcs: Pointer to EPCS structure
149*5113495bSYour Name  * @action_frm: Pointer to action frame
150*5113495bSYour Name  * @frm_len: frame length
151*5113495bSYour Name  *
152*5113495bSYour Name  * Return: QDF_STATUS
153*5113495bSYour Name  */
154*5113495bSYour Name static QDF_STATUS
wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)155*5113495bSYour Name wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info *epcs,
156*5113495bSYour Name 					 struct wlan_action_frame *action_frm,
157*5113495bSYour Name 					 uint32_t frm_len)
158*5113495bSYour Name {
159*5113495bSYour Name 	struct epcs_frm *epcs_action_frm;
160*5113495bSYour Name 	struct ml_pa_info *priority_access_info = &epcs->pa_info;
161*5113495bSYour Name 	uint8_t *pa_ie;
162*5113495bSYour Name 	uint16_t pa_ie_len;
163*5113495bSYour Name 
164*5113495bSYour Name 	/*
165*5113495bSYour Name 	 * EPCS request action frame
166*5113495bSYour Name 	 *
167*5113495bSYour Name 	 *   1-byte     1-byte     1-byte    variable
168*5113495bSYour Name 	 *--------------------------------------------
169*5113495bSYour Name 	 * |         |           |        |          |
170*5113495bSYour Name 	 * | Category| Protected | Dialog | PA ML IE |
171*5113495bSYour Name 	 * |         |    EHT    | token  |          |
172*5113495bSYour Name 	 * |         |  Action   |        |          |
173*5113495bSYour Name 	 *--------------------------------------------
174*5113495bSYour Name 	 */
175*5113495bSYour Name 
176*5113495bSYour Name 	epcs_action_frm = (struct epcs_frm *)action_frm;
177*5113495bSYour Name 
178*5113495bSYour Name 	epcs->cat = epcs_action_frm->protected_eht_action;
179*5113495bSYour Name 	epcs->dialog_token = epcs_action_frm->dialog_token;
180*5113495bSYour Name 	epcs_info("EPCS frame rcv : category:%d action:%d dialog_token:%d frmlen %d",
181*5113495bSYour Name 		  epcs_action_frm->category,
182*5113495bSYour Name 		  epcs_action_frm->protected_eht_action,
183*5113495bSYour Name 		  epcs_action_frm->dialog_token, frm_len);
184*5113495bSYour Name 
185*5113495bSYour Name 	if (frm_len > EPCS_REQ_MIN_LENGTH) {
186*5113495bSYour Name 		pa_ie = (uint8_t *)epcs_action_frm + EPCS_REQ_MIN_LENGTH;
187*5113495bSYour Name 		pa_ie_len = frm_len - EPCS_REQ_MIN_LENGTH;
188*5113495bSYour Name 		return mlo_process_ml_priorityaccess_ie(pa_ie,
189*5113495bSYour Name 							pa_ie_len,
190*5113495bSYour Name 							priority_access_info);
191*5113495bSYour Name 	} else {
192*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
193*5113495bSYour Name 	}
194*5113495bSYour Name }
195*5113495bSYour Name 
196*5113495bSYour Name /**
197*5113495bSYour Name  * wlan_mlo_parse_epcs_response_action_frame() - API to parse EPCS response
198*5113495bSYour Name  * action frame.
199*5113495bSYour Name  * @epcs: Pointer to EPCS structure
200*5113495bSYour Name  * @action_frm: Pointer to action frame
201*5113495bSYour Name  * @frm_len: frame length
202*5113495bSYour Name  *
203*5113495bSYour Name  * Return: QDF_STATUS
204*5113495bSYour Name  */
205*5113495bSYour Name static QDF_STATUS
wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)206*5113495bSYour Name wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info *epcs,
207*5113495bSYour Name 					  struct wlan_action_frame *action_frm,
208*5113495bSYour Name 					  uint32_t frm_len)
209*5113495bSYour Name {
210*5113495bSYour Name 	struct epcs_frm *epcs_action_frm;
211*5113495bSYour Name 	struct ml_pa_info *priority_access_info = &epcs->pa_info;
212*5113495bSYour Name 	uint8_t *pa_ie;
213*5113495bSYour Name 	uint16_t pa_ie_len;
214*5113495bSYour Name 
215*5113495bSYour Name 	/*
216*5113495bSYour Name 	 * EPCS response action frame
217*5113495bSYour Name 	 *
218*5113495bSYour Name 	 *   1-byte     1-byte     1-byte   1-byte   variable
219*5113495bSYour Name 	 *----------------------------------------------------
220*5113495bSYour Name 	 * |         |           |        |        |         |
221*5113495bSYour Name 	 * | Category| Protected | Dialog | Status | PA   IE |
222*5113495bSYour Name 	 * |         |    EHT    | token  |  code  |         |
223*5113495bSYour Name 	 * |         |  Action   |        |        |         |
224*5113495bSYour Name 	 *----------------------------------------------------
225*5113495bSYour Name 	 */
226*5113495bSYour Name 
227*5113495bSYour Name 	epcs_action_frm = (struct epcs_frm *)action_frm;
228*5113495bSYour Name 
229*5113495bSYour Name 	epcs->cat = epcs_action_frm->protected_eht_action;
230*5113495bSYour Name 	epcs->dialog_token = epcs_action_frm->dialog_token;
231*5113495bSYour Name 	QDF_SET_BITS(epcs->status, 0, 8, epcs_action_frm->resp.status_code[0]);
232*5113495bSYour Name 	QDF_SET_BITS(epcs->status, 8, 8, epcs_action_frm->resp.status_code[1]);
233*5113495bSYour Name 	epcs_info("EPCS frame rcv : category:%d action:%d dialog_token:%d status %x %x frmlen %d",
234*5113495bSYour Name 		  epcs_action_frm->category,
235*5113495bSYour Name 		  epcs_action_frm->protected_eht_action,
236*5113495bSYour Name 		  epcs_action_frm->dialog_token,
237*5113495bSYour Name 		  epcs_action_frm->resp.status_code[0],
238*5113495bSYour Name 		  epcs_action_frm->resp.status_code[1], frm_len);
239*5113495bSYour Name 
240*5113495bSYour Name 	if (frm_len > EPCS_RESP_MIN_LENGTH) {
241*5113495bSYour Name 		pa_ie = (uint8_t *)epcs_action_frm + EPCS_RESP_MIN_LENGTH;
242*5113495bSYour Name 		pa_ie_len = frm_len - EPCS_RESP_MIN_LENGTH;
243*5113495bSYour Name 		return mlo_process_ml_priorityaccess_ie(pa_ie,
244*5113495bSYour Name 							pa_ie_len,
245*5113495bSYour Name 							priority_access_info);
246*5113495bSYour Name 	} else {
247*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
248*5113495bSYour Name 	}
249*5113495bSYour Name }
250*5113495bSYour Name 
251*5113495bSYour Name /**
252*5113495bSYour Name  * wlan_mlo_parse_epcs_teardown_action_frame() - API to parse EPCS teardown
253*5113495bSYour Name  * action frame.
254*5113495bSYour Name  * @epcs: Pointer to EPCS structure
255*5113495bSYour Name  * @action_frm: Pointer to action frame
256*5113495bSYour Name  * @frm_len: frame length
257*5113495bSYour Name  *
258*5113495bSYour Name  * Return: QDF_STATUS
259*5113495bSYour Name  */
260*5113495bSYour Name static QDF_STATUS
wlan_mlo_parse_epcs_teardown_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)261*5113495bSYour Name wlan_mlo_parse_epcs_teardown_action_frame(struct wlan_epcs_info *epcs,
262*5113495bSYour Name 					  struct wlan_action_frame *action_frm,
263*5113495bSYour Name 					  uint32_t frm_len)
264*5113495bSYour Name {
265*5113495bSYour Name 	struct epcs_frm *epcs_action_frm;
266*5113495bSYour Name 
267*5113495bSYour Name 	/*
268*5113495bSYour Name 	 * EPCS teardown action frame
269*5113495bSYour Name 	 *
270*5113495bSYour Name 	 *   1-byte     1-byte
271*5113495bSYour Name 	 *------------------------
272*5113495bSYour Name 	 * |         |           |
273*5113495bSYour Name 	 * | Category| Protected |
274*5113495bSYour Name 	 * |         |    EHT    |
275*5113495bSYour Name 	 * |         |  Action   |
276*5113495bSYour Name 	 *------------------------
277*5113495bSYour Name 	 */
278*5113495bSYour Name 
279*5113495bSYour Name 	epcs_action_frm = (struct epcs_frm *)action_frm;
280*5113495bSYour Name 
281*5113495bSYour Name 	epcs->cat = epcs_action_frm->protected_eht_action;
282*5113495bSYour Name 	epcs_info("EPCS frame rcv : category:%d action:%d frmlen %d",
283*5113495bSYour Name 		  epcs_action_frm->category,
284*5113495bSYour Name 		  epcs_action_frm->protected_eht_action, frm_len);
285*5113495bSYour Name 
286*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
287*5113495bSYour Name }
288*5113495bSYour Name 
289*5113495bSYour Name QDF_STATUS
wlan_mlo_parse_epcs_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)290*5113495bSYour Name wlan_mlo_parse_epcs_action_frame(struct wlan_epcs_info *epcs,
291*5113495bSYour Name 				 struct wlan_action_frame *action_frm,
292*5113495bSYour Name 				 uint32_t frm_len)
293*5113495bSYour Name {
294*5113495bSYour Name 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
295*5113495bSYour Name 
296*5113495bSYour Name 	switch (action_frm->action) {
297*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_REQUEST:
298*5113495bSYour Name 		return wlan_mlo_parse_epcs_request_action_frame(
299*5113495bSYour Name 				epcs, action_frm, frm_len);
300*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_RESPONSE:
301*5113495bSYour Name 		return wlan_mlo_parse_epcs_response_action_frame(
302*5113495bSYour Name 				epcs, action_frm, frm_len);
303*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_TEARDOWN:
304*5113495bSYour Name 		return wlan_mlo_parse_epcs_teardown_action_frame(
305*5113495bSYour Name 				epcs, action_frm, frm_len);
306*5113495bSYour Name 	default:
307*5113495bSYour Name 		ret_val = QDF_STATUS_E_INVAL;
308*5113495bSYour Name 			epcs_err("Invalid action :%d", action_frm->action);
309*5113495bSYour Name 	}
310*5113495bSYour Name 
311*5113495bSYour Name 	return ret_val;
312*5113495bSYour Name }
313*5113495bSYour Name 
314*5113495bSYour Name static uint8_t *
wlan_mlo_add_epcs_request_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)315*5113495bSYour Name wlan_mlo_add_epcs_request_action_frame(uint8_t *frm,
316*5113495bSYour Name 				       struct wlan_action_frame_args *args,
317*5113495bSYour Name 				       uint8_t *buf)
318*5113495bSYour Name {
319*5113495bSYour Name 	*frm++ = args->category;
320*5113495bSYour Name 	*frm++ = args->action;
321*5113495bSYour Name 	/* Dialog token*/
322*5113495bSYour Name 	*frm++ = args->arg1;
323*5113495bSYour Name 
324*5113495bSYour Name 	epcs_info("EPCS frame: category:%d action:%d dialog_token:%d",
325*5113495bSYour Name 		  args->category, args->action, args->arg1);
326*5113495bSYour Name 
327*5113495bSYour Name 	/* Add priority access ml ie in caller for AP mode */
328*5113495bSYour Name 	return frm;
329*5113495bSYour Name }
330*5113495bSYour Name 
331*5113495bSYour Name static uint8_t *
wlan_mlo_add_epcs_response_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)332*5113495bSYour Name wlan_mlo_add_epcs_response_action_frame(uint8_t *frm,
333*5113495bSYour Name 					struct wlan_action_frame_args *args,
334*5113495bSYour Name 					uint8_t *buf)
335*5113495bSYour Name {
336*5113495bSYour Name 	*frm++ = args->category;
337*5113495bSYour Name 	*frm++ = args->action;
338*5113495bSYour Name 	/* Dialog token*/
339*5113495bSYour Name 	*frm++ = args->arg1;
340*5113495bSYour Name 	/* Status code (2 bytes) */
341*5113495bSYour Name 	*frm++ = QDF_GET_BITS(args->arg2, 0, 8);
342*5113495bSYour Name 	*frm++ = QDF_GET_BITS(args->arg2, 8, 8);
343*5113495bSYour Name 
344*5113495bSYour Name 	epcs_info("EPCS response frame: category:%d action:%d dialog_token:%d status_code:%d",
345*5113495bSYour Name 		  args->category, args->action, args->arg1, args->arg2);
346*5113495bSYour Name 
347*5113495bSYour Name 	/* Add priority access ml ie for AP mode */
348*5113495bSYour Name 	return frm;
349*5113495bSYour Name }
350*5113495bSYour Name 
351*5113495bSYour Name uint8_t *
wlan_mlo_add_epcs_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)352*5113495bSYour Name wlan_mlo_add_epcs_action_frame(uint8_t *frm,
353*5113495bSYour Name 			       struct wlan_action_frame_args *args,
354*5113495bSYour Name 			       uint8_t *buf)
355*5113495bSYour Name {
356*5113495bSYour Name 	switch (args->action) {
357*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_REQUEST:
358*5113495bSYour Name 		return wlan_mlo_add_epcs_request_action_frame(frm, args,
359*5113495bSYour Name 							      buf);
360*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_RESPONSE:
361*5113495bSYour Name 		return wlan_mlo_add_epcs_response_action_frame(frm, args,
362*5113495bSYour Name 							      buf);
363*5113495bSYour Name 	case WLAN_EPCS_CATEGORY_TEARDOWN:
364*5113495bSYour Name 		*frm++ = args->category;
365*5113495bSYour Name 		*frm++ = args->action;
366*5113495bSYour Name 		return frm;
367*5113495bSYour Name 	default:
368*5113495bSYour Name 		epcs_err("Invalid category:%d", args->category);
369*5113495bSYour Name 	}
370*5113495bSYour Name 
371*5113495bSYour Name 	return frm;
372*5113495bSYour Name }
373*5113495bSYour Name 
374*5113495bSYour Name QDF_STATUS
wlan_mlo_peer_rcv_cmd(struct wlan_mlo_peer_context * ml_peer,struct wlan_epcs_info * epcs,bool * updparam)375*5113495bSYour Name wlan_mlo_peer_rcv_cmd(struct wlan_mlo_peer_context *ml_peer,
376*5113495bSYour Name 		      struct wlan_epcs_info *epcs,
377*5113495bSYour Name 		      bool *updparam)
378*5113495bSYour Name {
379*5113495bSYour Name 	uint32_t cur_state;
380*5113495bSYour Name 	uint32_t new_state;
381*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
382*5113495bSYour Name 
383*5113495bSYour Name 	if (!ml_peer) {
384*5113495bSYour Name 		epcs_err("Null MLO peer");
385*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
386*5113495bSYour Name 	}
387*5113495bSYour Name 
388*5113495bSYour Name 	*updparam = false;
389*5113495bSYour Name 
390*5113495bSYour Name 	epcs_dev_peer_lock_acquire(&ml_peer->epcs_info);
391*5113495bSYour Name 	cur_state = ml_peer->epcs_info.state;
392*5113495bSYour Name 	switch (ml_peer->epcs_info.state) {
393*5113495bSYour Name 	case EPCS_DOWN:
394*5113495bSYour Name 		if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
395*5113495bSYour Name 		/* check authorization */
396*5113495bSYour Name 			if (wlan_mlo_is_node_epcs_authorized(ml_peer) ==
397*5113495bSYour Name 			   QDF_STATUS_SUCCESS) {
398*5113495bSYour Name 				status = QDF_STATUS_SUCCESS;
399*5113495bSYour Name 				epcs->dialog_token =
400*5113495bSYour Name 				  ++ml_peer->epcs_info.self_gen_dialog_token;
401*5113495bSYour Name 			} else {
402*5113495bSYour Name 				epcs_info("peer not authorized to enable EPCS");
403*5113495bSYour Name 			}
404*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
405*5113495bSYour Name 			epcs_info("peer already in EPCS down state");
406*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
407*5113495bSYour Name 			epcs_err("Invalid command");
408*5113495bSYour Name 		}
409*5113495bSYour Name 		break;
410*5113495bSYour Name 	case EPCS_ENABLE:
411*5113495bSYour Name 		if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
412*5113495bSYour Name 			ml_peer->epcs_info.state = EPCS_DOWN;
413*5113495bSYour Name 			status = QDF_STATUS_SUCCESS;
414*5113495bSYour Name 			*updparam = true;
415*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
416*5113495bSYour Name 			epcs_info("peer already in EPCS enable state");
417*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
418*5113495bSYour Name 			epcs_err("Invalid command");
419*5113495bSYour Name 		}
420*5113495bSYour Name 		break;
421*5113495bSYour Name 	default:
422*5113495bSYour Name 		epcs_err("Invalid peer state %d",
423*5113495bSYour Name 			 ml_peer->epcs_info.state);
424*5113495bSYour Name 	}
425*5113495bSYour Name 
426*5113495bSYour Name 	new_state = ml_peer->epcs_info.state;
427*5113495bSYour Name 	epcs_debug("cmd:old state %d new state %d ev cat %d dialog token %d status %d",
428*5113495bSYour Name 		   cur_state, new_state, epcs->cat,
429*5113495bSYour Name 		   epcs->dialog_token, epcs->status);
430*5113495bSYour Name 
431*5113495bSYour Name 	epcs_dev_peer_lock_release(&ml_peer->epcs_info);
432*5113495bSYour Name 
433*5113495bSYour Name 	return status;
434*5113495bSYour Name }
435*5113495bSYour Name 
436*5113495bSYour Name QDF_STATUS
wlan_mlo_peer_rcv_action_frame(struct wlan_mlo_peer_context * ml_peer,struct wlan_epcs_info * epcs,bool * respond,bool * updparam)437*5113495bSYour Name wlan_mlo_peer_rcv_action_frame(struct wlan_mlo_peer_context *ml_peer,
438*5113495bSYour Name 			       struct wlan_epcs_info *epcs,
439*5113495bSYour Name 			       bool *respond,
440*5113495bSYour Name 			       bool *updparam)
441*5113495bSYour Name {
442*5113495bSYour Name 	uint32_t cur_state;
443*5113495bSYour Name 	uint32_t new_state;
444*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
445*5113495bSYour Name 
446*5113495bSYour Name 	if (!ml_peer) {
447*5113495bSYour Name 		epcs_err("Null MLO peer");
448*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
449*5113495bSYour Name 	}
450*5113495bSYour Name 
451*5113495bSYour Name 	*respond = false;
452*5113495bSYour Name 	*updparam = false;
453*5113495bSYour Name 
454*5113495bSYour Name 	epcs_dev_peer_lock_acquire(&ml_peer->epcs_info);
455*5113495bSYour Name 	cur_state = ml_peer->epcs_info.state;
456*5113495bSYour Name 	switch (ml_peer->epcs_info.state) {
457*5113495bSYour Name 	case EPCS_DOWN:
458*5113495bSYour Name 		if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
459*5113495bSYour Name 			if (epcs->status == STATUS_SUCCESS) {
460*5113495bSYour Name 				if (epcs->dialog_token ==
461*5113495bSYour Name 				    ml_peer->epcs_info.self_gen_dialog_token) {
462*5113495bSYour Name 					ml_peer->epcs_info.state = EPCS_ENABLE;
463*5113495bSYour Name 					status = QDF_STATUS_SUCCESS;
464*5113495bSYour Name 					*updparam = true;
465*5113495bSYour Name 				} else {
466*5113495bSYour Name 					epcs_err("Response dialog token mismatch self_gen_dialog_token %d response token %d", ml_peer->epcs_info.self_gen_dialog_token, epcs->dialog_token);
467*5113495bSYour Name 				}
468*5113495bSYour Name 			} else {
469*5113495bSYour Name 				epcs_info("epcs rejected with status code %d",
470*5113495bSYour Name 					  epcs->status);
471*5113495bSYour Name 			}
472*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
473*5113495bSYour Name 			/* check authorization */
474*5113495bSYour Name 			if (wlan_mlo_is_node_epcs_authorized(ml_peer) ==
475*5113495bSYour Name 			   QDF_STATUS_SUCCESS) {
476*5113495bSYour Name 				ml_peer->epcs_info.state = EPCS_ENABLE;
477*5113495bSYour Name 				status = QDF_STATUS_SUCCESS;
478*5113495bSYour Name 				*respond = true;
479*5113495bSYour Name 				*updparam = true;
480*5113495bSYour Name 			} else {
481*5113495bSYour Name 				epcs_info("peer not authorized to enable EPCS");
482*5113495bSYour Name 			}
483*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
484*5113495bSYour Name 			epcs_info("peer not in EPCS enable state");
485*5113495bSYour Name 		}
486*5113495bSYour Name 		break;
487*5113495bSYour Name 	case EPCS_ENABLE:
488*5113495bSYour Name 		if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
489*5113495bSYour Name 			ml_peer->epcs_info.state = EPCS_DOWN;
490*5113495bSYour Name 			status = QDF_STATUS_SUCCESS;
491*5113495bSYour Name 			*updparam = true;
492*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
493*5113495bSYour Name 			epcs_info("peer already in EPCS enable state");
494*5113495bSYour Name 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
495*5113495bSYour Name 			epcs_info("peer already in EPCS enable state");
496*5113495bSYour Name 		}
497*5113495bSYour Name 		break;
498*5113495bSYour Name 	default:
499*5113495bSYour Name 		epcs_err("Invalid peer state %d", ml_peer->epcs_info.state);
500*5113495bSYour Name 	}
501*5113495bSYour Name 
502*5113495bSYour Name 	new_state = ml_peer->epcs_info.state;
503*5113495bSYour Name 	epcs_debug("action:old state %d new state %d ev cat %d dialog token %d status %d",
504*5113495bSYour Name 		   cur_state, new_state, epcs->cat,
505*5113495bSYour Name 		   epcs->dialog_token, epcs->status);
506*5113495bSYour Name 
507*5113495bSYour Name 	epcs_dev_peer_lock_release(&ml_peer->epcs_info);
508*5113495bSYour Name 
509*5113495bSYour Name 	return status;
510*5113495bSYour Name }
511*5113495bSYour Name 
512*5113495bSYour Name QDF_STATUS
wlan_mlo_update_authorize_epcs_mac_addr(struct wlan_objmgr_vdev * vdev,uint8_t * peer_mld_mac)513*5113495bSYour Name wlan_mlo_update_authorize_epcs_mac_addr(struct wlan_objmgr_vdev *vdev,
514*5113495bSYour Name 					uint8_t *peer_mld_mac)
515*5113495bSYour Name {
516*5113495bSYour Name 	bool found_entry = false;
517*5113495bSYour Name 	int free_index = -1;
518*5113495bSYour Name 	int i = 0;
519*5113495bSYour Name 	struct wlan_epcs_context *epcs_ctx;
520*5113495bSYour Name 
521*5113495bSYour Name 	if (!vdev) {
522*5113495bSYour Name 		epcs_err("vdev is null");
523*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
524*5113495bSYour Name 	}
525*5113495bSYour Name 
526*5113495bSYour Name 	epcs_ctx = &vdev->mlo_dev_ctx->epcs_ctx;
527*5113495bSYour Name 
528*5113495bSYour Name 	epcs_dev_lock_acquire(epcs_ctx);
529*5113495bSYour Name 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
530*5113495bSYour Name 		/* Finding first available slot */
531*5113495bSYour Name 		if ((!epcs_ctx->authorize_info[i].valid) && (free_index < 0))
532*5113495bSYour Name 			free_index = i;
533*5113495bSYour Name 
534*5113495bSYour Name 		/* Checking for already available valid entry */
535*5113495bSYour Name 		if (epcs_ctx->authorize_info[i].valid &&
536*5113495bSYour Name 		    !qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
537*5113495bSYour Name 				 peer_mld_mac,
538*5113495bSYour Name 				 QDF_MAC_ADDR_SIZE)) {
539*5113495bSYour Name 			found_entry = true;
540*5113495bSYour Name 			break;
541*5113495bSYour Name 		}
542*5113495bSYour Name 	}
543*5113495bSYour Name 
544*5113495bSYour Name 	if (found_entry) {
545*5113495bSYour Name 		epcs_debug("Mac add "QDF_MAC_ADDR_FMT" is already authorized",
546*5113495bSYour Name 			   QDF_MAC_ADDR_REF(peer_mld_mac));
547*5113495bSYour Name 		epcs_dev_lock_release(epcs_ctx);
548*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
549*5113495bSYour Name 	}
550*5113495bSYour Name 
551*5113495bSYour Name 	if (free_index < 0) {
552*5113495bSYour Name 		epcs_debug("EPCS authorize database is full");
553*5113495bSYour Name 		epcs_dev_lock_release(epcs_ctx);
554*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
555*5113495bSYour Name 	}
556*5113495bSYour Name 
557*5113495bSYour Name 	epcs_ctx->authorize_info[free_index].valid = true;
558*5113495bSYour Name 	qdf_mem_copy(epcs_ctx->authorize_info[free_index]. peer_mld_mac,
559*5113495bSYour Name 		     peer_mld_mac,
560*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
561*5113495bSYour Name 	epcs_dev_lock_release(epcs_ctx);
562*5113495bSYour Name 
563*5113495bSYour Name 	epcs_debug("EPCS Stored authorize mac addr is"QDF_MAC_ADDR_FMT" at index %d",
564*5113495bSYour Name 		   QDF_MAC_ADDR_REF(peer_mld_mac), free_index);
565*5113495bSYour Name 
566*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
567*5113495bSYour Name }
568*5113495bSYour Name 
569*5113495bSYour Name QDF_STATUS
wlan_mlo_update_deauthorize_epcs_mac_addr(struct wlan_objmgr_vdev * vdev,uint8_t * peer_mld_mac)570*5113495bSYour Name wlan_mlo_update_deauthorize_epcs_mac_addr(struct wlan_objmgr_vdev *vdev,
571*5113495bSYour Name 					  uint8_t *peer_mld_mac)
572*5113495bSYour Name {
573*5113495bSYour Name 	int i = 0;
574*5113495bSYour Name 	struct wlan_epcs_context *epcs_ctx;
575*5113495bSYour Name 	bool found_entry = false;
576*5113495bSYour Name 
577*5113495bSYour Name 	if (!vdev) {
578*5113495bSYour Name 		epcs_err("vdev is null");
579*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
580*5113495bSYour Name 	}
581*5113495bSYour Name 
582*5113495bSYour Name 	epcs_ctx = &vdev->mlo_dev_ctx->epcs_ctx;
583*5113495bSYour Name 
584*5113495bSYour Name 	epcs_dev_lock_acquire(epcs_ctx);
585*5113495bSYour Name 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
586*5113495bSYour Name 		if (!qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
587*5113495bSYour Name 				 peer_mld_mac,
588*5113495bSYour Name 				 QDF_MAC_ADDR_SIZE)) {
589*5113495bSYour Name 			found_entry = true;
590*5113495bSYour Name 			break;
591*5113495bSYour Name 		}
592*5113495bSYour Name 	}
593*5113495bSYour Name 
594*5113495bSYour Name 	if (!found_entry) {
595*5113495bSYour Name 		epcs_debug("Mac addr "QDF_MAC_ADDR_FMT" not found in authorized database",
596*5113495bSYour Name 			   QDF_MAC_ADDR_REF(peer_mld_mac));
597*5113495bSYour Name 		epcs_dev_lock_release(epcs_ctx);
598*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
599*5113495bSYour Name 	}
600*5113495bSYour Name 
601*5113495bSYour Name 	if (found_entry && !epcs_ctx->authorize_info[i].valid) {
602*5113495bSYour Name 		epcs_debug("Mac addr "QDF_MAC_ADDR_FMT" is already deauthorized in database",
603*5113495bSYour Name 			   QDF_MAC_ADDR_REF(peer_mld_mac));
604*5113495bSYour Name 		epcs_dev_lock_release(epcs_ctx);
605*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
606*5113495bSYour Name 	}
607*5113495bSYour Name 
608*5113495bSYour Name 	epcs_ctx->authorize_info[i].valid = false;
609*5113495bSYour Name 	epcs_dev_lock_release(epcs_ctx);
610*5113495bSYour Name 	epcs_debug("EPCS Stored authorize mac addr is "QDF_MAC_ADDR_FMT" at idx %d is removed",
611*5113495bSYour Name 		   QDF_MAC_ADDR_REF(peer_mld_mac), i);
612*5113495bSYour Name 
613*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
614*5113495bSYour Name }
615