| /* |
| * 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; |
| } |