diff options
Diffstat (limited to 'drivers/staging/otus/80211core/cinit.c')
-rw-r--r-- | drivers/staging/otus/80211core/cinit.c | 1911 |
1 files changed, 1911 insertions, 0 deletions
diff --git a/drivers/staging/otus/80211core/cinit.c b/drivers/staging/otus/80211core/cinit.c new file mode 100644 index 000000000000..5f853ce79309 --- /dev/null +++ b/drivers/staging/otus/80211core/cinit.c @@ -0,0 +1,1911 @@ +/* + * 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. + */ +/* */ +/* Module Name : init.c */ +/* */ +/* Abstract */ +/* This module contains init functions. */ +/* */ +/* NOTES */ +/* None */ +/* */ +/************************************************************************/ +#include "cprecomp.h" +#include "../hal/hpreg.h" + +extern const u8_t zcUpToAc[8]; + +u16_t zcIndextoRateBG[16] = {1000, 2000, 5500, 11000, 0, 0, 0, 0, 48000, + 24000, 12000, 6000, 54000, 36000, 18000, 9000}; +u32_t zcIndextoRateN20L[16] = {6500, 13000, 19500, 26000, 39000, 52000, 58500, + 65000, 13000, 26000, 39000, 52000, 78000, 104000, + 117000, 130000}; +u32_t zcIndextoRateN20S[16] = {7200, 14400, 21700, 28900, 43300, 57800, 65000, + 72200, 14400, 28900, 43300, 57800, 86700, 115600, + 130000, 144400}; +u32_t zcIndextoRateN40L[16] = {13500, 27000, 40500, 54000, 81000, 108000, 121500, + 135000, 27000, 54000, 81000, 108000, 162000, 216000, + 243000, 270000}; +u32_t zcIndextoRateN40S[16] = {15000, 30000, 45000, 60000, 90000, 120000, 135000, + 150000, 30000, 60000, 90000, 120000, 180000, 240000, + 270000, 300000}; + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfTxGenWlanHeader */ +/* Generate WLAN MAC header and LLC header. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer pointer */ +/* id : Index of TxD */ +/* port : WLAN port */ +/* */ +/* OUTPUTS */ +/* length of removed Ethernet header */ +/* */ +/* AUTHOR */ +/* Stephen ZyDAS Technology Corporation 2005.5 */ +/* */ +/************************************************************************/ +u16_t zfTxGenWlanHeader(zdev_t* dev, zbuf_t* buf, u16_t* header, u16_t seq, + u8_t flag, u16_t plusLen, u16_t minusLen, u16_t port, + u16_t* da, u16_t* sa, u8_t up, u16_t *micLen, + u16_t* snap, u16_t snapLen, struct aggControl *aggControl) +{ + + u16_t len; + u16_t macCtrl; + u32_t phyCtrl; + u16_t hlen = 16; + u16_t icvLen = 0; + u16_t wdsPortId; + u16_t vap = 0; + u16_t mcs = 0; + u16_t mt = 0; + u8_t qosType; + u8_t b1, b2; + u16_t wdsPort; + u8_t encExemptionActionType; + u16_t rateProbingFlag = 0; + u8_t tkipFrameOffset = 0; + +#ifdef ZM_ENABLE_IBSS_WPA2PSK + u8_t res, peerIdx; + u8_t userIdx=0; + u16_t *iv16; + u32_t *iv32; +#endif + + zmw_get_wlan_dev(dev); + + /* Generate WLAN header */ + /* Frame control */ + header[4] = 0x0008 | (flag<<8); + /* Duration */ + header[5] = 0x0000; + + if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) + { + /* ToDS bit */ + header[4] |= 0x0100; + + /*Sometimes we wake up to tx/rx but AP still think we are sleeping, so still need to set this bit*/ + if ( zfPowerSavingMgrIsSleeping(dev) || wd->sta.psMgr.tempWakeUp == 1 ) + { + header[4] |= 0x1000; + } + + /* Address 1 = BSSID */ + header[6] = wd->sta.bssid[0]; + header[7] = wd->sta.bssid[1]; + header[8] = wd->sta.bssid[2]; + /* Address 3 = DA */ + header[12] = da[0]; + header[13] = da[1]; + header[14] = da[2]; + } + else if (wd->wlanMode == ZM_MODE_PSEUDO) + { + /* Address 1 = DA */ + header[6] = da[0]; + header[7] = da[1]; + header[8] = da[2]; + /* Address 3 = 00:00:00:00:00:00 */ + header[12] = 0; + header[13] = 0; + header[14] = 0; + + /* PSEUDO test : WDS */ + if (wd->enableWDS) + { + /* ToDS and FromDS bit */ + header[4] |= 0x0300; + + /* Address 4 = SA */ + header[16] = 0; + header[17] = 0; + header[18] = 0; + + hlen = 19; + } + } + else if (wd->wlanMode == ZM_MODE_IBSS) + { + /* Address 1 = DA */ + header[6] = da[0]; + header[7] = da[1]; + header[8] = da[2]; + /* Address 3 = BSSID */ + header[12] = wd->sta.bssid[0]; + header[13] = wd->sta.bssid[1]; + header[14] = wd->sta.bssid[2]; + +#ifdef ZM_ENABLE_IBSS_WPA2PSK + zmw_enter_critical_section(dev); + res = zfStaFindOppositeByMACAddr(dev, da, &peerIdx); + if(res == 0) // Find opposite in our OppositeInfo Structure ! + { + userIdx = peerIdx; + } + zmw_leave_critical_section(dev); +#endif + } + else if (wd->wlanMode == ZM_MODE_AP) + { + if (port < 0x20) + /* AP mode */ + { + /* FromDS bit */ + header[4] |= 0x0200; + + /* Address 1 = DA */ + header[6] = da[0]; + header[7] = da[1]; + header[8] = da[2]; + /* Address 3 = SA */ + header[12] = sa[0]; + header[13] = sa[1]; + header[14] = sa[2]; + + if (port < ZM_MAX_AP_SUPPORT) + { + vap = port; + header[14] += (vap<<8); + } + } + else + /* WDS port */ + { + /* ToDS and FromDS bit */ + header[4] |= 0x0300; + + wdsPortId = port - 0x20; + + /* Address 1 = RA */ + header[6] = wd->ap.wds.macAddr[wdsPortId][0]; + header[7] = wd->ap.wds.macAddr[wdsPortId][1]; + header[8] = wd->ap.wds.macAddr[wdsPortId][2]; + /* Address 3 = DA */ + header[12] = da[0]; + header[13] = da[1]; + header[14] = da[2]; + /* Address 4 = SA */ + header[16] = sa[0]; + header[17] = sa[1]; + header[18] = sa[2]; + + hlen = 19; + } + } /* else if (wd->wlanMode == ZM_MODE_AP) */ + + /* Address 2 = TA */ + header[9] = wd->macAddr[0]; + header[10] = wd->macAddr[1]; +#ifdef ZM_VAPMODE_MULTILE_SSID + header[11] = wd->macAddr[2]; //Multiple SSID +#else + header[11] = wd->macAddr[2] + (vap<<8); //VAP +#endif + + if ( (wd->wlanMode == ZM_MODE_IBSS) && (wd->XLinkMode) ) + { + header[9] = sa[0]; + header[10] = sa[1]; + header[11] = sa[2]; + } + + /* Sequence Control */ + header[15] = seq; + + + if (wd->wlanMode == ZM_MODE_AP) + { + zfApGetStaTxRateAndQosType(dev, da, &phyCtrl, &qosType, &rateProbingFlag); + mt = (u16_t)(phyCtrl & 0x3); + mcs = (u16_t)((phyCtrl >> 16) & 0x3f); +#if 1 + //zfApGetStaQosType(dev, da, &qosType); + + /* if DA == WME STA */ + if (qosType == 1) + { + /* QoS data */ + header[4] |= 0x0080; + + /* QoS Control */ + header[hlen] = up; + hlen += 1; + } +#endif + } + +#if 0 + //AGG Test Code + if (header[6] == 0x8000) + { + /* QoS data */ + header[4] |= 0x0080; + + /* QoS Control */ + header[hlen] = 0; + hlen += 1; + } +#endif + + if (wd->wlanMode == ZM_MODE_AP) { + /* Todo: rate control here for qos field */ + } + else { + /* Rate control */ + zfStaGetTxRate(dev, da, &phyCtrl, &rateProbingFlag); + mt = (u16_t)(phyCtrl & 0x3); + mcs = (u16_t)((phyCtrl >> 16) & 0x3f); + } + + if (wd->txMCS != 0xff) + { + /* fixed rate */ + phyCtrl = ((u32_t)wd->txMCS<<16) + wd->txMT; + mcs = wd->txMCS; + mt = wd->txMT; + } + + if (wd->enableAggregation) + { + /* force enable aggregation */ + if (wd->enableAggregation==2 && !(header[6]&0x1)) + { + /* QoS data */ + header[4] |= 0x0080; + + /* QoS Control */ + header[hlen] = 0; + hlen += 1; + } + /* if wd->enableAggregation=1 => force disable */ + /* if wd->enableAggregation=0 => auto */ + } + +#ifdef ZM_ENABLE_AGGREGATION + /* + * aggregation control + */ + + /* + * QoS data + */ + if (wd->wlanMode == ZM_MODE_AP) { + if (aggControl && mt == 2) { + if (wd->enableAggregation==0 && !(header[6]&0x1)) + { + header[4] |= 0x0080; + + /* + * QoS Control + */ + header[hlen] = 0; + hlen += 1; + } + } + } +#endif + + // MSDU Length + len = zfwBufGetSize(dev, buf); + + /* Generate control setting */ + /* Backoff, Non-Burst and hardware duration */ + macCtrl = 0x208; + + /* ACK */ + if ((header[6] & 0x1) == 0x1) + { + /* multicast frame : Set NO-ACK bit */ + macCtrl |= 0x4; + } + else + { + /* unicast frame */ + #if 0 + // Enable RTS according to MPDU Lengths ( not MSDU Lengths ) + if (len >= wd->rtsThreshold) + { + /* Enable RTS */ + macCtrl |= 1; + } + #endif + } + /* VAP test code */ + //macCtrl |= 0x4; + + if (wd->wlanMode == ZM_MODE_AP) + { + u8_t encryType; + u16_t iv16; + u32_t iv32; + + /* Check whether this is a multicast frame */ + if ((header[6] & 0x1) == 0x1) + { + /* multicast frame */ + if (wd->ap.encryMode[vap] == ZM_TKIP) + { + wd->ap.iv16[vap]++; + + if(wd->ap.iv16[vap] == 0) + { + wd->ap.iv32[vap]++; + } + + b1 = (u8_t) (wd->ap.iv16[vap] >> 8); + b2 = (b1 | 0x20) & 0x7f; + header[hlen] = ((u16_t)b2 << 8) + b1; + b1 = (u8_t) wd->ap.iv16[vap]; + b2 = 0x20 | (wd->ap.bcKeyIndex[vap] << 6); + header[hlen+1] = ((u16_t)b2 << 8) + b1; + header[hlen+2] = (u16_t) wd->ap.iv32[vap]; + header[hlen+3] = (u16_t) (wd->ap.iv32[vap] >> 16); + + //macCtrl |= 0x80; + macCtrl |= 0x40; + icvLen = 4; + + /* set hardware MIC */ + if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) + { + macCtrl |= 0x100; + plusLen += 8; + *micLen = 8; + } + + header[4] |= 0x4000; + hlen += 4; + } + else if (wd->ap.encryMode[vap] == ZM_AES) + { + wd->ap.iv16[vap]++; + + if(wd->ap.iv16[vap] == 0) + { + wd->ap.iv32[vap]++; + } + + b1 = (u8_t) wd->ap.iv16[vap]; + b2 = (u8_t) (wd->ap.iv16[vap] >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + header[hlen+1] = 0x2000 | (wd->ap.bcKeyIndex[vap] << 14); + header[hlen+2] = (u16_t) (wd->ap.iv32[vap]); + header[hlen+3] = (u16_t) (wd->ap.iv32[vap] >> 16); + + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + + header[4] |= 0x4000; + hlen += 4; + } + #ifdef ZM_ENABLE_CENC + else if (wd->ap.encryMode[vap] == ZM_CENC) + { + //u32_t txiv[4]; + + wd->ap.txiv[vap][0]++; + + if (wd->ap.txiv[vap][0] == 0) + { + wd->ap.txiv[vap][1]++; + } + + if (wd->ap.txiv[vap][1] == 0) + { + wd->ap.txiv[vap][2]++; + } + + if (wd->ap.txiv[vap][2] == 0) + { + wd->ap.txiv[vap][3]++; + } + + if (wd->ap.txiv[vap][3] == 0) + { + wd->ap.txiv[vap][0] = 0; + wd->ap.txiv[vap][1] = 0; + wd->ap.txiv[vap][2] = 0; + } + + header[hlen] = (wd->ap.bcKeyIndex[vap] & 0x0001); /* For Key Id and reserved field */ + header[hlen+1] = (u16_t)wd->ap.txiv[vap][0]; + header[hlen+2] = (u16_t)(wd->ap.txiv[vap][0] >> 16); + header[hlen+3] = (u16_t)wd->ap.txiv[vap][1]; + header[hlen+4] = (u16_t)(wd->ap.txiv[vap][1] >> 16); + header[hlen+5] = (u16_t)wd->ap.txiv[vap][2]; + header[hlen+6] = (u16_t)(wd->ap.txiv[vap][2] >> 16); + header[hlen+7] = (u16_t)wd->ap.txiv[vap][3]; + header[hlen+8] = (u16_t)(wd->ap.txiv[vap][3] >> 16); + + macCtrl |= 0x80; + icvLen = 16; /* MIC */ + + header[4] |= 0x4000; + hlen += 9; + } + #endif //ZM_ENABLE_CENC + } + else + { + /* Get STA's encryption type */ + zfApGetStaEncryType(dev, da, &encryType); + + if (encryType == ZM_TKIP) + { + /* Get iv16 and iv32 */ + zfApGetStaWpaIv(dev, da, &iv16, &iv32); + + iv16++; + if (iv16 == 0) + { + iv32++; + } + + b1 = (u8_t) (iv16 >> 8); + b2 = (b1 | 0x20) & 0x7f; + header[hlen] = ((u16_t)b2 << 8) + b1; + b1 = (u8_t) iv16; + b2 = 0x20; + header[hlen+1] = ((u16_t)b2 << 8) + b1; + header[hlen+2] = (u16_t) iv32; + header[hlen+3] = (u16_t) (iv32 >> 16); + + //macCtrl |= 0x80; + macCtrl |= 0x40; + icvLen = 4; + + /* set hardware MIC */ + if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) + { + macCtrl |= 0x100; + plusLen += 8; + *micLen = 8; + } + + header[4] |= 0x4000; + hlen += 4; + + /* Set iv16 and iv32 */ + zfApSetStaWpaIv(dev, da, iv16, iv32); + } + else if (encryType == ZM_AES) + { + /* Get iv16 and iv32 */ + zfApGetStaWpaIv(dev, da, &iv16, &iv32); + + iv16++; + if (iv16 == 0) + { + iv32++; + } + + b1 = (u8_t) iv16; + b2 = (u8_t) (iv16 >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + header[hlen+1] = 0x2000; + header[hlen+2] = (u16_t) (iv32); + header[hlen+3] = (u16_t) (iv32 >> 16); + + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + + header[4] |= 0x4000; + hlen += 4; + + /* Set iv16 and iv32 */ + zfApSetStaWpaIv(dev, da, iv16, iv32); + } + #ifdef ZM_ENABLE_CENC + else if (encryType == ZM_CENC) + { + u32_t txiv[4]; + u8_t keyIdx; + + /* Get CENC TxIV */ + zfApGetStaCencIvAndKeyIdx(dev, da, txiv, &keyIdx); + + txiv[0] += 2; + + if (txiv[0] == 0 || txiv[0] == 1) + { + txiv[1]++; + } + + if (txiv[1] == 0) + { + txiv[2]++; + } + + if (txiv[2] == 0) + { + txiv[3]++; + } + + if (txiv[3] == 0) + { + txiv[0] = 0; + txiv[1] = 0; + txiv[2] = 0; + } + + header[hlen] = (keyIdx & 0x0001); /* For Key Id and reserved field */ + header[hlen+1] = (u16_t)txiv[0]; + header[hlen+2] = (u16_t)(txiv[0] >> 16); + header[hlen+3] = (u16_t)txiv[1]; + header[hlen+4] = (u16_t)(txiv[1] >> 16); + header[hlen+5] = (u16_t)txiv[2]; + header[hlen+6] = (u16_t)(txiv[2] >> 16); + header[hlen+7] = (u16_t)txiv[3]; + header[hlen+8] = (u16_t)(txiv[3] >> 16); + + macCtrl |= 0x80; + icvLen = 16; /* MIC */ + + header[4] |= 0x4000; + hlen += 9; + + /* Set CENC IV */ + zfApSetStaCencIv(dev, da, txiv); + } + #endif //ZM_ENABLE_CENC + } + + /* protection mode */ + if (wd->ap.protectionMode == 1) + { + /* Enable Self-CTS */ + macCtrl &= 0xFFFC; + macCtrl |= 2; + } + + /* Rate Control */ + if (port < 0x20) + { + /* AP */ + /* IV */ + if ((wd->ap.encryMode[vap] == ZM_WEP64) || + (wd->ap.encryMode[vap] == ZM_WEP128) || + (wd->ap.encryMode[vap] == ZM_WEP256)) + { + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = wd->ap.bcKeyIndex[vap] << 14; //IV with Keyid--CWYang(m) + hlen += 2; + icvLen = 4; + macCtrl |= 0x40; + } + } + else + { + /* WDS */ + + /* TODO : Fixed rate to 54M */ + phyCtrl = 0xc0001; //PHY control L + + /* WDS port checking */ + if ((wdsPort = (port - 0x20)) >= ZM_MAX_WDS_SUPPORT) + { + wdsPort = 0; + } + + #if 1 + /* IV */ + switch (wd->ap.wds.encryMode[wdsPort]) + { + case ZM_WEP64: + case ZM_WEP128: + case ZM_WEP256: + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = wd->ap.bcKeyIndex[vap] << 14; //IV with Keyid + hlen += 2; + icvLen = 4; + macCtrl |= 0x40; + break; + + case ZM_TKIP: + wd->sta.iv16++; + + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + b1 = (u8_t) (wd->sta.iv16 >> 8); + b2 = (b1 | 0x20) & 0x7f; + header[hlen] = ((u16_t)b2 << 8) + b1; + b1 = (u8_t) wd->sta.iv16; + b2 = 0x20; + header[hlen+1] = ((u16_t)b2 << 8) + b1; + header[hlen+2] = (u16_t) wd->sta.iv32; + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + + //macCtrl |= 0x80; + macCtrl |= 0x40; + icvLen = 4; + + /* set hardware MIC */ + if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) + { + macCtrl |= 0x100; + plusLen += 8; + *micLen = 8; + } + + header[4] |= 0x4000; + hlen += 4; + break; + + case ZM_AES: + wd->sta.iv16++; + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + b1 = (u8_t) wd->sta.iv16; + b2 = (u8_t) (wd->sta.iv16 >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + header[hlen+1] = 0x2000; + header[hlen+2] = (u16_t) (wd->sta.iv32); + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + + macCtrl |= 0xc0; /* Set to AES in control setting */ + icvLen = 8; /* MIC */ + + header[4] |= 0x4000; /* Set WEP bit in wlan header */ + hlen += 4; /* plus IV length */ + break; + }/* end of switch */ + #endif + } + } + else /* wd->wlanMode != ZM_MODE_AP */ + { + encExemptionActionType = zfwGetPktEncExemptionActionType(dev, buf); + + if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) + { + #if 1 + /* if WME AP */ + if (wd->sta.wmeConnected != 0) + { + /* QoS data */ + header[4] |= 0x0080; + + /* QoS Control */ + header[hlen] = up; + hlen += 1; + } + #endif + + if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) + { + if ( wd->sta.authMode < ZM_AUTH_MODE_WPA ) + { /* non-WPA */ + if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) + { + if ( (wd->sta.encryMode == ZM_WEP64)|| + (wd->sta.encryMode == ZM_WEP128)|| + (wd->sta.encryMode == ZM_WEP256) ) + { + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = 0x0; //IV + header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); + hlen += 2; + icvLen = 4; + + /* For Software WEP */ + if ((wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) != 0) + { + u8_t keyLen = 5; + u8_t iv[3]; + + iv[0] = 0x0; + iv[1] = 0x0; + iv[2] = 0x0; + + if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP64) + { + keyLen = 5; + } + else if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP128) + { + keyLen = 13; + } + else if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP256) + { + keyLen = 29; + } + + zfWEPEncrypt(dev, buf, (u8_t*) snap, snapLen, minusLen, keyLen, + wd->sta.wepKey[wd->sta.keyId], iv); + } + else + { + macCtrl |= 0x40; + } + } + } + } + else + { /* WPA */ + if ( wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK ) + { + wd->sta.iv16++; + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + /* set encryption mode */ + if ( wd->sta.encryMode == ZM_TKIP ) + { + b1 = (u8_t) (wd->sta.iv16 >> 8); + b2 = (b1 | 0x20) & 0x7f; + header[hlen] = ((u16_t)b2 << 8) + b1; + b1 = (u8_t) wd->sta.iv16; + b2 = 0x20; + + // header[hlen+1] = (((u16_t) wd->sta.keyId) << 14) | (((u16_t)b2 << 8) + b1); + // STA in infrastructure mode should use keyId = 0 to transmit unicast ! + header[hlen+1] = (((u16_t)b2 << 8) + b1); + header[hlen+2] = (u16_t) wd->sta.iv32; + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + + /* If software encryption enable */ + if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0) + { + //macCtrl |= 0x80; + /* TKIP same to WEP */ + macCtrl |= 0x40; + icvLen = 4; + + /* set hardware MIC */ + if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) + { + macCtrl |= 0x100; + plusLen += 8; + *micLen = 8; + } + } + else + { + u8_t mic[8]; + u16_t offset; + u32_t icv; + u8_t RC4Key[16]; + + /* TODO: Remove the criticial section here. */ + zmw_declare_for_critical_section(); + + zmw_enter_critical_section(dev); + /* Calculate MIC */ + zfCalTxMic(dev, buf, (u8_t *)snap, snapLen, minusLen, da, sa, up, mic); + + offset = zfwBufGetSize(dev, buf); + + /* Append MIC to the buffer */ + zfCopyToIntTxBuffer(dev, buf, mic, offset, 8); + zfwBufSetSize(dev, buf, offset+8); + zmw_leave_critical_section(dev); + + /* TKIP Key Mixing */ + zfTkipPhase1KeyMix(wd->sta.iv32, &wd->sta.txSeed); + zfTkipPhase2KeyMix(wd->sta.iv16, &wd->sta.txSeed); + zfTkipGetseeds(wd->sta.iv16, RC4Key, &wd->sta.txSeed); + + /* Encrypt Data */ + zfTKIPEncrypt(dev, buf, (u8_t *)snap, snapLen, minusLen, 16, RC4Key, &icv); + + icvLen = 4; + len += 8; + } + + header[4] |= 0x4000; + hlen += 4; + } + else if ( wd->sta.encryMode == ZM_AES ) + { + b1 = (u8_t) wd->sta.iv16; + b2 = (u8_t) (wd->sta.iv16 >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + // header[hlen+1] = (((u16_t) wd->sta.keyId) << 14) | (0x2000); + // STA in infrastructure mode should use keyId = 0 to transmit unicast ! + header[hlen+1] = 0x2000; + header[hlen+2] = (u16_t) (wd->sta.iv32); + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + + header[4] |= 0x4000; + hlen += 4; + } + #ifdef ZM_ENABLE_CENC + else if ( wd->sta.encryMode == ZM_CENC ) + { + /* Accumlate the PN sequence */ + wd->sta.txiv[0] += 2; + + if (wd->sta.txiv[0] == 0 || wd->sta.txiv[0] == 1) + { + wd->sta.txiv[1]++; + } + + if (wd->sta.txiv[1] == 0) + { + wd->sta.txiv[2]++; + } + + if (wd->sta.txiv[2] == 0) + { + wd->sta.txiv[3]++; + } + + if (wd->sta.txiv[3] == 0) + { + wd->sta.txiv[0] = 0; + wd->sta.txiv[1] = 0; + wd->sta.txiv[2] = 0; + } + + header[hlen] = (wd->sta.cencKeyId & 0x0001); /* For Key Id and reserved field */ + header[hlen+1] = (u16_t) wd->sta.txiv[0]; + header[hlen+2] = (u16_t) (wd->sta.txiv[0] >> 16); + header[hlen+3] = (u16_t) wd->sta.txiv[1]; + header[hlen+4] = (u16_t) (wd->sta.txiv[1] >> 16); + header[hlen+5] = (u16_t) wd->sta.txiv[2]; + header[hlen+6] = (u16_t) (wd->sta.txiv[2] >> 16); + header[hlen+7] = (u16_t) wd->sta.txiv[3]; + header[hlen+8] = (u16_t) (wd->sta.txiv[3] >> 16); + + macCtrl |= 0x80; + icvLen = 16; /* MIC */ + + header[4] |= 0x4000; + hlen += 9; + } + #endif //ZM_ENABLE_CENC + } + } + } // if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) + } /* if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE ) */ + + if ( wd->wlanMode == ZM_MODE_IBSS ) + { + if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) + { +#ifdef ZM_ENABLE_IBSS_WPA2PSK + if( wd->sta.oppositeInfo[userIdx].wpaState >= ZM_STA_WPA_STATE_PK_OK || wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK) + { + int isUnicast = 1 ; + + if((da[0]& 0x1)) + { + isUnicast = 0 ; // Not unicast , is broadcast + } + + if( wd->sta.ibssWpa2Psk == 1 ) + { /* The IV order is not the same between unicast and broadcast ! */ + if ( isUnicast ) + { + iv16 = &wd->sta.oppositeInfo[userIdx].iv16; + iv32 = &wd->sta.oppositeInfo[userIdx].iv32; + } + else + { + iv16 = &wd->sta.iv16; + iv32 = &wd->sta.iv32; + } + } + else + { + iv16 = &wd->sta.iv16; + iv32 = &wd->sta.iv32; + } + + (*iv16)++; + if ( *iv16 == 0 ) + { + *iv32++; + } + + if ( wd->sta.oppositeInfo[userIdx].encryMode == ZM_AES || wd->sta.encryMode == ZM_AES) + { + //printk("Station encryption mode is AES-CCMP\n") ; + b1 = (u8_t) (*iv16); + b2 = (u8_t) ((*iv16) >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + + if ( isUnicast ) + { + header[hlen+1] = 0x2000; + } + else + { + header[hlen+1] = 0x2000 | (((u16_t) wd->sta.keyId) << 14); + } + + header[hlen+2] = (u16_t) (*iv32); + header[hlen+3] = (u16_t) ((*iv32) >> 16); + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + } + + header[4] |= 0x4000; + hlen += 4; + } + else if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED) + { + if ( (wd->sta.encryMode == ZM_WEP64)|| + (wd->sta.encryMode == ZM_WEP128)|| + (wd->sta.encryMode == ZM_WEP256) ) + { + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = 0x0; //IV + header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); + hlen += 2; + icvLen = 4; + macCtrl |= 0x40; + } + } +#else + /* ----- 20070405 add by Mxzeng ----- */ + if( wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK ) + { + int isUnicast = 1 ; + + if((da[0]& 0x1)) + { + isUnicast = 0 ; // Not unicast , is broadcast + } + + wd->sta.iv16++; + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + if ( wd->sta.encryMode == ZM_AES ) + { + //printk("Station encryption mode is AES-CCMP\n") ; + b1 = (u8_t) wd->sta.iv16; + b2 = (u8_t) (wd->sta.iv16 >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + + if ( isUnicast ) + { + header[hlen+1] = 0x2000; + } + else + { + header[hlen+1] = 0x2000 | (((u16_t) wd->sta.keyId) << 14); + } + + header[hlen+2] = (u16_t) (wd->sta.iv32); + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + } + + header[4] |= 0x4000; + hlen += 4; + } + else if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED) + { + if ( (wd->sta.encryMode == ZM_WEP64)|| + (wd->sta.encryMode == ZM_WEP128)|| + (wd->sta.encryMode == ZM_WEP256) ) + { + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = 0x0; //IV + header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); + hlen += 2; + icvLen = 4; + macCtrl |= 0x40; + } + } +#endif + } // End if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) + } // End if ( wd->wlanMode == ZM_MODE_IBSS ) + else if ( wd->wlanMode == ZM_MODE_PSEUDO ) + { + switch (wd->sta.encryMode) + { + case ZM_WEP64: + case ZM_WEP128: + case ZM_WEP256: + header[4] |= 0x4000; + header[hlen] = 0x0; //IV + header[hlen+1] = 0x0; //IV + hlen += 2; + icvLen = 4; + macCtrl |= 0x40; + break; + + case ZM_TKIP: + { + wd->sta.iv16++; + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + b1 = (u8_t) (wd->sta.iv16 >> 8); + b2 = (b1 | 0x20) & 0x7f; + header[hlen] = ((u16_t)b2 << 8) + b1; + b1 = (u8_t) wd->sta.iv16; + b2 = 0x20; + header[hlen+1] = ((u16_t)b2 << 8) + b1; + header[hlen+2] = (u16_t) wd->sta.iv32; + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + + //macCtrl |= 0x80; + macCtrl |= 0x40; + icvLen = 4; + + /* set hardware MIC */ + if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) + { + macCtrl |= 0x100; + plusLen += 8; + *micLen = 8; + } + + header[4] |= 0x4000; + hlen += 4; + }/* end of PSEUDO TKIP */ + break; + + case ZM_AES: + { + wd->sta.iv16++; + if ( wd->sta.iv16 == 0 ) + { + wd->sta.iv32++; + } + + b1 = (u8_t) wd->sta.iv16; + b2 = (u8_t) (wd->sta.iv16 >> 8); + header[hlen] = ((u16_t)b2 << 8) + b1; + header[hlen+1] = 0x2000; + header[hlen+2] = (u16_t) (wd->sta.iv32); + header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); + macCtrl |= 0xc0; + icvLen = 8; /* MIC */ + header[4] |= 0x4000; + hlen += 4; + }/* end of PSEUDO AES */ + break; + + #ifdef ZM_ENABLE_CENC + case ZM_CENC: + /* Accumlate the PN sequence */ + wd->sta.txiv[0] += 2; + + if (wd->sta.txiv[0] == 0 || wd->sta.txiv[0] == 1) + { + wd->sta.txiv[1]++; + } + + if (wd->sta.txiv[1] == 0) + { + wd->sta.txiv[2]++; + } + + if (wd->sta.txiv[2] == 0) + { + wd->sta.txiv[3]++; + } + + if (wd->sta.txiv[3] == 0) + { + wd->sta.txiv[0] = 0; + wd->sta.txiv[1] = 0; + wd->sta.txiv[2] = 0; + } + + header[hlen] = 0; + header[hlen+1] = (u16_t) wd->sta.txiv[0]; + header[hlen+2] = (u16_t) (wd->sta.txiv[0] >> 16); + header[hlen+3] = (u16_t) wd->sta.txiv[1]; + header[hlen+4] = (u16_t) (wd->sta.txiv[1] >> 16); + header[hlen+5] = (u16_t) wd->sta.txiv[2]; + header[hlen+6] = (u16_t) (wd->sta.txiv[2] >> 16); + header[hlen+7] = (u16_t) wd->sta.txiv[3]; + header[hlen+8] = (u16_t) (wd->sta.txiv[3] >> 16); + + macCtrl |= 0x80; + icvLen = 16; /* MIC */ + + header[4] |= 0x4000; + hlen += 9; + break; + #endif //ZM_ENABLE_CENC + }/* end of switch */ + } + + /* Generate control setting */ + + /* protection mode */ + if (wd->enableProtectionMode) + { + if (wd->enableProtectionMode==2) + { + /* Force enable protection: self cts */ + macCtrl &= 0xFFFC; + macCtrl |= 2; + } + /* if wd->enableProtectionMode=1 => force disable */ + /* if wd->enableProtectionMode=0 => auto */ + } + else + { + + /* protection mode */ + if (wd->sta.bProtectionMode == TRUE) + { + /* Enable Self-CTS */ + macCtrl &= 0xFFFC; + macCtrl |= 2; + } + } + + } + + if (wd->txMCS != 0xff) + { + /* fixed rate */ + phyCtrl = ((u32_t)wd->txMCS<<16) + wd->txMT; + mcs = wd->txMCS; + mt = wd->txMT; + } + + if (mt == 2) + { +#if 0 + /* HT PT: 0 Mixed mode 1 Green field */ + if (wd->sta.preambleTypeHT == ZM_PREAMBLE_TYPE_GREEN_FIELD) + { + phyCtrl |= 0x4; /* Bit 2 */ + } +#endif + /* Bandwidth */ + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) + { + phyCtrl |= (0x80<<16); /* BIT 23 */ + } +#if 0 + /* STBC */ + if (wd->sta.htCtrlSTBC<=0x3) + { + phyCtrl |= (wd->sta.htCtrlSTBC<<28); /* BIT 23 */ + } +#endif + /* Short GI */ + if(wd->sta.htCtrlSG) + { + phyCtrl |= (0x8000<<16); /* BIT 31 */ + } + + /* TA */ + if ( ((mcs >=0x8) && (mcs<=0xf)) || (wd->sta.htCtrlSTBC) ) + { + phyCtrl |= 0x1800; /* BIT 11 12 */ + } + } + else if(mt == 1) + { + #if 0 + //bug that cause OFDM rate become duplicate legacy rate + /* Bandwidth */ + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) + { + phyCtrl |= (0x80<<16); /* BIT 23 */ + mt = 3; /* duplicate legacy */ + phyCtrl |= mt; + } + #endif + } + else if(mt == 0) + { + /* CCK PT: Legcy Preamble: 1 long preamble 2 short preamble */ + if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_SHORT) + { + //phyCtrl |= 0x4; /* BIT 2 */ + } + } + + /* TA */ + if (wd->sta.defaultTA) + { + phyCtrl |= 0x1000; + } + else + { + phyCtrl |= 0x0800; + } + + //Get CurrentTxRate -- CWYang(+) + if ((mt == 0) || (mt == 1)) //B,G Rate + { + if (mcs < 16) + { + wd->CurrentTxRateKbps = zcIndextoRateBG[mcs]; + } + } + else if (mt == 2) + { + if (mcs < 16) + { + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) + { + if((phyCtrl & 0x80000000) != 0) + { + /* Short GI 40 MHz MIMO Rate */ + wd->CurrentTxRateKbps = zcIndextoRateN40S[mcs]; + } + else + { + /* Long GI 40 MHz MIMO Rate */ + wd->CurrentTxRateKbps = zcIndextoRateN40L[mcs]; + } + } + else + { + if((phyCtrl & 0x80000000) != 0) + { + /* Short GI 20 MHz MIMO Rate */ + wd->CurrentTxRateKbps = zcIndextoRateN20S[mcs]; + } + else + { + /* Long GI 20 MHz MIMO Rate */ + wd->CurrentTxRateKbps = zcIndextoRateN20L[mcs]; + } + } + } + } + + //802.11 header(include IV) = (hlen<<1)-8 + //ethernet frame = len + //snap + mic = plusLen + //ethernet header = minusLen + //icv = icvLen + //crc32 = 4 + //length=802.11 header+snap+(ethernet frame-ethernet header)+mic+icv+crc32 + header[0] = ((hlen<<1)-8)+plusLen+(len-minusLen)+icvLen+4; //Length + + // header[0] : MPDU Lengths + if ((header[6] & 0x1) != 0x1) // Unicast Frame + { + if (header[0] >= wd->rtsThreshold) + { + /* Enable RTS */ + macCtrl |= 1; + } + } + + if ( wd->sta.encryMode == ZM_TKIP ) + tkipFrameOffset = 8; + + if( wd->sta.EnableHT != 1 ) + { // Aggregation should not be fragmented ! + if ( header[0] > ( wd->fragThreshold + tkipFrameOffset ) ) + { + return 0; // Need to be fragmented ! ! + } + } + + //if ( wd->sta.encryMode == ZM_TKIP ) + //{ + // zm_debug_msg1("ctrl length = ", header[0]); + //} + + //MAC control + if (rateProbingFlag != 0) + { + macCtrl |= 0x8000; + } + header[1] = macCtrl; + //PHY control L + header[2] = (u16_t) ((phyCtrl&0xffff) | 0x700 | (zcUpToAc[up&0x7]<<13)); + //PHY control H + header[3] = (u16_t) ((phyCtrl>>16) | 0x700); + + if (wd->enableAggregation) + { + /* force enable aggregation */ + if (wd->enableAggregation==2 && !(header[6]&0x1)) + { + if (((header[2] & 0x3) == 2)) + { + /* Enable aggregation */ + header[1] |= 0x20; + } + } + /* if wd->enableAggregation=1 => force disable */ + /* if wd->enableAggregation=0 => auto */ + } + +#ifdef ZM_ENABLE_AGGREGATION + if (wd->addbaComplete) { + #ifdef ZM_BYPASS_AGGR_SCHEDULING + if (!(header[6]&0x1) && !rateProbingFlag && (wd->enableAggregation != 1)) + { + if (((header[2] & 0x3) == 2)) + { + /* Unicast frame with HT rate => Enable aggregation */ + /* We only support software encryption in single packet mode */ + if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0 && + (wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) == 0) + { + /* Set aggregation group bits per AC */ + header[1] |= (0x20 | (zcUpToAc[up&0x7]<<10)); + + //if (wd->sta.currentFrequency < 3000) + { + /* issue: -PB42 Enable RTS/CTS to prevent OWL Tx hang up */ + /* If this is Owl Ap, enable RTS/CTS protect */ + if ( (wd->sta.athOwlAp == 1) || (wd->sta.RTSInAGGMode == TRUE) ) + { + header[1] &= 0xfffc; + header[1] |= 0x1; + } + + /* Enable RIFS : workaround 854T RTS/CTS */ + /* Bit13 : TI enable RIFS */ + //header[1] |= 0x2000; + } + } + } + } + #else + /* + * aggregation ampduIndication control + */ + if (aggControl && aggControl->aggEnabled) { + if (wd->enableAggregation==0 && !(header[6]&0x1)) + { + if (((header[2] & 0x3) == 2)) + { + /* Enable aggregation */ + header[1] |= 0x20; + if (ZM_AGG_LAST_MPDU == aggControl->ampduIndication) + header[1] |= 0x4000; + } + else { + zm_debug_msg1("no aggr, header[2]&0x3 = ",header[2] & 0x3) + aggControl->aggEnabled = 0; + } + } + else { + zm_debug_msg1("no aggr, wd->enableAggregation = ", wd->enableAggregation); + zm_debug_msg1("no aggr, !header[6]&0x1 = ",!(header[6]&0x1)); + aggControl->aggEnabled = 0; + } + } + #endif + + #ifdef ZM_AGGR_BIT_ON + if (!(header[6]&0x1) && !rateProbingFlag) + { + if (((header[2] & 0x3) == 2)) + { + /* Unicast frame with HT rate => Enable aggregation */ + /* Set aggregation group bits per AC */ + header[1] |= (0x20 | (zcUpToAc[up&0x7]<<10)); + + //if (wd->sta.currentFrequency < 3000) + { + /* Enable RTS/CTS to prevent OWL Tx hang up */ + header[1] &= 0xfffc; + header[1] |= 0x1; + } + } + } + #endif + } +#endif + + return (hlen<<1); +} + + +u16_t zfTxGenMmHeader(zdev_t* dev, u8_t frameType, u16_t* dst, + u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt) +{ + //u16_t bodyLen; + u8_t hlen = 32; // MAC ctrl + PHY ctrl + 802.11 MM header + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + /* Generate control setting */ + //bodyLen = zfwBufGetSize(dev, buf); + header[0] = 24+len+4; //Length + if ((dst[0] & 0x1) != 0) //Broadcast, multicast frames + { + header[1] = 0xc; //MAC control, backoff + noack + } + else + { + header[1] = 0x8; //MAC control, backoff + (ack) + } + /* Dualband Management frame tx Rate */ + if (wd->wlanMode == ZM_MODE_AP) + { + if (wd->frequency < 3000) + { + /* CCK 1M */ + header[2] = 0x0f00; //PHY control L + header[3] = 0x0000; //PHY control H + } + else + { + /* CCK 6M */ + header[2] = 0x0f01; //PHY control L + header[3] = 0x000B; //PHY control H + } + } + else + { + if (wd->sta.currentFrequency < 3000) + { + /* CCK 2M */ + header[2] = 0x0f00; //PHY control L + header[3] = 0x0001; //PHY control H + } + else + { + /* CCK 6M */ + header[2] = 0x0f01; //PHY control L + header[3] = 0x000B; //PHY control H + } + } + /* Generate WLAN header */ + /* Frame control */ + header[4+0] = frameType; + /* Duration */ + header[4+1] = 0; + + if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) + { + if ( frameType == ZM_WLAN_FRAME_TYPE_PROBEREQ ) + { + header[4+8] = 0xFFFF; + header[4+9] = 0xFFFF; + header[4+10] = 0xFFFF; + } + else if ( frameType == ZM_WLAN_FRAME_TYPE_BA ) { + /* do nothing */ + } + else + { + header[4+8] = wd->sta.bssid[0]; + header[4+9] = wd->sta.bssid[1]; + header[4+10] = wd->sta.bssid[2]; + } + } + else if (wd->wlanMode == ZM_MODE_PSEUDO) + { + /* Address 3 = 00:00:00:00:00:00 */ + header[4+8] = 0; + header[4+9] = 0; + header[4+10] = 0; + } + else if (wd->wlanMode == ZM_MODE_IBSS) + { + header[4+8] = wd->sta.bssid[0]; + header[4+9] = wd->sta.bssid[1]; + header[4+10] = wd->sta.bssid[2]; + + if ( frameType == ZM_WLAN_FRAME_TYPE_ATIM ) + { + /* put ATIM to queue 5th */ + //header[2] |= (ZM_BIT_13|ZM_BIT_14); + header[2] |= ZM_BIT_15; + } + } + else if (wd->wlanMode == ZM_MODE_AP) + { + /* Address 3 = BSSID */ + header[4+8] = wd->macAddr[0]; + header[4+9] = wd->macAddr[1]; +#ifdef ZM_VAPMODE_MULTILE_SSID + header[4+10] = wd->macAddr[2]; //Multiple SSID +#else + header[4+10] = wd->macAddr[2] + (vap<<8); //VAP +#endif + //if in scan, must set address 3 to broadcast because of some ap would care this + //if ((wd->heartBeatNotification & ZM_BSSID_LIST_SCAN) + // == ZM_BSSID_LIST_SCAN) + //if FrameType is Probe Request, Address3 should be boradcast + if (frameType == ZM_WLAN_FRAME_TYPE_PROBEREQ) + { + header[4+8] = 0xFFFF; + header[4+9] = 0xFFFF; + header[4+10] = 0xFFFF; + } + } + + /* Address 1 = DA */ + header[4+2] = dst[0]; + header[4+3] = dst[1]; + header[4+4] = dst[2]; + + /* Address 2 = SA */ + header[4+5] = wd->macAddr[0]; + header[4+6] = wd->macAddr[1]; + if (wd->wlanMode == ZM_MODE_AP) + { +#ifdef ZM_VAPMODE_MULTILE_SSID + header[4+7] = wd->macAddr[2]; //Multiple SSID +#else + header[4+7] = wd->macAddr[2] + (vap<<8); //VAP +#endif + } + else + { + header[4+7] = wd->macAddr[2]; + } + + /* Sequence Control */ + zmw_enter_critical_section(dev); + header[4+11] = ((wd->mmseq++)<<4); + zmw_leave_critical_section(dev); + + if( frameType == ZM_WLAN_FRAME_TYPE_QOS_NULL ) + { + /*Qos Control*/ + header[4+12] = 0x0; + hlen+=2; + header[0]+=2; + } + + if ( encrypt ) + { + if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) + { + if ( (wd->sta.encryMode == ZM_WEP64)|| + (wd->sta.encryMode == ZM_WEP128)|| + (wd->sta.encryMode == ZM_WEP256) ) + { + header[4] |= 0x4000; + header[16] = 0x0; //IV + header[17] = 0x0; //IV + header[17] |= (((u16_t) wd->sta.keyId) << 14); + hlen += 4; + + header[0] += 8; // icvLen = 4; + header[1] |= 0x40; // enable encryption on macCtrl + } + } + } + + // Enable HW duration + if ( frameType != ZM_WLAN_FRAME_TYPE_PSPOLL ) + { + header[1] |= 0x200; + } + + return hlen; +} + +void zfInitMacApMode(zdev_t* dev) +{ + u16_t i; + + zmw_get_wlan_dev(dev); + + zfHpEnableBeacon(dev, ZM_MODE_AP, (wd->beaconInterval/wd->ap.vapNumber), 1, 0); + + /* AP mode */ + zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_AP); + + /* VAP test code */ + /* AP + VAP mode */ + if (wd->ap.vapNumber >= 2) + { + for (i=1; i<ZM_MAX_AP_SUPPORT; i++) + { + if (((wd->ap.apBitmap >> i) & 0x1) != 0) + { + u16_t mac[3]; + mac[0] = wd->macAddr[0]; + mac[1] = wd->macAddr[1]; +#ifdef ZM_VAPMODE_MULTILE_SSID + mac[2] = wd->macAddr[2]; //Multiple SSID +#else + mac[2] = wd->macAddr[2] + (i<<8); //VAP +#endif + zfHpSetMacAddress(dev, mac, i); + + } + } + } + + /* basic rate setting */ + zfHpSetBasicRateSet(dev, wd->bRateBasic, wd->gRateBasic); + + /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME AP default. */ + zfUpdateDefaultQosParameter(dev, 1); + + return; +} + +u16_t zfChGetNextChannel(zdev_t* dev, u16_t frequency, u8_t* pbPassive) +{ + u8_t i; + u8_t bPassive; + + zmw_get_wlan_dev(dev); + + /* Avoid NULL value */ + if ( pbPassive == NULL ) + { + pbPassive = &bPassive; + } + + for( i=0; i<wd->regulationTable.allowChannelCnt; i++ ) + { + if ( wd->regulationTable.allowChannel[i].channel == frequency ) + { + if ( i == (wd->regulationTable.allowChannelCnt-1) ) + { + i = 0; + } + else + { + i++; + } + + if ( wd->regulationTable.allowChannel[i].channelFlags + & ZM_REG_FLAG_CHANNEL_PASSIVE ) + { + *pbPassive = TRUE; + } + else + { + *pbPassive = FALSE; + } + + return wd->regulationTable.allowChannel[i].channel; + } + } + + return 0xffff; +} + +u16_t zfChGetFirstChannel(zdev_t* dev, u8_t* pbPassive) +{ + u8_t bPassive; + + zmw_get_wlan_dev(dev); + + /* Avoid NULL value */ + if ( pbPassive == NULL ) + { + pbPassive = &bPassive; + } + + if ( wd->regulationTable.allowChannel[0].channelFlags & ZM_REG_FLAG_CHANNEL_PASSIVE ) + { + *pbPassive = TRUE; + } + else + { + *pbPassive = FALSE; + } + + return wd->regulationTable.allowChannel[0].channel; +} + +u16_t zfChGetFirst2GhzChannel(zdev_t* dev) +{ + u8_t i; + + zmw_get_wlan_dev(dev); + + for( i=0; i<wd->regulationTable.allowChannelCnt; i++ ) + { + if ( wd->regulationTable.allowChannel[i].channel < 3000 ) + { + /* find the first 2Ghz channel */ + return wd->regulationTable.allowChannel[i].channel; + } + } + + /* Can not find any 2Ghz channel */ + return 0; +} + +u16_t zfChGetFirst5GhzChannel(zdev_t* dev) +{ + u8_t i; + + zmw_get_wlan_dev(dev); + + for( i=0; i<wd->regulationTable.allowChannelCnt; i++ ) + { + if ( wd->regulationTable.allowChannel[i].channel > 3000 ) + { + /* find the first 5Ghz channel */ + return wd->regulationTable.allowChannel[i].channel; + } + } + + /* Can not find any 5Ghz channel */ + return 0; +} + +u16_t zfChGetLastChannel(zdev_t* dev, u8_t* pbPassive) +{ + u8_t bPassive; + u8_t ChannelIndex; + + zmw_get_wlan_dev(dev); + + ChannelIndex = wd->regulationTable.allowChannelCnt-1; + + /* Avoid NULL value */ + if ( pbPassive == NULL ) + { + pbPassive = &bPassive; + } + + if ( wd->regulationTable.allowChannel[ChannelIndex].channelFlags + & ZM_REG_FLAG_CHANNEL_PASSIVE ) + { + *pbPassive = TRUE; + } + else + { + *pbPassive = FALSE; + } + + return wd->regulationTable.allowChannel[ChannelIndex].channel; +} + +u16_t zfChGetLast5GhzChannel(zdev_t* dev) +{ + u8_t i; + u16_t last5Ghzfrequency; + + zmw_get_wlan_dev(dev); + + last5Ghzfrequency = 0; + for( i=0; i<wd->regulationTable.allowChannelCnt; i++ ) + { + if ( wd->regulationTable.allowChannel[i].channel > 3000 ) + { + last5Ghzfrequency = wd->regulationTable.allowChannel[i].channel; + } + } + + return last5Ghzfrequency; +} + +/* freqBand = 0 => auto check */ +/* = 1 => 2.4 GHz band */ +/* = 2 => 5 GHz band */ +u16_t zfChNumToFreq(zdev_t* dev, u8_t ch, u8_t freqBand) +{ + u16_t freq = 0xffff; + + if ( freqBand == 0 ) + { + if (ch > 14) + { /* adapter is at 5 GHz band */ + freqBand = 2; + } + else + { + freqBand = 1; + } + } + + if ( freqBand == 2 ) + { /* the channel belongs to 5 GHz band */ + if ( (ch >= 184)&&(ch <= 196) ) + { + freq = 4000 + ch*5; + } + else + { + freq = 5000 + ch*5; + } + } + else + { /* the channel belongs to 2.4 GHz band */ + if ( ch == 14 ) + { + freq = ZM_CH_G_14; + } + else + { + freq = ZM_CH_G_1 + (ch-1)*5; + } + } + + return freq; +} + +u8_t zfChFreqToNum(u16_t freq, u8_t* pbIs5GBand) +{ + u8_t ch; + u8_t Is5GBand; + + /* to avoid NULL value */ + if ( pbIs5GBand == NULL ) + { + pbIs5GBand = &Is5GBand; + } + + *pbIs5GBand = FALSE; + + if ( freq == ZM_CH_G_14 ) + { + ch = 14; + } + else if ( freq < 4000 ) + { + ch = (freq - ZM_CH_G_1) / 5 + 1; + } + else if ( freq < 5000 ) + { + ch = (freq - 4000) / 5; + *pbIs5GBand = TRUE; + } + else + { + ch = (freq - 5000) / 5; + *pbIs5GBand = TRUE; + } + + return ch; +} |