/* * 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 - 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 - 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 - 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 - 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<bRateBasic & (0x1<gRate & (0x1<gRateBasic & (0x1< 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 management 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 management 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; ista.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; iap.apBitmap & (1<