blob: c84f079e3d84a5ffa7c5ead5b61bb8f8067d5f22 [file] [log] [blame]
/*
* Copyright (c) 2007-2008 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "cprecomp.h"
#include "ratectrl.h"
void zfUpdateBssid(zdev_t* dev, u8_t* bssid)
{
zmw_get_wlan_dev(dev);
//zmw_declare_for_critical_section();
//zmw_enter_critical_section(dev);
wd->sta.bssid[0] = bssid[0] + (((u16_t) bssid[1]) << 8);
wd->sta.bssid[1] = bssid[2] + (((u16_t) bssid[3]) << 8);
wd->sta.bssid[2] = bssid[4] + (((u16_t) bssid[5]) << 8);
//zmw_leave_critical_section(dev);
zfHpSetBssid(dev, bssid);
}
/************************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfResetSupportRate */
/* Reset support rate to default value. */
/* */
/* INPUTS */
/* dev : device pointer */
/* type: ZM_DEFAULT_SUPPORT_RATE_ZERO => reset to zero */
/* ZM_DEFAULT_SUPPORT_RATE_DISCONNECT => reset to disconnect status */
/* ZM_DEFAULT_SUPPORT_RATE_IBSS_B => reset to IBSS creator(b mode) */
/* ZM_DEFAULT_SUPPORT_RATE_IBSS_AG => reset to IBSS creator(a/g mode) */
/* */
/************************************************************************************/
void zfResetSupportRate(zdev_t* dev, u8_t type)
{
zmw_get_wlan_dev(dev);
switch(type)
{
case ZM_DEFAULT_SUPPORT_RATE_ZERO:
wd->bRate = 0;
wd->bRateBasic = 0;
wd->gRate = 0;
wd->gRateBasic = 0;
break;
case ZM_DEFAULT_SUPPORT_RATE_DISCONNECT:
wd->bRate = 0xf;
wd->bRateBasic = 0xf;
wd->gRate = 0xff;
wd->gRateBasic = 0x15;
break;
case ZM_DEFAULT_SUPPORT_RATE_IBSS_B:
wd->bRate = 0xf;
wd->bRateBasic = 0xf;
wd->gRate = 0;
wd->gRateBasic = 0;
break;
case ZM_DEFAULT_SUPPORT_RATE_IBSS_AG:
wd->bRate = 0xf;
wd->bRateBasic = 0xf;
wd->gRate = 0xff;
wd->gRateBasic = 0;
break;
}
}
void zfUpdateSupportRate(zdev_t* dev, u8_t* rateArray)
{
u8_t bRate=0, bRateBasic=0, gRate=0, gRateBasic=0;
u8_t length = rateArray[1];
u8_t i, j;
zmw_get_wlan_dev(dev);
for(i=2; i<length+2; i++)
{
for(j=0; j<4; j++)
{
if ( (rateArray[i] & 0x7f) == zg11bRateTbl[j] )
{
bRate |= (1 << j);
if ( rateArray[i] & 0x80 )
{
bRateBasic |= (1 << j);
}
}
}
if ( j == 4 )
{
for(j=0; j<8; j++)
{
if ( (rateArray[i] & 0x7f) == zg11gRateTbl[j] )
{
gRate |= (1 << j);
if ( rateArray[i] & 0x80 )
{
gRateBasic |= (1 << j);
}
}
}
}
}
wd->bRate |= bRate;
wd->bRateBasic |= bRateBasic;
wd->gRate |= gRate;
wd->gRateBasic |= gRateBasic;
}
u8_t zfIsGOnlyMode(zdev_t* dev, u16_t frequency, u8_t* rateArray)
{
u8_t length = rateArray[1];
u8_t i, j;
if (frequency < 3000) {
for (i = 2; i < length+2; i++) {
for (j = 0; j < 8; j++) {
if ( ((rateArray[i] & 0x7f) == zg11gRateTbl[j])
&& (rateArray[i] & 0x80) ) {
return 1;
}
}
}
}
return 0;
}
void zfGatherBMode(zdev_t* dev, u8_t* rateArray, u8_t* extrateArray)
{
u8_t gatherBMode[ZM_MAX_SUPP_RATES_IE_SIZE + 2];
u8_t i, j, k = 0;
u8_t length;
gatherBMode[0] = ZM_WLAN_EID_SUPPORT_RATE;
gatherBMode[1] = 0;
length = rateArray[1];
for (i = 2; i < length+2; i++) {
for (j = 0; j < 4; j++) {
if ( (rateArray[i] & 0x7f) == zg11bRateTbl[j] ) {
gatherBMode[2+k] = rateArray[i];
gatherBMode[1]++;
k++;
}
}
}
length = extrateArray[1];
for (i = 2; i < length+2; i++) {
for (j = 0; j < 4; j++) {
if ( (extrateArray[i] & 0x7f) == zg11bRateTbl[j] ) {
gatherBMode[2+k] = extrateArray[i];
gatherBMode[1]++;
k++;
}
}
}
extrateArray[0] = extrateArray[1] = 0;
zfMemoryCopy(rateArray, gatherBMode, gatherBMode[1]+2);
}
u16_t zfGetRandomNumber(zdev_t* dev, u16_t initValue)
{
#if 0
/* Compiler/Linker error on Linux */
if ( initValue )
{
srand(initValue);
}
return ((u16_t)rand());
#endif
return 0;
}
u8_t zfPSDeviceSleep(zdev_t* dev)
{
//zmw_get_wlan_dev(dev);
/* enter PS mode */
return 0;
}
u8_t zcOfdmPhyCrtlToRate[] =
{
/* 0x8=48M, 0x9=24M, 0xa=12M, 0xb=6M, 0xc=54M, 0xd=36M, 0xe=18M, 0xf=9M */
10, 8, 6, 4, 11, 9, 7, 5
};
u8_t zfPhyCtrlToRate(u32_t phyCtrl)
{
u32_t mt, mcs, sg;
u8_t rate = 0;
mt = phyCtrl & 0x3;
mcs = (phyCtrl>>18) & 0x3f;
sg = (phyCtrl>>31) & 0x1;
if ((mt == 0) && (mcs <=3))
{
rate = (u8_t)mcs;
}
else if ((mt == 1) && (mcs >= 0x8) && (mcs <= 0xf))
{
rate = zcOfdmPhyCrtlToRate[mcs-8];
}
else if ((mt == 2) && (mcs <= 15))
{
rate = (u8_t)mcs + 12;
if(sg) {
if (mcs != 7)
{
rate = (u8_t)mcs + 12 + 2;
}
else //MCS7-SG
{
rate = (u8_t)30;
}
}
}
return rate;
}
void zfCoreEvent(zdev_t* dev, u16_t event, u8_t* rsp)
{
u16_t i;
zbuf_t* psBuf;
u8_t moreData;
u8_t vap = 0;
u8_t peerIdx;
s8_t res;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if (event == 0) //Beacon Event
{
if ( wd->wlanMode == ZM_MODE_AP )
{
zfApSendBeacon(dev);
if (wd->CurrentDtimCount == 0)
{
/* TODO : Send queued broadcast frames at BC/MC event */
do
{
psBuf = NULL;
moreData = 0;
zmw_enter_critical_section(dev);
if (wd->ap.bcmcTail[vap] != wd->ap.bcmcHead[vap])
{
//zm_msg0_mm(ZM_LV_0, "Send BCMC frames");
psBuf = wd->ap.bcmcArray[vap][wd->ap.bcmcHead[vap]];
wd->ap.bcmcHead[vap] = (wd->ap.bcmcHead[vap] + 1)
& (ZM_BCMC_ARRAY_SIZE - 1);
if (wd->ap.bcmcTail[vap] != wd->ap.bcmcHead[vap])
{
moreData = 0x20;
}
}
zmw_leave_critical_section(dev);
if (psBuf != NULL)
{
/* TODO : config moreData bit */
zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF,
moreData);
}
} while(psBuf != NULL);
}
}
else
{
/* STA mode */
if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE )
{
/* send queued packets */
for(i=0; i<wd->sta.staPSDataCount; i++)
{
zfTxSendEth(dev, wd->sta.staPSDataQueue[i], 0,
ZM_EXTERNAL_ALLOC_BUF, 0);
}
wd->sta.staPSDataCount = 0;
}
if ( wd->wlanMode == ZM_MODE_IBSS )
{
zfStaSendBeacon(dev);
wd->sta.ibssAtimTimer = ZM_BIT_15 | wd->sta.atimWindow;
}
zfPowerSavingMgrPreTBTTInterrupt(dev);
}
} //if (event == 0) //Beacon Event
else if (event == 1) //Retry completed event
{
u32_t retryRate;
retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8)
+ (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24);
/* Degrade Tx Rate */
if (wd->wlanMode == ZM_MODE_AP)
{
zmw_enter_critical_section(dev);
if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff)
{
zfRateCtrlTxFailEvent(dev, &wd->ap.staTable[i].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
}
else
{
zmw_enter_critical_section(dev);
res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx);
if ( res == 0 )
{
zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
}
} //else if (event == 1) //Retry completed event
else if (event == 2) //Tx Fail event
{
u32_t retryRate;
retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8)
+ (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24);
/* Degrade Tx Rate */
if (wd->wlanMode == ZM_MODE_AP)
{
zmw_enter_critical_section(dev);
if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff)
{
zfRateCtrlTxFailEvent(dev, &wd->ap.staTable[i].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
zfApSendFailure(dev, rsp);
}
else
{
zmw_enter_critical_section(dev);
res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx);
if ( res == 0 )
{
zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
}
} //else if (event == 2) //Tx Fail event
else if (event == 3) //Tx Comp event
{
u32_t retryRate;
retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8)
+ (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24);
/* TODO : Tx completed, used for rate control probing */
if (wd->wlanMode == ZM_MODE_AP)
{
zmw_enter_critical_section(dev);
if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff)
{
zfRateCtrlTxSuccessEvent(dev, &wd->ap.staTable[i].rcCell, zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
}
else
{
zmw_enter_critical_section(dev);
res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx);
if ( res == 0 )
{
zfRateCtrlTxSuccessEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, zfPhyCtrlToRate(retryRate));
}
zmw_leave_critical_section(dev);
}
} //else if (event == 3) //Tx Comp event
else if (event == 4) //BA failed count
{
u32_t fail;
u32_t rate;
peerIdx = 0;
fail=((u32_t*)rsp)[0] & 0xFFFF;
rate=((u32_t*)rsp)[0] >> 16;
if (rate > 15) {
rate = (rate & 0xF) + 12 + 2;
}
else {
rate = rate + 12;
}
zmw_enter_critical_section(dev);
zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, (u8_t)rate, fail);
zmw_leave_critical_section(dev);
}
}
void zfBeaconCfgInterrupt(zdev_t* dev, u8_t* rsp)
{
u32_t txBeaconCounter;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if ( wd->wlanMode == ZM_MODE_IBSS )
{
txBeaconCounter = *((u32_t *)rsp);
if ( wd->sta.beaconTxCnt != txBeaconCounter )
{
wd->sta.txBeaconInd = 1;
zmw_enter_critical_section(dev);
wd->tickIbssSendBeacon = 0;
zmw_leave_critical_section(dev);
}
else
{
wd->sta.txBeaconInd = 0;
}
#ifdef ZM_ENABLE_IBSS_DELAYED_JOIN_INDICATION
if ( wd->sta.txBeaconInd && wd->sta.ibssDelayedInd )
{
if (wd->zfcbIbssPartnerNotify != NULL)
{
wd->zfcbIbssPartnerNotify(dev, 1, &wd->sta.ibssDelayedIndEvent);
}
wd->sta.ibssDelayedInd = 0;
}
#endif
wd->sta.beaconTxCnt = txBeaconCounter;
// Need to check if the time is expired after ATIM window??
// Check if we have buffered any data for those stations that are sleeping
// If it's true, then transmitting ATIM pkt to notify them
#ifdef ZM_ENABLE_IBSS_PS
// TODO: Need to check if the station receive our ATIM pkt???
zfStaIbssPSSend(dev);
if ( wd->sta.atimWindow == 0 )
{
// We won't receive the end of ATIM isr so we fake it
zfPowerSavingMgrAtimWinExpired(dev);
}
#endif
}
}
void zfEndOfAtimWindowInterrupt(zdev_t* dev)
{
#ifdef ZM_ENABLE_IBSS_PS
zmw_get_wlan_dev(dev);
if ( wd->wlanMode == ZM_MODE_IBSS )
{
// Transmit any queued pkt for the stations!!
zfPowerSavingMgrAtimWinExpired(dev);
}
#endif
}