1 /*
2  * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2024 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  * This file contains TSPEC and STA admit control related functions
22  * NOTE: applies only to AP builds
23  *
24  * Author:      Sandesh Goel
25  * Date:        02/25/02
26  * History:-
27  * Date            Modified by    Modification Information
28  * --------------------------------------------------------------------
29  *
30  */
31 #include "sys_def.h"
32 #include "lim_api.h"
33 #include "lim_trace.h"
34 #include "lim_send_sme_rsp_messages.h"
35 #include "lim_types.h"
36 #include "lim_admit_control.h"
37 
38 /* total available bandwidth in bps in each phy mode
39  * these should be defined in hal or dph - replace these later
40  */
41 #define LIM_TOTAL_BW_11A   54000000
42 #define LIM_MIN_BW_11A     6000000
43 #define LIM_TOTAL_BW_11B   11000000
44 #define LIM_MIN_BW_11B     1000000
45 #define LIM_TOTAL_BW_11G   LIM_TOTAL_BW_11A
46 #define LIM_MIN_BW_11G     LIM_MIN_BW_11B
47 
48 /* conversion factors */
49 #define LIM_CONVERT_SIZE_BITS(numBytes) ((numBytes) * 8)
50 #define LIM_CONVERT_RATE_MBPS(rate)     ((rate)/1000000)
51 
52 /* ------------------------------------------------------------------------------ */
53 /* local protos */
54 
55 static void lim_get_available_bw(struct mac_context *, uint32_t *, uint32_t *, uint32_t,
56 				 uint32_t);
57 
58 /** -------------------------------------------------------------
59    \fn lim_calculate_svc_int
60    \brief TSPEC validation and servcie interval determination
61    \param     struct mac_context *   mac
62    \param         struct mac_tspec_ie *pTspec
63    \param         uint32_t            *pSvcInt
64    \return QDF_STATUS - status of the comparison
65    -------------------------------------------------------------*/
66 
67 static QDF_STATUS
lim_calculate_svc_int(struct mac_context * mac,struct mac_tspec_ie * pTspec,uint32_t * pSvcInt)68 lim_calculate_svc_int(struct mac_context *mac,
69 		      struct mac_tspec_ie *pTspec, uint32_t *pSvcInt)
70 {
71 	uint32_t msduSz, dataRate;
72 	*pSvcInt = 0;
73 
74 	/* if a service interval is already specified, we are done */
75 	if ((pTspec->minSvcInterval != 0) || (pTspec->maxSvcInterval != 0)) {
76 		*pSvcInt = (pTspec->maxSvcInterval != 0)
77 			   ? pTspec->maxSvcInterval : pTspec->minSvcInterval;
78 		return QDF_STATUS_SUCCESS;
79 	}
80 
81 	/* Masking off the fixed bits according to definition of MSDU size
82 	 * in IEEE 802.11-2007 spec (section 7.3.2.30). Nominal MSDU size
83 	 * is defined as:  Bit[0:14]=Size, Bit[15]=Fixed
84 	 */
85 	if (pTspec->nomMsduSz != 0)
86 		msduSz = (pTspec->nomMsduSz & 0x7fff);
87 	else if (pTspec->maxMsduSz != 0)
88 		msduSz = pTspec->maxMsduSz;
89 	else {
90 		pe_err("MsduSize not specified");
91 		return QDF_STATUS_E_FAILURE;
92 	}
93 
94 	/* need to calculate a reasonable service interval
95 	 * this is simply the msduSz/meanDataRate
96 	 */
97 	if (pTspec->meanDataRate != 0)
98 		dataRate = pTspec->meanDataRate;
99 	else if (pTspec->peakDataRate != 0)
100 		dataRate = pTspec->peakDataRate;
101 	else if (pTspec->minDataRate != 0)
102 		dataRate = pTspec->minDataRate;
103 	else {
104 		pe_err("DataRate not specified");
105 		return QDF_STATUS_E_FAILURE;
106 	}
107 
108 	*pSvcInt =
109 		LIM_CONVERT_SIZE_BITS(msduSz) / LIM_CONVERT_RATE_MBPS(dataRate);
110 	return QDF_STATUS_E_FAILURE;
111 }
112 
113 /**
114  * lim_validate_tspec_edca() - Validate the parameters
115  * @mac_ctx: Global MAC context
116  * @tspec:   Pointer to the TSPEC
117  * @session_entry: Session Entry
118  *
119  * validate the parameters in the edca tspec
120  * mandatory fields are derived from 11e Annex I (Table I.1)
121  *
122  * Return: Status
123  **/
124 static QDF_STATUS
lim_validate_tspec_edca(struct mac_context * mac_ctx,struct mac_tspec_ie * tspec,struct pe_session * session_entry)125 lim_validate_tspec_edca(struct mac_context *mac_ctx,
126 			struct mac_tspec_ie *tspec,
127 			struct pe_session *session_entry)
128 {
129 	uint32_t max_phy_rate, min_phy_rate;
130 	uint32_t phy_mode;
131 	QDF_STATUS retval = QDF_STATUS_SUCCESS;
132 
133 	lim_get_phy_mode(mac_ctx, &phy_mode, session_entry);
134 
135 	lim_get_available_bw(mac_ctx, &max_phy_rate, &min_phy_rate, phy_mode,
136 			     1 /* bandwidth mult factor */);
137 	/* mandatory fields are derived from 11e Annex I (Table I.1) */
138 	if ((tspec->nomMsduSz == 0) ||
139 	    (tspec->meanDataRate == 0) ||
140 	    (tspec->surplusBw == 0) ||
141 	    (tspec->minPhyRate == 0) ||
142 	    (tspec->minPhyRate > max_phy_rate)) {
143 		pe_warn("Invalid EDCA Tspec: NomMsdu: %d meanDataRate: %d surplusBw: %d min_phy_rate: %d",
144 			tspec->nomMsduSz, tspec->meanDataRate,
145 			tspec->surplusBw, tspec->minPhyRate);
146 		retval = QDF_STATUS_E_FAILURE;
147 	}
148 
149 	pe_debug("return status: %d", retval);
150 	return retval;
151 }
152 
153 /** -------------------------------------------------------------
154    \fn lim_validate_tspec
155    \brief validate the offered tspec
156    \param   struct mac_context *mac
157    \param         struct mac_tspec_ie *pTspec
158    \return QDF_STATUS - status
159    -------------------------------------------------------------*/
160 
161 static QDF_STATUS
lim_validate_tspec(struct mac_context * mac,struct mac_tspec_ie * pTspec,struct pe_session * pe_session)162 lim_validate_tspec(struct mac_context *mac,
163 		   struct mac_tspec_ie *pTspec, struct pe_session *pe_session)
164 {
165 	QDF_STATUS retval = QDF_STATUS_SUCCESS;
166 
167 	switch (pTspec->tsinfo.traffic.accessPolicy) {
168 	case SIR_MAC_ACCESSPOLICY_EDCA:
169 		retval = lim_validate_tspec_edca(mac, pTspec, pe_session);
170 		if (retval != QDF_STATUS_SUCCESS)
171 			pe_warn("EDCA tspec invalid");
172 		break;
173 
174 	case SIR_MAC_ACCESSPOLICY_HCCA:
175 	case SIR_MAC_ACCESSPOLICY_BOTH:
176 	/* TBD: should we support hybrid tspec as well?? for now, just fall through */
177 	default:
178 		pe_warn("AccessType: %d not supported",
179 			pTspec->tsinfo.traffic.accessPolicy);
180 		retval = QDF_STATUS_E_FAILURE;
181 		break;
182 	}
183 	return retval;
184 }
185 
186 /* ----------------------------------------------------------------------------- */
187 /* Admit Control Policy */
188 
189 /** -------------------------------------------------------------
190    \fn lim_compute_mean_bw_used
191    \brief determime the used/allocated bandwidth
192    \param   struct mac_context *mac
193    \param       uint32_t              *pBw
194    \param       uint32_t               phyMode
195    \param       tpLimTspecInfo    pTspecInfo
196    \return void
197    -------------------------------------------------------------*/
198 
199 static void
lim_compute_mean_bw_used(struct mac_context * mac,uint32_t * pBw,uint32_t phyMode,tpLimTspecInfo pTspecInfo,struct pe_session * pe_session)200 lim_compute_mean_bw_used(struct mac_context *mac,
201 			 uint32_t *pBw,
202 			 uint32_t phyMode,
203 			 tpLimTspecInfo pTspecInfo, struct pe_session *pe_session)
204 {
205 	uint32_t ctspec;
206 	*pBw = 0;
207 	for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) {
208 		if (pTspecInfo->inuse) {
209 			tpDphHashNode pSta =
210 				dph_get_hash_entry(mac, pTspecInfo->assocId,
211 						   &pe_session->dph.dphHashTable);
212 			if (!pSta) {
213 				/* maybe we should delete the tspec?? */
214 				pe_err("Tspec: %d assocId: %d dphNode not found",
215 					ctspec, pTspecInfo->assocId);
216 				continue;
217 			}
218 			*pBw += pTspecInfo->tspec.meanDataRate;
219 		}
220 	}
221 }
222 
223 /** -------------------------------------------------------------
224    \fn lim_get_available_bw
225    \brief based on the phy mode and the bw_factor, determine the total bandwidth that
226        can be supported
227    \param   struct mac_context *mac
228    \param       uint32_t              *pMaxBw
229    \param       uint32_t              *pMinBw
230    \param       uint32_t               phyMode
231    \param       uint32_t               bw_factor
232    \return void
233    -------------------------------------------------------------*/
234 
235 static void
lim_get_available_bw(struct mac_context * mac,uint32_t * pMaxBw,uint32_t * pMinBw,uint32_t phyMode,uint32_t bw_factor)236 lim_get_available_bw(struct mac_context *mac,
237 		     uint32_t *pMaxBw,
238 		     uint32_t *pMinBw, uint32_t phyMode, uint32_t bw_factor)
239 {
240 	switch (phyMode) {
241 	case WNI_CFG_PHY_MODE_11B:
242 		*pMaxBw = LIM_TOTAL_BW_11B;
243 		*pMinBw = LIM_MIN_BW_11B;
244 		break;
245 
246 	case WNI_CFG_PHY_MODE_11A:
247 		*pMaxBw = LIM_TOTAL_BW_11A;
248 		*pMinBw = LIM_MIN_BW_11A;
249 		break;
250 
251 	case WNI_CFG_PHY_MODE_11G:
252 	case WNI_CFG_PHY_MODE_NONE:
253 	default:
254 		*pMaxBw = LIM_TOTAL_BW_11G;
255 		*pMinBw = LIM_MIN_BW_11G;
256 		break;
257 	}
258 	*pMaxBw *= bw_factor;
259 }
260 
261 /**
262  * lim_admit_policy_oversubscription() - Admission control policy
263  * @mac_ctx:        Global MAC Context
264  * @tspec:          Pointer to the tspec
265  * @admit_policy:   Admission policy
266  * @tspec_info:     TSPEC information
267  * @session_entry:  Session Entry
268  *
269  * simple admission control policy based on oversubscription
270  * if the total bandwidth of all admitted tspec's exceeds (factor * phy-bw) then
271  * reject the tspec, else admit it. The phy-bw is the peak available bw in the
272  * current phy mode. The 'factor' is the configured oversubscription factor.
273  *
274  * Return: Status
275  **/
276 static QDF_STATUS
lim_admit_policy_oversubscription(struct mac_context * mac_ctx,struct mac_tspec_ie * tspec,tpLimAdmitPolicyInfo admit_policy,tpLimTspecInfo tspec_info,struct pe_session * session_entry)277 lim_admit_policy_oversubscription(struct mac_context *mac_ctx,
278 				  struct mac_tspec_ie *tspec,
279 				  tpLimAdmitPolicyInfo admit_policy,
280 				  tpLimTspecInfo tspec_info,
281 				  struct pe_session *session_entry)
282 {
283 	uint32_t totalbw, minbw, usedbw;
284 	uint32_t phy_mode;
285 
286 	/* determine total bandwidth used so far */
287 	lim_get_phy_mode(mac_ctx, &phy_mode, session_entry);
288 
289 	lim_compute_mean_bw_used(mac_ctx, &usedbw, phy_mode,
290 			tspec_info, session_entry);
291 
292 	/* determine how much bw is available based on the current phy mode */
293 	lim_get_available_bw(mac_ctx, &totalbw, &minbw, phy_mode,
294 			     admit_policy->bw_factor);
295 
296 	if (usedbw > totalbw)   /* this can't possibly happen */
297 		return QDF_STATUS_E_FAILURE;
298 
299 	if ((totalbw - usedbw) < tspec->meanDataRate) {
300 		pe_warn("Total BW: %d Used: %d Tspec request: %d not possible",
301 			totalbw, usedbw, tspec->meanDataRate);
302 		return QDF_STATUS_E_FAILURE;
303 	}
304 	return QDF_STATUS_SUCCESS;
305 }
306 
307 /** -------------------------------------------------------------
308    \fn lim_admit_policy
309    \brief determine the current admit control policy and apply it for the offered tspec
310    \param   struct mac_context *mac
311    \param         struct mac_tspec_ie   *pTspec
312    \return QDF_STATUS - status
313    -------------------------------------------------------------*/
314 
lim_admit_policy(struct mac_context * mac,struct mac_tspec_ie * pTspec,struct pe_session * pe_session)315 static QDF_STATUS lim_admit_policy(struct mac_context *mac,
316 				      struct mac_tspec_ie *pTspec,
317 				      struct pe_session *pe_session)
318 {
319 	QDF_STATUS retval = QDF_STATUS_E_FAILURE;
320 	tpLimAdmitPolicyInfo pAdmitPolicy = &mac->lim.admitPolicyInfo;
321 
322 	switch (pAdmitPolicy->type) {
323 	case WNI_CFG_ADMIT_POLICY_ADMIT_ALL:
324 		retval = QDF_STATUS_SUCCESS;
325 		break;
326 
327 	case WNI_CFG_ADMIT_POLICY_BW_FACTOR:
328 		retval = lim_admit_policy_oversubscription(mac, pTspec,
329 							   &mac->lim.
330 							   admitPolicyInfo,
331 							   &mac->lim.tspecInfo[0],
332 							   pe_session);
333 		if (retval != QDF_STATUS_SUCCESS)
334 			pe_err("rejected by BWFactor policy");
335 		break;
336 
337 	case WNI_CFG_ADMIT_POLICY_REJECT_ALL:
338 		retval = QDF_STATUS_E_FAILURE;
339 		break;
340 
341 	default:
342 		retval = QDF_STATUS_SUCCESS;
343 		pe_warn("Admit Policy: %d unknown, admitting all traffic",
344 			pAdmitPolicy->type);
345 		break;
346 	}
347 	return retval;
348 }
349 
350 /** -------------------------------------------------------------
351    \fn lim_tspec_delete
352    \brief delete the specified tspec
353    \param   struct mac_context *mac
354    \param     tpLimTspecInfo pInfo
355    \return void
356    -------------------------------------------------------------*/
357 
358 /* ----------------------------------------------------------------------------- */
359 /* delete the specified tspec */
lim_tspec_delete(struct mac_context * mac,tpLimTspecInfo pInfo)360 static void lim_tspec_delete(struct mac_context *mac, tpLimTspecInfo pInfo)
361 {
362 	if (!pInfo)
363 		return;
364 	/* pierre */
365 	pe_debug("tspec entry: %d delete tspec: %pK", pInfo->idx, pInfo);
366 	pInfo->inuse = 0;
367 
368 	return;
369 }
370 
371 /** -------------------------------------------------------------
372    \fn lim_tspec_find_by_sta_addr
373    \brief Send halMsg_AddTs to HAL
374    \param   struct mac_context *mac
375    \param   \param       uint8_t               *pAddr
376    \param       struct mac_tspec_ie    *pTspecIE
377    \param       tpLimTspecInfo    pTspecList
378    \param       tpLimTspecInfo   *ppInfo
379    \return QDF_STATUS - status
380    -------------------------------------------------------------*/
381 
382 /* find the specified tspec in the list */
383 static QDF_STATUS
lim_tspec_find_by_sta_addr(struct mac_context * mac,uint8_t * pAddr,struct mac_tspec_ie * pTspecIE,tpLimTspecInfo pTspecList,tpLimTspecInfo * ppInfo)384 lim_tspec_find_by_sta_addr(struct mac_context *mac,
385 			   uint8_t *pAddr,
386 			   struct mac_tspec_ie *pTspecIE,
387 			   tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo)
388 {
389 	int ctspec;
390 
391 	*ppInfo = NULL;
392 
393 	for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) {
394 		if ((pTspecList->inuse) &&
395 		    (!qdf_mem_cmp(pAddr, pTspecList->staAddr,
396 				  sizeof(pTspecList->staAddr))) &&
397 		    (!qdf_mem_cmp(pTspecIE, &pTspecList->tspec,
398 				  sizeof(*pTspecIE)))) {
399 			*ppInfo = pTspecList;
400 			return QDF_STATUS_SUCCESS;
401 		}
402 	}
403 	return QDF_STATUS_E_FAILURE;
404 }
405 
406 /** -------------------------------------------------------------
407    \fn lim_tspec_find_by_assoc_id
408    \brief find tspec with matching staid and Tspec
409    \param   struct mac_context *mac
410    \param       uint32_t               staid
411    \param       struct mac_tspec_ie    *pTspecIE
412    \param       tpLimTspecInfo    pTspecList
413    \param       tpLimTspecInfo   *ppInfo
414    \return QDF_STATUS - status
415    -------------------------------------------------------------*/
416 
417 QDF_STATUS
lim_tspec_find_by_assoc_id(struct mac_context * mac,uint16_t assocId,struct mac_tspec_ie * pTspecIE,tpLimTspecInfo pTspecList,tpLimTspecInfo * ppInfo)418 lim_tspec_find_by_assoc_id(struct mac_context *mac,
419 			   uint16_t assocId,
420 			   struct mac_tspec_ie *pTspecIE,
421 			   tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo)
422 {
423 	int ctspec;
424 
425 	*ppInfo = NULL;
426 
427 	pe_debug("Trying to find tspec entry for assocId: %d pTsInfo->traffic.direction: %d pTsInfo->traffic.tsid: %d",
428 		assocId, pTspecIE->tsinfo.traffic.direction,
429 		pTspecIE->tsinfo.traffic.tsid);
430 
431 	for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) {
432 		if ((pTspecList->inuse) &&
433 		    (assocId == pTspecList->assocId) &&
434 		    (!qdf_mem_cmp(pTspecIE, &pTspecList->tspec,
435 				  sizeof(*pTspecIE)))) {
436 			*ppInfo = pTspecList;
437 			return QDF_STATUS_SUCCESS;
438 		}
439 	}
440 	return QDF_STATUS_E_FAILURE;
441 }
442 
443 /** -------------------------------------------------------------
444    \fn lim_find_tspec
445    \brief finding a TSPEC entry with assocId, tsinfo.direction and tsinfo.tsid
446    \param    uint16_t               assocId
447    \param     struct mac_context *   mac
448    \param     struct mac_ts_info   *pTsInfo
449    \param         tpLimTspecInfo    pTspecList
450    \param         tpLimTspecInfo   *ppInfo
451    \return QDF_STATUS - status of the comparison
452    -------------------------------------------------------------*/
453 
454 static QDF_STATUS
lim_find_tspec(struct mac_context * mac,uint16_t assocId,struct mac_ts_info * pTsInfo,tpLimTspecInfo pTspecList,tpLimTspecInfo * ppInfo)455 lim_find_tspec(struct mac_context *mac,
456 	       uint16_t assocId,
457 	       struct mac_ts_info *pTsInfo,
458 	       tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo)
459 {
460 	int ctspec;
461 
462 	*ppInfo = NULL;
463 
464 	pe_debug("Trying to find tspec entry for assocId: %d pTsInfo->traffic.direction: %d pTsInfo->traffic.tsid: %d",
465 		assocId, pTsInfo->traffic.direction, pTsInfo->traffic.tsid);
466 
467 	for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) {
468 		if ((pTspecList->inuse)
469 		    && (assocId == pTspecList->assocId)
470 		    && (pTsInfo->traffic.direction ==
471 			pTspecList->tspec.tsinfo.traffic.direction)
472 		    && (pTsInfo->traffic.tsid ==
473 			pTspecList->tspec.tsinfo.traffic.tsid)) {
474 			*ppInfo = pTspecList;
475 			return QDF_STATUS_SUCCESS;
476 		}
477 	}
478 	return QDF_STATUS_E_FAILURE;
479 }
480 
481 /** -------------------------------------------------------------
482    \fn lim_tspec_add
483    \brief add or update the specified tspec to the tspec list
484    \param struct mac_context *   mac
485    \param uint8_t               *pAddr
486    \param uint16_t               assocId
487    \param struct mac_tspec_ie   *pTspec
488    \param uint32_t               interval
489    \param tpLimTspecInfo   *ppInfo
490 
491    \return QDF_STATUS - status of the comparison
492    -------------------------------------------------------------*/
493 
lim_tspec_add(struct mac_context * mac,uint8_t * pAddr,uint16_t assocId,struct mac_tspec_ie * pTspec,uint32_t interval,tpLimTspecInfo * ppInfo)494 QDF_STATUS lim_tspec_add(struct mac_context *mac,
495 			    uint8_t *pAddr,
496 			    uint16_t assocId,
497 			    struct mac_tspec_ie *pTspec,
498 			    uint32_t interval, tpLimTspecInfo *ppInfo)
499 {
500 	tpLimTspecInfo pTspecList = &mac->lim.tspecInfo[0];
501 	*ppInfo = NULL;
502 
503 	/* validate the assocId */
504 	if (assocId >= mac->lim.maxStation) {
505 		pe_err("Invalid assocId 0x%x", assocId);
506 		return QDF_STATUS_E_FAILURE;
507 	}
508 	/* decide whether to add/update */
509 	{
510 		*ppInfo = NULL;
511 
512 		if (QDF_STATUS_SUCCESS ==
513 		    lim_find_tspec(mac, assocId, &pTspec->tsinfo, pTspecList,
514 				   ppInfo)) {
515 			/* update this entry. */
516 			pe_debug("updating TSPEC table entry: %d",
517 				(*ppInfo)->idx);
518 		} else {
519 			/* We didn't find one to update. So find a free slot in the
520 			 * LIM TSPEC list and add this new entry
521 			 */
522 			uint8_t ctspec = 0;
523 
524 			for (ctspec = 0, pTspecList = &mac->lim.tspecInfo[0];
525 			     ctspec < LIM_NUM_TSPEC_MAX;
526 			     ctspec++, pTspecList++) {
527 				if (!pTspecList->inuse) {
528 					pe_debug("Found free slot in TSPEC list. Add to TSPEC table entry: %d",
529 						ctspec);
530 					break;
531 				}
532 			}
533 
534 			if (ctspec >= LIM_NUM_TSPEC_MAX)
535 				return QDF_STATUS_E_FAILURE;
536 
537 			/* Record the new index entry */
538 			pTspecList->idx = ctspec;
539 		}
540 	}
541 
542 	/* update the tspec info */
543 	pTspecList->tspec = *pTspec;
544 	pTspecList->assocId = assocId;
545 	qdf_mem_copy(pTspecList->staAddr, pAddr, sizeof(pTspecList->staAddr));
546 
547 	/* for edca tspec's, we are all done */
548 	if (pTspec->tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) {
549 		pTspecList->inuse = 1;
550 		*ppInfo = pTspecList;
551 		pe_debug("added entry for EDCA AccessPolicy");
552 		return QDF_STATUS_SUCCESS;
553 	}
554 
555 	/*
556 	 * for hcca tspec's, must set the parameterized bit in the queues
557 	 * the 'ts' bit in the queue data structure indicates that the queue is
558 	 * parameterized (hcca). When the schedule is written this bit is used
559 	 * in the tsid field (bit 3) and the other three bits (0-2) are simply
560 	 * filled in as the user priority (or qid). This applies only to uplink
561 	 * polls where the qos control field must contain the tsid specified in the
562 	 * tspec.
563 	 */
564 	pTspecList->inuse = 1;
565 	*ppInfo = pTspecList;
566 	pe_debug("added entry for HCCA AccessPolicy");
567 	return QDF_STATUS_SUCCESS;
568 }
569 
570 /** -------------------------------------------------------------
571    \fn lim_validate_access_policy
572    \brief Validates Access policy
573    \param   struct mac_context *mac
574    \param       uint8_t              accessPolicy
575    \param       uint16_t             assocId
576    \return QDF_STATUS - status
577    -------------------------------------------------------------*/
578 
579 static QDF_STATUS
lim_validate_access_policy(struct mac_context * mac,uint8_t accessPolicy,uint16_t assocId,struct pe_session * pe_session)580 lim_validate_access_policy(struct mac_context *mac,
581 			   uint8_t accessPolicy,
582 			   uint16_t assocId, struct pe_session *pe_session)
583 {
584 	QDF_STATUS retval = QDF_STATUS_E_FAILURE;
585 	tpDphHashNode pSta =
586 		dph_get_hash_entry(mac, assocId, &pe_session->dph.dphHashTable);
587 
588 	if ((!pSta) || (!pSta->valid)) {
589 		pe_err("invalid station address passed");
590 		return QDF_STATUS_E_FAILURE;
591 	}
592 
593 	switch (accessPolicy) {
594 	case SIR_MAC_ACCESSPOLICY_EDCA:
595 		if (pSta->wmeEnabled || pSta->lleEnabled)
596 			retval = QDF_STATUS_SUCCESS;
597 		break;
598 
599 	case SIR_MAC_ACCESSPOLICY_HCCA:
600 	case SIR_MAC_ACCESSPOLICY_BOTH:
601 	default:
602 		pe_err("Invalid accessPolicy: %d",
603 			       accessPolicy);
604 		break;
605 	}
606 
607 	if (retval != QDF_STATUS_SUCCESS)
608 		pe_warn("accPol: %d lle: %d wme: %d wsm: %d sta mac "
609 			QDF_MAC_ADDR_FMT, accessPolicy, pSta->lleEnabled,
610 			pSta->wmeEnabled, pSta->wsmEnabled,
611 			QDF_MAC_ADDR_REF(pSta->staAddr));
612 
613 	return retval;
614 }
615 
616 /**
617  * lim_admit_control_add_ts() -        Check if STA can be admitted
618  * @mac:               Global MAC context
619  * @pAddr:              Address
620  * @pAddts:             ADD TS
621  * @pQos:               QOS fields
622  * @assocId:            Association ID
623  * @alloc:              Allocate bandwidth for this tspec
624  * @pSch:               Schedule IE
625  * @pTspecIdx:          TSPEC index
626  * @pe_session:      PE Session Entry
627  *
628  * Determine if STA with the specified TSPEC can be admitted. If it can,
629  * a schedule element is provided
630  *
631  * Return: status
632  **/
lim_admit_control_add_ts(struct mac_context * mac,uint8_t * pAddr,tSirAddtsReqInfo * pAddts,tSirMacQosCapabilityStaIE * pQos,uint16_t assocId,uint8_t alloc,tSirMacScheduleIE * pSch,uint8_t * pTspecIdx,struct pe_session * pe_session)633 QDF_STATUS lim_admit_control_add_ts(struct mac_context *mac, uint8_t *pAddr,
634 		tSirAddtsReqInfo *pAddts, tSirMacQosCapabilityStaIE *pQos,
635 		uint16_t assocId, uint8_t alloc, tSirMacScheduleIE *pSch,
636 		uint8_t *pTspecIdx, struct pe_session *pe_session)
637 {
638 	tpLimTspecInfo pTspecInfo;
639 	QDF_STATUS retval;
640 	uint32_t svcInterval;
641 	(void)pQos;
642 
643 	/* TBD: modify tspec as needed */
644 	/* EDCA: need to fill in the medium time and the minimum phy rate */
645 	/* to be consistent with the desired traffic parameters. */
646 
647 	pe_debug("tsid: %d directn: %d start: %d intvl: %d accPolicy: %d up: %d",
648 		pAddts->tspec.tsinfo.traffic.tsid,
649 		pAddts->tspec.tsinfo.traffic.direction,
650 		pAddts->tspec.svcStartTime, pAddts->tspec.minSvcInterval,
651 		pAddts->tspec.tsinfo.traffic.accessPolicy,
652 		pAddts->tspec.tsinfo.traffic.userPrio);
653 
654 	/* check for duplicate tspec */
655 	retval = (alloc)
656 		 ? lim_tspec_find_by_assoc_id(mac, assocId, &pAddts->tspec,
657 					      &mac->lim.tspecInfo[0], &pTspecInfo)
658 		 : lim_tspec_find_by_sta_addr(mac, pAddr, &pAddts->tspec,
659 					      &mac->lim.tspecInfo[0], &pTspecInfo);
660 
661 	if (retval == QDF_STATUS_SUCCESS) {
662 		pe_err("duplicate tspec index: %d", pTspecInfo->idx);
663 		return QDF_STATUS_E_FAILURE;
664 	}
665 	/* check that the tspec's are well formed and acceptable */
666 	if (lim_validate_tspec(mac, &pAddts->tspec, pe_session) !=
667 	    QDF_STATUS_SUCCESS) {
668 		pe_warn("tspec validation failed");
669 		return QDF_STATUS_E_FAILURE;
670 	}
671 	/* determine a service interval for the tspec */
672 	if (lim_calculate_svc_int(mac, &pAddts->tspec, &svcInterval) !=
673 	    QDF_STATUS_SUCCESS) {
674 		pe_warn("SvcInt calculate failed");
675 		return QDF_STATUS_E_FAILURE;
676 	}
677 	/* determine if the tspec can be admitted or not based on current policy */
678 	if (lim_admit_policy(mac, &pAddts->tspec, pe_session) != QDF_STATUS_SUCCESS) {
679 		pe_warn("tspec rejected by admit control policy");
680 		return QDF_STATUS_E_FAILURE;
681 	}
682 	/* fill in a schedule if requested */
683 	if (pSch) {
684 		qdf_mem_zero((uint8_t *) pSch, sizeof(*pSch));
685 		pSch->svcStartTime = pAddts->tspec.svcStartTime;
686 		pSch->svcInterval = svcInterval;
687 		pSch->maxSvcDuration = (uint16_t) pSch->svcInterval;    /* use SP = SI */
688 		pSch->specInterval = 0x1000;    /* fixed for now: TBD */
689 
690 		pSch->info.direction = pAddts->tspec.tsinfo.traffic.direction;
691 		pSch->info.tsid = pAddts->tspec.tsinfo.traffic.tsid;
692 		pSch->info.aggregation = 0;     /* no support for aggregation for now: TBD */
693 	}
694 	/* if no allocation is requested, done */
695 	if (!alloc)
696 		return QDF_STATUS_SUCCESS;
697 
698 	/* check that we are in the proper mode to deal with the tspec type */
699 	if (lim_validate_access_policy
700 		    (mac, (uint8_t) pAddts->tspec.tsinfo.traffic.accessPolicy, assocId,
701 		    pe_session) != QDF_STATUS_SUCCESS) {
702 		pe_warn("AccessPolicy: %d is not valid in current mode",
703 			pAddts->tspec.tsinfo.traffic.accessPolicy);
704 		return QDF_STATUS_E_FAILURE;
705 	}
706 	/* add tspec to list */
707 	if (lim_tspec_add
708 		    (mac, pAddr, assocId, &pAddts->tspec, svcInterval, &pTspecInfo)
709 	    != QDF_STATUS_SUCCESS) {
710 		pe_err("no space in tspec list");
711 		return QDF_STATUS_E_FAILURE;
712 	}
713 	/* passing lim tspec table index to the caller */
714 	*pTspecIdx = pTspecInfo->idx;
715 
716 	return QDF_STATUS_SUCCESS;
717 }
718 
719 /** -------------------------------------------------------------
720    \fn lim_admit_control_delete_ts
721    \brief Delete the specified Tspec for the specified STA
722    \param   struct mac_context *mac
723    \param       uint16_t               assocId
724    \param       struct mac_ts_info    *pTsInfo
725    \param       uint8_t               *pTsStatus
726    \param       uint8_t             *ptspecIdx
727    \return QDF_STATUS - status
728    -------------------------------------------------------------*/
729 
730 QDF_STATUS
lim_admit_control_delete_ts(struct mac_context * mac,uint16_t assocId,struct mac_ts_info * pTsInfo,uint8_t * pTsStatus,uint8_t * ptspecIdx)731 lim_admit_control_delete_ts(struct mac_context *mac,
732 			    uint16_t assocId,
733 			    struct mac_ts_info *pTsInfo,
734 			    uint8_t *pTsStatus, uint8_t *ptspecIdx)
735 {
736 	tpLimTspecInfo pTspecInfo = NULL;
737 
738 	if (pTsStatus)
739 		*pTsStatus = 0;
740 
741 	if (lim_find_tspec
742 		    (mac, assocId, pTsInfo, &mac->lim.tspecInfo[0],
743 		    &pTspecInfo) == QDF_STATUS_SUCCESS) {
744 		if (pTspecInfo) {
745 			pe_debug("Tspec entry: %d found", pTspecInfo->idx);
746 
747 			*ptspecIdx = pTspecInfo->idx;
748 			lim_tspec_delete(mac, pTspecInfo);
749 			return QDF_STATUS_SUCCESS;
750 		}
751 	}
752 	return QDF_STATUS_E_FAILURE;
753 }
754 
755 /** -------------------------------------------------------------
756    \fn lim_admit_control_delete_sta
757    \brief Delete all TSPEC for the specified STA
758    \param   struct mac_context *mac
759    \param     uint16_t assocId
760    \return QDF_STATUS - status
761    -------------------------------------------------------------*/
762 
lim_admit_control_delete_sta(struct mac_context * mac,uint16_t assocId)763 QDF_STATUS lim_admit_control_delete_sta(struct mac_context *mac, uint16_t assocId)
764 {
765 	tpLimTspecInfo pTspecInfo = &mac->lim.tspecInfo[0];
766 	int ctspec;
767 
768 	for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) {
769 		if (assocId == pTspecInfo->assocId) {
770 			lim_tspec_delete(mac, pTspecInfo);
771 			pe_debug("Deleting TSPEC: %d for assocId: %d", ctspec,
772 				assocId);
773 		}
774 	}
775 	pe_debug("assocId: %d done", assocId);
776 
777 	return QDF_STATUS_SUCCESS;
778 }
779 
780 /** -------------------------------------------------------------
781    \fn lim_admit_control_init
782    \brief init tspec table
783    \param   struct mac_context *mac
784    \return QDF_STATUS - status
785    -------------------------------------------------------------*/
lim_admit_control_init(struct mac_context * mac)786 QDF_STATUS lim_admit_control_init(struct mac_context *mac)
787 {
788 	qdf_mem_zero(mac->lim.tspecInfo,
789 		    LIM_NUM_TSPEC_MAX * sizeof(tLimTspecInfo));
790 	return QDF_STATUS_SUCCESS;
791 }
792 
793 /** -------------------------------------------------------------
794    \fn lim_send_hal_msg_add_ts
795    \brief Send halMsg_AddTs to HAL
796    \param   struct mac_context *mac
797    \param     uint8_t         tspecIdx
798    \param       struct mac_tspec_ie tspecIE
799    \param       tSirTclasInfo   *tclasInfo
800    \param       uint8_t           tclasProc
801    \param       uint16_t          tsm_interval
802    \return QDF_STATUS - status
803    -------------------------------------------------------------*/
804 #ifdef FEATURE_WLAN_ESE
805 QDF_STATUS
lim_send_hal_msg_add_ts(struct mac_context * mac,uint8_t tspecIdx,struct mac_tspec_ie tspecIE,uint8_t sessionId,uint16_t tsm_interval)806 lim_send_hal_msg_add_ts(struct mac_context *mac,
807 			uint8_t tspecIdx,
808 			struct mac_tspec_ie tspecIE,
809 			uint8_t sessionId, uint16_t tsm_interval)
810 #else
811 QDF_STATUS
812 lim_send_hal_msg_add_ts(struct mac_context *mac,
813 			uint8_t tspecIdx,
814 			struct mac_tspec_ie tspecIE,
815 			uint8_t sessionId)
816 #endif
817 {
818 	struct scheduler_msg msg = {0};
819 	struct add_ts_param *pAddTsParam;
820 
821 	struct pe_session *pe_session = pe_find_session_by_session_id(mac, sessionId);
822 
823 	if (!pe_session) {
824 		pe_err("Unable to get Session for session Id: %d",
825 			sessionId);
826 		return QDF_STATUS_E_FAILURE;
827 	}
828 
829 	pAddTsParam = qdf_mem_malloc(sizeof(*pAddTsParam));
830 	if (!pAddTsParam)
831 		return QDF_STATUS_E_NOMEM;
832 
833 	pAddTsParam->tspec_idx = tspecIdx;
834 	qdf_mem_copy(&pAddTsParam->tspec, &tspecIE,
835 		     sizeof(struct mac_tspec_ie));
836 	pAddTsParam->pe_session_id = sessionId;
837 	pAddTsParam->vdev_id = pe_session->smeSessionId;
838 
839 #ifdef FEATURE_WLAN_ESE
840 	pAddTsParam->tsm_interval = tsm_interval;
841 #endif
842 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
843 	if (mac->mlme_cfg->lfr.lfr3_roaming_offload &&
844 	    pe_session->is11Rconnection)
845 		pAddTsParam->set_ric_params = true;
846 #endif
847 
848 	msg.type = WMA_ADD_TS_REQ;
849 	msg.bodyptr = pAddTsParam;
850 	msg.bodyval = 0;
851 
852 	/* We need to defer any incoming messages until we get a
853 	 * WMA_ADD_TS_RSP from HAL.
854 	 */
855 	SET_LIM_PROCESS_DEFD_MESGS(mac, false);
856 	MTRACE(mac_trace_msg_tx(mac, sessionId, msg.type));
857 
858 	if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) {
859 		pe_warn("wma_post_ctrl_msg() failed");
860 		SET_LIM_PROCESS_DEFD_MESGS(mac, true);
861 		qdf_mem_free(pAddTsParam);
862 		return QDF_STATUS_E_FAILURE;
863 	}
864 	return QDF_STATUS_SUCCESS;
865 }
866 
867 /** -------------------------------------------------------------
868    \fn lim_send_hal_msg_del_ts
869    \brief Send halMsg_AddTs to HAL
870    \param   struct mac_context *mac
871    \param     uint8_t         tspecIdx
872    \param     tSirAddtsReqInfo addts
873    \return QDF_STATUS - status
874    -------------------------------------------------------------*/
875 
876 QDF_STATUS
lim_send_hal_msg_del_ts(struct mac_context * mac,uint8_t tspecIdx,struct delts_req_info delts,uint8_t sessionId,uint8_t * bssId)877 lim_send_hal_msg_del_ts(struct mac_context *mac,
878 			uint8_t tspecIdx,
879 			struct delts_req_info delts,
880 			uint8_t sessionId, uint8_t *bssId)
881 {
882 	struct scheduler_msg msg = {0};
883 	struct del_ts_params *pDelTsParam;
884 	struct pe_session *pe_session = NULL;
885 
886 	pDelTsParam = qdf_mem_malloc(sizeof(*pDelTsParam));
887 	if (!pDelTsParam)
888 		return QDF_STATUS_E_NOMEM;
889 
890 	msg.type = WMA_DEL_TS_REQ;
891 	msg.bodyptr = pDelTsParam;
892 	msg.bodyval = 0;
893 
894 	/* filling message parameters. */
895 	pDelTsParam->tspecIdx = tspecIdx;
896 	qdf_mem_copy(&pDelTsParam->bssId, bssId, sizeof(tSirMacAddr));
897 
898 	pe_session = pe_find_session_by_session_id(mac, sessionId);
899 	if (!pe_session) {
900 		pe_err("Session does Not exist with given sessionId: %d",
901 			       sessionId);
902 		goto err;
903 	}
904 	pDelTsParam->sessionId = pe_session->smeSessionId;
905 	pDelTsParam->userPrio = delts.wmeTspecPresent ?
906 			delts.tspec.tsinfo.traffic.userPrio :
907 			delts.tsinfo.traffic.userPrio;
908 
909 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
910 	if (mac->mlme_cfg->lfr.lfr3_roaming_offload &&
911 	    pe_session->is11Rconnection) {
912 		qdf_mem_copy(&pDelTsParam->delTsInfo, &delts,
913 			     sizeof(struct delts_req_info));
914 		pDelTsParam->setRICparams = 1;
915 	}
916 #endif
917 	MTRACE(mac_trace_msg_tx(mac, sessionId, msg.type));
918 
919 	if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) {
920 		pe_warn("wma_post_ctrl_msg() failed");
921 		goto err;
922 	}
923 	return QDF_STATUS_SUCCESS;
924 
925 err:
926 	qdf_mem_free(pDelTsParam);
927 	return QDF_STATUS_E_FAILURE;
928 }
929 
930 /** -------------------------------------------------------------
931    \fn     lim_process_hal_add_ts_rsp
932    \brief  This function process the WMA_ADD_TS_RSP from HAL.
933  \       If response is successful, then send back SME_ADDTS_RSP.
934  \       Otherwise, send DELTS action frame to peer and then
935  \       then send back SME_ADDTS_RSP.
936  \
937    \param  struct mac_context * mac
938    \param  struct scheduler_msg *limMsg
939    -------------------------------------------------------------*/
lim_process_hal_add_ts_rsp(struct mac_context * mac,struct scheduler_msg * limMsg)940 void lim_process_hal_add_ts_rsp(struct mac_context *mac,
941 				struct scheduler_msg *limMsg)
942 {
943 	struct add_ts_param *pAddTsRspMsg = NULL;
944 	tpDphHashNode pSta = NULL;
945 	uint16_t assocId = 0;
946 	tSirMacAddr peerMacAddr;
947 	uint8_t rspReqd = 1;
948 	struct pe_session *pe_session = NULL;
949 
950 	/* Need to process all the deferred messages enqueued
951 	 * since sending the WMA_ADD_TS_REQ.
952 	 */
953 	SET_LIM_PROCESS_DEFD_MESGS(mac, true);
954 
955 	if (!limMsg->bodyptr) {
956 		pe_err("Received WMA_ADD_TS_RSP with NULL");
957 		goto end;
958 	}
959 
960 	pAddTsRspMsg = limMsg->bodyptr;
961 
962 	/* 090803: Use pe_find_session_by_session_id() to obtain the PE session context */
963 	/* from the sessionId in the Rsp Msg from HAL */
964 	pe_session = pe_find_session_by_session_id(mac,
965 						   pAddTsRspMsg->pe_session_id);
966 
967 	if (!pe_session) {
968 		pe_err("Session does Not exist with given sessionId: %d",
969 			       pAddTsRspMsg->pe_session_id);
970 		lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED,
971 				       pe_session, pAddTsRspMsg->tspec,
972 				       mac->lim.gLimAddtsReq.sessionId);
973 		goto end;
974 	}
975 
976 	if (pAddTsRspMsg->status == QDF_STATUS_SUCCESS) {
977 		pe_debug("Received successful ADDTS response from HAL");
978 		/* Use the smesessionId and smetransactionId from the PE session context */
979 		lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_SUCCESS,
980 				       pe_session, pAddTsRspMsg->tspec,
981 				       pe_session->smeSessionId);
982 		goto end;
983 	} else {
984 		pe_debug("Received failure ADDTS response from HAL");
985 		/* Send DELTS action frame to AP */
986 		/* 090803: Get peer MAC addr from session */
987 		sir_copy_mac_addr(peerMacAddr, pe_session->bssId);
988 
989 		/* 090803: Add the SME Session ID */
990 		lim_send_delts_req_action_frame(mac, peerMacAddr, rspReqd,
991 						&pAddTsRspMsg->tspec.tsinfo,
992 						&pAddTsRspMsg->tspec, pe_session);
993 
994 		/* Delete TSPEC */
995 		/* 090803: Pull the hash table from the session */
996 		pSta = dph_lookup_hash_entry(mac, peerMacAddr, &assocId,
997 					     &pe_session->dph.dphHashTable);
998 		if (pSta)
999 			lim_admit_control_delete_ts(mac, assocId,
1000 						    &pAddTsRspMsg->tspec.tsinfo,
1001 						    NULL,
1002 						    (uint8_t *) &pAddTsRspMsg->
1003 						    tspec_idx);
1004 
1005 		/* Send SME_ADDTS_RSP */
1006 		/* 090803: Use the smesessionId and smetransactionId from the PE session context */
1007 		lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED,
1008 				       pe_session, pAddTsRspMsg->tspec,
1009 				       pe_session->smeSessionId);
1010 		goto end;
1011 	}
1012 
1013 end:
1014 	if (pAddTsRspMsg)
1015 		qdf_mem_free(pAddTsRspMsg);
1016 	return;
1017 }
1018