/*
 * Copyright (c) 2012-2017, 2019-2020 The Linux Foundation. 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.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */




/*
 * This file limProcessActionFrame.cc contains the code
 * for processing Action Frame.
 * Author:      Michael Lui
 * Date:        05/23/03
 * History:-
 * Date           Modified by    Modification Information
 * --------------------------------------------------------------------
 *
 */
#include "palTypes.h"
#include "wniApi.h"
#include "sirApi.h"
#include "aniGlobal.h"
#include "wniCfg.h"
#include "schApi.h"
#include "utilsApi.h"
#include "limTypes.h"
#include "limUtils.h"
#include "limAssocUtils.h"
#include "limSecurityUtils.h"
#include "limSerDesUtils.h"
#include "limSendSmeRspMessages.h"
#include "parserApi.h"
#include "limAdmitControl.h"
#include "wmmApsd.h"
#include "limSendMessages.h"
#if defined WLAN_FEATURE_VOWIFI
#include "rrmApi.h"
#endif
#include "limSessionUtils.h"
#ifdef WLAN_FEATURE_RMC
#include "limRMC.h"
#endif

#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
#include "eseApi.h"
#endif
#include "wlan_qct_wda.h"

#ifdef WLAN_FEATURE_LFR_MBB
#include "lim_mbb.h"
#endif
#include "dot11f.h"

#define BA_DEFAULT_TX_BUFFER_SIZE 64

typedef enum
{
  LIM_ADDBA_RSP = 0,
  LIM_ADDBA_REQ = 1
}tLimAddBaValidationReqType;

/* Note: The test passes if the STAUT stops sending any frames, and no further
 frames are transmitted on this channel by the station when the AP has sent
 the last 6 beacons, with the channel switch information elements as seen
 with the sniffer.*/
#define SIR_CHANSW_TX_STOP_MAX_COUNT 6
/**-----------------------------------------------------------------
\fn     limStopTxAndSwitchChannel
\brief  Stops the transmission if channel switch mode is silent and
        starts the channel switch timer.

\param  pMac
\return NONE
-----------------------------------------------------------------*/
void limStopTxAndSwitchChannel(tpAniSirGlobal pMac, tANI_U8 sessionId)
{
    tANI_U8 isFullPowerRequested = 0;
    tpPESession psessionEntry;

    psessionEntry = peFindSessionBySessionId( pMac , sessionId );

    if( NULL == psessionEntry )
    {
      limLog(pMac, LOGE, FL("Session %d  not active\n "), sessionId);
      return;
    }

    if(pMac->ft.ftPEContext.pFTPreAuthReq)
    {
        limLog(pMac, LOGE,
           FL("Avoid Switch Channel req during pre auth"));
        return;
    }

    limLog(pMac, LOG1, FL("Channel switch Mode == %d"),
                       psessionEntry->gLimChannelSwitch.switchMode);

    if (psessionEntry->gLimChannelSwitch.switchMode == eSIR_CHANSW_MODE_SILENT ||
        psessionEntry->gLimChannelSwitch.switchCount <= SIR_CHANSW_TX_STOP_MAX_COUNT)
    {
        /* Freeze the transmission */
        limFrameTransmissionControl(pMac, eLIM_TX_ALL, eLIM_STOP_TX);

        /*Request for Full power only if the device is in powersave*/
        if(!limIsSystemInActiveState(pMac))
        {
            /* Request Full Power */
            limSendSmePreChannelSwitchInd(pMac);
            isFullPowerRequested = 1;
        }
    }
    else
    {
        /* Resume the transmission */
        limFrameTransmissionControl(pMac, eLIM_TX_ALL, eLIM_RESUME_TX);
    }

    pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId = sessionId;
    /* change the channel immediatly only if the channel switch count is 0 and the 
     * device is not in powersave 
     * If the device is in powersave channel switch should happen only after the
     * device comes out of the powersave */
    if (psessionEntry->gLimChannelSwitch.switchCount == 0) 
    {
        if(limIsSystemInActiveState(pMac))
        {
            limProcessChannelSwitchTimeout(pMac);
        }
        else if(!isFullPowerRequested)
        {
            /* If the Full power is already not requested 
             * Request Full Power so the channel switch happens 
             * after device comes to full power */
            limSendSmePreChannelSwitchInd(pMac);
        }
        return;
    }
    MTRACE(macTrace(pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, eLIM_CHANNEL_SWITCH_TIMER));


    if (tx_timer_activate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != TX_SUCCESS)
    {
        limLog(pMac, LOGP, FL("tx_timer_activate failed"));
    }
    return;
}

/**------------------------------------------------------------
\fn     limStartChannelSwitch
\brief  Switches the channel if switch count == 0, otherwise
        starts the timer for channel switch and stops BG scan
        and heartbeat timer tempororily.

\param  pMac
\param  psessionEntry
\return NONE
------------------------------------------------------------*/
tSirRetStatus limStartChannelSwitch(tpAniSirGlobal pMac, tpPESession psessionEntry)
{
    limLog(pMac, LOG1, FL(" ENTER"));

#ifdef WLAN_FEATURE_LFR_MBB
    if (lim_is_mbb_reassoc_in_progress(pMac, psessionEntry))
    {
        limLog(pMac, LOGE,
             FL("Ignore channel switch as LFR MBB in progress"));
        return eSIR_SUCCESS;
    }
#endif

    /*If channel switch is already running and it is on a different session, just return*/  
    /*This need to be removed for MCC */
    if( limIsChanSwitchRunning (pMac) &&
        psessionEntry->gLimSpecMgmt.dot11hChanSwState != eLIM_11H_CHANSW_RUNNING )
    {
       limLog(pMac, LOGW, FL("Ignoring channel switch on session %d"), psessionEntry->peSessionId);
       return eSIR_SUCCESS;
    }
#ifdef FEATURE_WLAN_DIAG_SUPPORT
    limDiagEventReport(pMac, WLAN_PE_DIAG_CHANNEL_SWITCH_ANOUNCEMENT,
                       psessionEntry, eSIR_SUCCESS, LIM_SWITCH_CHANNEL_CSA);
#endif

    psessionEntry->channelChangeCSA =  LIM_SWITCH_CHANNEL_CSA;
    /* Deactivate and change reconfigure the timeout value */
    //limDeactivateAndChangeTimer(pMac, eLIM_CHANNEL_SWITCH_TIMER);
    MTRACE(macTrace(pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, eLIM_CHANNEL_SWITCH_TIMER));
    if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != eSIR_SUCCESS)
    {
        limLog(pMac, LOGP, FL("tx_timer_deactivate failed!"));
        return eSIR_FAILURE;
    }

    if (tx_timer_change(&pMac->lim.limTimers.gLimChannelSwitchTimer,
                psessionEntry->gLimChannelSwitch.switchTimeoutValue,
                            0) != TX_SUCCESS)
    {
        limLog(pMac, LOGP, FL("tx_timer_change failed "));
        return eSIR_FAILURE;
    }

    /* Follow the channel switch, forget about the previous quiet. */
    //If quiet is running, chance is there to resume tx on its timeout.
    //so stop timer for a safer side.
    if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN)
    {
        MTRACE(macTrace(pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, eLIM_QUIET_TIMER));
        if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != TX_SUCCESS)
        {
            limLog(pMac, LOGP, FL("tx_timer_deactivate failed"));
            return eSIR_FAILURE;
        }
    }
    else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING)
    {
        MTRACE(macTrace(pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER));
        if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) != TX_SUCCESS)
        {
            limLog(pMac, LOGP, FL("tx_timer_deactivate failed"));
            return eSIR_FAILURE;
        }
    }
    psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT;

    /* Prepare for 11h channel switch */
    limPrepareFor11hChannelSwitch(pMac, psessionEntry);

    /** Dont add any more statements here as we posted finish scan request
     * to HAL, wait till we get the response
     */
    return eSIR_SUCCESS;
}


/**
 *  __limProcessChannelSwitchActionFrame
 *
 *FUNCTION:
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - A pointer to packet info structure
 * @return None
 */

static void

__limProcessChannelSwitchActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{

    tpSirMacMgmtHdr         pHdr;
    tANI_U8                 *pBody;
    tDot11fChannelSwitch    *pChannelSwitchFrame;
    tANI_U16                beaconPeriod;
    tANI_U32                val;
    tANI_U32                frameLen;
    tANI_U32                nStatus;

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    limLog(pMac, LOG1, FL("Received Channel switch action frame"));
    if (!psessionEntry->lim11hEnable)
        return;

    pChannelSwitchFrame = vos_mem_malloc(sizeof(*pChannelSwitchFrame));
    if (NULL == pChannelSwitchFrame)
    {
        limLog(pMac, LOGE,
            FL("AllocateMemory failed"));
        return;
    }

    /* Unpack channel switch frame */
    nStatus = dot11fUnpackChannelSwitch(pMac, pBody, frameLen, pChannelSwitchFrame);

    if( DOT11F_FAILED( nStatus ))
    {
        limLog( pMac, LOGE,
            FL( "Failed to unpack and parse an 11h-CHANSW Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen);
        vos_mem_free(pChannelSwitchFrame);
        return;
    }
    else if(DOT11F_WARNED( nStatus ))
    {
        limLog( pMac, LOGW,
            FL( "There were warnings while unpacking an 11h-CHANSW Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen);
    }

    if (vos_mem_compare((tANI_U8 *) &psessionEntry->bssId,
                        (tANI_U8 *) &pHdr->sa,
                        sizeof(tSirMacAddr)))
    {
        #if 0
        if (wlan_cfgGetInt(pMac, WNI_CFG_BEACON_INTERVAL, &val) != eSIR_SUCCESS)
        {
            vos_mem_free(pChannelSwitchFrame);
            limLog(pMac, LOGP, FL("could not retrieve Beacon interval"));
            return;
        }
        #endif// TO SUPPORT BT-AMP

        /* copy the beacon interval from psessionEntry*/
        val = psessionEntry->beaconParams.beaconInterval;

        beaconPeriod = (tANI_U16) val;

        psessionEntry->gLimChannelSwitch.primaryChannel = pChannelSwitchFrame->ChanSwitchAnn.newChannel;
        psessionEntry->gLimChannelSwitch.switchCount = pChannelSwitchFrame->ChanSwitchAnn.switchCount;
        psessionEntry->gLimChannelSwitch.switchTimeoutValue = SYS_MS_TO_TICKS(beaconPeriod) *
                                                         psessionEntry->gLimChannelSwitch.switchCount;
        psessionEntry->gLimChannelSwitch.switchMode = pChannelSwitchFrame->ChanSwitchAnn.switchMode;
#ifdef WLAN_FEATURE_11AC
        if ( pChannelSwitchFrame->WiderBWChanSwitchAnn.present && psessionEntry->vhtCapability)
        {
            psessionEntry->gLimWiderBWChannelSwitch.newChanWidth = pChannelSwitchFrame->WiderBWChanSwitchAnn.newChanWidth;
            psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0 = pChannelSwitchFrame->WiderBWChanSwitchAnn.newCenterChanFreq0;
            psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1 = pChannelSwitchFrame->WiderBWChanSwitchAnn.newCenterChanFreq1;
        }
#endif

       limLog(pMac, LOG1, FL("Rcv Chnl Swtch Frame: Timeout in %d ticks"),
                             psessionEntry->gLimChannelSwitch.switchTimeoutValue);

        /* Only primary channel switch element is present */
        psessionEntry->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_PRIMARY_ONLY;
        psessionEntry->gLimChannelSwitch.secondarySubBand = PHY_SINGLE_CHANNEL_CENTERED;

        if (psessionEntry->htSupportedChannelWidthSet)
        {
            if ((pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) ||
                (pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY))
            {
                psessionEntry->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
                psessionEntry->gLimChannelSwitch.secondarySubBand = pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset;
            }
#ifdef WLAN_FEATURE_11AC
            if(psessionEntry->vhtCapability && pChannelSwitchFrame->WiderBWChanSwitchAnn.present)
            {
                if (pChannelSwitchFrame->WiderBWChanSwitchAnn.newChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ)
                {
                    if (pChannelSwitchFrame->sec_chan_offset.present && ((pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) ||
                        (pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)))
                    {
                        psessionEntry->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
                        psessionEntry->gLimChannelSwitch.secondarySubBand =
                           limGet11ACPhyCBState(pMac,
                                                psessionEntry->gLimChannelSwitch.primaryChannel,
                                                pChannelSwitchFrame->sec_chan_offset.secondaryChannelOffset,
                                                pChannelSwitchFrame->WiderBWChanSwitchAnn.newCenterChanFreq0,
                                                psessionEntry);
                    }
                }
            }
#endif
        }

    }
    else
    {
        limLog(pMac, LOG1, FL("LIM: Received action frame not from our BSS, dropping..."));
    }

    if (eSIR_SUCCESS != limStartChannelSwitch(pMac, psessionEntry))
    {
        limLog(pMac, LOG1, FL("Could not start channel switch"));
    }

    vos_mem_free(pChannelSwitchFrame);
    return;
} /*** end limProcessChannelSwitchActionFrame() ***/

/**
 * lim_process_ecsa_action_frame()- Process ECSA Action
 * Frames.
 * @mac_ctx: pointer to global mac structure
 * @rx_packet_info: rx packet meta information
 * @session_entry: Session entry.
 *
 * This function is called when ECSA action frame is received on STA interface.
 *
 * Return: void
 */
static void
lim_process_ecsa_action_frame(tpAniSirGlobal mac_ctx,
		uint8_t *rx_packet_info, tpPESession session_entry)
{
    tpSirMacMgmtHdr hdr;
    uint8_t *body;
    tDot11fext_channel_switch_action_frame  *ecsa_frame;
    struct ecsa_frame_params ecsa_req;
    uint32_t frame_len;
    uint32_t status;

    hdr = WDA_GET_RX_MAC_HEADER(rx_packet_info);
    body = WDA_GET_RX_MPDU_DATA(rx_packet_info);
    frame_len = WDA_GET_RX_PAYLOAD_LEN(rx_packet_info);

    limLog(mac_ctx, LOG1, FL("Received ECSA action frame"));


    ecsa_frame = vos_mem_malloc(sizeof(*ecsa_frame));
    if (!ecsa_frame) {
        limLog(mac_ctx, LOGE, FL("AllocateMemory failed"));
        return;
    }

    /* Unpack channel switch frame */
    status = dot11fUnpackext_channel_switch_action_frame(mac_ctx,
                  body, frame_len, ecsa_frame);

    if (DOT11F_FAILED(status)) {
        limLog(mac_ctx, LOGE, FL("Failed to parse CHANSW action frame (0x%08x, len %d):"),
               status, frame_len);
        goto free_ecsa;
    } else if (DOT11F_WARNED(status)) {
        limLog(mac_ctx, LOGW, FL("There were warnings while unpacking CHANSW Request (0x%08x, %d bytes):"),
               status, frame_len);
    }

    if (session_entry->currentOperChannel ==
        ecsa_frame->ext_chan_switch_ann_action.new_channel) {
        limLog(mac_ctx, LOGE, FL("New channel %d is same as old channel ignore req"),
               ecsa_frame->ext_chan_switch_ann_action.new_channel);
        goto free_ecsa;
    }

    ecsa_req.new_channel = ecsa_frame->ext_chan_switch_ann_action.new_channel;
    ecsa_req.op_class = ecsa_frame->ext_chan_switch_ann_action.op_class;
    ecsa_req.switch_mode = ecsa_frame->ext_chan_switch_ann_action.switch_mode;
    ecsa_req.switch_count = ecsa_frame->ext_chan_switch_ann_action.switch_count;
    limLog(mac_ctx, LOG1, FL("New channel %d op class %d switch mode %d switch count %d"),
           ecsa_req.new_channel, ecsa_req.op_class,
           ecsa_req.switch_mode, ecsa_req.switch_count);

    lim_handle_ecsa_req(mac_ctx, &ecsa_req, session_entry);
free_ecsa:
    vos_mem_free(ecsa_frame);
}


#ifdef WLAN_FEATURE_11AC
static void
__limProcessOperatingModeActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{

    tpSirMacMgmtHdr         pHdr;
    tANI_U8                 *pBody;
    tDot11fOperatingMode    *pOperatingModeframe;
    tANI_U32                frameLen;
    tANI_U32                nStatus;
    tpDphHashNode           pSta;
    tANI_U16                aid;
    tANI_U8                 operMode;
    tANI_U32                channelBondingMode;

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    limLog(pMac, LOG1, FL("Received Operating Mode action frame"));

    if( RF_CHAN_14 >= psessionEntry->currentOperChannel )
    {
        channelBondingMode = pMac->roam.configParam.channelBondingMode24GHz;
    }
    else
    {
        channelBondingMode = pMac->roam.configParam.channelBondingMode5GHz;
    }

    /* Do not update the channel bonding mode if channel bonding
     * mode is disabled in INI.
     */
    if(WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == channelBondingMode)
    {
        limLog(pMac, LOGW,
            FL("channel bonding disabled"));
        return;
    }

    if (( RF_CHAN_14 >= psessionEntry->currentOperChannel )&&
          !IS_HT40_OBSS_SCAN_FEATURE_ENABLE)
    {
        limLog(pMac, LOGW,
              FL("channel bonding disabled as FW doesn't supoort CB in 2.4gz"));
        return;
    }

    pOperatingModeframe = vos_mem_malloc(sizeof(*pOperatingModeframe));
    if (NULL == pOperatingModeframe)
    {
        limLog(pMac, LOGE,
            FL("AllocateMemory failed"));
        return;
    }

    /* Unpack channel switch frame */
    nStatus = dot11fUnpackOperatingMode(pMac, pBody, frameLen, pOperatingModeframe);

    if( DOT11F_FAILED( nStatus ))
    {
        limLog( pMac, LOGE,
            FL( "Failed to unpack and parse an 11h-CHANSW Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen);
        vos_mem_free(pOperatingModeframe);
        return;
    }
    else if(DOT11F_WARNED( nStatus ))
    {
        limLog( pMac, LOGW,
            FL( "There were warnings while unpacking an 11h-CHANSW Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen);
    }
    pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
    if (pSta == NULL)
    {
        PELOGE(limLog(pMac, LOGE, FL("Station context not found"));)
        return;
    }
    
    operMode = pSta->vhtSupportedChannelWidthSet ? eHT_CHANNEL_WIDTH_80MHZ : pSta->htSupportedChannelWidthSet ? eHT_CHANNEL_WIDTH_40MHZ: eHT_CHANNEL_WIDTH_20MHZ;
    if( operMode != pOperatingModeframe->OperatingMode.chanWidth)
    {
        limLog(pMac, LOGE, 
            FL(" received Chanwidth %d, staIdx = %d"),
            (pOperatingModeframe->OperatingMode.chanWidth ),
            pSta->staIndex);

        limLog(pMac, LOGE, 
            FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"),
            pHdr->sa[0],
            pHdr->sa[1],
            pHdr->sa[2],
            pHdr->sa[3],
            pHdr->sa[4],
            pHdr->sa[5]);

        if(pOperatingModeframe->OperatingMode.chanWidth == eHT_CHANNEL_WIDTH_80MHZ)
        {
            pSta->vhtSupportedChannelWidthSet = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
            pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ;
        } 
        else if(pOperatingModeframe->OperatingMode.chanWidth == eHT_CHANNEL_WIDTH_40MHZ)
        {
            pSta->vhtSupportedChannelWidthSet = WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ;
            pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ;
        }
        else if(pOperatingModeframe->OperatingMode.chanWidth == eHT_CHANNEL_WIDTH_20MHZ)
        {
            pSta->vhtSupportedChannelWidthSet = WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ;
            pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_20MHZ;
        }
        limCheckVHTOpModeChange( pMac, psessionEntry, 
                                 (pOperatingModeframe->OperatingMode.chanWidth), pSta->staIndex);\
    }
    vos_mem_free(pOperatingModeframe);
    return;
}
#endif

static void
__limProcessAddTsReq(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
}


static void
__limProcessAddTsRsp(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
    tSirAddtsRspInfo addts;
    tSirRetStatus    retval;
    tpSirMacMgmtHdr  pHdr;
    tpDphHashNode    pSta;
    tANI_U16         aid;
    tANI_U32         frameLen;
    tANI_U8          *pBody;
    tpLimTspecInfo   tspecInfo;
    tANI_U8          ac; 
    tpDphHashNode    pStaDs = NULL;
    tANI_U8          rspReqd = 1;
    tANI_U32   cfgLen;
    tSirMacAddr  peerMacAddr;


    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);


    PELOGW(limLog(pMac, LOGW, "Recv AddTs Response");)
    if ((psessionEntry->limSystemRole == eLIM_AP_ROLE)||(psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE))
    {
        PELOGW(limLog(pMac, LOGW, FL("AddTsRsp recvd at AP: ignoring"));)
        return;
    }

    pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
    if (pSta == NULL)
    {
        PELOGE(limLog(pMac, LOGE, FL("Station context not found - ignoring AddTsRsp"));)
        return;
    }

    retval = sirConvertAddtsRsp2Struct(pMac, pBody, frameLen, &addts);
    if (retval != eSIR_SUCCESS)
    {
        PELOGW(limLog(pMac, LOGW, FL("AddTsRsp parsing failed (error %d)"), retval);)
        return;
    }

    // don't have to check for qos/wme capabilities since we wouldn't have this
    // flag set otherwise
    if (! pMac->lim.gLimAddtsSent)
    {
        // we never sent an addts request!
        PELOGW(limLog(pMac, LOGW, "Recvd AddTsRsp but no request was ever sent - ignoring");)
        return;
    }

    if (pMac->lim.gLimAddtsReq.req.dialogToken != addts.dialogToken)
    {
        limLog(pMac, LOGW, "AddTsRsp: token mismatch (got %d, exp %d) - ignoring",
               addts.dialogToken, pMac->lim.gLimAddtsReq.req.dialogToken);
        return;
    }

    /*
     * for successful addts reponse, try to add the classifier.
     * if this fails for any reason, we should send a delts request to the ap
     * for now, its ok not to send a delts since we are going to add support for
     * multiple tclas soon and until then we won't send any addts requests with
     * multiple tclas elements anyway.
     * In case of addClassifier failure, we just let the addts timer run out
     */
    if (((addts.tspec.tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) ||
         (addts.tspec.tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_BOTH)) &&
        (addts.status == eSIR_MAC_SUCCESS_STATUS))
    {
        // add the classifier - this should always succeed
        if (addts.numTclas > 1) // currently no support for multiple tclas elements
        {
            limLog(pMac, LOGE, FL("Sta %d: Too many Tclas (%d), only 1 supported"),
                   aid, addts.numTclas);
            return;
        }
        else if (addts.numTclas == 1)
        {
            limLog(pMac, LOGW, "AddTs Response from STA %d: tsid %d, UP %d, OK!", aid,
                   addts.tspec.tsinfo.traffic.tsid, addts.tspec.tsinfo.traffic.userPrio);
        }
    }
    limLog(pMac, LOGW, "Recv AddTsRsp: tsid %d, UP %d, status %d ",
          addts.tspec.tsinfo.traffic.tsid, addts.tspec.tsinfo.traffic.userPrio,
          addts.status);

    // deactivate the response timer
    limDeactivateAndChangeTimer(pMac, eLIM_ADDTS_RSP_TIMER);

    if (addts.status != eSIR_MAC_SUCCESS_STATUS)
    {
        limLog(pMac, LOGW, "Recv AddTsRsp: tsid %d, UP %d, status %d ",
              addts.tspec.tsinfo.traffic.tsid, addts.tspec.tsinfo.traffic.userPrio,
              addts.status);
        limSendSmeAddtsRsp(pMac, true, addts.status, psessionEntry, addts.tspec, 
                psessionEntry->smeSessionId, psessionEntry->transactionId);

        // clear the addts flag
        pMac->lim.gLimAddtsSent = false;

        return;
    }
#ifdef FEATURE_WLAN_ESE
    if (addts.tsmPresent)
    {
        limLog(pMac, LOGW, "TSM IE Present");
        psessionEntry->eseContext.tsm.tid = addts.tspec.tsinfo.traffic.userPrio;
        vos_mem_copy(&psessionEntry->eseContext.tsm.tsmInfo,
                                         &addts.tsmIE,sizeof(tSirMacESETSMIE));
#ifdef FEATURE_WLAN_ESE_UPLOAD
        limSendSmeTsmIEInd(pMac, psessionEntry, addts.tsmIE.tsid,
                           addts.tsmIE.state, addts.tsmIE.msmt_interval);
#else
        limActivateTSMStatsTimer(pMac, psessionEntry);
#endif /* FEATURE_WLAN_ESE_UPLOAD */
    }
#endif
    /* Since AddTS response was successful, check for the PSB flag
     * and directional flag inside the TS Info field. 
     * An AC is trigger enabled AC if the PSB subfield is set to 1  
     * in the uplink direction.
     * An AC is delivery enabled AC if the PSB subfield is set to 1 
     * in the downlink direction.
     * An AC is trigger and delivery enabled AC if the PSB subfield  
     * is set to 1 in the bi-direction field.
     */
    if (addts.tspec.tsinfo.traffic.psb == 1)
        limSetTspecUapsdMask(pMac, &addts.tspec.tsinfo, SET_UAPSD_MASK);
    else 
        limSetTspecUapsdMask(pMac, &addts.tspec.tsinfo, CLEAR_UAPSD_MASK);


    /* ADDTS success, so AC is now admitted. We shall now use the default
     * EDCA parameters as advertised by AP and send the updated EDCA params
     * to HAL. 
     */
    ac = upToAc(addts.tspec.tsinfo.traffic.userPrio);
    if(addts.tspec.tsinfo.traffic.direction == SIR_MAC_DIRECTION_UPLINK)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= (1 << ac);
    }
    else if(addts.tspec.tsinfo.traffic.direction == SIR_MAC_DIRECTION_DNLINK)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= (1 << ac);
    }
    else if(addts.tspec.tsinfo.traffic.direction == SIR_MAC_DIRECTION_BIDIR)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= (1 << ac);
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= (1 << ac);
    }

    limSetActiveEdcaParams(pMac, psessionEntry->gLimEdcaParams, psessionEntry);

    pStaDs = dphGetHashEntry(pMac, DPH_STA_HASH_INDEX_PEER, &psessionEntry->dph.dphHashTable);
    if (pStaDs != NULL)
    {
        if (pStaDs->aniPeer == eANI_BOOLEAN_TRUE) 
            limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive, pStaDs->bssId, eANI_BOOLEAN_TRUE);
        else
            limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive, pStaDs->bssId, eANI_BOOLEAN_FALSE);
    }
    else
        limLog(pMac, LOGE, FL("Self entry missing in Hash Table "));

        
    sirCopyMacAddr(peerMacAddr,psessionEntry->bssId);

    //if schedule is not present then add TSPEC with svcInterval as 0.
    if(!addts.schedulePresent)
      addts.schedule.svcInterval = 0;
    if(eSIR_SUCCESS != limTspecAdd(pMac, pSta->staAddr, pSta->assocId, &addts.tspec,  addts.schedule.svcInterval, &tspecInfo))
    {
        PELOGE(limLog(pMac, LOGE, FL("Adding entry in lim Tspec Table failed "));)
        limSendDeltsReqActionFrame(pMac, peerMacAddr, rspReqd, &addts.tspec.tsinfo, &addts.tspec,
                psessionEntry);
        pMac->lim.gLimAddtsSent = false;
        return;   //Error handling. send the response with error status. need to send DelTS to tear down the TSPEC status.
    }
    if((addts.tspec.tsinfo.traffic.accessPolicy != SIR_MAC_ACCESSPOLICY_EDCA) ||
       ((upToAc(addts.tspec.tsinfo.traffic.userPrio) < MAX_NUM_AC)))
    {
        retval = limSendHalMsgAddTs(pMac, pSta->staIndex, tspecInfo->idx, addts.tspec, psessionEntry->peSessionId);
        if(eSIR_SUCCESS != retval)
        {
            limAdmitControlDeleteTS(pMac, pSta->assocId, &addts.tspec.tsinfo, NULL, &tspecInfo->idx);
    
            // Send DELTS action frame to AP        
            cfgLen = sizeof(tSirMacAddr);
            limSendDeltsReqActionFrame(pMac, peerMacAddr, rspReqd, &addts.tspec.tsinfo, &addts.tspec,
                    psessionEntry);
            limSendSmeAddtsRsp(pMac, true, retval, psessionEntry, addts.tspec,
                    psessionEntry->smeSessionId, psessionEntry->transactionId);
            pMac->lim.gLimAddtsSent = false;
            return;
        }
        PELOGW(limLog(pMac, LOGW, FL("AddTsRsp received successfully(UP %d, TSID %d)"),
           addts.tspec.tsinfo.traffic.userPrio, addts.tspec.tsinfo.traffic.tsid);)
    }
    else
    {
        PELOGW(limLog(pMac, LOGW, FL("AddTsRsp received successfully(UP %d, TSID %d)"),
               addts.tspec.tsinfo.traffic.userPrio, addts.tspec.tsinfo.traffic.tsid);)
        PELOGW(limLog(pMac, LOGW, FL("no ACM: Bypass sending WDA_ADD_TS_REQ to HAL "));)
        // Use the smesessionId and smetransactionId from the PE session context
        limSendSmeAddtsRsp(pMac, true, eSIR_SME_SUCCESS, psessionEntry, addts.tspec,
                psessionEntry->smeSessionId, psessionEntry->transactionId);
    }

    // clear the addts flag
    pMac->lim.gLimAddtsSent = false;
    return;
}


static void
__limProcessDelTsReq(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
    tSirRetStatus    retval;
    tSirDeltsReqInfo delts;
    tpSirMacMgmtHdr  pHdr;
    tpDphHashNode    pSta;
    tANI_U32              frameLen;
    tANI_U16              aid;
    tANI_U8              *pBody;
    tANI_U8               tsStatus;
    tSirMacTSInfo   *tsinfo;
    tANI_U8 tspecIdx;
    tANI_U8  ac;
    tpDphHashNode  pStaDs = NULL;


    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
    if (pSta == NULL)
    {
        PELOGE(limLog(pMac, LOGE, FL("Station context not found - ignoring DelTs"));)
        return;
    }

    // parse the delts request
    retval = sirConvertDeltsReq2Struct(pMac, pBody, frameLen, &delts);
    if (retval != eSIR_SUCCESS)
    {
        PELOGW(limLog(pMac, LOGW, FL("DelTs parsing failed (error %d)"), retval);)
        return;
    }

    if (delts.wmeTspecPresent)
    {
        if ((!psessionEntry->limWmeEnabled) || (! pSta->wmeEnabled))
        {
            PELOGW(limLog(pMac, LOGW, FL("Ignoring delts request: wme not enabled/capable"));)
            return;
        }
        limLog(pMac, LOG1, FL("WME Delts received"));
    }
    else if ((psessionEntry->limQosEnabled) && pSta->lleEnabled)
        {
        limLog(pMac, LOG1, FL("11e QoS Delts received"));
        }
    else if ((psessionEntry->limWsmEnabled) && pSta->wsmEnabled)
        {
        limLog(pMac, LOG1, FL("WSM Delts received"));
        }
    else
    {
        PELOGW(limLog(pMac, LOGW, FL("Ignoring delts request: qos not enabled/capable"));)
        return;
    }

    tsinfo = delts.wmeTspecPresent ? &delts.tspec.tsinfo : &delts.tsinfo;

    // if no Admit Control, ignore the request
    if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA))
    {
    
        if (upToAc(tsinfo->traffic.userPrio) >= MAX_NUM_AC)
        {
            limLog(pMac, LOGW, FL("DelTs with UP %d has no AC - ignoring request"),
                   tsinfo->traffic.userPrio);
            return;
        }
    }

    if ((psessionEntry->limSystemRole != eLIM_AP_ROLE) &&
        (psessionEntry->limSystemRole != eLIM_BT_AMP_AP_ROLE))
        limSendSmeDeltsInd(pMac, &delts, aid,psessionEntry);

    // try to delete the TS
    if (eSIR_SUCCESS != limAdmitControlDeleteTS(pMac, pSta->assocId, tsinfo, &tsStatus, &tspecIdx))
    {
        PELOGW(limLog(pMac, LOGW, FL("Unable to Delete TS"));)
        return;
    }

    else if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) ||
             (tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_BOTH))
    {
      //Edca only for now.
    }
    else
    {
      //send message to HAL to delete TS
      if(eSIR_SUCCESS != limSendHalMsgDelTs(pMac,
                                            pSta->staIndex,
                                            tspecIdx,
                                            delts,
                                            psessionEntry->peSessionId,
                                            psessionEntry->bssId))
      {
        limLog(pMac, LOGW, FL("DelTs with UP %d failed in limSendHalMsgDelTs - ignoring request"),
                         tsinfo->traffic.userPrio);
         return;
      }
    }

    /* We successfully deleted the TSPEC. Update the dynamic UAPSD Mask.
     * The AC for this TSPEC is no longer trigger enabled if this Tspec
     * was set-up in uplink direction only.
     * The AC for this TSPEC is no longer delivery enabled if this Tspec
     * was set-up in downlink direction only.
     * The AC for this TSPEC is no longer triiger enabled and delivery 
     * enabled if this Tspec was a bidirectional TSPEC.
     */
    limSetTspecUapsdMask(pMac, tsinfo, CLEAR_UAPSD_MASK);


    /* We're deleting the TSPEC.
     * The AC for this TSPEC is no longer admitted in uplink/downlink direction
     * if this TSPEC was set-up in uplink/downlink direction only.
     * The AC for this TSPEC is no longer admitted in both uplink and downlink
     * directions if this TSPEC was a bi-directional TSPEC.
     * If ACM is set for this AC and this AC is admitted only in downlink
     * direction, PE needs to downgrade the EDCA parameter 
     * (for the AC for which TS is being deleted) to the
     * next best AC for which ACM is not enabled, and send the
     * updated values to HAL. 
     */ 
    ac = upToAc(tsinfo->traffic.userPrio);

    if(tsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= ~(1 << ac);
    }
    else if(tsinfo->traffic.direction == SIR_MAC_DIRECTION_DNLINK)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= ~(1 << ac);
    }
    else if(tsinfo->traffic.direction == SIR_MAC_DIRECTION_BIDIR)
    {
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= ~(1 << ac);
      pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= ~(1 << ac);
    }

    limSetActiveEdcaParams(pMac, psessionEntry->gLimEdcaParams, psessionEntry);

    pStaDs = dphGetHashEntry(pMac, DPH_STA_HASH_INDEX_PEER, &psessionEntry->dph.dphHashTable);
    if (pStaDs != NULL)
    {
        if (pStaDs->aniPeer == eANI_BOOLEAN_TRUE) 
            limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive, pStaDs->bssId, eANI_BOOLEAN_TRUE);
        else
            limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive, pStaDs->bssId, eANI_BOOLEAN_FALSE);
    }
    else
        limLog(pMac, LOGE, FL("Self entry missing in Hash Table "));

    limLog(pMac, LOG1, FL("DeleteTS succeeded"));

