prima: WLAN Driver Release 3.1.7.9
This is the initial release of the Prima WLAN Driver
diff --git a/CORE/SME/src/QoS/sme_Qos.c b/CORE/SME/src/QoS/sme_Qos.c
new file mode 100644
index 0000000..7729594
--- /dev/null
+++ b/CORE/SME/src/QoS/sme_Qos.c
@@ -0,0 +1,7890 @@
+/*
+ * 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 sme_Qos.c
+
+ \brief implementation for SME QoS APIs
+
+ Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
+
+ Qualcomm Confidential and Proprietary.
+
+ ========================================================================*/
+/* $Header$ */
+/*--------------------------------------------------------------------------
+ Include Files
+ ------------------------------------------------------------------------*/
+
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+#include "halInternal.h" //Check if the below include of aniGobal.h is sufficient for Volans too.
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+#include "aniGlobal.h"
+#endif
+
+#include "smeInside.h"
+#include "vos_diag_core_event.h"
+#include "vos_diag_core_log.h"
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+#include "smsDebug.h"
+#include "utilsParser.h"
+#endif
+#ifdef FEATURE_WLAN_CCX
+#include <csrCcx.h>
+#endif
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+/* TODO : 6Mbps as Cisco APs seem to like only this value; analysis req. */
+#define SME_QOS_MIN_PHY_RATE 0x5B8D80
+#define SME_QOS_SURPLUS_BW_ALLOWANCE 0x2000 /* Ratio of 1.0 */
+/*---------------------------------------------------------------------------
+ Max values to bound tspec params against and avoid rollover
+---------------------------------------------------------------------------*/
+#define SME_QOS_32BIT_MAX 0xFFFFFFFF
+#define SME_QOS_16BIT_MAX 0xFFFF
+#define SME_QOS_16BIT_MSB 0x8000
+/*---------------------------------------------------------------------------
+ Adds y to x, but saturates at 32-bit max to avoid rollover
+---------------------------------------------------------------------------*/
+#define SME_QOS_BOUNDED_U32_ADD_Y_TO_X( _x, _y ) \
+ do \
+ { \
+ (_x) = ( (SME_QOS_32BIT_MAX-(_x))<(_y) ) ? \
+ (SME_QOS_32BIT_MAX) : (_x)+(_y); \
+ } while(0)
+/*---------------------------------------------------------------------------
+ As per WMM spec there could be max 2 TSPEC running on the same AC with
+ different direction. We will refer each TSPEC with an index
+---------------------------------------------------------------------------*/
+#define SME_QOS_TSPEC_INDEX_0 0
+#define SME_QOS_TSPEC_INDEX_1 1
+#define SME_QOS_TSPEC_INDEX_MAX 2
+#define SME_QOS_TSPEC_MASK_BIT_1_SET 1
+#define SME_QOS_TSPEC_MASK_BIT_2_SET 2
+#define SME_QOS_TSPEC_MASK_BIT_1_2_SET 3
+#define SME_QOS_TSPEC_MASK_CLEAR 0
+
+//which key to search on, in the flowlist (1 = flowID, 2 = AC, 4 = reason)
+#define SME_QOS_SEARCH_KEY_INDEX_1 1
+#define SME_QOS_SEARCH_KEY_INDEX_2 2
+#define SME_QOS_SEARCH_KEY_INDEX_3 4
+#define SME_QOS_SEARCH_KEY_INDEX_4 8 // ac + direction
+#define SME_QOS_SEARCH_KEY_INDEX_5 0x10 // ac + tspec_mask
+//special value for searching any Session Id
+#define SME_QOS_SEARCH_SESSION_ID_ANY CSR_ROAM_SESSION_MAX
+#define SME_QOS_ACCESS_POLICY_EDCA 1
+#define SME_QOS_MAX_TID 255
+#define SME_QOS_TSPEC_IE_LENGTH 61
+#define SME_QOS_TSPEC_IE_TYPE 2
+#define SME_QOS_MIN_FLOW_ID 1
+#define SME_QOS_MAX_FLOW_ID 0xFFFFFFFE
+#define SME_QOS_INVALID_FLOW_ID 0xFFFFFFFF
+// per the WMM Specification v1.2 Section 2.2.10
+// The Dialog Token field shall be set [...] to a non-zero value
+#define SME_QOS_MIN_DIALOG_TOKEN 1
+#define SME_QOS_MAX_DIALOG_TOKEN 0xFF
+/*--------------------------------------------------------------------------
+ Type declarations
+ ------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------
+ Enumeration of the various states in the QoS state m/c
+---------------------------------------------------------------------------*/
+typedef enum
+{
+ SME_QOS_CLOSED = 0,
+ SME_QOS_INIT,
+ SME_QOS_LINK_UP,
+ SME_QOS_REQUESTED,
+ SME_QOS_QOS_ON,
+ SME_QOS_HANDOFF,
+
+}sme_QosStates;
+/*---------------------------------------------------------------------------
+ Enumeration of the various QoS cmds
+---------------------------------------------------------------------------*/
+typedef enum
+{
+ SME_QOS_SETUP_REQ = 0,
+ SME_QOS_RELEASE_REQ,
+ SME_QOS_MODIFY_REQ,
+ SME_QOS_RESEND_REQ,
+ SME_QOS_CMD_MAX
+}sme_QosCmdType;
+/*---------------------------------------------------------------------------
+ Enumeration of the various QoS reason codes to be used in the Flow list
+---------------------------------------------------------------------------*/
+typedef enum
+{
+ SME_QOS_REASON_SETUP = 0,
+ SME_QOS_REASON_RELEASE,
+ SME_QOS_REASON_MODIFY,
+ SME_QOS_REASON_MODIFY_PENDING,
+ SME_QOS_REASON_REQ_SUCCESS,
+ SME_QOS_REASON_MAX
+}sme_QosReasonType;
+
+/*---------------------------------------------------------------------------
+ Table to map user priority passed in as an argument to appropriate Access
+ Category as specified in 802.11e/WMM
+---------------------------------------------------------------------------*/
+sme_QosEdcaAcType sme_QosUPtoACMap[SME_QOS_WMM_UP_MAX] =
+{
+ SME_QOS_EDCA_AC_BE, /* User Priority 0 */
+ SME_QOS_EDCA_AC_BK, /* User Priority 1 */
+ SME_QOS_EDCA_AC_BK, /* User Priority 2 */
+ SME_QOS_EDCA_AC_BE, /* User Priority 3 */
+ SME_QOS_EDCA_AC_VI, /* User Priority 4 */
+ SME_QOS_EDCA_AC_VI, /* User Priority 5 */
+ SME_QOS_EDCA_AC_VO, /* User Priority 6 */
+ SME_QOS_EDCA_AC_VO /* User Priority 7 */
+};
+
+/*---------------------------------------------------------------------------
+ Table to map access category (AC) to appropriate user priority as specified
+ in 802.11e/WMM
+ Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs
+ Mapping is done for consistency
+---------------------------------------------------------------------------*/
+sme_QosWmmUpType sme_QosACtoUPMap[SME_QOS_EDCA_AC_MAX] =
+{
+ SME_QOS_WMM_UP_BE, /* AC BE */
+ SME_QOS_WMM_UP_BK, /* AC BK */
+ SME_QOS_WMM_UP_VI, /* AC VI */
+ SME_QOS_WMM_UP_VO /* AC VO */
+};
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's FLOW Link List structure. This list can hold information per
+ flow/request, like TSPEC params requested, which AC it is running on
+---------------------------------------------------------------------------*/
+typedef struct sme_QosFlowInfoEntry_s
+{
+ tListElem link; /* list links */
+ v_U8_t sessionId;
+ v_U8_t tspec_mask;
+ sme_QosReasonType reason;
+ v_U32_t QosFlowID;
+ sme_QosEdcaAcType ac_type;
+ sme_QosWmmTspecInfo QoSInfo;
+ void * HDDcontext;
+ sme_QosCallback QoSCallback;
+ v_BOOL_t hoRenewal;//set to TRUE while re-negotiating flows after
+ //handoff, will set to FALSE once done with
+ //the process. Helps SME to decide if at all
+ //to notify HDD/LIS for flow renewal after HO
+} sme_QosFlowInfoEntry;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's setup request cmd related information structure.
+---------------------------------------------------------------------------*/
+typedef struct sme_QosSetupCmdInfo_s
+{
+ v_U32_t QosFlowID;
+ sme_QosWmmTspecInfo QoSInfo;
+ void *HDDcontext;
+ sme_QosCallback QoSCallback;
+ sme_QosWmmUpType UPType;
+ v_BOOL_t hoRenewal;//set to TRUE while re-negotiating flows after
+ //handoff, will set to FALSE once done with
+ //the process. Helps SME to decide if at all
+ //to notify HDD/LIS for flow renewal after HO
+} sme_QosSetupCmdInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's modify cmd related information structure.
+---------------------------------------------------------------------------*/
+typedef struct sme_QosModifyCmdInfo_s
+{
+ v_U32_t QosFlowID;
+ sme_QosEdcaAcType ac;
+ sme_QosWmmTspecInfo QoSInfo;
+} sme_QosModifyCmdInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's resend cmd related information structure.
+---------------------------------------------------------------------------*/
+typedef struct sme_QosResendCmdInfo_s
+{
+ v_U8_t tspecMask;
+ sme_QosEdcaAcType ac;
+ sme_QosWmmTspecInfo QoSInfo;
+} sme_QosResendCmdInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's release cmd related information structure.
+---------------------------------------------------------------------------*/
+typedef struct sme_QosReleaseCmdInfo_s
+{
+ v_U32_t QosFlowID;
+} sme_QosReleaseCmdInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's buffered cmd related information structure.
+---------------------------------------------------------------------------*/
+typedef struct sme_QosCmdInfo_s
+{
+ sme_QosCmdType command;
+ tpAniSirGlobal pMac;
+ v_U8_t sessionId;
+ union
+ {
+ sme_QosSetupCmdInfo setupCmdInfo;
+ sme_QosModifyCmdInfo modifyCmdInfo;
+ sme_QosResendCmdInfo resendCmdInfo;
+ sme_QosReleaseCmdInfo releaseCmdInfo;
+ }u;
+} sme_QosCmdInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's buffered cmd List structure. This list can hold information
+ related to any pending cmd from HDD
+---------------------------------------------------------------------------*/
+typedef struct sme_QosCmdInfoEntry_s
+{
+ tListElem link; /* list links */
+ sme_QosCmdInfo cmdInfo;
+} sme_QosCmdInfoEntry;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's Per AC information structure. This can hold information on
+ how many flows running on the AC, the current, previous states the AC is in
+---------------------------------------------------------------------------*/
+typedef struct sme_QosACInfo_s
+{
+ v_U8_t num_flows[SME_QOS_TSPEC_INDEX_MAX];
+ sme_QosStates curr_state;
+ sme_QosStates prev_state;
+ sme_QosWmmTspecInfo curr_QoSInfo[SME_QOS_TSPEC_INDEX_MAX];
+ sme_QosWmmTspecInfo requested_QoSInfo[SME_QOS_TSPEC_INDEX_MAX];
+ v_BOOL_t reassoc_pending;//reassoc requested for APSD
+ //As per WMM spec there could be max 2 TSPEC running on the same AC with
+ //different direction. We will refer each TSPEC with an index
+ v_U8_t tspec_mask_status; //status showing if both the indices are in use
+ v_U8_t tspec_pending;//tspec negotiation going on for which index
+ v_BOOL_t hoRenewal;//set to TRUE while re-negotiating flows after
+ //handoff, will set to FALSE once done with
+ //the process. Helps SME to decide if at all
+ //to notify HDD/LIS for flow renewal after HO
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ v_U8_t ricIdentifier[SME_QOS_TSPEC_INDEX_MAX];
+ /* stores the ADD TS response for each AC. The ADD TS response is formed by
+ parsing the RIC received in the the reassoc response */
+ tSirAddtsRsp addTsRsp[SME_QOS_TSPEC_INDEX_MAX];
+#endif
+
+} sme_QosACInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's Per session information structure. This can hold information
+ on the state of the session
+---------------------------------------------------------------------------*/
+typedef struct sme_QosSessionInfo_s
+{
+ // what is this entry's session id
+ v_U8_t sessionId;
+ // is the session currently active
+ v_BOOL_t sessionActive;
+ // All AC info for this session
+ sme_QosACInfo ac_info[SME_QOS_EDCA_AC_MAX];
+ // Bitmask of the ACs with APSD on
+ // Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored
+ v_U8_t apsdMask;
+ // association information for this session
+ sme_QosAssocInfo assocInfo;
+ // ID assigned to our reassoc request
+ v_U32_t roamID;
+ // maintaining a powersave status in QoS module, to be fed back to PMC at
+ // times through the sme_QosPmcCheckRoutine
+ v_BOOL_t readyForPowerSave;
+ // are we in the process of handing off to a different AP
+ v_BOOL_t handoffRequested;
+ // following reassoc or AddTS has UAPSD already been requested from PMC
+ v_BOOL_t uapsdAlreadyRequested;
+ // commands that are being buffered for this session
+ tDblLinkList bufferedCommandList;
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ v_BOOL_t ftHandoffInProgress;
+#endif
+
+} sme_QosSessionInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ Search key union. We can use the flowID, ac type, or reason to find an entry
+ in the flow list
+---------------------------------------------------------------------------*/
+typedef union sme_QosSearchKey_s
+{
+ v_U32_t QosFlowID;
+ sme_QosEdcaAcType ac_type;
+ sme_QosReasonType reason;
+}sme_QosSearchKey;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ We can either use the flowID or the ac type to find an entry in the flow list.
+ The index is a bitmap telling us which key to use. Starting from LSB,
+ bit 0 - Flow ID
+ bit 1 - AC type
+---------------------------------------------------------------------------*/
+typedef struct sme_QosSearchInfo_s
+{
+ v_U8_t sessionId;
+ v_U8_t index;
+ sme_QosSearchKey key;
+ sme_QosWmmDirType direction;
+ v_U8_t tspec_mask;
+}sme_QosSearchInfo;
+/*---------------------------------------------------------------------------
+DESCRIPTION
+ SME QoS module's internal control block.
+---------------------------------------------------------------------------*/
+struct sme_QosCb_s
+{
+ //global Mac pointer
+ tpAniSirGlobal pMac;
+ //All Session Info
+ sme_QosSessionInfo sessionInfo[CSR_ROAM_SESSION_MAX];
+ //All FLOW info
+ tDblLinkList flow_list;
+ //default TSPEC params
+ sme_QosWmmTspecInfo def_QoSInfo[SME_QOS_EDCA_AC_MAX];
+ //counter for assigning Flow IDs
+ v_U32_t nextFlowId;
+ //counter for assigning Dialog Tokens
+ v_U8_t nextDialogToken;
+}sme_QosCb;
+typedef eHalStatus (*sme_QosProcessSearchEntry)(tpAniSirGlobal pMac, tListElem *pEntry);
+/*--------------------------------------------------------------------------
+ Internal function declarations
+ ------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosInternalSetupReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosCallback QoSCallback,
+ void * HDDcontext,
+ sme_QosWmmUpType UPType,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd,
+ v_BOOL_t hoRenewal);
+sme_QosStatusType sme_QosInternalModifyReq(tpAniSirGlobal pMac,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd);
+sme_QosStatusType sme_QosInternalReleaseReq(tpAniSirGlobal pMac,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd);
+sme_QosStatusType sme_QosSetup(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo *pTspec_Info,
+ sme_QosEdcaAcType ac);
+eHalStatus sme_QosAddTsReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pTspec_Info,
+ sme_QosEdcaAcType ac);
+eHalStatus sme_QosDelTsReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspec_mask);
+eHalStatus sme_QosProcessAddTsRsp(tpAniSirGlobal pMac, void *pMsgBuf);
+eHalStatus sme_QosProcessDelTsInd(tpAniSirGlobal pMac, void *pMsgBuf);
+eHalStatus sme_QosProcessDelTsRsp(tpAniSirGlobal pMac, void *pMsgBuf);
+eHalStatus sme_QosProcessAssocCompleteEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessReassocReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessReassocSuccessEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessReassocFailureEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessDisconnectEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessJoinReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessHandoffAssocReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessHandoffSuccessEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessHandoffFailureEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+#ifdef WLAN_FEATURE_VOWIFI_11R
+eHalStatus sme_QosProcessPreauthSuccessInd(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessSetKeySuccessInd(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info);
+eHalStatus sme_QosProcessAggrQosRsp(tpAniSirGlobal pMac, void *pMsgBuf);
+eHalStatus sme_QosFTAggrQosReq( tpAniSirGlobal pMac, v_U8_t sessionId );
+#endif
+eHalStatus sme_QosProcessAddTsSuccessRsp(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ tSirAddtsRspInfo * pRsp);
+eHalStatus sme_QosProcessAddTsFailureRsp(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ tSirAddtsRspInfo * pRsp);
+eHalStatus sme_QosAggregateParams(
+ sme_QosWmmTspecInfo * pInput_Tspec_Info,
+ sme_QosWmmTspecInfo * pCurrent_Tspec_Info,
+ sme_QosWmmTspecInfo * pUpdated_Tspec_Info);
+static eHalStatus sme_QosUpdateParams(v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspec_mask,
+ sme_QosWmmTspecInfo * pTspec_Info);
+sme_QosWmmUpType sme_QosAcToUp(sme_QosEdcaAcType ac);
+sme_QosEdcaAcType sme_QosUpToAc(sme_QosWmmUpType up);
+v_BOOL_t sme_QosIsACM(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc,
+ sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes);
+tListElem *sme_QosFindInFlowList(sme_QosSearchInfo search_key);
+eHalStatus sme_QosFindAllInFlowList(tpAniSirGlobal pMac,
+ sme_QosSearchInfo search_key,
+ sme_QosProcessSearchEntry fnp);
+static void sme_QosStateTransition(v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ sme_QosStates new_state);
+eHalStatus sme_QosBufferCmd(sme_QosCmdInfo *pcmd, v_BOOL_t insert_head);
+static eHalStatus sme_QosProcessBufferedCmd(v_U8_t sessionId);
+eHalStatus sme_QosSaveAssocInfo(sme_QosSessionInfo *pSession, sme_QosAssocInfo *pAssoc_info);
+eHalStatus sme_QosSetupFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosModificationNotifyFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosModifyFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosDelTsIndFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosReassocSuccessEvFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosAddTsFailureFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+eHalStatus sme_QosAddTsSuccessFnp(tpAniSirGlobal pMac, tListElem *pEntry);
+static v_BOOL_t sme_QosIsRspPending(v_U8_t sessionId, sme_QosEdcaAcType ac);
+static v_BOOL_t sme_QosIsUapsdActive(void);
+void sme_QosPmcFullPowerCallback(void *callbackContext, eHalStatus status);
+void sme_QosPmcStartUapsdCallback(void *callbackContext, eHalStatus status);
+v_BOOL_t sme_QosPmcCheckRoutine(void *callbackContext);
+void sme_QosPmcDeviceStateUpdateInd(void *callbackContext, tPmcState pmcState);
+eHalStatus sme_QosProcessOutOfUapsdMode(tpAniSirGlobal pMac);
+eHalStatus sme_QosProcessIntoUapsdMode(tpAniSirGlobal pMac);
+static eHalStatus sme_QosBufferExistingFlows(tpAniSirGlobal pMac,
+ v_U8_t sessionId);
+static eHalStatus sme_QosDeleteExistingFlows(tpAniSirGlobal pMac,
+ v_U8_t sessionId);
+static void sme_QosCleanupCtrlBlkForHandoff(tpAniSirGlobal pMac,
+ v_U8_t sessionId);
+static eHalStatus sme_QosDeleteBufferedRequests(tpAniSirGlobal pMac,
+ v_U8_t sessionId);
+v_BOOL_t sme_QosValidateRequestedParams(tpAniSirGlobal pMac,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U8_t sessionId);
+
+extern eHalStatus sme_AcquireGlobalLock( tSmeStruct *psSme);
+extern eHalStatus sme_ReleaseGlobalLock( tSmeStruct *psSme);
+static eHalStatus qosIssueCommand( tpAniSirGlobal pMac, v_U8_t sessionId,
+ eSmeCommandType cmdType, sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosEdcaAcType ac, v_U8_t tspec_mask );
+/*
+ sme_QosReRequestAddTS to re-send AddTS for the combined QoS request
+*/
+static sme_QosStatusType sme_QosReRequestAddTS(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspecMask);
+static void sme_QosInitACs(tpAniSirGlobal pMac, v_U8_t sessionId);
+static eHalStatus sme_QosRequestReassoc(tpAniSirGlobal pMac, tANI_U8 sessionId,
+ tCsrRoamModifyProfileFields *pModFields,
+ v_BOOL_t fForce );
+static v_U32_t sme_QosAssignFlowId(void);
+static v_U8_t sme_QosAssignDialogToken(void);
+static eHalStatus sme_QosUpdateTspecMask(v_U8_t sessionId,
+ sme_QosSearchInfo search_key,
+ v_U8_t new_tspec_mask);
+/*--------------------------------------------------------------------------
+ External APIs definitions
+ ------------------------------------------------------------------------*/
+/* --------------------------------------------------------------------------
+ \brief sme_QosOpen() - This function must be called before any API call to
+ SME QoS module.
+ \param pMac - Pointer to the global MAC parameter structure.
+
+ \return eHalStatus
+----------------------------------------------------------------------------*/
+eHalStatus sme_QosOpen(tpAniSirGlobal pMac)
+{
+ sme_QosSessionInfo *pSession;
+ v_U8_t sessionId;
+ eHalStatus status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: initializing SME-QoS module",
+ __FUNCTION__, __LINE__);
+ //init the control block
+ //(note that this will make all sessions invalid)
+ vos_mem_zero(&sme_QosCb, sizeof(sme_QosCb));
+ sme_QosCb.pMac = pMac;
+ sme_QosCb.nextFlowId = SME_QOS_MIN_FLOW_ID;
+ sme_QosCb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN;
+ //init flow list
+ status = csrLLOpen(pMac->hHdd, &sme_QosCb.flow_list);
+ if (!HAL_STATUS_SUCCESS(status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot initialize Flow List",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId)
+ {
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pSession->sessionId = sessionId;
+ // initialize the session's per-AC information
+ sme_QosInitACs(pMac, sessionId);
+ // initialize the session's buffered command list
+ status = csrLLOpen(pMac->hHdd, &pSession->bufferedCommandList);
+ if (!HAL_STATUS_SUCCESS(status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot initialize cmd list for session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return eHAL_STATUS_FAILURE;
+ }
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ //the routine registered here gets called by PMC whenever the device is about
+ //to enter one of the power save modes. PMC runs a poll with all the
+ //registered modules if device can enter powersave mode or remain full power
+ if(!HAL_STATUS_SUCCESS(
+ pmcRegisterPowerSaveCheck(pMac, sme_QosPmcCheckRoutine, pMac)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot register with pmcRegisterPowerSaveCheck()",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ //the routine registered here gets called by PMC whenever there is a device
+ // state change. PMC might go to full power because of many reasons and this
+ // is the way for PMC to inform all the other registered modules so that
+ // everyone is in sync.
+ if(!HAL_STATUS_SUCCESS(
+ pmcRegisterDeviceStateUpdateInd(pMac, sme_QosPmcDeviceStateUpdateInd, pMac)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot register with pmcRegisterDeviceStateUpdateInd()",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: done initializing SME-QoS module",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_SUCCESS;
+}
+/* --------------------------------------------------------------------------
+ \brief sme_QosClose() - To close down SME QoS module. There should not be
+ any API call into this module after calling this function until another
+ call of sme_QosOpen.
+ \param pMac - Pointer to the global MAC parameter structure.
+
+ \return eHalStatus
+----------------------------------------------------------------------------*/
+eHalStatus sme_QosClose(tpAniSirGlobal pMac)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosEdcaAcType ac;
+ v_U8_t sessionId;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: closing down SME-QoS",
+ __FUNCTION__, __LINE__);
+ // deregister with PMC
+ if(!HAL_STATUS_SUCCESS(
+ pmcDeregisterDeviceStateUpdateInd(pMac, sme_QosPmcDeviceStateUpdateInd)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot deregister with pmcDeregisterDeviceStateUpdateInd()",
+ __FUNCTION__, __LINE__);
+ }
+ if(!HAL_STATUS_SUCCESS(
+ pmcDeregisterPowerSaveCheck(pMac, sme_QosPmcCheckRoutine)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: cannot deregister with pmcDeregisterPowerSaveCheck()",
+ __FUNCTION__, __LINE__);
+ }
+ //cleanup control block
+ //close the flow list
+ csrLLClose(&sme_QosCb.flow_list);
+ // shut down all of the sessions
+ for(sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId)
+ {
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if (pSession == NULL)
+ continue;
+
+ sme_QosInitACs(pMac, sessionId);
+ // this session doesn't require UAPSD
+ pSession->apsdMask = 0;
+
+ pSession->uapsdAlreadyRequested = VOS_FALSE;
+ pSession->handoffRequested = VOS_FALSE;
+ pSession->readyForPowerSave = VOS_TRUE;
+ pSession->roamID = 0;
+ //need to clean up buffered req
+ sme_QosDeleteBufferedRequests(pMac, sessionId);
+ //need to clean up flows
+ sme_QosDeleteExistingFlows(pMac, sessionId);
+
+ // Clean up the assoc info if already allocated
+ if (pSession->assocInfo.pBssDesc) {
+ vos_mem_free(pSession->assocInfo.pBssDesc);
+ pSession->assocInfo.pBssDesc = NULL;
+ }
+
+ // close the session's buffered command list
+ csrLLClose(&pSession->bufferedCommandList);
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ sme_QosStateTransition(sessionId, ac, SME_QOS_CLOSED);
+ }
+ pSession->sessionActive = VOS_FALSE;
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: closed down QoS",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosSetupReq() - The SME QoS API exposed to HDD to request for QoS
+ on a particular AC. This function should be called after a link has been
+ established, i.e. STA is associated with an AP etc. If the request involves
+ admission control on the requested AC, HDD needs to provide the necessary
+ Traffic Specification (TSPEC) parameters otherwise SME is going to use the
+ default params.
+
+ \param hHal - The handle returned by macOpen.
+ \param sessionId - sessionId returned by sme_OpenSession.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info as defined above, provided by HDD
+ \param QoSCallback - The callback which is registered per flow while
+ requesting for QoS. Used for any notification for the
+ flow (i.e. setup success/failure/release) which needs to
+ be sent to HDD
+ \param HDDcontext - A cookie passed by HDD to be used by SME during any QoS
+ notification (through the callabck) to HDD
+ \param UPType - Useful only if HDD or any other upper layer module (BAP etc.)
+ looking for implicit QoS setup, in that
+ case, the pQoSInfo will be NULL & SME will know about the AC
+ (from the UP provided in this param) QoS is requested on
+ \param pQosFlowID - Identification per flow running on each AC generated by
+ SME.
+ It is only meaningful if the QoS setup for the flow is
+ successful
+
+ \return eHAL_STATUS_SUCCESS - Setup is successful.
+
+ Other status means Setup request failed
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosSetupReq(tHalHandle hHal, tANI_U32 sessionId,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosCallback QoSCallback,
+ void * HDDcontext,
+ sme_QosWmmUpType UPType, v_U32_t * pQosFlowID)
+{
+ sme_QosSessionInfo *pSession;
+ eHalStatus lock_status = eHAL_STATUS_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+ sme_QosStatusType status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS Setup requested by client on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ lock_status = sme_AcquireGlobalLock( &pMac->sme );
+ if ( !HAL_STATUS_SUCCESS( lock_status ) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Unable to obtain lock",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ //Make sure the session is valid
+ if (!CSR_IS_SESSION_VALID( pMac, sessionId ))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Supplied Session ID %d is invalid",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ else
+ {
+ //Make sure the session is active
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if (!pSession->sessionActive)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Supplied Session ID %d is inactive",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ else
+ {
+ //Assign a Flow ID
+ *pQosFlowID = sme_QosAssignFlowId();
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS request on session %d assigned Flow ID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, *pQosFlowID);
+ //Call the internal function for QoS setup,
+ // adding a layer of abstraction
+ status = sme_QosInternalSetupReq(pMac, (v_U8_t)sessionId, pQoSInfo,
+ QoSCallback, HDDcontext, UPType,
+ *pQosFlowID, VOS_FALSE, VOS_FALSE);
+ }
+ }
+ sme_ReleaseGlobalLock( &pMac->sme );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS setup return status on session %d is %d",
+ __FUNCTION__, __LINE__,
+ sessionId, status);
+ return status;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosModifyReq() - The SME QoS API exposed to HDD to request for
+ modification of certain QoS params on a flow running on a particular AC.
+ This function should be called after a link has been established, i.e. STA is
+ associated with an AP etc. & a QoS setup has been succesful for that flow.
+ If the request involves admission control on the requested AC, HDD needs to
+ provide the necessary Traffic Specification (TSPEC) parameters & SME might
+ start the renegotiation process through ADDTS.
+
+ \param hHal - The handle returned by macOpen.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info as defined above, provided by HDD
+ \param QosFlowID - Identification per flow running on each AC generated by
+ SME.
+ It is only meaningful if the QoS setup for the flow has
+ been successful already
+
+ \return SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful.
+
+ Other status means request failed
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosModifyReq(tHalHandle hHal,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U32_t QosFlowID)
+{
+ eHalStatus lock_status = eHAL_STATUS_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+ sme_QosStatusType status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS Modify requested by client for Flow %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ lock_status = sme_AcquireGlobalLock( &pMac->sme );
+ if ( !HAL_STATUS_SUCCESS( lock_status ) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Unable to obtain lock",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ //Call the internal function for QoS modify, adding a layer of abstraction
+ status = sme_QosInternalModifyReq(pMac, pQoSInfo, QosFlowID, VOS_FALSE);
+ sme_ReleaseGlobalLock( &pMac->sme );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS Modify return status on Flow %d is %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID, status);
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosReleaseReq() - The SME QoS API exposed to HDD to request for
+ releasing a QoS flow running on a particular AC. This function should be
+ called only if a QoS is set up with a valid FlowID. HDD sould invoke this
+ API only if an explicit request for QoS release has come from Application
+
+ \param hHal - The handle returned by macOpen.
+ \param QosFlowID - Identification per flow running on each AC generated by SME
+ It is only meaningful if the QoS setup for the flow is
+ successful
+
+ \return eHAL_STATUS_SUCCESS - Release is successful.
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosReleaseReq(tHalHandle hHal, v_U32_t QosFlowID)
+{
+ eHalStatus lock_status = eHAL_STATUS_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+ sme_QosStatusType status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS Release requested by client for Flow %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ lock_status = sme_AcquireGlobalLock( &pMac->sme );
+ if ( !HAL_STATUS_SUCCESS( lock_status ) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Unable to obtain lock",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ }
+ //Call the internal function for QoS release, adding a layer of abstraction
+ status = sme_QosInternalReleaseReq(pMac, QosFlowID, VOS_FALSE);
+ sme_ReleaseGlobalLock( &pMac->sme );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS Release return status on Flow %d is %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID, status);
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosSetParams() - This function is used by HDD to provide the
+ default TSPEC params to SME.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info per AC as defined above, provided by HDD
+
+ \return eHAL_STATUS_SUCCESS - Setparam is successful.
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosSetParams(tpAniSirGlobal pMac, sme_QosWmmTspecInfo * pQoSInfo)
+{
+ sme_QosEdcaAcType ac;
+ // find the AC
+ ac = sme_QosUpToAc(pQoSInfo->ts_info.up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Invalid AC %d (via UP %d)",
+ __FUNCTION__, __LINE__,
+ ac, pQoSInfo->ts_info.up );
+ return eHAL_STATUS_FAILURE;
+ }
+ //copy over the default params for this AC
+ sme_QosCb.def_QoSInfo[ac] = *pQoSInfo;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: QoS default params set for AC %d (via UP %d)",
+ __FUNCTION__, __LINE__,
+ ac, pQoSInfo->ts_info.up );
+ return eHAL_STATUS_SUCCESS;
+}
+
+void qosReleaseCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand )
+{
+ vos_mem_zero( &pCommand->u.qosCmd, sizeof( tGenericQosCmd ) );
+ smeReleaseCommand( pMac, pCommand );
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosMsgProcessor() - sme_ProcessMsg() calls this function for the
+ messages that are handled by SME QoS module.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param msg_type - the type of msg passed by PE as defined in wniApi.h
+ \param pMsgBuf - a pointer to a buffer that maps to various structures base
+ on the message type.
+ The beginning of the buffer can always map to tSirSmeRsp.
+
+ \return eHAL_STATUS_SUCCESS - Validation is successful.
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosMsgProcessor( tpAniSirGlobal pMac, v_U16_t msg_type,
+ void *pMsgBuf)
+{
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: msg = %d for QoS",
+ __FUNCTION__, __LINE__, msg_type);
+ //switch on the msg type & make the state transition accordingly
+ switch(msg_type)
+ {
+ case eWNI_SME_ADDTS_RSP:
+ pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if( pEntry )
+ {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if( eSmeCommandAddTs == pCommand->command )
+ {
+ status = sme_QosProcessAddTsRsp(pMac, pMsgBuf);
+ if( csrLLRemoveEntry( &pMac->sme.smeCmdActiveList, pEntry, LL_ACCESS_LOCK ) )
+ {
+ qosReleaseCommand( pMac, pCommand );
+ }
+ smeProcessPendingQueue( pMac );
+ }
+ }
+ break;
+ case eWNI_SME_DELTS_RSP:
+ pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if( pEntry )
+ {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if( eSmeCommandDelTs == pCommand->command )
+ {
+ status = sme_QosProcessDelTsRsp(pMac, pMsgBuf);
+ if( csrLLRemoveEntry( &pMac->sme.smeCmdActiveList, pEntry, LL_ACCESS_LOCK ) )
+ {
+ qosReleaseCommand( pMac, pCommand );
+ }
+ smeProcessPendingQueue( pMac );
+ }
+ }
+ break;
+ case eWNI_SME_DELTS_IND:
+ status = sme_QosProcessDelTsInd(pMac, pMsgBuf);
+ break;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ case eWNI_SME_FT_AGGR_QOS_RSP:
+ status = sme_QosProcessAggrQosRsp(pMac, pMsgBuf);
+ break;
+#endif
+
+ default:
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: unknown msg type = %d",
+ __FUNCTION__, __LINE__, msg_type);
+ break;
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosValidateParams() - The SME QoS API exposed to CSR to validate AP
+ capabilities regarding QoS support & any other QoS parameter validation.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pBssDesc - Pointer to the BSS Descriptor information passed down by
+ CSR to PE while issuing the Join request
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosValidateParams(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc)
+{
+ tDot11fBeaconIEs *pIes = NULL;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: validation for QAP & APSD",
+ __FUNCTION__, __LINE__);
+ do
+ {
+ if(!HAL_STATUS_SUCCESS(csrGetParsedBssDescriptionIEs(pMac, pBssDesc, &pIes)))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: csrGetParsedBssDescriptionIEs() failed",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ //check if the AP is QAP & it supports APSD
+ if( !CSR_IS_QOS_BSS(pIes) )
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: AP doesn't support QoS",
+ __FUNCTION__, __LINE__);
+
+ break;
+ }
+ if(!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) &&
+ !(pIes->WMMInfoAp.uapsd))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: AP doesn't support APSD",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ status = eHAL_STATUS_SUCCESS;
+ }while(0);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: validated with status = %d",
+ __FUNCTION__, __LINE__, status);
+ if(pIes)
+ {
+ vos_mem_free(pIes);
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosCsrEventInd() - The QoS sub-module in SME expects notifications
+ from CSR when certain events occur as mentioned in sme_QosCsrEventIndType.
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param ind - The event occurred of type sme_QosCsrEventIndType.
+ \param pEvent_info - Information related to the event
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosCsrEventInd(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosCsrEventIndType ind,
+ void *pEvent_info)
+{
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On Session %d Event %d received from CSR",
+ __FUNCTION__, __LINE__,
+ sessionId, ind );
+ switch(ind)
+ {
+ case SME_QOS_CSR_ASSOC_COMPLETE:
+ //expecting assoc info in pEvent_info
+ status = sme_QosProcessAssocCompleteEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_REASSOC_REQ:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessReassocReqEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_REASSOC_COMPLETE:
+ //expecting assoc info in pEvent_info
+ status = sme_QosProcessReassocSuccessEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_REASSOC_FAILURE:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessReassocFailureEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_DISCONNECT_REQ:
+ case SME_QOS_CSR_DISCONNECT_IND:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessDisconnectEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_JOIN_REQ:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessJoinReqEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_HANDOFF_ASSOC_REQ:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessHandoffAssocReqEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_HANDOFF_COMPLETE:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessHandoffSuccessEv(pMac, sessionId, pEvent_info);
+ break;
+ case SME_QOS_CSR_HANDOFF_FAILURE:
+ //nothing expected in pEvent_info
+ status = sme_QosProcessHandoffFailureEv(pMac, sessionId, pEvent_info);
+ break;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ case SME_QOS_CSR_PREAUTH_SUCCESS_IND:
+ status = sme_QosProcessPreauthSuccessInd(pMac, sessionId, pEvent_info);
+ break;
+#ifdef FEATURE_WLAN_CCX
+ case SME_QOS_CSR_SET_KEY_SUCCESS_IND:
+ status = sme_QosProcessSetKeySuccessInd(pMac, sessionId, pEvent_info);
+ break;
+#endif
+#endif
+ default:
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On Session %d Unknown Event %d received from CSR",
+ __FUNCTION__, __LINE__,
+ sessionId, ind );
+ break;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On Session %d processed Event %d with status %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ind, status );
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosGetACMMask() - The QoS sub-module API to find out on which ACs
+ AP mandates Admission Control (ACM = 1)
+ (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored)
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pSirBssDesc - The event occurred of type sme_QosCsrEventIndType.
+
+ \return a bit mask indicating for which ACs AP has ACM set to 1
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+v_U8_t sme_QosGetACMMask(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes)
+{
+ sme_QosEdcaAcType ac;
+ v_U8_t acm_mask = 0;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked",
+ __FUNCTION__, __LINE__);
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ if(sme_QosIsACM(pMac, pSirBssDesc, ac, pIes))
+ {
+ acm_mask = acm_mask | (1 << (SME_QOS_EDCA_AC_VO - ac));
+ }
+
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: mask is %d",
+ __FUNCTION__, __LINE__, acm_mask);
+ return acm_mask;
+}
+/*--------------------------------------------------------------------------
+ Internal function definitions
+ ------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------
+ \brief sme_QosInternalSetupReq() - The SME QoS internal setup request handling
+ function.
+ If the request involves admission control on the requested AC, HDD needs to
+ provide the necessary Traffic Specification (TSPEC) parameters otherwise SME
+ is going to use the default params.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info as defined above, provided by HDD
+ \param QoSCallback - The callback which is registered per flow while
+ requesting for QoS. Used for any notification for the
+ flow (i.e. setup success/failure/release) which needs to
+ be sent to HDD
+ \param HDDcontext - A cookie passed by HDD to be used by SME during any QoS
+ notification (through the callabck) to HDD
+ \param UPType - Useful only if HDD or any other upper layer module (BAP etc.)
+ looking for implicit QoS setup, in that
+ case, the pQoSInfo will be NULL & SME will know about the AC
+ (from the UP provided in this param) QoS is requested on
+ \param QosFlowID - Identification per flow running on each AC generated by
+ SME.
+ It is only meaningful if the QoS setup for the flow is
+ successful
+ \param buffered_cmd - tells us if the cmd was a buffered one or fresh from
+ client
+
+ \return eHAL_STATUS_SUCCESS - Setup is successful.
+
+ Other status means Setup request failed
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosInternalSetupReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosCallback QoSCallback,
+ void * HDDcontext,
+ sme_QosWmmUpType UPType,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd,
+ v_BOOL_t hoRenewal)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+ sme_QosWmmTspecInfo Tspec_Info;
+ sme_QosStates new_state = SME_QOS_CLOSED;
+ sme_QosFlowInfoEntry *pentry = NULL;
+ sme_QosCmdInfo cmd;
+ sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ v_U8_t tmask = 0;
+ v_U8_t new_tmask = 0;
+ sme_QosSearchInfo search_key;
+ v_BOOL_t bufferCommand;
+ eHalStatus hstatus;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for flow %d",
+ __FUNCTION__, __LINE__,
+ sessionId, QosFlowID);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ // if caller sent an empty TSPEC, fill up with the default one
+ if(!pQoSInfo)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ "%s: %d: caller sent an empty QoS param list, using defaults",
+ __FUNCTION__, __LINE__);
+ // find the AC with UPType passed in
+ ac = sme_QosUpToAc(UPType);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__,
+ ac, UPType);
+
+ return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP;
+ }
+ Tspec_Info = sme_QosCb.def_QoSInfo[ac];
+ }
+ else
+ {
+ // find the AC
+ ac = sme_QosUpToAc(pQoSInfo->ts_info.up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__,
+ ac, pQoSInfo->ts_info.up);
+
+ return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP;
+ }
+ //validate QoS params
+ if(!sme_QosValidateRequestedParams(pMac, pQoSInfo, sessionId))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid params",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP;
+ }
+ Tspec_Info = *pQoSInfo;
+ }
+ pACInfo = &pSession->ac_info[ac];
+ // need to vote off powersave for the duration of this request
+ pSession->readyForPowerSave = VOS_FALSE;
+ // assume we won't have to (re)buffer the command
+ bufferCommand = VOS_FALSE;
+ //check to consider the following flowing scenario
+ //Addts request is pending on one AC, while APSD requested on another which
+ //needs a reassoc. Will buffer a request if Addts is pending on any AC,
+ //which will safegaurd the above scenario, & also won't confuse PE with back
+ //to back Addts or Addts followed by Reassoc
+ if(sme_QosIsRspPending(sessionId, ac))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the setup request for flow %d in state %d "
+ "since another request is pending",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ else
+ {
+ // make sure we are in full power so that we can issue
+ // an AddTS or reassoc if necessary
+ hstatus = pmcRequestFullPower(pMac, sme_QosPmcFullPowerCallback,
+ pSession, eSME_REASON_OTHER);
+ if( eHAL_STATUS_PMC_PENDING == hstatus )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the setup request for flow %d in state %d, "
+ "waiting for full power",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ }
+ if (bufferCommand)
+ {
+ // we need to buffer the command
+ cmd.command = SME_QOS_SETUP_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.setupCmdInfo.HDDcontext = HDDcontext;
+ cmd.u.setupCmdInfo.QoSInfo = Tspec_Info;
+ cmd.u.setupCmdInfo.QoSCallback = QoSCallback;
+ cmd.u.setupCmdInfo.UPType = UPType;
+ cmd.u.setupCmdInfo.hoRenewal = hoRenewal;
+ cmd.u.setupCmdInfo.QosFlowID = QosFlowID;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the setup request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Buffered setup request for flow = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ return SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ }
+
+ //get into the state m/c to see if the request can be granted
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_LINK_UP:
+ //call the internal qos setup logic to decide on if the
+ // request is NOP, or need reassoc for APSD and/or need to send out ADDTS
+ status = sme_QosSetup(pMac, sessionId, &Tspec_Info, ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d with AC %d in state SME_QOS_LINK_UP "
+ "sme_QosSetup returned with status %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, status);
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status)
+ {
+ // we aren't waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)||
+ (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ // we received an expected "good" status
+ //create an entry in the flow list
+ pentry = vos_mem_malloc(sizeof(*pentry));
+ if (!pentry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the new "
+ "entry in the Flow List",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ pentry->ac_type = ac;
+ pentry->HDDcontext = HDDcontext;
+ pentry->QoSCallback = QoSCallback;
+ pentry->hoRenewal = hoRenewal;
+ pentry->QosFlowID = QosFlowID;
+ pentry->sessionId = sessionId;
+ // since we are in state SME_QOS_LINK_UP this must be the
+ // first TSPEC on this AC, so use index 0 (mask bit 1)
+ pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0] = Tspec_Info;
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)
+ {
+ if(pACInfo->tspec_mask_status &&
+ !pACInfo->reassoc_pending)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d with AC %d in state "
+ "SME_QOS_LINK_UP tspec_mask_status is %d "
+ "but should not be set yet",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->tspec_mask_status);
+ //ASSERT
+ VOS_ASSERT(0);
+ vos_mem_free(pentry);
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ if(!pACInfo->reassoc_pending)
+ {
+ // we didn't request for reassoc, it must be a tspec negotiation
+ pACInfo->tspec_pending = 1;
+ }
+
+ pentry->reason = SME_QOS_REASON_SETUP;
+ new_state = SME_QOS_REQUESTED;
+ }
+ else
+ {
+ // SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP or
+ // SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY
+ pentry->reason = SME_QOS_REASON_REQ_SUCCESS;
+ new_state = SME_QOS_QOS_ON;
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = Tspec_Info;
+ if(buffered_cmd && !pentry->hoRenewal)
+ {
+ QoSCallback(pMac, HDDcontext,
+ &pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ status,
+ pentry->QosFlowID);
+ }
+ pentry->hoRenewal = VOS_FALSE;
+ }
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]++;
+
+ //indicate on which index the flow entry belongs to & add it to the
+ //Flow List at the end
+ pentry->tspec_mask = pACInfo->tspec_mask_status;
+ pentry->QoSInfo = Tspec_Info;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Creating entry on session %d at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, pentry, QosFlowID);
+ csrLLInsertTail(&sme_QosCb.flow_list, &pentry->link, VOS_TRUE);
+ }
+ else
+ {
+ // unexpected status returned by sme_QosSetup()
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unexpected status %d "
+ "returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ sessionId, status);
+ new_state = pACInfo->curr_state;
+ if(buffered_cmd && hoRenewal)
+ {
+ QoSCallback(pMac, HDDcontext,
+ &pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ SME_QOS_STATUS_RELEASE_QOS_LOST_IND,
+ QosFlowID);
+ }
+ }
+ break;
+ case SME_QOS_HANDOFF:
+ case SME_QOS_REQUESTED:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: Buffering setup request for flow %d in state = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ //buffer cmd
+ cmd.command = SME_QOS_SETUP_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.setupCmdInfo.HDDcontext = HDDcontext;
+ cmd.u.setupCmdInfo.QoSInfo = Tspec_Info;
+ cmd.u.setupCmdInfo.QoSCallback = QoSCallback;
+ cmd.u.setupCmdInfo.UPType = UPType;
+ cmd.u.setupCmdInfo.hoRenewal = hoRenewal;
+ cmd.u.setupCmdInfo.QosFlowID = QosFlowID;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d couldn't buffer the setup "
+ "request for flow %d in state = %d",
+ __FUNCTION__, __LINE__,
+ sessionId, QosFlowID, pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ new_state = pACInfo->curr_state;
+ break;
+ case SME_QOS_QOS_ON:
+
+ //check if multiple flows running on the ac
+ if((pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] > 0)||
+ (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0))
+ {
+ //do we need to care about the case where APSD needed on ACM = 0 below?
+ if(CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) ||
+ sme_QosIsACM(pMac, pSession->assocInfo.pBssDesc, ac, NULL))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: tspec_mask_status = %d for AC = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->tspec_mask_status, ac);
+ if(!pACInfo->tspec_mask_status)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: tspec_mask_status can't be 0 for ac = %d in "
+ "state = %d",
+ __FUNCTION__, __LINE__,
+ ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return status;
+ }
+ /* Flow aggregation */
+ if(SME_QOS_TSPEC_MASK_BIT_1_2_SET != pACInfo->tspec_mask_status)
+ {
+ /* Either of upstream, downstream or bidirectional flows are present */
+ /* If either of new stream or current stream is for bidirecional, aggregate
+ * the new stream with the current streams present and send out aggregated Tspec.*/
+ if((Tspec_Info.ts_info.direction == SME_QOS_WMM_TS_DIR_BOTH) ||
+ (pACInfo->curr_QoSInfo[pACInfo->tspec_mask_status - 1].
+ ts_info.direction == SME_QOS_WMM_TS_DIR_BOTH))
+ {
+ // Aggregate the new stream with the current stream(s).
+ tmask = pACInfo->tspec_mask_status;
+ }
+ /* None of new stream or current (aggregated) streams are for bidirectional.
+ * Check if the new stream direction matches the current stream direction. */
+ else if(pACInfo->curr_QoSInfo[pACInfo->tspec_mask_status - 1].
+ ts_info.direction == Tspec_Info.ts_info.direction)
+ {
+ // Aggregate the new stream with the current stream(s).
+ tmask = pACInfo->tspec_mask_status;
+ }
+ /* New stream is in different direction. */
+ else
+ {
+ // No Aggregation. Mark the 2nd tpsec index also as active.
+ tmask = SME_QOS_TSPEC_MASK_CLEAR;
+ new_tmask = SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~pACInfo->tspec_mask_status;
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_BIT_1_2_SET;
+ }
+ }
+ else
+ {
+ /* Both uplink and downlink streams are present. */
+ /* If new stream is bidirectional, aggregate new stream with all existing
+ * upstreams and downstreams. Send out new aggregated tpsec. */
+ if(Tspec_Info.ts_info.direction == SME_QOS_WMM_TS_DIR_BOTH)
+ {
+ // Only one tspec index (0) will be in use after this aggregation.
+ tmask = SME_QOS_TSPEC_MASK_BIT_1_2_SET;
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ }
+ /* New stream is also uni-directional
+ * Find out the tsepc index with which it needs to be aggregated */
+ else if(pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.direction !=
+ Tspec_Info.ts_info.direction)
+ {
+ // Aggregate with 2nd tspec index
+ tmask = SME_QOS_TSPEC_MASK_BIT_2_SET;
+ }
+ else
+ {
+ // Aggregate with 1st tspec index
+ tmask = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ }
+ }
+ }
+ else
+ {
+ //ACM = 0
+ // We won't be sending a TSPEC to the AP but we still need
+ // to aggregate to calculate trigger frame parameters
+ tmask = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: tmask = %d, new_tmask = %d in state = %d",
+ __FUNCTION__, __LINE__,
+ tmask, new_tmask, pACInfo->curr_state );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: tspec_mask_status = %d for AC = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->tspec_mask_status, ac);
+ if(tmask)
+ {
+ // create the aggregate TSPEC
+ if(tmask != SME_QOS_TSPEC_MASK_BIT_1_2_SET)
+ {
+ hstatus = sme_QosAggregateParams(&Tspec_Info,
+ &pACInfo->curr_QoSInfo[tmask - 1],
+ &pACInfo->requested_QoSInfo[tmask - 1]);
+ }
+ else
+ {
+ /* Aggregate the new bidirectional stream with the existing upstreams and
+ * downstreams in tspec indices 0 and 1. */
+ tmask = SME_QOS_TSPEC_MASK_BIT_1_SET;
+
+ if((hstatus = sme_QosAggregateParams(&Tspec_Info,
+ &pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ &pACInfo->requested_QoSInfo[tmask - 1]))
+ == eHAL_STATUS_SUCCESS)
+ {
+ hstatus = sme_QosAggregateParams(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ &pACInfo->requested_QoSInfo[tmask - 1],
+ NULL);
+ }
+ }
+
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: failed to aggregate params",
+ __FUNCTION__, __LINE__);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ }
+ else
+ {
+ tmask = new_tmask;
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no flows running for ac = %d while in state = %d",
+ __FUNCTION__, __LINE__,
+ ac, pACInfo->curr_state );
+ //ASSERT
+ VOS_ASSERT(0);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return status;
+ }
+ //although aggregating, make sure to request on the correct UP
+ pACInfo->requested_QoSInfo[tmask - 1].ts_info.up = Tspec_Info.ts_info.up;
+ status = sme_QosSetup(pMac, sessionId,
+ &pACInfo->requested_QoSInfo[tmask - 1], ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON "
+ "sme_QosSetup returned with status %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, status);
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status)
+ {
+ // we aren't waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)||
+ (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ // we received an expected "good" status
+ //create an entry in the flow list
+ pentry = (sme_QosFlowInfoEntry *) vos_mem_malloc(sizeof(*pentry));
+ if (!pentry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the new "
+ "entry in the Flow List",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ }
+ pentry->ac_type = ac;
+ pentry->HDDcontext = HDDcontext;
+ pentry->QoSCallback = QoSCallback;
+ pentry->hoRenewal = hoRenewal;
+ pentry->QosFlowID = QosFlowID;
+ pentry->sessionId = sessionId;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Creating flow %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ if((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status)||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ new_state = pACInfo->curr_state;
+ pentry->reason = SME_QOS_REASON_REQ_SUCCESS;
+ pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] =
+ pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0];
+ if(buffered_cmd && !pentry->hoRenewal)
+ {
+ QoSCallback(pMac, HDDcontext,
+ &pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ status,
+ pentry->QosFlowID);
+ }
+ if(SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)
+ {
+ // if we are not in handoff, then notify all flows on
+ // this AC that the aggregate TSPEC may have changed
+ if(!pentry->hoRenewal)
+ {
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ hstatus = sme_QosFindAllInFlowList(pMac, search_key,
+ sme_QosSetupFnp);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't notify other "
+ "entries on this AC =%d",
+ __FUNCTION__, __LINE__, ac);
+ }
+ }
+ }
+ pentry->hoRenewal = VOS_FALSE;
+ }
+ else
+ {
+ // SME_QOS_STATUS_SETUP_REQ_PENDING_RSP
+ new_state = SME_QOS_REQUESTED;
+ pentry->reason = SME_QOS_REASON_SETUP;
+ //Need this info when addts comes back from PE to know on
+ //which index of the AC the request was from
+ pACInfo->tspec_pending = tmask;
+ }
+ pACInfo->num_flows[tmask - 1]++;
+ //indicate on which index the flow entry belongs to & add it to the
+ //Flow List at the end
+ pentry->tspec_mask = tmask;
+ pentry->QoSInfo = Tspec_Info;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d creating entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, pentry, QosFlowID);
+ csrLLInsertTail(&sme_QosCb.flow_list, &pentry->link, VOS_TRUE);
+ }
+ else
+ {
+ // unexpected status returned by sme_QosSetup()
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unexpected status %d "
+ "returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ sessionId, status);
+ new_state = pACInfo->curr_state;
+ }
+ break;
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: setup requested in unexpected state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ VOS_ASSERT(0);
+ new_state = pACInfo->curr_state;
+ }
+ /* if current state is same as previous no need for transistion,
+ if we are doing reassoc & we are already in handoff state, no need to move
+ to requested state. But make sure to set the previous state as requested
+ state
+ */
+ if((new_state != pACInfo->curr_state)&&
+ (!(pACInfo->reassoc_pending &&
+ (SME_QOS_HANDOFF == pACInfo->curr_state))))
+ {
+ sme_QosStateTransition(sessionId, ac, new_state);
+ }
+
+ if(pACInfo->reassoc_pending &&
+ (SME_QOS_HANDOFF == pACInfo->curr_state))
+ {
+ pACInfo->prev_state = SME_QOS_REQUESTED;
+ }
+ if((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ }
+ return status;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosInternalModifyReq() - The SME QoS internal function to request
+ for modification of certain QoS params on a flow running on a particular AC.
+ If the request involves admission control on the requested AC, HDD needs to
+ provide the necessary Traffic Specification (TSPEC) parameters & SME might
+ start the renegotiation process through ADDTS.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info as defined above, provided by HDD
+ \param QosFlowID - Identification per flow running on each AC generated by
+ SME.
+ It is only meaningful if the QoS setup for the flow has
+ been successful already
+
+ \return SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful.
+
+ Other status means request failed
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosInternalModifyReq(tpAniSirGlobal pMac,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd)
+{
+ tListElem *pEntry= NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *pNewEntry= NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosEdcaAcType ac;
+ sme_QosStates new_state = SME_QOS_CLOSED;
+ sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ sme_QosWmmTspecInfo Aggr_Tspec_Info;
+ sme_QosSearchInfo search_key;
+ sme_QosCmdInfo cmd;
+ v_U8_t sessionId;
+ v_BOOL_t bufferCommand;
+ eHalStatus hstatus;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked for flow %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.QosFlowID = QosFlowID;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_1;
+ search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY;
+ //go through the link list to find out the details on the flow
+ pEntry = sme_QosFindInFlowList(search_key);
+ if(!pEntry)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no match found for flowID = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP;
+ }
+ // find the AC
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+
+ sessionId = flow_info->sessionId;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+
+ //validate QoS params
+ if(!sme_QosValidateRequestedParams(pMac, pQoSInfo, sessionId))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid params",
+ __FUNCTION__, __LINE__);
+ return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP;
+ }
+ // For modify, make sure that direction, TID and UP are not being altered
+ if((pQoSInfo->ts_info.direction != flow_info->QoSInfo.ts_info.direction) ||
+ (pQoSInfo->ts_info.up != flow_info->QoSInfo.ts_info.up) ||
+ (pQoSInfo->ts_info.tid != flow_info->QoSInfo.ts_info.tid))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Modification of direction/tid/up is not allowed",
+ __FUNCTION__, __LINE__);
+
+ return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP;
+ }
+ // need to vote off powersave for the duration of this request
+ pSession->readyForPowerSave = VOS_FALSE;
+ // assume we won't have to (re)buffer the command
+ bufferCommand = VOS_FALSE;
+ //check to consider the following flowing scenario
+ //Addts request is pending on one AC, while APSD requested on another which
+ //needs a reassoc. Will buffer a request if Addts is pending on any AC,
+ //which will safegaurd the above scenario, & also won't confuse PE with back
+ //to back Addts or Addts followed by Reassoc
+ if(sme_QosIsRspPending(sessionId, ac))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the modify request for flow %d in state %d "
+ "since another request is pending",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ else
+ {
+ // make sure we are in full power so that we can issue
+ // an AddTS or reassoc if necessary
+ hstatus = pmcRequestFullPower(pMac, sme_QosPmcFullPowerCallback,
+ pSession, eSME_REASON_OTHER);
+ if( eHAL_STATUS_PMC_PENDING == hstatus )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the modify request for flow %d in state %d, "
+ "waiting for full power",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ }
+ if (bufferCommand)
+ {
+ // we need to buffer the command
+ cmd.command = SME_QOS_MODIFY_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.modifyCmdInfo.QosFlowID = QosFlowID;
+ cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the modify request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Buffered modify request for flow = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ }
+ //get into the stat m/c to see if the request can be granted
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_QOS_ON:
+ //save the new params adding a new (duplicate) entry in the Flow List
+ //Once we have decided on OTA exchange needed or not we can delete the
+ //original one from the List
+ pNewEntry = (sme_QosFlowInfoEntry *) vos_mem_malloc(sizeof(*pNewEntry));
+ if (!pNewEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the new "
+ "entry in the Flow List",
+ __FUNCTION__, __LINE__);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ pNewEntry->ac_type = ac;
+ pNewEntry->sessionId = sessionId;
+ pNewEntry->HDDcontext = flow_info->HDDcontext;
+ pNewEntry->QoSCallback = flow_info->QoSCallback;
+ pNewEntry->QosFlowID = flow_info->QosFlowID;
+ pNewEntry->reason = SME_QOS_REASON_MODIFY_PENDING;
+ //since it is a modify request, use the same index on which the flow
+ //entry originally was running & add it to the Flow List at the end
+ pNewEntry->tspec_mask = flow_info->tspec_mask;
+ pNewEntry->QoSInfo = *pQoSInfo;
+ //update the entry from Flow List which needed to be modified
+ flow_info->reason = SME_QOS_REASON_MODIFY;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d creating modified "
+ "entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, pNewEntry, pNewEntry->QosFlowID);
+ //add the new entry under construction to the Flow List
+ csrLLInsertTail(&sme_QosCb.flow_list, &pNewEntry->link, VOS_TRUE);
+ //update TSPEC with the new param set
+ hstatus = sme_QosUpdateParams(sessionId,
+ ac, pNewEntry->tspec_mask,
+ &Aggr_Tspec_Info);
+ if(HAL_STATUS_SUCCESS(hstatus))
+ {
+ pACInfo->requested_QoSInfo[pNewEntry->tspec_mask -1] = Aggr_Tspec_Info;
+ //if ACM, send out a new ADDTS
+ status = sme_QosSetup(pMac, sessionId,
+ &pACInfo->requested_QoSInfo[pNewEntry->tspec_mask -1],
+ ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON "
+ "sme_QosSetup returned with status %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, status);
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status)
+ {
+ // we aren't waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)
+ {
+ new_state = SME_QOS_REQUESTED;
+ status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ pACInfo->tspec_pending = pNewEntry->tspec_mask;
+ }
+ else if((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ new_state = SME_QOS_QOS_ON;
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //delete the original entry in FLOW list which got modified
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ hstatus = sme_QosFindAllInFlowList(pMac, search_key,
+ sme_QosModifyFnp);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ if(SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP != status)
+ {
+ pACInfo->curr_QoSInfo[pNewEntry->tspec_mask -1] =
+ pACInfo->requested_QoSInfo[pNewEntry->tspec_mask -1];
+ if(SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)
+ {
+ status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY;
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ hstatus = sme_QosFindAllInFlowList(pMac, search_key,
+ sme_QosModificationNotifyFnp);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't notify other "
+ "entries on this AC =%d",
+ __FUNCTION__, __LINE__, ac);
+ }
+ }
+ else if(SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status)
+ {
+ status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP;
+ }
+ }
+ if(buffered_cmd)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[pNewEntry->tspec_mask -1],
+ status,
+ flow_info->QosFlowID);
+ }
+
+ }
+ else
+ {
+ // unexpected status returned by sme_QosSetup()
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unexpected status %d "
+ "returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ sessionId, status);
+ new_state = SME_QOS_QOS_ON;
+ }
+ }
+ else
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosUpdateParams() failed",
+ __FUNCTION__, __LINE__);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ new_state = SME_QOS_LINK_UP;
+ }
+ /* if we are doing reassoc & we are already in handoff state, no need
+ to move to requested state. But make sure to set the previous state
+ as requested state
+ */
+ if(!(pACInfo->reassoc_pending &&
+ (SME_QOS_HANDOFF == pACInfo->curr_state)))
+ {
+ sme_QosStateTransition(sessionId, ac, new_state);
+ }
+ else
+ {
+ pACInfo->prev_state = SME_QOS_REQUESTED;
+ }
+ break;
+ case SME_QOS_HANDOFF:
+ case SME_QOS_REQUESTED:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: Buffering modify request for flow %d in state = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ //buffer cmd
+ cmd.command = SME_QOS_MODIFY_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.modifyCmdInfo.QosFlowID = QosFlowID;
+ cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the modify request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ break;
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ case SME_QOS_LINK_UP:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: modify requested in unexpected state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ break;
+ }
+ if((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosInternalReleaseReq() - The SME QoS internal function to request
+ for releasing a QoS flow running on a particular AC.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param QosFlowID - Identification per flow running on each AC generated by SME
+ It is only meaningful if the QoS setup for the flow is
+ successful
+
+ \return eHAL_STATUS_SUCCESS - Release is successful.
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosInternalReleaseReq(tpAniSirGlobal pMac,
+ v_U32_t QosFlowID,
+ v_BOOL_t buffered_cmd)
+{
+ tListElem *pEntry= NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosFlowInfoEntry *pDeletedFlow = NULL;
+ sme_QosEdcaAcType ac;
+ sme_QosStates new_state = SME_QOS_CLOSED;
+ sme_QosStatusType status = SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ sme_QosWmmTspecInfo Aggr_Tspec_Info;
+ sme_QosSearchInfo search_key;
+ sme_QosCmdInfo cmd;
+ tCsrRoamModifyProfileFields modifyProfileFields;
+ v_BOOL_t deltsIssued = VOS_FALSE;
+ v_U8_t sessionId;
+ v_BOOL_t bufferCommand;
+ eHalStatus hstatus;
+ v_BOOL_t biDirectionalFlowsPresent = VOS_FALSE;
+ v_BOOL_t uplinkFlowsPresent = VOS_FALSE;
+ v_BOOL_t downlinkFlowsPresent = VOS_FALSE;
+ tListElem *pResult= NULL;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked for flow %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.QosFlowID = QosFlowID;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_1;
+ search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY;
+ //go through the link list to find out the details on the flow
+ pEntry = sme_QosFindInFlowList(search_key);
+
+ if(!pEntry)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no match found for flowID = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP;
+ }
+ // find the AC
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ sessionId = flow_info->sessionId;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ // need to vote off powersave for the duration of this request
+ pSession->readyForPowerSave = VOS_FALSE;
+ // assume we won't have to (re)buffer the command
+ bufferCommand = VOS_FALSE;
+ //check to consider the following flowing scenario
+ //Addts request is pending on one AC, while APSD requested on another which
+ //needs a reassoc. Will buffer a request if Addts is pending on any AC,
+ //which will safegaurd the above scenario, & also won't confuse PE with back
+ //to back Addts or Addts followed by Reassoc
+ if(sme_QosIsRspPending(sessionId, ac))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the release request for flow %d in state %d "
+ "since another request is pending",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ else
+ {
+ // make sure we are in full power so that we can issue
+ // a DelTS or reassoc if necessary
+ hstatus = pmcRequestFullPower(pMac, sme_QosPmcFullPowerCallback,
+ pSession, eSME_REASON_OTHER);
+ if( eHAL_STATUS_PMC_PENDING == hstatus )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: buffering the release request for flow %d in state %d, "
+ "waiting for full power",
+ __FUNCTION__, __LINE__,
+ QosFlowID, pACInfo->curr_state );
+ bufferCommand = VOS_TRUE;
+ }
+ }
+ if (bufferCommand)
+ {
+ // we need to buffer the command
+ cmd.command = SME_QOS_RELEASE_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.releaseCmdInfo.QosFlowID = QosFlowID;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the release request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Buffered release request for flow = %d",
+ __FUNCTION__, __LINE__,
+ QosFlowID);
+ return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP;
+ }
+ //get into the stat m/c to see if the request can be granted
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_QOS_ON:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: tspec_mask_status = %d for AC = %d with "
+ "entry tspec_mask = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->tspec_mask_status, ac, flow_info->tspec_mask);
+
+ //check if multiple flows running on the ac
+ if(pACInfo->num_flows[flow_info->tspec_mask - 1] > 1)
+ {
+ //don't want to include the flow in the new TSPEC on which release
+ //is requested
+ flow_info->reason = SME_QOS_REASON_RELEASE;
+
+ /* Check if the flow being released is for bi-diretional.
+ * Following flows may present in the system.
+ * a) bi-directional flows
+ * b) uplink flows
+ * c) downlink flows.
+ * If the flow being released is for bidirectional, splitting of existing
+ * streams into two tspec indices is required in case ff (b), (c) are present
+ * and not (a).
+ * In case if split occurs, all upstreams are aggregated into tspec index 0,
+ * downstreams are aggregaed into tspec index 1 and two tspec requests for
+ * (aggregated) upstream(s) followed by (aggregated) downstream(s) is sent
+ * to AP. */
+ if(flow_info->QoSInfo.ts_info.direction == SME_QOS_WMM_TS_DIR_BOTH)
+ {
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_4;
+ search_key.sessionId = sessionId;
+ search_key.direction = SME_QOS_WMM_TS_DIR_BOTH;
+ pResult = sme_QosFindInFlowList(search_key);
+ if(pResult)
+ biDirectionalFlowsPresent = VOS_TRUE;
+
+ if(!biDirectionalFlowsPresent)
+ {
+ // The only existing bidirectional flow is being released
+
+ // Check if uplink flows exist
+ search_key.direction = SME_QOS_WMM_TS_DIR_UPLINK;
+ pResult = sme_QosFindInFlowList(search_key);
+ if(pResult)
+ uplinkFlowsPresent = VOS_TRUE;
+
+ // Check if downlink flows exist
+ search_key.direction = SME_QOS_WMM_TS_DIR_DOWNLINK;
+ pResult = sme_QosFindInFlowList(search_key);
+ if(pResult)
+ downlinkFlowsPresent = VOS_TRUE;
+
+ if(uplinkFlowsPresent && downlinkFlowsPresent)
+ {
+ // Need to split the uni-directional flows into SME_QOS_TSPEC_INDEX_0 and SME_QOS_TSPEC_INDEX_1
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ // Mark all downstream flows as using tspec index 1
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_4;
+ search_key.sessionId = sessionId;
+ search_key.direction = SME_QOS_WMM_TS_DIR_DOWNLINK;
+ sme_QosUpdateTspecMask(sessionId, search_key, SME_QOS_TSPEC_MASK_BIT_2_SET);
+
+ // Aggregate all downstream flows
+ hstatus = sme_QosUpdateParams(sessionId,
+ ac, SME_QOS_TSPEC_MASK_BIT_2_SET,
+ &Aggr_Tspec_Info);
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d buffering the AddTS request "
+ "for AC %d in state %d as Addts is pending "
+ "on other Tspec index of this AC",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+
+ // Buffer the (aggregated) tspec request for downstream flows.
+ // Please note that the (aggregated) tspec for upstream flows is sent
+ // out by the susequent logic.
+ cmd.command = SME_QOS_RESEND_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.resendCmdInfo.ac = ac;
+ cmd.u.resendCmdInfo.tspecMask = SME_QOS_TSPEC_MASK_BIT_2_SET;
+ cmd.u.resendCmdInfo.QoSInfo = Aggr_Tspec_Info;
+ pACInfo->requested_QoSInfo[SME_QOS_TSPEC_MASK_BIT_2_SET - 1] = Aggr_Tspec_Info;
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_FALSE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unable to buffer the AddTS "
+ "request for AC %d TSPEC %d in state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, SME_QOS_TSPEC_MASK_BIT_2_SET, pACInfo->curr_state);
+
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_BIT_1_2_SET;
+
+ }
+ }
+ }
+
+ /* In case of splitting of existing streams,
+ * tspec_mask will be pointing to tspec index 0 and
+ * aggregated tspec for upstream(s) is sent out here. */
+ hstatus = sme_QosUpdateParams(sessionId,
+ ac, flow_info->tspec_mask,
+ &Aggr_Tspec_Info);
+ if(HAL_STATUS_SUCCESS(hstatus))
+ {
+ pACInfo->requested_QoSInfo[flow_info->tspec_mask - 1] = Aggr_Tspec_Info;
+ //if ACM, send out a new ADDTS
+ status = sme_QosSetup(pMac, sessionId,
+ &pACInfo->requested_QoSInfo[flow_info->tspec_mask - 1], ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON "
+ "sme_QosSetup returned with status %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, status);
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status)
+ {
+ // we aren't waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)
+ {
+ new_state = SME_QOS_REQUESTED;
+ status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP;
+ pACInfo->tspec_pending = flow_info->tspec_mask;
+ }
+ else if((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ new_state = SME_QOS_QOS_ON;
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1] =
+ pACInfo->requested_QoSInfo[flow_info->tspec_mask - 1];
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ pDeletedFlow = flow_info;
+ if(SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)
+ {
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ hstatus = sme_QosFindAllInFlowList(pMac, search_key,
+ sme_QosSetupFnp);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't notify other "
+ "entries on this AC =%d",
+ __FUNCTION__, __LINE__, ac);
+ }
+ }
+ status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP;
+ if(buffered_cmd)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ status,
+ flow_info->QosFlowID);
+ }
+ }
+ else
+ {
+ // unexpected status returned by sme_QosSetup()
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unexpected status %d "
+ "returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ sessionId, status);
+ new_state = SME_QOS_LINK_UP;
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1] =
+ pACInfo->requested_QoSInfo[flow_info->tspec_mask - 1];
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d deleting entry at "
+ "%p with flowID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, flow_info, QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ pDeletedFlow = flow_info;
+ if(buffered_cmd)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ status,
+ flow_info->QosFlowID);
+ }
+ }
+ }
+ else
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosUpdateParams() failed",
+ __FUNCTION__, __LINE__);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ new_state = SME_QOS_LINK_UP;
+ if(buffered_cmd)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ status,
+ flow_info->QosFlowID);
+ }
+ }
+ }
+ else
+ {
+ // this is the only flow aggregated in this TSPEC
+ status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP;
+#ifdef FEATURE_WLAN_CCX
+ if (ac == SME_QOS_EDCA_AC_VO)
+ {
+ // Indicate to neighbor roam logic of the new required VO
+ // ac bandwidth requirement.
+ csrNeighborRoamIndicateVoiceBW( pMac, pACInfo->curr_QoSInfo[0].peak_data_rate, FALSE );
+ }
+#endif
+ //check if delts needs to be sent
+ if(CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) ||
+ sme_QosIsACM(pMac, pSession->assocInfo.pBssDesc, ac, NULL))
+ {
+ //check if other TSPEC for this AC is also in use
+ if(SME_QOS_TSPEC_MASK_BIT_1_2_SET != pACInfo->tspec_mask_status)
+ {
+ // this is the only TSPEC active on this AC
+ // so indicate that we no longer require APSD
+ pSession->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ //Also update modifyProfileFields.uapsd_mask in CSR for consistency
+ csrGetModifyProfileFields(pMac, flow_info->sessionId, &modifyProfileFields);
+ modifyProfileFields.uapsd_mask = pSession->apsdMask;
+ csrSetModifyProfileFields(pMac, flow_info->sessionId, &modifyProfileFields);
+ if(!pSession->apsdMask)
+ {
+ // this session no longer needs UAPSD
+ // do any sessions still require UAPSD?
+ if (!sme_QosIsUapsdActive())
+ {
+ // No sessions require UAPSD so turn it off
+ // (really don't care when PMC stops it)
+ (void)pmcStopUapsd(pMac);
+ }
+ }
+ }
+ //send delts
+ hstatus = qosIssueCommand(pMac, sessionId, eSmeCommandDelTs,
+ NULL, ac, flow_info->tspec_mask);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosDelTsReq() failed",
+ __FUNCTION__, __LINE__);
+ status = SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ // we won't be waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ else
+ {
+ pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET &
+ (~flow_info->tspec_mask);
+ deltsIssued = VOS_TRUE;
+ }
+ }
+ else if(pSession->apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac)))
+ {
+ //reassoc logic
+ csrGetModifyProfileFields(pMac, sessionId, &modifyProfileFields);
+ modifyProfileFields.uapsd_mask |= pSession->apsdMask;
+ modifyProfileFields.uapsd_mask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ pSession->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ if(!pSession->apsdMask)
+ {
+ // this session no longer needs UAPSD
+ // do any sessions still require UAPSD?
+ if (!sme_QosIsUapsdActive())
+ {
+ // No sessions require UAPSD so turn it off
+ // (really don't care when PMC stops it)
+ (void)pmcStopUapsd(pMac);
+ }
+ }
+ hstatus = sme_QosRequestReassoc(pMac, sessionId,
+ &modifyProfileFields, VOS_FALSE);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Reassoc failed",
+ __FUNCTION__, __LINE__);
+ status = SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ // we won't be waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ else
+ {
+ pACInfo->reassoc_pending = VOS_FALSE;//no need to wait
+ pACInfo->prev_state = SME_QOS_LINK_UP;
+ pACInfo->tspec_pending = 0;
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: nothing to do for AC = %d",
+ __FUNCTION__, __LINE__, ac);
+ // we won't be waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if(buffered_cmd)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ NULL,
+ status,
+ flow_info->QosFlowID);
+ }
+ if(SME_QOS_STATUS_RELEASE_FAILURE_RSP == status)
+ {
+ break;
+ }
+
+ if(((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info->tspec_mask) > 0) &&
+ ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info->tspec_mask) <=
+ SME_QOS_TSPEC_INDEX_MAX))
+ {
+ if(pACInfo->num_flows[(SME_QOS_TSPEC_MASK_BIT_1_2_SET &
+ ~flow_info->tspec_mask) - 1] > 0)
+ {
+ new_state = SME_QOS_QOS_ON;
+ }
+ else
+ {
+ new_state = SME_QOS_LINK_UP;
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Exceeded the array bounds of pACInfo->num_flows",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT (0);
+ return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP;
+ }
+
+ if(VOS_FALSE == deltsIssued)
+ {
+ vos_mem_zero(&pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ sizeof(sme_QosWmmTspecInfo));
+ }
+ vos_mem_zero(&pACInfo->requested_QoSInfo[flow_info->tspec_mask - 1],
+ sizeof(sme_QosWmmTspecInfo));
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ sessionId, flow_info, QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ pDeletedFlow = flow_info;
+ }
+ /* if we are doing reassoc & we are already in handoff state, no need
+ to move to requested state. But make sure to set the previous state
+ as requested state
+ */
+ if(SME_QOS_HANDOFF != pACInfo->curr_state)
+ {
+ sme_QosStateTransition(sessionId, ac, new_state);
+ }
+ if(pACInfo->reassoc_pending)
+ {
+ pACInfo->prev_state = SME_QOS_REQUESTED;
+ }
+ break;
+ case SME_QOS_HANDOFF:
+ case SME_QOS_REQUESTED:
+ //buffer cmd
+ cmd.command = SME_QOS_RELEASE_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.releaseCmdInfo.QosFlowID = QosFlowID;
+ hstatus = sme_QosBufferCmd(&cmd, buffered_cmd);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the release request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ }
+ status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP;
+ break;
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ case SME_QOS_LINK_UP:
+ default:
+ //print error msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: release request in unexpected state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ //ASSERT
+ VOS_ASSERT(0);
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ break;
+ }
+ // if we deleted a flow, reclaim the memory
+ if (pDeletedFlow)
+ {
+ vos_mem_free(pDeletedFlow);
+ }
+ if((SME_QOS_STATUS_RELEASE_SUCCESS_RSP == status))
+ {
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ }
+ return status;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosSetup() - The internal qos setup function which has the
+ intelligence if the request is NOP, or for APSD and/or need to send out ADDTS.
+ It also does the sanity check for QAP, AP supports APSD etc.
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - Session upon which setup is being performed
+ \param pTspec_Info - Pointer to sme_QosWmmTspecInfo which contains the WMM
+ TSPEC related info as defined above
+ \param ac - Enumeration of the various EDCA Access Categories.
+
+ \return SME_QOS_STATUS_SETUP_SUCCESS_RSP if the setup is successful
+ The logic used in the code might be confusing. Trying to cover all the cases
+ here.
+ AP supports App wants ACM = 1 Already set APSD Result
+ | 0 | 0 | 0 | 0 | NO ACM NO APSD
+ | 0 | 0 | 0 | 1 | NO ACM NO APSD/INVALID
+ | 0 | 0 | 1 | 0 | ADDTS
+ | 0 | 0 | 1 | 1 | ADDTS
+ | 0 | 1 | 0 | 0 | FAILURE
+ | 0 | 1 | 0 | 1 | INVALID
+ | 0 | 1 | 1 | 0 | ADDTS
+ | 0 | 1 | 1 | 1 | ADDTS
+ | 1 | 0 | 0 | 0 | NO ACM NO APSD
+ | 1 | 0 | 0 | 1 | NO ACM NO APSD
+ | 1 | 0 | 1 | 0 | ADDTS
+ | 1 | 0 | 1 | 1 | ADDTS
+ | 1 | 1 | 0 | 0 | REASSOC
+ | 1 | 1 | 0 | 1 | NOP: APSD SET ALREADY
+ | 1 | 1 | 1 | 0 | ADDTS
+ | 1 | 1 | 1 | 1 | ADDTS
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosStatusType sme_QosSetup(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo *pTspec_Info,
+ sme_QosEdcaAcType ac)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ tDot11fBeaconIEs *pIes = NULL;
+ tCsrRoamModifyProfileFields modifyProfileFields;
+ eHalStatus hstatus;
+ if( !CSR_IS_SESSION_VALID( pMac, sessionId ) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session Id %d is invalid",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return status;
+ }
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if( !pSession->sessionActive )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session %d is inactive",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return status;
+ }
+ if(!pSession->assocInfo.pBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session %d has an Invalid BSS Descriptor",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ return status;
+ }
+ hstatus = csrGetParsedBssDescriptionIEs(pMac,
+ pSession->assocInfo.pBssDesc,
+ &pIes);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unable to parse BSS IEs",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ return status;
+ }
+
+ /* success so pIes was allocated */
+
+ if( !CSR_IS_QOS_BSS(pIes) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AP doesn't support QoS",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ vos_mem_free(pIes);
+ //notify HDD through the synchronous status msg
+ return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP;
+ }
+ if(pTspec_Info->max_service_interval || pTspec_Info->min_service_interval)
+ {
+ pTspec_Info->ts_info.psb = 1;
+ }
+ else
+ {
+ pTspec_Info->ts_info.psb = 0;
+ }
+
+ pACInfo = &pSession->ac_info[ac];
+ do
+ {
+ // is ACM enabled for this AC?
+ if(CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) ||
+ sme_QosIsACM(pMac, pSession->assocInfo.pBssDesc, ac, NULL))
+ {
+ // ACM is enabled for this AC so we must send an AddTS
+ if(pTspec_Info->ts_info.psb &&
+ (!pMac->pmc.uapsdEnabled ))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Request is looking for APSD but PMC doesn't "
+ "have support for APSD",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ if(SME_QOS_MAX_TID == pTspec_Info->ts_info.tid)
+ {
+ //App didn't set TID, generate one
+ pTspec_Info->ts_info.tid =
+ (v_U8_t)(SME_QOS_WMM_UP_NC - pTspec_Info->ts_info.up);
+ }
+ //addts logic
+ hstatus = qosIssueCommand(pMac, sessionId, eSmeCommandAddTs,
+ pTspec_Info, ac, 0);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosAddTsReq() failed",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d AddTS on AC %d is pending",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ break;
+ }
+ // ACM is not enabled for this AC
+ // Is the application looking for APSD?
+ if(0 == pTspec_Info->ts_info.psb)
+ {
+ //no, we don't need APSD
+ //but check the case, if the setup is called as a result of a release
+ // or modify which boils down to the fact that APSD was set on this AC
+ // but no longer needed - so we need a reassoc for the above case to
+ // let the AP know
+ if(pSession->apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac)))
+ {
+ // APSD was formerly enabled on this AC but is no longer required
+ // so we must reassociate
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d reassoc needed "
+ "to disable APSD on AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ csrGetModifyProfileFields(pMac, sessionId, &modifyProfileFields);
+ modifyProfileFields.uapsd_mask |= pSession->apsdMask;
+ modifyProfileFields.uapsd_mask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ hstatus = sme_QosRequestReassoc(pMac, sessionId,
+ &modifyProfileFields, VOS_FALSE);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Unable to request reassociation",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d reassociation to enable "
+ "APSD on AC %d is pending",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ pACInfo->reassoc_pending = VOS_TRUE;
+ }
+ }
+ else
+ {
+ // we don't need APSD on this AC
+ // and we don't currently have APSD on this AC
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Request is not looking for APSD & Admission "
+ "Control isn't mandatory for the AC",
+ __FUNCTION__, __LINE__);
+ //return success right away
+ status = SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP;
+ }
+ break;
+ }
+ else if(!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) &&
+ !(pIes->WMMInfoAp.uapsd))
+ {
+ // application is looking for APSD but AP doesn't support it
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AP doesn't support APSD",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ break;
+ }
+ else if(pSession->apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac)))
+ {
+ // application is looking for APSD
+ // and it is already enabled on this AC
+ status = SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Request is looking for APSD and it is already "
+ "set for the AC",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ else
+ {
+ // application is looking for APSD
+ // but it is not enabled on this AC
+ // so we need to reassociate
+ if(pMac->pmc.uapsdEnabled)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d reassoc needed "
+ "to enable APSD on AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ //reassoc logic
+ // update the UAPSD mask to include the new
+ // AC on which APSD is requested
+ csrGetModifyProfileFields(pMac, sessionId, &modifyProfileFields);
+ modifyProfileFields.uapsd_mask |= pSession->apsdMask;
+ modifyProfileFields.uapsd_mask |= 1 << (SME_QOS_EDCA_AC_VO - ac);
+ hstatus = sme_QosRequestReassoc(pMac, sessionId,
+ &modifyProfileFields, VOS_FALSE);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Unable to request reassociation",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d reassociation to enable "
+ "APSD on AC %d is pending",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ pACInfo->reassoc_pending = VOS_TRUE;
+ }
+ }
+ else
+ {
+ //err msg: no support for APSD from PMC
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no support for APSD or BMPS from PMC",
+ __FUNCTION__, __LINE__);
+ }
+ }
+ }while(0);
+
+ vos_mem_free(pIes);
+ return status;
+}
+
+#ifdef FEATURE_WLAN_CCX
+/* This is a dummy function now. But the purpose of me adding this was to
+ * delay the TSPEC processing till SET_KEY completes. This function can be
+ * used to do any SME_QOS processing after the SET_KEY. As of now, it is
+ * not required as we are ok with tspec getting programmed before set_key
+ * as the roam timings are measured without tspec in reassoc!
+ */
+eHalStatus sme_QosProcessSetKeySuccessInd(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ "########### CCX Set Key Complete #############");
+ return eHAL_STATUS_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosCCXSaveTspecResponse() - This function saves the TSPEC
+ parameters that came along in the TSPEC IE in the reassoc response
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - SME session ID
+ \param pTspec - Pointer to the TSPEC IE from the reassoc rsp
+ \param ac - Access Category for which this TSPEC rsp is received
+ \param tspecIndex - flow/direction
+
+ \return eHAL_STATUS_SUCCESS - Release is successful.
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosCCXSaveTspecResponse(tpAniSirGlobal pMac, v_U8_t sessionId, tDot11fIEWMMTSPEC *pTspec, v_U8_t ac, v_U8_t tspecIndex)
+{
+ tpSirAddtsRsp pAddtsRsp = &sme_QosCb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex];
+
+ ac = sme_QosUPtoACMap[pTspec->user_priority];
+
+ vos_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp));
+
+ pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP;
+ pAddtsRsp->length = sizeof(tSirAddtsRsp);
+ pAddtsRsp->rc = eSIR_SUCCESS;
+ pAddtsRsp->sessionId = sessionId;
+ pAddtsRsp->rsp.dialogToken = 0;
+ pAddtsRsp->rsp.status = eSIR_SUCCESS;
+ pAddtsRsp->rsp.wmeTspecPresent = pTspec->present;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ "%s: Copy Tspec to local data structure ac=%d, tspecIdx=%d",
+ __FUNCTION__, ac, tspecIndex);
+
+ if (pAddtsRsp->rsp.wmeTspecPresent)
+ {
+ //Copy TSPEC params received in assoc response to addts response
+ ConvertWMMTSPEC(pMac, &pAddtsRsp->rsp.tspec, pTspec);
+ }
+
+ return eHAL_STATUS_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosCCXProcessReassocTspecRsp() - This function processes the
+ WMM TSPEC IE in the reassoc response. Reassoc triggered as part of
+ CCX roaming to another CCX capable AP. If the TSPEC was added before
+ reassoc, as part of Call Admission Control, the reasso req from the
+ STA would carry the TSPEC parameters which were already negotiated
+ with the older AP.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - SME session ID
+ \param pEven_info - Pointer to the smeJoinRsp structure
+
+ \return eHAL_STATUS_SUCCESS - Release is successful.
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosCCXProcessReassocTspecRsp(tpAniSirGlobal pMac, v_U8_t sessionId, void* pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ tDot11fIEWMMTSPEC *pTspecIE = NULL;
+ tCsrRoamSession *pCsrSession = CSR_GET_SESSION( pMac, sessionId );
+ tCsrRoamConnectedInfo *pCsrConnectedInfo = &pCsrSession->connectedInfo;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ v_U8_t ac, numTspec, cnt;
+ v_U8_t tspec_flow_index, tspec_mask_status;
+ v_U32_t tspecIeLen;
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ // Get the TSPEC IEs which came along with the reassoc response
+ // from the pbFrames pointer
+ pTspecIE = (tDot11fIEWMMTSPEC *)(pCsrConnectedInfo->pbFrames + pCsrConnectedInfo->nBeaconLength +
+ pCsrConnectedInfo->nAssocReqLength + pCsrConnectedInfo->nAssocRspLength + pCsrConnectedInfo->nRICRspLength);
+
+ // Get the number of tspecs Ies in the frame, the min length
+ // should be atleast equal to the one TSPEC IE
+ tspecIeLen = pCsrConnectedInfo->nTspecIeLength;
+ if (tspecIeLen < sizeof(tDot11fIEWMMTSPEC)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("CCX Tspec IE len %d less than min %d"),
+ tspecIeLen, sizeof(tDot11fIEWMMTSPEC));
+ return eHAL_STATUS_FAILURE;
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ "TspecLen = %d, pbFrames = %p, pTspecIE = %p\n",
+ tspecIeLen, pCsrConnectedInfo->pbFrames, pTspecIE);
+
+ numTspec = (tspecIeLen)/sizeof(tDot11fIEWMMTSPEC);
+ for(cnt=0; cnt<numTspec; cnt++) {
+ ac = sme_QosUpToAc(pTspecIE->user_priority);
+ pACInfo = &pSession->ac_info[ac];
+ tspec_mask_status = pACInfo->tspec_mask_status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ FL("UP=%d, ac=%d, tspec_mask_status=%x"),
+ pTspecIE->user_priority, ac, tspec_mask_status );
+
+ for (tspec_flow_index = 0; tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++) {
+ if (tspec_mask_status & (1 << tspec_flow_index)) {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ FL("Found Tspec entry flow = %d AC = %d"),tspec_flow_index, ac);
+ sme_QosCCXSaveTspecResponse(pMac, sessionId, pTspecIE, ac, tspec_flow_index);
+ } else {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ FL("Not found Tspec entry flow = %d AC = %d"),tspec_flow_index, ac);
+ }
+ }
+ // Increment the pointer to point it to the next TSPEC IE
+ pTspecIE++;
+ }
+
+ /* Send the Aggregated QoS request to HAL */
+ status = sme_QosFTAggrQosReq(pMac,sessionId);
+
+ return status;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosCopyTspecInfo() - This function copies the existing TSPEC
+ parameters from the source structure to the destination structure.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pTspec_Info - source structure
+ \param pTspec - destination structure
+
+ \return void
+ --------------------------------------------------------------------------*/
+static void sme_QosCopyTspecInfo(tpAniSirGlobal pMac, sme_QosWmmTspecInfo *pTspec_Info, tSirMacTspecIE* pTspec)
+{
+ /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service
+ * Interval, Service Start Time, Suspension Interval and Delay Bound are
+ * all intended for HCCA operation and therefore must be set to zero*/
+ pTspec->delayBound = pTspec_Info->delay_bound;
+ pTspec->inactInterval = pTspec_Info->inactivity_interval;
+ pTspec->length = SME_QOS_TSPEC_IE_LENGTH;
+ pTspec->maxBurstSz = pTspec_Info->max_burst_size;
+ pTspec->maxMsduSz = pTspec_Info->maximum_msdu_size;
+ pTspec->maxSvcInterval = pTspec_Info->max_service_interval;
+ pTspec->meanDataRate = pTspec_Info->mean_data_rate;
+ pTspec->mediumTime = pTspec_Info->medium_time;
+ pTspec->minDataRate = pTspec_Info->min_data_rate;
+ pTspec->minPhyRate = pTspec_Info->min_phy_rate;
+ pTspec->minSvcInterval = pTspec_Info->min_service_interval;
+ pTspec->nomMsduSz = pTspec_Info->nominal_msdu_size;
+ pTspec->peakDataRate = pTspec_Info->peak_data_rate;
+ pTspec->surplusBw = pTspec_Info->surplus_bw_allowance;
+ pTspec->suspendInterval = pTspec_Info->suspension_interval;
+ pTspec->svcStartTime = pTspec_Info->svc_start_time;
+ pTspec->tsinfo.traffic.direction = pTspec_Info->ts_info.direction;
+
+ //Make sure UAPSD is allowed. BTC may want to disable UAPSD while keep QoS setup
+ if (pTspec_Info->ts_info.psb && btcIsReadyForUapsd(pMac)) {
+ pTspec->tsinfo.traffic.psb = pTspec_Info->ts_info.psb;
+ } else {
+ pTspec->tsinfo.traffic.psb = 0;
+ pTspec_Info->ts_info.psb = 0;
+ }
+ pTspec->tsinfo.traffic.tsid = pTspec_Info->ts_info.tid;
+ pTspec->tsinfo.traffic.userPrio = pTspec_Info->ts_info.up;
+ pTspec->tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA;
+ pTspec->tsinfo.traffic.burstSizeDefn = pTspec_Info->ts_info.burst_size_defn;
+ pTspec->tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy;
+ pTspec->type = SME_QOS_TSPEC_IE_TYPE;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: up = %d, tid = %d",
+ __FUNCTION__, __LINE__,
+ pTspec_Info->ts_info.up,
+ pTspec_Info->ts_info.tid);
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosCCxRetrieveTspecInfo() - This function is called by CSR
+ when try to create reassoc request message to PE - csrSendSmeReassocReqMsg
+ This functions get the existing tspec parameters to be included
+ in the reassoc request.
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - SME session ID
+ \param pTspecInfo - Pointer to the structure to carry back the TSPEC parameters
+
+ \return v_U8_t - number of existing negotiated TSPECs
+ --------------------------------------------------------------------------*/
+v_U8_t sme_QosCCxRetrieveTspecInfo(tpAniSirGlobal pMac, v_U8_t sessionId, tTspecInfo *pTspecInfo)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t tspec_mask_status = 0;
+ v_U8_t tspec_pending_status = 0;
+ v_U8_t ac, numTspecs = 0;
+ tTspecInfo *pDstTspec = pTspecInfo;
+
+ //TODO: Check if TSPEC has already been established, if not return
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) {
+ volatile v_U8_t tspec_index = 0;
+
+ pACInfo = &pSession->ac_info[ac];
+ tspec_pending_status = pACInfo->tspec_pending;
+ tspec_mask_status = pACInfo->tspec_mask_status;
+
+ do {
+ if (tspec_mask_status & SME_QOS_TSPEC_MASK_BIT_1_SET) {
+ /* If a tspec status is pending, take requested_QoSInfo for RIC request, else use curr_QoSInfo
+ for the RIC request */
+ if (tspec_pending_status & SME_QOS_TSPEC_MASK_BIT_1_SET) {
+ sme_QosCopyTspecInfo(pMac, &pACInfo->requested_QoSInfo[tspec_index], &pDstTspec->tspec);
+ } else {
+ sme_QosCopyTspecInfo(pMac, &pACInfo->curr_QoSInfo[tspec_index], &pDstTspec->tspec);
+ }
+ pDstTspec->valid = TRUE;
+ numTspecs++;
+ pDstTspec++;
+ }
+ tspec_mask_status >>= 1;
+ tspec_pending_status >>= 1;
+ tspec_index++;
+ } while (tspec_mask_status);
+ }
+
+ return numTspecs;
+}
+
+#endif
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+
+eHalStatus sme_QosCreateTspecRICIE(tpAniSirGlobal pMac, sme_QosWmmTspecInfo *pTspec_Info,
+ v_U8_t *pRICBuffer, v_U32_t *pRICLength, v_U8_t *pRICIdentifier)
+{
+ tDot11fIERICDataDesc ricIE;
+ tANI_U32 nStatus;
+
+ VOS_ASSERT(NULL != pRICBuffer);
+ VOS_ASSERT(NULL != pRICLength);
+ VOS_ASSERT(NULL != pRICIdentifier);
+
+ vos_mem_zero(&ricIE, sizeof(tDot11fIERICDataDesc));
+
+ ricIE.present = 1;
+ ricIE.RICData.present = 1;
+ ricIE.RICData.resourceDescCount = 1;
+ ricIE.RICData.statusCode = 0;
+ ricIE.RICData.Identifier = sme_QosAssignDialogToken();
+#ifndef USE_80211_WMMTSPEC_FOR_RIC
+ ricIE.TSPEC.present = 1;
+ ricIE.TSPEC.delay_bound = pTspec_Info->delay_bound;
+ ricIE.TSPEC.inactivity_int = pTspec_Info->inactivity_interval;
+ ricIE.TSPEC.burst_size = pTspec_Info->max_burst_size;
+ ricIE.TSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size;
+ ricIE.TSPEC.max_service_int = pTspec_Info->max_service_interval;
+ ricIE.TSPEC.mean_data_rate = pTspec_Info->mean_data_rate;
+ ricIE.TSPEC.medium_time = pTspec_Info->medium_time;
+ ricIE.TSPEC.min_data_rate = pTspec_Info->min_data_rate;
+ ricIE.TSPEC.min_phy_rate = pTspec_Info->min_phy_rate;
+ ricIE.TSPEC.min_service_int = pTspec_Info->min_service_interval;
+ ricIE.TSPEC.size = pTspec_Info->nominal_msdu_size;
+ ricIE.TSPEC.peak_data_rate = pTspec_Info->peak_data_rate;
+ ricIE.TSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance;
+ ricIE.TSPEC.suspension_int = pTspec_Info->suspension_interval;
+ ricIE.TSPEC.service_start_time = pTspec_Info->svc_start_time;
+ ricIE.TSPEC.direction = pTspec_Info->ts_info.direction;
+ //Make sure UAPSD is allowed. BTC may want to disable UAPSD while keep QoS setup
+ if( pTspec_Info->ts_info.psb && btcIsReadyForUapsd(pMac) )
+ {
+ ricIE.TSPEC.psb = pTspec_Info->ts_info.psb;
+ }
+ else
+ {
+ ricIE.TSPEC.psb = 0;
+ }
+ ricIE.TSPEC.tsid = pTspec_Info->ts_info.tid;
+ ricIE.TSPEC.user_priority = pTspec_Info->ts_info.up;
+ ricIE.TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA;
+
+ *pRICIdentifier = ricIE.RICData.Identifier;
+
+ nStatus = dot11fPackIeRICDataDesc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), pRICLength);
+ if (DOT11F_FAILED(nStatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Packing of RIC Data of length %d failed with status %d"),
+ *pRICLength, nStatus);
+ }
+#else // WMM TSPEC
+ /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service
+ Interval, Service Start Time, Suspension Interval and Delay Bound are
+ all intended for HCCA operation and therefore must be set to zero*/
+ ricIE.WMMTSPEC.present = 1;
+ ricIE.WMMTSPEC.version = 1;
+ ricIE.WMMTSPEC.delay_bound = pTspec_Info->delay_bound;
+ ricIE.WMMTSPEC.inactivity_int = pTspec_Info->inactivity_interval;
+ ricIE.WMMTSPEC.burst_size = pTspec_Info->max_burst_size;
+ ricIE.WMMTSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size;
+ ricIE.WMMTSPEC.max_service_int = pTspec_Info->max_service_interval;
+ ricIE.WMMTSPEC.mean_data_rate = pTspec_Info->mean_data_rate;
+ ricIE.WMMTSPEC.medium_time = pTspec_Info->medium_time;
+ ricIE.WMMTSPEC.min_data_rate = pTspec_Info->min_data_rate;
+ ricIE.WMMTSPEC.min_phy_rate = pTspec_Info->min_phy_rate;
+ ricIE.WMMTSPEC.min_service_int = pTspec_Info->min_service_interval;
+ ricIE.WMMTSPEC.size = pTspec_Info->nominal_msdu_size;
+ ricIE.WMMTSPEC.peak_data_rate = pTspec_Info->peak_data_rate;
+ ricIE.WMMTSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance;
+ ricIE.WMMTSPEC.suspension_int = pTspec_Info->suspension_interval;
+ ricIE.WMMTSPEC.service_start_time = pTspec_Info->svc_start_time;
+ ricIE.WMMTSPEC.direction = pTspec_Info->ts_info.direction;
+ //Make sure UAPSD is allowed. BTC may want to disable UAPSD while keep QoS setup
+ if( pTspec_Info->ts_info.psb && btcIsReadyForUapsd(pMac) )
+ {
+ ricIE.WMMTSPEC.psb = pTspec_Info->ts_info.psb;
+ }
+ else
+ {
+ ricIE.WMMTSPEC.psb = 0;
+ }
+ ricIE.WMMTSPEC.tsid = pTspec_Info->ts_info.tid;
+ ricIE.WMMTSPEC.user_priority = pTspec_Info->ts_info.up;
+ ricIE.WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA;
+
+
+ nStatus = dot11fPackIeRICDataDesc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), pRICLength);
+ if (DOT11F_FAILED(nStatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Packing of RIC Data of length %d failed with status %d"),
+ *pRICLength, nStatus);
+ }
+#endif /* 80211_TSPEC */
+ *pRICIdentifier = ricIE.RICData.Identifier;
+ return nStatus;
+}
+
+eHalStatus sme_QosProcessFTReassocReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac, qos_requested = FALSE;
+ v_U8_t tspec_flow_index;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ tListElem *pEntry= NULL;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ FL("Invoked on session %d"), sessionId);
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ qos_requested = FALSE;
+
+ for (tspec_flow_index = 0; tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++)
+ {
+ /* Only in the below case, copy the AC's curr QoS Info to requested QoS info */
+ if ((pACInfo->ricIdentifier[tspec_flow_index] && !pACInfo->tspec_pending) ||
+ (pACInfo->tspec_mask_status & (1<<tspec_flow_index)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("Copying the currentQos to requestedQos for AC=%d, flow=%d\n"),
+ ac, tspec_flow_index );
+
+ pACInfo->requested_QoSInfo[tspec_flow_index] = pACInfo->curr_QoSInfo[tspec_flow_index];
+ vos_mem_zero(&pACInfo->curr_QoSInfo[tspec_flow_index], sizeof(sme_QosWmmTspecInfo));
+ qos_requested = TRUE;
+ }
+ }
+
+ // Only if the tspec is required, transition the state to
+ // SME_QOS_REQUESTED for this AC
+ if (qos_requested)
+ {
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_HANDOFF:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_REQUESTED);
+ break;
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("FT Reassoc req event in unexpected state %d"), pACInfo->curr_state);
+ VOS_ASSERT(0);
+ }
+ }
+
+ }
+
+ /* At this point of time, we are disconnected from the old AP, so it is safe
+ * to reset all these session variables */
+ pSession->apsdMask = 0;
+ pSession->uapsdAlreadyRequested = 0;
+ pSession->readyForPowerSave = 0;
+
+ /* Now change reason and HO renewal of all the flow in this session only */
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ "%s: %d: Flow List empty, nothing to update",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ do
+ {
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if(sessionId == flow_info->sessionId)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Changing FlowID %d reason to SETUP and HO renewal to FALSE",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ flow_info->reason = SME_QOS_REASON_SETUP;
+ flow_info->hoRenewal = eANI_BOOLEAN_TRUE;
+ }
+ pEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ } while( pEntry );
+
+ return eHAL_STATUS_SUCCESS;
+}
+
+
+eHalStatus sme_QosFTAggrQosReq( tpAniSirGlobal pMac, v_U8_t sessionId )
+{
+ tSirAggrQosReq *pMsg = NULL;
+ sme_QosSessionInfo *pSession;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ int i, j = 0;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d", __FUNCTION__, __LINE__,
+ sessionId);
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ pMsg = (tSirAggrQosReq *)vos_mem_malloc(sizeof(tSirAggrQosReq));
+
+ if (!pMsg)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the msg buffer",
+ __FUNCTION__, __LINE__);
+
+ return eHAL_STATUS_FAILURE;
+ }
+
+ vos_mem_zero(pMsg, sizeof(tSirAggrQosReq));
+
+ pMsg->messageType = pal_cpu_to_be16((v_U16_t)eWNI_SME_FT_AGGR_QOS_REQ);
+ pMsg->length = sizeof(tSirAggrQosReq);
+ pMsg->sessionId = sessionId;
+ pMsg->timeout = 0;
+ pMsg->rspReqd = VOS_TRUE;
+ vos_mem_copy( &pMsg->bssId[ 0 ],
+ &pSession->assocInfo.pBssDesc->bssId[ 0 ],
+ sizeof(tCsrBssid) );
+
+ for( i = 0; i < SME_QOS_EDCA_AC_MAX; i++ )
+ {
+ for( j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++ )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("ac=%d, tspec_mask_staus=%x, tspec_index=%d\n"),
+ i, pSession->ac_info[i].tspec_mask_status, j);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("direction = %d\n"), pSession->ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic.direction);
+ // Check if any flow is active on this AC
+ if ((pSession->ac_info[i].tspec_mask_status) & (1 << j))
+ {
+ tANI_U8 direction = pSession->ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic.direction;
+ if ((direction == SME_QOS_WMM_TS_DIR_UPLINK) ||
+ (direction == SME_QOS_WMM_TS_DIR_BOTH))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_WARN,
+ FL("Found tspec entry AC=%d, flow=%d, direction = %d\n"), i, j, direction);
+ pMsg->aggrInfo.aggrAddTsInfo[i].dialogToken =
+ sme_QosAssignDialogToken();
+ pMsg->aggrInfo.aggrAddTsInfo[i].lleTspecPresent =
+ pSession->ac_info[i].addTsRsp[j].rsp.lleTspecPresent;
+ pMsg->aggrInfo.aggrAddTsInfo[i].numTclas =
+ pSession->ac_info[i].addTsRsp[j].rsp.numTclas;
+ vos_mem_copy( pMsg->aggrInfo.aggrAddTsInfo[i].tclasInfo,
+ pSession->ac_info[i].addTsRsp[j].rsp.tclasInfo,
+ SIR_MAC_TCLASIE_MAXNUM );
+ pMsg->aggrInfo.aggrAddTsInfo[i].tclasProc =
+ pSession->ac_info[i].addTsRsp[j].rsp.tclasProc;
+ pMsg->aggrInfo.aggrAddTsInfo[i].tclasProcPresent =
+ pSession->ac_info[i].addTsRsp[j].rsp.tclasProcPresent;
+ pMsg->aggrInfo.aggrAddTsInfo[i].tspec =
+ pSession->ac_info[i].addTsRsp[j].rsp.tspec;
+ pMsg->aggrInfo.aggrAddTsInfo[i].wmeTspecPresent =
+ pSession->ac_info[i].addTsRsp[j].rsp.wmeTspecPresent;
+ pMsg->aggrInfo.aggrAddTsInfo[i].wsmTspecPresent =
+ pSession->ac_info[i].addTsRsp[j].rsp.wsmTspecPresent;
+ pMsg->aggrInfo.tspecIdx |= ( 1 << i );
+
+ // Mark the index for this AC as pending for response, which would be
+ // used to validate the AddTS response from HAL->PE->SME
+ pSession->ac_info[i].tspec_pending = (1<<j);
+ }
+ }
+ }
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ "Sending aggregated message to HAL 0x%x\n", pMsg->aggrInfo.tspecIdx);
+
+ if(HAL_STATUS_SUCCESS(palSendMBMessage(pMac->hHdd, pMsg)))
+ {
+ status = eHAL_STATUS_SUCCESS;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: sent down a AGGR QoS req to PE",
+ __FUNCTION__, __LINE__);
+ }
+
+ return status;
+}
+
+eHalStatus sme_QosProcessFTRICResponse(tpAniSirGlobal pMac, v_U8_t sessionId, tDot11fIERICDataDesc *pRicDataDesc, v_U8_t ac, v_U8_t tspecIndex)
+{
+ tANI_U8 i = 0;
+ tpSirAddtsRsp pAddtsRsp
+ = &sme_QosCb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex];
+
+ vos_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp));
+
+ pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP;
+ pAddtsRsp->length = sizeof(tSirAddtsRsp);
+ pAddtsRsp->rc = pRicDataDesc->RICData.statusCode;
+ pAddtsRsp->sessionId = sessionId;
+ pAddtsRsp->rsp.dialogToken = pRicDataDesc->RICData.Identifier;
+ pAddtsRsp->rsp.status = pRicDataDesc->RICData.statusCode;
+ pAddtsRsp->rsp.wmeTspecPresent = pRicDataDesc->TSPEC.present;
+ if (pAddtsRsp->rsp.wmeTspecPresent)
+ {
+ //Copy TSPEC params received in RIC response to addts response
+ ConvertTSPEC(pMac, &pAddtsRsp->rsp.tspec, &pRicDataDesc->TSPEC);
+ }
+
+ pAddtsRsp->rsp.numTclas = pRicDataDesc->num_TCLAS;
+ if (pAddtsRsp->rsp.numTclas)
+ {
+ for (i = 0; i < pAddtsRsp->rsp.numTclas; i++)
+ {
+ //Copy TCLAS info per index to the addts response
+ ConvertTCLAS(pMac, &pAddtsRsp->rsp.tclasInfo[i], &pRicDataDesc->TCLAS[i]);
+ }
+ }
+
+ pAddtsRsp->rsp.tclasProcPresent = pRicDataDesc->TCLASSPROC.present;
+ if (pAddtsRsp->rsp.tclasProcPresent)
+ pAddtsRsp->rsp.tclasProc = pRicDataDesc->TCLASSPROC.processing;
+
+
+ pAddtsRsp->rsp.schedulePresent = pRicDataDesc->Schedule.present;
+ if (pAddtsRsp->rsp.schedulePresent)
+ {
+ //Copy Schedule IE params to addts response
+ ConvertSchedule(pMac, &pAddtsRsp->rsp.schedule, &pRicDataDesc->Schedule);
+ }
+
+ //Need to check the below portion is a part of WMM TSPEC
+ //Process Delay element
+ if (pRicDataDesc->TSDelay.present)
+ ConvertTSDelay(pMac, &pAddtsRsp->rsp.delay, &pRicDataDesc->TSDelay);
+ //return sme_QosProcessAddTsRsp(pMac, &addtsRsp);
+ return eHAL_STATUS_SUCCESS;
+ }
+eHalStatus sme_QosProcessAggrQosRsp(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tpSirAggrQosRsp pAggrRsp = (tpSirAggrQosRsp)pMsgBuf;
+ tSirAddtsRsp addtsRsp;
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+ int i, j = 0;
+ tANI_U8 sessionId = pAggrRsp->sessionId;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("Received AGGR_QOS resp from LIM"));
+
+ /* Copy over the updated response information for TSPEC of all the ACs */
+ for( i = 0; i < SIR_QOS_NUM_AC_MAX; i++ )
+ {
+ tANI_U8 tspec_mask_status = sme_QosCb.sessionInfo[sessionId].ac_info[i].tspec_mask_status;
+ for( j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++ )
+ {
+ tANI_U8 direction = sme_QosCb.sessionInfo[sessionId].ac_info[i].
+ addTsRsp[j].rsp.tspec.tsinfo.traffic.direction;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("Addts rsp from LIM AC=%d, flow=%d dir=%d, tspecIdx=%x\n"),
+ i, j, direction, pAggrRsp->aggrInfo.tspecIdx);
+ // Check if the direction is Uplink or bi-directional
+ if( ((1<<i) & pAggrRsp->aggrInfo.tspecIdx) &&
+ ((tspec_mask_status) & (1<<j)) &&
+ ((direction == SME_QOS_WMM_TS_DIR_UPLINK) ||
+ (direction == SME_QOS_WMM_TS_DIR_BOTH)))
+ {
+ addtsRsp = sme_QosCb.sessionInfo[sessionId].ac_info[i].addTsRsp[j];
+ addtsRsp.rc = pAggrRsp->aggrInfo.aggrRsp[i].status;
+ addtsRsp.rsp.status = pAggrRsp->aggrInfo.aggrRsp[i].status;
+ addtsRsp.rsp.tspec = pAggrRsp->aggrInfo.aggrRsp[i].tspec;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("%s: Processing Addts rsp from LIM AC=%d, flow=%d\n"), i, j);
+ /* post ADD TS response for each */
+ if (sme_QosProcessAddTsRsp(pMac, &addtsRsp) != eHAL_STATUS_SUCCESS)
+ {
+ status = eHAL_STATUS_FAILURE;
+ }
+ }
+ }
+ }
+ return status;
+}
+
+
+eHalStatus sme_QosProcessFTReassocRspEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac;
+ v_U8_t tspec_flow_index;
+ tDot11fIERICDataDesc *pRicDataDesc = NULL;
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+ tCsrRoamSession *pCsrSession = CSR_GET_SESSION( pMac, sessionId );
+ tCsrRoamConnectedInfo *pCsrConnectedInfo = &pCsrSession->connectedInfo;
+ tANI_U32 ricRspLen = pCsrConnectedInfo->nRICRspLength;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ pRicDataDesc = (tDot11fIERICDataDesc *)pCsrConnectedInfo->pbFrames + pCsrConnectedInfo->nBeaconLength +
+ pCsrConnectedInfo->nAssocReqLength + pCsrConnectedInfo->nAssocRspLength;
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+
+ for (tspec_flow_index = 0; tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++)
+ {
+ /* Only in the below case, copy the AC's curr QoS Info to requested QoS info */
+ if (pACInfo->ricIdentifier[tspec_flow_index])
+ {
+
+ if (!ricRspLen)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("RIC Response not received for AC %d on TSPEC Index %d, RIC Req Identifier = %d"),
+ ac, tspec_flow_index, pACInfo->ricIdentifier[tspec_flow_index]);
+ VOS_ASSERT(0);
+ }
+ else
+ {
+ /* Now we got response for this identifier. Process it. */
+ if (pRicDataDesc->present)
+ {
+ if (pRicDataDesc->RICData.present)
+ {
+ if (pRicDataDesc->RICData.Identifier != pACInfo->ricIdentifier[tspec_flow_index])
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("RIC response order not same as request sent. Request ID = %d, Response ID = %d"),
+ pACInfo->ricIdentifier[tspec_flow_index], pRicDataDesc->RICData.Identifier);
+ VOS_ASSERT(0);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("Processing RIC Response for AC %d, TSPEC Flow index %d with RIC ID %d \n"),
+ ac, tspec_flow_index, pRicDataDesc->RICData.Identifier);
+ status = sme_QosProcessFTRICResponse(pMac, sessionId, pRicDataDesc, ac, tspec_flow_index);
+ if (eHAL_STATUS_SUCCESS != status)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("Failed with status %d for AC %d in TSPEC Flow index = %d\n"),
+ status, ac, tspec_flow_index);
+ }
+ }
+ pRicDataDesc++;
+ ricRspLen -= sizeof(tDot11fIERICDataDesc);
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ if (ricRspLen)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ FL("RIC Response still follows despite traversing through all ACs. Remaining len = %d\n"), ricRspLen);
+ VOS_ASSERT(0);
+ }
+
+ /* Send the Aggregated QoS request to HAL */
+ status = sme_QosFTAggrQosReq(pMac,sessionId);
+
+ return status;
+}
+
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosAddTsReq() - To send down the ADDTS request with TSPEC params
+ to PE
+
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - Session upon which the TSPEC should be added
+ \param pTspec_Info - Pointer to sme_QosWmmTspecInfo which contains the WMM
+ TSPEC related info as defined above
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosAddTsReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pTspec_Info,
+ sme_QosEdcaAcType ac)
+{
+ tSirAddtsReq *pMsg = NULL;
+ sme_QosSessionInfo *pSession;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+#ifdef FEATURE_WLAN_CCX
+ tCsrRoamSession *pCsrSession = CSR_GET_SESSION( pMac, sessionId );
+#endif
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ WLAN_VOS_DIAG_EVENT_DEF(qos, vos_event_wlan_qos_payload_type);
+#endif
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pMsg = (tSirAddtsReq *)vos_mem_malloc(sizeof(tSirAddtsReq));
+ if (!pMsg)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the msg buffer",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_zero(pMsg, sizeof(tSirAddtsReq));
+ pMsg->messageType = pal_cpu_to_be16((v_U16_t)eWNI_SME_ADDTS_REQ);
+ pMsg->length = sizeof(tSirAddtsReq);
+ pMsg->sessionId = sessionId;
+ pMsg->timeout = 0;
+ pMsg->rspReqd = VOS_TRUE;
+ pMsg->req.dialogToken = sme_QosAssignDialogToken();
+ /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service
+ Interval, Service Start Time, Suspension Interval and Delay Bound are
+ all intended for HCCA operation and therefore must be set to zero*/
+ pMsg->req.tspec.delayBound = 0;
+ pMsg->req.tspec.inactInterval = pTspec_Info->inactivity_interval;
+ pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH;
+ pMsg->req.tspec.maxBurstSz = pTspec_Info->max_burst_size;
+ pMsg->req.tspec.maxMsduSz = pTspec_Info->maximum_msdu_size;
+ pMsg->req.tspec.maxSvcInterval = pTspec_Info->max_service_interval;
+ pMsg->req.tspec.meanDataRate = pTspec_Info->mean_data_rate;
+ pMsg->req.tspec.mediumTime = pTspec_Info->medium_time;
+ pMsg->req.tspec.minDataRate = pTspec_Info->min_data_rate;
+ pMsg->req.tspec.minPhyRate = pTspec_Info->min_phy_rate;
+ pMsg->req.tspec.minSvcInterval = pTspec_Info->min_service_interval;
+ pMsg->req.tspec.nomMsduSz = pTspec_Info->nominal_msdu_size;
+ pMsg->req.tspec.peakDataRate = pTspec_Info->peak_data_rate;
+ pMsg->req.tspec.surplusBw = pTspec_Info->surplus_bw_allowance;
+ pMsg->req.tspec.suspendInterval = pTspec_Info->suspension_interval;
+ pMsg->req.tspec.svcStartTime = 0;
+ pMsg->req.tspec.tsinfo.traffic.direction = pTspec_Info->ts_info.direction;
+ //Make sure UAPSD is allowed. BTC may want to disable UAPSD while keep QoS setup
+ if( pTspec_Info->ts_info.psb
+ && btcIsReadyForUapsd(pMac)
+ )
+ {
+ pMsg->req.tspec.tsinfo.traffic.psb = pTspec_Info->ts_info.psb;
+ }
+ else
+ {
+ pMsg->req.tspec.tsinfo.traffic.psb = 0;
+ pTspec_Info->ts_info.psb = 0;
+ }
+ pMsg->req.tspec.tsinfo.traffic.tsid = pTspec_Info->ts_info.tid;
+ pMsg->req.tspec.tsinfo.traffic.userPrio = pTspec_Info->ts_info.up;
+ pMsg->req.tspec.tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA;
+ pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = pTspec_Info->ts_info.burst_size_defn;
+ pMsg->req.tspec.tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy;
+ pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE;
+ /*Fill the BSSID pMsg->req.bssId*/
+ if (NULL == pSession->assocInfo.pBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: BSS descriptor is NULL so we don't send requst to PE",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_copy( &pMsg->bssId[ 0 ],
+ &pSession->assocInfo.pBssDesc->bssId[ 0 ],
+ sizeof(tCsrBssid) );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: up = %d, tid = %d",
+ __FUNCTION__, __LINE__,
+ pTspec_Info->ts_info.up,
+ pTspec_Info->ts_info.tid);
+#ifdef FEATURE_WLAN_CCX
+ if(pCsrSession->connectedProfile.isCCXAssoc)
+ {
+ pMsg->req.tsrsIE.tsid = pTspec_Info->ts_info.up;
+ pMsg->req.tsrsPresent = 1;
+ }
+#endif
+ if(HAL_STATUS_SUCCESS(palSendMBMessage(pMac->hHdd, pMsg)))
+ {
+ status = eHAL_STATUS_SUCCESS;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: sent down a ADDTS req to PE",
+ __FUNCTION__, __LINE__);
+ //event: EVENT_WLAN_QOS
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ qos.eventId = SME_QOS_DIAG_ADDTS_REQ;
+ qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED;
+ WLAN_VOS_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS);
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosDelTsReq() - To send down the DELTS request with TSPEC params
+ to PE
+
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param sessionId - Session from which the TSPEC should be deleted
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \param tspec_mask - on which tspec per AC, the delts is requested
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosDelTsReq(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspec_mask)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ tSirDeltsReq *pMsg;
+ sme_QosWmmTspecInfo *pTspecInfo;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ WLAN_VOS_DIAG_EVENT_DEF(qos, vos_event_wlan_qos_payload_type);
+#endif
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ pMsg = (tSirDeltsReq *)vos_mem_malloc(sizeof(tSirDeltsReq));
+ if (!pMsg)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the msg buffer",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_zero(pMsg, sizeof(tSirDeltsReq));
+ // get pointer to the TSPEC being deleted
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ pTspecInfo = &pACInfo->curr_QoSInfo[tspec_mask - 1];
+ pMsg->messageType = pal_cpu_to_be16((v_U16_t)eWNI_SME_DELTS_REQ);
+ pMsg->length = sizeof(tSirDeltsReq);
+ pMsg->sessionId = sessionId;
+ pMsg->rspReqd = VOS_TRUE;
+ pMsg->req.tspec.delayBound = pTspecInfo->delay_bound;
+ pMsg->req.tspec.inactInterval = pTspecInfo->inactivity_interval;
+ pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH;
+ pMsg->req.tspec.maxBurstSz = pTspecInfo->max_burst_size;
+ pMsg->req.tspec.maxMsduSz = pTspecInfo->maximum_msdu_size;
+ pMsg->req.tspec.maxSvcInterval = pTspecInfo->max_service_interval;
+ pMsg->req.tspec.meanDataRate = pTspecInfo->mean_data_rate;
+ pMsg->req.tspec.mediumTime = pTspecInfo->medium_time;
+ pMsg->req.tspec.minDataRate = pTspecInfo->min_data_rate;
+ pMsg->req.tspec.minPhyRate = pTspecInfo->min_phy_rate;
+ pMsg->req.tspec.minSvcInterval = pTspecInfo->min_service_interval;
+ pMsg->req.tspec.nomMsduSz = pTspecInfo->nominal_msdu_size;
+ pMsg->req.tspec.peakDataRate = pTspecInfo->peak_data_rate;
+ pMsg->req.tspec.surplusBw = pTspecInfo->surplus_bw_allowance;
+ pMsg->req.tspec.suspendInterval = pTspecInfo->suspension_interval;
+ pMsg->req.tspec.svcStartTime = pTspecInfo->svc_start_time;
+ pMsg->req.tspec.tsinfo.traffic.direction = pTspecInfo->ts_info.direction;
+ pMsg->req.tspec.tsinfo.traffic.psb = pTspecInfo->ts_info.psb;
+ pMsg->req.tspec.tsinfo.traffic.tsid = pTspecInfo->ts_info.tid;
+ pMsg->req.tspec.tsinfo.traffic.userPrio = pTspecInfo->ts_info.up;
+ pMsg->req.tspec.tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA;
+ pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = pTspecInfo->ts_info.burst_size_defn;
+ pMsg->req.tspec.tsinfo.traffic.ackPolicy = pTspecInfo->ts_info.ack_policy;
+ pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE;
+ /*Fill the BSSID pMsg->req.bssId*/
+ if (NULL == pSession->assocInfo.pBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: BSS descriptor is NULL so we don't send request to PE",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_copy( &pMsg->bssId[ 0 ],
+ &pSession->assocInfo.pBssDesc->bssId[ 0 ],
+ sizeof(tCsrBssid) );
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: up = %d, tid = %d",
+ __FUNCTION__, __LINE__,
+ pTspecInfo->ts_info.up,
+ pTspecInfo->ts_info.tid);
+ vos_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1],
+ sizeof(sme_QosWmmTspecInfo));
+ if(HAL_STATUS_SUCCESS(palSendMBMessage(pMac->hHdd, pMsg)))
+ {
+ status = eHAL_STATUS_SUCCESS;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: sme_QosDelTsReq:Test: sent down a DELTS req to PE",
+ __FUNCTION__, __LINE__);
+ //event: EVENT_WLAN_QOS
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ qos.eventId = SME_QOS_DIAG_DELTS;
+ qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED;
+ WLAN_VOS_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS);
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+ }
+
+ return status;
+}
+
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessAddTsRsp() - Function to process the
+ eWNI_SME_ADDTS_RSP came from PE
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pMsgBuf - Pointer to the msg buffer came from PE.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessAddTsRsp(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp)pMsgBuf;
+ sme_QosSessionInfo *pSession;
+ v_U8_t sessionId = paddts_rsp->sessionId;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ sme_QosWmmUpType up = (sme_QosWmmUpType)paddts_rsp->rsp.tspec.tsinfo.traffic.userPrio;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+#endif
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for UP %d",
+ __FUNCTION__, __LINE__,
+ sessionId, up);
+
+ ac = sme_QosUpToAc(up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__, ac, up);
+
+ return eHAL_STATUS_FAILURE;
+ }
+ pACInfo = &pSession->ac_info[ac];
+ if (SME_QOS_HANDOFF == pACInfo->curr_state)
+ {
+ smsLog(pMac, LOG1, FL("ADDTS Response received for AC %d in HANDOFF State.. Dropping"), ac);
+ pSession->readyForPowerSave = VOS_TRUE;
+ return eHAL_STATUS_SUCCESS;
+ }
+#endif
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ WLAN_VOS_DIAG_EVENT_DEF(qos, vos_event_wlan_qos_payload_type);
+#endif
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d with return code %d",
+ __FUNCTION__, __LINE__,
+ sessionId, paddts_rsp->rc);
+ // our outstanding request has been serviced
+ // we can go into powersave
+ pSession->readyForPowerSave = VOS_TRUE;
+ if(paddts_rsp->rc)
+ {
+ //event: EVENT_WLAN_QOS
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ qos.eventId = SME_QOS_DIAG_ADDTS_RSP;
+ qos.reasonCode = SME_QOS_DIAG_ADDTS_REFUSED;
+ WLAN_VOS_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS);
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+ status = sme_QosProcessAddTsFailureRsp(pMac, sessionId, &paddts_rsp->rsp);
+ }
+ else
+ {
+ status = sme_QosProcessAddTsSuccessRsp(pMac, sessionId, &paddts_rsp->rsp);
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessDelTsRsp() - Function to process the
+ eWNI_SME_DELTS_RSP came from PE
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pMsgBuf - Pointer to the msg buffer came from PE.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessDelTsRsp(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp)pMsgBuf;
+ sme_QosSessionInfo *pSession;
+ v_U8_t sessionId = pDeltsRsp->sessionId;
+ // msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d with return code %d",
+ __FUNCTION__, __LINE__,
+ sessionId, pDeltsRsp->rc);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ // our outstanding request has been serviced
+ // we can go into powersave
+ pSession->readyForPowerSave = VOS_TRUE;
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessDelTsInd() - Function to process the
+ eWNI_SME_DELTS_IND came from PE
+
+ Since it's a DELTS indication from AP, will notify all the flows running on
+ this AC about QoS release
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pMsgBuf - Pointer to the msg buffer came from PE.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessDelTsInd(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp)pMsgBuf;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t sessionId = pdeltsind->sessionId;
+ sme_QosEdcaAcType ac;
+ sme_QosSearchInfo search_key;
+ sme_QosWmmUpType up = (sme_QosWmmUpType)pdeltsind->rsp.tspec.tsinfo.traffic.userPrio;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ WLAN_VOS_DIAG_EVENT_DEF(qos, vos_event_wlan_qos_payload_type);
+#endif
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d for UP %d",
+ __FUNCTION__, __LINE__,
+ sessionId, up);
+ ac = sme_QosUpToAc(up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__,
+ ac, up);
+ return eHAL_STATUS_FAILURE;
+ }
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ //find all Flows on the perticular AC & delete them, also send HDD indication
+ // through the callback it registered per request
+ if(!HAL_STATUS_SUCCESS(sme_QosFindAllInFlowList(pMac, search_key, sme_QosDelTsIndFnp)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no match found for ac = %d",
+ __FUNCTION__, __LINE__,
+ search_key.key.ac_type);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ //clean up the CB
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR;
+ pACInfo->tspec_pending = 0;
+ //event: EVENT_WLAN_QOS
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ qos.eventId = SME_QOS_DIAG_DELTS;
+ qos.reasonCode = SME_QOS_DIAG_DELTS_IND_FROM_AP;
+ WLAN_VOS_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS);
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+
+ sme_QosStateTransition(sessionId, ac, SME_QOS_LINK_UP);
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessAssocCompleteEv() - Function to process the
+ SME_QOS_CSR_ASSOC_COMPLETE event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessAssocCompleteEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_BE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if(((SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state)&&
+ (SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state)&&
+ (SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state)&&
+ (SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state)) ||
+ (pSession->handoffRequested))
+ {
+ //get the association info
+ if(!pEvent_info)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pEvent_info is NULL",
+ __FUNCTION__, __LINE__);
+ return status;
+ }
+ if(!((sme_QosAssocInfo *)pEvent_info)->pBssDesc)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pBssDesc is NULL",
+ __FUNCTION__, __LINE__);
+ return status;
+ }
+ if((pSession->assocInfo.pBssDesc) &&
+ (csrIsBssidMatch(pMac, (tCsrBssid *)&pSession->assocInfo.pBssDesc->bssId,
+ (tCsrBssid *) &(((sme_QosAssocInfo *)pEvent_info)->pBssDesc->bssId))))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: assoc with the same BSS, no update needed",
+ __FUNCTION__, __LINE__);
+ }
+ else
+ {
+ status = sme_QosSaveAssocInfo(pSession, pEvent_info);
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: wrong state: BE %d, BK %d, VI %d, VO %d",
+ __FUNCTION__, __LINE__,
+ pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state,
+ pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state,
+ pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state,
+ pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ return status;
+ }
+ // the session is active
+ pSession->sessionActive = VOS_TRUE;
+ if(pSession->handoffRequested)
+ {
+ pSession->handoffRequested = VOS_FALSE;
+ //renew all flows
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ status = eHAL_STATUS_SUCCESS;
+ }
+ else
+ {
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_INIT:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_LINK_UP);
+ break;
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ case SME_QOS_HANDOFF:
+ case SME_QOS_CLOSED:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessReassocReqEv() - Function to process the
+ SME_QOS_CSR_REASSOC_REQ event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessReassocReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if(pSession->ftHandoffInProgress)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: no need for state transition, should "
+ "already be in handoff state",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(pSession->ac_info[0].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[1].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[2].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[3].curr_state == SME_QOS_HANDOFF);
+ sme_QosProcessFTReassocReqEv(pMac, sessionId, pEvent_info);
+ return eHAL_STATUS_SUCCESS;
+ }
+#endif
+
+ if(pSession->handoffRequested)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: no need for state transition, should "
+ "already be in handoff state",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(pSession->ac_info[0].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[1].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[2].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[3].curr_state == SME_QOS_HANDOFF);
+
+ //buffer the existing flows to be renewed after handoff is done
+ sme_QosBufferExistingFlows(pMac, sessionId);
+ //clean up the control block partially for handoff
+ sme_QosCleanupCtrlBlkForHandoff(pMac, sessionId);
+ return eHAL_STATUS_SUCCESS;
+ }
+//TBH: Assuming both handoff algo & 11r willn't be enabled at the same time
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if(pSession->ftHandoffInProgress)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: no need for state transition, should "
+ "already be in handoff state",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(pSession->ac_info[0].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[1].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[2].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[3].curr_state == SME_QOS_HANDOFF);
+
+ sme_QosProcessFTReassocReqEv(pMac, sessionId, pEvent_info);
+ return eHAL_STATUS_SUCCESS;
+ }
+#endif
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_HANDOFF);
+ break;
+ case SME_QOS_HANDOFF:
+ //This is normal because sme_QosRequestReassoc may already change the state
+ break;
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessReassocSuccessEv() - Function to process the
+ SME_QOS_CSR_REASSOC_COMPLETE event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessReassocSuccessEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ tpSirSmeJoinRsp pSmeJoinRsp = (tpSirSmeJoinRsp) pEvent_info;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac, ac_index;
+ sme_QosSearchInfo search_key;
+ sme_QosSearchInfo search_key1;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ tListElem *pEntry= NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ // our pending reassociation has completed
+ // we can allow powersave
+ pSession->readyForPowerSave = VOS_TRUE;
+ //get the association info
+ if(!pEvent_info)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pEvent_info is NULL",
+ __FUNCTION__, __LINE__);
+ return status;
+ }
+ if(!((sme_QosAssocInfo *)pEvent_info)->pBssDesc)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pBssDesc is NULL",
+ __FUNCTION__, __LINE__);
+ return status;
+ }
+ status = sme_QosSaveAssocInfo(pSession, pEvent_info);
+ if(status)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosSaveAssocInfo() failed",
+ __FUNCTION__, __LINE__);
+ }
+//TBH: Assuming both handoff algo & 11r willn't be enabled at the same time
+ if(pSession->handoffRequested)
+ {
+ pSession->handoffRequested = VOS_FALSE;
+ //renew all flows
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ return eHAL_STATUS_SUCCESS;
+ }
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (pSession->ftHandoffInProgress)
+ {
+ if (csrRoamIs11rAssoc(pMac)) {
+ if (pSmeJoinRsp->parsedRicRspLen) {
+ status = sme_QosProcessFTReassocRspEv(pMac, sessionId, pEvent_info);
+ }
+ }
+#ifdef FEATURE_WLAN_CCX
+ // If CCX association check for TSPEC IEs in the reassoc rsp frame
+ if (csrRoamIsCCXAssoc(pMac)) {
+ if (pSmeJoinRsp->tspecIeLen) {
+ status = sme_QosCCXProcessReassocTspecRsp(pMac, sessionId, pEvent_info);
+ }
+ }
+#endif
+ pSession->ftHandoffInProgress = VOS_FALSE;
+ pSession->handoffRequested = VOS_FALSE;
+ return status;
+ }
+#endif
+
+ pSession->sessionActive = VOS_TRUE;
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_HANDOFF:
+ // return to our previous state
+ sme_QosStateTransition(sessionId, ac, pACInfo->prev_state);
+ //for which ac APSD (hence the reassoc) is requested
+ if(pACInfo->reassoc_pending)
+ {
+ //update the apsd mask in CB - make sure to take care of the case
+ //where we are resetting the bit in apsd_mask
+ if(pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb)
+ {
+ pSession->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac);
+ }
+ else
+ {
+ pSession->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ }
+ pACInfo->reassoc_pending = VOS_FALSE;
+ //during setup it gets set as addts & reassoc both gets a pending flag
+ //pACInfo->tspec_pending = 0;
+ sme_QosStateTransition(sessionId, ac, SME_QOS_QOS_ON);
+ // notify HDD with new Service Interval
+ pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] =
+ pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0];
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ //notify PMC that reassoc is done for APSD on certain AC??
+
+ vos_mem_zero(&search_key1, sizeof(sme_QosSearchInfo));
+ //set the hoRenewal field in control block if needed
+ search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3;
+ search_key1.key.reason = SME_QOS_REASON_SETUP;
+ search_key1.sessionId = sessionId;
+ for(ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; ac_index++)
+ {
+ pEntry = sme_QosFindInFlowList(search_key1);
+ if(pEntry)
+ {
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if(flow_info->ac_type == ac)
+ {
+ pACInfo->hoRenewal = flow_info->hoRenewal;
+ break;
+ }
+ }
+ }
+ //notify HDD the success for the requested flow
+ //notify all the other flows running on the AC that QoS got modified
+ if(!HAL_STATUS_SUCCESS(sme_QosFindAllInFlowList(pMac, search_key, sme_QosReassocSuccessEvFnp)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no match found for ac = %d",
+ __FUNCTION__, __LINE__,
+ search_key.key.ac_type);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ pACInfo->hoRenewal = VOS_FALSE;
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ }
+ status = eHAL_STATUS_SUCCESS;
+ break;
+ case SME_QOS_INIT:
+ case SME_QOS_CLOSED:
+ //NOP
+ status = eHAL_STATUS_SUCCESS;
+ break;
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ return status;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessReassocFailureEv() - Function to process the
+ SME_QOS_CSR_REASSOC_FAILURE event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessReassocFailureEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ // our pending reassociation has completed
+ // we can allow powersave
+ pSession->readyForPowerSave = VOS_TRUE;
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_HANDOFF:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_INIT);
+ if(pACInfo->reassoc_pending)
+ {
+ pACInfo->reassoc_pending = VOS_FALSE;
+ }
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR;
+ pACInfo->tspec_pending = 0;
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0;
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0;
+ break;
+ case SME_QOS_INIT:
+ case SME_QOS_CLOSED:
+ //NOP
+ break;
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ //need to clean up flows
+ sme_QosDeleteExistingFlows(pMac, sessionId);
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessHandoffAssocReqEv() - Function to process the
+ SME_QOS_CSR_HANDOFF_ASSOC_REQ event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessHandoffAssocReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_HANDOFF);
+ break;
+ case SME_QOS_HANDOFF:
+ //print error msg
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if(pSession->ftHandoffInProgress)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: SME_QOS_CSR_HANDOFF_ASSOC_REQ received in "
+ "SME_QOS_HANDOFF state with FT in progress"
+ , __FUNCTION__, __LINE__);
+ break;
+ }
+#endif
+
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ // If FT handoff is in progress, legacy handoff need not be enabled
+ if (!pSession->ftHandoffInProgress) {
+ pSession->handoffRequested = VOS_TRUE;
+ }
+ // this session no longer needs UAPSD
+ pSession->apsdMask = 0;
+ // do any sessions still require UAPSD?
+ if (!sme_QosIsUapsdActive())
+ {
+ // No sessions require UAPSD so turn it off
+ // (really don't care when PMC stops it)
+ (void)pmcStopUapsd(pMac);
+ }
+ pSession->uapsdAlreadyRequested = VOS_FALSE;
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessHandoffSuccessEv() - Function to process the
+ SME_QOS_CSR_HANDOFF_COMPLETE event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessHandoffSuccessEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ //go back to original state before handoff
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_HANDOFF:
+ sme_QosStateTransition(sessionId, ac, pACInfo->prev_state);
+ //we will retry for the requested flow(s) with the new AP
+ if(SME_QOS_REQUESTED == pACInfo->curr_state)
+ {
+ pACInfo->curr_state = SME_QOS_LINK_UP;
+ }
+ status = eHAL_STATUS_SUCCESS;
+ break;
+ // FT logic, has already moved it to QOS_REQUESTED state during the
+ // reassoc request event, which would include the Qos (TSPEC) params
+ // in the reassoc req frame
+ case SME_QOS_REQUESTED:
+ break;
+ case SME_QOS_INIT:
+ case SME_QOS_CLOSED:
+ case SME_QOS_LINK_UP:
+ case SME_QOS_QOS_ON:
+ default:
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the
+ state may be SME_QOS_REQUESTED */
+ if( pSession->ftHandoffInProgress )
+ break;
+#endif
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessHandoffFailureEv() - Function to process the
+ SME_QOS_CSR_HANDOFF_FAILURE event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessHandoffFailureEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_HANDOFF:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_INIT);
+ //need to clean up flows: TODO
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ vos_mem_zero(&pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_1],
+ sizeof(sme_QosWmmTspecInfo));
+ pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR;
+ pACInfo->tspec_pending = 0;
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0;
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0;
+ break;
+ case SME_QOS_INIT:
+ case SME_QOS_CLOSED:
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+ //no longer in handoff
+ pSession->handoffRequested = VOS_FALSE;
+ //clean up the assoc info
+ if(pSession->assocInfo.pBssDesc)
+ {
+ vos_mem_free(pSession->assocInfo.pBssDesc);
+ pSession->assocInfo.pBssDesc = NULL;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessDisconnectEv() - Function to process the
+ SME_QOS_CSR_DISCONNECT_REQ or SME_QOS_CSR_DISCONNECT_IND event indication
+ from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessDisconnectEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if((pSession->handoffRequested)
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the
+ state may be SME_QOS_REQUESTED */
+ && !pSession->ftHandoffInProgress
+#endif
+ )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: no need for state transition, should "
+ "already be in handoff state",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(pSession->ac_info[0].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[1].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[2].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[3].curr_state == SME_QOS_HANDOFF);
+ return eHAL_STATUS_SUCCESS;
+ }
+ sme_QosInitACs(pMac, sessionId);
+ // this session doesn't require UAPSD
+ pSession->apsdMask = 0;
+ // do any sessions still require UAPSD?
+ if (!sme_QosIsUapsdActive())
+ {
+ // No sessions require UAPSD so turn it off
+ // (really don't care when PMC stops it)
+ (void)pmcStopUapsd(pMac);
+ }
+ pSession->uapsdAlreadyRequested = VOS_FALSE;
+ pSession->handoffRequested = VOS_FALSE;
+ pSession->readyForPowerSave = VOS_TRUE;
+ pSession->roamID = 0;
+ //need to clean up buffered req
+ sme_QosDeleteBufferedRequests(pMac, sessionId);
+ //need to clean up flows
+ sme_QosDeleteExistingFlows(pMac, sessionId);
+ //clean up the assoc info
+ if(pSession->assocInfo.pBssDesc)
+ {
+ vos_mem_free(pSession->assocInfo.pBssDesc);
+ pSession->assocInfo.pBssDesc = NULL;
+ }
+ sme_QosCb.sessionInfo[sessionId].sessionActive = VOS_FALSE;
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessJoinReqEv() - Function to process the
+ SME_QOS_CSR_JOIN_REQ event indication from CSR
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessJoinReqEv(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosEdcaAcType ac;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if(pSession->handoffRequested)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: no need for state transition, should "
+ "already be in handoff state",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(pSession->ac_info[0].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[1].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[2].curr_state == SME_QOS_HANDOFF);
+ VOS_ASSERT(pSession->ac_info[3].curr_state == SME_QOS_HANDOFF);
+ //buffer the existing flows to be renewed after handoff is done
+ sme_QosBufferExistingFlows(pMac, sessionId);
+ //clean up the control block partially for handoff
+ sme_QosCleanupCtrlBlkForHandoff(pMac, sessionId);
+ return eHAL_STATUS_SUCCESS;
+ }
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ sme_QosStateTransition(sessionId, ac, SME_QOS_INIT);
+ }
+ //clean up the assoc info if already set
+ if(pSession->assocInfo.pBssDesc)
+ {
+ vos_mem_free(pSession->assocInfo.pBssDesc);
+ pSession->assocInfo.pBssDesc = NULL;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessPreauthSuccessInd() - Function to process the
+ SME_QOS_CSR_PREAUTH_SUCCESS_IND event indication from CSR
+
+ \param pEvent_info - Pointer to relevant info from CSR.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessPreauthSuccessInd(tpAniSirGlobal pMac, v_U8_t sessionId, void * pEvent_info)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac;
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_LINK_UP:
+ case SME_QOS_REQUESTED:
+ case SME_QOS_QOS_ON:
+ sme_QosStateTransition(sessionId, ac, SME_QOS_HANDOFF);
+ break;
+ case SME_QOS_HANDOFF:
+ //print error msg
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d is in wrong state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ }
+
+ pSession->ftHandoffInProgress = VOS_TRUE;
+
+ // Check if its a 11R roaming before preparing the RIC IEs
+ if (csrRoamIs11rAssoc(pMac))
+ {
+ v_U16_t ricOffset = 0;
+ v_U32_t ricIELength = 0;
+ v_U8_t *ricIE;
+ v_U8_t tspec_mask_status = 0;
+ v_U8_t tspec_pending_status = 0;
+
+ /* Any Block Ack info there, should have been already filled by PE and present in this buffer
+ and the ric_ies_length should contain the length of the whole RIC IEs. Filling of TSPEC info
+ should start from this length */
+ ricIE = pMac->ft.ftSmeContext.psavedFTPreAuthRsp->ric_ies;
+ ricOffset = pMac->ft.ftSmeContext.psavedFTPreAuthRsp->ric_ies_length;
+
+ /* Now we have to process the currentTspeInfo inside this session and create the RIC IEs */
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ volatile v_U8_t tspec_index = 0;
+
+ pACInfo = &pSession->ac_info[ac];
+ tspec_pending_status = pACInfo->tspec_pending;
+ tspec_mask_status = pACInfo->tspec_mask_status;
+ vos_mem_zero(pACInfo->ricIdentifier, SME_QOS_TSPEC_INDEX_MAX);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ FL("AC %d ==> TSPEC status = %d, tspec pending = %d"),
+ ac, tspec_mask_status, tspec_pending_status);
+
+ do
+ {
+ if (tspec_mask_status & 0x1)
+ {
+ /* If a tspec status is pending, take requested_QoSInfo for RIC request, else use curr_QoSInfo
+ for the RIC request */
+ if (tspec_pending_status & 0x1)
+ {
+ status = sme_QosCreateTspecRICIE(pMac, &pACInfo->requested_QoSInfo[tspec_index],
+ ricIE + ricOffset, &ricIELength, &pACInfo->ricIdentifier[tspec_index]);
+ }
+ else
+ {
+ status = sme_QosCreateTspecRICIE(pMac, &pACInfo->curr_QoSInfo[tspec_index],
+ ricIE + ricOffset, &ricIELength, &pACInfo->ricIdentifier[tspec_index]);
+ }
+ }
+ ricOffset += ricIELength;
+ pMac->ft.ftSmeContext.psavedFTPreAuthRsp->ric_ies_length += ricIELength;
+
+ tspec_mask_status >>= 1;
+ tspec_pending_status >>= 1;
+ tspec_index++;
+ } while (tspec_mask_status);
+ }
+ }
+ return status;
+}
+
+#endif
+
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessAddTsFailureRsp() - Function to process the
+ Addts request failure response came from PE
+
+ We will notify HDD only for the requested Flow, other Flows running on the AC
+ stay intact
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pRsp - Pointer to the addts response structure came from PE.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessAddTsFailureRsp(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ tSirAddtsRspInfo * pRsp)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+ sme_QosSearchInfo search_key;
+ v_U8_t tspec_pending;
+ sme_QosWmmUpType up = (sme_QosWmmUpType)pRsp->tspec.tsinfo.traffic.userPrio;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for UP %d",
+ __FUNCTION__, __LINE__,
+ sessionId, up);
+ ac = sme_QosUpToAc(up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__, ac, up);
+ return eHAL_STATUS_FAILURE;
+ }
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ // is there a TSPEC request pending on this AC?
+ tspec_pending = pACInfo->tspec_pending;
+ if(!tspec_pending)
+ {
+ //ASSERT
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d an AddTS is not pending on AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ if(!HAL_STATUS_SUCCESS(sme_QosFindAllInFlowList(pMac, search_key, sme_QosAddTsFailureFnp)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d no match found for ac = %d",
+ __FUNCTION__, __LINE__,
+ sessionId, search_key.key.ac_type);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1],
+ sizeof(sme_QosWmmTspecInfo));
+
+ if((!pACInfo->num_flows[0])&&
+ (!pACInfo->num_flows[1]))
+ {
+ pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET &
+ (~pACInfo->tspec_pending);
+ sme_QosStateTransition(sessionId, ac, SME_QOS_LINK_UP);
+ }
+ else
+ {
+ sme_QosStateTransition(sessionId, ac, SME_QOS_QOS_ON);
+ }
+ pACInfo->tspec_pending = 0;
+
+ (void)sme_QosProcessBufferedCmd(sessionId);
+
+ return eHAL_STATUS_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosUpdateTspecMask() - Utiltity function to update the tspec.
+ Typical usage while aggregating unidirectional flows into a bi-directional
+ flow on AC which is running multiple flows
+
+ \param sessionId - Session upon which the TSPEC is being updated
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \param old_tspec_mask - on which tspec per AC, the update is requested
+ \param new_tspec_mask - tspec to be set for this AC
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosUpdateTspecMask(v_U8_t sessionId,
+ sme_QosSearchInfo search_key,
+ v_U8_t new_tspec_mask)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for AC %d TSPEC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, search_key.key.ac_type, new_tspec_mask);
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ if (search_key.key.ac_type < SME_QOS_EDCA_AC_MAX)
+ {
+ pACInfo = &pSession->ac_info[search_key.key.ac_type];
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Exceeded the array bounds of pSession->ac_info",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT (0);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, nothing to update",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+
+ if(search_key.sessionId == flow_info->sessionId)
+ {
+ if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_4)
+ {
+ if((search_key.key.ac_type == flow_info->ac_type) &&
+ (search_key.direction == flow_info->QoSInfo.ts_info.direction))
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Flow %d matches",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ pACInfo->num_flows[new_tspec_mask - 1]++;
+ flow_info->tspec_mask = new_tspec_mask;
+ }
+ }
+ else if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_5)
+ {
+ if((search_key.key.ac_type == flow_info->ac_type) &&
+ (search_key.tspec_mask == flow_info->tspec_mask))
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Flow %d matches",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ pACInfo->num_flows[new_tspec_mask - 1]++;
+ flow_info->tspec_mask = new_tspec_mask;
+ }
+ }
+ }
+
+ pEntry = pNextEntry;
+ }
+
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessAddTsSuccessRsp() - Function to process the
+ Addts request success response came from PE
+
+ We will notify HDD with addts success for the requested Flow, & for other
+ Flows running on the AC we will send an addts modify status
+
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pRsp - Pointer to the addts response structure came from PE.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessAddTsSuccessRsp(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ tSirAddtsRspInfo * pRsp)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac, ac_index;
+ sme_QosSearchInfo search_key;
+ sme_QosSearchInfo search_key1;
+ v_U8_t tspec_pending;
+ tListElem *pEntry= NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosWmmUpType up = (sme_QosWmmUpType)pRsp->tspec.tsinfo.traffic.userPrio;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ WLAN_VOS_DIAG_EVENT_DEF(qos, vos_event_wlan_qos_payload_type);
+ vos_log_qos_tspec_pkt_type *log_ptr = NULL;
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for UP %d",
+ __FUNCTION__, __LINE__,
+ sessionId, up);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ ac = sme_QosUpToAc(up);
+ if(SME_QOS_EDCA_AC_MAX == ac)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid AC %d from UP %d",
+ __FUNCTION__, __LINE__, ac, up);
+ return eHAL_STATUS_FAILURE;
+ }
+ pACInfo = &pSession->ac_info[ac];
+ // is there a TSPEC request pending on this AC?
+ tspec_pending = pACInfo->tspec_pending;
+ if(!tspec_pending)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d an AddTS is not pending on AC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ //App is looking for APSD or the App which was looking for APSD has been
+ //released, so STA re-negotiated with AP
+ if(pACInfo->requested_QoSInfo[tspec_pending - 1].ts_info.psb)
+ {
+ //update the session's apsd mask
+ pSession->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac);
+ }
+ else
+ {
+ if(((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) > 0) &&
+ ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) <=
+ SME_QOS_TSPEC_INDEX_MAX))
+ {
+ if(!pACInfo->requested_QoSInfo
+ [(SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) - 1].ts_info.psb)
+ {
+ //update the session's apsd mask
+ pSession->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Exceeded the array bounds of pACInfo->requested_QosInfo",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT (0);
+ return eHAL_STATUS_FAILURE;
+ }
+ }
+ pACInfo->curr_QoSInfo[tspec_pending - 1] =
+ pACInfo->requested_QoSInfo[tspec_pending - 1];
+ /* Check if the current flow is for bi-directional. If so, update the number of flows
+ * to reflect that all flows are aggregated into tspec index 0. */
+ if((pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1].ts_info.direction == SME_QOS_WMM_TS_DIR_BOTH) &&
+ (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0))
+ {
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ /* update tspec_mask for all the flows having SME_QOS_TSPEC_MASK_BIT_2_SET to SME_QOS_TSPEC_MASK_BIT_1_SET */
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_5;
+ search_key.sessionId = sessionId;
+ search_key.tspec_mask = SME_QOS_TSPEC_MASK_BIT_2_SET;
+ sme_QosUpdateTspecMask(sessionId, search_key, SME_QOS_TSPEC_MASK_BIT_1_SET);
+ }
+
+ vos_mem_zero(&search_key1, sizeof(sme_QosSearchInfo));
+ //set the horenewal field in control block if needed
+ search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3;
+ search_key1.key.reason = SME_QOS_REASON_SETUP;
+ search_key1.sessionId = sessionId;
+ for(ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; ac_index++)
+ {
+ pEntry = sme_QosFindInFlowList(search_key1);
+ if(pEntry)
+ {
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if(flow_info->ac_type == ac)
+ {
+ pACInfo->hoRenewal = flow_info->hoRenewal;
+ break;
+ }
+ }
+ }
+ vos_mem_zero(&search_key, sizeof(sme_QosSearchInfo));
+ //set the key type & the key to be searched in the Flow List
+ search_key.key.ac_type = ac;
+ search_key.index = SME_QOS_SEARCH_KEY_INDEX_2;
+ search_key.sessionId = sessionId;
+ //notify HDD the success for the requested flow
+ //notify all the other flows running on the AC that QoS got modified
+ if(!HAL_STATUS_SUCCESS(sme_QosFindAllInFlowList(pMac, search_key, sme_QosAddTsSuccessFnp)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d no match found for ac %d",
+ __FUNCTION__, __LINE__,
+ sessionId, search_key.key.ac_type);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ pACInfo->hoRenewal = VOS_FALSE;
+ vos_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1],
+ sizeof(sme_QosWmmTspecInfo));
+ //event: EVENT_WLAN_QOS
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+ qos.eventId = SME_QOS_DIAG_ADDTS_RSP;
+ qos.reasonCode = SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED;
+ WLAN_VOS_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS);
+ WLAN_VOS_DIAG_LOG_ALLOC(log_ptr, vos_log_qos_tspec_pkt_type, LOG_WLAN_QOS_TSPEC_C);
+ if(log_ptr)
+ {
+ log_ptr->delay_bound = pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound;
+ log_ptr->inactivity_interval = pACInfo->curr_QoSInfo[tspec_pending - 1].inactivity_interval;
+ log_ptr->max_burst_size = pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size;
+ log_ptr->max_service_interval = pACInfo->curr_QoSInfo[tspec_pending - 1].max_service_interval;
+ log_ptr->maximum_msdu_size = pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size;
+ log_ptr->mean_data_rate = pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate;
+ log_ptr->medium_time = pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time;
+ log_ptr->min_data_rate = pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate;
+ log_ptr->min_phy_rate = pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate;
+ log_ptr->min_service_interval = pACInfo->curr_QoSInfo[tspec_pending - 1].min_service_interval;
+ log_ptr->nominal_msdu_size = pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size;
+ log_ptr->peak_data_rate = pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate;
+ log_ptr->surplus_bw_allowance = pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance;
+ log_ptr->suspension_interval = pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance;
+ log_ptr->suspension_interval = pACInfo->curr_QoSInfo[tspec_pending - 1].suspension_interval;
+ log_ptr->svc_start_time = pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time;
+ log_ptr->tsinfo[0] = pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.direction << 5 |
+ pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.tid << 1;
+ log_ptr->tsinfo[1] = pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.up << 11 |
+ pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.psb << 10;
+ log_ptr->tsinfo[2] = 0;
+ }
+ WLAN_VOS_DIAG_LOG_REPORT(log_ptr);
+#endif //FEATURE_WLAN_DIAG_SUPPORT
+#ifdef FEATURE_WLAN_CCX
+ if (ac == SME_QOS_EDCA_AC_VO)
+ {
+ // Indicate to neighbor roam logic of the new required VO
+ // ac bandwidth requirement.
+ csrNeighborRoamIndicateVoiceBW( pMac, pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate, TRUE );
+ }
+#endif
+ pACInfo->tspec_pending = 0;
+
+ sme_QosStateTransition(sessionId, ac, SME_QOS_QOS_ON);
+
+
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ return eHAL_STATUS_SUCCESS;
+
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosAggregateParams() - Utiltity function to increament the TSPEC
+ params per AC. Typical usage while using flow aggregation or deletion of flows
+
+ \param pInput_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains the
+ WMM TSPEC related info with which pCurrent_Tspec_Info will be updated
+ \param pCurrent_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains
+ current the WMM TSPEC related info
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosAggregateParams(
+ sme_QosWmmTspecInfo * pInput_Tspec_Info,
+ sme_QosWmmTspecInfo * pCurrent_Tspec_Info,
+ sme_QosWmmTspecInfo * pUpdated_Tspec_Info)
+{
+ sme_QosWmmTspecInfo TspecInfo;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked",
+ __FUNCTION__, __LINE__);
+ if(!pInput_Tspec_Info)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: input is NULL, nothing to aggregate",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ if(!pCurrent_Tspec_Info)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Current is NULL, can't aggregate",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_copy(&TspecInfo, pCurrent_Tspec_Info,
+ sizeof(sme_QosWmmTspecInfo));
+ /*-------------------------------------------------------------------------
+ APSD preference is only meaningful if service interval was set by app
+ -------------------------------------------------------------------------*/
+ if(pCurrent_Tspec_Info->min_service_interval && pInput_Tspec_Info->min_service_interval)
+ {
+ TspecInfo.min_service_interval = VOS_MIN(
+ pCurrent_Tspec_Info->min_service_interval,
+ pInput_Tspec_Info->min_service_interval);
+ }
+ else if(pInput_Tspec_Info->min_service_interval)
+ {
+ TspecInfo.min_service_interval = pInput_Tspec_Info->min_service_interval;
+ }
+ if(pCurrent_Tspec_Info->max_service_interval)
+ {
+ TspecInfo.max_service_interval = VOS_MIN(
+ pCurrent_Tspec_Info->max_service_interval,
+ pInput_Tspec_Info->max_service_interval);
+ }
+ else
+ {
+ TspecInfo.max_service_interval = pInput_Tspec_Info->max_service_interval;
+ }
+ /*-------------------------------------------------------------------------
+ If directions don't match, it must necessarily be both uplink and
+ downlink
+ -------------------------------------------------------------------------*/
+ if(pCurrent_Tspec_Info->ts_info.direction !=
+ pInput_Tspec_Info->ts_info.direction)
+ {
+ TspecInfo.ts_info.direction = SME_QOS_WMM_TS_DIR_BOTH;
+ }
+ /*-------------------------------------------------------------------------
+ Max MSDU size : these sizes are `maxed'
+ -------------------------------------------------------------------------*/
+ TspecInfo.maximum_msdu_size = VOS_MAX(pCurrent_Tspec_Info->maximum_msdu_size,
+ pInput_Tspec_Info->maximum_msdu_size);
+
+ /*-------------------------------------------------------------------------
+ Inactivity interval : these sizes are `maxed'
+ -------------------------------------------------------------------------*/
+ TspecInfo.inactivity_interval = VOS_MAX(pCurrent_Tspec_Info->inactivity_interval,
+ pInput_Tspec_Info->inactivity_interval);
+
+ /*-------------------------------------------------------------------------
+ Delay bounds: min of all values
+ Check on 0: if 0, it means initial value since delay can never be 0!!
+ -------------------------------------------------------------------------*/
+ if(pCurrent_Tspec_Info->delay_bound)
+ {
+ TspecInfo.delay_bound = VOS_MIN(pCurrent_Tspec_Info->delay_bound,
+ pInput_Tspec_Info->delay_bound);
+ }
+ else
+ {
+ TspecInfo.delay_bound = pInput_Tspec_Info->delay_bound;
+ }
+ TspecInfo.max_burst_size = VOS_MAX(pCurrent_Tspec_Info->max_burst_size,
+ pInput_Tspec_Info->max_burst_size);
+
+ /*-------------------------------------------------------------------------
+ Nominal MSDU size also has a fixed bit that needs to be `handled' before
+ aggregation
+ This can be handled only if previous size is the same as new or both have
+ the fixed bit set
+ These sizes are not added: but `maxed'
+ -------------------------------------------------------------------------*/
+ TspecInfo.nominal_msdu_size = VOS_MAX(
+ pCurrent_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB,
+ pInput_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB);
+
+ if( ((pCurrent_Tspec_Info->nominal_msdu_size == 0) ||
+ (pCurrent_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)) &&
+ ((pInput_Tspec_Info->nominal_msdu_size == 0) ||
+ (pInput_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)))
+ {
+ TspecInfo.nominal_msdu_size |= SME_QOS_16BIT_MSB;
+ }
+
+ /*-------------------------------------------------------------------------
+ Data rates:
+ Add up the rates for aggregation
+ -------------------------------------------------------------------------*/
+ SME_QOS_BOUNDED_U32_ADD_Y_TO_X( TspecInfo.peak_data_rate,
+ pInput_Tspec_Info->peak_data_rate );
+ SME_QOS_BOUNDED_U32_ADD_Y_TO_X( TspecInfo.min_data_rate,
+ pInput_Tspec_Info->min_data_rate );
+ /* mean data rate = peak data rate: aggregate to be flexible on apps */
+ SME_QOS_BOUNDED_U32_ADD_Y_TO_X( TspecInfo.mean_data_rate,
+ pInput_Tspec_Info->mean_data_rate );
+
+ /*-------------------------------------------------------------------------
+ Suspension interval : this is set to the inactivity interval since per
+ spec it is less than or equal to inactivity interval
+ This is not provided by app since we currently don't support the HCCA
+ mode of operation
+ Currently set it to 0 to avoid confusion: Cisco CCX needs ~0; spec
+ requires inactivity interval to be > suspension interval: this could
+ be tricky!
+ -------------------------------------------------------------------------*/
+ TspecInfo.suspension_interval = 0;
+ /*-------------------------------------------------------------------------
+ Remaining parameters do not come from app as they are very WLAN
+ air interface specific
+ Set meaningful values here
+ -------------------------------------------------------------------------*/
+ TspecInfo.medium_time = 0; /* per WMM spec */
+ TspecInfo.min_phy_rate = SME_QOS_MIN_PHY_RATE;
+ TspecInfo.svc_start_time = 0; /* arbitrary */
+ TspecInfo.surplus_bw_allowance += pInput_Tspec_Info->surplus_bw_allowance;
+ if(TspecInfo.surplus_bw_allowance > SME_QOS_SURPLUS_BW_ALLOWANCE)
+ {
+ TspecInfo.surplus_bw_allowance = SME_QOS_SURPLUS_BW_ALLOWANCE;
+ }
+ /* Set ack_policy to block ack even if one stream requests block ack policy */
+ if((pInput_Tspec_Info->ts_info.ack_policy == SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) ||
+ (pCurrent_Tspec_Info->ts_info.ack_policy == SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK))
+ {
+ TspecInfo.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
+ }
+
+ if(pInput_Tspec_Info->ts_info.burst_size_defn || pCurrent_Tspec_Info->ts_info.burst_size_defn )
+ {
+ TspecInfo.ts_info.burst_size_defn = 1;
+ }
+ if(pUpdated_Tspec_Info)
+ {
+ vos_mem_copy(pUpdated_Tspec_Info, &TspecInfo,
+ sizeof(sme_QosWmmTspecInfo));
+ }
+ else
+ {
+ vos_mem_copy(pCurrent_Tspec_Info, &TspecInfo,
+ sizeof(sme_QosWmmTspecInfo));
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosUpdateParams() - Utiltity function to update the TSPEC
+ params per AC. Typical usage while deleting flows on AC which is running
+ multiple flows
+
+ \param sessionId - Session upon which the TSPEC is being updated
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \param tspec_mask - on which tspec per AC, the update is requested
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosUpdateParams(v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspec_mask,
+ sme_QosWmmTspecInfo * pTspec_Info)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosWmmTspecInfo Tspec_Info;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: invoked on session %d for AC %d TSPEC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, tspec_mask);
+ if(!pTspec_Info)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: output is NULL, can't aggregate",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_zero(&Tspec_Info, sizeof(sme_QosWmmTspecInfo));
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, nothing to update",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ //init the TS info field
+ Tspec_Info.ts_info.up = pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.up;
+ Tspec_Info.ts_info.psb = pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.psb;
+ Tspec_Info.ts_info.tid = pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.tid;
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if((sessionId == flow_info->sessionId) &&
+ (ac == flow_info->ac_type) &&
+ (tspec_mask == flow_info->tspec_mask))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Flow %d matches",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+
+ if((SME_QOS_REASON_RELEASE == flow_info->reason ) ||
+ (SME_QOS_REASON_MODIFY == flow_info->reason))
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Skipping Flow %d as it is marked "
+ "for release/modify",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ else if(!HAL_STATUS_SUCCESS(sme_QosAggregateParams(&flow_info->QoSInfo,
+ &Tspec_Info,
+ NULL)))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosAggregateParams() failed",
+ __FUNCTION__, __LINE__);
+ }
+ }
+ pEntry = pNextEntry;
+ }
+ // return the aggregate
+ *pTspec_Info = Tspec_Info;
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosAcToUp() - Utiltity function to map an AC to UP
+ Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs
+ Mapping is done for consistency
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \return an User Priority
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosWmmUpType sme_QosAcToUp(sme_QosEdcaAcType ac)
+{
+ sme_QosWmmUpType up = SME_QOS_WMM_UP_MAX;
+ if(ac >= 0 && ac < SME_QOS_EDCA_AC_MAX)
+ {
+ up = sme_QosACtoUPMap[ac];
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: ac = %d up = %d returned",
+ __FUNCTION__, __LINE__, ac, up);
+ return up;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosUpToAc() - Utiltity function to map an UP to AC
+ \param up - Enumeration of the various User priorities (UP).
+ \return an Access Category
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+sme_QosEdcaAcType sme_QosUpToAc(sme_QosWmmUpType up)
+{
+ sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_MAX;
+ if(up >= 0 && up < SME_QOS_WMM_UP_MAX)
+ {
+ ac = sme_QosUPtoACMap[up];
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+ "%s: %d: up = %d ac = %d returned",
+ __FUNCTION__, __LINE__, up, ac);
+ return ac;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosStateTransition() - The state transition function per AC. We
+ save the previous state also.
+ \param sessionId - Session upon which the state machine is running
+ \param ac - Enumeration of the various EDCA Access Categories.
+ \param new_state - The state FSM is moving to.
+
+ \return None
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static void sme_QosStateTransition(v_U8_t sessionId,
+ sme_QosEdcaAcType ac,
+ sme_QosStates new_state)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ pACInfo->prev_state = pACInfo->curr_state;
+ pACInfo->curr_state = new_state;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d new state=%d, old state=%d, for AC=%d",
+ __FUNCTION__, __LINE__,
+ sessionId, pACInfo->curr_state, pACInfo->prev_state, ac );
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosFindInFlowList() - Utility function to find an flow entry from
+ the flow_list.
+ \param search_key - We can either use the flowID or the ac type to find the
+ entry in the flow list.
+ A bitmap in sme_QosSearchInfo tells which key to use. Starting from LSB,
+ bit 0 - Flow ID
+ bit 1 - AC type
+ \return the pointer to the entry in the link list
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+tListElem *sme_QosFindInFlowList(sme_QosSearchInfo search_key)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, can't search",
+ __FUNCTION__, __LINE__);
+ return NULL;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if((search_key.sessionId == flow_info->sessionId) ||
+ (search_key.sessionId == SME_QOS_SEARCH_SESSION_ID_ANY))
+ {
+ if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_1)
+ {
+ if(search_key.key.QosFlowID == flow_info->QosFlowID)
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on flowID, ending search",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ }
+ else if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_2)
+ {
+ if(search_key.key.ac_type == flow_info->ac_type)
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on ac, ending search",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ }
+ else if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_3)
+ {
+ if(search_key.key.reason == flow_info->reason)
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on reason, ending search",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ }
+ else if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_4)
+ {
+ if((search_key.key.ac_type == flow_info->ac_type) &&
+ (search_key.direction == flow_info->QoSInfo.ts_info.direction))
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on reason, ending search",
+ __FUNCTION__, __LINE__);
+
+ break;
+ }
+ }
+ }
+ pEntry = pNextEntry;
+ }
+ return pEntry;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosFindAllInFlowList() - Utility function to find an flow entry
+ from the flow_list & act on it.
+ \param search_key - We can either use the flowID or the ac type to find the
+ entry in the flow list.
+ A bitmap in sme_QosSearchInfo tells which key to use. Starting from LSB,
+ bit 0 - Flow ID
+ bit 1 - AC type
+ \param fnp - function pointer specifying the action type for the entry found
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosFindAllInFlowList(tpAniSirGlobal pMac,
+ sme_QosSearchInfo search_key,
+ sme_QosProcessSearchEntry fnp)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, can't search",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ if((search_key.sessionId == flow_info->sessionId) ||
+ (search_key.sessionId == SME_QOS_SEARCH_SESSION_ID_ANY))
+ {
+ if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_1)
+ {
+ if(search_key.key.QosFlowID == flow_info->QosFlowID)
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on flowID, ending search",
+ __FUNCTION__, __LINE__);
+ status = fnp(pMac, pEntry);
+ if(eHAL_STATUS_FAILURE == status)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Failed to process entry",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ }
+ }
+ else if(search_key.index & SME_QOS_SEARCH_KEY_INDEX_2)
+ {
+ if(search_key.key.ac_type == flow_info->ac_type)
+ {
+ //msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: match found on ac, ending search",
+ __FUNCTION__, __LINE__);
+ flow_info->hoRenewal = pSession->ac_info[flow_info->ac_type].hoRenewal;
+ status = fnp(pMac, pEntry);
+ if(eHAL_STATUS_FAILURE == status)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Failed to process entry",
+ __FUNCTION__, __LINE__);
+ break;
+ }
+ }
+ }
+ }
+ pEntry = pNextEntry;
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosIsACM() - Utility function to check if a particular AC
+ mandates Admission Control.
+ \param ac - Enumeration of the various EDCA Access Categories.
+
+ \return VOS_TRUE if the AC mandates Admission Control
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+v_BOOL_t sme_QosIsACM(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc,
+ sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes)
+{
+ v_BOOL_t ret_val = VOS_FALSE;
+ tDot11fBeaconIEs *pIesLocal;
+ if(!pSirBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pSirBssDesc is NULL",
+ __FUNCTION__, __LINE__);
+ return VOS_FALSE;
+ }
+
+ if (NULL != pIes)
+ {
+ /* IEs were provided so use them locally */
+ pIesLocal = pIes;
+ }
+ else
+ {
+ /* IEs were not provided so parse them ourselves */
+ if (!HAL_STATUS_SUCCESS(csrGetParsedBssDescriptionIEs(pMac, pSirBssDesc, &pIesLocal)))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: csrGetParsedBssDescriptionIEs() failed",
+ __FUNCTION__, __LINE__);
+ return VOS_FALSE;
+ }
+
+ /* if success then pIesLocal was allocated */
+ }
+
+ if(CSR_IS_QOS_BSS(pIesLocal))
+ {
+ switch(ac)
+ {
+ case SME_QOS_EDCA_AC_BE:
+ if(pIesLocal->WMMParams.acbe_acm) ret_val = VOS_TRUE;
+ break;
+ case SME_QOS_EDCA_AC_BK:
+ if(pIesLocal->WMMParams.acbk_acm) ret_val = VOS_TRUE;
+ break;
+ case SME_QOS_EDCA_AC_VI:
+ if(pIesLocal->WMMParams.acvi_acm) ret_val = VOS_TRUE;
+ break;
+ case SME_QOS_EDCA_AC_VO:
+ if(pIesLocal->WMMParams.acvo_acm) ret_val = VOS_TRUE;
+ break;
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: unknown AC = %d",
+ __FUNCTION__, __LINE__, ac);
+ //Assert
+ VOS_ASSERT(0);
+ break;
+ }
+ }//IS_QOS_BSS
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: ACM = %d for AC = %d",
+ __FUNCTION__, __LINE__, ret_val, ac );
+ if (NULL == pIes)
+ {
+ /* IEs were allocated locally so free them */
+ vos_mem_free(pIesLocal);
+ }
+ return ret_val;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosBufferExistingFlows() - Utility function to buffer the existing
+ flows in flow_list, so that we can renew them after handoff is done.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosBufferExistingFlows(tpAniSirGlobal pMac,
+ v_U8_t sessionId)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosSessionInfo *pSession;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosCmdInfo cmd;
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, nothing to buffer",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if (flow_info->sessionId == sessionId)
+ {
+ if((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason )||
+ (SME_QOS_REASON_SETUP == flow_info->reason ))
+ {
+ cmd.command = SME_QOS_SETUP_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.setupCmdInfo.HDDcontext = flow_info->HDDcontext;
+ cmd.u.setupCmdInfo.QoSInfo = flow_info->QoSInfo;
+ cmd.u.setupCmdInfo.QoSCallback = flow_info->QoSCallback;
+ cmd.u.setupCmdInfo.UPType = SME_QOS_WMM_UP_MAX;//shouldn't be needed
+ cmd.u.setupCmdInfo.QosFlowID = flow_info->QosFlowID;
+ if(SME_QOS_REASON_SETUP == flow_info->reason )
+ {
+ cmd.u.setupCmdInfo.hoRenewal = VOS_FALSE;
+ }
+ else
+ {
+ cmd.u.setupCmdInfo.hoRenewal = VOS_TRUE;//TODO: might need this for modify
+ }
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_TRUE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the setup request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: buffered a setup request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ }
+ else if(SME_QOS_REASON_RELEASE == flow_info->reason )
+ {
+ cmd.command = SME_QOS_RELEASE_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID;
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_TRUE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the release request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: buffered a release request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ }
+ else if(SME_QOS_REASON_MODIFY_PENDING == flow_info->reason)
+ {
+ cmd.command = SME_QOS_MODIFY_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.modifyCmdInfo.QosFlowID = flow_info->QosFlowID;
+ cmd.u.modifyCmdInfo.QoSInfo = flow_info->QoSInfo;
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_TRUE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the modify request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: buffered a modify request for "
+ "flow %d in handoff state",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ }
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting original entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ vos_mem_free(flow_info);
+ }
+ pEntry = pNextEntry;
+ }
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pSession->uapsdAlreadyRequested = VOS_FALSE;
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosDeleteExistingFlows() - Utility function to Delete the existing
+ flows in flow_list, if we lost connectivity.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosDeleteExistingFlows(tpAniSirGlobal pMac,
+ v_U8_t sessionId)
+{
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_TRUE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, nothing to delete",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ if (flow_info->sessionId == sessionId)
+ {
+ if((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason )||
+ (SME_QOS_REASON_SETUP == flow_info->reason )||
+ (SME_QOS_REASON_RELEASE == flow_info->reason )||
+ (SME_QOS_REASON_MODIFY == flow_info->reason ))
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ NULL,
+ SME_QOS_STATUS_RELEASE_QOS_LOST_IND,
+ flow_info->QosFlowID);
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ //delete the entry from Flow List
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ vos_mem_free(flow_info);
+ }
+ pEntry = pNextEntry;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosBufferCmd() - Utility function to buffer a request (setup/modify/
+ release) from client while processing another one on the same AC.
+ \param pcmd - a pointer to the cmd structure to be saved inside the buffered
+ cmd link list
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosBufferCmd(sme_QosCmdInfo *pcmd, v_BOOL_t insert_head)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosCmdInfoEntry * pentry = NULL;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked",
+ __FUNCTION__, __LINE__);
+ pentry = (sme_QosCmdInfoEntry *) vos_mem_malloc(sizeof(sme_QosCmdInfoEntry));
+ if (!pentry)
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Memory allocation failure",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ // copy the entire CmdInfo
+ pentry->cmdInfo = *pcmd;
+
+ pSession = &sme_QosCb.sessionInfo[pcmd->sessionId];
+ if(insert_head)
+ {
+ csrLLInsertHead(&pSession->bufferedCommandList, &pentry->link, VOS_TRUE);
+ }
+ else
+ {
+ csrLLInsertTail(&pSession->bufferedCommandList, &pentry->link, VOS_TRUE);
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessBufferedCmd() - Utility function to process a buffered
+ request (setup/modify/release) initially came from the client.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosProcessBufferedCmd(v_U8_t sessionId)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosCmdInfoEntry *pcmd = NULL;
+ tListElem *pEntry= NULL;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ eHalStatus halStatus = eHAL_STATUS_SUCCESS;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if(!csrLLIsListEmpty( &pSession->bufferedCommandList, VOS_FALSE ))
+ {
+ pEntry = csrLLRemoveHead( &pSession->bufferedCommandList, VOS_TRUE );
+ if(!pEntry)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: no more buffered commands on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ pSession->readyForPowerSave = VOS_TRUE;
+ return eHAL_STATUS_FAILURE;
+ }
+ pcmd = GET_BASE_ADDR( pEntry, sme_QosCmdInfoEntry, link );
+ switch(pcmd->cmdInfo.command)
+ {
+ case SME_QOS_SETUP_REQ:
+ hdd_status = sme_QosInternalSetupReq(pcmd->cmdInfo.pMac,
+ pcmd->cmdInfo.sessionId,
+ &pcmd->cmdInfo.u.setupCmdInfo.QoSInfo,
+ pcmd->cmdInfo.u.setupCmdInfo.QoSCallback,
+ pcmd->cmdInfo.u.setupCmdInfo.HDDcontext,
+ pcmd->cmdInfo.u.setupCmdInfo.UPType,
+ pcmd->cmdInfo.u.setupCmdInfo.QosFlowID,
+ VOS_TRUE,
+ pcmd->cmdInfo.u.setupCmdInfo.hoRenewal);
+ if(SME_QOS_STATUS_SETUP_FAILURE_RSP == hdd_status)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosInternalSetupReq failed on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ halStatus = eHAL_STATUS_FAILURE;
+ }
+ break;
+ case SME_QOS_RELEASE_REQ:
+ hdd_status = sme_QosInternalReleaseReq(pcmd->cmdInfo.pMac,
+ pcmd->cmdInfo.u.releaseCmdInfo.QosFlowID,
+ VOS_TRUE);
+ if(SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosInternalReleaseReq failed on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ halStatus = eHAL_STATUS_FAILURE;
+ }
+ break;
+ case SME_QOS_MODIFY_REQ:
+ hdd_status = sme_QosInternalModifyReq(pcmd->cmdInfo.pMac,
+ &pcmd->cmdInfo.u.modifyCmdInfo.QoSInfo,
+ pcmd->cmdInfo.u.modifyCmdInfo.QosFlowID,
+ VOS_TRUE);
+ if(SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == hdd_status)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosInternalModifyReq failed on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ halStatus = eHAL_STATUS_FAILURE;
+ }
+ break;
+ case SME_QOS_RESEND_REQ:
+ hdd_status = sme_QosReRequestAddTS(pcmd->cmdInfo.pMac,
+ pcmd->cmdInfo.sessionId,
+ &pcmd->cmdInfo.u.resendCmdInfo.QoSInfo,
+ pcmd->cmdInfo.u.resendCmdInfo.ac,
+ pcmd->cmdInfo.u.resendCmdInfo.tspecMask);
+ if(SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == hdd_status)
+ {
+ //Err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: sme_QosReRequestAddTS failed on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ halStatus = eHAL_STATUS_FAILURE;
+ }
+ break;
+ default:
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unknown cmd = %d",
+ __FUNCTION__, __LINE__,
+ sessionId, pcmd->cmdInfo.command);
+ //ASSERT
+ VOS_ASSERT(0);
+ break;
+ }
+ // buffered command has been processed, reclaim the memory
+ vos_mem_free(pcmd);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: cmd buffer empty",
+ __FUNCTION__, __LINE__);
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ return halStatus;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosDeleteBufferedRequests() - Utility function to Delete the buffered
+ requests in the buffered_cmd_list, if we lost connectivity.
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static eHalStatus sme_QosDeleteBufferedRequests(tpAniSirGlobal pMac,
+ v_U8_t sessionId)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosCmdInfoEntry *pcmd = NULL;
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d",
+ __FUNCTION__, __LINE__, sessionId);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pEntry = csrLLPeekHead( &pSession->bufferedCommandList, VOS_TRUE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Buffered List empty, nothing to delete on session %d",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &pSession->bufferedCommandList, pEntry, VOS_TRUE );
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: deleting entry from buffered List",
+ __FUNCTION__, __LINE__);
+ //delete the entry from Flow List
+ csrLLRemoveEntry(&pSession->bufferedCommandList, pEntry, VOS_TRUE );
+ // reclaim the memory
+ pcmd = GET_BASE_ADDR( pEntry, sme_QosCmdInfoEntry, link );
+ vos_mem_free(pcmd);
+ pEntry = pNextEntry;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosSaveAssocInfo() - Utility function to save the assoc info in the
+ CB like BSS descritor of the AP, the profile that HDD sent down with the
+ connect request, while CSR notifies for assoc/reassoc success.
+ \param pAssoc_info - pointer to the assoc structure to store the BSS descritor
+ of the AP, the profile that HDD sent down with the
+ connect request
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosSaveAssocInfo(sme_QosSessionInfo *pSession, sme_QosAssocInfo *pAssoc_info)
+{
+ tSirBssDescription *pBssDesc = NULL;
+ v_U32_t bssLen = 0;
+ if(NULL == pAssoc_info)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: pAssoc_info is NULL",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ //clean up the assoc info if already set
+ if(pSession->assocInfo.pBssDesc)
+ {
+ vos_mem_free(pSession->assocInfo.pBssDesc);
+ pSession->assocInfo.pBssDesc = NULL;
+ }
+ bssLen = pAssoc_info->pBssDesc->length +
+ sizeof(pAssoc_info->pBssDesc->length);
+ //save the bss Descriptor
+ pBssDesc = (tSirBssDescription *)vos_mem_malloc(bssLen);
+ if (!pBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't allocate memory for the bss Descriptor",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ vos_mem_copy(pBssDesc, pAssoc_info->pBssDesc, bssLen);
+ pSession->assocInfo.pBssDesc = pBssDesc;
+ //save the apsd info from assoc
+ if(pAssoc_info->pProfile)
+ {
+ pSession->apsdMask |= pAssoc_info->pProfile->uapsd_mask;
+ }
+ // [TODO] Do we need to update the global APSD bitmap?
+ return eHAL_STATUS_SUCCESS;
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosSetupFnp() - Utility function (pointer) to notify other entries
+ in FLOW list on the same AC that qos params got modified
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosSetupFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND;
+ sme_QosEdcaAcType ac;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ if(SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)
+ {
+ //notify HDD, only the other Flows running on the AC
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ hdd_status,
+ flow_info->QosFlowID);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Entry with flowID = %d getting notified",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosModificationNotifyFnp() - Utility function (pointer) to notify
+ other entries in FLOW list on the same AC that qos params got modified
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosModificationNotifyFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND;
+ sme_QosEdcaAcType ac;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ if(SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)
+ {
+ //notify HDD, only the other Flows running on the AC
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ hdd_status,
+ flow_info->QosFlowID);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Entry with flowID = %d getting notified",
+ __FUNCTION__, __LINE__,
+ flow_info->QosFlowID);
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosModifyFnp() - Utility function (pointer) to delete the origianl
+ entry in FLOW list & add the modified one
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosModifyFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ switch(flow_info->reason)
+ {
+ case SME_QOS_REASON_MODIFY_PENDING:
+ //set the proper reason code for the new (with modified params) entry
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ break;
+ case SME_QOS_REASON_MODIFY:
+ //delete the original entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting original entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ // reclaim the memory
+ vos_mem_free(flow_info);
+ break;
+ default:
+ break;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosDelTsIndFnp() - Utility function (pointer) to find all Flows on
+ the perticular AC & delete them, also send HDD indication through the callback
+ it registered per request
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosDelTsIndFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ sme_QosEdcaAcType ac;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ //delete the entry from Flow List
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[flow_info->tspec_mask - 1],
+ SME_QOS_STATUS_RELEASE_QOS_LOST_IND,
+ flow_info->QosFlowID);
+ pACInfo->num_flows[flow_info->tspec_mask - 1]--;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ // reclaim the memory
+ vos_mem_free(flow_info);
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosReassocSuccessEvFnp() - Utility function (pointer) to notify HDD
+ the success for the requested flow & notify all the other flows running on the
+ same AC that QoS params got modified
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosReassocSuccessEvFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ v_BOOL_t delete_entry = VOS_FALSE;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ sme_QosEdcaAcType ac;
+ eHalStatus pmc_status = eHAL_STATUS_FAILURE;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link);
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ switch(flow_info->reason)
+ {
+ case SME_QOS_REASON_SETUP:
+ hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND;
+ delete_entry = VOS_FALSE;
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ //check for the case where we had to do reassoc to reset the apsd bit
+ //for the ac - release or modify scenario
+ if(pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb)
+ {
+ // notify PMC as App is looking for APSD. If we already requested
+ // then we don't need to do anything.
+ if(!pSession->uapsdAlreadyRequested)
+ {
+ // this is the first flow to detect we need PMC in UAPSD mode
+
+ pmc_status = pmcStartUapsd(pMac,
+ sme_QosPmcStartUapsdCallback,
+ pSession);
+ // if PMC doesn't return success right away means it is yet to put
+ // the module in BMPS state & later to UAPSD state
+
+ if(eHAL_STATUS_FAILURE == pmc_status)
+ {
+ hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED;
+ //we need to always notify this case
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ else if(eHAL_STATUS_PMC_PENDING == pmc_status)
+ {
+ // let other flows know PMC has been notified
+ pSession->uapsdAlreadyRequested = VOS_TRUE;
+ }
+ // for any other pmc status we declare success
+ }
+ }
+ break;
+ case SME_QOS_REASON_RELEASE:
+ pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]--;
+ // fall through
+ case SME_QOS_REASON_MODIFY:
+ delete_entry = VOS_TRUE;
+ break;
+ case SME_QOS_REASON_MODIFY_PENDING:
+ hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND;
+ delete_entry = VOS_FALSE;
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ if(pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb)
+ {
+
+ if(!pSession->uapsdAlreadyRequested)
+ {
+ // this is the first flow to detect we need PMC in UAPSD mode
+ pmc_status = pmcStartUapsd(pMac,
+ sme_QosPmcStartUapsdCallback,
+ pSession);
+
+ // if PMC doesn't return success right away means it is yet to put
+ // the module in BMPS state & later to UAPSD state
+ if(eHAL_STATUS_FAILURE == pmc_status)
+ {
+ hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED;
+ // we need to always notify this case
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ else if(eHAL_STATUS_PMC_PENDING == pmc_status)
+ {
+ pSession->uapsdAlreadyRequested = VOS_TRUE;
+ }
+ // for any other pmc status we declare success
+ }
+ }
+ break;
+ case SME_QOS_REASON_REQ_SUCCESS:
+ hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND;
+ // fall through
+ default:
+ delete_entry = VOS_FALSE;
+ break;
+ }
+ if(!delete_entry)
+ {
+ if(!flow_info->hoRenewal)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0],
+ hdd_status,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ }
+ else
+ {
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ // reclaim the memory
+ vos_mem_free(flow_info);
+ }
+
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosAddTsFailureFnp() - Utility function (pointer),
+ if the Addts request was for for an flow setup request, delete the entry from
+ Flow list & notify HDD
+ if the Addts request was for downgrading of QoS params because of an flow
+ release requested on the AC, delete the entry from Flow list & notify HDD
+ if the Addts request was for change of QoS params because of an flow
+ modification requested on the AC, delete the new entry from Flow list & notify
+ HDD
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosAddTsFailureFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ v_BOOL_t inform_hdd = VOS_FALSE;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ sme_QosEdcaAcType ac;
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ switch(flow_info->reason)
+ {
+ case SME_QOS_REASON_SETUP:
+ hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ pACInfo->num_flows[pACInfo->tspec_pending - 1]--;
+ inform_hdd = VOS_TRUE;
+ break;
+ case SME_QOS_REASON_RELEASE:
+ hdd_status = SME_QOS_STATUS_RELEASE_FAILURE_RSP;
+ pACInfo->num_flows[pACInfo->tspec_pending - 1]--;
+ inform_hdd = VOS_TRUE;
+ break;
+ case SME_QOS_REASON_MODIFY_PENDING:
+ hdd_status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ inform_hdd = VOS_TRUE;
+ break;
+ case SME_QOS_REASON_MODIFY:
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ case SME_QOS_REASON_REQ_SUCCESS:
+ default:
+ inform_hdd = VOS_FALSE;
+ break;
+ }
+ if(inform_hdd)
+ {
+ //notify HDD, only the requested Flow, other Flows running on the AC stay
+ // intact
+ if(!flow_info->hoRenewal)
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1],
+ hdd_status,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1],
+ SME_QOS_STATUS_RELEASE_QOS_LOST_IND,
+ flow_info->QosFlowID);
+ }
+ //delete the entry from Flow List
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ // reclaim the memory
+ vos_mem_free(flow_info);
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosAddTsSuccessFnp() - Utility function (pointer),
+ if the Addts request was for for an flow setup request, notify HDD for success
+ for the flow & notify all the other flows running on the same AC that QoS
+ params got modified
+ if the Addts request was for downgrading of QoS params because of an flow
+ release requested on the AC, delete the entry from Flow list & notify HDD
+ if the Addts request was for change of QoS params because of an flow
+ modification requested on the AC, delete the old entry from Flow list & notify
+ HDD for success for the flow & notify all the other flows running on the same
+ AC that QoS params got modified
+ \param pMac - Pointer to the global MAC parameter structure.
+ \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure)
+
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosAddTsSuccessFnp(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+ v_BOOL_t inform_hdd = VOS_FALSE;
+ v_BOOL_t delete_entry = VOS_FALSE;
+ sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP;
+ sme_QosEdcaAcType ac;
+ eHalStatus pmc_status = eHAL_STATUS_FAILURE;
+ tCsrRoamModifyProfileFields modifyProfileFields;
+
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Entry is NULL",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ return eHAL_STATUS_FAILURE;
+ }
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ ac = flow_info->ac_type;
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ if(flow_info->tspec_mask != pACInfo->tspec_pending)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: No need to notify the HDD, the ADDTS "
+ "success is not for index = %d of the AC = %d",
+ __FUNCTION__, __LINE__,
+ flow_info->tspec_mask, ac);
+ return eHAL_STATUS_SUCCESS;
+ }
+ switch(flow_info->reason)
+ {
+ case SME_QOS_REASON_SETUP:
+ hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND;
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ delete_entry = VOS_FALSE;
+ inform_hdd = VOS_TRUE;
+ // check if App is looking for APSD
+ if(pACInfo->requested_QoSInfo[pACInfo->tspec_pending - 1].ts_info.psb)
+ {
+ // notify PMC as App is looking for APSD. If we already requested
+ // then we don't need to do anything
+ if(!pSession->uapsdAlreadyRequested)
+ {
+ // this is the first flow to detect we need PMC in UAPSD mode
+ pmc_status = pmcStartUapsd(pMac,
+ sme_QosPmcStartUapsdCallback,
+ pSession);
+ // if PMC doesn't return success right away means it is yet to put
+ // the module in BMPS state & later to UAPSD state
+ if(eHAL_STATUS_FAILURE == pmc_status)
+ {
+ hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED;
+ // we need to always notify this case
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ else if(eHAL_STATUS_PMC_PENDING == pmc_status)
+ {
+ // let other flows know PMC has been notified
+ pSession->uapsdAlreadyRequested = VOS_TRUE;
+ }
+ // for any other pmc status we declare success
+ }
+ }
+ break;
+ case SME_QOS_REASON_RELEASE:
+ pACInfo->num_flows[pACInfo->tspec_pending - 1]--;
+ hdd_status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP;
+ inform_hdd = VOS_TRUE;
+ delete_entry = VOS_TRUE;
+ break;
+ case SME_QOS_REASON_MODIFY:
+ delete_entry = VOS_TRUE;
+ inform_hdd = VOS_FALSE;
+ break;
+ case SME_QOS_REASON_MODIFY_PENDING:
+ hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND;
+ delete_entry = VOS_FALSE;
+ flow_info->reason = SME_QOS_REASON_REQ_SUCCESS;
+ inform_hdd = VOS_TRUE;
+ //notify PMC if App is looking for APSD
+ if(pACInfo->requested_QoSInfo[pACInfo->tspec_pending - 1].ts_info.psb)
+ {
+ // notify PMC as App is looking for APSD. If we already requested
+ // then we don't need to do anything.
+ if(!pSession->uapsdAlreadyRequested)
+ {
+ // this is the first flow to detect we need PMC in UAPSD mode
+ pmc_status = pmcStartUapsd(pMac,
+ sme_QosPmcStartUapsdCallback,
+ pSession);
+ // if PMC doesn't return success right away means it is yet to put
+ // the module in BMPS state & later to UAPSD state
+ if(eHAL_STATUS_FAILURE == pmc_status)
+ {
+ hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED;
+ // we need to always notify this case
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ else if(eHAL_STATUS_PMC_PENDING == pmc_status)
+ {
+ // let other flows know PMC has been notified
+ pSession->uapsdAlreadyRequested = VOS_TRUE;
+ }
+ // for any other pmc status we declare success
+ }
+ }
+ else
+ {
+ if((pACInfo->num_flows[flow_info->tspec_mask - 1] == 1) &&
+ (SME_QOS_TSPEC_MASK_BIT_1_2_SET != pACInfo->tspec_mask_status))
+ {
+ // this is the only TSPEC active on this AC
+ // so indicate that we no longer require APSD
+ pSession->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac));
+ //Also update modifyProfileFields.uapsd_mask in CSR for consistency
+ csrGetModifyProfileFields(pMac, flow_info->sessionId, &modifyProfileFields);
+ modifyProfileFields.uapsd_mask = pSession->apsdMask;
+ csrSetModifyProfileFields(pMac, flow_info->sessionId, &modifyProfileFields);
+ if(!pSession->apsdMask)
+ {
+ // this session no longer needs UAPSD
+ // do any sessions still require UAPSD?
+ if (!sme_QosIsUapsdActive())
+ {
+ // No sessions require UAPSD so turn it off
+ // (really don't care when PMC stops it)
+ (void)pmcStopUapsd(pMac);
+ }
+ }
+ }
+ }
+ break;
+ case SME_QOS_REASON_REQ_SUCCESS:
+ hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND;
+ inform_hdd = VOS_TRUE;
+ default:
+ delete_entry = VOS_FALSE;
+ break;
+ }
+ if(inform_hdd)
+ {
+ if(!flow_info->hoRenewal)
+ {
+
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1],
+ hdd_status,
+ flow_info->QosFlowID);
+ }
+ else
+ {
+ flow_info->hoRenewal = VOS_FALSE;
+ }
+ }
+ if(delete_entry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Deleting entry at %p with flowID %d",
+ __FUNCTION__, __LINE__,
+ flow_info, flow_info->QosFlowID);
+ //delete the entry from Flow List
+ csrLLRemoveEntry(&sme_QosCb.flow_list, pEntry, VOS_TRUE );
+ // reclaim the memory
+ vos_mem_free(flow_info);
+ }
+
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosIsRspPending() - Utility function to check if we are waiting
+ for an AddTS or reassoc response on some AC other than the given AC
+
+ \param sessionId - Session we are interted in
+ \param ac - Enumeration of the various EDCA Access Categories.
+
+ \return boolean
+ TRUE - Response is pending on an AC
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static v_BOOL_t sme_QosIsRspPending(v_U8_t sessionId, sme_QosEdcaAcType ac)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType acIndex;
+ v_BOOL_t status = VOS_FALSE;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ for(acIndex = SME_QOS_EDCA_AC_BE; acIndex < SME_QOS_EDCA_AC_MAX; acIndex++)
+ {
+ if(acIndex == ac)
+ {
+ continue;
+ }
+ pACInfo = &pSession->ac_info[acIndex];
+ if((pACInfo->tspec_pending) || (pACInfo->reassoc_pending))
+ {
+ status = VOS_TRUE;
+ break;
+ }
+ }
+ return status;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosIsUapsdActive() - Function which can be called to determine
+ if any sessions require PMC to be in U-APSD mode.
+ \return boolean
+
+ Returns true if at least one session required PMC to be in U-APSD mode
+ Returns false if no sessions require PMC to be in U-APSD mode
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+static v_BOOL_t sme_QosIsUapsdActive(void)
+{
+ sme_QosSessionInfo *pSession;
+ v_U8_t sessionId;
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId)
+ {
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if ((pSession->sessionActive) && (pSession->apsdMask))
+ {
+ return VOS_TRUE;
+ }
+ }
+ // no active sessions have U-APSD active
+ return VOS_FALSE;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosPmcFullPowerCallback() - Callback function registered with PMC
+ to notify SME-QoS when it puts the chip into full power
+
+ \param callbackContext - The context passed to PMC during pmcRequestFullPower
+ call.
+ \param status - eHalStatus returned by PMC.
+
+ \return None
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+void sme_QosPmcFullPowerCallback(void *callbackContext, eHalStatus status)
+{
+ sme_QosSessionInfo *pSession = callbackContext;
+ if(HAL_STATUS_SUCCESS(status))
+ {
+ (void)sme_QosProcessBufferedCmd(pSession->sessionId);
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: PMC failed to put the chip in Full power",
+ __FUNCTION__, __LINE__);
+ //ASSERT
+ VOS_ASSERT(0);
+ }
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosPmcStartUAPSDCallback() - Callback function registered with PMC
+ to notify SME-QoS when it puts the chip into UAPSD mode
+
+ \param callbackContext - The context passed to PMC during pmcStartUapsd call.
+ \param status - eHalStatus returned by PMC.
+
+ \return None
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+void sme_QosPmcStartUapsdCallback(void *callbackContext, eHalStatus status)
+{
+ sme_QosSessionInfo *pSession = callbackContext;
+ // NOTE WELL
+ //
+ // In the orignal QoS design the TL module was responsible for
+ // the generation of trigger frames. When that design was in
+ // use, we had to queue up any flows which were waiting for PMC
+ // since we didn't want to notify HDD until PMC had changed to
+ // UAPSD state. Otherwise HDD would provide TL with the trigger
+ // frame parameters, and TL would start trigger frame generation
+ // before PMC was ready. The flows were queued in various places
+ // throughout this module, and they were dequeued here following
+ // a successful transition to the UAPSD state by PMC.
+ //
+ // In the current QoS design the Firmware is responsible for the
+ // generation of trigger frames, but the parameters are still
+ // provided by TL via HDD. The Firmware will be notified of the
+ // change to UAPSD state directly by PMC, at which time it will be
+ // responsible for the generation of trigger frames. Therefore
+ // where we used to queue up flows waiting for PMC to transition
+ // to the UAPSD state, we now always transition directly to the
+ // "success" state so that HDD will immediately provide the trigger
+ // frame parameters to TL, who will in turn plumb them down to the
+ // Firmware. That way the Firmware will have the trigger frame
+ // parameters when it needs them
+ // just note that there is no longer an outstanding request
+ pSession->uapsdAlreadyRequested = VOS_FALSE;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosPmcCheckRoutine() - Function registered with PMC to check with
+ SME-QoS whenever the device is about to enter one of the power
+ save modes. PMC runs a poll with all the registered modules if device can
+ enter powersave mode or remain in full power
+
+ \param callbackContext - The context passed to PMC during registration through
+ pmcRegisterPowerSaveCheck.
+ \return boolean
+
+ SME-QOS returns PMC true or false respectively if it wants to vote for
+ entering power save or not
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+v_BOOL_t sme_QosPmcCheckRoutine(void *callbackContext)
+{
+ sme_QosSessionInfo *pSession;
+ v_U8_t sessionId;
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId)
+ {
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if ((pSession->sessionActive) &&
+ (!pSession->readyForPowerSave))
+ {
+ return VOS_FALSE;
+ }
+ }
+ // all active sessions have voted for powersave
+ return VOS_TRUE;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosPmcDeviceStateUpdateInd() - Callback function registered with
+ PMC to notify SME-QoS when it changes the power state
+
+ \param callbackContext - The context passed to PMC during registration
+ through pmcRegisterDeviceStateUpdateInd.
+ \param pmcState - Current power state that PMC moved into.
+
+ \return None
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+void sme_QosPmcDeviceStateUpdateInd(void *callbackContext, tPmcState pmcState)
+{
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT( callbackContext );
+ //check all the entries in Flow list for non-zero service interval, which will
+ //tell us if we need to notify HDD when PMC is out of UAPSD mode or going
+ // back to UAPSD mode
+ switch(pmcState)
+ {
+ case FULL_POWER:
+ status = sme_QosProcessOutOfUapsdMode(pMac);
+ break;
+ case UAPSD:
+ status = sme_QosProcessIntoUapsdMode(pMac);
+ break;
+ default:
+ status = eHAL_STATUS_SUCCESS;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: nothing to process in PMC state %d",
+ __FUNCTION__, __LINE__,
+ pmcState);
+ }
+ if(!HAL_STATUS_SUCCESS(status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: ignoring Device(PMC) state change to %d",
+ __FUNCTION__, __LINE__,
+ pmcState);
+ }
+
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessOutOfUapsdMode() - Function to notify HDD when PMC
+ notifies SME-QoS that it moved out of UAPSD mode to FULL power
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessOutOfUapsdMode(tpAniSirGlobal pMac)
+{
+ sme_QosSessionInfo *pSession;
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, can't search",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ //only notify the flows which already successfully setup UAPSD
+ if((flow_info->QoSInfo.max_service_interval ||
+ flow_info->QoSInfo.min_service_interval) &&
+ (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason))
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pSession->ac_info[flow_info->ac_type].curr_QoSInfo[flow_info->tspec_mask - 1],
+ SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND,
+ flow_info->QosFlowID);
+ }
+ pEntry = pNextEntry;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+/*--------------------------------------------------------------------------
+ \brief sme_QosProcessIntoUapsdMode() - Function to notify HDD when PMC
+ notifies SME-QoS that it is moving into UAPSD mode
+
+ \param pMac - Pointer to the global MAC parameter structure.
+ \return eHalStatus
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+eHalStatus sme_QosProcessIntoUapsdMode(tpAniSirGlobal pMac)
+{
+ sme_QosSessionInfo *pSession;
+ tListElem *pEntry= NULL, *pNextEntry = NULL;
+ sme_QosFlowInfoEntry *flow_info = NULL;
+
+ pEntry = csrLLPeekHead( &sme_QosCb.flow_list, VOS_FALSE );
+ if(!pEntry)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Flow List empty, can't search",
+ __FUNCTION__, __LINE__);
+ return eHAL_STATUS_FAILURE;
+ }
+ while( pEntry )
+ {
+ pNextEntry = csrLLNext( &sme_QosCb.flow_list, pEntry, VOS_FALSE );
+ flow_info = GET_BASE_ADDR( pEntry, sme_QosFlowInfoEntry, link );
+ pSession = &sme_QosCb.sessionInfo[flow_info->sessionId];
+ //only notify the flows which already successfully setup UAPSD
+ if((flow_info->QoSInfo.max_service_interval ||
+ flow_info->QoSInfo.min_service_interval) &&
+ (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason))
+ {
+ flow_info->QoSCallback(pMac, flow_info->HDDcontext,
+ &pSession->ac_info[flow_info->ac_type].curr_QoSInfo[flow_info->tspec_mask - 1],
+ SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND,
+ flow_info->QosFlowID);
+ }
+ pEntry = pNextEntry;
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+
+void sme_QosCleanupCtrlBlkForHandoff(tpAniSirGlobal pMac, v_U8_t sessionId)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosEdcaAcType ac;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ vos_mem_zero(pACInfo->curr_QoSInfo,
+ sizeof(sme_QosWmmTspecInfo) * SME_QOS_TSPEC_INDEX_MAX);
+ vos_mem_zero(pACInfo->requested_QoSInfo,
+ sizeof(sme_QosWmmTspecInfo) * SME_QOS_TSPEC_INDEX_MAX);
+ pACInfo->num_flows[0] = 0;
+ pACInfo->num_flows[1] = 0;
+ pACInfo->reassoc_pending = VOS_FALSE;
+ pACInfo->tspec_mask_status = 0;
+ pACInfo->tspec_pending = VOS_FALSE;
+ pACInfo->hoRenewal = VOS_FALSE;
+ pACInfo->prev_state = SME_QOS_LINK_UP;
+ }
+}
+
+/*--------------------------------------------------------------------------
+ \brief sme_QosIsTSInfoAckPolicyValid() - The SME QoS API exposed to HDD to
+ check if TS info ack policy field can be set to "HT-immediate block acknowledgement"
+
+ \param pMac - The handle returned by macOpen.
+ \param pQoSInfo - Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC
+ related info, provided by HDD
+ \param sessionId - sessionId returned by sme_OpenSession.
+
+ \return VOS_TRUE - Current Association is HT association and so TS info ack policy
+ can be set to "HT-immediate block acknowledgement"
+
+ \sa
+
+ --------------------------------------------------------------------------*/
+v_BOOL_t sme_QosIsTSInfoAckPolicyValid(tpAniSirGlobal pMac,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U8_t sessionId)
+{
+ tDot11fBeaconIEs *pIes = NULL;
+ sme_QosSessionInfo *pSession;
+ eHalStatus hstatus;
+ if( !CSR_IS_SESSION_VALID( pMac, sessionId ) )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session Id %d is invalid",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return VOS_FALSE;
+ }
+
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+
+ if( !pSession->sessionActive )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session %d is inactive",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return VOS_FALSE;
+ }
+
+ if(!pSession->assocInfo.pBssDesc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Session %d has an Invalid BSS Descriptor",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return VOS_FALSE;
+ }
+
+ hstatus = csrGetParsedBssDescriptionIEs(pMac,
+ pSession->assocInfo.pBssDesc,
+ &pIes);
+ if(!HAL_STATUS_SUCCESS(hstatus))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unable to parse BSS IEs",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ return VOS_FALSE;
+ }
+
+ /* success means pIes was allocated */
+
+ if(!pIes->HTCaps.present &&
+ pQoSInfo->ts_info.ack_policy == SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d HT Caps aren't present but application set ack policy to HT ",
+ __FUNCTION__, __LINE__,
+ sessionId);
+
+ vos_mem_free(pIes);
+ return VOS_FALSE;
+ }
+
+ vos_mem_free(pIes);
+ return VOS_TRUE;
+}
+
+v_BOOL_t sme_QosValidateRequestedParams(tpAniSirGlobal pMac,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ v_U8_t sessionId)
+{
+ v_BOOL_t rc = VOS_FALSE;
+
+ do
+ {
+ if(SME_QOS_WMM_TS_DIR_RESV == pQoSInfo->ts_info.direction) break;
+ if(!sme_QosIsTSInfoAckPolicyValid(pMac, pQoSInfo, sessionId)) break;
+
+ rc = VOS_TRUE;
+ }while(0);
+ return rc;
+}
+
+static eHalStatus qosIssueCommand( tpAniSirGlobal pMac, v_U8_t sessionId,
+ eSmeCommandType cmdType, sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosEdcaAcType ac, v_U8_t tspec_mask )
+{
+ eHalStatus status = eHAL_STATUS_RESOURCES;
+ tSmeCmd *pCommand = NULL;
+ do
+ {
+ pCommand = smeGetCommandBuffer( pMac );
+ if ( !pCommand )
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: fail to get command buffer for command %d",
+ __FUNCTION__, __LINE__, cmdType);
+ break;
+ }
+ pCommand->command = cmdType;
+ pCommand->sessionId = sessionId;
+ switch ( cmdType )
+ {
+ case eSmeCommandAddTs:
+ if( pQoSInfo )
+ {
+ status = eHAL_STATUS_SUCCESS;
+ pCommand->u.qosCmd.tspecInfo = *pQoSInfo;
+ pCommand->u.qosCmd.ac = ac;
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: NULL pointer passed",
+ __FUNCTION__, __LINE__);
+ status = eHAL_STATUS_INVALID_PARAMETER;
+ }
+ break;
+ case eSmeCommandDelTs:
+ status = eHAL_STATUS_SUCCESS;
+ pCommand->u.qosCmd.ac = ac;
+ pCommand->u.qosCmd.tspec_mask = tspec_mask;
+ break;
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid command type %d",
+ __FUNCTION__, __LINE__, cmdType );
+ status = eHAL_STATUS_INVALID_PARAMETER;
+ break;
+ }
+ } while( 0 );
+ if( HAL_STATUS_SUCCESS( status ) && pCommand )
+ {
+ smePushCommand( pMac, pCommand, eANI_BOOLEAN_FALSE );
+ }
+ else if( pCommand )
+ {
+ qosReleaseCommand( pMac, pCommand );
+ }
+ return( status );
+}
+tANI_BOOLEAN qosProcessCommand( tpAniSirGlobal pMac, tSmeCmd *pCommand )
+{
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+ tANI_BOOLEAN fRemoveCmd = eANI_BOOLEAN_TRUE;
+ do
+ {
+ switch ( pCommand->command )
+ {
+ case eSmeCommandAddTs:
+ status = sme_QosAddTsReq( pMac, (v_U8_t)pCommand->sessionId, &pCommand->u.qosCmd.tspecInfo, pCommand->u.qosCmd.ac);
+ if( HAL_STATUS_SUCCESS( status ) )
+ {
+ fRemoveCmd = eANI_BOOLEAN_FALSE;
+ status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP;
+ }
+ break;
+ case eSmeCommandDelTs:
+ status = sme_QosDelTsReq( pMac, (v_U8_t)pCommand->sessionId, pCommand->u.qosCmd.ac, pCommand->u.qosCmd.tspec_mask );
+ if( HAL_STATUS_SUCCESS( status ) )
+ {
+ fRemoveCmd = eANI_BOOLEAN_FALSE;
+ }
+ break;
+ default:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: invalid command type %d",
+ __FUNCTION__, __LINE__, pCommand->command );
+ break;
+ }//switch
+ } while(0);
+ return( fRemoveCmd );
+}
+
+/*
+ sme_QosTriggerUapsdChange
+ Invoked by BTC when UAPSD bypass is enabled or disabled
+ We, in turn, must disable or enable UAPSD on all flows as appropriate
+ That may require us to re-add TSPECs or to reassociate
+*/
+sme_QosStatusType sme_QosTriggerUapsdChange( tpAniSirGlobal pMac )
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ v_U8_t ac, tspec1 = 0, tspec2 = 0;
+ v_U8_t uapsd_mask;
+ tDot11fBeaconIEs *pIesLocal;
+ v_U8_t acm_mask;
+ v_BOOL_t fIsUapsdNeeded;
+ v_U8_t sessionId;
+ v_BOOL_t addtsWhenACMNotSet = CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked",
+ __FUNCTION__, __LINE__);
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId)
+ {
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ if( !pSession->sessionActive )
+ {
+ continue;
+ }
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Session %d is active",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ if( HAL_STATUS_SUCCESS(csrGetParsedBssDescriptionIEs(pMac, pSession->assocInfo.pBssDesc, &pIesLocal)) )
+ {
+ // get the ACM mask
+ acm_mask = sme_QosGetACMMask(pMac, pSession->assocInfo.pBssDesc, pIesLocal);
+ vos_mem_free(pIesLocal);
+ // get the uapsd mask for this session
+ uapsd_mask = pSession->apsdMask;
+ // unmask the bits with ACM on to avoid reassoc on them
+ uapsd_mask &= ~acm_mask;
+ // iterate through the ACs to determine if we need to re-add any TSPECs
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ // Does this AC have QoS active?
+ if( SME_QOS_QOS_ON == pACInfo->curr_state )
+ {
+ // Yes, QoS is active on this AC
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d AC %d has QoS active",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ // Does this AC require ACM?
+ if(( acm_mask & (1 << (SME_QOS_EDCA_AC_VO - ac)) ) || addtsWhenACMNotSet )
+ {
+ // Yes, so we need to re-add any TSPECS
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d AC %d has ACM enabled",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ // Are any TSPECs active?
+ if( pACInfo->tspec_mask_status )
+ {
+ // Yes, at least 1 TSPEC is active. Are they both active?
+ if( SME_QOS_TSPEC_MASK_BIT_1_2_SET == pACInfo->tspec_mask_status )
+ {
+ //both TSPECS are active
+ tspec1 = SME_QOS_TSPEC_MASK_BIT_1_SET;
+ tspec2 = SME_QOS_TSPEC_MASK_BIT_2_SET;
+ }
+ else
+ {
+ // only one TSPEC is active, get its mask
+ tspec1 = SME_QOS_TSPEC_MASK_BIT_1_2_SET & pACInfo->tspec_mask_status;
+ }
+ // Does TSPEC 1 really require UAPSD?
+ fIsUapsdNeeded = (v_BOOL_t)(pACInfo->curr_QoSInfo[tspec1 - 1].max_service_interval ||
+ pACInfo->curr_QoSInfo[tspec1 - 1].min_service_interval);
+ //double check whether we need to do anything
+ if( fIsUapsdNeeded )
+ {
+ pACInfo->requested_QoSInfo[tspec1 - 1] =
+ pACInfo->curr_QoSInfo[tspec1 - 1];
+ sme_QosReRequestAddTS( pMac, sessionId,
+ &pACInfo->requested_QoSInfo[tspec1 - 1],
+ ac,
+ tspec1 );
+ }
+ // Is TSPEC 2 active?
+ if( tspec2 )
+ {
+ // Does TSPEC 2 really require UAPSD?
+ fIsUapsdNeeded = (v_BOOL_t)(pACInfo->curr_QoSInfo[tspec2 - 1].max_service_interval ||
+ pACInfo->curr_QoSInfo[tspec2 - 1].min_service_interval);
+ if( fIsUapsdNeeded )
+ {
+ //No need to inform HDD
+ //pACInfo->hoRenewal = VOS_TRUE;
+ pACInfo->requested_QoSInfo[tspec2 - 1] =
+ pACInfo->curr_QoSInfo[tspec2 - 1];
+ sme_QosReRequestAddTS( pMac, sessionId,
+ &pACInfo->requested_QoSInfo[tspec2 - 1],
+ ac,
+ tspec2);
+ }
+ }
+ }
+ else
+ {
+ // QoS is set, ACM is on, but no TSPECs -- inconsistent state
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d AC %d has QoS enabled and ACM is set, but no TSPEC",
+ __FUNCTION__, __LINE__,
+ sessionId, ac);
+ VOS_ASSERT(0);
+ }
+ }
+ else
+ {
+ //Since ACM bit is not set, there should be only one QoS information for both directions.
+ fIsUapsdNeeded = (v_BOOL_t)(pACInfo->curr_QoSInfo[0].max_service_interval ||
+ pACInfo->curr_QoSInfo[0].min_service_interval);
+ if(fIsUapsdNeeded)
+ {
+ // we need UAPSD on this AC (and we may not currently have it)
+ uapsd_mask |= 1 << (SME_QOS_EDCA_AC_VO - ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: On session %d AC %d has ACM disabled, uapsd mask now 0x%X",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, uapsd_mask);
+ }
+ }
+ }
+ }
+ // do we need to reassociate?
+ if(uapsd_mask)
+ {
+ tCsrRoamModifyProfileFields modifyProfileFields;
+ //we need to do a reassoc on these AC
+ csrGetModifyProfileFields(pMac, sessionId, &modifyProfileFields);
+ if( btcIsReadyForUapsd(pMac) )
+ {
+ modifyProfileFields.uapsd_mask = uapsd_mask;
+ }
+ else
+ {
+ modifyProfileFields.uapsd_mask = 0;
+ }
+ //Do we need to inform HDD?
+ if(!HAL_STATUS_SUCCESS(sme_QosRequestReassoc(pMac, sessionId, &modifyProfileFields, VOS_TRUE)))
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On Session %d Reassoc failed",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ }
+ }
+ }
+ else
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On Session %d failed to parse IEs",
+ __FUNCTION__, __LINE__,
+ sessionId);
+ }
+ }
+ // return status is ignored by BTC
+ return SME_QOS_STATUS_SETUP_SUCCESS_IND;
+}
+
+/*
+ sme_QosReRequestAddTS to re-send AddTS for the combined QoS request
+*/
+static sme_QosStatusType sme_QosReRequestAddTS(tpAniSirGlobal pMac,
+ v_U8_t sessionId,
+ sme_QosWmmTspecInfo * pQoSInfo,
+ sme_QosEdcaAcType ac,
+ v_U8_t tspecMask)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ sme_QosCmdInfo cmd;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d for AC %d TSPEC %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, tspecMask);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ pACInfo = &pSession->ac_info[ac];
+ // need to vote off powersave for the duration of this request
+ pSession->readyForPowerSave = VOS_FALSE;
+ //call PMC's request for power function
+ // AND
+ //another check is added considering the flowing scenario
+ //Addts reqest is pending on one AC, while APSD requested on another which
+ //needs a reassoc. Will buffer a request if Addts is pending on any AC,
+ //which will safegaurd the above scenario, & also won't confuse PE with back
+ //to back Addts or Addts followed by Reassoc
+ if(sme_QosIsRspPending(sessionId, ac) ||
+ ( eHAL_STATUS_PMC_PENDING == pmcRequestFullPower(pMac, sme_QosPmcFullPowerCallback, pSession, eSME_REASON_OTHER)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d buffering the AddTS request "
+ "for AC %d in state %d as Addts is pending "
+ "on other AC or waiting for full power",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, pACInfo->curr_state);
+ //buffer cmd
+ cmd.command = SME_QOS_RESEND_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.resendCmdInfo.ac = ac;
+ cmd.u.resendCmdInfo.tspecMask = tspecMask;
+ cmd.u.resendCmdInfo.QoSInfo = *pQoSInfo;
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_FALSE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: On session %d unable to buffer the AddTS "
+ "request for AC %d TSPEC %d in state %d",
+ __FUNCTION__, __LINE__,
+ sessionId, ac, tspecMask, pACInfo->curr_state);
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ }
+ //get into the stat m/c to see if the request can be granted
+ switch(pACInfo->curr_state)
+ {
+ case SME_QOS_QOS_ON:
+ {
+ //if ACM, send out a new ADDTS
+ pACInfo->hoRenewal = VOS_TRUE;
+ status = sme_QosSetup(pMac, sessionId, pQoSInfo, ac);
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: sme_QosSetup returned in SME_QOS_QOS_ON state on "
+ "AC %d with status =%d",
+ __FUNCTION__, __LINE__,
+ ac, status);
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status)
+ {
+ // we aren't waiting for a response from the AP
+ // so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ }
+ if(SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status)
+ {
+ status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ pACInfo->tspec_pending = tspecMask;
+ }
+ else if((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) ||
+ (SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING == status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: UAPSD is setup already status = %d "
+ "returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ status);
+ }
+ else
+ {
+ //err msg
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: unexpected status = %d returned by sme_QosSetup",
+ __FUNCTION__, __LINE__,
+ status);
+ }
+ }
+ break;
+ case SME_QOS_HANDOFF:
+ case SME_QOS_REQUESTED:
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: Re-Add request in state = %d buffer the request",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state);
+ cmd.command = SME_QOS_RESEND_REQ;
+ cmd.pMac = pMac;
+ cmd.sessionId = sessionId;
+ cmd.u.resendCmdInfo.ac = ac;
+ cmd.u.resendCmdInfo.tspecMask = tspecMask;
+ cmd.u.resendCmdInfo.QoSInfo = *pQoSInfo;
+ if(!HAL_STATUS_SUCCESS(sme_QosBufferCmd(&cmd, VOS_FALSE)))
+ {
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: couldn't buffer the readd request in state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to buffer the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP;
+ }
+ status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP;
+ break;
+ case SME_QOS_CLOSED:
+ case SME_QOS_INIT:
+ case SME_QOS_LINK_UP:
+ default:
+ //print error msg,
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+ "%s: %d: ReAdd request in unexpected state = %d",
+ __FUNCTION__, __LINE__,
+ pACInfo->curr_state );
+ // unable to service the request
+ // nothing is pending so vote powersave back on
+ pSession->readyForPowerSave = VOS_TRUE;
+ // ASSERT?
+ break;
+ }
+ if((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) ||
+ (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == status))
+ {
+ (void)sme_QosProcessBufferedCmd(sessionId);
+ }
+ return (status);
+}
+
+static void sme_QosInitACs(tpAniSirGlobal pMac, v_U8_t sessionId)
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosEdcaAcType ac;
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ vos_mem_zero(&pSession->ac_info[ac], sizeof(sme_QosACInfo));
+ sme_QosStateTransition(sessionId, ac, SME_QOS_INIT);
+ }
+}
+static eHalStatus sme_QosRequestReassoc(tpAniSirGlobal pMac, tANI_U8 sessionId,
+ tCsrRoamModifyProfileFields *pModFields,
+ v_BOOL_t fForce )
+{
+ sme_QosSessionInfo *pSession;
+ sme_QosACInfo *pACInfo;
+ eHalStatus status;
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: %d: Invoked on session %d with UAPSD mask 0x%X",
+ __FUNCTION__, __LINE__,
+ sessionId, pModFields->uapsd_mask);
+ pSession = &sme_QosCb.sessionInfo[sessionId];
+ status = csrReassoc(pMac, sessionId, pModFields, &pSession->roamID, fForce);
+ if(HAL_STATUS_SUCCESS(status))
+ {
+ //Update the state to Handoff so subsequent requests are queued until
+ // this one is finished
+ sme_QosEdcaAcType ac;
+ for(ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++)
+ {
+ pACInfo = &pSession->ac_info[ac];
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO,
+ "%s: %d: AC[%d] is in state [%d]",
+ __FUNCTION__, __LINE__,
+ ac, pACInfo->curr_state );
+ // If it is already in HANDOFF state, don't do anything since we
+ // MUST preserve the previous state and sme_QosStateTransition
+ // will change the previous state
+ if(SME_QOS_HANDOFF != pACInfo->curr_state)
+ {
+ sme_QosStateTransition(sessionId, ac, SME_QOS_HANDOFF);
+ }
+ }
+ }
+ return status;
+}
+static v_U32_t sme_QosAssignFlowId(void)
+{
+ v_U32_t flowId;
+ flowId = sme_QosCb.nextFlowId;
+ if (SME_QOS_MAX_FLOW_ID == flowId)
+ {
+ // The Flow ID wrapped. This is obviously not a real life scenario
+ // but handle it to keep the software test folks happy
+ VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL,
+ "%s: %d: Software Test made the flow counter wrap, "
+ "QoS may no longer be functional",
+ __FUNCTION__, __LINE__);
+ sme_QosCb.nextFlowId = SME_QOS_MIN_FLOW_ID;
+ }
+ else
+ {
+ sme_QosCb.nextFlowId++;
+ }
+ return flowId;
+}
+
+static v_U8_t sme_QosAssignDialogToken(void)
+{
+ v_U8_t token;
+ token = sme_QosCb.nextDialogToken;
+ if (SME_QOS_MAX_DIALOG_TOKEN == token)
+ {
+ // wrap is ok
+ sme_QosCb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN;
+ }
+ else
+ {
+ sme_QosCb.nextDialogToken++;
+ }
+ return token;
+}
+#endif /* WLAN_MDM_CODE_REDUCTION_OPT */