prima: WLAN Driver Release 3.1.7.9
This is the initial release of the Prima WLAN Driver
diff --git a/CORE/HDD/src/wlan_hdd_wmm.c b/CORE/HDD/src/wlan_hdd_wmm.c
new file mode 100644
index 0000000..c8da218
--- /dev/null
+++ b/CORE/HDD/src/wlan_hdd_wmm.c
@@ -0,0 +1,2501 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*============================================================================
+ @file wlan_hdd_wmm.c
+
+ This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
+ houses all the logic for WMM in HDD.
+
+ On the control path, it has the logic to setup QoS, modify QoS and delete
+ QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
+ explicit application invoked and an internal HDD invoked. The implicit QoS
+ is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
+ which DO mark their traffic for priortization. It also has logic to start,
+ update and stop the U-APSD trigger frame generation. It also has logic to
+ read WMM related config parameters from the registry.
+
+ On the data path, it has the logic to figure out the WMM AC of an egress
+ packet and when to signal TL to serve a particular AC queue. It also has the
+ logic to retrieve a packet based on WMM priority in response to a fetch from
+ TL.
+
+ The remaining functions are utility functions for information hiding.
+
+
+ Copyright (c) 2008-9 QUALCOMM Incorporated.
+ All Rights Reserved.
+ Qualcomm Confidential and Proprietary
+============================================================================*/
+
+/*---------------------------------------------------------------------------
+ Include files
+ -------------------------------------------------------------------------*/
+#include <wlan_hdd_tx_rx.h>
+#include <wlan_hdd_dp_utils.h>
+#include <wlan_hdd_wmm.h>
+#include <wlan_hdd_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/semaphore.h>
+#include <wlan_hdd_hostapd.h>
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+#include <wlan_hdd_softap_tx_rx.h>
+#endif
+
+// change logging behavior based upon debug flag
+#ifdef HDD_WMM_DEBUG
+#define WMM_TRACE_LEVEL_FATAL VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_ERROR VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_WARN VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_INFO VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_INFO_HIGH VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_INFO_LOW VOS_TRACE_LEVEL_FATAL
+#else
+#define WMM_TRACE_LEVEL_FATAL VOS_TRACE_LEVEL_FATAL
+#define WMM_TRACE_LEVEL_ERROR VOS_TRACE_LEVEL_ERROR
+#define WMM_TRACE_LEVEL_WARN VOS_TRACE_LEVEL_WARN
+#define WMM_TRACE_LEVEL_INFO VOS_TRACE_LEVEL_INFO
+#define WMM_TRACE_LEVEL_INFO_HIGH VOS_TRACE_LEVEL_INFO_HIGH
+#define WMM_TRACE_LEVEL_INFO_LOW VOS_TRACE_LEVEL_INFO_LOW
+#endif
+
+
+// UAPSD Mask bits
+// (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored)
+#define HDD_AC_VO 0x1
+#define HDD_AC_VI 0x2
+#define HDD_AC_BK 0x4
+#define HDD_AC_BE 0x8
+
+#define WLAN_HDD_MAX_DSCP 0x3f
+
+static sme_QosWmmUpType hddWmmDscpToUpMap[WLAN_HDD_MAX_DSCP+1];
+
+const v_U8_t hddWmmUpToAcMap[] = {
+ WLANTL_AC_BE,
+ WLANTL_AC_BK,
+ WLANTL_AC_BK,
+ WLANTL_AC_BE,
+ WLANTL_AC_VI,
+ WLANTL_AC_VI,
+ WLANTL_AC_VO,
+ WLANTL_AC_VO
+};
+
+//Linux based UP -> AC Mapping
+const v_U8_t hddLinuxUpToAcMap[8] = {
+ HDD_LINUX_AC_BE,
+ HDD_LINUX_AC_BK,
+ HDD_LINUX_AC_BK,
+ HDD_LINUX_AC_BE,
+ HDD_LINUX_AC_VI,
+ HDD_LINUX_AC_VI,
+ HDD_LINUX_AC_VO,
+ HDD_LINUX_AC_VO
+};
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+/**
+ @brief hdd_wmm_enable_tl_uapsd() - function which decides whether and
+ how to update UAPSD parameters in TL
+
+ @param pQosContext : [in] the pointer the QoS instance control block
+
+ @return
+ None
+*/
+static void hdd_wmm_enable_tl_uapsd (hdd_wmm_qos_context_t* pQosContext)
+{
+ hdd_adapter_t* pAdapter = pQosContext->pAdapter;
+ WLANTL_ACEnumType acType = pQosContext->acType;
+ hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+ VOS_STATUS status;
+ v_U32_t service_interval;
+ v_U32_t suspension_interval;
+ sme_QosWmmDirType direction;
+
+
+ // The TSPEC must be valid
+ if (pAc->wmmAcTspecValid == VOS_FALSE)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Invoked with invalid TSPEC",
+ __FUNCTION__);
+ return;
+ }
+
+ // determine the service interval
+ if (pAc->wmmAcTspecInfo.min_service_interval)
+ {
+ service_interval = pAc->wmmAcTspecInfo.min_service_interval;
+ }
+ else if (pAc->wmmAcTspecInfo.max_service_interval)
+ {
+ service_interval = pAc->wmmAcTspecInfo.max_service_interval;
+ }
+ else
+ {
+ // no service interval is present in the TSPEC
+ // this is OK, there just won't be U-APSD
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: No service interval supplied",
+ __FUNCTION__);
+ return;
+ }
+
+ // determine the suspension interval & direction
+ suspension_interval = pAc->wmmAcTspecInfo.suspension_interval;
+ direction = pAc->wmmAcTspecInfo.ts_info.direction;
+
+ // if we have previously enabled U-APSD, have any params changed?
+ if ((pAc->wmmAcUapsdInfoValid) &&
+ (pAc->wmmAcUapsdServiceInterval == service_interval) &&
+ (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) &&
+ (pAc->wmmAcUapsdDirection == direction))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: No change in U-APSD parameters",
+ __FUNCTION__);
+ return;
+ }
+
+ // are we in the appropriate power save modes?
+ if (!sme_IsPowerSaveEnabled(WLAN_HDD_GET_HAL_CTX(pAdapter), ePMC_BEACON_MODE_POWER_SAVE))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: BMPS is not enabled",
+ __FUNCTION__);
+ return;
+ }
+
+ if (!sme_IsPowerSaveEnabled(WLAN_HDD_GET_HAL_CTX(pAdapter), ePMC_UAPSD_MODE_POWER_SAVE))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: U-APSD is not enabled",
+ __FUNCTION__);
+ return;
+ }
+
+ // everything is in place to notify TL
+ status = WLANTL_EnableUAPSDForAC((WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType,
+ pAc->wmmAcTspecInfo.ts_info.tid,
+ pAc->wmmAcTspecInfo.ts_info.up,
+ service_interval,
+ suspension_interval,
+ direction);
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to enable U-APSD for AC=%d",
+ __FUNCTION__, acType );
+ return;
+ }
+
+ // stash away the parameters that were used
+ pAc->wmmAcUapsdInfoValid = VOS_TRUE;
+ pAc->wmmAcUapsdServiceInterval = service_interval;
+ pAc->wmmAcUapsdSuspensionInterval = suspension_interval;
+ pAc->wmmAcUapsdDirection = direction;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Enabled UAPSD in TL srv_int=%ld "
+ "susp_int=%ld dir=%d AC=%d",
+ __FUNCTION__,
+ service_interval,
+ suspension_interval,
+ direction,
+ acType);
+
+}
+
+/**
+ @brief hdd_wmm_disable_tl_uapsd() - function which decides whether
+ to disable UAPSD parameters in TL
+
+ @param pQosContext : [in] the pointer the QoS instance control block
+
+ @return
+ None
+*/
+static void hdd_wmm_disable_tl_uapsd (hdd_wmm_qos_context_t* pQosContext)
+{
+ hdd_adapter_t* pAdapter = pQosContext->pAdapter;
+ WLANTL_ACEnumType acType = pQosContext->acType;
+ hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+ VOS_STATUS status;
+
+
+ // have we previously enabled UAPSD?
+ if (pAc->wmmAcUapsdInfoValid == VOS_TRUE)
+ {
+ status = WLANTL_DisableUAPSDForAC((WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType);
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to disable U-APSD for AC=%d",
+ __FUNCTION__, acType );
+ }
+ else
+ {
+ // TL no longer has valid UAPSD info
+ pAc->wmmAcUapsdInfoValid = VOS_FALSE;
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Disabled UAPSD in TL for AC=%d",
+ __FUNCTION__,
+ acType);
+ }
+ }
+}
+
+#endif
+
+/**
+ @brief hdd_wmm_free_context() - function which frees a QoS context
+
+ @param pQosContext : [in] the pointer the QoS instance control block
+
+ @return
+ None
+*/
+static void hdd_wmm_free_context (hdd_wmm_qos_context_t* pQosContext)
+{
+ hdd_adapter_t* pAdapter;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered, context %p",
+ __FUNCTION__, pQosContext);
+
+ if (unlikely((NULL == pQosContext) ||
+ (HDD_WMM_CTX_MAGIC != pQosContext->magic)))
+ {
+ // must have been freed in another thread
+ return;
+ }
+
+ // get pointer to the adapter context
+ pAdapter = pQosContext->pAdapter;
+
+ // take the wmmLock since we're manipulating the context list
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+
+ // make sure nobody thinks this is a valid context
+ pQosContext->magic = 0;
+
+ // unlink the context
+ list_del(&pQosContext->node);
+
+ // done manipulating the list
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+
+ // reclaim memory
+ kfree(pQosContext);
+
+}
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+/**
+ @brief hdd_wmm_notify_app() - function which notifies an application
+ changes in state of it flow
+
+ @param pQosContext : [in] the pointer the QoS instance control block
+
+ @return
+ None
+*/
+#define MAX_NOTIFY_LEN 50
+static void hdd_wmm_notify_app (hdd_wmm_qos_context_t* pQosContext)
+{
+ hdd_adapter_t* pAdapter;
+ union iwreq_data wrqu;
+ char buf[MAX_NOTIFY_LEN+1];
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered, context %p",
+ __FUNCTION__, pQosContext);
+
+ if (unlikely((NULL == pQosContext) ||
+ (HDD_WMM_CTX_MAGIC != pQosContext->magic)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Invalid QoS Context",
+ __FUNCTION__);
+ return;
+ }
+
+
+ // create the event
+ memset(&wrqu, 0, sizeof(wrqu));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]",
+ (unsigned int)pQosContext->handle,
+ (unsigned int)pQosContext->lastStatus);
+
+ wrqu.data.pointer = buf;
+ wrqu.data.length = strlen(buf);
+
+ // get pointer to the adapter
+ pAdapter = pQosContext->pAdapter;
+
+ // send the event
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Sending [%s]", __FUNCTION__, buf);
+ wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
+}
+
+
+/**
+ @brief hdd_wmm_is_access_allowed() - function which determines if access
+ is allowed for the given AC. this is designed to be called during SME
+ callback processing since that is when access can be granted or removed
+
+ @param pAdapter : [in] pointer to adapter context
+ @param pAc : [in] pointer to the per-AC status
+
+ @return : VOS_TRUE - access is allowed
+ : VOS_FALSE - access is not allowed
+ None
+*/
+static v_BOOL_t hdd_wmm_is_access_allowed(hdd_adapter_t* pAdapter,
+ hdd_wmm_ac_status_t* pAc)
+{
+ // if we don't want QoS or the AP doesn't support QoS
+ // or we don't want to do implicit QoS
+ // or if AP doesn't require admission for this AC
+ // then we have access
+ if (!hdd_wmm_is_active(pAdapter) ||
+ !(WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->bImplicitQosEnabled ||
+ !pAc->wmmAcAccessRequired)
+ {
+ return VOS_TRUE;
+ }
+
+ // if implicit QoS has already completed, successfully or not,
+ // then access is allowed
+ if (pAc->wmmAcAccessGranted || pAc->wmmAcAccessFailed)
+ {
+ return VOS_TRUE;
+ }
+
+ // admission is required and implicit QoS hasn't completed
+ // however explicit QoS may have completed and we'll have
+ // a Tspec
+ // if we don't have a Tspec then access is not allowed
+ if (!pAc->wmmAcTspecValid)
+ {
+ return VOS_FALSE;
+ }
+
+ // we have a Tspec -- does it allow upstream or bidirectional traffic?
+ // if it only allows downstream traffic then access is not allowed
+ if (pAc->wmmAcTspecInfo.ts_info.direction == SME_QOS_WMM_TS_DIR_DOWNLINK)
+ {
+ return VOS_FALSE;
+ }
+
+ // we meet all of the criteria for access
+ return VOS_TRUE;
+}
+
+#ifdef FEATURE_WLAN_CCX
+/**
+ @brief hdd_wmm_inactivity_timer_cb() - timer handler function which is
+ called for every inactivity interval per AC. This function gets the
+ current transmitted packets on the given AC, and checks if there where
+ any TX activity from the previous interval. If there was no traffic
+ then it would delete the TS that was negotiated on that AC.
+
+ @param pUserData : [in] pointer to pQosContext
+
+ @return : NONE
+*/
+void hdd_wmm_inactivity_timer_cb( v_PVOID_t pUserData )
+{
+ hdd_wmm_qos_context_t* pQosContext = (hdd_wmm_qos_context_t*)pUserData;
+ hdd_adapter_t* pAdapter;
+ hdd_wmm_ac_status_t *pAc;
+ hdd_wlan_wmm_status_e status;
+ VOS_STATUS vos_status;
+ v_U32_t currentTrafficCnt = 0;
+ WLANTL_ACEnumType acType = pQosContext->acType;
+
+ pAdapter = pQosContext->pAdapter;
+ pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+
+ // Get the Tx stats for this AC.
+ currentTrafficCnt = pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->acType];
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
+ FL("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d\n"),
+ acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt);
+ if (pAc->wmmPrevTrafficCnt == currentTrafficCnt)
+ {
+ // If there is no traffic activity, delete the TSPEC for this AC
+ status = hdd_wmm_delts(pAdapter, pQosContext->handle);
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
+ FL("Deleted TS on AC %d, due to inactivity with status = %d!!!"),
+ acType, status);
+ }
+ else
+ {
+ pAc->wmmPrevTrafficCnt = currentTrafficCnt;
+ if (pAc->wmmInactivityTimer.state == VOS_TIMER_STATE_STOPPED)
+ {
+ // Restart the timer
+ vos_status = vos_timer_start(&pAc->wmmInactivityTimer, pAc->wmmInactivityTime);
+ if (!VOS_IS_STATUS_SUCCESS(vos_status))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("Restarting inactivity timer failed on AC %d"), acType);
+ }
+ }
+ else
+ {
+ VOS_ASSERT(vos_timer_getCurrentState(
+ &pAc->wmmInactivityTimer) == VOS_TIMER_STATE_STOPPED);
+ }
+ }
+
+ return;
+}
+
+
+/**
+ @brief hdd_wmm_enable_inactivity_timer() - function to enable the
+ traffic inactivity timer for the given AC, if the inactivity_interval
+ specified in the ADDTS parameters is non-zero
+
+ @param pQosContext : [in] pointer to pQosContext
+ @param inactivityTime: [in] value of the inactivity interval in millisecs
+
+ @return : VOS_STATUS_E_FAILURE
+ VOS_STATUS_SUCCESS
+*/
+VOS_STATUS hdd_wmm_enable_inactivity_timer(hdd_wmm_qos_context_t* pQosContext, v_U32_t inactivityTime)
+{
+ VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
+ hdd_adapter_t* pAdapter = pQosContext->pAdapter;
+ WLANTL_ACEnumType acType = pQosContext->acType;
+ hdd_wmm_ac_status_t *pAc;
+
+ pAdapter = pQosContext->pAdapter;
+ pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+
+
+ // If QoS-Tspec is successfully setup and if the inactivity timer is non-zero,
+ // a traffic inactivity timer needs to be started for the given AC
+ vos_status = vos_timer_init(
+ &pAc->wmmInactivityTimer,
+ VOS_TIMER_TYPE_SW,
+ hdd_wmm_inactivity_timer_cb,
+ (v_PVOID_t)pQosContext );
+ if ( !VOS_IS_STATUS_SUCCESS(vos_status))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("Initializing inactivity timer failed on AC %d"), acType);
+ return vos_status;
+ }
+
+ // Start the inactivity timer
+ vos_status = vos_timer_start(
+ &pAc->wmmInactivityTimer,
+ inactivityTime);
+ if ( !VOS_IS_STATUS_SUCCESS(vos_status))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("Starting inactivity timer failed on AC %d"), acType);
+ return vos_status;
+ }
+ pAc->wmmInactivityTime = inactivityTime;
+ // Initialize the current tx traffic count on this AC
+ pAc->wmmPrevTrafficCnt = pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->acType];
+
+ return vos_status;
+}
+
+/**
+ @brief hdd_wmm_enable_inactivity_timer() - function to disable the
+ traffic inactivity timer for the given AC. This would be called when
+ deleting the TS.
+
+ @param pQosContext : [in] pointer to pQosContext
+
+ @return : VOS_STATUS_E_FAILURE
+ VOS_STATUS_SUCCESS
+*/
+VOS_STATUS hdd_wmm_disable_inactivity_timer(hdd_wmm_qos_context_t* pQosContext)
+{
+ hdd_adapter_t* pAdapter = pQosContext->pAdapter;
+ WLANTL_ACEnumType acType = pQosContext->acType;
+ hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+ VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
+
+ // Clear the timer and the counter
+ pAc->wmmInactivityTime = 0;
+ pAc->wmmPrevTrafficCnt = 0;
+ vos_timer_stop(&pAc->wmmInactivityTimer);
+ vos_status = vos_timer_destroy(&pAc->wmmInactivityTimer);
+
+ return vos_status;
+}
+#endif // FEATURE_WLAN_CCX
+
+/**
+ @brief hdd_wmm_sme_callback() - callback registered by HDD with SME for receiving
+ QoS notifications. Even though this function has a static scope it gets called
+ externally through some function pointer magic (so there is a need for
+ rigorous parameter checking)
+
+ @param hHal : [in] the HAL handle
+ @param HddCtx : [in] the HDD specified handle
+ @param pCurrentQosInfo : [in] the TSPEC params
+ @param SmeStatus : [in] the QoS related SME status
+
+ @return
+ eHAL_STATUS_SUCCESS if all good, eHAL_STATUS_FAILURE otherwise
+*/
+static eHalStatus hdd_wmm_sme_callback (tHalHandle hHal,
+ void * hddCtx,
+ sme_QosWmmTspecInfo* pCurrentQosInfo,
+ sme_QosStatusType smeStatus,
+ v_U32_t qosFlowId)
+{
+ hdd_wmm_qos_context_t* pQosContext = hddCtx;
+ hdd_adapter_t* pAdapter;
+ WLANTL_ACEnumType acType;
+ hdd_wmm_ac_status_t *pAc;
+ VOS_STATUS status;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered, context %p",
+ __FUNCTION__, pQosContext);
+
+ if (unlikely((NULL == pQosContext) ||
+ (HDD_WMM_CTX_MAGIC != pQosContext->magic)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Invalid QoS Context",
+ __FUNCTION__);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ pAdapter = pQosContext->pAdapter;
+ acType = pQosContext->acType;
+ pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: status %d flowid %d info %p",
+ __FUNCTION__, smeStatus, qosFlowId, pCurrentQosInfo);
+
+ switch (smeStatus)
+ {
+
+ case SME_QOS_STATUS_SETUP_SUCCESS_IND:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Setup is complete",
+ __FUNCTION__);
+
+ // there will always be a TSPEC returned with this status, even if
+ // a TSPEC is not exchanged OTA
+ if (pCurrentQosInfo)
+ {
+ pAc->wmmAcTspecValid = VOS_TRUE;
+ memcpy(&pAc->wmmAcTspecInfo,
+ pCurrentQosInfo,
+ sizeof(pAc->wmmAcTspecInfo));
+ }
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL for TL AC %d",
+ __FUNCTION__, acType);
+
+ // this was triggered by implicit QoS so we know packets are pending
+ // update state
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+ pAc->wmmAcAccessGranted = VOS_TRUE;
+ pAc->wmmAcAccessPending = VOS_FALSE;
+
+ // notify TL that packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+#ifdef FEATURE_WLAN_CCX
+ // Check if the inactivity interval is specified
+ if (pCurrentQosInfo->inactivity_interval) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Inactivity timer value = %d for AC=%d\n",
+ __FUNCTION__, pCurrentQosInfo->inactivity_interval, acType);
+ hdd_wmm_enable_inactivity_timer(pQosContext, pCurrentQosInfo->inactivity_interval);
+ }
+#endif // FEATURE_WLAN_CCX
+
+ // notify TL to enable trigger frames if necessary
+ hdd_wmm_enable_tl_uapsd(pQosContext);
+
+ break;
+
+ case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Setup is complete (U-APSD set previously)",
+ __FUNCTION__);
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL",
+ __FUNCTION__);
+
+ // this was triggered by implicit QoS so we know packets are pending
+ // update state
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+ pAc->wmmAcAccessGranted = VOS_TRUE;
+ pAc->wmmAcAccessPending = VOS_FALSE;
+
+ // notify TL that packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ break;
+
+ case SME_QOS_STATUS_SETUP_FAILURE_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Setup failed",
+ __FUNCTION__);
+ // QoS setup failed
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL",
+ __FUNCTION__);
+
+ // we note the failure, but we also mark access as allowed so that
+ // the packets will flow. Note that the MAC will "do the right thing"
+ pAc->wmmAcAccessPending = VOS_FALSE;
+ pAc->wmmAcAccessFailed = VOS_TRUE;
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+
+ // this was triggered by implicit QoS so we know packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ /* Setting up QoS Failed, QoS context can be released.
+ * SME is releasing this flow information and if HDD doen't release this context,
+ * next time if application uses the same handle to set-up QoS, HDD (as it has
+ * QoS context for this handle) will issue Modify QoS request to SME but SME will
+ * reject as no it has no information for this flow.
+ */
+ hdd_wmm_free_context(pQosContext);
+ break;
+
+ case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Setup Invalid Params, notify TL",
+ __FUNCTION__);
+ // QoS setup failed
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL",
+ __FUNCTION__);
+
+ // we note the failure, but we also mark access as allowed so that
+ // the packets will flow. Note that the MAC will "do the right thing"
+ pAc->wmmAcAccessPending = VOS_FALSE;
+ pAc->wmmAcAccessFailed = VOS_TRUE;
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+
+ // this was triggered by implicit QoS so we know packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Setup failed, not a QoS AP\n",
+ __FUNCTION__);
+ if (!HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Setup pending",
+ __FUNCTION__);
+ // not a callback status -- ignore if we get it
+ break;
+
+ case SME_QOS_STATUS_SETUP_MODIFIED_IND:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Setup modified",
+ __FUNCTION__);
+ if (pCurrentQosInfo)
+ {
+ // update the TSPEC
+ pAc->wmmAcTspecValid = VOS_TRUE;
+ memcpy(&pAc->wmmAcTspecInfo,
+ pCurrentQosInfo,
+ sizeof(pAc->wmmAcTspecInfo));
+
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFIED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // need to tell TL to update its UAPSD handling
+ hdd_wmm_enable_tl_uapsd(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL",
+ __FUNCTION__);
+
+ // this was triggered by implicit QoS so we know packets are pending
+ pAc->wmmAcAccessPending = VOS_FALSE;
+ pAc->wmmAcAccessGranted = VOS_TRUE;
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+
+ // notify TL that packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
+ // nothing to do for now
+ break;
+
+ case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Setup successful but U-APSD failed",
+ __FUNCTION__);
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Implicit Qos, notifying TL",
+ __FUNCTION__);
+
+ // QoS setup was successful but setting U=APSD failed
+ // Since the OTA part of the request was successful, we don't mark
+ // this as a failure.
+ // the packets will flow. Note that the MAC will "do the right thing"
+ pAc->wmmAcAccessGranted = VOS_TRUE;
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+ pAc->wmmAcAccessFailed = VOS_FALSE;
+ pAc->wmmAcAccessPending = VOS_FALSE;
+
+ // this was triggered by implicit QoS so we know packets are pending
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // Since U-APSD portion failed disabled trigger frame generation
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+
+ break;
+
+ case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Release is complete",
+ __FUNCTION__);
+
+ if (pCurrentQosInfo)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: flows still active",
+ __FUNCTION__);
+
+ // there is still at least one flow active for this AC
+ // so update the AC state
+ memcpy(&pAc->wmmAcTspecInfo,
+ pCurrentQosInfo,
+ sizeof(pAc->wmmAcTspecInfo));
+
+ // need to tell TL to update its UAPSD handling
+ hdd_wmm_enable_tl_uapsd(pQosContext);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: last flow",
+ __FUNCTION__);
+
+ // this is the last flow active for this AC so update the AC state
+ pAc->wmmAcTspecValid = VOS_FALSE;
+
+ // need to tell TL to update its UAPSD handling
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+ }
+
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // we are done with this flow
+ hdd_wmm_free_context(pQosContext);
+ break;
+
+ case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Release failure",
+ __FUNCTION__);
+
+ // we don't need to update our state or TL since nothing has changed
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ break;
+
+ case SME_QOS_STATUS_RELEASE_QOS_LOST_IND:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: QOS Lost indication received",
+ __FUNCTION__);
+
+ // current TSPEC is no longer valid
+ pAc->wmmAcTspecValid = VOS_FALSE;
+
+ // need to tell TL to update its UAPSD handling
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+
+ if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle)
+ {
+ // we no longer have implicit access granted
+ pAc->wmmAcAccessGranted = VOS_FALSE;
+ pAc->wmmAcAccessFailed = VOS_FALSE;
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Explicit Qos, notifying userspace",
+ __FUNCTION__);
+
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // we are done with this flow
+ hdd_wmm_free_context(pQosContext);
+ break;
+
+ case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Release pending",
+ __FUNCTION__);
+ // not a callback status -- ignore if we get it
+ break;
+
+ case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Release Invalid Params",
+ __FUNCTION__);
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Modification is complete, notify TL",
+ __FUNCTION__);
+
+ // there will always be a TSPEC returned with this status, even if
+ // a TSPEC is not exchanged OTA
+ if (pCurrentQosInfo)
+ {
+ pAc->wmmAcTspecValid = VOS_TRUE;
+ memcpy(&pAc->wmmAcTspecInfo,
+ pCurrentQosInfo,
+ sizeof(pAc->wmmAcTspecInfo));
+ }
+
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // notify TL to enable trigger frames if necessary
+ hdd_wmm_enable_tl_uapsd(pQosContext);
+
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
+ // the flow modification failed so we'll leave in place
+ // whatever existed beforehand
+
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: modification pending",
+ __FUNCTION__);
+ // not a callback status -- ignore if we get it
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
+ // the flow modification was successful but no QoS changes required
+
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
+ // invalid params -- notify the application
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
+ hdd_wmm_notify_app(pQosContext);
+ }
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING:
+ // nothing to do for now. when APSD is established we'll have work to do
+ break;
+
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED:
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Modify successful but U-APSD failed",
+ __FUNCTION__);
+
+ // QoS modification was successful but setting U=APSD failed.
+ // This will always be an explicit QoS instance, so all we can
+ // do is notify the application and let it clean up.
+ if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle)
+ {
+ // this was triggered by an application
+ pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED;
+ hdd_wmm_notify_app(pQosContext);
+ }
+
+ // Since U-APSD portion failed disabled trigger frame generation
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+
+ break;
+
+ case SME_QOS_STATUS_HANDING_OFF:
+ // no roaming so we won't see this
+ break;
+
+ case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND:
+ // need to tell TL to stop trigger frame generation
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+ break;
+
+ case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND:
+ // need to tell TL to start sending trigger frames again
+ hdd_wmm_enable_tl_uapsd(pQosContext);
+ break;
+
+ default:
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: unexpected SME Status=%d\n",
+ __FUNCTION__, smeStatus );
+ VOS_ASSERT(0);
+ }
+
+ // our access to the particular access category may have changed.
+ // some of the implicit QoS cases above may have already set this
+ // prior to invoking TL (so that we will properly service the
+ // Tx queues) but let's consistently handle all cases here
+ pAc->wmmAcAccessAllowed = hdd_wmm_is_access_allowed(pAdapter, pAc);
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: complete, access for TL AC %d is%sallowed",
+ __FUNCTION__,
+ acType,
+ pAc->wmmAcAccessAllowed ? " " : " not ");
+
+ return eHAL_STATUS_SUCCESS;
+}
+#endif
+
+/**============================================================================
+ @brief hdd_wmm_do_implicit_qos() - Function which will attempt to setup
+ QoS for any AC requiring it
+
+ @param work : [in] pointer to work structure
+
+ @return : void
+ ===========================================================================*/
+static void hdd_wmm_do_implicit_qos(struct work_struct *work)
+{
+ hdd_wmm_qos_context_t* pQosContext =
+ container_of(work, hdd_wmm_qos_context_t, wmmAcSetupImplicitQos);
+ hdd_adapter_t* pAdapter;
+ WLANTL_ACEnumType acType;
+ hdd_wmm_ac_status_t *pAc;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ VOS_STATUS status;
+ sme_QosStatusType smeStatus;
+#endif
+ sme_QosWmmTspecInfo qosInfo;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered, context %p",
+ __FUNCTION__, pQosContext);
+
+ if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Invalid QoS Context",
+ __FUNCTION__);
+ return;
+ }
+
+ pAdapter = pQosContext->pAdapter;
+ acType = pQosContext->acType;
+ pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: pAdapter %p acType %d",
+ __FUNCTION__, pAdapter, acType);
+
+ if (!pAc->wmmAcAccessNeeded)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: AC %d doesn't need service",
+ __FUNCTION__, acType);
+ pQosContext->magic = 0;
+ kfree(pQosContext);
+ return;
+ }
+
+ pAc->wmmAcAccessPending = VOS_TRUE;
+ pAc->wmmAcAccessNeeded = VOS_FALSE;
+
+ memset(&qosInfo, 0, sizeof(qosInfo));
+
+ switch (acType)
+ {
+ case WLANTL_AC_VO:
+ qosInfo.ts_info.up = SME_QOS_WMM_UP_VO;
+ qosInfo.ts_info.psb = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->UapsdMask & 0x01;
+ qosInfo.ts_info.direction = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraDirAcVo;
+ qosInfo.ts_info.tid = 255;
+ qosInfo.mean_data_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMeanDataRateAcVo;
+ qosInfo.min_phy_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMinPhyRateAcVo;
+ qosInfo.min_service_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdVoSrvIntv;
+ qosInfo.nominal_msdu_size = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraNomMsduSizeAcVo;
+ qosInfo.surplus_bw_allowance = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraSbaAcVo;
+ qosInfo.suspension_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdVoSuspIntv;
+ break;
+ case WLANTL_AC_VI:
+ qosInfo.ts_info.up = SME_QOS_WMM_UP_VI;
+ qosInfo.ts_info.psb = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->UapsdMask & 0x02;
+ qosInfo.ts_info.direction = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraDirAcVi;
+ qosInfo.ts_info.tid = 255;
+ qosInfo.mean_data_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMeanDataRateAcVi;
+ qosInfo.min_phy_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMinPhyRateAcVi;
+ qosInfo.min_service_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdViSrvIntv;
+ qosInfo.nominal_msdu_size = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraNomMsduSizeAcVi;
+ qosInfo.surplus_bw_allowance = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraSbaAcVi;
+ qosInfo.suspension_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdViSuspIntv;
+ break;
+ default:
+ case WLANTL_AC_BE:
+ qosInfo.ts_info.up = SME_QOS_WMM_UP_BE;
+ qosInfo.ts_info.psb = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->UapsdMask & 0x08;
+ qosInfo.ts_info.direction = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraDirAcBe;
+ qosInfo.ts_info.tid = 255;
+ qosInfo.mean_data_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMeanDataRateAcBe;
+ qosInfo.min_phy_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMinPhyRateAcBe;
+ qosInfo.min_service_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBeSrvIntv;
+ qosInfo.nominal_msdu_size = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraNomMsduSizeAcBe;
+ qosInfo.surplus_bw_allowance = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraSbaAcBe;
+ qosInfo.suspension_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBeSuspIntv;
+ break;
+ case WLANTL_AC_BK:
+ qosInfo.ts_info.up = SME_QOS_WMM_UP_BK;
+ qosInfo.ts_info.psb = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->UapsdMask & 0x04;
+ qosInfo.ts_info.direction = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraDirAcBk;
+ qosInfo.ts_info.tid = 255;
+ qosInfo.mean_data_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMeanDataRateAcBk;
+ qosInfo.min_phy_rate = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraMinPhyRateAcBk;
+ qosInfo.min_service_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBkSrvIntv;
+ qosInfo.nominal_msdu_size = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraNomMsduSizeAcBk;
+ qosInfo.surplus_bw_allowance = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraSbaAcBk;
+ qosInfo.suspension_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBkSuspIntv;
+ break;
+ }
+#ifdef FEATURE_WLAN_CCX
+ qosInfo.inactivity_interval = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraInactivityInterval;
+#endif
+ qosInfo.ts_info.burst_size_defn = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->burstSizeDefinition;
+
+ switch ((WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->tsInfoAckPolicy)
+ {
+ case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK:
+ qosInfo.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
+ break;
+
+ case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
+ qosInfo.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
+ break;
+
+ default:
+ // unknown
+ qosInfo.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
+ }
+
+ if(qosInfo.ts_info.ack_policy == SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)
+ {
+ if(!sme_QosIsTSInfoAckPolicyValid((tpAniSirGlobal)WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo, pAdapter->sessionId))
+ {
+ qosInfo.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
+ }
+ }
+
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+ list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ smeStatus = sme_QosSetupReq(WLAN_HDD_GET_HAL_CTX(pAdapter),
+ pAdapter->sessionId,
+ &qosInfo,
+ hdd_wmm_sme_callback,
+ pQosContext,
+ qosInfo.ts_info.up,
+ &pQosContext->qosFlowId);
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: sme_QosSetupReq returned %d flowid %d",
+ __FUNCTION__, smeStatus, pQosContext->qosFlowId);
+
+ // need to check the return values and act appropriately
+ switch (smeStatus)
+ {
+ case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
+ case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
+ // setup is pending, so no more work to do now.
+ // all further work will be done in hdd_wmm_sme_callback()
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Setup is pending, no further work",
+ __FUNCTION__);
+
+ break;
+
+
+ case SME_QOS_STATUS_SETUP_FAILURE_RSP:
+ // we can't tell the difference between when a request fails because
+ // AP rejected it versus when SME encountered an internal error
+
+ // in either case SME won't ever reference this context so
+ // free the record
+ hdd_wmm_free_context(pQosContext);
+
+ // fall through and start packets flowing
+ case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
+ // no ACM in effect, no need to setup U-APSD
+ case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
+ // no ACM in effect, U-APSD is desired but was already setup
+
+ // for these cases everything is already setup so we can
+ // signal TL that it has work to do
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Setup is complete, notify TL",
+ __FUNCTION__);
+
+ pAc->wmmAcAccessAllowed = VOS_TRUE;
+ pAc->wmmAcAccessGranted = VOS_TRUE;
+ pAc->wmmAcAccessPending = VOS_FALSE;
+
+ status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ acType );
+
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Failed to signal TL for AC=%d",
+ __FUNCTION__, acType );
+ }
+
+ break;
+
+
+ default:
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: unexpected SME Status=%d\n",
+ __FUNCTION__, smeStatus );
+ VOS_ASSERT(0);
+ }
+#endif
+
+}
+
+/**============================================================================
+ @brief hdd_wmm_init() - Function which will initialize the WMM configuation
+ and status to an initial state. The configuration can later be overwritten
+ via application APIs
+
+ @param pHddCtx : [in] pointer to HDD context
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_init ( hdd_context_t* pHddCtx )
+{
+ v_U8_t dscp;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+
+ // DSCP to User Priority Lookup Table
+ for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++)
+ {
+ hddWmmDscpToUpMap[dscp] = SME_QOS_WMM_UP_BE;
+ }
+ hddWmmDscpToUpMap[8] = SME_QOS_WMM_UP_BK;
+ hddWmmDscpToUpMap[16] = SME_QOS_WMM_UP_RESV;
+ hddWmmDscpToUpMap[24] = SME_QOS_WMM_UP_EE;
+ hddWmmDscpToUpMap[32] = SME_QOS_WMM_UP_CL;
+ hddWmmDscpToUpMap[40] = SME_QOS_WMM_UP_VI;
+ hddWmmDscpToUpMap[48] = SME_QOS_WMM_UP_VO;
+ hddWmmDscpToUpMap[56] = SME_QOS_WMM_UP_NC;
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**============================================================================
+ @brief hdd_wmm_adapter_init() - Function which will initialize the WMM configuation
+ and status to an initial state. The configuration can later be overwritten
+ via application APIs
+
+ @param pAdapter : [in] pointer to Adapter context
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_adapter_init( hdd_adapter_t *pAdapter )
+{
+ hdd_wmm_ac_status_t *pAcStatus;
+ WLANTL_ACEnumType acType;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+
+ pAdapter->hddWmmStatus.wmmQap = VOS_FALSE;
+ INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList);
+ mutex_init(&pAdapter->hddWmmStatus.wmmLock);
+
+ for (acType = 0; acType < WLANTL_MAX_AC; acType++)
+ {
+ pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
+ pAcStatus->wmmAcAccessRequired = VOS_FALSE;
+ pAcStatus->wmmAcAccessNeeded = VOS_FALSE;
+ pAcStatus->wmmAcAccessPending = VOS_FALSE;
+ pAcStatus->wmmAcAccessFailed = VOS_FALSE;
+ pAcStatus->wmmAcAccessGranted = VOS_FALSE;
+ pAcStatus->wmmAcAccessAllowed = VOS_FALSE;
+ pAcStatus->wmmAcTspecValid = VOS_FALSE;
+ pAcStatus->wmmAcUapsdInfoValid = VOS_FALSE;
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+/**============================================================================
+ @brief hdd_wmm_close() - Function which will perform any necessary work to
+ to clean up the WMM functionality prior to the kernel module unload
+
+ @param pAdapter : [in] pointer to adapter context
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_adapter_close ( hdd_adapter_t* pAdapter )
+{
+ hdd_wmm_qos_context_t* pQosContext;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+
+ // free any context records that we still have linked
+ while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList))
+ {
+ pQosContext = list_first_entry(&pAdapter->hddWmmStatus.wmmContextList,
+ hdd_wmm_qos_context_t, node);
+#ifdef FEATURE_WLAN_CCX
+ hdd_wmm_disable_inactivity_timer(pQosContext);
+#endif
+ hdd_wmm_free_context(pQosContext);
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**============================================================================
+ @brief hdd_wmm_classify_pkt() - Function which will classify an OS packet
+ into a WMM AC based on either 802.1Q or DSCP
+
+ @param pAdapter : [in] pointer to adapter context
+ @param skb : [in] pointer to OS packet (sk_buff)
+ @param pAcType : [out] pointer to WMM AC type of OS packet
+
+ @return : None
+ ===========================================================================*/
+v_VOID_t hdd_wmm_classify_pkt ( hdd_adapter_t* pAdapter,
+ struct sk_buff *skb,
+ WLANTL_ACEnumType* pAcType,
+ sme_QosWmmUpType *pUserPri)
+{
+ unsigned char * pPkt;
+ union generic_ethhdr *pHdr;
+ struct iphdr *pIpHdr;
+ unsigned char tos;
+ unsigned char dscp;
+ sme_QosWmmUpType userPri;
+ WLANTL_ACEnumType acType;
+
+ // this code is executed for every packet therefore
+ // all debug code is kept conditional
+
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+#endif // HDD_WMM_DEBUG
+
+ pPkt = skb->data;
+ pHdr = (union generic_ethhdr *)pPkt;
+
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: proto/length is 0x%04x",
+ __FUNCTION__, pHdr->eth_II.h_proto);
+#endif // HDD_WMM_DEBUG
+
+ if (HDD_WMM_CLASSIFICATION_DSCP == (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->PktClassificationBasis)
+ {
+ if (pHdr->eth_II.h_proto == htons(ETH_P_IP))
+ {
+ // case 1: Ethernet II IP packet
+ pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_II)];
+ tos = pIpHdr->tos;
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Ethernet II IP Packet, tos is %d",
+ __FUNCTION__, tos);
+#endif // HDD_WMM_DEBUG
+
+ }
+ else if ((ntohs(pHdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
+ (pHdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
+ (pHdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
+ (pHdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
+ (pHdr->eth_8023.h_proto == htons(ETH_P_IP)))
+ {
+ // case 2: 802.3 LLC/SNAP IP packet
+ pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)];
+ tos = pIpHdr->tos;
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: 802.3 LLC/SNAP IP Packet, tos is %d",
+ __FUNCTION__, tos);
+#endif // HDD_WMM_DEBUG
+ }
+ else if (pHdr->eth_II.h_proto == htons(ETH_P_8021Q))
+ {
+ // VLAN tagged
+
+ if (pHdr->eth_IIv.h_vlan_encapsulated_proto == htons(ETH_P_IP))
+ {
+ // case 3: Ethernet II vlan-tagged IP packet
+ pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_IIv)];
+ tos = pIpHdr->tos;
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Ethernet II VLAN tagged IP Packet, tos is %d",
+ __FUNCTION__, tos);
+#endif // HDD_WMM_DEBUG
+ }
+ else if ((ntohs(pHdr->eth_IIv.h_vlan_encapsulated_proto) < WLAN_MIN_PROTO) &&
+ (pHdr->eth_8023v.h_snap.dsap == WLAN_SNAP_DSAP) &&
+ (pHdr->eth_8023v.h_snap.ssap == WLAN_SNAP_SSAP) &&
+ (pHdr->eth_8023v.h_snap.ctrl == WLAN_SNAP_CTRL) &&
+ (pHdr->eth_8023v.h_proto == htons(ETH_P_IP)))
+ {
+ // case 4: 802.3 LLC/SNAP vlan-tagged IP packet
+ pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023v)];
+ tos = pIpHdr->tos;
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
+ __FUNCTION__, tos);
+#endif // HDD_WMM_DEBUG
+ }
+ else
+ {
+ // default
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
+ "%s: VLAN tagged Unhandled Protocol, using default tos",
+ __FUNCTION__);
+#endif // HDD_WMM_DEBUG
+ tos = 0;
+ }
+ }
+ else
+ {
+ // default
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
+ "%s: Unhandled Protocol, using default tos",
+ __FUNCTION__);
+#endif // HDD_WMM_DEBUG
+ //Give the highest priority to 802.1x packet
+ if (pHdr->eth_II.h_proto == htons(HDD_ETHERTYPE_802_1_X))
+ tos = 0xC0;
+ else
+ tos = 0;
+ }
+
+ dscp = (tos>>2) & 0x3f;
+ userPri = hddWmmDscpToUpMap[dscp];
+
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: tos is %d, dscp is %d, up is %d",
+ __FUNCTION__, tos, dscp, userPri);
+#endif // HDD_WMM_DEBUG
+
+ }
+ else if (HDD_WMM_CLASSIFICATION_802_1Q == (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->PktClassificationBasis)
+ {
+ if (pHdr->eth_IIv.h_vlan_proto == htons(ETH_P_8021Q))
+ {
+ // VLAN tagged
+ userPri = (ntohs(pHdr->eth_IIv.h_vlan_TCI)>>13) & 0x7;
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Tagged frame, UP is %d",
+ __FUNCTION__, userPri);
+#endif // HDD_WMM_DEBUG
+ }
+ else
+ {
+ // not VLAN tagged, use default
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
+ "%s: Untagged frame, using default UP",
+ __FUNCTION__);
+#endif // HDD_WMM_DEBUG
+ //Give the highest priority to 802.1x packet
+ if (pHdr->eth_II.h_proto == htons(HDD_ETHERTYPE_802_1_X))
+ userPri = SME_QOS_WMM_UP_VO;
+ else
+ userPri = SME_QOS_WMM_UP_BE;
+ }
+ }
+ else
+ {
+ // default
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Unknown classification scheme, using default UP",
+ __FUNCTION__);
+#endif // HDD_WMM_DEBUG
+ userPri = SME_QOS_WMM_UP_BE;
+ }
+
+ acType = hddWmmUpToAcMap[userPri];
+
+#ifdef HDD_WMM_DEBUG
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: UP is %d, AC is %d",
+ __FUNCTION__, userPri, acType);
+#endif // HDD_WMM_DEBUG
+
+ *pUserPri = userPri;
+ *pAcType = acType;
+
+ return;
+}
+
+/**============================================================================
+ @brief hdd_hostapd_select_quueue() - Function which will classify the packet
+ according to linux qdisc expectation.
+
+
+ @param dev : [in] pointer to net_device structure
+ @param skb : [in] pointer to os packet
+
+ @return : Qdisc queue index
+ ===========================================================================*/
+v_U16_t hdd_hostapd_select_queue(struct net_device * dev, struct sk_buff *skb)
+{
+ WLANTL_ACEnumType ac;
+ sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
+ v_USHORT_t queueIndex;
+ v_MACADDR_t *pDestMacAddress = (v_MACADDR_t*)skb->data;
+ hdd_adapter_t *pAdapter = (hdd_adapter_t *)netdev_priv(dev);
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ tpAniSirGlobal pMac = (tpAniSirGlobal) vos_get_context(VOS_MODULE_ID_HAL, pHddCtx->pvosContext);
+#endif //FEATURE_WLAN_NON_INTEGRATED_SOC
+ v_U8_t STAId;
+ v_U8_t *pSTAId = (v_U8_t *)(((v_U8_t *)(skb->data)) - 1);
+
+ /*Get the Station ID*/
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ if (eHAL_STATUS_SUCCESS != halTable_FindStaidByAddr(pMac, (tANI_U8 *)pDestMacAddress, &STAId))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to find right station", __FUNCTION__);
+ *pSTAId = HDD_WLAN_INVALID_STA_ID;
+ goto done;
+ }
+#else
+ if (VOS_STATUS_SUCCESS != hdd_softap_GetStaId(pAdapter, pDestMacAddress, &STAId))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to find right station", __FUNCTION__);
+ *pSTAId = HDD_WLAN_INVALID_STA_ID;
+ goto done;
+ }
+#endif //FEATURE_WLAN_NON_INTEGRATED_SOC
+
+ spin_lock_bh( &pAdapter->staInfo_lock );
+ if (FALSE == vos_is_macaddr_equal(&pAdapter->aStaInfo[STAId].macAddrSTA, pDestMacAddress))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR,
+ "%s: Station MAC address does not matching", __FUNCTION__);
+
+ *pSTAId = HDD_WLAN_INVALID_STA_ID;
+ goto release_lock;
+ }
+ if (pAdapter->aStaInfo[STAId].isUsed && pAdapter->aStaInfo[STAId].isQosEnabled && (HDD_WMM_USER_MODE_NO_QOS != pHddCtx->cfg_ini->WmmMode))
+ {
+ /* Get the user priority from IP header & corresponding AC */
+ hdd_wmm_classify_pkt (pAdapter, skb, &ac, &up);
+ }
+ *pSTAId = STAId;
+
+release_lock:
+ spin_unlock_bh( &pAdapter->staInfo_lock );
+done:
+ skb->priority = up;
+ queueIndex = hddLinuxUpToAcMap[skb->priority];
+
+ return queueIndex;
+}
+
+/**============================================================================
+ @brief hdd_wmm_select_quueue() - Function which will classify the packet
+ according to linux qdisc expectation.
+
+
+ @param dev : [in] pointer to net_device structure
+ @param skb : [in] pointer to os packet
+
+ @return : Qdisc queue index
+ ===========================================================================*/
+v_U16_t hdd_wmm_select_queue(struct net_device * dev, struct sk_buff *skb)
+{
+ WLANTL_ACEnumType ac;
+ sme_QosWmmUpType up = 0;
+ v_USHORT_t queueIndex;
+
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+ // if we don't want QoS or the AP doesn't support Qos
+ // All traffic will get equal opportuniy to transmit data frames.
+ if( hdd_wmm_is_active(pAdapter) ) {
+ /* Get the user priority from IP header & corresponding AC */
+ hdd_wmm_classify_pkt (pAdapter, skb, &ac, &up);
+ }
+
+ skb->priority = up;
+ queueIndex = hddLinuxUpToAcMap[skb->priority];
+
+ return queueIndex;
+}
+
+/**============================================================================
+ @brief hdd_wmm_acquire_access() - Function which will attempt to acquire
+ admittance for a WMM AC
+
+ @param pAdapter : [in] pointer to adapter context
+ @param acType : [in] WMM AC type of OS packet
+ @param pGranted : [out] pointer to boolean flag when indicates if access
+ has been granted or not
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_acquire_access( hdd_adapter_t* pAdapter,
+ WLANTL_ACEnumType acType,
+ v_BOOL_t * pGranted )
+{
+ hdd_wmm_qos_context_t *pQosContext;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered for AC %d", __FUNCTION__, acType);
+
+ if (!hdd_wmm_is_active(pAdapter) || !(WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->bImplicitQosEnabled)
+ {
+ // either we don't want QoS or the AP doesn't support QoS
+ // or we don't want to do implicit QoS
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: QoS not configured on both ends ", __FUNCTION__);
+
+ pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = VOS_TRUE;
+ *pGranted = VOS_TRUE;
+ return VOS_STATUS_SUCCESS;
+ }
+
+ // do we already have an implicit QoS request pending for this AC?
+ if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) ||
+ (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending))
+ {
+ // request already pending so we need to wait for that response
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Implicit QoS for TL AC %d already scheduled",
+ __FUNCTION__, acType);
+
+ *pGranted = VOS_FALSE;
+ return VOS_STATUS_SUCCESS;
+ }
+
+ // did we already fail to establish implicit QoS for this AC?
+ // (if so, access should have been granted when the failure was handled)
+ if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed)
+ {
+ // request previously failed
+ // allow access, but we'll be downgraded
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Implicit QoS for TL AC %d previously failed",
+ __FUNCTION__, acType);
+
+ pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = VOS_TRUE;
+ *pGranted = VOS_TRUE;
+ return VOS_STATUS_SUCCESS;
+ }
+
+ // we need to establish implicit QoS
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p",
+ __FUNCTION__, acType, pAdapter);
+
+ pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = VOS_TRUE;
+
+ pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL);
+ if (NULL == pQosContext)
+ {
+ // no memory for QoS context. Nothing we can do but let data flow
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Unable to allocate context", __FUNCTION__);
+ pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = VOS_TRUE;
+ *pGranted = VOS_TRUE;
+ return VOS_STATUS_SUCCESS;
+ }
+
+ pQosContext->acType = acType;
+ pQosContext->pAdapter = pAdapter;
+ pQosContext->qosFlowId = 0;
+ pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT;
+ pQosContext->magic = HDD_WMM_CTX_MAGIC;
+ INIT_WORK(&pQosContext->wmmAcSetupImplicitQos,
+ hdd_wmm_do_implicit_qos);
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Scheduling work for AC %d, context %p",
+ __FUNCTION__, acType, pQosContext);
+
+ schedule_work(&pQosContext->wmmAcSetupImplicitQos);
+
+ // caller will need to wait until the work takes place and
+ // TSPEC negotiation completes
+ *pGranted = VOS_FALSE;
+ return VOS_STATUS_SUCCESS;
+}
+
+/**============================================================================
+ @brief hdd_wmm_assoc() - Function which will handle the housekeeping
+ required by WMM when association takes place
+
+ @param pAdapter : [in] pointer to adapter context
+ @param pRoamInfo: [in] pointer to roam information
+ @param eBssType : [in] type of BSS
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_assoc( hdd_adapter_t* pAdapter,
+ tCsrRoamInfo *pRoamInfo,
+ eCsrRoamBssType eBssType )
+{
+ tANI_U8 uapsdMask;
+ VOS_STATUS status;
+
+ // when we associate we need to notify TL if it needs to enable
+ // UAPSD for any access categories
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+
+ if (pRoamInfo->fReassocReq)
+ {
+ // when we reassociate we should continue to use whatever
+ // parameters were previously established. if we are
+ // reassociating due to a U-APSD change for a particular
+ // Access Category, then the change will be communicated
+ // to HDD via the QoS callback associated with the given
+ // flow, and U-APSD parameters will be updated there
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Reassoc so no work, Exiting", __FUNCTION__);
+
+ return VOS_STATUS_SUCCESS;
+ }
+
+ // get the negotiated UAPSD Mask
+ uapsdMask = pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: U-APSD mask is 0x%02x", __FUNCTION__, (int) uapsdMask);
+
+ if (uapsdMask & HDD_AC_VO)
+ {
+ status = WLANTL_EnableUAPSDForAC( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ WLANTL_AC_VO,
+ 7,
+ 7,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdVoSrvIntv,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdVoSuspIntv,
+ WLANTL_BI_DIR );
+
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ));
+ }
+
+ if (uapsdMask & HDD_AC_VI)
+ {
+ status = WLANTL_EnableUAPSDForAC( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ WLANTL_AC_VI,
+ 5,
+ 5,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdViSrvIntv,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdViSuspIntv,
+ WLANTL_BI_DIR );
+
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ));
+ }
+
+ if (uapsdMask & HDD_AC_BK)
+ {
+ status = WLANTL_EnableUAPSDForAC( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ WLANTL_AC_BK,
+ 2,
+ 2,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBkSrvIntv,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBkSuspIntv,
+ WLANTL_BI_DIR );
+
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ));
+ }
+
+ if (uapsdMask & HDD_AC_BE)
+ {
+ status = WLANTL_EnableUAPSDForAC( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+ (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.staId[0],
+ WLANTL_AC_BE,
+ 3,
+ 3,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBeSrvIntv,
+ (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBeSuspIntv,
+ WLANTL_BI_DIR );
+
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ));
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Exiting", __FUNCTION__);
+
+ return VOS_STATUS_SUCCESS;
+}
+
+
+
+static const v_U8_t acmMaskBit[WLANTL_MAX_AC] =
+ {
+ 0x4, /* WLANTL_AC_BK */
+ 0x8, /* WLANTL_AC_BE */
+ 0x2, /* WLANTL_AC_VI */
+ 0x1 /* WLANTL_AC_VO */
+ };
+
+/**============================================================================
+ @brief hdd_wmm_connect() - Function which will handle the housekeeping
+ required by WMM when a connection is established
+
+ @param pAdapter : [in] pointer to adapter context
+ @param pRoamInfo: [in] pointer to roam information
+ @param eBssType : [in] type of BSS
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_connect( hdd_adapter_t* pAdapter,
+ tCsrRoamInfo *pRoamInfo,
+ eCsrRoamBssType eBssType )
+{
+ int ac;
+ v_BOOL_t qap;
+ v_BOOL_t qosConnection;
+ v_U8_t acmMask;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered", __FUNCTION__);
+
+ if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) &&
+ pRoamInfo &&
+ pRoamInfo->u.pConnectedProfile)
+ {
+ qap = pRoamInfo->u.pConnectedProfile->qap;
+ qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection;
+ acmMask = pRoamInfo->u.pConnectedProfile->acm_mask;
+ }
+ else
+ {
+ qap = VOS_TRUE;
+ qosConnection = VOS_TRUE;
+ acmMask = 0x0;
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: qap is %d, qosConnection is %d, acmMask is 0x%x",
+ __FUNCTION__, qap, qosConnection, acmMask);
+
+ pAdapter->hddWmmStatus.wmmQap = qap;
+ pAdapter->hddWmmStatus.wmmQosConnection = qosConnection;
+
+ for (ac = 0; ac < WLANTL_MAX_AC; ac++)
+ {
+ if (qap &&
+ qosConnection &&
+ (acmMask & acmMaskBit[ac]))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: ac %d on",
+ __FUNCTION__, ac);
+
+ // admission is required
+ pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired = VOS_TRUE;
+ pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed = VOS_FALSE;
+ pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessGranted = VOS_FALSE;
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: ac %d off",
+ __FUNCTION__, ac);
+ // admission is not required so access is allowed
+ pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired = VOS_FALSE;
+ pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed = VOS_TRUE;
+ }
+
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Exiting", __FUNCTION__);
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**============================================================================
+ @brief hdd_wmm_get_uapsd_mask() - Function which will calculate the
+ initial value of the UAPSD mask based upon the device configuration
+
+ @param pAdapter : [in] pointer to adapter context
+ @param pUapsdMask: [in] pointer to where the UAPSD Mask is to be stored
+
+ @return : VOS_STATUS_SUCCESS if succssful
+ : other values if failure
+ ===========================================================================*/
+VOS_STATUS hdd_wmm_get_uapsd_mask( hdd_adapter_t* pAdapter,
+ tANI_U8 *pUapsdMask )
+{
+ tANI_U8 uapsdMask;
+
+ if (HDD_WMM_USER_MODE_NO_QOS == (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->WmmMode)
+ {
+ // no QOS then no UAPSD
+ uapsdMask = 0;
+ }
+ else
+ {
+ // start with the default mask
+ uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->UapsdMask;
+
+ // disable UAPSD for any ACs with a 0 Service Interval
+ if( (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdVoSrvIntv == 0 )
+ {
+ uapsdMask &= ~HDD_AC_VO;
+ }
+
+ if( (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdViSrvIntv == 0 )
+ {
+ uapsdMask &= ~HDD_AC_VI;
+ }
+
+ if( (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBkSrvIntv == 0 )
+ {
+ uapsdMask &= ~HDD_AC_BK;
+ }
+
+ if( (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini->InfraUapsdBeSrvIntv == 0 )
+ {
+ uapsdMask &= ~HDD_AC_BE;
+ }
+ }
+
+ // return calculated mask
+ *pUapsdMask = uapsdMask;
+ return VOS_STATUS_SUCCESS;
+}
+
+
+/**============================================================================
+ @brief hdd_wmm_is_active() - Function which will determine if WMM is
+ active on the current connection
+
+ @param pAdapter : [in] pointer to adapter context
+
+ @return : VOS_TRUE if WMM is enabled
+ : VOS_FALSE if WMM is not enabled
+ ===========================================================================*/
+v_BOOL_t hdd_wmm_is_active( hdd_adapter_t* pAdapter )
+{
+ if ((!pAdapter->hddWmmStatus.wmmQosConnection) ||
+ (!pAdapter->hddWmmStatus.wmmQap))
+ {
+ return VOS_FALSE;
+ }
+ else
+ {
+ return VOS_TRUE;
+ }
+}
+
+/**============================================================================
+ @brief hdd_wmm_addts() - Function which will add a traffic spec at the
+ request of an application
+
+ @param pAdapter : [in] pointer to adapter context
+ @param handle : [in] handle to uniquely identify a TS
+ @param pTspec : [in] pointer to the traffic spec
+
+ @return : HDD_WLAN_WMM_STATUS_*
+ ===========================================================================*/
+hdd_wlan_wmm_status_e hdd_wmm_addts( hdd_adapter_t* pAdapter,
+ v_U32_t handle,
+ sme_QosWmmTspecInfo* pTspec )
+{
+ hdd_wmm_qos_context_t *pQosContext;
+ hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS ;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_QosStatusType smeStatus;
+#endif
+ v_BOOL_t found = VOS_FALSE;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered with handle 0x%x", __FUNCTION__, handle);
+
+ // see if a context already exists with the given handle
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+ list_for_each_entry(pQosContext,
+ &pAdapter->hddWmmStatus.wmmContextList,
+ node)
+ {
+ if (pQosContext->handle == handle)
+ {
+ found = VOS_TRUE;
+ break;
+ }
+ }
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+ if (found)
+ {
+ // record with that handle already exists
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Record already exists with handle 0x%x",
+ __FUNCTION__, handle);
+
+ /* Application is trying to modify some of the Tspec params. Allow it */
+ smeStatus = sme_QosModifyReq(WLAN_HDD_GET_HAL_CTX(pAdapter),
+ pTspec,
+ pQosContext->qosFlowId);
+
+ // need to check the return value and act appropriately
+ switch (smeStatus)
+ {
+ case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
+ status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
+ break;
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
+ status = HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
+ break;
+ case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
+ status = HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
+ break;
+ case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
+ status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
+ break;
+ case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
+ status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
+ break;
+ case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
+ status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
+ break;
+ default:
+ // we didn't get back one of the SME_QOS_STATUS_MODIFY_* status codes
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: unexpected SME Status=%d\n", smeStatus );
+ VOS_ASSERT(0);
+ return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
+ }
+
+ // we were successful, save the status
+ pQosContext->lastStatus = status;
+ return status;
+ }
+
+ pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL);
+ if (NULL == pQosContext)
+ {
+ // no memory for QoS context. Nothing we can do
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: Unable to allocate QoS context", __FUNCTION__);
+ return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
+ }
+
+ // we assume the tspec has already been validated by the caller
+
+ pQosContext->handle = handle;
+ pQosContext->acType = hddWmmUpToAcMap[pTspec->ts_info.up];
+ pQosContext->pAdapter = pAdapter;
+ pQosContext->qosFlowId = 0;
+ pQosContext->magic = HDD_WMM_CTX_MAGIC;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: Setting up QoS, context %p",
+ __FUNCTION__, pQosContext);
+
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+ list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ smeStatus = sme_QosSetupReq(WLAN_HDD_GET_HAL_CTX(pAdapter),
+ pAdapter->sessionId,
+ pTspec,
+ hdd_wmm_sme_callback,
+ pQosContext,
+ pTspec->ts_info.up,
+ &pQosContext->qosFlowId);
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
+ "%s: sme_QosSetupReq returned %d flowid %d",
+ __FUNCTION__, smeStatus, pQosContext->qosFlowId);
+
+ // need to check the return value and act appropriately
+ switch (smeStatus)
+ {
+ case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
+ status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
+ break;
+ case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
+ status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
+ break;
+ case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
+ status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
+ break;
+ case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
+ status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
+ break;
+ case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
+ hdd_wmm_free_context(pQosContext);
+ return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
+ case SME_QOS_STATUS_SETUP_FAILURE_RSP:
+ // we can't tell the difference between when a request fails because
+ // AP rejected it versus when SME encounterd an internal error
+ hdd_wmm_free_context(pQosContext);
+ return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
+ case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
+ hdd_wmm_free_context(pQosContext);
+ return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
+ default:
+ // we didn't get back one of the SME_QOS_STATUS_SETUP_* status codes
+ hdd_wmm_free_context(pQosContext);
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: unexpected SME Status=%d\n", smeStatus );
+ VOS_ASSERT(0);
+ return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
+ }
+#endif
+
+ // we were successful, save the status
+ pQosContext->lastStatus = status;
+
+ return status;
+}
+
+/**============================================================================
+ @brief hdd_wmm_delts() - Function which will delete a traffic spec at the
+ request of an application
+
+ @param pAdapter : [in] pointer to adapter context
+ @param handle : [in] handle to uniquely identify a TS
+
+ @return : HDD_WLAN_WMM_STATUS_*
+ ===========================================================================*/
+hdd_wlan_wmm_status_e hdd_wmm_delts( hdd_adapter_t* pAdapter,
+ v_U32_t handle )
+{
+ hdd_wmm_qos_context_t *pQosContext;
+ v_BOOL_t found = VOS_FALSE;
+ WLANTL_ACEnumType acType = 0;
+ v_U32_t qosFlowId = 0;
+ hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS ;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_QosStatusType smeStatus;
+#endif
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered with handle 0x%x", __FUNCTION__, handle);
+
+ // locate the context with the given handle
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+ list_for_each_entry(pQosContext,
+ &pAdapter->hddWmmStatus.wmmContextList,
+ node)
+ {
+ if (pQosContext->handle == handle)
+ {
+ found = VOS_TRUE;
+ acType = pQosContext->acType;
+ qosFlowId = pQosContext->qosFlowId;
+ break;
+ }
+ }
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+
+ if (VOS_FALSE == found)
+ {
+ // we didn't find the handle
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: handle 0x%x not found", __FUNCTION__, handle);
+ return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
+ }
+
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: found handle 0x%x, flow %d, AC %d, context %p",
+ __FUNCTION__, handle, qosFlowId, acType, pQosContext);
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ smeStatus = sme_QosReleaseReq( WLAN_HDD_GET_HAL_CTX(pAdapter), qosFlowId );
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: SME flow %d released, SME status %d",
+ __FUNCTION__, qosFlowId, smeStatus);
+
+ switch(smeStatus)
+ {
+ case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
+ // this flow is the only one on that AC, so go ahead and update
+ // our TSPEC state for the AC
+ pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid = VOS_FALSE;
+
+ // need to tell TL to stop trigger timer, etc
+ hdd_wmm_disable_tl_uapsd(pQosContext);
+
+#ifdef FEATURE_WLAN_CCX
+ // disable the inactivity timer
+ hdd_wmm_disable_inactivity_timer(pQosContext);
+#endif
+ // we are done with this context
+ hdd_wmm_free_context(pQosContext);
+
+ // SME must not fire any more callbacks for this flow since the context
+ // is no longer valid
+
+ return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
+
+ case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
+ // do nothing as we will get a response from SME
+ status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
+ break;
+
+ case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
+ // nothing we can do with the existing flow except leave it
+ status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
+ break;
+
+ case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
+ // nothing we can do with the existing flow except leave it
+ status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
+
+ default:
+ // we didn't get back one of the SME_QOS_STATUS_RELEASE_* status codes
+ VOS_TRACE( VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
+ "%s: unexpected SME Status=%d\n", smeStatus );
+ VOS_ASSERT(0);
+ status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
+ }
+
+#endif
+ pQosContext->lastStatus = status;
+ return status;
+}
+
+/**============================================================================
+ @brief hdd_wmm_checkts() - Function which will return the status of a traffic
+ spec at the request of an application
+
+ @param pAdapter : [in] pointer to adapter context
+ @param handle : [in] handle to uniquely identify a TS
+
+ @return : HDD_WLAN_WMM_STATUS_*
+ ===========================================================================*/
+hdd_wlan_wmm_status_e hdd_wmm_checkts( hdd_adapter_t* pAdapter,
+ v_U32_t handle )
+{
+ hdd_wmm_qos_context_t *pQosContext;
+ hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: Entered with handle 0x%x", __FUNCTION__, handle);
+
+ // locate the context with the given handle
+ mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
+ list_for_each_entry(pQosContext,
+ &pAdapter->hddWmmStatus.wmmContextList,
+ node)
+ {
+ if (pQosContext->handle == handle)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
+ "%s: found handle 0x%x, context %p",
+ __FUNCTION__, handle, pQosContext);
+
+ status = pQosContext->lastStatus;
+ break;
+ }
+ }
+ mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
+ return status;
+}