#ifdef FEATURE_WLAN_ESE
#ifdef FEATURE_WLAN_ESE_UPLOAD
    limSendSmeTsmIEInd(pMac, psessionEntry, 0, 0, 0);
#else
    limDeactivateAndChangeTimer(pMac,eLIM_TSM_TIMER);
#endif /* FEATURE_WLAN_ESE_UPLOAD */
#endif

}

static void
__limProcessQosMapConfigureFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,
                                                     tpPESession psessionEntry)
{
     tpSirMacMgmtHdr  pHdr;
     tANI_U32         frameLen;
     tANI_U8          *pBody;
     tSirRetStatus    retval;
     pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
     pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
     frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
     retval = sirConvertQosMapConfigureFrame2Struct(pMac, pBody, frameLen,
                                                        &psessionEntry->QosMapSet);
     if (retval != eSIR_SUCCESS)
     {
         PELOGW(limLog(pMac, LOGE,
         FL("QosMapConfigure frame parsing failed (error %d)"), retval);)
         return;
     }
     limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                        pRxPacketInfo, psessionEntry,
                                        WDA_GET_RX_RSSI_DB(pRxPacketInfo),
                                        RXMGMT_FLAG_NONE);
}

#ifdef ANI_SUPPORT_11H
/**
 *  limProcessBasicMeasReq
 *
 *FUNCTION:
 * This function is called by limProcessMeasurementRequestFrame()
 * when it received a Basic measurement Request action frame.
 * Station/BP receiving this should perform basic measurements
 * and then send Basic Measurement Report. AP should not perform
 * any measurements, and send report indicating refusal.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  pMeasReqFrame - A pointer to Basic Meas. Req structure
 * @return None
 */
static void
__limProcessBasicMeasReq(tpAniSirGlobal pMac,
                       tpSirMacMeasReqActionFrame pMeasReqFrame,
                       tSirMacAddr peerMacAddr)
{
    // TBD - Station shall perform basic measurements

    if (limSendMeasReportFrame(pMac,
                               pMeasReqFrame,
                               peerMacAddr) != eSIR_SUCCESS)
    {
        PELOGE(limLog(pMac, LOGE, FL("fail to send Basic Meas report "));)
        return;
    }
}


/**
 *  limProcessCcaMeasReq
 *
 *FUNCTION:
 * This function is called by limProcessMeasurementRequestFrame()
 * when it received a CCA measurement Request action frame.
 * Station/BP receiving this should perform CCA measurements
 * and then send CCA Measurement Report. AP should not perform
 * any measurements, and send report indicating refusal.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  pMeasReqFrame - A pointer to CCA Meas. Req structure
 * @return None
 */
