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