Files
Linux_Drivers/osdrv/extdrv/wireless/mediatek/mt7603/common/acm_comm.c
forum_service 213c880673 add driver of tp、wiegand-gpio and wireless
Change-Id: Ie3c11d9d85cf1a05042f5690ac711856fe8b1ad7
2023-12-22 09:56:05 +08:00

14778 lines
371 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 common (AP/STA) function body.
History:
1. 2009/08/26 Sample Lin
(1) Move ACM_APSD_Ctrl() to ACM_TC_Destroy()
(2) Do not delete TSPEC if DELTS is not sent to STA when STA
is in Power Save mode, i.e. UAPSD mode.
(3) Duplicate action frames to legacy PS queue
in AP_QueuePsActionPacket if UAPSD of VO is enabled,
not all ACs are UAPSD mode and STA is in PS mode.
2. 2009/09/29 Sample Lin
(1) Improve WMM ACM TCLAS add command in acm_iocl.c.
(2) No need check timeout if timeout function is disabled in
ACMP_DataNullHandle().
(3) No need TCLAS UP check in ACMP_DataNullHandle().
3. 2009/11/09 Sample Lin
(1) Add some TODO notes in the fucture.
4. 2009/12/15 Sample Lin
(1) Fix bugs in CPU 64bit. Can not use (UINT32)pAd.
5. 2009/12/22 Sample Lin
(1) Fix bugs for big-endian mode in acm_extr.h.
6. 2010/01/07 Sample Lin
(1) Add function: ACL list. (admit control list)
Only accept ACM request in the list.
(2) Add function: Aggregation (AMSDU)
(3) Fix bug: LenDataId --
No need to do "LenDataId --" when getting LenDataId.
EX: Data Size = 64, LenDataId will be 64 >> 5 = 2
So the tx time of 64B will be same as the tx time of 95B.
(64+32-1 = 95B)
7. 2010/01/25 Sample Lin
(1) Fix bug: Minimum physical rate infinite loop when rate is
not one of supported rates.
8. 2010/02/20 Sample Lin
(1) Fix bug: Minimum physical rate of TSPEC must meet support
rate list, but the rule is error for 5.5Mbps.
(2) Fix bug: Bandwidth check for bi-directional TSPEC replacement.
The problem will occur when the available ACM capacity is less.
(3) Fix bug: Only station mode, update QBSS Load from AP.
The problem will only influence the OBSS load element in beacon.
9. 2010/06/10 Sample Lin
(1) Fix bug: In RTMPDeQueuePacket, after calling ACMP_MsduClassify,
if we decide to discard the packet, we also need to do unlock.
10. 2010/07/07 Sample Lin
(1) Fix bug: Improve/Add spin lock to protect some resources.
11. 2010/09/03 Sample Lin
(1) Fix bug: In AP mode, need to check ERP element for RTS/CTS
calculation.
12. 2010/09/10 Sample Lin
(1) Fix bug: In AP mode, when station sends a TSPEC without correct
physical rate, we will re-select the wrong rate.
12. 2010/09/23 Sample Lin
(1) Add 11n AMSDU and AMPDU TSPEC based on
WMM_Specification_1.2-wmmac-11n-100622-mgr.doc.
***************************************************************************/
#ifdef RELEASE_EXCLUDE
/*
Code Size Information in PC (Debian 2.6.18-6-686):
1. No ACM Module
text data bss dec hex filename
393045 25088 4188 422321 671b1 os/linux/rt2860ap.ko
Size = 0, Data = 0
2. ACM Module (includes Simulation Code & Debug)
text data bss dec hex filename
448015 25196 31276 504487 7b2a7 os/linux/rt2860ap.ko
Size = 54970B, Data = 27088B
3. ACM Module (includes Debug)
text data bss dec hex filename
438303 25184 31016 494503 78ba7 os/linux/rt2860ap.ko
Size = 45258B, Data = 26828B
4. ACM Module
text data bss dec hex filename
295407 25024 4188 324619 4f40b os/linux/rt2860ap.ko
text data bss dec hex filename
331018 25120 31016 387154 5e852 os/linux/rt2860ap.ko
Size = 35611B, Data = 26828B
*/
/*
Performance Impact:
Rate (from window station UI): 270M/270M
Chariot: 2 uplinks + 2 dnlinks, TCP, high throughput script
Window Station: v3.0.99.159/ v1.4.1.42/ v0.1.0.146/ v1.1/ v0.19
Platform: 5VT (as below)
Processor : ARM926EJ-Sid(wb) rev 5 (v5l)
BogoMIPS : 285.90
Features : swp half fastmult edsp java
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant : 0x0
CPU part : 0x926
CPU revision : 5
Cache type : write-back
Cache clean : cp15 c7 ops
Cache lockdown : format C
Cache format : Harvard
I size : 16384
I assoc : 4
I line length : 32
I sets : 128
D size : 16384
D assoc : 4
D line length : 32
D sets : 128
Hardware : 5VT13XX
Revision : 0000
Serial : 0000000000000000
1. WMM ACM included (no any ACM of AC is enabled)
BE throughput impact: 0 ~ 1Mbps (117Mbps)
(2 uplinks: 44.1M; 2 dnlinks: 14.8M)
2. WMM ACM included (all ACM of AC are enabled but no any TSPEC)
BE throughput impact: 0 ~ 1Mbps (117Mbps)
3. WMM ACM included (ACM of VO/VI are enabled and a bi-VOICE TSPEC)
BE throughput impact: 1 ~ 2Mbps (116Mbps)
4. WMM ACM included (all ACM of AC are enabled and a bi-BE TSPEC)
a. No statistics count/ only ACM when queuing data/ rough tx time
BE throughput impact: 2 ~ 13Mbps (average 105Mbps)
b. No statistics count/ only ACM when queuing data/ accurate tx time
BE throughput impact: 2 ~ 16Mbps (average 102Mbps)
(Text Size: 445257B - 393045B = 52212B)
(BSS Size: 4716B - 4188B = 528B)
c. No statistics count/ ACM when queuing data and tx/ rough tx time
BE throughput impact: 2 ~ 19Mbps (average 99Mbps)
d. No statistics count/ ACM when queuing data and tx/ accurate tx time
BE throughput impact: 2 ~ 23Mbps (average 95Mbps)
e. Statistics count/ ACM when queuing data and tx/ accurate tx time
BE throughput impact: 2 ~ 23Mbps (average 95Mbps)
*/
#endif /* RELEASE_EXCLUDE */
#ifdef RELEASE_EXCLUDE
/*
WMM ACM Design Note
Protection:
Any ACMP_xxx function, we must do protection in these functions except
you can sure no any ACM resouce is accessed.
We do no need to do protection in other local functions.
Task:
ACM_TASK_General
responsible for multiple BSS ACM function or
chan utilization monitor function
ACM_TASK_STM_Check
responsible for TSPEC timeout monitor function
ACM_TASK_TC_ReqCheck
responsible for TSPEC request timeout monitor function (STA-only)
Management Action Frame Input Flow:
1. common/action.c PeerWMMAction
2. common/acm_comm.c ACMP_ManagementHandle
ACM_ActionHandleByQAP or ACM_ActionHandleByQSTA
3. common/acm_edca.c ACM_WME_ActionHandle
4. common/acm_comm.c ACM_TC_ReqHandle, ACM_TC_RspHandle, or
ACM_TC_DestroyBy_TS_Info
TSPEC Request Flow in STA mode:
ACMP_WME_TC_Request() : Send a new TSPEC to the AP
When STA is in Power Save mode, we have two methods to send the TSPEC
Request frame by ACM_CC_FUNC_PS_MGMT_FME:
1. Send Request in ACTIVE mode (default)
(1) ACM_PS_ActiveOn, let STA enters ACTIVE mode temporarily;
(2) Send the TSPEC Request Frame;
(3) Wait for the TSPEC Response Frame or timeout;
(4) ACMP_StaPsCtrlRightReturn, let STA restores to old mode.
Note: Maybe many TSPEC Request Frames are sent simultaneously so
ACMP_StaPsCtrlRightReturn is NOT put in ACM_TC_RspHandle.
We will call it when no any request is pending.
2. Send Request in Power Save mode (not recommendation in WiFi test plan)
(1) Set PM bit of 802.11 header in the TSPEC Request Frame;
(2) Send the TSPEC Request Frame;
(3) Send any trigger frame or PS-Poll frame to get TSPEC Response
Frame based on dynamic or static power save mode.
Note: Currently we do not care about replacement rules defined in
WiFi test plan so we can send a request with any set (TID vs UP).
TSPEC Negotiate Flow in STA mode:
ACMP_TC_Renegotiate() : Send a negotiation TSPEC to the AP
Power Save behavior is same as "TSPEC Request Flow in STA mode".
1. If negotiation fail, we must not delete original TSPEC.
2. If negotiation success, we must replace original TSPEC with the one.
TSPEC Response Flow in AP mode:
ACM_TC_ReqHandle Handle a TSPEC Request/Negotiation
1. STA is in ACTIVE mode
Send the response directly.
2. STA is in POWER SAVE mode
(1) If UAPSD of VO is not enabled, queue the response frame in
Legacy-PS queue.
(2) If UAPSD of all ACs are enabled, queue the response frame in
UAPSD queue.
(3) If UAPSD of VO is enabled, queue the response frame in
UAPSD and Legacy-PS queue.
Note: In Spec., we can not put the Power-Save action frame in
Legacy-PS queue but this is dangerous that it is possible that
AP can not delete TSPEC actively.
UAPSD State Check Point: (non-3*3 chips)
1. AP mode
STA is in ACTIVE mode:
(1) Correct Behavior (need hardware support)
Receive a TSPEC request
Send a TSPEC response
Receive the ACK of TSPEC response ==> Change UAPSD state
(2) Current Behavior
Receive a TSPEC request
Send a TSPEC response ==> Change UAPSD state
Receive the ACK of TSPEC response
STA is in POWER-SAVE mode:
(1) Correct Behavior (need hardware support)
Receive a TSPEC request
Queue a TSPEC response
Receive a trigger frame or PS-Poll frame
Send a TSPEC response
Receive the ACK of TSPEC response ==> Change UAPSD state
(2) Current Behavior
Receive a TSPEC request
Queue a TSPEC response
Receive a trigger frame or PS-Poll frame
Send a TSPEC response ==> Change UAPSD state
Receive the ACK of TSPEC response
2. STA mode
(1) Correct Behavior
Send a TSPEC request
Receive a TSPEC response ==> Change UAPSD state
(2) Current Behavior
Send a TSPEC request
Receive a TSPEC response ==> Change UAPSD state
11N Operation:
1. We calculate medium time whatever AMPDU or AMSDU in AP device.
(1) Because we can not predict the MPDU number in a AMPDU or AMSDU.
(2) When we use AMPDU to do transmission, maybe many bandwidth
is wasted, but the bandwidth can be for BE/BK traffic.
2. Parameters
802.11 MAC header Header AES / TKIP Info
FC 2 bytes
Duration 2
Addr 1 6
Addr 2 6
Addr 3 6
Sequence control 2
QoS control 2
FCS 4
Security
AES / TKIP Header 8 8
MIC 8 8
TKIP ICV 0 4
Total 46 50
SNAP header 8
IP header 20
UDP header 8
RTP header 12
Total 48
Normal GI Short GI
MCS 20 40 20 40
0 6.5 13.5 7.2 15.0 Mbps
1 13.0 27.0 14.4 30.0
2 19.5 40.5 21.7 45.0
3 26.0 54.0 28.9 60.0
4 39.0 81.0 43.3 90.0
5 52.0 108.0 57.8 120.0
6 58.5 121.5 65.0 135.0
7 65.0 135.0 72.2 150.0
8 13.0 27.0 14.4 30.0
9 26.0 54.0 28.9 60.0
10 39.0 81.0 43.3 90.0
11 52.0 108.0 57.8 120.0
12 78.0 162.0 86.7 180.0
13 104.0 216.0 115.6 240.0
14 117.0 243.0 130.0 270.0
15 130.0 270.0 144.4 300.0
16 19.5 40.5 21.7 45.0
17 39.0 81.0 43.3 90.0
18 58.5 121.5 65.0 135.0
19 78.0 162.0 86.7 180.0
20 117.0 243.0 130.0 270.0
21 156.0 324.0 173.3 360.0
22 175.5 364.5 195.0 405.0
23 195.0 405.0 216.7 450.0
24 26.0 54.0 28.9 60.0
25 52.0 108.0 57.8 120.0
26 78.0 162.0 86.7 180.0
27 104.0 216.0 115.6 240.0
28 156.0 324.0 173.3 360.0
29 208.0 432.0 231.1 480.0
30 234.0 486.0 260.0 540.0
31 260.0 540.0 288.9 600.0
802.11b 802.11g 802.11a 802.11n-1SS units
Preamble 72 16 16 36 us
Greenfield Preamble 24 us
Long Preamble 144 us
PLCP header 24 4 4 us
Long PLCP 48 us
Signal Extension 0 6 0 us
SIFS 10 10 16 us
Slot 20 20 9 us
DIFS 50 50 34 same as a/g us
EIFS 268 99 89 same as a/g us
ACK 14 14 14 same as a/g bytes
CTS 14 14 14 bytes
RTS 20 20 20 bytes
802.11 MAC 46 46 46 bytes
A-MSDU header 14 bytes (does not include padding)
A-MPDU header 4 bytes (does not include padding)
Block ACK 32 bytes (compressed bitmap)
ht-sig 8 us
ht-gf-stf 8 us
ht-ltf1 4/8 us (4 more us in GF mode)
ht-lft2 4 us
ht-stf 4 us
l-sig 4 us
l-stf 8 us
l-ltf 8 us
mm 36 us
gf 24 us
<< Raw ACK Times >>
802.11b
Long Preamble Short Preamble
Length | Rate 11 5.5 2 1 11 5.5 2 1 Units
14 200 210 250 300 110 120 150 210 us
802.11a
Length | Rate 54 48 36 24 18 12 9 6 Units
14 28 28 28 28 28 32 36 44 us
802.11g
Length | Rate 54 48 36 24 18 12 9 6 Units
14 34 34 34 34 34 38 42 50 us
<< CTS+SIFS Times >>
802.11b
Long Preamble Short Preamble
Length | Rate 11 5.5 2 1 11 5.5 2 1 Units
14 212 222 258 314 116 126 162 218 us
802.11a
Length | Rate 54 48 36 24 18 12 9 6
14 44 44 44 44 44 48 52 60 us
802.11g
Length | Rate 54 48 36 24 18 12 9 6
14 44 44 44 44 44 48 52 60 us
<< RTS+SIFS Times >>
802.11b
Long Preamble Short Preamble
Length | Rate 11 5.5 2 1 11 5.5 2 1 Units
20 217 231 282 362 121 135 186 266 us
802.11a
Length | Rate 54 48 36 24 18 12 9 6
20 44 44 44 44 48 52 60 68 us
802.11g
Length | Rate 54 48 36 24 18 12 9 6
20 44 44 44 44 48 52 60 68 us
3. Fomula
*/
#endif /* RELEASE_EXCLUDE */
#include "rt_config.h"
//#define PERFORMANCE_IMPACT_TEST /* only for test */
//#define WMM_ACM_FUNC_DEBUG /* only for function hang debug */
#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 */
#ifdef WMM_ACM_FUNC_DEBUG
#define WMM_ACM_FUNC_NAME_PRINT(__pMsg) \
ACMR_DEBUG(ACMR_DEBUG_ERR, ("acm_func> %s: %s\n", __FUNCTION__, __pMsg));
#else
#define WMM_ACM_FUNC_NAME_PRINT(__pMsg)
#endif /* WMM_ACM_FUNC_DEBUG */
/* ----- Extern Variable ----- */
/* other WLAN modules */
extern VOID BA_MaxWinSizeReasign(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntryPeer,
OUT UCHAR *pWinSize);
/* from EDCA module (acm_edca.c) */
extern UCHAR gEDCA_UP_AC[]; /* EDCA Priority vs. AC */
extern UCHAR gEDCA_AC_UP[]; /* EDCA AC vs. Priority */
extern UCHAR gEDCA_UP_DSCP[]; /* DSCP vs. Priority */
/* ----- Private Variable ----- */
/* TCLAS related */
UCHAR gTCLAS_Elm_Len[3] = { ACM_TCLAS_TYPE_WME_ETHERNET_LEN,
ACM_TCLAS_TYPE_WME_IP_V4_LEN,
ACM_TCLAS_TYPE_WME_8021DQ_LEN };
UCHAR gAcmTestFlag = 0; /* used for self-test */
#ifdef RELEASE_EXCLUDE
/* Frame TX Rate and TX Time */
/* we pre-calculate transmission time here so we can use the pre-known time to
get the frame tx time on the fly */
#endif /* RELEASE_EXCLUDE */
static const UCHAR gAcmRateLegacy[4] =
{ ACM_RATE_11M, ACM_RATE_5_5M, ACM_RATE_2M, ACM_RATE_1M};
static const UCHAR gAcmRateG[8] =
{ ACM_RATE_54M, ACM_RATE_48M, ACM_RATE_36M, ACM_RATE_24M,
ACM_RATE_18M, ACM_RATE_12M, ACM_RATE_9M, ACM_RATE_6M};
/* cck & ofdm MCS */
#define ACM_RATE_UNIT ((UINT32)100000) /* 100000bps */
#define ACM_CCK_LPM_MIN_MCS 0
#define ACM_CCK_LPM_MAX_MCS 3
#define ACM_CCK_SPM_MIN_MCS 8
#define ACM_CCK_SPM_MAX_MCS 11
UINT8 gAcmMCS_CCK[2][4][2] =
{
/* b mode, [2]: long preamble and short preamble */
/* unit: 100000bps */
{ { 0, 10 }, { 1, 20 }, { 2, 55 }, { 3, 110 } },
{ { 8, 10 }, { 9, 20 }, { 10, 55 }, { 11, 110 } }
};
UINT16 gAcmMCS_OFDM[8][2] =
{
/* g mode */
/* unit: 100000bps */
{ 0, 60 }, { 1, 90 }, { 2, 120 }, { 3, 180 },
{ 4, 240 }, { 5, 360 }, { 6, 480 }, { 7, 540 }
};
#ifndef ACM_CC_FUNC_AUX_TX_TIME
/* use approximation method to calculate packet transmission time */
#ifdef RELEASE_EXCLUDE
/* tx time for frame body, length = 1 ~ 1536 */
#endif /* RELEASE_EXCLUDE */
static UINT16 gAcmTxTimeBody[ACM_RATE_MAX_NUM][ACM_PRE_TIME_DATA_SIZE_NUM];
#ifdef RELEASE_EXCLUDE
/* tx time for cts-self, rts/cts, header, ack */
/*
1st []: rate id is such as ACM_RATE_ID_1M, ...
2nd []: 0 (long preamble), 1 (short preamble)
3rd []: 0 (rate id) 1 (cts-self tx time) 2 (rts/cts tx time)
3 (header time) 4 ack tx time
*/
#endif /* RELEASE_EXCLUDE */
static UINT16 gAcmTxTimeOthers[ACM_RATE_MAX_NUM][2][5];
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
#ifdef ACM_CC_FUNC_11N
#ifdef RELEASE_EXCLUDE
/* [0] for 20 or 40MHz; [1] for Regular or Short GI; [2] for MCS */
#endif /* RELEASE_EXCLUDE */
static const UINT16 gAcmMCS_HT[2][2][32] =
{
/* 20MHz */
{
/* Regular GI */
/* MCS0 ~ MCS31: (unit 100000bps) */
{
65, 130, 195, 260, 390, 520, 585, 650, 130, 260,
390, 520, 780, 1040, 1170, 1300, 195, 390, 585, 780,
1170, 1560, 1755, 1950, 260, 520, 780, 1040, 1560, 2080,
2340, 2600
},
/* Short GI */
/* MCS0 ~ MCS31: (unit 100000bps) */
{
72, 144, 217, 289, 433, 578, 650, 722, 144, 289,
433, 578, 867, 1156, 1300, 1444, 217, 433, 650, 867,
1300, 1733, 1950, 2167, 2890, 578, 867, 1156, 1733, 2311,
2600, 2889
},
},
/* 40MHz */
{
/* Regular GI */
/* MCS0 ~ MCS31: (unit 100000bps) */
/*
In G mode, also have 54Mbps. when your minimum physical rate
is 54Mbps, we will regard the rate as non-11n rate.
*/
{
135, 270, 405, 540, 810, 1080, 1215, 1350, 270, 540,
810, 1080, 1620, 2160, 2430, 2700, 405, 810, 1215, 1620,
2430, 3240, 3645, 4050, 540, 1080, 1620, 2160, 3240, 4320,
4860, 5400
},
/* Short GI */
/* MCS0 ~ MCS31: (unit 100000bps) */
{
150, 300, 450, 600, 900, 1200, 1350, 1500, 300, 600,
900, 1200, 1800, 2400, 2700, 3000, 450, 900, 1350, 1800,
2700, 3600, 4050, 4500, 600, 1200, 1800, 2400, 3600, 4800,
5400, 6000
},
},
};
#ifdef RELEASE_EXCLUDE
/* reference to Table20-29 ~ Table20-35 of Draft802.11n_D3.07.pdf */
#endif /* RELEASE_EXCLUDE */
static const UINT16 gAcmRateNdbps[2][32] =
{
/* MCS0 ~ MCS31 */
/* 20MHz */
{
26, 52, 78, 104, 156, 208, 234, 260,
52, 104, 156, 208, 312, 416, 468, 520,
78, 156, 234, 312, 468, 624, 702, 780,
104, 208, 312, 416, 624, 832, 936, 1040
},
/* MCS0 ~ MCS31 */
/* 40MHz */
{
54, 108, 162, 216, 324, 432, 486, 540,
108, 216, 324, 432, 648, 864, 972, 1080,
162, 324, 486, 648, 972, 1296, 1458, 1620,
216, 432, 648, 864, 1296, 1728, 1944, 2160
},
};
#ifdef RELEASE_EXCLUDE
/* reference to Table20-29 ~ Table20-35 of Draft802.11n_D3.07.pdf */
/* where 1:mean Nes = 2 for the MCS; 0:mean Nes=1 for the MCS */
/* [0] for 20MHz, [1] for 40MHz */
#endif /* RELEASE_EXCLUDE */
static const UINT32 gAcmRateNes[2] = { 0x00000000, 0xF0E00000 };
#ifndef ACM_CC_FUNC_AUX_TX_TIME
#ifdef RELEASE_EXCLUDE
/* tx time for header+frame body, length = 1 ~ 1536 */
/*
[2]: 20 or 20/40MHz
[2]: regular or short GI
[ACM_RATE_MAX_NUM_HT]: 0 ~ 31
[ACM_PRE_TIME_DATA_SIZE_NUM]: 0 ~
[2]: 0 (tx time includes preamble, data, block ack)
1 (only header+data tx time)
2 (only data tx time)
*/
#endif /* RELEASE_EXCLUDE */
static UINT16 gAcmTxTimeBodyHT[2][2][ACM_RATE_MAX_NUM_HT][ACM_PRE_TIME_DATA_SIZE_NUM][3];
/* tx time for block ack whatever 20/40 or GI */
static UINT16 gAcmTxTimeOthersHT;
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
#endif /* ACM_CC_FUNC_11N */
/* for memory allocation/free test purpose */
#ifdef ACM_MEMORY_TEST
UINT32 gAcmMemAllocNum = 0;
UINT32 gAcmMemFreeNum = 0;
#endif /* ACM_MEMORY_TEST */
/* =========================== Global Function (AP) ========================= */
/*
========================================================================
Routine Description:
Initialize the ACM Module.
Arguments:
pAd - WLAN control block pointer
FlgIsAcm0Enable - the ACM flag for AC0
FlgIsAcm1Enable - the ACM flag for AC1
FlgIsAcm2Enable - the ACM flag for AC2
FlgIsAcm3Enable - the ACM flag for AC3
FlgVb - the variable bandwidth flag
Return Value:
ACM_RTN_OK - init OK
ACM_RTN_FAIL - init fail
Note:
FlgIsAcm0Enable ~ FlgIsAcm3Enable and FlgVb are valid only for QAP mode.
========================================================================
*/
ACM_FUNC_STATUS ACMP_Init(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsAcm0Enable,
ACM_PARAM_IN UCHAR FlgIsAcm1Enable,
ACM_PARAM_IN UCHAR FlgIsAcm2Enable,
ACM_PARAM_IN UCHAR FlgIsAcm3Enable,
ACM_PARAM_IN UCHAR FlgVb)
{
ACM_CTRL_PARAM *pEdcaParam;
/* allocate ACM Control Block memory */
ACMR_MEM_ALLOC(ACMR_ADAPTER_DB, sizeof(ACM_CTRL_BLOCK), (VOID *));
if (ACMR_ADAPTER_DB == NULL)
return ACM_RTN_FAIL;
/* End of if */
ACMR_MEM_ZERO(ACMR_ADAPTER_DB, sizeof(ACM_CTRL_BLOCK));
/* init tasklets */
/* Note: pAd can not be casted to non-ULONG, ex: (UINT32)pAd */
ACMR_TASK_INIT(pAd, ACMR_CB->TaskletTspecReqCheck,
ACM_TASK_TC_ReqCheck, pAd, "ACM_TCREQ");
ACMR_TASK_INIT(pAd, ACMR_CB->TaskletStreamAliveCheck,
ACM_TASK_STM_Check, pAd, "ACM_AVCK");
/* init timers */
ACMR_TIMER_INIT(pAd, ACMR_CB->TimerTspecReqCheck,
ACMP_TR_TC_ReqCheck, pAd);
ACMR_TIMER_INIT(pAd, ACMR_CB->TimerStreamAliveCheck,
ACMP_TR_STM_Check, pAd);
/* init other parameters */
pEdcaParam = &ACMR_CB->EdcaCtrlParam;
/* enable channel busy time calculation */
pEdcaParam->FlgIsChanUtilEnable = 1;
ACMR_CHAN_BUSY_DETECT_ENABLE(pAd);
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
/* init available ACM time */
ACMR_AVAIL_ACM_TIME_UPDATE(pAd, 0);
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
/* init chan utilization */
pEdcaParam->ChanUtil = 0;
/* init mininum time for total EDCA streams and AC0/1 streams */
/* use default value */
pEdcaParam->CP_MinNu = ACM_MIN_CP_NU_DEFAULT;
pEdcaParam->CP_MinDe = ACM_MIN_CP_DE_DEFAULT;
/* use default value */
pEdcaParam->BEK_MinNu = ACM_MIN_BEK_NU_DEFAULT;
pEdcaParam->BEK_MinDe = ACM_MIN_BEK_DE_DEFAULT;
/* default TSPEC can change UAPSD settings */
pEdcaParam->FlgIsTspecUpasdEnable = 1;
/* init Downgrade function (default: DISABLE) */
ACMR_MEM_SET(
pEdcaParam->DowngradeAcNum,
ACM_DOWNGRADE_DISABLE,
sizeof(pEdcaParam->DowngradeAcNum));
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
/* init ACM flag in QAP; QSTA will follow the ACM indication in beacon */
pEdcaParam->FlgAcmStatus[0] = FlgIsAcm0Enable;
pEdcaParam->FlgAcmStatus[1] = FlgIsAcm1Enable;
pEdcaParam->FlgAcmStatus[2] = FlgIsAcm2Enable;
pEdcaParam->FlgAcmStatus[3] = FlgIsAcm3Enable;
ACMR_AC_ACM_CTRL(pAd,
FlgIsAcm0Enable,
FlgIsAcm1Enable,
FlgIsAcm2Enable,
FlgIsAcm3Enable);
#ifdef RELEASE_EXCLUDE
/* dynamic ATL: init DATL */
pEdcaParam->FlgDatl = FlgVb;
#endif /* RELEASE_EXCLUDE */
#ifdef ACM_CC_FUNC_ACL
/* init link list */
ACMR_CB->ACL_IsEnabled = FALSE;
ACMR_LIST_INIT(&ACMR_CB->ACL_List);
#endif /* ACM_CC_FUNC_ACL */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef RELEASE_EXCLUDE
/* dynamic ATL: init DATL */
pEdcaParam->DatlBwMin[ACM_EDCA_VO_AC_QUE_ID] = ACM_DATL_BW_MIN_VO;
pEdcaParam->DatlBwMax[ACM_EDCA_VO_AC_QUE_ID] = ACM_DATL_BW_MAX_VO;
pEdcaParam->DatlBwMin[ACM_EDCA_VI_AC_QUE_ID] = ACM_DATL_BW_MIN_VI;
pEdcaParam->DatlBwMax[ACM_EDCA_VI_AC_QUE_ID] = ACM_DATL_BW_MAX_VI;
pEdcaParam->DatlBwMin[ACM_EDCA_BE_AC_QUE_ID] = ACM_DATL_BW_MIN_BE;
pEdcaParam->DatlBwMax[ACM_EDCA_BE_AC_QUE_ID] = ACM_DATL_BW_MAX_BE;
pEdcaParam->DatlBwMin[ACM_EDCA_BK_AC_QUE_ID] = ACM_DATL_BW_MIN_BK;
pEdcaParam->DatlBwMax[ACM_EDCA_BK_AC_QUE_ID] = ACM_DATL_BW_MAX_BK;
#endif /* RELEASE_EXCLUDE */
/* init Transmission Time value for different packet size */
ACM_TX_TimeCalPre(pAd);
/* init cmd */
ACM_CMD_Init(pAd);
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* backup original UAPSD state */
ACMR_UAPSD_BACKUP(pAd);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
/* allow to handle TSPEC request */
ACM_MR_TSPEC_ALLOW();
/* activate a general timer */
ACMR_TASK_INIT(pAd, ACMR_CB->TaskletGeneral,
ACM_TASK_General, (ULONG)pAd, "ACM_OTHER");
ACMR_TIMER_INIT(pAd, ACMR_CB->TimerGeneral,
ACMP_TR_TC_General, (ULONG)pAd);
#if defined(ACM_CC_FUNC_MBSS) || defined(ACM_CC_FUNC_CHAN_UTIL_MONITOR)
ACMR_TIMER_ENABLE(ACMR_CB->FlgTimerGeneralEnable,
ACMR_CB->TimerGeneral,
ACM_TIMER_GENERAL_PERIOD_TIMEOUT);
#endif /* ACM_CC_FUNC_MBSS || ACM_CC_FUNC_CHAN_UTIL_MONITOR */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
#ifdef ACM_CC_FUNC_CHAN_UTIL_MONITOR
/* backup original AIFSN of AC */
ACMR_AIFSN_DEFAULT_GET(pAd, ACMR_CB->CU_MON_AifsnAp,
ACMR_CB->CU_MON_AifsnBss);
#endif /* ACM_CC_FUNC_CHAN_UTIL_MONITOR */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
return ACM_RTN_OK;
} /* End of ACMP_Init */
/*
========================================================================
Routine Description:
Release the ACM Resource.
Arguments:
pAd - WLAN control block pointer
Return Value:
ACM_RTN_OK - release OK
ACM_RTN_FAIL - release fail
Note:
Only used in module remove.
========================================================================
*/
ACM_FUNC_STATUS ACMP_Release(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
/* sanity check */
if (ACMR_CB == NULL)
return ACM_RTN_OK;
/* End of if */
/* release all resources */
ACMR_TIMER_DISABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck);
ACMR_TIMER_DISABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck);
ACMR_TIMER_DISABLE(ACMR_CB->FlgTimerGeneralEnable,
ACMR_CB->TimerGeneral);
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
#ifdef ACM_CC_FUNC_ACL
ACM_ACL_EMPTY(pAd);
#endif /* ACM_CC_FUNC_ACL */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
ACM_TC_ReleaseAll(pAd);
ACM_CMD_Release(pAd);
ACMR_MEM_FREE(ACMR_ADAPTER_DB);
ACMR_ADAPTER_DB = NULL;
#ifdef ACM_MEMORY_TEST
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_msg> ACM_MEM_Alloc_Num = %d\n", gAcmMemAllocNum));
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_msg> ACM_MEM_Free_Num = %d\n", gAcmMemFreeNum));
#endif /* ACM_MEMORY_TEST */
return ACM_RTN_OK;
} /* End of ACMP_Release */
/*
========================================================================
Routine Description:
Get bandwidth information.
Arguments:
pAd - WLAN control block pointer
*pInfo - the bandwidth information
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_BandwidthInfoGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_OUT ACM_BANDWIDTH_INFO *pInfo)
{
ACM_CTRL_PARAM *pEdcaParam;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((pAd == NULL) || (pInfo == NULL))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Input is NULL! ControlInfomationGet()\n"));
return ACM_RTN_FAIL;
} /* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* total ACM time = EDCA ACM time + HCCA ACM time (HCCA not support) */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pInfo->AcmUsedTime = pEdcaParam->AcmTotalTime;
#ifdef ACM_CC_FUNC_MBSS
/* MBSS time */
pInfo->MbssTotalUsedTime = ACMR_CB->MbssTotalUsedTime;
#endif /* ACM_CC_FUNC_MBSS */
/* EDCA AC ACM time */
pInfo->AcUsedTime = pEdcaParam->AcmTotalTime;
/* undetermined TSPEC number */
pInfo->NumReqLink = ACMR_CB->TspecListReq.TspecNum;
/* determined EDCA link number */
pInfo->NumAcLinkUp = pEdcaParam->LinkNumUp;
pInfo->NumAcLinkDn = pEdcaParam->LinkNumDn;
pInfo->NumAcLinkDi = pEdcaParam->LinkNumDi;
pInfo->NumAcLinkBi = pEdcaParam->LinkNumBi;
/* channel utilization & busy time */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
pEdcaParam->StationCount = ACMR_STATION_COUNT_GET(pAd);
pEdcaParam->ChanUtil = ACMR_CHAN_UTIL_GET(pAd);
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
pInfo->StationCount = pEdcaParam->StationCount;
pInfo->ChanUtil = pEdcaParam->ChanUtil;
pInfo->AvalAdmCap = pEdcaParam->AvalAdmCap;
ACMR_CHAN_BUSY_GET(pAd, &pInfo->ChanBusyTime);
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_OK;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACMP_BandwidthInfoGet */
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Set bandwidth information.
Arguments:
pAd - WLAN control block pointer
StationCount - station count of the associated BSS
ChanUtil - channel utilization of the associated BSS
AvalAdmCap - available admission capability of the associated BSS
Return Value:
ACM_RTN_OK - set ok
ACM_RTN_FAIL - set fail
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_BandwidthInfoSet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT16 StationCount,
ACM_PARAM_IN UINT8 ChanUtil,
ACM_PARAM_IN UINT16 AvalAdmCap)
{
ACM_CTRL_PARAM *pEdcaParam;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (pAd == NULL)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Input is NULL! ControlInfomationSet()\n"));
return ACM_RTN_FAIL;
} /* End of if */
if (!ACMR_IS_PORT_SECURE(pAd))
return ACM_RTN_FAIL;
/* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* total ACM time = EDCA ACM time + HCCA ACM time (HCCA not support) */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pEdcaParam->StationCount = StationCount;
pEdcaParam->ChanUtil = ChanUtil; /* unit: 1/255 */
pEdcaParam->AvalAdmCap = AvalAdmCap; /* unit: 32us */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_OK;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACMP_BandwidthInfoSet */
#endif /* CONFIG_STA_SUPPORT */
/*
========================================================================
Routine Description:
Check if the BE packet is needed to release.
Arguments:
pAd - WLAN control block pointer
*pCdb - the destination QSTA
QueIdx - 0 ~ 3 (AC0 ~ AC3)
*pQueueHeader - the software queue header
pMbuf - the packet expected to send out
Return Value:
ACM_RTN_OK - release it
ACM_RTN_FAIL - do not release it
Note:
If we can find a TSPEC for the BE packet, we will search a non-TSPEC
packet in the BE software queue and release it.
========================================================================
*/
ACM_FUNC_STATUS ACMP_BE_IsReallyToReleaseWhenQueFull(
ACM_PARAM_IN RTMP_ADAPTER *pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR QueIdx,
ACM_PARAM_IN ACMR_MBUF *pMbuf)
{
#ifdef ACM_CC_FUNC_BE_BW_CTRL
ACM_FUNC_STATUS Status;
UINT32 QueueType;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* check if the packet is BE and ACM of BE is enabled */
if ((QueIdx == ACM_EDCA_BE_AC_QUE_ID) &&
(ACMR_CB->EdcaCtrlParam.FlgAcmStatus[ACM_EDCA_BE_AC_QUE_ID]))
{
ACMR_PKT_QOS_TYPE_SET(pMbuf, 0);
/* check if any TSPEC is built and calculate the tx time */
Status = ACMP_DataPacketQueue(pAd, pCdb, pMbuf, 0, &QueueType);
if ((Status == ACM_RTN_OK) &&
(ACMP_BE_QueueFullHandle(pAd, pCdb, pMbuf) == ACM_RTN_OK))
{
/*
Medium time is enough and another non-TSPEC packet is released
so we can enqueue the TSPEC packet.
*/
return ACM_RTN_FAIL;
}
}
#endif /* ACM_CC_FUNC_BE_BW_CTRL */
return ACM_RTN_OK;
} /* End of ACMP_BE_IsReallyToReleaseWhenQueFull */
/*
========================================================================
Routine Description:
Handle the event when BE software queue is full.
Arguments:
pAd - WLAN control block pointer
*pCdb - the destination QSTA
pMbuf - the packet expected to send out
Return Value:
ACM_RTN_OK - handle ok, a non-TSPEC packet is released
ACM_RTN_FAIL - handle fail, no non-TSPEC packet is released
Note:
If the ACM of BE is enabled and the bandwidth is saturated, we will
protect the bandwidth for BE traffic with TSPEC.
Two cases:
1. (only for AP) Origin priority is BE but no any BE TSPEC is built
for the station, we do NOT need to protect it.
2. (for AP & STA) Origin priority is not BE but no any non-BE TSPEC
is built for the station, we will translate it to BE traffic,
but we do NOT need to protect it.
========================================================================
*/
ACM_FUNC_STATUS ACMP_BE_QueueFullHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACMR_MBUF *pMbuf)
{
#ifdef ACM_CC_FUNC_BE_BW_CTRL
WMM_ACM_FUNC_NAME_PRINT("IN");
if (pCdb->ACM_NumOfOutTspecInAc[ACM_EDCA_BE_AC_QUE_ID] > 0)
{
/* we only need to do protection when BE TSPEC exists */
if (RTMP_GET_PACKET_TX_TIME(pMbuf) > 0)
{
/* the packet is not downgraded to BE so we handle it */
QUEUE_HEADER *pQueueHeader;
ACMR_QUEUE_ENTRY *pQueueEntry, *pQueueEntryPrev;
ULONG IrqFlags;
/* try to look for any queued packet without TSPEC in BE queue */
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
pQueueHeader = &pAd->TxSwQueue[ACM_EDCA_BE_AC_QUE_ID];
if (pQueueHeader != NULL)
{
/* should be here */
pQueueEntry = pQueueHeader->Head;
pQueueEntryPrev = pQueueEntry;
while(pQueueEntry != NULL)
{
if (RTMP_GET_PACKET_TX_TIME(\
QUEUE_ENTRY_TO_PACKET(pQueueEntry)) == 0)
{
/* if the packet is not allowed by TSPEC, tx time = 0 */
/* remove the entry from the queue list */
pQueueEntryPrev->Next = pQueueEntry->Next;
if (pQueueEntry == pQueueHeader->Head)
pQueueHeader->Head = pQueueEntry->Next;
if (pQueueEntry == pQueueHeader->Tail)
pQueueHeader->Tail = pQueueEntryPrev;
pQueueEntry->Next = NULL;
pQueueHeader->Number --;
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
/* discard the packet without matched TSPEC */
RELEASE_NDIS_PACKET(pAd,
QUEUE_ENTRY_TO_PACKET(pQueueEntry),
NDIS_STATUS_FAILURE);
return ACM_RTN_OK;
}
pQueueEntryPrev = pQueueEntry;
pQueueEntry = pQueueEntry->Next;
}
}
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
}
}
#endif /* ACM_CC_FUNC_BE_BW_CTRL */
return ACM_RTN_FAIL;
}
/*
========================================================================
Routine Description:
Get current EDCA ACM Information.
Arguments:
pAd - WLAN control block pointer
*pInfo - the EDCA ACM information
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_ControlInfomationGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_CTRL_INFO *pInfo)
{
ACM_CTRL_PARAM *pEdcaParam;
UINT32 IdAcNum;
#ifdef CONFIG_AP_SUPPORT
INT32 AvailAdmTime;
UINT32 IdAcOther;
#endif /* CONFIG_AP_SUPPORT */
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((pAd == NULL) || (pInfo == NULL))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Input is NULL! ControlInfomationGet()\n"));
return ACM_RTN_FAIL;
}
/* init */
ACMR_MEM_ZERO(pInfo, sizeof(ACM_CTRL_INFO));
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* copy information */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
pInfo->FlgIsAcmEnable[IdAcNum] = pEdcaParam->FlgAcmStatus[IdAcNum];
pInfo->DowngradeAcNum[IdAcNum] = pEdcaParam->DowngradeAcNum[IdAcNum];
pInfo->AcmOutTime[IdAcNum] = pEdcaParam->AcmOutTime[IdAcNum];
pInfo->AcmAcTime[IdAcNum] = pEdcaParam->AcmAcTime[IdAcNum];
}
pInfo->CP_MinNu = pEdcaParam->CP_MinNu;
pInfo->CP_MinDe = pEdcaParam->CP_MinDe;
pInfo->BEK_MinNu = pEdcaParam->BEK_MinNu;
pInfo->BEK_MinDe = pEdcaParam->BEK_MinDe;
pInfo->AcmTotalTime = pEdcaParam->AcmTotalTime;
pInfo->LinkNumUp = pEdcaParam->LinkNumUp;
pInfo->LinkNumDn = pEdcaParam->LinkNumDn;
pInfo->LinkNumBi = pEdcaParam->LinkNumBi;
pInfo->LinkNumDi = pEdcaParam->LinkNumDi;
pInfo->FlgIsTspecUpasdEnable = pEdcaParam->FlgIsTspecUpasdEnable;
pInfo->FlgIsTspecTimeoutEnable = pEdcaParam->FlgIsTspecTimeoutEnable;
#ifdef RELEASE_EXCLUDE
/* dynamic ATL */
pInfo->FlgDatl = pEdcaParam->FlgDatl;
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
pInfo->DatlBwMin[IdAcNum] = pEdcaParam->DatlBwMin[IdAcNum];
pInfo->DatlBwMax[IdAcNum] = pEdcaParam->DatlBwMax[IdAcNum];
}
ACMR_MEM_COPY(
pInfo->DatlBorAcBw,
pEdcaParam->DatlBorAcBw,
sizeof(pInfo->DatlBorAcBw));
#endif /* RELEASE_EXCLUDE */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
/* calculate available admission capability for each AC */
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
#ifdef RELEASE_EXCLUDE
/* dynamic ATL */
if (pEdcaParam->FlgDatl == TRUE)
{
AvailAdmTime = (INT32)pEdcaParam->DatlBwMax[IdAcNum];
AvailAdmTime *= ACM_TIME_BASE;
AvailAdmTime /= 100;
for(IdAcOther=0; IdAcOther<ACM_DEV_NUM_OF_AC; IdAcOther++)
AvailAdmTime -= (INT32)pEdcaParam->DatlBorAcBw[IdAcNum][IdAcOther];
if (AvailAdmTime < 0)
AvailAdmTime = 0; /* should not be here */
pInfo->AvalAdmCapAc[IdAcNum] = AvailAdmTime >> 5; /* unit: 32us */
}
else
#endif /* RELEASE_EXCLUDE */
{
/* not support for the AC */
pInfo->AvalAdmCapAc[IdAcNum] = pEdcaParam->AvalAdmCap; /* unit: 32us */
}
}
}
#endif /* CONFIG_AP_SUPPORT */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_OK;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
}
/*
========================================================================
Routine Description:
Handle something when a QoS data or null frame is received.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
pHeader - the WLAN MAC header
Return Value:
None
Note:
1. Only for QAP.
2. The frame shall be uplink.
3. For EDCA, we shall reset activity timeout for QoS data frames.
4. In LINUX, the function must be called in a tasklet.
5. If PktTsid is 0xFF, we will get TSID from pHeader.
========================================================================
*/
VOID ACMP_DataNullHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACMR_WLAN_HEADER *pHeader)
{
ACM_CTRL_PARAM *pEdcaParam;
ACM_ENTRY_INFO *pStaAcmInfo;
ACM_STREAM **ppStmListIn;
ACM_STREAM *pStream;
UINT16 FrmSubType;
UINT16 QosCtrl;
UCHAR UP, PktAcId;
UINT32 IdTidNum;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
/*
We will check ACM_NumOfTspecIn of pCdb before calling the function;
if > 0, at least one TSPEC exists.
*/
/* if (!ACMR_IS_ENABLED(pAd))
return; */
/* End of if */
if (ACMR_CB == NULL)
return;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
if (pEdcaParam->FlgIsTspecTimeoutEnable == 0)
goto LabelOK; /* no need to do TSPEC timeout check */
/* init */
QosCtrl = ACMR_FME_QOSCTRL_GET(pHeader);
FrmSubType = ACMR_FME_SUBTYPE_GET(pHeader);
pStream = NULL;
/* reset activity & suspension timeout for QoS Data or QoS Null frames */
if ((FrmSubType == ACMR_FME_SUB_TYPE_QOS_DATA) ||
(FrmSubType == ACMR_FME_SUB_TYPE_QOS_NULL))
{
#ifdef ACM_CC_FUNC_TCLAS
/*
TODO: We need to compare packet with all TCLAS to get UP.
Solution: Currently we use same UP for all TCLAS in a TSPEC.
*/
UP = ACM_TID_GET(QosCtrl);
#else
UP = ACM_TID_GET(QosCtrl);
#endif /* ACM_CC_FUNC_TCLAS */
if (ACM_IS_EDCA_STREAM(UP))
{
/* EDCA stream */
/* translate UP to AC ID */
PktAcId = ACM_MR_EDCA_AC(UP);
/* try to find the IN TSPEC by AC ID */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
ppStmListIn = (ACM_STREAM **)pStaAcmInfo->pAcStmIn;
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (ppStmListIn[IdTidNum] != NULL)
{
if (PktAcId == ACM_MR_EDCA_AC(ppStmListIn[IdTidNum]->UP))
{
/* only one IN TSPEC for a AC */
pStream = ppStmListIn[IdTidNum];
break;
}
}
}
/* update its timeout timers if exists */
if (pStream != NULL)
{
ACM_TSPEC *pTspec = pStream->pTspec;
if (pTspec->InactivityInt != ACM_TSPEC_INACTIVITY_DISABLE)
pStream->InactivityCur = pStream->pTspec->InactivityInt;
#ifdef ACM_CC_FUNC_HCCA
if (pTspec->SuspensionInt != ACM_TSPEC_SUSPENSION_DISABLE)
pStream->SuspensionCur = pStream->pTspec->SuspensionInt;
#endif /* ACM_CC_FUNC_HCCA */
}
}
}
LabelOK:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
}
/*
========================================================================
Routine Description:
Check if the packet can be queued to the packet queue of the AC.
Arguments:
pAd - WLAN control block pointer
*pCdb - the peer device
*pMbuf - the packet
FlgIsForceToHighAc - 1: force the packet to AC3
*pQueueType - the new packet queue type
(ACMR_QID_AC_BE ~ ACMR_QID_AC_VO)
Return Value:
ACM_RTN_OK - classify successfully
ACM_RTN_FAIL - do not allow to send the packet
ACM_RTN_NO_ACM - the ACM of the AC is disabled
========================================================================
*/
#ifdef RELEASE_EXCLUDE
/*
Note:
Used the function to enqueue your WLAN packets.
WMM ACM Test Plan 4.1.3 APUT Operation with Legacy STAs
1. When one WMM ACM station and one WMM legacy station connects to
our AP, and WMM ACM STA creates a TSPEC for dnlink.
2. Send traffics from AP to two stations with priority VO.
3. We need to enqueue VO packets for WMM ACM station to VO queue
and enqueue the VO packets for WMM legacy station to BE queue.
4. Or if we enqueue all VO packets to the VO queue and partition packets
to different queue when Dequeue packets, a problem will occur as below:
a. When the traffic from AP to WMM legacy station saturates the
bandwidth;
b. We will drop VO packets because the VO queue is full;
c. And we will drop VO packets for WMM ACM station but it is not
correct because WMM ACM station has created a TSPEC for the
VO traffic. So We need to protect the VO traffic of WMM ACM STA.
TODO: When any packet is belong to other station or any packet is belong
to other different priority, the AMPDU sum time must be reset.
*/
#endif /* RELEASE_EXCLUDE */
#ifdef WMM_ACM_PKT_NUM_DEBUG
/* global variables but only for debug */
UINT32 WMM_ACM_NumOfPkt[WMM_ACM_DEBUG_TIME_MAX_NUM_REC][4]; /* for 4 AC */
UINT32 WMM_ACM_NumOfPktId = 0, WMM_ACM_TimeRecId = 0, WMM_ACM_TimeId = 0;
UINT32 WMM_ACM_Time[WMM_ACM_DEBUG_TIME_MAX_NUM_REC][4]; /* for 4 AC */
BOOLEAN WMM_ACM_IsTimeValid = TRUE;
#endif /* WMM_ACM_PKT_NUM_DEBUG */
ACM_FUNC_STATUS ACMP_DataPacketQueue(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACMR_MBUF *pMbuf,
ACM_PARAM_IN UCHAR FlgIsForceToHighAc,
ACM_PARAM_OUT UINT32 *pQueueType)
{
ACM_STREAM **ppAcmStmList;
ACM_STREAM *pStream;
ACM_TS_INFO *pTsInfo;
ACM_ENTRY_INFO *pStaAcmInfo;
ACM_CTRL_PARAM *pEdcaParam;
ACM_STATISTICS *pStats;
UINT32 PktLen, LenFrag, LenLastFrag, NumFrag;
UCHAR FlgIsFindTspec;
UINT32 PktAcId, TxTime;
UCHAR UP, TSID;
UINT32 TxQueueType;
UCHAR AccessPolicy, AckPolicy;
UINT32 IdTidNum;
ULONG SplFlags;
#ifdef ACM_CC_FUNC_TCLAS
ACM_TCLAS *pTclas, TclasIpClass;
UINT32 IdTclasNum;
UCHAR TclasBitmap;
UCHAR *pPkt; /* same as pMbuf */
UCHAR *pAddrSrc, *pAddrDst;
UINT16 Type; /* ethernet frame type/len */
UINT16 VlanTag;
UCHAR FlgIsMatchTspec, FlgIsIpPkt;
#endif /* ACM_CC_FUNC_TCLAS */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
RTMP_SET_PACKET_TX_TIME(pMbuf, 0);
*pQueueType = ACMR_QID_AC_BE;
if (pCdb == NULL)
{
/* *pQueueType is useless */
return ACM_RTN_NO_ACM;
}
/* we will check before calling the function to speed up */
/* if (ACMP_IsAnyACEnabled(pAd) != ACM_RTN_OK)
return ACM_RTN_NO_ACM; */
/* End of if */
/* init */
PktLen = ACMR_WLAN_LEN_GET(pMbuf);
#ifdef ACM_CC_FUNC_TCLAS
pPkt = (UCHAR *)ACMR_WLAN_PKT_GET(pMbuf);
pAddrDst = (UCHAR *)pPkt;
pAddrSrc = (UCHAR *)(pPkt + ACM_ETH_DA_ADDR_LEN);
Type = *(UINT16 *)(pPkt + ACM_ETH_DA_ADDR_LEN + ACM_ETH_SA_ADDR_LEN);
TclasIpClass.ClassifierMask = 0;
VlanTag = 0xFFFF;
FlgIsIpPkt = 0;
FlgIsMatchTspec = 0;
#endif /* ACM_CC_FUNC_TCLAS */
pStream = NULL;
FlgIsFindTspec = 0;
TSID = 0xff; /* default: no TSID information */
UP = 0xff;
LenFrag = 0;
LenLastFrag = 0;
NumFrag = 0;
TxTime = 33; /* minimum tx time, > 1 unit = 32us */
if (FlgIsForceToHighAc == 1)
TSID = 0x07; /* force to use AC3 */
else
{
if (ACMR_PKT_QOS_TYPE_GET(pMbuf) == ACM_QOS_TYPE_NULL)
TSID = ACMR_PKT_UP_GET(pMbuf);
}
ACMR_PKT_MARK_MIN_PHY_MODE(pMbuf, ACMR_PHY_NONE);
ACMR_PKT_MARK_MIN_PHY_MCS(pMbuf, 0);
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_CLSFY_NOT_ALLOW);
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pStats = &pEdcaParam->Stats;
#ifdef ACM_CC_FUNC_TCLAS
/* check TCLAS in WMM streams */
if (FlgIsForceToHighAc == 0)
{
ppAcmStmList = (ACM_STREAM **)pStaAcmInfo->pAcStmOut;
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
pStream = ppAcmStmList[IdTidNum];
if ((pStream == NULL) || (pStream->pTclas == NULL))
continue; /* no TSPEC exists, check next one */
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
{
if (pStream->pTclas[IdTclasNum] == NULL)
{
IdTclasNum = ACM_TSPEC_TCLAS_MAX_NUM;
break; /* no other TCLAS */
}
pTclas = pStream->pTclas[IdTclasNum];
TclasBitmap = pTclas->ClassifierMask;
FlgIsMatchTspec = 0;
switch(pTclas->ClassifierType)
{
case ACM_TCLAS_TYPE_ETHERNET:
if (TclasBitmap & 0x01)
{
/* check source address */
if (!(AMR_IS_SAME_MAC(pAddrSrc,
pTclas->Clasifier.Ethernet.AddrSrc)))
{
break; /* compare fail */
}
}
if (TclasBitmap & 0x02)
{
/* check destination address */
if (!(AMR_IS_SAME_MAC(pAddrDst,
pTclas->Clasifier.Ethernet.AddrDst)))
{
break; /* compare fail */
}
}
if (TclasBitmap & 0x04)
{
/* check type */
if (Type != pTclas->Clasifier.Ethernet.Type)
break; /* compare fail */
}
FlgIsMatchTspec = 1;
break;
case ACM_TCLAS_TYPE_IP_V4:
if (TclasIpClass.ClassifierMask == 0)
{
/* get IP info. from the frame at first loop */
TclasIpClass.ClassifierMask = 1;
if (ACM_TCLAS_IP_INFO_Get(pPkt,
&TclasIpClass) == ACM_RTN_OK)
{
FlgIsIpPkt = 1;
}
}
if (FlgIsIpPkt == 0)
break; /* the frame is not a IP packet */
if ((TclasBitmap & 0x01) &&
(pTclas->Clasifier.IPv4.Version != \
TclasIpClass.Clasifier.IPv4.Version))
{
break; /* compare Version fail */
}
if ((TclasBitmap & 0x02) &&
(pTclas->Clasifier.IPv4.IpSource != \
TclasIpClass.Clasifier.IPv4.IpSource))
{
break; /* compare source IP fail */
}
if ((TclasBitmap & 0x04) &&
(pTclas->Clasifier.IPv4.IpDest != \
TclasIpClass.Clasifier.IPv4.IpDest))
{
break; /* compare destination IP fail */
}
if ((TclasBitmap & 0x08) &&
(pTclas->Clasifier.IPv4.PortSource != \
TclasIpClass.Clasifier.IPv4.PortSource))
{
break; /* compare source port fail */
}
if ((TclasBitmap & 0x10) &&
(pTclas->Clasifier.IPv4.PortDest != \
TclasIpClass.Clasifier.IPv4.PortDest))
{
break; /* compare destination port fail */
}
if ((TclasBitmap & 0x20) &&
(pTclas->Clasifier.IPv4.DSCP != \
TclasIpClass.Clasifier.IPv4.DSCP))
{
break; /* compare DSCP fail */
}
if ((TclasBitmap & 0x40) &&
(pTclas->Clasifier.IPv4.Protocol != \
TclasIpClass.Clasifier.IPv4.Protocol))
{
break; /* compare protocol fail */
}
FlgIsMatchTspec = 1;
break;
case ACM_TCLAS_TYPE_8021DQ:
if (VlanTag == 0xFFFF)
{
/* only get VLAN tag once at first loop */
ACM_TCLAS_VLAN_INFO_Get(pPkt, &VlanTag);
}
if ((TclasBitmap & 0x01) &&
(VlanTag != 0xFFFF) &&
(pTclas->Clasifier.IEEE8021Q.TagType != VlanTag))
{
break; /* compare TAG Type fail */
}
FlgIsMatchTspec = 1;
break;
} /* End of switch */
if (FlgIsMatchTspec == 1)
{
if (pStream->TclasProcessing == \
ACM_WME_TCLAS_PROCESSING_ONE)
{
/* find a matched TCLAS so is the TS */
FlgIsFindTspec = 1;
break;
}
}
else
{
if (pStream->TclasProcessing == \
ACM_WME_TCLAS_PROCESSING_ALL)
break; /* all TCLAS must be matched so not the TS */
}
}
if ((FlgIsMatchTspec == 1) &&
(IdTclasNum == ACM_TSPEC_TCLAS_MAX_NUM))
{
FlgIsFindTspec = 1; /* all TCLASS are matched */
}
if (FlgIsFindTspec == 1)
break; /* the frame belongs to the stream */
}
}
#endif /* ACM_CC_FUNC_TCLAS */
/* check if any TSPEC with TCLAS number = 0 exists */
if ((FlgIsFindTspec == 0) &&
(FlgIsForceToHighAc == 0) &&
((pStream == NULL) ||
pStream->pTclas[0] == NULL))
{
/*
Though, TCLAS number = 0, but maybe the medium time of a
TSPEC != 0, search the TSPEC.
*/
/* check if the packet is QoS Null frame */
if (!(ACMR_PKT_QOS_TYPE_GET(pMbuf) == ACM_QOS_TYPE_NULL))
{
/* the packet is NOT QoS Null frame */
/* the condition to find the TSPEC is 'same AC ID' */
TSID = ACM_TSID_Get(pAd, pMbuf);
PktAcId = ACM_MR_EDCA_AC(TSID);
/* check if the ACM of the AC is enabled */
if (pEdcaParam->FlgAcmStatus[PktAcId] != ACM_FLG_FUNC_ENABLED)
{
/* *pQueueType is useless */
goto LabelErrNoACM;
}
/* check if the UP matches any out TSPEC with TCLAS number = 0 */
ppAcmStmList = (ACM_STREAM **)pStaAcmInfo->pAcStmOut;
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
pStream = ppAcmStmList[IdTidNum];
if (pStream == NULL)
continue; /* no TSPEC exists, check next one */
if (pStream->pTclas[0] == NULL)
{
/* find the TSPEC without TCLAS */
if (PktAcId == ACM_MR_EDCA_AC(pStream->pTspec->TsInfo.UP))
{
/* find the TSPEC */
FlgIsFindTspec = 1;
break;
}
}
}
}
}
if ((FlgIsFindTspec == 1) &&
(pStream != NULL) &&
(FlgIsForceToHighAc == 0))
{
/* at least one TSPEC matches the packet */
pTsInfo = &pStream->pTspec->TsInfo;
AccessPolicy = pTsInfo->AccessPolicy;
AckPolicy = pTsInfo->AckPolicy;
PktAcId = pStream->AcmAcId;
/* refresh inactivity & suspension timeout for the TS */
if (pStream->pTspec->InactivityInt != ACM_TSPEC_INACTIVITY_DISABLE)
pStream->InactivityCur = pStream->pTspec->InactivityInt;
/* End of if */
#ifdef ACM_CC_FUNC_HCCA
if (pStream->pTspec->SuspensionInt != ACM_TSPEC_SUSPENSION_DISABLE)
pStream->SuspensionCur = pStream->pTspec->SuspensionInt;
/* End of if */
#endif /* ACM_CC_FUNC_HCCA */
}
else
{
/* no TSPEC is matched */
AccessPolicy = ACM_ACCESS_POLICY_EDCA;
AckPolicy = ACM_ACK_POLICY_NORMAL;
if (ACMR_PKT_QOS_TYPE_GET(pMbuf) == ACM_QOS_TYPE_NULL)
{
/* use the TID of the QoS Null packet */
PktAcId = ACM_MR_EDCA_AC(ACMR_PKT_UP_GET(pMbuf));
}
else
PktAcId = ACM_MR_EDCA_AC(TSID);
}
/* here, we have got the PktAcId */
#ifdef ACM_CC_FUNC_SOFT_ACM
/*
Test Note:
When you want to test a TSPEC with 208B/83Kbps, you must not
send packets with 1514B to do the test.
Because we have about 51 packets with 208B and we will have
51 * (11g preamble time + sifs + ack time), if you send packets
with 1514B, these extra times will be used to send packets with
1514B, you will not see the 83kbps throughput and you will see
higher throughput.
*/
ACM_TG_CMT_USED_TIME_PASS_CRITERIA;
/* check whether tx time > TXOP limit for AC2 & AC3 */
if (pStream != NULL)
{
/* no TSPEC is found so no need to calculate the tx time */
UINT64 Timestamp, TimeOffset;
UINT32 TimeAllowed;
/* get 64-bit Timestamp */
ACMR_TIMESTAMP_GET(pAd, Timestamp);
#ifdef ACM_CC_FUNC_11N
if (ACMR_IS_HT_RATE_USED(pCdb))
{
/* the station uses HT rate */
TxTime = ACM_TX_TimeCalOnFlyHT(
pAd,
pCdb,
pStream,
Timestamp,
PktLen,
ACMR_CLIENT_MCS_GET(pCdb),
0);
}
else
#endif /* ACM_CC_FUNC_11N */
{
UCHAR FlgIsRtsEnable, FlgIsCtsEnable;
FlgIsRtsEnable = ACMR_RTS_FLAG_GET(pAd, pMbuf);
/* priority of RTS/CTS is over CTS-self */
if (FlgIsRtsEnable == 0)
FlgIsCtsEnable = ACMR_CTS_FLAG_GET(pAd, pMbuf);
else
FlgIsCtsEnable = 0;
/* End of if */
TxTime = ACM_TX_TimeCalOnFly(
pAd,
pCdb,
PktLen,
ACM_Rate_Mapping(pAd, pCdb),
FlgIsCtsEnable,
FlgIsRtsEnable,
ACMR_STA_IS_SPREAMBLE(pAd, pCdb),
0);
}
if (TxTime > 0x0000FFFF)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_err> Tx Time > 0xFFFF us!\n"));
} /* End of if */
RTMP_SET_PACKET_TX_TIME(pMbuf, (UINT16)TxTime);
RTMP_SET_PACKET_STM_TSID(pMbuf, pStream->pTspec->TsInfo.TSID);
/* no need to mark direction, must be output TSPEC */
/* translate MediumTime (unit: 32us) to us */
ACMR_ALLOWED_TIME_GET(pStream, TimeAllowed);
#ifdef ACM_CC_FUNC_11N_AGG
/*
For AMSDU, we will calculate used time based on non-AMSDU so
we need to enlarge the allow time here; Or many packets will
be dropped here.
Because when we queue the packet, we do not yet know if we can do
AMSDU for it. We will do AMSDU in MSDU_Classify(), not here.
*/
if (ACMR_11N_IS_AMSDU_USED(pCdb, pMbuf))
TimeAllowed *= 2; /* 2: rough estimation, maybe need to enlarge */
/* End of if */
#endif /* ACM_CC_FUNC_11N_AGG */
/* use signed INT64 to avoid round-up problem */
TimeOffset = (UINT64)((INT64)Timestamp - \
(INT64)pStream->TxTimestampMarkEnqueue);
if (TimeOffset >= ACM_TIME_BASE)
{
/* the first packet in next second */
pStream->TxTimestampMarkEnqueue = Timestamp;
#ifdef ACM_CC_FUNC_11N
pStream->TxTimestampEnqueueHT = Timestamp;
#endif /* ACM_CC_FUNC_11N */
/* reset the used time */
if (pStream->AcmUsedTimeEnqueue > TimeAllowed)
pStream->AcmUsedTimeEnqueue -= TimeAllowed;
else
pStream->AcmUsedTimeEnqueue = 0;
/* End of if */
/* reset aggregation parameters */
pStream->TxAmpduNumEnqueueHT = 0;
pStream->TxTimeEnqueueHT = 0;
#ifdef WMM_ACM_PKT_NUM_DEBUG
++WMM_ACM_NumOfPktId;
if (WMM_ACM_NumOfPktId >= WMM_ACM_DEBUG_TIME_MAX_NUM_REC)
WMM_ACM_NumOfPktId = 0;
/* End of if */
WMM_ACM_NumOfPkt[WMM_ACM_NumOfPktId][PktAcId] = 0;
++WMM_ACM_TimeRecId;
if (WMM_ACM_TimeRecId == 5)
NdisZeroMemory(WMM_ACM_Time, sizeof(WMM_ACM_Time));
/* End of if */
WMM_ACM_IsTimeValid = TRUE;
#endif /* WMM_ACM_PKT_NUM_DEBUG */
}
else
{
#ifndef PERFORMANCE_IMPACT_TEST
/* during a second */
if (pStream->AcmUsedTimeEnqueue > TimeAllowed)
{
/* can not tx the packet to the AC so check downgrade flag */
RTMP_SET_PACKET_TX_TIME(pMbuf, 0);
if (pEdcaParam->DowngradeAcNum[PktAcId] != ACM_DOWNGRADE_DISABLE)
{
TxQueueType = ACM_TxQueueTypeGet(pEdcaParam->DowngradeAcNum[PktAcId]);
ACM_STATS_COUNT_INC(pStats->Downgrade[PktAcId]);
/*
In WMM spec., A.2 Use of Admission Control and
Downgrading
(3) The MSDU is sent using a different UP. The UP is
changed to map to a lower AC that does not require
admission control. The UP has to be changed prior to
calculating the MIC, assignment of the TSC and mixing
the keys. Changing of the UP is performed outside the
MAC and is out of the scope of this spec.
In an AC for which the admission control mandatory
flag is set to 1, a WMM AP should use option (3).
*/
/* need to change the UP of QoS Control field */
TSID = gEDCA_AC_UP[pEdcaParam->DowngradeAcNum[PktAcId]];
ACMR_PKT_MARK_UP(pMbuf, TSID);
goto LabelOK;
}
ACM_STATS_COUNT_INC(pStats->DropByAdmittedTime);
#ifdef WMM_ACM_PKT_NUM_DEBUG
WMM_ACM_IsTimeValid = FALSE;
#endif /* WMM_ACM_PKT_NUM_DEBUG */
/* downgrade function is disabled so discarding the packet */
goto LabelErr;
}
#endif /* PERFORMANCE_IMPACT_TEST */
}
/* accumulate used time */
#ifdef WMM_ACM_PKT_NUM_DEBUG
if (WMM_ACM_TimeRecId == 5)
{
if (WMM_ACM_TimeId >= WMM_ACM_DEBUG_TIME_MAX_NUM_REC)
WMM_ACM_TimeId = 0;
WMM_ACM_Time[WMM_ACM_TimeId][PktAcId] = TxTime;
WMM_ACM_TimeId ++;
}
WMM_ACM_NumOfPkt[WMM_ACM_NumOfPktId][PktAcId] ++;
#endif /* WMM_ACM_PKT_NUM_DEBUG */
pStream->AcmUsedTimeEnqueue += TxTime;
}
else
{
/* No TSPEC is found so Tx Time = 0 (default) */
}
#endif /* ACM_CC_FUNC_SOFT_ACM */
/* assign AC ID or TS ID to the frame */
if ((FlgIsFindTspec == 1) &&
(pStream != NULL) &&
(FlgIsForceToHighAc == 0))
{
/* re-set user priority to packet information, used by WLAN module */
TxQueueType = pStream->TxQueueType;
if (TSID == 0xff)
TSID = ACM_TSID_Get(pAd, pMbuf);/* get TSID by UP or DSCP */
ACMR_PKT_MARK_UP(pMbuf, TSID);
ACMR_PKT_MARK_MIN_PHY_MODE(pMbuf, pStream->PhyModeMin);
ACMR_PKT_MARK_MIN_PHY_MCS(pMbuf, pStream->McsMin);
}
else
{
/*
Can not find any matched TCLAS/TSPEC so classify the packet to
the queue by UP or DSCP (EDCA stream).
*/
if (!(ACMR_PKT_QOS_TYPE_GET(pMbuf) == ACM_QOS_TYPE_NULL))
{
/* for non-QoS Null frame */
if (TSID == 0xff)
TSID = ACM_TSID_Get(pAd, pMbuf);/* get TSID by UP or DSCP */
PktAcId = ACM_MR_EDCA_AC(TSID);
}
if ((PktAcId != ACM_EDCA_BK_AC_QUE_ID) &&
(pEdcaParam->FlgAcmStatus[PktAcId] == ACM_FLG_FUNC_ENABLED) &&
(FlgIsForceToHighAc == 0))
{
/*
The ACM for the AC is enabled but we can not get any TSPEC
for the packet so we shall send the frame to AC0 (BE) queue
except BK traffic.
*/
TSID = 0; /* use BE */
PktAcId = ACM_EDCA_BE_AC_QUE_ID;
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
#ifdef RELEASE_EXCLUDE
/*
Since an AP manages the downlink flows using its own rules
and policies (it does not have to police used time, for
example), so we still can use BE to transmit traffic even
the ACM of BE is set.
*/
#endif /* RELEASE_EXCLUDE */
if (pEdcaParam->FlgAcmStatus[PktAcId] == ACM_FLG_FUNC_ENABLED)
{
ACM_STATS_COUNT_INC(pStats->DropByACM);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ACM of BE is set!\n"));
/*
My god!
The ACM of BE is also enabled! Discard the packet!
*/
goto LabelErr;
}
}
#endif /* CONFIG_STA_SUPPORT */
ACM_STATS_COUNT_INC(pStats->PriorityChange[PktAcId]);
}
/* send the frame the the AC */
pStream = NULL; /* no TSPEC is found */
TxQueueType = ACM_TxQueueTypeGet(PktAcId);
/* re-set user priority to packet information, used by WLAN module */
ACMR_PKT_MARK_UP(pMbuf, TSID);
}
LabelOK:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
*pQueueType = TxQueueType;
return ACM_RTN_OK;
LabelErrNoACM:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return ACM_RTN_NO_ACM;
LabelErr:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return ACM_RTN_FAIL;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_NO_ACM;
} /* End of ACMP_DataPacketQueue */
#ifdef RELEASE_EXCLUDE
/*
========================================================================
Routine Description:
Enable or disable Dynamic ATL function.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: enable; 0: disable
*pDatlBwMin - new minimum bandwidth threshold
*pDatlBwMax - new maximum bandwidth threshold
Return Value:
None
Note:
if you dont want to change bandwidth threshold, you can input NULL.
pDatlBwMin = NULL or pDatlBwMax = NULL
========================================================================
*/
VOID ACMP_DatlCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable,
ACM_PARAM_IN UCHAR *pDatlBwMin,
ACM_PARAM_IN UCHAR *pDatlBwMax)
{
ACM_CTRL_PARAM *pEdcaParam;
UINT32 IdAcNum, IdAcNumOther;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (!ACMR_IS_ENABLED(pAd))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> WMM ACM is disabled!\n"));
return;
} /* End of if */
/* first delete all TSPEC */
ACMP_TC_DeleteAll(pAd);
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/*
Assign new minimum and maximum bandwidth threshold
and clear all borrowing bandwidth.
*/
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
/* change DATL flag */
pEdcaParam->FlgDatl = FlgIsEnable;
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
if (pDatlBwMin != NULL)
pEdcaParam->DatlBwMin[IdAcNum] = pDatlBwMin[IdAcNum];
/* End of if */
if (pDatlBwMax != NULL)
pEdcaParam->DatlBwMax[IdAcNum] = pDatlBwMax[IdAcNum];
/* End of if */
for(IdAcNumOther=0; IdAcNumOther<ACM_DEV_NUM_OF_AC; IdAcNumOther++)
pEdcaParam->DatlBorAcBw[IdAcNum][IdAcNumOther] = 0;
/* End of for */
} /* End of for */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> DATL reset!\n"));
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_DatlCtrl */
#endif /* RELEASE_EXCLUDE */
#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
Append the QBSS Load element to the beacon frame.
Arguments:
pAd - WLAN control block pointer
*pPkt - the beacon frame
Return Value:
the element total length
Note:
========================================================================
*/
UINT32 ACMP_Element_QBSS_LoadAppend(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN_OUT UCHAR *pPkt)
{
ACM_ELM_QBSS_LOAD QBSS_Load, *pLoad = &QBSS_Load;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (!ACMR_IS_ENABLED(pAd))
return 0;
/* End of if */
/* copy information */
pLoad->ElementId = ACM_ELM_QBSS_LOAD_ID;
pLoad->Length = ACM_ELM_QBSS_LOAD_LEN;
pLoad->StationCount = ACMR_STA_CUR_COUNT(pAd);
pLoad->ChanUtil = ACMR_CHAN_UTILIZATION_GET(pAd);
pLoad->AvalAdmCap = 0;
/* copy the QBSS element to the frame, pPkt */
ACMR_MEM_COPY(pPkt, (UCHAR *)pLoad, sizeof(ACM_ELM_QBSS_LOAD));
return (ACM_ELM_ID_LEN_SIZE + ACM_ELM_QBSS_LOAD_LEN);
} /* End of ACMP_Element_QBSS_LoadAppend */
#endif /* CONFIG_AP_SUPPORT */
/*
========================================================================
Routine Description:
Reset current ACM Flag for each AC.
Arguments:
pAd - WLAN control block pointer
FlgIsAcm0Enable - the ACM flag for AC0
FlgIsAcm1Enable - the ACM flag for AC1
FlgIsAcm2Enable - the ACM flag for AC2
FlgIsAcm3Enable - the ACM flag for AC3
Return Value:
None
Note:
========================================================================
*/
VOID ACMP_EnableFlagReset(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsAcm0Enable,
ACM_PARAM_IN UCHAR FlgIsAcm1Enable,
ACM_PARAM_IN UCHAR FlgIsAcm2Enable,
ACM_PARAM_IN UCHAR FlgIsAcm3Enable)
{
UCHAR *pFlgArrayIsAcmEnabled;
UCHAR FlgIsAllTspecNeedToDelete;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FlgIsAllTspecNeedToDelete = 1;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* check if we need to delete all TS */
pFlgArrayIsAcmEnabled = ACMR_CB->EdcaCtrlParam.FlgAcmStatus;
if ((pFlgArrayIsAcmEnabled[0] == FlgIsAcm0Enable) &&
(pFlgArrayIsAcmEnabled[1] == FlgIsAcm1Enable) &&
(pFlgArrayIsAcmEnabled[2] == FlgIsAcm2Enable) &&
(pFlgArrayIsAcmEnabled[3] == FlgIsAcm3Enable))
{
/* same ACM flag for all AC so no need to delete TSPECs */
FlgIsAllTspecNeedToDelete = 0;
}
#if 0
/* maybe NULL TSPEC exists */
else if ((pFlgArrayIsAcmEnabled[0] == 0) &&
(pFlgArrayIsAcmEnabled[1] == 0) &&
(pFlgArrayIsAcmEnabled[2] == 0) &&
(pFlgArrayIsAcmEnabled[3] == 0))
{
/* old ACM flag of all AC are all-zero so no any TSPEC exists */
FlgIsAllTspecNeedToDelete = 0;
} /* End of if */
#endif
/* update new ACM flag */
pFlgArrayIsAcmEnabled[0] = FlgIsAcm0Enable;
pFlgArrayIsAcmEnabled[1] = FlgIsAcm1Enable;
pFlgArrayIsAcmEnabled[2] = FlgIsAcm2Enable;
pFlgArrayIsAcmEnabled[3] = FlgIsAcm3Enable;
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* update new TSPEC UAPSD function */
if (ACMR_APSD_CAPABLE_GET(pAd) == TRUE)
ACM_PS_UapsdCtrl(pAd, 1); /* can change UAPSD in TSPEC */
else
ACM_PS_UapsdCtrl(pAd, 0); /* can not change UAPSD in TSPEC */
/* End of if */
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Reset ACM flag to %d %d %d %d\n",
FlgIsAcm0Enable, FlgIsAcm1Enable, FlgIsAcm2Enable, FlgIsAcm3Enable));
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
ACMR_AC_ACM_CTRL(pAd,
FlgIsAcm0Enable,
FlgIsAcm1Enable,
FlgIsAcm2Enable,
FlgIsAcm3Enable);
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
/* delete all streams if needed */
if (FlgIsAllTspecNeedToDelete)
ACMP_TC_DeleteAll(pAd);
/* End of if */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* reset the UAPSD state */
/* suppose the function should be called in LinkUp() */
ACMR_UAPSD_BACKUP(pAd);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_EnableFlagReset */
/*
========================================================================
Routine Description:
Send a broadcast Bandwidth Annonce frame.
Arguments:
pAd - WLAN control block pointer
FlgIsForceToSent - 1: forece to send the frame
Return Value:
None
Note:
1. Carefully! This is a broadcast frame and must be non-encryption.
2. The frame is only sent by AP. STA only forward it.
3. AP A <--> AP B <--> AP C
AP B only need to broadcast its used ACM time, no AP A used time.
Because AP C does not see AP A.
========================================================================
*/
STATIC VOID ACMP_FrameBwAnnSend(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsForceToSent)
{
#ifdef ACM_CC_FUNC_MBSS
#ifdef CONFIG_AP_SUPPORT
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACMP_FrameBwAnnSend(pAd, FlgIsForceToSent);
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
#endif /* CONFIG_AP_SUPPORT */
#endif /* ACM_CC_FUNC_MBSS */
return;
}
/*
========================================================================
Routine Description:
Resume the ACM.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
========================================================================
*/
VOID ACMP_FSM_Resume(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACM_MR_TSPEC_ALLOW(pAd);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_FSM_Resume */
/*
========================================================================
Routine Description:
Suspend the ACM.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
QSTA: No any TSPEC request can be issued.
QAP: No any TSPEC request can be handled.
========================================================================
*/
VOID ACMP_FSM_Suspend(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACM_MR_TSPEC_DISALLOW(pAd);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_FSM_Suspend */
/*
========================================================================
Routine Description:
Get the device entry of MAC.
Arguments:
pAd - WLAN control block pointer
pDevMac - the entry MAC
Return Value:
TRUE - WMM is enabled
FALSE - WMM is disabled
Note:
========================================================================
*/
ACMR_STA_DB *ACMP_InfoStaEntryGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return MacTableLookup(pAd, pDevMac);
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* only one entry in QSTA, i.e. associated QAP */
return (IS_ENTRY_CLIENT(&(pAd->MacTab.Content[BSSID_WCID])) ? \
(&pAd->MacTab.Content[BSSID_WCID]) : NULL);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return NULL; /* impossible */
} /* End of ACMP_InfoStaEntryGet */
/*
========================================================================
Routine Description:
Return TRUE if the ACM of all AC are enabled.
Arguments:
pAd - WLAN control block pointer
Return Value:
ACM_RTN_OK - the ACM of all AC is enabled
ACM_RTN_FAIL - the ACM of one AC is disabled
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_IsAllACEnabled(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
UCHAR FlgAcmStatus[ACM_DEV_NUM_OF_AC];
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* copy ACM enabled flag first */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
ACMR_MEM_COPY(FlgAcmStatus,
ACMR_CB->EdcaCtrlParam.FlgAcmStatus,
sizeof(ACMR_CB->EdcaCtrlParam.FlgAcmStatus));
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* check ACM enabled flag */
if ((FlgAcmStatus[ACM_EDCA_BE_AC_QUE_ID] == 0) ||
(FlgAcmStatus[ACM_EDCA_BK_AC_QUE_ID] == 0) ||
(FlgAcmStatus[ACM_EDCA_VI_AC_QUE_ID] == 0) ||
(FlgAcmStatus[ACM_EDCA_VO_AC_QUE_ID] == 0))
{
/* at least one AC ACM is disabled */
return ACM_RTN_FAIL;
} /* End of if */
return ACM_RTN_OK;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACMP_IsAllACEnabled */
/*
========================================================================
Routine Description:
Return TRUE if the ACM of any AC is enabled.
Arguments:
pAd - WLAN control block pointer
Return Value:
ACM_RTN_OK - the ACM of any AC is enabled
ACM_RTN_FAIL - the ACM of all AC is disabled
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_IsAnyACEnabled(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
UCHAR FlgAcmStatus[ACM_DEV_NUM_OF_AC];
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* copy ACM enabled flag first */
ACM_TSPEC_IRQ_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
*(UINT32 *)(FlgAcmStatus) = *(UINT32 *)(ACMR_CB->EdcaCtrlParam.FlgAcmStatus);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
/* check ACM enabled flag */
if (*(UINT32 *)(FlgAcmStatus) == 0)
{
/* all AC ACM are disabled */
return ACM_RTN_FAIL;
} /* End of if */
return ACM_RTN_OK;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACMP_IsAnyACEnabled */
/*
========================================================================
Routine Description:
Return TRUE if the frame is Bandwidth Announce Action Frame.
Arguments:
pAd - WLAN control block pointer
*pMbuf - the frame
Return Value:
ACM_RTN_OK - Yes
ACM_RTN_FAIL - No
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_IsBwAnnounceActionFrame(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN VOID *pMbuf)
{
#ifdef ACM_CC_FUNC_MBSS
ACM_BW_ANN_FRAME *pFrameAnn;
UCHAR *pActFrame;
WMM_ACM_FUNC_NAME_PRINT("IN");
pActFrame = (UCHAR *)pMbuf + ACMR_FME_LEG_HEADER_SIZE;
pFrameAnn = (ACM_BW_ANN_FRAME *)pActFrame;
if ((pFrameAnn->Category == ACM_CATEGORY_WME) &&
(pFrameAnn->Action == ACM_ACTION_WME_BW_ANN))
{
return ACM_RTN_OK;
} /* End of if */
return ACM_RTN_FAIL;
#else
return ACM_RTN_FAIL;
#endif /* ACM_CC_FUNC_MBSS */
} /* End of ACMP_IsBwAnnounceActionFrame */
/*
========================================================================
Routine Description:
Check if the action frame is the DELTS frame.
Arguments:
*pMblk - the action frame
Return Value:
TRUE - Yes
FALSE - No
Note:
========================================================================
*/
BOOLEAN ACMP_IsDeltsFrame(
ACM_PARAM_IN UCHAR *pMblk)
{
UCHAR *pActFrame;
UCHAR Category, Action;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* points to the action frame WLAN header */
pActFrame = (UCHAR *)pMblk;
/* get Category & Action field */
Category = *pActFrame;
Action = *(pActFrame+1);
/* checking */
if (Category == ACM_CATEGORY_WME)
{
if (Action == ACM_ACTION_WME_TEAR_DOWN)
return TRUE;
/* End of if */
} /* End of if */
return FALSE;
} /* End of ACMP_IsDeltsFrame */
/*
========================================================================
Routine Description:
Check if the packet needs to do ACM.
Arguments:
pAd - WLAN control block pointer
*pCdb - the destination QSTA
UP - user priority
Return Value:
TRUE - Yes
FALSE - No
Note:
When the ACM of AC is set, the packet is needed to do ACM.
Only used in transmission path.
========================================================================
*/
BOOLEAN ACMP_IsNeedToDoAcm(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR UP)
{
UINT8 AcId;
ULONG SplFlags;
/* init */
WMM_ACM_FUNC_NAME_PRINT("IN");
AcId = ACM_MR_EDCA_AC(UP);
/* check */
ACM_TSPEC_IRQ_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, FALSE);
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[AcId])
{
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return TRUE;
} /* End of if */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return FALSE;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return FALSE;
} /* End of ACMP_IsNeedToDoAcm */
/*
========================================================================
Routine Description:
Check if the action frame is the ADDTS Response frame.
Arguments:
*pMblk - the action frame
Return Value:
TRUE - Yes
FALSE - No
Note:
========================================================================
*/
BOOLEAN ACMP_IsResponseFrame(
ACM_PARAM_IN UCHAR *pMblk)
{
UCHAR *pActFrame;
UCHAR Category, Action;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* points to the action frame WLAN header */
pActFrame = (UCHAR *)pMblk;
/* get Category & Action field */
Category = *pActFrame;
Action = *(pActFrame+1);
/* checking */
if (Category == ACM_CATEGORY_WME)
{
if (Action == ACM_ACTION_WME_SETUP_RSP)
return TRUE;
/* End of if */
} /* End of if */
return FALSE;
} /* End of ACMP_IsResponseFrame */
/*
========================================================================
Routine Description:
Handle the management action frame.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
SubType - the subtype of the frame
pMblk - the received frame
PhyRate - the physical tx rate for the frame
Return Value:
ACM_RTN_OK - pMblk is released or forwarded
ACM_RTN_FAIL - handle ok and pMblk is not released
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_ManagementHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UINT32 SubType,
ACM_PARAM_IN UCHAR *pMblk,
ACM_PARAM_IN UINT32 PktLen,
ACM_PARAM_IN UINT32 PhyRate)
{
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
/*
We can accept request due to ps mode change only
so we do NOT use ACMR_IS_ENABLED(pAd) here.
*/
if (!ACMR_SANITY_CHECK(pAd))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> discard ACM action frame!\n"));
return ACM_RTN_FAIL;
} /* End of if */
if (SubType != ACMR_SUBTYPE_ACTION)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> drop non ACM action frame!\n"));
return ACM_RTN_FAIL; /* not ACTION frame */
} /* End of if */
/* QAP mode */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
ACM_ActionHandleByQAP(pAd, pCdb, pMblk, PktLen, PhyRate);
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
/* QSTA mode */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
ACM_ActionHandleByQSTA(pAd, pCdb, pMblk, PktLen);
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
return ACM_RTN_OK;
} /* End of ACMP_ManagementHandle */
/*
========================================================================
Routine Description:
Classify the QoS frame to a AC queue.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
pMbuf - the received frame
QueueTypeCur - the current used queue type
FlgIsForceToHighAc - 1: force the packet to AC3
Return Value:
Queue Type: AC0 ~ AC3
not AC0 ~ AC3: can not transmit
Note:
1. Suppose the Tx Rate is not changed between ACMP_DataPacketQueue()
and ACMP_MsduClassify().
2. We re-do ACM control here because maybe OS delay between
ACMP_DataPacketQueue() and ACMP_MsduClassify().
========================================================================
*/
#ifdef WMM_ACM_PKT_NUM_DEBUG
/* global variables but only for debug */
UINT32 WMM_ACM_TimeAmsdu[WMM_ACM_DEBUG_TIME_MAX_NUM_REC][2];
UINT32 WMM_ACM_TimeAmsduId = 0, WMM_ACM_TimeAmsduRecId = 0;
#endif /* WMM_ACM_PKT_NUM_DEBUG */
UINT32 ACMP_MsduClassify(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACMR_MBUF *pMbuf,
ACM_PARAM_IN UINT32 QueueTypeCur,
ACM_PARAM_IN UCHAR FlgIsForceToHighAc,
ACM_PARAM_IN UCHAR AggType,
ACM_PARAM_IN UCHAR AggId)
{
#ifdef ACM_CC_FUNC_SOFT_ACM
#ifdef ACM_CC_FUNC_QUE_TX_CTRL
ACM_STREAM *pStream;
ACM_ENTRY_INFO *pStaAcmInfo;
ACM_CTRL_PARAM *pEdcaParam;
ACM_STATISTICS *pStats;
UCHAR *pPkt; /* same as pMbuf */
UINT32 PktLen;
UINT32 TxTime;
UCHAR TSID;
#ifndef PERFORMANCE_IMPACT_TEST
UINT32 PktAcId;
UINT32 TxQueueType;
#endif /* PERFORMANCE_IMPACT_TEST */
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (pCdb == NULL)
return QueueTypeCur;
TxTime = RTMP_GET_PACKET_TX_TIME(pMbuf);
if (TxTime == 0)
return QueueTypeCur;
pPkt = (UCHAR *)ACMR_WLAN_PKT_GET(pMbuf);
PktLen = ACMR_WLAN_LEN_GET(pMbuf);
if (AggType == ACMR_AGG_RALINK)
{
/* TODO */
}
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_CLSFY_NOT_ALLOW);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pStats = &pEdcaParam->Stats;
/* get TSPEC */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
TSID = RTMP_GET_PACKET_STM_TSID(pMbuf);
pStream = (ACM_STREAM *)pStaAcmInfo->pAcStmOut[TSID];
#ifdef ACM_CC_FUNC_11N_AGG
/* aggregation check */
if ((pStream != NULL) &&
(pStream->pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_NORMAL))
{
/*
WLAN Header + A-MSDU Subframe 1 + A-MSDU Subframe 2 + ...
A-MSDU Subframe is as below:
DA(6) + SA(6) + Length(2) + MSDU + Padding (0~3)
Nothing to do for 1st A-MSDU.
*/
if ((AggType == ACMR_AGG_AMSDU) && (AggId > 1))
{
/* re-calculate TX time */
#ifdef ACM_CC_FUNC_AUX_TX_TIME
ACM_TX_TimeCalHT(pAd, NULL,
PktLen+FRM_LENGTH_AGG_AMSDU_HDR, /* body len */
McsId, /* MCS Index */
ACMR_IS_2040_STA(pCdb), /* 20 or 20/40 MHz */
0, /* regular or short GI */
0, /* rts/cts */
0, /* no ack */
1, /* no AMPDU or fist pkt in AMPDU */
0xFFFFFFFF, /* txop limit */
0, /* do not care */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* ack tx time */
NULL, /* data+hdr only tx time */
&TxTime); /* data only tx time */
#else
UINT32 LenDataId;
UINT32 McsId;
McsId = ACMR_CLIENT_MCS_GET(pCdb);
LenDataId = (PktLen+FRM_LENGTH_AGG_AMSDU_HDR);
LenDataId >>= ACM_PRE_TIME_DATA_SIZE_OFFSET;
#if 0
if (LenDataId > 0)
LenDataId --; /* use smaller length */
#endif /* 0 */
if (LenDataId >= ACM_PRE_TIME_DATA_SIZE_NUM)
LenDataId = ACM_PRE_TIME_DATA_SIZE_NUM-1;
/* data time */
TxTime = gAcmTxTimeBodyHT\
[ACMR_IS_2040_STA(pCdb)][0][McsId][LenDataId][2];
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
}
}
#endif /* ACM_CC_FUNC_11N_AGG */
/* check if tx time > TXOP limit for AC2 & AC3 */
if (pStream != NULL)
{
UINT64 Timestamp, TimeOffset;
UINT32 TimeAllowed;
/* get 64-bit Timestamp */
ACMR_TIMESTAMP_GET(pAd, Timestamp);
/* translate MediumTime (unit: 32us) to us */
ACMR_ALLOWED_TIME_GET(pStream, TimeAllowed);
TimeOffset = (UINT64)((INT64)Timestamp - \
(INT64)pStream->TxTimestampMarkTransmit);
if (TimeOffset >= ACM_TIME_BASE)
{
/* the first packet in next second */
pStream->TxTimestampMarkTransmit = Timestamp;
/* reset the used time */
if (pStream->AcmUsedTimeTransmit > TimeAllowed)
pStream->AcmUsedTimeTransmit -= TimeAllowed;
else
pStream->AcmUsedTimeTransmit = 0;
#ifdef WMM_ACM_PKT_NUM_DEBUG
WMM_ACM_TimeAmsduRecId ++;
if (WMM_ACM_TimeAmsduRecId == 5)
NdisZeroMemory(WMM_ACM_TimeAmsdu, sizeof(WMM_ACM_TimeAmsdu));
#endif /* WMM_ACM_PKT_NUM_DEBUG */
}
else
{
#ifndef PERFORMANCE_IMPACT_TEST
/* during a second */
if (pStream->AcmUsedTimeTransmit > TimeAllowed)
{
/* can not tx the packet to the AC so check downgrade flag */
PktAcId = pStream->AcmAcId;
if (ACMR_CB->EdcaCtrlParam.DowngradeAcNum[PktAcId] != \
ACM_DOWNGRADE_DISABLE)
{
TxQueueType = ACM_TxQueueTypeGet( \
ACMR_CB->EdcaCtrlParam.DowngradeAcNum[PktAcId]);
ACM_STATS_COUNT_INC(pStats->Downgrade[PktAcId]);
/* need to change the UP of QoS Control field */
TSID = gEDCA_AC_UP[pEdcaParam->DowngradeAcNum[PktAcId]];
ACMR_PKT_MARK_UP(pMbuf, TSID);
goto LabelDowngrade;
}
ACM_STATS_COUNT_INC(pStats->DropByAdmittedTime);
/* downgrade function is disabled so discarding the packet */
goto LabelDiscard;
}
#endif /* PERFORMANCE_IMPACT_TEST */
#ifdef WMM_ACM_PKT_NUM_DEBUG
if (WMM_ACM_TimeAmsduRecId == 5)
{
WMM_ACM_TimeAmsdu[WMM_ACM_TimeAmsduId][0] = TxTime;
WMM_ACM_TimeAmsdu[WMM_ACM_TimeAmsduId++][1] = \
pStream->AcmUsedTimeTransmit;
if (WMM_ACM_TimeAmsduId >= WMM_ACM_DEBUG_TIME_MAX_NUM_REC)
WMM_ACM_TimeAmsduId = 0;
}
#endif /* WMM_ACM_PKT_NUM_DEBUG */
}
/* accumulate used time */
pStream->AcmUsedTimeTransmit += TxTime;
}
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return QueueTypeCur;
LabelDowngrade:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return TxQueueType;
LabelDiscard:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return ACM_CLSFY_NOT_ALLOW;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_CLSFY_NOT_ALLOW;
#else
/* no ACM in packet dequeue */
return QueueTypeCur;
#endif /* ACM_CC_FUNC_QUE_TX_CTRL */
#else
/* no hardware ACM */
return QueueTypeCur;
#endif /* ACM_CC_FUNC_SOFT_ACM */
}
/*
========================================================================
Routine Description:
Get new adjust parameters for non-ACM AC.
Arguments:
pAd - WLAN control block pointer
*pEdcaParam - the parameters
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
Only for QAP.
========================================================================
*/
VOID ACMP_NonAcmAdjustParamUpdate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pEdcaParam)
{
#ifdef CONFIG_AP_SUPPORT
#ifdef ACM_CC_FUNC_CHAN_UTIL_MONITOR
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (!ACMR_SANITY_CHECK(pAd))
return;
/* End of if */
if (pEdcaParam == NULL)
return;
/* End of if */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
if (ACMR_CB->CU_MON_FlgChangeNeed != 0)
{
/* update WMM Parameters to AP CSR */
EDCA_AC_CFG_STRUC CsrCfgAc0, CsrCfgAc1, CsrCfgAc2, CsrCfgAc3;
AIFSN_CSR_STRUC CsrAifsn;
UCHAR AIFSN[ACM_DEV_NUM_OF_AC];
ACMR_MEM_COPY(AIFSN, ACMR_CB->CU_MON_AifsnAp, ACM_DEV_NUM_OF_AC);
CsrAifsn.field.Aifsn0 = AIFSN[0];
CsrAifsn.field.Aifsn1 = AIFSN[1];
CsrAifsn.field.Aifsn2 = AIFSN[2];
CsrAifsn.field.Aifsn3 = AIFSN[3];
RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, CsrAifsn.word);
RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &CsrCfgAc0.word);
CsrCfgAc0.field.Aifsn = AIFSN[0];
RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, CsrCfgAc0.word);
RTMP_IO_READ32(pAd, EDCA_AC1_CFG, &CsrCfgAc1.word);
CsrCfgAc1.field.Aifsn = AIFSN[1];
RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, CsrCfgAc1.word);
RTMP_IO_READ32(pAd, EDCA_AC2_CFG, &CsrCfgAc2.word);
CsrCfgAc2.field.Aifsn = AIFSN[2];
RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, CsrCfgAc2.word);
RTMP_IO_READ32(pAd, EDCA_AC3_CFG, &CsrCfgAc3.word);
CsrCfgAc3.field.Aifsn = AIFSN[3];
RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, CsrCfgAc3.word);
} /* End of if */
/* update to BSS beacon */
ACMR_MEM_COPY(pEdcaParam, ACMR_CB->CU_MON_AifsnBss, ACM_DEV_NUM_OF_AC);
ACMR_CB->CU_MON_FlgChangeNeed = 0;
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#endif /* ACM_CC_FUNC_CHAN_UTIL_MONITOR */
#endif /* CONFIG_AP_SUPPORT */
} /* End of ACMP_NonAcmAdjustParamUpdate */
/*
========================================================================
Routine Description:
Get current number of input TSPEC for the UP.
Arguments:
*pCdb - the QSTA
UP - the UP
Return Value:
Number of TSPEC
Note:
========================================================================
*/
UINT32 ACMP_NumOfAcTspecInGet(
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR UP)
{
UINT32 AcId = ACM_MR_EDCA_AC(UP);
/* ACM_NumOfInTspecInAc[] is a array, skip to protect to speed up */
return pCdb->ACM_NumOfInTspecInAc[AcId];
} /* End of ACMP_NumOfAcTspecInGet */
/*
========================================================================
Routine Description:
Get current number of output TSPEC for the UP.
Arguments:
*pCdb - the QSTA
UP - the UP
Return Value:
Number of TSPEC
Note:
========================================================================
*/
UINT32 ACMP_NumOfAcTspecOutGet(
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR UP)
{
UINT32 AcId = ACM_MR_EDCA_AC(UP);
/* ACM_NumOfOutTspecInAc[] is a array, skip to protect to speed up */
return pCdb->ACM_NumOfOutTspecInAc[AcId];
} /* End of ACMP_NumOfAcTspecOutGet */
/*
========================================================================
Routine Description:
Check if the current tx PHY Mode and MCS > minimum PHY Mode and MCS.
Arguments:
pAd - WLAN control block pointer
*pMbuf - the frame expected to transmit
FlgIs2040 - 1: the packet uses 40MHz
FlgIsShortGI - 1: the packet uses Short GI
PhyMode - the PHY Mode expected to use
Mcs - the MCS expected to use
Return Value:
ACM_RTN_OK - current Mode & MCS is allowed
ACM_RTN_FAIL - current Mode & MCS is not allowed
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_PacketPhyModeMCSCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_MBUF *pMbuf,
ACM_PARAM_IN UCHAR FlgIs2040,
ACM_PARAM_IN UCHAR FlgIsShortGI,
ACM_PARAM_IN UCHAR PhyMode,
ACM_PARAM_IN UCHAR Mcs)
{
#ifdef RELEASE_EXCLUDE
/*
MCS Information:
CCK PHY Mode (0) 1M 2M 5.5M 11M
Short Preamble MCS: 0 1 2 3
Long Preamble MCS: 8 9 10 11
OFDM PHY Mode (1) 6M 9M 12M 18M 24M 36M 48M 54M
MCS: 0 1 2 3 4 5 6 7
HT PHY Mode (2) reference to gAcmMCS_HT[]
*/
#endif /* RELEASE_EXCLUDE */
UINT32 RateMin, Rate;
UCHAR PhyModeMin, McsMin;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* get minimum rate information from the packet */
ACMR_PKT_MIN_PHY_MODE_GET(pMbuf, PhyModeMin);
if (PhyModeMin == ACMR_PHY_NONE)
{
/* no minimum rate requirement for the packet, do NOT need to check */
return ACM_RTN_OK;
} /* End of if */
/* init */
ACMR_PKT_MIN_PHY_MCS_GET(pMbuf, McsMin);
/* get minimum physical rate */
switch(PhyModeMin)
{
case ACMR_PHY_CCK:
if (McsMin <= ACM_CCK_LPM_MAX_MCS)
{
/* long preamble */
RateMin = gAcmMCS_CCK[0][McsMin][1];
}
else if (McsMin <= ACM_CCK_SPM_MAX_MCS)
{
/* short preamble */
RateMin = gAcmMCS_CCK[1][McsMin - ACM_CCK_SPM_MIN_MCS][1];
}
else
RateMin = gAcmMCS_CCK[0][0][1];
/* End of if */
break;
case ACMR_PHY_OFDM:
RateMin = gAcmMCS_OFDM[McsMin][1];
break;
#ifdef ACM_CC_FUNC_11N
case ACMR_PHY_HT:
/* always use regular GI */
RateMin = gAcmMCS_HT[FlgIs2040][0][McsMin];
break;
#endif /* ACM_CC_FUNC_11N */
default:
/* no minimum rate requirement for the packet, do NOT need to check */
return ACM_RTN_OK;
} /* End of switch */
/* get current physical rate */
switch(PhyMode)
{
case ACMR_PHY_CCK:
if (Mcs <= ACM_CCK_LPM_MAX_MCS)
{
/* long preamble */
Rate = gAcmMCS_CCK[0][Mcs][1];
}
else if (Mcs <= ACM_CCK_SPM_MAX_MCS)
{
/* short preamble */
Rate = gAcmMCS_CCK[1][Mcs - ACM_CCK_SPM_MIN_MCS][1];
}
else
Rate = gAcmMCS_CCK[0][0][1];
/* End of if */
break;
case ACMR_PHY_OFDM:
Rate = gAcmMCS_OFDM[Mcs][1];
break;
#ifdef ACM_CC_FUNC_11N
case ACMR_PHY_HT:
Rate = gAcmMCS_HT[FlgIs2040][FlgIsShortGI][Mcs];
break;
#endif /* ACM_CC_FUNC_11N */
default:
/* no minimum rate requirement for the packet, do NOT need to check */
return ACM_RTN_OK;
} /* End of switch */
/* check if current used rate is not smaller than the minimum rate */
if (Rate < RateMin)
return ACM_RTN_FAIL;
/* End of if */
return ACM_RTN_OK;
} /* End of ACMP_PacketPhyModeMCSCheck */
/*
========================================================================
Routine Description:
Return power save right to system.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
1. Only for STATION mode.
2. We will return PS right when no any pending ADDTS request frame.
========================================================================
*/
VOID ACMP_StaPsCtrlRightReturn(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_STA_SUPPORT
#ifndef ACM_CC_FUNC_PS_MGMT_FME
ACM_STREAM *pStreamReq;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
pStreamReq = ACMR_CB->TspecListReq.pHead;
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* only return the PS right when no any requested TSPEC is pending */
if (pStreamReq == NULL)
{
/* no any requested TSPEC exists */
ACMR_STA_PS_MODE_RECOVER(pAd);
} /* End of if */
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
#endif /* ACMR_STA_PS_MODE_RECOVER */
#endif /* CONFIG_STA_SUPPORT */
return;
} /* End of ACMP_StaPsCtrlRightReturn */
#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
Used to signal WMM ACM Non-ACM TSPEC response support in the AP.
Arguments:
pAd - WLAN control block pointer
*pElementWme - the WMM Parameter IE
Return Value:
None
Note:
Used in QAP.
Now that we've agreed that WMM-AC APs shall respond to/accept TSPEC
requests on non-ACM ACs, how about setting b6 of the "Reserved" octet
in the WMM Parameter IE .
========================================================================
*/
VOID ACMP_NullTspecSupportSignal(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN_OUT UCHAR *pElementWme)
{
if (!ACMR_SANITY_CHECK(pAd))
return;
/* End of if */
pElementWme[9] |= 0x40; /* bit 6 in reserved field */
} /* End of ACMP_NullTspecSupportSignal */
/*
========================================================================
Routine Description:
Update UAPSD states after ADDTS Response or DELTS is sent out.
Arguments:
pAd - WLAN control block pointer
*pCdb - the QSTA
*pActFrameBody - the action frame
Return Value:
None
Note:
Used in QAP.
========================================================================
*/
ACM_EXTERN VOID ACMP_PsRspDeltsSentOutHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN_OUT UCHAR *pActFrameBody)
{
ACM_WME_NOT_FRAME *pNotFrame;
ACM_STREAM **ppAcmStmList, *pStream;
UINT32 TID, Direction;
UCHAR AcId, UP;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((pCdb == NULL) || (!ACMR_SANITY_CHECK(pAd)))
return;
/* End of if */
/* get TSID & Direction */
pNotFrame = (ACM_WME_NOT_FRAME *)pActFrameBody;
if (pNotFrame->Category != ACM_CATEGORY_WME)
return; /* not WME action frame */
/* End of if */
/* DELTS */
if (pNotFrame->Action == ACM_ACTION_WME_TEAR_DOWN)
{
ACM_TS_INFO TsInfo;
/* get TID from the DELTS frame */
ACMR_MEM_ZERO(&TsInfo, sizeof(TsInfo));
TsInfo.TSID = pNotFrame->ElmTspec.Tspec.TsInfo.TID;
/* handle the DELTS frame */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACM_DeltsFrameACK(pAd, ACMR_CLIENT_MAC(pCdb), (UCHAR *)&TsInfo, 0);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
ACMP_FrameBwAnnSend(pAd, FALSE);
return; /* handle DELTS ok for power-save station */
} /* End of if */
/* ADDTS Response */
if (pNotFrame->StatusCode != WLAN_STATUS_CODE_WME_ACM_ACCEPTED)
return; /* only care about SUCCESS */
/* End of if */
Direction = pNotFrame->ElmTspec.Tspec.TsInfo.Direction;
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* check if we need to update UAPSD state after the RESPONSE is sent out */
if ((Direction == ACM_DIRECTION_BIDIREC_LINK) ||
(Direction == ACM_DIRECTION_DOWN_LINK))
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, ACMR_CLIENT_MAC(pCdb), ACM_PEER_TSPEC_OUTPUT_GET);
}
else
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, ACMR_CLIENT_MAC(pCdb), ACM_PEER_TSPEC_INPUT_GET);
} /* End of if */
if (ppAcmStmList == NULL)
goto LabelOK;
/* End of if */
TID = pNotFrame->ElmTspec.Tspec.TsInfo.TID;
pStream = ppAcmStmList[TID];
if ((pStream != NULL) && (pStream->FlgUapsdHandleNeed))
{
/* we need to reset UAPSD state for the PS TSPEC */
UP = pNotFrame->ElmTspec.Tspec.TsInfo.UP;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ADDTS Rsp is sent! (TID=%d, DIR=%d, UP=%d)\n",
TID, Direction, UP));
AcId = ACM_MR_EDCA_AC(UP);
ACM_APSD_Ctrl(pAd, pCdb, AcId,
pStream->pTspec->TsInfo.Direction,
1, pStream->pTspec->TsInfo.APSD);
pStream->FlgUapsdHandleNeed = 0; /* handle ok */
} /* End of if */
LabelOK:
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_PsRspDeltsSentOutHandle */
/*
========================================================================
Routine Description:
Handle the resource allocation.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
*pBufRscReq - the buffer which includes the TSPEC request
*pBufRscRsp - the buffer where we can put TSPEC response
*pBufRspLen - the respone frame length
Return Value:
ACM_RTN_OK - handle ok
ACM_RTN_FAIL - handle fail
Note:
1. Used in QAP.
2. Currently only TSPEC element for request/response, no TCLAS.
========================================================================
*/
ACM_EXTERN ACM_FUNC_STATUS ACMP_ResourceAllocate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pBufRscReq,
ACM_PARAM_OUT UCHAR *pBufRscRsp,
ACM_PARAM_OUT UINT32 *pBufRspLen)
{
ACM_ELM_WME_TSPEC *pElmWmeTspec;
ACM_TCLAS *pTclas[ACM_TSPEC_TCLAS_MAX_NUM];
ACM_TSPEC Tspec;
UINT32 TclasNum;
UCHAR TclasProcessing;
UCHAR StatusCode;
UINT16 MediumTime;
ACM_FUNC_STATUS RtnCode;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
pElmWmeTspec = (ACM_ELM_WME_TSPEC *)pBufRscReq;
if ((pElmWmeTspec->ElementId != ACM_ELM_WME_ID) ||
(pElmWmeTspec->OUI[0] != ACM_WME_OUI_0) ||
(pElmWmeTspec->OUI[1] != ACM_WME_OUI_1) ||
(pElmWmeTspec->OUI[2] != ACM_WME_OUI_2) ||
(pElmWmeTspec->OUI_Type != ACM_WME_OUI_TYPE) ||
(pElmWmeTspec->OUI_SubType != ACM_WME_OUI_SUBTYPE_TSPEC) ||
(pElmWmeTspec->Version != ACM_WME_OUI_VERSION))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Not WME TSPEC! ACMP_ResourceAllocate()\n"));
goto label_fail; /* sanity check fail */
} /* End of if */
/* translate WME TSPEC to 11e TSPEC */
/* skip 4B Category, action, DialogToken, & StatusCode */
if (ACM_WME_11E_TSPEC_TCLAS_Translate(
pBufRscReq,
4+sizeof(ACM_ELM_WME_TSPEC),
&Tspec,
pTclas,
&TclasNum,
&TclasProcessing) != ACM_RTN_OK)
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> Translate TSPEC fail! "
"ACMP_ResourceAllocate()\n"));
goto label_fail; /* translate fail */
} /* End of if */
/* handle the request */
RtnCode = ACM_TC_ReqHandle(
pAd, pCdb, ACM_STREAM_TYPE_WIFI,
0, &Tspec,
TclasNum, pTclas,
TclasProcessing,
0, &StatusCode, &MediumTime);
if (RtnCode != ACM_RTN_OK)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A WME Setup request is not allowed %d! "
"ACMP_ResourceAllocate()\n", RtnCode));
goto label_fail; /* allocate fail */
}
else
pElmWmeTspec->Tspec.MediumTime = MediumTime;
/* End of if */
/* copy response content */
ACMR_MEM_COPY(pBufRscRsp, pElmWmeTspec, sizeof(ACM_ELM_WME_TSPEC));
*pBufRspLen = sizeof(ACM_ELM_WME_TSPEC);
/* send a broadcast private ACTION frame to advise used ACM time in AP */
ACMP_FrameBwAnnSend(pAd, FALSE);
return ACM_RTN_OK;
label_fail:
/* copy response content */
ACMR_MEM_COPY(pBufRscRsp, pElmWmeTspec, sizeof(ACM_ELM_WME_TSPEC));
*pBufRspLen = sizeof(ACM_ELM_WME_TSPEC);
return ACM_RTN_FAIL;
} /* End of ACMP_ResourceAllocate */
/*
========================================================================
Routine Description:
Update the UAPSD state based on current all TSPECs.
Arguments:
pAd - WLAN control block pointer
*pCdb - the QSTA
Return Value:
None
Note:
Used in QAP.
Use the function after reassociation request.
Because TSPEC is not deleted after reassociation request, we need
to update new UAPSD state based on these TSPEC and recover to some
static settings in reassociation frame after any TSPEC is deleted.
========================================================================
*/
VOID ACMP_UAPSD_StateUpdate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
ACM_STREAM **ppAcmStmList;
ACM_TS_INFO *pTsInfo;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UINT32 IdTidNum, IdLinkNum;
UCHAR AcId, Direction, UP, APSD;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((pCdb == NULL) || (!ACMR_SANITY_CHECK(pAd)))
return;
/* End of if */
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* check all output and input streams for the peer device */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, ACMR_CLIENT_MAC(pCdb), DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
break;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (ppAcmStmList[IdTidNum] != NULL)
{
pTsInfo = &(ppAcmStmList[IdTidNum]->pTspec->TsInfo);
Direction = pTsInfo->Direction;
UP = pTsInfo->UP;
APSD = pTsInfo->APSD;
AcId = ACM_MR_EDCA_AC(UP);
if (Direction == ACM_DIRECTION_BIDIREC_LINK)
{
pCdb->bAPSDCapablePerAC[AcId] = APSD;
pCdb->bAPSDDeliverEnabledPerAC[AcId] = APSD;
}
else if (Direction == ACM_DIRECTION_DOWN_LINK)
{
pCdb->bAPSDDeliverEnabledPerAC[AcId] = APSD;
}
else if (Direction == ACM_DIRECTION_UP_LINK)
{
pCdb->bAPSDCapablePerAC[AcId] = APSD;
} /* End of if */
} /* End of if */
} /* End of for */
} /* End of while */
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
if ((pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BE] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BK] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VI] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VO] == 1))
{
/* all AC are U-APSD delivery-enabled */
pCdb->bAPSDAllAC = 1;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> all AC are UAPSD!\n"));
}
else
{
/* at least one AC is not U-APSD delivery-enabled */
pCdb->bAPSDAllAC = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> not all AC are UAPSD!\n"));
} /* End of if */
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_UAPSD_StateUpdate */
#endif /* CONFIG_AP_SUPPORT */
/*
========================================================================
Routine Description:
Get ACM related statistics counts.
Arguments:
pAd - WLAN control block pointer
*pStats - the statistics counts
Return Value:
TRUE - get ok
FALSE - get fail
Note:
========================================================================
*/
BOOLEAN ACMP_StatisticsGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_OUT ACM_STATISTICS *pStats)
{
ACM_CTRL_PARAM *pEdcaParam;
ULONG SplFlags;
/* sanity check for WMM */
if (!ACMR_SANITY_CHECK(pAd))
return FALSE;
/* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, FALSE);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
*pStats = pEdcaParam->Stats;
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return TRUE;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return FALSE;
} /* End of ACMP_StatisticsGet */
/*
========================================================================
Routine Description:
Delete a QSTA due to deauthentication or deassociation, etc.
Arguments:
pAd - WLAN control block pointer
*pCdb - the QSTA
Return Value:
None
Note:
1. Used in QAP and QSTA.
2. Before any entry deletion, you must call the function to release TS first.
========================================================================
*/
VOID ACMP_StationDelete(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
ACM_ENTRY_INFO *pStaAcmInfo;
ACM_STREAM *pStream;
UINT32 IdTidNum;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* sanity check for WMM */
if (!ACMR_SANITY_CHECK(pAd))
return;
/* End of if */
/* recover UAPSD state */
/*
Note: must put before ACMR_IS_ENABLED() because we can change PS mode
without ACM bit set.
*/
pAd->CommonCfg.bAPSDAC_VO = \
pAd->CommonCfg.bACMAPSDBackup[ACM_EDCA_VO_AC_QUE_ID];
pAd->CommonCfg.bAPSDAC_VI = \
pAd->CommonCfg.bACMAPSDBackup[ACM_EDCA_VI_AC_QUE_ID];
pAd->CommonCfg.bAPSDAC_BK = \
pAd->CommonCfg.bACMAPSDBackup[ACM_EDCA_BK_AC_QUE_ID];
pAd->CommonCfg.bAPSDAC_BE = \
pAd->CommonCfg.bACMAPSDBackup[ACM_EDCA_BE_AC_QUE_ID];
#if 0
/*
2009/07/23
We can not reset bAPSDCapable to 0.
The flag is a static flag from RT28xxSTA.dat
We can not modify it in any time.
Or after AP disassociates us, MaxSPLength is always 0 in next
association request frame due to pAd->CommonCfg.bAPSDCapable = 0 of
MlmeAssocReqAction().
*/
if ((pAd->CommonCfg.bAPSDAC_VO == FALSE) &&
(pAd->CommonCfg.bAPSDAC_VI == FALSE) &&
(pAd->CommonCfg.bAPSDAC_BE == FALSE) &&
(pAd->CommonCfg.bAPSDAC_BK == FALSE))
{
pAd->CommonCfg.bAPSDCapable = FALSE;
}
else
pAd->CommonCfg.bAPSDCapable = TRUE;
/* End of if */
#endif
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
/* sanity check for ACM */
if ((pCdb == NULL) || (!ACMR_SANITY_CHECK(pAd)))
return;
/* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Station associates or is deleted! "
"ACMP_StationDelete()\n"));
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* free all requested TSPECs for the device entry if exists */
ACM_TC_ReqDeviceFree(pAd, pCdb);
/* free all TSPECs silently without sending DELTS frames */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
/* for OUT stream */
pStream = (ACM_STREAM *)(pStaAcmInfo->pAcStmOut[IdTidNum]);
if (pStream != NULL)
ACM_TC_Discard(pAd, pStream);
/* End of if */
pStaAcmInfo->pAcStmOut[IdTidNum] = NULL;
/* for IN stream */
pStream = (ACM_STREAM *)pStaAcmInfo->pAcStmIn[IdTidNum];
if (pStream != NULL)
ACM_TC_Discard(pAd, pStream);
/* End of if */
pStaAcmInfo->pAcStmIn[IdTidNum] = NULL;
} /* End of for */
/* free the peer device record ever reserving bandwidth */
ACM_PeerDeviceDel(pAd, ACMR_CLIENT_MAC(pCdb));
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* announce new bandwidth */
ACMP_FrameBwAnnSend(pAd, FALSE);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_StationDelete */
/*
========================================================================
Routine Description:
Clear failed stream information.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
========================================================================
*/
VOID ACMP_StreamFailClear(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ACM_TSPEC_REQ_LIST *pTspecFreedList;
ULONG SplFlags;
/* sanity check */
if (!ACMR_IS_ENABLED(pAd))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> WMM ACM is disabled! StreamFailClear()\n"));
return;
} /* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* free "all" failed stream records */
pTspecFreedList = &ACMR_CB->TspecListFail;
ACM_LIST_ALL_FREE(pAd, pTspecFreedList);
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_StreamFailClear */
/*
========================================================================
Routine Description:
Get some streams information.
Arguments:
pAd - WLAN control block pointer
Category - ACM_STM_CATEGORY_REQ,
ACM_STM_CATEGORY_ACT,
ACM_SM_CATEGORY_PEER,
ACM_STM_CATEGORY_ERR
Type - ACM_ACCESS_POLICY_EDCA
*pNumStm - the number of streams you want, must > 0
*pStaMac - the QSTA MAC
*pStreamBuf - the stream information buffers
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - no more stream
Note:
1. if pStream->pTspec == NULL, the function will not copy
TSPEC information.
2. if pStream->pTclas[i] == NULL, the function will not
copy TCLAS information.
3. If you want to get all stream information, you shall call
ACMP_StreamNumGet() first.
========================================================================
*/
ACM_FUNC_STATUS ACMP_StreamsGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 Category,
ACM_PARAM_IN UINT32 Type,
ACM_PARAM_IN_OUT UINT32 *pNumStm,
ACM_PARAM_IN UCHAR *pStaMac,
ACM_PARAM_OUT ACM_STREAM_INFO *pStreamBuf)
{
ACM_PEER_DEV_LIST *pAcmDevList;
ACM_STREAM *pStream, **ppAcmStmList;
UINT32 NumWant, NumActualGot;
UINT32 IdTidNum, IdLinkNum;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UCHAR MAC[ACM_MAC_ADDR_LEN];
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((*pNumStm) == 0)
return ACM_RTN_FAIL;
/* End of if */
/* init */
pStream = NULL;
NumWant = *pNumStm;
NumActualGot = 0;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* copy stream information */
switch(Category)
{
case ACM_SM_CATEGORY_REQ: /* requested list */
pStream = ACMR_CB->TspecListReq.pHead;
while((pStream != NULL) && (NumActualGot < NumWant))
{
ACM_STM_InfoCopy(&pStreamBuf[NumActualGot++], pStream);
pStream = pStream->pNext;
} /* End of while */
break;
case ACM_SM_CATEGORY_ACT: /* output links of 'all' peers */
pAcmDevList = NULL;
while(1)
{
/* get next device */
if (ACM_PeerDeviceGetNext(pAd, &pAcmDevList, MAC) != ACM_RTN_OK)
break;
/* End of if */
/* copy output and input TS information */
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, MAC, ACM_PEER_TSPEC_OUTPUT_GET);
if (ppAcmStmList == NULL)
continue;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (NumActualGot >= NumWant)
break;
/* End of if */
if (ppAcmStmList[IdTidNum] != NULL)
{
ACM_STM_InfoCopy(&pStreamBuf[NumActualGot++],
ppAcmStmList[IdTidNum]);
} /* End of if */
} /* End of for */
} /* End of while */
break;
case ACM_SM_CATEGORY_PEER: /* input and output links of a peer */
/* 2 links: input and output TSPEC */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, pStaMac, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
break;;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (NumActualGot >= NumWant)
break;
/* End of if */
if (ppAcmStmList[IdTidNum] != NULL)
{
if ((IdLinkNum == 1) &&
(ppAcmStmList[IdTidNum]->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK))
{
/* for bidirectional link, only copy one */
continue;
} /* End of if */
ACM_STM_InfoCopy(&pStreamBuf[NumActualGot++],
ppAcmStmList[IdTidNum]);
} /* End of if */
} /* End of for */
} /* End of for */
break;
case ACM_SM_CATEGORY_ERR: /* failed list */
pStream = ACMR_CB->TspecListFail.pHead;
while((pStream != NULL) && (NumActualGot < NumWant))
{
ACM_STM_InfoCopy(&pStreamBuf[NumActualGot++], pStream);
pStream = pStream->pNext;
} /* End of while */
break;
default:
goto LabelErr;
} /* End of switch */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* return actual got number */
*pNumStm = NumActualGot;
return ACM_RTN_OK;
LabelErr:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_FAIL;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACMP_StreamsGet */
/*
========================================================================
Routine Description:
Get the number of streams.
Arguments:
pAd - WLAN control block pointer
Category - ACM_STM_CATEGORY_REQ,
ACM_STM_CATEGORY_ACT,
ACM_SM_CATEGORY_PEER,
ACM_STM_CATEGORY_ERR
Type - ACM_ACCESS_POLICY_EDCA
*pStaMac - the QSTA MAC
Return Value:
current number of streams
Note:
========================================================================
*/
UINT32 ACMP_StreamNumGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 Category,
ACM_PARAM_IN UINT32 Type,
ACM_PARAM_IN UCHAR *pStaMac)
{
ACM_PEER_DEV_LIST *pAcmDevList;
ACM_STREAM *pStream, **ppAcmStmList;
UINT32 NumStream, IdTidNum, IdLinkNum;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UCHAR MAC[ACM_MAC_ADDR_LEN];
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
NumStream = 0;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, 0);
switch(Category)
{
case ACM_SM_CATEGORY_REQ: /* requested list */
pStream = ACMR_CB->TspecListReq.pHead;
while(pStream != NULL)
{
NumStream ++;
pStream = pStream->pNext;
} /* End of while */
break;
case ACM_SM_CATEGORY_ACT: /* output links of all peers */
pAcmDevList = NULL;
while(1)
{
/* get next device */
if (ACM_PeerDeviceGetNext(pAd, &pAcmDevList, MAC) != ACM_RTN_OK)
break;
/* End of if */
/* copy output TS information */
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, MAC, ACM_PEER_TSPEC_OUTPUT_GET);
if (ppAcmStmList == NULL)
continue;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (ppAcmStmList[IdTidNum] != NULL)
NumStream++;
/* End of if */
} /* End of for */
} /* End of while */
break;
case ACM_SM_CATEGORY_PEER: /* input and output links of a peer */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, pStaMac, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
break;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (ppAcmStmList[IdTidNum] != NULL)
{
if ((IdLinkNum == 1) &&
(ppAcmStmList[IdTidNum]->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK))
{
/* for bidirectional link, only copy once */
continue;
} /* End of if */
NumStream++;
} /* End of if */
} /* End of for */
} /* End of for */
break;
case ACM_SM_CATEGORY_ERR: /* failed list */
pStream = ACMR_CB->TspecListFail.pHead;
while(pStream != NULL)
{
NumStream ++;
pStream = pStream->pNext;
} /* End of while */
break;
} /* End of switch */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return NumStream;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return 0;
} /* End of ACMP_StreamNumGet */
/*
========================================================================
Routine Description:
Delete all activated TSPECs.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
1. Send a DELTS to the QSTA or QAP.
2. Insert the activated TSPEC to the requested list.
3. The TSPEC will be moved to the failed list when DELTS ACK
is received or retry count is reached.
4. Can not used in disassociation.
========================================================================
*/
VOID ACMP_TC_DeleteAll(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ACM_STREAM **ppAcmStmList, *pStream;
ACMR_LIST StreamList;
ACM_PEER_DEV_LIST *pAcmDevList;
UINT32 IdTidNum, IdLinkNum;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UCHAR MAC[ACM_MAC_ADDR_LEN];
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pAcmDevList = NULL;
ACMR_LIST_INIT(&StreamList);
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* clear all requested TSPEC if exists */
ACM_TC_ReqAllFree(pAd);
/* delete all output and input links for all device entries */
while(1)
{
/* get next device entry */
if (ACM_PeerDeviceGetNext(pAd, &pAcmDevList, MAC) != ACM_RTN_OK)
break; /* no other device */
/* End of if */
/* delete all input and output streams */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, MAC, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
break;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
pStream = ppAcmStmList[IdTidNum];
if (pStream != NULL)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
pStream->Cause = ACM_TC_CAUSE_DELETED_BY_QAP;
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
pStream->Cause = ACM_TC_CAUSE_DELETED_BY_QSTA;
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
if (ACM_TC_Delete(pAd, pStream) == TRUE)
{
ACMR_LIST_ALLOC_AND_INSERT_TO_TAIL(pAd, &StreamList, pStream);
} /* End of if */
/* empty the record */
ppAcmStmList[IdTidNum] = NULL;
} /* End of if */
} /* End of for */
} /* End of for */
} /* End of while */
/* free all backup device entries */
ACM_PeerDeviceAllFree(pAd);
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
/* send a DELTS frame for each TSPEC */
while(1)
{
pStream = (ACM_STREAM *)ACMR_LIST_REMOVE_FRM_HEAD(&StreamList);
if (pStream == NULL)
break;
/* End of if */
ACM_DELTS_SEND(pAd, pStream->pCdb, pStream, LabelSemErr);
/* isolate the stream */
pStream->pPrev = NULL;
pStream->pNext = NULL;
/* free it */
ACM_TC_Free(pAd, pStream);
}
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_TC_DeleteAll */
/*
========================================================================
Routine Description:
Delete a TSPEC silently.
Arguments:
pAd - WLAN control block pointer
*pMacPeer - the MAC of peer
TID - the TID of the TSPEC
Return Value:
TRUE - find it and delete it ok
FALSE - do not find it or delete it fail
Note:
For QAP, the pMacPeer means the MAC of a station;
For QSTA, the pMacPeer means the MAC of associated AP;
No DELTS frame is sent.
========================================================================
*/
BOOLEAN ACMP_TC_DeleteOneSilently(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pMacPeer,
ACM_PARAM_IN UCHAR TID)
{
ACM_STREAM *pStream;
ACM_TS_INFO TsInfo;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
TsInfo.TSID = TID;
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, FALSE);
/* find the request */
pStream = ACM_TC_Find(pAd, pMacPeer, &TsInfo);
if (pStream == NULL)
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_msg> can not find the stream (TID=%d)!\n", TID));
goto LabelNotFound;
} /* End of if */
/* delete the stream */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
pStream->Cause = TSPEC_CAUSE_DELETED_BY_QAP;
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
pStream->Cause = TSPEC_CAUSE_DELETED_BY_QSTA;
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
ACM_TC_Destroy(pAd, pStream, 0);
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return TRUE;
LabelNotFound:
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return FALSE;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return FALSE;
} /* End of ACMP_TC_DeleteOneSilently */
/*
========================================================================
Routine Description:
Move it to the fail list.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the QSTA sends the DELTS frame
*pTsInfo - the TS Info
FlgIsFromSta - 1: destroy from QSTA; 0: destroy from QAP
Return Value:
ACM_RTN_OK - destroy ok
ACM_RTN_FAIL - destroy fail
ACM_RTN_SEM_GET_ERR - get semaphore fail
Note:
========================================================================
*/
ACM_FUNC_STATUS ACMP_TC_DestroyBy_TS_Info(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo,
ACM_PARAM_IN UCHAR FlgIsFromSta)
{
ACM_STREAM *pStream;
ACMR_STA_DB *pCdb;
UCHAR StmAcId;
UCHAR Direction;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pCdb = NULL;
StmAcId = 0;
Direction = ACM_DIRECTION_UP_LINK;
/* semaphore protection */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* find the stream */
pStream = ACM_TC_Find(pAd, pDevMac, pTsInfo);
if (pStream == NULL)
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> DEL a stream but can not find it! "
"ACM_TC_DestroyBy_TS_Info()\n"));
goto LabelDestroyOk; /* the stream does NOT exist */
} /* End of if */
/*
Check if the stream is created by the QSTA, only the original QSTA
can delete the stream, other QSTA can NOT delete.
*/
if (!(AMR_IS_SAME_MAC(ACMR_CLIENT_MAC(pStream->pCdb), pDevMac)))
goto LabelErr;
/* End of if */
if (FlgIsFromSta == 1)
pStream->Cause = TSPEC_CAUSE_DELETED_BY_QSTA;
else
pStream->Cause = TSPEC_CAUSE_DELETED_BY_QAP;
/* End of if */
pCdb = pStream->pCdb;
StmAcId = pStream->AcmAcId;
Direction = pStream->pTspec->TsInfo.Direction;
ACM_TC_Destroy(pAd, pStream, 0);
LabelDestroyOk:
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* recover UAPSD state */
#if 0
if (pStream != NULL)
ACM_APSD_Ctrl(pAd, pCdb, StmAcId, Direction, 0, 0);
/* End of if */
#endif /* 0 */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DEL a stream! TC_DestroyBy_TS_Info()\n"));
return ACM_RTN_OK;
LabelErr:
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_FAIL;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_SEM_GET_ERR;
} /* End of ACMP_TC_DestroyBy_TS_Info */
#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
Enable or disable all TSPEC rejection function.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: enable; 0: disable
Return Value:
None
Note:
Only for QAP.
========================================================================
*/
VOID ACMP_TC_RejectCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable)
{
ULONG SplFlags;
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
if (FlgIsEnable)
{
ACM_MR_TSPEC_ALLOW();
}
else
{
/*
We will not accept any new TSPEC request
but we will keep old TSPECs.
*/
ACM_MR_TSPEC_DISALLOW();
} /* End of if */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_TC_RejectCtrl */
#endif /* CONFIG_AP_SUPPORT */
/*
========================================================================
Routine Description:
Enable or disable TSPEC timeout function.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: enable; 0: disable
Return Value:
None
Note:
Only for QAP.
========================================================================
*/
VOID ACMP_TC_TimeoutCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable)
{
ACM_CTRL_PARAM *pEdcaParam;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pEdcaParam->FlgIsTspecTimeoutEnable = FlgIsEnable;
/* active stream check timer for any stream */
ACMR_TIMER_ENABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck,
ACM_STREAM_CHECK_OFFSET);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TSPEC timeout mechanism flag = %d!\n", FlgIsEnable));
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_TC_TimeoutCtrl */
/* =========================== Global Function (STA) ======================== */
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Send a renegotiated TSPEC request to the QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - our STATION entry
*pTspecSrc - the requested TSPEC pointer
TclasNum - the number of TCLASS, max 5
*pTclasSrc - the requested TCLASS array pointer
TclasProcessing - 1: means matching all TCLAS
StreamType - the stream type: WME stream
Return Value:
ACM_RTN_OK - request is accepted
ACM_RTN_FAIL - semaphore lock fail or others
ACM_RTN_NULL_POINTER - null pointer
ACM_RTN_NOT_EXIST - the old TSPEC does not exist
ACM_RTN_INVALID_PARAM - invalid input parameters
ACM_RTN_SEM_GET_ERR - get semaphore fail
ACM_RTN_FATAL_ERR - can not call the func in error mode
ACM_RTN_NO_FREE_TS - no free TS ID or same TSID & Direction
ACM_RTN_ALLOC_ERR - TSPEC request structure allocation fail
Note:
1. Only for non-IBSS QSTA Mode.
2. DLP is not allowed.
========================================================================
*/
ACM_FUNC_STATUS ACMP_TC_Renegotiate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACM_TSPEC *pTspecSrc,
ACM_PARAM_IN UINT32 TclasNum,
ACM_PARAM_IN ACM_TCLAS *pTclasSrc,
ACM_PARAM_IN UCHAR TclasProcessing,
ACM_PARAM_IN UCHAR StreamType)
{
ACM_CTRL_PARAM *pEdcaParam;
ACM_TCLAS *pTclas;
ACM_STREAM *pOldStreamIn, *pOldStreamOut, *pOldStreamDiffAc;
ACM_STREAM *pStreamReq;
ACM_FUNC_STATUS RtnCode, Status;
UCHAR UserPriority;
ULONG SplFlags;
UCHAR *pFrameBuf;
UINT32 FrameLen;
#ifdef ACM_CC_FUNC_TCLAS
UINT32 IdTclasNum;
#endif /* ACM_CC_FUNC_TCLAS */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pTclas = pTclasSrc;
RtnCode = ACM_RTN_SEM_GET_ERR;
UserPriority = ACM_UP_UNKNOWN;
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
/* we can send out a TSPEC to change PS mode only */
/* sanity check if the ACM of all AC is disabled */
if (ACMP_IsAnyACEnabled(pAd) != ACM_RTN_OK)
return ACM_RTN_DISALLOW;
/* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
/* sanity check for input parameters */
/*
In WMM spec., TCLAS can be NULL; if NULL, for WME, use UP or DSCP to
classify MSDUs.
*/
if (pTspecSrc == NULL)
return ACM_RTN_NULL_POINTER;
/* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
/* check whether same TSPEC exists in the active links (EDCA or HCCA) */
UserPriority = ACM_TC_UP_Get(&pTspecSrc->TsInfo, TclasNum, pTclasSrc);
Status = ACM_TC_RenegotiationCheck(pAd,
ACMR_CLIENT_MAC(pCdb),
UserPriority,
&pTspecSrc->TsInfo,
&pOldStreamIn,
&pOldStreamOut,
&pOldStreamDiffAc);
if (Status != ACM_RTN_OK)
{
/* can not find it in active list so can not re-negotiate it */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Old TSPEC does not exist!\n"));
RtnCode = ACM_RTN_NOT_EXIST;
goto LabelErr;
} /* End of if */
#ifdef RELEASE_EXCLUDE
/*
1. TCLASS number can be 0 when the link is uplink or direct link
because QAP dont need TCLASS for these links;
2. TCLASS number can be 0 for EDCA mode and 802.1D/Q frames can be
classified by TSID;
3. TCLASS number can not be 0 for HCCA or HCCA+EDCA mode because
QAP can have max 16 TS queues and frames can not be classified by
TSID.
*/
#endif /* RELEASE_EXCLUDE */
if (pTspecSrc->TsInfo.AccessPolicy != ACM_ACCESS_POLICY_EDCA)
{
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelErr;
} /* End of if */
#ifdef ACM_CC_FUNC_TCLAS
/* maximum TCLASS number is limited */
if (TclasNum > ACM_TCLAS_MAX_NUM)
{
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelErr;
} /* End of if */
/* check user priority and get the user priority */
if ((TclasNum > 0) && (pTclas != NULL))
{
/* all TCLAS shall have the same user priority */
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pTclas != NULL)
{
if (UserPriority == ACM_UP_UNKNOWN)
UserPriority = pTclas->UserPriority;
else
{
if (pTclas->UserPriority != UserPriority)
{
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelErr;
} /* End of if */
} /* End of if */
} /* End of if */
pTclas ++;
} /* End of for */
} /* End of if */
#endif /* ACM_CC_FUNC_TCLAS */
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
/* we can send out a TSPEC to change PS mode only */
/* check if ACM is needed for the AC */
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[ACM_MR_EDCA_AC(UserPriority)] == 0)
{
RtnCode = ACM_RTN_DISALLOW;
goto LabelErr;
} /* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
/* allocate a TSPEC request structure */
ACMR_MEM_ALLOC(pStreamReq, sizeof(ACM_STREAM), (ACM_STREAM *));
if (pStreamReq == NULL)
{
RtnCode = ACM_RTN_ALLOC_ERR;
goto LabelErr;
} /* End of if */
/* init the TSPEC request structure: TSPEC, TCLAS, etc. */
ACMR_MEM_ZERO(pStreamReq, sizeof(ACM_STREAM));
ACMR_MEM_ALLOC(pStreamReq->pTspec, sizeof(ACM_TSPEC), (ACM_TSPEC *));
if (pStreamReq->pTspec == NULL)
{
ACMR_MEM_FREE(pStreamReq);
RtnCode = ACM_RTN_ALLOC_ERR;
goto LabelErr;
} /* End of if */
ACM_TSPEC_COPY(pStreamReq->pTspec, pTspecSrc);
pTclas = pTclasSrc;
#ifdef ACM_CC_FUNC_TCLAS
if (pTclas != NULL)
{
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pTclas == NULL)
break;
/* End of if */
if (pStreamReq->pTclas[IdTclasNum] != NULL)
ACMR_MEM_FREE(pStreamReq->pTclas[IdTclasNum]);
/* End of if */
pStreamReq->pTclas[IdTclasNum] = \
(ACM_TCLAS *)ACMR_MEM_ALLOC(sizeof(ACM_TCLAS));
if (pStreamReq->pTclas[IdTclasNum] == NULL)
{
TclasNum = IdTclasNum+1;
goto LabelErrAlloc;
} /* End of if */
ACM_TCLAS_COPY(pStreamReq->pTclas[IdTclasNum], pTclas);
pTclas ++;
} /* End of for */
} /* End of if */
#endif /* ACM_CC_FUNC_TCLAS */
pStreamReq->StreamType = StreamType;
pStreamReq->Status = TSPEC_STATUS_RENEGOTIATING;
/* we can not send DELTS if no response; we need to keep old TSPEC */
pStreamReq->TimeoutAction = ACM_TC_TIMEOUT_ACTION_DELTS;
pStreamReq->TclasProcessing = TclasProcessing;
pStreamReq->Retry = 0; /* no retry if request timeout */
ACM_STREAM_CDB_COPY(pStreamReq, pCdb);
pStreamReq->UP = UserPriority;
/* timeout unit: 100ms */
pStreamReq->Timeout = ACM_ADDTS_REQUEST_TIMEOUT;
pStreamReq->Timeout = pStreamReq->Timeout * 1000 / ACM_TIMEOUT_CHECK_BASE;
TSPEC_DIALOG_TOKEN_GET(pAd, pStreamReq->DialogToken);
/* PHY_TSID will be determined after ADDTS response is received */
pStreamReq->AcmAcId = ACM_MR_EDCA_AC(pStreamReq->UP);
/* check if need to recover UAPSD field of TS Info */
if (!pEdcaParam->FlgIsTspecUpasdEnable)
{
/*
Does not support the modification of the Power Save settings via
TSPEC.
*/
pStreamReq->pTspec->TsInfo.APSD = \
pAd->CommonCfg.bACMAPSDBackup[pStreamReq->AcmAcId];
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Recover APSD to %d! WME_TC_Request()\n",
pStreamReq->pTspec->TsInfo.APSD));
} /* End of if */
/* timeout unit: 100ms */
pStreamReq->TimeoutAddts = pStreamReq->Timeout;
pStreamReq->TimeoutDelts = ACM_DELTS_TIMEOUT / ACM_TIMEOUT_CHECK_BASE;
pStreamReq->ReNegotiation = 1; /* this is a renegotiation TSPEC */
/* check inactivity timeout */
if (pStreamReq->pTspec->InactivityInt == 0)
pStreamReq->pTspec->InactivityInt = ACM_WME_TSPEC_INACTIVITY_DEFAULT;
/* End of if */
/* insert the new requested TSPEC to the request list */
ACM_TC_ReqInsert(pAd, pStreamReq);
/* add the check timer */
ACMR_TIMER_ENABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck,
ACM_STREAM_CHECK_OFFSET);
/* make up ADDTS Request frame */
ACM_ADDREQ_MAKEUP(pAd, pCdb, pFrameBuf, FrameLen, pStreamReq, LabelSemErr);
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* set PS mode to ACTIVE mode to wait for ADDTS response frame */
ACM_PS_ActiveOn(pAd);
/* send ADDTS Request frame */
ACM_ADDREQ_SEND(pAd, pFrameBuf, FrameLen);
return ACM_RTN_OK;
LabelErr:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> Negotiate Fail! TC_Renegotiate()\n"));
return RtnCode;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return RtnCode;
#ifdef ACM_CC_FUNC_TCLAS
LabelErrAlloc:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* free TCLAS memory */
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pStreamReq->pTclas[IdTclasNum] != NULL)
ACMR_MEM_FREE(pStreamReq->pTclas[IdTclasNum]);
/* End of if */
} /* End of for */
return ACM_RTN_ALLOC_ERR;
#endif /* ACM_CC_FUNC_TCLAS */
} /* End of ACMP_TC_Renegotiate */
/*
========================================================================
Routine Description:
Adjust retry count limit automatically.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
Only for QSTA.
Retry count enable:
(1) Power Save mode;
(2) No TSPEC;
========================================================================
*/
VOID ACMP_RetryCountCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_STA_SUPPORT
ULONG SplFlags;
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACM_ASIC_RetryCountCtrl(pAd);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#endif /* CONFIG_STA_SUPPORT */
} /* End of ACMP_RetryCountCtrl */
/*
========================================================================
Routine Description:
Enable or disable TSPEC UAPSD function.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: enable; 0: disable
Return Value:
None
Note:
Only for QSTA.
If TSPEC UAPSD function is disabled, the UAPSD field of TSPEC will
be same as the value in station association request frame.
========================================================================
*/
VOID ACMP_TC_UapsdCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable)
{
ULONG SplFlags;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACM_PS_UapsdCtrl(pAd, FlgIsEnable);
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACMP_TC_UapsdCtrl */
#endif /* CONFIG_STA_SUPPORT */
/*
========================================================================
Routine Description:
Timer APIs are provided for WLAN module use.
Arguments:
ACM_TIMER_API_PARAM
Return Value:
None
Note:
========================================================================
*/
VOID ACMP_TR_TC_ReqCheck(ACM_TIMER_API_PARAM)
{
ACM_TR_TC_ReqCheck(ACM_TIMER_API_DATA);
}
VOID ACMP_TR_STM_Check(ACM_TIMER_API_PARAM)
{
ACM_TR_STM_Check(ACM_TIMER_API_DATA);
}
VOID ACMP_TR_TC_General(ACM_TIMER_API_PARAM)
{
ACM_TR_TC_General(ACM_TIMER_API_DATA);
}
VOID ACMP_CMD_Timer_Data_Simulation(ACM_TIMER_API_PARAM)
{
ACM_CMD_Timer_Data_Simulation(ACM_TIMER_API_DATA);
}
#ifdef CONFIG_STA_SUPPORT_SIM
/*
========================================================================
Routine Description:
Send a TSPEC request to the QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - our STATION entry
*pTspecSrc - the requested TSPEC pointer
TclasNum - the number of TCLASS, max 5
*pTclasSrc - the requested TCLASS array pointer
TclasProcessing - 1: must match all TCLAS
StreamType - the stream type: WME stream
Return Value:
ACM_RTN_OK - request is accepted
ACM_RTN_FAIL - semaphore lock fail or others
ACM_RTN_NULL_POINTER - null pointer
ACM_RTN_INVALID_PARAM - invalid input parameters
ACM_RTN_SEM_GET_ERR - get semaphore fail
ACM_RTN_FATAL_ERR - can not call the func in error mode
ACM_RTN_NO_FREE_TS - no free TS ID or same TSID & Direction
ACM_RTN_ALLOC_ERR - TSPEC request structure allocation fail
ACM_RTN_DISALLOW - the request is not allowed
Note:
1. Only for non-IBSS Station Mode.
2. pTclasSrc is limited by ACM_TSPEC_TCLAS_MAX_NUM.
3. DLP TSPEC is not allowed but DLP is allowed.
4. *pTspecSrc & *pTclasSrc[] can not be freed in calling function.
5. For WMM STA, the used TSPEC is the same.
ACM_TG_CMT_SPEC_UNCLEAR_ON_RESERVED_FIELD
========================================================================
*/
ACM_FUNC_STATUS ACMP_WME_TC_Request(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACM_TSPEC *pTspecSrc,
ACM_PARAM_IN UINT32 TclasNum,
ACM_PARAM_IN ACM_TCLAS *pTclasSrc,
ACM_PARAM_IN UCHAR TclasProcessing,
ACM_PARAM_IN UCHAR StreamType,
ACM_PARAM_IN UINT16 DialogToken)
{
ACM_CTRL_PARAM *pEdcaParam;
ACM_TCLAS *pTclas;
ACM_STREAM *pOldStreamIn, *pOldStreamOut, *pOldStreamDiffAc;
ACM_STREAM *pStreamReq;
ACM_FUNC_STATUS RtnCode, Status;
UCHAR UserPriority;
ULONG SplFlags;
UCHAR *pFrameBuf;
UINT32 FrameLen;
#ifdef ACM_CC_FUNC_TCLAS
UINT32 IdTclasNum;
#endif /* ACM_CC_FUNC_TCLAS */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pTclas = pTclasSrc;
RtnCode = ACM_RTN_OK;
UserPriority = ACM_UP_UNKNOWN;
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
if (!ACM_MR_TSPEC_IS_ALLOWED(pAd))
{
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> ACM is not allowed!\n"));
return ACM_RTN_DISALLOW;
} /* End of if */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* check if QSTA is in ASSOCIATION state */
if (!ACMR_IS_PORT_SECURE(pAd))
{
/* QSTA yet associate to the QAP */
/* QSTA can send ADDTS request only when it associates to a AP */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> Station does not yet associate to any AP!\n"));
return ACM_RTN_FAIL;
} /* End of if */
#ifdef RELEASE_EXCLUDE
/*
"2.2.11 WMM TSPEC Element", WMM_Specification_1-1a-wmmac-070601.doc
A STA may need to transmit a WMM TSPEC request for an AC that does
not mandate admission control, e.g for the establishment of the
triggered power save mode of operation.
*/
#endif /* RELEASE_EXCLUDE */
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
/* we can send out a TSPEC to change PS mode only */
/* check if the ACM of all AC is disabled */
if (ACMP_IsAnyACEnabled(pAd) != ACM_RTN_OK)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> ACM is disabled!\n"));
return ACM_RTN_DISALLOW;
} /* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
/* sanity check for input parameters of WME STA */
if (pTspecSrc == NULL)
return ACM_RTN_NULL_POINTER;
/* End of if */
/* sanity check for tx rate */
if ((pTspecSrc->MinPhyRate > 0) &&
(pTspecSrc->MeanDataRate > 0) &&
(pTspecSrc->MinPhyRate <= pTspecSrc->MeanDataRate))
{
/* minimum PHY rate must > mean data rate */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> Minimum Phy Rate > Mean Data Rate!\n"));
return ACM_RTN_INVALID_PARAM;
} /* End of if */
if (((pTspecSrc->MinDataRate != 0) &&
(pTspecSrc->MeanDataRate != 0) &&
(pTspecSrc->MinDataRate > pTspecSrc->MeanDataRate)) ||
((pTspecSrc->PeakDataRate != 0) &&
(pTspecSrc->MeanDataRate != 0) &&
(pTspecSrc->MeanDataRate > pTspecSrc->PeakDataRate)))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> Min/Mean Data Rate > Mean/Peak Data Rate!\n"));
return ACM_RTN_INVALID_PARAM;
} /* End of if */
#if 0 /* TODO */
/* check min phy rate it can not be larger than maximum supported rate */
ACMR_SUP_RATE_MAX_GET(pAd, pCdb, MaxRate);
if (pTspecSrc->MinPhyRate > MaxRate)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> min phy rate %dbps > "
"maximum supported rate %dbps!\n",
pTspecSrc->MinPhyRate, MaxRate));
return ACM_RTN_INVALID_PARAM;
} /* End of if */
#endif
#ifdef ACM_CC_FUNC_TCLAS
#ifdef RELEASE_EXCLUDE
/*
1. TCLASS number can be 0 when the link is uplink or direct link
because QAP dont need TCLASS for these links;
2. TCLASS number can be 0 for EDCA mode and 802.1D/Q frames can be
classified by TSID;
3. TCLASS number can not be 0 for HCCA or HCCA+EDCA mode because
QAP can have max 16 TS queues and frames can not be classified by
TSID.
*/
#endif /* RELEASE_EXCLUDE */
/* maximum TCLASS number is limited */
if (TclasNum > ACM_TSPEC_TCLAS_MAX_NUM)
return ACM_RTN_INVALID_PARAM;
/* End of if */
/* check user priority and get the user priority */
if ((TclasNum > 0) && (pTclas != NULL))
{
/* all TCLASS shall have the same user priority */
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pTclas != NULL)
{
if (UserPriority == ACM_UP_UNKNOWN)
UserPriority = pTclas->UserPriority;
else
{
if (pTclas->UserPriority != UserPriority)
return ACM_RTN_INVALID_PARAM;
/* End of if */
} /* End of if */
} /* End of if */
/* check next TCLAS */
pTclas ++;
} /* End of for */
}
else
#endif /* ACM_CC_FUNC_TCLAS */
{
/* no any TCLAS exists so use the UP of the TS Info */
UserPriority = pTspecSrc->TsInfo.UP;
} /* End of if */
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
/* we can send out a TSPEC to change PS mode only */
/* check if ACM is needed for the AC */
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[ACM_MR_EDCA_AC(UserPriority)] == 0)
{
RtnCode = ACM_RTN_DISALLOW;
goto LabelErr;
} /* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
/* check the TSID & Direction */
Status = ACM_TC_RenegotiationCheck(pAd,
ACMR_CLIENT_MAC(pCdb),
UserPriority,
&pTspecSrc->TsInfo,
&pOldStreamIn,
&pOldStreamOut,
&pOldStreamDiffAc);
if (Status == ACM_RTN_OK)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Already exist same TS! WME_TC_Request()\n"));
RtnCode = ACM_RTN_EXIST;
goto LabelErr;
} /* End of if */
/* allocate a TSPEC request structure */
ACMR_MEM_ALLOC(pStreamReq, sizeof(ACM_STREAM), (ACM_STREAM *));
if (pStreamReq == NULL)
{
RtnCode = ACM_RTN_ALLOC_ERR;
goto LabelErr;
} /* End of if */
/* init the TSPEC request structure */
ACMR_MEM_ZERO(pStreamReq, sizeof(ACM_STREAM));
ACMR_MEM_ALLOC(pStreamReq->pTspec, sizeof(ACM_TSPEC), (ACM_TSPEC *));
if (pStreamReq->pTspec == NULL)
{
ACMR_MEM_FREE(pStreamReq);
RtnCode = ACM_RTN_ALLOC_ERR;
goto LabelErr;
} /* End of if */
*pStreamReq->pTspec = *pTspecSrc;
pTclas = pTclasSrc;
#ifdef ACM_CC_FUNC_TCLAS
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
ACMR_MEM_ALLOC(pStreamReq->pTclas[IdTclasNum],
sizeof(ACM_TCLAS), (ACM_TCLAS *));
if (pStreamReq->pTclas[IdTclasNum] == NULL)
{
RtnCode = ACM_RTN_ALLOC_ERR;
TclasNum = IdTclasNum+1;
goto LabelErrAlloc;
} /* End of if */
*pStreamReq->pTclas[IdTclasNum] = *pTclas;
pTclas ++; /* move to next TCLAS */
} /* End of for */
#endif /* ACM_CC_FUNC_TCLAS */
pStreamReq->StreamType = StreamType;
pStreamReq->Status = TSPEC_STATUS_REQUEST;
pStreamReq->TimeoutAction = ACM_TC_TIMEOUT_ACTION_ADDTS_REQ;
pStreamReq->TclasProcessing = TclasProcessing;
pStreamReq->Retry = 0; /* no retry */
ACM_STREAM_CDB_COPY(pStreamReq, pCdb);
pStreamReq->UP = UserPriority;
/* timeout unit: 100ms */
pStreamReq->Timeout = ACM_ADDTS_REQUEST_TIMEOUT;
pStreamReq->Timeout = pStreamReq->Timeout * 1000 / ACM_TIMEOUT_CHECK_BASE;
if (DialogToken > 0)
pStreamReq->DialogToken = DialogToken; /* debug use */
else
{
TSPEC_DIALOG_TOKEN_GET(pAd, pStreamReq->DialogToken);
} /* End of if */
pStreamReq->AcmAcId = ACM_MR_EDCA_AC(pStreamReq->UP);
/* check if need to recover UAPSD field of TS Info */
if (!pEdcaParam->FlgIsTspecUpasdEnable)
{
/*
Does not support the modification of the Power Save settings via
TSPEC.
*/
pStreamReq->pTspec->TsInfo.APSD = \
pAd->CommonCfg.bACMAPSDBackup[pStreamReq->AcmAcId];
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Recover APSD to %d! WME_TC_Request()\n",
pStreamReq->pTspec->TsInfo.APSD));
} /* End of if */
/* timeout unit: 100ms */
pStreamReq->TimeoutAddts = pStreamReq->Timeout;
pStreamReq->TimeoutDelts = ACM_DELTS_TIMEOUT/ACM_TIMEOUT_CHECK_BASE;
/* insert the new requested TSPEC to the request list */
ACM_TC_ReqInsert(pAd, pStreamReq);
/* check whether the check timer is enabled */
ACMR_TIMER_ENABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck,
ACM_STREAM_CHECK_OFFSET);
/* make up ADDTS Request frame */
ACM_ADDREQ_MAKEUP(pAd, pCdb, pFrameBuf, FrameLen, pStreamReq, LabelSemErr);
/* check inactivity timeout */
if (pStreamReq->pTspec->InactivityInt == 0)
{
/*
We can request a TSPEC with inactivity timeout = 0;
but infinite inactivity timeout is not good I think,
so give a default timeout for the TSPEC.
After ACM_ADDREQ_MAKEUP()
*/
pStreamReq->pTspec->InactivityInt = ACM_WME_TSPEC_INACTIVITY_DEFAULT;
} /* End of if */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A request is created successfully! "
"ACMP_WME_TC_Request()\n"));
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* set PS mode to ACTIVE mode to wait for ADDTS response frame */
ACM_PS_ActiveOn(pAd);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
/* send a ADDTS Request frame */
ACM_ADDREQ_SEND(pAd, pFrameBuf, FrameLen);
return RtnCode;
LabelErr:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return RtnCode;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_SEM_GET_ERR;
#ifdef ACM_CC_FUNC_TCLAS
LabelErrAlloc:
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_MEM_FREE(pStreamReq->pTspec);
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
ACMR_MEM_FREE(pStreamReq->pTclas[IdTclasNum]);
/* End of for */
ACMR_MEM_FREE(pStreamReq);
return RtnCode;
#endif /* ACM_CC_FUNC_TCLAS */
} /* End of ACMP_WME_TC_Request */
#endif /* CONFIG_STA_SUPPORT_SIM */
/* =========================== ASIC Function =========================== */
/*
========================================================================
Routine Description:
Reset the medium time for the AC.
Arguments:
pAd - WLAN control block pointer
AcId - the AC ID (0 ~ 3)
MediumTime - the new medium time (unit: micro seconds)
Return Value:
None
Note:
1. If acm_time == 0, means the ACM for the AC will be disabled.
2. special mode, when AcId == 0x1234, the settings will be
applied for all ACs.
========================================================================
*/
STATIC VOID ACM_ASIC_ACM_Reset(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 AcId,
ACM_PARAM_IN UINT32 MediumTime)
{
/* currently no ASIC setting to be set */
} /* End of ACM_ASIC_ACM_Reset */
/*
========================================================================
Routine Description:
Enable ASIC channel busy time calculation.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: ENABLE; 0:DISABLE
Return Value:
None
Note:
1. If acm_time == 0, means the ACM for the AC will be disabled.
2. special mode, when AcId == 0x1234, the settings will be
applied for all ACs.
========================================================================
*/
STATIC VOID ACM_ASIC_ChanBusyEnable(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable)
{
if (FlgIsEnable)
{
ACMR_CHAN_BUSY_DETECT_ENABLE(pAd);
}
else
{
ACMR_CHAN_BUSY_DETECT_DISABLE(pAd);
} /* End of if */
} /* End of ACM_ASIC_ChanBusyEnable */
/*
========================================================================
Routine Description:
Get the channel busy time in last TBTT.
Arguments:
pAd - WLAN control block pointer
Return Value:
the channel busy time, unit: miscroseconds
Note:
========================================================================
*/
STATIC UINT32 ACM_ASIC_ChanBusyGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
UINT32 TimeBusy;
TimeBusy = 0;
ACMR_CHAN_BUSY_GET(pAd, &TimeBusy);
return TimeBusy;
} /* End of ACM_ASIC_ChanBusyGet */
/*
========================================================================
Routine Description:
Reset the WLAN QOS ASIC EDCA setting.
Arguments:
pAd - WLAN control block pointer
FlgIsDeltsAll - 1: delete all TSPECs; 0: reserve all TSPECs
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_ASIC_EDCA_Reset(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsDeltsAll)
{
/* no ASIC settings are needed to be set */
/* delete all activated TSPEC */
if (FlgIsDeltsAll == 1)
ACMP_TC_DeleteAll(pAd);
/* End of if */
} /* End of ACM_ASIC_EDCA_Reset */
/*
========================================================================
Routine Description:
Translate TUs into microseconds.
Arguments:
pAd - WLAN control block pointer
TU - the time unit
Return Value:
microseconds
Note:
========================================================================
*/
STATIC UINT32 ACM_ASIC_TU_Translate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 TU)
{
UINT32 Unit;
/* get a TU */
Unit = 1024; /* 1024 micro second (us) */
/* calculate TUs */
TU *= Unit;
return TU;
} /* End of ACM_ASIC_TU_Translate */
/*
========================================================================
Routine Description:
Adjust retry count limit automatically.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
Only for QSTA.
Retry count enable:
(1) Power Save mode;
(2) No TSPEC;
========================================================================
*/
VOID ACM_ASIC_RetryCountCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_STA_SUPPORT
UINT32 RetryCountOldSettings;
BOOLEAN FlgIsEnabled;
/* init */
FlgIsEnabled = FALSE;
RetryCountOldSettings = 0xFFFFFFFF;
ACMR_RETRY_GET(pAd, RetryCountOldSettings);
if ((ACMR_CB->EdcaCtrlParam.LinkNumUp > 0) ||
(ACMR_CB->EdcaCtrlParam.LinkNumDn > 0) ||
(ACMR_CB->EdcaCtrlParam.LinkNumBi > 0) ||
(ACMR_CB->EdcaCtrlParam.LinkNumDi > 0))
{
if (ACMR_IS_IN_ACTIVE_MODE(pAd))
{
if (RetryCountOldSettings != 0xFFFFFFFF)
ACMR_CB->RetryCountOldSettings = RetryCountOldSettings;
/* End of if */
}
else
FlgIsEnabled = TRUE;
/* End of if */
}
else
FlgIsEnabled = TRUE;
/* End of if */
if (FlgIsEnabled == TRUE)
{
ACMR_RETRY_ENABLE(pAd, RetryCountOldSettings);
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Enable retry!\n"));
}
else
{
ACMR_RETRY_DISABLE(pAd);
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Disable retry %x!\n",
RetryCountOldSettings));
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
} /* End of ACMP_RetryCountCtrl */
/* =========================== OTHER Function =========================== */
/*
========================================================================
Routine Description:
Handle UAPSD enable or disable.
Arguments:
pAd - WLAN control block pointer
*pCdb - the client database
StmAcId - the AC ID (0 ~ 3)
FlgTsAdd - 1: add a TS; 0: delete a TS
FlgIsApsdEnable - 1: enable APSD in TSPEC
Return Value:
None
Note:
WMM-PS is optional for WMM-AC certification.
RTMP_IRQ_LOCK will be used in the function so you can not put the function
in any bottom half lock section.
When FlgTsAdd == 0, FlgIsApsdEnable is not used.
An uplink TSPEC plus a downlink TSPEC, or a bi-directional TSPEC with the
APSD subfield set to 1 and the Schedule subfield set to 0, makes an AC both
trigger- and delivery-enabled.
An uplink TSPEC plus a downlink TSPEC, or a bi-directional TSPEC with the
APSD and the Schedule subfields both set to 0, makes an AC neither
trigger- nor delivery-enabled.
ACM_TG_CMT_UAPSD_CHANGED_BY_TSPEC
========================================================================
*/
STATIC VOID ACM_APSD_Ctrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR AcId,
ACM_PARAM_IN UCHAR Direction,
ACM_PARAM_IN UCHAR FlgTsAdd,
ACM_PARAM_IN UCHAR FlgIsApsdEnable)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
#ifdef UAPSD_SUPPORT
#if 0
QUEUE_HEADER *pPsQueAc;
PNDIS_PACKET *pPktQued;
ULONG SplFlags;
#endif /* 0 */
UCHAR FlgIsTrEnabled, FlgIsDeEnabled;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init new UAPSD state */
FlgIsTrEnabled = pCdb->bAPSDCapablePerAC[AcId];
FlgIsDeEnabled = pCdb->bAPSDDeliverEnabledPerAC[AcId];
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ac%d, old ADD=%d, APSD=%d, TR=%d, DE=%d\n",
AcId, FlgTsAdd, FlgIsApsdEnable, FlgIsTrEnabled,
FlgIsDeEnabled));
if (FlgTsAdd)
{
/* for addition use */
/* new TSPEC replaces current one or both */
if (Direction == ACM_DIRECTION_UP_LINK)
FlgIsTrEnabled = FlgIsApsdEnable;
else if (Direction == ACM_DIRECTION_DOWN_LINK)
FlgIsDeEnabled = FlgIsApsdEnable;
else
{
FlgIsTrEnabled = FlgIsApsdEnable;
FlgIsDeEnabled = FlgIsApsdEnable;
} /* End of if */
}
else
{
/* for deletion use */
/* deleted TSPEC recovers current one or both */
if (Direction == ACM_DIRECTION_UP_LINK)
FlgIsTrEnabled = pCdb->bACMAPSDBackup[AcId];
else if (Direction == ACM_DIRECTION_DOWN_LINK)
FlgIsDeEnabled = pCdb->bACMAPSDBackupDeliverEnabled[AcId];
else
{
FlgIsTrEnabled = pCdb->bACMAPSDBackup[AcId];
FlgIsDeEnabled = pCdb->bACMAPSDBackupDeliverEnabled[AcId];
} /* End of if */
} /* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ac%d, new ADD=%d, APSD=%d, TR=%d, DE=%d\n",
AcId, FlgTsAdd, FlgIsApsdEnable, FlgIsTrEnabled,
FlgIsDeEnabled));
/* check whether new UAPSD state is same as old UAPSD state */
if ((FlgIsTrEnabled == pCdb->bAPSDCapablePerAC[AcId]) &&
(FlgIsDeEnabled == pCdb->bAPSDDeliverEnabledPerAC[AcId]))
{
/* new UAPSD state is same as current UAPSD state */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> No change for PS mode!\n"));
return;
} /* End of if */
if (FlgIsTrEnabled)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AC%d is trigger-enabled AC!\n", AcId));
} /* End of if */
if (FlgIsDeEnabled)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AC%d is delivery-enabled AC!\n", AcId));
} /* End of if */
if (!FlgIsTrEnabled && !FlgIsDeEnabled)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AC%d is legacy-PS AC!\n", AcId));
} /* End of if */
#if 0 /* let all transient packets wait for timeout, let it simpler */
/* move UAPSD packets to legacy PS queue */
if (!FlgIsDeEnabled &&
pCdb->bAPSDDeliverEnabledPerAC[AcId] &&
pCdb->UAPSDQueue[AcId].Head)
{
RTMP_IRQ_LOCK(&pAd->irq_lock, SplFlags);
pPsQueAc = &pCdb->UAPSDQueue[AcId];
while(pPsQueAc->Head)
{
pPktQued = (PNDIS_PACKET)RemoveHeadQueue(pPsQueAc);
InsertTailQueue(&pCdb->PsQueue,
PACKET_TO_QUEUE_ENTRY(pPktQued));
} /* End of while */
RTMP_IRQ_UNLOCK(&pAd->irq_lock, SplFlags);
} /* End of if */
/* move legacy PS queue to UAPSD packets */
if (FlgIsDeEnabled &&
!pCdb->bAPSDDeliverEnabledPerAC[AcId] &&
pCdb->PsQueue.Head)
{
RTMP_IRQ_LOCK(&pAd->irq_lock, SplFlags);
pPsQueAc = &pCdb->PsQueue;
while(pPsQueAc->Head)
{
pPktQued = (PNDIS_PACKET)RemoveHeadQueue(pPsQueAc);
InsertTailQueue(&pCdb->UAPSDQueue[AcId],
PACKET_TO_QUEUE_ENTRY(pPktQued));
} /* End of while */
RTMP_IRQ_UNLOCK(&pAd->irq_lock, SplFlags);
} /* End of if */
#endif /* 0 */
/* update UAPSD state */
pCdb->bAPSDCapablePerAC[AcId] = FlgIsTrEnabled;
pCdb->bAPSDDeliverEnabledPerAC[AcId] = FlgIsDeEnabled;
/* update UAPSD control block information */
if ((pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BE] == 0) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BK] == 0) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VI] == 0) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VO] == 0))
{
CLIENT_STATUS_CLEAR_FLAG(pCdb, fCLIENT_STATUS_APSD_CAPABLE);
}
else
{
CLIENT_STATUS_SET_FLAG(pCdb, fCLIENT_STATUS_APSD_CAPABLE);
} /* End of if */
if ((pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BE] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_BK] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VI] == 1) &&
(pCdb->bAPSDDeliverEnabledPerAC[QID_AC_VO] == 1))
{
/* all AC are U-APSD delivery-enabled */
pCdb->bAPSDAllAC = 1;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> all AC are UAPSD!\n"));
}
else
{
/* at least one AC is not U-APSD delivery-enabled */
pCdb->bAPSDAllAC = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> not all AC are UAPSD!\n"));
} /* End of if */
#endif /* UAPSD_SUPPORT */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
BOOLEAN *pApsdCur;
WMM_ACM_FUNC_NAME_PRINT("IN");
#ifdef RELEASE_EXCLUDE
/*
In IEEE802.11e spec., section 11.2.1.5 (c),
When all ACs are delivery-enabled, the APSD-capable QAP shall
assemble the partial virtual bitmap containing the buffer status
for all ACs per destination for non-AP QSTAs.
So we only care about delivery-enabled AC and we only record for
trigger-enabled AC.
*/
#endif /* RELEASE_EXCLUDE */
if (Direction != ACM_DIRECTION_DOWN_LINK)
{
if (!FlgTsAdd)
FlgIsApsdEnable = pAd->CommonCfg.bACMAPSDBackup[AcId];
/* End of if */
pAd->CommonCfg.bACMAPSDTr[AcId] = FlgIsApsdEnable;
} /* End of if */
if (Direction == ACM_DIRECTION_UP_LINK)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Not care uplink APSD (TR=%d)!\n",
FlgIsApsdEnable));
return;
} /* End of if */
if (FlgTsAdd)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> UAPSD mode change to AcId = %d, dir = %d, "
"TSPEC add, apsd = %d\n",
AcId, Direction, FlgIsApsdEnable));
}
else
{
/* recover to old APSD state */
FlgIsApsdEnable = pAd->CommonCfg.bACMAPSDBackup[AcId];
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> UAPSD mode recover to AcId = %d, dir = %d, "
"TSPEC del, apsd = %d\n",
AcId, Direction, FlgIsApsdEnable));
} /* End of if */
switch(AcId)
{
case ACM_EDCA_VO_AC_QUE_ID:
pApsdCur = &pAd->CommonCfg.bAPSDAC_VO;
break;
case ACM_EDCA_VI_AC_QUE_ID:
pApsdCur = &pAd->CommonCfg.bAPSDAC_VI;
break;
case ACM_EDCA_BK_AC_QUE_ID:
pApsdCur = &pAd->CommonCfg.bAPSDAC_BK;
break;
default:
pApsdCur = &pAd->CommonCfg.bAPSDAC_BE;
break;
} /* End of switch */
if (((FlgIsApsdEnable && (*pApsdCur))) ||
((!FlgIsApsdEnable && !(*pApsdCur))))
{
/* nothing to do */
return;
} /* End of if */
if (FlgIsApsdEnable)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AC%d is delivery-enabled AC!\n", AcId));
}
else
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AC%d is not delivery-enabled AC!\n", AcId));
} /* End of if */
*pApsdCur = FlgIsApsdEnable;
#if 0
/*
2009/07/23
We can not reset bAPSDCapable to 0.
The flag is a static flag from RT28xxSTA.dat
We can not modify it in any time.
Or after AP disassociates us, MaxSPLength is always 0 in next
association request frame due to pAd->CommonCfg.bAPSDCapable = 0 of
MlmeAssocReqAction().
*/
if ((pAd->CommonCfg.bAPSDAC_VO == FALSE) &&
(pAd->CommonCfg.bAPSDAC_VI == FALSE) &&
(pAd->CommonCfg.bAPSDAC_BE == FALSE) &&
(pAd->CommonCfg.bAPSDAC_BK == FALSE))
{
pAd->CommonCfg.bAPSDCapable = FALSE;
}
else
pAd->CommonCfg.bAPSDCapable = TRUE;
/* End of if */
#endif
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
} /* End of ACM_APSD_Ctrl */
/*
========================================================================
Routine Description:
Check whether bandwidth is enough to allow new stream.
Arguments:
pAd - WLAN control block pointer
StmAcId - the AC
SI - the service interval
Policy - ACM_ACCESS_POLICY_EDCA
Direction - ACM_DIRECTION_UP_LINK,
ACM_DIRECTION_DOWN_LINK,
ACM_DIRECTION_DIRECT_LINK,
ACM_DIRECTION_BIDIREC_LINK
AcmTimeOld - old used time of the same stream, unit: microsecond
AcmTimeNew - the requested time of new stream, unit: microsecond
AcmTimeOldBi - old used time for bidirectional, unit: microsecond
*pTimeOffset - the insufficient time when check result is fail
*pVbAc - the borrowed AC ID, 0 ~ 3
*pVbBw - the borrowed bandwidth from a AC, unit: microsecond
Return Value:
ACM_RTN_OK - allow
ACM_RTN_FAIL - doesnt allow due to total ACM time < Tcp,
i.e. no any AC stream can be deleted to
increase bandwidth
ACM_RTN_INSUFFICIENT_BD_BUT_DEL_AC - doesnt allow but we maybe delete AC
streams to increase bandwidth
Note:
pTimeOffset can be NULL;
if pTimeOffset == NULL, no any output value will be set.
Only used for QAP.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_BandwidthCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 StmAcId,
ACM_PARAM_IN UINT32 SI,
ACM_PARAM_IN UINT32 Policy,
ACM_PARAM_IN UINT32 Direction,
ACM_PARAM_IN UINT32 AcmTimeOld,
ACM_PARAM_IN UINT32 AcmTimeNew,
ACM_PARAM_IN UINT32 AcmTimeOldBi,
ACM_PARAM_OUT UINT32 *pTimeOffset,
ACM_PARAM_OUT UINT32 *pVbAc,
ACM_PARAM_OUT UINT32 *pVbBw)
{
UINT32 TimeResidual;
UINT32 TimeAc10;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
#ifdef RELEASE_EXCLUDE
*pVbAc = ACM_DATL_NO_BORROW;
#else
*pVbAc = 0xFF;
#endif /* RELEASE_EXCLUDE */
*pVbBw = 0;
/* check AcmTimeNew */
if (AcmTimeNew > ACM_TIME_BASE)
goto LabelErr; /* > time base */
/* End of if */
/* check whether Direction is bidirectional link */
if (Direction == ACM_DIRECTION_BIDIREC_LINK)
{
/*
double medium time for bidirectional because bidirectional
link = uplink + dnlink
Only for new time because
AcmTimeOld = pOldStreamIn+pOldStreamOut+pOldStreamDiffAc
But when old stream is bidirectional TSPEC for the same AC,
we need to double the old time.
*/
AcmTimeNew = AcmTimeNew << 1;
AcmTimeOld += AcmTimeOldBi;
} /* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Old time = %d, new time = %d\n", AcmTimeOld, AcmTimeNew));
/* check whether new requested time <= old requested time */
if (AcmTimeNew <= AcmTimeOld)
return ACM_RTN_OK; /* bandwidth is enough */
/* End of if */
/* calculate reserved AC1/0 (best effort and background) time every sec */
if ((StmAcId == ACM_EDCA_VI_AC_QUE_ID) ||
(StmAcId == ACM_EDCA_VO_AC_QUE_ID))
{
/* only VI or VO ACM need to care about BE/BK reserved bandwidth */
TimeAc10 = ACM_BANDWIDTH_CHECK_BASE * ACMR_CB->EdcaCtrlParam.BEK_MinNu;
TimeAc10 /= ACMR_CB->EdcaCtrlParam.BEK_MinDe;
}
else
TimeAc10 = 0;
/* End of if */
/* examine residual bandwidth */
if (Policy == ACM_ACCESS_POLICY_EDCA)
{
/* EDCA stream */
if (SI == 0)
{
/* no any HCCA stream exists */
/* residual time = 1s - total ACM time */
TimeResidual = ACM_BANDWIDTH_CHECK_BASE;
TimeResidual -= ACMR_CB->EdcaCtrlParam.AcmTotalTime;
}
else
{
/* at lease one HCCA stream exists */
/* residual time = 1s - total polled time - total ACM time */
TimeResidual = SI; /* SI */
TimeResidual = TimeResidual*ACM_BANDWIDTH_CHECK_BASE/SI;
TimeResidual -= ACMR_CB->EdcaCtrlParam.AcmTotalTime;
} /* End of if */
/* substract reserved AC1/0 time from the residual time (1 second) */
TimeResidual -= TimeAc10;
#ifdef ACM_CC_FUNC_MBSS
/* substract time from other BSS */
if (TimeResidual < ACMR_CB->MbssTotalUsedTime)
TimeResidual = 0;
else
TimeResidual -= ACMR_CB->MbssTotalUsedTime;
/* End of if */
#endif /* ACM_CC_FUNC_MBSS */
/* check whether residual time is enough for the new stream */
if ((TimeResidual + AcmTimeOld) <= AcmTimeNew)
{
/* residual bandwidth is not enough for new EDCA stream */
goto LabelErr;
} /* End of if */
#ifdef RELEASE_EXCLUDE
/* dynamic ATL: also do dynamic ATL check */
if (ACMR_CB->EdcaCtrlParam.FlgDatl)
{
if (ACM_DATL_Handle(pAd, StmAcId, AcmTimeOld, AcmTimeNew,
pVbAc, pVbBw) != ACM_RTN_OK)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DATL not allow! BandwidthCheck()\n"));
goto LabelErr;
} /* End of if */
} /* End of if */
#endif /* RELEASE_EXCLUDE */
/* so bandwidth is enough */
return ACM_RTN_OK;
} /* End of if */
LabelErr:
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Not enough bandwidth (new request time = %dus)\n",
AcmTimeNew));
return ACM_RTN_FAIL;
} /* End of ACM_BandwidthCheck */
#ifdef RELEASE_EXCLUDE
/*
========================================================================
Routine Description:
Check whether bandwidth is enough to allow new stream.
Arguments:
pAd - WLAN control block pointer
DatlAcId - the AC
AcmTimeOld - old used time of the same stream, unit: microsecond
AcmTimeNew - the requested time of new stream, unit: microsecond
*pDatlAc - the borrowed AC ID, 0 ~ 3
*pDatlBw - the borrowed bandwidth from a AC, unit: microsecond
Return Value:
ACM_RTN_OK - allow
ACM_RTN_INSUFFICIENT_BD_BUT_DEL_AC - doesnt allow but we maybe delete AC
streams to increase bandwidth
Note:
We only check available bandwidth of 'A' AC, not for all ACs.
For example: if AC3 need more 100ms bandwidth, but residual bandwidth of
AC2 is 80ms and residual bandwidth of AC1 is 60ms, we still NOT allow the
TS. We only check 100>80 and 100>60 so we can not allow the TS.
We dont check 100<(80+60).
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_DATL_Handle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 StmAcId,
ACM_PARAM_IN UINT32 AcmTimeOld,
ACM_PARAM_IN UINT32 AcmTimeNew,
ACM_PARAM_OUT UINT32 *pDatlAc,
ACM_PARAM_OUT UINT32 *pDatlBw)
{
#define ACM_LMR_DATL_REAL_TIME_CAL(__Time, __Percent) \
__Time = __Percent; \
__Time *= AcmTotalTime; \
__Time /= 100;
ACM_CTRL_PARAM *pEdcaParam;
UINT32 *pTimeAcmCur;
UCHAR *pBwMax, *pBwMin;
INT32 AcmTotalTime;
INT32 TimeOpCur, TimeOpMax, TimeOpOff;
INT32 TimeAcCur, TimeAcMax, TimeAcMin, TimeAcOff;
UINT32 BwBorAc[ACM_DEV_NUM_OF_AC][ACM_DEV_NUM_OF_AC];
UINT32 IdAcNum, IdAcOther;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if ((AcmTimeOld != 0) && (AcmTimeNew <= AcmTimeOld))
return ACM_RTN_OK;
/* End of if */
/* here, AcmTimeNew >= AcmTimeOld (AcmTimeOld maybe 0) */
/* init */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pTimeAcmCur = pEdcaParam->AcmAcTime;
pBwMax = pEdcaParam->DatlBwMax; /* unit: percentage */
pBwMin = pEdcaParam->DatlBwMin; /* unit: percentage */
ACMR_MEM_COPY(BwBorAc, pEdcaParam->DatlBorAcBw, sizeof(BwBorAc));
*pDatlAc = ACM_DATL_NO_BORROW;
*pDatlBw = 0;
/* get TOTAL allowed ACM time */
AcmTotalTime = ACM_TIME_BASE;
/* get new used time for the AC */
TimeOpCur = pTimeAcmCur[StmAcId] + AcmTimeNew - AcmTimeOld;
if (TimeOpCur < 0)
return ACM_RTN_OK; /* should not be here */
/* End of if */
/* get maximum allowed ACM time for the AC */
ACM_LMR_DATL_REAL_TIME_CAL(TimeOpMax, pBwMax[StmAcId]);
#ifdef ACM_CC_FUNC_MBSS
TimeOpCur += ACMR_CB->MbssAcUsedTime[StmAcId];
#endif /* ACM_CC_FUNC_MBSS */
if (TimeOpCur <= TimeOpMax)
return ACM_RTN_OK; /* yet exceed its max time so no borrow is needed */
/* End of if */
/* here, extra bandwidth is needed so calculating needed extra bandwidth */
TimeOpOff = AcmTimeNew - AcmTimeOld; /* >= 0 */
/* sub extra bandwidth by self available bandwidth */
if ((INT32)(pTimeAcmCur[StmAcId]) < TimeOpMax)
{
if (TimeOpOff <= (TimeOpMax - (INT32)(pTimeAcmCur[StmAcId])))
{
/* current available bandwidth is enough */
/*
Should not be here because TimeOpCur will
<= TimeOpMax, we will return above.
*/
return ACM_RTN_OK;
} /* End of if */
TimeOpOff -= (TimeOpMax - pTimeAcmCur[StmAcId]);
} /* End of if */
/*
Check the needed extra bandwidth in the available bandwidth
of other ACs.
*/
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
if (pEdcaParam->FlgAcmStatus[IdAcNum] == 0)
continue; /* ACM is disabled */
/* End of if */
if (IdAcNum == StmAcId)
continue; /* skip same AC */
/* End of if */
if (pBwMin[IdAcNum] >= pBwMax[IdAcNum])
continue; /* no extra bandwidth can be borrow */
/* End of if */
/* calculate cur/max/min time for the AC, unit: microsecond */
TimeAcCur = pTimeAcmCur[IdAcNum];
ACM_LMR_DATL_REAL_TIME_CAL(TimeAcMax, pBwMax[IdAcNum]);
ACM_LMR_DATL_REAL_TIME_CAL(TimeAcMin, pBwMin[IdAcNum]);
#ifdef ACM_CC_FUNC_MBSS
TimeAcCur += ACMR_CB->MbssAcUsedTime[IdAcNum];
#endif /* ACM_CC_FUNC_MBSS */
/* no available bandwidth for the AC */
if (TimeAcCur > TimeAcMax)
continue;
/* End of if */
/*
If cur used time > min threshold time, use cur used time as
min threshold time.
*/
if (TimeAcCur > TimeAcMin)
TimeAcMin = TimeAcCur;
/* End of if */
/* accumulate borrowed bandwidth for the AC i */
for(IdAcOther=0; IdAcOther<ACM_DEV_NUM_OF_AC; IdAcOther++)
TimeAcMin += BwBorAc[IdAcNum][IdAcOther];
/* End of for */
/* calculate residual bandwidth that can be borrowed */
TimeAcOff = TimeAcMax - TimeAcMin;
if (TimeOpOff <= TimeAcOff)
{
/* we can borrow the bandwidth from the AC */
*pDatlAc = IdAcNum;
*pDatlBw = TimeOpOff;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> borrow bandwidth %dus from AC%d!"
"ACM_DATL_Handle()\n", TimeOpOff, IdAcNum));
return ACM_RTN_OK;
} /* End of if */
/* bandwidth is not enough, check next one */
} /* End of for */
return ACM_RTN_INSUFFICIENT_BD_BUT_DEL_AC;
} /* End of ACM_DATL_Handle */
/*
========================================================================
Routine Description:
Update ACM DATL information.
Arguments:
pAd - WLAN control block pointer
StmAcId - the AC
AcmTimeOld - old used time of the same stream, unit: microsecond
AcmTimeNew - the requested time of new stream, unit: microsecond
DatlAcId - the borrowed AC ID, 0 ~ 3
DatlBandwidth - the borrowed bandwidth from a AC, unit: microsecond
Return Value:
None
Note:
When AcmTimeNew > AcmTimeOld, DatlBandwidth will be the extra needed
bandwidth (AcmTimeNew - AcmTimeOld).
When AcmTimeNew <= AcmTimeOld, DatlBandwidth will be 0.
========================================================================
*/
STATIC VOID ACM_DATL_Update(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 StmAcId,
ACM_PARAM_IN UINT32 AcmTimeOld,
ACM_PARAM_IN UINT32 AcmTimeNew,
ACM_PARAM_OUT UINT32 DatlAcId,
ACM_PARAM_OUT UINT32 DatlBandwidth)
{
ACM_CTRL_PARAM *pEdcaParam;
UINT32 IdAcNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
/* reduce time_offset from any borrow bandwidth of other AC */
if ((AcmTimeOld != 0) && (AcmTimeOld > AcmTimeNew))
{
/* time_offset is the bandwidth we need to reclaim it to other AC */
UINT32 time_offset = AcmTimeOld - AcmTimeNew;
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
if (IdAcNum == StmAcId)
continue;
/* End of if */
if (time_offset > pEdcaParam->DatlBorAcBw[IdAcNum][StmAcId])
{
/* reclaim some time to the AC */
time_offset -= pEdcaParam->DatlBorAcBw[IdAcNum][StmAcId];
pEdcaParam->DatlBorAcBw[IdAcNum][StmAcId] = 0;
/* check next AC */
}
else
{
/* reclaim all time to the AC */
pEdcaParam->DatlBorAcBw[IdAcNum][StmAcId] -= time_offset;
break;
} /* End of if */
} /* End of for */
} /* End of if */
/* accumulate new borrowed bandwidth */
if (DatlAcId != ACM_DATL_NO_BORROW)
pEdcaParam->DatlBorAcBw[DatlAcId][StmAcId] += DatlBandwidth;
/* End of if */
} /* End of ACM_DATL_Update */
#endif /* RELEASE_EXCLUDE */
/*
========================================================================
Routine Description:
Send a delts frame to the peer.
Arguments:
pAd - WLAN control block pointer
*pCdb - the destination QSTA
*pStream - the stream
Return Value:
TRUE - send successfully
FALSE - send fail
Note:
========================================================================
*/
STATIC BOOLEAN ACM_DeltsFrameSend(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACM_STREAM *pStream)
{
UCHAR *pPktBuf;
UINT32 Len;
ACM_TS_INFO TsInfo;
if (ACMR_MGMT_FME_ALLOCATE(pAd, &pPktBuf) != NDIS_STATUS_SUCCESS)
return FALSE;
/* End of if */
Len = 0;
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
Len = ACM_FrameDeltsToStaMakeUp(pAd, pCdb, pPktBuf, pStream);
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
Len = ACM_FrameDeltsToApMakeUp(pAd, pCdb, pPktBuf, pStream);
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
ACMR_MEM_COPY(&TsInfo, &pStream->pTspec->TsInfo, sizeof(ACM_TS_INFO));
ACMR_MGMT_PKT_TX(pAd, pPktBuf, Len);
ACMR_MGMT_FME_FREE(pAd, pPktBuf);
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
if (ACMR_STATION_IS_NOT_IN_PS_MODE(pCdb))
{
ACM_DeltsFrameACK(pAd, ACMR_CLIENT_MAC(pStream->pCdb),
(UCHAR *)&pStream->pTspec->TsInfo, 0);
ACM_FrameBwAnnSend(pAd, FALSE);
} /* End of if */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
ACM_DeltsFrameACK(pAd, ACMR_AP_ADDR_GET(pAd),
(UCHAR *)&pStream->pTspec->TsInfo, 0);
ACM_FrameBwAnnSend(pAd, FALSE);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return TRUE;
} /* End of ACM_DeltsFrameSend */
/*
========================================================================
Routine Description:
Get extra data length for different entrypt mode.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
Return Value:
the extra data length
Note:
========================================================================
*/
STATIC UINT32 ACM_EncryptExtraLenGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
UINT32 DataExtraLen;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (pCdb == NULL)
return 0; /* error */
/* End of if */
if (ACMR_STA_ENCRYPT_MODE_GET(pCdb) == ACMR_ENCRYPT_WEP)
{
/* IV (4B) + ICV (4B) */
DataExtraLen = 8;
}
else if (ACMR_STA_ENCRYPT_MODE_GET(pCdb) == ACMR_ENCRYPT_TKIP)
{
/* IV/KeyID (4B) + Extended IV (4B) + MIC (8B) + ICV (4B) */
DataExtraLen = 20;
}
else if (ACMR_STA_ENCRYPT_MODE_GET(pCdb) == ACMR_ENCRYPT_AES)
{
/* CCMP Header (8B) + MIC (8B) */
DataExtraLen = 16;
}
else
DataExtraLen = 0;
/* End of if */
return DataExtraLen;
} /* End of ACM_EncryptExtraLenGet */
#ifdef CONFIG_STA_SUPPORT_SIM
/*
========================================================================
Routine Description:
Make up a WME Setup Request frame to the QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - the peer
*pBufFrame - the packet buffer
*pReqNew - the requested TSPEC pointer
Return Value:
Frame Length
Note:
1. Use high priority queue to send.
2. Only for QSTA mode (AP Client).
========================================================================
*/
STATIC UINT32 ACM_FrameAddtsReqMakeUp(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pBufFrame,
ACM_PARAM_IN ACM_STREAM *pReqNew)
{
ACMR_WLAN_HEADER HdrActionFrame;
ULONG FrameLen;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FrameLen = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Make up a ADDTS Request...\n"));
/* make the frame header */
MgtMacHeaderInit(
pAd, &HdrActionFrame, SUBTYPE_ACTION, 0,
ACMR_AP_ADDR_GET(pAd),
ACMR_CLIENT_MAC(pReqNew->pCdb));
MakeOutgoingFrame(
pBufFrame, &FrameLen,
sizeof(ACMR_WLAN_HEADER), &HdrActionFrame,
END_OF_ARGS);
/* make the frame body */
FrameLen += ACM_WME_ActionFrameBodyMake(
pAd, pReqNew,
(UCHAR *)&pBufFrame[FrameLen],
ACM_ACTION_WME_SETUP_REQ,
0);
return FrameLen;
} /* End of ACM_FrameAddtsReqMakeUp */
#endif /* CONFIG_STA_SUPPORT_SIM */
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Make up a WME Teardown frame to the QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - the peer
*pBufFrame - the packet buffer
*pStream - the stream want to delete
Return Value:
Frame Length
Note:
1. Use high priority queue to send.
2. No resource protection here.
========================================================================
*/
STATIC UINT32 ACM_FrameDeltsToApMakeUp(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pBufFrame,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACMR_WLAN_HEADER HdrActionFrame;
ULONG FrameLen;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FrameLen = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Make up a DELTS to QAP...\n"));
/* make the frame header */
MgtMacHeaderInit(
pAd, &HdrActionFrame, SUBTYPE_ACTION, 0,
ACMR_AP_ADDR_GET(pAd),
pStream->StaMac);
MakeOutgoingFrame(
pBufFrame, &FrameLen,
sizeof(ACMR_WLAN_HEADER), &HdrActionFrame,
END_OF_ARGS);
/* make the frame body */
FrameLen += ACM_WME_ActionFrameBodyMake(
pAd, pStream,
(UCHAR *)&pBufFrame[FrameLen],
ACM_ACTION_WME_TEAR_DOWN,
0);
return FrameLen;
} /* End of ACM_FrameDeltsToApMakeUp */
#endif /* CONFIG_STA_SUPPORT */
#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
Make up a WME Teardown frame to the QSTA.
Arguments:
pAd - WLAN control block pointer
*pCdb - the peer, no use
*pBufFrame - the packet buffer
*pStream - the stream want to delete
Return Value:
Frame Length
Note:
1. Use high priority queue to send.
2. No resource protection here.
========================================================================
*/
STATIC UINT32 ACM_FrameDeltsToStaMakeUp(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pBufFrame,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACMR_WLAN_HEADER HdrActionFrame;
ULONG FrameLen;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FrameLen = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Make up a DELTS to QSTA...\n"));
/* make the frame header */
MgtMacHeaderInit(
pAd, &HdrActionFrame, SUBTYPE_ACTION, 0,
ACMR_CLIENT_MAC(pStream->pCdb),
pAd->ApCfg.MBSSID[pStream->pCdb->apidx].Bssid);
MakeOutgoingFrame(
pBufFrame, &FrameLen,
sizeof(ACMR_WLAN_HEADER), &HdrActionFrame,
END_OF_ARGS);
/* make the frame body */
FrameLen += ACM_WME_ActionFrameBodyMake(
pAd, pStream,
(UCHAR *)&pBufFrame[FrameLen],
ACM_ACTION_WME_TEAR_DOWN,
0);
return FrameLen;
} /* End of ACM_FrameDeltsToStaMakeUp */
#endif /* CONFIG_AP_SUPPORT */
/*
========================================================================
Routine Description:
Increase or decrease the link number counter.
Arguments:
pAd - WLAN control block pointer
AccessPolicy - ACM_ACCESS_POLICY_EDCA
Dir - ACM_DIRECTION_UP_LINK,
ACM_DIRECTION_DOWN_LINK,
ACM_DIRECTION_DIRECT_LINK,
ACM_DIRECTION_BIDIREC_LINK
FlgIsAdd - 1: increase by 1; 0: decrease by 1
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_LinkNumCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 AccessPolicy,
ACM_PARAM_IN UINT32 Dir,
ACM_PARAM_IN UINT32 FlgIsAdd)
{
UINT32 *pAcLinkNum[ACM_DIRECTION_MAX] = \
{ &ACMR_CB->EdcaCtrlParam.LinkNumUp,
&ACMR_CB->EdcaCtrlParam.LinkNumDn,
&ACMR_CB->EdcaCtrlParam.LinkNumDi,
&ACMR_CB->EdcaCtrlParam.LinkNumBi };
UINT32 *pNumStm;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (AccessPolicy == ACM_ACCESS_POLICY_EDCA)
pNumStm = pAcLinkNum[Dir];
else
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> non-WMM is not supported! LinkNumCtrl()\n"));
return;
} /* End of if */
if (FlgIsAdd == 1)
(*pNumStm) ++; /* a new link is accepted */
else
{
if ((*pNumStm) > 0)
(*pNumStm) --; /* a old link is deleted */
else
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> link number == 0! dir = %d "
"ACM_LinkNumCtrl()\n", Dir));
(*pNumStm) = 0; /* fix it */
} /* End of if */
} /* End of if */
} /* End of ACM_LinkNumCtrl */
/*
========================================================================
Routine Description:
Set the minimum PHY Mode and MCS to the packet.
Arguments:
pAd - WLAN control block pointer
*pStream - the stream pointer
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
We have checked the min physical rate should be the supported rate.
So dont need to empty the non-supported rate in
gAcmMCS_CCK[] or gAcmMCS_OFDM[].
========================================================================
*/
STATIC VOID ACM_PacketPhyModeMCSSet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
UINT16 Rate[] = { /* non-11n rate */
10, 20, 55, 60, 90, 110, 120, 180, 240, 360, 480, 540 };
UINT32 MinPhyRate; /* unit: bps */
UCHAR PhyModeMin, McsMin;
UINT32 PreambleId, RateId;
ACMR_STA_DB *pCdb;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (pStream->pTspec->MinPhyRate == 0)
return;
/* End of if */
/* init */
PhyModeMin = ACMR_PHY_NONE;
McsMin = 0;
PreambleId = 0; /* 0: long preamble, 1: short preamble */
pCdb = pStream->pCdb;
if (ACMR_STA_IS_SPREAMBLE(pAd, pCdb))
PreambleId = 1;
/* End of if */
/* find the phy mode & mcs based on minimum physical rate */
while(1)
{
MinPhyRate = pStream->pTspec->MinPhyRate;
for(RateId=0; RateId<ACM_RATE_B_NUM; RateId++)
{
if (MinPhyRate == \
((UINT32)gAcmMCS_CCK[PreambleId][RateId][1] * ACM_RATE_UNIT))
{
PhyModeMin = ACMR_PHY_CCK;
McsMin = gAcmMCS_CCK[1][RateId][0];
break;
} /* End of if */
} /* End of for */
if (PhyModeMin == ACMR_PHY_NONE)
{
/* not found in CCK rate so try to find it in OFDM rate */
for(RateId=0; RateId<ACM_RATE_G_NUM; RateId++)
{
if (MinPhyRate == \
((UINT32)gAcmMCS_OFDM[RateId][1] * ACM_RATE_UNIT))
{
PhyModeMin = ACMR_PHY_OFDM;
McsMin = gAcmMCS_OFDM[RateId][0];
break;
} /* End of if */
} /* End of for */
} /* End of if */
#ifdef ACM_CC_FUNC_11N
if (PhyModeMin == ACMR_PHY_NONE)
{
BOOLEAN FlgIs2040;
UINT32 IdGI;
/* not found in OFDM rate so try to find it in N rate */
FlgIs2040 = ACMR_IS_2040_STA(pCdb);
for(IdGI=0; IdGI<2; IdGI++)
{
for(RateId=0; RateId<ACM_RATE_MAX_NUM_HT; RateId++)
{
if (MinPhyRate == \
((UINT32)gAcmMCS_HT[FlgIs2040][0][RateId] * \
ACM_RATE_UNIT))
{
/* always use regular GI */
PhyModeMin = ACMR_PHY_HT;
McsMin = RateId;
break;
} /* End of if */
} /* End of for */
} /* End of for */
} /* End of if */
#endif /* ACM_CC_FUNC_11N */
if (PhyModeMin != ACMR_PHY_NONE)
{
/* correct MIN PHY rate */
break;
} /* End of if */
/* should not be here */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> MIN PHY Rate %d bps is not "
"our supported rate!\n",
MinPhyRate));
/* the rate does not belong to any specified rate */
/* we need to choose one as the minimum physical rate */
MinPhyRate = MinPhyRate / ACM_RATE_UNIT;
/* try to find the correct rate in non-HT rates */
for(RateId=0; RateId<ACM_RATE_MAX_NUM; RateId++)
{
if (MinPhyRate < Rate[RateId])
{
if (RateId > 0)
RateId--;
/* End of if */
MinPhyRate = Rate[RateId];
break;
} /* End of if */
} /* End of for */
#ifdef ACM_CC_FUNC_11N
/* if not found, try to find the correct rate in HT rates */
if (RateId == ACM_RATE_MAX_NUM)
{
BOOLEAN FlgIs2040;
UINT32 McsRate, McsRateMin;
UINT32 OffsetMin;
FlgIs2040 = ACMR_IS_2040_STA(pCdb);
McsRateMin = gAcmMCS_HT[FlgIs2040][0][0] * ACM_RATE_UNIT;
OffsetMin = 0xFFFFFFFF;
#ifdef RELEASE_EXCLUDE
/*
Try to find the correct MCS rate with minimum offset with
the incorrect minimum physical rate and smaller than the
correct MCS rate.
Note: HT MCS 1 'maybe' not smaller than HT MCS 2.
*/
#endif /* RELEASE_EXCLUDE */
for(RateId=0; RateId<ACM_RATE_MAX_NUM_HT; RateId++)
{
McsRate = (UINT32)gAcmMCS_HT[FlgIs2040][0][RateId];
if (McsRate <= MinPhyRate)
{
if ((MinPhyRate - McsRate) < OffsetMin)
{
OffsetMin = (MinPhyRate - McsRate);
McsRateMin = McsRate;
} /* End of if */
} /* End of if */
} /* End of for */
MinPhyRate = McsRateMin;
} /* End of if */
#endif /* ACM_CC_FUNC_11N */
/* adjust the minimum physical rate to the correct rate number */
pStream->pTspec->MinPhyRate = MinPhyRate * ACM_RATE_UNIT;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Correct MIN PHY Rate to %d bps!\n",
pStream->pTspec->MinPhyRate));
} /* End of while */
/* assign minimum phy mode & mcs to the stream */
pStream->PhyModeMin = PhyModeMin;
pStream->McsMin = McsMin;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Min PHY mode = %d, Min MCS = %d\n",
PhyModeMin, McsMin));
} /* End of ACM_PacketPhyModeMCSSet */
/*
========================================================================
Routine Description:
Get the MAC address of next client data base.
Arguments:
pAd - WLAN control block pointer
*pDevIndex - search base, first = 0
*pDevMac - the MAC of the client
Return Value:
ACM_RTN_OK - get successfully
ACM_RTN_FAIL - no client can be got
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_PeerDeviceMacGetNext(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN_OUT UINT32 *pDevIndex,
ACM_PARAM_IN UCHAR *pDevMac)
{
ACMR_STA_DB *pCdb;
UINT32 IdDevNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pCdb = NULL; /* initial value must be NULL */
/* search for all client entries */
for(IdDevNum=(*pDevIndex); IdDevNum<ACMR_STA_MAX_NUM; IdDevNum++)
{
pCdb = ACMR_STA_GET(pAd, pCdb, IdDevNum);
if (ACMR_STA_IS_VALID(pCdb))
{
/* the client entry exists */
ACMR_MEM_MAC_COPY(pDevMac, ACMR_CLIENT_MAC(pCdb));
/* return next client entry index */
*pDevIndex = (IdDevNum+1);
return ACM_RTN_OK;
} /* End of if */
} /* End of for */
/* no any client exists */
return ACM_RTN_FAIL;
} /* End of ACM_PeerDeviceMacGetNext */
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Change PS mode to ACTIVE mode.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
We will enter ACTIVE mode after we send a ADDTS request frame.
========================================================================
*/
STATIC VOID ACM_PS_ActiveOn(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifndef ACM_CC_FUNC_PS_MGMT_FME
WMM_ACM_FUNC_NAME_PRINT("IN");
ACMR_STA_PS_MODE_ACTIVE(pAd);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Active On! PS_ActiveOn()\n"));
#endif /* ACM_CC_FUNC_PS_MGMT_FME */
} /* End of ACM_PS_ActiveOn */
/*
========================================================================
Routine Description:
Enable or disable TSPEC UAPSD function.
Arguments:
pAd - WLAN control block pointer
FlgIsEnable - 1: enable; 0: disable
Return Value:
None
Note:
Only for QSTA.
If TSPEC UAPSD function is disabled, the UAPSD field of TSPEC will
be same as the value in station association request frame.
========================================================================
*/
STATIC VOID ACM_PS_UapsdCtrl(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsEnable)
{
ACM_CTRL_PARAM *pEdcaParam;
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pEdcaParam->FlgIsTspecUpasdEnable = FlgIsEnable;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TSPEC UAPSD function flag = %d!\n", FlgIsEnable));
} /* End of ACMP_TC_UapsdCtrl */
#endif /* CONFIG_STA_SUPPORT */
/*
========================================================================
Routine Description:
Mapping current station rate to ACM rate.
Arguments:
pAd - WLAN control block pointer
*pCdb - the QSTA
Return Value:
ACM_PRE_TIME_ID_1M, etc.
Note:
========================================================================
*/
STATIC UCHAR ACM_Rate_Mapping(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
#ifdef RELEASE_EXCLUDE
/*
[0] is used in WLAN module;
[1] is used in tx time calculation;
[2] is used in tx time array index.
*/
#endif /* RELEASE_EXCLUDE */
UCHAR RateMapping[ACM_RATE_MAX_NUM][3] = {
{ ACMR_RATE_DRV_1M, ACM_RATE_1M, ACM_PRE_TIME_ID_1M },
{ ACMR_RATE_DRV_2M, ACM_RATE_2M, ACM_PRE_TIME_ID_2M },
{ ACMR_RATE_DRV_5_5M, ACM_RATE_5_5M, ACM_PRE_TIME_ID_5_5M },
{ ACMR_RATE_DRV_11M, ACM_RATE_11M, ACM_PRE_TIME_ID_11M },
{ ACMR_RATE_DRV_6M, ACM_RATE_6M, ACM_PRE_TIME_ID_6M },
{ ACMR_RATE_DRV_9M, ACM_RATE_9M, ACM_PRE_TIME_ID_9M },
{ ACMR_RATE_DRV_12M, ACM_RATE_12M, ACM_PRE_TIME_ID_12M },
{ ACMR_RATE_DRV_18M, ACM_RATE_18M, ACM_PRE_TIME_ID_18M },
{ ACMR_RATE_DRV_24M, ACM_RATE_24M, ACM_PRE_TIME_ID_24M },
{ ACMR_RATE_DRV_36M, ACM_RATE_36M, ACM_PRE_TIME_ID_36M },
{ ACMR_RATE_DRV_48M, ACM_RATE_48M, ACM_PRE_TIME_ID_48M },
{ ACMR_RATE_DRV_54M, ACM_RATE_54M, ACM_PRE_TIME_ID_54M } };
UINT32 PhyMode, MCS;
UINT32 RateIndex;
WMM_ACM_FUNC_NAME_PRINT("IN");
RateIndex = ACM_RATE_MAX_NUM - 1; /* default use maximum rate */
ACMR_CLIENT_PHY_MODE_MCS_GET(pCdb, PhyMode, MCS);
if (PhyMode == ACMR_PHY_CCK)
{
/* CCK PHY */
ACMR_CLIENT_CCK_RATE_INDEX_GET(MCS, RateIndex);
}
else
{
/* OFDM PHY */
ACMR_CLIENT_OFDM_RATE_INDEX_GET(MCS, RateIndex);
} /* End of if */
return RateMapping[RateIndex][2];
} /* End of ACM_Rate_Mapping */
/*
========================================================================
Routine Description:
Get the output or input TSPEC array list of the device.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the MAC of the client
FlgIsOutputLink - 1: output links; 0: input links
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
STATIC UCHAR **ACM_StationTspecListGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN BOOLEAN FlgIsOutputLink)
{
ACMR_STA_DB *pCdb;
ACM_ENTRY_INFO *pStaAcmInfo;
WMM_ACM_FUNC_NAME_PRINT("IN");
pCdb = ACMR_STA_ENTRY_GET(pAd, pDevMac);
if (pCdb == NULL)
{
/* maybe the peer device disassociated or we disassociated it */
return NULL;
} /* End of if */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
if (FlgIsOutputLink == TRUE)
return pStaAcmInfo->pAcStmOut;
/* End of if */
return pStaAcmInfo->pAcStmIn;
} /* End of ACM_StationTspecListGet */
/*
========================================================================
Routine Description:
Get the TSID from the packet from VLAN ID or DSCP.
Arguments:
pAd - WLAN control block pointer
*pMbuf - the QoS frame
Return Value:
the TSID
Note:
========================================================================
*/
STATIC UCHAR ACM_TSID_Get(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_MBUF *pMbuf)
{
ACM_IPHDR *pIpHdr;
PUCHAR pBufSrc;
UCHAR TSID;
WMM_ACM_FUNC_NAME_PRINT("IN");
TSID = 0; /* TSID = default BE */
ACMR_PKT_DATA_GET(pMbuf, pBufSrc);
if (((pBufSrc[12] << 8) + pBufSrc[13]) == 0x0800)
{
/* IPv4 packet */
pIpHdr = (ACM_IPHDR *)&pBufSrc[14];
TSID = pIpHdr->TOS >> 5; /* UP = DSCP / 8 */
}
else
{
/* VLAN priority is larger than DSCP */
if (((pBufSrc[12] << 8) + pBufSrc[13]) == 0x8100)
{
/* VLAN packet */
TSID = (pBufSrc[14] & 0xe0) >> 5;
} /* End of if */
} /* End of if */
return TSID;
} /* End of ACM_TSID_Get */
/*
========================================================================
Routine Description:
Get the physical transmit queue type.
Arguments:
AcmAcId - physical AC ID
Return Value:
the physical transmit queue type
Note:
========================================================================
*/
STATIC UINT32 ACM_TxQueueTypeGet(
ACM_PARAM_IN UCHAR AcmAcId)
{
/* EDCA stream, AC0 ~ AC3 */
switch(AcmAcId)
{
case 0:
return ACMR_QID_AC_BE; /* AC0 (BE) stream */
case 1:
return ACMR_QID_AC_BK; /* AC1 (BK) stream */
case 2:
return ACMR_QID_AC_VI; /* AC2 (VI) stream */
case 3:
return ACMR_QID_AC_VO; /* AC3 (VO) stream */
default: /* fatal error */
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> EDCA AcmAcId > 3! TxQueueTypeGet()\n"));
return ACMR_QID_AC_BE; /* default: AC0 (BE) stream */
} /* End of switch */
} /* End of ACM_TxQueueTypeGet */
/* =========== Peer device management function =========== */
/*
========================================================================
Routine Description:
Insert the peer device to the backup link list.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the MAC of the QSTA
Return Value:
ACM_RTN_OK - add ok
ACM_RTN_FAIL - add fail
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_PeerDeviceAdd(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac)
{
ACM_PEER_DEV_LIST *pAcmStmList, *pStmLast;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pAcmStmList = ACMR_CB->pDevListPeer;
/* check whether no any QSTA exists in the backup list */
if (pAcmStmList == NULL)
{
ACMR_MEM_ALLOC(ACMR_CB->pDevListPeer,
sizeof(ACM_PEER_DEV_LIST), (ACM_PEER_DEV_LIST *));
if (ACMR_CB->pDevListPeer == NULL)
goto LabelAllocFail;
/* End of if */
ACMR_CB->pDevListPeer->pPrev = NULL;
ACMR_CB->pDevListPeer->pNext = NULL;
ACMR_MEM_MAC_COPY(ACMR_CB->pDevListPeer->MAC, pDevMac);
return ACM_RTN_OK;
} /* End of if */
/* search the peer device in the list and find the last one */
while(pAcmStmList != NULL)
{
if (AMR_IS_SAME_MAC(pAcmStmList->MAC, pDevMac))
{
/* the peer device has already existed so no need to backup it */
return ACM_RTN_OK;
} /* End of if */
pStmLast = pAcmStmList;
pAcmStmList = pAcmStmList->pNext;
} /* End of while */
pAcmStmList = pStmLast;
/* do not find so append the new peer device to the last one */
ACMR_MEM_ALLOC(pStmLast, sizeof(ACM_PEER_DEV_LIST), (ACM_PEER_DEV_LIST *));
if (pStmLast == NULL)
goto LabelAllocFail;
/* End of if */
pAcmStmList->pNext = pStmLast;
pStmLast->pPrev = pAcmStmList;
pStmLast->pNext = NULL;
ACMR_MEM_MAC_COPY(pStmLast->MAC, pDevMac);
return ACM_RTN_OK;
LabelAllocFail:
ACMR_DEBUG(ACMR_DEBUG_ERR, ("acm_err> Allocate peer device entry fail!\n"));
return ACM_RTN_FAIL;
} /* End of ACM_PeerDeviceAdd */
/*
========================================================================
Routine Description:
Delete the peer device from the backup link list.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the MAC of the QSTA
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_PeerDeviceDel(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac)
{
ACM_PEER_DEV_LIST *pDevList, *pDevNext;
WMM_ACM_FUNC_NAME_PRINT("IN");
pDevList = ACMR_CB->pDevListPeer;
while(1)
{
if (pDevList == NULL)
{
/* can not found the next peer device */
break;
} /* End of if */
pDevNext = pDevList->pNext;
if (AMR_IS_SAME_MAC(pDevList->MAC, pDevMac))
{
/* find it and delete it */
if (pDevList->pPrev == NULL)
ACMR_CB->pDevListPeer = pDevList->pNext;
else
(pDevList->pPrev)->pNext = pDevList->pNext;
/* End of if */
if (pDevList->pNext != NULL)
(pDevList->pNext)->pPrev = pDevList->pPrev;
/* End of if */
ACMR_MEM_FREE(pDevList);
/* not break, try to delete all redudant entries for the peer */
/* should not occur */
} /* End of if */
pDevList = pDevNext;
} /* End of while */
} /* End of ACM_PeerDeviceDel */
/*
========================================================================
Routine Description:
Get next the peer device from the backup link list.
Arguments:
pAd - WLAN control block pointer
**ppDevicePeer - the last peer device
*pDevMac - the MAC of the QSTA
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_PeerDeviceGetNext(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_PEER_DEV_LIST **ppDevicePeer,
ACM_PARAM_IN UCHAR *pDevMac)
{
ACM_PEER_DEV_LIST *pDevNext;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (*ppDevicePeer == NULL)
{
/* get first peer */
pDevNext = ACMR_CB->pDevListPeer;
if (pDevNext == NULL)
{
*ppDevicePeer = NULL;
return ACM_RTN_FAIL;
} /* End of if */
}
else
{
/* get next peer */
pDevNext = *ppDevicePeer;
if (pDevNext->pNext == NULL)
{
*ppDevicePeer = NULL;
return ACM_RTN_FAIL;
} /* End of if */
pDevNext = pDevNext->pNext;
} /* End of if */
*ppDevicePeer = pDevNext;
ACMR_MEM_MAC_COPY(pDevMac, pDevNext->MAC);
return ACM_RTN_OK;
} /* End of ACM_PeerDeviceGetNext */
/*
========================================================================
Routine Description:
Free all the peer device backup link list.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_PeerDeviceAllFree(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ACM_PEER_DEV_LIST *pDevList, *pDevNext;
WMM_ACM_FUNC_NAME_PRINT("IN");
pDevList = ACMR_CB->pDevListPeer;
while(pDevList)
{
pDevNext = pDevList->pNext;
ACMR_MEM_FREE(pDevList);
pDevList = pDevNext;
} /* End of while */
ACMR_CB->pDevListPeer = NULL;
} /* End of ACM_PeerDeviceAllFree */
/*
========================================================================
Routine Description:
Maintain the peer device backup link list.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the MAC of the QSTA
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_PeerDeviceMaintain(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac)
{
ACMR_STA_DB *pCdb;
ACM_ENTRY_INFO *pStaAcmInfo;
UINT32 IdTidNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* get device entry */
pCdb = ACMR_STA_ENTRY_GET(pAd, pDevMac);
if (pCdb == NULL)
return;
/* End of if */
/* get ACM control block of the device */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
/* check if all TS are deleted for the device */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (pStaAcmInfo->pAcStmOut[IdTidNum] != NULL)
{
/* at least one output TS exists so dont kill the entry */
return;
} /* End of if */
if (pStaAcmInfo->pAcStmIn[IdTidNum] != NULL)
{
/* at least one input TS exists so dont kill the entry */
return;
} /* End of if */
} /* End of for */
/* no any TS exists so we delete the peer device record */
ACM_PeerDeviceDel(pAd, pDevMac);
} /* End of ACM_PeerDeviceMaintain */
/* ========================= Stream Management Function ===================== */
/*
========================================================================
Routine Description:
Check whether a stream is timeout due to inactivity or suspendsion.
Arguments:
pAd - WLAN control block pointer
*pStream - the activated stream
Return Value:
TRUE - Need to send out a DELTS frame
FALSE - No need to send out a DELTS frame
Note:
We can not delete steams only after station disassociated.
Because maybe one link timeout but other links do not timeout for a
QSTA.
========================================================================
*/
STATIC BOOLEAN ACM_STM_IdleCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
WMM_ACM_FUNC_NAME_PRINT("IN");
/* check current stream status */
if ((pStream->Status != TSPEC_STATUS_ACTIVE) &&
(pStream->Status != TSPEC_STATUS_ACTIVE_SUSPENSION))
{
/* the request will be deleted, do NOT need to care about it */
return FALSE;
} /* End of if */
/* check inactivity timeout */
if (pStream->pTspec->InactivityInt != ACM_TSPEC_INACTIVITY_DISABLE)
{
/* inactivity function is enabled */
if (pStream->InactivityCur <= ACM_STREAM_CHECK_BASE)
{
/* stream is timeout so we need to delete the stream */
if (pStream->InactivityCur > 0)
{
#ifdef RELEASE_EXCLUDE
/*
For bidirectional link, if dnlink is deleting, uplink will
not be deleting; when dnlink is deleted, uplink will also
be deleted. For its uplink, pStream->InactivityCur will
be 0 until its dnlink is deleted.
*/
#endif /* RELEASE_EXCLUDE */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Inactivity timeout! TX a DELTS frame! "
"(dir %d) ACM_STM_IdleCheck()!\n",
pStream->pTspec->TsInfo.Direction));
pStream->InactivityCur = 0;
pStream->Cause = TSPEC_CAUSE_INACTIVITY_TIMEOUT;
return ACM_TC_Delete(pAd, pStream);
} /* End of if */
}
else
pStream->InactivityCur -= ACM_STREAM_CHECK_BASE;
/* End of if */
} /* End of if */
return FALSE;
} /* End of ACM_STM_IdleCheck */
/*
========================================================================
Routine Description:
Copy the stream information.
Arguments:
*pStreamSrc - the source stream
*pStreamInfoDst - the destination buffer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_STM_InfoCopy(
ACM_PARAM_OUT ACM_STREAM_INFO *pStreamInfoDst,
ACM_PARAM_IN ACM_STREAM *pStreamSrc)
{
UINT32 IdTclasNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* copy information */
ACM_TSPEC_COPY((&(pStreamInfoDst->Tspec)), pStreamSrc->pTspec);
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
{
if (pStreamSrc->pTclas[IdTclasNum] != NULL)
{
ACM_TCLAS_COPY((&(pStreamInfoDst->Tclas[IdTclasNum])),
pStreamSrc->pTclas[IdTclasNum]);
} /* End of if */
} /* End of for */
ACMR_MEM_MAC_COPY(pStreamInfoDst->DevMac, pStreamSrc->StaMac);
pStreamInfoDst->TclasProcessing = pStreamSrc->TclasProcessing;
pStreamInfoDst->StreamType = pStreamSrc->StreamType;
pStreamInfoDst->UP = pStreamSrc->UP;
pStreamInfoDst->Status = pStreamSrc->Status;
pStreamInfoDst->Cause = pStreamSrc->Cause;
pStreamInfoDst->AcmAcId = pStreamSrc->AcmAcId;
pStreamInfoDst->FlgOutLink = pStreamSrc->FlgOutLink;
pStreamInfoDst->Reserved2[0] = 0;
pStreamInfoDst->Reserved2[1] = 0;
pStreamInfoDst->Reserved2[2] = 0;
pStreamInfoDst->InactivityCur = pStreamSrc->InactivityCur;
pStreamInfoDst->SuspensionCur = pStreamSrc->SuspensionCur;
pStreamInfoDst->PhyModeMin = pStreamSrc->PhyModeMin;
pStreamInfoDst->McsMin = pStreamSrc->McsMin;
} /* End of ACM_STM_InfoCopy */
/*
========================================================================
Routine Description:
Check inactivity and suspension for all activated streams.
Arguments:
Data - WLAN control block pointer
Return Value:
None
Note:
This is a tasklet.
========================================================================
*/
STATIC VOID ACM_TASK_STM_Check(
ACM_PARAM_IN ULONG Data)
{
PRTMP_ADAPTER pAd;
ACM_CTRL_PARAM *pEdcaParam;
ACM_PEER_DEV_LIST *pAcmDevList;
ACM_STREAM **ppAcmStmList, *pStream;
ACMR_LIST StreamList;
ACM_FUNC_STATUS RtnCode;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UCHAR MAC[ACM_MAC_ADDR_LEN], MAC_Last[ACM_MAC_ADDR_LEN];
UCHAR UP;
BOOLEAN FlgIsNeedToDel;
UINT32 IdTidNum, IdLinkNum, AcId;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pAd = (PRTMP_ADAPTER) Data;
RtnCode = ACM_RTN_FAIL;
FlgIsNeedToDel = FALSE;
ACMR_LIST_INIT(&StreamList);
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* sanity check */
pEdcaParam = &ACMR_CB->EdcaCtrlParam;
if (pEdcaParam->FlgIsTspecTimeoutEnable == 0)
{
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return; /* no need to do TSPEC timeout check */
} /* End of if */
/* check all output and input links for each peer */
pAcmDevList = NULL;
while(1)
{
/* get next device */
if (ACM_PeerDeviceGetNext(pAd, &pAcmDevList, MAC) != ACM_RTN_OK)
break;
/* End of if */
/*
Check if we need to delete the device entry due to NO any output
and input link for the peer device.
*/
if (FlgIsNeedToDel == TRUE)
ACM_PeerDeviceDel(pAd, MAC_Last);
/* End of if */
/* check all output and input streams for the peer device */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, MAC, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
{
/*
We can not delete the entry here or we can not find the
pNext in ACM_PeerDeviceGetNext(), we need to use sta_p at
next loop.
*/
ACMR_MEM_MAC_COPY(MAC_Last, MAC);
FlgIsNeedToDel = TRUE;
break;
} /* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
pStream = ppAcmStmList[IdTidNum];
if (pStream != NULL)
{
if ((IdLinkNum == 1) &&
(pStream->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK))
{
/*
For bidirectional link, we will check the one
when IdLinkNum == 0, so we dont need to check twice.
*/
continue;
} /* End of if */
UP = pStream->pTspec->TsInfo.UP;
AcId = ACM_MR_EDCA_AC(UP);
/* do NOT check NULL TSPEC */
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[AcId] != 0)
{
RtnCode = ACM_RTN_OK;
if (ACM_STM_IdleCheck(pAd, pStream) == TRUE)
{
/* the stream timeouts so we need to delete it */
ACMR_LIST_ALLOC_AND_INSERT_TO_TAIL(pAd, &StreamList, pStream);
} /* End of if */
} /* End of if */
} /* End of if */
} /* End of for */
FlgIsNeedToDel = FALSE;
} /* End of for */
} /* End of while */
/* check if no any activated stream exists */
if (RtnCode == ACM_RTN_FAIL)
{
#ifndef ACMR_HANDLE_IN_TIMER
/* disable the stream activity & suspend check timer */
ACMR_TIMER_DISABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck);
#endif /* ACMR_HANDLE_IN_TIMER */
}
else
{
#ifdef ACMR_HANDLE_IN_TIMER
/* schedule next timer */
ACMR_TIMER_ENABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck,
ACM_STREAM_CHECK_OFFSET);
#endif /* ACMR_HANDLE_IN_TIMER */
} /* End of if */
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
/* send a DELTS frame for each TSPEC */
while(1)
{
pStream = (ACM_STREAM *)ACMR_LIST_REMOVE_FRM_HEAD(&StreamList);
if (pStream == NULL)
break;
/* End of if */
ACM_DELTS_SEND(pAd, pStream->pCdb, pStream, LabelSemErr);
/* isolate the stream */
pStream->pPrev = NULL;
pStream->pNext = NULL;
/* free it */
ACM_TC_Free(pAd, pStream);
}
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACM_TASK_STM_Check */
/*
========================================================================
Routine Description:
Check inactivity and suspension for all activated streams.
Arguments:
Data - WLAN control block pointer
Return Value:
None
Note:
1. Only for QAP Mode.
2. Waked up every 100ms.
========================================================================
*/
VOID ACM_TR_STM_Check(
ACM_PARAM_IN ULONG Data)
{
#ifndef ACMR_HANDLE_IN_TIMER
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) Data;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* sanity check for enable flag */
if (ACMR_CB->FlgStreamAliveCheckEnable == 0)
{
ACMR_TIMER_DISABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
} /* End of if */
/* inform TSPEC request check task */
ACMR_TASK_ACTIVATE(ACMR_CB->TaskletStreamAliveCheck,
ACMR_CB->TimerStreamAliveCheck,
ACM_STREAM_CHECK_OFFSET);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#else
ACM_TASK_STM_Check(Data);
#endif /* ACMR_HANDLE_IN_TIMER */
} /* End of ACM_TR_STM_Check */
/* =========================== 11e TSPEC Function =========================== */
/*
========================================================================
Routine Description:
Inform us that tx compleletion interrupt occurred.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the destination MAC
*pTsInfo - the TS Info of the packet
FlgIsErr - if the frame tx is error
Return Value:
None
Note:
1. Responsible for DELTS ACK frame check.
2. Now we call the function after DELTS frame is sent immediately.
3. If we need to guarantee the DELTS frame is received in peer device,
we need to call the function in TX done service routine.
========================================================================
*/
VOID ACM_DeltsFrameACK(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN UCHAR *pTsInfo,
ACM_PARAM_IN UCHAR FlgIsErr)
{
ACM_STREAM *pStream;
ACMR_STA_DB *pCdb;
UINT32 NumMaxSearch;
UCHAR StmAcId;
UCHAR Direction;
/* UCHAR FlgIsActive; */
WMM_ACM_FUNC_NAME_PRINT("IN");
#if 0 /* if we use IRQ LOCK in WLAN module, we enable the check */
/* sanity check */
if (!ACMR_IS_ENABLED(pAd))
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> WMM ACM is disabled! DeltsFrameACK()\n"));
return;
} /* End of if */
/* DELTS ACK frame is received so we can free the stream */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> RV a DELTS ACK! DeltsFrameACK()\n"));
#endif /* 0 */
/* init */
pCdb = NULL;
NumMaxSearch = 0;
StmAcId = 0;
Direction = 0;
/* FlgIsActive = 0; */
/* find it in request or active list */
while(1)
{
/* should be once in the while loop */
pStream = ACM_TC_Find(pAd, pDevMac, (ACM_TS_INFO *)pTsInfo);
if (pStream == NULL)
break; /* not find */
/* End of if */
pCdb = pStream->pCdb;
StmAcId = pStream->AcmAcId;
Direction = pStream->pTspec->TsInfo.Direction;
#if 0
if ((pStream->Status == TSPEC_STATUS_ACTIVE) ||
(pStream->Status == TSPEC_STATUS_ACTIVE_SUSPENSION) ||
(pStream->Status == TSPEC_STATUS_ACT_DELETING))
{
FlgIsActive = 1;
} /* End of if */
#endif
/* destroy the request or active stream */
ACM_TC_Destroy(pAd, pStream, 0);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DEL the request ok! DeltsFrameACK()\n"));
if (++NumMaxSearch > 5)
break; /* avoid forever loop, should not be here */
/* End of if */
} /* End of while */
/* recover the UAPSD state if the deleted TSPEC is ever actived */
/* we have already recover UAPSD state in ACM_TC_Destroy() */
#if 0
if ((pCdb != NULL) && (FlgIsActive))
ACM_APSD_Ctrl(pAd, pCdb, StmAcId, Direction, 0, 0);
/* End of if */
#endif /* 0 */
#ifdef RELEASE_EXCLUDE
/*
Note: We can not call ACM_PS_CtrlRightReturn() here because
managemnet lock mabye locked before calling ACM_DeltsFrameACK();
If we call management frame tx function in ACM_PS_CtrlRightReturn(),
the tx function will lock again to cause 'CPU lock bug'.
So we remove calling it here.
*/
#endif /* RELEASE_EXCLUDE */
return;
} /* End of ACM_DeltsFrameACK */
/*
========================================================================
Routine Description:
Translate factor decimal part binary to decimal. (unit: 1/100)
Arguments:
BIN - the binary of decimal part
Return Value:
the decimal
Note:
Ex: 0b0001 1000 0000 0000 ==> 0.75
========================================================================
*/
UINT32 ACM_SurplusFactorDecimalBin2Dec(
ACM_PARAM_IN UINT32 BIN)
{
UINT32 ValueMax, Bit1Index, Base, ValueDec, ValueCarry;
UINT32 IdBitNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
#ifdef RELEASE_EXCLUDE
/* init */
/* ex1: 0b0001 1000 0000 0000 */
/* ex2: 0b0001 0000 0000 0000 */
/* ex3: 0b0000 0010 1110 0001 */
#endif /* RELEASE_EXCLUDE */
ValueMax = 1;
ValueMax <<= ACM_SURPLUS_DEC_BIT_NUM;
Bit1Index = ValueMax>>1;
Base = 0;
ValueDec = 0;
/* translate to decimal, unit: 1/(1<<ACM_SURPLUS_DEC_BIT_NUM) */
for(IdBitNum=0; IdBitNum<ACM_SURPLUS_DEC_BIT_NUM; IdBitNum++)
{
#ifdef RELEASE_EXCLUDE
/* 8192 = 2^13 */
/* ex1: decimal = 8192 + 4096 */
/* ex2: decimal = 8192 */
#endif /* RELEASE_EXCLUDE */
if (BIN & Bit1Index)
ValueDec += ValueMax >> Base;
/* End of if */
/* check next bit */
Bit1Index >>= 1;
Base ++;
} /* End of for */
#ifdef RELEASE_EXCLUDE
/* translate to decimal, unit: 1/ACM_SURPLUS_DEC_BASE */
/* ex1: decimal = 12288 * 100 / 8192 / 2 = 75 (i.e. 0.75) */
/* ex2: decimal = 8192 * 100 / 8192 / 2 = 50 */
#endif /* RELEASE_EXCLUDE */
ValueDec *= ACM_SURPLUS_DEC_BASE;
ValueCarry = ValueDec * 10;
ValueDec >>= ACM_SURPLUS_DEC_BIT_NUM;
ValueDec >>= 1;
ValueCarry >>= ACM_SURPLUS_DEC_BIT_NUM;
ValueCarry >>= 1;
/* check if we need to carry (>= 0.5) */
if ((ValueCarry - ValueDec*10) >= 5)
ValueDec ++;
/* End of if */
return ValueDec;
} /* End of ACM_SurplusFactorDecimalBin2Dec */
/*
========================================================================
Routine Description:
Translate factor decimal part decimal to binary.
Arguments:
DEC - the deciaml of decimal part, 00 ~ 99 (base 1/100)
Return Value:
the binary
Note:
Ex: 0.75 ==> 0b0001 1000 0000 0000
========================================================================
*/
STATIC UINT32 ACM_SurplusFactorDecimalDec2Bin(
ACM_PARAM_IN UINT32 DEC)
{
UINT32 ValueMax, Bin1Index, ValueBin;
UINT32 NumBit, TempValueDec;
UINT32 IdBitNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
#ifdef RELEASE_EXCLUDE
/* init */
/* ex1: 0.75, DEC = 75 */
/* ex2: 0.5, DEC = 50 */
/* ex3: 0.1, DEC = 10 */
/* ex4: 0.09, DEC = 9 */
#endif /* RELEASE_EXCLUDE */
Bin1Index = 1;
Bin1Index <<= (ACM_SURPLUS_DEC_BIT_NUM-1);
ValueBin = 0;
DEC = DEC % 100; /* 0.01 ~ 0.99 */
NumBit = 0;
ValueMax = 100;
/* translate to binary */
for(IdBitNum=0; IdBitNum<ACM_SURPLUS_DEC_BIT_NUM; IdBitNum++)
{
#ifdef RELEASE_EXCLUDE
/* DEC = DEC * 2 */
/* ex1: DEC = 150 */
/* ex2: DEC = 10 */
/* ex3: DEC = 2 */
#endif /* RELEASE_EXCLUDE */
DEC <<= 1;
#ifdef RELEASE_EXCLUDE
/* check if carry */
/* ex1: TempValueDec = 150/100 = 1
ValueBin = 0x1000
DEC = 50 */
/* ex2: TempValueDec = 10/10 = 1
ValueBin = 0x1000
DEC = 0 */
#endif /* RELEASE_EXCLUDE */
TempValueDec = DEC;
TempValueDec /= ValueMax;
if (TempValueDec)
{
ValueBin |= Bin1Index;
DEC -= ValueMax;
} /* End of if */
Bin1Index >>= 1;
} /* End of for */
return ValueBin;
} /* End of ACM_SurplusFactorDecimalDec2Bin */
/*
========================================================================
Routine Description:
Active a requested TSPEC and move it to the active table.
Arguments:
pAd - WLAN control block pointer
*pStreamReq - the requested TSPEC pointer
Return Value:
ACM_RTN_OK - active ok
ACM_RTN_FAIL - active fail
Note:
1. for QAP, the dnlink link TSPEC will be moved to the active
table; the bidirectional link TSPEC will be duplicated to
the active table & the client data base; otherwise to the
client data base;
2. for QSTA, the uplink or direct link TSPEC will be moved to
the active table; otherwise to the client data base;
3. If the requested TSPEC is a negotiation TSPEC, the old
TSPEC will be freed.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_Active(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStreamReq)
{
ACMR_STA_DB *pCdb;
ACM_ENTRY_INFO *pStaAcmInfo;
UINT32 Direction, AccessPolicy;
UCHAR FlgOutLink;
UCHAR StmAcId;
UCHAR TSID;
WMM_ACM_FUNC_NAME_PRINT("IN");
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> TC_Active()!\n"));
/* check whether current status of the request is DELETING */
if ((pStreamReq->Status == TSPEC_STATUS_REQ_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING))
{
/* rearrange the requested TSPEC */
ACM_TC_Rearrange(pAd, pStreamReq, ACM_MAX_NUM_OF_DELTS_RETRY);
return ACM_RTN_FAIL;
} /* End of if */
/* init */
pCdb = pStreamReq->pCdb;
FlgOutLink = 0; /* default input link */
AccessPolicy= pStreamReq->pTspec->TsInfo.AccessPolicy;
Direction = pStreamReq->pTspec->TsInfo.Direction;
StmAcId = 0; /* 0: BE */
/* determine if the link is output link */
if (ACMR_IS_AP_MODE(pAd))
{
/* QAP mode */
if ((Direction == ACM_DIRECTION_DOWN_LINK) ||
(Direction == ACM_DIRECTION_BIDIREC_LINK))
{
FlgOutLink = 1;
} /* End of if */
}
else
{
/* QSTA mode */
if ((Direction == ACM_DIRECTION_UP_LINK) ||
(Direction == ACM_DIRECTION_DIRECT_LINK) ||
(Direction == ACM_DIRECTION_BIDIREC_LINK))
{
FlgOutLink = 1;
} /* End of if */
} /* End of if */
/* backup the new stream */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
TSID = pStreamReq->pTspec->TsInfo.TSID;
if (FlgOutLink == 1)
{
/* assign actual AC queue ID */
StmAcId = ACM_MR_EDCA_AC(pStreamReq->UP);
pStreamReq->TxQueueType = ACM_TxQueueTypeGet(StmAcId);
/* backup output stream by TSID */
pStaAcmInfo->pAcStmOut[TSID] = (UCHAR *)pStreamReq;
/* for bidirectional link, we also backup it in input array by TSID */
/* for bidirectional link, FlgOutLink must be 1 */
if (Direction == ACM_DIRECTION_BIDIREC_LINK)
pStaAcmInfo->pAcStmIn[TSID] = (UCHAR *)pStreamReq;
/* End of if */
}
else
{
/* no transmit queue for input link */
pStreamReq->TxQueueType = ACM_TX_QUEUE_TYPE_NOT_EXIST;
/* backup input stream by TSID */
pStaAcmInfo->pAcStmIn[TSID] = (UCHAR *)pStreamReq;
} /* End of if */
/* change status to ACTIVE */
pStreamReq->FlgOutLink = FlgOutLink;
pStreamReq->Status = TSPEC_STATUS_ACTIVE;
/* statustics counter */
ACM_LINK_NUM_INCREASE(pAd, pStreamReq->pTspec->TsInfo.AccessPolicy, Direction);
/* count number of TSPEC */
ACM_NUM_OF_TSPEC_RECOUNT(pAd, pStreamReq->pCdb);
return ACM_RTN_OK;
} /* End of ACM_TC_Active */
/*
========================================================================
Routine Description:
Remove a activated TSPEC.
Arguments:
pAd - WLAN control block pointer
*pStream - the actived stream
Return Value:
None
Note:
"Activated" means the TSPEC is accepted, whatever dnlink or uplink or
bidirectional link.
========================================================================
*/
STATIC VOID ACM_TC_ActRemove(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACMR_STA_DB *pCdb;
ACM_ENTRY_INFO *pStaAcmInfo;
ACM_STREAM *pStmFree;
BOOLEAN FlgIsNeedToFree;
UCHAR TSID;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
pCdb = pStream->pCdb;
if (pCdb == NULL)
return;
/* End of if */
/* check if the request is from a actived stream */
FlgIsNeedToFree = 0;
if ((pStream->Status == TSPEC_STATUS_ACT_DELETING) ||
(pStream->Status == TSPEC_STATUS_RENEGOTIATING))
{
/* pStream is in request list so we will free other copys in
non-request lists */
FlgIsNeedToFree = 1;
} /* End of if */
/* reset the backup array for the stream */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
TSID = pStream->pTspec->TsInfo.TSID;
if (pStream->FlgOutLink)
pStmFree = (ACM_STREAM *)pStaAcmInfo->pAcStmOut[TSID];
else
pStmFree = (ACM_STREAM *)pStaAcmInfo->pAcStmIn[TSID];
/* End of if */
pStaAcmInfo->pAcStmOut[TSID] = NULL;
pStaAcmInfo->pAcStmIn[TSID] = NULL;
if (pStmFree == NULL)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> TSPEC == NULL! TC_ActRemove()\n"));
} /* End of if */
/* maybe free it */
if ((FlgIsNeedToFree) && (pStmFree != NULL))
ACM_TC_Free(pAd, pStmFree);
/* End of if */
} /* End of ACM_TC_ActRemove */
/*
========================================================================
Routine Description:
Delete a activated TSPEC.
Arguments:
pAd - WLAN control block pointer
*pStream - the activated stream
Return Value:
TRUE - Need to send out a DELTS frame
FALSE - No need to send out a DELTS frame
Note:
1. Send a DELTS to the QSTA or QAP.
2. Insert the activated TSPEC to the requested list.
3. The TSPEC will be moved to the failed list when DELTS ACK
is received or retry count is reached.
========================================================================
*/
STATIC BOOLEAN ACM_TC_Delete(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACM_STREAM *pTspecDup;
WMM_ACM_FUNC_NAME_PRINT("IN");
if ((pStream->Status == TSPEC_STATUS_REQ_DELETING) ||
(pStream->Status == TSPEC_STATUS_ACT_DELETING))
{
/* already in deleting state */
return FALSE;
} /* End of if */
if ((pStream->Status == TSPEC_STATUS_REQUEST) ||
(pStream->Status == TSPEC_STATUS_RENEGOTIATING))
{
/* only for QSTA mode: request TSPEC or renegotiate TSPEC */
ACM_TC_Req_ADDTS2DELTS(pAd, pStream);
goto label_check_timer_enable;
} /* End of if */
if ((pStream->Status == TSPEC_STATUS_ACTIVE) ||
(pStream->Status == TSPEC_STATUS_ACTIVE_SUSPENSION))
{
/* QAP or QSTA mode: actived TSPEC */
/*
Duplicate the stream, because we can not insert the stream to the
requested list directly; Or the pPrev & pNext will be modified in
ACM_TC_ReqInsert().
So we duplicate a same stream and put it to the request list.
If deletion is successfully, we will move the stream and the
duplicated one.
*/
pTspecDup = ACM_TC_Duplicate(pAd, pStream);
if (pTspecDup == NULL)
{
/* no enough memory, delete the stream at next time */
pStream->InactivityCur = ACM_STREAM_CHECK_BASE;
return FALSE;
} /* End of if */
/* change its state to deleting mode */
pTspecDup->Status = TSPEC_STATUS_ACT_DELETING;
pTspecDup->TimeoutAction = ACM_TC_TIMEOUT_ACTION_DELTS;
pTspecDup->Timeout = pStream->TimeoutDelts;
pTspecDup->Retry = ACM_MAX_NUM_OF_DELTS_RETRY;
/* insert the duplicated stream to the requested list */
if (ACM_TC_ReqInsert(pAd, pTspecDup) != ACM_RTN_OK)
{
/* insert fail (maybe already exist), free duplicate one */
ACM_TC_Free(pAd, pTspecDup);
/* delete the stream at next time */
pStream->InactivityCur = ACM_STREAM_CHECK_BASE;
}
else
{
/* insert ok so send a DELTS frame to peer */
/*
The new allocated stream is put into the request list so
we dont need to use the stream to send DELTS, we can use
pStream to send the DELTS frame.
*/
goto label_check_timer_enable;
} /* End of if */
} /* End of if */
return FALSE;
label_check_timer_enable:
/* enable request timeout check timer */
ACMR_TIMER_ENABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck,
ACM_STREAM_CHECK_OFFSET);
return TRUE;
} /* End of ACM_TC_Delete */
/*
========================================================================
Routine Description:
Move TSPEC active the the fail list.
Arguments:
pAd - WLAN control block pointer
*pStreamReq - the TSPEC pointer
FlgIsActiveExcluded - 1: do not delete active TSPEC
0: delete both request and active TSPEC
Return Value:
None
Note:
1. Put the TSPEC into the failed list. Not free it to OS kernel.
2. If pStreamReq belongs to a active TSPEC, we will delete the
both of request TSPEC and active TSPEC simulatenously.
========================================================================
*/
STATIC VOID ACM_TC_Destroy(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStreamReq,
ACM_PARAM_IN BOOLEAN FlgIsActiveExcluded)
{
ACM_TSPEC_REQ_LIST *pTspecFreedList;
ACM_STREAM *pTspecFree;
UINT32 Direction;
UCHAR FlgIsActStm;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check whether the request exists in the failed list */
FlgIsActStm = 0;
pTspecFreedList = &ACMR_CB->TspecListFail;
pTspecFree = pTspecFreedList->pHead;
while(pTspecFree != NULL)
{
if (AMR_IS_SAME_POINTER(pTspecFree, pStreamReq))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> already deleted! TC_Destroy()\n"));
return; /* already exists (same pointer) */
} /* End of if */
pTspecFree = pTspecFree->pNext;
} /* End of while */
/*
Remove the TSPEC from the requested list or the active table
For Status == TSPEC_STATUS_ACT_DELETING, we should delete it in the
requested list and the active table.
*/
if ((pStreamReq->Status == TSPEC_STATUS_REQUEST) ||
(pStreamReq->Status == TSPEC_STATUS_REQ_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_RENEGOTIATING))
{
/* remove it from the requested linked list */
ACM_TC_ReqRemove(pAd, pStreamReq);
} /* End of if */
if (FlgIsActiveExcluded == 0)
{
/* need also to delete active TSPEC */
if ((pStreamReq->Status == TSPEC_STATUS_ACTIVE) ||
(pStreamReq->Status == TSPEC_STATUS_ACTIVE_SUSPENSION) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING))
{
/* remove it from the active table linked list */
FlgIsActStm = 1; /* this is a active stream */
ACM_TC_ActRemove(pAd, pStreamReq);
} /* End of if */
} /* End of if */
/* change current status to fail */
pStreamReq->Status = TSPEC_STATUS_FAIL;
/* insert it to the failed list */
if (pTspecFreedList->TspecNum >= ACM_MAX_NUM_OF_FAIL_RSV_TSPEC)
{
/* free the first one (the oldest one) */
pTspecFree = pTspecFreedList->pHead;
if (pTspecFree == NULL)
{
/* fatal error: pHead == NULL but TspecNum > 0 */
pTspecFreedList->TspecNum = 0;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> pTspecFree == NULL! TC_Destroy()\n"));
}
else
{
pTspecFreedList->pHead = pTspecFree->pNext;
pTspecFree->pNext->pPrev = NULL;
pTspecFreedList->TspecNum --;
ACM_FREE_TS(pTspecFree);
} /* End of if */
} /* End of if */
/* insert the new failed TSPEC to the last one */
if (pTspecFreedList->pTail != NULL)
{
pTspecFreedList->pTail->pNext = pStreamReq;
pStreamReq->pPrev = pTspecFreedList->pTail;
pTspecFreedList->pTail = pStreamReq;
}
else
{
pTspecFreedList->pTail = pStreamReq;
pStreamReq->pPrev = NULL;
} /* End of if */
if (pTspecFreedList->pHead == NULL)
pTspecFreedList->pHead = pTspecFreedList->pTail;
/* End of if */
pStreamReq->pNext = NULL;
pTspecFreedList->TspecNum ++;
/* reclaim the used time of the stream */
if (FlgIsActStm)
{
/* only for ACTIVE stream */
ACM_EDCA_AllocatedTimeReturn(pAd, pStreamReq);
/* statistics counter */
Direction = pStreamReq->pTspec->TsInfo.Direction;
ACM_LINK_NUM_DECREASE(pAd,
pStreamReq->pTspec->TsInfo.AccessPolicy,
Direction);
/* delete peer device record if no any TSPEC exists for the peer */
if (pStreamReq->pCdb != NULL)
ACM_PeerDeviceMaintain(pAd, ACMR_CLIENT_MAC(pStreamReq->pCdb));
/* End of if */
/* recover the UAPSD state if the TSPEC is active TSPEC */
if (pStreamReq->pCdb != NULL)
{
ACM_APSD_Ctrl(pAd,
pStreamReq->pCdb,
ACM_MR_EDCA_AC(pStreamReq->UP),
Direction, 0, 0);
} /* End of if */
} /* End of if */
/* count number of TSPEC */
ACM_NUM_OF_TSPEC_RECOUNT(pAd, pStreamReq->pCdb);
} /* End of ACM_TC_Destroy */
/*
========================================================================
Routine Description:
Free a stream and do NOT move the failed TSPEC to the fail list.
Arguments:
pAd - WLAN control block pointer
*pStreamReq - the TSPEC pointer
Return Value:
None
Note:
1. Free the TSPEC silently. Do NOT put it to the failed list.
========================================================================
*/
STATIC VOID ACM_TC_Discard(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStreamReq)
{
ACMR_STA_DB *pCdb;
UCHAR FlgIsActStm;
UINT32 Direction;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FlgIsActStm = 0;
/*
Remove the TSPEC from the requested list or the active table
For Status == TSPEC_STATUS_ACT_DELETING, we should delete it in the
requested list and the active table.
*/
if ((pStreamReq->Status == TSPEC_STATUS_REQUEST) ||
(pStreamReq->Status == TSPEC_STATUS_REQ_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_RENEGOTIATING))
{
/* remove it from the requested list */
ACM_TC_ReqRemove(pAd, pStreamReq);
} /* End of if */
if ((pStreamReq->Status == TSPEC_STATUS_ACTIVE) ||
(pStreamReq->Status == TSPEC_STATUS_ACTIVE_SUSPENSION) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING))
{
/* also remove it from the active table */
FlgIsActStm = 1;
ACM_TC_ActRemove(pAd, pStreamReq);
} /* End of if */
/* reclaim the used time of the stream */
Direction = pStreamReq->pTspec->TsInfo.Direction;
if (FlgIsActStm == 1)
{
/* only for ACTIVE stream */
ACM_EDCA_AllocatedTimeReturn(pAd, pStreamReq);
/* statistics counter */
ACM_LINK_NUM_DECREASE(pAd,
pStreamReq->pTspec->TsInfo.AccessPolicy,
Direction);
/* delete peer device record if no any TSPEC for the peer */
if (pStreamReq->pCdb != NULL)
ACM_PeerDeviceMaintain(pAd, ACMR_CLIENT_MAC(pStreamReq->pCdb));
/* End of if */
} /* End of if */
#ifdef RELEASE_EXCLUDE
/* recover APSD state */ /* bug fixed in Test Event 3 */
#endif /* RELEASE_EXCLUDE */
if (pStreamReq->pCdb != NULL)
{
ACM_APSD_Ctrl(pAd, pStreamReq->pCdb,
ACM_MR_EDCA_AC(pStreamReq->UP), Direction, 0, 0);
} /* End of if */
/* free the stream */
pCdb = pStreamReq->pCdb;
ACM_TC_Free(pAd, pStreamReq);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Discard the TSPEC (out flag = %d) ok!\n",
FlgIsActStm));
/* count number of TSPEC */
if (pCdb != NULL)
ACM_NUM_OF_TSPEC_RECOUNT(pAd, pCdb);
/* End of if */
} /* End of ACM_TC_Discard */
/*
========================================================================
Routine Description:
Duplicate a stream.
Arguments:
pAd - WLAN control block pointer
*pStream - the source stream
Return Value:
the duplicate stream
Note:
========================================================================
*/
STATIC ACM_STREAM *ACM_TC_Duplicate(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACM_STREAM *pTspecDup;
#ifdef ACM_CC_FUNC_TCLAS
UINT32 IdTclasNum;
#endif /* ACM_CC_FUNC_TCLAS */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* allocate & copy the stream */
ACMR_MEM_ALLOC(pTspecDup, sizeof(ACM_STREAM), (ACM_STREAM *));
if (pTspecDup == NULL)
return NULL;
/* End of if */
ACMR_MEM_COPY(pTspecDup, pStream, sizeof(ACM_STREAM));
pTspecDup->pPrev = pTspecDup->pNext = NULL;
/* allocate & copy TSPEC */
ACMR_MEM_ALLOC(pTspecDup->pTspec, sizeof(ACM_TSPEC), (ACM_TSPEC *));
if (pTspecDup->pTspec == NULL)
{
ACMR_MEM_FREE(pTspecDup);
return NULL;
} /* End of if */
ACM_TSPEC_COPY(pTspecDup->pTspec, pStream->pTspec);
#ifdef ACM_CC_FUNC_TCLAS
/* allocate & copy TCLAS */
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
pTspecDup->pTclas[IdTclasNum] = NULL;
/* End of for */
for(IdTclasNum=0; IdTclasNum<ACM_TSPEC_TCLAS_MAX_NUM; IdTclasNum++)
{
if (pStream->pTclas[IdTclasNum] != NULL)
{
ACMR_MEM_ALLOC(pTspecDup->pTclas[IdTclasNum],
sizeof(ACM_TCLAS), (ACM_TCLAS *));
if (pTspecDup->pTclas[IdTclasNum] == NULL)
goto label_dup_err;
/* End of if */
ACM_TCLAS_COPY(pTspecDup->pTclas[IdTclasNum],
pStream->pTclas[IdTclasNum]);
} /* End of if */
} /* End of for */
#endif /* ACM_CC_FUNC_TCLAS */
return pTspecDup;
#ifdef ACM_CC_FUNC_TCLAS
label_dup_err:
ACM_FREE_TS(pTspecDup);
return NULL;
#endif /* ACM_CC_FUNC_TCLAS */
} /* End of ACM_TC_Duplicate */
/*
========================================================================
Routine Description:
Find a stream by TS Info.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the QSTA
*pTsInfo - the TS Info
Return Value:
the stream
Note:
1. the search sequence must be REQ --> CDB
2. we need STATION MAC information to compare because TS INFO can
be the same for two different QSTAs.
3. we only need pTsInfo->TSID to find a TS, other fields can be 0.
So you can NOT use the function to check if same TS exists.
========================================================================
*/
STATIC ACM_STREAM *ACM_TC_Find(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo)
{
ACM_STREAM *pStream;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (pDevMac == NULL)
return NULL;
/* End of if */
/* search the TSPEC in the requested list */
pStream = ACM_TC_FindInReq(pAd, pDevMac, pTsInfo);
if (pStream != NULL)
return pStream;
/* End of if */
/* search the TSPEC in the peer device database (input and output TSPEC) */
pStream = ACM_TC_FindInPeer(pAd, pDevMac, pTsInfo);
if (pStream != NULL)
return pStream;
/* End of if */
return NULL;
} /* End of ACM_TC_Find */
/*
========================================================================
Routine Description:
Find a stream in the peer record by TS Info.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the QSTA
*pTsInfo - the TS Info
Return Value:
the stream
Note:
========================================================================
*/
STATIC ACM_STREAM *ACM_TC_FindInPeer(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo)
{
ACM_STREAM *pStream;
ACM_STREAM **ppAcmStmList;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UINT32 IdTidNum, IdLinkNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (pDevMac == NULL)
return NULL;
/* End of if */
/* try to find it */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, pDevMac, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
continue;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
pStream = ppAcmStmList[IdTidNum];
while(pStream != NULL)
{
if (ACM_IS_SAME_TS_INFOP(&pStream->pTspec->TsInfo, pTsInfo))
{
/* same TS INFO so we find it */
return pStream;
} /* End of if */
/* only one TS for a direction/AC so the step can be skipped */
/* pStream->pNext should be always NULL */
pStream = pStream->pNext;
} /* End of while */
} /* End of for */
} /* End of for */
return NULL;
} /* End of ACM_TC_FindInPeer */
/*
========================================================================
Routine Description:
Find a stream in the requested list by TS Info.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the QSTA
*pTsInfo - the TS Info
Return Value:
the stream
Note:
========================================================================
*/
STATIC ACM_STREAM *ACM_TC_FindInReq(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo)
{
ACM_STREAM *pStream;
WMM_ACM_FUNC_NAME_PRINT("IN");
pStream = ACMR_CB->TspecListReq.pHead;
while(pStream != NULL)
{
if ((AMR_IS_SAME_MAC(ACMR_CLIENT_MAC(pStream->pCdb), pDevMac)) &&
(ACM_IS_SAME_TS_INFOP(&pStream->pTspec->TsInfo, pTsInfo)))
{
/* same peer and TS INFO so we find it */
return pStream;
} /* End of if */
pStream = pStream->pNext;
} /* End of while */
return NULL;
} /* End of ACM_TC_FindInReq */
/*
========================================================================
Routine Description:
Free a TSPEC.
Arguments:
pAd - WLAN control block pointer
*pStream - the stream
Return Value:
ACM_RTN_OK - free ok
ACM_RTN_FAIL - *pStream = NULL
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_Free(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (pStream == NULL)
return ACM_RTN_FAIL;
/* End of if */
/* free the TSPEC */
ACM_FREE_TS(pStream);
return ACM_RTN_OK;
} /* End of ACM_TC_Free */
/*
========================================================================
Routine Description:
Get the user priority.
Arguments:
*pTsInfo - the TS Info element
TclasNum - the number of TCLASS, max 5
*pTclas - the requested TCLASS array pointer
Return Value:
None
Note:
========================================================================
*/
STATIC UCHAR ACM_TC_UP_Get(
ACM_PARAM_IN ACM_TS_INFO *pTsInfo,
ACM_PARAM_IN UINT32 TclasNum,
ACM_PARAM_IN ACM_TCLAS *pTclas)
{
#ifdef ACM_CC_FUNC_TCLAS
if (TclasNum > 0)
return pTclas->UserPriority;
/* End of if */
#endif /* ACM_CC_FUNC_TCLAS */
return pTsInfo->UP;
} /* End of ACM_TC_UP_Get */
/*
========================================================================
Routine Description:
Rearrange a requested TSPEC in the request list.
Arguments:
pAd - WLAN control block pointer
*pReqNew - the requested TSPEC pointer
Retry - the retry count, base 0
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TC_Rearrange(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pReqNew,
ACM_PARAM_IN UINT16 Retry)
{
ACM_STREAM *pStmPrev, *pStmNext;
UINT32 TimeoutNew;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* reset the timeout & retry count */
switch(pReqNew->Status)
{
case TSPEC_STATUS_REQUEST:
/* the TSPEC is waiting for ADDTS response */
TimeoutNew = pReqNew->TimeoutAddts;
break;
case TSPEC_STATUS_REQ_DELETING:
case TSPEC_STATUS_ACT_DELETING:
/* the TSPEC is waiting for DELTS response */
TimeoutNew = pReqNew->TimeoutDelts;
break;
default:
return; /* error status */
} /* End of switch */
pReqNew->Retry = Retry;
/* check the number of requested TSPEC */
if (ACMR_CB->TspecListReq.TspecNum <= 1)
{
pReqNew->Timeout = TimeoutNew;
return; /* only a requested TSPEC, do NOT need to rearrange */
} /* End of if */
/* remove the requested TSPEC from the requested list */
if (pReqNew->pPrev == NULL)
{
/* the TSPEC is the first one */
pStmNext = pReqNew->pNext;
if (pStmNext == NULL)
{
/* fatal error: only one requested TSPEC but TspecNum != 1 */
/* prev = next = NULL */
ACMR_CB->TspecListReq.TspecNum = 1; /* fix the Tspec number */
pReqNew->Timeout = TimeoutNew;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> pNext == NULL! TC_Rearrange()\n"));
return;
} /* End of if */
/* adjust the timeout for next request */
pStmNext->Timeout += pReqNew->Timeout;
pStmNext->pPrev = NULL;
ACMR_CB->TspecListReq.pHead = pStmNext;
ACMR_CB->TspecListReq.TspecNum --;
}
else
{
/* the TSPEC is not the first one */
pStmPrev = pReqNew->pPrev;
pStmNext = pReqNew->pNext;
if (pStmNext == NULL)
{
/* the TSPEC is the last one so dont need to adjust timeout */
pStmPrev->pNext = NULL;
ACMR_CB->TspecListReq.pTail = pStmPrev;
ACMR_CB->TspecListReq.TspecNum --;
}
else
{
/* the TSPEC is not the first one or the last one */
pStmPrev->pNext = pStmNext;
pStmNext->pPrev = pStmPrev;
pStmNext->Timeout += pReqNew->Timeout;
ACMR_CB->TspecListReq.TspecNum --;
} /* End of if */
} /* End of if */
/* re-insert the requested TSPEC to the list */
pReqNew->Timeout = TimeoutNew;
ACM_TC_ReqInsert(pAd, pReqNew);
} /* End of ACM_TC_Rearrange */
/*
========================================================================
Routine Description:
Check whether the requested TSPEC is a renegotiation TSPEC.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the client MAC address
UP - the user priority of new stream
*pTsInfo - the TS Info element
**ppStreamIn - the old in TSPEC of same AC, can be NULL
**ppStreamOut - the old out TSPEC of same AC, can be NULL
**ppStreamDifAc - the old TSPEC of different AC, can be NULL
Return Value:
ACM_RTN_OK - renegotiation TSPEC in active table or database
ACM_RTN_RENO_IN_REQ_LIST- renegotiation TSPEC in the req list
ACM_RTN_FAIL - new TSPEC
ACM_RTN_FATAL_ERR - unexpected error occurred
Note:
Maximum 2 TS can be existed in a AC, such as a uplink TS and a dnlink TS.
04112008:
Spec. metions that "The admission of any TS with the same TID as an
existing TS deletes the existing TS and replaces it with the new TS,
even if the TSs are in different ACs"
So a new TSPEC can replace uplink TSPEC (same AC), dnlink TSPEC (same AC),
bilink (same AC), uplink/dnlink/bilink (different AC, same TID)
For example:
(exist) 1) VI, TID3, bi
2) VO, TID6, up
3) VO, TID7, dn
(new) VO, TID3, bi
==> delete all exist ones and use new one (VO, TID3, bi) in VO queue.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_RenegotiationCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN UCHAR UP,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo,
ACM_PARAM_OUT ACM_STREAM **ppStreamIn,
ACM_PARAM_OUT ACM_STREAM **ppStreamOut,
ACM_PARAM_OUT ACM_STREAM **ppStreamDifAc)
{
/* two TSPECs are the same when their TS Info are the same */
#define LMR_MEMCMP_RENE_TC(other_ts_info) \
ACM_IS_SAME_TS_INFOP(&other_ts_info, pTsInfo)
ACMR_STA_DB *pCdb;
ACM_STREAM *pStreamReq;
ACM_ENTRY_INFO *pStaAcmInfo;
BOOLEAN FlgIsFindSameTspec;
UINT32 IdTidNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FlgIsFindSameTspec = FALSE;
if (ppStreamIn != NULL)
*ppStreamIn = NULL;
/* End of if */
if (ppStreamOut != NULL)
*ppStreamOut = NULL;
/* End of if */
if (ppStreamDifAc != NULL)
*ppStreamDifAc = NULL;
/* End of if */
pCdb = ACMR_STA_ENTRY_GET(pAd, pDevMac);
if (pCdb == NULL)
return ACM_RTN_FATAL_ERR;
/* End of if */
/* check wether no any requested TSPEC exists */
if (ACMR_CB->TspecListReq.TspecNum <= 0)
{
/* no TSPEC requested list in QAP mode */
goto label_active_check;
} /* End of if */
/* find the TSPEC in requested list */
pStreamReq = ACMR_CB->TspecListReq.pHead;
while(pStreamReq != NULL)
{
if (pStreamReq->pTspec == NULL)
{
/* fatal error: TSPEC pointer is NULL, delete it */
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> TSPEC = NULL! TC_RenegotiationCheck()\n"));
}
else
{
/* check whether TS Info element is same */
if ((AMR_IS_SAME_MAC(ACMR_CLIENT_MAC(pStreamReq->pCdb), pDevMac)) &&
(LMR_MEMCMP_RENE_TC(pStreamReq->pTspec->TsInfo)))
{
/* find the original TSPEC in the request list */
return ACM_RTN_RENO_IN_REQ_LIST;
} /* End of if */
} /* End of if */
/* check next outstanding requested TSPEC */
pStreamReq = pStreamReq->pNext;
} /* End of while */
label_active_check:
/* check all existed output and input streams of the peer */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
/* find the TSPEC with same TID but different AC */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (pStaAcmInfo->pAcStmOut[IdTidNum] != NULL)
{
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmOut[IdTidNum];
/* same TID but different same AC ID */
if ((pStreamReq->pTspec->TsInfo.TSID == pTsInfo->TSID) &&
(ACM_MR_EDCA_AC(pStreamReq->UP) != ACM_MR_EDCA_AC(UP)))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Same OUT TS! Exist TSID = %d "
"dif UP = %d DIR = %d! "
"New TSID = %d UP = %d DIR = %d! "
"ACM_TC_RenegotiationCheck()\n",
pStreamReq->pTspec->TsInfo.TSID,
pStreamReq->UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->TSID,
UP,
pTsInfo->Direction));
FlgIsFindSameTspec = TRUE;
if (ppStreamDifAc != NULL)
*ppStreamDifAc = pStreamReq;
/* End of if */
/* only one possible stream with same TID and different AC */
break;
} /* End of if */
} /* End of if */
if (pStaAcmInfo->pAcStmIn[IdTidNum] != NULL)
{
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmIn[IdTidNum];
/* same TID but different same AC ID */
if ((pStreamReq->pTspec->TsInfo.TSID == pTsInfo->TSID) &&
(ACM_MR_EDCA_AC(pStreamReq->UP) != ACM_MR_EDCA_AC(UP)))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Same IN TS! Exist TSID = %d "
"dif UP = %d DIR = %d! "
"New TSID = %d UP = %d DIR = %d! "
"ACM_TC_RenegotiationCheck()\n",
pStreamReq->pTspec->TsInfo.TSID,
pStreamReq->UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->TSID,
UP,
pTsInfo->Direction));
FlgIsFindSameTspec = TRUE;
if (ppStreamDifAc != NULL)
*ppStreamDifAc = pStreamReq;
/* End of if */
/* only one possible stream with same TID and different AC */
break;
} /* End of if */
} /* End of if */
} /* End of for */
/* find the TSPEC with same TID or same AC */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (pStaAcmInfo->pAcStmOut[IdTidNum] != NULL)
{
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmOut[IdTidNum];
/* skip ppStreamDifAc */
if (ppStreamDifAc != NULL)
{
if (AMR_IS_SAME_POINTER(pStreamReq, (*ppStreamDifAc)))
continue;
/* End of if */
} /* End of if */
/* same TID or same AC ID */
if (ACM_IS_SAME_TS(pStreamReq->pTspec->TsInfo.TSID,
pTsInfo->TSID,
pStreamReq->UP,
UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->Direction))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Same OUT TS! Exist TSID = %d "
"UP = %d DIR = %d! "
"New TSID = %d UP = %d DIR = %d! "
"ACM_TC_RenegotiationCheck()\n",
pStreamReq->pTspec->TsInfo.TSID,
pStreamReq->UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->TSID,
UP,
pTsInfo->Direction));
FlgIsFindSameTspec = TRUE;
if (ppStreamOut != NULL)
*ppStreamOut = pStreamReq;
/* End of if */
if (pStreamReq->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK)
{
/* for bi-directional link, check once is enough */
return ACM_RTN_OK;
} /* End of if */
/* not return, try to find another input stream maybe */
} /* End of if */
} /* End of if */
if (pStaAcmInfo->pAcStmIn[IdTidNum] != NULL)
{
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmIn[IdTidNum];
/* skip ppStreamDifAc */
if (ppStreamDifAc != NULL)
{
if (AMR_IS_SAME_POINTER(pStreamReq, (*ppStreamDifAc)))
continue;
/* End of if */
} /* End of if */
/* same TID or same AC ID */
if (ACM_IS_SAME_TS(pStreamReq->pTspec->TsInfo.TSID,
pTsInfo->TSID,
pStreamReq->UP,
UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->Direction))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Same IN TS! Exist TSID = %d "
"UP = %d DIR = %d! "
"New TSID = %d UP = %d DIR = %d! "
"ACM_TC_RenegotiationCheck()\n",
pStreamReq->pTspec->TsInfo.TSID,
pStreamReq->UP,
pStreamReq->pTspec->TsInfo.Direction,
pTsInfo->TSID,
UP,
pTsInfo->Direction));
FlgIsFindSameTspec = TRUE;
if (ppStreamIn != NULL)
*ppStreamIn = pStreamReq;
/* End of if */
if (pStreamReq->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK)
{
/* for bi-directional link, check once is enough */
return ACM_RTN_OK;
} /* End of if */
/* not return, try to find another output stream maybe */
} /* End of if */
} /* End of if */
} /* End of for */
if (FlgIsFindSameTspec == TRUE)
return ACM_RTN_OK; /* find one */
/* End of if */
return ACM_RTN_FAIL;
} /* End of ACM_TC_RenegotiationCheck */
#ifdef ACM_CC_FUNC_REPLACE_RULE_TG
/*
========================================================================
Routine Description:
Check whether the replacement TSPEC can be accepted.
Arguments:
pAd - WLAN control block pointer
*pDevMac - the client MAC address
UP - the user priority of new stream
*pTsInfo - the TS Info element
Return Value:
ACM_RTN_OK - accept
ACM_RTN_FAIL - reject
ACM_RTN_FATAL_ERR - unexpected error occurred
Note:
We can not accept a replacement TSPEC from QSTA if
1. same TID, but not same AC; or
2. same TID, same AC, but not same Direction;
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_ReplacementCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pDevMac,
ACM_PARAM_IN UCHAR UP,
ACM_PARAM_IN ACM_TS_INFO *pTsInfo)
{
ACMR_STA_DB *pCdb;
ACM_STREAM *pStreamReq;
ACM_TS_INFO *pTsInfoOld;
ACM_ENTRY_INFO *pStaAcmInfo;
UINT32 IdTidNum, IdDirNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pCdb = ACMR_STA_ENTRY_GET(pAd, pDevMac);
if (pCdb == NULL)
return ACM_RTN_FATAL_ERR;
/* End of if */
pStaAcmInfo = ACMR_STA_ACM_PARAM_INFO(pCdb);
/* check for all TSPECs in input and output TSPECs */
for(IdDirNum=0; IdDirNum<2; IdDirNum++)
{
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (IdDirNum == 0)
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmOut[IdTidNum];
else
pStreamReq = (ACM_STREAM *)pStaAcmInfo->pAcStmIn[IdTidNum];
/* End of if */
if (pStreamReq != NULL)
{
pTsInfoOld = &pStreamReq->pTspec->TsInfo;
/* same TID but different same AC ID */
if ((pTsInfoOld->TSID == pTsInfo->TSID) &&
(ACM_MR_EDCA_AC(pStreamReq->UP) != ACM_MR_EDCA_AC(UP)))
{
/* match condition 1 */
return ACM_RTN_FAIL;
} /* End of if */
#if 0 /* rejected in WMM ACM discussion */
/* same TID/AC but different Direction */
if ((pTsInfoOld->Direction != ACM_DIRECTION_BIDIREC_LINK) &&
(pTsInfo->Direction != ACM_DIRECTION_BIDIREC_LINK))
{
if ((pTsInfoOld->TSID == pTsInfo->TSID) &&
(ACM_MR_EDCA_AC(pStreamReq->UP) == ACM_MR_EDCA_AC(UP)))
{
if (pTsInfoOld->Direction != pTsInfo->Direction)
{
/* match condition 2 */
return ACM_RTN_FAIL;
} /* End of if */
} /* End of if */
} /* End of if */
#endif
} /* End of if */
} /* End of for */
} /* End of for */
return ACM_RTN_OK;
} /* End of ACM_TC_ReplacementCheck */
#endif /* ACM_CC_FUNC_REPLACE_RULE_TG */
/*
========================================================================
Routine Description:
Change ADDTS state to DELTS state.
Arguments:
pAd - WLAN control block pointer
*pStreamReq - the requested TSPEC pointer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TC_Req_ADDTS2DELTS(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStreamReq)
{
WMM_ACM_FUNC_NAME_PRINT("IN");
/* change its state to deleting mode */
pStreamReq->Status = TSPEC_STATUS_REQ_DELETING;
pStreamReq->TimeoutAction = ACM_TC_TIMEOUT_ACTION_DELTS;
pStreamReq->Timeout = pStreamReq->TimeoutDelts;
pStreamReq->Retry = ACM_MAX_NUM_OF_DELTS_RETRY;
/* rearrange the requested TSPEC in the requested list */
ACM_TC_Rearrange(pAd, pStreamReq, ACM_MAX_NUM_OF_DELTS_RETRY);
} /* End of ACM_TC_Req_ADDTS2DELTS */
/*
========================================================================
Routine Description:
Check if another link or same link exists in the requested list.
Arguments:
pAd - WLAN control block pointer
*pStream - the requested or actived stream
Return Value:
ACM_RTN_EXIST - same link exists
ACM_RTN_NOT_EXIST - no same link exists
Note:
Same link means same TS info and same QSTA MAC.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_ReqCheck(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStream)
{
ACM_STREAM *pAcmStmList;
WMM_ACM_FUNC_NAME_PRINT("IN");
pAcmStmList = ACMR_CB->TspecListReq.pHead;
while(pAcmStmList != NULL)
{
/* check whether they are from same QSTA */
if (AMR_IS_SAME_POINTER(pAcmStmList->pCdb, pStream->pCdb))
{
/* check whether TSPEC is the same */
if (ACM_IS_SAME_TSPEC(pAcmStmList->pTspec, pStream->pTspec))
return ACM_RTN_EXIST;
/* End of if */
} /* End of if */
pAcmStmList = pAcmStmList->pNext;
} /* End of while */
return ACM_RTN_NOT_EXIST;
} /* End of ACM_TC_ReqCheck */
/*
========================================================================
Routine Description:
Free all requested TSPEC.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TC_ReqAllFree(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ACM_TSPEC_REQ_LIST *pStmReqList;
WMM_ACM_FUNC_NAME_PRINT("IN");
pStmReqList = &ACMR_CB->TspecListReq;
ACM_LIST_ALL_FREE(pAd, pStmReqList);
} /* End of ACM_TC_ReqAllFree */
/*
========================================================================
Routine Description:
Free requested TSPEC for the peer device.
Arguments:
pAd - WLAN control block pointer
*pCdb - the destination device entry
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TC_ReqDeviceFree(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
ACM_TSPEC_REQ_LIST *pStmReqList;
ACM_STREAM *pStreamReq, *pStreamReqNext;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pStmReqList = &ACMR_CB->TspecListReq;
pStreamReq = pStmReqList->pHead;
/* loop for all request TSPEC */
while(pStreamReq != NULL)
{
pStreamReqNext = pStreamReq->pNext;
/* check whether same device MAC */
if (AMR_IS_SAME_CDB(pStreamReq->pCdb, pCdb))
{
/* remove the request from the request list */
ACM_TC_ReqRemove(pAd, pStreamReq);
/* free it */
ACM_TC_Free(pAd, pStreamReq);
} /* End of if */
pStreamReq = pStreamReqNext;
} /* End of while */
} /* End of ACM_TC_ReqDeviceFree */
/*
========================================================================
Routine Description:
Insert a requested TSPEC to the request list.
Arguments:
pAd - WLAN control block pointer
*pReqNew - the requested TSPEC pointer
Return Value:
ACM_RTN_OK - insert ok
ACM_RTN_FAIL - insert fail
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_ReqInsert(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pReqNew)
{
ACM_TSPEC_REQ_LIST *pStmReqList;
ACM_STREAM *pStmReq;
ACM_STREAM *pStmSwapUse;
UINT32 NumTimeout;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pStmReqList = &ACMR_CB->TspecListReq;
pReqNew->pPrev = NULL;
pReqNew->pNext = NULL;
NumTimeout = 0;
/* insert */
if (pStmReqList->pHead == NULL)
{
/* no any outgoing requested TSPEC exists */
pStmReqList->pHead = pReqNew;
pStmReqList->pTail = pReqNew;
pStmReqList->TspecNum = 1;
}
else
{
/* check if the request exists */
if (ACM_TC_ReqCheck(pAd, pReqNew) == ACM_RTN_EXIST)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> req already exist!\n"));
return ACM_RTN_FAIL; /* the request already exists */
} /* End of if */
/* at least one outgoing requested TSPEC exists */
pStmReq = pStmReqList->pHead;
while(pStmReq != NULL)
{
/* calculate timeout sum */
NumTimeout += pStmReq->Timeout;
if (pReqNew->Timeout <= NumTimeout)
{
/* insert the new requested TSPEC */
/* adjust request timeout */
pReqNew->Timeout -= (NumTimeout - pStmReq->Timeout);
pStmReq->Timeout -= pReqNew->Timeout;
if (pStmReq->pPrev == NULL)
{
/* the old request is the first one */
pStmReqList->pHead = pReqNew;
pReqNew->pNext = pStmReq;
pStmReq->pPrev = pReqNew;
}
else
{
/* the old request is not the first one */
pStmSwapUse = pStmReq->pPrev;
pStmSwapUse->pNext = pReqNew;
pReqNew->pPrev = pStmSwapUse;
pReqNew->pNext = pStmReq;
pStmReq->pPrev = pReqNew;
} /* End of if */
/* a new requested TSPEC is added */
pStmReqList->TspecNum ++;
return ACM_RTN_OK;
} /* End of if */
/* move to next requested TSPEC */
pStmReq = pStmReq->pNext;
} /* End of while */
/* insert it to the last one */
pStmReq = pStmReqList->pTail;
pStmReq->pNext = pReqNew;
pReqNew->pPrev = pStmReq;
pStmReqList->pTail = pReqNew;
pReqNew->Timeout -= NumTimeout;
pStmReqList->TspecNum ++;
} /* End of if */
return ACM_RTN_OK;
} /* End of ACM_TC_ReqInsert */
/*
========================================================================
Routine Description:
Remove a requested TSPEC from the request list.
Arguments:
pAd - WLAN control block pointer
*pStreamReq - the requested TSPEC pointer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TC_ReqRemove(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACM_STREAM *pStreamReq)
{
ACM_TSPEC_REQ_LIST *pStmReqList;
ACM_STREAM *pAcmStmList;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pStmReqList = &ACMR_CB->TspecListReq;
pAcmStmList = pStmReqList->pHead;
/* check whether the request exists in the requested list */
while(pAcmStmList != NULL)
{
if (AMR_IS_SAME_POINTER(pAcmStmList, pStreamReq))
break; /* find it */
/* End of if */
pAcmStmList = pAcmStmList->pNext;
} /* End of while */
if (pAcmStmList == NULL)
{
/* fatal error, can NOT find the request */
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> The stream is not in the requested list! "
"TC_ReqRemove()\n"));
return;
} /* End of if */
/* remove it */
if (AMR_IS_SAME_POINTER(pStmReqList->pHead, pStreamReq))
{
/* the requested TSPEC is the first one */
if (AMR_IS_SAME_POINTER(pStmReqList->pTail, pStreamReq))
{
/* the requested TSPEC is also the last one */
pStmReqList->pHead = pStmReqList->pTail = NULL;
pStmReqList->TspecNum = 0;
return;
} /* End of if */
/* here, exist at least two requests */
pStmReqList->pHead = pStreamReq->pNext;
(pStreamReq->pNext)->pPrev = NULL;
(pStreamReq->pNext)->Timeout += pStreamReq->Timeout;
pStmReqList->TspecNum --;
return;
} /* End of if */
if (AMR_IS_SAME_POINTER(pStmReqList->pTail, pStreamReq))
{
/* the requested TSPEC is the last one */
pStmReqList->pTail = pStreamReq->pPrev;
(pStreamReq->pPrev)->pNext = NULL;
pStmReqList->TspecNum --;
return;
} /* End of if */
/* the requested TSPEC is not either the first one or the last one */
(pStreamReq->pPrev)->pNext = pStreamReq->pNext;
(pStreamReq->pNext)->pPrev = pStreamReq->pPrev;
(pStreamReq->pNext)->Timeout += pStreamReq->Timeout;
pStmReqList->TspecNum --;
} /* End of ACM_TC_ReqRemove */
/*
========================================================================
Routine Description:
Release all activated TSPECs without DELTS.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
Used in module remove only.
========================================================================
*/
STATIC VOID ACM_TC_ReleaseAll(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
ACM_TSPEC_REQ_LIST *pTspecFreedList;
ACM_STREAM **ppAcmStmList;
ACM_PEER_DEV_LIST *pAcmDevList;
UCHAR DirectionId[2] = \
{ ACM_PEER_TSPEC_OUTPUT_GET, ACM_PEER_TSPEC_INPUT_GET };
UCHAR MAC[ACM_MAC_ADDR_LEN];
UINT32 IdTidNum, IdLinkNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* sanity check */
if (ACMR_ADAPTER_DB == NULL)
return;
/* End of if */
/* clean all requested TSPEC if exists */
ACM_TC_ReqAllFree(pAd);
/* free all streams for all peer devices */
pAcmDevList = NULL; /* get first device */
while(1)
{
/* get next device */
if (ACM_PeerDeviceGetNext(pAd, &pAcmDevList, MAC) != ACM_RTN_OK)
break;
/* End of if */
/* delete all streams for device */
for(IdLinkNum=0; IdLinkNum<2; IdLinkNum++)
{
ppAcmStmList = (ACM_STREAM **)ACM_StationTspecListGet(
pAd, MAC, DirectionId[IdLinkNum]);
if (ppAcmStmList == NULL)
break;
/* End of if */
for(IdTidNum=0; IdTidNum<ACM_STA_TID_MAX_NUM; IdTidNum++)
{
if (ppAcmStmList[IdTidNum] != NULL)
{
if ((IdLinkNum != 0) &&
(ppAcmStmList[IdTidNum]->pTspec->TsInfo.Direction == \
ACM_DIRECTION_BIDIREC_LINK))
{
/*
We only backup one stream for IdLinkNum = 0
for bi-dir link so we can not free it twice.
*/
}
else
ACM_TC_Free(pAd, ppAcmStmList[IdTidNum]);
/* End of if */
/* empty the record */
ppAcmStmList[IdTidNum] = NULL;
} /* End of if */
} /* End of for */
} /* End of for */
} /* End of while */
/* free all backup peer device entries */
ACM_PeerDeviceAllFree(pAd);
/* free all failed streams in the failed list */
pTspecFreedList = &ACMR_CB->TspecListFail;
ACM_LIST_ALL_FREE(pAd, pTspecFreedList);
} /* End of ACM_TC_ReleaseAll */
/*
========================================================================
Routine Description:
Activate periodically.
Arguments:
Data
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_TASK_General(
ACM_PARAM_IN ULONG Data)
{
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
#if defined(ACM_CC_FUNC_MBSS) || defined(ACM_CC_FUNC_CHAN_UTIL_MONITOR)
BOOLEAN FlgIsAnyAcEnabled;
ULONG SplFlags;
FlgIsAnyAcEnabled = (ACMP_IsAnyACEnabled(pAd) == ACM_RTN_OK) ? TRUE : FALSE;
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
#endif /* ACM_CC_FUNC_MBSS || ACM_CC_FUNC_CHAN_UTIL_MONITOR */
pAd = pAd; /* avoid compile warning */
WMM_ACM_FUNC_NAME_PRINT("IN");
#ifdef ACM_CC_FUNC_MBSS
ACMR_CB->TimeoutMbssAcm ++;
if (ACMR_CB->TimeoutMbssAcm >= ACM_MBSS_BW_ANNONCE_TIMEOUT_NUM)
{
ACM_TC_TASK_BwAnn(Data);
ACMR_CB->TimeoutMbssAcm = 0;
} /* End of if */
#endif /* ACM_CC_FUNC_MBSS */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
#ifdef ACM_CC_FUNC_CHAN_UTIL_MONITOR
/* TODO: maybe we can check at least one TSPEC exist */
if (FlgIsAnyAcEnabled == TRUE)
{
/* only do the function when at least one AC ACM is set */
ACMR_CB->CU_MON_Timeout ++;
if (ACMR_CB->CU_MON_Timeout >= ACM_CH_MON_TIMEOUT_NUM)
{
ACM_TC_TASK_CU_Mon(Data);
ACMR_CB->CU_MON_Timeout = 0;
} /* End of if */
}
else
{
/* reset all parameters */
ACMR_CB->CU_MON_Timeout = 0;
ACMR_CB->CU_MON_FlgLastMode = ACM_CU_MON_MODE_RECOVER;
ACMR_CB->CU_MON_AdjustCount = 0;
ACMR_CB->CU_MON_AdjustNum = 0;
ACMR_CB->CU_MON_RecoverCount = 0;
ACMR_AIFSN_DEFAULT_GET(pAd, ACMR_CB->CU_MON_AifsnAp, ACMR_CB->CU_MON_AifsnBss);
ACMR_CB->CU_MON_FlgChangeNeed = 1;
} /* End of if */
#endif /* ACM_CC_FUNC_CHAN_UTIL_MONITOR */
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
#if defined(ACM_CC_FUNC_MBSS) || defined(ACM_CC_FUNC_CHAN_UTIL_MONITOR)
ACMR_TIMER_ENABLE(ACMR_CB->FlgTimerGeneralEnable,
ACMR_CB->TimerGeneral,
ACM_TIMER_GENERAL_PERIOD_TIMEOUT);
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#endif /* ACM_CC_FUNC_MBSS || ACM_CC_FUNC_CHAN_UTIL_MONITOR */
} /* End of ACM_TASK_General */
/*
========================================================================
Routine Description:
Check if TSPEC requests are timeout.
Arguments:
Data
Return Value:
None
Note:
For USB driver, we can not call ACM_DELTS_SEND() or ACM_ADDREQ_SEND()
in spin lock range, or we will fail in RTUSB_VendorRequest().
If you do spin lock first, in_interrupt() will be 1.
========================================================================
*/
STATIC VOID ACM_TASK_TC_ReqCheck(
ACM_PARAM_IN ULONG Data)
{
#define TASK_LMR_STREAM_DESTROY(pAd, pStreamReq, FlgIsActiveExcluded) \
StmAcId = pStreamReq->AcmAcId; \
ACM_TC_Destroy(pAd, pStreamReq, FlgIsActiveExcluded);
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
ACM_TSPEC_REQ_LIST *pStmReqList;
ACM_STREAM *pStreamReq, *pNext;
ACMR_LIST StreamList;
UCHAR StmAcId;
#ifdef CONFIG_STA_SUPPORT
UCHAR *pFrameBuf;
UINT32 FrameLen;
#endif /* CONFIG_STA_SUPPORT */
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
ACMR_LIST_INIT(&StreamList);
/* get management semaphore */
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* check if no any requested TSPEC exists */
pStmReqList = &ACMR_CB->TspecListReq;
if (pStmReqList->TspecNum == 0)
goto LabelDisableTimer;
/* End of if */
pStreamReq = pStmReqList->pHead;
if (pStreamReq == NULL)
goto LabelDisableTimer;
/* End of if */
/* sanity check for timeout of 1st requested TSPEC */
if (pStreamReq->Timeout <= 0)
{
/* error: the timeout == 0 */
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> timeout of 1st TSPEC == 0! "
"TC_TASK_ReqCheck()\n"));
/* reset timeout */
pStreamReq->Timeout = 1;
} /* End of if */
/* subtract 1 from timeout */
pStreamReq->Timeout --;
if (pStreamReq->Timeout > 0)
{
/* no timeout occurred */
goto LabelSemRelease;
} /* End of if */
/* handle TSPEC timeout */
while(pStreamReq != NULL)
{
/*
Backup next requested stream (must put here), because pStreamReq
maybe moved to the last one in the list by ACM_TC_Rearrange().
If pStreamReq is moved to the last one, the pStreamReq->pNext
will be NULL.
*/
pNext = pStreamReq->pNext;
/* init */
StmAcId = 0;
#ifdef CONFIG_STA_SUPPORT
pFrameBuf = NULL;
FrameLen = 0;
#endif /* CONFIG_STA_SUPPORT */
/* check retry count */
if (pStreamReq->Retry > 0)
{
/* subtract 1 from retry count */
pStreamReq->Retry --;
/* execute timeout action for the TSPEC (retransmit) */
switch(pStreamReq->TimeoutAction)
{
case ACM_TC_TIMEOUT_ACTION_DELTS:
/* re-send a DELTS frame! */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DELTS timeout! "
"TC_TASK_ReqCheck()\n"));
ACM_TC_Rearrange(pAd, pStreamReq, pStreamReq->Retry);
ACMR_LIST_ALLOC_AND_INSERT_TO_TAIL(pAd, &StreamList, pStreamReq);
break;
case ACM_TC_TIMEOUT_ACTION_ADDTS_REQ:
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* send ADDTS Request frame to QAP */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ADDTS timeout! "
"TC_TASK_ReqCheck()\n"));
/* make up ADDTS Request frame */
ACM_TC_Rearrange(pAd, pStreamReq, pStreamReq->Retry);
ACMR_LIST_ALLOC_AND_INSERT_TO_TAIL(pAd, &StreamList, pStreamReq);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
/* for QAP, the type is error type, so delete the request */
TASK_LMR_STREAM_DESTROY(pAd, pStreamReq, 0);
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
break;
default:
/* error timeout action, delete it */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> error timeout action! "
"TASK_TC_Req_Check()\n"));
TASK_LMR_STREAM_DESTROY(pAd, pStreamReq, 0);
break;
} /* End of switch */
}
else
{
/* reach retry limit count */
switch(pStreamReq->TimeoutAction)
{
case ACM_TC_TIMEOUT_ACTION_DELTS:
default:
/* we do not yet take care about ACK frame of DELTS */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* move to the fail list from the requested list */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DELTS tx limit! "
"Delete the request/active! "
"TC_TASK_ReqCheck()\n"));
/*
In STA, AP will not sleep so AP will receive the
DELTS frame.
Delete both of request TSPEC and active TSPEC.
*/
TASK_LMR_STREAM_DESTROY(pAd, pStreamReq, 0);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> DELTS tx limit! "
"Delete the request! "
"TC_TASK_ReqCheck()\n"));
/*
We can not delete activated TSPEC after DELTS
timeout in AP if PS STA does not use trigger frame
or PS-Poll frame to get the DELTS frame.
So we just only delete TSPEC request, not TSPEC
active.
EX: UAPSD of VO is enabled, all DELTS will be put
in VO queue. DELTS will not sent from AP if STA does
not send any trigger frame.
*/
TASK_LMR_STREAM_DESTROY(pAd, pStreamReq, 1);
} /* End of if */
#endif /* CONFIG_AP_SUPPORT */
break;
case ACM_TC_TIMEOUT_ACTION_ADDTS_REQ:
/* change to delts action in the requested list */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ADDTS timeout! "
"TC_TASK_ReqCheck()\n"));
ACM_TC_Req_ADDTS2DELTS(pAd, pStreamReq);
ACMR_LIST_ALLOC_AND_INSERT_TO_TAIL(pAd, &StreamList, pStreamReq);
break;
} /* End of switch */
} /* End of if */
/* check next requested TSPEC */
pStreamReq = pNext;
if ((pStreamReq != NULL) && (pStreamReq->Timeout > 0))
{
/* yet timeout for next request */
break;
} /* End of if */
} /* End of while */
LabelSemRelease:
#ifdef ACMR_HANDLE_IN_TIMER
/* schedule next time */
ACMR_TIMER_ENABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck,
ACM_STREAM_CHECK_OFFSET);
#endif /* ACMR_HANDLE_IN_TIMER */
/* release semaphore */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
/* send a action frame for each timeout stream */
while(1)
{
pStreamReq = (ACM_STREAM *)ACMR_LIST_REMOVE_FRM_HEAD(&StreamList);
if (pStreamReq == NULL)
break; /* no any more */
/* End of if */
if (pStreamReq->Retry > 0)
{
switch(pStreamReq->TimeoutAction)
{
case ACM_TC_TIMEOUT_ACTION_DELTS:
/* re-send a DELTS frame! */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TX a DELTS frame! "
"TC_TASK_ReqCheck()\n"));
ACM_DELTS_SEND(pAd, pStreamReq->pCdb, pStreamReq, LabelSemErr);
break;
case ACM_TC_TIMEOUT_ACTION_ADDTS_REQ:
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* send ADDTS Request frame to QAP */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TX a ADDTS! "
"TC_TASK_ReqCheck()\n"));
/* make up ADDTS Request frame */
ACM_ADDREQ_MAKEUP(pAd, pStreamReq->pCdb, pFrameBuf,
FrameLen, pStreamReq, LabelSemErr);
/* send ADDTS Request frame again */
if (FrameLen > 0)
{
ACM_ADDREQ_SEND(pAd, pFrameBuf, FrameLen);
} /* End of if */
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
/* nothing for AP mode */
break;
} /* End of switch */
}
else
{
/* reach retry limit count */
switch(pStreamReq->TimeoutAction)
{
case ACM_TC_TIMEOUT_ACTION_DELTS:
default:
/* nothing to do */
break;
case ACM_TC_TIMEOUT_ACTION_ADDTS_REQ:
/* change to delts action in the requested list */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TX a DELTS frame! "
"TC_TASK_ReqCheck()\n"));
ACM_DELTS_SEND(pAd, pStreamReq->pCdb, pStreamReq, LabelSemErr);
break;
} /* End of switch */
} /* End of if */
/* isolate the stream */
pStreamReq->pPrev = NULL;
pStreamReq->pNext = NULL;
/* free it */
ACM_TC_Free(pAd, pStreamReq);
} /* End of while */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* return power save right if possible */
ACMP_StaPsCtrlRightReturn(pAd);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return;
LabelDisableTimer:
#ifndef ACMR_HANDLE_IN_TIMER
/* give up schedule next time */
ACMR_TIMER_DISABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck);
#endif /* ACMR_HANDLE_IN_TIMER */
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* return power save right if possible */
ACMP_StaPsCtrlRightReturn(pAd);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACM_TASK_TC_ReqCheck */
/*
========================================================================
Routine Description:
Get IP information from the frame.
Arguments:
*pPkt - the IP header
*pTclas - the IP information
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TCLAS_IP_INFO_Get(
ACM_PARAM_IN UCHAR *pPkt,
ACM_PARAM_OUT ACM_TCLAS *pTclas)
{
ACM_IPHDR *pIpHdr;
UINT16 Type;
UINT16 *pPortSrc;
WMM_ACM_FUNC_NAME_PRINT("IN");
Type = *(UINT16 *)pPkt;
if (Type != ACMR_HTONS(0x0800)) /* 0800: IP packet type */
return ACM_RTN_FAIL;
/* End of if */
pIpHdr = (ACM_IPHDR *)(pPkt+2);
pTclas->Clasifier.IPv4.Version = pIpHdr->Version;
pTclas->Clasifier.IPv4.IpSource = pIpHdr->AddrSrc;
pTclas->Clasifier.IPv4.IpDest = pIpHdr->AddrDst;
pTclas->Clasifier.IPv4.DSCP = pIpHdr->TOS;
pTclas->Clasifier.IPv4.Protocol = pIpHdr->Protocol;
pPortSrc = (UINT16 *)((UCHAR *)pIpHdr + (pIpHdr->IHL<<2));
pTclas->Clasifier.IPv4.PortSource = *pPortSrc;
pTclas->Clasifier.IPv4.PortDest = *(pPortSrc+1);
return ACM_RTN_OK;
} /* End of ACM_TCLAS_IP_INFO_Get */
/*
========================================================================
Routine Description:
Get VLAN information from the frame.
Arguments:
*pPkt - the frame
*pVlanTag - the VLAN Tag of the frame
Return Value:
ACM_RTN_OK - get ok
ACM_RTN_FAIL - get fail
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TCLAS_VLAN_INFO_Get(
ACM_PARAM_IN UCHAR *pPkt,
ACM_PARAM_OUT UINT16 *pVlanTag)
{
UINT16 Type;
WMM_ACM_FUNC_NAME_PRINT("IN");
Type = *(UINT16 *)pPkt;
if (Type != ACMR_HTONS(0x8100)) /* 8100: VLAN packet type */
return ACM_RTN_FAIL;
/* End of if */
*pVlanTag = *(UINT16 *)(&pPkt[2]);
return ACM_RTN_OK;
} /* End of ACM_TCLAS_VLAN_INFO_Get */
/*
========================================================================
Routine Description:
Activate periodically.
Arguments:
Data
Return Value:
None
Note:
========================================================================
*/
VOID ACM_TR_TC_General(
ACM_PARAM_IN ULONG Data)
{
#ifndef ACMR_HANDLE_IN_TIMER
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
ULONG SplFlags;
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
ACMR_TASK_ACTIVATE(ACMR_CB->TaskletGeneral,
ACMR_CB->TimerGeneral,
ACM_TIMER_GENERAL_PERIOD_TIMEOUT);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#else
ACM_TASK_General(Data);
#endif /* ACMR_HANDLE_IN_TIMER */
} /* End of ACM_TR_TC_General */
/*
========================================================================
Routine Description:
Check whether TSPEC request is timeout.
If timeout, move it to the failure list.
Arguments:
Data
Return Value:
None
Note:
1. waked up every 100ms
2. for example, the request list is
timeout = 0 --> 0 --> 4 --> 6 --> 2
real timeout = 0ms, 0ms, 400ms, 1000ms, 1200ms
========================================================================
*/
VOID ACM_TR_TC_ReqCheck(
ACM_PARAM_IN ULONG Data)
{
#ifndef ACMR_HANDLE_IN_TIMER
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
ULONG SplFlags;
ACM_TSPEC_IRQ_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* sanity check for enable flag */
if (ACMR_CB->FlgTspecReqCheckEnable == 0)
{
ACMR_TIMER_DISABLE(ACMR_CB->FlgTspecReqCheckEnable,
ACMR_CB->TimerTspecReqCheck);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
} /* End of if */
/* inform TSPEC request check task */
ACMR_TASK_ACTIVATE(ACMR_CB->TaskletTspecReqCheck,
ACMR_CB->TimerTspecReqCheck,
ACM_STREAM_CHECK_OFFSET);
ACM_TSPEC_IRQ_UNLOCK(pAd, SplFlags, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
#else
ACM_TASK_TC_ReqCheck(Data);
#endif /* ACMR_HANDLE_IN_TIMER */
} /* End of ACM_TR_TC_ReqCheck */
/* ============================= Chan Util Monitor ====================== */
#ifdef CONFIG_AP_SUPPORT
#ifdef ACM_CC_FUNC_CHAN_UTIL_MONITOR
/*
========================================================================
Routine Description:
Adjust AIFSN of non-ACM AC when channel utilization is too high.
Arguments:
Data
Return Value:
None
Note:
To achieve the maximum throughput and short delay, CUmax should be
set in the range of 0.9 to 0.95 (RTS/CTS).
Where CUmax is maximum channel utilization.
Fast adjust and slow recover.
Protect in caller.
========================================================================
*/
STATIC VOID ACM_TC_TASK_CU_Mon(
ACM_PARAM_IN ULONG Data)
{
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
ACM_CTRL_PARAM *pEdcaParam;
UINT32 CUmax;
UINT32 IdAcNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pEdcaParam = &ACMR_CB->EdcaCtrlParam;
CUmax = (255 * ACM_CH_MON_CUMAX)/100;
/* handle new chan utilization */
if (ACMR_CHAN_UTILIZATION_GET(pAd) >= CUmax)
{
ACMR_CB->CU_MON_AdjustCount ++;
ACMR_CB->CU_MON_RecoverCount = 0;
}
else
{
ACMR_CB->CU_MON_AdjustCount = 0;
ACMR_CB->CU_MON_RecoverCount ++;
} /* End of if */
/* check if we need to adjust AIFSN of non-ACM AC */
if (ACMR_CB->CU_MON_AdjustCount >= ACM_CH_MON_ADJUST_NUM)
{
ACMR_CB->CU_MON_AdjustNum ++;
if (ACMR_CB->CU_MON_AdjustNum < ACM_CH_MON_MAX_ADJUST)
{
ACMR_CB->CU_MON_FlgLastMode = ACM_CU_MON_MODE_ADJUST;
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
if (pEdcaParam->FlgAcmStatus[IdAcNum] == 0)
{
if (ACMR_CB->CU_MON_AifsnAp[IdAcNum] < 0x0e)
{
ACMR_CB->CU_MON_FlgChangeNeed = 1;
ACMR_CB->CU_MON_AifsnAp[IdAcNum] += 2;
} /* End of if */
if (ACMR_CB->CU_MON_AifsnBss[IdAcNum] < 0x0e)
{
ACMR_CB->CU_MON_FlgChangeNeed = 1;
ACMR_CB->CU_MON_AifsnBss[IdAcNum] += 2;
} /* End of if */
if (ACMR_CB->CU_MON_FlgChangeNeed)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> chan busy, adjust AC%d...\n", IdAcNum));
} /* End of if */
} /* End of if */
} /* End of for */
} /* End of if */
ACMR_CB->CU_MON_AdjustCount = 0; /* re-check */
} /* End of if */
/* check if we need to recover AIFSN of non-ACM AC */
if (ACMR_CB->CU_MON_RecoverCount >= ACM_CH_MON_RECOVER_NUM)
{
UCHAR aifns_ap[ACM_DEV_NUM_OF_AC];
UCHAR aifns_bss[ACM_DEV_NUM_OF_AC];
ACMR_AIFSN_DEFAULT_GET(pAd, aifns_ap, aifns_bss);
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
if (pEdcaParam->FlgAcmStatus[IdAcNum] == 0)
{
if (ACMR_CB->CU_MON_AifsnAp[IdAcNum] > aifns_ap[IdAcNum])
{
ACMR_CB->CU_MON_FlgChangeNeed = 1;
ACMR_CB->CU_MON_AifsnAp[IdAcNum] --;
} /* End of if */
if (ACMR_CB->CU_MON_AifsnBss[IdAcNum] > aifns_bss[IdAcNum])
{
ACMR_CB->CU_MON_FlgChangeNeed = 1;
ACMR_CB->CU_MON_AifsnBss[IdAcNum] --;
} /* End of if */
if (ACMR_CB->CU_MON_FlgChangeNeed)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> chan idle, recover AC%d...\n", IdAcNum));
} /* End of if */
} /* End of if */
} /* End of for */
ACMR_CB->CU_MON_AdjustNum = 0;
ACMR_CB->CU_MON_RecoverCount = 0; /* re-check */
} /* End of if */
} /* End of ACM_TC_TASK_CU_Mon */
#endif /* ACM_CC_FUNC_CHAN_UTIL_MONITOR */
#endif /* CONFIG_AP_SUPPORT */
/* ============================= MBSS function ========================== */
/*
========================================================================
Routine Description:
Send a broadcast Bandwidth Annonce frame.
Arguments:
pAd - WLAN control block pointer
FlgIsForceToSent - 1: forece to send the frame
Return Value:
None
Note:
1. Carefully! This is a broadcast frame and must be non-encryption.
2. The frame is only sent by AP. STA only forward it.
3. AP A <--> AP B <--> AP C
AP B only need to broadcast its used ACM time, no AP A used time.
Because AP C does not see AP A.
========================================================================
*/
STATIC VOID ACM_FrameBwAnnSend(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR FlgIsForceToSent)
{
#ifdef ACM_CC_FUNC_MBSS
#ifdef CONFIG_AP_SUPPORT
ACM_CTRL_PARAM *pEdcaParam;
ACM_BW_ANN_FRAME *pFrameBwAnn;
ACMR_WLAN_HEADER HdrActionFrame;
ULONG FrameLen;
UCHAR *pBufFrame;
UCHAR MAC_BC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
UINT32 IdAcNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
FrameLen = 0;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Make up a BW ANN...\n"));
/* allocate a frame buffer */
if (ACMR_MGMT_FME_ALLOCATE(pAd, &pBufFrame) != NDIS_STATUS_SUCCESS)
return;
/* End of if */
/* make the frame header */
MgtMacHeaderInit(
pAd, &HdrActionFrame, SUBTYPE_ACTION, 0,
MAC_BC,
pAd->ApCfg.MBSSID[BSS0].Bssid);
ACMR_MEM_MAC_COPY(HdrActionFrame.Addr3, MAC_BC); /* BSSID = broadcast */
MakeOutgoingFrame(
pBufFrame, &FrameLen,
sizeof(ACMR_WLAN_HEADER), &HdrActionFrame,
END_OF_ARGS);
/* make the frame body */
pFrameBwAnn = (ACM_BW_ANN_FRAME *)&pBufFrame[FrameLen];
memset(pFrameBwAnn, 0, sizeof(ACM_BW_ANN_FRAME));
pFrameBwAnn->Category = ACM_CATEGORY_WME;
pFrameBwAnn->Action = ACM_ACTION_WME_BW_ANN;
/* sanity check */
pEdcaParam = &ACMR_CB->EdcaCtrlParam;
if (FlgIsForceToSent == FALSE)
{
if (ACMR_CB->AcmTotalTimeOld == pEdcaParam->AcmTotalTime)
goto LabelOK; /* same acm time, no need to announce */
/* End of if */
} /* End of if */
/* make the frame body */
pFrameBwAnn->MBSS.Identifier = ACMR_CB->MbssIdentifier++;
pFrameBwAnn->MBSS.Channel = ACMR_CHAN_GET(pAd);
ACMR_MEM_MAC_COPY(pFrameBwAnn->MBSS.BSSID, ACMR_AP_ADDR_GET(pAd));
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
pFrameBwAnn->MBSS.UsedTime[IdAcNum] = pEdcaParam->AcmAcTime[IdAcNum];
/* End of for */
/* backup total acm used time */
ACMR_CB->AcmTotalTimeOld = pEdcaParam->AcmTotalTime;
FrameLen += sizeof(ACM_BW_ANN_FRAME);
/* send out the frame and free it */
ACMR_MGMT_PKT_TX(pAd, pBufFrame, FrameLen);
MlmeFreeMemory(pAd, pBufFrame);
return;
LabelOK:
MlmeFreeMemory(pAd, pBufFrame);
return;
#endif /* CONFIG_AP_SUPPORT */
#endif /* ACM_CC_FUNC_MBSS */
return;
} /* End of ACM_FrameBwAnnSend */
#ifdef ACM_CC_FUNC_MBSS
/*
========================================================================
Routine Description:
Forward the bandwidth announce action frame.
Arguments:
pAd - WLAN control block pointer
*pMblk - the received frame
PktLen - the frame length
Return Value:
None
Note:
1. Only when ASSOC OK.
2. If the source is from our AP, forward it to broadcast;
3. If the source is not from our AP, forward it to our AP.
4. TODO: Can not encrypt the frame.
========================================================================
*/
STATIC VOID ACM_MBSS_BwAnnForward(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pMblk,
ACM_PARAM_IN UINT32 PktLen)
{
ACMR_WLAN_HEADER *pHeader;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (ACMR_IS_PORT_SECURE(pAd))
{
pHeader = (ACMR_WLAN_HEADER *)pMblk;
if (ACMR_MAC_CMP(pHeader->Addr2, ACMR_AP_ADDR_GET(pAd)) != 0)
{
/* from other BSS so translating to unicast frame to our AP */
ACMR_WLAN_PKT_RA_SET(pMblk, ACMR_AP_ADDR_GET(pAd));
ACMR_WLAN_PKT_BSSID_SET(pMblk, ACMR_AP_ADDR_GET(pAd));
} /* End of if */
ACMR_WLAN_PKT_TA_SET(pMblk, ACMR_SELF_MAC_GET(pAd));
ACMR_MGMT_PKT_TX(pAd, pMblk, PktLen);
} /* End of if */
} /* End of ACM_MBSS_BwAnnForward */
/*
========================================================================
Routine Description:
Handle the bandwidth announce action frame from other BSS.
Arguments:
pAd - WLAN control block pointer
Return Value:
ACM_RTN_OK - forward the frame
ACM_RTN_FAIL - do NOT forward the frame
Note:
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_MBSS_BwAnnHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UCHAR *pActFrame,
ACM_PARAM_IN UINT32 PktLen)
{
ACM_BW_ANN_FRAME *pFrameAnn;
ACM_MBSS_BW *pMbssNew, *pMbss;
UINT32 IdMbssNum;
UCHAR FlgIsNewAnn;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
pFrameAnn = (ACM_BW_ANN_FRAME *)pActFrame;
pMbssNew = &pFrameAnn->MBSS;
FlgIsNewAnn = 0;
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
pMbss = &ACMR_CB->MBSS[0];
/* learn it to our database */
for(IdMbssNum=0; IdMbssNum<ACM_MBSS_BK_NUM; IdMbssNum++)
{
/* TODO: Need check SSID ? */
if ((pMbssNew->Channel == pMbss->Channel) &&
(memcmp(pMbssNew->BSSID, pMbss->BSSID, 6) == 0))
{
/* this is from same channel and BSSID */
if (pMbssNew->Identifier != pMbss->Identifier)
{
/* new announce */
if ((pMbssNew->UsedTime[0] != pMbss->UsedTime[0]) ||
(pMbssNew->UsedTime[1] != pMbss->UsedTime[1]) ||
(pMbssNew->UsedTime[2] != pMbss->UsedTime[2]) ||
(pMbssNew->UsedTime[3] != pMbss->UsedTime[3]))
{
/* we regard as a new one only when different used time */
FlgIsNewAnn = 1;
} /* End of if */
} /* End of if */
break; /* find it */
} /* End of if */
pMbss ++; /* check next one */
} /* End of for */
if (IdMbssNum == ACM_MBSS_BK_NUM)
{
/* not found, new announce, try to find an empty entry */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> [mbss] New Ann from %02x:%02x:%02x:%02x:%02x:%02x\n",
pMbssNew->BSSID[0], pMbssNew->BSSID[1],
pMbssNew->BSSID[2], pMbssNew->BSSID[3],
pMbssNew->BSSID[4], pMbssNew->BSSID[5]));
pMbss = &ACMR_CB->MBSS[0];
for(IdMbssNum=0; IdMbssNum<ACM_MBSS_BK_NUM; IdMbssNum++)
{
if (pMbss->Channel == 0)
break;
/* End of if */
} /* End of for */
if (IdMbssNum == ACM_MBSS_BK_NUM)
return ACM_RTN_OK; /* My god! Too many BSS in the same channel */
/* End of if */
FlgIsNewAnn = 1;
} /* End of if */
/* update new used time */
ACMR_MEM_COPY(pMbss, pMbssNew, sizeof(ACM_MBSS_BW));
pMbss->Timeout = 0;
/* calculate total used time */
ACM_MBSS_BwReCalculate(pAd);
if (FlgIsNewAnn)
{
/* need to forward the announce frame */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> [mbss] Ann Time %d %d %d %d!\n",
pMbss->UsedTime[0], pMbss->UsedTime[1],
pMbss->UsedTime[2], pMbss->UsedTime[3]));
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_OK;
} /* End of if */
/* release semaphore */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* this is duplicated announce frame */
return ACM_RTN_FAIL;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return ACM_RTN_FAIL;
} /* End of ACM_MBSS_BwAnnHandle */
/*
========================================================================
Routine Description:
Re-calculate the used time for other BSS.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_MBSS_BwReCalculate(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
UINT32 IdMbssNum, IdAcNum;
WMM_ACM_FUNC_NAME_PRINT("IN");
ACMR_CB->MbssTotalUsedTime = 0;
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
ACMR_CB->MbssAcUsedTime[IdAcNum] = 0;
/* End of for */
for(IdMbssNum=0; IdMbssNum<ACM_MBSS_BK_NUM; IdMbssNum++)
{
if (memcmp(ACMR_CB->MBSS[IdMbssNum].BSSID, ACMR_SELF_MAC_GET(pAd), 6) != 0)
{
/* only for different BSS */
if (ACMR_CB->MBSS[IdMbssNum].Channel != 0)
{
/* valid entry */
for(IdAcNum=0; IdAcNum<ACM_DEV_NUM_OF_AC; IdAcNum++)
{
ACMR_CB->MbssTotalUsedTime += \
ACMR_CB->MBSS[IdMbssNum].UsedTime[IdAcNum];
ACMR_CB->MbssAcUsedTime[IdAcNum] += \
ACMR_CB->MBSS[IdMbssNum].UsedTime[IdAcNum];
} /* End of for */
} /* End of if */
} /* End of if */
} /* End of for */
} /* End of ACM_MBSS_BwReCalculate */
/*
========================================================================
Routine Description:
Broadcast our used bandwidth periodically.
Arguments:
Data
Return Value:
None
Note:
We need to inform other BSS our used ACM time because we share same
channel bandwidth.
========================================================================
*/
STATIC VOID ACM_TC_TASK_BwAnn(
ACM_PARAM_IN ULONG Data)
{
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Data;
UINT32 IdMbssNum;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* broadcast our bandwidth */
ACMP_FrameBwAnnSend(pAd, TRUE);
/* get management semaphore */
ACM_TSPEC_SEM_LOCK_CHK(pAd, SplFlags, LabelSemErr);
/* check admission time timeout from other BSS */
for(IdMbssNum=0; IdMbssNum<ACM_MBSS_BK_NUM; IdMbssNum++)
{
if (ACMR_CB->MBSS[IdMbssNum].Channel == 0)
continue; /* check next one */
/* End of if */
if (++ACMR_CB->MBSS[IdMbssNum].Timeout >= ACM_MBSS_ENTRY_TIMEOUT)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> [mbss] TimeOut %02x:%02x:%02x:%02x:%02x:%02x\n",
ACMR_CB->MBSS[IdMbssNum].BSSID[0],
ACMR_CB->MBSS[IdMbssNum].BSSID[1],
ACMR_CB->MBSS[IdMbssNum].BSSID[2],
ACMR_CB->MBSS[IdMbssNum].BSSID[3],
ACMR_CB->MBSS[IdMbssNum].BSSID[4],
ACMR_CB->MBSS[IdMbssNum].BSSID[5]));
ACMR_MEM_ZERO(&ACMR_CB->MBSS[IdMbssNum], sizeof(ACM_MBSS_BW));
} /* End of if */
} /* End of for */
/* re-calculate used time for other BSS */
ACM_MBSS_BwReCalculate(pAd);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return;
LabelSemErr:
ACMR_SEM_FAIL_PRINT();
return;
} /* End of ACM_TC_TASK_BwAnn */
#endif /* ACM_CC_FUNC_MBSS */
/* ============================= TX time function ========================== */
/*
========================================================================
Routine Description:
Calculate the QoS packet transmission time.
Arguments:
pAd - WLAN control block pointer
*pCdb - the connected client data base
BodyLen - the data length, not include WLAN header
RateIndex - transmission rate
FlgIsGmode - GMODE flag
FlgIsCtsEnable - CTS-self flag
FlgIsRtsEnable - RTS/CTS flag
FlgIsSpreambleUsed - Short preamble flag
FlgIsNoAckUsed - NO ACK flag
TxopLimit - TXOP limitation (microseconds)
*pTimeNoData - the tx time, not include data body
*pTimeHeader - the tx time, only include WLAN header
*pTimeCtsSelf - the tx time, CTS-self
*pTimeRtsCts - the tx time, RTS/CTS
*pTimeAck - the tx time, ACK
Return Value:
transmission time (miscro second, us)
Note:
1. Only for QoS packet.
2. If you want to get pTimeHeader only, BodyLen must not be 0.
========================================================================
*/
UINT32 ACM_TX_TimeCal(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UCHAR RateIndex,
ACM_PARAM_IN UCHAR FlgIsGmode,
ACM_PARAM_IN UCHAR FlgIsCtsEnable,
ACM_PARAM_IN UCHAR FlgIsRtsEnable,
ACM_PARAM_IN UCHAR FlgIsSpreambleUsed,
ACM_PARAM_IN UCHAR FlgIsNoAckUsed,
ACM_PARAM_IN UINT32 TxopLimit,
ACM_PARAM_OUT UINT32 *pTimeNoData,
ACM_PARAM_OUT UINT32 *pTimeHeader,
ACM_PARAM_OUT UINT32 *pTimeCtsSelf,
ACM_PARAM_OUT UINT32 *pTimeRtsCts,
ACM_PARAM_OUT UINT32 *pTimeAck)
{
#ifdef RELEASE_EXCLUDE
/*
For G mode, no long or short preamble time, only long (20us) or
short slot time (9us).
*/
#endif /* RELEASE_EXCLUDE */
#define LMR_PREAMBL_TIME(__FlgIsGmode, __FlgIsSpreamble, __Time) \
{ \
if (__FlgIsGmode == 0) \
{ \
if (__FlgIsSpreamble == 0) \
__Time += TIME_LONG_PREAMBLE; \
else \
__Time += TIME_SHORT_PREAMBLE; \
} \
else \
__Time += 20; \
}
UINT32 LenHeader;
UINT32 RateId;
UINT32 TxTime;
#ifndef ACM_CC_FUNC_SOFT_ACM
UINT32 TxTimeFragment;
#endif /* ACM_CC_FUNC_SOFT_ACM */
UINT32 TimeHeader, TimeData, TimeFrag, TimeRtsCts;
UINT32 TxTimeCtsSelf, TxTimeRtsCts, TxTimeAck;
UINT32 DataExtraLen, LenFrag, LenLastFrag, NumFrag;
UCHAR FlgIsNeedHardwareFrag;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
LenHeader = ACMR_FME_QOS_HEADER_SIZE + 4; /* 4: FCS size */
TxTime = 0;
TimeRtsCts = 0;
TxTimeCtsSelf = 0;
TxTimeRtsCts = 0;
TxTimeAck = 0;
TimeHeader = 0;
/* CTS-self */
if (FlgIsCtsEnable == 1)
{
/* tx time += preamble + CTS-self + SIFS */
TxTimeCtsSelf = 0;
switch(RateIndex)
{
case ACM_RATE_54M:
RateId = ACM_RATE_ID_54M;
break;
case ACM_RATE_48M:
RateId = ACM_RATE_ID_48M;
break;
case ACM_RATE_36M:
RateId = ACM_RATE_ID_36M;
break;
case ACM_RATE_24M:
RateId = ACM_RATE_ID_24M;
break;
case ACM_RATE_18M:
RateId = ACM_RATE_ID_18M;
break;
case ACM_RATE_12M:
RateId = ACM_RATE_ID_12M;
break;
case ACM_RATE_9M:
RateId = ACM_RATE_ID_9M;
break;
case ACM_RATE_6M:
RateId = ACM_RATE_ID_6M;
break;
case ACM_RATE_11M:
RateId = ACM_RATE_ID_11M;
break;
case ACM_RATE_5_5M:
RateId = ACM_RATE_ID_5_5M;
break;
case ACM_RATE_2M:
RateId = ACM_RATE_ID_2M;
break;
case ACM_RATE_1M:
RateId = ACM_RATE_ID_1M;
break;
default:
RateId = ACM_RATE_ID_1M;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> RateIndex Error! TX_TimeCal()\n"));
break;
} /* End of switch */
LMR_PREAMBL_TIME(FlgIsGmode, FlgIsSpreambleUsed, TxTimeCtsSelf);
TxTimeCtsSelf += \
ACM_TX_TimePlcpCal(FRM_LENGTH_ACK, RateId, FlgIsGmode);
TxTimeCtsSelf += TIME_SIFSG;
if (pTimeCtsSelf != NULL)
*pTimeCtsSelf = TxTimeCtsSelf;
/* End of if */
} /* End of if */
/* RTS and CTS */
if ((FlgIsCtsEnable == 0) && (FlgIsRtsEnable == 1))
{
/* tx time += preamble + RTS + SIFS + preamble + CTS + SIFS */
LMR_PREAMBL_TIME(FlgIsGmode, FlgIsSpreambleUsed, TimeRtsCts);
LMR_PREAMBL_TIME(FlgIsGmode, FlgIsSpreambleUsed, TimeRtsCts);
switch(RateIndex)
{
case ACM_RATE_54M:
case ACM_RATE_48M:
case ACM_RATE_36M:
case ACM_RATE_24M:
TimeRtsCts += TIME_SIFSGx2;
RateId = ACM_RATE_ID_24M;
break;
case ACM_RATE_18M:
case ACM_RATE_12M:
TimeRtsCts += TIME_SIFSGx2;
RateId = ACM_RATE_ID_12M;
break;
case ACM_RATE_9M:
case ACM_RATE_6M:
TimeRtsCts += TIME_SIFSGx2;
RateId = ACM_RATE_ID_6M;
break;
case ACM_RATE_11M:
TimeRtsCts += TIME_SIFSx2;
RateId = ACM_RATE_ID_11M;
break;
case ACM_RATE_5_5M:
TimeRtsCts += TIME_SIFSx2;
RateId = ACM_RATE_ID_5_5M;
break;
case ACM_RATE_2M:
TimeRtsCts += TIME_SIFSx2;
RateId = ACM_RATE_ID_2M;
break;
case ACM_RATE_1M:
TimeRtsCts += TIME_SIFSx2;
RateId = ACM_RATE_ID_1M;
break;
default:
TimeRtsCts += TIME_SIFSx2;
RateId = ACM_RATE_ID_1M;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> RateIndex Error! TX_TimeCal()\n"));
break;
} /* End of switch */
TimeRtsCts += ACM_TX_TimePlcpCal(FRM_LENGTH_RTS, RateId, FlgIsGmode);
TimeRtsCts += ACM_TX_TimePlcpCal(FRM_LENGTH_ACK, RateId, FlgIsGmode);
if (pTimeRtsCts != NULL)
*pTimeRtsCts = TimeRtsCts;
/* End of if */
} /* End of if */
/* SIFS + preamble + ACK */
if (FlgIsNoAckUsed == 0)
{
TxTimeAck = 0;
LMR_PREAMBL_TIME(FlgIsGmode, FlgIsSpreambleUsed, TxTimeAck);
switch(RateIndex)
{
case ACM_RATE_54M:
case ACM_RATE_48M:
case ACM_RATE_36M:
case ACM_RATE_24M:
TxTimeAck += TIME_SIFSG;
RateId = ACM_RATE_ID_24M;
break;
case ACM_RATE_18M:
case ACM_RATE_12M:
TxTimeAck += TIME_SIFSG;
RateId = ACM_RATE_ID_12M;
break;
case ACM_RATE_9M:
case ACM_RATE_6M:
TxTimeAck += TIME_SIFSG;
RateId = ACM_RATE_ID_6M;
break;
case ACM_RATE_11M:
TxTimeAck += TIME_SIFS;
RateId = ACM_RATE_ID_11M;
break;
case ACM_RATE_5_5M:
TxTimeAck += TIME_SIFS;
RateId = ACM_RATE_ID_5_5M;
break;
case ACM_RATE_2M:
TxTimeAck += TIME_SIFS;
RateId = ACM_RATE_ID_2M;
break;
case ACM_RATE_1M:
TxTimeAck += TIME_SIFS;
RateId = ACM_RATE_ID_1M;
break;
default:
TxTimeAck += TIME_SIFS;
RateId = ACM_RATE_ID_1M;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> RateIndex Error! TX_TimeCal()\n"));
break;
} /* End of switch */
/*
EX: data size = 208B, rate = 54Mbps,
TxTimeAck = 44us in A band.
*/
TxTimeAck += ACM_TX_TimePlcpCal(FRM_LENGTH_ACK, RateId, FlgIsGmode);
}
else
{
/* use NO ACK policy so ack time = 0 */
TxTimeAck = 0;
} /* End of if */
if (pTimeAck != NULL)
*pTimeAck = TxTimeAck;
/* End of if */
if (BodyLen > 0)
{
/* preamble + Data */
switch(RateIndex)
{
case ACM_RATE_54M:
RateId = ACM_RATE_ID_54M;
break;
case ACM_RATE_48M:
RateId = ACM_RATE_ID_48M;
break;
case ACM_RATE_36M:
RateId = ACM_RATE_ID_36M;
break;
case ACM_RATE_24M:
RateId = ACM_RATE_ID_24M;
break;
case ACM_RATE_18M:
RateId = ACM_RATE_ID_18M;
break;
case ACM_RATE_12M:
RateId = ACM_RATE_ID_12M;
break;
case ACM_RATE_9M:
RateId = ACM_RATE_ID_9M;
break;
case ACM_RATE_6M:
RateId = ACM_RATE_ID_6M;
break;
case ACM_RATE_11M:
RateId = ACM_RATE_ID_11M;
break;
case ACM_RATE_5_5M:
RateId = ACM_RATE_ID_5_5M;
break;
case ACM_RATE_2M:
RateId = ACM_RATE_ID_2M;
break;
case ACM_RATE_1M:
RateId = ACM_RATE_ID_1M;
break;
default:
RateId = ACM_RATE_ID_1M;
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> RateIndex Error! TX_TimeCal()\n"));
break;
} /* End of switch */
/* add data preamble tx time */
/*
EX: data size = 208B, rate = 54Mbps,
LenHeader = 30B, TimeHeader = 28us in A band.
*/
LMR_PREAMBL_TIME(FlgIsGmode, FlgIsSpreambleUsed, TimeHeader);
TimeHeader += ACM_TX_TimePlcpCal(LenHeader, RateId, FlgIsGmode);
/* maybe software fragment */
if (TxopLimit > 0)
{
/* check whether tx time > txop limit */
LenFrag = ACMR_FRG_THRESH(pAd);
if ((LenFrag == 0) || (BodyLen <= LenFrag))
{
/* no fragment is needed */
LenFrag = BodyLen;
FlgIsNeedHardwareFrag = 0;
}
else
{
/* fragment is needed */
FlgIsNeedHardwareFrag = 1;
} /* End of if */
/* LenFrag = total len (no fragment) or fragment len */
/* calculate data body transmission time */
DataExtraLen = ACM_EncryptExtraLenGet(pAd, pCdb);
TimeData = ACM_TX_TimePlcpCal(LenFrag+DataExtraLen, RateId, FlgIsGmode);
/* calculate all transmission time */
if (FlgIsRtsEnable == 1)
TxTimeRtsCts = TimeRtsCts; /* need RTS/CTS */
else
TxTimeRtsCts = 0;
/* End of if */
/* pre-sum CTS-self "or" (not "and") RTS/CTS tx time */
TxTime = TxTimeCtsSelf + TxTimeRtsCts;
if (FlgIsNeedHardwareFrag == 1)
{
/*
Calculate all fragment tx time because our ASIC can not
distribute fragment to different TXOP.
*/
NumFrag = BodyLen/ LenFrag;
TxTime += (TimeHeader + TimeData + TxTimeAck) * NumFrag;
LenLastFrag = BodyLen % LenFrag;
if (LenLastFrag > 0)
{
/* sum the last fragment tx time */
TimeData = ACM_TX_TimePlcpCal(LenLastFrag+DataExtraLen,
RateId, FlgIsGmode);
TxTime += TimeHeader + TimeData + TxTimeAck;
} /* End of if */
}
else
{
/* only a packet, no fragment */
TxTime += (TimeHeader + TimeData + TxTimeAck);
} /* End of if */
/* check whether tx time > TXOP limitation */
#ifndef ACM_CC_FUNC_SOFT_ACM
if (TxTime > TxopLimit)
{
/* we need to do software fragment, calculate residant TXOP */
/* MUST no hardware fragment */
TxTime = (TxTimeCtsSelf + TxTimeRtsCts +
TimeHeader + TxTimeAck);
if (TxopLimit > TxTime)
{
if (FlgIsNeedHardwareFrag == 0)
{
TxopLimit -= (TxTimeCtsSelf + TxTimeRtsCts +
TimeHeader + TxTimeAck);
}
else
{
/* calculate a fragment tx time */
TxTimeFragment = TimeHeader+TimeData+TxTimeAck;
/* dont care about CTS-Self or RTS/CTS tx time */
TxopLimit -= (TxTimeCtsSelf + TxTimeRtsCts);
if (TxTimeFragment > TxopLimit)
{
/*
A fragment tx time > TXOP limit
so do need to do fragment, we must make a
packet len <= fragment threshold.
*/
TxopLimit -= (TimeHeader + TxTimeAck);
}
else
{
/*
We can not use the LenFrag as software fragment
length, when >= 2 fragments can be transmitted
in a TXOP, maybe another MSDU and our fragment
is transmitted in a TXOP or our both fragments
are transmitted in a TXOP, we can not predict
the case.
*/
TxopLimit -= (TimeHeader + TxTimeAck);
} /* End of if */
} /* End of if */
/* calculate packet len allowed to be transmitted in a TXOP */
if (FlgIsGmode == 1)
{
LenFrag = TxopLimit>>2;
LenFrag = (LenFrag<<1)*RateIndex;
if (LenFrag > 22)
LenFrag = (LenFrag-22)>>3;
/* End of if */
}
else
LenFrag = ((TxopLimit*RateIndex)>>4);
/* End of if */
if (LenFrag >= DataExtraLen)
{
LenFrag -= DataExtraLen;
if (LenFrag > 1)
LenFrag --; /* for safe */
/* End of if */
/* for software fragment, we dont need 128-double */
} /* End of if */
}
else
{
/*
Fatal error, txop limit is too small.
So dont care txop limit and transmit the packet without
fragment.
*/
LenFrag = BodyLen;
} /* End of if */
} /* End of if */
#endif /* ACM_CC_FUNC_SOFT_ACM */
/*
Calculate MSDU exchange time, LenFrag is the packet length
allowed to transmitted in a TXOP.
*/
if (LenFrag == BodyLen)
{
/* no fragment is needed */
TimeData = ACM_TX_TimePlcpCal(BodyLen+DataExtraLen,
RateId, FlgIsGmode);
/* sum all tx time */
TxTime = TxTimeCtsSelf + TxTimeRtsCts;
TxTime += TimeHeader + TxTimeAck;
}
else
{
/* fragment is needed */
/* LenFrag = a software fragment length in a TXOP */
TimeFrag = ACM_TX_TimePlcpCal(LenFrag+DataExtraLen,
RateId, FlgIsGmode);
NumFrag = BodyLen/ LenFrag;
LenLastFrag = BodyLen % LenFrag;
if (LenFrag <= ACMR_RTS_THRESH(pAd))
TxTimeRtsCts = 0; /* no RTS/CTS is needed for new len */
/* End of if */
/* add other fragment tx time except the tail fragment */
if (NumFrag >= 1)
{
TimeData = (TxTimeCtsSelf + TxTimeRtsCts +
TimeHeader + TimeFrag +
TxTimeAck) * NumFrag;
} /* End of if */
/* add tail fragment tx time */
if (LenLastFrag > 0)
{
TimeData += (TxTimeCtsSelf + TxTimeRtsCts +
TimeHeader + TxTimeAck);
TimeData += ACM_TX_TimePlcpCal(LenLastFrag+DataExtraLen,
RateId, FlgIsGmode);
} /* End of if */
/* tx time is included in TimeData */
TxTime = 0;
} /* End of if */
}
else
{
/* add data tx time */
/*
EX: data size = 208B, rate = 54Mbps,
TimeData without header = 32us in A band.
*/
if (BodyLen > 0)
{
DataExtraLen = ACM_EncryptExtraLenGet(pAd, pCdb);
TimeData = ACM_TX_TimePlcpCal(BodyLen+DataExtraLen,
RateId, FlgIsGmode);
}
else
TimeData = 0;
/* End of if */
/* sum all tx time */
TxTime = TxTimeCtsSelf + TxTimeRtsCts;
TxTime += TimeHeader + TxTimeAck;
} /* End of if */
}
else
TimeData = 0;
/* End of if */
if (pTimeNoData != NULL)
*pTimeNoData = TxTime;
/* End of if */
if (pTimeHeader != NULL)
*pTimeHeader = TimeHeader;
/* End of if */
TxTime += TimeData;
/*
EX1: data size = 208B, rate = 54Mbps,
TxTime = 104us in A band.
EX2: data size = 208B, rate = 6Mbps,
In A band, TxTimeAck = 60us, TimeHeader = 64us,
TimeData = 284us, so TxTime = 64+284+60 = 408us.
*/
return TxTime;
} /* End of ACM_TX_TimeCal */
#ifdef ACM_CC_FUNC_11N
/*
========================================================================
Routine Description:
Calculate the QoS packet transmission time for HT rate.
Arguments:
pAd - WLAN control block pointer
*pCdb - the connected client data base
BodyLen - the data length, not include WLAN header
McsId - transmission MCS
BwId - 20 or 20/40MHz
GIId - regular or short GI
FlgIsRtsEnable - RTS/CTS flag
FlgIsNoAckUsed - NO ACK flag
FlgIsOnlyData - 1: no HT preamble time
TxopLimit - TXOP limitation (microseconds)
FlgIsAmsdu - 1: the MSDU is belong to AMSDU
NominalAggSize - number of MSDUs in a aggregation
*pTimeNoData - the tx time, not include data body
*pTimeHeader - the tx time, only include WLAN header
*pTimeAck - the tx time, BLOCK ACK
*pTimeDataHdrOnly - the tx time, data + BLOCK ACK
*pTimeDataOnly - the tx time, data
Return Value:
transmission time (miscro second, us)
Note:
1. Only for QoS packet.
2. No HT rate for RTS/CTS.
========================================================================
*/
UINT32 ACM_TX_TimeCalHT(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UINT32 McsId,
ACM_PARAM_IN UINT32 BwId,
ACM_PARAM_IN UINT32 GIId,
ACM_PARAM_IN BOOLEAN FlgIsRtsEnable,
ACM_PARAM_IN BOOLEAN FlgIsNoAckUsed,
ACM_PARAM_IN BOOLEAN FlgIsOnlyData,
ACM_PARAM_IN UINT32 TxopLimit,
ACM_PARAM_IN BOOLEAN FlgIsAmsdu,
ACM_PARAM_IN UINT16 NominalAggSize,
ACM_PARAM_OUT UINT32 *pTimeNoData,
ACM_PARAM_OUT UINT32 *pTimeHeader,
ACM_PARAM_OUT UINT32 *pTimeAck,
ACM_PARAM_OUT UINT32 *pTimeDataHdrOnly,
ACM_PARAM_OUT UINT32 *pTimeDataOnly)
{
UINT32 LenHeader;
UINT32 TxTime;
UINT32 TimeHeader, TimeData;
UINT32 TxTimeAck;
UINT32 DataExtraLen;
UINT32 Nss;
WMM_ACM_FUNC_NAME_PRINT("IN");
/*
<AMPDU> is used in AP or station.
Nominal A-MPDU Size =
Nominal MSDU Aggregation * Nominal A-MPDU Subframe Size
- Pad Size
Nominal A-MPDU Subframe Size =
MPDU Delimiter Size
+ MAC Header Size
+ Nominal MSDU Size
+ Security Encapsulation Size
+ FCS Size
+ Pad Size
A-MPDU Subframe is as below:
AMPDU subframe header (4) + Padding (0~3)
*/
/*
<AMSDU> is used only in station.
Nominal A-MSDU Size =
MAC Header Size
+ Nominal MSDU Aggregation * Nominal A-MSDU Subframe Size
- Pad Size
+ Security Encapsulation Size
+ FCS Size
Nominal A-MSDU Subframe Size =
A-MSDU Subframe Header Size
+ Nominal MSDU Size
+ Pad Size
A-MSDU Subframe is as below:
DA(6) + SA(6) + Length(2) + MSDU + Padding (0~3)
*/
/* init */
LenHeader = ACMR_FME_QOS_N_HEADER_SIZE;
TxTime = 0;
TxTimeAck = 0;
TimeHeader = 0;
DataExtraLen = 0;
if (McsId < 8)
Nss = 1;
else
{
if (McsId < 16)
Nss = 2;
else
{
if (McsId < 24)
Nss = 3;
else
{
if (McsId < 32)
Nss = 4;
else
{
McsId = 31; /* maximum MCS */
Nss = 1;
} /* End of if */
} /* End of if */
} /* End of if */
} /* End of if */
/* TODO: If in green-field mode, use RIFS */
/* SIFS + ACK */
if (FlgIsNoAckUsed == 0)
{
TxTimeAck = 0;
LMR_PREAMBL_TIME(1, 0, TxTimeAck);
TxTimeAck += TIME_SIFSG;
TxTimeAck += ACM_TX_TimePlcpCal(
FRM_LENGTH_BLOCK_ACK,
ACM_RATE_ID_24M,
1);
}
else
{
/* use NO ACK policy so ack time = 0 */
TxTimeAck = 0;
} /* End of if */
if (pTimeAck != NULL)
*pTimeAck = TxTimeAck;
/* End of if */
/* If FlgIsOnlyData == 1, means we do not care HT preamble time */
/* preamble + header */
TimeHeader = ACM_TX_TimePlcpCalHT(
LenHeader,
McsId,
Nss,
0,
0,
BwId,
GIId,
FlgIsOnlyData);
/* add data tx time without preamble */
if (BodyLen > 0)
{
if (pCdb != NULL)
DataExtraLen = ACM_EncryptExtraLenGet(pAd, pCdb);
/* End of if */
if (NominalAggSize > 0)
{
if (FlgIsAmsdu == TRUE)
{
/* AMSDU */
/* DA(6) + SA(6) + Length(2) + MSDU + Padding (0~3) */
DataExtraLen += FRM_LENGTH_AGG_AMSDU_HDR;
DataExtraLen += (FRM_LENGTH_AGG_AMSDU_HDR+BodyLen) *\
(NominalAggSize - 1);
}
else
{
/* AMPDU */
/* 4 for AMPDU subframe header, 3 for padding */
DataExtraLen += 4+3;
DataExtraLen += (LenHeader+BodyLen+4+3);
/* include security octets for each MPDU in the AMPDU */
DataExtraLen *= (NominalAggSize - 1);
} /* End of if */
} /* End of if */
/* first MPDU */
TimeData = ACM_TX_TimePlcpCalHT(
LenHeader+BodyLen+DataExtraLen,
McsId,
Nss,
0,
0,
BwId,
GIId,
FlgIsOnlyData);
TimeData -= TimeHeader; /* only data, no HT preamble */
if (NominalAggSize > 1)
{
/* aggregation */
if (FlgIsAmsdu == FALSE)
{
/* AMPDU */
/* Minimum MPDU Start Spacing, suppose tMMSS = 16us */
TimeData += 16 * (NominalAggSize - 1);
} /* End of if */
} /* End of if */
}
else
TimeData = 0;
/* End of if */
/* sum all tx time */
TxTime = TimeHeader + TxTimeAck;
if (pTimeNoData != NULL)
*pTimeNoData = TxTime;
/* End of if */
if (pTimeHeader != NULL)
*pTimeHeader = TimeHeader;
/* End of if */
if (pTimeDataHdrOnly != NULL)
{
if ((pCdb != NULL) && (TimeData > 0))
DataExtraLen = ACM_EncryptExtraLenGet(pAd, pCdb);
/* End of if */
if ((BodyLen > 0) && (TimeData == 0))
{
/* calculate time */
*pTimeDataHdrOnly = ACM_TX_TimePlcpCalHT(
LenHeader+BodyLen+DataExtraLen,
McsId,
Nss,
0,
0,
BwId,
GIId,
FlgIsOnlyData);
}
else
*pTimeDataHdrOnly = TimeHeader + TimeData;
/* End of if */
} /* End of if */
if (pTimeDataOnly != NULL)
{
if ((pCdb != NULL) && (TimeData > 0))
DataExtraLen = ACM_EncryptExtraLenGet(pAd, pCdb);
/* End of if */
if ((BodyLen > 0) && (TimeData == 0))
{
/* calculate time */
*pTimeDataOnly = ACM_TX_TimePlcpCalHT(
BodyLen+DataExtraLen,
McsId,
Nss,
0,
0,
BwId,
GIId,
FlgIsOnlyData);
}
else
*pTimeDataOnly = TimeData;
/* End of if */
} /* End of if */
TxTime += TimeData;
if (FlgIsRtsEnable != 0)
{
/* add RTS/CTS 24Mbps time */
#ifdef ACM_CC_FUNC_AUX_TX_TIME
UINT32 TimeRtsCts;
ACM_TX_TimeCal(pAd, NULL,
0, /* BodyLen = 0 */
ACM_RATE_24M, /* RateIndex */
1, /* g mode */
0, /* cts-self */
1, /* rts/cts */
0, /* IdPreambleNum */
1, /* no ack */
0, /* txop limit */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* cts self tx time */
&TimeRtsCts, /* rts/cts tx time */
NULL); /* ack tx time */
TxTime += TimeRtsCts;
#else
TxTime += gAcmTxTimeOthers[ACM_PRE_TIME_ID_24M][0][2];
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
} /* End of if */
return TxTime;
} /* End of ACM_TX_TimeCalHT */
#endif /* ACM_CC_FUNC_11N */
/*
========================================================================
Routine Description:
Calculate the QoS packet transmission time on the fly.
Arguments:
pAd - WLAN control block pointer
*pCdb - the connected client data base
BodyLen - the data length, not include WLAN header
RateIndex - transmission rate, such as ACM_PRE_TIME_ID_1M, etc.
FlgIsCtsEnable - CTS-self flag
FlgIsRtsEnable - RTS/CTS flag
FlgIsSpreambleUsed - Short preamble flag
FlgIsNoAckUsed - NO ACK flag
Return Value:
transmission time (miscro second, us)
Note:
1. Only for QoS packet.
========================================================================
*/
UINT32 ACM_TX_TimeCalOnFly(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UCHAR RateIndex,
ACM_PARAM_IN UCHAR FlgIsCtsEnable,
ACM_PARAM_IN UCHAR FlgIsRtsEnable,
ACM_PARAM_IN UCHAR FlgIsSpreambleUsed,
ACM_PARAM_IN UCHAR FlgIsNoAckUsed)
{
UINT32 TxTime;
#ifndef ACM_CC_FUNC_AUX_TX_TIME
UINT32 LenDataId;
UINT32 RateRtsCtsId;
WMM_ACM_FUNC_NAME_PRINT("IN");
LenDataId = BodyLen >> ACM_PRE_TIME_DATA_SIZE_OFFSET;
if (RateIndex > ACM_PRE_TIME_ID_54M)
RateIndex = ACM_PRE_TIME_ID_54M;
/* End of if */
#if 0
if (LenDataId > 0)
LenDataId --; /* use smaller length */
/* End of if */
#endif /* 0 */
if (LenDataId >= ACM_PRE_TIME_DATA_SIZE_NUM)
LenDataId = ACM_PRE_TIME_DATA_SIZE_NUM-1;
/* End of if */
/* sum the time: cts-self + rts/cts + preamble + header + data + ack */
TxTime = gAcmTxTimeOthers[RateIndex][FlgIsSpreambleUsed][ACM_PRE_TIME_HEADER];
TxTime += gAcmTxTimeBody[RateIndex][LenDataId];
if (FlgIsCtsEnable)
{
RateRtsCtsId = ACMR_PHY_RATE_ID_RTS_CTS_GET(pAd);
TxTime += gAcmTxTimeOthers[RateRtsCtsId][FlgIsSpreambleUsed][ACM_PRE_TIME_CTS_SELF];
} /* End of if */
if (FlgIsRtsEnable)
{
RateRtsCtsId = ACMR_PHY_RATE_ID_RTS_CTS_GET(pAd);
TxTime += gAcmTxTimeOthers[RateRtsCtsId][FlgIsSpreambleUsed][ACM_PRE_TIME_RTS_CTS];
} /* End of if */
if (FlgIsNoAckUsed == 0)
TxTime += gAcmTxTimeOthers[RateIndex][FlgIsSpreambleUsed][ACM_PRE_TIME_ACK];
/* End of if */
#else
UCHAR RateMapping[ACM_RATE_MAX_NUM] = {
ACM_RATE_1M, ACM_RATE_2M, ACM_RATE_5_5M,
ACM_RATE_11M, ACM_RATE_6M, ACM_RATE_9M,
ACM_RATE_12M, ACM_RATE_18M, ACM_RATE_24M,
ACM_RATE_36M, ACM_RATE_48M, ACM_RATE_54M
};
UCHAR FlgIsGmode;
if (RateIndex <= 3)
FlgIsGmode = 0;
else
FlgIsGmode = 1;
/* End of if */
if (FlgIsCtsEnable)
FlgIsRtsEnable = 0;
/* End of if */
TxTime = ACM_TX_TimeCal(pAd, NULL,
0, /* BodyLen = 0 */
RateMapping[RateIndex], /* RateIndex */
FlgIsGmode, /* g mode */
FlgIsCtsEnable, /* cts-self */
FlgIsRtsEnable, /* rts/cts */
FlgIsSpreambleUsed, /* IdPreambleNum */
FlgIsNoAckUsed, /* no ack */
0, /* txop limit */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* cts self tx time */
NULL, /* rts/cts tx time */
NULL); /* ack tx time */
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
return TxTime;
} /* End of ACM_TX_TimeCalOnFly */
#ifdef ACM_CC_FUNC_11N
/*
========================================================================
Routine Description:
Calculate the QoS packet transmission time on the fly for HT rate.
Arguments:
pAd - WLAN control block pointer
*pCdb - the connected client data base
*pStream - the matched TSPEC
Timestamp - current Timestamp, unit: micro second
BodyLen - the data length, not include WLAN header
McsId - transmission rate, 0 ~ 31
FlgIsNoAckUsed - NO ACK flag
Return Value:
transmission time (miscro second, us)
Note:
1. Only for QoS packet.
2. Protect in caller.
========================================================================
*/
#ifdef WMM_ACM_PKT_NUM_DEBUG
/* global variables but only for debug */
UINT32 WMM_ACM_TimeOffsetHTId = 0;
UINT32 WMM_ACM_TimeOffsetHT[WMM_ACM_DEBUG_TIME_MAX_NUM_REC][4];
#endif /* WMM_ACM_PKT_NUM_DEBUG */
UINT32 ACM_TX_TimeCalOnFlyHT(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN ACM_STREAM *pStream,
ACM_PARAM_IN UINT64 Timestamp,
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UINT32 McsId,
ACM_PARAM_IN UCHAR FlgIsNoAckUsed)
{
#ifdef RELEASE_EXCLUDE
/*
One packet or AMPDU transmission rule:
1. If the packet is the first one, backup its tx time T1 and timestamp;
2. If the packet is not the first one,
check if current total tx time is larger than T1;
(1) If yes, the packet is the new first one, goto 1;
(2) If no, add the tx time to the total tx time and
use AMPDU rule to calculate total tx time;
*/
#endif /* RELEASE_EXCLUDE */
UINT32 TxTime;
UINT32 TimeOffset;
UINT8 NumOfBaWinSize;
WMM_ACM_FUNC_NAME_PRINT("IN");
TimeOffset = (UINT32)(Timestamp - pStream->TxTimestampEnqueueHT);
if (pStream->pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
NumOfBaWinSize = pStream->HT_BaWinSize;
else
NumOfBaWinSize = 0; /* not BLOCK ACK for the TSPEC */
/* End of if */
if (!ACMR_HT_IS_BA_BUILT(pCdb, pStream->UP))
NumOfBaWinSize = 0; /* not yet build the BA session */
/* End of if */
#ifdef WMM_ACM_PKT_NUM_DEBUG
if ((NumOfBaWinSize != 0) &&
(WMM_ACM_TimeRecId == 5) &&
(WMM_ACM_IsTimeValid == TRUE))
{
/* AMPDU */
if (WMM_ACM_TimeOffsetHTId >= WMM_ACM_DEBUG_TIME_MAX_NUM_REC)
WMM_ACM_TimeOffsetHTId = 0;
/* End of if */
WMM_ACM_TimeOffsetHT[WMM_ACM_TimeOffsetHTId][0] = TimeOffset;
WMM_ACM_TimeOffsetHT[WMM_ACM_TimeOffsetHTId][1] = pStream->TxTimeEnqueueHT;
WMM_ACM_TimeOffsetHT[WMM_ACM_TimeOffsetHTId][2] = pStream->TxAmpduNumEnqueueHT;
} /* End of if */
#endif /* WMM_ACM_PKT_NUM_DEBUG */
if ((pStream->TxAmpduNumEnqueueHT == 0) ||
(pStream->TxAmpduNumEnqueueHT > (UINT32)NumOfBaWinSize) ||
(TimeOffset > pStream->TxTimeEnqueueHT))
{
#ifdef RELEASE_EXCLUDE
/*
1. first packet before making up a AMPDU;
2. maximum BLOCK ACK NUM is limited;
2. offset between new packet and first packet is larger than
the tx time of first packet, we will not put the packet
into the AMPDU so we make up another AMPDU;
*/
#endif /* RELEASE_EXCLUDE */
/* sum the time: rts/cts + preamble + header + data + block ack */
/* 802.11 header is included defaultly in ACM_TX_TimeCalHT() */
#ifdef ACM_CC_FUNC_AUX_TX_TIME
TxTime = ACM_TX_TimeCalHT(pAd, NULL,
BodyLen, /* body len */
McsId, /* MCS Index */
ACMR_IS_2040_STA(pCdb), /* 20 or 20/40 MHz */
0, /* regular or short GI */
1, /* rts/cts */
0, /* no AMPDU or fist pkt in AMPDU */
FlgIsNoAckUsed, /* no ack */
0xFFFFFFFF, /* txop limit */
0, /* non-AMSDU means AMPDU */
0, /* do not care */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* ack tx time */
NULL, /* data+hdr only tx time */
NULL); /* data only tx time */
#else
UINT32 LenDataId;
LenDataId = (BodyLen+ACMR_FME_QOS_N_HEADER_SIZE);
LenDataId >>= ACM_PRE_TIME_DATA_SIZE_OFFSET;
#if 0
if (LenDataId > 0)
LenDataId --; /* use smaller length */
/* End of if */
#endif /* 0 */
if (LenDataId >= ACM_PRE_TIME_DATA_SIZE_NUM)
LenDataId = ACM_PRE_TIME_DATA_SIZE_NUM-1;
/* End of if */
/* add RTS/CTS time (maybe no RTS/CTS in the air) */
TxTime = gAcmTxTimeOthers[ACM_PRE_TIME_ID_24M][0][2];
/* add data time */
TxTime += gAcmTxTimeBodyHT\
[ACMR_IS_2040_STA(pCdb)][0][McsId][LenDataId][0];
/* add block ack time */
if (FlgIsNoAckUsed == 0)
TxTime += gAcmTxTimeOthersHT;
/* End of if */
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
/* statistics */
#ifdef ACM_CC_FUNC_STATS
if (pStream->TxAmpduNumEnqueueHT > 1)
{
ACM_CTRL_PARAM *pEdcaParam;
ACM_STATISTICS *pStats;
pEdcaParam = &(ACMR_CB->EdcaCtrlParam);
pStats = &pEdcaParam->Stats;
ACM_STATS_COUNT_INC(pStats->AMPDU[pStream->TxAmpduNumEnqueueHT]);
} /* End of if */
#endif /* ACM_CC_FUNC_STATS */
/* backup time record */
if (pStream->TxAmpduNumEnqueueHT == 0)
pStream->TxAmpduNumEnqueueHT ++;
else
{
pStream->TxTimestampEnqueueHT = Timestamp;
pStream->TxTimeEnqueueHT = TxTime;
pStream->TxAmpduNumEnqueueHT = 0;
} /* End of if */
}
else
{
/* AMPDU handle */
/* skip PHY preamble & ACK time */
/* ACMR_FME_QOS_N_HEADER_SIZE + 4 for AMPDU subframe header, 3 for padding */
#ifdef ACM_CC_FUNC_AUX_TX_TIME
UINT32 TimeData;
/* 802.11 header is included defaultly in ACM_TX_TimeCalHT() */
TimeData = ACM_TX_TimeCalHT(pAd, NULL,
BodyLen+4+3, /* body len */
McsId, /* MCS Index */
ACMR_IS_2040_STA(pCdb), /* 20 or 20/40 MHz */
0, /* regular or short GI */
1, /* rts/cts */
1, /* AMPDU */
FlgIsNoAckUsed, /* no ack */
0, /* txop limit */
0, /* non-AMSDU means AMPDU */
0, /* do not care */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* ack tx time */
&TxTime, /* data+hdr only tx time */
NULL); /* data only tx time */
#else
UINT32 LenDataId;
/* 802.11 header for each MPDU of A-MPDU */
LenDataId = (ACMR_FME_QOS_N_HEADER_SIZE + BodyLen + 4 + 3);
LenDataId = LenDataId >> ACM_PRE_TIME_DATA_SIZE_OFFSET;
#if 0
if (LenDataId > 0)
LenDataId --; /* use smaller length */
/* End of if */
#endif /* 0 */
if (LenDataId >= ACM_PRE_TIME_DATA_SIZE_NUM)
LenDataId = ACM_PRE_TIME_DATA_SIZE_NUM-1;
/* End of if */
/* we only care about tx time for header + data body */
TxTime = gAcmTxTimeBodyHT\
[ACMR_IS_2040_STA(pCdb)][0][McsId][LenDataId][1];
/* TODO: we need to minus the PHY preamble time */
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
/*
Need to add Minimum MPDU Start Spacing, suppose tMMSS = 16us.
(0 ~ 16us)
An HT STA shall not start the transmission of more than one MPDU
within the time limit described in the Minimum MPDU Start Spacing
field.
To satisfy this requirement, the number of octets between the start
of two consecutive MPDUs in an A-MPDU, measured at the PHY SAP,
shall be equal or greater than:
tMMSS * r / 8, where r = PHY Data Rate (unit: Mbps)
*/
TxTime += 16; /* use maximum value */
/* maybe we can make up a AMPDU from the WLAN hardware */
pStream->TxAmpduNumEnqueueHT ++;
} /* End of if */
#ifdef WMM_ACM_PKT_NUM_DEBUG
if ((NumOfBaWinSize != 0) &&
(WMM_ACM_TimeRecId == 5) &&
(WMM_ACM_IsTimeValid == TRUE))
{
WMM_ACM_TimeOffsetHT[WMM_ACM_TimeOffsetHTId][3] = TxTime;
WMM_ACM_TimeOffsetHTId ++;
} /* End of if */
#endif /* WMM_ACM_PKT_NUM_DEBUG */
return TxTime;
} /* End of ACM_TX_TimeCalOnFlyHT */
#endif /* ACM_CC_FUNC_11N */
/*
========================================================================
Routine Description:
Pre-Calculate the QoS packet transmission time.
Arguments:
pAd - WLAN control block pointer
Return Value:
None
Note:
All possible tx time are kept in a local array.
[0] duration id [1] cts-self tx time [2] rts/cts tx time
[3] header time [4] ack tx time
Do NOT include "data body tx time".
For HT packet, suppose that
1. RTS/CTS (11M) for each packet
2. BLOCK ACK (11M) for each packet
========================================================================
*/
VOID ACM_TX_TimeCalPre(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifndef ACM_CC_FUNC_AUX_TX_TIME
UINT32 RateMap[ACM_RATE_MAX_NUM][3] = {
{ ACM_RATE_1M, 0, ACM_RATE_ID_1M },
{ ACM_RATE_2M, 0, ACM_RATE_ID_2M },
{ ACM_RATE_5_5M, 0, ACM_RATE_ID_5_5M },
{ ACM_RATE_11M, 0, ACM_RATE_ID_11M },
{ ACM_RATE_6M, 1, ACM_RATE_ID_6M },
{ ACM_RATE_9M, 1, ACM_RATE_ID_9M },
{ ACM_RATE_12M, 1, ACM_RATE_ID_12M },
{ ACM_RATE_18M, 1, ACM_RATE_ID_18M },
{ ACM_RATE_24M, 1, ACM_RATE_ID_24M },
{ ACM_RATE_36M, 1, ACM_RATE_ID_36M },
{ ACM_RATE_48M, 1, ACM_RATE_ID_48M },
{ ACM_RATE_54M, 1, ACM_RATE_ID_54M }};
UINT32 TimeHeader, TimeCtsSelf, TimeRtsCts, TimeAck;
UINT32 TimeDataAck;
UINT32 IdRateNum, IdSizeNum, IdPreambleNum, Size;
#ifdef ACM_CC_FUNC_11N
UINT32 TimeDatHdrOnly, TimeDataOnly;
UINT32 IdBw, IdGI;
#endif /* ACM_CC_FUNC_11N */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* for all rates */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> calculate frame body tx time...\n"));
for(IdRateNum=0; IdRateNum<ACM_RATE_MAX_NUM; IdRateNum++)
{
Size = ACM_PRE_TIME_DATA_SIZE_INTERVAL-1;
for(IdSizeNum=0; IdSizeNum<ACM_PRE_TIME_DATA_SIZE_NUM; IdSizeNum++)
{
TimeDataAck = ACM_TX_TimeCal(pAd, NULL,
Size, /* body len */
RateMap[IdRateNum][0], /* RateIndex */
RateMap[IdRateNum][1], /* g mode */
0, /* cts-self */
0, /* rts/cts */
0, /* short IdPreambleNum */
1, /* no ack */
0, /* txop limit */
NULL, /* no data tx time */
&TimeHeader, /* wlan header tx time */
NULL, /* cts self tx time */
NULL, /* rts/cts tx time */
NULL); /* ack tx time */
TimeDataAck -= TimeHeader;
gAcmTxTimeBody[IdRateNum][IdSizeNum] = TimeDataAck;
Size += ACM_PRE_TIME_DATA_SIZE_INTERVAL;
} /* End of for */
} /* End of for */
#ifdef ACM_CC_FUNC_11N
for(IdBw=0; IdBw<2; IdBw++)
{
for(IdGI=0; IdGI<2; IdGI++)
{
for(IdRateNum=0; IdRateNum<ACM_RATE_MAX_NUM_HT; IdRateNum++)
{
Size = ACM_PRE_TIME_DATA_SIZE_INTERVAL-1;
for(IdSizeNum=0;
IdSizeNum<ACM_PRE_TIME_DATA_SIZE_NUM;
IdSizeNum++)
{
/* not include RTS/CTS time */
TimeDataAck = ACM_TX_TimeCalHT(pAd, NULL,
Size, /* body len */
IdRateNum, /* MCS Index */
IdBw, /* 20 or 20/40 MHz */
IdGI, /* regular or short GI */
0, /* rts/cts */
1, /* no ack */
0, /* not AMPDU */
0, /* txop limit */
0, /* do not care */
0, /* do not care */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* ack tx time */
&TimeDatHdrOnly,/* data+hdr only tx time */
&TimeDataOnly); /* data only tx time */
gAcmTxTimeBodyHT\
[IdBw][IdGI][IdRateNum][IdSizeNum][0] = TimeDataAck;
gAcmTxTimeBodyHT\
[IdBw][IdGI][IdRateNum][IdSizeNum][1] = TimeDatHdrOnly;
gAcmTxTimeBodyHT\
[IdBw][IdGI][IdRateNum][IdSizeNum][2] = TimeDataOnly;
Size += ACM_PRE_TIME_DATA_SIZE_INTERVAL;
} /* End of for */
} /* End of for */
} /* End of for */
} /* End of for */
#endif /* ACM_CC_FUNC_11N */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> calculate other tx time...\n"));
for(IdRateNum=0; IdRateNum<ACM_RATE_MAX_NUM; IdRateNum++)
{
/* short IdPreambleNum (0) and long IdPreambleNum (1) */
for(IdPreambleNum=0; IdPreambleNum<2; IdPreambleNum++)
{
ACM_TX_TimeCal(pAd, NULL,
1, /* BodyLen = 1 */
RateMap[IdRateNum][0], /* RateIndex */
RateMap[IdRateNum][1], /* g mode */
1, /* cts-self */
0, /* rts/cts */
IdPreambleNum, /* IdPreambleNum */
0, /* no ack */
0, /* txop limit */
NULL, /* no data tx time */
&TimeHeader, /* wlan header tx time */
&TimeCtsSelf, /* cts self tx time */
NULL, /* rts/cts tx time */
&TimeAck); /* ack tx time */
ACM_TX_TimeCal(pAd, NULL,
0, /* BodyLen = 0 */
RateMap[IdRateNum][0], /* RateIndex */
RateMap[IdRateNum][1], /* g mode */
0, /* cts-self */
1, /* rts/cts */
IdPreambleNum, /* IdPreambleNum */
1, /* no ack */
0, /* txop limit */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
NULL, /* cts self tx time */
&TimeRtsCts, /* rts/cts tx time */
NULL); /* ack tx time */
gAcmTxTimeOthers[IdRateNum][IdPreambleNum][0] = RateMap[IdRateNum][2];
gAcmTxTimeOthers[IdRateNum][IdPreambleNum][1] = (UINT16)TimeCtsSelf;
gAcmTxTimeOthers[IdRateNum][IdPreambleNum][2] = (UINT16)TimeRtsCts;
gAcmTxTimeOthers[IdRateNum][IdPreambleNum][3] = (UINT16)TimeHeader;
gAcmTxTimeOthers[IdRateNum][IdPreambleNum][4] = (UINT16)TimeAck;
} /* End of for */
} /* End of for */
#ifdef ACM_CC_FUNC_11N
/* only for BLOCK ACK frame, 24Mbps */
TimeDataAck = ACM_TX_TimeCalHT(pAd, NULL,
FRM_LENGTH_BLOCK_ACK, /* body len */
0, /* MCS Index */
0, /* 20 or 20/40 MHz */
0, /* regular or short GI */
0, /* rts/cts */
0, /* no ack */
0, /* not AMPDU */
0, /* txop limit */
0, /* do not care */
0, /* do not care */
NULL, /* no data tx time */
NULL, /* wlan header tx time */
&TimeAck, /* ack tx time */
NULL, /* data+hdr only tx time */
NULL); /* data only tx time */
gAcmTxTimeOthersHT = (UINT16)TimeAck;
#endif /* ACM_CC_FUNC_11N */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> pre-calculattion ok!\n"));
#endif /* ACM_CC_FUNC_AUX_TX_TIME */
} /* End of ACM_TX_TimeCalPre */
/*
========================================================================
Routine Description:
Calculate the frame body transmission time.
Arguments:
BodyLen - frame body
RateId - frame tx time
FlgIsGmode - is G mode
Return Value:
transmission time (miscro second, us)
Note:
========================================================================
*/
STATIC UINT16 ACM_TX_TimePlcpCal(
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UINT32 RateId,
ACM_PARAM_IN UCHAR FlgIsGmode)
{
UINT32 PLCP;
WMM_ACM_FUNC_NAME_PRINT("IN");
if (FlgIsGmode)
{
#ifdef RELEASE_EXCLUDE
/*
EX1: BodyLen = 30B and rate = 54Mbps,
1. additional 22 bit in PSDU
PLCP = 30*8 + 22 = 262 bits
2. round_up{X / 4} * 4 means OFDM symbol is in unit of 4 usec
PLCP = (262/54) = 4.8xxx us
4.8xxx / 4 = 1.2xxx
3. PLCP = round up(1.2xxx) * 4 = 2 * 4 = 8 us
EX2: BodyLen = 14B and rate = 6Mbps,
1. additional 22 bit in PSDU
PLCP = 14*8 + 22 = 134 bits
2. round_up{X / 4} * 4 means OFDM symbol is in unit of 4 usec
PLCP = (134/6) = 22.3xxx us
22.3xxx / 4 = 5.583xxx
3. PLCP = round up(5.583xxx) * 4 = 6 * 4 = 24 us
*/
#endif /* RELEASE_EXCLUDE */
PLCP = (BodyLen << 3) + 22; /* need to add 22 bits in 11g */
PLCP = (PLCP % (gAcmRateG[RateId]<<1)) ? (PLCP/(gAcmRateG[RateId]<<1))+1 :
(PLCP/(gAcmRateG[RateId]<<1));
return (PLCP << 2);
} /* End of if */
#ifdef RELEASE_EXCLUDE
/* ex: BodyLen = 30B and rate = 11Mbps,
PLCP = 30 * 8 / 11 = 22us */
#endif /* RELEASE_EXCLUDE */
if (RateId > ACM_RATE_ID_1M)
RateId = ACM_RATE_ID_1M; /* should not be here */
/* End of if */
return (BodyLen << 4)/gAcmRateLegacy[RateId];
} /* End of ACM_TX_TimePlcpCal */
#ifdef ACM_CC_FUNC_11N
/*
========================================================================
Routine Description:
Calculate the frame body transmission time for HT rate.
Arguments:
BodyLen - frame body
McsId - frame tx MCS
Nss - Number of Spatial Streams
Ness - Number of Extension Spatial Streams
FlgIsGF - 1: Greenfield mode
FlgIs2040 - 1: support 20/40MHz
FlgIsSGI - 1: use short GI
FlgIsOnlyData - 1: only calcualte tx time for data, no preamble
Return Value:
transmission time (miscro second, us)
Note:
========================================================================
*/
STATIC UINT16 ACM_TX_TimePlcpCalHT(
ACM_PARAM_IN UINT32 BodyLen,
ACM_PARAM_IN UINT32 McsId,
ACM_PARAM_IN UINT32 Nss,
ACM_PARAM_IN UINT32 Ness,
ACM_PARAM_IN BOOLEAN FlgIsGF,
ACM_PARAM_IN BOOLEAN FlgIs2040,
ACM_PARAM_IN BOOLEAN FlgIsSGI,
ACM_PARAM_IN BOOLEAN FlgIsOnlyData)
{
#ifdef RELEASE_EXCLUDE
/*
Reference to Draft802.11n_D3.07, Transmission Time =
1. Mix mode, short GI
TXTIME = T_LEG_PREAMBLE + T_L_SIG + T_HT_PREAMBLE + T_HT_SIG +
T_SYM * Ceiling{T_SYMS * N_SYM / T_SYM}
2. Mix mode, regular GI
TXTIME = T_LEG_PREAMBLE + T_L_SIG + T_HT_PREAMBLE + T_HT_SIG +
T_SYM * N_SYM
3. GreenField mode, short GI
TXTIME = T_GF_HT_PREAMBLE + T_HT_SIG + T_SYMS * N_SYM
4. GreenField mode, regular GI
TXTIME = T_GF_HT_PREAMBLE + T_HT_SIG + T_SYM * N_SYM
Where
(1) T_LEG_PREAMBLE = T_L_STF + T_L_LTF = 8 + 8 = 16 us
(2) T_L_SIG = 4 us
(3) T_HT_PREAMBLE = T_HT_STF + T_HT_LTF1 + (N_LTF - 1) * T_HT_LTFS
= 4 + 4 + ((N_DLTF + N_ELTF) - 1) * 4
EX: Nss = 2, N_DLTF = 2, Ness = 0, N_ELTF = 0, T_HT_PREAMBLE = 12 us
(4) T_HT_SIG = 8 us
(5) T_SYM = 4 us
(6) T_SYMS = 3.6 us
(7) N_SYM = mSTBC * Ceil((8*len+16+6*N_ES)/(mSTBC * N_DBPS))
(8) T_GF_HT_PREAMBLE= T_HT_GF_STF + T_HT_LTF1 + (N_LTF - 1) * T_HT_LTFS
= 8 + 4 + ((N_DLTF + N_ELTF) - 1) * 4
*/
#endif /* RELEASE_EXCLUDE */
UINT32 T_LEG_PREAMBLE, T_L_SIG, T_HT_PREAMBLE, T_HT_SIG;
UINT32 T_SYM, T_SYMS, N_SYM;
UINT32 T_GF_HT_PREAMBLE;
UINT32 TxTime;
UINT32 N_DLTF[5] = { 1, 1, 2, 4, 4 };
UINT32 N_ELTF[4] = { 0, 1, 2, 4 };
UINT32 N_SYM_1_NUM; /* numerator of N_SYM */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
T_LEG_PREAMBLE = 16;
T_L_SIG = 4;
T_HT_SIG = 8;
T_SYM = 4;
T_SYMS = 36; /* unit: 0.1us */
TxTime = 0;
/* calculate N_SYM */
/* ex: 1538B, 1st MPDU of AMPDU, (1538 * 8 + 22)/1080 + 1 = 12 */
/* STBC is not used, BCC is used */
N_SYM = 1*((BodyLen << 3) + 16 + 6)/(1*gAcmRateNdbps[FlgIs2040][McsId])+1;
/* calculate transmission time */
if (FlgIsGF == 0)
{
/* ex: 1538B, 1st MPDU of AMPDU, 4 + 4 + 2*4 = 16us */
T_HT_PREAMBLE = 4 + 4 + ((N_DLTF[Nss] + N_ELTF[Ness] - 1) << 2);
/* ex: 1538B, 1st MPDU of AMPDU, 16 + 4 + 16 + 8 = 44us */
if (FlgIsOnlyData == 0)
TxTime = T_LEG_PREAMBLE + T_L_SIG + T_HT_PREAMBLE + T_HT_SIG;
/* End of if */
/* ex: 1538B, 1st MPDU of AMPDU, 4 * 12 = 48us */
if (FlgIsSGI == 0)
{
TxTime += T_SYM * N_SYM;
}
else
{
N_SYM_1_NUM = (T_SYMS * N_SYM) / (T_SYM * 10);
if ((T_SYMS * N_SYM) % (T_SYM * 10))
N_SYM_1_NUM ++;
/* End of if */
TxTime += T_SYM * N_SYM_1_NUM;
} /* End of if */
}
else
{
T_GF_HT_PREAMBLE = 8 + 4 + ((N_DLTF[Nss] + N_ELTF[Ness] - 1) << 2);
if (FlgIsOnlyData == 0)
TxTime = T_GF_HT_PREAMBLE + T_HT_SIG;
/* End of if */
if (FlgIsSGI == 0)
TxTime += T_SYM * N_SYM;
else
TxTime += (T_SYMS * N_SYM) / 10;
/* End of if */
} /* End of if */
return TxTime;
} /* End of ACM_TX_TimePlcpCalHT */
#endif /* ACM_CC_FUNC_11N */
/* =========================== Information Function ================== */
/*
========================================================================
Routine Description:
Get TXOP information.
Arguments:
pAd - WLAN control block pointer
AcId - the AC ID
Return Value:
TXOP
Note:
========================================================================
*/
UINT32 ACM_InfoTxopBssGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 AcId)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return ACMR_AP_TXOP_BSS_GET(pAd, AcId);
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
return ACMR_STA_TXOP_BSS_GET(pAd, AcId);
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
return 0; /* impossible */
} /* End of ACM_InfoTxopBssGet */
/*
========================================================================
Routine Description:
Get WMM information.
Arguments:
pAd - WLAN control block pointer
Return Value:
TRUE - WMM is enabled
FALSE - WMM is disabled
Note:
========================================================================
*/
BOOLEAN ACM_InfoWmmStatusGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return ACMR_AP_WMM_IS_ENABLED(pAd);
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
return ACMR_STA_WMM_IS_ENABLED(pAd);
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
return 0; /* impossible */
} /* End of ACM_InfoWmmStatusGet */
/*
========================================================================
Routine Description:
Get AP BSSID information.
Arguments:
pAd - WLAN control block pointer
Return Value:
TRUE - WMM is enabled
FALSE - WMM is disabled
Note:
========================================================================
*/
UCHAR *ACM_InfoApAddrGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return pAd->CurrentAddress;
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
return pAd->MlmeAux.Bssid;
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
return 0; /* impossible */
} /* End of ACM_InfoApAddrGet */
/*
========================================================================
Routine Description:
Get port secure information.
Arguments:
pAd - WLAN control block pointer
Return Value:
TRUE - port is secured
FALSE - port is not secured
Note:
========================================================================
*/
BOOLEAN ACM_InfoPortSecureGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return TRUE;
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* check if we have associated to a AP */
return (pAd->IndicateMediaState == NdisMediaStateConnected);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return FALSE; /* impossible */
} /* End of ACM_InfoPortSecureGet */
/*
========================================================================
Routine Description:
Get short preamble information.
Arguments:
pAd - WLAN control block pointer
Return Value:
TRUE - short preamble
FALSE - not short preamble
Note:
========================================================================
*/
BOOLEAN ACM_InfoShortPreambleGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
return (CAP_IS_SHORT_PREAMBLE_ON(pCdb->CapabilityInfo));
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
{
/* check if we have associated to a AP */
return (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort);
} /* End of if */
#endif /* CONFIG_STA_SUPPORT */
return FALSE; /* impossible */
} /* End of ACM_InfoShortPreambleGet */
/*
========================================================================
Routine Description:
Get channel busy time in a TBT.
Arguments:
pAd - WLAN control block pointer
*pTime - the busy time
Return Value:
None
Note:
========================================================================
*/
VOID ACM_InfoChanBusyGet(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN UINT32 *pTime)
{
#ifdef CONFIG_AP_SUPPORT
if (ACMR_IS_AP_MODE(pAd))
*pTime = pAd->phy_ctrl.QloadLatestChannelBusyTimePri;
/* End of if */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
if (ACMR_IS_STA_MODE(pAd))
*pTime = 0;
/* End of if */
#endif /* CONFIG_STA_SUPPORT */
} /* End of ACM_InfoChanBusyGet */
/* =========================== AP Function =========================== */
#ifdef CONFIG_AP_SUPPORT
/*
========================================================================
Routine Description:
Handle the Action Frame transmitted from QSTA.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
pMblk - the received frame
PhyRate - the physical tx rate for the frame
Return Value:
None
Note:
1. Only for QAP.
2. PhyRate is used to calculate medium time or polled TXOP
when min phy rate in the TSPEC is not assigned.
3. No QoS Control field (2B) in the action management frame.
4. No any packet free here.
========================================================================
*/
STATIC VOID ACM_ActionHandleByQAP(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pMblk,
ACM_PARAM_IN UINT32 PktLen,
ACM_PARAM_IN UINT32 PhyRate)
{
ACM_WME_NOT_FRAME *pNotFrame;
UCHAR *pActFrame;
UCHAR Category, Action;
UINT32 BodyLen;
UCHAR StatusCode;
UINT16 MediumTime;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* points to the action frame WLAN header */
pActFrame = (UCHAR *)pMblk;
BodyLen = PktLen - ACMR_FME_LEG_HEADER_SIZE;
/* get Category & Action field */
pActFrame += ACMR_FME_LEG_HEADER_SIZE;
Category = *pActFrame;
Action = *(pActFrame+1);
/* sanity check for peer */
#ifdef ACM_CC_FUNC_MBSS
if ((Action != ACM_ACTION_WME_BW_ANN) && (pCdb == NULL))
#else
if (pCdb == NULL)
#endif /* ACM_CC_FUNC_MBSS */
goto label_exit; /* wrong packet source */
/* End of if */
/* handle it by Category field */
if (Category == ACM_CATEGORY_WME)
{
#ifdef ACM_CC_FUNC_MBSS
if (Action != ACM_ACTION_WME_BW_ANN)
#endif /* ACM_CC_FUNC_MBSS */
{
if (!ACMR_IS_WMM_STA(pCdb))
{
ACMR_DEBUG(ACMR_DEBUG_ERR,
("acm_err> A WME frame is RCV from a non-WME STA! "
"Discard the frame! ActionHandleByQAP()\n"));
goto label_exit; /* wrong packet type */
} /* End of if */
} /* End of if */
/* WME action frame */
switch(Action)
{
case ACM_ACTION_WME_SETUP_REQ: /* ADDTS Request */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A WME Setup Request frame is received!\n"));
ACM_WME_ActionHandle(pAd,
pCdb,
pActFrame,
BodyLen,
PhyRate,
ACM_ACTION_WME_SETUP_REQ,
&StatusCode,
&MediumTime);
break;
case ACM_ACTION_WME_TEAR_DOWN: /* DELTS */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A WME Teardown frame is received!\n"));
ACM_WME_ActionHandle(pAd,
pCdb,
pActFrame,
BodyLen,
0, /* dont care phy rate */
ACM_ACTION_WME_TEAR_DOWN,
&StatusCode,
&MediumTime);
break;
#ifdef ACM_CC_FUNC_MBSS
case ACM_ACTION_WME_BW_ANN: /* BW ANN */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A WME BW ANN frame is received!\n"));
ACM_MBSS_BwAnnHandle(pAd, pActFrame, BodyLen);
/* not forward the public frame to other BSSs to avoid loop */
goto label_exit;
#endif /* ACM_CC_FUNC_MBSS */
default:
goto label_exit;
} /* End of switch */
/* check whether we need to reply a ADDTS Response frame;
if TRUE, send out one */
if (Action == ACM_ACTION_WME_SETUP_REQ)
{
/* if the ACM of the AC is disabled, we do not need to response */
if (StatusCode != ACM_STATUS_CODE_PRIVATE_ACM_DISABLED)
{
UCHAR MacRa[6], MacTa[6];
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> prepare to response...\n"));
/* init response frame */
StatusCode = ACM_11E_WMM_StatusTranslate(StatusCode);
pNotFrame = (ACM_WME_NOT_FRAME *)pActFrame;
pNotFrame->Action = ACM_ACTION_WME_SETUP_RSP;
pNotFrame->StatusCode = StatusCode;
/*
Test Event 1 found:
we need to re-assign the allowed medium time.
*/
pNotFrame->ElmTspec.Tspec.MediumTime = MediumTime;
/* swap DA & SA */
ACMR_WLAN_PKT_RA_GET(pMblk, MacRa);
ACMR_WLAN_PKT_TA_GET(pMblk, MacTa);
ACMR_WLAN_PKT_RA_SET(pMblk, MacTa);
ACMR_WLAN_PKT_TA_SET(pMblk, MacRa);
/* send out it */
ACM_ADDRSP_SEND(pAd, pMblk, PktLen);
/* only test use */
if (gAcmTestFlag)
ACM_ADDRSP_SEND(pAd, pMblk, PktLen);
/* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Send a WME Setup response (len=%d).\n", PktLen));
} /* End of if */
} /* End of if */
/* send a private public ACTION frame to advise used ACM time in AP */
ACMP_FrameBwAnnSend(pAd, FALSE);
} /* End of if */
label_exit:
return;
} /* End of ACM_ActionHandleByQAP */
/*
========================================================================
Routine Description:
Handle a TSPEC request from the QSTA.
Arguments:
pAd - WLAN control block pointer
*pCdb - the QSTA database
StreamType - the stream type: ACM_STREAM_TYPE_WIFI
DialogToken - the TSPEC ID
*pTspec - the requested TSPEC pointer
TclasNum - the number of TCLASS, max 5
*pTclas[] - the requested TCLASS array pointer
TclasProcessing - the TCLAS Processing element
PhyRate - the observed physical transmit rate (bps)
*pStatusCode - response status code
*pMediumTime - the allowed medium time
Return Value:
ACM_RTN_OK - request is accepted
ACM_RTN_FAIL - semaphore lock fail or others
ACM_RTN_NULL_POINTER - null pointer
ACM_RTN_ALLOC_ERR - TSPEC request structure allocation fail
ACM_RTN_DISALLOW - the request is not allowed
Note:
1. Only for Root AP Mode.
2. pTclasSrc is limited by ACM_TSPEC_TCLAS_MAX_NUM.
3. DLP is not allowed because we can not monitor traffic
on the direct link when inactivity timeout != 0.
We allow DLP protocol but we dont allow DLP TSPEC.
4. for uplink, dst_cdb_p == NULL means the destination STA is QAP;
for direct link, dst_cdb must NOT be NULL;
for dnlink, dst_cdb_p == NULL;
for bidirectional link, dst_cdb_p = NULL.
5. TSPEC parameters that must be non-zero to pass in ADDTS Rsp:
(1) Mean Data Rate;
(2) Nominal MSDU Size;
(3) Maximum Service Interval;
(4) Minimum PHY Rate.
6. TCLAS number can be 0 for EDCA/WMM streams.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_ReqHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR StreamType,
ACM_PARAM_IN UINT16 DialogToken,
ACM_PARAM_IN ACM_TSPEC *pTspec,
ACM_PARAM_IN UINT32 TclasNum,
ACM_PARAM_IN ACM_TCLAS *pTclas[],
ACM_PARAM_IN UCHAR TclasProcessing,
ACM_PARAM_IN UINT32 PhyRate,
ACM_PARAM_OUT UCHAR *pStatusCode,
ACM_PARAM_OUT UINT16 *pMediumTime)
{
ACM_STREAM *pNewStream;
ACM_STREAM *pOldStreamIn, *pOldStreamOut, *pOldStreamDiffAc;
ACM_FUNC_STATUS RtnCode, Status;
UCHAR StatusCode;
UCHAR Policy, UserPriority;
UCHAR StmAcId, ApsdAcId, FlgIsApsdEnable;
UCHAR FlgIsSupRate;
ULONG SplFlags;
#ifdef ACM_CC_FUNC_TCLAS
UINT32 IdTclasNum;
#endif /* ACM_CC_FUNC_TCLAS */
#ifdef ACM_CC_FUNC_HCCA
UINT32 MinServInt;
#endif /* ACM_CC_FUNC_HCCA */
UCHAR FlgAcmStatus[ACM_DEV_NUM_OF_AC];
WMM_ACM_FUNC_NAME_PRINT("IN");
/* ---- Sanity check for input parameters ---- */
*pStatusCode = ACM_STATUS_CODE_UNSPECIFIED_FAILURE;
if (pTspec == NULL)
{
/* TSPEC element shall NOT be NULL */
return ACM_RTN_NULL_POINTER;
} /* End of if */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
if (!ACM_MR_TSPEC_IS_ALLOWED(pAd))
{
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> ACM is not allowed!\n"));
return ACM_RTN_DISALLOW;
} /* End of if */
#ifdef ACM_CC_FUNC_ACL
/* ACL check */
if (ACM_MR_ACL_IS_ENABLED(pAd))
{
BOOLEAN FlgIsAllowed;
ACM_ACL_ENTRY_GET(pAd, ACMR_CLIENT_MAC(pCdb), FlgIsAllowed, NULL);
if (FlgIsAllowed == FALSE)
{
/* not in ACL list so we reject it */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
return ACM_RTN_DISALLOW;
} /* End of if */
}
#endif /* ACM_CC_FUNC_ACL */
ACMR_MEM_COPY(FlgAcmStatus, ACMR_CB->EdcaCtrlParam.FlgAcmStatus,
sizeof(FlgAcmStatus));
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* init */
pOldStreamIn = NULL;
pOldStreamOut = NULL;
pOldStreamDiffAc = NULL;
RtnCode = ACM_RTN_FAIL;
StatusCode = ACM_STATUS_CODE_UNSPECIFIED_FAILURE;
ApsdAcId = 0;
FlgIsApsdEnable = 0;
*pMediumTime = 0;
FlgIsSupRate = 0;
/* allocate a TSPEC request TS */
ACMR_MEM_ALLOC(pNewStream, sizeof(ACM_STREAM), (ACM_STREAM *));
if (pNewStream == NULL)
return ACM_RTN_ALLOC_ERR;
/* End of if */
ACMR_MEM_ZERO(pNewStream, sizeof(ACM_STREAM));
/* init client database pointer, Dialog Token, TSPEC, TCLASS, and
TCLASS Processing */
ACM_STREAM_CDB_COPY(pNewStream, pCdb);
pNewStream->DialogToken = DialogToken;
pNewStream->StreamType = StreamType;
/* allocate/copy a TSPEC */
ACMR_MEM_ALLOC(pNewStream->pTspec, sizeof(ACM_TSPEC), (ACM_TSPEC *));
if (pNewStream->pTspec == NULL)
goto LabelErrAlloc;
/* End of if */
ACM_TSPEC_COPY(pNewStream->pTspec, pTspec);
#ifdef ACM_CC_FUNC_TCLAS
/* continue to check input TSPEC parameters */
if ((TclasNum > 1) && (TclasProcessing == ACM_TCLAS_PROCESSING_NOT_EXIST))
{
/* ERR! no TCLAS Processing element is found when num of TCLAS >= 2 */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> No tclas processing element!\n"));
StatusCode = ACM_STATUS_CODE_DECLINED;
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
#endif /* ACM_CC_FUNC_TCLAS */
if (pTspec->TsInfo.AccessPolicy != ACM_ACCESS_POLICY_EDCA)
{
/* ERR! we do NOT support HCCA */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Access policy %d != EDCA %d!\n",
pTspec->TsInfo.AccessPolicy,
ACM_ACCESS_POLICY_EDCA));
StatusCode = ACM_STATUS_CODE_DECLINED;
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
#ifdef ACM_CC_FUNC_TCLAS
if ((TclasProcessing != ACM_WME_TCLAS_PROCESSING_ALL) &&
(TclasProcessing != ACM_WME_TCLAS_PROCESSING_ONE) &&
(TclasProcessing != ACM_TCLAS_PROCESSING_NOT_EXIST))
{
/* ERR! invalid TCLAS Processing value in D6.0 */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Wrong tclas process value!\n"));
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
#endif /* ACM_CC_FUNC_TCLAS */
/* ---- Create and init a stream structure ---- */
#ifdef RELEASE_EXCLUDE
/* =====================================================================
1. Specification Interval must be greater than or equal to
Delay Bound;
2. Service Interval must be less than or equal to Maximum Service
Interval and greater than or equal to Minimum Service Interval;
3. The total sum of maximum service durations of all service
intervals within the specification interval must be greater than
((MDR * SI)/NMS) * D, where MDR = Mean Data Rate,
SI = Specification Interval, NMS = Nominal MSDU Size and
D = the duration to transmit a MSDU of size equal to Nominal MSDU
Size at Minimum PHY Rate.
===================================================================== */
#endif /* RELEASE_EXCLUDE */
#ifdef ACM_CC_FUNC_TCLAS
/* allocate/copy TCLAS */
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pTclas[IdTclasNum] != NULL)
{
ACMR_MEM_ALLOC(pNewStream->pTclas[IdTclasNum],
sizeof(ACM_TCLAS), (ACM_TCLAS *));
if (pNewStream->pTclas[IdTclasNum] == NULL)
{
RtnCode = ACM_RTN_ALLOC_ERR;
goto LabelRspErr;
} /* End of if */
ACM_TCLAS_COPY(pNewStream->pTclas[IdTclasNum], pTclas[IdTclasNum]);
continue;
} /* End of if */
/* OK! all TCLAS are copied */
break;
} /* End of for */
#endif /* ACM_CC_FUNC_TCLAS */
/* init other parameters */
pNewStream->TclasProcessing = TclasProcessing;
pNewStream->TimeoutDelts = ACM_DELTS_TIMEOUT/ACM_TIMEOUT_CHECK_BASE;
/* ---- Sanity check for TSPEC parameters ---- */
/* check source STA */
if ((ACMR_IS_QSTA(pCdb) == 0) && (!ACMR_IS_WMM_STA(pCdb)))
{
/* ERR! source STA is not a QSTA and not a WMM STA */
StatusCode = ACM_STATUS_CODE_DECLINED;
goto LabelRspErr;
} /* End of if */
/* check TCLSS parameters and get user priority */
UserPriority = ACM_UP_UNKNOWN;
#ifdef ACM_CC_FUNC_TCLAS
for(IdTclasNum=0; IdTclasNum<TclasNum; IdTclasNum++)
{
if (pTclas[IdTclasNum] != NULL)
{
/* check classifier type */
if (pTclas[IdTclasNum]->ClassifierType > ACM_TCLAS_TYPE_MAX)
{
/* classifier type is illegal */
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
/* check user priority, priority for each TCLAS must be the same */
if (UserPriority == ACM_UP_UNKNOWN)
UserPriority = pTclas[IdTclasNum]->UserPriority;
else
{
if (pTclas[IdTclasNum]->UserPriority != UserPriority)
{
/* user priority for all TCLASS element shall be the same */
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
} /* End of if */
} /* End of if */
} /* End of for */
#endif /* ACM_CC_FUNC_TCLAS */
/* ---- Check for Direct Link TSPEC ---- */
if (pTspec->TsInfo.Direction == ACM_DIRECTION_DIRECT_LINK)
{
/* DLP is not allowed */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Direct Link is not allowed!\n"));
StatusCode = ACM_STATUS_CODE_DIRECT_LINK_IS_NOT_ALLOWED;
goto LabelRspErr;
} /* End of if */
/* ---- Update the UP ---- */
if (UserPriority == ACM_UP_UNKNOWN)
{
/* use the UP in the TSPEC if no any TCLAS exists */
UserPriority = pTspec->TsInfo.UP;
} /* End of if */
pNewStream->UP = UserPriority;
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> UP = %d\n", UserPriority));
/* ---- non-ACM TSPEC check ---- */
StmAcId = ACM_MR_EDCA_AC(UserPriority);
/* we need to keep the TSPEC even it is a NULL TSPEC so mark the code */
#if 0
if ((FlgAcmStatus[StmAcId] == ACM_FLG_FUNC_DISABLED)
#ifdef ACM_CC_FUNC_SPEC_CHANGE_TG
/*
WMM Spec changes for TSPECs on non-ACM ACs:
Note that the Mean Data Rate field in a TSPEC request may be set
to zero, indicating that no admitted time is being requested.
This might be used, for example, to modify the U-APSD settings
for the AC.
*/
|| (pTspec->MeanDataRate == 0)
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
)
{
/* change PS mode only because ACM is disabled */
/* reset to Legacy or UAPSD PS */
ACM_APSD_Ctrl(pAd, pCdb, StmAcId,
pNewStream->pTspec->TsInfo.Direction,
1, pTspec->TsInfo.APSD);
#ifdef ACM_CC_FUNC_SPEC_CHANGE_TG
if (pTspec->MeanDataRate == 0)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Mean Data Rate == 0! Only change PS mechanism!\n"));
}
else
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> ACM is disabled! Only change PS mechanism!\n"));
StatusCode = ACM_STATUS_CODE_SUCCESS;
RtnCode = ACM_RTN_OK;
goto LabelErrAlloc;
} /* End of if */
#endif
/* ---- Sanity check for TSPEC parameters (after non-ACM TSPEC) ---- */
if (pTspec->MinPhyRate == 0)
{
/* use observed physical rate of the ADDTS request frame */
pTspec->MinPhyRate = PhyRate;
} /* End of if */
#ifdef ACM_CC_FUNC_TCLAS
if ((pTspec->MinPhyRate == 0) ||
(TclasNum > ACM_TSPEC_TCLAS_MAX_NUM))
#else
if (pTspec->MinPhyRate == 0)
#endif /* ACM_CC_FUNC_TCLAS */
{
/* in WMM ACM WIFI test spec., min phy rate can NOT be 0 */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> min phy rate = 0 or tclas is too many!\n"));
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
ACM_TG_CMT_UAPSD_SETTING_ON_NON_ACM_AC;
/* check if the TSPEC is for non-ACM AC */
#ifdef ACM_CC_FUNC_SPEC_CHANGE_TG
if (FlgAcmStatus[StmAcId] != ACM_FLG_FUNC_DISABLED)
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
{
UINT32 MaxRate;
ACM_TG_CMT_MIN_PHY_RATE;
/* check min phy rate can not larger than maximum supported rate */
ACMR_SUP_RATE_MAX_GET(pAd, pCdb, MaxRate);
if (pTspec->MinPhyRate > MaxRate)
{
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> min phy rate %dbps > "
"maximum supported rate %dbps!\n",
pTspec->MinPhyRate, MaxRate));
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
/* check min phy rate must be one of supported rates non-11n */
#ifdef ACM_CC_FUNC_11N
if (!ACMR_IS_11N_ONLY_SUPPORT(pAd, pCdb))
/* if only 11n is supported, no need to check non-11n supported rate */
#endif /* ACM_CC_FUNC_11N */
{
ACMR_SUP_RATE_CHECK(pAd, pTspec->MinPhyRate, FlgIsSupRate);
}
#ifdef ACM_CC_FUNC_11N_AGG
/* set maximum BA Window Size */
pNewStream->HT_BaWinSize = 64; /* default maximum */
ACMR_STA_MAX_BACK_NUM_GET(pAd, pCdb, pNewStream->HT_BaWinSize);
/* get packet aggregation information */
if (pTspec->MaxBurstSize > 0)
{
if (pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
{
/* double check the number of MPDUs */
if (pTspec->TsInfo.Direction != ACM_DIRECTION_UP_LINK)
{
/* no need to check for uplink of QSTA */
if (pTspec->MaxBurstSize > pNewStream->HT_BaWinSize)
pTspec->MaxBurstSize = pNewStream->HT_BaWinSize;
/* End of if */
} /* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> number of MPDUs in a AMPDU = %d\n",
ACMR_11N_AGG_NUM_OF_MSDUS_GET(pTspec->MaxBurstSize)));
} /* End of if */
/* maybe update modified MaxBurstSize for 11n */
pNewStream->pTspec->MaxBurstSize = pTspec->MaxBurstSize;
}
else
{
/*
If the TS Info Ack Policy field is set to the value for
HT-immediate block acknowledgement, then the MaxBurstSize
shall be larger than 0.
*/
if (pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
pTspec->TsInfo.AckPolicy = ACM_ACK_POLICY_NORMAL;
/* End of if */
} /* End of if */
if (ACMR_IS_11N_SUPPORT(pAd) && ACMR_STA_IS_11N_SUPPORT(pCdb))
;
else
{
/* reset parameters for non-11n devices (AP or STA) */
if (pTspec->TsInfo.AckPolicy == ACM_ACK_POLICY_BLOCK)
pTspec->TsInfo.AckPolicy = ACM_ACK_POLICY_NORMAL;
/* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> AP or STA is not 11n so reset "
"AckPolicy to Normal ACK\n"));
} /* End of if */
#endif /* ACM_CC_FUNC_11N_AGG */
if (FlgIsSupRate == 0)
{
#ifdef ACM_CC_FUNC_11N
/* check if AP & STA support 11n mode */
if (ACMR_IS_11N_SUPPORT(pAd) && ACMR_STA_IS_11N_SUPPORT(pCdb))
{
/* check min phy rate must be one of supported rates 11n */
ACMR_SUP_RATE_CHECK_11N(pAd,
pCdb,
pTspec->MinPhyRate,
FlgIsSupRate);
} /* End of if */
#endif /* ACM_CC_FUNC_11N */
#if 0
/*
Too many vendors use non-supported minimum physical rate in
Plugfest#6, so I disable the function to avoid our customers
complains it in the future.
*/
if (FlgIsSupRate == 0)
{
/* not supported rate */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> min phy rate %d is not a supported rate!!!\n",
pTspec->MinPhyRate));
RtnCode = ACM_RTN_INVALID_PARAM;
goto LabelRspErr;
} /* End of if */
#endif /* 0 */
} /* End of if */
ACM_TG_CMT_B0_TS_INFO;
/* check minimum TSPEC parameters, reference to Annex H.1 in D6.0 */
Policy = pTspec->TsInfo.AccessPolicy;
if (Policy == ACM_ACCESS_POLICY_EDCA)
{
/* Contention Based CBR Traffic, EDCA */
if ((pTspec->NominalMsduSize == 0) ||
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
(pTspec->MeanDataRate == 0) ||
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
(pTspec->SurplusBandwidthAllowance == 0) ||
(pTspec->TsInfo.Aggregation != ACM_AGGREGATION_DISABLE) ||
(pTspec->TsInfo.Schedule != ACM_SCHEDULE_NO))
{
/* some parameters are invalid */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> nominal msdu size = %d or "
"mean data rate = %d or "
"surplus bandwidth allowance = %d or "
"aggregation = %d or "
"schedule = %d!\n",
pTspec->NominalMsduSize,
pTspec->MeanDataRate,
pTspec->SurplusBandwidthAllowance,
pTspec->TsInfo.Aggregation,
pTspec->TsInfo.Schedule));
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
}
else
{
/* non-EDCA is not support */
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
#ifdef ACM_CC_FUNC_HCCA
/* check suspension interval */
if ((pTspec->SuspensionInt != ACM_TSPEC_SUSPENSION_DISABLE) &&
(pTspec->InactivityInt != ACM_TSPEC_INACTIVITY_DISABLE))
{
/* suspension and inactivity interval are enabled */
if (pTspec->SuspensionInt >= pTspec->InactivityInt)
{
/* error: suspension interval > inactivity interval */
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
} /* End of if */
/* check TS Info */
if (pTspec->TsInfo.AckPolicy != ACM_ACK_POLICY_NORMAL)
{
ACM_TG_CMT_NO_ACK_POLICY;
/*
1. Block Ack state change is not supported for WMM ACM;
2. No ACK is not supported for WMM ACM;
3. No schedule is needed because no scheduled EDCA APSD
is supported.
*/
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
/* get QOS MIB database */
if (pTspec->TsInfo.Aggregation == 1)
{
/* not support */
} /* End of if */
/* check service start time */
if (pTspec->ServiceStartTime != 0)
{
/* not support */
} /* End of if */
/* check minimum service interval */
if (pTspec->MinServInt != 0)
{
/* mininum service interval is enabled */
if (pTspec->MinServInt < ACM_TSPEC_MIN_SERV_INT_LIMIT)
{
/* minimum service interval is too small */
pTspec->MinServInt = ACM_TSPEC_MIN_SERV_INT_LIMIT;
StatusCode = ACM_STATUS_CODE_SUGGESTED_TSPEC;
goto LabelRspErr;
} /* End of if */
} /* End of if */
if (pTspec->MinServInt > ACM_TSPEC_INACTIVITY_MIN)
MinServInt = (pTspec->MinServInt<<1); /* for safe, *2 */
else
MinServInt = ACM_TSPEC_INACTIVITY_MIN;
/* End of if */
/* check minimum inactivity interval (must > minimum SI) */
if (pTspec->InactivityInt != ACM_TSPEC_INACTIVITY_DISABLE)
{
/* inactivity interval is enabled */
if (pTspec->InactivityInt < MinServInt)
{
/* inactivity interval is too small */
pTspec->InactivityInt = MinServInt;
StatusCode = ACM_STATUS_CODE_SUGGESTED_TSPEC;
goto LabelRspErr;
} /* End of if */
} /* End of if */
/* check minimum suspension interval */
if (pTspec->SuspensionInt != ACM_TSPEC_SUSPENSION_DISABLE)
{
/* suspension interval is enabled */
if (pTspec->SuspensionInt < ACM_TSPEC_SUSPENSION_MIN)
{
/* suspension interval is too small */
pTspec->SuspensionInt = ACM_TSPEC_SUSPENSION_MIN;
StatusCode = ACM_STATUS_CODE_SUGGESTED_TSPEC;
goto LabelRspErr;
} /* End of if */
} /* End of if */
#endif /* ACM_CC_FUNC_HCCA */
} /* End of if */
/* ---- Handle TSPEC ---- */
/* #ifndef ACM_CC_FUNC_SPEC_CHANGE_TG */
/* adjust min phy rate and get minimum phy mode & mcs */
ACM_PacketPhyModeMCSSet(pAd, pNewStream);
/* #endif */
if (pTspec->TsInfo.AccessPolicy == ACM_ACCESS_POLICY_EDCA)
{
/* no aggregation support for EDCA */
if (pTspec->TsInfo.Aggregation == ACM_AGGREGATION_ENABLE)
{
pTspec->TsInfo.Aggregation = ACM_AGGREGATION_DISABLE;
StatusCode = ACM_STATUS_CODE_SUGGESTED_TSPEC;
goto LabelRspErr;
} /* End of if */
RtnCode = ACM_RTN_SEM_GET_ERR;
/* semaphore protection */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* check if the request is a negotiated request */
Status = ACM_TC_RenegotiationCheck(
pAd,
ACMR_CLIENT_MAC(pCdb),
UserPriority,
&pTspec->TsInfo,
&pOldStreamIn,
&pOldStreamOut,
&pOldStreamDiffAc);
#ifdef ACM_CC_FUNC_REPLACE_RULE_TG
#ifdef RELEASE_EXCLUDE
/* apply replacement check rule from WMM ACM Task Group */
/* but some rules can be accepted in IEEE802.11e spec. */
/*
We can not accept a replacement TSPEC if
1. same TID, but not same AC;
*/
#endif /* RELEASE_EXCLUDE */
if (Status == ACM_RTN_OK)
{
if (ACM_TC_ReplacementCheck(pAd,
ACMR_CLIENT_MAC(pCdb),
UserPriority,
&pTspec->TsInfo) != ACM_RTN_OK)
{
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Reject the TSPEC due to "
"replacement rule check!\n"));
StatusCode = ACM_STATUS_CODE_INVALID_PARAMETERS;
goto LabelRspErr;
} /* End of if */
} /* End of if */
#endif /* ACM_CC_FUNC_REPLACE_RULE_TG */
switch(Status)
{
case ACM_RTN_FAIL:
/* this is a new request */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> new TSPEC!\n"));
break;
case ACM_RTN_OK:
/* this is negotiated request */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> same TSPEC!\n"));
pNewStream->ReNegotiation = 1; /* this is a nego TSPEC */
break;
case ACM_RTN_FATAL_ERR:
case ACM_RTN_RENO_IN_REQ_LIST:
default:
/*
Only these TSPEC whose Status == DELETING will exist in
the requested list, means the old one is in DELETING state,
we do NOT handle any negotiated request for this one.
*/
StatusCode = ACM_STATUS_CODE_UNSPECIFIED_FAILURE;
goto LabelErr;
} /* End of switch */
/*
Assign TS ID:
AcmAcId: for dnlink or bidirectional link, it is the physical TS
or AC ID; otherwise it is the backup array ID.
*/
pNewStream->AcmAcId = ACM_MR_EDCA_AC(pNewStream->UP);
/*
Check ok so calculate needed medium time.
Note: if no ACM is needed for the AC, ACM_EDCA_ReqHandle() will
return error.
*/
StatusCode = ACM_EDCA_ReqHandle(pAd,
pCdb,
pNewStream,
pOldStreamIn,
pOldStreamOut,
pOldStreamDiffAc);
if (StatusCode == ACM_STATUS_CODE_SUCCESS)
{
/* add the device to the entry list */
ACM_PeerDeviceAdd(pAd, ACMR_CLIENT_MAC(pCdb));
/* get UAPSD parameters */
ApsdAcId = pNewStream->AcmAcId;
FlgIsApsdEnable = pTspec->TsInfo.APSD;
/* assign return medium time */
if (pTspec->TsInfo.Direction != ACM_DIRECTION_DOWN_LINK)
*pMediumTime = pNewStream->pTspec->MediumTime;
/* End of if */
} /* End of if */
if (StatusCode != ACM_STATUS_CODE_SUCCESS)
{
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
goto LabelRspErr;
} /* End of if */
goto LabelOK;
} /* End of if */
/* ---- Handle non-EDCA TSPEC ---- */
/* HCCA is not support */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> HCCA is not supported!\n"));
StatusCode = ACM_STATUS_CODE_DECLINED;
RtnCode = ACM_RTN_DISALLOW;
goto LabelRspErr;
LabelOK:
/* active stream check timer for any stream */
ACMR_TIMER_ENABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck,
ACM_STREAM_CHECK_OFFSET);
#ifdef RELEASE_EXCLUDE
/*
If Station is in PS mode, we need to reset APSD state after the queued
ADDTS Response frame is sent to the PS station.
*/
#endif /* RELEASE_EXCLUDE */
if (ACMR_STA_IS_IN_ACTIVE_MODE(pCdb))
{
/* reset UAPSD state only in ACTIVE state */
ACM_APSD_Ctrl(pAd, pCdb, ApsdAcId,
pNewStream->pTspec->TsInfo.Direction,
1, FlgIsApsdEnable);
}
else
{
/* mark a UAPSD unhandled flag for TSPEC */
pNewStream->FlgUapsdHandleNeed = 1;
} /* End of if */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* response TSPEC to QSTA with code = success */
*pStatusCode = ACM_STATUS_CODE_SUCCESS;
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("\nacm_msg> A request is accepted (Status=%d)!\n",
*pStatusCode));
return ACM_RTN_OK;
LabelErr:
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
LabelRspErr:
LabelSemErr:
/* response TSPEC to QSTA with error code */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A request is rejected (%d)!\n", StatusCode));
LabelErrAlloc:
/* free local allocated memory */
ACM_FREE_TS(pNewStream);
*pStatusCode = StatusCode;
return RtnCode;
} /* End of ACM_TC_ReqHandle */
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
/* =========================== Station Function =========================== */
/*
========================================================================
Routine Description:
Handle the Action Frame transmitted from QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - the source QSTA
*pMblk - the received frame
PktLen - the frame length
Return Value:
None
Note:
========================================================================
*/
STATIC VOID ACM_ActionHandleByQSTA(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR *pMblk,
ACM_PARAM_IN UINT32 PktLen)
{
ACM_WME_NOT_FRAME *pNotFrame;
UCHAR *pActFrame;
UCHAR Category, Action;
UINT32 BodyLen;
UCHAR StatusCode;
UINT16 MediumTime; /* no use */
WMM_ACM_FUNC_NAME_PRINT("IN");
/* points to the action frame WLAN header */
pActFrame = (UCHAR *)pMblk;
/* get Category & Action field */
BodyLen = PktLen - ACMR_FME_LEG_HEADER_SIZE;
pActFrame += ACMR_FME_LEG_HEADER_SIZE;
Category = *pActFrame;
Action = *(pActFrame+1);
/* sanity check for peer */
#ifdef ACM_CC_FUNC_MBSS
if ((Action != ACM_ACTION_WME_BW_ANN) && (pCdb == NULL))
#else
if (pCdb == NULL)
#endif /* ACM_CC_FUNC_MBSS */
goto label_exit; /* wrong packet source */
/* End of if */
/* handle by Category */
if (Category == ACM_CATEGORY_WME)
{
/* WME action frame */
switch(Action)
{
case ACM_ACTION_WME_SETUP_RSP: /* ADDTS Response */
ACM_WME_ActionHandle(pAd,
pCdb,
pActFrame,
BodyLen,
0, /* dont care */
ACM_ACTION_WME_SETUP_RSP,
&StatusCode,
&MediumTime);
break;
case ACM_ACTION_WME_TEAR_DOWN: /* DELTS */
ACM_WME_ActionHandle(pAd,
pCdb,
pActFrame,
BodyLen,
0, /* dont care */
ACM_ACTION_WME_TEAR_DOWN,
&StatusCode,
&MediumTime);
break;
#ifdef ACM_CC_FUNC_MBSS
case ACM_ACTION_WME_BW_ANN: /* BW ANN */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> A WME BW ANN frame is received!\n"));
ACM_MBSS_BwAnnHandle(pAd, pActFrame, BodyLen);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Forward the bandwidth announce...\n"));
/* forward the public frame to other BSSs */
ACM_MBSS_BwAnnForward(pAd, pMblk, PktLen);
goto label_exit;
#endif /* ACM_CC_FUNC_MBSS */
default:
goto label_exit;
} /* End of switch */
/* check if we need to reply a DELTS frame; if TRUE, send out one */
if (Action == ACM_ACTION_WME_SETUP_RSP)
{
StatusCode = ACM_11E_WMM_StatusTranslate(StatusCode);
if (StatusCode == WLAN_STATUS_CODE_WME_REFUSED)
{
UCHAR MAC_RA[6], MAC_TA[6];
/* init response frame */
pNotFrame = (ACM_WME_NOT_FRAME *)pActFrame;
pNotFrame->Action = ACM_ACTION_WME_TEAR_DOWN;
pNotFrame->DialogToken = 0;
pNotFrame->StatusCode = 0;
/* swap DA & SA */
ACMR_WLAN_PKT_RA_GET(pMblk, MAC_RA);
ACMR_WLAN_PKT_TA_GET(pMblk, MAC_TA);
ACMR_WLAN_PKT_RA_SET(pMblk, MAC_TA);
ACMR_WLAN_PKT_TA_SET(pMblk, MAC_RA);
/* send out it */
ACMR_MGMT_PKT_TX(pAd, pMblk, PktLen);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> TX a DELTS frame.\n"));
} /* End of if */
} /* End of if */
} /* End of if */
label_exit:
return;
} /* End of ACM_ActionHandleByQSTA */
/*
========================================================================
Routine Description:
Handle a TSPEC response from the QAP.
Arguments:
pAd - WLAN control block pointer
*pCdb - the client database
DialogToken - the TSPEC ID
StatusCode - the response status
*pTspec - the requested TSPEC pointer
*pTsDelay - the TS Delay element (no use)
*pStatusCode - response status code
Return Value:
ACM_RTN_OK - request is accepted
ACM_RTN_FATAL_ERR - error operation mode
ACM_RTN_FAIL - semaphore lock fail or others
ACM_RTN_NULL_POINTER - null pointer
ACM_RTN_ALLOC_ERR - TSPEC request structure allocation fail
ACM_RTN_DELTS - need to send a DELTS to the peer
Note:
1. Only for Client Mode.
2. DLP is not allowed.
3. *pTspec can not be freed here.
========================================================================
*/
STATIC ACM_FUNC_STATUS ACM_TC_RspHandle(
ACM_PARAM_IN PRTMP_ADAPTER pAd,
ACM_PARAM_IN ACMR_STA_DB *pCdb,
ACM_PARAM_IN UCHAR DialogToken,
ACM_PARAM_IN UCHAR StatusCode,
ACM_PARAM_IN ACM_TSPEC *pTspec,
ACM_PARAM_IN ACM_ELM_TS_DELAY *pTsDelay,
ACM_PARAM_OUT UCHAR *pStatusCode)
{
#define TC_LMR_STREAM_DESTROY(__pAd, __StmAcId, __pStreamReq) \
__StmAcId = __pStreamReq->AcmAcId; \
ACM_TC_Destroy(__pAd, __pStreamReq, 0);
ACM_STREAM *pStreamReq, *pOldStreamIn, *pOldStreamOut, *pOldStreamDiffAc;
ACM_FUNC_STATUS RtnCode, Status;
UINT32 Direction, RetryCountOldSettings;
UCHAR StmAcId, ApsdAcId, FlgIsApsdEnable;
ULONG SplFlags;
WMM_ACM_FUNC_NAME_PRINT("IN");
/* init */
*pStatusCode = ACM_STATUS_CODE_SUCCESS;
RtnCode = ACM_RTN_FAIL;
RetryCountOldSettings = 0xFFFFFFFF;
ACMR_RETRY_GET(pAd, RetryCountOldSettings);
/* semaphore protection */
ACM_TSPEC_SEM_LOCK_CHK_RTN(pAd, SplFlags, LabelSemErr, ACM_RTN_FAIL);
/* find its requested TSPEC in the requested list */
pStreamReq = ACMR_CB->TspecListReq.pHead;
while(pStreamReq != NULL)
{
if (pStreamReq->DialogToken == DialogToken)
break; /* find it */
/* End of if */
pStreamReq = pStreamReq->pNext;
} /* End of while */
if (pStreamReq == NULL)
{
/* maybe error response Dialog Token, try to find the correct TSPEC */
pStreamReq = ACM_TC_FindInReq(\
pAd, ACMR_CLIENT_MAC(pCdb), &pTspec->TsInfo);
if (pStreamReq != NULL)
pStreamReq->Cause = TSPEC_CAUSE_REJ_INVALID_TOKEN;
/* End of if */
pStreamReq = ACM_TC_FindInPeer(\
pAd, ACMR_CLIENT_MAC(pCdb), &pTspec->TsInfo);
if (pStreamReq != NULL)
{
/* already exist in ACTIVE TSPECs */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> Find exist same active TSPEC. Skip the response. "
"TC_RspHandle()\n"));
goto LabelHandleOK;
} /* End of if */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> Can not find any request/active TSPEC! "
"TC_RspHandle()\n"));
pStreamReq = NULL;
goto LabelHandleErr;
} /* End of if */
/* check if the status of our requested TSPEC is DELETING */
if ((pStreamReq->Status == TSPEC_STATUS_REQ_DELETING) ||
(pStreamReq->Status == TSPEC_STATUS_ACT_DELETING))
{
goto LabelHandleErr;
} /* End of if */
if ((pStreamReq->Status != TSPEC_STATUS_REQUEST) &&
(pStreamReq->Status != TSPEC_STATUS_RENEGOTIATING))
{
/* must be new TSPEC request or TSPEC negotiate */
goto LabelHandleErr;
} /* End of if */
#ifdef ACM_CC_FUNC_SPEC_CHANGE_TG
#ifdef RELEASE_EXCLUDE
/*
WMM Spec changes for TSPECs on non-ACM ACs:
1. Verify the following bits: TID (b4-b1), DIR (b6-b5), b7=1, b8=0,
PSB (b10), UP (b13-b11)
2. Reserved (b23 ~ b16, b9) are 0
3. Verify b0 is identical to b0 in the TS_INFO field of the
TSPEC in the ADDTS Request frame
4. Verify b15-b14 are identical to b15-b14 in the TS_INFO field of the
TSPEC in the ADDTS Request frame.
*/
#endif /* RELEASE_EXCLUDE */
if ((pTspec->TsInfo.AccessPolicy != ACM_ACCESS_POLICY_EDCA) ||
(pTspec->TsInfo.Aggregation != ACM_AGGREGATION_DISABLE) ||
(pTspec->TsInfo.Schedule != ACM_SCHEDULE_NO) ||
(pTspec->TsInfo.TrafficType != pStreamReq->pTspec->TsInfo.TrafficType) ||
(pTspec->TsInfo.AckPolicy != pStreamReq->pTspec->TsInfo.AckPolicy))
{
goto LabelHandleErr;
} /* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
/* check the response status code */
if (pStreamReq->StreamType == ACM_SM_TYPE_11E)
{
/* 11E ADDTS response */
switch(StatusCode)
{
case ACM_STATUS_CODE_SUGGESTED_TSPEC:
/* QAP modify our requested TSPEC */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> QAP gives me a suggested TSPEC! "
"TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CAUSE_SUGGESTED_TSPEC;
goto LabelErr;
case ACM_STATUS_CODE_DECLINED:
/* QAP declines us */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> QAP declines my request! "
"TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CAUSE_REJECTED;
goto LabelErr;
case ACM_STATUS_CODE_SUCCESS:
/* QAP accept us */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> QAP accepts my request! "
"TC_RspHandle()\n"));
break;
default:
/* other error status code */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> QAP rejects my request with unknown "
"status! TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CAUSE_UNKNOWN_STATUS;
goto LabelErr;
} /* End of switch */
}
else
{
/* WMM ADDTS response */
switch(StatusCode)
{
case ACM_STATUS_CODE_WMM_INVALID_PARAMETERS:
/* QAP modify our requested TSPEC */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> QAP refuses my request due to invalid "
"parameters! TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CASUE_REJ_INVALID_PARAM;
goto LabelErr;
case ACM_STATUS_CODE_WMM_REFUSED:
/* QAP declines us */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_err> QAP refuses my request! "
"TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CAUSE_REJECTED;
goto LabelErr;
case ACM_STATUS_CODE_WMM_SUCCESS:
/* QAP accept us */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> QAP accepts my request! "
"TC_RspHandle()\n"));
break;
default:
/* other error status code */
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> QAP rejects my request with unknown "
"status! TC_RspHandle()\n"));
pStreamReq->Cause = TSPEC_CAUSE_UNKNOWN_STATUS;
goto LabelErr;
} /* End of switch */
} /* End of if */
/* remove it from the "requested" list, not free it */
ACM_TC_ReqRemove(pAd, pStreamReq);
/* we need to keep the TSPEC even it is a NULL TSPEC */
#ifndef ACM_CC_FUNC_SPEC_CHANGE_TG
/* check if ACM is needed for the AC */
if (ACMR_CB->EdcaCtrlParam.FlgAcmStatus[ACM_MR_EDCA_AC(pStreamReq->UP)] == 0)
{
ApsdAcId = pStreamReq->AcmAcId;
FlgIsApsdEnable = pStreamReq->pTspec->TsInfo.APSD;
/* change PS mode only because ACM is disabled */
ACMR_DEBUG(ACMR_DEBUG_TRACE, ("acm_msg> Only change PS mode!\n"));
/* reset UAPSD state */
ACM_APSD_Ctrl(pAd, pCdb, ApsdAcId,
pStreamReq->pTspec->TsInfo.Direction,
1, FlgIsApsdEnable);
/* free the request */
ACM_TC_Free(pAd, pStreamReq);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* return power save right to system */
ACMP_StaPsCtrlRightReturn(pAd);
goto LabelHandleOK;
} /* End of if */
#endif /* ACM_CC_FUNC_SPEC_CHANGE_TG */
/* response status is SUCCESS so active the stream */
if (pStreamReq->pTspec->TsInfo.AccessPolicy == ACM_ACCESS_POLICY_EDCA)
{
/* update the medium time allocated from QAP */
pStreamReq->pTspec->MediumTime = pTspec->MediumTime;
/* get old input or output TSPEC if exists */
if (pStreamReq->ReNegotiation == 0)
{
/* new stream is accepted */
pOldStreamIn = NULL;
pOldStreamOut = NULL;
pOldStreamDiffAc = NULL;
}
else
{
/* negotiated stream is accepted */
Status = ACM_TC_RenegotiationCheck(pAd,
ACMR_CLIENT_MAC(pCdb),
pStreamReq->UP,
&pStreamReq->pTspec->TsInfo,
&pOldStreamIn,
&pOldStreamOut,
&pOldStreamDiffAc);
} /* End of if */
/* update stream status and inactivity time */
pStreamReq->Status = TSPEC_STATUS_ACTIVE;
pStreamReq->InactivityCur = pStreamReq->pTspec->InactivityInt;
/* delete old TSPEC if exists */
if (pOldStreamIn != NULL)
ACM_TC_Discard(pAd, pOldStreamIn);
/* End of if */
if (pOldStreamOut != NULL)
ACM_TC_Discard(pAd, pOldStreamOut);
/* End of if */
if (pOldStreamDiffAc != NULL)
ACM_TC_Discard(pAd, pOldStreamDiffAc);
/* End of if */
/* active the new or negotiated stream */
if (ACM_TC_Active(pAd, pStreamReq) != ACM_RTN_OK)
{
/* should be not here */
*pStatusCode = ACM_STATUS_CODE_DECLINED;
goto LabelErr;
} /* End of if */
/* update new used ACM time */
Direction = pStreamReq->pTspec->TsInfo.Direction;
if (pStreamReq->pTspec->MediumTime > 0)
{
ACM_EDCA_Param_ACM_Update(pAd, pStreamReq->AcmAcId,
Direction,
pStreamReq->UP,
pStreamReq->pTspec->MediumTime<<5,
0,
#ifdef RELEASE_EXCLUDE
ACM_DATL_NO_BORROW,
#else
0,
#endif /* RELEASE_EXCLUDE */
0);
/* update to CSR if needed */
if ((Direction == ACM_DIRECTION_UP_LINK) ||
(Direction == ACM_DIRECTION_DIRECT_LINK))
{
StmAcId = pStreamReq->AcmAcId;
ACM_ASIC_ACM_Reset(pAd, StmAcId,
ACMR_CB->EdcaCtrlParam.AcmOutTime[StmAcId]);
} /* End of if */
} /* End of if */
/* backup peer device MAC */
ACM_PeerDeviceAdd(pAd, ACMR_CLIENT_MAC(pCdb));
}
else
{
/* non-EDCA access policy is not supported */
TC_LMR_STREAM_DESTROY(pAd, StmAcId, pStreamReq);
goto LabelHandleErr;
} /* End of if */
/* calculate minimum phy mode & mcs to the pStreamReq */
ACM_PacketPhyModeMCSSet(pAd, pStreamReq);
#ifdef ACM_CC_FUNC_11N
/* set maximum BA Window Size */
pStreamReq->HT_BaWinSize = 64; /* maximum */
ACMR_STA_MAX_BACK_NUM_GET(pAd, pCdb, pStreamReq->HT_BaWinSize);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> BA Win Size = %d\n", pStreamReq->HT_BaWinSize));
#endif /* ACM_CC_FUNC_11N */
/* get UAPSD parameters */
ApsdAcId = pStreamReq->AcmAcId;
FlgIsApsdEnable = pStreamReq->pTspec->TsInfo.APSD;
/* active stream check timer for any stream */
ACMR_TIMER_ENABLE(ACMR_CB->FlgStreamAliveCheckEnable,
ACMR_CB->TimerStreamAliveCheck,
ACM_STREAM_CHECK_OFFSET);
/* reset UAPSD state */
ACM_APSD_Ctrl(pAd, pCdb, ApsdAcId,
pStreamReq->pTspec->TsInfo.Direction,
1, FlgIsApsdEnable);
if (RetryCountOldSettings != 0xFFFFFFFF)
ACMR_CB->RetryCountOldSettings = RetryCountOldSettings;
/* End of if */
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
/* return power save right to system */
ACMP_StaPsCtrlRightReturn(pAd);
/* retry count change */
ACMR_RETRY_DISABLE(pAd);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> My request is successfully %d! TC_RspHandle()\n",
*pStatusCode));
LabelHandleOK:
return ACM_RTN_OK;
LabelHandleErr:
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
#ifdef RELEASE_EXCLUDE
/*
The ADDTS response handle fail, send a DELTS frame to the QAP due to
parsing error.
Reply a DELTS frame to QAP and the stream will be deleted after
the DELTS frame is ACKed.
*/
#endif /* RELEASE_EXCLUDE */
*pStatusCode = ACM_STATUS_CODE_DECLINED;
LabelSemErr:
/* return power save right to system */
ACMP_StaPsCtrlRightReturn(pAd);
ACMR_DEBUG(ACMR_DEBUG_TRACE,
("acm_msg> Response Handle ERR! TC_RspHandle()\n"));
return RtnCode;
LabelErr:
/* delete the allocated stream */
TC_LMR_STREAM_DESTROY(pAd, StmAcId, pStreamReq);
ACM_TSPEC_SEM_UNLOCK(pAd, LabelSemErr);
#if 0 /* 2009/07/24: dont recover UAPSD state when ADDTS request fails */
/* recover UAPSD state */
ACM_APSD_Ctrl(pAd, pCdb, StmAcId,
pStreamReq->pTspec->TsInfo.Direction, 0, 0);
#endif /* 0 */
goto LabelSemErr;
} /* End of ACM_TC_RspHandle */
#endif /* CONFIG_STA_SUPPORT */
#endif /* WMM_ACM_SUPPORT */
/* End of acm_comm.c */