From 4bd43f507c7e2f225f58235226a8381fd6bbff1a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Oct 2008 22:44:22 -0700 Subject: Staging: add otus Atheros wireless network driver 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/otus/80211core/cmmap.c | 2402 ++++++++++++++++++++++++++++++++ 1 file changed, 2402 insertions(+) create mode 100644 drivers/staging/otus/80211core/cmmap.c (limited to 'drivers/staging/otus/80211core/cmmap.c') diff --git a/drivers/staging/otus/80211core/cmmap.c b/drivers/staging/otus/80211core/cmmap.c new file mode 100644 index 000000000000..7f09fded459e --- /dev/null +++ b/drivers/staging/otus/80211core/cmmap.c @@ -0,0 +1,2402 @@ +/* + * 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; iap.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; iap.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; vapap.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; iap.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; iap.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; iap.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; ista.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; iap.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; iap.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; iap.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; iap.wds.wdsBitmap & (1<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; +} -- cgit v1.2.3-59-g8ed1b