blob: c8c4d97fa31bbb50fc6088f66044b64b444e7ce8 [file] [log] [blame]
/*
* Copyright (c) 2012-2014, 2016-2017 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 "wni_cfg.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"
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
#include "eseApi.h"
#endif
#include "wlan_qct_wda.h"
#include "pmmApi.h"
#include "wma.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;
tANI_U8 isSessionPowerActive = false;
psessionEntry = peFindSessionBySessionId( pMac , sessionId );
if( NULL == psessionEntry )
{
limLog(pMac, LOGE, FL("Session %d not active"), sessionId);
return;
}
if(psessionEntry->ftPEContext.pFTPreAuthReq)
{
limLog(pMac, LOGE,
FL("Avoid Switch Channel req during pre auth"));
return;
}
/*
* Sme Session is passed in limSendSmePreChannelSwitchInd
* so that it can be passed till sme to request full power for
* particular session
*/
if(pMac->psOffloadEnabled)
{
isSessionPowerActive = pmmPsOffloadIsActive(pMac, psessionEntry);
}
else
{
isSessionPowerActive = limIsSystemInActiveState(pMac);
}
PELOG1(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(!isSessionPowerActive)
{
/* Request Full Power */
limSendSmePreChannelSwitchInd(pMac, psessionEntry);
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(isSessionPowerActive)
{
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, psessionEntry);
}
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)
{
PELOG1(limLog(pMac, LOG1, FL("Starting the channel switch"));)
/*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) ||
psessionEntry->csaOffloadEnable)
{
limLog(pMac, LOGW, FL("Ignoring channel switch on session %d"), psessionEntry->peSessionId);
return eSIR_SUCCESS;
}
/* 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);
PELOG3(limLog(pMac, LOG3, 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)))
{
/* 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
PELOG3(limLog(pMac, LOG3, 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_ele.
secondaryChannelOffset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) ||
(pChannelSwitchFrame->sec_chan_offset_ele.
secondaryChannelOffset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)) {
psessionEntry->gLimChannelSwitch.state =
eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
psessionEntry->gLimChannelSwitch.secondarySubBand =
pChannelSwitchFrame->sec_chan_offset_ele.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_ele.present &&
((pChannelSwitchFrame->sec_chan_offset_ele.
secondaryChannelOffset ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY) ||
(pChannelSwitchFrame->sec_chan_offset_ele.
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_ele.
secondaryChannelOffset,
pChannelSwitchFrame->WiderBWChanSwitchAnn.
newCenterChanFreq0,
psessionEntry);
}
}
}
#endif
}
}
else
{
PELOG1(limLog(pMac, LOG1, FL("LIM: Received action frame not from our BSS, dropping..."));)
}
if (eSIR_SUCCESS != limStartChannelSwitch(pMac, psessionEntry))
{
PELOG1(limLog(pMac, LOG1, FL("Could not start channel switch"));)
}
vos_mem_free(pChannelSwitchFrame);
return;
} /*** end limProcessChannelSwitchActionFrame() ***/
/**
* lim_process_ext_channel_switch_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.
*
* Return: void
*/
static void
lim_process_ext_channel_switch_action_frame(tpAniSirGlobal mac_ctx,
uint8_t *rx_packet_info, tpPESession session_entry)
{
tpSirMacMgmtHdr hdr;
uint8_t *body;
tDot11fext_channel_switch_action_frame *ext_channel_switch_frame;
uint32_t frame_len;
uint32_t status;
uint8_t target_channel;
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 EXT Channel switch action frame"));
ext_channel_switch_frame =
vos_mem_malloc(sizeof(*ext_channel_switch_frame));
if (NULL == ext_channel_switch_frame) {
limLog(mac_ctx, LOGE, FL("AllocateMemory failed"));
return;
}
/* Unpack channel switch frame */
status = dot11fUnpackext_channel_switch_action_frame(mac_ctx,
body, frame_len, ext_channel_switch_frame);
if (DOT11F_FAILED(status)) {
limLog( mac_ctx, LOGE,
FL( "Failed to parse CHANSW action frame (0x%08x, len %d):"),
status, frame_len);
vos_mem_free(ext_channel_switch_frame);
return;
} else if (DOT11F_WARNED(status)) {
limLog( mac_ctx, LOGW,
FL( "There were warnings while unpacking CHANSW Request (0x%08x, %d bytes):"),
status, frame_len);
}
target_channel =
ext_channel_switch_frame->ext_chan_switch_ann_action.new_channel;
/* Free ext_channel_switch_frame here as its no longer needed */
vos_mem_free(ext_channel_switch_frame);
/*
* Now, validate if channel change is required for the passed
* channel and if is valid in the current regulatory domain,
* and no concurrent session is running.
*/
if (!((session_entry->currentOperChannel != target_channel) &&
((vos_nv_getChannelEnabledState(target_channel)
== NV_CHANNEL_ENABLE) ||
(vos_nv_getChannelEnabledState(target_channel) == NV_CHANNEL_DFS &&
!vos_concurrent_open_sessions_running())))) {
limLog(mac_ctx, LOGE, FL(" Channel %d is not valid"),
target_channel);
return;
}
if ((eLIM_STA_ROLE == session_entry->limSystemRole) || \
(eLIM_P2P_DEVICE_CLIENT == session_entry->limSystemRole)) {
struct sir_sme_ext_cng_chan_ind *ext_cng_chan_ind;
tSirMsgQ mmh_msg;
ext_cng_chan_ind = vos_mem_malloc(sizeof(*ext_cng_chan_ind));
if (NULL == ext_cng_chan_ind) {
limLog(mac_ctx, LOGP,
FL("AllocateMemory failed for ext_cng_chan_ind"));
return;
}
vos_mem_zero(ext_cng_chan_ind,
sizeof(*ext_cng_chan_ind));
ext_cng_chan_ind->session_id=
session_entry->smeSessionId;
/* No need to extract op mode as BW will be decided in
* in SAP FSM depending on previous BW.
*/
ext_cng_chan_ind->new_channel = target_channel;
mmh_msg.type = eWNI_SME_EXT_CHANGE_CHANNEL_IND;
mmh_msg.bodyptr = ext_cng_chan_ind;
mmh_msg.bodyval = 0;
limSysProcessMmhMsgApi(mac_ctx, &mmh_msg, ePROT);
}
return;
} /*** end lim_process_ext_channel_switch_action_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_U8 cbMode;
tANI_U8 ch_bw = 0;
tANI_U8 skip_opmode_update = false;
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)
cbMode = pMac->roam.configParam.channelBondingMode24GHz;
else
cbMode = 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 == cbMode) {
limLog(pMac, LOGW, FL("channel bonding disabled"));
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) {
limLog(pMac, LOGE, FL("Station context not found"));
goto end;
}
operMode = pSta->vhtSupportedChannelWidthSet ? eHT_CHANNEL_WIDTH_80MHZ : pSta->htSupportedChannelWidthSet ? eHT_CHANNEL_WIDTH_40MHZ: eHT_CHANNEL_WIDTH_20MHZ;
if ((operMode == eHT_CHANNEL_WIDTH_80MHZ) &&
(pOperatingModeframe->OperatingMode.chanWidth >
eHT_CHANNEL_WIDTH_80MHZ))
skip_opmode_update = true;
if (!skip_opmode_update &&
(operMode != pOperatingModeframe->OperatingMode.chanWidth))
{
uint32_t fw_vht_ch_wd = wma_get_vht_ch_width();
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) &&
(fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) {
pSta->vhtSupportedChannelWidthSet =
WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ;
ch_bw = eHT_CHANNEL_WIDTH_160MHZ;
} else if(pOperatingModeframe->OperatingMode.chanWidth >=
eHT_CHANNEL_WIDTH_80MHZ) {
pSta->vhtSupportedChannelWidthSet = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ;
ch_bw = eHT_CHANNEL_WIDTH_80MHZ;
} else if(pOperatingModeframe->OperatingMode.chanWidth ==
eHT_CHANNEL_WIDTH_40MHZ) {
pSta->vhtSupportedChannelWidthSet =
WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ;
pSta->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ;
ch_bw = 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;
ch_bw = eHT_CHANNEL_WIDTH_20MHZ;
}
limCheckVHTOpModeChange(pMac, psessionEntry,
ch_bw, MODE_MAX,
pSta->staIndex, pHdr->sa);
}
if (pSta->vhtSupportedRxNss != (pOperatingModeframe->OperatingMode.rxNSS + 1)) {
pSta->vhtSupportedRxNss = pOperatingModeframe->OperatingMode.rxNSS + 1;
limSetNssChange( pMac, psessionEntry, pSta->vhtSupportedRxNss,
pSta->staIndex, pHdr->sa);
}
end:
vos_mem_free(pOperatingModeframe);
return;
}
static void
__limProcessGidManagementActionFrame(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo,tpPESession psessionEntry)
{
tpSirMacMgmtHdr pHdr;
tANI_U8 *pBody;
tDot11fVHTGidManagementActionFrame *pGidManagementframe;
tANI_U32 frameLen;
tANI_U32 nStatus;
tpDphHashNode pSta;
tANI_U16 aid;
tANI_U32 membership = 0;
tANI_U32 userPosition = 0;
tANI_U32 *pMemLower;
tANI_U32 *pMemUpper;
tANI_U32 *pMemCur;
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
PELOG3(limLog(pMac, LOG3, FL("Received GID Management action frame"));)
pGidManagementframe = vos_mem_malloc(sizeof(*pGidManagementframe));
if (NULL == pGidManagementframe)
{
limLog(pMac, LOGE,
FL("AllocateMemory failed"));
return;
}
/* Unpack Gid Mangement Action frame */
nStatus = dot11fUnpackVHTGidManagementActionFrame(pMac, pBody, frameLen, pGidManagementframe);
if( DOT11F_FAILED( nStatus ))
{
limLog( pMac, LOGE,
FL( "Failed to unpack and parse an GidManagement Action frame (0x%08x, %d bytes):"),
nStatus,
frameLen);
vos_mem_free(pGidManagementframe);
return;
}
else if(DOT11F_WARNED( nStatus ))
{
limLog( pMac, LOGW,
FL( "There were warnings while unpacking an GidManagement Action frame (0x%08x, %d bytes):"),
nStatus,
frameLen);
}
pSta = dphLookupHashEntry(pMac, pHdr->sa, &aid, &psessionEntry->dph.dphHashTable);
if (pSta != NULL) {
limLog(pMac, LOGE,
FL(" received Gid Management Action Frame , staIdx = %d"),
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]);
pMemLower = (tANI_U32 *)pGidManagementframe->VhtMembershipStatusArray.membershipStatusArray;
pMemUpper = (tANI_U32 *)&pGidManagementframe->VhtMembershipStatusArray.membershipStatusArray[4];
if (*pMemLower && *pMemUpper)
{
limLog(pMac, LOGE,
FL(" received frame with multiple group ID set, staIdx = %d"),
pSta->staIndex);
goto out;
}
if (*pMemLower)
{
pMemCur = pMemLower;
}
else if (*pMemUpper)
{
pMemCur = pMemUpper;
membership += sizeof(tANI_U32);
}
else
{
limLog(pMac, LOGE,
FL(" received Gid Management Frame with no group ID set, staIdx = %d"),
pSta->staIndex);
goto out;
}
while (!(*pMemCur & 1))
{
*pMemCur >>= 1;
++membership;
}
if (*pMemCur)
{
limLog(pMac, LOGE,
FL(" received frame with multiple group ID set, staIdx = %d"),
pSta->staIndex);
goto out;
}
/*Just read the last two bits */
userPosition = pGidManagementframe->VhtUserPositionArray.userPositionArray[membership]
& 0x3;
limCheckMembershipUserPosition( pMac, psessionEntry, membership,
userPosition, pSta->staIndex);
}
out:
vos_mem_free(pGidManagementframe);
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 (LIM_IS_AP_ROLE(psessionEntry) || LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) {
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(!pMac->psOffloadEnabled)
{
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);
}
}
else
{
if (addts.tspec.tsinfo.traffic.psb == 1)
limSetTspecUapsdMaskPerSession(pMac, psessionEntry,
&addts.tspec.tsinfo, SET_UAPSD_MASK);
else
limSetTspecUapsdMaskPerSession(pMac, psessionEntry,
&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)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= (1 << ac);
}
else if(addts.tspec.tsinfo.traffic.direction == SIR_MAC_DIRECTION_DNLINK)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= (1 << ac);
}
else if(addts.tspec.tsinfo.traffic.direction == SIR_MAC_DIRECTION_BIDIR)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= (1 << ac);
psessionEntry->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)
limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive,
pStaDs->bssId);
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)))
{
#ifdef FEATURE_WLAN_ESE
retval = limSendHalMsgAddTs(pMac,
pSta->staIndex,
tspecInfo->idx,
addts.tspec,
psessionEntry->peSessionId,
addts.tsmIE.msmt_interval);
#else
retval = limSendHalMsgAddTs(pMac,
pSta->staIndex,
tspecInfo->idx,
addts.tspec,
psessionEntry->peSessionId);
#endif
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;
}
PELOG2(limLog(pMac, LOG2, FL("WME Delts received"));)
}
else if ((psessionEntry->limQosEnabled) && pSta->lleEnabled)
{
PELOG2(limLog(pMac, LOG2, FL("11e QoS Delts received"));)
}
else if ((psessionEntry->limWsmEnabled) && pSta->wsmEnabled)
{
PELOG2(limLog(pMac, LOG2, 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 (!LIM_IS_AP_ROLE(psessionEntry) &&
!LIM_IS_BT_AMP_AP_ROLE(psessionEntry))
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.
*/
if(!pMac->psOffloadEnabled)
{
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);
}
}
else
{
limSetTspecUapsdMaskPerSession(pMac, psessionEntry,
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)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= ~(1 << ac);
}
else if(tsinfo->traffic.direction == SIR_MAC_DIRECTION_DNLINK)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= ~(1 << ac);
}
else if(tsinfo->traffic.direction == SIR_MAC_DIRECTION_BIDIR)
{
psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= ~(1 << ac);
psessionEntry->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)
limSendEdcaParams(pMac, psessionEntry->gLimEdcaParamsActive,
pStaDs->bssId);
else
limLog(pMac, LOGE, FL("Self entry missing in Hash Table "));
PELOG1(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, pHdr->fc.subType, (tANI_U8*)pHdr,
frameLen + sizeof(tSirMacMgmtHdr), 0,
WDA_GET_RX_CH( pRxPacketInfo ),
psessionEntry, 0);
}
static void
__limProcessSMPowerSaveUpdate(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo ,tpPESession psessionEntry)
{
tpSirMacMgmtHdr pHdr;
tDot11fSMPowerSave frmSMPower;
tSirMacHTMIMOPowerSaveState state;
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 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,
pSta->staAddr, psessionEntry->smeSessionId);
}
#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;
}
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, (tANI_U8*)pHdr,
frameLen + sizeof(tSirMacMgmtHdr), 0, WDA_GET_RX_CH(pRxPacketInfo),
psessionEntry, WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo));
/**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_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];
/* 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);
/* 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_U32 frameLen;
tANI_U8 *pBody;
tpDphHashNode pSta;
tANI_U16 aid;
tANI_U16 transId;
tANI_U8 retryNum;
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO,
("SA Query Response received...")) ;
/* When a station, supplicant handles SA Query Response.
* Forward to SME to HDD to wpa_supplicant.
*/
if (LIM_IS_STA_ROLE(psessionEntry)) {
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, (tANI_U8*)pHdr,
frameLen + sizeof(tSirMacMgmtHdr), 0,
WDA_GET_RX_CH( pRxPacketInfo ),
psessionEntry,
WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo));
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 (LIM_IS_AP_ROLE(psessionEntry) || LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) {
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_U32 frameLen;
#ifdef WLAN_FEATURE_11W
tpSirMacMgmtHdr pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
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
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
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)
{
case SIR_MAC_ACTION_CHANNEL_SWITCH_ID:
if (LIM_IS_STA_ROLE(psessionEntry)) {
__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_HT:
/** Type of HT Action to be performed*/
switch(pActionHdr->actionID) {
case SIR_MAC_SM_POWER_SAVE:
if (LIM_IS_AP_ROLE(psessionEntry))
__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:
{
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:
{
tpSirMacMgmtHdr pHdr;
tANI_S8 rssi = WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo);
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
/* Forward to the SME to HDD to wpa_supplicant */
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, (tANI_U8*)pHdr,
frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH( pRxPacketInfo ),
psessionEntry, rssi);
break;
}
default:
limLog(pMac, LOG1,
FL("Action ID %d not handled in WNM Action category"),
pActionHdr->actionID);
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)
case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY:
{
tpSirMacVendorSpecificFrameHdr pVendorSpecific = (tpSirMacVendorSpecificFrameHdr) pActionHdr;
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
tANI_U8 Oui[] = { 0x00, 0x00, 0xf0 };
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
//Check if it is a vendor specific action frame.
if (LIM_IS_STA_ROLE(psessionEntry) &&
(VOS_TRUE == vos_mem_compare(psessionEntry->selfMacAddr,
&pHdr->da[0], sizeof(tSirMacAddr))) &&
IS_WES_MODE_ENABLED(pMac) &&
vos_mem_compare(pVendorSpecific->Oui, Oui, 3)) {
PELOGE( 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, pHdr->fc.subType,
(tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry, 0);
}
else {
limLog(pMac, LOG1, FL("Dropping the vendor specific action frame because of( "
"WES Mode not enabled (WESMODE = %d) or OUI mismatch (%02x %02x %02x) or "
"not received with SelfSta Mac address) system role = %d"),
IS_WES_MODE_ENABLED(pMac),
pVendorSpecific->Oui[0],
pVendorSpecific->Oui[1],
pVendorSpecific->Oui[2],
GET_LIM_SYSTEM_ROLE(psessionEntry));
}
}
break;
#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE ||
FEATURE_WLAN_LFR */
case SIR_MAC_ACTION_PUBLIC_USAGE:
switch(pActionHdr->actionID) {
case SIR_MAC_ACTION_VENDOR_SPECIFIC:
{
tpSirMacVendorSpecificPublicActionFrameHdr pPubAction = (tpSirMacVendorSpecificPublicActionFrameHdr) pActionHdr;
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
tANI_U8 P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 };
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
if (frameLen < sizeof(pPubAction)) {
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, pHdr->fc.subType,
(tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry,
WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo));
}
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;
case SIR_MAC_ACTION_2040_BSS_COEXISTENCE:
{
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType,
(tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry,
WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo));
}
break;
#ifdef FEATURE_WLAN_TDLS
case SIR_MAC_TDLS_DIS_RSP:
{
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
tANI_S8 rssi;
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
rssi = WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo);
VOS_TRACE(VOS_MODULE_ID_PE, VOS_TRACE_LEVEL_INFO,
("Public Action TDLS Discovery RSP ..")) ;
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType,
(tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH( pRxPacketInfo ), psessionEntry, rssi);
}
break;
#endif
case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID:
lim_process_ext_channel_switch_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;
case SIR_MAC_VHT_GID_NOTIFICATION:
/* Only if ini supports it */
if (psessionEntry->enableVhtGid)
__limProcessGidManagementActionFrame(pMac,pRxPacketInfo,psessionEntry);
break;
default:
break;
}
}
break;
}
#endif
case SIR_MAC_ACTION_FST:
{
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
pHdr = WDA_GET_RX_MAC_HEADER(pRxPacketInfo);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
limLog(pMac, LOG1, FL("Received FST MGMT action frame"));
/* Forward to the SME to HDD */
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType, (tANI_U8*)pHdr,
frameLen + sizeof(tSirMacMgmtHdr),
psessionEntry->smeSessionId,
WDA_GET_RX_CH(pRxPacketInfo),
psessionEntry,
WDA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo));
break;
}
default:
limLog(pMac, LOGE,
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;
limLog( pMac, LOG1, "Received a Action frame -- no session");
switch ( pActionHdr->category )
{
case SIR_MAC_ACTION_PUBLIC_USAGE:
switch(pActionHdr->actionID) {
case SIR_MAC_ACTION_VENDOR_SPECIFIC:
{
tpSirMacMgmtHdr pHdr;
tANI_U32 frameLen;
tANI_U8 P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 };
pHdr = WDA_GET_RX_MAC_HEADER(pBd);
frameLen = WDA_GET_RX_PAYLOAD_LEN(pBd);
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(pActionHdr->Oui, P2POui, 4))
{
/* Forward to the SME to HDD to wpa_supplicant */
// type is ACTION
limSendSmeMgmtFrameInd(pMac, pHdr->fc.subType,
(tANI_U8*)pHdr, frameLen + sizeof(tSirMacMgmtHdr), 0,
WDA_GET_RX_CH( pBd ), NULL, WDA_GET_RX_RSSI_RAW(pBd));
}
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;
/* Handle vendor specific action */
case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY:
{
tpSirMacMgmtHdr header;
uint32_t frame_len;
header = WDA_GET_RX_MAC_HEADER(pBd);
frame_len = WDA_GET_RX_PAYLOAD_LEN(pBd);
limSendSmeMgmtFrameInd(pMac, header->fc.subType,
(uint8_t*)header, frame_len + sizeof(tSirMacMgmtHdr), 0,
WDA_GET_RX_CH(pBd), NULL, WDA_GET_RX_RSSI_RAW(pBd));
break;
}
default:
limLog(pMac, LOG1,
FL("Unhandled action frame without session -- %x "),
pActionHdr->category);
break;
}
}