blob: c9123d58b82f03899ca8b46d7b78bc7394cd9d93 [file] [log] [blame]
/*
* 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.
*/
#include "cprecomp.h"
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfGetAmsduSubFrame */
/* Get a subframe from a-MSDU. */
/* */
/* INPUTS */
/* dev : device pointer */
/* buf : A-MSDU frame buffer */
/* offset : offset of subframe in the A-MSDU */
/* */
/* OUTPUTS */
/* NULL or subframe */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2007.2 */
/* */
/************************************************************************/
zbuf_t* zfGetAmsduSubFrame(zdev_t* dev, zbuf_t* buf, u16_t* offset)
{
u16_t subframeLen;
u16_t amsduLen = zfwBufGetSize(dev, buf);
zbuf_t* newBuf;
ZM_PERFORMANCE_RX_AMSDU(dev, buf, amsduLen);
/* Verify A-MSDU length */
if (amsduLen < (*offset + 14))
{
return NULL;
}
/* Locate A-MSDU subframe by offset and verify subframe length */
subframeLen = (zmw_buf_readb(dev, buf, *offset + 12) << 8) +
zmw_buf_readb(dev, buf, *offset + 13);
if (subframeLen == 0)
{
return NULL;
}
/* Verify A-MSDU subframe length */
if ((*offset+14+subframeLen) <= amsduLen)
{
/* Allocate a new buffer */
if ((newBuf = zfwBufAllocate(dev, 24+2+subframeLen)) != NULL)
{
#ifdef ZM_ENABLE_NATIVE_WIFI
/* Copy and convert subframe to wlan frame format */
/* SHALL NOT INCLUDE QOS and AMSDU header. Ray 20070807 For Vista */
zfRxBufferCopy(dev, newBuf, buf, 0, 0, 24);
zfRxBufferCopy(dev, newBuf, buf, 24, *offset+14, subframeLen);
zfwBufSetSize(dev, newBuf, 24+subframeLen);
#else
/* Copy subframe to new buffer */
zfRxBufferCopy(dev, newBuf, buf, 0, *offset, 14+subframeLen);
zfwBufSetSize(dev, newBuf, 14+subframeLen);
#endif
/* Update offset */
*offset += (((14+subframeLen)+3) & 0xfffc);
/* Return buffer pointer */
return newBuf;
}
}
return NULL;
}
/************************************************************************/
/* */
/* FUNCTION DESCRIPTION zfDeAmsdu */
/* De-AMSDU. */
/* */
/* INPUTS */
/* dev : device pointer */
/* buf : A-MSDU frame buffer */
/* vap : VAP port */
/* */
/* OUTPUTS */
/* None */
/* */
/* AUTHOR */
/* Stephen Chen Atheros Communications, INC. 2007.2 */
/* */
/************************************************************************/
void zfDeAmsdu(zdev_t* dev, zbuf_t* buf, u16_t vap, u8_t encryMode)
{
u16_t offset = ZM_SIZE_OF_WLAN_DATA_HEADER+ZM_SIZE_OF_QOS_CTRL;
zbuf_t* subframeBuf;
zmw_get_wlan_dev(dev);
ZM_BUFFER_TRACE(dev, buf)
if (encryMode == ZM_AES || encryMode == ZM_TKIP)
{
offset += (ZM_SIZE_OF_IV + ZM_SIZE_OF_EXT_IV);
}
else if (encryMode == ZM_WEP64 || encryMode == ZM_WEP128)
{
offset += ZM_SIZE_OF_IV;
}
/* Repeatly calling zfGetAmsduSubFrame() until NULL returned */
while ((subframeBuf = zfGetAmsduSubFrame(dev, buf, &offset)) != NULL)
{
wd->commTally.NotifyNDISRxFrmCnt++;
if (wd->zfcbRecvEth != NULL)
{
wd->zfcbRecvEth(dev, subframeBuf, (u8_t)vap);
ZM_PERFORMANCE_RX_MSDU(dev, wd->tick);
}
}
zfwBufFree(dev, buf, 0);
return;
}