4bd43f507c
Initial dump of the otus USB wireless network driver. It builds properly, but a lot of work needs to be done cleaning it up before it can be merged into the wireless driver tree. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2403 lines
74 KiB
C
2403 lines
74 KiB
C
/*
|
|
* 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 : mm.c */
|
|
/* */
|
|
/* Abstract */
|
|
/* This module contains common functions for handle AP */
|
|
/* management frame. */
|
|
/* */
|
|
/* NOTES */
|
|
/* None */
|
|
/* */
|
|
/************************************************************************/
|
|
#include "cprecomp.h"
|
|
#include "ratectrl.h"
|
|
|
|
extern const u8_t zcUpToAc[];
|
|
|
|
void zfMmApTimeTick(zdev_t* dev)
|
|
{
|
|
u32_t now;
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
//zm_debug_msg1("wd->wlanMode : ", wd->wlanMode);
|
|
if (wd->wlanMode == ZM_MODE_AP)
|
|
{
|
|
/* => every 1.28 seconds */
|
|
/* AP : aging STA that does not active for wd->ap.staAgingTime */
|
|
now = wd->tick & 0x7f;
|
|
if (now == 0x0)
|
|
{
|
|
zfApAgingSta(dev);
|
|
}
|
|
else if (now == 0x1f)
|
|
{
|
|
zfQueueAge(dev, wd->ap.uapsdQ, wd->tick, 10000);
|
|
}
|
|
/* AP : check (wd->ap.protectedObss) and (wd->ap.bStaAssociated) */
|
|
/* to enable NonErp and Protection mode */
|
|
else if (now == 0x3f)
|
|
{
|
|
//zfApProtctionMonitor(dev);
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApInitStaTbl */
|
|
/* Init AP's station table. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* None */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
void zfApInitStaTbl(zdev_t* dev)
|
|
{
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
for (i=0; i<ZM_MAX_STA_SUPPORT; i++)
|
|
{
|
|
wd->ap.staTable[i].valid = 0;
|
|
wd->ap.staTable[i].state = 0;
|
|
wd->ap.staTable[i].addr[0] = 0;
|
|
wd->ap.staTable[i].addr[1] = 0;
|
|
wd->ap.staTable[i].addr[2] = 0;
|
|
wd->ap.staTable[i].time = 0;
|
|
wd->ap.staTable[i].vap = 0;
|
|
wd->ap.staTable[i].encryMode = ZM_NO_WEP;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApFindSta */
|
|
/* Find a STA in station table. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* addr : Target STA address */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* 0xffff : fail */
|
|
/* other : STA table index */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApFindSta(zdev_t* dev, u16_t* addr)
|
|
{
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
for (i=0; i<ZM_MAX_STA_SUPPORT; i++)
|
|
{
|
|
if (wd->ap.staTable[i].valid == 1)
|
|
{
|
|
if ((wd->ap.staTable[i].addr[0] == addr[0])
|
|
&& (wd->ap.staTable[i].addr[1] == addr[1])
|
|
&& (wd->ap.staTable[i].addr[2] == addr[2]))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
u16_t zfApGetSTAInfo(zdev_t* dev, u16_t* addr, u16_t* state, u8_t* vap)
|
|
{
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
*vap = wd->ap.staTable[id].vap;
|
|
*state = wd->ap.staTable[id++].state;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
return id;
|
|
}
|
|
|
|
|
|
void zfApGetStaQosType(zdev_t* dev, u16_t* addr, u8_t* qosType)
|
|
{
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
*qosType = wd->ap.staTable[id].qosType;
|
|
}
|
|
else
|
|
{
|
|
*qosType = 0;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
return;
|
|
}
|
|
|
|
void zfApGetStaTxRateAndQosType(zdev_t* dev, u16_t* addr, u32_t* phyCtrl,
|
|
u8_t* qosType, u16_t* rcProbingFlag)
|
|
{
|
|
u16_t id;
|
|
u8_t rate;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->ap.staTable[id].rcCell, rcProbingFlag);
|
|
#ifdef ZM_AP_DEBUG
|
|
//rate = 15;
|
|
#endif
|
|
*phyCtrl = zcRateToPhyCtrl[rate];
|
|
*qosType = wd->ap.staTable[id].qosType;
|
|
}
|
|
else
|
|
{
|
|
if (wd->frequency < 3000)
|
|
{
|
|
/* CCK 1M */
|
|
//header[2] = 0x0f00; //PHY control L
|
|
//header[3] = 0x0000; //PHY control H
|
|
*phyCtrl = 0x00000F00;
|
|
}
|
|
else
|
|
{
|
|
/* CCK 6M */
|
|
//header[2] = 0x0f01; //PHY control L
|
|
//header[3] = 0x000B; //PHY control H
|
|
*phyCtrl = 0x000B0F01;
|
|
}
|
|
*qosType = 0;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg2_mm(ZM_LV_3, "PhyCtrl=", *phyCtrl);
|
|
return;
|
|
}
|
|
|
|
void zfApGetStaEncryType(zdev_t* dev, u16_t* addr, u8_t* encryType)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
*encryType = wd->ap.staTable[id].encryMode;
|
|
}
|
|
else
|
|
{
|
|
*encryType = ZM_NO_WEP;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg2_mm(ZM_LV_3, "encyrType=", *encryType);
|
|
return;
|
|
}
|
|
|
|
void zfApGetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t* iv16, u32_t* iv32)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
*iv16 = wd->ap.staTable[id].iv16;
|
|
*iv32 = wd->ap.staTable[id].iv32;
|
|
}
|
|
else
|
|
{
|
|
*iv16 = 0;
|
|
*iv32 = 0;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg2_mm(ZM_LV_3, "iv16=", *iv16);
|
|
zm_msg2_mm(ZM_LV_3, "iv32=", *iv32);
|
|
return;
|
|
}
|
|
|
|
void zfApSetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t iv16, u32_t iv32)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
wd->ap.staTable[id].iv16 = iv16;
|
|
wd->ap.staTable[id].iv32 = iv32;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg2_mm(ZM_LV_3, "iv16=", iv16);
|
|
zm_msg2_mm(ZM_LV_3, "iv32=", iv32);
|
|
return;
|
|
}
|
|
|
|
void zfApClearStaKey(zdev_t* dev, u16_t* addr)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t bcAddr[3] = { 0xffff, 0xffff, 0xffff };
|
|
u16_t id;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
if (zfMemoryIsEqual((u8_t*)bcAddr, (u8_t*)addr, sizeof(bcAddr)) == TRUE)
|
|
{
|
|
/* Turn off group key information */
|
|
// zfClearKey(dev, 0);
|
|
}
|
|
else
|
|
{
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
/* Turn off STA's key information */
|
|
zfHpRemoveKey(dev, id+1);
|
|
|
|
/* Update STA's Encryption Type */
|
|
wd->ap.staTable[id].encryMode = ZM_NO_WEP;
|
|
}
|
|
else
|
|
{
|
|
zm_msg0_mm(ZM_LV_3, "Can't find STA address\n");
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
}
|
|
}
|
|
|
|
#ifdef ZM_ENABLE_CENC
|
|
void zfApGetStaCencIvAndKeyIdx(zdev_t* dev, u16_t* addr, u32_t *iv, u8_t *keyIdx)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t id;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
*iv++ = wd->ap.staTable[id].txiv[0];
|
|
*iv++ = wd->ap.staTable[id].txiv[1];
|
|
*iv++ = wd->ap.staTable[id].txiv[2];
|
|
*iv = wd->ap.staTable[id].txiv[3];
|
|
*keyIdx = wd->ap.staTable[id].cencKeyIdx;
|
|
}
|
|
else
|
|
{
|
|
*iv++ = 0x5c365c37;
|
|
*iv++ = 0x5c365c36;
|
|
*iv++ = 0x5c365c36;
|
|
*iv = 0x5c365c36;
|
|
*keyIdx = 0;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
return;
|
|
}
|
|
|
|
void zfApSetStaCencIv(zdev_t* dev, u16_t* addr, u32_t *iv)
|
|
{
|
|
//struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev);
|
|
u16_t id;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
wd->ap.staTable[id].txiv[0] = *iv++;
|
|
wd->ap.staTable[id].txiv[1] = *iv++;
|
|
wd->ap.staTable[id].txiv[2] = *iv++;
|
|
wd->ap.staTable[id].txiv[3] = *iv;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
return;
|
|
}
|
|
#endif //ZM_ENABLE_CENC
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApFlushBufferedPsFrame */
|
|
/* Free buffered PS frames. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* None */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen Atheros Communications, INC. 2007.1 */
|
|
/* */
|
|
/************************************************************************/
|
|
void zfApFlushBufferedPsFrame(zdev_t* dev)
|
|
{
|
|
u16_t emptyFlag;
|
|
u16_t freeCount;
|
|
u16_t vap;
|
|
zbuf_t* psBuf = NULL;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
freeCount = 0;
|
|
emptyFlag = 0;
|
|
while (1)
|
|
{
|
|
psBuf = NULL;
|
|
zmw_enter_critical_section(dev);
|
|
if (wd->ap.uniHead != wd->ap.uniTail)
|
|
{
|
|
psBuf = wd->ap.uniArray[wd->ap.uniHead];
|
|
wd->ap.uniHead = (wd->ap.uniHead + 1) & (ZM_UNI_ARRAY_SIZE - 1);
|
|
}
|
|
else
|
|
{
|
|
emptyFlag = 1;
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
if (psBuf != NULL)
|
|
{
|
|
zfwBufFree(dev, psBuf, ZM_ERR_FLUSH_PS_QUEUE);
|
|
}
|
|
zm_assert(freeCount++ < (ZM_UNI_ARRAY_SIZE*2));
|
|
|
|
if (emptyFlag != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (vap=0; vap<ZM_MAX_AP_SUPPORT; vap++)
|
|
{
|
|
freeCount = 0;
|
|
emptyFlag = 0;
|
|
while (1)
|
|
{
|
|
psBuf = NULL;
|
|
zmw_enter_critical_section(dev);
|
|
if (wd->ap.bcmcHead[vap] != wd->ap.bcmcTail[vap])
|
|
{
|
|
psBuf = wd->ap.bcmcArray[vap][wd->ap.bcmcHead[vap]];
|
|
wd->ap.bcmcHead[vap] = (wd->ap.bcmcHead[vap] + 1)
|
|
& (ZM_BCMC_ARRAY_SIZE - 1);
|
|
}
|
|
else
|
|
{
|
|
emptyFlag = 1;
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
if (psBuf != NULL)
|
|
{
|
|
zfwBufFree(dev, psBuf, ZM_ERR_FLUSH_PS_QUEUE);
|
|
}
|
|
zm_assert(freeCount++ < (ZM_BCMC_ARRAY_SIZE*2));
|
|
|
|
if (emptyFlag != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
u16_t zfApBufferPsFrame(zdev_t* dev, zbuf_t* buf, u16_t port)
|
|
{
|
|
u16_t id;
|
|
u16_t addr[3];
|
|
u16_t vap = 0;
|
|
u8_t up;
|
|
u16_t fragOff;
|
|
u8_t ac;
|
|
u16_t ret;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
if (port < ZM_MAX_AP_SUPPORT)
|
|
{
|
|
vap = port;
|
|
}
|
|
|
|
addr[0] = zmw_rx_buf_readh(dev, buf, 0);
|
|
addr[1] = zmw_rx_buf_readh(dev, buf, 2);
|
|
addr[2] = zmw_rx_buf_readh(dev, buf, 4);
|
|
|
|
if ((addr[0] & 0x1) == 0x1)
|
|
{
|
|
if (wd->ap.staPowerSaving > 0)
|
|
{
|
|
zmw_enter_critical_section(dev);
|
|
|
|
/* Buffer this BC or MC frame */
|
|
if (((wd->ap.bcmcTail[vap]+1)&(ZM_BCMC_ARRAY_SIZE-1))
|
|
!= wd->ap.bcmcHead[vap])
|
|
{
|
|
wd->ap.bcmcArray[vap][wd->ap.bcmcTail[vap]++] = buf;
|
|
wd->ap.bcmcTail[vap] &= (ZM_BCMC_ARRAY_SIZE-1);
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg0_tx(ZM_LV_0, "Buffer BCMC");
|
|
}
|
|
else
|
|
{
|
|
/* bcmcArray full */
|
|
zmw_leave_critical_section(dev);
|
|
|
|
zm_msg0_tx(ZM_LV_0, "BCMC buffer full");
|
|
|
|
/* free buffer according to buffer type */
|
|
zfwBufFree(dev, buf, ZM_ERR_BCMC_PS_BUFFER_UNAVAILABLE);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
if (wd->ap.staTable[id].psMode == 1)
|
|
{
|
|
|
|
zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff);
|
|
ac = zcUpToAc[up&0x7] & 0x3;
|
|
|
|
if ((wd->ap.staTable[id].qosType == 1) &&
|
|
((wd->ap.staTable[id].qosInfo & (0x8>>ac)) != 0))
|
|
{
|
|
ret = zfQueuePutNcs(dev, wd->ap.uapsdQ, buf, wd->tick);
|
|
zmw_leave_critical_section(dev);
|
|
if (ret != ZM_SUCCESS)
|
|
{
|
|
zfwBufFree(dev, buf, ZM_ERR_AP_UAPSD_QUEUE_FULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Buffer this unicast frame */
|
|
if (((wd->ap.uniTail+1)&(ZM_UNI_ARRAY_SIZE-1))
|
|
!= wd->ap.uniHead)
|
|
{
|
|
wd->ap.uniArray[wd->ap.uniTail++] = buf;
|
|
wd->ap.uniTail &= (ZM_UNI_ARRAY_SIZE-1);
|
|
zmw_leave_critical_section(dev);
|
|
zm_msg0_tx(ZM_LV_0, "Buffer UNI");
|
|
|
|
}
|
|
else
|
|
{
|
|
/* uniArray full */
|
|
zmw_leave_critical_section(dev);
|
|
zm_msg0_tx(ZM_LV_0, "UNI buffer full");
|
|
/* free buffer according to buffer type */
|
|
zfwBufFree(dev, buf, ZM_ERR_UNI_PS_BUFFER_UNAVAILABLE);
|
|
}
|
|
}
|
|
return 1;
|
|
} /* if (wd->ap.staTable[id++].psMode == 1) */
|
|
} /* if ((id = zfApFindSta(dev, addr)) != 0xffff) */
|
|
zmw_leave_critical_section(dev);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
u16_t zfApGetSTAInfoAndUpdatePs(zdev_t* dev, u16_t* addr, u16_t* state,
|
|
u8_t* vap, u16_t psMode, u8_t* uapsdTrig)
|
|
{
|
|
u16_t id;
|
|
u8_t uapsdStaAwake = 0;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
#ifdef ZM_AP_DEBUG
|
|
//psMode=0;
|
|
#endif
|
|
|
|
if ((id = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
if (psMode != 0)
|
|
{
|
|
zm_msg0_mm(ZM_LV_0, "psMode = 1");
|
|
if (wd->ap.staTable[id].psMode == 0)
|
|
{
|
|
wd->ap.staPowerSaving++;
|
|
}
|
|
else
|
|
{
|
|
if (wd->ap.staTable[id].qosType == 1)
|
|
{
|
|
zm_msg0_mm(ZM_LV_0, "UAPSD trigger");
|
|
*uapsdTrig = wd->ap.staTable[id].qosInfo;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (wd->ap.staTable[id].psMode != 0)
|
|
{
|
|
wd->ap.staPowerSaving--;
|
|
if ((wd->ap.staTable[id].qosType == 1) && ((wd->ap.staTable[id].qosInfo&0xf)!=0))
|
|
{
|
|
uapsdStaAwake = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
wd->ap.staTable[id].psMode = (u8_t) psMode;
|
|
wd->ap.staTable[id].time = wd->tick;
|
|
*vap = wd->ap.staTable[id].vap;
|
|
*state = wd->ap.staTable[id++].state;
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
if (uapsdStaAwake == 1)
|
|
{
|
|
zbuf_t* psBuf;
|
|
u8_t mb;
|
|
|
|
while (1)
|
|
{
|
|
if ((psBuf = zfQueueGetWithMac(dev, wd->ap.uapsdQ, (u8_t*)addr, &mb)) != NULL)
|
|
{
|
|
zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, 0);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApGetNewSta */
|
|
/* Get a new STA from station table. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* 0xffff : fail */
|
|
/* other : STA table index */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApGetNewSta(zdev_t* dev)
|
|
{
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
for (i=0; i<ZM_MAX_STA_SUPPORT; i++)
|
|
{
|
|
if (wd->ap.staTable[i].valid == 0)
|
|
{
|
|
zm_msg2_mm(ZM_LV_0, "zfApGetNewSta=", i);
|
|
return i;
|
|
}
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApAddSta */
|
|
/* Add a STA to station table. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* addr : STA MAC address */
|
|
/* state : STA state */
|
|
/* apId : Virtual AP ID */
|
|
/* type : 0=>11b, 1=>11g */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* 0xffff : fail */
|
|
/* Other : index */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApAddSta(zdev_t* dev, u16_t* addr, u16_t state, u16_t apId, u8_t type,
|
|
u8_t qosType, u8_t qosInfo)
|
|
{
|
|
u16_t index;
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
zm_msg1_mm(ZM_LV_0, "STA type=", type);
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
if ((index = zfApFindSta(dev, addr)) != 0xffff)
|
|
{
|
|
zm_msg0_mm(ZM_LV_2, "found");
|
|
/* Update STA state */
|
|
if ((state == ZM_STATE_AUTH) || (state == ZM_STATE_PREAUTH))
|
|
{
|
|
wd->ap.staTable[index].state = state;
|
|
wd->ap.staTable[index].time = wd->tick;
|
|
wd->ap.staTable[index].vap = (u8_t)apId;
|
|
}
|
|
else if (state == ZM_STATE_ASOC)
|
|
{
|
|
if ((wd->ap.staTable[index].state == ZM_STATE_AUTH))
|
|
//&& (wd->ap.staTable[index].vap == apId))
|
|
{
|
|
wd->ap.staTable[index].state = state;
|
|
wd->ap.staTable[index].time = wd->tick;
|
|
wd->ap.staTable[index].qosType = qosType;
|
|
wd->ap.staTable[index].vap = (u8_t)apId;
|
|
wd->ap.staTable[index].staType = type;
|
|
wd->ap.staTable[index].qosInfo = qosInfo;
|
|
|
|
if (wd->frequency < 3000)
|
|
{
|
|
/* Init 11b/g */
|
|
zfRateCtrlInitCell(dev, &wd->ap.staTable[index].rcCell, type, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
/* Init 11a */
|
|
zfRateCtrlInitCell(dev, &wd->ap.staTable[index].rcCell, type, 0, 1);
|
|
}
|
|
|
|
if (wd->zfcbApConnectNotify != NULL)
|
|
{
|
|
wd->zfcbApConnectNotify(dev, (u8_t*)addr, apId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
index = 0xffff;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zm_msg0_mm(ZM_LV_2, "Not found");
|
|
if ((state == ZM_STATE_AUTH) || (state == ZM_STATE_PREAUTH))
|
|
{
|
|
/* Get a new STA and update state */
|
|
index = zfApGetNewSta(dev);
|
|
zm_msg2_mm(ZM_LV_1, "new STA index=", index);
|
|
|
|
if (index != 0xffff)
|
|
{
|
|
for (i=0; i<3; i++)
|
|
{
|
|
wd->ap.staTable[index].addr[i] = addr[i];
|
|
}
|
|
wd->ap.staTable[index].state = state;
|
|
wd->ap.staTable[index].valid = 1;
|
|
wd->ap.staTable[index].time = wd->tick;
|
|
wd->ap.staTable[index].vap = (u8_t)apId;
|
|
wd->ap.staTable[index].encryMode = ZM_NO_WEP;
|
|
}
|
|
}
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
|
|
return index;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApAgingSta */
|
|
/* Aging STA in station table. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* number of 11b STA in STA table */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
void zfApAgingSta(zdev_t* dev)
|
|
{
|
|
u16_t i;
|
|
u32_t deltaMs;
|
|
u16_t addr[3];
|
|
u16_t txFlag;
|
|
u16_t psStaCount = 0;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
wd->ap.gStaAssociated = wd->ap.bStaAssociated = 0;
|
|
|
|
for (i=0; i<ZM_MAX_STA_SUPPORT; i++)
|
|
{
|
|
txFlag = 0;
|
|
zmw_enter_critical_section(dev);
|
|
if (wd->ap.staTable[i].valid == 1)
|
|
{
|
|
addr[0] = wd->ap.staTable[i].addr[0];
|
|
addr[1] = wd->ap.staTable[i].addr[1];
|
|
addr[2] = wd->ap.staTable[i].addr[2];
|
|
/* millisecond */
|
|
deltaMs = (u32_t)((u32_t)wd->tick-(u32_t)wd->ap.staTable[i].time)
|
|
* ZM_MS_PER_TICK;
|
|
|
|
/* preauth */
|
|
if ((wd->ap.staTable[i].state == ZM_STATE_PREAUTH)
|
|
&& (deltaMs > ZM_PREAUTH_TIMEOUT_MS))
|
|
{
|
|
/* Aging STA */
|
|
wd->ap.staTable[i].valid = 0;
|
|
wd->ap.authSharing = 0;
|
|
txFlag = 1;
|
|
}
|
|
|
|
/* auth */
|
|
if ((wd->ap.staTable[i].state == ZM_STATE_AUTH)
|
|
&& (deltaMs > ZM_AUTH_TIMEOUT_MS))
|
|
{
|
|
/* Aging STA */
|
|
wd->ap.staTable[i].valid = 0;
|
|
txFlag = 1;
|
|
}
|
|
|
|
/* asoc */
|
|
if (wd->ap.staTable[i].state == ZM_STATE_ASOC)
|
|
{
|
|
if (wd->ap.staTable[i].psMode != 0)
|
|
{
|
|
psStaCount++;
|
|
}
|
|
|
|
if (deltaMs > ((u32_t)wd->ap.staAgingTimeSec<<10))
|
|
{
|
|
/* Aging STA */
|
|
zm_msg1_mm(ZM_LV_0, "Age STA index=", i);
|
|
wd->ap.staTable[i].valid = 0;
|
|
txFlag = 1;
|
|
}
|
|
else if (deltaMs > ((u32_t)wd->ap.staProbingTimeSec<<10))
|
|
{
|
|
if (wd->ap.staTable[i].psMode == 0)
|
|
{
|
|
/* Probing non-PS STA */
|
|
zm_msg1_mm(ZM_LV_0, "Probing STA index=", i);
|
|
wd->ap.staTable[i].time +=
|
|
(wd->ap.staProbingTimeSec * ZM_TICK_PER_SECOND);
|
|
txFlag = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
if (txFlag == 1)
|
|
{
|
|
/* Send deauthentication management frame */
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, addr, 4, 0, 0);
|
|
}
|
|
else if (txFlag == 2)
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_DATA_FRAME, addr, 0, 0, 0);
|
|
}
|
|
|
|
}
|
|
|
|
wd->ap.staPowerSaving = psStaCount;
|
|
|
|
return;
|
|
}
|
|
|
|
void zfApProtctionMonitor(zdev_t* dev)
|
|
{
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
/* 11b STA associated => nonErp, Protect */
|
|
if (wd->ap.bStaAssociated > 0)
|
|
{
|
|
/* Enable NonErp bit in information element */
|
|
wd->erpElement = ZM_WLAN_NON_ERP_PRESENT_BIT
|
|
| ZM_WLAN_USE_PROTECTION_BIT;
|
|
|
|
/* Enable protection mode */
|
|
zfApSetProtectionMode(dev, 1);
|
|
|
|
}
|
|
/* 11b STA not associated, protection OBSS present => Protect */
|
|
else if (wd->ap.protectedObss > 2) //Threshold
|
|
{
|
|
if (wd->disableSelfCts == 0)
|
|
{
|
|
/* Disable NonErp bit in information element */
|
|
wd->erpElement = ZM_WLAN_USE_PROTECTION_BIT;
|
|
|
|
/* Enable protection mode */
|
|
zfApSetProtectionMode(dev, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Disable NonErp bit in information element */
|
|
wd->erpElement = 0;
|
|
|
|
/* Disable protection mode */
|
|
zfApSetProtectionMode(dev, 0);
|
|
}
|
|
wd->ap.protectedObss = 0;
|
|
}
|
|
|
|
|
|
void zfApProcessBeacon(zdev_t* dev, zbuf_t* buf)
|
|
{
|
|
u16_t offset;
|
|
u8_t ch;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zm_msg0_mm(ZM_LV_3, "Rx beacon");
|
|
|
|
/* update Non-ERP flag(wd->ap.nonErpObss) */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) == 0xffff)
|
|
{
|
|
/* 11b OBSS */
|
|
wd->ap.protectedObss++;
|
|
return;
|
|
}
|
|
|
|
ch = zmw_rx_buf_readb(dev, buf, offset+2);
|
|
if ((ch & ZM_WLAN_USE_PROTECTION_BIT) == ZM_WLAN_USE_PROTECTION_BIT)
|
|
{
|
|
/* Protected OBSS */
|
|
wd->ap.protectedObss = 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfProcessAuth */
|
|
/* Process authenticate management frame. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* buf : auth frame buffer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* none */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.10 */
|
|
/* */
|
|
/************************************************************************/
|
|
/* Note : AP allows one authenticating STA at a time, does not */
|
|
/* support multiple authentication process. Make sure */
|
|
/* authentication state machine will not be blocked due */
|
|
/* to incompleted authentication handshake. */
|
|
void zfApProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
|
|
{
|
|
u16_t algo, seq, status;
|
|
u8_t authSharing;
|
|
u16_t ret;
|
|
u16_t i;
|
|
u8_t challengePassed = 0;
|
|
u8_t frameCtrl;
|
|
u32_t retAlgoSeq;
|
|
u32_t retStatus;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
|
|
frameCtrl = zmw_rx_buf_readb(dev, buf, 1);
|
|
/* AP : Auth share 3 */
|
|
/* shift for WEP IV */
|
|
if ((frameCtrl & 0x40) != 0)
|
|
{
|
|
algo = zmw_rx_buf_readh(dev, buf, 28);
|
|
seq = zmw_rx_buf_readh(dev, buf, 30);
|
|
status = zmw_rx_buf_readh(dev, buf, 32);
|
|
}
|
|
else
|
|
{
|
|
algo = zmw_rx_buf_readh(dev, buf, 24);
|
|
seq = zmw_rx_buf_readh(dev, buf, 26);
|
|
status = zmw_rx_buf_readh(dev, buf, 28);
|
|
}
|
|
|
|
zm_msg2_mm(ZM_LV_0, "Rx Auth, seq=", seq);
|
|
|
|
/* Set default to authentication algorithm not support */
|
|
retAlgoSeq = 0x20000 | algo;
|
|
retStatus = 13; /* authentication algorithm not support */
|
|
|
|
/* AP : Auth open 1 */
|
|
if (algo == 0)
|
|
{
|
|
if (wd->ap.authAlgo[apId] == 0)
|
|
{
|
|
retAlgoSeq = 0x20000;
|
|
if (seq == 1)
|
|
{
|
|
/* AP : update STA to auth */
|
|
if ((ret = zfApAddSta(dev, src, ZM_STATE_AUTH, apId, 0, 0, 0)) != 0xffff)
|
|
{
|
|
/* AP : call zfwAuthNotify() for host to judge */
|
|
//zfwAuthNotify(dev, src);
|
|
|
|
/* AP : response Auth seq=2, success */
|
|
retStatus = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
/* AP : response Auth seq=2, unspecific error */
|
|
retStatus = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* AP : response Auth seq=2, sequence number out of expected */
|
|
retStatus = 14;
|
|
}
|
|
}
|
|
}
|
|
/* AP : Auth share 1 */
|
|
else if (algo == 1)
|
|
{
|
|
if (wd->ap.authAlgo[apId] == 1)
|
|
{
|
|
if (seq == 1)
|
|
{
|
|
retAlgoSeq = 0x20001;
|
|
|
|
/* critical section */
|
|
zmw_enter_critical_section(dev);
|
|
if (wd->ap.authSharing == 1)
|
|
{
|
|
authSharing = 1;
|
|
}
|
|
else
|
|
{
|
|
authSharing = 0;
|
|
wd->ap.authSharing = 1;
|
|
}
|
|
/* end of critical section */
|
|
zmw_leave_critical_section(dev);
|
|
|
|
if (authSharing == 1)
|
|
{
|
|
/* AP : response Auth seq=2, status = fail */
|
|
retStatus = 1;
|
|
}
|
|
else
|
|
{
|
|
/* AP : update STA to preauth */
|
|
zfApAddSta(dev, src, ZM_STATE_PREAUTH, apId, 0, 0, 0);
|
|
|
|
/* AP : call zfwAuthNotify() for host to judge */
|
|
//zfwAuthNotify(dev, src);
|
|
|
|
/* AP : response Auth seq=2 */
|
|
retStatus = 0;
|
|
}
|
|
}
|
|
else if (seq == 3)
|
|
{
|
|
retAlgoSeq = 0x40001;
|
|
|
|
if (wd->ap.authSharing == 1)
|
|
{
|
|
/* check challenge text */
|
|
if (zmw_buf_readh(dev, buf, 30+4) == 0x8010)
|
|
{
|
|
for (i=0; i<128; i++)
|
|
{
|
|
if (wd->ap.challengeText[i]
|
|
!= zmw_buf_readb(dev, buf, 32+i+4))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == 128)
|
|
{
|
|
challengePassed = 1;
|
|
}
|
|
}
|
|
|
|
if (challengePassed == 1)
|
|
{
|
|
/* AP : update STA to auth */
|
|
zfApAddSta(dev, src, ZM_STATE_AUTH, apId, 0, 0, 0);
|
|
|
|
/* AP : response Auth seq=2 */
|
|
retStatus = 0;
|
|
}
|
|
else
|
|
{
|
|
/* AP : response Auth seq=2, challenge failure */
|
|
retStatus = 15;
|
|
|
|
/* TODO : delete STA */
|
|
}
|
|
|
|
wd->ap.authSharing = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retAlgoSeq = 0x40001;
|
|
retStatus = 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH, src, retAlgoSeq,
|
|
retStatus, apId);
|
|
return;
|
|
}
|
|
|
|
void zfApProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
|
|
{
|
|
u16_t aid = 0xffff;
|
|
u8_t frameType;
|
|
u16_t offset;
|
|
u8_t staType = 0;
|
|
u8_t qosType = 0;
|
|
u8_t qosInfo = 0;
|
|
u8_t tmp;
|
|
u16_t i, j, k;
|
|
u16_t encMode = 0;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
/* AP : check SSID */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) != 0xffff)
|
|
{
|
|
k = 0;
|
|
for (j = 0; j < wd->ap.vapNumber; j++)
|
|
{
|
|
if ((tmp = zmw_buf_readb(dev, buf, offset+1))
|
|
!= wd->ap.ssidLen[j])
|
|
{
|
|
k++;
|
|
}
|
|
}
|
|
if (k == wd->ap.vapNumber)
|
|
{
|
|
goto zlDeauth;
|
|
}
|
|
|
|
k = 0;
|
|
for (j = 0; j < wd->ap.vapNumber; j++)
|
|
{
|
|
for (i=0; i<wd->ap.ssidLen[j]; i++)
|
|
{
|
|
if ((tmp = zmw_buf_readb(dev, buf, offset+2+i))
|
|
!= wd->ap.ssid[j][i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == wd->ap.ssidLen[j])
|
|
{
|
|
apId = j;
|
|
}
|
|
else
|
|
{
|
|
k++;
|
|
}
|
|
}
|
|
if (k == wd->ap.vapNumber)
|
|
{
|
|
goto zlDeauth;
|
|
}
|
|
}
|
|
|
|
/* TODO : check capability */
|
|
|
|
/* AP : check support rate */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff)
|
|
{
|
|
/* 11g STA */
|
|
staType = 1;
|
|
}
|
|
//CWYang(+)
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff)
|
|
{
|
|
/* 11n STA */
|
|
staType = 2;
|
|
}
|
|
|
|
/* TODO : do not allow 11b STA to associated in Pure G mode */
|
|
if (wd->ap.wlanType[apId] == ZM_WLAN_TYPE_PURE_G && staType == 0)
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 3, 0, 0);
|
|
return;
|
|
}
|
|
|
|
/* In pure B mode, we set G STA into B mode */
|
|
if (wd->ap.wlanType[apId] == ZM_WLAN_TYPE_PURE_B && staType == 1)
|
|
{
|
|
staType = 0;
|
|
}
|
|
|
|
/* AP : check 11i and WPA */
|
|
/* AP : check 11h */
|
|
|
|
/* AP : check WME */
|
|
if ((offset = zfFindWifiElement(dev, buf, 2, 0)) != 0xffff)
|
|
{
|
|
/* WME STA */
|
|
qosType = 1;
|
|
zm_msg0_mm(ZM_LV_0, "WME STA");
|
|
|
|
if (wd->ap.uapsdEnabled != 0)
|
|
{
|
|
qosInfo = zmw_rx_buf_readb(dev, buf, offset+8);
|
|
}
|
|
}
|
|
|
|
if (wd->ap.wpaSupport[apId] == 1)
|
|
{
|
|
if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_WPA_IE)) != 0xffff )
|
|
{
|
|
/* get WPA IE */
|
|
u8_t length = zmw_rx_buf_readb(dev, buf, offset+1);
|
|
if (length+2 < ZM_MAX_WPAIE_SIZE)
|
|
{
|
|
zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2);
|
|
wd->ap.stawpaLen[apId] = length+2;
|
|
encMode = 1;
|
|
|
|
|
|
zm_msg1_mm(ZM_LV_0, "WPA Mode zfwAsocNotify, apId=", apId);
|
|
|
|
/* AP : Call zfwAsocNotify() */
|
|
if (wd->zfcbAsocNotify != NULL)
|
|
{
|
|
wd->zfcbAsocNotify(dev, src, wd->ap.stawpaIe[apId], wd->ap.stawpaLen[apId], apId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto zlDeauth;
|
|
}
|
|
}
|
|
else if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_RSN_IE)) != 0xffff )
|
|
{
|
|
/* get RSN IE */
|
|
u8_t length = zmw_rx_buf_readb(dev, buf, offset+1);
|
|
if (length+2 < ZM_MAX_WPAIE_SIZE)
|
|
{
|
|
zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2);
|
|
wd->ap.stawpaLen[apId] = length+2;
|
|
encMode = 1;
|
|
|
|
zm_msg1_mm(ZM_LV_0, "RSN Mode zfwAsocNotify, apId=", apId);
|
|
|
|
/* AP : Call zfwAsocNotify() */
|
|
if (wd->zfcbAsocNotify != NULL)
|
|
{
|
|
wd->zfcbAsocNotify(dev, src, wd->ap.stawpaIe[apId], wd->ap.stawpaLen[apId], apId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto zlDeauth;
|
|
}
|
|
}
|
|
#ifdef ZM_ENABLE_CENC
|
|
else if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CENC_IE)) != 0xffff )
|
|
{
|
|
/* get CENC IE */
|
|
u8_t length = zmw_rx_buf_readb(dev, buf, offset+1);
|
|
|
|
if (length+2 < ZM_MAX_WPAIE_SIZE)
|
|
{
|
|
zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2);
|
|
wd->ap.stawpaLen[apId] = length+2;
|
|
encMode = 1;
|
|
|
|
zm_msg1_mm(ZM_LV_0, "CENC Mode zfwAsocNotify, apId=", apId);
|
|
|
|
/* AP : Call zfwAsocNotify() */
|
|
if (wd->zfcbCencAsocNotify != NULL)
|
|
{
|
|
wd->zfcbCencAsocNotify(dev, src, wd->ap.stawpaIe[apId],
|
|
wd->ap.stawpaLen[apId], apId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto zlDeauth;
|
|
}
|
|
}
|
|
#endif //ZM_ENABLE_CENC
|
|
else
|
|
{ /* ap is encryption but sta has no wpa/rsn ie */
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0);
|
|
return;
|
|
}
|
|
}
|
|
/* sta has wpa/rsn ie but ap is no encryption */
|
|
if ((wd->ap.wpaSupport[apId] == 0) && (encMode == 1))
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0);
|
|
return;
|
|
}
|
|
|
|
/* AP : update STA to asoc */
|
|
aid = zfApAddSta(dev, src, ZM_STATE_ASOC, apId, staType, qosType, qosInfo);
|
|
|
|
zfApStoreAsocReqIe(dev, buf, aid);
|
|
|
|
zlDeauth:
|
|
/* AP : send asoc rsp2 */
|
|
if (aid != 0xffff)
|
|
{
|
|
frameType = zmw_rx_buf_readb(dev, buf, 0);
|
|
|
|
if (frameType == ZM_WLAN_FRAME_TYPE_ASOCREQ)
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCRSP, src, 0, aid+1, apId);
|
|
}
|
|
else
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_REASOCRSP, src, 0, aid+1, apId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* TODO : send deauthentication */
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void zfApStoreAsocReqIe(zdev_t* dev, zbuf_t* buf, u16_t aid)
|
|
{
|
|
//struct zsWlanAssoFrameHeader* pAssoFrame;
|
|
//u8_t pBuf[sizeof(struct zsWlanAssoFrameHeader)];
|
|
u16_t offset;
|
|
u32_t i;
|
|
u16_t length;
|
|
u8_t *htcap;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
for (i=0; i<wd->sta.asocRspFrameBodySize; i++)
|
|
{
|
|
wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24);
|
|
}
|
|
/* capability: 2 octets */
|
|
offset = 24;
|
|
|
|
/* Listen interval: 2 octets */
|
|
offset = 26;
|
|
|
|
/* SSID */
|
|
offset = 28;
|
|
|
|
/* supported rates */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SUPPORT_RATE)) == 0xffff)
|
|
return;
|
|
length = zmw_rx_buf_readb(dev, buf, offset + 1);
|
|
|
|
/* extended supported rates */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) == 0xffff)
|
|
return;
|
|
length = zmw_rx_buf_readb(dev, buf, offset + 1);
|
|
|
|
/* power capability:4 octets */
|
|
offset = offset + 2 + length;
|
|
|
|
/* supported channels: 4 octets */
|
|
offset = offset + 2 + 4;
|
|
|
|
/* RSN */
|
|
|
|
/* QoS */
|
|
|
|
/* HT capabilities: 28 octets */
|
|
if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) {
|
|
/* atheros pre n */
|
|
htcap = (u8_t *)&wd->ap.ie[aid].HtCap;
|
|
htcap[0] = zmw_rx_buf_readb(dev, buf, offset);
|
|
htcap[1] = 26;
|
|
for (i=1; i<=26; i++)
|
|
{
|
|
htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i);
|
|
zm_debug_msg2("ASOC: HT Capabilities, htcap=", htcap[i+1]);
|
|
}
|
|
return;
|
|
}
|
|
else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff) {
|
|
/* pre n 2.0 standard */
|
|
htcap = (u8_t *)&wd->ap.ie[aid].HtCap;
|
|
for (i=0; i<28; i++)
|
|
{
|
|
htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i);
|
|
zm_debug_msg2("ASOC: HT Capabilities, htcap=", htcap[i]);
|
|
}
|
|
}
|
|
else {
|
|
/* not 11n AP */
|
|
return;
|
|
}
|
|
|
|
|
|
/* supported regulatory classes */
|
|
offset = offset + length;
|
|
//length = zmw_rx_buf_readb(dev, buf, offset + 1);
|
|
{
|
|
u8_t *htcap;
|
|
htcap = (u8_t *)&wd->sta.ie.HtInfo;
|
|
//zm_debug_msg2("ASOC: HT Capabilities info=", ((u16_t *)htcap)[1]);
|
|
//zm_debug_msg2("ASOC: A-MPDU parameters=", htcap[4]);
|
|
//zm_debug_msg2("ASOC: Supported MCS set=", ((u32_t *)htcap)[1]>>8);
|
|
}
|
|
|
|
}
|
|
|
|
void zfApProcessAsocRsp(zdev_t* dev, zbuf_t* buf)
|
|
{
|
|
|
|
}
|
|
|
|
void zfApProcessDeauth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
|
|
{
|
|
u16_t aid;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
/* AP : if SA=associated STA then deauthenticate STA */
|
|
if ((aid = zfApFindSta(dev, src)) != 0xffff)
|
|
{
|
|
/* Clear STA table */
|
|
wd->ap.staTable[aid].valid = 0;
|
|
if (wd->zfcbDisAsocNotify != NULL)
|
|
{
|
|
wd->zfcbDisAsocNotify(dev, (u8_t*)src, apId);
|
|
}
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
}
|
|
|
|
void zfApProcessDisasoc(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId)
|
|
{
|
|
u16_t aid;
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
zmw_enter_critical_section(dev);
|
|
/* AP : if SA=associated STA then deauthenticate STA */
|
|
if ((aid = zfApFindSta(dev, src)) != 0xffff)
|
|
{
|
|
/* Clear STA table */
|
|
wd->ap.staTable[aid].valid = 0;
|
|
zmw_leave_critical_section(dev);
|
|
if (wd->zfcbDisAsocNotify != NULL)
|
|
{
|
|
wd->zfcbDisAsocNotify(dev, (u8_t*)src, apId);
|
|
}
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
}
|
|
|
|
|
|
void zfApProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo)
|
|
{
|
|
#if 0
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zm_msg0_mm(ZM_LV_0, "Rx probersp");
|
|
|
|
/* Gather scan result */
|
|
|
|
//zm_debug_msg1("bssList Count = ", wd->sta.bssList.bssCount);
|
|
/* return if not in scanning */
|
|
if ((wd->heartBeatNotification & ZM_BSSID_LIST_SCAN)
|
|
!= ZM_BSSID_LIST_SCAN)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//if ( wd->sta.pUpdateBssList->bssCount == ZM_MAX_BSS )
|
|
if ( wd->sta.bssList.bssCount == ZM_MAX_BSS )
|
|
{
|
|
return;
|
|
}
|
|
|
|
zfProcessProbeRsp(dev, buf, AddInfo);
|
|
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApAddIeSsid */
|
|
/* Add AP information element SSID to buffer. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* buf : buffer to add information element */
|
|
/* offset : add information element from this offset */
|
|
/* vap : virtual AP ID */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* buffer offset after adding information element */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.11 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap)
|
|
{
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
/* Element ID */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID);
|
|
|
|
/* Element Length */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.ssidLen[vap]);
|
|
|
|
/* Information : SSID */
|
|
for (i=0; i<wd->ap.ssidLen[vap]; i++)
|
|
{
|
|
zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.ssid[vap][i]);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApAddIeTim */
|
|
/* Add AP information element TIM to buffer. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* buf : buffer to add information element */
|
|
/* offset : add information element from this offset */
|
|
/* vap : virtual AP ID */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* buffer offset after adding information element */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.11 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApAddIeTim(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap)
|
|
{
|
|
u8_t uniBitMap[9];
|
|
u16_t highestByte;
|
|
u16_t i;
|
|
u16_t lenOffset;
|
|
u16_t id;
|
|
u16_t dst[3];
|
|
u16_t aid;
|
|
u16_t bitPosition;
|
|
u16_t bytePosition;
|
|
zbuf_t* psBuf;
|
|
zbuf_t* tmpBufArray[ZM_UNI_ARRAY_SIZE];
|
|
u16_t tmpBufArraySize = 0;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
/* Element ID */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_TIM);
|
|
|
|
/* offset of Element Length */
|
|
lenOffset = offset++;
|
|
|
|
/* Information : TIM */
|
|
/* DTIM count */
|
|
/* TODO : Doesn't work for Virtual AP's case */
|
|
wd->CurrentDtimCount++;
|
|
if (wd->CurrentDtimCount >= wd->dtim)
|
|
{
|
|
wd->CurrentDtimCount = 0;
|
|
}
|
|
zmw_tx_buf_writeb(dev, buf, offset++, wd->CurrentDtimCount);
|
|
/* DTIM period */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, wd->dtim);
|
|
/* bitmap offset */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0);
|
|
|
|
/* Update BCMC bit */
|
|
if (wd->CurrentDtimCount == 0)
|
|
{
|
|
zmw_enter_critical_section(dev);
|
|
wd->ap.timBcmcBit[vap] = (wd->ap.bcmcTail[vap]!=wd->ap.bcmcHead[vap])?1:0;
|
|
zmw_leave_critical_section(dev);
|
|
}
|
|
else
|
|
{
|
|
wd->ap.timBcmcBit[vap] = 0;
|
|
}
|
|
|
|
/* Update Unicast bitmap */
|
|
/* reset bit map */
|
|
for (i=0; i<9; i++)
|
|
{
|
|
uniBitMap[i] = 0;
|
|
}
|
|
highestByte = 0;
|
|
#if 1
|
|
|
|
zmw_enter_critical_section(dev);
|
|
|
|
id = wd->ap.uniHead;
|
|
while (id != wd->ap.uniTail)
|
|
{
|
|
psBuf = wd->ap.uniArray[id];
|
|
|
|
/* TODO : Aging PS frame after queuing for more than 10 seconds */
|
|
|
|
/* get destination STA's aid */
|
|
dst[0] = zmw_tx_buf_readh(dev, psBuf, 0);
|
|
dst[1] = zmw_tx_buf_readh(dev, psBuf, 2);
|
|
dst[2] = zmw_tx_buf_readh(dev, psBuf, 4);
|
|
if ((aid = zfApFindSta(dev, dst)) != 0xffff)
|
|
{
|
|
if (wd->ap.staTable[aid].psMode != 0)
|
|
{
|
|
zm_msg1_mm(ZM_LV_0, "aid=",aid);
|
|
aid++;
|
|
zm_assert(aid<=64);
|
|
bitPosition = (1 << (aid & 0x7));
|
|
bytePosition = (aid >> 3);
|
|
uniBitMap[bytePosition] |= bitPosition;
|
|
|
|
if (bytePosition>highestByte)
|
|
{
|
|
highestByte = bytePosition;
|
|
}
|
|
id = (id+1) & (ZM_UNI_ARRAY_SIZE-1);
|
|
}
|
|
else
|
|
{
|
|
zm_msg0_mm(ZM_LV_0, "Send PS frame which STA no longer in PS mode");
|
|
/* Send PS frame which STA no longer in PS mode */
|
|
zfApRemoveFromPsQueue(dev, id, dst);
|
|
tmpBufArray[tmpBufArraySize++] = psBuf;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zm_msg0_mm(ZM_LV_0, "Free garbage PS frame");
|
|
/* Free garbage PS frame */
|
|
zfApRemoveFromPsQueue(dev, id, dst);
|
|
zfwBufFree(dev, psBuf, 0);
|
|
}
|
|
}
|
|
|
|
zmw_leave_critical_section(dev);
|
|
#endif
|
|
|
|
zfQueueGenerateUapsdTim(dev, wd->ap.uapsdQ, uniBitMap, &highestByte);
|
|
|
|
zm_msg1_mm(ZM_LV_3, "bm=",uniBitMap[0]);
|
|
zm_msg1_mm(ZM_LV_3, "highestByte=",highestByte);
|
|
zm_msg1_mm(ZM_LV_3, "timBcmcBit[]=",wd->ap.timBcmcBit[vap]);
|
|
|
|
/* bitmap */
|
|
zmw_tx_buf_writeb(dev, buf, offset++,
|
|
uniBitMap[0] | wd->ap.timBcmcBit[vap]);
|
|
for (i=0; i<highestByte; i++)
|
|
{
|
|
zmw_tx_buf_writeb(dev, buf, offset++, uniBitMap[i+1]);
|
|
}
|
|
|
|
/* Element Length */
|
|
zmw_tx_buf_writeb(dev, buf, lenOffset, highestByte+4);
|
|
|
|
for (i=0; i<tmpBufArraySize; i++)
|
|
{
|
|
/* Put to VTXQ[ac] */
|
|
zfPutVtxq(dev, tmpBufArray[i]);
|
|
}
|
|
/* Push VTXQ[ac] */
|
|
zfPushVtxq(dev);
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApRemoveFromPsQueue */
|
|
/* Remove zbuf from PS queue. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* id : index in ps queue */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* more data bit */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen Atheros Communications, INC. 2007.1 */
|
|
/* */
|
|
/************************************************************************/
|
|
u8_t zfApRemoveFromPsQueue(zdev_t* dev, u16_t id, u16_t* addr)
|
|
{
|
|
u16_t dst[3];
|
|
u16_t nid;
|
|
u8_t moreData = 0;
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
wd->ap.uniTail = (wd->ap.uniTail-1) & (ZM_UNI_ARRAY_SIZE-1);
|
|
while (id != wd->ap.uniTail)
|
|
{
|
|
nid = (id + 1) & (ZM_UNI_ARRAY_SIZE - 1);
|
|
wd->ap.uniArray[id] = wd->ap.uniArray[nid];
|
|
|
|
/* Search until tail to config more data bit */
|
|
dst[0] = zmw_buf_readh(dev, wd->ap.uniArray[id], 0);
|
|
dst[1] = zmw_buf_readh(dev, wd->ap.uniArray[id], 2);
|
|
dst[2] = zmw_buf_readh(dev, wd->ap.uniArray[id], 4);
|
|
if ((addr[0] == dst[0]) && (addr[1] == dst[1])
|
|
&& (addr[2] == dst[2]))
|
|
{
|
|
moreData = 0x20;
|
|
}
|
|
|
|
id = nid;
|
|
}
|
|
return moreData;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApAddIeWmePara */
|
|
/* Add WME Parameter Element to buffer. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* buf : buffer to add information element */
|
|
/* offset : add information element from this offset */
|
|
/* vap : virtual AP ID */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* buffer offset after adding information element */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2006.1 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfApAddIeWmePara(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap)
|
|
{
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
/* Element ID */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WIFI_IE);
|
|
|
|
/* Element Length */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 24);
|
|
|
|
/* OUI */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x50);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0xF2);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x02);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x01);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x01);
|
|
|
|
/* QoS Info */
|
|
if (wd->ap.uapsdEnabled)
|
|
{
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x81);
|
|
}
|
|
else
|
|
{
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x01);
|
|
}
|
|
|
|
/* Reserved */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
|
|
/* Best Effort AC parameters */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x03);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0xA4);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
/* Backfround AC parameters */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x27);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0xA4);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
/* Video AC parameters */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x42);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x43);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x5E);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
/* Voice AC parameters */
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x62);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x32);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x2F);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0x00);
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApSendBeacon */
|
|
/* Sned AP mode beacon. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* none */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen ZyDAS Technology Corporation 2005.11 */
|
|
/* */
|
|
/************************************************************************/
|
|
void zfApSendBeacon(zdev_t* dev)
|
|
{
|
|
zbuf_t* buf;
|
|
u16_t offset;
|
|
u16_t vap;
|
|
u16_t seq;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
wd->ap.beaconCounter++;
|
|
if (wd->ap.beaconCounter >= wd->ap.vapNumber)
|
|
{
|
|
wd->ap.beaconCounter = 0;
|
|
}
|
|
vap = wd->ap.beaconCounter;
|
|
|
|
|
|
zm_msg1_mm(ZM_LV_2, "Send beacon, vap=", vap);
|
|
|
|
/* TBD : Maximum size of beacon */
|
|
if ((buf = zfwBufAllocate(dev, 1024)) == NULL)
|
|
{
|
|
zm_msg0_mm(ZM_LV_0, "Alloc beacon buf Fail!");
|
|
return;
|
|
}
|
|
|
|
offset = 0;
|
|
|
|
/* wlan header */
|
|
/* Frame control */
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0x0080);
|
|
offset+=2;
|
|
/* Duration */
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0x0000);
|
|
offset+=2;
|
|
/* Address 1 */
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
|
|
offset+=2;
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
|
|
offset+=2;
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0xffff);
|
|
offset+=2;
|
|
/* Address 2 */
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]);
|
|
offset+=2;
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]);
|
|
offset+=2;
|
|
#ifdef ZM_VAPMODE_MULTILE_SSID
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]); //Multiple SSID
|
|
#else
|
|
zmw_tx_buf_writeh(dev, buf, offset, (wd->macAddr[2]+(vap<<8))); //VAP
|
|
#endif
|
|
offset+=2;
|
|
/* Address 3 */
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]);
|
|
offset+=2;
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]);
|
|
offset+=2;
|
|
#ifdef ZM_VAPMODE_MULTILE_SSID
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]); //Multiple SSID
|
|
#else
|
|
zmw_tx_buf_writeh(dev, buf, offset, (wd->macAddr[2]+(vap<<8))); //VAP
|
|
#endif
|
|
offset+=2;
|
|
|
|
/* Sequence number */
|
|
zmw_enter_critical_section(dev);
|
|
seq = ((wd->mmseq++)<<4);
|
|
zmw_leave_critical_section(dev);
|
|
zmw_tx_buf_writeh(dev, buf, offset, seq);
|
|
offset+=2;
|
|
|
|
/* 24-31 Time Stamp : hardware will fill this field */
|
|
zmw_tx_buf_writeh(dev, buf, offset, 0);
|
|
zmw_tx_buf_writeh(dev, buf, offset+2, 0);
|
|
zmw_tx_buf_writeh(dev, buf, offset+4, 0);
|
|
zmw_tx_buf_writeh(dev, buf, offset+6, 0);
|
|
offset+=8;
|
|
|
|
/* Beacon Interval */
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->beaconInterval);
|
|
offset+=2;
|
|
|
|
/* Capability */
|
|
zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]);
|
|
offset+=2;
|
|
|
|
/* SSID */
|
|
if (wd->ap.hideSsid[vap] == 0)
|
|
{
|
|
offset = zfApAddIeSsid(dev, buf, offset, vap);
|
|
}
|
|
else
|
|
{
|
|
zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID);
|
|
zmw_tx_buf_writeb(dev, buf, offset++, 0);
|
|
|
|
}
|
|
|
|
/* Support Rate */
|
|
if ( wd->frequency < 3000 )
|
|
{
|
|
offset = zfMmAddIeSupportRate(dev, buf, offset,
|
|
ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK);
|
|
}
|
|
else
|
|
{
|
|
offset = zfMmAddIeSupportRate(dev, buf, offset,
|
|
ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM);
|
|
}
|
|
|
|
/* DS parameter set */
|
|
offset = zfMmAddIeDs(dev, buf, offset);
|
|
|
|
/* TIM */
|
|
offset = zfApAddIeTim(dev, buf, offset, vap);
|
|
|
|
/* If WLAN Type is not PURE B */
|
|
if (wd->ap.wlanType[vap] != ZM_WLAN_TYPE_PURE_B)
|
|
{
|
|
if ( wd->frequency < 3000 )
|
|
{
|
|
/* ERP Information */
|
|
offset = zfMmAddIeErp(dev, buf, offset);
|
|
|
|
/* Extended Supported Rates */
|
|
offset = zfMmAddIeSupportRate(dev, buf, offset,
|
|
ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM);
|
|
}
|
|
}
|
|
|
|
/* TODO : country information */
|
|
/* TODO : RSN */
|
|
if (wd->ap.wpaSupport[vap] == 1)
|
|
{
|
|
offset = zfMmAddIeWpa(dev, buf, offset, vap);
|
|
}
|
|
|
|
/* WME Parameters */
|
|
if (wd->ap.qosMode == 1)
|
|
{
|
|
offset = zfApAddIeWmePara(dev, buf, offset, vap);
|
|
}
|
|
|
|
/* HT Capabilities Info */
|
|
offset = zfMmAddHTCapability(dev, buf, offset);
|
|
|
|
/* Extended HT Capabilities Info */
|
|
offset = zfMmAddExtendedHTCapability(dev, buf, offset);
|
|
|
|
/* 1212 : write to beacon fifo */
|
|
/* 1221 : write to share memory */
|
|
zfHpSendBeacon(dev, buf, offset);
|
|
|
|
/* Free beacon buffer */
|
|
/* TODO: In order to fit the madwifi beacon architecture, we need to
|
|
free beacon buffer in the HAL layer.
|
|
*/
|
|
|
|
//zfwBufFree(dev, buf, 0);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfIntrabssForward */
|
|
/* Called to transmit intra-BSS frame from upper layer. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* buf : buffer pointer */
|
|
/* vap : virtual AP */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* 1 : unicast intras-BSS frame */
|
|
/* 0 : other frames */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen ZyDAS Technology Corporation 2005.11 */
|
|
/* */
|
|
/************************************************************************/
|
|
u16_t zfIntrabssForward(zdev_t* dev, zbuf_t* buf, u8_t srcVap)
|
|
{
|
|
u16_t err;
|
|
u16_t asocFlag = 0;
|
|
u16_t dst[3];
|
|
u16_t aid;
|
|
u16_t staState;
|
|
zbuf_t* txBuf;
|
|
u16_t len;
|
|
u16_t i;
|
|
u16_t temp;
|
|
u16_t ret;
|
|
u8_t vap = 0;
|
|
#ifdef ZM_ENABLE_NATIVE_WIFI
|
|
dst[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET);
|
|
dst[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2);
|
|
dst[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4);
|
|
#else
|
|
dst[0] = zmw_rx_buf_readh(dev, buf, 0);
|
|
dst[1] = zmw_rx_buf_readh(dev, buf, 2);
|
|
dst[2] = zmw_rx_buf_readh(dev, buf, 4);
|
|
#endif // ZM_ENABLE_NATIVE_WIFI
|
|
|
|
/* Do Intra-BSS forward(data copy) if necessary*/
|
|
if ((dst[0]&0x1) != 0x1)
|
|
{
|
|
aid = zfApGetSTAInfo(dev, dst, &staState, &vap);
|
|
if ((aid != 0xffff) && (staState == ZM_STATE_ASOC) && (srcVap == vap))
|
|
{
|
|
asocFlag = 1;
|
|
zm_msg0_rx(ZM_LV_2, "Intra-BSS forward : asoc STA");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
vap = srcVap;
|
|
zm_msg0_rx(ZM_LV_2, "Intra-BSS forward : BCorMC");
|
|
}
|
|
|
|
/* destination address = associated STA or BC/MC */
|
|
if ((asocFlag == 1) || ((dst[0]&0x1) == 0x1))
|
|
{
|
|
/* Allocate frame */
|
|
if ((txBuf = zfwBufAllocate(dev, ZM_RX_FRAME_SIZE))
|
|
== NULL)
|
|
{
|
|
zm_msg0_rx(ZM_LV_1, "Alloc intra-bss buf Fail!");
|
|
goto zlAllocError;
|
|
}
|
|
|
|
/* Copy frame */
|
|
len = zfwBufGetSize(dev, buf);
|
|
for (i=0; i<len; i+=2)
|
|
{
|
|
temp = zmw_rx_buf_readh(dev, buf, i);
|
|
zmw_tx_buf_writeh(dev, txBuf, i, temp);
|
|
}
|
|
zfwBufSetSize(dev, txBuf, len);
|
|
|
|
#ifdef ZM_ENABLE_NATIVE_WIFI
|
|
/* Tx-A2 = Rx-A1, Tx-A3 = Rx-A2, Tx-A1 = Rx-A3 */
|
|
for (i=0; i<6; i+=2)
|
|
{
|
|
temp = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+i);
|
|
zmw_tx_buf_writeh(dev, txBuf, ZM_WLAN_HEADER_A2_OFFSET+i, temp);
|
|
temp = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+i);
|
|
zmw_tx_buf_writeh(dev, txBuf, ZM_WLAN_HEADER_A3_OFFSET+i, temp);
|
|
temp = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+i);
|
|
zmw_tx_buf_writeh(dev, txBuf, ZM_WLAN_HEADER_A1_OFFSET+i, temp);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Transmit frame */
|
|
/* Return error if port is disabled */
|
|
if ((err = zfTxPortControl(dev, txBuf, vap)) == ZM_PORT_DISABLED)
|
|
{
|
|
err = ZM_ERR_TX_PORT_DISABLED;
|
|
goto zlTxError;
|
|
}
|
|
|
|
#if 1
|
|
/* AP : Buffer frame for power saving STA */
|
|
if ((ret = zfApBufferPsFrame(dev, txBuf, vap)) == 0)
|
|
{
|
|
/* forward frame if not been buffered */
|
|
#if 1
|
|
/* Put to VTXQ[ac] */
|
|
ret = zfPutVtxq(dev, txBuf);
|
|
/* Push VTXQ[ac] */
|
|
zfPushVtxq(dev);
|
|
#else
|
|
zfTxSendEth(dev, txBuf, vap, ZM_INTERNAL_ALLOC_BUF, 0);
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
}
|
|
return asocFlag;
|
|
|
|
zlTxError:
|
|
zfwBufFree(dev, txBuf, 0);
|
|
zlAllocError:
|
|
return asocFlag;
|
|
}
|
|
|
|
struct zsMicVar* zfApGetRxMicKey(zdev_t* dev, zbuf_t* buf)
|
|
{
|
|
u8_t sa[6];
|
|
u16_t id = 0, macAddr[3];
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zfCopyFromRxBuffer(dev, buf, sa, ZM_WLAN_HEADER_A2_OFFSET, 6);
|
|
|
|
macAddr[0] = sa[0] + (sa[1] << 8);
|
|
macAddr[1] = sa[2] + (sa[3] << 8);
|
|
macAddr[2] = sa[4] + (sa[5] << 8);
|
|
|
|
if ((id = zfApFindSta(dev, macAddr)) != 0xffff)
|
|
return (&wd->ap.staTable[id].rxMicKey);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct zsMicVar* zfApGetTxMicKey(zdev_t* dev, zbuf_t* buf, u8_t* qosType)
|
|
{
|
|
u8_t da[6];
|
|
u16_t id = 0, macAddr[3];
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zfCopyFromIntTxBuffer(dev, buf, da, 0, 6);
|
|
|
|
macAddr[0] = da[0] + (da[1] << 8);
|
|
macAddr[1] = da[2] + (da[3] << 8);
|
|
macAddr[2] = da[4] + (da[5] << 8);
|
|
|
|
if ((macAddr[0] & 0x1))
|
|
{
|
|
return (&wd->ap.bcMicKey[0]);
|
|
}
|
|
else if ((id = zfApFindSta(dev, macAddr)) != 0xffff)
|
|
{
|
|
*qosType = wd->ap.staTable[id].qosType;
|
|
return (&wd->ap.staTable[id].txMicKey);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
u16_t zfApUpdatePsBit(zdev_t* dev, zbuf_t* buf, u8_t* vap, u8_t* uapsdTrig)
|
|
{
|
|
u16_t staState;
|
|
u16_t aid;
|
|
u16_t psBit;
|
|
u16_t src[3];
|
|
u16_t dst[1];
|
|
u16_t i;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
src[0] = zmw_rx_buf_readh(dev, buf, 10);
|
|
src[1] = zmw_rx_buf_readh(dev, buf, 12);
|
|
src[2] = zmw_rx_buf_readh(dev, buf, 14);
|
|
|
|
if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3)
|
|
{
|
|
/* AP */
|
|
dst[0] = zmw_rx_buf_readh(dev, buf, 4);
|
|
|
|
psBit = (zmw_rx_buf_readb(dev, buf, 1) & 0x10) >> 4;
|
|
/* Get AID and update STA PS mode */
|
|
aid = zfApGetSTAInfoAndUpdatePs(dev, src, &staState, vap, psBit, uapsdTrig);
|
|
|
|
/* if STA not associated, send deauth */
|
|
if ((aid == 0xffff) || (staState != ZM_STATE_ASOC))
|
|
{
|
|
if ((dst[0]&0x1)==0)
|
|
{
|
|
zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 0x7,
|
|
0, 0);
|
|
}
|
|
|
|
return ZM_ERR_STA_NOT_ASSOCIATED;
|
|
}
|
|
} /* if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3) */
|
|
else
|
|
{
|
|
/* WDS */
|
|
for (i=0; i<ZM_MAX_WDS_SUPPORT; i++)
|
|
{
|
|
if ((wd->ap.wds.wdsBitmap & (1<<i)) != 0)
|
|
{
|
|
if ((src[0] == wd->ap.wds.macAddr[i][0])
|
|
&& (src[1] == wd->ap.wds.macAddr[i][1])
|
|
&& (src[2] == wd->ap.wds.macAddr[i][2]))
|
|
{
|
|
*vap = 0x20 + i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ZM_SUCCESS;
|
|
}
|
|
|
|
void zfApProcessPsPoll(zdev_t* dev, zbuf_t* buf)
|
|
{
|
|
u16_t src[3];
|
|
u16_t dst[3];
|
|
zbuf_t* psBuf = NULL;
|
|
u16_t id;
|
|
u8_t moreData = 0;
|
|
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
zmw_declare_for_critical_section();
|
|
|
|
src[0] = zmw_tx_buf_readh(dev, buf, 10);
|
|
src[1] = zmw_tx_buf_readh(dev, buf, 12);
|
|
src[2] = zmw_tx_buf_readh(dev, buf, 14);
|
|
|
|
/* Find ps buffer for PsPoll */
|
|
zmw_enter_critical_section(dev);
|
|
id = wd->ap.uniHead;
|
|
while (id != wd->ap.uniTail)
|
|
{
|
|
psBuf = wd->ap.uniArray[id];
|
|
|
|
dst[0] = zmw_tx_buf_readh(dev, psBuf, 0);
|
|
dst[1] = zmw_tx_buf_readh(dev, psBuf, 2);
|
|
dst[2] = zmw_tx_buf_readh(dev, psBuf, 4);
|
|
|
|
if ((src[0] == dst[0]) && (src[1] == dst[1]) && (src[2] == dst[2]))
|
|
{
|
|
moreData = zfApRemoveFromPsQueue(dev, id, src);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
psBuf = NULL;
|
|
}
|
|
id = (id + 1) & (ZM_UNI_ARRAY_SIZE - 1);
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
|
|
/* Send ps buffer */
|
|
if (psBuf != NULL)
|
|
{
|
|
/* Send with more data bit */
|
|
zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, moreData);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void zfApSetProtectionMode(zdev_t* dev, u16_t mode)
|
|
{
|
|
zmw_get_wlan_dev(dev);
|
|
|
|
if (mode == 0)
|
|
{
|
|
if (wd->ap.protectionMode != mode)
|
|
{
|
|
/* Write MAC&PHY registers to disable protection */
|
|
|
|
wd->ap.protectionMode = mode;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (wd->ap.protectionMode != mode)
|
|
{
|
|
/* Write MAC&PHY registers to enable protection */
|
|
|
|
wd->ap.protectionMode = mode;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FUNCTION DESCRIPTION zfApSendFailure */
|
|
/* Send failure. */
|
|
/* */
|
|
/* INPUTS */
|
|
/* dev : device pointer */
|
|
/* addr : receiver address */
|
|
/* */
|
|
/* OUTPUTS */
|
|
/* None */
|
|
/* */
|
|
/* AUTHOR */
|
|
/* Stephen Chen Atheros Communications, INC. 2007.1 */
|
|
/* */
|
|
/************************************************************************/
|
|
void zfApSendFailure(zdev_t* dev, u8_t* addr)
|
|
{
|
|
u16_t id;
|
|
u16_t staAddr[3];
|
|
zmw_get_wlan_dev(dev);
|
|
zmw_declare_for_critical_section();
|
|
|
|
staAddr[0] = addr[0] + (((u16_t)addr[1])<<8);
|
|
staAddr[1] = addr[2] + (((u16_t)addr[3])<<8);
|
|
staAddr[2] = addr[4] + (((u16_t)addr[5])<<8);
|
|
zmw_enter_critical_section(dev);
|
|
if ((id = zfApFindSta(dev, staAddr)) != 0xffff)
|
|
{
|
|
/* Send failture : Add 3 minutes to inactive time that will */
|
|
/* will make STA been kicked out soon */
|
|
wd->ap.staTable[id].time -= (3*ZM_TICK_PER_MINUTE);
|
|
}
|
|
zmw_leave_critical_section(dev);
|
|
}
|
|
|
|
|
|
void zfApProcessAction(zdev_t* dev, zbuf_t* buf)
|
|
{
|
|
u8_t category;
|
|
|
|
//zmw_get_wlan_dev(dev);
|
|
|
|
//zmw_declare_for_critical_section();
|
|
|
|
category = zmw_rx_buf_readb(dev, buf, 24);
|
|
|
|
switch (category)
|
|
{
|
|
case ZM_WLAN_BLOCK_ACK_ACTION_FRAME:
|
|
zfAggBlockAckActionFrame(dev, buf);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|