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