diff options
Diffstat (limited to 'drivers/staging/otus/80211core/cmmsta.c')
-rw-r--r-- | drivers/staging/otus/80211core/cmmsta.c | 5782 |
1 files changed, 5782 insertions, 0 deletions
diff --git a/drivers/staging/otus/80211core/cmmsta.c b/drivers/staging/otus/80211core/cmmsta.c new file mode 100644 index 00000000000..c75ba11ee43 --- /dev/null +++ b/drivers/staging/otus/80211core/cmmsta.c @@ -0,0 +1,5782 @@ +/* + * 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) +{ + 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 | + +------+----------+------+-------------------+------------------+--------------------+ + */ + //u8_t length, channel, is5G; + u16_t offset; + + /* 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 + for(i=0; i<rsn[1]; i++) + { + pBssInfo->frameBody[offset++] = rsn[i+2] ; + } + + zfMemoryCopy(pBssInfo->rsnIe, rsn, rsn[1]+2); + } +#endif +} + +void zfIbssConnectNetwork(zdev_t* dev) +{ + struct zsBssInfo* pBssInfo; + struct zsBssInfo tmpBssInfo; + u8_t macAddr[6], bssid[6], bssNotFound = TRUE; + u16_t i, j=100; + u16_t k; + struct zsPartnerNotifyEvent event; + u32_t channelFlags; + u16_t oppositeWepStatus; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + /* change state to CONNECTING and stop the channel scanning */ + zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); + zfPowerSavingMgrWakeup(dev); + + /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME STA default. */ + zfUpdateDefaultQosParameter(dev, 0); + + wd->sta.bProtectionMode = FALSE; + zfHpSetSlotTime(dev, 1); + + /* ESS bit off */ + wd->sta.capability[0] &= ~ZM_BIT_0; + /* IBSS bit on */ + wd->sta.capability[0] |= ZM_BIT_1; + /* not not use short slot time */ + wd->sta.capability[1] &= ~ZM_BIT_2; + + wd->sta.wmeConnected = 0; + wd->sta.psMgr.tempWakeUp = 0; + wd->sta.qosInfo = 0; + wd->sta.EnableHT = 0; + wd->BandWidth40 = 0; + wd->ExtOffset = 0; + + if ( wd->sta.bssList.bssCount ) + { + //Reorder BssList by RSSI--CWYang(+) + zfBssInfoReorderList(dev); + + zmw_enter_critical_section(dev); + + pBssInfo = wd->sta.bssList.head; + + for(i=0; i<wd->sta.bssList.bssCount; i++) + { + // 20070806 #1 Privacy bit + if ( pBssInfo->capability[0] & ZM_BIT_4 ) + { // Privacy Ibss network +// zm_debug_msg0("Privacy bit on"); + oppositeWepStatus = ZM_ENCRYPTION_WEP_ENABLED; + + if ( pBssInfo->rsnIe[1] != 0 ) + { + if ( (pBssInfo->rsnIe[7] == 0x01) || (pBssInfo->rsnIe[7] == 0x05) ) + { // WEP-40 & WEP-104 +// zm_debug_msg0("WEP40 or WEP104"); + oppositeWepStatus = ZM_ENCRYPTION_WEP_ENABLED; + } + else if ( pBssInfo->rsnIe[7] == 0x02 ) + { // TKIP +// zm_debug_msg0("TKIP"); + oppositeWepStatus = ZM_ENCRYPTION_TKIP; + } + else if ( pBssInfo->rsnIe[7] == 0x04 ) + { // AES +// zm_debug_msg0("CCMP-AES"); + oppositeWepStatus = ZM_ENCRYPTION_AES; + } + } + } + else + { +// zm_debug_msg0("Privacy bit off"); + oppositeWepStatus = ZM_ENCRYPTION_WEP_DISABLED; + } + + if ( (zfMemoryIsEqual(&(pBssInfo->ssid[2]), wd->sta.ssid, + wd->sta.ssidLen))&& + (wd->sta.ssidLen == pBssInfo->ssid[1])&& + (oppositeWepStatus == wd->sta.wepStatus) ) + { + /* Check support mode */ + if (pBssInfo->frequency > 3000) { + if ( (pBssInfo->EnableHT == 1) + || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP + { + channelFlags = CHANNEL_A_HT; + if (pBssInfo->enableHT40 == 1) { + channelFlags |= CHANNEL_HT40; + } + } else { + channelFlags = CHANNEL_A; + } + } else { + if ( (pBssInfo->EnableHT == 1) + || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP + { + channelFlags = CHANNEL_G_HT; + if(pBssInfo->enableHT40 == 1) { + channelFlags |= CHANNEL_HT40; + } + } else { + if (pBssInfo->extSupportedRates[1] == 0) { + channelFlags = CHANNEL_B; + } else { + channelFlags = CHANNEL_G; + } + } + } + + if ( ((channelFlags == CHANNEL_B) && (wd->connectMode & ZM_BIT_0)) + || ((channelFlags == CHANNEL_G) && (wd->connectMode & ZM_BIT_1)) + || ((channelFlags == CHANNEL_A) && (wd->connectMode & ZM_BIT_2)) + || ((channelFlags & CHANNEL_HT20) && (wd->connectMode & ZM_BIT_3)) ) + { + pBssInfo = pBssInfo->next; + continue; + } + + /* Bypass DFS channel */ + if (zfHpIsDfsChannelNCS(dev, pBssInfo->frequency)) + { + zm_debug_msg0("Bypass DFS channel"); + continue; + } + + /* check IBSS bit */ + if ( pBssInfo->capability[0] & ZM_BIT_1 ) + { + /* may check timestamp here */ + j = i; + break; + } + } + + pBssInfo = pBssInfo->next; + } + + if ((j < wd->sta.bssList.bssCount) && (pBssInfo != NULL)) + { + zfwMemoryCopy((u8_t*)&tmpBssInfo, (u8_t*)(pBssInfo), sizeof(struct zsBssInfo)); + pBssInfo = &tmpBssInfo; + } + else + { + pBssInfo = NULL; + } + + zmw_leave_critical_section(dev); + + //if ( j < wd->sta.bssList.bssCount ) + if (pBssInfo != NULL) + { + int res; + + zm_debug_msg0("IBSS found"); + + /* Found IBSS, reset bssNotFoundCount */ + zmw_enter_critical_section(dev); + wd->sta.bssNotFoundCount = 0; + zmw_leave_critical_section(dev); + + bssNotFound = FALSE; + wd->sta.atimWindow = pBssInfo->atimWindow; + wd->frequency = pBssInfo->frequency; + //wd->sta.flagFreqChanging = 1; + zfCoreSetFrequency(dev, wd->frequency); + zfUpdateBssid(dev, pBssInfo->bssid); + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_ZERO); + zfUpdateSupportRate(dev, pBssInfo->supportedRates); + zfUpdateSupportRate(dev, pBssInfo->extSupportedRates); + wd->beaconInterval = pBssInfo->beaconInterval[0] + + (((u16_t) pBssInfo->beaconInterval[1]) << 8); + + if (wd->beaconInterval == 0) + { + wd->beaconInterval = 100; + } + + /* rsn information element */ + if ( pBssInfo->rsnIe[1] != 0 ) + { + zfMemoryCopy(wd->sta.rsnIe, pBssInfo->rsnIe, + pBssInfo->rsnIe[1]+2); + +#ifdef ZM_ENABLE_IBSS_WPA2PSK + /* If not use RSNA , run traditional */ + zmw_enter_critical_section(dev); + wd->sta.ibssWpa2Psk = 1; + zmw_leave_critical_section(dev); +#endif + } + else + { + wd->sta.rsnIe[1] = 0; + } + + /* privacy bit */ + if ( pBssInfo->capability[0] & ZM_BIT_4 ) + { + wd->sta.capability[0] |= ZM_BIT_4; + } + else + { + wd->sta.capability[0] &= ~ZM_BIT_4; + } + + /* preamble type */ + wd->preambleTypeInUsed = wd->preambleType; + if ( wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_AUTO ) + { + if (pBssInfo->capability[0] & ZM_BIT_5) + { + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; + } + else + { + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_LONG; + } + } + + if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) + { + wd->sta.capability[0] &= ~ZM_BIT_5; + } + else + { + wd->sta.capability[0] |= ZM_BIT_5; + } + + wd->sta.beaconFrameBodySize = pBssInfo->frameBodysize + 12; + + if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) + { + wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; + } + + for (k=0; k<8; k++) + { + wd->sta.beaconFrameBody[k] = pBssInfo->timeStamp[k]; + } + wd->sta.beaconFrameBody[8] = pBssInfo->beaconInterval[0]; + wd->sta.beaconFrameBody[9] = pBssInfo->beaconInterval[1]; + wd->sta.beaconFrameBody[10] = pBssInfo->capability[0]; + wd->sta.beaconFrameBody[11] = pBssInfo->capability[1]; + //for (k=12; k<wd->sta.beaconFrameBodySize; k++) + for (k=0; k<pBssInfo->frameBodysize; k++) + { + wd->sta.beaconFrameBody[k+12] = pBssInfo->frameBody[k]; + } + + zmw_enter_critical_section(dev); + res = zfStaSetOppositeInfoFromBSSInfo(dev, pBssInfo); + if ( res == 0 ) + { + zfMemoryCopy(event.bssid, (u8_t *)(pBssInfo->bssid), 6); + zfMemoryCopy(event.peerMacAddr, (u8_t *)(pBssInfo->macaddr), 6); + } + zmw_leave_critical_section(dev); + + //zfwIbssPartnerNotify(dev, 1, &event); + goto connect_done; + } + } + + /* IBSS not found */ + if ( bssNotFound ) + { +#ifdef ZM_ENABLE_IBSS_WPA2PSK + u16_t offset ; +#endif + if ( wd->sta.ibssJoinOnly ) + { + zm_debug_msg0("IBSS join only...retry..."); + goto retry_ibss; + } + + if(wd->sta.bssNotFoundCount<2) + { + zmw_enter_critical_section(dev); + zm_debug_msg1("IBSS not found, do sitesurvey!! bssNotFoundCount=", wd->sta.bssNotFoundCount); + wd->sta.bssNotFoundCount++; + zmw_leave_critical_section(dev); + goto retry_ibss; + } + else + { + zmw_enter_critical_section(dev); + /* Fail IBSS found, TODO create IBSS */ + wd->sta.bssNotFoundCount = 0; + zmw_leave_critical_section(dev); + } + + + if (zfHpIsDfsChannel(dev, wd->frequency)) + { + wd->frequency = zfHpFindFirstNonDfsChannel(dev, wd->frequency > 3000); + } + + if( wd->ws.autoSetFrequency == 0 ) + { /* Auto set frequency */ + zm_debug_msg1("Create Ad Hoc Network Band ", wd->ws.adhocMode); + wd->frequency = zfFindCleanFrequency(dev, wd->ws.adhocMode); + wd->ws.autoSetFrequency = 0xff; + } + zm_debug_msg1("IBSS not found, created one in channel ", wd->frequency); + + wd->sta.ibssBssIsCreator = 1; + + //wd->sta.flagFreqChanging = 1; + zfCoreSetFrequency(dev, wd->frequency); + if (wd->sta.bDesiredBssid == TRUE) + { + for (k=0; k<6; k++) + { + bssid[k] = wd->sta.desiredBssid[k]; + } + } + else + { + #if 1 + macAddr[0] = (wd->macAddr[0] & 0xff); + macAddr[1] = (wd->macAddr[0] >> 8); + macAddr[2] = (wd->macAddr[1] & 0xff); + macAddr[3] = (wd->macAddr[1] >> 8); + macAddr[4] = (wd->macAddr[2] & 0xff); + macAddr[5] = (wd->macAddr[2] >> 8); + zfGenerateRandomBSSID(dev, (u8_t *)wd->macAddr, (u8_t *)bssid); + #else + for (k=0; k<6; k++) + { + bssid[k] = (u8_t) zfGetRandomNumber(dev, 0); + } + bssid[0] &= ~ZM_BIT_0; + bssid[0] |= ZM_BIT_1; + #endif + } + + zfUpdateBssid(dev, bssid); + //wd->sta.atimWindow = 0x0a; + + /* rate information */ + if(wd->frequency <= ZM_CH_G_14) // 2.4 GHz b+g + { + if ( wd->wfc.bIbssGMode + && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) + { + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_AG); + } + else + { + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_B); + } + } else { + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_AG); + } + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED ) + { + wd->sta.capability[0] &= ~ZM_BIT_4; + } + else + { + wd->sta.capability[0] |= ZM_BIT_4; + } + + wd->preambleTypeInUsed = wd->preambleType; + if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) + { + wd->sta.capability[0] &= ~ZM_BIT_5; + } + else + { + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; + wd->sta.capability[0] |= ZM_BIT_5; + } + + zfIBSSSetupBssDesc(dev); + +#ifdef ZM_ENABLE_IBSS_WPA2PSK + + // 20070411 Add WPA2PSK information to its IBSS network !!! + offset = 0 ; + + /* timestamp */ + offset += 8 ; + + /* beacon interval */ + wd->sta.beaconFrameBody[offset++] = (u8_t)(wd->beaconInterval) ; + wd->sta.beaconFrameBody[offset++] = (u8_t)((wd->beaconInterval) >> 8) ; + + /* capability information */ + wd->sta.beaconFrameBody[offset++] = wd->sta.capability[0] ; + wd->sta.beaconFrameBody[offset++] = wd->sta.capability[1] ; + #if 0 + /* ssid */ + // ssid element id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_SSID ; + // ssid length + wd->sta.beaconFrameBody[offset++] = wd->sta.ssidLen ; + // ssid information + for(i=0; i<wd->sta.ssidLen; i++) + { + wd->sta.beaconFrameBody[offset++] = wd->sta.ssid[i] ; + } + + /* support rate */ + rateSet = ZM_RATE_SET_CCK ; + if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) + { + offset += 0 ; + } + else + { + // support rate element id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_SUPPORT_RATE ; + + // support rate length + lenOffset = offset++; + + // support rate information + for (i=0; i<4; i++) + { + if ((wd->bRate & (0x1<<i)) == (0x1<<i)) + { + wd->sta.beaconFrameBody[offset++] = + zg11bRateTbl[i]+((wd->bRateBasic & (0x1<<i))<<(7-i)) ; + len++; + } + } + + // support rate length + wd->sta.beaconFrameBody[lenOffset] = len ; + } + + /* DS parameter set */ + // DS parameter set elemet id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_DS ; + + // DS parameter set length + wd->sta.beaconFrameBody[offset++] = 1 ; + + // DS parameter set information + wd->sta.beaconFrameBody[offset++] = + zfChFreqToNum(wd->frequency, NULL) ; + + /* IBSS parameter set */ + // IBSS parameter set element id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_IBSS ; + + // IBSS parameter set length + wd->sta.beaconFrameBody[offset++] = 2 ; + + // IBSS parameter set information + wd->sta.beaconFrameBody[offset] = wd->sta.atimWindow ; + offset += 2 ; + + /* ERP Information and Extended Supported Rates */ + if ( wd->wfc.bIbssGMode + && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) + { + /* ERP Information */ + wd->erpElement = 0; + // ERP element id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_ERP ; + + // ERP length + wd->sta.beaconFrameBody[offset++] = 1 ; + + // ERP information + wd->sta.beaconFrameBody[offset++] = wd->erpElement ; + + /* Extended Supported Rates */ + if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) + { + offset += 0 ; + } + else + { + len = 0 ; + + // Extended Supported Rates element id + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_EXTENDED_RATE ; + + // Extended Supported Rates length + lenOffset = offset++ ; + + // Extended Supported Rates information + for (i=0; i<8; i++) + { + if ((wd->gRate & (0x1<<i)) == (0x1<<i)) + { + wd->sta.beaconFrameBody[offset++] = + zg11gRateTbl[i]+((wd->gRateBasic & (0x1<<i))<<(7-i)); + len++; + } + } + + // extended support rate length + wd->sta.beaconFrameBody[lenOffset] = len ; + } + } + #endif + + /* RSN : important information influence the result of creating an IBSS network */ + if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) + { + u8_t frameType = ZM_WLAN_FRAME_TYPE_AUTH ; + 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 + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_RSN_IE ; + + // RSN length + wd->sta.beaconFrameBody[offset++] = rsn[1] ; + + // RSN information + for(i=0; i<rsn[1]; i++) + wd->sta.beaconFrameBody[offset++] = rsn[i+2] ; + + zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); + +#ifdef ZM_ENABLE_IBSS_WPA2PSK + /* If not use RSNA , run traditional */ + zmw_enter_critical_section(dev); + wd->sta.ibssWpa2Psk = 1; + zmw_leave_critical_section(dev); +#endif + } + + #if 0 + /* HT Capabilities Info */ + { + u8_t OUI[3] = { 0x0 , 0x90 , 0x4C } ; + + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_WPA_IE ; + + wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Data.Length + 4 ; + + for (i = 0; i < 3; i++) + { + wd->sta.beaconFrameBody[offset++] = OUI[i] ; + } + + wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Data.ElementID ; + + for (i = 0; i < 26; i++) + { + wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Byte[i+2] ; + } + } + + /* Extended HT Capabilities Info */ + { + u8_t OUI[3] = { 0x0 , 0x90 , 0x4C } ; + + wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_WPA_IE ; + + wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Data.Length + 4 ; + + for (i = 0; i < 3; i++) + { + wd->sta.beaconFrameBody[offset++] = OUI[i] ; + } + + wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Data.ElementID ; + + for (i = 0; i < 22; i++) + { + wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Byte[i+2] ; + } + } + #endif + + wd->sta.beaconFrameBodySize = offset ; + + if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) + { + wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; + } + + // 20070416 Let Create IBSS network could enter the zfwIbssPartnerNotify function + // bssNotFound = FALSE ; + + printk("The capability info 1 = %02x\n", wd->sta.capability[0]) ; + printk("The capability info 2 = %02x\n", wd->sta.capability[1]) ; + for(k=0; k<wd->sta.beaconFrameBodySize; k++) + { + printk("%02x ", wd->sta.beaconFrameBody[k]) ; + } + #if 0 + zmw_enter_critical_section(dev); + zfMemoryCopy(event.bssid, (u8_t *)bssid, 6); + zfMemoryCopy(event.peerMacAddr, (u8_t *)wd->macAddr, 6); + zmw_leave_critical_section(dev); + #endif +#endif + + //zmw_enter_critical_section(dev); + //wd->sta.ibssPartnerStatus = ZM_IBSS_PARTNER_LOST; + //zmw_leave_critical_section(dev); + } + else + { + wd->sta.ibssBssIsCreator = 0; + } + +connect_done: + zfHpEnableBeacon(dev, ZM_MODE_IBSS, wd->beaconInterval, wd->dtim, (u8_t)wd->sta.atimWindow); + zfStaSendBeacon(dev); // Refresh Beacon content for ZD1211B HalPlus + zfHpSetAtimWindow(dev, wd->sta.atimWindow); + + // Start the IBSS timer to monitor for new stations + zmw_enter_critical_section(dev); + zfTimerSchedule(dev, ZM_EVENT_IBSS_MONITOR, ZM_TICK_IBSS_MONITOR); + zmw_leave_critical_section(dev); + + + if (wd->zfcbConnectNotify != NULL) + { + wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); + } + zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); + wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev); + +#ifdef ZM_ENABLE_IBSS_DELAYED_JOIN_INDICATION + if ( !bssNotFound ) + { + wd->sta.ibssDelayedInd = 1; + zfMemoryCopy((u8_t *)&wd->sta.ibssDelayedIndEvent, (u8_t *)&event, sizeof(struct zsPartnerNotifyEvent)); + } +#else + if ( !bssNotFound ) + { + if (wd->zfcbIbssPartnerNotify != NULL) + { + wd->zfcbIbssPartnerNotify(dev, 1, &event); + } + } +#endif + + return; + +retry_ibss: + zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); + zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND, wd->sta.bssid, 0); + return; +} + +void zfStaProcessAtim(zdev_t* dev, zbuf_t* buf) +{ + zmw_get_wlan_dev(dev); + + zm_debug_msg0("Receiving Atim window notification"); + + wd->sta.recvAtim = 1; +} + +static struct zsBssInfo* zfInfraFindAPToConnect(zdev_t* dev, + struct zsBssInfo* candidateBss) +{ + struct zsBssInfo* pBssInfo; + struct zsBssInfo* pNowBssInfo=NULL; + u16_t i; + u16_t ret, apWepStatus; + u32_t k; + u32_t channelFlags; + + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + zmw_enter_critical_section(dev); + + pBssInfo = wd->sta.bssList.head; + + for(i=0; i<wd->sta.bssList.bssCount; i++) + { + if ( pBssInfo->capability[0] & ZM_BIT_4 ) + { + apWepStatus = ZM_ENCRYPTION_WEP_ENABLED; + } + else + { + apWepStatus = ZM_ENCRYPTION_WEP_DISABLED; + } + + if ( ((zfMemoryIsEqual(&(pBssInfo->ssid[2]), wd->sta.ssid, + wd->sta.ssidLen))&& + (wd->sta.ssidLen == pBssInfo->ssid[1]))|| + ((wd->sta.ssidLen == 0)&& + /* connect to any BSS: AP's ans STA's WEP status must match */ + (wd->sta.wepStatus == apWepStatus )&& + (pBssInfo->securityType != ZM_SECURITY_TYPE_WPA) )) + { + if ( wd->sta.ssidLen == 0 ) + { + zm_debug_msg0("ANY BSS found"); + } + + if ( ((wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED && apWepStatus == ZM_ENCRYPTION_WEP_ENABLED) || + (wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED && + (apWepStatus == ZM_ENCRYPTION_WEP_DISABLED && wd->sta.dropUnencryptedPkts == 1))) && + (wd->sta.authMode >= ZM_AUTH_MODE_OPEN && wd->sta.authMode <= ZM_AUTH_MODE_AUTO) ) + { + zm_debug_msg0("Privacy policy is inconsistent"); + pBssInfo = pBssInfo->next; + continue; + } + + /* for WPA negative test */ + if ( !zfCheckAuthentication(dev, pBssInfo) ) + { + pBssInfo = pBssInfo->next; + continue; + } + + /* Check bssid */ + if (wd->sta.bDesiredBssid == TRUE) + { + for (k=0; k<6; k++) + { + if (wd->sta.desiredBssid[k] != pBssInfo->bssid[k]) + { + zm_msg0_mm(ZM_LV_1, "desired bssid not matched 1"); + break; + } + } + + if (k != 6) + { + zm_msg0_mm(ZM_LV_1, "desired bssid not matched 2"); + pBssInfo = pBssInfo->next; + continue; + } + } + + /* Check support mode */ + if (pBssInfo->frequency > 3000) { + if ( (pBssInfo->EnableHT == 1) + || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP + { + channelFlags = CHANNEL_A_HT; + if (pBssInfo->enableHT40 == 1) { + channelFlags |= CHANNEL_HT40; + } + } else { + channelFlags = CHANNEL_A; + } + } else { + if ( (pBssInfo->EnableHT == 1) + || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP + { + channelFlags = CHANNEL_G_HT; + if(pBssInfo->enableHT40 == 1) { + channelFlags |= CHANNEL_HT40; + } + } else { + if (pBssInfo->extSupportedRates[1] == 0) { + channelFlags = CHANNEL_B; + } else { + channelFlags = CHANNEL_G; + } + } + } + + if ( ((channelFlags == CHANNEL_B) && (wd->connectMode & ZM_BIT_0)) + || ((channelFlags == CHANNEL_G) && (wd->connectMode & ZM_BIT_1)) + || ((channelFlags == CHANNEL_A) && (wd->connectMode & ZM_BIT_2)) + || ((channelFlags & CHANNEL_HT20) && (wd->connectMode & ZM_BIT_3)) ) + { + pBssInfo = pBssInfo->next; + continue; + } + + /* Skip if AP in blocking list */ + if ((ret = zfStaIsApInBlockingList(dev, pBssInfo->bssid)) == TRUE) + { + zm_msg0_mm(ZM_LV_0, "Candidate AP in blocking List, skip if there's stilla choice!"); + pNowBssInfo = pBssInfo; + pBssInfo = pBssInfo->next; + continue; + } + + if ( pBssInfo->capability[0] & ZM_BIT_0 ) // check if infra-BSS + { + pNowBssInfo = pBssInfo; + wd->sta.apWmeCapability = pBssInfo->wmeSupport; + + + goto done; + } + } + + pBssInfo = pBssInfo->next; + } + +done: + if (pNowBssInfo != NULL) + { + zfwMemoryCopy((void*)candidateBss, (void*)pNowBssInfo, sizeof(struct zsBssInfo)); + pNowBssInfo = candidateBss; + } + + zmw_leave_critical_section(dev); + + return pNowBssInfo; +} + + +void zfInfraConnectNetwork(zdev_t* dev) +{ + struct zsBssInfo* pBssInfo; + struct zsBssInfo* pNowBssInfo=NULL; + struct zsBssInfo candidateBss; + //u16_t i, j=100, quality=10000; + //u8_t ret=FALSE, apWepStatus; + u8_t ret=FALSE; + u16_t k; + u8_t density = ZM_MPDU_DENSITY_NONE; + + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + /* Reset bssNotFoundCount for Ad-Hoc:IBSS */ + /* Need review : IbssConn -> InfraConn -> IbssConn etc, flag/counter reset? */ + zmw_enter_critical_section(dev); + wd->sta.bssNotFoundCount = 0; + zmw_leave_critical_section(dev); + + /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME STA default. */ + zfUpdateDefaultQosParameter(dev, 0); + + zfStaRefreshBlockList(dev, 0); + + /* change state to CONNECTING and stop the channel scanning */ + zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); + zfPowerSavingMgrWakeup(dev); + + wd->sta.wmeConnected = 0; + wd->sta.psMgr.tempWakeUp = 0; + wd->sta.qosInfo = 0; + zfQueueFlush(dev, wd->sta.uapsdQ); + + wd->sta.connectState = ZM_STA_CONN_STATE_NONE; + + //Reorder BssList by RSSI--CWYang(+) + zfBssInfoReorderList(dev); + + pNowBssInfo = zfInfraFindAPToConnect(dev, &candidateBss); + + if (wd->sta.SWEncryptEnable != 0) + { + if (wd->sta.bSafeMode == 0) + { + zfStaDisableSWEncryption(dev);//Quickly reboot + } + } + if ( pNowBssInfo != NULL ) + { + //zm_assert(pNowBssInfo != NULL); + + pBssInfo = pNowBssInfo; + wd->sta.ssidLen = pBssInfo->ssid[1]; + zfMemoryCopy(wd->sta.ssid, &(pBssInfo->ssid[2]), pBssInfo->ssid[1]); + wd->frequency = pBssInfo->frequency; + //wd->sta.flagFreqChanging = 1; + + //zfCoreSetFrequency(dev, wd->frequency); + zfUpdateBssid(dev, pBssInfo->bssid); + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_ZERO); + zfUpdateSupportRate(dev, pBssInfo->supportedRates); + zfUpdateSupportRate(dev, pBssInfo->extSupportedRates); + + wd->beaconInterval = pBssInfo->beaconInterval[0] + + (((u16_t) pBssInfo->beaconInterval[1]) << 8); + if (wd->beaconInterval == 0) + { + wd->beaconInterval = 100; + } + + /* ESS bit on */ + wd->sta.capability[0] |= ZM_BIT_0; + /* IBSS bit off */ + wd->sta.capability[0] &= ~ZM_BIT_1; + + /* 11n AP flag */ + wd->sta.EnableHT = pBssInfo->EnableHT; + wd->sta.SG40 = pBssInfo->SG40; +#ifdef ZM_ENABLE_CENC + if ( pBssInfo->securityType == ZM_SECURITY_TYPE_CENC ) + { + wd->sta.wmeEnabled = 0; //Disable WMM in CENC + cencInit(dev); + cencSetCENCMode(dev, NdisCENC_PSK); + wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; + /* CENC */ + if ( pBssInfo->cencIe[1] != 0 ) + { + //wd->sta.wepStatus = ZM_ENCRYPTION_CENC; + //wd->sta.encryMode = ZM_CENC; + zfwCencHandleBeaconProbrespon(dev, (u8_t *)&pBssInfo->cencIe, + (u8_t *)&pBssInfo->ssid, (u8_t *)&pBssInfo->macaddr); + zfMemoryCopy(wd->sta.cencIe, pBssInfo->cencIe, + pBssInfo->cencIe[1]+2); + } + else + { + wd->sta.cencIe[1] = 0; + } + } +#endif //ZM_ENABLE_CENC + if ( pBssInfo->securityType == ZM_SECURITY_TYPE_WPA ) + { + wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_TKIP ) + { + wd->sta.encryMode = ZM_TKIP; + + /* Turn on software encryption/decryption for TKIP */ + if (wd->sta.EnableHT == 1) + { + zfStaEnableSWEncryption(dev, (ZM_SW_TKIP_ENCRY_EN|ZM_SW_TKIP_DECRY_EN)); + } + + /* Do not support TKIP in 11n mode */ + //wd->sta.EnableHT = 0; + //pBssInfo->enableHT40 = 0; + } + else if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + wd->sta.encryMode = ZM_AES; + + /* If AP supports HT mode */ + if (wd->sta.EnableHT) + { + /* Set MPDU density to 8 us*/ + density = ZM_MPDU_DENSITY_8US; + } + } + + if ( pBssInfo->wpaIe[1] != 0 ) + { + zfMemoryCopy(wd->sta.wpaIe, pBssInfo->wpaIe, + pBssInfo->wpaIe[1]+2); + } + else + { + wd->sta.wpaIe[1] = 0; + } + + if ( pBssInfo->rsnIe[1] != 0 ) + { + zfMemoryCopy(wd->sta.rsnIe, pBssInfo->rsnIe, + pBssInfo->rsnIe[1]+2); + } + else + { + wd->sta.rsnIe[1] = 0; + } + } + + + + /* check preamble bit */ + wd->preambleTypeInUsed = wd->preambleType; + if ( wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_AUTO ) + { + if (pBssInfo->capability[0] & ZM_BIT_5) + { + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; + } + else + { + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_LONG; + } + } + + if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) + { + wd->sta.capability[0] &= ~ZM_BIT_5; + } + else + { + wd->sta.capability[0] |= ZM_BIT_5; + } + + /* check 802.11n 40MHz Setting */ + if ((pBssInfo->enableHT40 == 1) && + ((pBssInfo->extChOffset == 1) || (pBssInfo->extChOffset == 3))) + { + wd->BandWidth40 = pBssInfo->enableHT40; + wd->ExtOffset = pBssInfo->extChOffset; + } + else + { + wd->BandWidth40 = 0; + wd->ExtOffset = 0; + } + + /* check 802.11H support bit */ + + /* check Owl Ap */ + if ( pBssInfo->athOwlAp & ZM_BIT_0 ) + { + /* In this function, FW retry will be enable, ZM_MAC_REG_RETRY_MAX + will be set to 0. + */ + zfHpDisableHwRetry(dev); + wd->sta.athOwlAp = 1; + /* Set MPDU density to 8 us*/ + density = ZM_MPDU_DENSITY_8US; + } + else + { + /* In this function, FW retry will be disable, ZM_MAC_REG_RETRY_MAX + will be set to 3. + */ + zfHpEnableHwRetry(dev); + wd->sta.athOwlAp = 0; + } + wd->reorder = 1; + + /* Set MPDU density */ + zfHpSetMPDUDensity(dev, density); + + /* check short slot time bit */ + if ( pBssInfo->capability[1] & ZM_BIT_2 ) + { + wd->sta.capability[1] |= ZM_BIT_2; + } + + if ( pBssInfo->erp & ZM_BIT_1 ) + { + //zm_debug_msg0("protection mode on"); + wd->sta.bProtectionMode = TRUE; + zfHpSetSlotTime(dev, 0); + } + else + { + //zm_debug_msg0("protection mode off"); + wd->sta.bProtectionMode = FALSE; + zfHpSetSlotTime(dev, 1); + } + + if (pBssInfo->marvelAp == 1) + { + wd->sta.enableDrvBA = 0; + /* + * 8701 : NetGear 3500 (MARVELL) + * Downlink issue : set slottime to 20. + */ + zfHpSetSlotTimeRegister(dev, 0); + } + else + { + wd->sta.enableDrvBA = 1; + + /* + * This is not good for here do reset slot time. + * I think it should reset when leave MARVELL ap + * or enter disconnect state etc. + */ + zfHpSetSlotTimeRegister(dev, 1); + } + + //Store probe response frame body, for VISTA only + wd->sta.beaconFrameBodySize = pBssInfo->frameBodysize + 12; + if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) + { + wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; + } + for (k=0; k<8; k++) + { + wd->sta.beaconFrameBody[k] = pBssInfo->timeStamp[k]; + } + wd->sta.beaconFrameBody[8] = pBssInfo->beaconInterval[0]; + wd->sta.beaconFrameBody[9] = pBssInfo->beaconInterval[1]; + wd->sta.beaconFrameBody[10] = pBssInfo->capability[0]; + wd->sta.beaconFrameBody[11] = pBssInfo->capability[1]; + for (k=0; k<(wd->sta.beaconFrameBodySize - 12); k++) + { + wd->sta.beaconFrameBody[k+12] = pBssInfo->frameBody[k]; + } + + if ( ( pBssInfo->capability[0] & ZM_BIT_4 )&& + (( wd->sta.authMode == ZM_AUTH_MODE_OPEN )|| + ( wd->sta.authMode == ZM_AUTH_MODE_SHARED_KEY)|| + (wd->sta.authMode == ZM_AUTH_MODE_AUTO)) ) + { /* privacy enabled */ + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED ) + { + zm_debug_msg0("Adapter is no WEP, try to connect to WEP AP"); + ret = FALSE; + } + + /* Do not support WEP in 11n mode */ + if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) + { + /* Turn on software encryption/decryption for WEP */ + if (wd->sta.EnableHT == 1) + { + zfStaEnableSWEncryption(dev, (ZM_SW_WEP_ENCRY_EN|ZM_SW_WEP_DECRY_EN)); + } + + //wd->sta.EnableHT = 0; + //wd->BandWidth40 = 0; + //wd->ExtOffset = 0; + } + + wd->sta.capability[0] |= ZM_BIT_4; + + if ( wd->sta.authMode == ZM_AUTH_MODE_AUTO ) + { /* Try to use open and shared-key authehtication alternatively */ + if ( (wd->sta.connectTimeoutCount % 2) == 0 ) + wd->sta.bIsSharedKey = 0; + else + wd->sta.bIsSharedKey = 1; + } + else if ( wd->sta.authMode != ZM_AUTH_MODE_SHARED_KEY ) + { /* open or auto */ + //zfStaStartConnect(dev, 0); + wd->sta.bIsSharedKey = 0; + } + else if ( wd->sta.authMode != ZM_AUTH_MODE_OPEN ) + { /* shared key */ + //zfStaStartConnect(dev, 1) ; + wd->sta.bIsSharedKey = 1; + } + } + else + { + if ( (pBssInfo->securityType == ZM_SECURITY_TYPE_WPA)|| + (pBssInfo->capability[0] & ZM_BIT_4) ) + { + wd->sta.capability[0] |= ZM_BIT_4; + /* initialize WPA related parameters */ + } + else + { + wd->sta.capability[0] &= (~ZM_BIT_4); + } + + /* authentication with open system */ + //zfStaStartConnect(dev, 0); + wd->sta.bIsSharedKey = 0; + } + + /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ + /* + if ( (pBssInfo->broadcomHTAp == 1) + && (wd->sta.SWEncryptEnable != 0) ) + { + zfHpSetTTSIFSTime(dev, 0xa); + } + else + { + zfHpSetTTSIFSTime(dev, 0x8); + } + */ + } + else + { + zm_debug_msg0("Desired SSID not found"); + goto zlConnectFailed; + } + + + zfCoreSetFrequencyV2(dev, wd->frequency, zfStaStartConnectCb); + return; + +zlConnectFailed: + zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND, wd->sta.bssid, 0); + return; +} + +u8_t zfCheckWPAAuth(zdev_t* dev, struct zsBssInfo* pBssInfo) +{ + u8_t ret=TRUE; + u8_t pmkCount; + u8_t i; + u16_t encAlgoType = 0; + + zmw_get_wlan_dev(dev); + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_TKIP ) + { + encAlgoType = ZM_TKIP; + } + else if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + encAlgoType = ZM_AES; + } + + switch(wd->sta.authMode) + { + case ZM_AUTH_MODE_WPA: + case ZM_AUTH_MODE_WPAPSK: + if ( pBssInfo->wpaIe[1] == 0 ) + { + ret = FALSE; + break; + } + + pmkCount = pBssInfo->wpaIe[12]; + for(i=0; i < pmkCount; i++) + { + if ( pBssInfo->wpaIe[17 + 4*i] == encAlgoType ) + { + ret = TRUE; + goto done; + } + } + + ret = FALSE; + break; + + case ZM_AUTH_MODE_WPA2: + case ZM_AUTH_MODE_WPA2PSK: + if ( pBssInfo->rsnIe[1] == 0 ) + { + ret = FALSE; + break; + } + + pmkCount = pBssInfo->rsnIe[8]; + for(i=0; i < pmkCount; i++) + { + if ( pBssInfo->rsnIe[13 + 4*i] == encAlgoType ) + { + ret = TRUE; + goto done; + } + } + + ret = FALSE; + break; + } + +done: + return ret; +} + +u8_t zfCheckAuthentication(zdev_t* dev, struct zsBssInfo* pBssInfo) +{ + u8_t ret=TRUE; + u16_t encAlgoType; + u16_t UnicastCipherNum; + + zmw_get_wlan_dev(dev); + + /* Connecting to ANY has been checked */ + if ( wd->sta.ssidLen == 0 ) + { + return ret; + } + + + switch(wd->sta.authMode) + //switch(wd->ws.authMode)//Quickly reboot + { + case ZM_AUTH_MODE_WPA_AUTO: + case ZM_AUTH_MODE_WPAPSK_AUTO: + encAlgoType = 0; + if(pBssInfo->rsnIe[1] != 0) + { + UnicastCipherNum = (pBssInfo->rsnIe[8]) + + (pBssInfo->rsnIe[9] << 8); + + /* If there is only one unicast cipher */ + if (UnicastCipherNum == 1) + { + encAlgoType = pBssInfo->rsnIe[13]; + //encAlgoType = pBssInfo->rsnIe[7]; + } + else + { + u16_t ii; + u16_t desiredCipher = 0; + u16_t IEOffSet = 13; + + /* Enumerate all the supported unicast cipher */ + for (ii = 0; ii < UnicastCipherNum; ii++) + { + if (pBssInfo->rsnIe[IEOffSet+ii*4] > desiredCipher) + { + desiredCipher = pBssInfo->rsnIe[IEOffSet+ii*4]; + } + } + + encAlgoType = desiredCipher; + } + + if ( encAlgoType == 0x02 ) + { + wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; + + if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2; + } + else //ZM_AUTH_MODE_WPAPSK_AUTO + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2PSK; + } + } + else if ( encAlgoType == 0x04 ) + { + wd->sta.wepStatus = ZM_ENCRYPTION_AES; + + if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2; + } + else //ZM_AUTH_MODE_WPAPSK_AUTO + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2PSK; + } + } + else + { + ret = FALSE; + } + } + else if(pBssInfo->wpaIe[1] != 0) + { + UnicastCipherNum = (pBssInfo->wpaIe[12]) + + (pBssInfo->wpaIe[13] << 8); + + /* If there is only one unicast cipher */ + if (UnicastCipherNum == 1) + { + encAlgoType = pBssInfo->wpaIe[17]; + //encAlgoType = pBssInfo->wpaIe[11]; + } + else + { + u16_t ii; + u16_t desiredCipher = 0; + u16_t IEOffSet = 17; + + /* Enumerate all the supported unicast cipher */ + for (ii = 0; ii < UnicastCipherNum; ii++) + { + if (pBssInfo->wpaIe[IEOffSet+ii*4] > desiredCipher) + { + desiredCipher = pBssInfo->wpaIe[IEOffSet+ii*4]; + } + } + + encAlgoType = desiredCipher; + } + + if ( encAlgoType == 0x02 ) + { + wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; + + if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA; + } + else //ZM_AUTH_MODE_WPAPSK_AUTO + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPAPSK; + } + } + else if ( encAlgoType == 0x04 ) + { + wd->sta.wepStatus = ZM_ENCRYPTION_AES; + + if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA; + } + else //ZM_AUTH_MODE_WPAPSK_AUTO + { + wd->sta.currentAuthMode = ZM_AUTH_MODE_WPAPSK; + } + } + else + { + ret = FALSE; + } + + + } + else + { + ret = FALSE; + } + + break; + + case ZM_AUTH_MODE_WPA: + case ZM_AUTH_MODE_WPAPSK: + case ZM_AUTH_MODE_WPA_NONE: + case ZM_AUTH_MODE_WPA2: + case ZM_AUTH_MODE_WPA2PSK: + { + if ( pBssInfo->securityType != ZM_SECURITY_TYPE_WPA ) + { + ret = FALSE; + } + + ret = zfCheckWPAAuth(dev, pBssInfo); + } + break; + + case ZM_AUTH_MODE_OPEN: + case ZM_AUTH_MODE_SHARED_KEY: + case ZM_AUTH_MODE_AUTO: + { + if ( pBssInfo->wscIe[1] ) + { + // If the AP is a Jumpstart AP, it's ok!! Ray + break; + } + else if ( pBssInfo->securityType == ZM_SECURITY_TYPE_WPA ) + { + ret = FALSE; + } + } + break; + + default: + break; + } + + return ret; +} + +u8_t zfStaIsConnected(zdev_t* dev) +{ + zmw_get_wlan_dev(dev); + + if ( wd->sta.adapterState == ZM_STA_STATE_CONNECTED ) + { + return TRUE; + } + + return FALSE; +} + +u8_t zfStaIsConnecting(zdev_t* dev) +{ + zmw_get_wlan_dev(dev); + + if ( wd->sta.adapterState == ZM_STA_STATE_CONNECTING ) + { + return TRUE; + } + + return FALSE; +} + +u8_t zfStaIsDisconnect(zdev_t* dev) +{ + zmw_get_wlan_dev(dev); + + if ( wd->sta.adapterState == ZM_STA_STATE_DISCONNECT ) + { + return TRUE; + } + + return FALSE; +} + +u8_t zfChangeAdapterState(zdev_t* dev, u8_t newState) +{ + u8_t ret = TRUE; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + //if ( newState == wd->sta.adapterState ) + //{ + // return FALSE; + //} + + switch(newState) + { + case ZM_STA_STATE_DISCONNECT: + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_DISCONNECT); + + #if 1 + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); + #else + if ( wd->sta.bChannelScan ) + { + /* stop the action of channel scanning */ + wd->sta.bChannelScan = FALSE; + ret = TRUE; + break; + } + #endif + + break; + case ZM_STA_STATE_CONNECTING: + #if 1 + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); + #else + if ( wd->sta.bChannelScan ) + { + /* stop the action of channel scanning */ + wd->sta.bChannelScan = FALSE; + ret = TRUE; + break; + } + #endif + + break; + case ZM_STA_STATE_CONNECTED: + break; + default: + break; + } + + //if ( ret ) + //{ + zmw_enter_critical_section(dev); + wd->sta.adapterState = newState; + zmw_leave_critical_section(dev); + + zm_debug_msg1("change adapter state = ", newState); + //} + + return ret; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaMmAddIeSsid */ +/* Add information element SSID to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Ji-Huang Lee ZyDAS Technology Corporation 2005.11 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + u16_t i; + + zmw_get_wlan_dev(dev); + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ssidLen); + + /* Information : SSID */ + for (i=0; i<wd->sta.ssidLen; i++) + { + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ssid[i]); + } + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaMmAddIeWpa */ +/* Add information element SSID to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Ji-Huang Lee ZyDAS Technology Corporation 2006.01 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) +{ + u32_t i; + u8_t ssn[64]={ + /* Element ID */ + 0xdd, + /* Length */ + 0x18, + /* OUI type */ + 0x00, 0x50, 0xf2, 0x01, + /* Version */ + 0x01, 0x00, + /* Group Cipher Suite, default=TKIP */ + 0x00, 0x50, 0xf2, 0x02, + /* Pairwise Cipher Suite Count */ + 0x01, 0x00, + /* Pairwise Cipher Suite, default=TKIP */ + 0x00, 0x50, 0xf2, 0x02, + /* Authentication and Key Management Suite Count */ + 0x01, 0x00, + /* Authentication type, default=PSK */ + 0x00, 0x50, 0xf2, 0x02, + /* WPA capability */ + 0x00, 0x00 + }; + + u8_t rsn[64]={ + /* Element ID */ + 0x30, + /* Length */ + 0x14, + /* Version */ + 0x01, 0x00, + /* Group Cipher Suite, default=TKIP */ + 0x00, 0x0f, 0xac, 0x02, + /* 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 + }; + + zmw_get_wlan_dev(dev); + + if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPAPSK ) + { + /* Overwrite Group Cipher Suite by AP's setting */ + zfMemoryCopy(ssn+8, wd->sta.wpaIe+8, 4); + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + /* Overwrite Pairwise Cipher Suite by AES */ + zfMemoryCopy(ssn+14, zgWpaAesOui, 4); + } + + zfCopyToIntTxBuffer(dev, buf, ssn, offset, ssn[1]+2); + zfMemoryCopy(wd->sta.wpaIe, ssn, ssn[1]+2); + offset += (ssn[1]+2); + } + else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA ) + { + /* Overwrite Group Cipher Suite by AP's setting */ + zfMemoryCopy(ssn+8, wd->sta.wpaIe+8, 4); + /* Overwrite Key Management Suite by WPA-Radius */ + zfMemoryCopy(ssn+20, zgWpaRadiusOui, 4); + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + /* Overwrite Pairwise Cipher Suite by AES */ + zfMemoryCopy(ssn+14, zgWpaAesOui, 4); + } + + zfCopyToIntTxBuffer(dev, buf, ssn, offset, ssn[1]+2); + zfMemoryCopy(wd->sta.wpaIe, ssn, ssn[1]+2); + offset += (ssn[1]+2); + } + else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA2PSK ) + { + /* Overwrite Group Cipher Suite by AP's setting */ + zfMemoryCopy(rsn+4, wd->sta.rsnIe+4, 4); + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + /* Overwrite Pairwise Cipher Suite by AES */ + zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); + } + + if ( frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ ) + { + for(i=0; i<wd->sta.pmkidInfo.bssidCount; i++) + { + if ( zfMemoryIsEqual((u8_t*) wd->sta.pmkidInfo.bssidInfo[i].bssid, + (u8_t*) wd->sta.bssid, 6) ) + { + /* matched */ + break; + } + + if ( i < wd->sta.pmkidInfo.bssidCount ) + { + // Fill PMKID Count in RSN information element + rsn[22] = 0x01; + rsn[23] = 0x00; + + // Fill PMKID in RSN information element + zfMemoryCopy(rsn+24, + wd->sta.pmkidInfo.bssidInfo[i].pmkid, 16); + rsn[1] += 18; + } + } + } + + zfCopyToIntTxBuffer(dev, buf, rsn, offset, rsn[1]+2); + zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); + offset += (rsn[1]+2); + } + else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA2 ) + { + /* Overwrite Group Cipher Suite by AP's setting */ + zfMemoryCopy(rsn+4, wd->sta.rsnIe+4, 4); + /* Overwrite Key Management Suite by WPA2-Radius */ + zfMemoryCopy(rsn+16, zgWpa2RadiusOui, 4); + + if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) + { + /* Overwrite Pairwise Cipher Suite by AES */ + zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); + } + + if (( frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ || ( frameType == ZM_WLAN_FRAME_TYPE_ASOCREQ ))) + { + + if (wd->sta.pmkidInfo.bssidCount != 0) { + // Fill PMKID Count in RSN information element + rsn[22] = 1; + rsn[23] = 0; + /* + * The caller is respnsible to give us the relevant PMKID. + * We'll only accept 1 PMKID for now. + */ + for(i=0; i<wd->sta.pmkidInfo.bssidCount; i++) + { + if ( zfMemoryIsEqual((u8_t*) wd->sta.pmkidInfo.bssidInfo[i].bssid, (u8_t*) wd->sta.bssid, 6) ) + { + zfMemoryCopy(rsn+24, wd->sta.pmkidInfo.bssidInfo[i].pmkid, 16); + break; + } + } + rsn[1] += 18; + } + + } + + zfCopyToIntTxBuffer(dev, buf, rsn, offset, rsn[1]+2); + zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); + offset += (rsn[1]+2); + } + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaAddIeIbss */ +/* Add information element IBSS parameter to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Ji-Huang Lee ZyDAS Technology Corporation 2005.12 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIeIbss(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + zmw_get_wlan_dev(dev); + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_IBSS); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, 2); + + /* ATIM window */ + zmw_tx_buf_writeh(dev, buf, offset, wd->sta.atimWindow); + offset += 2; + + return offset; +} + + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaAddIeWmeInfo */ +/* Add WME Information Element to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIeWmeInfo(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t qosInfo) +{ + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WIFI_IE); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, 7); + + /* OUI */ + zmw_tx_buf_writeb(dev, buf, offset++, 0x00); + zmw_tx_buf_writeb(dev, buf, offset++, 0x50); + zmw_tx_buf_writeb(dev, buf, offset++, 0xF2); + zmw_tx_buf_writeb(dev, buf, offset++, 0x02); + zmw_tx_buf_writeb(dev, buf, offset++, 0x00); + zmw_tx_buf_writeb(dev, buf, offset++, 0x01); + + /* QoS Info */ + zmw_tx_buf_writeb(dev, buf, offset++, qosInfo); + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaAddIePowerCap */ +/* Add information element Power capability to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Sharon 2007.12 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIePowerCap(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + u8_t MaxTxPower; + u8_t MinTxPower; + + zmw_get_wlan_dev(dev); + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_POWER_CAPABILITY); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, 2); + + MinTxPower = (u8_t)(zfHpGetMinTxPower(dev)/2); + MaxTxPower = (u8_t)(zfHpGetMaxTxPower(dev)/2); + + /* Min Transmit Power Cap */ + zmw_tx_buf_writeh(dev, buf, offset++, MinTxPower); + + /* Max Transmit Power Cap */ + zmw_tx_buf_writeh(dev, buf, offset++, MaxTxPower); + + return offset; +} +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfStaAddIeSupportCh */ +/* Add information element supported channels to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Sharon 2007.12 */ +/* */ +/************************************************************************/ +u16_t zfStaAddIeSupportCh(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + + u8_t i; + u16_t count_24G = 0; + u16_t count_5G = 0; + u16_t channelNum; + u8_t length; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + zmw_enter_critical_section(dev); + + for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) + { + if (wd->regulationTable.allowChannel[i].channel < 3000) + { // 2.4Hz + count_24G++; + } + else + { // 5GHz + count_5G++; + } + } + + length = (u8_t)(count_5G * 2 + 2); //5G fill by pair, 2,4G (continuous channels) fill 2 bytes + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SUPPORTED_CHANNELS ); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, length); + + // 2.4GHz (continuous channels) + /* First channel number */ + zmw_tx_buf_writeh(dev, buf, offset++, 1); //Start from channle 1 + /* Number of channels */ + zmw_tx_buf_writeh(dev, buf, offset++, count_24G); + + for (i = 0; i < wd->regulationTable.allowChannelCnt ; i++) + { + if (wd->regulationTable.allowChannel[i].channel > 4000 && wd->regulationTable.allowChannel[i].channel < 5000) + { // 5GHz 4000 -5000Mhz + channelNum = (wd->regulationTable.allowChannel[i].channel-4000)/5; + /* First channel number */ + zmw_tx_buf_writeh(dev, buf, offset++, channelNum); + /* Number of channels */ + zmw_tx_buf_writeh(dev, buf, offset++, 1); + } + else if (wd->regulationTable.allowChannel[i].channel >= 5000) + { // 5GHz >5000Mhz + channelNum = (wd->regulationTable.allowChannel[i].channel-5000)/5; + /* First channel number */ + zmw_tx_buf_writeh(dev, buf, offset++, channelNum); + /* Number of channels */ + zmw_tx_buf_writeh(dev, buf, offset++, 1); + } + } + zmw_leave_critical_section(dev); + + return offset; +} + +void zfStaStartConnectCb(zdev_t* dev) +{ + zmw_get_wlan_dev(dev); + + zfStaStartConnect(dev, wd->sta.bIsSharedKey); +} + +void zfStaStartConnect(zdev_t* dev, u8_t bIsSharedKey) +{ + u32_t p1, p2; + u8_t newConnState; + + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + /* p1_low = algorithm number, p1_high = transaction sequence number */ + if ( bIsSharedKey ) + { + //wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_SHARE_1; + newConnState = ZM_STA_CONN_STATE_AUTH_SHARE_1; + zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_SHARE_1"); + p1 = ZM_AUTH_ALGO_SHARED_KEY; + } + else + { + //wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_OPEN; + newConnState = ZM_STA_CONN_STATE_AUTH_OPEN; + zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_OPEN"); + if( wd->sta.leapEnabled ) + p1 = ZM_AUTH_ALGO_LEAP; + else + p1 = ZM_AUTH_ALGO_OPEN_SYSTEM; + } + + /* status code */ + p2 = 0x0; + + zmw_enter_critical_section(dev); + wd->sta.connectTimer = wd->tick; + wd->sta.connectState = newConnState; + zmw_leave_critical_section(dev); + + /* send the 1st authentication frame */ + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH, wd->sta.bssid, p1, p2, 0); + + return; +} + +void zfSendNullData(zdev_t* dev, u8_t type) +{ + zbuf_t* buf; + //u16_t addrTblSize; + //struct zsAddrTbl addrTbl; + u16_t err; + u16_t hlen; + u16_t header[(34+8+1)/2]; + u16_t bcastAddr[3] = {0xffff,0xffff,0xffff}; + u16_t *dstAddr; + + zmw_get_wlan_dev(dev); + + if ((buf = zfwBufAllocate(dev, 1024)) == NULL) + { + zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); + return; + } + + zfwBufSetSize(dev, buf, 0); + + //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); + + if ( wd->wlanMode == ZM_MODE_IBSS) + { + dstAddr = bcastAddr; + } + else + { + dstAddr = wd->sta.bssid; + } + + if (wd->sta.wmeConnected != 0) + { + /* If connect to a WMM AP, Send QoS Null data */ + hlen = zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_QOS_NULL, dstAddr, header, 0, buf, 0, 0); + } + else + { + hlen = zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_NULL, dstAddr, header, 0, buf, 0, 0); + } + + if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) + { + header[4] |= 0x0100; //TODS bit + } + + if ( type == 1 ) + { + header[4] |= 0x1000; + } + + /* Get buffer DMA address */ + //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) + //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) + //{ + // goto zlError; + //} + + /*increase unicast frame counter*/ + wd->commTally.txUnicastFrm++; + + if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, + ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) + { + goto zlError; + } + + + return; + +zlError: + + zfwBufFree(dev, buf, 0); + return; + +} + +void zfSendPSPoll(zdev_t* dev) +{ + zbuf_t* buf; + //u16_t addrTblSize; + //struct zsAddrTbl addrTbl; + u16_t err; + u16_t hlen; + u16_t header[(8+24+1)/2]; + + zmw_get_wlan_dev(dev); + + if ((buf = zfwBufAllocate(dev, 1024)) == NULL) + { + zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); + return; + } + + zfwBufSetSize(dev, buf, 0); + + //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); + + zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_PSPOLL, wd->sta.bssid, header, 0, buf, 0, 0); + + header[0] = 20; + header[4] |= 0x1000; + header[5] = wd->sta.aid | 0xc000; //Both bit-14 and bit-15 are 1 + hlen = 16 + 8; + + /* Get buffer DMA address */ + //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) + //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) + //{ + // goto zlError; + //} + + if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, + ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) + { + goto zlError; + } + + return; + +zlError: + + zfwBufFree(dev, buf, 0); + return; + +} + +void zfSendBA(zdev_t* dev, u16_t start_seq, u8_t *bitmap) +{ + zbuf_t* buf; + //u16_t addrTblSize; + //struct zsAddrTbl addrTbl; + u16_t err; + u16_t hlen; + u16_t header[(8+24+1)/2]; + u16_t i, offset = 0; + + zmw_get_wlan_dev(dev); + + if ((buf = zfwBufAllocate(dev, 1024)) == NULL) + { + zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); + return; + } + + zfwBufSetSize(dev, buf, 12); // 28 = FC 2 + DU 2 + RA 6 + TA 6 + BAC 2 + SEQ 2 + BitMap 8 + // 12 = BAC 2 + SEQ 2 + BitMap 8 + + //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); + + zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_BA, wd->sta.bssid, header, 0, buf, 0, 0); + + header[0] = 32; /* MAC header 16 + BA control 2 + BA info 10 + FCS 4*/ + header[1] = 0x4; /* No ACK */ + + /* send by OFDM 6M */ + header[2] = (u16_t)(zcRateToPhyCtrl[4] & 0xffff); + header[3] = (u16_t)(zcRateToPhyCtrl[4]>>16) & 0xffff; + + hlen = 16 + 8; /* MAC header 16 + control 8*/ + offset = 0; + zmw_tx_buf_writeh(dev, buf, offset, 0x05); /*compressed bitmap on*/ + offset+=2; + zmw_tx_buf_writeh(dev, buf, offset, start_seq); + offset+=2; + + for (i=0; i<8; i++) { + zmw_tx_buf_writeb(dev, buf, offset, bitmap[i]); + offset++; + } + + if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, + ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) + { + goto zlError; + } + + return; + +zlError: + + zfwBufFree(dev, buf, 0); + return; + +} + +void zfStaGetTxRate(zdev_t* dev, u16_t* macAddr, u32_t* phyCtrl, + u16_t* rcProbingFlag) +{ + u8_t addr[6], i; + u8_t rate; + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + ZM_MAC_WORD_TO_BYTE(macAddr, addr); + *phyCtrl = 0; + + if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) + { + zmw_enter_critical_section(dev); + rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[0].rcCell, rcProbingFlag); +//#ifdef ZM_FB50 + //rate = 27; +//#endif + *phyCtrl = zcRateToPhyCtrl[rate]; + zmw_leave_critical_section(dev); + } + else + { + zmw_enter_critical_section(dev); + for(i=0; i<wd->sta.oppositeCount; i++) + { + if ( addr[0] && 0x01 == 1 ) // The default beacon transmitted rate is CCK and 1 Mbps , but the a mode should use + // OFDM modulation and 6Mbps to transmit beacon. + { + //rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[i].rcCell, rcProbingFlag); + rate = wd->sta.oppositeInfo[i].rcCell.operationRateSet[0]; + *phyCtrl = zcRateToPhyCtrl[rate]; + break; + } + else if ( zfMemoryIsEqual(addr, wd->sta.oppositeInfo[i].macAddr, 6) ) + { + rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[i].rcCell, rcProbingFlag); + *phyCtrl = zcRateToPhyCtrl[rate]; + break; + } + } + zmw_leave_critical_section(dev); + } + + return; +} + +struct zsMicVar* zfStaGetRxMicKey(zdev_t* dev, zbuf_t* buf) +{ + u8_t keyIndex; + u8_t da0; + + zmw_get_wlan_dev(dev); + + /* if need not check MIC, return NULL */ + if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| + (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) + { + return NULL; + } + + da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); + + if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) == 0x80) + keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+5); /* Qos Packet*/ + else + keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+3); /* normal Packet*/ + keyIndex = (keyIndex & 0xc0) >> 6; + + return (&wd->sta.rxMicKey[keyIndex]); +} + +struct zsMicVar* zfStaGetTxMicKey(zdev_t* dev, zbuf_t* buf) +{ + zmw_get_wlan_dev(dev); + + /* if need not check MIC, return NULL */ + //if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| + // (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) + if ( (wd->sta.encryMode != ZM_TKIP) || (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) + { + return NULL; + } + + return (&wd->sta.txMicKey); +} + +u16_t zfStaRxValidateFrame(zdev_t* dev, zbuf_t* buf) +{ + u8_t frameType, frameCtrl; + u8_t da0; + //u16_t sa[3]; + u16_t ret; + u16_t i; + //u8_t sa0; + + zmw_get_wlan_dev(dev); + + frameType = zmw_rx_buf_readb(dev, buf, 0); + da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); + //sa0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); + + if ( (!zfStaIsConnected(dev))&&((frameType & 0xf) == ZM_WLAN_DATA_FRAME) ) + { + return ZM_ERR_DATA_BEFORE_CONNECTED; + } + + + if ( (zfStaIsConnected(dev))&&((frameType & 0xf) == ZM_WLAN_DATA_FRAME) ) + { + /* check BSSID */ + if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) + { + /* Big Endian and Little Endian Compatibility */ + u16_t mac[3]; + mac[0] = zmw_cpu_to_le16(wd->sta.bssid[0]); + mac[1] = zmw_cpu_to_le16(wd->sta.bssid[1]); + mac[2] = zmw_cpu_to_le16(wd->sta.bssid[2]); + if ( !zfRxBufferEqualToStr(dev, buf, (u8_t *)mac, + ZM_WLAN_HEADER_A2_OFFSET, 6) ) + { +/*We will get lots of garbage data, especially in AES mode.*/ +/*To avoid sending too many deauthentication frames in STA mode, mark it.*/ +#if 0 + /* If unicast frame, send deauth to the transmitter */ + if (( da0 & 0x01 ) == 0) + { + for (i=0; i<3; i++) + { + sa[i] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+(i*2)); + } + /* If mutilcast address, don't send deauthentication*/ + if (( sa0 & 0x01 ) == 0) + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, sa, 7, 0, 0); + } +#endif + return ZM_ERR_DATA_BSSID_NOT_MATCHED; + } + } + else if ( wd->wlanMode == ZM_MODE_IBSS ) + { + /* Big Endian and Little Endian Compatibility */ + u16_t mac[3]; + mac[0] = zmw_cpu_to_le16(wd->sta.bssid[0]); + mac[1] = zmw_cpu_to_le16(wd->sta.bssid[1]); + mac[2] = zmw_cpu_to_le16(wd->sta.bssid[2]); + if ( !zfRxBufferEqualToStr(dev, buf, (u8_t *)mac, + ZM_WLAN_HEADER_A3_OFFSET, 6) ) + { + return ZM_ERR_DATA_BSSID_NOT_MATCHED; + } + } + + frameCtrl = zmw_rx_buf_readb(dev, buf, 1); + + /* check security bit */ + if ( wd->sta.dropUnencryptedPkts && + (wd->sta.wepStatus != ZM_ENCRYPTION_WEP_DISABLED )&& + ( !(frameCtrl & ZM_BIT_6) ) ) + { /* security on, but got data without encryption */ + + #if 1 + ret = ZM_ERR_DATA_NOT_ENCRYPTED; + if ( wd->sta.pStaRxSecurityCheckCb != NULL ) + { + ret = wd->sta.pStaRxSecurityCheckCb(dev, buf); + } + else + { + ret = ZM_ERR_DATA_NOT_ENCRYPTED; + } + if (ret == ZM_ERR_DATA_NOT_ENCRYPTED) + { + wd->commTally.swRxDropUnencryptedCount++; + } + return ret; + #else + if ( (wd->sta.wepStatus != ZM_ENCRYPTION_TKIP)&& + (wd->sta.wepStatus != ZM_ENCRYPTION_AES) ) + { + return ZM_ERR_DATA_NOT_ENCRYPTED; + } + #endif + } + } + + return ZM_SUCCESS; +} + +void zfStaMicFailureHandling(zdev_t* dev, zbuf_t* buf) +{ + u8_t da0; + u8_t micNotify = 1; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + if ( wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK ) + { + return; + } + + zmw_enter_critical_section(dev); + + wd->sta.cmMicFailureCount++; + + if ( wd->sta.cmMicFailureCount == 1 ) + { + zm_debug_msg0("get the first MIC failure"); + //zfTimerSchedule(dev, ZM_EVENT_CM_TIMER, ZM_TICK_CM_TIMEOUT); + + /* Timer Resolution on WinXP is 15/16 ms */ + /* Decrease Time offset for <XP> Counter Measure */ + zfTimerSchedule(dev, ZM_EVENT_CM_TIMER, ZM_TICK_CM_TIMEOUT - ZM_TICK_CM_TIMEOUT_OFFSET); + } + else if ( wd->sta.cmMicFailureCount == 2 ) + { + zm_debug_msg0("get the second MIC failure"); + /* reserve 2 second for OS to send MIC failure report to AP */ + wd->sta.cmDisallowSsidLength = wd->sta.ssidLen; + zfMemoryCopy(wd->sta.cmDisallowSsid, wd->sta.ssid, wd->sta.ssidLen); + //wd->sta.cmMicFailureCount = 0; + zfTimerCancel(dev, ZM_EVENT_CM_TIMER); + //zfTimerSchedule(dev, ZM_EVENT_CM_DISCONNECT, ZM_TICK_CM_DISCONNECT); + + /* Timer Resolution on WinXP is 15/16 ms */ + /* Decrease Time offset for <XP> Counter Measure */ + zfTimerSchedule(dev, ZM_EVENT_CM_DISCONNECT, ZM_TICK_CM_DISCONNECT - ZM_TICK_CM_DISCONNECT_OFFSET); + } + else + { + micNotify = 0; + } + + zmw_leave_critical_section(dev); + + if (micNotify == 1) + { + da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); + if ( da0 & 0x01 ) + { + if (wd->zfcbMicFailureNotify != NULL) + { + wd->zfcbMicFailureNotify(dev, wd->sta.bssid, ZM_MIC_GROUP_ERROR); + } + } + else + { + if (wd->zfcbMicFailureNotify != NULL) + { + wd->zfcbMicFailureNotify(dev, wd->sta.bssid, ZM_MIC_PAIRWISE_ERROR); + } + } + } +} + + +u8_t zfStaBlockWlanScan(zdev_t* dev) +{ + u8_t ret=FALSE; + + zmw_get_wlan_dev(dev); + + if ( wd->sta.bChannelScan ) + { + return TRUE; + } + + return ret; +} + +void zfStaResetStatus(zdev_t* dev, u8_t bInit) +{ + u8_t i; + + zmw_get_wlan_dev(dev); + + zfHpDisableBeacon(dev); + + wd->dtim = 1; + wd->sta.capability[0] = 0x01; + wd->sta.capability[1] = 0x00; + /* 802.11h */ + if (wd->sta.DFSEnable || wd->sta.TPCEnable) + wd->sta.capability[1] |= ZM_BIT_0; + + /* release queued packets */ + for(i=0; i<wd->sta.ibssPSDataCount; i++) + { + zfwBufFree(dev, wd->sta.ibssPSDataQueue[i], 0); + } + + for(i=0; i<wd->sta.staPSDataCount; i++) + { + zfwBufFree(dev, wd->sta.staPSDataQueue[i], 0); + } + + wd->sta.ibssPSDataCount = 0; + wd->sta.staPSDataCount = 0; + zfZeroMemory((u8_t*) &wd->sta.staPSList, sizeof(struct zsStaPSList)); + + wd->sta.wmeConnected = 0; + wd->sta.psMgr.tempWakeUp = 0; + wd->sta.qosInfo = 0; + zfQueueFlush(dev, wd->sta.uapsdQ); + + return; + +} + +void zfStaIbssMonitoring(zdev_t* dev, u8_t reset) +{ + u16_t i; + u16_t oppositeCount; + struct zsPartnerNotifyEvent event; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + //zm_debug_msg1("zfStaIbssMonitoring %d", wd->sta.oppositeCount); + + zmw_enter_critical_section(dev); + + if ( wd->sta.oppositeCount == 0 ) + { + goto done; + } + + if ( wd->sta.bChannelScan ) + { + goto done; + } + + oppositeCount = wd->sta.oppositeCount; + + for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) + { + if ( oppositeCount == 0 ) + { + break; + } + + if ( reset ) + { + wd->sta.oppositeInfo[i].valid = 0; + } + + if ( wd->sta.oppositeInfo[i].valid == 0 ) + { + continue; + } + + oppositeCount--; + + if ( wd->sta.oppositeInfo[i].aliveCounter ) + { + zm_debug_msg1("Setting alive to ", wd->sta.oppositeInfo[i].aliveCounter); + + zmw_leave_critical_section(dev); + + if ( wd->sta.oppositeInfo[i].aliveCounter != ZM_IBSS_PEER_ALIVE_COUNTER ) + { + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, + (u16_t*)wd->sta.oppositeInfo[i].macAddr, 1, 0, 0); + } + + zmw_enter_critical_section(dev); + wd->sta.oppositeInfo[i].aliveCounter--; + } + else + { + zm_debug_msg0("zfStaIbssMonitoring remove the peer station"); + zfMemoryCopy(event.bssid, (u8_t *)(wd->sta.bssid), 6); + zfMemoryCopy(event.peerMacAddr, wd->sta.oppositeInfo[i].macAddr, 6); + + wd->sta.oppositeInfo[i].valid = 0; + wd->sta.oppositeCount--; + if (wd->zfcbIbssPartnerNotify != NULL) + { + zmw_leave_critical_section(dev); + wd->zfcbIbssPartnerNotify(dev, 0, &event); + zmw_enter_critical_section(dev); + } + } + } + +done: + if ( reset == 0 ) + { + zfTimerSchedule(dev, ZM_EVENT_IBSS_MONITOR, ZM_TICK_IBSS_MONITOR); + } + + zmw_leave_critical_section(dev); +} + +void zfInitPartnerNotifyEvent(zdev_t* dev, zbuf_t* buf, struct zsPartnerNotifyEvent *event) +{ + u16_t *peerMacAddr; + + zmw_get_wlan_dev(dev); + + peerMacAddr = (u16_t *)event->peerMacAddr; + + zfMemoryCopy(event->bssid, (u8_t *)(wd->sta.bssid), 6); + 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); +} + +void zfStaInitOppositeInfo(zdev_t* dev) +{ + int i; + + zmw_get_wlan_dev(dev); + + for(i=0; i<ZM_MAX_OPPOSITE_COUNT; i++) + { + wd->sta.oppositeInfo[i].valid = 0; + wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER; + } +} +#ifdef ZM_ENABLE_CENC +u16_t zfStaAddIeCenc(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + zmw_get_wlan_dev(dev); + + if (wd->sta.cencIe[1] != 0) + { + zfCopyToIntTxBuffer(dev, buf, wd->sta.cencIe, offset, wd->sta.cencIe[1]+2); + offset += (wd->sta.cencIe[1]+2); + } + return offset; +} +#endif //ZM_ENABLE_CENC +u16_t zfStaProcessAction(zdev_t* dev, zbuf_t* buf) +{ + u8_t category, actionDetails; + zmw_get_wlan_dev(dev); + + category = zmw_rx_buf_readb(dev, buf, 24); + actionDetails = zmw_rx_buf_readb(dev, buf, 25); + switch (category) + { + case 0: //Spectrum Management + switch(actionDetails) + { + case 0: //Measurement Request + break; + case 1: //Measurement Report + //ProcessActionSpectrumFrame_MeasurementReport(Adapter,pActionBody+3); + break; + case 2: //TPC request + //if (wd->sta.TPCEnable) + // zfStaUpdateDot11HTPC(dev, buf); + break; + case 3: //TPC report + //if (wd->sta.TPCEnable) + // zfStaUpdateDot11HTPC(dev, buf); + break; + case 4: //Channel Switch Announcement + if (wd->sta.DFSEnable) + zfStaUpdateDot11HDFS(dev, buf); + break; + default: + zm_debug_msg1("Action Frame contain not support action field ", actionDetails); + break; + } + break; + case ZM_WLAN_BLOCK_ACK_ACTION_FRAME: + zfAggBlockAckActionFrame(dev, buf); + break; + case 17: //Qos Management + break; + } + + return 0; +} + +/* Determine the time not send beacon , if more than some value , + re-write the beacon start address */ +void zfReWriteBeaconStartAddress(zdev_t* dev) +{ + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + zmw_enter_critical_section(dev); + wd->tickIbssSendBeacon++; // Increase 1 per 10ms . + zmw_leave_critical_section(dev); + + if ( wd->tickIbssSendBeacon == 40 ) + { +// DbgPrint("20070727"); + zfHpEnableBeacon(dev, ZM_MODE_IBSS, wd->beaconInterval, wd->dtim, (u8_t)wd->sta.atimWindow); + zmw_enter_critical_section(dev); + wd->tickIbssSendBeacon = 0; + zmw_leave_critical_section(dev); + } +} + +struct zsTkipSeed* zfStaGetRxSeed(zdev_t* dev, zbuf_t* buf) +{ + u8_t keyIndex; + u8_t da0; + + zmw_get_wlan_dev(dev); + + /* if need not check MIC, return NULL */ + if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| + (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) + { + return NULL; + } + + da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); + + if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) == 0x80) + keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+5); /* Qos Packet*/ + else + keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+3); /* normal Packet*/ + keyIndex = (keyIndex & 0xc0) >> 6; + + return (&wd->sta.rxSeed[keyIndex]); +} + +void zfStaEnableSWEncryption(zdev_t *dev, u8_t value) +{ + zmw_get_wlan_dev(dev); + + wd->sta.SWEncryptEnable = value; + zfHpSWDecrypt(dev, 1); + zfHpSWEncrypt(dev, 1); +} + +void zfStaDisableSWEncryption(zdev_t *dev) +{ + zmw_get_wlan_dev(dev); + + wd->sta.SWEncryptEnable = 0; + zfHpSWDecrypt(dev, 0); + zfHpSWEncrypt(dev, 0); +} + +u16_t zfComputeBssInfoWeightValue(zdev_t *dev, u8_t isBMode, u8_t isHT, u8_t isHT40, u8_t signalStrength) +{ + u8_t weightOfB = 0; + u8_t weightOfAGBelowThr = 0; + u8_t weightOfAGUpThr = 15; + u8_t weightOfN20BelowThr = 15; + u8_t weightOfN20UpThr = 30; + u8_t weightOfN40BelowThr = 16; + u8_t weightOfN40UpThr = 32; + + zmw_get_wlan_dev(dev); + + if( isBMode == 0 ) + return (signalStrength + weightOfB); // pure b mode , do not add the weight value for this AP ! + else + { + if( isHT == 0 && isHT40 == 0 ) + { // a , g , b/g mode ! add the weight value 15 for this AP if it's signal strength is more than some value ! + if( signalStrength < 18 ) // -77 dBm + return signalStrength + weightOfAGBelowThr; + else + return (signalStrength + weightOfAGUpThr); + } + else if( isHT == 1 && isHT40 == 0 ) + { // 80211n mode use 20MHz + if( signalStrength < 23 ) // -72 dBm + return (signalStrength + weightOfN20BelowThr); + else + return (signalStrength + weightOfN20UpThr); + } + else // isHT == 1 && isHT40 == 1 + { // 80211n mode use 40MHz + if( signalStrength < 16 ) // -79 dBm + return (signalStrength + weightOfN40BelowThr); + else + return (signalStrength + weightOfN40UpThr); + } + } +} + +u16_t zfStaAddIbssAdditionalIE(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + u16_t i; + + zmw_get_wlan_dev(dev); + + for (i=0; i<wd->sta.ibssAdditionalIESize; i++) + { + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ibssAdditionalIE[i]); + } + + return offset; +} |