blob: 11823311e9ce0fc90160389a7d781e25a8ca81da [file] [log] [blame]
/*
* Copyright (c) 2007-2008 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* */
/* 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 */
wdsPort = port - 0x20;
if (wdsPort >= 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;
}