MT7601u/src/sta/tdls_uapsd.c
Murat Demirtas 612db32659 FIXED
2016-10-30 14:40:00 +00:00

1863 lines
45 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 TDLS UAPSD functions.
***************************************************************************/
#ifdef UAPSD_SUPPORT
#define MODULE_TDLS_UAPSD
#include "rt_config.h"
/* receive a traffic indication frame */
static VOID TDLS_UAPSD_PeerTrafficIndAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *pElem);
/* receive a traffic response frame */
static VOID TDLS_UAPSD_PeerTrafficRspAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *pElem);
/* build the traffic indication frame */
static ULONG TDLS_UAPSD_TrafficIndBuild(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac,
OUT UCHAR *pFrameBuf,
OUT UCHAR *pHeader802_3);
/* build the traffic indication frame payload */
static VOID TDLS_UAPSD_TrafficIndPayloadBuild(
IN PRTMP_ADAPTER pAd,
OUT PUCHAR pFrameBuf,
OUT PULONG pFrameLen,
IN PRT_802_11_TDLS pTDLS);
/* send a traffic indication frame */
static NDIS_STATUS TDLS_UAPSD_TrafficIndSend(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac);
/* send a traffic response frame */
static NDIS_STATUS TDLS_UAPSD_TrafficRspSend(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac,
IN UCHAR PeerToken);
/* build the traffic response frame body */
static VOID TDLS_UAPSD_TrafficRspBuild(
IN PRTMP_ADAPTER pAd,
OUT PUCHAR pFrameBuf,
OUT PULONG pFrameLen,
IN PRT_802_11_TDLS pTDLS,
IN UCHAR PeerToken);
/* get argument number value */
static UINT32 TDLS_UAPSD_CmdUtilHexGet(
IN CHAR **ppArgv);
/* get argument number value */
static UINT32 TDLS_UAPSD_CmdUtilNumGet(
IN CHAR **ppArgv);
/* get argument MAC value */
static VOID TDLS_UAPSD_CmdUtilMacGet(
IN CHAR **ppArgv,
IN UCHAR *pDevMac);
/* simulate to send a TDLS Setup request to a peer */
static VOID TDLS_UAPSD_CmdSimSetupReqSend(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* simulate to receive a TDLS Traffic response from a peer */
static VOID TDLS_UAPSD_CmdSimTrafficRspRcv(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* simulate to receive a TDLS Traffic indication from a peer */
static VOID TDLS_UAPSD_CmdSimTrafficIndRcv(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* simulate to change the power save of a peer */
static VOID TDLS_UAPSD_CmdSimPeerPowerSaveChg(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* simulate to change our power save */
static VOID TDLS_UAPSD_CmdSimSelfPowerSaveChg(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* simulate to send a TDLS Traffic response to a peer */
static VOID TDLS_UAPSD_CmdSimTrafficRspSnd(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv);
/* public functions */
/*
========================================================================
Routine Description:
Initialze TDLS UAPSD function.
Arguments:
pAd - WLAN control block pointer
pFSM - TDLS Finite State Machine
Return Value:
TRUE - init ok
FALSE - init fail
Note:
Peer U-APSD Sleep STA is default feature in spec.
Peer U-APSD Buffer STA is optional feature in spec.
========================================================================
*/
BOOLEAN TDLS_UAPSDP_Init(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *pFSM)
{
/* init FSM */
StateMachineSetAction(pFSM, TDLS_IDLE, MT2_PEER_TDLS_TRAFFIC_IND,
(STATE_MACHINE_FUNC)TDLS_UAPSD_PeerTrafficIndAction);
StateMachineSetAction(pFSM, TDLS_IDLE, MT2_PEER_TDLS_TRAFFIC_RSP,
(STATE_MACHINE_FUNC)TDLS_UAPSD_PeerTrafficRspAction);
/* init lock */
NdisAllocateSpinLock(pAd, &pAd->StaCfg.TdlsInfo.TDLSUapsdLock);
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> initialization ok!\n"));
return TRUE;
}
/*
========================================================================
Routine Description:
Release TDLS UAPSD function.
Arguments:
pAd - WLAN control block pointer
Return Value:
TRUE - release ok
FALSE - release fail
Note:
========================================================================
*/
BOOLEAN TDLS_UAPSDP_Release(
IN PRTMP_ADAPTER pAd)
{
/* free lock */
NdisFreeSpinLock(&pAd->StaCfg.TdlsInfo.TDLSUapsdLock);
return TRUE;
}
/*
========================================================================
Routine Description:
Send a traffic indication frame.
Arguments:
pAd - WLAN control block pointer
pPeerMac - the peer MAC
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
Note:
11.2.1.14.1 Peer U-APSD Behavior at the PU buffer STA
A PU buffer STA shall transmit a unicast TDLS Peer Traffic
Indication frame to a PU sleep STA, through the AP, if and only if
all of the following conditions are met:
-- A frame with an RA corresponding to a PU sleep STA was placed
into a buffer at the PU buffer STA;
-- The buffer into which the frame was placed contained no other
frames with the same RA; and
-- One or more periods of dot11TDLSPeerUAPSDIndicationWindow
beacon intervals have expired after the last service period.
========================================================================
*/
NDIS_STATUS TDLS_UAPSDP_TrafficIndSend(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac)
{
NDIS_STATUS NStatus;
TDLS_SEMLOCK(pAd);
NStatus = TDLS_UAPSD_TrafficIndSend(pAd, pPeerMac);
TDLS_SEMUNLOCK(pAd);
return NStatus;
}
/*
========================================================================
Routine Description:
Check if ASIC can go to sleep mode.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
Check all TDLS entries and return TRUE if all SPs are closed.
========================================================================
*/
BOOLEAN TDLS_UAPSDP_AsicCanSleep(
IN PRTMP_ADAPTER pAd)
{
RT_802_11_TDLS *pTDLS;
UINT32 IdEntry;
BOOLEAN FlgAllSpClosed = TRUE;
TDLS_SEMLOCK(pAd);
/* check if all SPs are closed */
for(IdEntry=0; IdEntry<MAX_NUM_OF_TDLS_ENTRY; IdEntry++)
{
pTDLS = (PRT_802_11_TDLS)&pAd->StaCfg.TdlsInfo.TDLSEntry[IdEntry];
if ((pTDLS->Valid == TRUE) &&
(pTDLS->Status == TDLS_MODE_CONNECTED))
{
UINT32 Wcid = pTDLS->MacTabMatchWCID;
PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[Wcid];
if (!IS_ENTRY_TDLS(pEntry))
continue;
/*
Two cases we can not sleep:
1. One of any SP is not ended.
2. A traffic indication is sent and no response is received.
*/
if ((pEntry->bAPSDFlagSPStart != 0) ||
(pTDLS->FlgIsWaitingUapsdTraRsp == TRUE))
{
DBGPRINT(RT_DEBUG_TRACE,
("tdls uapsd> SP not close or Ind sent (%d %d)!\n",
pEntry->bAPSDFlagSPStart,
pTDLS->FlgIsWaitingUapsdTraRsp));
hex_dump("pEntry=", pEntry->Addr, 6);
FlgAllSpClosed = FALSE;
break;
}
}
}
TDLS_SEMUNLOCK(pAd);
return FlgAllSpClosed;
}
/*
========================================================================
Routine Description:
Check if ASIC can go to sleep mode.
Arguments:
pAd - WLAN control block pointer
PsmOld - Current power save mode
PsmNew - New power save mode
Return Value:
None
Note:
========================================================================
*/
VOID TDLS_UAPSDP_PsmModeChange(
IN PRTMP_ADAPTER pAd,
IN USHORT PsmOld,
IN USHORT PsmNew)
{
MAC_TABLE_ENTRY *pMacEntry;
RT_802_11_TDLS *pTDLS;
UINT32 IdTdls;
if (PsmOld == PsmNew)
return; /* no inform needs */
/* sanity check */
/* WPA 802.1x secured port control */
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
#ifdef WPA_SUPPLICANT_SUPPORT
|| (pAd->StaCfg.IEEE8021X == TRUE)
#endif
#ifdef WAPI_SUPPORT
|| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAICERT)
|| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWAIPSK)
#endif /* WAPI_SUPPORT */
) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
{
return; /* port not yet secure */
}
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> our PSM mode change!\n"));
/* indicate the peer */
TDLS_SEMLOCK(pAd);
for(IdTdls=0; IdTdls<MAX_NUM_OF_TDLS_ENTRY; IdTdls++)
{
pTDLS = (RT_802_11_TDLS *) &pAd->StaCfg.TdlsInfo.TDLSEntry[IdTdls];
if ((pTDLS->Valid) && (pTDLS->Status == TDLS_MODE_CONNECTED))
{
/* get MAC Entry */
pMacEntry = MacTableLookup(pAd, pTDLS->MacAddr);
if (pMacEntry == NULL)
continue; /* check next one */
/* check if the peer is in ACTIVE mode */
if (TDLS_UAPSD_ARE_PEER_IN_ACTIVE(pMacEntry))
{
/*
pMacEntry->RssiSample.LastRssi0 is used to check if
we have ever received any packet from the peer.
*/
/* send a null frame to the peer directly */
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> send a NULL frame!\n"));
RtmpEnqueueNullFrame(pAd, pMacEntry->Addr,
pAd->CommonCfg.TxRate, pMacEntry->Aid,
pMacEntry->apidx, TRUE, FALSE, 0);
continue;
}
/*
Send traffic indication frame to the peer when the peer
is in power-save mode.
*/
TDLS_UAPSD_TrafficIndSend(pAd, pMacEntry->Addr);
}
}
TDLS_SEMUNLOCK(pAd);
}
/* private functions */
/*
========================================================================
Routine Description:
Display the UAPSD information for a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=01_[PEER MAC]
========================================================================
*/
static VOID TDLS_UAPSD_CmdPeerInfoDisplay(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
MAC_TABLE_ENTRY *pMacEntry;
UCHAR PeerMac[6];
UINT32 IdAcNum;
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* get pEntry */
pMacEntry = MacTableLookup(pAd, PeerMac);
if (pMacEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("tdls_cmd> ERROR! No such peer!\n"));
return;
}
/* display UAPSD information */
if (TDLS_UAPSD_ARE_PEER_IN_PS(pMacEntry))
printk("\n EDCA AC UAPSD information: (POWER SAVE)\n");
else
printk("\n EDCA AC UAPSD information: (ACTIVE)\n");
/* End of if */
if (pMacEntry->MaxSPLength != 0)
{
printk(" Max SP Length: %d (%d frames)\n",
pMacEntry->MaxSPLength, pMacEntry->MaxSPLength<<1);
}
else
printk(" Max SP Length: 0 (all frames)\n");
/* End of if */
printk(" UAPSD/AC AC0 AC1 AC2 AC3");
printk("\n Tr/De ");
for(IdAcNum=0; IdAcNum<4; IdAcNum++)
{
printk("%d/%d ",
pMacEntry->bAPSDCapablePerAC[IdAcNum],
pMacEntry->bAPSDDeliverEnabledPerAC[IdAcNum]);
} /* End of for */
printk("\n");
}
/*
========================================================================
Routine Description:
Display our UAPSD information.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=02
2. 11.2.1.14 Peer U-APSD
A STA that configured Peer U-APSD at a TDLS peer STA enters power save
mode on a TDLS direct link after the successful transmission to the
TDLS peer STA over the direct link of an acknowledged MPDU with the
Power Management field set to one.
========================================================================
*/
static VOID TDLS_UAPSD_CmdSelfInfoDisplay(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
if (TDLS_UAPSD_ARE_WE_IN_PS(pAd))
printk("\n EDCA AC UAPSD information: (POWER SAVE)\n");
else
printk("\n EDCA AC UAPSD information: (ACTIVE)\n");
/* End of if */
if (pAd->CommonCfg.MaxSPLength != 0)
{
printk(" Max SP Length: %d (%d frames)\n",
pAd->CommonCfg.MaxSPLength, pAd->CommonCfg.MaxSPLength<<1);
}
else
printk(" Max SP Length: 0 (all frames)\n");
/* End of if */
printk(" AP UAPSD/AC AC0 AC1 AC2 AC3");
printk("\n Tr/De %d/%d %d/%d %d/%d %d/%d\n\n",
pAd->CommonCfg.bACMAPSDTr[0],
pAd->CommonCfg.bAPSDAC_BE,
pAd->CommonCfg.bACMAPSDTr[1],
pAd->CommonCfg.bAPSDAC_BK,
pAd->CommonCfg.bACMAPSDTr[2],
pAd->CommonCfg.bAPSDAC_VI,
pAd->CommonCfg.bACMAPSDTr[3],
pAd->CommonCfg.bAPSDAC_VO);
printk(" TDLS UAPSD/AC AC0 AC1 AC2 AC3");
printk("\n Tr/De %d/%d %d/%d %d/%d %d/%d\n",
pAd->CommonCfg.TDLS_bAPSDAC_BE,
pAd->CommonCfg.TDLS_bAPSDAC_BE,
pAd->CommonCfg.TDLS_bAPSDAC_BK,
pAd->CommonCfg.TDLS_bAPSDAC_BK,
pAd->CommonCfg.TDLS_bAPSDAC_VI,
pAd->CommonCfg.TDLS_bAPSDAC_VI,
pAd->CommonCfg.TDLS_bAPSDAC_VO,
pAd->CommonCfg.TDLS_bAPSDAC_VO);
printk("\n");
}
/*
========================================================================
Routine Description:
Configure our UAPSD information.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=03_1_1_1_1_0
[UAPSD for BE] [UAPSD for BK] [UAPSD for VI] [UAPSD for VO]
[Max SP length]
========================================================================
*/
static VOID TDLS_UAPSD_CmdConfigure(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
pAd->CommonCfg.TDLS_bAPSDAC_BE = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
pAd->CommonCfg.TDLS_bAPSDAC_BK = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
pAd->CommonCfg.TDLS_bAPSDAC_VI = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
pAd->CommonCfg.TDLS_bAPSDAC_VO = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
pAd->CommonCfg.TDLS_MaxSPLength = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> configure our UAPSD to %d %d %d %d %d\n",
pAd->CommonCfg.TDLS_bAPSDAC_BE,
pAd->CommonCfg.TDLS_bAPSDAC_BK,
pAd->CommonCfg.TDLS_bAPSDAC_VI,
pAd->CommonCfg.TDLS_bAPSDAC_VO,
pAd->CommonCfg.TDLS_MaxSPLength));
}
#define TDLS_UAPSD_PEER_SHOW 01 /* tdls uapsd peer display */
#define TDLS_UAPSD_SELF_SHOW 02 /* tdls uapsd self display */
#define TDLS_UAPSD_CONFIG 03 /* tdls uapsd configure */
#ifdef TDLS_UAPSD_DEBUG
#define TDLS_UAPSD_SIM_SETUP_REQ 51 /* tdls setup request */
#define TDLS_UAPSD_SIM_TRAFFIC_RSP_RCV 52 /* tdls traffic rsp receive */
#define TDLS_UAPSD_SIM_TRAFFIC_IND_RCV 53 /* tdls traffic ind receive */
#define TDLS_UAPSD_SIM_PEER_PS 54 /* tdls peer ps mode change */
#define TDLS_UAPSD_SIM_PS 55 /* tdls ps mode change */
#define TDLS_UAPSD_SIM_TRAFFIC_RSP_SND 56 /* tdls traffic rsp send */
#define TDLS_UAPSD_SIM_BEACON_LOST 57 /* tdls beacon lost */
#endif /* TDLS_UAPSD_DEBUG */
/*
========================================================================
Routine Description:
Test command.
Arguments:
pAd - WLAN control block pointer
pArgvIn - the data flow information
Return Value:
0 - OK
others - FAIL
========================================================================
*/
INT TDLS_Ioctl(
IN PRTMP_ADAPTER pAd,
IN PSTRING pArgvIn)
{
CHAR BufCmd[3] = { 0, 0, 0 };
CHAR *pArgv, *pParam;
UINT32 Command;
INT32 Argc;
/* init */
pArgv = (CHAR *)pArgvIn;
/* get command type */
/* command format is iwpriv ra0 set tdls=[cmd id]_[arg1]_......_[argn] */
NdisCopyMemory(BufCmd, pArgv, 2);
Command = simple_strtol((PSTRING)BufCmd, 0, 10);
pArgv += 2; /* skip command field */
/* get Argc number */
Argc = 0;
pParam = pArgv;
while(1)
{
if (*pParam == '_')
Argc ++;
/* End of if */
if ((*pParam == 0x00) || (Argc > 20))
break;
/* End of if */
pParam++;
} /* End of while */
pArgv++; /* skip _ points to arg1 */
/* handle the command */
switch(Command)
{
case TDLS_UAPSD_PEER_SHOW: /* display peer uapsd info */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> display peer UAPSD information\n"));
TDLS_UAPSD_CmdPeerInfoDisplay(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SELF_SHOW: /* display self uapsd info */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> display self UAPSD information\n"));
TDLS_UAPSD_CmdSelfInfoDisplay(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_CONFIG: /* tdls uapsd configure */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> configure our UAPSD\n"));
TDLS_UAPSD_CmdConfigure(pAd, Argc, pArgv);
break;
#ifdef TDLS_UAPSD_DEBUG
case TDLS_UAPSD_SIM_SETUP_REQ: /* tdls setup request */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to send a setup request\n"));
TDLS_UAPSD_CmdSimSetupReqSend(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_TRAFFIC_RSP_RCV: /* tdls traffic response */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to receive a traffic response\n"));
TDLS_UAPSD_CmdSimTrafficRspRcv(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_TRAFFIC_IND_RCV: /* tdls traffic indication */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to receive a traffic indication\n"));
TDLS_UAPSD_CmdSimTrafficIndRcv(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_PEER_PS: /* tdls peer power save */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to change the peer power save\n"));
TDLS_UAPSD_CmdSimPeerPowerSaveChg(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_PS: /* tdls power save */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to change our power save\n"));
TDLS_UAPSD_CmdSimSelfPowerSaveChg(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_TRAFFIC_RSP_SND: /* tdls traffic response */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate to send traffic response\n"));
TDLS_UAPSD_CmdSimTrafficRspSnd(pAd, Argc, pArgv);
break;
case TDLS_UAPSD_SIM_BEACON_LOST: /* tdls beacon lost */
DBGPRINT(RT_DEBUG_TRACE,
("tdls_cmd> simulate the beacon lost case\n"));
pAd->Mlme.ChannelQuality = 0;
if (pAd->StaCfg.bAutoConnectByBssid)
pAd->StaCfg.bAutoConnectByBssid = FALSE;
pAd->MlmeAux.CurrReqIsFromNdis = FALSE;
/* Lost AP, send disconnect & link down event*/
LinkDown(pAd, FALSE);
break;
#endif /* TDLS_UAPSD_DEBUG */
default: /* error command type */
DBGPRINT(RT_DEBUG_ERROR, ("tdls_cmd> ERROR! No such command!\n"));
return -EINVAL; /* input error */
} /* End of switch */
return 0; /* ok */
}
/*
========================================================================
Routine Description:
Set our UAPSD.
Arguments:
pAd - WLAN control block pointer
pArgvIn - the data flow information
Return Value:
0 - OK
others - FAIL
========================================================================
*/
INT Set_TdlsUapsdProc(
IN PRTMP_ADAPTER pAd,
IN PSTRING pArgvIn)
{
return TDLS_Ioctl(pAd, pArgvIn);
}
/* private function */
/*
========================================================================
Routine Description:
Build the traffic indication frame.
Arguments:
pAd - WLAN control block pointer
pPeerMac - the peer
pFrameBuf - frame
pHeader802_3 - frame header
Return Value:
Frame Length
Note:
========================================================================
*/
static ULONG TDLS_UAPSD_TrafficIndBuild(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac,
OUT UCHAR *pFrameBuf,
OUT UCHAR *pHeader802_3)
{
RT_802_11_TDLS *pTDLS = NULL;
UCHAR TDLS_ETHERTYPE[] = {0x89, 0x0d};
ULONG FrameLen = 0;
INT32 LinkId;
BOOLEAN TimerCancelled;
DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
/* search TDLS entry */
LinkId = TDLS_SearchLinkId(pAd, pPeerMac);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_TRACE,
("%s: can not find the LinkId!\n", __FUNCTION__));
TDLS_UAPSD_REBUILD_LINK(pAd, pPeerMac);
goto LabelExit;
}
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> LinkId = %d\n", LinkId));
pTDLS = TDLS_UAPSD_ENTRY_GET(pAd, LinkId);
/* sanity check */
if (TDLS_UAPSD_IS_CONN_NOT_BUILT(pTDLS))
{
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> link is not yet built "
"so we can not send a traffic ind to the peer!!!"));
goto LabelExit;
}
if (pTDLS->FlgIsWaitingUapsdTraRsp == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> traffic ind was sent before!\n"));
goto LabelExit; /* has sent it */
}
pTDLS->FlgIsWaitingUapsdTraRsp = TRUE;
/* init packet header */
MAKE_802_3_HEADER(pHeader802_3, pTDLS->MacAddr,
pAd->CurrentAddress, TDLS_ETHERTYPE);
/* build the frame */
TDLS_UAPSD_TrafficIndPayloadBuild(pAd, pFrameBuf, &FrameLen, pTDLS);
hex_dump("TDLS UAPSD Peer Traffic Ind sending packet", pFrameBuf, FrameLen);
/*
11.2.1.14.1 Peer U-APSD Behavior at the PU buffer STA
When no corresponding TDLS Peer Traffic Response frame has been
received within dot11TDLSResponseTimeout after sending a TDLS Peer
Traffic Indication frame, the STA shall tear down the direct link.
The default value is 5 seconds.
*/
/* set traffic indication timer */
RTMPCancelTimer(&pTDLS->Timer, &TimerCancelled);
RTMPSetTimer(&pTDLS->Timer, TDLS_TIMEOUT);
/* free resources */
LabelExit:
return FrameLen;
}
/*
========================================================================
Routine Description:
Build the traffic indication frame payload.
Arguments:
pAd - WLAN control block pointer
pFrameBuf - frame
pFrameLen - frame length
pTDLS - TDLS link entry
Return Value:
None
Note:
========================================================================
*/
static VOID TDLS_UAPSD_TrafficIndPayloadBuild(
IN PRTMP_ADAPTER pAd,
OUT PUCHAR pFrameBuf,
OUT PULONG pFrameLen,
IN PRT_802_11_TDLS pTDLS)
{
UCHAR RemoteFrameType = PROTO_NAME_TDLS;
ULONG TempLen;
UCHAR Token; // Dialog token
/* fill remote frame type */
MakeOutgoingFrame(pFrameBuf, &TempLen,
1, &RemoteFrameType,
END_OF_ARGS);
*pFrameLen = TempLen;
/* fill action code */
TDLS_InsertActField(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
CATEGORY_TDLS, TDLS_ACTION_CODE_PEER_TRAFFIC_INDICATION);
/* fill Dialog Token */
TDLS_UAPSD_DIALOG_GET(pAd, Token);
TDLS_InsertDialogToken(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
Token);
/* fill link identifier */
if (pTDLS->bInitiator)
TDLS_InsertLinkIdentifierIE(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
pTDLS->MacAddr, pAd->CurrentAddress);
else
TDLS_InsertLinkIdentifierIE(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
pAd->CurrentAddress, pTDLS->MacAddr);
/* fill PU buffer status */
TDLS_InsertPuBufferStatus(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
pTDLS->MacAddr);
}
/*
========================================================================
Routine Description:
Send a traffic indication frame.
Arguments:
pAd - WLAN control block pointer
pPeerMac - the peer MAC
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
Note:
11.2.1.14.1 Peer U-APSD Behavior at the PU buffer STA
A PU buffer STA shall transmit a unicast TDLS Peer Traffic
Indication frame to a PU sleep STA, through the AP, if and only if
all of the following conditions are met:
-- A frame with an RA corresponding to a PU sleep STA was placed
into a buffer at the PU buffer STA;
-- The buffer into which the frame was placed contained no other
frames with the same RA; and
-- One or more periods of dot11TDLSPeerUAPSDIndicationWindow
beacon intervals have expired after the last service period.
========================================================================
*/
static NDIS_STATUS TDLS_UAPSD_TrafficIndSend(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac)
{
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
UCHAR Header802_3[14];
NDIS_STATUS NStatus = NDIS_STATUS_FAILURE;
DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
/* allocate resources */
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
goto LabelExit;
FrameLen = TDLS_UAPSD_TrafficIndBuild(pAd, pPeerMac,
pOutBuffer, Header802_3);
if (FrameLen <= 0)
goto LabelExit;
/*
Keep ACTIVE and do not enter sleep mode until all EOSPs are sent
and we will wake up our ASIC in STAHardTransmit() of
TDLS_UAPSD_PKT_SEND_THROUGH_AP() if we are sleep.
*/
ASIC_PS_CAN_NOT_SLEEP(pAd);
/* send the frame to the peer with AP's help */
TDLS_UAPSD_PKT_SEND_THROUGH_AP(pAd, Header802_3, pOutBuffer, FrameLen);
/* hex_dump("TDLS traffic indication send pack", pOutBuffer, FrameLen); */
NStatus = NDIS_STATUS_SUCCESS;
/* free resources */
LabelExit:
if (pOutBuffer != NULL)
MlmeFreeMemory(pAd, pOutBuffer);
return NStatus;
}
/*
========================================================================
Routine Description:
Send a traffic response frame.
Arguments:
pAd - WLAN control block pointer
pTDLS - the peer entry
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
Note:
========================================================================
*/
static NDIS_STATUS TDLS_UAPSD_TrafficRspSend(
IN PRTMP_ADAPTER pAd,
IN UCHAR *pPeerMac,
IN UCHAR PeerToken)
{
MAC_TABLE_ENTRY *pMacEntry;
RT_802_11_TDLS *pTDLS = NULL;
UCHAR TDLS_ETHERTYPE[] = {0x89, 0x0d};
UCHAR Header802_3[14];
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
ULONG TempLen;
INT32 LinkId;
UCHAR RemoteFrameType = PROTO_NAME_TDLS;
NDIS_STATUS NStatus = NDIS_STATUS_FAILURE;
DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
/* search TDLS entry */
LinkId = TDLS_SearchLinkId(pAd, pPeerMac);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_TRACE,
("%s: can not find the LinkId!\n", __FUNCTION__));
TDLS_UAPSD_REBUILD_LINK(pAd, pPeerMac);
goto LabelExit;
}
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> LinkId = %d\n", LinkId));
pTDLS = TDLS_UAPSD_ENTRY_GET(pAd, LinkId);
/* sanity check */
if (TDLS_UAPSD_IS_CONN_NOT_BUILT(pTDLS))
{
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> link is not yet built "
"so we can not send a traffic ind to the peer!!!"));
goto LabelExit;
}
/* init */
MAKE_802_3_HEADER(Header802_3, pTDLS->MacAddr,
pAd->CurrentAddress, TDLS_ETHERTYPE);
/* allocate buffer for transmitting message */
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
goto LabelExit;
/* build the frame */
MakeOutgoingFrame(pOutBuffer, &TempLen,
1, &RemoteFrameType,
END_OF_ARGS);
FrameLen = FrameLen + TempLen;
TDLS_UAPSD_TrafficRspBuild(pAd, pOutBuffer, &FrameLen, pTDLS, PeerToken);
hex_dump("TDLS UAPSD Peer Traffic Response sending packet", pOutBuffer, FrameLen);
/* need to set the power save mode of the peer to ACTIVE */
/* we will recover its mode after EOSP frame is received */
pMacEntry = MacTableLookup(pAd, pTDLS->MacAddr);
if (pMacEntry == NULL)
goto LabelExit;
/* peer can not sleep for a while */
RTMP_PS_VIRTUAL_WAKEUP_PEER(pMacEntry);
/* send the frame to the peer without AP's help */
TDLS_UAPSD_PKT_SEND_TO_PEER(pAd, Header802_3, pOutBuffer, FrameLen, pTDLS);
/* hex_dump("TDLS traffic response send pack", pOutBuffer, FrameLen); */
NStatus = NDIS_STATUS_SUCCESS;
/* free resources */
LabelExit:
if (pOutBuffer != NULL)
MlmeFreeMemory(pAd, pOutBuffer);
return NStatus;
}
/*
========================================================================
Routine Description:
Build the traffic response frame body.
Arguments:
pAd - WLAN control block pointer
pFrameBuf - frame
pFrameLen - frame length
pTDLS - TDLS link entry
Return Value:
None
Note:
========================================================================
*/
static VOID TDLS_UAPSD_TrafficRspBuild(
IN PRTMP_ADAPTER pAd,
OUT PUCHAR pFrameBuf,
OUT PULONG pFrameLen,
IN PRT_802_11_TDLS pTDLS,
IN UCHAR PeerToken)
{
/* fill action code */
TDLS_InsertActField(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
CATEGORY_TDLS, TDLS_ACTION_CODE_PEER_TRAFFIC_RESPONSE);
/* fill Dialog Token */
TDLS_InsertDialogToken(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
PeerToken);
/* fill link identifier */
if (pTDLS->bInitiator)
{
TDLS_InsertLinkIdentifierIE(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
pTDLS->MacAddr, pAd->CurrentAddress);
}
else
{
TDLS_InsertLinkIdentifierIE(pAd, (pFrameBuf + *pFrameLen), pFrameLen,
pAd->CurrentAddress, pTDLS->MacAddr);
}
}
/*
========================================================================
Routine Description:
Receive a traffic indication frame.
Arguments:
pAd - WLAN control block pointer
pElem - the frame information
Return Value:
None
Note:
========================================================================
*/
static VOID TDLS_UAPSD_PeerTrafficIndAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *pElem)
{
UCHAR Token;
UCHAR PeerAddr[6];
UCHAR PeerAddr1[6];
ULONG OffsetPuBuff;
INT LinkId = 0xff;
PRT_802_11_TDLS pTDLS = NULL;
PFRAME_802_11 pFrame = (PFRAME_802_11)pElem->Msg;
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> ====> %s\n", __FUNCTION__));
/* Not TDLS Capable, ignore it */
if (!IS_TDLS_SUPPORT(pAd))
return;
/* Not BSS mode, ignore it */
if (!INFRA_ON(pAd))
return;
hex_dump("TDLS UAPSD Peer Traffic Ind receive pack", pElem->Msg, pElem->MsgLen);
/* sanity check */
if (TDLS_UAPSD_ARE_WE_IN_ACTIVE(pAd))
return; /* we are not in power-save mode */
COPY_MAC_ADDR(PeerAddr, &pFrame->Hdr.Addr3);
// Drop not within my TDLS Table that created before !
LinkId = TDLS_SearchLinkId(pAd, PeerAddr);
if (LinkId == -1 || LinkId == MAX_NUM_OF_TDLS_ENTRY)
{
DBGPRINT(RT_DEBUG_ERROR,("TDLS - TDLS_UAPSD_PeerTrafficIndAction() can not find the LinkId!\n"));
return;
}
// Point to the current Link ID
pTDLS = (PRT_802_11_TDLS)&pAd->StaCfg.TdlsInfo.TDLSEntry[LinkId];
OffsetPuBuff = PeerTdlsBasicSanity(pAd,
pElem->Msg,
pElem->MsgLen,
pTDLS->bInitiator,
&Token,
PeerAddr1);
if (OffsetPuBuff <= 0)
return;
/* hex_dump("PeerAddr=", PeerAddr, 6); */
DBGPRINT(RT_DEBUG_ERROR, ("tdls uapsd> PU Buffer Status = 0x%x\n",
pElem->Msg[OffsetPuBuff+2])); /* 2: skip ID and length field */
/* reply a response frame with UP = 5 */
/* for TDLS UAPSD, all AC will be UAPSD mode */
TDLS_UAPSD_TrafficRspSend(pAd, PeerAddr, Token);
}
/*
========================================================================
Routine Description:
Receive a traffic response frame.
Arguments:
pAd - WLAN control block pointer
pElem - the frame information
Return Value:
None
Note:
========================================================================
*/
static VOID TDLS_UAPSD_PeerTrafficRspAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *pElem)
{
UCHAR Token;
UCHAR PeerAddr[6];
UCHAR PeerAddr1[6];
RT_802_11_TDLS *pTDLS;
INT32 LinkId = 0xff;
BOOLEAN TimerCancelled;
PFRAME_802_11 pFrame = (PFRAME_802_11)pElem->Msg;
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> ====> %s\n", __FUNCTION__));
/* Not TDLS Capable, ignore it */
if (!IS_TDLS_SUPPORT(pAd))
return;
/* Not BSS mode, ignore it */
if (!INFRA_ON(pAd))
return;
hex_dump("TDLS UAPSD Peer Traffic Response receive pack", pElem->Msg, pElem->MsgLen);
COPY_MAC_ADDR(PeerAddr, &pFrame->Hdr.Addr2);
// Drop not within my TDLS Table that created before !
LinkId = TDLS_SearchLinkId(pAd, PeerAddr);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_ERROR, ("%s: can not find the LinkId!\n", __FUNCTION__));
return;
}
// Point to the current Link ID
pTDLS = (PRT_802_11_TDLS)&pAd->StaCfg.TdlsInfo.TDLSEntry[LinkId];
/* sanity check */
PeerTdlsBasicSanity(pAd,
pElem->Msg,
pElem->MsgLen,
pTDLS->bInitiator,
&Token,
PeerAddr1);
/* hex_dump("PeerAddr=", PeerAddr, 6); */
/* search TDLS entry */
LinkId = TDLS_SearchLinkId(pAd, PeerAddr);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_TRACE,
("%s: can not find the LinkId!\n", __FUNCTION__));
TDLS_UAPSD_REBUILD_LINK(pAd, PeerAddr);
return;
}
DBGPRINT(RT_DEBUG_TRACE, ("tdls uapsd> LinkId = %d\n", LinkId));
/* cancel waiting flag to avoid tear down the link */
pTDLS = TDLS_UAPSD_ENTRY_GET(pAd, LinkId);
pTDLS->FlgIsWaitingUapsdTraRsp = FALSE;
RTMPCancelTimer(&pTDLS->Timer, &TimerCancelled);
/* check if we can sleep if we are sleep mode */
RtmpAsicSleepHandle(pAd);
}
/*
========================================================================
Routine Description:
Get argument number value.
Arguments:
**ppArgv - input parameters
Return Value:
decimal number
Note:
Only for one hex byte.
========================================================================
*/
static UINT32 TDLS_UAPSD_CmdUtilHexGet(
IN CHAR **ppArgv)
{
CHAR Buf[3], *pNum;
UINT32 ID;
UCHAR Value;
pNum = (*ppArgv);
Buf[0] = 0x30;
Buf[1] = 0x30;
Buf[2] = 0;
for(ID=0; ID<sizeof(Buf)-1; ID++)
{
if ((*pNum == '_') || (*pNum == 0x00))
break;
/* End of if */
pNum ++;
} /* End of for */
if (ID == 0)
return 0; /* argument length is too small */
/* End of if */
if (ID >= 2)
memcpy(Buf, (*ppArgv), 2);
else
Buf[1] = (**ppArgv);
/* End of if */
(*ppArgv) += ID;
if ((**ppArgv) == '_')
(*ppArgv) ++; /* skip _ */
/* End of if */
AtoH(Buf, &Value, 1);
return (UINT32)Value;
} /* End of TDLS_UAPSD_CmdUtilHexGet */
/*
========================================================================
Routine Description:
Get argument number value.
Arguments:
*pArgv - input parameters
Return Value:
decimal number
Note:
========================================================================
*/
static UINT32 TDLS_UAPSD_CmdUtilNumGet(
IN CHAR **ppArgv)
{
CHAR Buf[20], *pNum;
UINT32 ID;
pNum = (*ppArgv);
for(ID=0; ID<sizeof(Buf)-1; ID++)
{
if ((*pNum == '_') || (*pNum == 0x00))
break;
/* End of if */
pNum ++;
} /* End of for */
if (ID == sizeof(Buf)-1)
return 0; /* argument length is too large */
/* End of if */
memcpy(Buf, (*ppArgv), ID);
Buf[ID] = 0x00;
*ppArgv += ID+1; /* skip _ */
return simple_strtol((PSTRING)Buf, 0, 10);
} /* End of TDLS_UAPSD_CmdUtilNumGet */
/*
========================================================================
Routine Description:
Get argument MAC value.
Arguments:
**ppArgv - input parameters
*pDevMac - MAC address
Return Value:
None
Note:
========================================================================
*/
static VOID TDLS_UAPSD_CmdUtilMacGet(
IN CHAR **ppArgv,
IN UCHAR *pDevMac)
{
CHAR Buf[3];
CHAR *pMAC = (CHAR *)(*ppArgv);
UINT32 ID;
if ((pMAC[0] == '0') && (pMAC[1] == '_'))
{
*ppArgv = (&pMAC[2]);
return;
} /* End of if */
NdisZeroMemory(pDevMac, 6);
/* must exist 18 octets */
for(ID=0; ID<18; ID+=2)
{
if ((pMAC[ID] == '_') || (pMAC[ID] == 0x00))
{
*ppArgv = (&pMAC[ID]+1);
return;
} /* End of if */
} /* End of for */
/* get mac */
for(ID=0; ID<18; ID+=3)
{
Buf[0] = pMAC[0];
Buf[1] = pMAC[1];
Buf[2] = 0x00;
AtoH(Buf, pDevMac, 1);
pMAC += 3;
pDevMac ++;
} /* End of for */
*ppArgv += 17+1; /* skip _ */
} /* End of TDLS_UAPSD_CmdUtilMacGet */
/*
========================================================================
Routine Description:
Simulate to send a TDLS Setup request to a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=51_[PEER MAC]
11.21.4 TDLS direct-link establishment
TDLS Setup Request frames, TDLS Setup Response frames, and TDLS Setup
Confirm frames shall be transmitted through the AP and shall not be
transmitted to a group address.
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimSetupReqSend(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
MLME_QUEUE_ELEM *pElem;
RT_802_11_TDLS TDLS, *pTDLS = &TDLS;
UCHAR TDLS_ETHERTYPE[] = {0x89, 0x0d};
UCHAR Header802_3[14];
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
ULONG TempLen;
UCHAR RemoteFrameType = PROTO_NAME_TDLS;
NDIS_STATUS NStatus = NDIS_STATUS_SUCCESS;
UCHAR PeerMac[6];
UINT32 IdTdls;
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* allocate buffer for transmitting message */
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
return;
os_alloc_mem(NULL, (UCHAR **)&pElem, sizeof(MLME_QUEUE_ELEM));
if (pElem == NULL)
{
MlmeFreeMemory(pAd, pOutBuffer);
return;
}
/* init link entry */
NdisZeroMemory(pTDLS, sizeof(RT_802_11_TDLS));
pTDLS->TimeOut = 0;
COPY_MAC_ADDR(pTDLS->MacAddr, PeerMac);
pTDLS->Valid = 1;
/* search a empty entry */
for(IdTdls=0; IdTdls<MAX_NUM_OF_TDLS_ENTRY; IdTdls++)
{
if (!pAd->StaCfg.TdlsInfo.TDLSEntry[IdTdls].Valid)
{
NdisMoveMemory(&pAd->StaCfg.TdlsInfo.TDLSEntry[IdTdls],
pTDLS, sizeof(RT_802_11_TDLS_UI));
break;
}
}
if (IdTdls == MAX_NUM_OF_TDLS_ENTRY)
{
MlmeFreeMemory(pAd, pOutBuffer);
os_free_mem(NULL, pElem);
return;
}
/* init request frame */
MAKE_802_3_HEADER(Header802_3, pTDLS->MacAddr,
pAd->CurrentAddress, TDLS_ETHERTYPE);
MakeOutgoingFrame(pOutBuffer, &TempLen,
1, &RemoteFrameType,
END_OF_ARGS);
FrameLen = FrameLen + TempLen;
TDLS_BuildSetupRequest(pAd, pOutBuffer, &FrameLen,
TDLS_UAPSD_ENTRY_GET(pAd, IdTdls));
hex_dump("Request=", pOutBuffer, FrameLen);
TDLS_UAPSD_PKT_SEND_THROUGH_AP(pAd, Header802_3, pOutBuffer, FrameLen);
/* init response frame */
FrameLen += LENGTH_802_11 + LENGTH_802_1_H;
pElem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + FrameLen;
/* copy payload type, category, action (3B) */
memcpy(pElem->Msg + LENGTH_802_11 + LENGTH_802_1_H,
pOutBuffer, 3);
/* status code = 0x00 00 (2B) */
*(USHORT *)(pElem->Msg + LENGTH_802_11 + LENGTH_802_1_H + 3) = 0x00;
/* copy others */
memcpy(pElem->Msg + LENGTH_802_11 + LENGTH_802_1_H + 3 + 2,
pOutBuffer + 3, FrameLen - 3);
/* handle response frame */
TDLS_PeerSetupRspAction(pAd, pElem);
/* free memory */
MlmeFreeMemory(pAd, pOutBuffer);
os_free_mem(NULL, pElem);
} /* End of TDLS_UAPSD_CmdSimSetupReqSend */
/*
========================================================================
Routine Description:
Simulate to receive a TDLS Traffic response from a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=52_[PEER MAC]
2. In the actual case, the traffic response frame will be handled in
STAHandleRxDataFrame() because the traffic response frame is a
DATA frame, not management action frame.
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimTrafficRspRcv(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
MAC_TABLE_ENTRY *pMacEntry;
UCHAR PeerMac[6];
RT_802_11_TDLS *pTDLS = NULL;
INT32 LinkId;
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* get pEntry */
pMacEntry = MacTableLookup(pAd, PeerMac);
if (pMacEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("tdls_cmd> ERROR! No such peer!\n"));
return;
}
/* search TDLS entry */
LinkId = TDLS_SearchLinkId(pAd, PeerMac);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_ERROR,
("%s: can not find the LinkId!\n", __FUNCTION__));
TDLS_UAPSD_REBUILD_LINK(pAd, PeerMac);
return;
}
DBGPRINT(RT_DEBUG_ERROR, ("tdls uapsd> LinkId = %d\n", LinkId));
/* cancel waiting flag to avoid tear down the link */
pTDLS = TDLS_UAPSD_ENTRY_GET(pAd, LinkId);
pTDLS->FlgIsWaitingUapsdTraRsp = FALSE;
/* handle UAPSD SP */
/*
TDLS uses Ethertype 89-0d frames, as defined in Annex U.
The TDLS payload contains a TDLS Action frame body as is specified
in 7.4.11. The UP shall be AC_VI, unless otherwise specified.
So these TDLS action frames are DATA frame, not management frame.
*/
UAPSD_TriggerFrameHandle(pAd, pMacEntry, 5);
}
/*
========================================================================
Routine Description:
Simulate to receive a TDLS Traffic indication from a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=53_[PEER MAC]
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimTrafficIndRcv(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
UCHAR PeerMac[6];
MLME_QUEUE_ELEM *pElem = NULL;
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
INT32 LinkId;
RT_802_11_TDLS *pTDLS = NULL;
NDIS_STATUS NStatus = NDIS_STATUS_SUCCESS;
UCHAR RemoteFrameType = PROTO_NAME_TDLS;
ULONG TempLen;
UCHAR Token; // Dialog token
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* allocate resources */
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
goto LabelExit;
/* make up a virtual traffic indication frame */
/* search TDLS entry */
LinkId = TDLS_SearchLinkId(pAd, PeerMac);
if (TDLS_UAPSD_IS_LINK_INVALID(LinkId))
{
DBGPRINT(RT_DEBUG_ERROR,
("%s: can not find the LinkId!\n", __FUNCTION__));
TDLS_UAPSD_REBUILD_LINK(pAd, PeerMac);
goto LabelExit;
}
pTDLS = TDLS_UAPSD_ENTRY_GET(pAd, LinkId);
/* build the frame */
/* fill remote frame type */
MakeOutgoingFrame(pOutBuffer, &TempLen,
1, &RemoteFrameType,
END_OF_ARGS);
FrameLen = TempLen;
/* fill action code */
TDLS_InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen,
CATEGORY_TDLS, TDLS_ACTION_CODE_SETUP_REQUEST);
/* fill Dialog Token */
TDLS_UAPSD_DIALOG_GET(pAd, Token);
TDLS_InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen,
Token);
/* fill link identifier */
TDLS_InsertLinkIdentifierIE(pAd, (pOutBuffer + FrameLen), &FrameLen,
pTDLS->MacAddr, pAd->CurrentAddress);
/* fill PU buffer status */
TDLS_InsertPuBufferStatus(pAd, (pOutBuffer + FrameLen), &FrameLen,
pTDLS->MacAddr);
if (FrameLen <= 0)
goto LabelExit;
/* hex_dump("TDLS traffic indication send pack", pOutBuffer, FrameLen); */
/* allocate resources */
os_alloc_mem(NULL, (UCHAR **)&pElem, sizeof(MLME_QUEUE_ELEM));
if (pElem == NULL)
goto LabelExit;
/* copy the indication frame */
FrameLen += LENGTH_802_11 + LENGTH_802_1_H;
pElem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + FrameLen;
/* copy payload */
memcpy(pElem->Msg + LENGTH_802_11 + LENGTH_802_1_H,
pOutBuffer, FrameLen);
/* handle it */
TDLS_UAPSD_PeerTrafficIndAction(pAd, pElem);
/* free resources */
LabelExit:
if (pElem != NULL)
os_free_mem(NULL, pElem);
if (pOutBuffer != NULL)
MlmeFreeMemory(pAd, pOutBuffer);
}
/*
========================================================================
Routine Description:
Simulate to change the power save of a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=54_[PEER MAC]_[0/1]
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimPeerPowerSaveChg(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
MAC_TABLE_ENTRY *pMacEntry;
UCHAR PeerMac[6];
UINT32 PeerPsMode;
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* get pEntry */
pMacEntry = MacTableLookup(pAd, PeerMac);
if (pMacEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("tdls_cmd> ERROR! No such peer!\n"));
return;
}
/* change mode */
PeerPsMode = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
if (PeerPsMode != 0)
{
pMacEntry->PsMode = PWR_ACTIVE;
DBGPRINT(RT_DEBUG_TRACE, ("tdls_cmd> Change to ACTIVE!\n"));
}
else
{
pMacEntry->PsMode = PWR_SAVE;
DBGPRINT(RT_DEBUG_TRACE, ("tdls_cmd> Change to POWER SAVE!\n"));
}
}
/*
========================================================================
Routine Description:
Simulate to change our power save.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=55_[0/1]
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimSelfPowerSaveChg(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
UINT32 PeerPsMode;
PeerPsMode = TDLS_UAPSD_CmdUtilNumGet(&pArgv);
if (PeerPsMode != 0)
{
pAd->StaCfg.Psm = PWR_ACTIVE;
DBGPRINT(RT_DEBUG_TRACE, ("tdls_cmd> Change to ACTIVE!\n"));
}
else
{
pAd->StaCfg.Psm = PWR_SAVE;
DBGPRINT(RT_DEBUG_TRACE, ("tdls_cmd> Change to POWER SAVE!\n"));
}
}
/*
========================================================================
Routine Description:
Simulate to send a TDLS Traffic response to a peer.
Arguments:
pAd - WLAN control block pointer
Argc - the number of input parameters
*pArgv - input parameters
Return Value:
None
Note:
1. Command Format:
iwpriv ra0 set tdls=56_[PEER MAC]
========================================================================
*/
static VOID TDLS_UAPSD_CmdSimTrafficRspSnd(
IN PRTMP_ADAPTER pAd,
IN INT32 Argc,
IN CHAR *pArgv)
{
MAC_TABLE_ENTRY *pMacEntry;
UCHAR PeerMac[6];
UCHAR Token = 0;
/* get MAC address */
TDLS_UAPSD_CmdUtilMacGet(&pArgv, PeerMac);
/* get pEntry */
pMacEntry = MacTableLookup(pAd, PeerMac);
if (pMacEntry == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("tdls_cmd> ERROR! No such peer!\n"));
return;
}
/* send reponse */
TDLS_UAPSD_TrafficRspSend(pAd, PeerMac, Token);
}
#endif /* UAPSD_SUPPORT */
/* End of tdls_uapsd.c */