1 /*
2  * Copyright (c) 2011-2016, 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  *
22  * This file lim_aid_mgmt.c contains the functions related to
23  * AID pool management like initialization, assignment etc.
24  * Author:        Chandra Modumudi
25  * Date:          03/20/02
26  * History:-
27  * Date           Modified by    Modification Information
28  * --------------------------------------------------------------------
29  */
30 
31 #include "cds_api.h"
32 #include "wni_cfg.h"
33 #include "ani_global.h"
34 #include "sir_params.h"
35 #include "lim_utils.h"
36 #include "lim_timer_utils.h"
37 #include "lim_ft_defs.h"
38 #include "lim_session.h"
39 #include "lim_session_utils.h"
40 #include <wlan_mlo_mgr_ap.h>
41 #include <wlan_mlo_mgr_peer.h>
42 
43 #define LIM_START_PEER_IDX   1
44 
45 /**
46  * lim_init_peer_idxpool_legacy() - init aid pool for non MLO SAP
47  * @mac: Pointer to Global MAC structure
48  * @pe_session: pe session
49  *
50  * Return: Void
51  */
lim_init_peer_idxpool_legacy(struct mac_context * mac,struct pe_session * pe_session)52 static void lim_init_peer_idxpool_legacy(struct mac_context *mac,
53 					 struct pe_session *pe_session)
54 {
55 	uint8_t i;
56 	uint8_t max_assoc_sta = mac->lim.max_sta_of_pe_session;
57 
58 	pe_session->gpLimPeerIdxpool[0] = 0;
59 
60 #ifdef FEATURE_WLAN_TDLS
61 	/*
62 	* In station role, DPH_STA_HASH_INDEX_PEER (index 1) is reserved
63 	* for peer station index corresponding to AP. Avoid choosing that index
64 	* and get index starting from (DPH_STA_HASH_INDEX_PEER + 1)
65 	* (index 2) for TDLS stations;
66 	*/
67 	if (LIM_IS_STA_ROLE(pe_session)) {
68 		pe_session->freePeerIdxHead = DPH_STA_HASH_INDEX_PEER + 1;
69 	} else
70 #endif
71 	{
72 		pe_session->freePeerIdxHead = LIM_START_PEER_IDX;
73 	}
74 
75 	for (i = pe_session->freePeerIdxHead; i < max_assoc_sta; i++)
76 		pe_session->gpLimPeerIdxpool[i] = i + 1;
77 
78 	pe_session->gpLimPeerIdxpool[i] = 0;
79 
80 	pe_session->freePeerIdxTail = i;
81 }
82 
lim_init_peer_idxpool(struct mac_context * mac,struct pe_session * pe_session)83 void lim_init_peer_idxpool(struct mac_context *mac,
84 			   struct pe_session *pe_session)
85 {
86 	if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
87 		lim_init_peer_idxpool_legacy(mac, pe_session);
88 }
89 
90 /**
91  * lim_create_peer_idxpool_legacy() - AID pool creation for non-MLO AP
92  * @pe_session: pe session
93  * @idx_pool_size: aid pool size
94  *
95  * Return: true if pool is created successfully
96  */
lim_create_peer_idxpool_legacy(struct pe_session * pe_session,uint8_t idx_pool_size)97 static bool lim_create_peer_idxpool_legacy(struct pe_session *pe_session,
98 					   uint8_t idx_pool_size)
99 {
100 	pe_session->gpLimPeerIdxpool = qdf_mem_malloc(
101 		sizeof(*pe_session->gpLimPeerIdxpool) * idx_pool_size);
102 	if (!pe_session->gpLimPeerIdxpool)
103 		return false;
104 
105 	pe_session->freePeerIdxHead = 0;
106 	pe_session->freePeerIdxTail = 0;
107 
108 	return true;
109 }
110 
lim_create_peer_idxpool(struct pe_session * pe_session,uint8_t idx_pool_size)111 bool lim_create_peer_idxpool(struct pe_session *pe_session,
112 			     uint8_t idx_pool_size)
113 {
114 	pe_session->gLimNumOfCurrentSTAs = 0;
115 	if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
116 		return lim_create_peer_idxpool_legacy(pe_session,
117 						      idx_pool_size);
118 
119 	return true;
120 }
121 
122 /**
123  * lim_free_peer_idxpool_legacy() - Free the non-MLO AP aid pool
124  * @pe_session: pe session
125  *
126  * Return: Void
127  */
lim_free_peer_idxpool_legacy(struct pe_session * pe_session)128 static void lim_free_peer_idxpool_legacy(struct pe_session *pe_session)
129 {
130 	if (pe_session->gpLimPeerIdxpool) {
131 		qdf_mem_free(pe_session->gpLimPeerIdxpool);
132 		pe_session->gpLimPeerIdxpool = NULL;
133 	}
134 }
135 
lim_free_peer_idxpool(struct pe_session * pe_session)136 void lim_free_peer_idxpool(struct pe_session *pe_session)
137 {
138 	if (!pe_session->vdev) {
139 		pe_debug("vdev is null");
140 		return;
141 	}
142 	if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
143 		lim_free_peer_idxpool_legacy(pe_session);
144 }
145 
146 /**
147  * lim_assign_peer_idx_mlo() - trigger mlo api to allocate an AID for a STA
148  * @pe_session: pe session
149  *
150  * Return: peer_idx - assigned AID for STA
151  */
152 #ifdef WLAN_FEATURE_11BE_MLO
lim_assign_peer_idx_mlo(struct pe_session * pe_session)153 static uint16_t lim_assign_peer_idx_mlo(struct pe_session *pe_session)
154 {
155 	return mlme_get_aid(pe_session->vdev);
156 }
157 #else
lim_assign_peer_idx_mlo(struct pe_session * pe_session)158 static uint16_t lim_assign_peer_idx_mlo(struct pe_session *pe_session)
159 {
160 	return 0;               /* no more free peer index */
161 }
162 #endif
163 
164 /**
165  * lim_assign_peer_idx_legacy() - non-MLO AP allocates an AID for a STA
166  * @mac: Pointer to Global MAC structure
167  * @pe_session: pe session
168  *
169  * Return: peer_idx - assigned AID for STA
170  */
lim_assign_peer_idx_legacy(struct mac_context * mac,struct pe_session * pe_session)171 static uint16_t lim_assign_peer_idx_legacy(struct mac_context *mac,
172 					   struct pe_session *pe_session)
173 {
174 	uint16_t peer_id;
175 
176 	/* return head of free list */
177 
178 	if (pe_session->freePeerIdxHead) {
179 		peer_id = pe_session->freePeerIdxHead;
180 		pe_session->freePeerIdxHead =
181 		    pe_session->gpLimPeerIdxpool[pe_session->freePeerIdxHead];
182 		if (pe_session->freePeerIdxHead == 0)
183 			pe_session->freePeerIdxTail = 0;
184 		return peer_id;
185 	}
186 
187 	return 0;               /* no more free peer index */
188 }
189 
190 /**
191  * lim_assign_peer_idx()
192  *
193  ***FUNCTION:
194  * This function is called to get a peer station index. This index is
195  * used during Association/Reassociation
196  * frame handling to assign association ID (aid) to a STA.
197  * In case of TDLS, this is used to assign a index into the Dph hash entry.
198  *
199  ***LOGIC:
200  *
201  ***ASSUMPTIONS:
202  * NA
203  *
204  ***NOTE:
205  *
206  * @param  mac - Pointer to Global MAC structure
207  * @return peerIdx  - assigned peer Station IDx for STA
208  */
209 
lim_assign_peer_idx(struct mac_context * mac,struct pe_session * pe_session)210 uint16_t lim_assign_peer_idx(struct mac_context *mac,
211 			     struct pe_session *pe_session)
212 {
213 	uint16_t peer_id;
214 
215 	/* make sure we haven't exceeded the configurable limit on associations */
216 	/* This count is global to ensure that it doesn't exceed the hardware limits. */
217 	if (pe_get_current_stas_count(mac) >=
218 	    mac->mlme_cfg->sap_cfg.assoc_sta_limit) {
219 		/* too many associations already active */
220 		return 0;
221 	}
222 
223 	if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
224 		peer_id = lim_assign_peer_idx_mlo(pe_session);
225 	else
226 		peer_id = lim_assign_peer_idx_legacy(mac, pe_session);
227 
228 	if (peer_id)
229 		pe_session->gLimNumOfCurrentSTAs++;
230 
231 	return peer_id;
232 }
233 
234 #ifdef WLAN_FEATURE_11BE_MLO
lim_assign_mlo_conn_idx(struct mac_context * mac,struct pe_session * pe_session,uint16_t partner_peer_idx)235 uint16_t lim_assign_mlo_conn_idx(struct mac_context *mac,
236 				 struct pe_session *pe_session,
237 				 uint16_t partner_peer_idx)
238 {
239 	uint16_t peer_id;
240 
241 	if (pe_get_current_stas_count(mac) >=
242 	    mac->mlme_cfg->sap_cfg.assoc_sta_limit) {
243 		/* too many associations already active */
244 		return 0;
245 	}
246 
247 	if (partner_peer_idx)
248 		peer_id = partner_peer_idx;
249 	else
250 		peer_id = mlo_get_aid(pe_session->vdev);
251 
252 	if (peer_id)
253 		pe_session->gLimNumOfCurrentSTAs++;
254 
255 	return peer_id;
256 }
257 
258 /**
259  * lim_release_peer_idx_mlo() - trigger mlo api to release aid
260  * @peer_idx: aid to free
261  * @pe_session: pe session
262  *
263  * Return: Void
264  */
lim_release_peer_idx_mlo(uint16_t peer_idx,struct pe_session * pe_session)265 static void lim_release_peer_idx_mlo(uint16_t peer_idx,
266 				     struct pe_session *pe_session)
267 {
268 	return mlme_free_aid(pe_session->vdev, peer_idx);
269 }
270 #else
lim_release_peer_idx_mlo(uint16_t peer_idx,struct pe_session * pe_session)271 static void lim_release_peer_idx_mlo(uint16_t peer_idx,
272 				     struct pe_session *pe_session)
273 {
274 }
275 #endif
276 
277 /**
278  * lim_release_peer_idx_legacy() - non-MLO AP releases an AID
279  * @mac: Pointer to Global MAC structure
280  * @peer_idx: aid to free
281  * @pe_session: pe session
282  *
283  * Return: Void
284  */
lim_release_peer_idx_legacy(struct mac_context * mac,uint16_t peer_idx,struct pe_session * pe_session)285 static void lim_release_peer_idx_legacy(struct mac_context *mac,
286 					uint16_t peer_idx,
287 					struct pe_session *pe_session)
288 {
289 	/* insert at tail of free list */
290 	if (pe_session->freePeerIdxTail) {
291 		pe_session->gpLimPeerIdxpool[pe_session->freePeerIdxTail] =
292 			(uint8_t)peer_idx;
293 		pe_session->freePeerIdxTail = (uint8_t)peer_idx;
294 	} else {
295 		pe_session->freePeerIdxTail =
296 			pe_session->freePeerIdxHead = (uint8_t)peer_idx;
297 	}
298 	pe_session->gpLimPeerIdxpool[(uint8_t)peer_idx] = 0;
299 }
300 
301 /**
302  * lim_release_peer_idx()
303  *
304  ***FUNCTION:
305  * This function is called when a STA context is removed
306  * at AP (or TDLS) to return peer Index
307  * to free pool.
308  *
309  ***LOGIC:
310  *
311  ***ASSUMPTIONS:
312  * NA
313  *
314  ***NOTE:
315  *
316  * @param  mac - Pointer to Global MAC structure
317  * @param  peerIdx - peer station index that need to return to free pool
318  *
319  * @return None
320  */
321 
322 void
lim_release_peer_idx(struct mac_context * mac,uint16_t peer_idx,struct pe_session * pe_session)323 lim_release_peer_idx(struct mac_context *mac, uint16_t peer_idx,
324 		     struct pe_session *pe_session)
325 {
326 	pe_session->gLimNumOfCurrentSTAs--;
327 
328 	if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
329 		lim_release_peer_idx_mlo(peer_idx, pe_session);
330 	else
331 		lim_release_peer_idx_legacy(mac, peer_idx, pe_session);
332 }
333 
334 #ifdef WLAN_FEATURE_11BE_MLO
335 void
lim_release_mlo_conn_idx(struct mac_context * mac,uint16_t peer_idx,struct pe_session * session,bool free_aid)336 lim_release_mlo_conn_idx(struct mac_context *mac, uint16_t peer_idx,
337 			 struct pe_session *session, bool free_aid)
338 {
339 	session->gLimNumOfCurrentSTAs--;
340 	if (free_aid &&
341 	    wlan_mlo_get_mlpeer_by_aid(session->vdev->mlo_dev_ctx, peer_idx))
342 		mlo_free_aid(session->vdev, peer_idx);
343 }
344 #endif
345