static void
__limProcessCcaMeasReq(tpAniSirGlobal pMac,
                     tpSirMacMeasReqActionFrame pMeasReqFrame,
                     tSirMacAddr peerMacAddr)
{
    // TBD - Station shall perform cca measurements

    if (limSendMeasReportFrame(pMac,
                               pMeasReqFrame,
                               peerMacAddr) != eSIR_SUCCESS)
    {
        PELOGE(limLog(pMac, LOGE, FL("fail to send CCA Meas report "));)
        return;
    }
}


/**
 *  __limProcessRpiMeasReq
 *
 *FUNCTION:
 * This function is called by limProcessMeasurementRequestFrame()
 * when it received a RPI measurement Request action frame.
 * Station/BP/AP  receiving this shall not perform any measurements,
 * and send report indicating refusal.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  pMeasReqFrame - A pointer to RPI Meas. Req structure
 * @return None
 */
static void
__limProcessRpiMeasReq(tpAniSirGlobal pMac,
                     tpSirMacMeasReqActionFrame pMeasReqFrame,
                     tSirMacAddr peerMacAddr)
{
    if (limSendMeasReportFrame(pMac,
                               pMeasReqFrame,
                               peerMacAddr) != eSIR_SUCCESS)
    {
        PELOGE(limLog(pMac, LOGE, FL("fail to send RPI Meas report "));)
        return;
    }
}


/**
 *  __limProcessMeasurementRequestFrame
 *
 *FUNCTION:
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - A pointer to packet info structure
 * @return None
 */

static void
__limProcessMeasurementRequestFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo)
{
    tpSirMacMgmtHdr                       pHdr;
    tANI_U8                                    *pBody;
    tpSirMacMeasReqActionFrame            pMeasReqFrame;
    tANI_U32                                   frameLen;

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    pMeasReqFrame = vos_mem_malloc(sizeof( tSirMacMeasReqActionFrame ));
    if (NULL == pMeasReqFrame)
    {
        limLog(pMac, LOGE,
            FL("limProcessMeasurementRequestFrame: AllocateMemory failed "));
        return;
    }

    if (sirConvertMeasReqFrame2Struct(pMac, pBody, pMeasReqFrame, frameLen) !=
        eSIR_SUCCESS)
    {
        PELOGW(limLog(pMac, LOGW, FL("Rcv invalid Measurement Request Action Frame "));)
        return;
    }


    switch(pMeasReqFrame->measReqIE.measType)
    {
        case SIR_MAC_BASIC_MEASUREMENT_TYPE:
            __limProcessBasicMeasReq(pMac, pMeasReqFrame, pHdr->sa);
            break;

        case SIR_MAC_CCA_MEASUREMENT_TYPE:
            __limProcessCcaMeasReq(pMac, pMeasReqFrame, pHdr->sa);
            break;

        case SIR_MAC_RPI_MEASUREMENT_TYPE:
            __limProcessRpiMeasReq(pMac, pMeasReqFrame, pHdr->sa);
            break;

        default:
            limLog(pMac, LOG1, FL("Unknown Measurement Type %d "),
                   pMeasReqFrame->measReqIE.measType);
            break;
    }

} /*** end limProcessMeasurementRequestFrame ***/


/**
 *  limProcessTpcRequestFrame
 *
 *FUNCTION:
 *  This function is called upon receiving Tpc Request frame.
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - A pointer to packet info structure
 * @return None
 */

static void
__limProcessTpcRequestFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo)
{
    tpSirMacMgmtHdr                       pHdr;
    tANI_U8                                    *pBody;
    tpSirMacTpcReqActionFrame             pTpcReqFrame;
    tANI_U32                                   frameLen;

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    limLog(pMac, LOG1, FL("****LIM: Processing TPC Request from peer ****"));

    pTpcReqFrame = vos_mem_malloc(sizeof( tSirMacTpcReqActionFrame ));
    if (NULL == pTpcReqFrame)
    {
        PELOGE(limLog(pMac, LOGE, FL("AllocateMemory failed "));)
        return;
    }

    if (sirConvertTpcReqFrame2Struct(pMac, pBody, pTpcReqFrame, frameLen) !=
        eSIR_SUCCESS)
    {
        PELOGW(limLog(pMac, LOGW, FL("Rcv invalid TPC Req Action Frame "));)
        return;
    }

    if (limSendTpcReportFrame(pMac,
                              pTpcReqFrame,
                              pHdr->sa) != eSIR_SUCCESS)
    {
        PELOGE(limLog(pMac, LOGE, FL("fail to send TPC Report Frame. "));)
        return;
    }
}
#endif


/**
 * \brief Validate an ADDBA Req from peer with respect
 * to our own BA configuration
 *
 * \sa __limValidateAddBAParameterSet
 *
 * \param pMac The global tpAniSirGlobal object
 *
 * \param baParameterSet The ADDBA Parameter Set.
 *
 * \param pDelBAFlag this parameter is NULL except for call from processAddBAReq
 *        delBAFlag is set when entry already exists.
 *
 * \param reqType ADDBA Req v/s ADDBA Rsp
 * 1 - ADDBA Req
 * 0 - ADDBA Rsp
 *
 * \return eSIR_SUCCESS if setup completes successfully
 *         eSIR_FAILURE is some problem is encountered
 */

static tSirMacStatusCodes
__limValidateAddBAParameterSet( tpAniSirGlobal pMac,
    tpDphHashNode pSta,
    tDot11fFfAddBAParameterSet baParameterSet,
    tANI_U8 dialogueToken,
    tLimAddBaValidationReqType reqType ,
    tANI_U8* pDelBAFlag /*this parameter is NULL except for call from processAddBAReq*/)
{
  if(baParameterSet.tid >= STACFG_MAX_TC)
  {
      return eSIR_MAC_WME_INVALID_PARAMS_STATUS;
  }

  //check if there is already a BA session setup with this STA/TID while processing AddBaReq
  if((true == pSta->tcCfg[baParameterSet.tid].fUseBARx) &&
        (LIM_ADDBA_REQ == reqType))
  {
      //There is already BA session setup for STA/TID.
      limLog( pMac, LOGE,
          FL( "AddBAReq rcvd when there is already a session for this StaId = %d, tid = %d\n " ),
          pSta->staIndex, baParameterSet.tid);
      limPrintMacAddr( pMac, pSta->staAddr, LOGW );

      if(pDelBAFlag)
        *pDelBAFlag = true;
  }
  return eSIR_MAC_SUCCESS_STATUS;
}

/**
 * \brief Validate a DELBA Ind from peer with respect
 * to our own BA configuration
 *
 * \sa __limValidateDelBAParameterSet
 *
 * \param pMac The global tpAniSirGlobal object
 *
 * \param baParameterSet The DELBA Parameter Set.
 *
 * \param pSta Runtime, STA-related configuration cached
 * in the HashNode object
 *
 * \return eSIR_SUCCESS if setup completes successfully
 *         eSIR_FAILURE is some problem is encountered
 */
static tSirMacStatusCodes 
__limValidateDelBAParameterSet( tpAniSirGlobal pMac,
    tDot11fFfDelBAParameterSet baParameterSet,
    tpDphHashNode pSta )
{
tSirMacStatusCodes statusCode = eSIR_MAC_STA_BLK_ACK_NOT_SUPPORTED_STATUS;

	  if (!(baParameterSet.tid < STACFG_MAX_TC))
		return statusCode;

  // Validate if a BA is active for the requested TID
    if( pSta->tcCfg[baParameterSet.tid].fUseBATx ||
        pSta->tcCfg[baParameterSet.tid].fUseBARx )
    {
      statusCode = eSIR_MAC_SUCCESS_STATUS;

      limLog( pMac, LOGW,
          FL("Valid DELBA Ind received. Time to send WDA_DELBA_IND to HAL..."));
    }
    else
      limLog( pMac, LOGW,
          FL("Received an INVALID DELBA Ind for TID %d..."),
          baParameterSet.tid );

  return statusCode;
}

/**
 * \brief Process an ADDBA REQ
 *
 * \sa limProcessAddBAReq
 *
 * \param pMac The global tpAniSirGlobal object
 *
 * \param pRxPacketInfo Handle to the Rx packet info from HDD
 *
 * \return none
 *
 */
static void
__limProcessAddBAReq( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
    tDot11fAddBAReq frmAddBAReq;
    tpSirMacMgmtHdr pHdr;
    tpDphHashNode pSta;
    tSirMacStatusCodes status = eSIR_MAC_SUCCESS_STATUS;
    tANI_U16 aid;
    tANI_U32 frameLen, nStatus,val, val1;
    tANI_U8 *pBody;
    tANI_U8 delBAFlag =0;

    pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
    pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
    frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );
    val = 0;
    val1 = 0;

    // Unpack the received frame
    nStatus = dot11fUnpackAddBAReq( pMac, pBody, frameLen, &frmAddBAReq );
    if( DOT11F_FAILED( nStatus ))
    {
        limLog( pMac, LOGE,
            FL("Failed to unpack and parse an ADDBA Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen );

        PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)

        // Without an unpacked request we cannot respond, so silently ignore the request
        return;
    }
    else if ( DOT11F_WARNED( nStatus ) )
    {
        limLog( pMac, LOGW,
            FL( "There were warnings while unpacking an ADDBA Request (0x%08x, %d bytes):"),
            nStatus,
            frameLen );

        PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
    }

    psessionEntry->amsduSupportedInBA = frmAddBAReq.AddBAParameterSet.amsduSupported;

    pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid,
                              &psessionEntry->dph.dphHashTable);
    if( pSta == NULL )
    {
        limLog( pMac, LOGE,
            FL( "STA context not found - ignoring ADDBA from " ));
        limPrintMacAddr( pMac, pHdr->sa, LOGE );

        // FIXME - Should we do this?
        status = eSIR_MAC_INABLITY_TO_CONFIRM_ASSOC_STATUS;
        goto returnAfterError;
    }
    limLog( pMac, LOG1, FL( "ADDBA Req from STA "MAC_ADDRESS_STR " with AID %d"
                            " tid = %d policy = %d buffsize = %d"
                            " amsduSupported = %d"), MAC_ADDR_ARRAY(pHdr->sa),
                            aid, frmAddBAReq.AddBAParameterSet.tid,
                            frmAddBAReq.AddBAParameterSet.policy,
                            frmAddBAReq.AddBAParameterSet.bufferSize,
                            frmAddBAReq.AddBAParameterSet.amsduSupported);

    limLog( pMac, LOG1, FL( "ssn = %d fragNumber = %d" ),
                            frmAddBAReq.BAStartingSequenceControl.ssn,
                            frmAddBAReq.BAStartingSequenceControl.fragNumber);

#ifdef WLAN_SOFTAP_VSTA_FEATURE
    // we can only do BA on "hard" STAs
    if (!(IS_HWSTA_IDX(pSta->staIndex)))
    {
        status = eSIR_MAC_REQ_DECLINED_STATUS;
        limLog( pMac, LOG1,
            FL( "ta Id is not HW Sta Id, Status code is %d " ), status);
        goto returnAfterError;
    }
