blob: b28a4e25e107e80c81bedfbfef409d5de5cf17e5 [file] [log] [blame] [edit]
/*
* 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"
#include "../hal/hpreg.h"
/* TODO : change global variable to constant */
u8_t zgWpaRadiusOui[] = { 0x00, 0x50, 0xf2, 0x01 };
u8_t zgWpaAesOui[] = { 0x00, 0x50, 0xf2, 0x04 };
u8_t zgWpa2RadiusOui[] = { 0x00, 0x0f, 0xac, 0x01 };
u8_t zgWpa2AesOui[] = { 0x00, 0x0f, 0xac, 0x04 };
const u16_t zcCwTlb[16] = { 0, 1, 3, 7, 15, 31, 63, 127,
255, 511, 1023, 2047, 4095, 4095, 4095, 4095};
void zfStaStartConnectCb(zdev_t* dev);
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfStaPutApIntoBlockingList */
/* Put AP into blocking AP list. */
/* */
/* INPUTS */
/* dev : device pointer */
/* bssid : AP's BSSID */
/* weight : weight of AP */
/* */
/* OUTPUTS */
/* none */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2006.12 */
/* */
/************************************************************************/
void zfStaPutApIntoBlockingList(zdev_t* dev, u8_t* bssid, u8_t weight)
{
u16_t i, j;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if (weight > 0)
{
zmw_enter_critical_section(dev);
/*Find same bssid entry first*/
for (i=0; i<ZM_MAX_BLOCKING_AP_LIST_SIZE; i++)
{
for (j=0; j<6; j++)
{
if(wd->sta.blockingApList[i].addr[j]!= bssid[j])
{
break;
}
}
if(j==6)
{
break;
}
}
/*This bssid doesn't have old record.Find an empty entry*/
if (i == ZM_MAX_BLOCKING_AP_LIST_SIZE)
{
for (i=0; i<ZM_MAX_BLOCKING_AP_LIST_SIZE; i++)
{
if (wd->sta.blockingApList[i].weight == 0)
{
break;
}
}
}
/* If the list is full, pick one entry for replacement */
if (i == ZM_MAX_BLOCKING_AP_LIST_SIZE)
{
i = bssid[5] & (ZM_MAX_BLOCKING_AP_LIST_SIZE-1);
}
/* Update AP address and weight */
for (j=0; j<6; j++)
{
wd->sta.blockingApList[i].addr[j] = bssid[j];
}
wd->sta.blockingApList[i].weight = weight;
zmw_leave_critical_section(dev);
}
return;
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfStaIsApInBlockingList */
/* Is AP in blocking list. */
/* */
/* INPUTS */
/* dev : device pointer */
/* bssid : AP's BSSID */
/* */
/* OUTPUTS */
/* TRUE : AP in blocking list */
/* FALSE : AP not in blocking list */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2006.12 */
/* */
/************************************************************************/
u16_t zfStaIsApInBlockingList(zdev_t* dev, u8_t* bssid)
{
u16_t i, j;
zmw_get_wlan_dev(dev);
//zmw_declare_for_critical_section();
//zmw_enter_critical_section(dev);
for (i=0; i<ZM_MAX_BLOCKING_AP_LIST_SIZE; i++)
{
if (wd->sta.blockingApList[i].weight != 0)
{
for (j=0; j<6; j++)
{
if (wd->sta.blockingApList[i].addr[j] != bssid[j])
{
break;
}
}
if (j == 6)
{
//zmw_leave_critical_section(dev);
return TRUE;
}
}
}
//zmw_leave_critical_section(dev);
return FALSE;
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfStaRefreshBlockList */
/* Is AP in blocking list. */
/* */
/* INPUTS */
/* dev : device pointer */
/* flushFlag : flush whole blocking list */
/* */
/* OUTPUTS */
/* none */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2006.12 */
/* */
/************************************************************************/
void zfStaRefreshBlockList(zdev_t* dev, u16_t flushFlag)
{
u16_t i;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
for (i=0; i<ZM_MAX_BLOCKING_AP_LIST_SIZE; i++)
{
if (wd->sta.blockingApList[i].weight != 0)
{
if (flushFlag != 0)
{
wd->sta.blockingApList[i].weight = 0;
}
else
{
wd->sta.blockingApList[i].weight--;
}
}
}
zmw_leave_critical_section(dev);
return;
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfStaConnectFail */
/* Handle Connect failure. */
/* */
/* INPUTS */
/* dev : device pointer */
/* bssid : BSSID */
/* reason : reason of failure */
/* */
/* OUTPUTS */
/* none */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2006.12 */
/* */
/************************************************************************/
void zfStaConnectFail(zdev_t* dev, u16_t reason, u16_t* bssid, u8_t weight)
{
zmw_get_wlan_dev(dev);
/* Change internal state */
zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT);
/* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */
//zfHpSetTTSIFSTime(dev, 0x8);
/* Notify wrapper of connection status changes */
if (wd->zfcbConnectNotify != NULL)
{
wd->zfcbConnectNotify(dev, reason, bssid);
}
/* Put AP into internal blocking list */
zfStaPutApIntoBlockingList(dev, (u8_t *)bssid, weight);
/* Issue another SCAN */
if ( wd->sta.bAutoReconnect )
{
zm_debug_msg0("Start internal scan...");
zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL);
zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_INTERNAL);
}
}
u8_t zfiWlanIBSSGetPeerStationsCount(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
return wd->sta.oppositeCount;
}
u8_t zfiWlanIBSSIteratePeerStations(zdev_t* dev, u8_t numToIterate, zfpIBSSIteratePeerStationCb callback, void *ctx)
{
u8_t oppositeCount;
u8_t i;
u8_t index = 0;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
oppositeCount = wd->sta.oppositeCount;
if ( oppositeCount > numToIterate )
{
oppositeCount = numToIterate;
}
for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++)
{
if ( oppositeCount == 0 )
{
break;
}
if ( wd->sta.oppositeInfo[i].valid == 0 )
{
continue;
}
callback(dev, &wd->sta.oppositeInfo[i], ctx, index++);
oppositeCount--;
}
zmw_leave_critical_section(dev);
return index;
}
s8_t zfStaFindFreeOpposite(zdev_t* dev, u16_t *sa, int *pFoundIdx)
{
int oppositeCount;
int i;
zmw_get_wlan_dev(dev);
oppositeCount = wd->sta.oppositeCount;
for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++)
{
if ( oppositeCount == 0 )
{
break;
}
if ( wd->sta.oppositeInfo[i].valid == 0 )
{
continue;
}
oppositeCount--;
if ( zfMemoryIsEqual((u8_t*) sa, wd->sta.oppositeInfo[i].macAddr, 6) )
{
//wd->sta.oppositeInfo[i].aliveCounter++;
wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER;
/* it is already stored */
return 1;
}
}
// Check if there's still space for new comer
if ( wd->sta.oppositeCount == ZM_MAX_OPPOSITE_COUNT )
{
return -1;
}
// Find an unused slot for new peer station
for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++)
{
if ( wd->sta.oppositeInfo[i].valid == 0 )
{
break;
}
}
*pFoundIdx = i;
return 0;
}
s8_t zfStaFindOppositeByMACAddr(zdev_t* dev, u16_t *sa, u8_t *pFoundIdx)
{
u32_t oppositeCount;
u32_t i;
zmw_get_wlan_dev(dev);
oppositeCount = wd->sta.oppositeCount;
for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++)
{
if ( oppositeCount == 0 )
{
break;
}
if ( wd->sta.oppositeInfo[i].valid == 0 )
{
continue;
}
oppositeCount--;
if ( zfMemoryIsEqual((u8_t*) sa, wd->sta.oppositeInfo[i].macAddr, 6) )
{
*pFoundIdx = (u8_t)i;
return 0;
}
}
*pFoundIdx = 0;
return 1;
}
static void zfStaInitCommonOppositeInfo(zdev_t* dev, int i)
{
zmw_get_wlan_dev(dev);
/* set the default rate to the highest rate */
wd->sta.oppositeInfo[i].valid = 1;
wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER;
wd->sta.oppositeCount++;
#ifdef ZM_ENABLE_IBSS_WPA2PSK
/* Set parameters for new opposite peer station !!! */
wd->sta.oppositeInfo[i].camIdx = 0xff; // Not set key in this location
wd->sta.oppositeInfo[i].pkInstalled = 0;
wd->sta.oppositeInfo[i].wpaState = ZM_STA_WPA_STATE_INIT ; // No encryption
#endif
}
int zfStaSetOppositeInfoFromBSSInfo(zdev_t* dev, struct zsBssInfo* pBssInfo)
{
int i;
u8_t* dst;
u16_t sa[3];
int res;
u32_t oneTxStreamCap;
zmw_get_wlan_dev(dev);
zfMemoryCopy((u8_t*) sa, pBssInfo->macaddr, 6);
res = zfStaFindFreeOpposite(dev, sa, &i);
if ( res != 0 )
{
goto zlReturn;
}
dst = wd->sta.oppositeInfo[i].macAddr;
zfMemoryCopy(dst, (u8_t *)sa, 6);
oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM);
if (pBssInfo->extSupportedRates[1] != 0)
{
/* TODO : Handle 11n */
if (pBssInfo->frequency < 3000)
{
/* 2.4GHz */
if (pBssInfo->EnableHT == 1)
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, pBssInfo->SG40);
else
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 1, pBssInfo->SG40);
}
else
{
/* 5GHz */
if (pBssInfo->EnableHT == 1)
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, pBssInfo->SG40);
else
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, pBssInfo->SG40);
}
}
else
{
/* TODO : Handle 11n */
if (pBssInfo->frequency < 3000)
{
/* 2.4GHz */
if (pBssInfo->EnableHT == 1)
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, pBssInfo->SG40);
else
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 0, 1, pBssInfo->SG40);
}
else
{
/* 5GHz */
if (pBssInfo->EnableHT == 1)
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, pBssInfo->SG40);
else
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, pBssInfo->SG40);
}
}
zfStaInitCommonOppositeInfo(dev, i);
zlReturn:
return 0;
}
int zfStaSetOppositeInfoFromRxBuf(zdev_t* dev, zbuf_t* buf)
{
int i;
u8_t* dst;
u16_t sa[3];
int res = 0;
u16_t offset;
u8_t bSupportExtRate;
u32_t rtsctsRate = 0xffffffff; /* CTS:OFDM 6M, RTS:OFDM 6M */
u32_t oneTxStreamCap;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET);
sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2);
sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4);
zmw_enter_critical_section(dev);
res = zfStaFindFreeOpposite(dev, sa, &i);
if ( res != 0 )
{
goto zlReturn;
}
dst = wd->sta.oppositeInfo[i].macAddr;
zfCopyFromRxBuffer(dev, buf, dst, ZM_WLAN_HEADER_A2_OFFSET, 6);
if ( (wd->sta.currentFrequency < 3000) && !(wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) )
{
bSupportExtRate = 0;
} else {
bSupportExtRate = 1;
}
if ( (bSupportExtRate == 1)
&& (wd->sta.currentFrequency < 3000)
&& (wd->wlanMode == ZM_MODE_IBSS)
&& (wd->wfc.bIbssGMode == 0) )
{
bSupportExtRate = 0;
}
wd->sta.connection_11b = 0;
oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM);
if ( ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff)
&& (bSupportExtRate == 1) )
{
/* TODO : Handle 11n */
if (wd->sta.currentFrequency < 3000)
{
/* 2.4GHz */
if (wd->sta.EnableHT == 1)
{
//11ng
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, wd->sta.SG40);
}
else
{
//11g
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 1, wd->sta.SG40);
}
rtsctsRate = 0x00001bb; /* CTS:CCK 1M, RTS:OFDM 6M */
}
else
{
/* 5GHz */
if (wd->sta.EnableHT == 1)
{
//11na
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, wd->sta.SG40);
}
else
{
//11a
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, wd->sta.SG40);
}
rtsctsRate = 0x10b01bb; /* CTS:OFDM 6M, RTS:OFDM 6M */
}
}
else
{
/* TODO : Handle 11n */
if (wd->sta.currentFrequency < 3000)
{
/* 2.4GHz */
if (wd->sta.EnableHT == 1)
{
//11ng
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, wd->sta.SG40);
rtsctsRate = 0x00001bb; /* CTS:CCK 1M, RTS:OFDM 6M */
}
else
{
//11b
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 0, 1, wd->sta.SG40);
rtsctsRate = 0x0; /* CTS:CCK 1M, RTS:CCK 1M */
wd->sta.connection_11b = 1;
}
}
else
{
/* 5GHz */
if (wd->sta.EnableHT == 1)
{
//11na
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, wd->sta.SG40);
}
else
{
//11a
zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, wd->sta.SG40);
}
rtsctsRate = 0x10b01bb; /* CTS:OFDM 6M, RTS:OFDM 6M */
}
}
zfStaInitCommonOppositeInfo(dev, i);
zlReturn:
zmw_leave_critical_section(dev);
if (rtsctsRate != 0xffffffff)
{
zfHpSetRTSCTSRate(dev, rtsctsRate);
}
return res;
}
void zfStaProtErpMonitor(zdev_t* dev, zbuf_t* buf)
{
u16_t offset;
u8_t erp;
u8_t bssid[6];
zmw_get_wlan_dev(dev);
if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&&(zfStaIsConnected(dev)) )
{
ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid);
if (zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6))
{
if ( (offset=zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff )
{
erp = zmw_rx_buf_readb(dev, buf, offset+2);
if ( erp & ZM_BIT_1 )
{
//zm_debug_msg0("protection mode on");
if (wd->sta.bProtectionMode == FALSE)
{
wd->sta.bProtectionMode = TRUE;
zfHpSetSlotTime(dev, 0);
}
}
else
{
//zm_debug_msg0("protection mode off");
if (wd->sta.bProtectionMode == TRUE)
{
wd->sta.bProtectionMode = FALSE;
zfHpSetSlotTime(dev, 1);
}
}
}
}
//Check the existence of Non-N AP
//Follow the check the "pBssInfo->EnableHT"
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff)
{}
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff)
{}
else
{wd->sta.NonNAPcount++;}
}
}
void zfStaUpdateWmeParameter(zdev_t* dev, zbuf_t* buf)
{
u16_t tmp;
u16_t aifs[5];
u16_t cwmin[5];
u16_t cwmax[5];
u16_t txop[5];
u8_t acm;
u8_t ac;
u16_t len;
u16_t i;
u16_t offset;
u8_t rxWmeParameterSetCount;
zmw_get_wlan_dev(dev);
/* Update if WME parameter set count is changed */
/* If connect to WME AP */
if (wd->sta.wmeConnected != 0)
{
/* Find WME parameter element */
if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff)
{
if ((len = zmw_rx_buf_readb(dev, buf, offset+1)) >= 7)
{
rxWmeParameterSetCount=zmw_rx_buf_readb(dev, buf, offset+8);
if (rxWmeParameterSetCount != wd->sta.wmeParameterSetCount)
{
zm_msg0_mm(ZM_LV_0, "wmeParameterSetCount changed!");
wd->sta.wmeParameterSetCount = rxWmeParameterSetCount;
/* retrieve WME parameter and update TxQ parameters */
acm = 0xf;
for (i=0; i<4; i++)
{
if (len >= (8+(i*4)+4))
{
tmp=zmw_rx_buf_readb(dev, buf, offset+10+i*4);
ac = (tmp >> 5) & 0x3;
if ((tmp & 0x10) == 0)
{
acm &= (~(1<<ac));
}
aifs[ac] = ((tmp & 0xf) * 9) + 10;
tmp=zmw_rx_buf_readb(dev, buf, offset+11+i*4);
/* Convert to 2^n */
cwmin[ac] = zcCwTlb[(tmp & 0xf)];
cwmax[ac] = zcCwTlb[(tmp >> 4)];
txop[ac]=zmw_rx_buf_readh(dev, buf,
offset+12+i*4);
}
}
if ((acm & 0x4) != 0)
{
cwmin[2] = cwmin[0];
cwmax[2] = cwmax[0];
aifs[2] = aifs[0];
txop[2] = txop[0];
}
if ((acm & 0x8) != 0)
{
cwmin[3] = cwmin[2];
cwmax[3] = cwmax[2];
aifs[3] = aifs[2];
txop[3] = txop[2];
}
cwmin[4] = 3;
cwmax[4] = 7;
aifs[4] = 28;
if ((cwmin[2]+aifs[2]) > ((cwmin[0]+aifs[0])+1))
{
wd->sta.ac0PriorityHigherThanAc2 = 1;
}
else
{
wd->sta.ac0PriorityHigherThanAc2 = 0;
}
zfHpUpdateQosParameter(dev, cwmin, cwmax, aifs, txop);
}
}
}
} //if (wd->sta.wmeConnected != 0)
}
/* process 802.11h Dynamic Frequency Selection */
void zfStaUpdateDot11HDFS(zdev_t* dev, zbuf_t* buf)
{
//u8_t length, channel, is5G;
u16_t offset;
zmw_get_wlan_dev(dev);
/*
Channel Switch Announcement Element Format
+------+----------+------+-------------------+------------------+--------------------+
|Format|Element ID|Length|Channel Switch Mode|New Channel Number|Channel Switch Count|
+------+----------+------+-------------------+------------------+--------------------+
|Bytes | 1 | 1 | 1 | 1 | 1 |
+------+----------+------+-------------------+------------------+--------------------+
|Value | 37 | 3 | 0 or 1 |unsigned integer |unsigned integer |
+------+----------+------+-------------------+------------------+--------------------+
*/
/* get EID(Channel Switch Announcement) */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CHANNEL_SWITCH_ANNOUNCE)) == 0xffff )
{
//zm_debug_msg0("EID(Channel Switch Announcement) not found");
return;
}
else if ( zmw_rx_buf_readb(dev, buf, offset+1) == 0x3 )
{
zm_debug_msg0("EID(Channel Switch Announcement) found");
//length = zmw_rx_buf_readb(dev, buf, offset+1);
//zfCopyFromRxBuffer(dev, buf, pBssInfo->supportedRates, offset, length+2);
//Chanell Switch Mode set to 1, driver should disable transmit immediate
//we do this by poll CCA high
if (zmw_rx_buf_readb(dev, buf, offset+2) == 0x1 )
{
//use ZM_OID_INTERNAL_WRITE,ZM_CMD_RESET to notice firmware flush quene and stop dma,
//then restart rx dma but not tx dma
if (wd->sta.DFSDisableTx != TRUE)
{
/* TODO : zfHpResetTxRx would cause Rx hang */
//zfHpResetTxRx(dev);
wd->sta.DFSDisableTx = TRUE;
/* Trgger Rx DMA */
zfHpStartRecv(dev);
}
//Adapter->ZD80211HSetting.DisableTxBy80211H=TRUE;
//AcquireCtrOfPhyReg(Adapter);
//ZD1205_WRITE_REGISTER(Adapter,CR24, 0x0);
//ReleaseDoNotSleep(Adapter);
}
if (zmw_rx_buf_readb(dev, buf, offset+4) <= 0x2 )
{
//Channel Switch
//if Channel Switch Count = 0 , STA should change channel immediately.
//if Channel Switch Count > 0 , STA should change channel after TBTT*count
//But it won't be accurate to let driver calculate TBTT*count, and the value of
//Channel Switch Count will decrease by one each when continue receving beacon
//So we change channel here when we receive count <=2.
zfHpDeleteAllowChannel(dev, wd->sta.currentFrequency);
wd->frequency = zfChNumToFreq(dev, zmw_rx_buf_readb(dev, buf, offset+3), 0);
//zfHpAddAllowChannel(dev, wd->frequency);
zm_debug_msg1("CWY - jump to frequency = ", wd->frequency);
zfCoreSetFrequency(dev, wd->frequency);
wd->sta.DFSDisableTx = FALSE;
/* Increase rxBeaconCount to prevent beacon lost */
if (zfStaIsConnected(dev))
{
wd->sta.rxBeaconCount = 1 << 6; // 2 times of check would pass
}
//start tx dma to transmit packet
//if (zmw_rx_buf_readb(dev, buf, offset+3) != wd->frequency)
//{
// //ZDDbgPrint(("Radar Detect by AP\n"));
// zfCoreSetFrequency();
// ProcessRadarDetectEvent(Adapter);
// Set_RF_Channel(Adapter, SwRfd->Rfd->RxBuffer[index+3], (UCHAR)Adapter->RF_Mode, 1);
// Adapter->CardSetting.Channel = SwRfd->Rfd->RxBuffer[index+3];
// Adapter->SaveChannel = Adapter->CardSetting.Channel;
// Adapter->UtilityChannel = Adapter->CardSetting.Channel;
//}
}
}
}
/* TODO : process 802.11h Transmission Power Control */
void zfStaUpdateDot11HTPC(zdev_t* dev, zbuf_t* buf)
{
}
/* IBSS power-saving mode */
void zfStaIbssPSCheckState(zdev_t* dev, zbuf_t* buf)
{
u8_t i, frameCtrl;
zmw_get_wlan_dev(dev);
if ( !zfStaIsConnected(dev) )
{
return;
}
if ( wd->wlanMode != ZM_MODE_IBSS )
{
return ;
}
/* check BSSID */
if ( !zfRxBufferEqualToStr(dev, buf, (u8_t*) wd->sta.bssid,
ZM_WLAN_HEADER_A3_OFFSET, 6) )
{
return;
}
frameCtrl = zmw_rx_buf_readb(dev, buf, 1);
/* check power management bit */
if ( frameCtrl & ZM_BIT_4 )
{
for(i=1; i<ZM_MAX_PS_STA; i++)
{
if ( !wd->sta.staPSList.entity[i].bUsed )
{
continue;
}
/* check source address */
if ( zfRxBufferEqualToStr(dev, buf,
wd->sta.staPSList.entity[i].macAddr,
ZM_WLAN_HEADER_A2_OFFSET, 6) )
{
return;
}
}
for(i=1; i<ZM_MAX_PS_STA; i++)
{
if ( !wd->sta.staPSList.entity[i].bUsed )
{
wd->sta.staPSList.entity[i].bUsed = TRUE;
wd->sta.staPSList.entity[i].bDataQueued = FALSE;
break;
}
}
if ( i == ZM_MAX_PS_STA )
{
/* STA list is full */
return;
}
zfCopyFromRxBuffer(dev, buf, wd->sta.staPSList.entity[i].macAddr,
ZM_WLAN_HEADER_A2_OFFSET, 6);
if ( wd->sta.staPSList.count == 0 )
{
// enable ATIM window
//zfEnableAtimWindow(dev);
}
wd->sta.staPSList.count++;
}
else if ( wd->sta.staPSList.count )
{
for(i=1; i<ZM_MAX_PS_STA; i++)
{
if ( wd->sta.staPSList.entity[i].bUsed )
{
if ( zfRxBufferEqualToStr(dev, buf,
wd->sta.staPSList.entity[i].macAddr,
ZM_WLAN_HEADER_A2_OFFSET, 6) )
{
wd->sta.staPSList.entity[i].bUsed = FALSE;
wd->sta.staPSList.count--;
if ( wd->sta.staPSList.entity[i].bDataQueued )
{
/* send queued data */
}
}
}
}
if ( wd->sta.staPSList.count == 0 )
{
/* disable ATIM window */
//zfDisableAtimWindow(dev);
}
}
}
/* IBSS power-saving mode */
u8_t zfStaIbssPSQueueData(zdev_t* dev, zbuf_t* buf)
{
u8_t i;
u16_t da[3];
zmw_get_wlan_dev(dev);
if ( !zfStaIsConnected(dev) )
{
return 0;
}
if ( wd->wlanMode != ZM_MODE_IBSS )
{
return 0;
}
if ( wd->sta.staPSList.count == 0 && wd->sta.powerSaveMode <= ZM_STA_PS_NONE )
{
return 0;
}
/* DA */
#ifdef ZM_ENABLE_NATIVE_WIFI
da[0] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET);
da[1] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET + 2);
da[2] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET + 4);
#else
da[0] = zmw_tx_buf_readh(dev, buf, 0);
da[1] = zmw_tx_buf_readh(dev, buf, 2);
da[2] = zmw_tx_buf_readh(dev, buf, 4);
#endif
if ( ZM_IS_MULTICAST_OR_BROADCAST(da) )
{
wd->sta.staPSList.entity[0].bDataQueued = TRUE;
wd->sta.ibssPSDataQueue[wd->sta.ibssPSDataCount++] = buf;
return 1;
}
// Unicast packet...
for(i=1; i<ZM_MAX_PS_STA; i++)
{
if ( zfMemoryIsEqual(wd->sta.staPSList.entity[i].macAddr,
(u8_t*) da, 6) )
{
wd->sta.staPSList.entity[i].bDataQueued = TRUE;
wd->sta.ibssPSDataQueue[wd->sta.ibssPSDataCount++] = buf;
return 1;
}
}
#if 0
if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE )
{
wd->sta.staPSDataQueue[wd->sta.staPSDataCount++] = buf;
return 1;
}
#endif
return 0;
}
/* IBSS power-saving mode */
void zfStaIbssPSSend(zdev_t* dev)
{
u8_t i;
u16_t bcastAddr[3] = {0xffff, 0xffff, 0xffff};
zmw_get_wlan_dev(dev);
if ( !zfStaIsConnected(dev) )
{
return ;
}
if ( wd->wlanMode != ZM_MODE_IBSS )
{
return ;
}
for(i=0; i<ZM_MAX_PS_STA; i++)
{
if ( wd->sta.staPSList.entity[i].bDataQueued )
{
if ( i == 0 )
{
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ATIM,
bcastAddr,
0, 0, 0);
}
else if ( wd->sta.staPSList.entity[i].bUsed )
{
// Send ATIM to prevent the peer to go to sleep
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ATIM,
(u16_t*) wd->sta.staPSList.entity[i].macAddr,
0, 0, 0);
}
wd->sta.staPSList.entity[i].bDataQueued = FALSE;
}
}
for(i=0; i<wd->sta.ibssPSDataCount; i++)
{
zfTxSendEth(dev, wd->sta.ibssPSDataQueue[i], 0,
ZM_EXTERNAL_ALLOC_BUF, 0);
}
wd->sta.ibssPrevPSDataCount = wd->sta.ibssPSDataCount;
wd->sta.ibssPSDataCount = 0;
}
void zfStaReconnect(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE &&
wd->wlanMode != ZM_MODE_IBSS )
{
return;
}
if ( (zfStaIsConnected(dev))||(zfStaIsConnecting(dev)) )
{
return;
}
if ( wd->sta.bChannelScan )
{
return;
}
/* Recover zero SSID length */
if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && (wd->ws.ssidLen == 0))
{
zm_debug_msg0("zfStaReconnect: NOT Support!! Set SSID to any BSS");
/* ANY BSS */
zmw_enter_critical_section(dev);
wd->sta.ssid[0] = 0;
wd->sta.ssidLen = 0;
zmw_leave_critical_section(dev);
}
// RAY: To ensure no TX pending before re-connecting
zfFlushVtxq(dev);
zfWlanEnable(dev);
zfScanMgrScanAck(dev);
}
void zfStaTimer100ms(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
if ( (wd->tick % 10) == 0 )
{
zfPushVtxq(dev);
// zfPowerSavingMgrMain(dev);
}
}
void zfStaCheckRxBeacon(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) && (zfStaIsConnected(dev)))
{
if (wd->beaconInterval == 0)
{
wd->beaconInterval = 100;
}
if ( (wd->tick % ((wd->beaconInterval * 10) / ZM_MS_PER_TICK)) == 0 )
{
/* Check rxBeaconCount */
if (wd->sta.rxBeaconCount == 0)
{
if (wd->sta.beaconMissState == 1)
{
/*notify AP that we left*/
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0);
/* Beacon Lost */
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_BEACON_MISS,
wd->sta.bssid, 0);
}
else
{
wd->sta.beaconMissState = 1;
/* Reset channel */
zfCoreSetFrequencyExV2(dev, wd->frequency, wd->BandWidth40,
wd->ExtOffset, NULL, 1);
}
}
else
{
wd->sta.beaconMissState = 0;
}
wd->sta.rxBeaconCount = 0;
}
}
}
void zfStaCheckConnectTimeout(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE )
{
return;
}
if ( !zfStaIsConnecting(dev) )
{
return;
}
zmw_enter_critical_section(dev);
if ( (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_OPEN)||
(wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_1)||
(wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_2)||
(wd->sta.connectState == ZM_STA_CONN_STATE_ASSOCIATE) )
{
if ( (wd->tick - wd->sta.connectTimer) > ZM_INTERVAL_CONNECT_TIMEOUT )
{
if ( wd->sta.connectByReasso )
{
wd->sta.failCntOfReasso++;
if ( wd->sta.failCntOfReasso > 2 )
{
wd->sta.connectByReasso = FALSE;
}
}
wd->sta.connectState = ZM_STA_CONN_STATE_NONE;
zm_debug_msg1("connect timeout, state = ", wd->sta.connectState);
//zfiWlanDisable(dev);
goto failed;
}
}
zmw_leave_critical_section(dev);
return;
failed:
zmw_leave_critical_section(dev);
if(wd->sta.authMode == ZM_AUTH_MODE_AUTO)
{ // Fix some AP not send authentication failed message to sta and lead to connect timeout !
wd->sta.connectTimeoutCount++;
}
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_TIMEOUT, wd->sta.bssid, 2);
return;
}
void zfMmStaTimeTick(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
/* airopeek */
if (wd->wlanMode != ZM_MODE_AP && !wd->swSniffer)
{
if ( wd->tick & 1 )
{
zfTimerCheckAndHandle(dev);
}
zfStaCheckRxBeacon(dev);
zfStaTimer100ms(dev);
zfStaCheckConnectTimeout(dev);
zfPowerSavingMgrMain(dev);
}
#ifdef ZM_ENABLE_AGGREGATION
/*
* add by honda
*/
zfAggScanAndClear(dev, wd->tick);
#endif
}
void zfStaSendBeacon(zdev_t* dev)
{
zbuf_t* buf;
u16_t offset, seq;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
//zm_debug_msg0("\n");
/* TBD : Maximum size of beacon */
if ((buf = zfwBufAllocate(dev, 1024)) == NULL)
{
zm_debug_msg0("Allocate beacon buffer failed");
return;
}
offset = 0;
/* wlan header */
/* Frame control */
zmw_tx_buf_writeh(dev, buf, offset, 0x0080);
offset+=2;
/* Duration */
zmw_tx_buf_writeh(dev, buf, offset, 0x0000);
offset+=2;
/* Address 1 */
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
offset+=2;
/* Address 2 */
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]);
offset+=2;
/* Address 3 */
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[0]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[1]);
offset+=2;
zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[2]);
offset+=2;
/* Sequence number */
zmw_enter_critical_section(dev);
seq = ((wd->mmseq++)<<4);
zmw_leave_critical_section(dev);
zmw_tx_buf_writeh(dev, buf, offset, seq);
offset+=2;
/* 24-31 Time Stamp : hardware will fill this field */
offset+=8;
/* Beacon Interval */
zmw_tx_buf_writeh(dev, buf, offset, wd->beaconInterval);
offset+=2;
/* Capability */
zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]);
zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]);
/* SSID */
offset = zfStaAddIeSsid(dev, buf, offset);
if(wd->frequency <= ZM_CH_G_14) // 2.4 GHz b+g
{
/* Support Rate */
offset = zfMmAddIeSupportRate(dev, buf, offset,
ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK);
/* DS parameter set */
offset = zfMmAddIeDs(dev, buf, offset);
offset = zfStaAddIeIbss(dev, buf, offset);
if( wd->wfc.bIbssGMode
&& (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode .
{
/* ERP Information */
wd->erpElement = 0;
offset = zfMmAddIeErp(dev, buf, offset);
}
/* TODO : country information */
/* RSN */
if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK )
{
offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH);
}
if( wd->wfc.bIbssGMode
&& (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode .
{
/* Enable G Mode */
/* Extended Supported Rates */
offset = zfMmAddIeSupportRate(dev, buf, offset,
ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM);
}
}
else // 5GHz a
{
/* Support Rate a Mode */
offset = zfMmAddIeSupportRate(dev, buf, offset,
ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM);
/* DS parameter set */
offset = zfMmAddIeDs(dev, buf, offset);
offset = zfStaAddIeIbss(dev, buf, offset);
/* TODO : country information */
/* RSN */
if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK )
{
offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH);
}
}
if ( wd->wlanMode != ZM_MODE_IBSS )
{
/* TODO : Need to check if it is ok */
/* HT Capabilities Info */
offset = zfMmAddHTCapability(dev, buf, offset);
/* Extended HT Capabilities Info */
offset = zfMmAddExtendedHTCapability(dev, buf, offset);
}
if ( wd->sta.ibssAdditionalIESize )
offset = zfStaAddIbssAdditionalIE(dev, buf, offset);
/* 1212 : write to beacon fifo */
/* 1221 : write to share memory */
zfHpSendBeacon(dev, buf, offset);
/* Free beacon buffer */
//zfwBufFree(dev, buf, 0);
}
void zfStaSignalStatistic(zdev_t* dev, u8_t SignalStrength, u8_t SignalQuality) //CWYang(+)
{
zmw_get_wlan_dev(dev);
/* Add Your Code to Do Works Like Moving Average Here */
wd->SignalStrength = (wd->SignalStrength * 7 + SignalStrength * 3)/10;
wd->SignalQuality = (wd->SignalQuality * 7 + SignalQuality * 3)/10;
}
struct zsBssInfo* zfStaFindBssInfo(zdev_t* dev, zbuf_t* buf, struct zsWlanProbeRspFrameHeader *pProbeRspHeader)
{
u8_t i;
u8_t j;
u8_t k;
u8_t isMatched, length, channel;
u16_t offset, frequency;
struct zsBssInfo* pBssInfo;
zmw_get_wlan_dev(dev);
if ((pBssInfo = wd->sta.bssList.head) == NULL)
{
return NULL;
}
for( i=0; i<wd->sta.bssList.bssCount; i++ )
{
//zm_debug_msg2("check pBssInfo = ", pBssInfo);
/* Check BSSID */
for( j=0; j<6; j++ )
{
if ( pBssInfo->bssid[j] != pProbeRspHeader->bssid[j] )
{
break;
}
}
/* Check SSID */
if (j == 6)
{
if (pProbeRspHeader->ssid[1] <= 32)
{
/* compare length and ssid */
isMatched = 1;
if((pProbeRspHeader->ssid[1] != 0) && (pBssInfo->ssid[1] != 0))
{
for( k=1; k<pProbeRspHeader->ssid[1] + 1; k++ )
{
if ( pBssInfo->ssid[k] != pProbeRspHeader->ssid[k] )
{
isMatched = 0;
break;
}
}
}
}
else
{
isMatched = 0;
}
}
else
{
isMatched = 0;
}
/* Check channel */
/* Add check channel to solve the bug #31222 */
if (isMatched) {
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_DS)) != 0xffff) {
if ((length = zmw_rx_buf_readb(dev, buf, offset+1)) == 1) {
channel = zmw_rx_buf_readb(dev, buf, offset+2);
if (zfHpIsAllowedChannel(dev, zfChNumToFreq(dev, channel, 0)) == 0) {
frequency = 0;
} else {
frequency = zfChNumToFreq(dev, channel, 0);;
}
} else {
frequency = 0;
}
} else {
frequency = wd->sta.currentFrequency;
}
if (frequency != 0) {
if ( ((frequency > 3000) && (pBssInfo->frequency > 3000))
|| ((frequency < 3000) && (pBssInfo->frequency < 3000)) ) {
/* redundant */
break;
}
}
}
pBssInfo = pBssInfo->next;
}
if ( i == wd->sta.bssList.bssCount )
{
pBssInfo = NULL;
}
return pBssInfo;
}
u8_t zfStaInitBssInfo(zdev_t* dev, zbuf_t* buf,
struct zsWlanProbeRspFrameHeader *pProbeRspHeader,
struct zsBssInfo* pBssInfo, struct zsAdditionInfo* AddInfo, u8_t type)
{
u8_t length, channel, is5G;
u16_t i, offset;
u8_t apQosInfo;
u16_t eachIElength = 0;
u16_t accumulateLen = 0;
zmw_get_wlan_dev(dev);
if ((type == 1) && ((pBssInfo->flag & ZM_BSS_INFO_VALID_BIT) != 0))
{
goto zlUpdateRssi;
}
/* get SSID */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff )
{
zm_debug_msg0("EID(SSID) not found");
goto zlError;
}
length = zmw_rx_buf_readb(dev, buf, offset+1);
{
u8_t Show_Flag = 0;
zfwGetShowZeroLengthSSID(dev, &Show_Flag);
if(Show_Flag)
{
if (length > ZM_MAX_SSID_LENGTH )
{
zm_debug_msg0("EID(SSID) is invalid");
goto zlError;
}
}
else
{
if ( length == 0 || length > ZM_MAX_SSID_LENGTH )
{
zm_debug_msg0("EID(SSID) is invalid");
goto zlError;
}
}
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->ssid, offset, length+2);
/* get DS parameter */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_DS)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if ( length != 1 )
{
zm_msg0_mm(ZM_LV_0, "Abnormal DS Param Set IE");
goto zlError;
}
channel = zmw_rx_buf_readb(dev, buf, offset+2);
if (zfHpIsAllowedChannel(dev, zfChNumToFreq(dev, channel, 0)) == 0)
{
goto zlError2;
}
pBssInfo->frequency = zfChNumToFreq(dev, channel, 0); // auto check
pBssInfo->channel = channel;
}
else
{
/* DS parameter not found */
pBssInfo->frequency = wd->sta.currentFrequency;
pBssInfo->channel = zfChFreqToNum(wd->sta.currentFrequency, &is5G);
}
/* initialize security type */
pBssInfo->securityType = ZM_SECURITY_TYPE_NONE;
/* get macaddr */
for( i=0; i<6; i++ )
{
pBssInfo->macaddr[i] = pProbeRspHeader->sa[i];
}
/* get bssid */
for( i=0; i<6; i++ )
{
pBssInfo->bssid[i] = pProbeRspHeader->bssid[i];
}
/* get timestamp */
for( i=0; i<8; i++ )
{
pBssInfo->timeStamp[i] = pProbeRspHeader->timeStamp[i];
}
/* get beacon interval */
pBssInfo->beaconInterval[0] = pProbeRspHeader->beaconInterval[0];
pBssInfo->beaconInterval[1] = pProbeRspHeader->beaconInterval[1];
/* get capability */
pBssInfo->capability[0] = pProbeRspHeader->capability[0];
pBssInfo->capability[1] = pProbeRspHeader->capability[1];
/* Copy frame body */
offset = 36; // Copy from the start of variable IE
pBssInfo->frameBodysize = zfwBufGetSize(dev, buf)-offset;
if (pBssInfo->frameBodysize > (ZM_MAX_PROBE_FRAME_BODY_SIZE-1))
{
pBssInfo->frameBodysize = ZM_MAX_PROBE_FRAME_BODY_SIZE-1;
}
accumulateLen = 0;
do
{
eachIElength = zmw_rx_buf_readb(dev, buf, offset + accumulateLen+1) + 2; //Len+(EID+Data)
if ( (eachIElength >= 2)
&& ((accumulateLen + eachIElength) <= pBssInfo->frameBodysize) )
{
zfCopyFromRxBuffer(dev, buf, pBssInfo->frameBody+accumulateLen, offset+accumulateLen, eachIElength);
accumulateLen+=(u16_t)eachIElength;
}
else
{
zm_msg0_mm(ZM_LV_1, "probersp frameBodysize abnormal");
break;
}
}
while(accumulateLen < pBssInfo->frameBodysize);
pBssInfo->frameBodysize = accumulateLen;
/* get supported rates */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SUPPORT_RATE)) == 0xffff )
{
zm_debug_msg0("EID(supported rates) not found");
goto zlError;
}
length = zmw_rx_buf_readb(dev, buf, offset+1);
if ( length == 0 || length > ZM_MAX_SUPP_RATES_IE_SIZE)
{
zm_msg0_mm(ZM_LV_0, "Supported rates IE length abnormal");
goto zlError;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->supportedRates, offset, length+2);
/* get Country information */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_COUNTRY)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_COUNTRY_INFO_SIZE)
{
length = ZM_MAX_COUNTRY_INFO_SIZE;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->countryInfo, offset, length+2);
/* check 802.11d support data */
if (wd->sta.b802_11D)
{
zfHpGetRegulationTablefromISO(dev, (u8_t *)&pBssInfo->countryInfo, 3);
/* only set regulatory one time */
wd->sta.b802_11D = 0;
}
}
/* get ERP information */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff )
{
pBssInfo->erp = zmw_rx_buf_readb(dev, buf, offset+2);
}
/* get extended supported rates */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_SUPP_RATES_IE_SIZE)
{
zm_msg0_mm(ZM_LV_0, "Extended rates IE length abnormal");
goto zlError;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->extSupportedRates, offset, length+2);
}
else
{
pBssInfo->extSupportedRates[0] = 0;
pBssInfo->extSupportedRates[1] = 0;
}
/* get WPA IE */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_WPA_IE)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_IE_SIZE)
{
length = ZM_MAX_IE_SIZE;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->wpaIe, offset, length+2);
pBssInfo->securityType = ZM_SECURITY_TYPE_WPA;
}
else
{
pBssInfo->wpaIe[1] = 0;
}
/* get WPS IE */
if ((offset = zfFindWifiElement(dev, buf, 4, 0xff)) != 0xffff)
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_WPS_IE_SIZE )
{
length = ZM_MAX_WPS_IE_SIZE;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->wscIe, offset, length+2);
}
else
{
pBssInfo->wscIe[1] = 0;
}
/* get SuperG IE */
if ((offset = zfFindSuperGElement(dev, buf, ZM_WLAN_EID_VENDOR_PRIVATE)) != 0xffff)
{
pBssInfo->apCap |= ZM_SuperG_AP;
}
/* get XR IE */
if ((offset = zfFindXRElement(dev, buf, ZM_WLAN_EID_VENDOR_PRIVATE)) != 0xffff)
{
pBssInfo->apCap |= ZM_XR_AP;
}
/* get RSN IE */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_RSN_IE)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_IE_SIZE)
{
length = ZM_MAX_IE_SIZE;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->rsnIe, offset, length+2);
pBssInfo->securityType = ZM_SECURITY_TYPE_WPA;
}
else
{
pBssInfo->rsnIe[1] = 0;
}
#ifdef ZM_ENABLE_CENC
/* get CENC IE */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CENC_IE)) != 0xffff )
{
length = zmw_rx_buf_readb(dev, buf, offset+1);
if (length > ZM_MAX_IE_SIZE )
{
length = ZM_MAX_IE_SIZE;
}
zfCopyFromRxBuffer(dev, buf, pBssInfo->cencIe, offset, length+2);
pBssInfo->securityType = ZM_SECURITY_TYPE_CENC;
pBssInfo->capability[0] &= 0xffef;
}
else
{
pBssInfo->cencIe[1] = 0;
}
#endif //ZM_ENABLE_CENC
/* get WME Parameter IE, probe rsp may contain WME parameter element */
//if ( wd->bQoSEnable )
{
if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff)
{
apQosInfo = zmw_rx_buf_readb(dev, buf, offset+8) & 0x80;
pBssInfo->wmeSupport = 1 | apQosInfo;
}
else if ((offset = zfFindWifiElement(dev, buf, 2, 0)) != 0xffff)
{
apQosInfo = zmw_rx_buf_readb(dev, buf, offset+8) & 0x80;
pBssInfo->wmeSupport = 1 | apQosInfo;
}
else
{
pBssInfo->wmeSupport = 0;
}
}
//CWYang(+)
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff)
{
/* 11n AP */
pBssInfo->EnableHT = 1;
if (zmw_rx_buf_readb(dev, buf, offset+1) & 0x02)
{
pBssInfo->enableHT40 = 1;
}
else
{
pBssInfo->enableHT40 = 0;
}
if (zmw_rx_buf_readb(dev, buf, offset+1) & 0x40)
{
pBssInfo->SG40 = 1;
}
else
{
pBssInfo->SG40 = 0;
}
}
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff)
{
/* 11n AP */
pBssInfo->EnableHT = 1;
pBssInfo->apCap |= ZM_All11N_AP;
if (zmw_rx_buf_readb(dev, buf, offset+2) & 0x02)
{
pBssInfo->enableHT40 = 1;
}
else
{
pBssInfo->enableHT40 = 0;
}
if (zmw_rx_buf_readb(dev, buf, offset+2) & 0x40)
{
pBssInfo->SG40 = 1;
}
else
{
pBssInfo->SG40 = 0;
}
}
else
{
pBssInfo->EnableHT = 0;
}
/* HT information */
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff)
{
/* atheros pre n */
pBssInfo->extChOffset = zmw_rx_buf_readb(dev, buf, offset+2) & 0x03;
}
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTINFORMATION)) != 0xffff)
{
/* pre n 2.0 standard */
pBssInfo->extChOffset = zmw_rx_buf_readb(dev, buf, offset+3) & 0x03;
}
else
{
pBssInfo->extChOffset = 0;
}
if ( (pBssInfo->enableHT40 == 1)
&& ((pBssInfo->extChOffset != 1) && (pBssInfo->extChOffset != 3)) )
{
pBssInfo->enableHT40 = 0;
}
if (pBssInfo->enableHT40 == 1)
{
if (zfHpIsAllowedChannel(dev, pBssInfo->frequency+((pBssInfo->extChOffset==1)?20:-20)) == 0)
{
/* if extension channel is not an allowed channel, treat AP as non-HT mode */
pBssInfo->EnableHT = 0;
pBssInfo->enableHT40 = 0;
pBssInfo->extChOffset = 0;
}
}
/* get ATH Extended Capability */
if ( ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff)&&
((offset = zfFindBrdcmMrvlRlnkExtCap(dev, buf)) == 0xffff))
{
pBssInfo->athOwlAp = 1;
}
else
{
pBssInfo->athOwlAp = 0;
}
/* get Broadcom Extended Capability */
if ( (pBssInfo->EnableHT == 1) //((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff)
&& ((offset = zfFindBroadcomExtCap(dev, buf)) != 0xffff) )
{
pBssInfo->broadcomHTAp = 1;
}
else
{
pBssInfo->broadcomHTAp = 0;
}
/* get Marvel Extended Capability */
if ((offset = zfFindMarvelExtCap(dev, buf)) != 0xffff)
{
pBssInfo->marvelAp = 1;
}
else
{
pBssInfo->marvelAp = 0;
}
/* get ATIM window */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_IBSS)) != 0xffff )
{
pBssInfo->atimWindow = zmw_rx_buf_readh(dev, buf,offset+2);
}
/* Fit for support mode */
if (pBssInfo->frequency > 3000) {
if (wd->supportMode & ZM_WIRELESS_MODE_5_N) {
#if 0
if (wd->supportMode & ZM_WIRELESS_MODE_5_54) {
/* support mode: a, n */
/* do nothing */
} else {
/* support mode: n */
/* reject non-n bss info */
if (!pBssInfo->EnableHT) {
goto zlError2;
}
}
#endif
} else {
if (wd->supportMode & ZM_WIRELESS_MODE_5_54) {
/* support mode: a */
/* delete n mode information */
pBssInfo->EnableHT = 0;
pBssInfo->enableHT40 = 0;
pBssInfo->apCap &= (~ZM_All11N_AP);
pBssInfo->extChOffset = 0;
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_EID_HT_CAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTCAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTINFORMATION);
} else {
/* support mode: none */
goto zlError2;
}
}
} else {
if (wd->supportMode & ZM_WIRELESS_MODE_24_N) {
#if 0
if (wd->supportMode & ZM_WIRELESS_MODE_24_54) {
if (wd->supportMode & ZM_WIRELESS_MODE_24_11) {
/* support mode: b, g, n */
/* do nothing */
} else {
/* support mode: g, n */
/* reject b-only bss info */
if ( (!pBssInfo->EnableHT)
&& (pBssInfo->extSupportedRates[1] == 0) ) {
goto zlError2;
}
}
} else {
if (wd->supportMode & ZM_WIRELESS_MODE_24_11) {
/* support mode: b, n */
/* 1. reject g-only bss info
* 2. if non g-only, delete g mode information
*/
if ( !pBssInfo->EnableHT ) {
if ( zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->supportedRates)
|| zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->extSupportedRates) ) {
goto zlError2;
} else {
zfGatherBMode(dev, pBssInfo->supportedRates,
pBssInfo->extSupportedRates);
pBssInfo->erp = 0;
pBssInfo->frameBodysize = zfRemoveElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
ZM_WLAN_EID_ERP);
pBssInfo->frameBodysize = zfRemoveElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
ZM_WLAN_EID_EXTENDED_RATE);
pBssInfo->frameBodysize = zfUpdateElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
pBssInfo->supportedRates);
}
}
} else {
/* support mode: n */
/* reject non-n bss info */
if (!pBssInfo->EnableHT) {
goto zlError2;
}
}
}
#endif
} else {
/* delete n mode information */
pBssInfo->EnableHT = 0;
pBssInfo->enableHT40 = 0;
pBssInfo->apCap &= (~ZM_All11N_AP);
pBssInfo->extChOffset = 0;
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_EID_HT_CAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTCAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY);
pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody,
pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTINFORMATION);
if (wd->supportMode & ZM_WIRELESS_MODE_24_54) {
#if 0
if (wd->supportMode & ZM_WIRELESS_MODE_24_11) {
/* support mode: b, g */
/* delete n mode information */
} else {
/* support mode: g */
/* delete n mode information */
/* reject b-only bss info */
if (pBssInfo->extSupportedRates[1] == 0) {
goto zlError2;
}
}
#endif
} else {
if (wd->supportMode & ZM_WIRELESS_MODE_24_11) {
/* support mode: b */
/* delete n mode information */
if ( zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->supportedRates)
|| zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->extSupportedRates) ) {
goto zlError2;
} else {
zfGatherBMode(dev, pBssInfo->supportedRates,
pBssInfo->extSupportedRates);
pBssInfo->erp = 0;
pBssInfo->frameBodysize = zfRemoveElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
ZM_WLAN_EID_ERP);
pBssInfo->frameBodysize = zfRemoveElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
ZM_WLAN_EID_EXTENDED_RATE);
pBssInfo->frameBodysize = zfUpdateElement(dev,
pBssInfo->frameBody, pBssInfo->frameBodysize,
pBssInfo->supportedRates);
}
} else {
/* support mode: none */
goto zlError2;
}
}
}
}
pBssInfo->flag |= ZM_BSS_INFO_VALID_BIT;
zlUpdateRssi:
/* Update Timer information */
pBssInfo->tick = wd->tick;
/* Update ERP information */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff )
{
pBssInfo->erp = zmw_rx_buf_readb(dev, buf, offset+2);
}
if( (s8_t)pBssInfo->signalStrength < (s8_t)AddInfo->Tail.Data.SignalStrength1 )
{
/* Update signal strength */
pBssInfo->signalStrength = (u8_t)AddInfo->Tail.Data.SignalStrength1;
/* Update signal quality */
pBssInfo->signalQuality = (u8_t)(AddInfo->Tail.Data.SignalStrength1 * 2);
/* Update the sorting value */
pBssInfo->sortValue = zfComputeBssInfoWeightValue(dev,
(pBssInfo->supportedRates[6] + pBssInfo->extSupportedRates[0]),
pBssInfo->EnableHT,
pBssInfo->enableHT40,
pBssInfo->signalStrength);
}
return 0;
zlError:
return 1;
zlError2:
return 2;
}
void zfStaProcessBeacon(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) //CWYang(m)
{
/* Parse TIM and send PS-POLL in power saving mode */
struct zsWlanBeaconFrameHeader* pBeaconHeader;
struct zsBssInfo* pBssInfo;
u8_t pBuf[sizeof(struct zsWlanBeaconFrameHeader)];
u8_t bssid[6];
int res;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
/* sta routine jobs */
zfStaProtErpMonitor(dev, buf); /* check protection mode */
if (zfStaIsConnected(dev))
{
ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid);
if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE )
{
if ( zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6) )
{
zfPowerSavingMgrProcessBeacon(dev, buf);
zfStaUpdateWmeParameter(dev, buf);
if (wd->sta.DFSEnable)
zfStaUpdateDot11HDFS(dev, buf);
if (wd->sta.TPCEnable)
zfStaUpdateDot11HTPC(dev, buf);
/* update signal strength and signal quality */
zfStaSignalStatistic(dev, AddInfo->Tail.Data.SignalStrength1,
AddInfo->Tail.Data.SignalQuality); //CWYang(+)
wd->sta.rxBeaconCount++;
}
}
else if ( wd->wlanMode == ZM_MODE_IBSS )
{
if ( zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A3_OFFSET, 6) )
{
int res;
struct zsPartnerNotifyEvent event;
zm_debug_msg0("20070916 Receive opposite Beacon!");
zmw_enter_critical_section(dev);
wd->sta.ibssReceiveBeaconCount++;
zmw_leave_critical_section(dev);
res = zfStaSetOppositeInfoFromRxBuf(dev, buf);
if ( res == 0 )
{
// New peer station found. Notify the wrapper now
zfInitPartnerNotifyEvent(dev, buf, &event);
if (wd->zfcbIbssPartnerNotify != NULL)
{
wd->zfcbIbssPartnerNotify(dev, 1, &event);
}
}
/* update signal strength and signal quality */
zfStaSignalStatistic(dev, AddInfo->Tail.Data.SignalStrength1,
AddInfo->Tail.Data.SignalQuality); //CWYang(+)
}
//else if ( wd->sta.ibssPartnerStatus == ZM_IBSS_PARTNER_LOST )
// Why does this happen in IBSS?? The impact of Vista since
// we need to tell it the BSSID
#if 0
else if ( wd->sta.oppositeCount == 0 )
{ /* IBSS merge if SSID matched */
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) != 0xffff )
{
if ( (wd->sta.ssidLen == zmw_buf_readb(dev, buf, offset+1))&&
(zfRxBufferEqualToStr(dev, buf, wd->sta.ssid,
offset+2, wd->sta.ssidLen)) )
{
capabilityInfo = zmw_buf_readh(dev, buf, 34);
if ( capabilityInfo & ZM_BIT_1 )
{
if ( (wd->sta.capability[0] & ZM_BIT_4) ==
(capabilityInfo & ZM_BIT_4) )
{
zm_debug_msg0("IBSS merge");
zfCopyFromRxBuffer(dev, buf, bssid,
ZM_WLAN_HEADER_A3_OFFSET, 6);
zfUpdateBssid(dev, bssid);
}
}
}
}
}
#endif
}
}
/* return if not channel scan */
if ( !wd->sta.bChannelScan )
{
goto zlReturn;
}
zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanBeaconFrameHeader));
pBeaconHeader = (struct zsWlanBeaconFrameHeader*) pBuf;
zmw_enter_critical_section(dev);
//zm_debug_msg1("bss count = ", wd->sta.bssList.bssCount);
pBssInfo = zfStaFindBssInfo(dev, buf, pBeaconHeader);
if ( pBssInfo == NULL )
{
/* Allocate a new entry if BSS not in the scan list */
pBssInfo = zfBssInfoAllocate(dev);
if (pBssInfo != NULL)
{
res = zfStaInitBssInfo(dev, buf, pBeaconHeader, pBssInfo, AddInfo, 0);
//zfDumpSSID(pBssInfo->ssid[1], &(pBssInfo->ssid[2]));
if ( res != 0 )
{
zfBssInfoFree(dev, pBssInfo);
}
else
{
zfBssInfoInsertToList(dev, pBssInfo);
}
}
}
else
{
res = zfStaInitBssInfo(dev, buf, pBeaconHeader, pBssInfo, AddInfo, 1);
if (res == 2)
{
zfBssInfoRemoveFromList(dev, pBssInfo);
zfBssInfoFree(dev, pBssInfo);
}
else if ( wd->wlanMode == ZM_MODE_IBSS )
{
int idx;
// It would reset the alive counter if the peer station is found!
zfStaFindFreeOpposite(dev, (u16_t *)pBssInfo->macaddr, &idx);
}
}
zmw_leave_critical_section(dev);
zlReturn:
return;
}
void zfAuthFreqCompleteCb(zdev_t* dev)
{
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
zmw_enter_critical_section(dev);
if (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_COMPLETED)
{
zm_debug_msg0("ZM_STA_CONN_STATE_ASSOCIATE");
wd->sta.connectTimer = wd->tick;
wd->sta.connectState = ZM_STA_CONN_STATE_ASSOCIATE;
}
zmw_leave_critical_section(dev);
return;
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfProcessAuth */
/* Process authenticate management frame. */
/* */
/* INPUTS */
/* dev : device pointer */
/* buf : auth frame buffer */
/* */
/* OUTPUTS */
/* none */
/* */
/* AUTHOR */
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
/* */
/************************************************************************/
/* Note : AP allows one authenticating STA at a time, does not */
/* support multiple authentication process. Make sure */
/* authentication state machine will not be blocked due */
/* to incompleted authentication handshake. */
void zfStaProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
{
struct zsWlanAuthFrameHeader* pAuthFrame;
u8_t pBuf[sizeof(struct zsWlanAuthFrameHeader)];
u32_t p1, p2;
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
if ( !zfStaIsConnecting(dev) )
{
return;
}
pAuthFrame = (struct zsWlanAuthFrameHeader*) pBuf;
zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanAuthFrameHeader));
if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_OPEN )
{
if ( (zmw_le16_to_cpu(pAuthFrame->seq) == 2)&&
(zmw_le16_to_cpu(pAuthFrame->algo) == 0)&&
(zmw_le16_to_cpu(pAuthFrame->status) == 0) )
{
zmw_enter_critical_section(dev);
wd->sta.connectTimer = wd->tick;
zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_COMPLETED");
wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_COMPLETED;
zmw_leave_critical_section(dev);
//Set channel according to AP's configuration
//Move to here because of Cisco 11n AP feature
zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40,
wd->ExtOffset, zfAuthFreqCompleteCb);
/* send association frame */
if ( wd->sta.connectByReasso )
{
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_REASOCREQ,
wd->sta.bssid, 0, 0, 0);
}
else
{
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCREQ,
wd->sta.bssid, 0, 0, 0);
}
}
else
{
zm_debug_msg1("authentication failed, status = ",
pAuthFrame->status);
if (wd->sta.authMode == ZM_AUTH_MODE_AUTO)
{
wd->sta.bIsSharedKey = 1;
zfStaStartConnect(dev, wd->sta.bIsSharedKey);
}
else
{
zm_debug_msg0("ZM_STA_STATE_DISCONNECT");
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3);
}
}
}
else if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_1 )
{
if ( (zmw_le16_to_cpu(pAuthFrame->algo) == 1) &&
(zmw_le16_to_cpu(pAuthFrame->seq) == 2) &&
(zmw_le16_to_cpu(pAuthFrame->status) == 0))
//&& (pAuthFrame->challengeText[1] <= 255) )
{
zfMemoryCopy(wd->sta.challengeText, pAuthFrame->challengeText,
pAuthFrame->challengeText[1]+2);
/* send the 3rd authentication frame */
p1 = 0x30001;
p2 = 0;
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH,
wd->sta.bssid, p1, p2, 0);
zmw_enter_critical_section(dev);
wd->sta.connectTimer = wd->tick;
zm_debug_msg0("ZM_STA_SUB_STATE_AUTH_SHARE_2");
wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_SHARE_2;
zmw_leave_critical_section(dev);
}
else
{
zm_debug_msg1("authentication failed, status = ",
pAuthFrame->status);
zm_debug_msg0("ZM_STA_STATE_DISCONNECT");
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3);
}
}
else if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_2 )
{
if ( (zmw_le16_to_cpu(pAuthFrame->algo) == 1)&&
(zmw_le16_to_cpu(pAuthFrame->seq) == 4)&&
(zmw_le16_to_cpu(pAuthFrame->status) == 0) )
{
//Set channel according to AP's configuration
//Move to here because of Cisco 11n AP feature
zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40,
wd->ExtOffset, NULL);
/* send association frame */
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCREQ,
wd->sta.bssid, 0, 0, 0);
zmw_enter_critical_section(dev);
wd->sta.connectTimer = wd->tick;
zm_debug_msg0("ZM_STA_SUB_STATE_ASSOCIATE");
wd->sta.connectState = ZM_STA_CONN_STATE_ASSOCIATE;
zmw_leave_critical_section(dev);
}
else
{
zm_debug_msg1("authentication failed, status = ",
pAuthFrame->status);
zm_debug_msg0("ZM_STA_STATE_DISCONNECT");
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3);
}
}
else
{
zm_debug_msg0("unknown case");
}
}
void zfStaProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
{
return;
}
void zfStaProcessAsocRsp(zdev_t* dev, zbuf_t* buf)
{
struct zsWlanAssoFrameHeader* pAssoFrame;
u8_t pBuf[sizeof(struct zsWlanAssoFrameHeader)];
u16_t offset;
u32_t i;
u32_t oneTxStreamCap;
zmw_get_wlan_dev(dev);
if ( !zfStaIsConnecting(dev) )
{
return;
}
pAssoFrame = (struct zsWlanAssoFrameHeader*) pBuf;
zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanAssoFrameHeader));
if ( wd->sta.connectState == ZM_STA_CONN_STATE_ASSOCIATE )
{
if ( pAssoFrame->status == 0 )
{
zm_debug_msg0("ZM_STA_STATE_CONNECTED");
if (wd->sta.EnableHT == 1)
{
wd->sta.wmeConnected = 1;
}
if ((wd->sta.wmeEnabled & ZM_STA_WME_ENABLE_BIT) != 0) //WME enabled
{
/* Asoc rsp may contain WME parameter element */
if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff)
{
zm_debug_msg0("WME enable");
wd->sta.wmeConnected = 1;
if ((wd->sta.wmeEnabled & ZM_STA_UAPSD_ENABLE_BIT) != 0)
{
if ((zmw_rx_buf_readb(dev, buf, offset+8) & 0x80) != 0)
{
zm_debug_msg0("UAPSD enable");
wd->sta.qosInfo = wd->sta.wmeQosInfo;
}
}
zfStaUpdateWmeParameter(dev, buf);
}
}
//Store asoc response frame body, for VISTA only
wd->sta.asocRspFrameBodySize = zfwBufGetSize(dev, buf)-24;
if (wd->sta.asocRspFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE)
{
wd->sta.asocRspFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE;
}
for (i=0; i<wd->sta.asocRspFrameBodySize; i++)
{
wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24);
}
zfStaStoreAsocRspIe(dev, buf);
if (wd->sta.EnableHT &&
((wd->sta.ie.HtCap.HtCapInfo & HTCAP_SupChannelWidthSet) != 0) &&
(wd->ExtOffset != 0))
{
wd->sta.htCtrlBandwidth = 1;
}
else
{
wd->sta.htCtrlBandwidth = 0;
}
//Set channel according to AP's configuration
//zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40,
// wd->ExtOffset, NULL);
if (wd->sta.EnableHT == 1)
{
wd->addbaComplete = 0;
if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0 &&
(wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) == 0)
{
wd->addbaCount = 1;
zfAggSendAddbaRequest(dev, wd->sta.bssid, 0, 0);
zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_ADDBA, 100);
}
}
/* set RIFS support */
if(wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_RIFSMode)
{
wd->sta.HT2040 = 1;
// zfHpSetRifs(dev, wd->sta.EnableHT, 1, (wd->sta.currentFrequency < 3000)? 1:0);
}
wd->sta.aid = pAssoFrame->aid & 0x3fff;
wd->sta.oppositeCount = 0; /* reset opposite count */
zfStaSetOppositeInfoFromRxBuf(dev, buf);
wd->sta.rxBeaconCount = 16;
zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED);
wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev);
if (wd->zfcbConnectNotify != NULL)
{
if (wd->sta.EnableHT != 0) /* 11n */
{
oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM);
if (wd->sta.htCtrlBandwidth == 1) /* HT40*/
{
if(oneTxStreamCap) /* one Tx stream */
{
if (wd->sta.SG40)
{
wd->CurrentTxRateKbps = 150000;
wd->CurrentRxRateKbps = 300000;
}
else
{
wd->CurrentTxRateKbps = 135000;
wd->CurrentRxRateKbps = 270000;
}
}
else /* Two Tx streams */
{
if (wd->sta.SG40)
{
wd->CurrentTxRateKbps = 300000;
wd->CurrentRxRateKbps = 300000;
}
else
{
wd->CurrentTxRateKbps = 270000;
wd->CurrentRxRateKbps = 270000;
}
}
}
else /* HT20 */
{
if(oneTxStreamCap) /* one Tx stream */
{
wd->CurrentTxRateKbps = 650000;
wd->CurrentRxRateKbps = 130000;
}
else /* Two Tx streams */
{
wd->CurrentTxRateKbps = 130000;
wd->CurrentRxRateKbps = 130000;
}
}
}
else /* 11abg */
{
if (wd->sta.connection_11b != 0)
{
wd->CurrentTxRateKbps = 11000;
wd->CurrentRxRateKbps = 11000;
}
else
{
wd->CurrentTxRateKbps = 54000;
wd->CurrentRxRateKbps = 54000;
}
}
wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid);
}
wd->sta.connectByReasso = TRUE;
wd->sta.failCntOfReasso = 0;
zfPowerSavingMgrConnectNotify(dev);
/* Disable here because fixed rate is only for test, TBD. */
//if (wd->sta.EnableHT)
//{
// wd->txMCS = 7; //Rate = 65Mbps
// wd->txMT = 2; // Ht rate
// wd->enableAggregation = 2; // Enable Aggregation
//}
}
else
{
zm_debug_msg1("association failed, status = ",
pAssoFrame->status);
zm_debug_msg0("ZM_STA_STATE_DISCONNECT");
wd->sta.connectByReasso = FALSE;
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_ASOC_FAILED, wd->sta.bssid, 3);
}
}
}
void zfStaStoreAsocRspIe(zdev_t* dev, zbuf_t* buf)
{
u16_t offset;
u32_t i;
u16_t length;
u8_t *htcap;
u8_t asocBw40 = 0;
u8_t asocExtOffset = 0;
zmw_get_wlan_dev(dev);
for (i=0; i<wd->sta.asocRspFrameBodySize; i++)
{
wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24);
}
/* HT capabilities: 28 octets */
if ( ((wd->sta.currentFrequency > 3000) && !(wd->supportMode & ZM_WIRELESS_MODE_5_N))
|| ((wd->sta.currentFrequency < 3000) && !(wd->supportMode & ZM_WIRELESS_MODE_24_N)) )
{
/* not 11n AP */
htcap = (u8_t *)&wd->sta.ie.HtCap;
for (i=0; i<28; i++)
{
htcap[i] = 0;
}
wd->BandWidth40 = 0;
wd->ExtOffset = 0;
return;
}
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff)
{
/* atheros pre n */
zm_debug_msg0("atheros pre n");
htcap = (u8_t *)&wd->sta.ie.HtCap;
htcap[0] = zmw_rx_buf_readb(dev, buf, offset);
htcap[1] = 26;
for (i=1; i<=26; i++)
{
htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i);
zm_msg2_mm(ZM_LV_1, "ASOC: HT Capabilities, htcap=", htcap[i+1]);
}
}
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff)
{
/* pre n 2.0 standard */
zm_debug_msg0("pre n 2.0 standard");
htcap = (u8_t *)&wd->sta.ie.HtCap;
for (i=0; i<28; i++)
{
htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i);
zm_msg2_mm(ZM_LV_1, "ASOC: HT Capabilities, htcap=", htcap[i]);
}
}
else
{
/* not 11n AP */
htcap = (u8_t *)&wd->sta.ie.HtCap;
for (i=0; i<28; i++)
{
htcap[i] = 0;
}
wd->BandWidth40 = 0;
wd->ExtOffset = 0;
return;
}
asocBw40 = (u8_t)((wd->sta.ie.HtCap.HtCapInfo & HTCAP_SupChannelWidthSet) >> 1);
/* HT information */
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff)
{
/* atheros pre n */
zm_debug_msg0("atheros pre n HTINFO");
length = 22;
htcap = (u8_t *)&wd->sta.ie.HtInfo;
htcap[0] = zmw_rx_buf_readb(dev, buf, offset);
htcap[1] = 22;
for (i=1; i<=22; i++)
{
htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i);
zm_msg2_mm(ZM_LV_1, "ASOC: HT Info, htinfo=", htcap[i+1]);
}
}
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTINFORMATION)) != 0xffff)
{
/* pre n 2.0 standard */
zm_debug_msg0("pre n 2.0 standard HTINFO");
length = zmw_rx_buf_readb(dev, buf, offset + 1);
htcap = (u8_t *)&wd->sta.ie.HtInfo;
for (i=0; i<24; i++)
{
htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i);
zm_msg2_mm(ZM_LV_1, "ASOC: HT Info, htinfo=", htcap[i]);
}
}
else
{
zm_debug_msg0("no HTINFO");
htcap = (u8_t *)&wd->sta.ie.HtInfo;
for (i=0; i<24; i++)
{
htcap[i] = 0;
}
}
asocExtOffset = wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_ExtChannelOffsetBelow;
if ((wd->sta.EnableHT == 1) && (asocBw40 == 1) && ((asocExtOffset == 1) || (asocExtOffset == 3)))
{
wd->BandWidth40 = asocBw40;
wd->ExtOffset = asocExtOffset;
}
else
{
wd->BandWidth40 = 0;
wd->ExtOffset = 0;
}
return;
}
void zfStaProcessDeauth(zdev_t* dev, zbuf_t* buf)
{
u16_t apMacAddr[3];
zmw_get_wlan_dev(dev);
zmw_declare_for_critical_section();
/* STA : if SA=connected AP then disconnect with AP */
if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE )
{
apMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET);
apMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2);
apMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4);
if ((apMacAddr[0] == wd->sta.bssid[0]) && (apMacAddr[1] == wd->sta.bssid[1]) && (apMacAddr[2] == wd->sta.bssid[2]))
{
if (zfwBufGetSize(dev, buf) >= 24+2) //not a malformed frame
{
if ( zfStaIsConnected(dev) )
{
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_DEAUTH, wd->sta.bssid, 2);
}
else if (zfStaIsConnecting(dev))
{
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3);
}
else
{
}
}
}
}
else if ( wd->wlanMode == ZM_MODE_IBSS )
{
u16_t peerMacAddr[3];
u8_t peerIdx;
s8_t res;
if ( zfStaIsConnected(dev) )
{
peerMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET);
peerMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2);
peerMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4);
zmw_enter_critical_section(dev);
res = zfStaFindOppositeByMACAddr(dev, peerMacAddr, &peerIdx);
if ( res == 0 )
{
wd->sta.oppositeInfo[peerIdx].aliveCounter = 0;
}
zmw_leave_critical_section(dev);
}
}
}
void zfStaProcessDisasoc(zdev_t* dev, zbuf_t* buf)
{
u16_t apMacAddr[3];
zmw_get_wlan_dev(dev);
/* STA : if SA=connected AP then disconnect with AP */
if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE )
{
apMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET);
apMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2);
apMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4);
if ((apMacAddr[0] == wd->sta.bssid[0]) && (apMacAddr[1] == wd->sta.bssid[1]) && (apMacAddr[2] == wd->sta.bssid[2]))
{
if (zfwBufGetSize(dev, buf) >= 24+2) //not a malformed frame
{
if ( zfStaIsConnected(dev) )
{
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_DISASOC, wd->sta.bssid, 2);
}
else
{
zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_ASOC_FAILED, wd->sta.bssid, 3);
}
}
}
}
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfProcessProbeReq */
/* Process probe request management frame. */
/* */
/* INPUTS */
/* dev : device pointer */
/* buf : auth frame buffer */
/* */
/* OUTPUTS */
/* none */
/* */
/* AUTHOR */
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
/* */
/************************************************************************/
void zfStaProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src)
{
u16_t offset;
u8_t len;
u16_t i, j;
u16_t sendFlag;
zmw_get_wlan_dev(dev);
/* check mode : AP/IBSS */
if ((wd->wlanMode != ZM_MODE_AP) || (wd->wlanMode != ZM_MODE_IBSS))
{
zm_msg0_mm(ZM_LV_3, "Ignore probe req");
return;
}
/* check SSID */
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff)
{
zm_msg0_mm(ZM_LV_3, "probe req SSID not found");
return;
}
len = zmw_rx_buf_readb(dev, buf, offset+1);
for (i=0; i<ZM_MAX_AP_SUPPORT; i++)
{
if ((wd->ap.apBitmap & (i<<i)) != 0)
{
sendFlag = 0;
/* boardcast SSID */
if ((len == 0) && (wd->ap.hideSsid[i] == 0))
{
sendFlag = 1;
}
/* Not broadcast SSID */
else if (wd->ap.ssidLen[i] == len)
{
for (j=0; j<len; j++)
{
if (zmw_rx_buf_readb(dev, buf, offset+1+j)
!= wd->ap.ssid[i][j])
{
break;
}
}
if (j == len)
{
sendFlag = 1;
}
}
if (sendFlag == 1)
{
/* Send probe response */
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBERSP, src, i, 0, 0);
}
}
}
}
void zfStaProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo)
{
/* return if not channel scan */
// Probe response is sent with unicast. Is this required?
// IBSS would send probe request and the code below would prevent
// the probe response from handling.
#if 0
zmw_get_wlan_dev(dev);
if ( !wd->sta.bChannelScan )
{
return;
}
#endif
zfProcessProbeRsp(dev, buf, AddInfo);
}
void zfIBSSSetupBssDesc(zdev_t *dev)
{
#ifdef ZM_ENABLE_IBSS_WPA2PSK
u8_t i;
#endif
struct zsBssInfo *pBssInfo;
u16_t offset = 0;
zmw_get_wlan_dev(dev);
pBssInfo = &wd->sta.ibssBssDesc;
zfZeroMemory((u8_t *)pBssInfo, sizeof(struct zsBssInfo));
pBssInfo->signalStrength = 100;
zfMemoryCopy((u8_t *)pBssInfo->macaddr, (u8_t *)wd->macAddr,6);
zfMemoryCopy((u8_t *)pBssInfo->bssid, (u8_t *)wd->sta.bssid, 6);
pBssInfo->beaconInterval[0] = (u8_t)(wd->beaconInterval) ;
pBssInfo->beaconInterval[1] = (u8_t)((wd->beaconInterval) >> 8) ;
pBssInfo->capability[0] = wd->sta.capability[0];
pBssInfo->capability[1] = wd->sta.capability[1];
pBssInfo->ssid[0] = ZM_WLAN_EID_SSID;
pBssInfo->ssid[1] = wd->sta.ssidLen;
zfMemoryCopy((u8_t *)&pBssInfo->ssid[2], (u8_t *)wd->sta.ssid, wd->sta.ssidLen);
zfMemoryCopy((u8_t *)&pBssInfo->frameBody[offset], (u8_t *)pBssInfo->ssid,
wd->sta.ssidLen + 2);
offset += wd->sta.ssidLen + 2;
/* support rate */
/* DS parameter set */
pBssInfo->channel = zfChFreqToNum(wd->frequency, NULL);
pBssInfo->frequency = wd->frequency;
pBssInfo->atimWindow = wd->sta.atimWindow;
#ifdef ZM_ENABLE_IBSS_WPA2PSK
if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK )
{
u8_t rsn[64]=
{
/* Element ID */
0x30,
/* Length */
0x14,
/* Version */
0x01, 0x00,
/* Group Cipher Suite, default=TKIP */
0x00, 0x0f, 0xac, 0x04,
/* Pairwise Cipher Suite Count */
0x01, 0x00,
/* Pairwise Cipher Suite, default=TKIP */
0x00, 0x0f, 0xac, 0x02,
/* Authentication and Key Management Suite Count */
0x01, 0x00,
/* Authentication type, default=PSK */
0x00, 0x0f, 0xac, 0x02,
/* RSN capability */
0x00, 0x00
};
/* Overwrite Group Cipher Suite by AP's setting */
zfMemoryCopy(rsn+4, zgWpa2AesOui, 4);
if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES )
{
/* Overwrite Pairwise Cipher Suite by AES */
zfMemoryCopy(rsn+10, zgWpa2AesOui, 4);
}
// RSN element id
pBssInfo->frameBody[offset++] = ZM_WLAN_EID_RSN_IE ;
// RSN length
pBssInfo->frameBody[offset++] = rsn[1] ;
// RSN information