aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/otus/80211core/cmmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/otus/80211core/cmmap.c')
-rw-r--r--drivers/staging/otus/80211core/cmmap.c2402
1 files changed, 2402 insertions, 0 deletions
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; 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;
+}