#endif //WLAN_SOFTAP_VSTA_FEATURE

    if (wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_TX_RX_AGGREGATION, &val1) !=
                    eSIR_SUCCESS)
    {
        limLog(pMac, LOGE,
               FL("Unable to get WNI_CFG_ENABLE_TX_RX_AGGREGATION"));
        val1 = 1;
    }
    if (!val1)
    {
        limLog(pMac, LOGE,
               FL("aggregation disabled - ignoring ADDBA"));
        goto returnAfterError;
    }

    if (wlan_cfgGetInt(pMac, WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC, &val) !=
                    eSIR_SUCCESS)
    {
        limLog(pMac, LOGE,
               FL("Unable to get WNI_CFG_DEL_ALL_RX_TX_BA_SESSIONS_2_4_G_BTC"));
        val = 0;
    }
    if ((SIR_BAND_2_4_GHZ == limGetRFBand(psessionEntry->currentOperChannel)) &&
                    val)
    {
        limLog( pMac, LOGW,
            FL( "BTC disabled aggregation - ignoring ADDBA from " ));
        limPrintMacAddr( pMac, pHdr->sa, LOGW );

        status = eSIR_MAC_REQ_DECLINED_STATUS;
        goto returnAfterError;
    }

    // Now, validate the ADDBA Req
    if( eSIR_MAC_SUCCESS_STATUS !=
      (status = __limValidateAddBAParameterSet( pMac, pSta,
                                              frmAddBAReq.AddBAParameterSet,
                                              0, //dialogue token is don't care in request validation.
                                              LIM_ADDBA_REQ, &delBAFlag)))
    {
        limLog( pMac, LOGE,
            FL( "ADDBA parameters validation failed with status %d" ), status);
        goto returnAfterError;
    }

    //BA already set, so we need to delete it before adding new one.
    if(delBAFlag)
    {
        if( eSIR_SUCCESS != limPostMsgDelBAInd( pMac,
            pSta,
            (tANI_U8)frmAddBAReq.AddBAParameterSet.tid,
            eBA_RECIPIENT,psessionEntry))
        {
            status = eSIR_MAC_UNSPEC_FAILURE_STATUS;
            limLog( pMac, LOGE,
                FL( "Deletion of Existing BA session failed with status %d" ),
                    status);
            goto returnAfterError;
        }
    }

  // Check if the ADD BA Declined configuration is Disabled
    if ((pMac->lim.gAddBA_Declined & ( 1 << frmAddBAReq.AddBAParameterSet.tid ) )) {
        limLog( pMac, LOGE, FL( "Declined the ADDBA Req for the TID %d  " ),
                        frmAddBAReq.AddBAParameterSet.tid);
        status = eSIR_MAC_REQ_DECLINED_STATUS;
        goto returnAfterError;
    }

  //
  // Post WDA_ADDBA_REQ to HAL.
  // If HAL/HDD decide to allow this ADDBA Req session,
  // then this BA session is termed active
  //

  // Change the Block Ack state of this STA to wait for
  // ADDBA Rsp from HAL
  LIM_SET_STA_BA_STATE(pSta, frmAddBAReq.AddBAParameterSet.tid, eLIM_BA_STATE_WT_ADD_RSP);

  if (wlan_cfgGetInt(pMac, WNI_CFG_NUM_BUFF_ADVERT , &val) != eSIR_SUCCESS)
  {
        limLog(pMac, LOGP, FL("Unable to get WNI_CFG_NUM_BUFF_ADVERT"));
        return ;
  }


  if (frmAddBAReq.AddBAParameterSet.bufferSize)
  {
      frmAddBAReq.AddBAParameterSet.bufferSize =
            VOS_MIN(val, frmAddBAReq.AddBAParameterSet.bufferSize);
  }
  else
  {
      frmAddBAReq.AddBAParameterSet.bufferSize = val;
  }
  limLog( pMac, LOG1, FL( "ADDBAREQ NUMBUFF %d" ),
                        frmAddBAReq.AddBAParameterSet.bufferSize);

  if( eSIR_SUCCESS != limPostMsgAddBAReq( pMac,
        pSta,
        (tANI_U8) frmAddBAReq.DialogToken.token,
        (tANI_U8) frmAddBAReq.AddBAParameterSet.tid,
        (tANI_U8) frmAddBAReq.AddBAParameterSet.policy,
        frmAddBAReq.AddBAParameterSet.bufferSize,
        frmAddBAReq.BATimeout.timeout,
        (tANI_U16) frmAddBAReq.BAStartingSequenceControl.ssn,
        eBA_RECIPIENT,psessionEntry))
  {
        status = eSIR_MAC_UNSPEC_FAILURE_STATUS;
        limLog( pMac, LOGE,
            FL( "Request to setup new BA session with peer "
                " "MAC_ADDRESS_STR " failed" ), MAC_ADDR_ARRAY(pSta->staAddr));
  }
  else
    return;

returnAfterError:

  //
  // Package LIM_MLM_ADDBA_RSP to MLME, with proper
  // status code. MLME will then send an ADDBA RSP
  // over the air to the peer MAC entity
  //
  if( eSIR_SUCCESS != limPostMlmAddBARsp( pMac,
        pHdr->sa,
        status,
        frmAddBAReq.DialogToken.token,
        (tANI_U8) frmAddBAReq.AddBAParameterSet.tid,
        (tANI_U8) frmAddBAReq.AddBAParameterSet.policy,
        frmAddBAReq.AddBAParameterSet.bufferSize,
        frmAddBAReq.BATimeout.timeout,psessionEntry))
  {
    limLog( pMac, LOGW,
        FL( "Failed to post LIM_MLM_ADDBA_RSP to " ));
    limPrintMacAddr( pMac, pHdr->sa, LOGW );
  }

}

/**
 * \brief Process an ADDBA RSP
 *
 * \sa limProcessAddBARsp
 *
 * \param pMac The global tpAniSirGlobal object
 *
 * \param pRxPacketInfo Handle to the packet info structure from HDD
 *
 * \return none
 *
 */
static void
__limProcessAddBARsp( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
tDot11fAddBARsp frmAddBARsp;
tpSirMacMgmtHdr pHdr;
tpDphHashNode pSta;
tSirMacReasonCodes reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON;
tANI_U16 aid;
tANI_U32 frameLen, nStatus;
tANI_U8 *pBody;

  pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
  pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
  frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

  pSta = dphLookupHashEntry( pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable );
  if( pSta == NULL )
  {
    limLog( pMac, LOGE,
        FL( "STA context not found - ignoring ADDBA from " ));
    limPrintMacAddr( pMac, pHdr->sa, LOGW );
    return;
  }

#ifdef WLAN_SOFTAP_VSTA_FEATURE
  // We can only do BA on "hard" STAs.  We should not have issued an ADDBA
  // Request, so we should never be processing a ADDBA Response
  if (!(IS_HWSTA_IDX(pSta->staIndex)))
  {
    limLog( pMac, LOGE, FL( "Sta Id is not HW Sta Id " ));
    return;
  }
#endif //WLAN_SOFTAP_VSTA_FEATURE

  // Unpack the received frame
  nStatus = dot11fUnpackAddBARsp( pMac, pBody, frameLen, &frmAddBARsp );
  if( DOT11F_FAILED( nStatus ))
  {
    limLog( pMac, LOGE,
        FL( "Failed to unpack and parse an ADDBA Response (0x%08x, %d bytes):"),
        nStatus,
        frameLen );

    PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
    goto returnAfterError;
  }
  else if ( DOT11F_WARNED( nStatus ) )
  {
    limLog( pMac, LOGW,
        FL( "There were warnings while unpacking an ADDBA Response (0x%08x, %d bytes):"),
        nStatus,
        frameLen );

    PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
  }

  limLog( pMac, LOG1, FL( "ADDBA Rsp from STA "MAC_ADDRESS_STR " with AID %d "
                          "tid = %d policy = %d buffsize = %d "
                          "amsduSupported = %d status = %d"),
                          MAC_ADDR_ARRAY(pHdr->sa), aid,
                          frmAddBARsp.AddBAParameterSet.tid,
                          frmAddBARsp.AddBAParameterSet.policy,
                          frmAddBARsp.AddBAParameterSet.bufferSize,
                          frmAddBARsp.AddBAParameterSet.amsduSupported,
                          frmAddBARsp.Status.status);
  //if there is no matchin dialougue token then ignore the response.

  if(eSIR_SUCCESS != limSearchAndDeleteDialogueToken(pMac, frmAddBARsp.DialogToken.token,
        pSta->assocId, frmAddBARsp.AddBAParameterSet.tid))
  {
      limLog(pMac, LOGE,
        FL("dialogueToken in received addBARsp did not match with outstanding requests"));
      return;
  }

  // Check first if the peer accepted the ADDBA Req
  if( eSIR_MAC_SUCCESS_STATUS == frmAddBARsp.Status.status )
  {
    tANI_U32 val;
    pMac->lim.staBaInfo[pSta->staIndex].
        failed_count[frmAddBARsp.AddBAParameterSet.tid] = 0;
    pMac->lim.staBaInfo[pSta->staIndex].
        failed_timestamp[frmAddBARsp.AddBAParameterSet.tid] = 0;
    if (wlan_cfgGetInt(pMac, WNI_CFG_NUM_BUFF_ADVERT , &val) != eSIR_SUCCESS)
    {
        limLog(pMac, LOG1, FL("Unable to get WNI_CFG_NUM_BUFF_ADVERT"));
        goto returnAfterError;
    }
    if (0 == frmAddBARsp.AddBAParameterSet.bufferSize)
        frmAddBARsp.AddBAParameterSet.bufferSize = val;
    else
        frmAddBARsp.AddBAParameterSet.bufferSize =
                    VOS_MIN(val, frmAddBARsp.AddBAParameterSet.bufferSize);
        limLog( pMac, LOG1,
            FL( "ADDBA RSP  Buffsize = %d" ),
            frmAddBARsp.AddBAParameterSet.bufferSize);
    // Now, validate the ADDBA Rsp
    if( eSIR_MAC_SUCCESS_STATUS !=
        __limValidateAddBAParameterSet( pMac, pSta,
                                       frmAddBARsp.AddBAParameterSet,
                                       (tANI_U8)frmAddBARsp.DialogToken.token,
                                       LIM_ADDBA_RSP, NULL))
    {
        limLog( pMac, LOGE,
            FL( "ADDBA parameters validation failed" ));
        goto returnAfterError;
    }
  }
  else
  {
    pMac->lim.staBaInfo[pSta->staIndex].
       failed_count[frmAddBARsp.AddBAParameterSet.tid]++;
    pMac->lim.staBaInfo[pSta->staIndex].failed_timestamp[
       frmAddBARsp.AddBAParameterSet.tid] = jiffies_to_msecs(jiffies);
    goto returnAfterError;
  }
  // Change STA state to wait for ADDBA Rsp from HAL
  LIM_SET_STA_BA_STATE(pSta, frmAddBARsp.AddBAParameterSet.tid, eLIM_BA_STATE_WT_ADD_RSP);

  //
  // Post WDA_ADDBA_REQ to HAL.
  // If HAL/HDD decide to allow this ADDBA Rsp session,
  // then this BA session is termed active
  //

  if( eSIR_SUCCESS != limPostMsgAddBAReq( pMac,
        pSta,
        (tANI_U8) frmAddBARsp.DialogToken.token,
        (tANI_U8) frmAddBARsp.AddBAParameterSet.tid,
        (tANI_U8) frmAddBARsp.AddBAParameterSet.policy,
        frmAddBARsp.AddBAParameterSet.bufferSize,
        frmAddBARsp.BATimeout.timeout,
        0,
        eBA_INITIATOR,psessionEntry))
  {
      reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON;
      limLog( pMac, LOGE,
          FL( "Request to setup new BA session with peer "
              " "MAC_ADDRESS_STR " failed" ), MAC_ADDR_ARRAY(pSta->staAddr));
  }
  else
    return;

returnAfterError:

  // TODO: Do we need to signal an error status to SME,
  // if status != eSIR_MAC_SUCCESS_STATUS

  // Restore STA "BA" State
  LIM_SET_STA_BA_STATE(pSta, frmAddBARsp.AddBAParameterSet.tid, eLIM_BA_STATE_IDLE);
  //
  // Need to send a DELBA IND to peer, who
  // would have setup a BA session with this STA
  //
  if( eSIR_MAC_SUCCESS_STATUS == frmAddBARsp.Status.status )
  {
    //
    // Package LIM_MLM_DELBA_REQ to MLME, with proper
    // status code. MLME will then send a DELBA IND
    // over the air to the peer MAC entity
    //
    if( eSIR_SUCCESS != limPostMlmDelBAReq( pMac,
          pSta,
          eBA_INITIATOR,
          (tANI_U8) frmAddBARsp.AddBAParameterSet.tid,
          reasonCode, psessionEntry))
    {
      limLog( pMac, LOGW,
          FL( "Failed to post LIM_MLM_DELBA_REQ to " ));
      limPrintMacAddr( pMac, pHdr->sa, LOGW );
    }
  }
}

/**
 * \brief Process a DELBA Indication
 *
 * \sa limProcessDelBAInd
 *
 * \param pMac The global tpAniSirGlobal object
 *
 * \param pRxPacketInfo Handle to the Rx packet info from HDD
 *
 * \return none
 *
 */
