diff options
author | merge <null@invalid> | 2009-01-22 13:55:32 +0000 |
---|---|---|
committer | Andy Green <agreen@octopus.localdomain> | 2009-01-22 13:55:32 +0000 |
commit | aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 (patch) | |
tree | fbb786d0ac6f8a774fd834e9ce951197e60fbffa /drivers/staging/otus/80211core/cmm.c | |
parent | f2d78193eae5dccd3d588d2c8ea0866efc368332 (diff) |
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141
pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040
stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch
mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage:
From: Andy Green <andy@openmoko.com>
fix-stray-endmenu.patch
Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/staging/otus/80211core/cmm.c')
-rw-r--r-- | drivers/staging/otus/80211core/cmm.c | 2141 |
1 files changed, 2141 insertions, 0 deletions
diff --git a/drivers/staging/otus/80211core/cmm.c b/drivers/staging/otus/80211core/cmm.c new file mode 100644 index 00000000000..b74379d928f --- /dev/null +++ b/drivers/staging/otus/80211core/cmm.c @@ -0,0 +1,2141 @@ +/* + * 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 management */ +/* frame. */ +/* */ +/* NOTES */ +/* None */ +/* */ +/************************************************************************/ +#include "cprecomp.h" +#include "../hal/hpreg.h" + +/* TODO : put all constant tables to a file */ +const u8_t zg11bRateTbl[4] = {2, 4, 11, 22}; +const u8_t zg11gRateTbl[8] = {12, 18, 24, 36, 48, 72, 96, 108}; + +/* 0xff => element does not exist */ +const u8_t zgElementOffsetTable[] = +{ + 4, /* 0 : asoc req */ + 6, /* 1 : asoc rsp */ + 10, /* 2 : reasoc req*/ + 6, /* 3 : reasoc rsp */ + 0, /* 4 : probe req */ + 12, /* 5 : probe rsp */ + 0xff, /* 6 : reserved */ + 0xff, /* 7 : reserved */ + 12, /* 8 : beacon */ + 4, /* 9 : ATIM */ + 0xff, /* 10 : disasoc */ + 6, /* 11 : auth */ + 0xff, /* 12 : deauth */ + 4, /* 13 : action */ + 0xff, /* 14 : reserved */ + 0xff, /* 15 : reserved */ +}; + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfFindElement */ +/* Find a specific element in management frame */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : management frame buffer */ +/* eid : target element id */ +/* */ +/* OUTPUTS */ +/* byte offset of target element */ +/* or 0xffff if not found */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +u16_t zfFindElement(zdev_t* dev, zbuf_t* buf, u8_t eid) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id, HTEid=0; + u8_t oui[4] = {0x00, 0x50, 0xf2, 0x01}; + u8_t oui11n[3] = {0x00,0x90,0x4C}; + u8_t HTType = 0; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + // jhlee HT 0 + + if ((eid == ZM_WLAN_EID_HT_CAPABILITY) || + (eid == ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) + { + HTEid = eid; + eid = ZM_WLAN_EID_WPA_IE; + HTType = 1; + } + + + bufLen = zfwBufGetSize(dev, buf); + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == eid) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 && eid != ZM_WLAN_EID_SSID) + { + /* Element length error */ + return 0xffff; + } + + if ( eid == ZM_WLAN_EID_WPA_IE ) + { + /* avoid sta to be thought use 11n when find a WPA_IE */ + if ( (HTType == 0) && zfRxBufferEqualToStr(dev, buf, oui, offset+2, 4) ) + { + return offset; + } + + // jhlee HT 0 + // CWYang(+) + + if ((HTType == 1) && ( zfRxBufferEqualToStr(dev, buf, oui11n, offset+2, 3) )) + { + if ( zmw_rx_buf_readb(dev, buf, offset+5) == HTEid ) + { + return offset + 5; + } + } + + } + else + { + return offset; + } + } + /* Advance to next element */ + #if 1 + elen = zmw_rx_buf_readb(dev, buf, offset+1); + #else + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + #endif + + offset += (elen+2); + } + return 0xffff; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfFindWifiElement */ +/* Find a specific Wifi element in management frame */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : management frame buffer */ +/* type : OUI type */ +/* subType : OUI subtype */ +/* */ +/* OUTPUTS */ +/* byte offset of target element */ +/* or 0xffff if not found */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2006.1 */ +/* */ +/************************************************************************/ +u16_t zfFindWifiElement(zdev_t* dev, zbuf_t* buf, u8_t type, u8_t subtype) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_WIFI_IE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x50) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0xF2) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+5)) == type)) + + { + if ( subtype != 0xff ) + { + if ( (tmp = zmw_rx_buf_readb(dev, buf, offset+6)) == subtype ) + { + return offset; + } + } + else + { + return offset; + } + } + } + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + offset += (elen+2); + } + return 0xffff; +} + +u16_t zfRemoveElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t eid) +{ + u16_t offset = 0; + u16_t elen; + u8_t HTEid = 0; + u8_t oui[4] = {0x00, 0x50, 0xf2, 0x01}; + u8_t oui11n[3] = {0x00,0x90,0x4C}; + u8_t HTType = 0; + + if ((eid == ZM_WLAN_EID_HT_CAPABILITY) || + (eid == ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) + { + HTEid = eid; + eid = ZM_WLAN_EID_WPA_IE; + HTType = 1; + } + + while (offset < size) + { + elen = *(buf+offset+1); + + if (*(buf+offset) == eid) + { + if ( eid == ZM_WLAN_EID_WPA_IE ) + { + if ( (HTType == 0) + && (*(buf+offset+2) == oui[0]) + && (*(buf+offset+3) == oui[1]) + && (*(buf+offset+4) == oui[2]) + && (*(buf+offset+5) == oui[3]) ) + { + zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); + return (size-elen-2); + } + + if ( (HTType == 1) + && (*(buf+offset+2) == oui11n[0]) + && (*(buf+offset+3) == oui11n[1]) + && (*(buf+offset+4) == oui11n[2]) + && (*(buf+offset+5) == HTEid) ) + { + zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); + return (size-elen-2); + } + } + else + { + zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); + return (size-elen-2); + } + } + + offset += (elen+2); + } + + return size; +} + +u16_t zfUpdateElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t* updateeid) +{ + u16_t offset = 0; + u16_t elen; + + while (offset < size) { + elen = *(buf+offset+1); + + if (*(buf+offset) == updateeid[0]) { + if (updateeid[1] <= elen) { + zfMemoryMove(buf+offset, updateeid, updateeid[1]+2); + zfMemoryMove(buf+offset+updateeid[1]+2, buf+offset+elen+2, size-offset-elen-2); + + return size-(elen-updateeid[1]); + } else { + zfMemoryMove(buf+offset+updateeid[1]+2, buf+offset+elen+2, size-offset-elen-2); + zfMemoryMove(buf+offset, updateeid, updateeid[1]+2); + + return size+(updateeid[1]-elen); + } + } + + offset += (elen+2); + } + + return size; +} + +u16_t zfFindSuperGElement(zdev_t* dev, zbuf_t* buf, u8_t type) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t super_feature; + u8_t ouiSuperG[6] = {0x00,0x03,0x7f,0x01, 0x01, 0x00}; + + zmw_get_wlan_dev(dev); + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_VENDOR_PRIVATE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (zfRxBufferEqualToStr(dev, buf, ouiSuperG, offset+2, 6) && ( zmw_rx_buf_readb(dev, buf, offset+1) >= 6)) + { + /* super_feature 0:useFastFrame, 1:useCompression, 2:useTurboPrime */ + super_feature= zmw_rx_buf_readb(dev, buf, offset+8); + if ((super_feature & 0x01) || (super_feature & 0x02) || (super_feature & 0x04)) + { + return offset; + } + } + } + /* Advance to next element */ + #if 1 + elen = zmw_rx_buf_readb(dev, buf, offset+1); + #else + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + #endif + + offset += (elen+2); + } + return 0xffff; +} + +u16_t zfFindXRElement(zdev_t* dev, zbuf_t* buf, u8_t type) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t ouixr[6] = {0x00,0x03,0x7f,0x03, 0x01, 0x00}; + + zmw_get_wlan_dev(dev); + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_VENDOR_PRIVATE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (zfRxBufferEqualToStr(dev, buf, ouixr, offset+2, 6) && ( zmw_rx_buf_readb(dev, buf, offset+1) >= 6)) + { + return offset; + } + } + /* Advance to next element */ + #if 1 + elen = zmw_rx_buf_readb(dev, buf, offset+1); + #else + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + #endif + + offset += (elen+2); + } + return 0xffff; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddIeSupportRate */ +/* Add information element Support Rate to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* eid : element ID */ +/* rateSet : CCK or OFDM */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +u16_t zfMmAddIeSupportRate(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t eid, u8_t rateSet) +{ + u8_t len = 0; + u16_t i; + + zmw_get_wlan_dev(dev); + + //if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) + //{ + // return offset; + //} + + /* Information : Support Rate */ + if ( rateSet == ZM_RATE_SET_CCK ) + { + for (i=0; i<4; i++) + { + if ((wd->bRate & (0x1<<i)) == (0x1<<i)) + //if ((0xf & (0x1<<i)) == (0x1<<i)) + { + zmw_tx_buf_writeb(dev, buf, offset+len+2, + zg11bRateTbl[i]+((wd->bRateBasic & (0x1<<i))<<(7-i))); + len++; + } + } + } + else if ( rateSet == ZM_RATE_SET_OFDM ) + { + for (i=0; i<8; i++) + { + if ((wd->gRate & (0x1<<i)) == (0x1<<i)) + //if ((0xff & (0x1<<i)) == (0x1<<i)) + { + zmw_tx_buf_writeb(dev, buf, offset+len+2, + zg11gRateTbl[i]+((wd->gRateBasic & (0x1<<i))<<(7-i))); + len++; + } + } + } + + if (len > 0) + { + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset, eid); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset+1, len); + + /* Return value */ + offset += (2+len); + } + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddIeDs */ +/* Add information element DS to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +u16_t zfMmAddIeDs(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + zmw_get_wlan_dev(dev); + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_DS); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, 1); + + /* Information : DS */ + zmw_tx_buf_writeb(dev, buf, offset++, + zfChFreqToNum(wd->frequency, NULL)); + + return offset; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddIeErp */ +/* Add information element ERP to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +u16_t zfMmAddIeErp(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + zmw_get_wlan_dev(dev); + + /* Element ID */ + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_ERP); + + /* Element Length */ + zmw_tx_buf_writeb(dev, buf, offset++, 1); + + /* Information : ERP */ + zmw_tx_buf_writeb(dev, buf, offset++, wd->erpElement); + + return offset; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddIeWpa */ +/* Add information element WPA to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Yuan-Gu Wei ZyDAS Technology Corporation 2006.2 */ +/* */ +/************************************************************************/ +u16_t zfMmAddIeWpa(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t apId) +{ + //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); + int i; + + zmw_get_wlan_dev(dev); + + /* Element ID */ + //zmw_inttx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); + + /* Element Length */ + //zmw_inttx_buf_writeb(dev, buf, offset++, wd->ap.wpaLen); + for(i = 0; i < wd->ap.wpaLen[apId]; i++) + { + /* Information : WPA */ + zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.wpaIe[apId][i]); + } + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddHTCapability */ +/* Add HT Capability Infomation to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Chao-Wen Yang ZyDAS Technology Corporation 2006.06 */ +/* */ +/************************************************************************/ +u16_t zfMmAddHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + u8_t OUI[3] = {0x0,0x90,0x4C}; + u16_t i; + + zmw_get_wlan_dev(dev); + + /* Prob ID */ + zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); + + if ( wd->wlanMode == ZM_MODE_AP ) + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.Length + 4); + + /* OUI Data */ + for (i = 0; i < 3; i++) + { + zmw_buf_writeb(dev, buf, offset++, OUI[i]); + } + + /* Element Type ID */ + zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.ElementID); + + /* HT Capability Data */ + for (i = 0; i < 26; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Byte[i+2]); + } + } + else + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.Length + 4); + + /* OUI Data */ + for (i = 0; i < 3; i++) + { + zmw_buf_writeb(dev, buf, offset++, OUI[i]); + } + + /* Element Type ID */ + zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.ElementID); + + /* HT Capability Data */ + for (i = 0; i < 26; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Byte[i+2]); + } + } + + return offset; +} + + +u16_t zfMmAddPreNHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + //u8_t OUI[3] = {0x0,0x90,0x4C}; + u16_t i; + + zmw_get_wlan_dev(dev); + + /* Prob ID */ + zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_PREN2_EID_HTCAPABILITY); + + if ( wd->wlanMode == ZM_MODE_AP ) + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.Length); + + /* HT Capability Data */ + for (i = 0; i < 26; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Byte[i+2]); + } + } + else + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.Length); + + /* HT Capability Data */ + for (i = 0; i < 26; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Byte[i+2]); + } + } + + return offset; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfMmAddExtendedHTCapability */ +/* Add Extended HT Capability Infomation to buffer. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : buffer to add information element */ +/* offset : add information element from this offset */ +/* */ +/* OUTPUTS */ +/* buffer offset after adding information element */ +/* */ +/* AUTHOR */ +/* Chao-Wen Yang ZyDAS Technology Corporation 2006.06 */ +/* */ +/************************************************************************/ +u16_t zfMmAddExtendedHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) +{ + u8_t OUI[3] = {0x0,0x90,0x4C}; + u16_t i; + + zmw_get_wlan_dev(dev); + + /* Prob ID */ + zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); + + if ( wd->wlanMode == ZM_MODE_AP ) + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Data.Length + 4); + + /* OUI Data */ + for (i = 0; i < 3; i++) + { + zmw_buf_writeb(dev, buf, offset++, OUI[i]); + } + + /* Element Type ID */ + zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Data.ElementID); + + /* HT Capability Data */ + for (i = 0; i < 22; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Byte[i+2]); + } + } + else + { + /* Element Length */ + zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Data.Length + 4); + + /* OUI Data */ + for (i = 0; i < 3; i++) + { + zmw_buf_writeb(dev, buf, offset++, OUI[i]); + } + + /* Element Type ID */ + zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Data.ElementID); + + /* HT Capability Data */ + for (i = 0; i < 22; i++) + { + zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Byte[i+2]); + } + } + + return offset; +} + + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfSendMmFrame */ +/* Send management frame. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* frameType : management frame type */ +/* dst : destination MAC address */ +/* p1 : parameter 1 */ +/* p2 : parameter 2 */ +/* p3 : parameter 3 */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +/* probe req : p1=> bWithSSID, p2=>R, p3=>R */ +/* probe rsp : p1=>R, p2=>R, p3=>VAP ID(AP) */ +/* deauth : p1=>Reason Code, p2=>R, p3=>VAP ID(AP) */ +/* Disasoc : p1=>Reason Code, p2=>R, p3=>VAP ID(AP) */ +/* ATIM : p1=>R, p2=>R, p3=>R */ +/* (re)asoc rsp : p1=>Status Code, p2=>AID, p3=>VAP ID(AP) */ +/* asoc req : p1=>R, p2=>R, p3=>R */ +/* reasoc req : p1=>AP MAC[0], p2=>AP MAC[1], p3=>AP MAC[2] */ +/* auth : p1=>low=Algorithm, high=Transaction, p2=>Status, p3=>VAP ID */ +void zfSendMmFrame(zdev_t* dev, u8_t frameType, u16_t* dst, + u32_t p1, u32_t p2, u32_t p3) +{ + zbuf_t* buf; + //u16_t addrTblSize; + //struct zsAddrTbl addrTbl; + u16_t offset = 0; + u16_t hlen = 32; + u16_t header[(24+25+1)/2]; + u16_t vap = 0; + u16_t i; + u8_t encrypt = 0; + u16_t aid; + + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + zm_msg2_mm(ZM_LV_2, "Send mm frame, type=", frameType); + /* TBD : Maximum size of managment frame */ + if ((buf = zfwBufAllocate(dev, 1024)) == NULL) + { + zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); + return; + } + + //Reserve room for wlan header + offset = hlen; + + switch (frameType) + { + case ZM_WLAN_FRAME_TYPE_PROBEREQ : + offset = zfSendProbeReq(dev, buf, offset, (u8_t) p1); + break; + + case ZM_WLAN_FRAME_TYPE_PROBERSP : + zm_msg0_mm(ZM_LV_3, "probe rsp"); + /* 24-31 Time Stamp : hardware WON'T 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; + + if (wd->wlanMode == ZM_MODE_AP) + { + vap = (u16_t) p3; + /* Capability */ + zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]); + offset+=2; + /* SSID */ + offset = zfApAddIeSsid(dev, buf, offset, vap); + } + else + { + /* Capability */ + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]); + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]); + /* SSID */ + offset = zfStaAddIeSsid(dev, buf, offset); + } + + /* 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); + + /* TODO ĄG IBSS */ + if ( wd->wlanMode == ZM_MODE_IBSS ) + { + offset = zfStaAddIeIbss(dev, buf, offset); + + if (wd->frequency < 3000) + { + if( wd->wfc.bIbssGMode + && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode . + { + /* ERP Information */ + wd->erpElement = 0; + offset = zfMmAddIeErp(dev, buf, offset); + + /* Enable G Mode */ + /* Extended Supported Rates */ + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + } + } + + + if ((wd->wlanMode == ZM_MODE_AP) + && (wd->ap.wlanType[vap] != ZM_WLAN_TYPE_PURE_B)) + { + /* ERP Information */ + offset = zfMmAddIeErp(dev, buf, offset); + + /* Extended Supported Rates */ + if ( wd->frequency < 3000 ) + { + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + } + + /* 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 : RSN */ + if (wd->wlanMode == ZM_MODE_AP && wd->ap.wpaSupport[vap] == 1) + { + offset = zfMmAddIeWpa(dev, buf, offset, vap); + } + else if ( wd->wlanMode == ZM_MODE_IBSS && wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK) + { + offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH); + } + + /* WME Parameters */ + if (wd->wlanMode == ZM_MODE_AP) + { + if (wd->ap.qosMode == 1) + { + offset = zfApAddIeWmePara(dev, buf, offset, vap); + } + } + + if ( wd->wlanMode != ZM_MODE_IBSS ) + { + // jhlee HT 0 + //CWYang(+) + /* TODO : Need to check if it is ok */ + /* HT Capabilities Info */ + offset = zfMmAddHTCapability(dev, buf, offset); + //CWYang(+) + /* Extended HT Capabilities Info */ + offset = zfMmAddExtendedHTCapability(dev, buf, offset); + } + + if ( wd->sta.ibssAdditionalIESize ) + offset = zfStaAddIbssAdditionalIE(dev, buf, offset); + break; + + case ZM_WLAN_FRAME_TYPE_AUTH : + if (p1 == 0x30001) + { + hlen += 4; + offset += 4; // for reserving wep header + encrypt = 1; + } + + /* Algotrithm Number */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1&0xffff)); + offset+=2; + + /* Transaction Number */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1>>16)); + offset+=2; + + /* Status Code */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p2); + offset+=2; + + if (wd->wlanMode == ZM_MODE_AP) + { + vap = (u16_t) p3; + } + + /* Challenge Text => share-2 or share-3 */ + if (p1 == 0x20001) + { + if (p2 == 0) //Status == success + { + zmw_buf_writeh(dev, buf, offset, 0x8010); + offset+=2; + /* share-2 : AP generate challenge text */ + for (i=0; i<128; i++) + { + wd->ap.challengeText[i] = (u8_t)zfGetRandomNumber(dev, 0); + } + zfCopyToIntTxBuffer(dev, buf, wd->ap.challengeText, offset, 128); + offset += 128; + } + } + else if (p1 == 0x30001) + { + /* share-3 : STA return challenge Text */ + zfCopyToIntTxBuffer(dev, buf, wd->sta.challengeText, offset, wd->sta.challengeText[1]+2); + offset += (wd->sta.challengeText[1]+2); + } + + break; + + case ZM_WLAN_FRAME_TYPE_ASOCREQ : + case ZM_WLAN_FRAME_TYPE_REASOCREQ : + /* Capability */ + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]); + zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]); + + /* Listen Interval */ + zmw_tx_buf_writeh(dev, buf, offset, 0x0005); + offset+=2; + + /* Reassocaited Request : Current AP address */ + if (frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ) + { + zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[0]); + offset+=2; + zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[1]); + offset+=2; + zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[2]); + offset+=2; + } + + /* SSID */ + offset = zfStaAddIeSsid(dev, buf, offset); + + + if ( wd->sta.currentFrequency < 3000 ) + { + /* Support Rate */ + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); + } + else + { + /* Support Rate */ + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); + } + + if ((wd->sta.capability[1] & ZM_BIT_0) == 1) + { //spectrum managment flag enable + offset = zfStaAddIePowerCap(dev, buf, offset); + offset = zfStaAddIeSupportCh(dev, buf, offset); + } + + if (wd->sta.currentFrequency < 3000) + { + /* Extended Supported Rates */ + if (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) + { + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + } + + + //offset = zfStaAddIeWpaRsn(dev, buf, offset, frameType); + //Move to wrapper function, for OS difference--CWYang(m) + //for windows wrapper, zfwStaAddIeWpaRsn() should be below: + //u16_t zfwStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) + //{ + // return zfStaAddIeWpaRsn(dev, buf, offset, frameType); + //} + offset = zfwStaAddIeWpaRsn(dev, buf, offset, frameType); + +#ifdef ZM_ENABLE_CENC + /* CENC */ + //if (wd->sta.encryMode == ZM_CENC) + offset = zfStaAddIeCenc(dev, buf, offset); +#endif //ZM_ENABLE_CENC + if (((wd->sta.wmeEnabled & ZM_STA_WME_ENABLE_BIT) != 0) //WME enabled + && ((wd->sta.apWmeCapability & 0x1) != 0)) //WME AP + { + if (((wd->sta.apWmeCapability & 0x80) != 0) //UAPSD AP + && ((wd->sta.wmeEnabled & ZM_STA_UAPSD_ENABLE_BIT) != 0)) //UAPSD enabled + { + offset = zfStaAddIeWmeInfo(dev, buf, offset, wd->sta.wmeQosInfo); + } + else + { + offset = zfStaAddIeWmeInfo(dev, buf, offset, 0); + } + } + // jhlee HT 0 + //CWYang(+) + if (wd->sta.EnableHT != 0) + { + #ifndef ZM_DISABLE_AMSDU8K_SUPPORT + //Support 8K A-MSDU + if (wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED) + { + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_MaxAMSDULength; + } + else + { + wd->sta.HTCap.Data.HtCapInfo &= (~HTCAP_MaxAMSDULength); + } + #else + //Support 4K A-MSDU + wd->sta.HTCap.Data.HtCapInfo &= (~HTCAP_MaxAMSDULength); + #endif + + /* HT Capabilities Info */ + if (wd->BandWidth40 == 1) { + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; + } + else { + wd->sta.HTCap.Data.HtCapInfo &= ~HTCAP_SupChannelWidthSet; + //wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; + } + + wd->sta.HTCap.Data.AMPDUParam &= ~HTCAP_MaxRxAMPDU3; + wd->sta.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; + wd->sta.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 + offset = zfMmAddHTCapability(dev, buf, offset); + offset = zfMmAddPreNHTCapability(dev, buf, offset); + //CWYang(+) + /* Extended HT Capabilities Info */ + //offset = zfMmAddExtendedHTCapability(dev, buf, offset); + } + + + //Store asoc request frame body, for VISTA only + wd->sta.asocReqFrameBodySize = ((offset - hlen) > + ZM_CACHED_FRAMEBODY_SIZE)? + ZM_CACHED_FRAMEBODY_SIZE:(offset - hlen); + for (i=0; i<wd->sta.asocReqFrameBodySize; i++) + { + wd->sta.asocReqFrameBody[i] = zmw_tx_buf_readb(dev, buf, i + hlen); + } + break; + + case ZM_WLAN_FRAME_TYPE_ASOCRSP : + case ZM_WLAN_FRAME_TYPE_REASOCRSP : + vap = (u16_t) p3; + + /* Capability */ + zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]); + offset+=2; + + /* Status Code */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1); + offset+=2; + + /* AID */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p2|0xc000)); + offset+=2; + + + if ( wd->frequency < 3000 ) + { + /* Support Rate */ + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); + + /* Extended Supported Rates */ + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + else + { + /* Support Rate */ + offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); + } + + + + /* WME Parameters */ + if (wd->wlanMode == ZM_MODE_AP) + { + /* TODO : if WME STA then send WME parameter element */ + if (wd->ap.qosMode == 1) + { + offset = zfApAddIeWmePara(dev, buf, offset, vap); + } + } + // jhlee HT 0 + //CWYang(+) + /* HT Capabilities Info */ + offset = zfMmAddHTCapability(dev, buf, offset); + //CWYang(+) + /* Extended HT Capabilities Info */ + offset = zfMmAddExtendedHTCapability(dev, buf, offset); + break; + + case ZM_WLAN_FRAME_TYPE_ATIM : + /* NULL frame */ + /* TODO : add two dumb bytes temporarily */ + offset += 2; + break; + + case ZM_WLAN_FRAME_TYPE_QOS_NULL : + zmw_buf_writeh(dev, buf, offset, 0x0010); + offset += 2; + break; + + case ZM_WLAN_DATA_FRAME : + break; + + case ZM_WLAN_FRAME_TYPE_DISASOC : + case ZM_WLAN_FRAME_TYPE_DEAUTH : + if (wd->wlanMode == ZM_MODE_AP) + { + vap = (u16_t) p3; + + if ((aid = zfApFindSta(dev, dst)) != 0xffff) + { + zmw_enter_critical_section(dev); + /* Clear STA table */ + wd->ap.staTable[aid].valid = 0; + + zmw_leave_critical_section(dev); + + if (wd->zfcbDisAsocNotify != NULL) + { + wd->zfcbDisAsocNotify(dev, (u8_t*)dst, vap); + } + } + } + /* Reason Code */ + zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1); + offset+=2; + break; + } + + zfwBufSetSize(dev, buf, offset); + + zm_msg2_mm(ZM_LV_2, "management frame body size=", offset-hlen); + + //Copy wlan header + zfTxGenMmHeader(dev, frameType, dst, header, offset-hlen, buf, vap, encrypt); + for (i=0; i<(hlen>>1); i++) + { + zmw_tx_buf_writeh(dev, buf, i*2, header[i]); + } + + /* Get buffer DMA address */ + //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) + //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) + //{ + // goto zlError; + //} + + zm_msg2_mm(ZM_LV_2, "offset=", offset); + zm_msg2_mm(ZM_LV_2, "hlen=", hlen); + //zm_msg2_mm(ZM_LV_2, "addrTblSize=", addrTblSize); + //zm_msg2_mm(ZM_LV_2, "addrTbl.len[0]=", addrTbl.len[0]); + //zm_msg2_mm(ZM_LV_2, "addrTbl.physAddrl[0]=", addrTbl.physAddrl[0]); + //zm_msg2_mm(ZM_LV_2, "buf->data=", buf->data); + + #if 0 + if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, + ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) + { + goto zlError; + } + #else + zfPutVmmq(dev, buf); + zfPushVtxq(dev); + #endif + + return; +#if 0 +zlError: + + zfwBufFree(dev, buf, 0); + return; +#endif +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfProcessManagement */ +/* Process received management frame. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : received management frame buffer */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +void zfProcessManagement(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) //CWYang(m) +{ + u8_t frameType; + u16_t ta[3]; + u16_t ra[3]; + u16_t vap = 0, index = 0; + //u16_t i; + + zmw_get_wlan_dev(dev); + + ra[0] = zmw_rx_buf_readh(dev, buf, 4); + ra[1] = zmw_rx_buf_readh(dev, buf, 6); + ra[2] = zmw_rx_buf_readh(dev, buf, 8); + + ta[0] = zmw_rx_buf_readh(dev, buf, 10); + ta[1] = zmw_rx_buf_readh(dev, buf, 12); + ta[2] = zmw_rx_buf_readh(dev, buf, 14); + + frameType = zmw_rx_buf_readb(dev, buf, 0); + + if (wd->wlanMode == ZM_MODE_AP) + { +#if 1 + vap = 0; + if ((ra[0] & 0x1) != 1) + { + /* AP : Find virtual AP */ + if ((index = zfApFindSta(dev, ta)) != 0xffff) + { + vap = wd->ap.staTable[index].vap; + } + } + zm_msg2_mm(ZM_LV_2, "vap=", vap); +#endif + + /* Dispatch by frame type */ + switch (frameType) + { + /* Beacon */ + case ZM_WLAN_FRAME_TYPE_BEACON : + zfApProcessBeacon(dev, buf); + break; + /* Authentication */ + case ZM_WLAN_FRAME_TYPE_AUTH : + zfApProcessAuth(dev, buf, ta, vap); + break; + /* Association request */ + case ZM_WLAN_FRAME_TYPE_ASOCREQ : + /* Reassociation request */ + case ZM_WLAN_FRAME_TYPE_REASOCREQ : + zfApProcessAsocReq(dev, buf, ta, vap); + break; + /* Association response */ + case ZM_WLAN_FRAME_TYPE_ASOCRSP : + //zfApProcessAsocRsp(dev, buf); + break; + /* Deauthentication */ + case ZM_WLAN_FRAME_TYPE_DEAUTH : + zfApProcessDeauth(dev, buf, ta, vap); + break; + /* Disassociation */ + case ZM_WLAN_FRAME_TYPE_DISASOC : + zfApProcessDisasoc(dev, buf, ta, vap); + break; + /* Probe request */ + case ZM_WLAN_FRAME_TYPE_PROBEREQ : + zfProcessProbeReq(dev, buf, ta); + break; + /* Probe response */ + case ZM_WLAN_FRAME_TYPE_PROBERSP : + zfApProcessProbeRsp(dev, buf, AddInfo); + break; + /* Action */ + case ZM_WLAN_FRAME_TYPE_ACTION : + zfApProcessAction(dev, buf); + break; + } + } + else //if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) || (wd->wlanMode == ZM_MODE_IBSS)) + { + /* Dispatch by frame type */ + switch (frameType) + { + /* Beacon */ + case ZM_WLAN_FRAME_TYPE_BEACON : + /* if enable 802.11h and current chanel is silent but receive beacon from other AP */ + if (((wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags + & ZM_REG_FLAG_CHANNEL_CSA) != 0) && wd->sta.DFSEnable) + { + wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags + &= ~(ZM_REG_FLAG_CHANNEL_CSA & ZM_REG_FLAG_CHANNEL_PASSIVE); + } + zfStaProcessBeacon(dev, buf, AddInfo); //CWYang(m) + break; + /* Authentication */ + case ZM_WLAN_FRAME_TYPE_AUTH : + /* TODO : vap parameter is useless in STA mode, get rid of it */ + zfStaProcessAuth(dev, buf, ta, 0); + break; + /* Association request */ + case ZM_WLAN_FRAME_TYPE_ASOCREQ : + /* TODO : vap parameter is useless in STA mode, get rid of it */ + zfStaProcessAsocReq(dev, buf, ta, 0); + break; + /* Association response */ + case ZM_WLAN_FRAME_TYPE_ASOCRSP : + /* Reassociation request */ + case ZM_WLAN_FRAME_TYPE_REASOCRSP : + zfStaProcessAsocRsp(dev, buf); + break; + /* Deauthentication */ + case ZM_WLAN_FRAME_TYPE_DEAUTH : + zm_debug_msg0("Deauthentication received"); + zfStaProcessDeauth(dev, buf); + break; + /* Disassociation */ + case ZM_WLAN_FRAME_TYPE_DISASOC : + zm_debug_msg0("Disassociation received"); + zfStaProcessDisasoc(dev, buf); + break; + /* Probe request */ + case ZM_WLAN_FRAME_TYPE_PROBEREQ : + zfProcessProbeReq(dev, buf, ta); + break; + /* Probe response */ + case ZM_WLAN_FRAME_TYPE_PROBERSP : + /* if enable 802.11h and current chanel is silent but receive probe response from other AP */ + if (((wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags + & ZM_REG_FLAG_CHANNEL_CSA) != 0) && wd->sta.DFSEnable) + { + wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags + &= ~(ZM_REG_FLAG_CHANNEL_CSA & ZM_REG_FLAG_CHANNEL_PASSIVE); + } + zfStaProcessProbeRsp(dev, buf, AddInfo); + break; + + case ZM_WLAN_FRAME_TYPE_ATIM: + zfStaProcessAtim(dev, buf); + break; + /* Action */ + case ZM_WLAN_FRAME_TYPE_ACTION : + zm_msg0_mm(ZM_LV_2, "ProcessActionMgtFrame"); + zfStaProcessAction(dev, buf); + break; + } + } +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfProcessProbeReq */ +/* Process probe request management frame. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : auth frame buffer */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ +/* */ +/************************************************************************/ +void zfProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src) +{ + u16_t offset; + u8_t len; + u16_t i, j; + u8_t ch; + u16_t sendFlag; + + zmw_get_wlan_dev(dev); + + /* check mode : AP/IBSS */ + if ((wd->wlanMode != ZM_MODE_AP) && (wd->wlanMode != ZM_MODE_IBSS)) + { + zm_msg0_mm(ZM_LV_3, "Ignore probe req"); + return; + } + + if ((wd->wlanMode != ZM_MODE_AP) && (wd->sta.adapterState == ZM_STA_STATE_DISCONNECT)) + { + zm_msg0_mm(ZM_LV_3, "Packets dropped due to disconnect state"); + return; + } + + if ( wd->wlanMode == ZM_MODE_IBSS ) + { + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBERSP, src, 0, 0, 0); + + return; + } + + /* check SSID */ + if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff) + { + zm_msg0_mm(ZM_LV_3, "probe req SSID not found"); + return; + } + + len = zmw_rx_buf_readb(dev, buf, offset+1); + + for (i=0; i<ZM_MAX_AP_SUPPORT; i++) + { + if ((wd->ap.apBitmap & (1<<i)) != 0) + { + zm_msg1_mm(ZM_LV_3, "len=", len); + sendFlag = 0; + /* boardcast SSID */ + if (len == 0) + { + if (wd->ap.hideSsid[i] == 0) + { + sendFlag = 1; + } + } + /* Not broadcast SSID */ + else if (wd->ap.ssidLen[i] == len) + { + for (j=0; j<len; j++) + { + if ((ch = zmw_rx_buf_readb(dev, buf, offset+2+j)) + != wd->ap.ssid[i][j]) + { + break; + } + } + if (j == len) + { + sendFlag = 1; + } + } + if (sendFlag == 1) + { + /* Send probe response */ + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBERSP, src, i, 0, i); + } + } + } +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfProcessProbeRsp */ +/* Process probe response management frame. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* buf : auth frame buffer */ +/* AddInfo : Rx Header and Rx Mac Status */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Aress Yang ZyDAS Technology Corporation 2006.11 */ +/* */ +/************************************************************************/ +void zfProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) +{ + /* Gather scan result */ + /* Parse TIM and send PS-POLL in power saving mode */ + struct zsWlanProbeRspFrameHeader* pProbeRspHeader; + struct zsBssInfo* pBssInfo; + u8_t pBuf[sizeof(struct zsWlanProbeRspFrameHeader)]; + int res; + + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + zfCopyFromRxBuffer(dev, buf, pBuf, 0, + sizeof(struct zsWlanProbeRspFrameHeader)); + pProbeRspHeader = (struct zsWlanProbeRspFrameHeader*) pBuf; + + zmw_enter_critical_section(dev); + + //zm_debug_msg1("bss count = ", wd->sta.bssList.bssCount); + + pBssInfo = zfStaFindBssInfo(dev, buf, pProbeRspHeader); + + //if ( i == wd->sta.bssList.bssCount ) + if ( pBssInfo == NULL ) + { + /* Allocate a new entry if BSS not in the scan list */ + pBssInfo = zfBssInfoAllocate(dev); + if (pBssInfo != NULL) + { + res = zfStaInitBssInfo(dev, buf, pProbeRspHeader, pBssInfo, AddInfo, 0); + //zfDumpSSID(pBssInfo->ssid[1], &(pBssInfo->ssid[2])); + if ( res != 0 ) + { + zfBssInfoFree(dev, pBssInfo); + } + else + { + zfBssInfoInsertToList(dev, pBssInfo); + } + } + } + else + { + res = zfStaInitBssInfo(dev, buf, pProbeRspHeader, pBssInfo, AddInfo, 1); + if (res == 2) + { + zfBssInfoRemoveFromList(dev, pBssInfo); + zfBssInfoFree(dev, pBssInfo); + } + else if ( wd->wlanMode == ZM_MODE_IBSS ) + { + int idx; + + // It would reset the alive counter if the peer station is found! + zfStaFindFreeOpposite(dev, (u16_t *)pBssInfo->macaddr, &idx); + } + } + + zmw_leave_critical_section(dev); + + return; +} + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfSendProbeReq */ +/* Send probe request management frame. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Ji-Huang Lee ZyDAS Technology Corporation 2005.11 */ +/* */ +/************************************************************************/ + +u16_t zfSendProbeReq(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t bWithSSID) +{ + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + + /* SSID */ + if (bWithSSID == 0) /* broadcast ssid */ + { + //zmw_leave_critical_section(dev); + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); + zmw_tx_buf_writeb(dev, buf, offset++, 0); /* length = 0 */ + } + else + { + zmw_enter_critical_section(dev); + if (wd->ws.probingSsidList[bWithSSID-1].ssidLen == 0) + { + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); + zmw_tx_buf_writeb(dev, buf, offset++, 0); /* length = 0 */ + } + else + { + zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); + zmw_tx_buf_writeb(dev, buf, offset++, + wd->ws.probingSsidList[bWithSSID-1].ssidLen); + zfCopyToIntTxBuffer(dev, buf, + wd->ws.probingSsidList[bWithSSID-1].ssid, + offset, + wd->ws.probingSsidList[bWithSSID-1].ssidLen); /* ssid */ + offset += wd->ws.probingSsidList[bWithSSID-1].ssidLen; + } + zmw_leave_critical_section(dev); + } + + /* Supported rates */ + if ( wd->sta.currentFrequency < 3000 ) + { /* 802.11b+g */ + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); + + if (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) { + if (wd->wlanMode == ZM_MODE_IBSS) { + if (wd->wfc.bIbssGMode) { + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + } else { + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); + } + } + } + else + { /* 802.11a */ + offset = zfMmAddIeSupportRate(dev, buf, offset, + ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); + } + + return offset; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfUpdateDefaultQosParameter */ +/* Update TxQs CWMIN, CWMAX, AIFS and TXO to WME default value. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* mode : 0=>STA, 1=>AP */ +/* */ +/* OUTPUTS */ +/* none */ +/* */ +/* AUTHOR */ +/* Stephen ZyDAS Technology Corporation 2006.6 */ +/* */ +/************************************************************************/ +void zfUpdateDefaultQosParameter(zdev_t* dev, u8_t mode) +{ + u16_t cwmin[5]; + u16_t cwmax[5]; + u16_t aifs[5]; + u16_t txop[5]; + + /* WMM parameter for STA */ + /* Best Effor */ + cwmin[0] = 15; + cwmax[0] = 1023; + aifs[0] = 3 * 9 + 10; + txop[0] = 0; + /* Back Ground */ + cwmin[1] = 15; + cwmax[1] = 1023; + aifs[1] = 7 * 9 + 10; + txop[1] = 0; + /* VIDEO */ + cwmin[2] = 7; + cwmax[2] = 15; + aifs[2] = 2 * 9 + 10; + txop[2] = 94; + /* VOICE */ + cwmin[3] = 3; + cwmax[3] = 7; + aifs[3] = 2 * 9 + 10; + txop[3] = 47; + /* Special TxQ */ + cwmin[4] = 3; + cwmax[4] = 7; + aifs[4] = 2 * 9 + 10; + txop[4] = 0; + + /* WMM parameter for AP */ + if (mode == 1) + { + cwmax[0] = 63; + aifs[3] = 1 * 9 + 10; + aifs[4] = 1 * 9 + 10; + } + zfHpUpdateQosParameter(dev, cwmin, cwmax, aifs, txop); +} + +u16_t zfFindATHExtCap(zdev_t* dev, zbuf_t* buf, u8_t type, u8_t subtype) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_WIFI_IE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x03) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0x7f) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+5)) == type)) + + { + if ( subtype != 0xff ) + { + if ( (tmp = zmw_rx_buf_readb(dev, buf, offset+6)) == subtype ) + { + return offset; + } + } + else + { + return offset; + } + } + } + + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + offset += (elen+2); + } + return 0xffff; +} + +u16_t zfFindBrdcmMrvlRlnkExtCap(zdev_t* dev, zbuf_t* buf) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_WIFI_IE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x10) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0x18)) + + { + return offset; + } + else if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x50) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0x43)) + + { + return offset; + } + } + else if ((id = zmw_rx_buf_readb(dev, buf, offset)) == 0x7F) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if ((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x01) + + { + return offset; + } + } + + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + offset += (elen+2); + } + return 0xffff; +} + +u16_t zfFindMarvelExtCap(zdev_t* dev, zbuf_t* buf) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + + /* Search loop */ + while ((offset+2)<bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_WIFI_IE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1))>(bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x50) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0x43)) + + { + return offset; + } + } + + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + offset += (elen+2); + } + return 0xffff; +} + +u16_t zfFindBroadcomExtCap(zdev_t* dev, zbuf_t* buf) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + + /* Search loop */ + while((offset+2) < bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == ZM_WLAN_EID_WIFI_IE) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) > (bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if (elen == 0) + { + return 0xffff; + } + + if ( ((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x10) + && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0x18) ) + { + return offset; + } + } + + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + + offset += (elen+2); + } + + return 0xffff; +} + +u16_t zfFindRlnkExtCap(zdev_t* dev, zbuf_t* buf) +{ + u8_t subType; + u16_t offset; + u16_t bufLen; + u16_t elen; + u8_t id; + u8_t tmp; + + /* Get offset of first element */ + subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); + + if ((offset = zgElementOffsetTable[subType]) == 0xff) + { + zm_assert(0); + } + + /* Plus wlan header */ + offset += 24; + + bufLen = zfwBufGetSize(dev, buf); + + /* Search loop */ + while((offset+2) < bufLen) // including element ID and length (2bytes) + { + /* Search target element */ + if ((id = zmw_rx_buf_readb(dev, buf, offset)) == 0x7F) + { + /* Bingo */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) > (bufLen - offset)) + { + /* Element length error */ + return 0xffff; + } + + if ( elen == 0 ) + { + return 0xffff; + } + + if ((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x01) + + { + return offset; + } + } + + /* Advance to next element */ + if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) + { + return 0xffff; + } + + offset += (elen+2); + } + + return 0xffff; +} |