1 /* 2 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: HDD WMM 21 * 22 * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) 23 * houses all the logic for WMM in HDD. 24 * 25 * On the control path, it has the logic to setup QoS, modify QoS and delete 26 * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an 27 * explicit application invoked and an internal HDD invoked. The implicit QoS 28 * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but 29 * which DO mark their traffic for priortization. It also has logic to start, 30 * update and stop the U-APSD trigger frame generation. It also has logic to 31 * read WMM related config parameters from the registry. 32 * 33 * On the data path, it has the logic to figure out the WMM AC of an egress 34 * packet and when to signal TL to serve a particular AC queue. It also has the 35 * logic to retrieve a packet based on WMM priority in response to a fetch from 36 * TL. 37 * 38 * The remaining functions are utility functions for information hiding. 39 */ 40 41 /* Include files */ 42 #include <linux/netdevice.h> 43 #include <linux/skbuff.h> 44 #include <linux/etherdevice.h> 45 #include <linux/if_vlan.h> 46 #include <linux/ip.h> 47 #include <linux/semaphore.h> 48 #include <linux/ipv6.h> 49 #include <wlan_hdd_tx_rx.h> 50 #include <wlan_hdd_wmm.h> 51 #include <wlan_hdd_ether.h> 52 #include <wlan_hdd_hostapd.h> 53 #include <wlan_hdd_softap_tx_rx.h> 54 #include <cds_sched.h> 55 #include "sme_api.h" 56 57 #define WLAN_HDD_MAX_DSCP 0x3f 58 59 #define HDD_WMM_UP_TO_AC_MAP_SIZE 8 60 61 const uint8_t hdd_wmm_up_to_ac_map[] = { 62 SME_AC_BE, 63 SME_AC_BK, 64 SME_AC_BK, 65 SME_AC_BE, 66 SME_AC_VI, 67 SME_AC_VI, 68 SME_AC_VO, 69 SME_AC_VO 70 }; 71 72 /** 73 * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to 74 * operate on different traffic. 75 */ 76 #ifdef QCA_LL_TX_FLOW_CONTROL_V2 77 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter) 78 { 79 /* Enable HI_PRIO queue */ 80 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO); 81 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI); 82 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE); 83 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK); 84 netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); 85 86 } 87 #else 88 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter) 89 { 90 } 91 #endif 92 93 /* Linux based UP -> AC Mapping */ 94 const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = { 95 HDD_LINUX_AC_BE, 96 HDD_LINUX_AC_BK, 97 HDD_LINUX_AC_BK, 98 HDD_LINUX_AC_BE, 99 HDD_LINUX_AC_VI, 100 HDD_LINUX_AC_VI, 101 HDD_LINUX_AC_VO, 102 HDD_LINUX_AC_VO 103 }; 104 105 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 106 /** 107 * hdd_wmm_enable_tl_uapsd() - function which decides whether and 108 * how to update UAPSD parameters in TL 109 * 110 * @pQosContext: [in] the pointer the QoS instance control block 111 * 112 * Return: None 113 */ 114 static void hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext) 115 { 116 struct hdd_adapter *adapter = pQosContext->adapter; 117 sme_ac_enum_type acType = pQosContext->acType; 118 struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 119 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 120 QDF_STATUS status; 121 uint32_t service_interval; 122 uint32_t suspension_interval; 123 enum sme_qos_wmm_dir_type direction; 124 bool psb; 125 126 /* The TSPEC must be valid */ 127 if (pAc->wmmAcTspecValid == false) { 128 hdd_err("Invoked with invalid TSPEC"); 129 return; 130 } 131 /* determine the service interval */ 132 if (pAc->wmmAcTspecInfo.min_service_interval) { 133 service_interval = pAc->wmmAcTspecInfo.min_service_interval; 134 } else if (pAc->wmmAcTspecInfo.max_service_interval) { 135 service_interval = pAc->wmmAcTspecInfo.max_service_interval; 136 } else { 137 /* no service interval is present in the TSPEC */ 138 /* this is OK, there just won't be U-APSD */ 139 hdd_debug("No service interval supplied"); 140 service_interval = 0; 141 } 142 143 /* determine the suspension interval & direction */ 144 suspension_interval = pAc->wmmAcTspecInfo.suspension_interval; 145 direction = pAc->wmmAcTspecInfo.ts_info.direction; 146 psb = pAc->wmmAcTspecInfo.ts_info.psb; 147 148 /* if we have previously enabled U-APSD, have any params changed? */ 149 if ((pAc->wmmAcUapsdInfoValid) && 150 (pAc->wmmAcUapsdServiceInterval == service_interval) && 151 (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) && 152 (pAc->wmmAcUapsdDirection == direction) && 153 (pAc->wmmAcIsUapsdEnabled == psb)) { 154 hdd_debug("No change in U-APSD parameters"); 155 return; 156 } 157 /* everything is in place to notify TL */ 158 status = 159 sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR(adapter))-> 160 conn_info.staId[0], acType, 161 pAc->wmmAcTspecInfo.ts_info.tid, 162 pAc->wmmAcTspecInfo.ts_info.up, 163 service_interval, suspension_interval, 164 direction, psb, adapter->session_id, 165 hdd_ctx->config->DelayedTriggerFrmInt); 166 167 if (!QDF_IS_STATUS_SUCCESS(status)) { 168 hdd_err("Failed to enable U-APSD for AC=%d", acType); 169 return; 170 } 171 /* stash away the parameters that were used */ 172 pAc->wmmAcUapsdInfoValid = true; 173 pAc->wmmAcUapsdServiceInterval = service_interval; 174 pAc->wmmAcUapsdSuspensionInterval = suspension_interval; 175 pAc->wmmAcUapsdDirection = direction; 176 pAc->wmmAcIsUapsdEnabled = psb; 177 178 hdd_debug("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d", 179 service_interval, suspension_interval, direction, acType); 180 181 } 182 183 /** 184 * hdd_wmm_disable_tl_uapsd() - function which decides whether 185 * to disable UAPSD parameters in TL 186 * 187 * @pQosContext: [in] the pointer the QoS instance control block 188 * 189 * Return: None 190 */ 191 static void hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext) 192 { 193 struct hdd_adapter *adapter = pQosContext->adapter; 194 sme_ac_enum_type acType = pQosContext->acType; 195 struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 196 QDF_STATUS status; 197 198 /* have we previously enabled UAPSD? */ 199 if (pAc->wmmAcUapsdInfoValid == true) { 200 status = 201 sme_disable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR 202 (adapter))->conn_info.staId[0], 203 acType, adapter->session_id); 204 205 if (!QDF_IS_STATUS_SUCCESS(status)) { 206 hdd_err("Failed to disable U-APSD for AC=%d", acType); 207 } else { 208 /* TL no longer has valid UAPSD info */ 209 pAc->wmmAcUapsdInfoValid = false; 210 hdd_debug("Disabled UAPSD in TL for AC=%d", acType); 211 } 212 } 213 } 214 215 #endif 216 217 /** 218 * hdd_wmm_free_context() - function which frees a QoS context 219 * 220 * @pQosContext: [in] the pointer the QoS instance control block 221 * 222 * Return: None 223 */ 224 static void hdd_wmm_free_context(struct hdd_wmm_qos_context *pQosContext) 225 { 226 struct hdd_adapter *adapter; 227 228 hdd_debug("Entered, context %pK", pQosContext); 229 230 if (unlikely((NULL == pQosContext) || 231 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { 232 /* must have been freed in another thread */ 233 return; 234 } 235 /* get pointer to the adapter context */ 236 adapter = pQosContext->adapter; 237 238 /* take the wmmLock since we're manipulating the context list */ 239 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 240 241 /* make sure nobody thinks this is a valid context */ 242 pQosContext->magic = 0; 243 244 /* unlink the context */ 245 list_del(&pQosContext->node); 246 247 /* done manipulating the list */ 248 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 249 250 /* reclaim memory */ 251 qdf_mem_free(pQosContext); 252 253 } 254 255 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 256 /** 257 * hdd_wmm_notify_app() - function which notifies an application 258 * of changes in state of it flow 259 * 260 * @pQosContext: [in] the pointer the QoS instance control block 261 * 262 * Return: None 263 */ 264 #define MAX_NOTIFY_LEN 50 265 static void hdd_wmm_notify_app(struct hdd_wmm_qos_context *pQosContext) 266 { 267 struct hdd_adapter *adapter; 268 union iwreq_data wrqu; 269 char buf[MAX_NOTIFY_LEN + 1]; 270 271 hdd_debug("Entered, context %pK", pQosContext); 272 273 if (unlikely((NULL == pQosContext) || 274 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { 275 hdd_err("Invalid QoS Context"); 276 return; 277 } 278 279 /* create the event */ 280 memset(&wrqu, 0, sizeof(wrqu)); 281 memset(buf, 0, sizeof(buf)); 282 283 snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]", 284 (unsigned int)pQosContext->handle, 285 (unsigned int)pQosContext->lastStatus); 286 287 wrqu.data.pointer = buf; 288 wrqu.data.length = strlen(buf); 289 290 /* get pointer to the adapter */ 291 adapter = pQosContext->adapter; 292 293 /* send the event */ 294 hdd_debug("Sending [%s]", buf); 295 wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); 296 } 297 298 #ifdef FEATURE_WLAN_ESE 299 /** 300 * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function 301 * 302 * @user_data: opaque user data registered with the timer. In the 303 * case of this timer, the associated wmm QoS context is registered. 304 * 305 * This timer handler function is called for every inactivity interval 306 * per AC. This function gets the current transmitted packets on the 307 * given AC, and checks if there was any TX activity from the previous 308 * interval. If there was no traffic then it would delete the TS that 309 * was negotiated on that AC. 310 * 311 * Return: None 312 */ 313 static void hdd_wmm_inactivity_timer_cb(void *user_data) 314 { 315 struct hdd_wmm_qos_context *pQosContext = user_data; 316 struct hdd_adapter *adapter; 317 struct hdd_wmm_ac_status *pAc; 318 hdd_wlan_wmm_status_e status; 319 QDF_STATUS qdf_status; 320 uint32_t currentTrafficCnt = 0; 321 sme_ac_enum_type acType; 322 323 if (!pQosContext) { 324 hdd_err("invalid user data"); 325 return; 326 } 327 acType = pQosContext->acType; 328 329 adapter = pQosContext->adapter; 330 if ((NULL == adapter) || 331 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { 332 hdd_err("invalid adapter: %pK", adapter); 333 return; 334 } 335 336 pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 337 338 /* Get the Tx stats for this AC. */ 339 currentTrafficCnt = 340 adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext-> 341 acType]; 342 343 hdd_warn("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d", 344 acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt); 345 if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) { 346 /* there is no traffic activity, delete the TSPEC for this AC */ 347 status = hdd_wmm_delts(adapter, pQosContext->handle); 348 hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!", 349 acType, status); 350 } else { 351 pAc->wmmPrevTrafficCnt = currentTrafficCnt; 352 if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) { 353 /* Restart the timer */ 354 qdf_status = 355 qdf_mc_timer_start(&pAc->wmmInactivityTimer, 356 pAc->wmmInactivityTime); 357 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 358 hdd_err("Restarting inactivity timer failed on AC %d", 359 acType); 360 } 361 } else { 362 QDF_ASSERT(qdf_mc_timer_get_current_state 363 (&pAc->wmmInactivityTimer) == 364 QDF_TIMER_STATE_STOPPED); 365 } 366 } 367 } 368 369 /** 370 * hdd_wmm_enable_inactivity_timer() - 371 * function to enable the traffic inactivity timer for the given AC 372 * 373 * @pQosContext: [in] pointer to pQosContext 374 * @inactivityTime: [in] value of the inactivity interval in millisecs 375 * 376 * When a QoS-Tspec is successfully setup, if the inactivity interval 377 * time specified in the AddTS parameters is non-zero, this function 378 * is invoked to start a traffic inactivity timer for the given AC. 379 * 380 * Return: QDF_STATUS enumeration 381 */ 382 static QDF_STATUS 383 hdd_wmm_enable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext, 384 uint32_t inactivityTime) 385 { 386 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; 387 struct hdd_adapter *adapter = pQosContext->adapter; 388 sme_ac_enum_type acType = pQosContext->acType; 389 struct hdd_wmm_ac_status *pAc; 390 391 adapter = pQosContext->adapter; 392 pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 393 394 qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer, 395 QDF_TIMER_TYPE_SW, 396 hdd_wmm_inactivity_timer_cb, 397 pQosContext); 398 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 399 hdd_err("Initializing inactivity timer failed on AC %d", 400 acType); 401 return qdf_status; 402 } 403 /* Start the inactivity timer */ 404 qdf_status = qdf_mc_timer_start(&pAc->wmmInactivityTimer, 405 inactivityTime); 406 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 407 hdd_err("Starting inactivity timer failed on AC %d", 408 acType); 409 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); 410 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) 411 hdd_err("Failed to destroy inactivity timer"); 412 413 return qdf_status; 414 } 415 pAc->wmmInactivityTime = inactivityTime; 416 /* Initialize the current tx traffic count on this AC */ 417 pAc->wmmPrevTrafficCnt = 418 adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext-> 419 acType]; 420 pQosContext->is_inactivity_timer_running = true; 421 return qdf_status; 422 } 423 424 /** 425 * hdd_wmm_disable_inactivity_timer() - 426 * function to disable the traffic inactivity timer for the given AC. 427 * 428 * @pQosContext: [in] pointer to pQosContext 429 * 430 * This function is invoked to disable the traffic inactivity timer 431 * for the given AC. This is normally done when the TS is deleted. 432 * 433 * Return: QDF_STATUS enumeration 434 */ 435 static QDF_STATUS 436 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext) 437 { 438 struct hdd_adapter *adapter = pQosContext->adapter; 439 sme_ac_enum_type acType = pQosContext->acType; 440 struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 441 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; 442 443 /* Clear the timer and the counter */ 444 pAc->wmmInactivityTime = 0; 445 pAc->wmmPrevTrafficCnt = 0; 446 447 if (pQosContext->is_inactivity_timer_running == true) { 448 pQosContext->is_inactivity_timer_running = false; 449 qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer); 450 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 451 hdd_err("Failed to stop inactivity timer"); 452 return qdf_status; 453 } 454 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); 455 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) 456 hdd_err("Failed to destroy inactivity timer:Timer started"); 457 } 458 459 return qdf_status; 460 } 461 #else 462 463 static QDF_STATUS 464 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext) 465 { 466 return QDF_STATUS_SUCCESS; 467 } 468 #endif /* FEATURE_WLAN_ESE */ 469 470 /** 471 * hdd_wmm_sme_callback() - callback for QoS notifications 472 * 473 * @mac_handle: [in] the MAC handle 474 * @context : [in] the HDD callback context 475 * @pCurrentQosInfo : [in] the TSPEC params 476 * @smeStatus : [in] the QoS related SME status 477 * @qosFlowId: [in] the unique identifier of the flow 478 * 479 * This callback is registered by HDD with SME for receiving QoS 480 * notifications. Even though this function has a static scope it 481 * gets called externally through some function pointer magic (so 482 * there is a need for rigorous parameter checking). 483 * 484 * Return: QDF_STATUS enumeration 485 */ 486 static QDF_STATUS hdd_wmm_sme_callback(mac_handle_t mac_handle, 487 void *context, 488 struct sme_qos_wmmtspecinfo *pCurrentQosInfo, 489 enum sme_qos_statustype smeStatus, 490 uint32_t qosFlowId) 491 { 492 struct hdd_wmm_qos_context *pQosContext = context; 493 struct hdd_adapter *adapter; 494 sme_ac_enum_type acType; 495 struct hdd_wmm_ac_status *pAc; 496 497 hdd_debug("Entered, context %pK", pQosContext); 498 499 if (unlikely((NULL == pQosContext) || 500 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { 501 hdd_err("Invalid QoS Context"); 502 return QDF_STATUS_E_FAILURE; 503 } 504 505 adapter = pQosContext->adapter; 506 acType = pQosContext->acType; 507 pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 508 509 hdd_debug("status %d flowid %d info %pK", 510 smeStatus, qosFlowId, pCurrentQosInfo); 511 512 switch (smeStatus) { 513 514 case SME_QOS_STATUS_SETUP_SUCCESS_IND: 515 hdd_debug("Setup is complete"); 516 517 /* there will always be a TSPEC returned with this 518 * status, even if a TSPEC is not exchanged OTA 519 */ 520 if (pCurrentQosInfo) { 521 pAc->wmmAcTspecValid = true; 522 memcpy(&pAc->wmmAcTspecInfo, 523 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); 524 } 525 pAc->wmmAcAccessAllowed = true; 526 pAc->wmmAcAccessGranted = true; 527 pAc->wmmAcAccessPending = false; 528 pAc->wmmAcAccessFailed = false; 529 530 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 531 532 hdd_debug("Explicit Qos, notifying user space"); 533 534 /* this was triggered by an application */ 535 pQosContext->lastStatus = 536 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; 537 hdd_wmm_notify_app(pQosContext); 538 } 539 540 #ifdef FEATURE_WLAN_ESE 541 /* Check if the inactivity interval is specified */ 542 if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) { 543 hdd_debug("Inactivity timer value = %d for AC=%d", 544 pCurrentQosInfo->inactivity_interval, acType); 545 hdd_wmm_enable_inactivity_timer(pQosContext, 546 pCurrentQosInfo-> 547 inactivity_interval); 548 } 549 #endif /* FEATURE_WLAN_ESE */ 550 551 /* notify TL to enable trigger frames if necessary */ 552 hdd_wmm_enable_tl_uapsd(pQosContext); 553 554 break; 555 556 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: 557 hdd_debug("Setup is complete (U-APSD set previously)"); 558 559 pAc->wmmAcAccessAllowed = true; 560 pAc->wmmAcAccessGranted = true; 561 pAc->wmmAcAccessPending = false; 562 563 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 564 565 hdd_debug("Explicit Qos, notifying user space"); 566 567 /* this was triggered by an application */ 568 pQosContext->lastStatus = 569 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; 570 hdd_wmm_notify_app(pQosContext); 571 } 572 573 break; 574 575 case SME_QOS_STATUS_SETUP_FAILURE_RSP: 576 hdd_err("Setup failed"); 577 /* QoS setup failed */ 578 579 pAc->wmmAcAccessPending = false; 580 pAc->wmmAcAccessFailed = true; 581 pAc->wmmAcAccessAllowed = false; 582 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 583 584 hdd_debug("Explicit Qos, notifying user space"); 585 586 /* this was triggered by an application */ 587 pQosContext->lastStatus = 588 HDD_WLAN_WMM_STATUS_SETUP_FAILED; 589 590 hdd_wmm_notify_app(pQosContext); 591 } 592 593 /* disable the inactivity timer */ 594 hdd_wmm_disable_inactivity_timer(pQosContext); 595 596 /* Setting up QoS Failed, QoS context can be released. 597 * SME is releasing this flow information and if HDD 598 * doesn't release this context, next time if 599 * application uses the same handle to set-up QoS, HDD 600 * (as it has QoS context for this handle) will issue 601 * Modify QoS request to SME but SME will reject as now 602 * it has no information for this flow. 603 */ 604 hdd_wmm_free_context(pQosContext); 605 break; 606 607 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: 608 hdd_err("Setup Invalid Params, notify TL"); 609 /* QoS setup failed */ 610 pAc->wmmAcAccessAllowed = false; 611 612 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { 613 614 /* we note the failure, but we also mark 615 * access as allowed so that the packets will 616 * flow. Note that the MAC will "do the right 617 * thing" 618 */ 619 pAc->wmmAcAccessPending = false; 620 pAc->wmmAcAccessFailed = true; 621 pAc->wmmAcAccessAllowed = true; 622 623 } else { 624 hdd_debug("Explicit Qos, notifying user space"); 625 626 /* this was triggered by an application */ 627 pQosContext->lastStatus = 628 HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; 629 hdd_wmm_notify_app(pQosContext); 630 } 631 break; 632 633 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: 634 hdd_err("Setup failed, not a QoS AP"); 635 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 636 hdd_info("Explicit Qos, notifying user space"); 637 638 /* this was triggered by an application */ 639 pQosContext->lastStatus = 640 HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; 641 hdd_wmm_notify_app(pQosContext); 642 } 643 break; 644 645 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: 646 hdd_debug("Setup pending"); 647 /* not a callback status -- ignore if we get it */ 648 break; 649 650 case SME_QOS_STATUS_SETUP_MODIFIED_IND: 651 hdd_debug("Setup modified"); 652 if (pCurrentQosInfo) { 653 /* update the TSPEC */ 654 pAc->wmmAcTspecValid = true; 655 memcpy(&pAc->wmmAcTspecInfo, 656 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); 657 658 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 659 hdd_debug("Explicit Qos, notifying user space"); 660 661 /* this was triggered by an application */ 662 pQosContext->lastStatus = 663 HDD_WLAN_WMM_STATUS_MODIFIED; 664 hdd_wmm_notify_app(pQosContext); 665 } 666 /* need to tell TL to update its UAPSD handling */ 667 hdd_wmm_enable_tl_uapsd(pQosContext); 668 } 669 break; 670 671 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: 672 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { 673 674 /* this was triggered by implicit QoS so we 675 * know packets are pending 676 */ 677 pAc->wmmAcAccessPending = false; 678 pAc->wmmAcAccessGranted = true; 679 pAc->wmmAcAccessAllowed = true; 680 681 } else { 682 hdd_debug("Explicit Qos, notifying user space"); 683 684 /* this was triggered by an application */ 685 pQosContext->lastStatus = 686 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; 687 hdd_wmm_notify_app(pQosContext); 688 } 689 break; 690 691 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: 692 /* nothing to do for now */ 693 break; 694 695 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED: 696 hdd_err("Setup successful but U-APSD failed"); 697 698 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { 699 700 /* QoS setup was successful but setting U=APSD 701 * failed. Since the OTA part of the request 702 * was successful, we don't mark this as a 703 * failure. the packets will flow. Note that 704 * the MAC will "do the right thing" 705 */ 706 pAc->wmmAcAccessGranted = true; 707 pAc->wmmAcAccessAllowed = true; 708 pAc->wmmAcAccessFailed = false; 709 pAc->wmmAcAccessPending = false; 710 711 } else { 712 hdd_info("Explicit Qos, notifying user space"); 713 714 /* this was triggered by an application */ 715 pQosContext->lastStatus = 716 HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED; 717 hdd_wmm_notify_app(pQosContext); 718 } 719 720 /* Since U-APSD portion failed disabled trigger frame 721 * generation 722 */ 723 hdd_wmm_disable_tl_uapsd(pQosContext); 724 725 break; 726 727 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: 728 hdd_debug("Release is complete"); 729 730 if (pCurrentQosInfo) { 731 hdd_debug("flows still active"); 732 733 /* there is still at least one flow active for 734 * this AC so update the AC state 735 */ 736 memcpy(&pAc->wmmAcTspecInfo, 737 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); 738 739 /* need to tell TL to update its UAPSD handling */ 740 hdd_wmm_enable_tl_uapsd(pQosContext); 741 } else { 742 hdd_debug("last flow"); 743 744 /* this is the last flow active for this AC so 745 * update the AC state 746 */ 747 pAc->wmmAcTspecValid = false; 748 749 /* DELTS is successful, do not allow */ 750 pAc->wmmAcAccessAllowed = false; 751 752 /* need to tell TL to update its UAPSD handling */ 753 hdd_wmm_disable_tl_uapsd(pQosContext); 754 } 755 756 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 757 hdd_debug("Explicit Qos, notifying user space"); 758 759 /* this was triggered by an application */ 760 pQosContext->lastStatus = 761 HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; 762 hdd_wmm_notify_app(pQosContext); 763 } 764 /* disable the inactivity timer */ 765 hdd_wmm_disable_inactivity_timer(pQosContext); 766 767 /* we are done with this flow */ 768 hdd_wmm_free_context(pQosContext); 769 break; 770 771 case SME_QOS_STATUS_RELEASE_FAILURE_RSP: 772 hdd_debug("Release failure"); 773 774 /* we don't need to update our state or TL since 775 * nothing has changed 776 */ 777 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 778 hdd_debug("Explicit Qos, notifying user space"); 779 780 /* this was triggered by an application */ 781 pQosContext->lastStatus = 782 HDD_WLAN_WMM_STATUS_RELEASE_FAILED; 783 hdd_wmm_notify_app(pQosContext); 784 } 785 786 break; 787 788 case SME_QOS_STATUS_RELEASE_QOS_LOST_IND: 789 hdd_debug("QOS Lost indication received"); 790 791 /* current TSPEC is no longer valid */ 792 pAc->wmmAcTspecValid = false; 793 /* AP has sent DELTS, do not allow */ 794 pAc->wmmAcAccessAllowed = false; 795 796 /* need to tell TL to update its UAPSD handling */ 797 hdd_wmm_disable_tl_uapsd(pQosContext); 798 799 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { 800 /* we no longer have implicit access granted */ 801 pAc->wmmAcAccessGranted = false; 802 pAc->wmmAcAccessFailed = false; 803 } else { 804 hdd_debug("Explicit Qos, notifying user space"); 805 806 /* this was triggered by an application */ 807 pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST; 808 hdd_wmm_notify_app(pQosContext); 809 } 810 811 /* disable the inactivity timer */ 812 hdd_wmm_disable_inactivity_timer(pQosContext); 813 814 /* we are done with this flow */ 815 hdd_wmm_free_context(pQosContext); 816 break; 817 818 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: 819 hdd_debug("Release pending"); 820 /* not a callback status -- ignore if we get it */ 821 break; 822 823 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: 824 hdd_err("Release Invalid Params"); 825 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 826 /* this was triggered by an application */ 827 pQosContext->lastStatus = 828 HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; 829 hdd_wmm_notify_app(pQosContext); 830 } 831 break; 832 833 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND: 834 hdd_debug("Modification is complete, notify TL"); 835 836 /* there will always be a TSPEC returned with this 837 * status, even if a TSPEC is not exchanged OTA 838 */ 839 if (pCurrentQosInfo) { 840 pAc->wmmAcTspecValid = true; 841 memcpy(&pAc->wmmAcTspecInfo, 842 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); 843 } 844 845 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 846 /* this was triggered by an application */ 847 pQosContext->lastStatus = 848 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS; 849 hdd_wmm_notify_app(pQosContext); 850 } 851 /* notify TL to enable trigger frames if necessary */ 852 hdd_wmm_enable_tl_uapsd(pQosContext); 853 854 break; 855 856 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: 857 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 858 /* this was triggered by an application */ 859 pQosContext->lastStatus = 860 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; 861 hdd_wmm_notify_app(pQosContext); 862 } 863 break; 864 865 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: 866 /* the flow modification failed so we'll leave in 867 * place whatever existed beforehand 868 */ 869 870 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 871 /* this was triggered by an application */ 872 pQosContext->lastStatus = 873 HDD_WLAN_WMM_STATUS_MODIFY_FAILED; 874 hdd_wmm_notify_app(pQosContext); 875 } 876 break; 877 878 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: 879 hdd_debug("modification pending"); 880 /* not a callback status -- ignore if we get it */ 881 break; 882 883 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: 884 /* the flow modification was successful but no QoS 885 * changes required 886 */ 887 888 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 889 /* this was triggered by an application */ 890 pQosContext->lastStatus = 891 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; 892 hdd_wmm_notify_app(pQosContext); 893 } 894 break; 895 896 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: 897 /* invalid params -- notify the application */ 898 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 899 /* this was triggered by an application */ 900 pQosContext->lastStatus = 901 HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; 902 hdd_wmm_notify_app(pQosContext); 903 } 904 break; 905 906 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING: 907 /* nothing to do for now. when APSD is established we'll have work to do */ 908 break; 909 910 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED: 911 hdd_err("Modify successful but U-APSD failed"); 912 913 /* QoS modification was successful but setting U=APSD 914 * failed. This will always be an explicit QoS 915 * instance, so all we can do is notify the 916 * application and let it clean up. 917 */ 918 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { 919 /* this was triggered by an application */ 920 pQosContext->lastStatus = 921 HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED; 922 hdd_wmm_notify_app(pQosContext); 923 } 924 /* Since U-APSD portion failed disabled trigger frame 925 * generation 926 */ 927 hdd_wmm_disable_tl_uapsd(pQosContext); 928 929 break; 930 931 case SME_QOS_STATUS_HANDING_OFF: 932 /* no roaming so we won't see this */ 933 break; 934 935 case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND: 936 /* need to tell TL to stop trigger frame generation */ 937 hdd_wmm_disable_tl_uapsd(pQosContext); 938 break; 939 940 case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND: 941 /* need to tell TL to start sending trigger frames again */ 942 hdd_wmm_enable_tl_uapsd(pQosContext); 943 break; 944 945 default: 946 hdd_err("unexpected SME Status=%d", smeStatus); 947 QDF_ASSERT(0); 948 } 949 950 /* if Tspec only allows downstream traffic then access is not 951 * allowed 952 */ 953 if (pAc->wmmAcTspecValid && 954 (pAc->wmmAcTspecInfo.ts_info.direction == 955 SME_QOS_WMM_TS_DIR_DOWNLINK)) { 956 pAc->wmmAcAccessAllowed = false; 957 } 958 /* if we have valid Tpsec or if ACM bit is not set, allow access */ 959 if ((pAc->wmmAcTspecValid && 960 (pAc->wmmAcTspecInfo.ts_info.direction != 961 SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) { 962 pAc->wmmAcAccessAllowed = true; 963 } 964 965 hdd_debug("complete, access for TL AC %d is%sallowed", 966 acType, pAc->wmmAcAccessAllowed ? " " : " not "); 967 968 return QDF_STATUS_SUCCESS; 969 } 970 #endif 971 972 /** 973 * hdd_wmmps_helper() - Function to set uapsd psb dynamically 974 * 975 * @adapter: [in] pointer to adapter structure 976 * @ptr: [in] pointer to command buffer 977 * 978 * Return: Zero on success, appropriate error on failure. 979 */ 980 int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr) 981 { 982 if (NULL == adapter) { 983 hdd_err("adapter is NULL"); 984 return -EINVAL; 985 } 986 if (NULL == ptr) { 987 hdd_err("ptr is NULL"); 988 return -EINVAL; 989 } 990 /* convert ASCII to integer */ 991 adapter->configured_psb = ptr[9] - '0'; 992 adapter->psb_changed = HDD_PSB_CHANGED; 993 994 return 0; 995 } 996 997 /** 998 * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup 999 * QoS for any AC requiring it. 1000 * @work: [in] pointer to work structure. 1001 * 1002 * Return: none 1003 */ 1004 static void __hdd_wmm_do_implicit_qos(struct work_struct *work) 1005 { 1006 struct hdd_wmm_qos_context *pQosContext = 1007 container_of(work, struct hdd_wmm_qos_context, 1008 wmmAcSetupImplicitQos); 1009 struct hdd_adapter *adapter; 1010 sme_ac_enum_type acType; 1011 struct hdd_wmm_ac_status *pAc; 1012 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 1013 enum sme_qos_statustype smeStatus; 1014 #endif 1015 struct sme_qos_wmmtspecinfo qosInfo; 1016 struct hdd_context *hdd_ctx; 1017 mac_handle_t mac_handle; 1018 1019 hdd_debug("Entered, context %pK", pQosContext); 1020 1021 if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) { 1022 hdd_err("Invalid QoS Context"); 1023 return; 1024 } 1025 1026 adapter = pQosContext->adapter; 1027 1028 hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1029 if (wlan_hdd_validate_context(hdd_ctx)) 1030 return; 1031 1032 mac_handle = hdd_ctx->mac_handle; 1033 1034 acType = pQosContext->acType; 1035 pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 1036 1037 hdd_debug("adapter %pK acType %d", adapter, acType); 1038 1039 if (!pAc->wmmAcAccessNeeded) { 1040 hdd_err("AC %d doesn't need service", acType); 1041 pQosContext->magic = 0; 1042 qdf_mem_free(pQosContext); 1043 return; 1044 } 1045 1046 pAc->wmmAcAccessPending = true; 1047 pAc->wmmAcAccessNeeded = false; 1048 1049 memset(&qosInfo, 0, sizeof(qosInfo)); 1050 1051 qosInfo.ts_info.psb = adapter->configured_psb; 1052 1053 switch (acType) { 1054 case SME_AC_VO: 1055 qosInfo.ts_info.up = SME_QOS_WMM_UP_VO; 1056 /* Check if there is any valid configuration from framework */ 1057 if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { 1058 qosInfo.ts_info.psb = 1059 ((WLAN_HDD_GET_CTX(adapter))->config-> 1060 UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0; 1061 } 1062 qosInfo.ts_info.direction = 1063 (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVo; 1064 qosInfo.ts_info.tid = 255; 1065 qosInfo.mean_data_rate = 1066 (WLAN_HDD_GET_CTX(adapter))->config-> 1067 InfraMeanDataRateAcVo; 1068 qosInfo.min_phy_rate = 1069 (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVo; 1070 qosInfo.min_service_interval = 1071 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSrvIntv; 1072 qosInfo.nominal_msdu_size = 1073 (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVo; 1074 qosInfo.surplus_bw_allowance = 1075 (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVo; 1076 qosInfo.suspension_interval = 1077 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSuspIntv; 1078 break; 1079 case SME_AC_VI: 1080 qosInfo.ts_info.up = SME_QOS_WMM_UP_VI; 1081 /* Check if there is any valid configuration from framework */ 1082 if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { 1083 qosInfo.ts_info.psb = 1084 ((WLAN_HDD_GET_CTX(adapter))->config-> 1085 UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0; 1086 } 1087 qosInfo.ts_info.direction = 1088 (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVi; 1089 qosInfo.ts_info.tid = 255; 1090 qosInfo.mean_data_rate = 1091 (WLAN_HDD_GET_CTX(adapter))->config-> 1092 InfraMeanDataRateAcVi; 1093 qosInfo.min_phy_rate = 1094 (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVi; 1095 qosInfo.min_service_interval = 1096 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSrvIntv; 1097 qosInfo.nominal_msdu_size = 1098 (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVi; 1099 qosInfo.surplus_bw_allowance = 1100 (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVi; 1101 qosInfo.suspension_interval = 1102 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSuspIntv; 1103 break; 1104 default: 1105 case SME_AC_BE: 1106 qosInfo.ts_info.up = SME_QOS_WMM_UP_BE; 1107 /* Check if there is any valid configuration from framework */ 1108 if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { 1109 qosInfo.ts_info.psb = 1110 ((WLAN_HDD_GET_CTX(adapter))->config-> 1111 UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0; 1112 } 1113 qosInfo.ts_info.direction = 1114 (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBe; 1115 qosInfo.ts_info.tid = 255; 1116 qosInfo.mean_data_rate = 1117 (WLAN_HDD_GET_CTX(adapter))->config-> 1118 InfraMeanDataRateAcBe; 1119 qosInfo.min_phy_rate = 1120 (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBe; 1121 qosInfo.min_service_interval = 1122 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSrvIntv; 1123 qosInfo.nominal_msdu_size = 1124 (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBe; 1125 qosInfo.surplus_bw_allowance = 1126 (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBe; 1127 qosInfo.suspension_interval = 1128 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSuspIntv; 1129 break; 1130 case SME_AC_BK: 1131 qosInfo.ts_info.up = SME_QOS_WMM_UP_BK; 1132 /* Check if there is any valid configuration from framework */ 1133 if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { 1134 qosInfo.ts_info.psb = 1135 ((WLAN_HDD_GET_CTX(adapter))->config-> 1136 UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0; 1137 } 1138 qosInfo.ts_info.direction = 1139 (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBk; 1140 qosInfo.ts_info.tid = 255; 1141 qosInfo.mean_data_rate = 1142 (WLAN_HDD_GET_CTX(adapter))->config-> 1143 InfraMeanDataRateAcBk; 1144 qosInfo.min_phy_rate = 1145 (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBk; 1146 qosInfo.min_service_interval = 1147 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSrvIntv; 1148 qosInfo.nominal_msdu_size = 1149 (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBk; 1150 qosInfo.surplus_bw_allowance = 1151 (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBk; 1152 qosInfo.suspension_interval = 1153 (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSuspIntv; 1154 break; 1155 } 1156 #ifdef FEATURE_WLAN_ESE 1157 qosInfo.inactivity_interval = 1158 (WLAN_HDD_GET_CTX(adapter))->config->InfraInactivityInterval; 1159 #endif 1160 qosInfo.ts_info.burst_size_defn = 1161 (WLAN_HDD_GET_CTX(adapter))->config->burstSizeDefinition; 1162 1163 switch ((WLAN_HDD_GET_CTX(adapter))->config->tsInfoAckPolicy) { 1164 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: 1165 qosInfo.ts_info.ack_policy = 1166 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; 1167 break; 1168 1169 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: 1170 qosInfo.ts_info.ack_policy = 1171 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; 1172 break; 1173 1174 default: 1175 /* unknown */ 1176 qosInfo.ts_info.ack_policy = 1177 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; 1178 } 1179 1180 if (qosInfo.ts_info.ack_policy == 1181 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { 1182 if (!sme_qos_is_ts_info_ack_policy_valid 1183 ((tpAniSirGlobal) mac_handle, &qosInfo, 1184 adapter->session_id)) { 1185 qosInfo.ts_info.ack_policy = 1186 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; 1187 } 1188 } 1189 1190 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 1191 list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList); 1192 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 1193 1194 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 1195 smeStatus = sme_qos_setup_req(mac_handle, 1196 adapter->session_id, 1197 &qosInfo, 1198 hdd_wmm_sme_callback, 1199 pQosContext, 1200 qosInfo.ts_info.up, 1201 &pQosContext->qosFlowId); 1202 1203 hdd_debug("sme_qos_setup_req returned %d flowid %d", 1204 smeStatus, pQosContext->qosFlowId); 1205 1206 /* need to check the return values and act appropriately */ 1207 switch (smeStatus) { 1208 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: 1209 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: 1210 /* setup is pending, so no more work to do now. all 1211 * further work will be done in hdd_wmm_sme_callback() 1212 */ 1213 hdd_debug("Setup is pending, no further work"); 1214 1215 break; 1216 1217 case SME_QOS_STATUS_SETUP_FAILURE_RSP: 1218 /* disable the inactivity timer */ 1219 hdd_wmm_disable_inactivity_timer(pQosContext); 1220 1221 /* we can't tell the difference between when a request 1222 * fails because AP rejected it versus when SME 1223 * encountered an internal error. in either case SME 1224 * won't ever reference this context so free the 1225 * record 1226 */ 1227 hdd_wmm_free_context(pQosContext); 1228 1229 /* fall through and start packets flowing */ 1230 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: 1231 /* no ACM in effect, no need to setup U-APSD */ 1232 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: 1233 /* no ACM in effect, U-APSD is desired but was already setup */ 1234 1235 /* for these cases everything is already setup so we 1236 * can signal TL that it has work to do 1237 */ 1238 hdd_debug("Setup is complete, notify TL"); 1239 1240 pAc->wmmAcAccessAllowed = true; 1241 pAc->wmmAcAccessGranted = true; 1242 pAc->wmmAcAccessPending = false; 1243 1244 break; 1245 1246 default: 1247 hdd_err("unexpected SME Status=%d", smeStatus); 1248 QDF_ASSERT(0); 1249 } 1250 #endif 1251 1252 } 1253 1254 /** 1255 * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos 1256 * @work: pointer to work_struct 1257 * 1258 * Return: none 1259 */ 1260 static void hdd_wmm_do_implicit_qos(struct work_struct *work) 1261 { 1262 cds_ssr_protect(__func__); 1263 __hdd_wmm_do_implicit_qos(work); 1264 cds_ssr_unprotect(__func__); 1265 } 1266 1267 /** 1268 * hdd_wmm_init() - initialize the WMM DSCP configuation 1269 * @adapter : [in] pointer to Adapter context 1270 * 1271 * This function will initialize the WMM DSCP configuation of an 1272 * adapter to an initial state. The configuration can later be 1273 * overwritten via application APIs or via QoS Map sent OTA. 1274 * 1275 * Return: QDF_STATUS enumeration 1276 */ 1277 QDF_STATUS hdd_wmm_init(struct hdd_adapter *adapter) 1278 { 1279 enum sme_qos_wmmuptype *dscp_to_up_map = adapter->dscp_to_up_map; 1280 uint8_t dscp; 1281 1282 hdd_enter(); 1283 1284 /* DSCP to User Priority Lookup Table 1285 * By default use the 3 Precedence bits of DSCP as the User Priority 1286 */ 1287 for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) 1288 dscp_to_up_map[dscp] = dscp >> 3; 1289 1290 /* Special case for Expedited Forwarding (DSCP 46) */ 1291 dscp_to_up_map[46] = SME_QOS_WMM_UP_VO; 1292 1293 return QDF_STATUS_SUCCESS; 1294 } 1295 1296 /** 1297 * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter 1298 * @adapter: [in] pointer to Adapter context 1299 * 1300 * This function will initialize the WMM configuation and status of an 1301 * adapter to an initial state. The configuration can later be 1302 * overwritten via application APIs 1303 * 1304 * Return: QDF_STATUS enumeration 1305 */ 1306 QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter) 1307 { 1308 struct hdd_wmm_ac_status *pAcStatus; 1309 sme_ac_enum_type acType; 1310 1311 hdd_enter(); 1312 1313 adapter->hdd_wmm_status.wmmQap = false; 1314 INIT_LIST_HEAD(&adapter->hdd_wmm_status.wmmContextList); 1315 mutex_init(&adapter->hdd_wmm_status.wmmLock); 1316 1317 for (acType = 0; acType < WLAN_MAX_AC; acType++) { 1318 pAcStatus = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 1319 pAcStatus->wmmAcAccessRequired = false; 1320 pAcStatus->wmmAcAccessNeeded = false; 1321 pAcStatus->wmmAcAccessPending = false; 1322 pAcStatus->wmmAcAccessFailed = false; 1323 pAcStatus->wmmAcAccessGranted = false; 1324 pAcStatus->wmmAcAccessAllowed = false; 1325 pAcStatus->wmmAcTspecValid = false; 1326 pAcStatus->wmmAcUapsdInfoValid = false; 1327 } 1328 /* Invalid value(0xff) to indicate psb not configured through 1329 * framework initially. 1330 */ 1331 adapter->configured_psb = HDD_PSB_CFG_INVALID; 1332 1333 return QDF_STATUS_SUCCESS; 1334 } 1335 1336 /** 1337 * hdd_wmm_adapter_clear() - Function which will clear the WMM status 1338 * for all the ACs 1339 * 1340 * @adapter: [in] pointer to Adapter context 1341 * 1342 * Return: QDF_STATUS enumeration 1343 */ 1344 QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter) 1345 { 1346 struct hdd_wmm_ac_status *pAcStatus; 1347 sme_ac_enum_type acType; 1348 1349 hdd_enter(); 1350 for (acType = 0; acType < WLAN_MAX_AC; acType++) { 1351 pAcStatus = &adapter->hdd_wmm_status.wmmAcStatus[acType]; 1352 pAcStatus->wmmAcAccessRequired = false; 1353 pAcStatus->wmmAcAccessNeeded = false; 1354 pAcStatus->wmmAcAccessPending = false; 1355 pAcStatus->wmmAcAccessFailed = false; 1356 pAcStatus->wmmAcAccessGranted = false; 1357 pAcStatus->wmmAcAccessAllowed = false; 1358 pAcStatus->wmmAcTspecValid = false; 1359 pAcStatus->wmmAcUapsdInfoValid = false; 1360 } 1361 return QDF_STATUS_SUCCESS; 1362 } 1363 1364 /** 1365 * hdd_wmm_close() - WMM close function 1366 * @adapter: [in] pointer to adapter context 1367 * 1368 * Function which will perform any necessary work to to clean up the 1369 * WMM functionality prior to the kernel module unload. 1370 * 1371 * Return: QDF_STATUS enumeration 1372 */ 1373 QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter) 1374 { 1375 struct hdd_wmm_qos_context *pQosContext; 1376 1377 hdd_enter(); 1378 1379 /* free any context records that we still have linked */ 1380 while (!list_empty(&adapter->hdd_wmm_status.wmmContextList)) { 1381 pQosContext = 1382 list_first_entry(&adapter->hdd_wmm_status.wmmContextList, 1383 struct hdd_wmm_qos_context, node); 1384 1385 hdd_wmm_disable_inactivity_timer(pQosContext); 1386 1387 if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT 1388 && pQosContext->magic == HDD_WMM_CTX_MAGIC) 1389 cds_flush_work(&pQosContext->wmmAcSetupImplicitQos); 1390 1391 hdd_wmm_free_context(pQosContext); 1392 } 1393 1394 return QDF_STATUS_SUCCESS; 1395 } 1396 1397 /** 1398 * hdd_wmm_classify_pkt() - Function which will classify an OS packet 1399 * into a WMM AC based on DSCP 1400 * 1401 * @adapter: adapter upon which the packet is being transmitted 1402 * @skb: pointer to network buffer 1403 * @user_pri: user priority of the OS packet 1404 * @is_eapol: eapol packet flag 1405 * 1406 * Return: None 1407 */ 1408 static 1409 void hdd_wmm_classify_pkt(struct hdd_adapter *adapter, 1410 struct sk_buff *skb, 1411 enum sme_qos_wmmuptype *user_pri, 1412 bool *is_eapol) 1413 { 1414 unsigned char dscp; 1415 unsigned char tos; 1416 union generic_ethhdr *eth_hdr; 1417 struct iphdr *ip_hdr; 1418 struct ipv6hdr *ipv6hdr; 1419 unsigned char *pkt; 1420 1421 /* this code is executed for every packet therefore 1422 * all debug code is kept conditional 1423 */ 1424 1425 #ifdef HDD_WMM_DEBUG 1426 hdd_enter(); 1427 #endif /* HDD_WMM_DEBUG */ 1428 1429 pkt = skb->data; 1430 eth_hdr = (union generic_ethhdr *)pkt; 1431 1432 #ifdef HDD_WMM_DEBUG 1433 hdd_debug("proto is 0x%04x", skb->protocol); 1434 #endif /* HDD_WMM_DEBUG */ 1435 1436 if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) { 1437 /* case 1: Ethernet II IP packet */ 1438 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)]; 1439 tos = ip_hdr->tos; 1440 #ifdef HDD_WMM_DEBUG 1441 hdd_debug("Ethernet II IP Packet, tos is %d", tos); 1442 #endif /* HDD_WMM_DEBUG */ 1443 1444 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) { 1445 ipv6hdr = ipv6_hdr(skb); 1446 tos = ntohs(*(const __be16 *)ipv6hdr) >> 4; 1447 #ifdef HDD_WMM_DEBUG 1448 hdd_debug("Ethernet II IPv6 Packet, tos is %d", tos); 1449 #endif /* HDD_WMM_DEBUG */ 1450 } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) && 1451 (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) && 1452 (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) && 1453 (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) && 1454 (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) { 1455 /* case 2: 802.3 LLC/SNAP IP packet */ 1456 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)]; 1457 tos = ip_hdr->tos; 1458 #ifdef HDD_WMM_DEBUG 1459 hdd_debug("802.3 LLC/SNAP IP Packet, tos is %d", tos); 1460 #endif /* HDD_WMM_DEBUG */ 1461 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) { 1462 /* VLAN tagged */ 1463 1464 if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto == 1465 htons(ETH_P_IP)) { 1466 /* case 3: Ethernet II vlan-tagged IP packet */ 1467 ip_hdr = 1468 (struct iphdr *) 1469 &pkt[sizeof(eth_hdr->eth_IIv)]; 1470 tos = ip_hdr->tos; 1471 #ifdef HDD_WMM_DEBUG 1472 hdd_debug("Ether II VLAN tagged IP Packet, tos is %d", 1473 tos); 1474 #endif /* HDD_WMM_DEBUG */ 1475 } else 1476 if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto) 1477 < WLAN_MIN_PROTO) 1478 && (eth_hdr->eth_8023v.h_snap.dsap == 1479 WLAN_SNAP_DSAP) 1480 && (eth_hdr->eth_8023v.h_snap.ssap == 1481 WLAN_SNAP_SSAP) 1482 && (eth_hdr->eth_8023v.h_snap.ctrl == 1483 WLAN_SNAP_CTRL) 1484 && (eth_hdr->eth_8023v.h_proto == 1485 htons(ETH_P_IP))) { 1486 /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */ 1487 ip_hdr = 1488 (struct iphdr *) 1489 &pkt[sizeof(eth_hdr->eth_8023v)]; 1490 tos = ip_hdr->tos; 1491 #ifdef HDD_WMM_DEBUG 1492 hdd_debug("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d", 1493 tos); 1494 #endif /* HDD_WMM_DEBUG */ 1495 } else { 1496 /* default */ 1497 #ifdef HDD_WMM_DEBUG 1498 hdd_warn("VLAN tagged Unhandled Protocol, using default tos"); 1499 #endif /* HDD_WMM_DEBUG */ 1500 tos = 0; 1501 } 1502 } else { 1503 /* default */ 1504 #ifdef HDD_WMM_DEBUG 1505 hdd_warn("Unhandled Protocol, using default tos"); 1506 #endif /* HDD_WMM_DEBUG */ 1507 /* Give the highest priority to 802.1x packet */ 1508 if (eth_hdr->eth_II.h_proto == 1509 htons(HDD_ETHERTYPE_802_1_X)) { 1510 tos = 0xC0; 1511 *is_eapol = true; 1512 } else 1513 tos = 0; 1514 } 1515 1516 dscp = (tos >> 2) & 0x3f; 1517 *user_pri = adapter->dscp_to_up_map[dscp]; 1518 1519 #ifdef HDD_WMM_DEBUG 1520 hdd_debug("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri); 1521 #endif /* HDD_WMM_DEBUG */ 1522 } 1523 1524 /** 1525 * __hdd_get_queue_index() - get queue index 1526 * @up: user priority 1527 * 1528 * Return: queue_index 1529 */ 1530 static uint16_t __hdd_get_queue_index(uint16_t up) 1531 { 1532 if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map))) 1533 return HDD_LINUX_AC_BE; 1534 return hdd_linux_up_to_ac_map[up]; 1535 } 1536 1537 #if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_HL_NETDEV_FLOW_CONTROL) 1538 /** 1539 * hdd_get_queue_index() - get queue index 1540 * @up: user priority 1541 * @is_eapol: is_eapol flag 1542 * 1543 * Return: queue_index 1544 */ 1545 static 1546 uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) 1547 { 1548 if (qdf_unlikely(is_eapol == true)) 1549 return HDD_LINUX_AC_HI_PRIO; 1550 return __hdd_get_queue_index(up); 1551 } 1552 #else 1553 static 1554 uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) 1555 { 1556 return __hdd_get_queue_index(up); 1557 } 1558 #endif 1559 1560 1561 /** 1562 * hdd_hostapd_select_queue() - Function which will classify the packet 1563 * according to linux qdisc expectation. 1564 * 1565 * @dev: [in] pointer to net_device structure 1566 * @skb: [in] pointer to os packet 1567 * 1568 * Return: Qdisc queue index 1569 */ 1570 uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb 1571 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) 1572 , void *accel_priv 1573 #endif 1574 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) 1575 , select_queue_fallback_t fallback 1576 #endif 1577 1578 ) 1579 { 1580 enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE; 1581 uint16_t queueIndex; 1582 struct hdd_adapter *adapter = (struct hdd_adapter *) netdev_priv(dev); 1583 struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter); 1584 bool is_eapol = false; 1585 int status = 0; 1586 1587 status = wlan_hdd_validate_context(hddctx); 1588 1589 if (status != 0) { 1590 skb->priority = SME_QOS_WMM_UP_BE; 1591 return HDD_LINUX_AC_BE; 1592 } 1593 1594 /* Get the user priority from IP header */ 1595 hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol); 1596 skb->priority = up; 1597 queueIndex = hdd_get_queue_index(skb->priority, is_eapol); 1598 1599 return queueIndex; 1600 } 1601 1602 /** 1603 * hdd_wmm_select_queue() - Function which will classify the packet 1604 * according to linux qdisc expectation. 1605 * 1606 * @dev: [in] pointer to net_device structure 1607 * @skb: [in] pointer to os packet 1608 * 1609 * Return: Qdisc queue index 1610 */ 1611 uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb) 1612 { 1613 enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE; 1614 uint16_t queueIndex; 1615 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 1616 bool is_crtical = false; 1617 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1618 int status; 1619 enum qdf_proto_subtype proto_subtype; 1620 1621 status = wlan_hdd_validate_context(hdd_ctx); 1622 if (status != 0) { 1623 skb->priority = SME_QOS_WMM_UP_BE; 1624 return HDD_LINUX_AC_BE; 1625 } 1626 1627 /* Get the user priority from IP header */ 1628 hdd_wmm_classify_pkt(adapter, skb, &up, &is_crtical); 1629 spin_lock_bh(&adapter->pause_map_lock); 1630 if ((adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL)) && 1631 !(adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL_PRIORITY))) { 1632 if (qdf_nbuf_is_ipv4_arp_pkt(skb)) 1633 is_crtical = true; 1634 else if (qdf_nbuf_is_icmpv6_pkt(skb)) { 1635 proto_subtype = qdf_nbuf_get_icmpv6_subtype(skb); 1636 switch (proto_subtype) { 1637 case QDF_PROTO_ICMPV6_NA: 1638 case QDF_PROTO_ICMPV6_NS: 1639 is_crtical = true; 1640 break; 1641 default: 1642 break; 1643 } 1644 } 1645 } 1646 spin_unlock_bh(&adapter->pause_map_lock); 1647 skb->priority = up; 1648 queueIndex = hdd_get_queue_index(skb->priority, is_crtical); 1649 1650 return queueIndex; 1651 } 1652 1653 /** 1654 * hdd_wmm_acquire_access_required() - Function which will determine 1655 * acquire admittance for a WMM AC is required or not based on psb configuration 1656 * done in framework 1657 * 1658 * @adapter: [in] pointer to adapter structure 1659 * @acType: [in] WMM AC type of OS packet 1660 * 1661 * Return: void 1662 */ 1663 void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter, 1664 sme_ac_enum_type acType) 1665 { 1666 /* Each bit in the LSB nibble indicates 1 AC. 1667 * Clearing the particular bit in LSB nibble to indicate 1668 * access required 1669 */ 1670 switch (acType) { 1671 case SME_AC_BK: 1672 /* clear first bit */ 1673 adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK; 1674 break; 1675 case SME_AC_BE: 1676 /* clear second bit */ 1677 adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK; 1678 break; 1679 case SME_AC_VI: 1680 /* clear third bit */ 1681 adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK; 1682 break; 1683 case SME_AC_VO: 1684 /* clear fourth bit */ 1685 adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK; 1686 break; 1687 default: 1688 hdd_err("Invalid AC Type"); 1689 break; 1690 } 1691 } 1692 1693 /** 1694 * hdd_wmm_acquire_access() - Function which will attempt to acquire 1695 * admittance for a WMM AC 1696 * 1697 * @adapter: [in] pointer to adapter context 1698 * @acType: [in] WMM AC type of OS packet 1699 * @pGranted: [out] pointer to bool flag when indicates if access 1700 * has been granted or not 1701 * 1702 * Return: QDF_STATUS enumeration 1703 */ 1704 QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter, 1705 sme_ac_enum_type acType, bool *pGranted) 1706 { 1707 struct hdd_wmm_qos_context *pQosContext; 1708 1709 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1710 "%s: Entered for AC %d", __func__, acType); 1711 1712 if (!hdd_wmm_is_active(adapter) || 1713 !(WLAN_HDD_GET_CTX(adapter))->config->bImplicitQosEnabled || 1714 !adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessRequired) { 1715 /* either we don't want QoS or the AP doesn't support 1716 * QoS or we don't want to do implicit QoS 1717 */ 1718 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1719 "%s: QoS not configured on both ends ", __func__); 1720 1721 *pGranted = 1722 adapter->hdd_wmm_status.wmmAcStatus[acType]. 1723 wmmAcAccessAllowed; 1724 1725 return QDF_STATUS_SUCCESS; 1726 } 1727 /* do we already have an implicit QoS request pending for this AC? */ 1728 if ((adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded) || 1729 (adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessPending)) { 1730 /* request already pending so we need to wait for that 1731 * response 1732 */ 1733 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1734 "%s: Implicit QoS for TL AC %d already scheduled", 1735 __func__, acType); 1736 1737 *pGranted = false; 1738 return QDF_STATUS_SUCCESS; 1739 } 1740 /* did we already fail to establish implicit QoS for this AC? 1741 * (if so, access should have been granted when the failure 1742 * was handled) 1743 */ 1744 if (adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessFailed) { 1745 /* request previously failed 1746 * allow access, but we'll be downgraded 1747 */ 1748 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1749 "%s: Implicit QoS for TL AC %d previously failed", 1750 __func__, acType); 1751 1752 if (!adapter->hdd_wmm_status.wmmAcStatus[acType]. 1753 wmmAcAccessRequired) { 1754 adapter->hdd_wmm_status.wmmAcStatus[acType]. 1755 wmmAcAccessAllowed = true; 1756 *pGranted = true; 1757 } else { 1758 adapter->hdd_wmm_status.wmmAcStatus[acType]. 1759 wmmAcAccessAllowed = false; 1760 *pGranted = false; 1761 } 1762 1763 return QDF_STATUS_SUCCESS; 1764 } 1765 /* we need to establish implicit QoS */ 1766 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1767 "%s: Need to schedule implicit QoS for TL AC %d, adapter is %pK", 1768 __func__, acType, adapter); 1769 1770 adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded = true; 1771 1772 pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); 1773 if (NULL == pQosContext) { 1774 /* no memory for QoS context. Nothing we can do but 1775 * let data flow 1776 */ 1777 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, 1778 "%s: Unable to allocate context", __func__); 1779 adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed = 1780 true; 1781 *pGranted = true; 1782 return QDF_STATUS_SUCCESS; 1783 } 1784 1785 pQosContext->acType = acType; 1786 pQosContext->adapter = adapter; 1787 pQosContext->qosFlowId = 0; 1788 pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT; 1789 pQosContext->magic = HDD_WMM_CTX_MAGIC; 1790 pQosContext->is_inactivity_timer_running = false; 1791 1792 INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos); 1793 1794 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, 1795 "%s: Scheduling work for AC %d, context %pK", 1796 __func__, acType, pQosContext); 1797 1798 schedule_work(&pQosContext->wmmAcSetupImplicitQos); 1799 1800 /* caller will need to wait until the work takes place and 1801 * TSPEC negotiation completes 1802 */ 1803 *pGranted = false; 1804 return QDF_STATUS_SUCCESS; 1805 } 1806 1807 /** 1808 * hdd_wmm_assoc() - Function which will handle the housekeeping 1809 * required by WMM when association takes place 1810 * 1811 * @adapter: [in] pointer to adapter context 1812 * @roam_info: [in] pointer to roam information 1813 * @eBssType: [in] type of BSS 1814 * 1815 * Return: QDF_STATUS enumeration 1816 */ 1817 QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter, 1818 struct csr_roam_info *roam_info, 1819 eCsrRoamBssType eBssType) 1820 { 1821 uint8_t uapsdMask; 1822 QDF_STATUS status; 1823 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); 1824 1825 /* when we associate we need to notify TL if it needs to 1826 * enable UAPSD for any access categories 1827 */ 1828 1829 hdd_enter(); 1830 1831 if (roam_info->fReassocReq) { 1832 /* when we reassociate we should continue to use 1833 * whatever parameters were previously established. 1834 * if we are reassociating due to a U-APSD change for 1835 * a particular Access Category, then the change will 1836 * be communicated to HDD via the QoS callback 1837 * associated with the given flow, and U-APSD 1838 * parameters will be updated there 1839 */ 1840 1841 hdd_debug("Reassoc so no work, Exiting"); 1842 1843 return QDF_STATUS_SUCCESS; 1844 } 1845 /* get the negotiated UAPSD Mask */ 1846 uapsdMask = 1847 roam_info->u.pConnectedProfile->modifyProfileFields.uapsd_mask; 1848 1849 hdd_debug("U-APSD mask is 0x%02x", (int)uapsdMask); 1850 1851 if (uapsdMask & HDD_AC_VO) { 1852 status = 1853 sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR 1854 (adapter))->conn_info.staId[0], 1855 SME_AC_VO, 7, 7, 1856 hdd_ctx->config->InfraUapsdVoSrvIntv, 1857 hdd_ctx->config->InfraUapsdVoSuspIntv, 1858 SME_QOS_WMM_TS_DIR_BOTH, 1, 1859 adapter->session_id, 1860 hdd_ctx->config->DelayedTriggerFrmInt); 1861 1862 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); 1863 } 1864 1865 if (uapsdMask & HDD_AC_VI) { 1866 status = 1867 sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR 1868 (adapter))->conn_info.staId[0], 1869 SME_AC_VI, 5, 5, 1870 hdd_ctx->config->InfraUapsdViSrvIntv, 1871 hdd_ctx->config->InfraUapsdViSuspIntv, 1872 SME_QOS_WMM_TS_DIR_BOTH, 1, 1873 adapter->session_id, 1874 hdd_ctx->config->DelayedTriggerFrmInt); 1875 1876 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); 1877 } 1878 1879 if (uapsdMask & HDD_AC_BK) { 1880 status = 1881 sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR 1882 (adapter))->conn_info.staId[0], 1883 SME_AC_BK, 2, 2, 1884 hdd_ctx->config->InfraUapsdBkSrvIntv, 1885 hdd_ctx->config->InfraUapsdBkSuspIntv, 1886 SME_QOS_WMM_TS_DIR_BOTH, 1, 1887 adapter->session_id, 1888 hdd_ctx->config->DelayedTriggerFrmInt); 1889 1890 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); 1891 } 1892 1893 if (uapsdMask & HDD_AC_BE) { 1894 status = 1895 sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR 1896 (adapter))->conn_info.staId[0], 1897 SME_AC_BE, 3, 3, 1898 hdd_ctx->config->InfraUapsdBeSrvIntv, 1899 hdd_ctx->config->InfraUapsdBeSuspIntv, 1900 SME_QOS_WMM_TS_DIR_BOTH, 1, 1901 adapter->session_id, 1902 hdd_ctx->config->DelayedTriggerFrmInt); 1903 1904 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); 1905 } 1906 1907 status = sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle, 1908 adapter->dscp_to_up_map, 1909 adapter->session_id); 1910 1911 if (!QDF_IS_STATUS_SUCCESS(status)) 1912 hdd_wmm_init(adapter); 1913 1914 hdd_exit(); 1915 1916 return QDF_STATUS_SUCCESS; 1917 } 1918 1919 static const uint8_t acm_mask_bit[WLAN_MAX_AC] = { 1920 0x4, /* SME_AC_BK */ 1921 0x8, /* SME_AC_BE */ 1922 0x2, /* SME_AC_VI */ 1923 0x1 /* SME_AC_VO */ 1924 }; 1925 1926 /** 1927 * hdd_wmm_connect() - Function which will handle the housekeeping 1928 * required by WMM when a connection is established 1929 * 1930 * @adapter : [in] pointer to adapter context 1931 * @roam_info: [in] pointer to roam information 1932 * @eBssType : [in] type of BSS 1933 * 1934 * Return: QDF_STATUS enumeration 1935 */ 1936 QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter, 1937 struct csr_roam_info *roam_info, 1938 eCsrRoamBssType eBssType) 1939 { 1940 int ac; 1941 bool qap; 1942 bool qosConnection; 1943 uint8_t acmMask; 1944 mac_handle_t mac_handle; 1945 1946 hdd_enter(); 1947 1948 if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) && 1949 roam_info && roam_info->u.pConnectedProfile) { 1950 qap = roam_info->u.pConnectedProfile->qap; 1951 qosConnection = roam_info->u.pConnectedProfile->qosConnection; 1952 acmMask = roam_info->u.pConnectedProfile->acm_mask; 1953 } else { 1954 qap = true; 1955 qosConnection = true; 1956 acmMask = 0x0; 1957 } 1958 1959 hdd_debug("qap is %d, qosConnection is %d, acmMask is 0x%x", 1960 qap, qosConnection, acmMask); 1961 1962 adapter->hdd_wmm_status.wmmQap = qap; 1963 adapter->hdd_wmm_status.wmmQosConnection = qosConnection; 1964 mac_handle = hdd_adapter_get_mac_handle(adapter); 1965 1966 for (ac = 0; ac < WLAN_MAX_AC; ac++) { 1967 if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) { 1968 hdd_debug("ac %d on", ac); 1969 1970 /* admission is required */ 1971 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1972 wmmAcAccessRequired = true; 1973 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1974 wmmAcAccessAllowed = false; 1975 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1976 wmmAcAccessGranted = false; 1977 /* after reassoc if we have valid tspec, allow access */ 1978 if (adapter->hdd_wmm_status.wmmAcStatus[ac]. 1979 wmmAcTspecValid 1980 && (adapter->hdd_wmm_status.wmmAcStatus[ac]. 1981 wmmAcTspecInfo.ts_info.direction != 1982 SME_QOS_WMM_TS_DIR_DOWNLINK)) { 1983 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1984 wmmAcAccessAllowed = true; 1985 } 1986 if (!roam_info->fReassocReq && 1987 !sme_neighbor_roam_is11r_assoc( 1988 mac_handle, 1989 adapter->session_id) && 1990 !sme_roam_is_ese_assoc(roam_info)) { 1991 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1992 wmmAcTspecValid = false; 1993 adapter->hdd_wmm_status.wmmAcStatus[ac]. 1994 wmmAcAccessAllowed = false; 1995 } 1996 } else { 1997 hdd_debug("ac %d off", ac); 1998 /* admission is not required so access is allowed */ 1999 adapter->hdd_wmm_status.wmmAcStatus[ac]. 2000 wmmAcAccessRequired = false; 2001 adapter->hdd_wmm_status.wmmAcStatus[ac]. 2002 wmmAcAccessAllowed = true; 2003 } 2004 2005 } 2006 2007 hdd_exit(); 2008 2009 return QDF_STATUS_SUCCESS; 2010 } 2011 2012 /** 2013 * hdd_wmm_get_uapsd_mask() - Function which will calculate the 2014 * initial value of the UAPSD mask based upon the device configuration 2015 * 2016 * @adapter : [in] pointer to adapter context 2017 * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored 2018 * 2019 * Return: QDF_STATUS enumeration 2020 */ 2021 QDF_STATUS hdd_wmm_get_uapsd_mask(struct hdd_adapter *adapter, 2022 uint8_t *pUapsdMask) 2023 { 2024 uint8_t uapsdMask; 2025 2026 if (HDD_WMM_USER_MODE_NO_QOS == 2027 (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) { 2028 /* no QOS then no UAPSD */ 2029 uapsdMask = 0; 2030 } else { 2031 /* start with the default mask */ 2032 uapsdMask = (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask; 2033 2034 /* disable UAPSD for any ACs with a 0 Service Interval */ 2035 if ((WLAN_HDD_GET_CTX(adapter))->config-> 2036 InfraUapsdVoSrvIntv == 0) { 2037 uapsdMask &= ~HDD_AC_VO; 2038 } 2039 2040 if ((WLAN_HDD_GET_CTX(adapter))->config-> 2041 InfraUapsdViSrvIntv == 0) { 2042 uapsdMask &= ~HDD_AC_VI; 2043 } 2044 2045 if ((WLAN_HDD_GET_CTX(adapter))->config-> 2046 InfraUapsdBkSrvIntv == 0) { 2047 uapsdMask &= ~HDD_AC_BK; 2048 } 2049 2050 if ((WLAN_HDD_GET_CTX(adapter))->config-> 2051 InfraUapsdBeSrvIntv == 0) { 2052 uapsdMask &= ~HDD_AC_BE; 2053 } 2054 } 2055 2056 /* return calculated mask */ 2057 *pUapsdMask = uapsdMask; 2058 return QDF_STATUS_SUCCESS; 2059 } 2060 2061 /** 2062 * hdd_wmm_is_active() - Function which will determine if WMM is 2063 * active on the current connection 2064 * 2065 * @adapter: [in] pointer to adapter context 2066 * 2067 * Return: true if WMM is enabled, false if WMM is not enabled 2068 */ 2069 bool hdd_wmm_is_active(struct hdd_adapter *adapter) 2070 { 2071 if ((!adapter->hdd_wmm_status.wmmQosConnection) || 2072 (!adapter->hdd_wmm_status.wmmQap)) { 2073 return false; 2074 } else { 2075 return true; 2076 } 2077 } 2078 2079 bool hdd_wmm_is_acm_allowed(struct wlan_objmgr_vdev **vdev) 2080 { 2081 struct hdd_adapter *adapter; 2082 struct hdd_wmm_ac_status *wmm_ac_status; 2083 2084 2085 adapter = container_of(vdev, struct hdd_adapter, hdd_vdev); 2086 if (NULL == adapter) { 2087 hdd_err("failed, hdd adapter is NULL"); 2088 return false; 2089 } 2090 wmm_ac_status = adapter->hdd_wmm_status.wmmAcStatus; 2091 2092 if (hdd_wmm_is_active(adapter) && 2093 !(wmm_ac_status[OL_TX_WMM_AC_VI].wmmAcAccessAllowed)) 2094 return false; 2095 return true; 2096 } 2097 2098 /** 2099 * hdd_wmm_addts() - Function which will add a traffic spec at the 2100 * request of an application 2101 * 2102 * @adapter : [in] pointer to adapter context 2103 * @handle : [in] handle to uniquely identify a TS 2104 * @pTspec : [in] pointer to the traffic spec 2105 * 2106 * Return: HDD_WLAN_WMM_STATUS_* 2107 */ 2108 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter, 2109 uint32_t handle, 2110 struct sme_qos_wmmtspecinfo *pTspec) 2111 { 2112 struct hdd_wmm_qos_context *pQosContext; 2113 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; 2114 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 2115 enum sme_qos_statustype smeStatus; 2116 #endif 2117 bool found = false; 2118 mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); 2119 2120 hdd_debug("Entered with handle 0x%x", handle); 2121 2122 /* see if a context already exists with the given handle */ 2123 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2124 list_for_each_entry(pQosContext, 2125 &adapter->hdd_wmm_status.wmmContextList, node) { 2126 if (pQosContext->handle == handle) { 2127 found = true; 2128 break; 2129 } 2130 } 2131 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2132 if (found) { 2133 /* record with that handle already exists */ 2134 hdd_err("Record already exists with handle 0x%x", handle); 2135 2136 /* Application is trying to modify some of the Tspec 2137 * params. Allow it 2138 */ 2139 smeStatus = sme_qos_modify_req(mac_handle, 2140 pTspec, pQosContext->qosFlowId); 2141 2142 /* need to check the return value and act appropriately */ 2143 switch (smeStatus) { 2144 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: 2145 status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING; 2146 break; 2147 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: 2148 status = 2149 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; 2150 break; 2151 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: 2152 status = 2153 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; 2154 break; 2155 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: 2156 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; 2157 break; 2158 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: 2159 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED; 2160 break; 2161 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: 2162 status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; 2163 break; 2164 default: 2165 /* we didn't get back one of the 2166 * SME_QOS_STATUS_MODIFY_* status codes 2167 */ 2168 hdd_err("unexpected SME Status=%d", 2169 smeStatus); 2170 QDF_ASSERT(0); 2171 return HDD_WLAN_WMM_STATUS_MODIFY_FAILED; 2172 } 2173 2174 /* we were successful, save the status */ 2175 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2176 if (pQosContext->magic == HDD_WMM_CTX_MAGIC) 2177 pQosContext->lastStatus = status; 2178 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2179 2180 return status; 2181 } 2182 2183 pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); 2184 if (NULL == pQosContext) { 2185 /* no memory for QoS context. Nothing we can do */ 2186 hdd_err("Unable to allocate QoS context"); 2187 return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE; 2188 } 2189 /* we assume the tspec has already been validated by the caller */ 2190 2191 pQosContext->handle = handle; 2192 if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE) 2193 pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up]; 2194 else { 2195 hdd_err("ts_info.up (%d) larger than max value (%d), use default acType (%d)", 2196 pTspec->ts_info.up, 2197 HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]); 2198 pQosContext->acType = hdd_wmm_up_to_ac_map[0]; 2199 } 2200 pQosContext->adapter = adapter; 2201 pQosContext->qosFlowId = 0; 2202 pQosContext->magic = HDD_WMM_CTX_MAGIC; 2203 pQosContext->is_inactivity_timer_running = false; 2204 2205 hdd_debug("Setting up QoS, context %pK", pQosContext); 2206 2207 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2208 list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList); 2209 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2210 2211 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 2212 smeStatus = sme_qos_setup_req(mac_handle, 2213 adapter->session_id, 2214 pTspec, 2215 hdd_wmm_sme_callback, 2216 pQosContext, 2217 pTspec->ts_info.up, 2218 &pQosContext->qosFlowId); 2219 2220 hdd_debug("sme_qos_setup_req returned %d flowid %d", 2221 smeStatus, pQosContext->qosFlowId); 2222 2223 /* need to check the return value and act appropriately */ 2224 switch (smeStatus) { 2225 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: 2226 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; 2227 break; 2228 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: 2229 status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; 2230 break; 2231 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: 2232 status = 2233 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; 2234 break; 2235 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: 2236 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; 2237 break; 2238 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: 2239 /* disable the inactivity timer */ 2240 hdd_wmm_disable_inactivity_timer(pQosContext); 2241 hdd_wmm_free_context(pQosContext); 2242 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; 2243 case SME_QOS_STATUS_SETUP_FAILURE_RSP: 2244 /* disable the inactivity timer */ 2245 hdd_wmm_disable_inactivity_timer(pQosContext); 2246 /* we can't tell the difference between when a request 2247 * fails because AP rejected it versus when SME 2248 * encounterd an internal error 2249 */ 2250 hdd_wmm_free_context(pQosContext); 2251 return HDD_WLAN_WMM_STATUS_SETUP_FAILED; 2252 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: 2253 /* disable the inactivity timer */ 2254 hdd_wmm_disable_inactivity_timer(pQosContext); 2255 hdd_wmm_free_context(pQosContext); 2256 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; 2257 default: 2258 /* disable the inactivity timer */ 2259 hdd_wmm_disable_inactivity_timer(pQosContext); 2260 /* we didn't get back one of the 2261 * SME_QOS_STATUS_SETUP_* status codes 2262 */ 2263 hdd_wmm_free_context(pQosContext); 2264 hdd_err("unexpected SME Status=%d", smeStatus); 2265 QDF_ASSERT(0); 2266 return HDD_WLAN_WMM_STATUS_SETUP_FAILED; 2267 } 2268 #endif 2269 2270 /* we were successful, save the status */ 2271 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2272 if (pQosContext->magic == HDD_WMM_CTX_MAGIC) 2273 pQosContext->lastStatus = status; 2274 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2275 2276 return status; 2277 } 2278 2279 /** 2280 * hdd_wmm_delts() - Function which will delete a traffic spec at the 2281 * request of an application 2282 * 2283 * @adapter: [in] pointer to adapter context 2284 * @handle: [in] handle to uniquely identify a TS 2285 * 2286 * Return: HDD_WLAN_WMM_STATUS_* 2287 */ 2288 hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter, 2289 uint32_t handle) 2290 { 2291 struct hdd_wmm_qos_context *pQosContext; 2292 bool found = false; 2293 sme_ac_enum_type acType = 0; 2294 uint32_t qosFlowId = 0; 2295 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; 2296 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 2297 enum sme_qos_statustype smeStatus; 2298 mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); 2299 #endif 2300 2301 hdd_debug("Entered with handle 0x%x", handle); 2302 2303 /* locate the context with the given handle */ 2304 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2305 list_for_each_entry(pQosContext, 2306 &adapter->hdd_wmm_status.wmmContextList, node) { 2307 if (pQosContext->handle == handle) { 2308 found = true; 2309 acType = pQosContext->acType; 2310 qosFlowId = pQosContext->qosFlowId; 2311 break; 2312 } 2313 } 2314 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2315 2316 if (false == found) { 2317 /* we didn't find the handle */ 2318 hdd_info("handle 0x%x not found", handle); 2319 return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; 2320 } 2321 2322 hdd_debug("found handle 0x%x, flow %d, AC %d, context %pK", 2323 handle, qosFlowId, acType, pQosContext); 2324 2325 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 2326 smeStatus = sme_qos_release_req(mac_handle, adapter->session_id, 2327 qosFlowId); 2328 2329 hdd_debug("SME flow %d released, SME status %d", qosFlowId, smeStatus); 2330 2331 switch (smeStatus) { 2332 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: 2333 /* this flow is the only one on that AC, so go ahead 2334 * and update our TSPEC state for the AC 2335 */ 2336 adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcTspecValid = 2337 false; 2338 adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed = 2339 false; 2340 2341 /* need to tell TL to stop trigger timer, etc */ 2342 hdd_wmm_disable_tl_uapsd(pQosContext); 2343 2344 /* disable the inactivity timer */ 2345 hdd_wmm_disable_inactivity_timer(pQosContext); 2346 2347 /* we are done with this context */ 2348 hdd_wmm_free_context(pQosContext); 2349 2350 /* SME must not fire any more callbacks for this flow 2351 * since the context is no longer valid 2352 */ 2353 2354 return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; 2355 2356 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: 2357 /* do nothing as we will get a response from SME */ 2358 status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING; 2359 break; 2360 2361 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: 2362 /* nothing we can do with the existing flow except leave it */ 2363 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; 2364 break; 2365 2366 case SME_QOS_STATUS_RELEASE_FAILURE_RSP: 2367 /* nothing we can do with the existing flow except leave it */ 2368 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; 2369 break; 2370 2371 default: 2372 /* we didn't get back one of the 2373 * SME_QOS_STATUS_RELEASE_* status codes 2374 */ 2375 hdd_err("unexpected SME Status=%d", smeStatus); 2376 QDF_ASSERT(0); 2377 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; 2378 } 2379 2380 #endif 2381 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2382 if (pQosContext->magic == HDD_WMM_CTX_MAGIC) 2383 pQosContext->lastStatus = status; 2384 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2385 2386 return status; 2387 } 2388 2389 /** 2390 * hdd_wmm_checkts() - Function which will return the status of a traffic 2391 * spec at the request of an application 2392 * 2393 * @adapter: [in] pointer to adapter context 2394 * @handle: [in] handle to uniquely identify a TS 2395 * 2396 * Return: HDD_WLAN_WMM_STATUS_* 2397 */ 2398 hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, uint32_t handle) 2399 { 2400 struct hdd_wmm_qos_context *pQosContext; 2401 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST; 2402 2403 hdd_debug("Entered with handle 0x%x", handle); 2404 2405 /* locate the context with the given handle */ 2406 mutex_lock(&adapter->hdd_wmm_status.wmmLock); 2407 list_for_each_entry(pQosContext, 2408 &adapter->hdd_wmm_status.wmmContextList, node) { 2409 if (pQosContext->handle == handle) { 2410 hdd_debug("found handle 0x%x, context %pK", 2411 handle, pQosContext); 2412 2413 status = pQosContext->lastStatus; 2414 break; 2415 } 2416 } 2417 mutex_unlock(&adapter->hdd_wmm_status.wmmLock); 2418 return status; 2419 } 2420