static void
__limProcessDelBAReq( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
tDot11fDelBAInd frmDelBAInd;
tpSirMacMgmtHdr pHdr;
tpDphHashNode pSta;
tANI_U16 aid;
tANI_U32 frameLen, nStatus;
tANI_U8 *pBody;

  pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
  pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
  frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

  pSta = dphLookupHashEntry( pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable );
  if( pSta == NULL )
  {
    limLog( pMac, LOGE, FL( "STA context not found - ignoring DELBA from "));
    limPrintMacAddr( pMac, pHdr->sa, LOGW );
    return;
  }

  limLog( pMac, LOG1, FL( "DELBA Ind from STA with AID %d" ), aid );

  // Unpack the received frame
  nStatus = dot11fUnpackDelBAInd( pMac, pBody, frameLen, &frmDelBAInd );
  if( DOT11F_FAILED( nStatus ))
  {
    limLog( pMac, LOGE,
        FL( "Failed to unpack and parse a DELBA Indication (0x%08x, %d bytes):"),
        nStatus,
        frameLen );

    PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
    return;
  }
  else if ( DOT11F_WARNED( nStatus ) )
  {
    limLog( pMac, LOGW,
        FL( "There were warnings while unpacking a DELBA Indication (0x%08x, %d bytes):"),
        nStatus,
        frameLen );

    PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
  }

  limLog( pMac, LOG1,
      FL( "Received DELBA from: "MAC_ADDRESS_STR" for TID %d, Reason code %d" ),
      MAC_ADDR_ARRAY(pHdr->sa),
      frmDelBAInd.DelBAParameterSet.tid,
      frmDelBAInd.Reason.code );

  // Now, validate the DELBA Ind
  if( eSIR_MAC_SUCCESS_STATUS != __limValidateDelBAParameterSet( pMac,
                                             frmDelBAInd.DelBAParameterSet,
                                             pSta ))
  {
      limLog( pMac, LOGE,
          FL( "ADDBA parameters validation failed " ));
      return;
  }
  //
  // Post WDA_DELBA_IND to HAL and delete the
  // existing BA session
  //
  // NOTE - IEEE 802.11-REVma-D8.0, Section 7.3.1.16
  // is kind of confusing...
  //
  if( eSIR_SUCCESS != limPostMsgDelBAInd( pMac,
        pSta,
        (tANI_U8) frmDelBAInd.DelBAParameterSet.tid,
        (eBA_RECIPIENT == frmDelBAInd.DelBAParameterSet.initiator)?
          eBA_INITIATOR: eBA_RECIPIENT,psessionEntry))
    limLog( pMac, LOGE, FL( "Posting WDA_DELBA_IND to HAL failed "));

  return;

}

static void
__limProcessSMPowerSaveUpdate(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo ,tpPESession psessionEntry)
{

#if 0
        tpSirMacMgmtHdr                           pHdr;
        tDot11fSMPowerSave                    frmSMPower;
        tSirMacHTMIMOPowerSaveState  state;
        tpDphHashNode                             pSta;
        tANI_U16                                        aid;
        tANI_U32                                        frameLen, nStatus;
        tANI_U8                                          *pBody;

        pHdr = SIR_MAC_BD_TO_MPDUHEADER( pBd );
        pBody = SIR_MAC_BD_TO_MPDUDATA( pBd );
        frameLen = SIR_MAC_BD_TO_PAYLOAD_LEN( pBd );

        pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable );
        if( pSta == NULL ) {
            limLog( pMac, LOGE,FL( "STA context not found - ignoring UpdateSM PSave Mode from " ));
            limPrintMacAddr( pMac, pHdr->sa, LOGW );
            return;
        }

        /**Unpack the received frame */
        nStatus = dot11fUnpackSMPowerSave( pMac, pBody, frameLen, &frmSMPower);

        if( DOT11F_FAILED( nStatus )) {
            limLog( pMac, LOGE, FL( "Failed to unpack and parse a Update SM Power (0x%08x, %d bytes):"),
                                                    nStatus, frameLen );
            PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
            return;
        }else if ( DOT11F_WARNED( nStatus ) ) {
            limLog(pMac, LOGW, FL( "There were warnings while unpacking a SMPower Save update (0x%08x, %d bytes):"),
                                nStatus, frameLen );
            PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
        }

        limLog(pMac, LOGW, FL("Received SM Power save Mode update Frame with PS_Enable:%d"
                            "PS Mode: %d"), frmSMPower.SMPowerModeSet.PowerSave_En,
                                                    frmSMPower.SMPowerModeSet.Mode);

        /** Update in the DPH Table about the Update in the SM Power Save mode*/
        if (frmSMPower.SMPowerModeSet.PowerSave_En && frmSMPower.SMPowerModeSet.Mode)
            state = eSIR_HT_MIMO_PS_DYNAMIC;
        else if ((frmSMPower.SMPowerModeSet.PowerSave_En) && (frmSMPower.SMPowerModeSet.Mode ==0))
            state = eSIR_HT_MIMO_PS_STATIC;
        else if ((frmSMPower.SMPowerModeSet.PowerSave_En == 0) && (frmSMPower.SMPowerModeSet.Mode == 0))
            state = eSIR_HT_MIMO_PS_NO_LIMIT;
        else {
            PELOGW(limLog(pMac, LOGW, FL("Received SM Power save Mode update Frame with invalid mode"));)
            return;
        }

        if (state == pSta->htMIMOPSState) {
            PELOGE(limLog(pMac, LOGE, FL("The PEER is already set in the same mode"));)
            return;
        }

        /** Update in the HAL Station Table for the Update of the Protection Mode */
        pSta->htMIMOPSState = state;
        limPostSMStateUpdate(pMac,pSta->staIndex, pSta->htMIMOPSState);

#endif
        
}

#if defined WLAN_FEATURE_VOWIFI

