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