1889 lines
51 KiB
C
1889 lines
51 KiB
C
/****************************************************************************
|
|
* Ralink Tech Inc.
|
|
* Taiwan, R.O.C.
|
|
*
|
|
* (c) Copyright 2002, 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 WMM ACM EDCA function body.
|
|
|
|
***************************************************************************/
|
|
|
|
#define MODULE_WMM_ACM
|
|
#include "rt_config.h"
|
|
|
|
#ifdef WMM_ACM_SUPPORT
|
|
|
|
/* IEEE802.11E related include files */
|
|
#include "acm_extr.h" /* used for other modules */
|
|
#include "acm_comm.h" /* used for edca/wmm */
|
|
#include "acm_edca.h" /* used for edca/wmm */
|
|
|
|
|
|
|
|
/* ----- EDCA External Variable (only used in ACM module) ----- */
|
|
extern UCHAR gTCLAS_Elm_Len[];
|
|
|
|
#ifdef ACM_MEMORY_TEST
|
|
extern UINT32 gACM_MEM_Alloc_Num;
|
|
extern UINT32 gACM_MEM_Free_Num;
|
|
#endif /* ACM_MEMORY_TEST */
|
|
|
|
|
|
/* ----- EDCA Private Variable ----- */
|
|
/* AC0 (BE), AC1 (BK), AC2 (VI), AC3 (VO); AC3 > AC2 > AC0 > AC1 */
|
|
/* DSCP = (DSCP >> 3) & 0x07 */
|
|
UCHAR gEDCA_UP_AC[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
|
|
|
|
/* AC0 vs. UP0, AC1 vs. UP1, AC2 vs. UP4, AC3 vs. UP6 */
|
|
UCHAR gEDCA_AC_UP[4] = { 0, 1, 4, 6 };
|
|
|
|
/* DSCP(0) -> Priority 0 (AC_BE)
|
|
DSCP(1) -> Priority 1 (AC_BK)
|
|
DSCP(2) -> Priority 2 (AC_BK)
|
|
DSCP(3) -> Priority 3 (AC_BE)
|
|
DSCP(4) -> Priority 4 (AC_VI)
|
|
DSCP(5) -> Priority 5 (AC_VI)
|
|
DSCP(6) -> Priority 6 (AC_VO)
|
|
DSCP(7) -> Priority 7 (AC_VO) */
|
|
UCHAR gEDCA_UP_DSCP[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
|
|
|
|
|
|
|
|
|
|
|
/* ====================== Public Function ============================= */
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Change current EDCA Information.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
CpNu - the numerator of Contention Period,
|
|
if 0, no any update for CpNu
|
|
CpDe - the denominator of Contention Period
|
|
if 0, no any update for CpDe
|
|
BeNu - the numerator of Best Effort percentage,
|
|
if 0, no any update for BeNu
|
|
BeDe - the denominator of Best Effort percentage
|
|
if 0, no any update for BeDe
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - change ok
|
|
ACM_RTN_FAIL - change fail
|
|
|
|
Note:
|
|
1. CpNu/CpDe is the percentage of EDCA in 1 second.
|
|
2. BeNu/BeDe is the percentage of Best Effort streams in 1 second.
|
|
3. The function will not delete any stream if residunt
|
|
bandwidth is not enough for (CpNu/CpDe)*SI or (BeNu/BeDe).
|
|
4. New (CpNu/CpDe) or (BeNu/BeDe) will be valid after bandwidth is enough.
|
|
5. If the old ACM is enabled and the new ACM is disabled,
|
|
the function will not deleted these streams use the AC.
|
|
========================================================================
|
|
*/
|
|
ACM_FUNC_STATUS ACM_EDCA_InfomationChange(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN UINT16 CpNu,
|
|
ACM_PARAM_IN UINT16 CpDe,
|
|
ACM_PARAM_IN UINT16 BeNu,
|
|
ACM_PARAM_IN UINT16 BeDe)
|
|
{
|
|
ACM_CTRL_PARAM *pEdcaParam;
|
|
ULONG SplFlags;
|
|
|
|
|
|
/* change EDCA parameters */
|
|
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
|
|
|
|
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
|
|
|
|
/* copy new settings to new parameters */
|
|
if ((CpNu > 0) && (CpDe > 0))
|
|
{
|
|
pEdcaParam->CP_MinNu = CpNu;
|
|
pEdcaParam->CP_MinDe = CpDe;
|
|
} /* End of if */
|
|
|
|
if ((BeNu > 0) && (BeDe > 0))
|
|
{
|
|
pEdcaParam->BEK_MinNu = BeNu;
|
|
pEdcaParam->BEK_MinDe = BeDe;
|
|
} /* End of if */
|
|
|
|
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
|
|
|
|
/* delete all streams */
|
|
ACMP_TC_DeleteAll(pAd);
|
|
return ACM_RTN_OK;
|
|
|
|
LabelSemErr:
|
|
return ACM_RTN_FAIL;
|
|
} /* End of ACM_EDCA_InfomationChange */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Check whether the element is WME Information.
|
|
|
|
Arguments:
|
|
*pElm - the element
|
|
SubType - the sub type
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - check ok
|
|
ACM_RTN_FAIL - check fail
|
|
|
|
Note:
|
|
No semaphore protection is needed.
|
|
========================================================================
|
|
*/
|
|
ACM_FUNC_STATUS ACM_WME_ELM_Check(
|
|
ACM_PARAM_IN UCHAR *pElm,
|
|
ACM_PARAM_IN UCHAR SubType)
|
|
{
|
|
UCHAR ElmLen[3] = { ACM_ELM_WME_INFO_LEN,
|
|
ACM_ELM_WME_PARAM_LEN,
|
|
ACM_ELM_WME_TSPEC_LEN };
|
|
|
|
|
|
if ((pElm[0] == ACM_ELM_WME_ID) &&
|
|
(pElm[1] == ElmLen[SubType]) &&
|
|
(pElm[2] == ACM_WME_OUI_0) &&
|
|
(pElm[3] == ACM_WME_OUI_1) &&
|
|
(pElm[4] == ACM_WME_OUI_2) &&
|
|
(pElm[5] == ACM_WME_OUI_TYPE) &&
|
|
(pElm[6] == SubType) &&
|
|
(pElm[7] == ACM_WME_OUI_VERSION))
|
|
{
|
|
return ACM_RTN_OK;
|
|
} /* End of if */
|
|
|
|
return ACM_RTN_FAIL;
|
|
} /* End of ACM_WME_ELM_Check */
|
|
|
|
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Check a WME TSPEC element in a buffer.
|
|
|
|
Arguments:
|
|
*pBuffer - the buffer
|
|
*pTid - the TID of the TSPEC element
|
|
*pMediumTime - the medium time of the TSPEC element
|
|
|
|
Return Value:
|
|
TRUE - TSPEC element
|
|
FALSE - not TSPEC element
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
BOOLEAN ACMP_WME_TSPEC_ElementCheck(
|
|
ACM_PARAM_IN UCHAR *pBuffer,
|
|
ACM_PARAM_OUT UINT32 *pTid,
|
|
ACM_PARAM_OUT UINT32 *pMediumTime)
|
|
{
|
|
ACM_ELM_WME_TSPEC *pElmTspec;
|
|
|
|
|
|
if (pBuffer == NULL)
|
|
return FALSE;
|
|
/* End of if */
|
|
|
|
pElmTspec = (ACM_ELM_WME_TSPEC *)pBuffer;
|
|
|
|
if ((pElmTspec->ElementId != ACM_ELM_WME_ID) ||
|
|
(pElmTspec->Length != ACM_ELM_WME_TSPEC_LEN) ||
|
|
(pElmTspec->OUI[0] != ACM_WME_OUI_0) ||
|
|
(pElmTspec->OUI[1] != ACM_WME_OUI_1) ||
|
|
(pElmTspec->OUI[2] != ACM_WME_OUI_2) ||
|
|
(pElmTspec->OUI_Type != ACM_WME_OUI_TYPE) ||
|
|
(pElmTspec->OUI_SubType != ACM_WME_OUI_SUBTYPE_TSPEC) ||
|
|
(pElmTspec->Version != ACM_WME_OUI_VERSION))
|
|
{
|
|
/* not TSPEC element */
|
|
return FALSE;
|
|
} /* End of if */
|
|
|
|
*pTid = (UINT32)pElmTspec->Tspec.TsInfo.TID;
|
|
*pMediumTime = (UINT32)pElmTspec->Tspec.MediumTime;
|
|
return TRUE;
|
|
} /* End of ACMP_WME_TSPEC_ElementCheck */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
|
|
|
|
#ifdef CONFIG_STA_SUPPORT_SIM
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Fill a TSPEC element to a buffer.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pBuffer - the buffer
|
|
*pTspec11e - the current TSPEC
|
|
|
|
Return Value:
|
|
filled element length
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
UINT32 ACMP_WME_TSPEC_ElementFill(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN UCHAR *pBuffer,
|
|
ACM_PARAM_IN ACM_TSPEC *pTspec11e)
|
|
{
|
|
ACM_ELM_WME_TSPEC *pElmTspec;
|
|
ACM_WME_TSPEC *pTspecWme;
|
|
ACM_WME_TS_INFO *pInfo;
|
|
|
|
|
|
/* sanity check */
|
|
if ((pBuffer == NULL) || (pTspec11e == NULL))
|
|
return 0;
|
|
/* End of if */
|
|
|
|
/* TSPEC element */
|
|
pElmTspec = (ACM_ELM_WME_TSPEC *)pBuffer;
|
|
pElmTspec->ElementId = ACM_ELM_WME_ID;
|
|
pElmTspec->Length = ACM_ELM_WME_TSPEC_LEN;
|
|
|
|
/* init OUI field */
|
|
pElmTspec->OUI[0] = ACM_WME_OUI_0;
|
|
pElmTspec->OUI[1] = ACM_WME_OUI_1;
|
|
pElmTspec->OUI[2] = ACM_WME_OUI_2;
|
|
pElmTspec->OUI_Type = ACM_WME_OUI_TYPE;
|
|
pElmTspec->OUI_SubType = ACM_WME_OUI_SUBTYPE_TSPEC;
|
|
pElmTspec->Version = ACM_WME_OUI_VERSION;
|
|
|
|
/* init TS Info field */
|
|
pTspecWme = &pElmTspec->Tspec;
|
|
ACMR_MEM_ZERO(pTspecWme, sizeof(ACM_WME_TSPEC));
|
|
pInfo = &pElmTspec->Tspec.TsInfo;
|
|
|
|
pInfo->TID = pTspec11e->TsInfo.TSID;
|
|
pInfo->Direction = pTspec11e->TsInfo.Direction;
|
|
pInfo->UP = pTspec11e->TsInfo.UP;
|
|
pInfo->PSB = pTspec11e->TsInfo.APSD;
|
|
pInfo->One = 1; /* always 1 */
|
|
|
|
#ifdef ACM_CC_FUNC_11N_AGG
|
|
pInfo->AckPolicy = pTspec11e->TsInfo.AckPolicy;
|
|
#endif /* ACM_CC_FUNC_11N_AGG */
|
|
|
|
/* init TSPEC parameters */
|
|
pTspecWme->NominalMsduSize = pTspec11e->NominalMsduSize;
|
|
pTspecWme->MaxMsduSize = pTspec11e->MaxMsduSize;
|
|
pTspecWme->MinServInt = pTspec11e->MinServInt;
|
|
pTspecWme->MaxServInt = pTspec11e->MaxServInt;
|
|
pTspecWme->InactivityInt = pTspec11e->InactivityInt;
|
|
pTspecWme->SuspensionInt = pTspec11e->SuspensionInt;
|
|
pTspecWme->ServiceStartTime = pTspec11e->ServiceStartTime;
|
|
pTspecWme->MinDataRate = pTspec11e->MinDataRate;
|
|
pTspecWme->MeanDataRate = pTspec11e->MeanDataRate;
|
|
pTspecWme->PeakDataRate = pTspec11e->PeakDataRate;
|
|
pTspecWme->MaxBurstSize = pTspec11e->MaxBurstSize;
|
|
pTspecWme->DelayBound = pTspec11e->DelayBound;
|
|
pTspecWme->MinPhyRate = pTspec11e->MinPhyRate;
|
|
pTspecWme->SurplusBandwidthAllowance = \
|
|
pTspec11e->SurplusBandwidthAllowance;
|
|
|
|
return (sizeof(ACM_ELM_WME_TSPEC));
|
|
} /* End of ACMP_WME_TSPEC_ElementFill */
|
|
#endif /* CONFIG_STA_SUPPORT_SIM */
|
|
|
|
|
|
|
|
|
|
/* ====================== Private Function (EDCA) (AP) ====================== */
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Reclaim a EDCA used ACM time after a actived stream is deleted.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pStream - the EDCA stream
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
Protect in caller.
|
|
========================================================================
|
|
*/
|
|
STATIC VOID ACM_EDCA_AllocatedTimeReturn(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN ACM_STREAM *pStream)
|
|
{
|
|
#define ACM_LMR_TIME_DECREASE(time, value) \
|
|
if (time >= value) time -= value; else time = 0;
|
|
#define ACM_LMR_TIME_INCREASE(time, value) \
|
|
time += value;
|
|
|
|
ACM_CTRL_PARAM *pEdca;
|
|
ACM_TSPEC *pTspec;
|
|
UINT32 TimeUsed, AcId;
|
|
UINT32 Direction;
|
|
|
|
|
|
/* init */
|
|
pEdca = &ACMR_CB->EdcaCtrlParam;
|
|
pTspec = pStream->pTspec;
|
|
|
|
/* check if the stream is EDCA */
|
|
if (pTspec->TsInfo.AccessPolicy != ACM_ACCESS_POLICY_EDCA)
|
|
return;
|
|
/* End of if */
|
|
|
|
/* get AC ID */
|
|
AcId = ACM_MR_EDCA_AC(pStream->UP);
|
|
|
|
/* reclaim used time */
|
|
TimeUsed = pTspec->MediumTime << 5; /* unit: microsecond */
|
|
|
|
if (TimeUsed == 0)
|
|
return;
|
|
/* End of if */
|
|
|
|
ACM_LMR_TIME_DECREASE(pEdca->AcmTotalTime, TimeUsed);
|
|
ACM_LMR_TIME_DECREASE(pEdca->AcmAcTime[AcId], TimeUsed);
|
|
|
|
Direction = pTspec->TsInfo.Direction;
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
if (Direction == ACM_DIRECTION_BIDIREC_LINK)
|
|
{
|
|
/* for bidirectional link, used time = dnlink + uplink;
|
|
so we need to decrease it twice */
|
|
ACM_LMR_TIME_DECREASE(pEdca->AcmTotalTime, TimeUsed);
|
|
ACM_LMR_TIME_DECREASE(pEdca->AcmAcTime[AcId], TimeUsed);
|
|
} /* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
|
|
/* for main link or bidirectional link, we shall reset the CSR */
|
|
if ((pStream->FlgOutLink == 1) ||
|
|
(Direction == ACM_DIRECTION_BIDIREC_LINK))
|
|
{
|
|
ACM_LMR_TIME_DECREASE(pEdca->AcmOutTime[AcId], TimeUsed);
|
|
|
|
/* modify CSR setting */
|
|
ACM_ASIC_ACM_Reset(pAd, AcId, pEdca->AcmOutTime[AcId]);
|
|
} /* End of if */
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* dynamic ATL: update DATL time */
|
|
if (pEdca->FlgDatl)
|
|
ACM_DATL_Update(pAd, AcId, TimeUsed, 0, ACM_DATL_NO_BORROW, 0);
|
|
/* End of if */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
/* update available ACM time */
|
|
TimeUsed = pEdca->AcmTotalTime;
|
|
#ifdef ACM_CC_FUNC_MBSS
|
|
TimeUsed += ACMR_CB->MbssTotalUsedTime;
|
|
#endif /* ACM_CC_FUNC_MBSS */
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
ACMR_AVAIL_ACM_TIME_UPDATE(pAd, TimeUsed);
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
} /* End of ACM_EDCA_AllocatedTimeReturn */
|
|
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Delete a lower priority ACM AC stream to free bandwidth.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
TimeOff - the needed free time (us)
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - delete successfullly
|
|
ACM_RTN_FAIL - no any AC stream is deleted
|
|
|
|
Note:
|
|
Used in QAP.
|
|
========================================================================
|
|
*/
|
|
STATIC ACM_FUNC_STATUS ACM_EDCA_Lower_UP_Del(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN UINT32 TimeOff)
|
|
{
|
|
ACM_STREAM **ppAcmStmList, *pStream;
|
|
ACM_STREAM *pStreamDel;
|
|
UINT32 DevIndex;
|
|
UCHAR MAC[6];
|
|
UINT32 MediumTime, MediumTimeMax;
|
|
UINT32 IdTidNum;
|
|
|
|
|
|
/* check whether no any ACM stream exists */
|
|
if (ACMR_CB->EdcaCtrlParam.AcmTotalTime == 0)
|
|
return ACM_RTN_FAIL; /* no ACM AC stream can be deleted */
|
|
/* End of if */
|
|
|
|
/* init */
|
|
pStreamDel = NULL;
|
|
DevIndex = 0;
|
|
MediumTimeMax = 0;
|
|
|
|
/* try to find a non-bidirectional ACM AC whose medium time > TimeOff */
|
|
/* first, search in client database */
|
|
TimeOff = (TimeOff >> 5) + 1; /* change to 32 miscroseconds */
|
|
/* 1 is for roundUp */
|
|
|
|
while(1)
|
|
{
|
|
/* get a associated STATION MAC from our database */
|
|
if (ACM_PeerDeviceMacGetNext(pAd, &DevIndex, MAC) != ACM_RTN_OK)
|
|
break;
|
|
/* End of if */
|
|
|
|
/* get its WMM TS list */
|
|
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
|
|
pAd, MAC, ACM_PEER_TSPEC_INPUT_GET);
|
|
if (ppAcmStmList == NULL)
|
|
break;
|
|
/* End of if */
|
|
|
|
/* try to find a TS that its medium time >= TimeOff */
|
|
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
|
|
{
|
|
pStream = ppAcmStmList[IdTidNum];
|
|
|
|
if ((pStream != NULL) &&
|
|
(pStream->pTspec->TsInfo.Direction != \
|
|
ACM_DIRECTION_BIDIREC_LINK))
|
|
{
|
|
MediumTime = pStream->pTspec->MediumTime;
|
|
|
|
if (MediumTime >= TimeOff)
|
|
{
|
|
/* find one stream so delete it */
|
|
pStream->Cause = TSPEC_CAUSE_BANDWIDTH;
|
|
ACM_TC_Delete(pAd, pStream);
|
|
return ACM_RTN_OK;
|
|
} /* End of if */
|
|
|
|
if (MediumTime > MediumTimeMax)
|
|
{
|
|
/* backup the stream with max medium time */
|
|
MediumTimeMax = MediumTime;
|
|
pStreamDel = pStream;
|
|
} /* End of if */
|
|
} /* End of if */
|
|
} /* End of for */
|
|
} /* End of while */
|
|
|
|
if (pStreamDel == NULL)
|
|
return ACM_RTN_FAIL; /* no stream can be deleted */
|
|
/* End of if */
|
|
|
|
/* find it and delete the stream */
|
|
pStreamDel->Cause = TSPEC_CAUSE_BANDWIDTH;
|
|
ACM_TC_Delete(pAd, pStreamDel);
|
|
return ACM_RTN_OK;
|
|
} /* End of ACM_EDCA_Lower_UP_Del */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Handle a EDCA TSPEC request from the QSTA.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pCdb - the source QSTA
|
|
*pNewStream - the requested TSPEC
|
|
*pOldStreamIn - the old same in TSPEC with same AC
|
|
*pOldStreamOut - the old same out TSPEC with same AC
|
|
*pOldStreamDiffAc - the old same TSPEC with different AC
|
|
|
|
Return Value:
|
|
Status Code
|
|
|
|
Note:
|
|
1. Admission Control Mechanism for EDCA.
|
|
========================================================================
|
|
*/
|
|
STATIC UCHAR ACM_EDCA_ReqHandle(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN ACMR_STA_DB *pCdb,
|
|
ACM_PARAM_IN ACM_STREAM *pNewStream,
|
|
ACM_PARAM_IN ACM_STREAM *pOldStreamIn,
|
|
ACM_PARAM_IN ACM_STREAM *pOldStreamOut,
|
|
ACM_PARAM_IN ACM_STREAM *pOldStreamDiffAc)
|
|
{
|
|
/* unit: 100K bps */
|
|
UINT16 RateMapping[ACM_RATE_MAX_NUM][2] = {
|
|
{ 540, ACM_RATE_54M }, { 480, ACM_RATE_48M },
|
|
{ 360, ACM_RATE_36M }, { 240, ACM_RATE_24M },
|
|
{ 180, ACM_RATE_18M }, { 120, ACM_RATE_12M },
|
|
{ 90, ACM_RATE_9M }, { 60, ACM_RATE_6M },
|
|
{ 110, ACM_RATE_11M }, { 55, ACM_RATE_5_5M },
|
|
{ 20, ACM_RATE_2M }, { 10, ACM_RATE_1M } };
|
|
ACM_TSPEC *pTspec;
|
|
ACM_FUNC_STATUS RtnCode;
|
|
UINT32 SBA_Int, SBA_Dec;
|
|
UINT32 PPS; /* unit: packet per sec */
|
|
UINT32 MpduExgTime; /* unit: microseconds */
|
|
UINT32 MediumTime; /* unit: 32 microseconds */
|
|
UINT32 MediumTimeOld;
|
|
UINT32 AcmTimeOldBi;
|
|
UINT32 AcId;
|
|
UCHAR Direction;
|
|
UINT16 NormSize, NormMpduAgg;
|
|
UINT32 RateIndex, TxopLimit, TxopLimitDn, TxopLimitUp;
|
|
UCHAR FlgIsSpreambleUsed, FlgIsCtsEnable, FlgIsRtsEnable, FlgIsGmode;
|
|
UINT32 VbAcId, VbBandwidth;
|
|
UINT32 MediumTimeTemp, IdPhyRateNum;
|
|
|
|
|
|
/* check whether ACM is needed for the AC */
|
|
AcId = ACM_MR_EDCA_AC(pNewStream->UP);
|
|
|
|
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
|
|
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[AcId] == ACM_FLG_FUNC_DISABLED)
|
|
return ACM_STATUS_CODE_PRIVATE_ACM_DISABLED; /* no ACM is needed */
|
|
/* End of if */
|
|
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
|
|
|
|
pTspec = pNewStream->pTspec;
|
|
Direction = pTspec->TsInfo.Direction;
|
|
MediumTime = 0;
|
|
MediumTimeOld = 0;
|
|
AcmTimeOldBi = 0;
|
|
|
|
/* get minimum TXOP, maybe a packet tx time will excess the TXOP */
|
|
/* currently we do not use the field, TxopLimit */
|
|
TxopLimitDn = ACMR_TXOP_AP_GET(pAd, AcId);
|
|
TxopLimitUp = ACMR_TXOP_BSS_GET(pAd, AcId);
|
|
|
|
#if 0
|
|
if (Direction == ACM_DIR_UP_OR_DL)
|
|
TxopLimit = TxopLimitDn;
|
|
else if (Direction == ACM_DIR_DL_OR_UP)
|
|
TxopLimit = TxopLimitUp;
|
|
else if (TxopLimitDn > TxopLimitUp) /* choice the smaller one for BI */
|
|
TxopLimit = TxopLimitUp;
|
|
else
|
|
TxopLimit = TxopLimitDn;
|
|
/* End of if */
|
|
#else
|
|
|
|
TxopLimit = 0;
|
|
#endif
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* =====================================================================
|
|
IEEE802.11e D8.0 H.2.2 Deriving Medium Time
|
|
|
|
There are two requirements to consider: 1) the traffic requirements
|
|
of the application, and 2) the expected error performance of the
|
|
medium. The application requirements are captured by two TSPEC
|
|
parameters: Nominal MSDU Size and Mean Data Rate. The medium
|
|
requirements are captured by two TSPEC parameters: Surplus Bandwidth
|
|
Allowance and Minimum PHY Rate. When RTS/CTS protection is not used:
|
|
|
|
Medium Time = Surplus Bandwidth Allowance * pps * MPDUExchangeTime
|
|
|
|
where pps = ceiling (Mean Data Rate / 8) / Nominal MSDU Size;
|
|
the unit of Nominal MSDU Size is octet.
|
|
===================================================================== */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
/* parse the surplus bandwidth allowance */
|
|
/* Surplus Bandwidth Allowance = SBA_Int(3-bit).SBA_Dec(13-bit) */
|
|
SBA_Int = pTspec->SurplusBandwidthAllowance >> ACM_SURPLUS_DEC_BIT_NUM;
|
|
SBA_Dec = pTspec->SurplusBandwidthAllowance & ACM_SURPLUS_DEC_BITMAP;
|
|
SBA_Dec = ACM_SurplusFactorDecimalBin2Dec(SBA_Dec);
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> Surplus Bandwidth Allowance = %d.%02d!\n",
|
|
SBA_Int, SBA_Dec));
|
|
|
|
/* In WMM ACM Test Plan, the range for SBA should exclude 1.0 and 8.0 */
|
|
if (SBA_Int > ACM_SURPLUS_INT_MAX)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> Surplus Bandwidth Allowance = %d.%d > %d.0!\n",
|
|
SBA_Int, SBA_Dec, ACM_SURPLUS_INT_MAX));
|
|
return ACM_STATUS_CODE_WMM_INVALID_PARAMETERS;
|
|
} /* End of if */
|
|
|
|
/* calculate pps */
|
|
/* bit 15 = 1: means fix size; 0: means nominal size */
|
|
/* TODO: if NormSize >> MeanDataRate or maximum WLAN packet size (1548B) ? */
|
|
PPS = 1;
|
|
NormSize = pTspec->NominalMsduSize;
|
|
|
|
#ifdef ACM_CC_FUNC_11N_AGG
|
|
if (pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
|
|
NormMpduAgg = pTspec->MaxBurstSize; /* AMPDU aggregation number */
|
|
else
|
|
#endif /* ACM_CC_FUNC_11N_AGG */
|
|
NormMpduAgg = 1;
|
|
/* End of if */
|
|
|
|
if (NormSize > 0)
|
|
{
|
|
NormSize = NormSize & 0x7FFF;
|
|
PPS = (((pTspec->MeanDataRate>>3)/NormSize)/NormMpduAgg);
|
|
PPS += 1;
|
|
if (PPS <= 1)
|
|
{
|
|
#ifdef RELEASE_EXCLUDE
|
|
/*
|
|
Test Event 1 found:
|
|
This is illegal because norminal size > data rate size,
|
|
very strange, so fix the norminal data size.
|
|
|
|
But for CISCO and Marvell AP, they will response the ADDTS
|
|
Response frame and the medium time is "0".
|
|
*/
|
|
#endif /* RELEASE_EXCLUDE */
|
|
pTspec->NominalMsduSize = (pTspec->MeanDataRate)>>3;
|
|
NormSize = pTspec->NominalMsduSize;
|
|
} /* End of if */
|
|
} /* End of if */
|
|
|
|
/* calculate MPDU exchange time */
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* =====================================================================
|
|
MPDU exchange time maybe
|
|
(p: preamble tx time, rts/cts: rts/cts tx time,
|
|
cts-self: cts self tx time, h: WLAN header tx time,
|
|
data: data tx time, a: ack tx time)
|
|
|
|
1) p + h + data
|
|
2) p + h + data + sifs + p + ack
|
|
3) p + cts-self + sifs + p + h + data
|
|
4) p + cts-self + sifs + p + h + data + sifs + p + ack
|
|
5) p + rts + sifs + p + cts + sifs + p + h + data
|
|
6) p + rts + sifs + p + cts + sifs + p + h + data + sifs + p + ack
|
|
|
|
Note: Maybe cts-self + rts/cts are used. In HCCA, we need to
|
|
calculate the TXOP in the worse case because we do not know
|
|
if QSTA use cts-self and rts/cts simultaneouly.
|
|
===================================================================== */
|
|
|
|
/* =====================================================================
|
|
Data hardware fragment needs to be diabled when
|
|
|
|
1) a hardware fragment tx time > TXOP limit,
|
|
==> use software fragment, a fragment tx time = TXOP limit
|
|
2) sum of all hardware fragment tx time > TXOP limit,
|
|
==> use software fragment, a fragment tx time = TXOP limit
|
|
===================================================================== */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
/* check if ACM is enabled, only allocate bandwidth for enabled ACM */
|
|
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[AcId] != ACM_FLG_FUNC_DISABLED)
|
|
{
|
|
#ifdef ACM_CC_FUNC_11N
|
|
if (pNewStream->PhyModeMin >= ACMR_PHY_HT)
|
|
{
|
|
UINT16 NumOfAgg = 0;
|
|
|
|
|
|
/* for HT minimum physical rate, includes RTS/CTS time */
|
|
/* TODO: for AMSDU, if no legacy station connects, no RTS/CTS */
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> minimal MCS = %d, 20/40MHz Flag = %d\n",
|
|
pNewStream->McsMin, ACMR_IS_2040_STA(pCdb)));
|
|
|
|
#ifdef ACM_CC_FUNC_11N_AGG
|
|
if (pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
|
|
{
|
|
/* Nominal MPDU Aggregation */
|
|
NumOfAgg = pTspec->MaxBurstSize;
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> number of aggregation = %d\n",
|
|
pTspec->MaxBurstSize));
|
|
}
|
|
#endif /* ACM_CC_FUNC_11N_AGG */
|
|
|
|
MpduExgTime = ACM_TX_TimeCalHT(
|
|
pAd,
|
|
pCdb,
|
|
NormSize,
|
|
pNewStream->McsMin,
|
|
ACMR_IS_2040_STA(pCdb),
|
|
0, /* always use regular GI */
|
|
1, /* always use RTS/CTS */
|
|
0, /* always use BLOCK ACK */
|
|
0, /* no AMPDU */
|
|
TxopLimit,
|
|
FALSE, /* no AMSDU */
|
|
NumOfAgg,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
else
|
|
#endif /* ACM_CC_FUNC_11N */
|
|
{
|
|
/* find the rate ID of the minimum physical rate */
|
|
RateIndex = pTspec->MinPhyRate/100000;
|
|
for(IdPhyRateNum=0; IdPhyRateNum<ACM_RATE_MAX_NUM; IdPhyRateNum++)
|
|
{
|
|
if (RateMapping[IdPhyRateNum][0] == RateIndex)
|
|
{
|
|
RateIndex = RateMapping[IdPhyRateNum][1];
|
|
break;
|
|
} /* End of if */
|
|
} /* End of for */
|
|
|
|
if (IdPhyRateNum == ACM_RATE_MAX_NUM)
|
|
{
|
|
/* should not be here so using default 1M rate */
|
|
RateIndex = ACM_RATE_1M;
|
|
} /* End of if */
|
|
|
|
/* get CTS-self & B/G mode flag */
|
|
FlgIsCtsEnable = 0; /* no CTS-self function */
|
|
|
|
if ((RateIndex == ACM_RATE_1M) || (RateIndex == ACM_RATE_2M) ||
|
|
(RateIndex == ACM_RATE_5_5M) || (RateIndex == ACM_RATE_11M))
|
|
{
|
|
/* CCK rate */
|
|
FlgIsGmode = 0;
|
|
}
|
|
else
|
|
{
|
|
/* OFDM rate */
|
|
FlgIsGmode = 1;
|
|
} /* End of if */
|
|
|
|
/* get short or long preamble flag */
|
|
FlgIsSpreambleUsed = ACMR_STA_IS_SPREAMBLE(pAd, pCdb);
|
|
|
|
/* get rts/cts enable/disable flag */
|
|
if ((NormSize > ACMR_RTS_THRESH(pAd)) && (FlgIsCtsEnable == 0))
|
|
FlgIsRtsEnable = 1;
|
|
else
|
|
FlgIsRtsEnable = 0;
|
|
/* End of if */
|
|
|
|
if (ACMR_ERP_IS_BG_PROTECTION_ENABLED(pAd))
|
|
FlgIsRtsEnable = 1;
|
|
/* End of if */
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/*
|
|
EX: data size = 208B, rate = 54Mbps,
|
|
MpduExgTime = 104us in A band.
|
|
*/
|
|
#endif /* RELEASE_EXCLUDE */
|
|
MpduExgTime = ACM_TX_TimeCal(
|
|
pAd,
|
|
pCdb,
|
|
NormSize,
|
|
RateIndex,
|
|
FlgIsGmode,
|
|
FlgIsCtsEnable,
|
|
FlgIsRtsEnable,
|
|
FlgIsSpreambleUsed,
|
|
pTspec->TsInfo.AckPolicy,
|
|
TxopLimit,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
} /* End of if */
|
|
|
|
/* calculate the medium time, unit: microseconds */
|
|
MediumTime = SBA_Int * PPS * MpduExgTime;
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> norm_size = %d, pps = %d, MpduExgTime = %d, medium time = %d!\n",
|
|
NormSize, PPS, MpduExgTime, MediumTime));
|
|
|
|
if (SBA_Dec > 0)
|
|
{
|
|
/*
|
|
Avoid MediumTime * SBA_Dec > 0xFFFFFFFF because MediumTime
|
|
is only unsigned (32-bit).
|
|
*/
|
|
MediumTimeTemp = 0xFFFFFFFF/MediumTime;
|
|
if (SBA_Dec <= MediumTimeTemp)
|
|
{
|
|
/* medium time += 0.SBA_Dec * pps * MpduExgTime */
|
|
MediumTime += (SBA_Dec*PPS*MpduExgTime)/ACM_SURPLUS_DEC_BASE;
|
|
} /* End of if */
|
|
} /* End of if */
|
|
|
|
MediumTime &= 0xFFFFFFE0; /* unit: microseconds */
|
|
MediumTime += 32; /* extra 32us for roundUp */
|
|
MediumTimeOld = 0;
|
|
|
|
/* calculate old used ACM time */
|
|
if (pOldStreamIn != NULL)
|
|
MediumTimeOld += pOldStreamIn->pTspec->MediumTime << 5;
|
|
/* End of if */
|
|
|
|
if (pOldStreamOut != NULL)
|
|
{
|
|
MediumTimeOld += pOldStreamOut->pTspec->MediumTime << 5;
|
|
|
|
if (Direction == ACM_DIRECTION_BIDIREC_LINK)
|
|
AcmTimeOldBi = pOldStreamOut->pTspec->MediumTime << 5;
|
|
/* End of if */
|
|
} /* End of if */
|
|
|
|
if (pOldStreamDiffAc != NULL)
|
|
MediumTimeOld += pOldStreamDiffAc->pTspec->MediumTime << 5;
|
|
/* End of if */
|
|
|
|
/* check whether current bandwidth is enough */
|
|
RtnCode = ACM_BandwidthCheck(
|
|
pAd,
|
|
AcId,
|
|
0,
|
|
pTspec->TsInfo.AccessPolicy,
|
|
Direction,
|
|
MediumTimeOld, /* old used time */
|
|
MediumTime, /* new used time */
|
|
AcmTimeOldBi, /* old used time */
|
|
NULL,
|
|
&VbAcId,
|
|
&VbBandwidth);
|
|
|
|
if (RtnCode != ACM_RTN_OK)
|
|
return ACM_STATUS_CODE_ASSOC_DENIED_INSUFFICIENT_BANDWIDTH;
|
|
/* End of if */
|
|
} /* End of if */
|
|
|
|
/* the new stream is allowed */
|
|
pTspec->MediumTime = MediumTime>>5; /* transfer to unit: 32us */
|
|
|
|
pNewStream->Status = TSPEC_STATUS_ACTIVE;
|
|
pNewStream->InactivityCur = pTspec->InactivityInt;
|
|
#ifdef ACM_CC_FUNC_HCCA
|
|
pNewStream->SuspensionCur = pTspec->SuspensionInt;
|
|
#else
|
|
pNewStream->SuspensionCur = 0;
|
|
#endif /* ACM_CC_FUNC_HCCA */
|
|
|
|
/* free old TSPEC */
|
|
if (pOldStreamIn != NULL)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Free in stream!\n"));
|
|
ACM_TC_Discard(pAd, pOldStreamIn);
|
|
} /* End of if */
|
|
|
|
if (pOldStreamOut != NULL)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Free out stream!\n"));
|
|
ACM_TC_Discard(pAd, pOldStreamOut);
|
|
} /* End of if */
|
|
|
|
if (pOldStreamDiffAc != NULL)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Free dif stream!\n"));
|
|
ACM_TC_Discard(pAd, pOldStreamDiffAc);
|
|
} /* End of if */
|
|
|
|
/* active/add the new TSPEC */
|
|
if (ACM_TC_Active(pAd, pNewStream) == ACM_RTN_OK)
|
|
{
|
|
if (MediumTime > 0)
|
|
{
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* dynamic ATL */
|
|
if (ACMR_CB->EdcaCtrlParam.FlgDatl != 0)
|
|
{
|
|
if (MediumTime <= MediumTimeOld)
|
|
{
|
|
/*
|
|
Get the needed extra bandwidth for new medium time
|
|
because we will not handle the case above, we need to
|
|
handle the case here before ACM_EDCA_Param_ACM_Update()
|
|
*/
|
|
ACM_DATL_Handle(pAd, AcId, 0, MediumTime,
|
|
&VbAcId, &VbBandwidth);
|
|
} /* End of if */
|
|
} /* End of if */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
/* update used time */
|
|
ACM_EDCA_Param_ACM_Update(
|
|
pAd,
|
|
pNewStream->AcmAcId,
|
|
Direction,
|
|
pNewStream->UP,
|
|
MediumTime,
|
|
0,
|
|
VbAcId,
|
|
VbBandwidth);
|
|
} /* End of if */
|
|
|
|
RtnCode = ACM_STATUS_CODE_SUCCESS;
|
|
}
|
|
else
|
|
RtnCode = ACM_STATUS_CODE_UNSPECIFIED_FAILURE;
|
|
/* End of if */
|
|
|
|
/* update to CSR */
|
|
if ((Direction == ACM_DIRECTION_DOWN_LINK) ||
|
|
(Direction == ACM_DIRECTION_BIDIREC_LINK))
|
|
{
|
|
/*
|
|
When the Direction is donwlink or bidirectional link,
|
|
we maybe reset ASIC ACM control registers.
|
|
|
|
Currently no any related register is needed to re-set.
|
|
*/
|
|
AcId = pNewStream->AcmAcId;
|
|
|
|
ACM_ASIC_ACM_Reset(
|
|
pAd,
|
|
AcId,
|
|
ACMR_CB->EdcaCtrlParam.AcmOutTime[AcId]);
|
|
} /* End of if */
|
|
|
|
return RtnCode;
|
|
} /* End of ACM_EDCA_ReqHandle */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Update new ACM medium time for EDCA mechanism.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
AcmAcId - the AC for the stream (0 ~ 3)
|
|
Direction - the Direction of the stream
|
|
UP - the user priority
|
|
AcmTimeNew - new medium time of the stream (unit: microseconds)
|
|
AcmTimeOld - old medium time of the stream (unit: microseconds)
|
|
VbAcId - the borrowed AC ID, 0 ~ 3
|
|
VbBandwidth - the borrowed bandwidth from a AC (unit: microsecond)
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
Protect in caller.
|
|
========================================================================
|
|
*/
|
|
STATIC VOID ACM_EDCA_Param_ACM_Update(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN UINT32 AcmAcId,
|
|
ACM_PARAM_IN UCHAR Direction,
|
|
ACM_PARAM_IN UCHAR UP,
|
|
ACM_PARAM_IN UINT32 AcmTimeNew,
|
|
ACM_PARAM_IN UINT32 AcmTimeOld,
|
|
ACM_PARAM_IN UINT32 VbAcId,
|
|
ACM_PARAM_IN UINT32 VbBandwidth)
|
|
{
|
|
ACM_CTRL_PARAM *pEdcaParam;
|
|
UINT32 TimeNewDn, TimeOldDn;
|
|
UINT32 TimeNewUp, TimeOldUp;
|
|
UINT32 TimeUsed;
|
|
UINT32 AcId;
|
|
|
|
|
|
/* init */
|
|
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
|
|
TimeNewDn = 0;
|
|
TimeOldDn = 0;
|
|
TimeNewUp = 0;
|
|
TimeOldUp = 0;
|
|
AcId = AcmAcId;
|
|
|
|
switch(Direction)
|
|
{
|
|
case ACM_DIRECTION_UP_LINK: /* uplink */
|
|
case ACM_DIRECTION_DIRECT_LINK:
|
|
TimeNewUp = AcmTimeNew;
|
|
TimeOldUp = AcmTimeOld;
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
/* for uplink in QAP, AcmAcId is not AC ID; it is minor link;
|
|
so we need to re-get AC ID from UP of the uplink */
|
|
AcId = ACM_MR_EDCA_AC(UP);
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
break;
|
|
|
|
case ACM_DIRECTION_DOWN_LINK: /* dnlink */
|
|
TimeNewDn = AcmTimeNew;
|
|
TimeOldDn = AcmTimeOld;
|
|
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
if (ACMR_IS_STA_MODE(pAd))
|
|
{
|
|
/* for dnlink in QSTA, AcmAcId is not AC ID; it is minor link;
|
|
so we need to re-get AC ID from UP of the dnlink */
|
|
AcId = ACM_MR_EDCA_AC(UP);
|
|
} /* End of if */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
break;
|
|
|
|
case ACM_DIRECTION_BIDIREC_LINK: /* dnlink + uplink */
|
|
TimeNewDn = TimeNewUp = AcmTimeNew;
|
|
TimeOldDn = TimeOldUp = AcmTimeOld;
|
|
break;
|
|
} /* End of switch */
|
|
|
|
if ((TimeNewDn == TimeOldDn) && (TimeNewUp == TimeOldUp))
|
|
return; /* same time, do NOT need to update */
|
|
/* End of if */
|
|
|
|
|
|
/* accumulate new allocated time */
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
pEdcaParam->AcmTotalTime += TimeNewDn + TimeNewUp;
|
|
pEdcaParam->AcmOutTime[AcId] += TimeNewDn;
|
|
pEdcaParam->AcmAcTime[AcId] += TimeNewDn + TimeNewUp;
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
if (ACMR_IS_STA_MODE(pAd))
|
|
{
|
|
pEdcaParam->AcmTotalTime += TimeNewUp;
|
|
pEdcaParam->AcmOutTime[AcId] += TimeNewUp;
|
|
pEdcaParam->AcmAcTime[AcId] += TimeNewUp;
|
|
} /* End of if */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
|
|
|
|
/* substract old medium time from total ACM time parameters */
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmTotalTime >= (TimeOldDn + TimeOldUp))
|
|
pEdcaParam->AcmTotalTime -= (TimeOldDn + TimeOldUp);
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
if (ACMR_IS_STA_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmTotalTime >= TimeOldUp)
|
|
pEdcaParam->AcmTotalTime -= TimeOldUp;
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
else
|
|
{
|
|
pEdcaParam->AcmTotalTime = 0; /* fatal error */
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> Used total ACM time < stream medium time! "
|
|
"EDCA_Param_ACM_Update()\n"));
|
|
} /* End of if */
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmOutTime[AcId] >= TimeOldDn)
|
|
pEdcaParam->AcmOutTime[AcId] -= TimeOldDn;
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
if (ACMR_IS_STA_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmOutTime[AcId] >= TimeOldUp)
|
|
pEdcaParam->AcmOutTime[AcId] -= TimeOldUp;
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
else
|
|
{
|
|
pEdcaParam->AcmOutTime[AcId] = 0; /* fatal error */
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> Used ACM time < stream medium time! "
|
|
"EDCA_Param_ACM_Update()\n"));
|
|
} /* End of if */
|
|
|
|
|
|
/* update the ACM used time of the AC */
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmAcTime[AcId] >= (TimeOldDn + TimeOldUp))
|
|
pEdcaParam->AcmAcTime[AcId] -= (TimeOldDn + TimeOldUp);
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
if (ACMR_IS_STA_MODE(pAd))
|
|
{
|
|
if (pEdcaParam->AcmAcTime[AcId] >= TimeOldUp)
|
|
pEdcaParam->AcmAcTime[AcId] -= TimeOldUp;
|
|
/* End of if */
|
|
} /* End of if */
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
else
|
|
{
|
|
pEdcaParam->AcmAcTime[AcId] = 0; /* fatal error */
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> Used AC ACM time < stream medium time! "
|
|
"EDCA_Param_ACM_Update()\n"));
|
|
} /* End of if */
|
|
|
|
|
|
#ifdef RELEASE_EXCLUDE
|
|
/* dynamic ATL: update DATL time only in QAP */
|
|
if (pEdcaParam->FlgDatl)
|
|
{
|
|
ACM_DATL_Update(pAd, AcId, AcmTimeOld, AcmTimeNew,
|
|
VbAcId, VbBandwidth);
|
|
} /* End of if */
|
|
#endif /* RELEASE_EXCLUDE */
|
|
|
|
|
|
/* update available ACM time */
|
|
TimeUsed = pEdcaParam->AcmTotalTime;
|
|
#ifdef ACM_CC_FUNC_MBSS
|
|
TimeUsed += ACMR_CB->MbssTotalUsedTime;
|
|
#endif /* ACM_CC_FUNC_MBSS */
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
if (ACMR_IS_AP_MODE(pAd))
|
|
{
|
|
ACMR_AVAIL_ACM_TIME_UPDATE(pAd, TimeUsed);
|
|
} /* End of if */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
} /* End of ACM_EDCA_Param_ACM_Update */
|
|
|
|
|
|
|
|
|
|
/* ====================== Private Function (WMM) =========================== */
|
|
|
|
#ifdef ACM_CC_FUNC_WMM
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Translate 11e status code to WME status code.
|
|
|
|
Arguments:
|
|
StatusCode - 11e status code
|
|
|
|
Return Value:
|
|
WME status code
|
|
|
|
Note:
|
|
Only 3 status code for WMM ACM.
|
|
|
|
WLAN_STATUS_CODE_WME_INVALID_PARAM - invalid TSPEC parameters
|
|
WLAN_STATUS_CODE_WME_ACM_ACCEPTED - accept
|
|
WLAN_STATUS_CODE_WME_REFUSED - refuse due to insufficient BW
|
|
========================================================================
|
|
*/
|
|
STATIC UCHAR ACM_11E_WMM_StatusTranslate(
|
|
ACM_PARAM_IN UCHAR StatusCode)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> 11e status code = %d\n", StatusCode));
|
|
|
|
if (StatusCode == ACM_STATUS_CODE_INVALID_PARAMETERS)
|
|
return WLAN_STATUS_CODE_WME_INVALID_PARAM;
|
|
/* End of if */
|
|
|
|
if (StatusCode == ACM_STATUS_CODE_SUCCESS)
|
|
return WLAN_STATUS_CODE_WME_ACM_ACCEPTED;
|
|
/* End of if */
|
|
|
|
return WLAN_STATUS_CODE_WME_REFUSED;
|
|
} /* End of ACM_11E_WMM_StatusTranslate */
|
|
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Translate WME TSPEC & TCLAS to 11e TSPEC & TCLAS.
|
|
|
|
Arguments:
|
|
*pPktElm - the TSPEC related element in the packet buffer
|
|
BodyLen - the action frame length
|
|
*pETspec - the 11e TSPEC
|
|
*pTclas - the 11e TCLAS
|
|
*pTclasNum - the number of TCLAS
|
|
*pTclasProcessing - the TCLAS PROCESSING value
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - translate ok
|
|
ACM_RTN_FAIL - translate fail
|
|
|
|
Note:
|
|
Internally we use 11e TSPEC, not WMM TSPEC.
|
|
========================================================================
|
|
*/
|
|
STATIC ACM_FUNC_STATUS ACM_WME_11E_TSPEC_TCLAS_Translate(
|
|
ACM_PARAM_IN UCHAR *pPktElm,
|
|
ACM_PARAM_IN UINT32 BodyLen,
|
|
ACM_PARAM_IN ACM_TSPEC *pETspec,
|
|
ACM_PARAM_IN ACM_TCLAS **pTclas,
|
|
ACM_PARAM_IN UINT32 *pTclasNum,
|
|
ACM_PARAM_IN UCHAR *pTclasProcessing)
|
|
{
|
|
ACM_WME_TSPEC *pTspec;
|
|
ACM_ELM_WME_TCLAS *pElmTclas;
|
|
ACM_ELM_WME_TCLAS_PROCESSING *pElmTclasProcessing;
|
|
UCHAR *pElm;
|
|
UCHAR ElmID, ElmLen, ElmSubID;
|
|
UCHAR TclasType;
|
|
UINT32 IdTclasNum;
|
|
|
|
|
|
/* init */
|
|
pTspec = NULL;
|
|
|
|
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
|
|
pTclas[IdTclasNum] = NULL;
|
|
/* End of for */
|
|
|
|
pElm = (UCHAR *)pPktElm;
|
|
|
|
*pTclasNum = 0;
|
|
*pTclasProcessing = ACM_TCLAS_PROCESSING_NOT_EXIST;
|
|
|
|
BodyLen -= 4; /* skip Category, action, DialogToken, & StatusCode */
|
|
|
|
/* parsing TSPEC, TCLASS, & TCLASS Processing elements */
|
|
while(BodyLen > 0)
|
|
{
|
|
ElmID = *pElm;
|
|
ElmLen = *(pElm+1);
|
|
|
|
if (BodyLen < (UINT32)(ACM_ELM_ID_LEN_SIZE+ElmLen))
|
|
{
|
|
/* fatal error, packet size is not enough */
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> packet length %d is too small %d! "
|
|
"WME_11E_TSPEC_TCLAS_Translate()\n",
|
|
BodyLen, (ACM_ELM_ID_LEN_SIZE+ElmLen)));
|
|
goto LabelParseErr;
|
|
} /* End of if */
|
|
|
|
/* not check *(pElm+1) = element length and
|
|
not check *(pElm+6) = WMM sub element ID */
|
|
if ((ElmID != ACM_ELM_WME_ID) ||
|
|
(*(pElm+2) != ACM_WME_OUI_0) ||
|
|
(*(pElm+3) != ACM_WME_OUI_1) ||
|
|
(*(pElm+4) != ACM_WME_OUI_2) ||
|
|
(*(pElm+5) != ACM_WME_OUI_TYPE) ||
|
|
(*(pElm+7) != ACM_WME_OUI_VERSION))
|
|
{
|
|
/* not WMM element so check next element */
|
|
pElm += (ACM_ELM_ID_LEN_SIZE+ElmLen);
|
|
BodyLen -= (ACM_ELM_ID_LEN_SIZE+ElmLen);
|
|
continue;
|
|
} /* End of if */
|
|
|
|
ElmSubID = *(pElm+ACM_WME_OUI_ID_OFFSET);
|
|
|
|
switch(ElmSubID)
|
|
{
|
|
case ACM_WME_OUI_SUBTYPE_TSPEC: /* TSPEC element */
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> find a WMM TSPEC element! "
|
|
"WME_11E_TSPEC_TCLAS_Translate()\n"));
|
|
|
|
pTspec = &((ACM_ELM_WME_TSPEC *)pElm)->Tspec;
|
|
|
|
if (ACM_WME_11E_TSPEC_Translate(pTspec,
|
|
pETspec) != ACM_RTN_OK)
|
|
{
|
|
goto LabelParseErr;
|
|
} /* End of if */
|
|
break;
|
|
|
|
case ACM_WSM_OUI_SUBTYPE_TCLAS: /* TCLASS element */
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> find a WMM TCLAS element! "
|
|
"WME_11E_TSPEC_TCLAS_Translate()\n"));
|
|
|
|
/* sanity check for TCLAS number & element length */
|
|
if ((*pTclasNum) >= ACM_TCLAS_MAX_NUM)
|
|
goto LabelParseErr;
|
|
/* End of if */
|
|
|
|
/* skip element id/len, OUI header, user priority */
|
|
TclasType = *(pElm+2+ACM_WME_OUI_HDR_LEN+1);
|
|
|
|
switch(TclasType)
|
|
{
|
|
case ACM_TCLAS_TYPE_ETHERNET:
|
|
if (ElmLen != ACM_TCLAS_TYPE_WME_ETHERNET_LEN)
|
|
goto LabelParseErr;
|
|
/* End of if */
|
|
break;
|
|
|
|
case ACM_TCLAS_TYPE_IP_V4:
|
|
if (ElmLen != ACM_TCLAS_TYPE_WME_IP_V4_LEN)
|
|
goto LabelParseErr;
|
|
/* End of if */
|
|
break;
|
|
|
|
case ACM_TCLAS_TYPE_8021DQ:
|
|
if (ElmLen != ACM_TCLAS_TYPE_WME_8021DQ_LEN)
|
|
goto LabelParseErr;
|
|
/* End of if */
|
|
break;
|
|
|
|
default:
|
|
goto LabelParseErr;
|
|
} /* End of switch */
|
|
|
|
pElmTclas = (ACM_ELM_WME_TCLAS *)pElm;
|
|
pTclas[(*pTclasNum)++] = &pElmTclas->Tclas;
|
|
break;
|
|
|
|
case ACM_WSM_OUI_SUBTYPE_TCLAS_PROCESSING: /* TCLASS Processing */
|
|
if (ElmLen != ACM_ELM_WME_TCLAS_PROCESSING_LEN)
|
|
goto LabelParseErr;
|
|
/* End of if */
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> find a WMM TCLAS PROCESSING element! "
|
|
"WME_11E_TSPEC_TCLAS_Translate()\n"));
|
|
|
|
pElmTclasProcessing = (ACM_ELM_WME_TCLAS_PROCESSING *)pElm;
|
|
*pTclasProcessing = pElmTclasProcessing->Processing;
|
|
break;
|
|
} /* End of switch */
|
|
|
|
/* check next element */
|
|
pElm += (2+ElmLen); /* 2: Element ID & Element Length */
|
|
BodyLen -= (2+ElmLen); /* 2: Element ID & Element Length */
|
|
} /* End of while */
|
|
|
|
return ACM_RTN_OK;
|
|
|
|
LabelParseErr:
|
|
return ACM_RTN_FAIL;
|
|
} /* End of ACM_WME_11E_TSPEC_TCLAS_Translate */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Translate WME TSPEC to 11e TSPEC.
|
|
|
|
Arguments:
|
|
*pWTspec - the 'W'ME TSPEC
|
|
*pETspec - the 11'e' TSPEC
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - translate ok
|
|
ACM_RTN_FAIL - translate fail
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
STATIC ACM_FUNC_STATUS ACM_WME_11E_TSPEC_Translate(
|
|
ACM_PARAM_IN ACM_WME_TSPEC *pWTspec,
|
|
ACM_PARAM_IN ACM_TSPEC *pETspec)
|
|
{
|
|
ACM_TS_INFO *pInfo;
|
|
|
|
|
|
/* init */
|
|
pInfo = &pETspec->TsInfo;
|
|
|
|
/* translate WMM TSPEC to 11e TSPEC */
|
|
ACMR_MEM_ZERO((UCHAR *)pETspec, sizeof(ACM_TSPEC));
|
|
|
|
/* init TS Info field */
|
|
pInfo->TrafficType = pWTspec->TsInfo.Reserved4;
|
|
pInfo->TSID = pWTspec->TsInfo.TID;
|
|
|
|
pInfo->Direction = pWTspec->TsInfo.Direction;
|
|
pInfo->AccessPolicy = pWTspec->TsInfo.One;
|
|
pInfo->Aggregation = pWTspec->TsInfo.Zero1;
|
|
pInfo->APSD = pWTspec->TsInfo.PSB;
|
|
pInfo->UP = pWTspec->TsInfo.UP;
|
|
|
|
#ifdef ACM_CC_FUNC_11N_AGG
|
|
pInfo->AckPolicy = pWTspec->TsInfo.AckPolicy;
|
|
#endif /* ACM_CC_FUNC_11N_AGG */
|
|
|
|
/* in WMM ACM TG, we need to check bit16 ~ 23 and bit8 == 0,
|
|
and we will not use schedule field, so we set (bit16 ~ 23 | bit8)
|
|
to the field */
|
|
pInfo->Schedule = pWTspec->TsInfo.Reserved1 |
|
|
pWTspec->TsInfo.Reserved3;
|
|
|
|
/* init TSPEC parameters */
|
|
pETspec->NominalMsduSize = pWTspec->NominalMsduSize;
|
|
pETspec->MaxMsduSize = pWTspec->MaxMsduSize;
|
|
pETspec->MinServInt = pWTspec->MinServInt;
|
|
pETspec->MaxServInt = pWTspec->MaxServInt;
|
|
if (pWTspec->InactivityInt == 0)
|
|
{
|
|
/* can not be 0 so use default timeout */
|
|
pETspec->InactivityInt = ACM_WME_TSPEC_INACTIVITY_DEFAULT;
|
|
}
|
|
else
|
|
pETspec->InactivityInt = pWTspec->InactivityInt;
|
|
/* End of if */
|
|
|
|
pETspec->SuspensionInt = pWTspec->SuspensionInt;
|
|
pETspec->ServiceStartTime = pWTspec->ServiceStartTime;
|
|
pETspec->MinDataRate = pWTspec->MinDataRate;
|
|
pETspec->MeanDataRate = pWTspec->MeanDataRate;
|
|
pETspec->PeakDataRate = pWTspec->PeakDataRate;
|
|
|
|
/* if you want to issue NULL TSPEC, Min = Mean = Peak = 0 */
|
|
if (pETspec->MeanDataRate == 0)
|
|
{
|
|
if (pETspec->PeakDataRate != 0)
|
|
pETspec->MeanDataRate = pETspec->PeakDataRate;
|
|
else
|
|
{
|
|
if (pETspec->MinDataRate != 0)
|
|
pETspec->MeanDataRate = pETspec->MinDataRate;
|
|
/* End of if */
|
|
} /* End of if */
|
|
} /* End of if */
|
|
|
|
pETspec->MaxBurstSize = pWTspec->MaxBurstSize;
|
|
pETspec->DelayBound = pWTspec->DelayBound;
|
|
pETspec->MinPhyRate = pWTspec->MinPhyRate;
|
|
pETspec->SurplusBandwidthAllowance = \
|
|
pWTspec->SurplusBandwidthAllowance;
|
|
pETspec->MediumTime = pWTspec->MediumTime;
|
|
return ACM_RTN_OK;
|
|
} /* End of ACM_WME_11E_TSPEC_Translate */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Make a WME action frame body.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pStream - the stream
|
|
*pPkt - the frame body pointer
|
|
Action - action
|
|
StatusCode - status code, used when action = response
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - insert ok
|
|
ACM_RTN_FAIL - insert fail
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
STATIC UINT32 ACM_WME_ActionFrameBodyMake(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN ACM_STREAM *pStream,
|
|
ACM_PARAM_IN UCHAR *pPkt,
|
|
ACM_PARAM_IN UCHAR Action,
|
|
ACM_PARAM_IN UCHAR StatusCode)
|
|
{
|
|
ACM_WME_NOT_FRAME *pFrameBody;
|
|
ACM_ELM_WME_TSPEC *pElmTspec;
|
|
ACM_ELM_WME_TCLAS_PROCESSING *pElmTspecProcessing;
|
|
ACM_WME_TS_INFO *pInfo;
|
|
ACM_WME_TSPEC *pTspec;
|
|
UCHAR *pElmTclas;
|
|
UINT32 BodyLen, Len;
|
|
UINT32 IdTclasNum;
|
|
|
|
|
|
/* sanity check for type */
|
|
if (Action > ACM_ACTION_WME_TEAR_DOWN)
|
|
return 0;
|
|
/* End of if */
|
|
|
|
/* init frame body */
|
|
pFrameBody = (ACM_WME_NOT_FRAME *)pPkt;
|
|
pFrameBody->Category = ACM_CATEGORY_WME;
|
|
pFrameBody->Action = Action;
|
|
|
|
if (Action != ACM_ACTION_WME_TEAR_DOWN)
|
|
pFrameBody->DialogToken = pStream->DialogToken;
|
|
else
|
|
pFrameBody->DialogToken = 0; /* always 0 for DELTS */
|
|
/* End of if */
|
|
|
|
pFrameBody->StatusCode = StatusCode;
|
|
BodyLen = 4;
|
|
|
|
/* TSPEC element */
|
|
pElmTspec = &pFrameBody->ElmTspec;
|
|
pElmTspec->ElementId = ACM_ELM_WME_ID;
|
|
pElmTspec->Length = ACM_ELM_WME_TSPEC_LEN;
|
|
|
|
/* init OUI field */
|
|
pElmTspec->OUI[0] = ACM_WME_OUI_0;
|
|
pElmTspec->OUI[1] = ACM_WME_OUI_1;
|
|
pElmTspec->OUI[2] = ACM_WME_OUI_2;
|
|
pElmTspec->OUI_Type = ACM_WME_OUI_TYPE;
|
|
pElmTspec->OUI_SubType = ACM_WME_OUI_SUBTYPE_TSPEC;
|
|
pElmTspec->Version = ACM_WME_OUI_VERSION;
|
|
|
|
/* init TS Info field */
|
|
pTspec = &pFrameBody->ElmTspec.Tspec;
|
|
ACMR_MEM_ZERO(pTspec, sizeof(ACM_WME_TSPEC));
|
|
pInfo = &pFrameBody->ElmTspec.Tspec.TsInfo;
|
|
|
|
pInfo->TID = pStream->pTspec->TsInfo.TSID;
|
|
pInfo->Direction = pStream->pTspec->TsInfo.Direction;
|
|
pInfo->UP = pStream->pTspec->TsInfo.UP;
|
|
pInfo->PSB = pStream->pTspec->TsInfo.APSD;
|
|
pInfo->One = 1; /* always 1 */
|
|
|
|
#ifdef ACM_CC_FUNC_11N_AGG
|
|
pInfo->AckPolicy = pStream->pTspec->TsInfo.AckPolicy;
|
|
#endif /* ACM_CC_FUNC_11N_AGG */
|
|
|
|
/* init TSPEC parameters */
|
|
pTspec->NominalMsduSize = pStream->pTspec->NominalMsduSize;
|
|
pTspec->MaxMsduSize = pStream->pTspec->MaxMsduSize;
|
|
pTspec->MinServInt = pStream->pTspec->MinServInt;
|
|
pTspec->MaxServInt = pStream->pTspec->MaxServInt;
|
|
pTspec->InactivityInt = pStream->pTspec->InactivityInt;
|
|
pTspec->SuspensionInt = pStream->pTspec->SuspensionInt;
|
|
pTspec->ServiceStartTime = pStream->pTspec->ServiceStartTime;
|
|
pTspec->MinDataRate = pStream->pTspec->MinDataRate;
|
|
pTspec->MeanDataRate = pStream->pTspec->MeanDataRate;
|
|
pTspec->PeakDataRate = pStream->pTspec->PeakDataRate;
|
|
pTspec->MaxBurstSize = pStream->pTspec->MaxBurstSize;
|
|
pTspec->DelayBound = pStream->pTspec->DelayBound;
|
|
pTspec->MinPhyRate = pStream->pTspec->MinPhyRate;
|
|
pTspec->SurplusBandwidthAllowance = \
|
|
pStream->pTspec->SurplusBandwidthAllowance;
|
|
|
|
if (pTspec->TsInfo.Direction != ACM_DIRECTION_DOWN_LINK)
|
|
{
|
|
/* we need to fill medium time if the link is not downlink-only */
|
|
pTspec->MediumTime = pStream->pTspec->MediumTime;
|
|
} /* End of if */
|
|
|
|
BodyLen += (ACM_ELM_ID_LEN_SIZE+pElmTspec->Length);
|
|
|
|
/* TCLASS element */
|
|
pElmTclas = pFrameBody->Tclas;
|
|
|
|
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
|
|
{
|
|
if (pStream->pTclas[IdTclasNum] != NULL)
|
|
{
|
|
*pElmTclas++ = ACM_ELM_WME_ID;
|
|
Len = ACM_TCLAS_LEN_GET(pStream->pTclas[IdTclasNum]->ClassifierType);
|
|
*pElmTclas++ = Len;
|
|
|
|
*pElmTclas++ = ACM_WME_OUI_0;
|
|
*pElmTclas++ = ACM_WME_OUI_1;
|
|
*pElmTclas++ = ACM_WME_OUI_2;
|
|
*pElmTclas++ = ACM_WME_OUI_TYPE;
|
|
*pElmTclas++ = ACM_WSM_OUI_SUBTYPE_TCLAS;
|
|
*pElmTclas++ = ACM_WME_OUI_VERSION;
|
|
|
|
ACMR_MEM_COPY(pElmTclas,
|
|
pStream->pTclas[IdTclasNum],
|
|
Len-ACM_WME_OUI_HDR_LEN);
|
|
|
|
pElmTclas += (Len-ACM_WME_OUI_HDR_LEN);
|
|
|
|
BodyLen += (ACM_ELM_ID_LEN_SIZE+Len);
|
|
continue; /* check next TCLAS */
|
|
} /* End of if */
|
|
|
|
break; /* no more TCLAS exists */
|
|
} /* End of for */
|
|
|
|
/* TCLASS Processing element */
|
|
if (pStream->pTclas[0] != NULL)
|
|
{
|
|
/*
|
|
TCLAS PROCESSING element exists only when at least one TCLAS
|
|
element exists.
|
|
*/
|
|
if (pStream->TclasProcessing != ACM_TCLAS_PROCESSING_NOT_EXIST)
|
|
{
|
|
pElmTspecProcessing = (ACM_ELM_WME_TCLAS_PROCESSING *)pElmTclas;
|
|
BodyLen += (ACM_ELM_ID_LEN_SIZE+ACM_ELM_WME_TCLAS_PROCESSING_LEN);
|
|
|
|
pElmTspecProcessing->ElementId = ACM_ELM_WME_ID;
|
|
pElmTspecProcessing->Length = ACM_ELM_WME_TCLAS_PROCESSING_LEN;
|
|
|
|
pElmTspecProcessing->OUI[0] = ACM_WME_OUI_0;
|
|
pElmTspecProcessing->OUI[1] = ACM_WME_OUI_1;
|
|
pElmTspecProcessing->OUI[2] = ACM_WME_OUI_2;
|
|
pElmTspecProcessing->OUI_Type = ACM_WME_OUI_TYPE;
|
|
pElmTspecProcessing->OUI_SubType = ACM_WSM_OUI_SUBTYPE_TCLAS_PROCESSING;
|
|
pElmTspecProcessing->Version = ACM_WME_OUI_VERSION;
|
|
|
|
pElmTspecProcessing->Processing = pStream->TclasProcessing;
|
|
} /* End of if */
|
|
} /* End of if */
|
|
|
|
return BodyLen;
|
|
} /* End of ACM_WME_ActionFrameBodyMake */
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Handle a WME action frame.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pCdb - the source QSTA
|
|
*pFrameBody - the action frame body
|
|
BodyLen - the length of action frame body
|
|
PhyRate - the physical tx rate for the frame, bps
|
|
Action - Setup request, response, or teardown
|
|
*pStatusCode - response status code
|
|
*pMediumTime - the allowed medium time
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
STATIC VOID ACM_WME_ActionHandle(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN ACMR_STA_DB *pCdb,
|
|
ACM_PARAM_IN UCHAR *pFrameBody,
|
|
ACM_PARAM_IN UINT32 BodyLen,
|
|
ACM_PARAM_IN UINT32 PhyRate,
|
|
ACM_PARAM_IN UCHAR Action,
|
|
ACM_PARAM_OUT UCHAR *pStatusCode,
|
|
ACM_PARAM_OUT UINT16 *pMediumTime)
|
|
{
|
|
ACM_WME_NOT_FRAME *pNotFrame;
|
|
ACM_TCLAS *pTclas[ACM_TSPEC_TCLAS_MAX_NUM];
|
|
ACM_TSPEC Tspec;
|
|
UINT32 TclasNum;
|
|
UCHAR TclasProcessing;
|
|
UCHAR StatusCode;
|
|
ACM_FUNC_STATUS RtnCode;
|
|
|
|
|
|
/* init */
|
|
pNotFrame = (ACM_WME_NOT_FRAME *)pFrameBody;
|
|
TclasNum = 0;
|
|
TclasProcessing = ACM_TCLAS_PROCESSING_NOT_EXIST;
|
|
StatusCode = ACM_STATUS_CODE_SUCCESS;
|
|
|
|
/* sanity check for input parameters */
|
|
if (Action > ACM_ACTION_WME_TEAR_DOWN)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> Error action type = %d! "
|
|
"WME_ActionHandle()\n", Action));
|
|
return;
|
|
} /* End of if */
|
|
|
|
if (ACM_WME_ELM_Check((UCHAR *)&pNotFrame->ElmTspec,
|
|
ACM_WME_OUI_SUBTYPE_TSPEC) != ACM_RTN_OK)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> Element check error! "
|
|
"WME_ActionHandle()\n"));
|
|
return; /* TSPEC element error */
|
|
} /* End of if */
|
|
|
|
if (BodyLen < ACM_NOT_FRAME_BODY_LEN)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> Frame length is not enough! "
|
|
"WME_ActionHandle()\n"));
|
|
return; /* error! < minimum action frame length */
|
|
} /* End of if */
|
|
|
|
/* translate WME TSPEC to 11e TSPEC */
|
|
if (ACM_WME_11E_TSPEC_TCLAS_Translate(
|
|
(UCHAR *)&pNotFrame->ElmTspec,
|
|
BodyLen,
|
|
&Tspec,
|
|
pTclas,
|
|
&TclasNum,
|
|
&TclasProcessing) != ACM_RTN_OK)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_ERR,
|
|
("acm_err> Translate TSPEC fail! "
|
|
"WME_ActionHandle()\n"));
|
|
return; /* translate fail */
|
|
} /* End of if */
|
|
|
|
/* handle it by action */
|
|
switch(Action)
|
|
{
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
case ACM_ACTION_WME_SETUP_REQ:
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> A WME Request Frame is RCV! "
|
|
"WME_ActionHandle()\n"));
|
|
|
|
RtnCode = ACM_TC_ReqHandle(
|
|
pAd, pCdb, ACM_STREAM_TYPE_WIFI,
|
|
pNotFrame->DialogToken, &Tspec,
|
|
TclasNum, pTclas,
|
|
TclasProcessing,
|
|
PhyRate, &StatusCode, pMediumTime);
|
|
|
|
if (RtnCode != ACM_RTN_OK)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> A WME Setup request is not allowed %d! "
|
|
"WME_ActionHandle()\n", RtnCode));
|
|
} /* End of if */
|
|
break;
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
case ACM_ACTION_WME_SETUP_RSP:
|
|
RtnCode = ACM_TC_RspHandle(
|
|
pAd, pCdb, pNotFrame->DialogToken,
|
|
pNotFrame->StatusCode,
|
|
&Tspec, NULL, &StatusCode);
|
|
|
|
if (RtnCode != ACM_RTN_OK)
|
|
{
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> A WME Setup response is error %d! "
|
|
"WME_ActionHandle()\n", RtnCode));
|
|
} /* End of if */
|
|
break;
|
|
#endif /* CONFIG_STA_SUPPORT */
|
|
|
|
case ACM_ACTION_WME_TEAR_DOWN:
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE,
|
|
("acm_msg> A WME Tear down is RCV! "
|
|
"DEL the stream! WME_ActionHandle()\n"));
|
|
|
|
ACMP_TC_DestroyBy_TS_Info(
|
|
pAd,
|
|
ACMR_CLIENT_MAC(pCdb),
|
|
&Tspec.TsInfo,
|
|
ACMR_IS_AP_MODE(pAd));
|
|
break;
|
|
|
|
default:
|
|
/* should not be here */
|
|
break;
|
|
} /* End of switch */
|
|
|
|
/* upadte status code */
|
|
*pStatusCode = StatusCode;
|
|
} /* End of ACM_WME_ActionHandle */
|
|
|
|
|
|
|
|
|
|
/* ====================== Private Function (WMM) (AP) ====================== */
|
|
|
|
#ifdef CONFIG_AP_SUPPORT
|
|
#if 0 /* no use */
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Send a WME Setup Response frame to the QSTA.
|
|
|
|
Arguments:
|
|
pAd - WLAN control block pointer
|
|
*pReqNew - the requested TSPEC pointer
|
|
StatusCode - response status
|
|
|
|
Return Value:
|
|
ACM_RTN_OK - send ok
|
|
ACM_RTN_FAIL - send fail
|
|
ACM_RTN_ALLOC_ERR - allocate a frame fail
|
|
|
|
Note:
|
|
1. Use high priority queue to send.
|
|
2. Only for QAP mode.
|
|
========================================================================
|
|
*/
|
|
STATIC ACM_FUNC_STATUS EACM_WME_SETUP_RspSend(
|
|
ACM_PARAM_IN PRTMP_ADAPTER pAd,
|
|
ACM_PARAM_IN ACM_STREAM *pReqNew,
|
|
ACM_PARAM_IN UCHAR StatusCode)
|
|
{
|
|
ACMR_WLAN_HEADER HdrAction;
|
|
NDIS_STATUS Status;
|
|
ULONG FrameLen;
|
|
UCHAR *pBufFrame;
|
|
|
|
|
|
/* init */
|
|
FrameLen = 0;
|
|
pBufFrame = NULL;
|
|
|
|
/* get an unused nonpaged memory */
|
|
Status = MlmeAllocateMemory(pAd, &pBufFrame);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
return ACM_RTN_ALLOC_ERR;
|
|
/* End of if */
|
|
|
|
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Make up a ADDTS response...\n"));
|
|
|
|
/* make the frame header */
|
|
MgtMacHeaderInit(
|
|
pAd, &HdrAction, SUBTYPE_ACTION, 0,
|
|
ACMR_CLIENT_MAC(pReqNew->pCdb),
|
|
pAd->ApCfg.MBSSID[BSS0].Bssid);
|
|
MakeOutgoingFrame(
|
|
pBufFrame, &FrameLen,
|
|
sizeof(ACMR_WLAN_HEADER), &HdrAction,
|
|
END_OF_ARGS);
|
|
|
|
/* make the frame body */
|
|
FrameLen += ACM_WME_ActionFrameBodyMake(
|
|
pAd, pReqNew,
|
|
(UCHAR *)&pBufFrame[FrameLen],
|
|
ACM_ACTION_WME_SETUP_RSP,
|
|
StatusCode);
|
|
|
|
/* send out the frame */
|
|
MiniportMMRequest(pAd, 0, pBufFrame, FrameLen);
|
|
MlmeFreeMemory(pAd, pBufFrame);
|
|
return ACM_RTN_OK;
|
|
} /* End of EACM_WME_SETUP_RspSend */
|
|
#endif /* #if 0 */
|
|
#endif /* CONFIG_AP_SUPPORT */
|
|
|
|
#endif /* ACM_CC_FUNC_WMM */
|
|
|
|
#endif /* WMM_ACM_SUPPORT */
|
|
|
|
/* End of acm_edca.c */
|
|
|