static void
__limProcessRadioMeasureRequest( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo ,tpPESession psessionEntry )
{
     tpSirMacMgmtHdr                pHdr;
     tDot11fRadioMeasurementRequest frm;
     tANI_U32                       frameLen, nStatus;
     tANI_U8                        *pBody;

     pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
     pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
     frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

     if( psessionEntry == NULL )
     {
          return;
     }

     /**Unpack the received frame */
     nStatus = dot11fUnpackRadioMeasurementRequest( pMac, pBody, frameLen, &frm );

     if( DOT11F_FAILED( nStatus )) {
          limLog( pMac, LOGE, FL( "Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
               return;
     }else if ( DOT11F_WARNED( nStatus ) ) {
          limLog(pMac, LOGW, FL( "There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
     }

     // Call rrm function to handle the request.

     rrmProcessRadioMeasurementRequest( pMac, pHdr->sa, &frm, psessionEntry );
}

static void
__limProcessLinkMeasurementReq( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo ,tpPESession psessionEntry )
{
     tpSirMacMgmtHdr               pHdr;
     tDot11fLinkMeasurementRequest frm;
     tANI_U32                      frameLen, nStatus;
     tANI_U8                       *pBody;

     pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
     pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
     frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

     if( psessionEntry == NULL )
     {
          return;
     }

     /**Unpack the received frame */
     nStatus = dot11fUnpackLinkMeasurementRequest( pMac, pBody, frameLen, &frm );

     if( DOT11F_FAILED( nStatus )) {
          limLog( pMac, LOGE, FL( "Failed to unpack and parse a Link Measure request (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
               return;
     }else if ( DOT11F_WARNED( nStatus ) ) {
          limLog(pMac, LOGW, FL( "There were warnings while unpacking a Link Measure request (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
     }

     // Call rrm function to handle the request.

     rrmProcessLinkMeasurementRequest( pMac, pRxPacketInfo, &frm, psessionEntry );

}

static void
__limProcessNeighborReport( tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo ,tpPESession psessionEntry )
{
     tpSirMacMgmtHdr               pHdr;
     tDot11fNeighborReportResponse *pFrm;
     tANI_U32                      frameLen, nStatus;
     tANI_U8                       *pBody;

     pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
     pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
     frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

     pFrm = vos_mem_malloc(sizeof(tDot11fNeighborReportResponse));
     if (NULL == pFrm)
     {
         limLog(pMac, LOGE, FL("Unable to allocate memory in __limProcessNeighborReport") );
         return;
     }

     if(psessionEntry == NULL)
     {
          vos_mem_free(pFrm);
          return;
     }

     /**Unpack the received frame */
     nStatus = dot11fUnpackNeighborReportResponse( pMac, pBody, frameLen,pFrm );

     if( DOT11F_FAILED( nStatus )) {
          limLog( pMac, LOGE, FL( "Failed to unpack and parse a Neighbor report response (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
          vos_mem_free(pFrm);
          return;
     }else if ( DOT11F_WARNED( nStatus ) ) {
          limLog(pMac, LOGW, FL( "There were warnings while unpacking a Neighbor report response (0x%08x, %d bytes):"),
                    nStatus, frameLen );
          PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
     }

     //Call rrm function to handle the request.
     rrmProcessNeighborReportResponse( pMac, pFrm, psessionEntry ); 
     
     vos_mem_free(pFrm);
}

#endif

#ifdef WLAN_FEATURE_AP_HT40_24G
static void
__limProcess2040bssCoexistenceActionFrame(tpAniSirGlobal pMac,
                  tANI_U16 sessionId, tANI_U8 *pRxPacketInfo,
                  tpPESession psessionEntry)
{
    tpSirMacMgmtHdr     pHdr;
    tANI_U8             *pBody , i;
    tANI_U32            frameLen, nStatus;
    tDot11fHT2040BSSCoexistenceManagementActionFrame *pFrm;
    tpSirHT2040CoexInfoInd pSirSmeHT2040CoexInfoInd = NULL;
    tANI_U16              length;
    tSirMsgQ              mmhMsg;
    tANI_U8               num_channelList;

    pHdr = WDA_GET_RX_MAC_HEADER( pRxPacketInfo );
    pBody = WDA_GET_RX_MPDU_DATA( pRxPacketInfo );
    frameLen = WDA_GET_RX_PAYLOAD_LEN( pRxPacketInfo );

    pFrm =
     vos_mem_malloc(sizeof(tDot11fHT2040BSSCoexistenceManagementActionFrame));

    if (NULL == pFrm)
    {
        limLog(pMac, LOGE, FL("Unable to allocate memory"));
        return;
    }

    if(psessionEntry == NULL)
    {
         vos_mem_free(pFrm);
         return;
    }

    /**Unpack the received frame */
    nStatus = dot11fUnpackHT2040BSSCoexistenceManagementActionFrame( pMac,
                                                     pBody, frameLen, pFrm );

    if( DOT11F_FAILED( nStatus ))
    {
         limLog( pMac, LOGE, FL( "Failed to unpack and parse a 20/40"
                                 "Coex Action Frame (0x%08x, %d bytes):"),
                                  nStatus, frameLen );
         PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
         vos_mem_free(pFrm);
         return;
    }
    else if ( DOT11F_WARNED( nStatus ))
    {
         limLog(pMac, LOGW, FL( "There were warnings while unpacking a"
                                " 20/40 Coex Action Frame (0x%08x, %d bytes):"),
                                nStatus, frameLen );
         PELOG2(sirDumpBuf( pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen );)
    }

    num_channelList = pFrm->HT2040BSSIntolerantReport.num_channelList;

    if (num_channelList > 0)
    {
        length = (sizeof(tSirHT2040CoexInfoInd) - sizeof(tANI_U8) +
                   (num_channelList * sizeof(tANI_U8)));
    }
    else
        length = sizeof(tSirHT2040CoexInfoInd);

    limLog(pMac, LOGW,FL("tSirHT2040CoexInfoInd: Length: %d"),length);

    pSirSmeHT2040CoexInfoInd = vos_mem_malloc(length);

    if (NULL == pSirSmeHT2040CoexInfoInd)
    {
        limLog(pMac, LOGP,
               FL("AllocateMemory failed for eWNI_SME_2040_COEX_IND"));
         vos_mem_free(pFrm);
        return;
    }

    vos_mem_set((void*)pSirSmeHT2040CoexInfoInd, length, 0);

    pSirSmeHT2040CoexInfoInd->messageType = eWNI_SME_2040_COEX_IND;
    pSirSmeHT2040CoexInfoInd->sessionId = sessionId;
    pSirSmeHT2040CoexInfoInd->length = length;

    if (pFrm->HT2040BSSCoexistence.present)
    {

        limLog(pMac, LOGW, FL("infoRequest: %d fortyMHzIntolerant: %d"
                           " twentyMHzBssWidthReq: %d obssScanExemptionReq: %d"
                           " obssScanExemptionGrant: %d "),
                           pFrm->HT2040BSSCoexistence.infoRequest,
                           pFrm->HT2040BSSCoexistence.fortyMHzIntolerant,
                           pFrm->HT2040BSSCoexistence.twentyMHzBssWidthReq,
                           pFrm->HT2040BSSCoexistence.obssScanExemptionReq,
                           pFrm->HT2040BSSCoexistence.obssScanExemptionGrant);

       pSirSmeHT2040CoexInfoInd->HT40MHzIntolerant =
                             pFrm->HT2040BSSCoexistence.fortyMHzIntolerant;
       pSirSmeHT2040CoexInfoInd->HT20MHzBssWidthReq =
                             pFrm->HT2040BSSCoexistence.twentyMHzBssWidthReq;
    }

    if (pFrm->HT2040BSSIntolerantReport.present)
    {
       limLog(pMac, LOGW, FL("operatingClass: %d  num_channelList: %d "),
                         pFrm->HT2040BSSIntolerantReport.operatingClass,
                         num_channelList);

       if (num_channelList > 0)
       {
           vos_mem_zero(pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport,
                         num_channelList);
           vos_mem_copy(pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport,
                               pFrm->HT2040BSSIntolerantReport.channelList,
                               num_channelList);

           pSirSmeHT2040CoexInfoInd->channel_num = num_channelList;
       }

       for(i=0; i < num_channelList; i++)
       {
           limLog(pMac, LOGW, FL("Channel : %d "),
                        pSirSmeHT2040CoexInfoInd->HT2040BssIntoChanReport[i]);
       }
    }

    mmhMsg.type = eWNI_SME_2040_COEX_IND;
    mmhMsg.bodyptr = pSirSmeHT2040CoexInfoInd;
    mmhMsg.bodyval = 0;
    limLog(pMac, LOGW, FL("Posting eWNI_SME_2040_COEX_IND Message to SME "));
    limSysProcessMmhMsgApi(pMac, &mmhMsg, ePROT);

    vos_mem_free(pFrm);
}
#endif

#ifdef WLAN_FEATURE_11W
/**
 * limProcessSAQueryRequestActionFrame
 *
 *FUNCTION:
 * This function is called by limProcessActionFrame() upon
 * SA query request Action frame reception.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - Handle to the Rx packet info
 * @param  psessionEntry - PE session entry
 *
 * @return None
 */
static void __limProcessSAQueryRequestActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession psessionEntry)
{
    tpSirMacMgmtHdr     pHdr;
    tANI_U8             *pBody;
    tANI_U8             transId[2];
    uint32_t            frame_len;

    /* Prima  --- Below Macro not available in prima 
       pHdr = SIR_MAC_BD_TO_MPDUHEADER(pBd);
       pBody = SIR_MAC_BD_TO_MPDUDATA(pBd); */

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frame_len = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);

    if (frame_len < sizeof(struct sDot11fSaQueryReq)) {
         VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_ERROR,
                   ("Invalid frame length"));
         return;
    }
    /* If this is an unprotected SA Query Request, then ignore it. */
    if (pHdr->fc.wep == 0)
        return;

    /*Extract 11w trsansId from SA query request action frame
      In SA query response action frame we will send same transId
      In SA query request action frame:
      Category       : 1 byte
      Action         : 1 byte
      Transaction ID : 2 bytes */
    vos_mem_copy(&transId[0], &pBody[2], 2);

    //Send 11w SA query response action frame
    if (limSendSaQueryResponseFrame(pMac,
                              transId,
                              pHdr->sa,psessionEntry) != eSIR_SUCCESS)
    {
        PELOGE(limLog(pMac, LOGE, FL("fail to send SA query response action frame."));)
        return;
    }
}

/**
 * __limProcessSAQueryResponseActionFrame
 *
 *FUNCTION:
 * This function is called by limProcessActionFrame() upon
 * SA query response Action frame reception.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - Handle to the Rx packet info
 * @param  psessionEntry - PE session entry
 * @return None
 */
static void __limProcessSAQueryResponseActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tpPESession psessionEntry)
{
    tpSirMacMgmtHdr     pHdr;
    tANI_U8             *pBody;
    tpDphHashNode       pSta;
    tANI_U16            aid;
    tANI_U16            transId;
    tANI_U8             retryNum;
    uint32_t            frame_len;

    pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
    pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    frame_len = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
    VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO,
                         ("SA Query Response received...")) ;

    if (frame_len < sizeof(struct sDot11fSaQueryRsp)) {
        VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_ERROR,
                  ("Invalid frame length"));
        return;
    }
    /* When a station, supplicant handles SA Query Response.
       Forward to SME to HDD to wpa_supplicant. */
    if (eLIM_STA_ROLE == psessionEntry->limSystemRole)
    {
        limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                    pRxPacketInfo, psessionEntry,
                                    WDA_GET_RX_RSSI_DB(pRxPacketInfo),
                                    RXMGMT_FLAG_NONE);
        return;
    }

    /* If this is an unprotected SA Query Response, then ignore it. */
    if (pHdr->fc.wep == 0)
        return;

    pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
    if (NULL == pSta)
        return;

    limLog(pMac, LOG1,
           FL("SA Query Response source addr - %0x:%0x:%0x:%0x:%0x:%0x"),
           pHdr->sa[0], pHdr->sa[1], pHdr->sa[2], pHdr->sa[3],
           pHdr->sa[4], pHdr->sa[5]);
    limLog(pMac, LOG1,
           FL("SA Query state for station - %d"), pSta->pmfSaQueryState);

    if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState)
        return;

    /* Extract 11w trsansId from SA query reponse action frame
       In SA query response action frame:
          Category       : 1 byte
          Action         : 1 byte
          Transaction ID : 2 bytes */
    vos_mem_copy(&transId, &pBody[2], 2);

    /* If SA Query is in progress with the station and the station
       responds then the association request that triggered the SA
       query is from a rogue station, just go back to initial state. */
    for (retryNum = 0; retryNum <= pSta->pmfSaQueryRetryCount; retryNum++)
        if (transId == pSta->pmfSaQueryStartTransId + retryNum)
        {
            limLog(pMac, LOG1,
                   FL("Found matching SA Query Request - transaction ID %d"), transId);
            tx_timer_deactivate(&pSta->pmfSaQueryTimer);
            pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS;
            break;
        }
}
#endif

#ifdef WLAN_FEATURE_11W
/**
 * limDropUnprotectedActionFrame
 *
 *FUNCTION:
 * This function checks if an Action frame should be dropped since it is
 * a Robust Managment Frame, it is unprotected, and it is received on a
 * connection where PMF is enabled.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Global MAC structure
 * @param  psessionEntry - PE session entry
 * @param  pHdr - Frame header
 * @param  category - Action frame category
 * @return TRUE if frame should be dropped
 */

static tANI_BOOLEAN
limDropUnprotectedActionFrame (tpAniSirGlobal pMac, tpPESession psessionEntry,
                               tpSirMacMgmtHdr pHdr, tANI_U8 category)
{
    tANI_U16 aid;
    tpDphHashNode pStaDs;
    tANI_BOOLEAN rmfConnection = eANI_BOOLEAN_FALSE;

    if ((psessionEntry->limSystemRole == eLIM_AP_ROLE) ||
        (psessionEntry->limSystemRole == eLIM_BT_AMP_AP_ROLE))
    {
        pStaDs = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
        if (pStaDs != NULL)
            if (pStaDs->rmfEnabled)
                rmfConnection = eANI_BOOLEAN_TRUE;
    }
    else if (psessionEntry->limRmfEnabled)
        rmfConnection = eANI_BOOLEAN_TRUE;

    if (rmfConnection && (pHdr->fc.wep == 0))
    {
        PELOGE(limLog(pMac, LOGE, FL("Dropping unprotected Action category %d frame "
                                     "since RMF is enabled."), category);)
        return eANI_BOOLEAN_TRUE;
    }
    else
        return eANI_BOOLEAN_FALSE;
}
#endif

/**
 * limProcessActionFrame
 *
 *FUNCTION:
 * This function is called by limProcessMessageQueue() upon
 * Action frame reception.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pRxPacketInfo - A pointer to packet info structure
 * @return None
 */

void
limProcessActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
    tANI_U8 *pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
    tpSirMacActionFrameHdr pActionHdr = (tpSirMacActionFrameHdr) pBody;
    tANI_U8 frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
    tpSirMacMgmtHdr pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);

    if (frameLen < sizeof(*pActionHdr)) {
	limLog(pMac, LOGE,
	       FL("frame_len %d less than Action Frame Hdr size"),
	        frameLen);
	return;
    }

#ifdef WLAN_FEATURE_11W
    if (lim_is_robust_mgmt_action_frame(pActionHdr->category) &&
        limDropUnprotectedActionFrame(pMac, psessionEntry, pHdr,
                                      pActionHdr->category)) {
        limLog(pMac, LOGE,
               FL("Don't send unprotect action frame to upper layer categ %d "),
               pActionHdr->category);
        return;
    }
#endif

    switch (pActionHdr->category)
    {

        /*
         * WARNING: If you add Action frame category case here, set the
         * corresponding bit to 1 in sme_set_allowed_action_frames() for
         * the FW to hand over that frame to host without dropping itself
         */
        case SIR_MAC_ACTION_QOS_MGMT:
            if ( (psessionEntry->limQosEnabled) ||
                  (pActionHdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE) )
            {
                switch (pActionHdr->actionID)
                {
                    case SIR_MAC_QOS_ADD_TS_REQ:
                        __limProcessAddTsReq(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                        break;

                    case SIR_MAC_QOS_ADD_TS_RSP:
                        __limProcessAddTsRsp(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                        break;

                    case SIR_MAC_QOS_DEL_TS_REQ:
                        __limProcessDelTsReq(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                        break;

                    case SIR_MAC_QOS_MAP_CONFIGURE:
                        __limProcessQosMapConfigureFrame(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                    break;
                    default:
                        limLog(pMac, LOG1,
                         FL("Qos action %d not handled"),
                         pActionHdr->actionID);
                        break;
                }
                break ;
            }

           break;

        case SIR_MAC_ACTION_SPECTRUM_MGMT:
            switch (pActionHdr->actionID)
            {
#ifdef ANI_SUPPORT_11H
                case SIR_MAC_ACTION_MEASURE_REQUEST_ID:
                    if(psessionEntry->lim11hEnable)
                    {
                        __limProcessMeasurementRequestFrame(pMac, pRxPacketInfo);
                    }
                    break;

                case SIR_MAC_ACTION_TPC_REQUEST_ID:
                    if ((psessionEntry->limSystemRole == eLIM_STA_ROLE) ||
                        (pessionEntry->limSystemRole == eLIM_AP_ROLE))
                    {
                        if(psessionEntry->lim11hEnable)
                        {
                            __limProcessTpcRequestFrame(pMac, pRxPacketInfo);
                        }
                    }
                    break;

#endif
                case SIR_MAC_ACTION_CHANNEL_SWITCH_ID:
                    if (psessionEntry->limSystemRole == eLIM_STA_ROLE)
                    {
                        __limProcessChannelSwitchActionFrame(pMac, pRxPacketInfo,psessionEntry);
                    }
                    break;
                default:
                    limLog(pMac, LOG1,
                      FL("Spectrum mgmt action id %d not handled"),
                      pActionHdr->actionID);
                    break;
            }
            break;

        case SIR_MAC_ACTION_WME:
            if (! psessionEntry->limWmeEnabled)
            {
                limLog(pMac, LOGW, FL("WME mode disabled - dropping action frame %d"),
                       pActionHdr->actionID);
                break;
            }
            switch(pActionHdr->actionID)
            {
                case SIR_MAC_QOS_ADD_TS_REQ:
                    __limProcessAddTsReq(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                    break;

                case SIR_MAC_QOS_ADD_TS_RSP:
                    __limProcessAddTsRsp(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                    break;

                case SIR_MAC_QOS_DEL_TS_REQ:
                    __limProcessDelTsReq(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                    break;

                case SIR_MAC_QOS_MAP_CONFIGURE:
                    __limProcessQosMapConfigureFrame(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                    break;

                default:
                    limLog(pMac, LOG1, FL("WME action %d not handled"),
                                                  pActionHdr->actionID);
                    break;
            }
            break;

        case SIR_MAC_ACTION_BLKACK:
            // Determine the "type" of BA Action Frame
            switch(pActionHdr->actionID)
            {
              case SIR_MAC_BLKACK_ADD_REQ:
                __limProcessAddBAReq( pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                break;

              case SIR_MAC_BLKACK_ADD_RSP:
                __limProcessAddBARsp( pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                break;

              case SIR_MAC_BLKACK_DEL:
                __limProcessDelBAReq( pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
                break;

              default:
                break;
            }

            break;
    case SIR_MAC_ACTION_HT:
        /** Type of HT Action to be performed*/
        switch(pActionHdr->actionID) {
        case SIR_MAC_SM_POWER_SAVE:
            __limProcessSMPowerSaveUpdate(pMac, (tANI_U8 *) pRxPacketInfo,psessionEntry);
            break;
        default:
            limLog(pMac, LOG1,
                   FL("Action ID %d not handled in HT Action category"),
                   pActionHdr->actionID);
            break;
        }
        break;

    case SIR_MAC_ACTION_WNM:
    {
        PELOGE(limLog(pMac, LOG1, FL("WNM Action category %d action %d."),
                                pActionHdr->category, pActionHdr->actionID);)
        switch (pActionHdr->actionID)
        {
            case SIR_MAC_WNM_BSS_TM_QUERY:
            case SIR_MAC_WNM_BSS_TM_REQUEST:
            case SIR_MAC_WNM_BSS_TM_RESPONSE:
            case SIR_MAC_WNM_NOTIF_REQUEST:
            case SIR_MAC_WNM_NOTIF_RESPONSE:
            {
               tANI_S8 rssi = WDA_GET_RX_RSSI_DB(pRxPacketInfo);
               /* Forward to the SME to HDD to wpa_supplicant */
               limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                       pRxPacketInfo,
                                       psessionEntry, rssi, RXMGMT_FLAG_NONE);
               break;
            }
        }
        break;
    }
#if defined WLAN_FEATURE_VOWIFI
    case SIR_MAC_ACTION_RRM:
        /* Ignore RRM measurement request until DHCP is set */
        if(pMac->rrm.rrmPEContext.rrmEnable &&
           pMac->roam.roamSession[psessionEntry->smeSessionId].dhcp_done)
        {
            switch(pActionHdr->actionID) {
                case SIR_MAC_RRM_RADIO_MEASURE_REQ:
                    __limProcessRadioMeasureRequest( pMac, (tANI_U8 *) pRxPacketInfo, psessionEntry );
                    break;
                case SIR_MAC_RRM_LINK_MEASUREMENT_REQ:
                    __limProcessLinkMeasurementReq( pMac, (tANI_U8 *) pRxPacketInfo, psessionEntry );
                    break;
                case SIR_MAC_RRM_NEIGHBOR_RPT:   
                    __limProcessNeighborReport( pMac, (tANI_U8*) pRxPacketInfo, psessionEntry );
                    break;
                default:
                    limLog( pMac, LOG1, FL("Action ID %d not handled in RRM"),
                         pActionHdr->actionID);
                    break;

            }
        }
        else
        {
            // Else we will just ignore the RRM messages.
            limLog( pMac, LOG1,
              FL("RRM Action frame ignored as rrmEnable is %d or DHCP not completed %d"),
              pMac->rrm.rrmPEContext.rrmEnable,
              pMac->roam.roamSession[psessionEntry->smeSessionId].dhcp_done);
        }
        break;
#endif
#if  defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) \
    || defined (WLAN_FEATURE_RMC)
        case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY:
            {
              tpSirMacVendorSpecificFrameHdr pVendorSpecific = (tpSirMacVendorSpecificFrameHdr) pActionHdr;

		if(frameLen < sizeof(*pVendorSpecific)) {
			limLog(pMac, LOGE,
			       FL("frame len %d less than Vendor Specific Hdr len"), frameLen);
			break;
		  }

		if ((eLIM_STA_IN_IBSS_ROLE != psessionEntry->limSystemRole) &&
		    (VOS_TRUE == vos_mem_compare(psessionEntry->selfMacAddr,
		    &pHdr->da[0], sizeof(tSirMacAddr)))) {
			limLog(pMac, LOGW, FL("Received Vendor specific action frame, OUI %x %x %x"),
			       pVendorSpecific->Oui[0], pVendorSpecific->Oui[1], pVendorSpecific->Oui[2]);
                 /* Forward to the SME to HDD to wpa_supplicant */
                 // type is ACTION
                  limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                         pRxPacketInfo,
                                         psessionEntry, 0, RXMGMT_FLAG_NONE);
              }
#if defined (WLAN_FEATURE_RMC)
		else if (((VOS_TRUE == vos_mem_compare(SIR_MAC_RMC_MCAST_ADDRESS,
                    &pHdr->da[0], sizeof(tSirMacAddr))) ||
                   (VOS_TRUE == vos_mem_compare(psessionEntry->selfMacAddr,
                     &pHdr->da[0], sizeof(tSirMacAddr)))) &&
                   vos_mem_compare(pVendorSpecific->Oui, SIR_MAC_RMC_OUI, 3))
              {
                  tANI_U8 MagicCode[] =
                         { 0x4f, 0x58, 0x59, 0x47, 0x45, 0x4e };
                  tpSirMacIbssExtNetworkFrameHdr pIbssExtHdr =
                             (tpSirMacIbssExtNetworkFrameHdr) pActionHdr;

                  if (vos_mem_compare(pIbssExtHdr->MagicCode,
                      MagicCode, sizeof(MagicCode)) &&
                      pIbssExtHdr->version == SIR_MAC_RMC_VER )
                  {
                      switch (pIbssExtHdr->actionID)
                      {
                          default:
                              PELOGE(limLog(pMac, LOGE,
                                 FL("Action RMC actionID %d not handled"),
                                     pIbssExtHdr->actionID);)
                              break;
                          case SIR_MAC_RMC_RULER_INFORM_SELECTED:
                              limLog(pMac, LOG1,
                                 FL("Action RMC RULER_INFORM_SELECTED."));
                              limProcessRMCMessages(pMac,
                                 eLIM_RMC_OTA_RULER_INFORM_SELECTED,
                                 (tANI_U32 *)pRxPacketInfo);
                              break;
                          case SIR_MAC_RMC_RULER_INFORM_CANCELLED:
                              limLog(pMac, LOG1,
                                 FL("Action RMC RULER_INFORM_CANCELLED."));
                              limProcessRMCMessages(pMac,
                                 eLIM_RMC_OTA_RULER_INFORM_CANCELLED,
                                 (tANI_U32 *)pRxPacketInfo);
                              break;
                      }
                  }
                  else
                  {
                      limLog( pMac, LOG1,
                         FL("Dropping the vendor specific action frame in IBSS "
                             "mode because of Ibss Ext Magic mismatch "
                             MAC_ADDRESS_STR " or Version mismatch = %d"),
                             MAC_ADDR_ARRAY(pIbssExtHdr->MagicCode),
                             pIbssExtHdr->version );
                  }
              }
#endif /* WLAN_FEATURE_RMC */
           }
           break;
#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE ||
          FEATURE_WLAN_LFR || WLAN_FEATURE_RMC */
    case SIR_MAC_ACTION_PUBLIC_USAGE:
        switch(pActionHdr->actionID) {
        case SIR_MAC_ACTION_VENDOR_SPECIFIC:
            {
              tpSirMacVendorSpecificPublicActionFrameHdr pPubAction = (tpSirMacVendorSpecificPublicActionFrameHdr) pActionHdr;
              tANI_U8 P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 };

	      if (frameLen < sizeof(*pActionHdr)) {
			limLog(pMac, LOG1,
				FL("Received action frame of invalid len %d"), frameLen);
			break;
	      }

              //Check if it is a P2P public action frame.
              if (vos_mem_compare(pPubAction->Oui, P2POui, 4))
              {
                 /* Forward to the SME to HDD to wpa_supplicant */
                 // type is ACTION
                 limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                        pRxPacketInfo,
                                        psessionEntry,
                                        WDA_GET_RX_RSSI_DB(pRxPacketInfo),
                                        RXMGMT_FLAG_NONE);
              }
              else
              {
                 limLog( pMac, LOG1,
                    FL("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"),
                      pPubAction->Oui[0], pPubAction->Oui[1],
                      pPubAction->Oui[2], pPubAction->Oui[3] );
              }
           }
            break;
#ifdef WLAN_FEATURE_AP_HT40_24G
        case SIR_MAC_ACTION_2040_BSS_COEXISTENCE:
            {
               if (pMac->roam.configParam.apHT40_24GEnabled)
               {
                   limLog( pMac, LOGW, FL("Public Action 20/40 BSS"
                                  "Coexistence Management frame"));

                   __limProcess2040bssCoexistenceActionFrame(pMac,
                       psessionEntry->smeSessionId, (tANI_U8 *) pRxPacketInfo,
                       psessionEntry);
               }
               break;
            }
#endif
#ifdef FEATURE_WLAN_TDLS
           case SIR_MAC_TDLS_DIS_RSP:
           {
               tANI_S8             rssi;

               rssi = WDA_GET_RX_RSSI_DB(pRxPacketInfo);
               VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO, 
                                    ("Public Action TDLS Discovery RSP ..")) ;
               limSendSmeMgmtFrameInd(pMac, psessionEntry->smeSessionId,
                                      pRxPacketInfo,
                                      psessionEntry, rssi, RXMGMT_FLAG_NONE);
           }
               break;
#endif
           case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID:
               if (psessionEntry->limSystemRole == eLIM_STA_ROLE)
               {
                   lim_process_ecsa_action_frame(pMac,
                                                 pRxPacketInfo, psessionEntry);
               }
               break;
        default:
            limLog(pMac, LOG1, FL("Unhandled public action frame -- %x "),
                             pActionHdr->actionID);
            break;
        }
        break;

#ifdef WLAN_FEATURE_11W
    case SIR_MAC_ACTION_SA_QUERY:
    {
        PELOGE(limLog(pMac, LOG1, FL("SA Query Action category %d action %d."), pActionHdr->category, pActionHdr->actionID);)
        switch (pActionHdr->actionID)
        {
            case  SIR_MAC_SA_QUERY_REQ:
                /**11w SA query request action frame received**/
                /* Respond directly to the incoming request in LIM */
                __limProcessSAQueryRequestActionFrame(pMac,(tANI_U8*) pRxPacketInfo, psessionEntry );
                break;
            case  SIR_MAC_SA_QUERY_RSP:
                /**11w SA query response action frame received**/
                /* Handle based on the current SA Query state */
                __limProcessSAQueryResponseActionFrame(pMac,(tANI_U8*) pRxPacketInfo, psessionEntry );
                break;
            default:
                break;
        }
        break;
     }
#endif
#ifdef WLAN_FEATURE_11AC
    case SIR_MAC_ACTION_VHT:
    {
        if (psessionEntry->vhtCapability)
        {
            switch (pActionHdr->actionID)
            {
                case  SIR_MAC_VHT_OPMODE_NOTIFICATION:
                    __limProcessOperatingModeActionFrame(pMac,pRxPacketInfo,psessionEntry);                
                break;
                default:
                break;
            }
        }
        break;
    }
#endif
    default:
       limLog(pMac, LOG1,
         FL("Action category %d not handled"), pActionHdr->category);
       break;
    }
}

/**
 * limProcessActionFrameNoSession
 *
 *FUNCTION:
 * This function is called by limProcessMessageQueue() upon
 * Action frame reception and no session.
 * Currently only public action frames can be received from
 * a non-associated station.
 *
 *LOGIC:
 *
 *ASSUMPTIONS:
 *
 *NOTE:
 *
 * @param  pMac - Pointer to Global MAC structure
 * @param  *pBd - A pointer to Buffer descriptor + associated PDUs
 * @return None
 */

void
limProcessActionFrameNoSession(tpAniSirGlobal pMac, tANI_U8 *pBd)
{
   tANI_U8 *pBody = WDA_GET_RX_MPDU_DATA(pBd);
   tpSirMacVendorSpecificPublicActionFrameHdr pActionHdr = (tpSirMacVendorSpecificPublicActionFrameHdr) pBody;
   tANI_U32 frameLen = WDA_GET_RX_PAYLOAD_LEN(pBd);

   limLog( pMac, LOG1, "Received a Action frame -- no session");

   if (frameLen < sizeof(*pActionHdr)) {
	limLog(pMac, LOGE,
	      FL("Received action frame of invalid len %d"), frameLen);
	return;
   }

   switch ( pActionHdr->category )
   {
      case SIR_MAC_ACTION_PUBLIC_USAGE:
         switch(pActionHdr->actionID) {
            case SIR_MAC_ACTION_VENDOR_SPECIFIC:
              {
                tANI_U8 P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 };

                //Check if it is a P2P public action frame.
                if (vos_mem_compare(pActionHdr->Oui, P2POui, 4))
                {
                  /* Forward to the SME to HDD to wpa_supplicant */
                  // type is ACTION
                  limSendSmeMgmtFrameInd(pMac, 0, pBd, NULL,
                                         WDA_GET_RX_RSSI_DB(pBd),
                                         RXMGMT_FLAG_NONE);
                }
                else
                {
                  limLog( pMac, LOG1,
                     FL("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"),
                      pActionHdr->Oui[0], pActionHdr->Oui[1],
                      pActionHdr->Oui[2], pActionHdr->Oui[3]);
                }
              }
               break;
            default:
               limLog(pMac, LOG1,
                FL("Unhandled public action frame -- %x "), pActionHdr->actionID);
                  break;
         }
         break;
      default:
         limLog(pMac, LOG1,
          FL("Unhandled action frame without session -- %x "),
                                    pActionHdr->category);
         break;

   }
}
