226 lines
6.8 KiB
C
226 lines
6.8 KiB
C
/****************************************************************************
|
|
* Ralink Tech Inc.
|
|
* Taiwan, R.O.C.
|
|
*
|
|
* (c) Copyright 2010, Ralink Technology, Inc.
|
|
*
|
|
* All rights reserved. Ralink's source code is an unpublished work and the
|
|
* use of a copyright notice does not imply otherwise. This source code
|
|
* contains confidential trade secret material of Ralink Tech. Any attemp
|
|
* or participation in deciphering, decoding, reverse engineering or in any
|
|
* way altering the source code is stricitly prohibited, unless the prior
|
|
* written consent of Ralink Technology, Inc. is obtained.
|
|
***************************************************************************/
|
|
|
|
/****************************************************************************
|
|
|
|
Abstract:
|
|
|
|
All related POWER SAVE function body.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "rt_config.h"
|
|
|
|
/*
|
|
========================================================================
|
|
Description:
|
|
This routine frees all packets in PSQ that's destined to a specific DA.
|
|
BCAST/MCAST in DTIMCount=0 case is also handled here, just like a PS-POLL
|
|
is received from a WSTA which has MAC address FF:FF:FF:FF:FF:FF
|
|
========================================================================
|
|
*/
|
|
VOID RalHandleRxPsPoll(RTMP_ADAPTER *pAd, UCHAR *pAddr, USHORT wcid, BOOLEAN isActive)
|
|
{
|
|
QUEUE_ENTRY *pQEntry;
|
|
MAC_TABLE_ENTRY *pMacEntry;
|
|
unsigned long IrqFlags;
|
|
STA_TR_ENTRY *tr_entry;
|
|
|
|
/*
|
|
DBGPRINT(RT_DEBUG_TRACE, ("rcv PS-POLL (AID=%d) from %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
Aid, PRINT_MAC(pAddr)));
|
|
*/
|
|
|
|
pMacEntry = &pAd->MacTab.Content[wcid];
|
|
tr_entry = &pAd->MacTab.tr_entry[wcid];
|
|
|
|
{
|
|
/*NdisAcquireSpinLock(&pAd->MacTabLock); */
|
|
/*NdisAcquireSpinLock(&pAd->TxSwQueueLock); */
|
|
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
|
|
if (isActive == FALSE)
|
|
{
|
|
if (tr_entry->ps_queue.Head)
|
|
{
|
|
#ifdef UAPSD_SUPPORT
|
|
UINT32 NumOfOldPsPkt;
|
|
NumOfOldPsPkt = pAd->TxSwQueue[QID_AC_BE].Number;
|
|
#endif /* UAPSD_SUPPORT */
|
|
|
|
pQEntry = RemoveHeadQueue(&tr_entry->ps_queue);
|
|
if (tr_entry->ps_queue.Number >= 1)
|
|
{
|
|
RTMP_SET_PACKET_MOREDATA(RTPKT_TO_OSPKT(pQEntry), TRUE);
|
|
RTMP_SET_PACKET_TXTYPE(RTPKT_TO_OSPKT(pQEntry), TX_LEGACY_FRAME);
|
|
}
|
|
InsertTailQueueAc(pAd, pMacEntry, &pAd->TxSwQueue[QID_AC_BE], pQEntry);
|
|
|
|
#ifdef UAPSD_SUPPORT
|
|
/* we need to call RTMPDeQueuePacket() immediately as below */
|
|
if (NumOfOldPsPkt != pAd->TxSwQueue[QID_AC_BE].Number)
|
|
{
|
|
if (RTMP_GET_PACKET_DHCP(RTPKT_TO_OSPKT(pQEntry)) ||
|
|
RTMP_GET_PACKET_EAPOL(RTPKT_TO_OSPKT(pQEntry)) ||
|
|
RTMP_GET_PACKET_WAI(RTPKT_TO_OSPKT(pQEntry)))
|
|
{
|
|
/*
|
|
These packets will use 1M/6M rate to send.
|
|
If you use 1M(2.4G)/6M(5G) to send, no statistics
|
|
count in NICUpdateFifoStaCounters().
|
|
|
|
So we can not count it for UAPSD; Or the SP will
|
|
not closed until timeout.
|
|
*/
|
|
}
|
|
else
|
|
UAPSD_MR_MIX_PS_POLL_RCV(pAd, pMacEntry);
|
|
}
|
|
#endif /* UAPSD_SUPPORT */
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
or transmit a (QoS) Null Frame;
|
|
|
|
In addtion, in Station Keep Alive mechanism, we need to
|
|
send a QoS Null frame to detect the station live status.
|
|
*/
|
|
BOOLEAN bQosNull = FALSE;
|
|
|
|
if (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE))
|
|
bQosNull = TRUE;
|
|
|
|
RtmpEnqueueNullFrame(pAd, pMacEntry->Addr, tr_entry->CurrTxRate,
|
|
pMacEntry->Aid, pMacEntry->func_tb_idx,
|
|
bQosNull, TRUE, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef UAPSD_SUPPORT
|
|
/* deliver all queued UAPSD packets */
|
|
UAPSD_AllPacketDeliver(pAd, pMacEntry);
|
|
|
|
/* end the SP if exists */
|
|
UAPSD_MR_ENTRY_RESET(pAd, pMacEntry);
|
|
#endif /* UAPSD_SUPPORT */
|
|
|
|
while(tr_entry->ps_queue.Head)
|
|
{
|
|
pQEntry = RemoveHeadQueue(&tr_entry->ps_queue);
|
|
InsertTailQueueAc(pAd, pMacEntry, &pAd->TxSwQueue[QID_AC_BE], pQEntry);
|
|
}
|
|
}
|
|
|
|
/*NdisReleaseSpinLock(&pAd->TxSwQueueLock); */
|
|
/*NdisReleaseSpinLock(&pAd->MacTabLock); */
|
|
|
|
if ((pMacEntry->Aid > 0) && (pMacEntry->Aid < MAX_LEN_OF_MAC_TABLE) &&
|
|
(tr_entry->ps_queue.Number == 0))
|
|
{
|
|
/* clear corresponding TIM bit because no any PS packet */
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
IF_DEV_CONFIG_OPMODE_ON_AP(pAd) {
|
|
WLAN_MR_TIM_BIT_CLEAR(pAd, pMacEntry->func_tb_idx, pMacEntry->Aid);
|
|
}
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
tr_entry->PsQIdleCount = 0;
|
|
}
|
|
|
|
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
|
|
|
|
/*
|
|
Dequeue outgoing frames from TxSwQueue0..3 queue and process it
|
|
TODO: 2004-12-27 it's not a good idea to handle "More Data" bit here.
|
|
because the RTMPDeQueue process doesn't guarantee to de-queue the
|
|
desired MSDU from the corresponding TxSwQueue/PsQueue when QOS
|
|
in-used. We should consider "HardTransmt" this MPDU using MGMT
|
|
queue or things like that.
|
|
*/
|
|
RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, wcid, MAX_TX_PROCESS);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==========================================================================
|
|
Description:
|
|
Update the station current power save mode. Calling this routine also
|
|
prove the specified client is still alive. Otherwise AP will age-out
|
|
this client once IdleCount exceeds a threshold.
|
|
==========================================================================
|
|
*/
|
|
BOOLEAN RalPsIndicate(RTMP_ADAPTER *pAd, UCHAR *pAddr, UCHAR wcid, UCHAR Psm)
|
|
{
|
|
MAC_TABLE_ENTRY *pEntry;
|
|
UCHAR old_psmode;
|
|
STA_TR_ENTRY *tr_entry;
|
|
tr_entry = &pAd->MacTab.tr_entry[wcid];
|
|
|
|
if (wcid >= MAX_LEN_OF_MAC_TABLE)
|
|
return PWR_ACTIVE;
|
|
|
|
pEntry = &pAd->MacTab.Content[wcid];
|
|
old_psmode = pEntry->PsMode;
|
|
/* if (pEntry) */
|
|
{
|
|
/*
|
|
Change power save mode first because we will call
|
|
RTMPDeQueuePacket() in RtmpHandleRxPsPoll().
|
|
|
|
Or when Psm = PWR_ACTIVE, we will not do Aggregation in
|
|
RTMPDeQueuePacket().
|
|
*/
|
|
pEntry->NoDataIdleCount = 0;
|
|
pEntry->PsMode = Psm;
|
|
// TODO: shiang-usw, we need to rmove upper setting and migrate to tr_entry->PsMode
|
|
pAd->MacTab.tr_entry[wcid].PsMode = Psm;
|
|
|
|
if (old_psmode != Psm) {
|
|
DBGPRINT(RT_DEBUG_INFO, ("%s():%02x:%02x:%02x:%02x:%02x:%02x %s!\n",
|
|
__FUNCTION__, PRINT_MAC(pAddr),
|
|
(Psm == PWR_SAVE ? "Sleep" : "wakes up, act like rx PS-POLL")));
|
|
}
|
|
|
|
if ((old_psmode == PWR_SAVE) && (Psm == PWR_ACTIVE))
|
|
{
|
|
#ifdef RTMP_MAC_PCI
|
|
#ifdef DOT11_N_SUPPORT
|
|
/*
|
|
When sta wake up, we send BAR to refresh the BA sequence.
|
|
TODO:
|
|
For RT2870, how to handle BA when STA in PS mode?
|
|
*/
|
|
SendRefreshBAR(pAd, pEntry);
|
|
#endif /* DOT11_N_SUPPORT */
|
|
#endif /* RTMP_MAC_PCI */
|
|
|
|
/* sleep station awakes, move all pending frames from PSQ to TXQ if any */
|
|
RtmpHandleRxPsPoll(pAd, pAddr, pEntry->wcid, TRUE);
|
|
}
|
|
}
|
|
#ifdef RELEASE_EXCLUDE
|
|
/*
|
|
else
|
|
{
|
|
// not in table, try to learn it ???? why bother?
|
|
DBGPRINT(RT_DEBUG_INFO, ("%s():[%ldth] not match %02x:%02x:%02x:%02x:%02x:%02x \n",
|
|
__FUNCTION__, wcid, PRINT_MAC(pAddr)));
|
|
}
|
|
*/
|
|
#endif /* RELEASE_EXCLUDE */
|
|
return old_psmode;
|
|
}
|
|
|