2224 lines
84 KiB
C
2224 lines
84 KiB
C
/* dot11DpeLib.c - Implements data path for wireless framework */
|
|
|
|
/*
|
|
* Copyright (c) 2004-2007 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
Modification History
|
|
--------------------
|
|
03k,18jan10,mry Fix defect WIND00193008 (TSC byte order)
|
|
03j,02apr08,mry Adding support in Atheros driver for external supplicant to
|
|
specify external EAPOL processing (4wayHS)
|
|
03i,27feb08,hfc replace task/intlock with smp-safe api and add support for vxbus
|
|
03h,21feb08,mry Merging ipsupp/ipeap changes
|
|
|
|
|
|
03g,07feb08 mry Fix defect WIND00112513
|
|
03f,08mar07,spw Fix fragmentation reassembly pointers
|
|
03e,16jan07,tfo Fixing a Mblk chain issue with the new ipnet stack.
|
|
03d,10apr06,rb Fix to SPR 118145 - 802.1X Authentication fails with
|
|
fragmentation turned on
|
|
03c,16mar06,rb Fix Coverity issues (SPR 119148)
|
|
03b,02mar06,rb Fix to SPR 118377 - AppleTalk packets are not correctly
|
|
handled
|
|
03i,05jan06,rb Fix for SPR 116443 - Framentation threshold max value is
|
|
incorrect
|
|
03h,16dec05,rb Fix for SPR 115960 - Bad fragmentation calculations
|
|
03g,14dec05,rb Fix for SPR 113959 - WEP padding bits not checked
|
|
03f,13dec05,rb Fix to SPR 115958 - Incorrect fragmentation
|
|
03e,28feb06,rb Merge from 2.1.2 bugfix branch
|
|
03d,27feb06,rb Changes from code inspection
|
|
03c,22feb06,rb Fix minor bug with 802.1X and vlanId != 0
|
|
03b,17feb06,rb Fix endianess problem with VLANs
|
|
03a,17feb06,rb Code cleanup and warning removal
|
|
02z,13feb06,rb Added VLAN tagging support
|
|
02y,11nov05,rb Added mSSID feature
|
|
02x,28sep05,rb Update header comments and copyright
|
|
02w,18aug05,rb Fix for problem with multicast keys
|
|
02v,29jul05,rb Fix for SPR 110957 - poor performance in power management
|
|
02u,28jun05,rb Fix for SPR 110403 - WEP does not work with keyIndex > 0
|
|
02t,23jun05,rb Fix for SPR 110080: fragmentation does not work with TKIP/AES
|
|
02s,29apr05,rb Fix for bug B0270: WEP does not seem to be working
|
|
02r,27apr05,rb Fix for SPR 108017 - Improved statistics
|
|
02q,27apr05,rb Updated routines with APIGEN tags
|
|
02p,25apr05,rb Fix for B0258: Problems with 802.1X legacy mode
|
|
02o,06apr05,rb Fix for SPR 107235: data path does not handle non-ethernet
|
|
packets correctly
|
|
02n,23mar05,rb Moved sta-sta bridging for AP into endReceive()
|
|
02m,07mar05,rb Changes from dot11RsnLib.c code review
|
|
02l,02feb05,rb Resolved vxWorks 6.0 compatibility issues
|
|
02k,25jan05,rb Made security component optionally buildable
|
|
02j,20jan05,rb Added 802.1X and decrypt err statistics
|
|
02i,19jan05,rb 802.1X State machine bug
|
|
02h,19jan05,rb fixed compiler error
|
|
02g,19jan05,rb Fix dropping 802.1X packets
|
|
02f,10jan05,rb Changes to the 802.1X port control functionality
|
|
02e,05jan05,rb Fix for SPR 103854 - Need to update reference in TXD to use
|
|
MBlks
|
|
02d,22dec04,rb Fixed handling of ICV in AES
|
|
02c,05nov04,rb Added code to intercept EAPOL-Key messages and send them to
|
|
the RSN module
|
|
02b,24sep04,rb Fix for SPR 102025 - IPv6 Incompatabilities
|
|
02a,25aug04,rb Wind River Wireless Ethernet Driver 2.0 FCS
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
|
|
The data path entity is the portion of the driver that moves packets between
|
|
the MUX subsystem and the device hardware. It converts between the 802.3
|
|
frames used by the MUX and the 802.11 frames used by the driver.
|
|
|
|
SEE ALSO
|
|
Wind Net 802.11 Station 2.0 High Level Design Document
|
|
|
|
\NOMANUAL
|
|
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <muxLib.h>
|
|
#include <end.h>
|
|
#include <netBufLib.h>
|
|
#include <endLib.h>
|
|
#include <stdlib.h>
|
|
#include <netLib.h>
|
|
#include <tickLib.h>
|
|
#include <netinet/in.h>
|
|
#include <drv/wlan/dot11Lib.h>
|
|
#include <drv/wlan/dot11SmeLib.h>
|
|
#include <drv/wlan/dot11TimerLib.h>
|
|
|
|
/* Local prototypes */
|
|
LOCAL STATUS dot11DpeFree(DOT11_FW * pDot11);
|
|
LOCAL STATUS dot11DpeEndSend(END_OBJ * pEnd, M_BLK_ID pMblk);
|
|
LOCAL STATUS dot11DpeEndSendBss(DOT11_FW * pDot11, M_BLK_ID pDataMblk,
|
|
DOT11_BSS * pBss);
|
|
LOCAL STATUS dot11DpeFragmentSend(DOT11_FW * pDot11,
|
|
UINT8 * pDstAddr,
|
|
UINT8 * pSrcAddr,
|
|
M_BLK_ID pDataMblk,
|
|
int fragNum,
|
|
int nextFragLen,
|
|
DOT11_BSS * pBss);
|
|
LOCAL STATUS dot11DpeEndReceive(DOT11_FW * pDot11, M_BLK_ID pMblk,
|
|
UINT32 rate, UINT8 SSI);
|
|
LOCAL STATUS dot11DpeFragThresholdSet(DOT11_FW* pDot11, UINT32 fragThresh);
|
|
LOCAL STATUS dot11DpeFragThresholdGet(DOT11_FW* pDot11,UINT32 * fragThresh);
|
|
LOCAL STATUS dot11DpeEndPollRcv(END_OBJ* pEnd, M_BLK_ID pMblk);
|
|
LOCAL STATUS dot11DpeEndPollSend(END_OBJ* pEnd, M_BLK_ID pMblk);
|
|
LOCAL M_BLK_ID dot11DpeReassemble(DOT11_FW * pDot11, M_BLK_ID pMblk,
|
|
DOT11_KSL_ENTRY * pKsl);
|
|
LOCAL DOT11_FRAGMENT * dot11DpeReassemblePktGet(DOT11_FW * pDot11,
|
|
DOT11_HEADER * pHeader);
|
|
LOCAL VOID dot11DpeReassembleTimeout(DOT11_FW * pDot11, int fragSlot);
|
|
LOCAL DOT11_FRAGMENT * dot11DpeReassemblePktCreate(DOT11_FW * pDot11,
|
|
DOT11_HEADER * pHeader);
|
|
LOCAL STATUS dot11DpeTransmitQueueFlush(DOT11_FW * pDot11);
|
|
LOCAL M_BLK_ID dot11DpeMblkCoalesce(DOT11_FW * pDot11, M_BLK_ID pMblkChain);
|
|
|
|
/****************************************************************************
|
|
* dot11DpeInit - Initializes the data path entity
|
|
*
|
|
* This function inializes the DPE object, allocating memory and filling in
|
|
* function pointers as necessary.
|
|
*
|
|
* RETURNS: OK or ERROR on memory alloc failure.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
STATUS dot11DpeInit
|
|
(
|
|
DOT11_FW * pDot11 /* Pointer to device structure */
|
|
)
|
|
{
|
|
int i;
|
|
|
|
/* Allocate a DPE object and connect it to the DOT11_FW */
|
|
if ((pDot11->dpe = calloc(1, sizeof(DPE_OBJ))) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FATAL, DOT11_AREA_INIT,
|
|
("dot11DpeInit: Error allocating device structure\n", 0, 0,
|
|
0, 0, 0, 0));
|
|
return ERROR;
|
|
}
|
|
|
|
/* Fill in the function pointers for the DPE */
|
|
pDot11->dpe->free = dot11DpeFree;
|
|
pDot11->dpe->endSend = dot11DpeEndSend;
|
|
pDot11->dpe->endReceive = dot11DpeEndReceive;
|
|
pDot11->dpe->fragThresholdSet = dot11DpeFragThresholdSet;
|
|
pDot11->dpe->fragThresholdGet = dot11DpeFragThresholdGet;
|
|
pDot11->dpe->endPollSend = dot11DpeEndPollSend;
|
|
pDot11->dpe->endPollRcv = dot11DpeEndPollRcv;
|
|
pDot11->dpe->transmitQueueFlush = dot11DpeTransmitQueueFlush;
|
|
|
|
/* Start the initialization vector at 1, to avoid 0 which is weak */
|
|
pDot11->dpe->currentIV = 1;
|
|
|
|
/* Set the exclusion policy to disallow unencrypted packets when WEP
|
|
is enabled */
|
|
pDot11->dpe->exclusionPolicy = DOT11_EX_DOT1X;
|
|
|
|
/* The fragmentation is diabled by setting the threshold to MAX */
|
|
pDot11->dpe->fragThreshold = DOT11_MAX_PACKET;
|
|
|
|
/* Initialize the reassembly buffer */
|
|
for (i=0; i<DOT11_MAX_REASSEMBLY; i++)
|
|
{
|
|
pDot11->dpe->reassemblyBuff.packet[i].used = FALSE;
|
|
pDot11->dpe->reassemblyBuff.packet[i].pHead = NULL;
|
|
}
|
|
|
|
/* Initialize the transmit semaphore */
|
|
if ((pDot11->dpe->transmitSem = semMCreate(SEM_INVERSION_SAFE |
|
|
SEM_Q_PRIORITY)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FATAL, DOT11_AREA_INIT,
|
|
("dot11DpeInit: Error allocating \n", 0, 0,
|
|
0, 0, 0, 0));
|
|
|
|
free(pDot11->dpe);
|
|
pDot11->dpe = NULL;
|
|
|
|
return ERROR;
|
|
}
|
|
|
|
/* NULL out the transmit queue */
|
|
pDot11->dpe->transmitQueueHead = NULL;
|
|
pDot11->dpe->transmitQueueTail = NULL;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeFree - Frees all memory allocated in dot11DpeInit
|
|
*
|
|
* Returns all memory allocated by DPE. System is not useable after this point.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeFree
|
|
(
|
|
DOT11_FW * pDot11 /* Pointer to device structure */
|
|
)
|
|
{
|
|
STATUS status;
|
|
|
|
status = semDelete(pDot11->dpe->transmitSem);
|
|
|
|
free(pDot11->dpe);
|
|
|
|
pDot11->dpe = NULL;
|
|
return status;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeEndReceive - Receive routine for 802.11 Data packets;
|
|
*
|
|
* This is the END receive routine. It takes an incoming 802.11 data frame
|
|
* and strips the 802.11 header.
|
|
*
|
|
* The HDD passes packets to this function in a Cl-Blk/cluster frame, with
|
|
* 802.11 and SNAP headers in front of the payload. This function strips the
|
|
* 802.11 header in place, copying the DA and SA to form the etherHeader on top
|
|
* of the SNAP header. The <mData> field in the new Mblk is set to point to
|
|
* the start of the new RFC1042 packet. All of the conversion takes place in
|
|
* the original cluster - there is no copy or additional cluster added.
|
|
*
|
|
* Note that in response to SPR 107235, the above conversion only takes place on
|
|
* Ethernet or 802.1h packets. Other layer two packets with an LLC header
|
|
* will be transmitted as is.
|
|
*
|
|
* RETURNS: OK or ERROR on allocation error.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeEndReceive
|
|
(
|
|
DOT11_FW * pDot11, /* Pointer to device structure */
|
|
M_BLK_ID pMblk, /* mBlk containing data buffer */
|
|
UINT32 rate, /* Rate at which packet was RX in 500 kbps */
|
|
UINT8 SSI /* Signal level of received packet 0-100 */
|
|
)
|
|
{
|
|
UINT8 * pCluster; /* Cluster containing rx'd packet */
|
|
M_BLK_ID pHeadMblk; /* New Mblk to link cluster into */
|
|
DOT11_HEADER * pHeader; /* Pointer to 802.11 Hdr */
|
|
DOT11_KSL_ENTRY * pKsl; /* Pointer to KSL entry for source */
|
|
DOT11_KSL_ENTRY * pBridgeKsl; /* Pointer to KSL entry for quickbridge */
|
|
UINT32 pDataOffset; /* Keeps track of where payload starts*/
|
|
DOT11_LLC_HEADER * pLlcHeader;/* The packer's LLC/SNAP header */
|
|
BOOL stripLlc; /* Becomes true if we need to strip the LLC
|
|
header before passing to stack */
|
|
|
|
/* Sanity check */
|
|
if ((pDot11 == NULL) || (pMblk == NULL) || (pMblk->mBlkHdr.mLen == 0))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
pCluster = (UINT8*)pMblk->mBlkHdr.mData;
|
|
pHeader = (DOT11_HEADER *)pCluster;
|
|
|
|
/* Get the KSL entry for the immediate source-addr 2 (BSSID in a ESS). If
|
|
the entry does not exist, then we cannot be associated to the AP, so drop
|
|
the packet. Calling this function also serves to update the KSL timer
|
|
and enter the received rate and SSI information into the SME state
|
|
machine*/
|
|
if ((pKsl = pDot11->sme->ksl.rxUpdate(pDot11, pHeader->addr2, rate,
|
|
SSI)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Not Associated. Dropping packet.\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
/* The packet must be freed */
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Check if we're in a state to allow data packet reception */
|
|
if (pKsl->pBss->linkStatus == DOT11_LINK_DOWN)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Not CONNECTED!\n", 0, 0, 0, 0,
|
|
0,0));
|
|
/* The packet must be freed */
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
if (pDot11->sme->ksl.lock(pDot11) != OK)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Cannot get KSL lock.\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
/* The packet must be freed */
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Check if this is a station in power management, and the packet has the
|
|
more data bit set. */
|
|
if ((pDot11->dot11Mode == DOT11_MODE_ESS) &&
|
|
(((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) & DOT11_FCTL_MORE_DATA)!=0) &&
|
|
(pDot11->sme->powerManagement) &&
|
|
(!DOT11_IS_MCAST(pHeader->addr1)))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Requesting MORE_DATA.\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netJobAdd((FUNCPTR)pDot11->hdd->psPollSend, (int)pDot11,0,0,0,0);
|
|
|
|
/* Continue processing this packet */
|
|
}
|
|
|
|
/* MRY: As per standard (802.11i/WPA(2)):
|
|
* if in WPA/WPA2 (dot1x/PSK) mode, every packet (even dot1x) MUST be encrypted.
|
|
* once the 4 way handhsake is complete (i.e. pairwise keys are established).
|
|
* Otherwise drop
|
|
*/
|
|
if (
|
|
(((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) & DOT11_FCTL_WEP)==0) &&
|
|
(((pKsl->negAuthPol == DOT11_AUTHPOL_8021X) || (pKsl->negAuthPol == DOT11_AUTHPOL_PSK)) &&
|
|
(pKsl->fourWayState == DOT11_FOURWAY_ESTABLISHED))
|
|
)
|
|
{
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Dropping packet because "
|
|
"encryption keys established\n", 0, 0, 0, 0, 0, 0));
|
|
pDot11->stats.rxExcludeUnencrypted ++;
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Check if we have an unencrypted packet when encryption is turned on.
|
|
Generally this is a bad thing, unless explicitly allowed, either by virtue
|
|
of being an EAPOL packet when dot1x is enabled or by an explicit policy
|
|
decision */
|
|
if (((pKsl->uniEncryptType != DOT11_ENCRYPT_NONE) ||
|
|
(pKsl->pBss->multiEncryptType != DOT11_ENCRYPT_NONE)) &&
|
|
(((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) & DOT11_FCTL_WEP)==0)&&
|
|
(pDot11->dpe->exclusionPolicy != DOT11_EX_NONE))
|
|
{
|
|
/* The packet is unencrypted, and encryption is specified */
|
|
if (((!pKsl->dot1xControlled) && (pKsl->negSecPol == 0)) ||
|
|
((pKsl->dot1xControlled) &&
|
|
(*(UINT16 *)(pCluster + sizeof(DOT11_HEADER) +
|
|
DOT11_SNAP_HEADER_LEN - sizeof(UINT16)) !=
|
|
(DOT1X_ETHERTYPE))))
|
|
{
|
|
/* Return OK, since the packet was succesfully consumed; it was not
|
|
an error that it was dropped, just a policy decision. */
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Dropping non-EAPOL packet by "
|
|
"policy\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
pDot11->stats.rxExcludeUnencrypted ++;
|
|
netMblkClChainFree(pMblk);
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
|
|
/* If the packet used WEP, check that the IV bits are non-zero */
|
|
if (((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) & DOT11_FCTL_WEP) != 0)
|
|
{
|
|
if ((*(pCluster + sizeof(DOT11_HEADER) + 3) & 0x1f) != 0)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_SME,
|
|
("dot11DpeEndReceive: Station " DOT11_MAC_ADDR_STR
|
|
" send packet with WEP pad bits set\n",
|
|
DOT11_MAC_ADDR(pHeader->addr2)));
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/* Fix for SPR 102025 - IPv6 Incompatabilities. In ESS mode, we need to
|
|
filter out our own broadcast packets that are getting sent back from the
|
|
AP since they confuse the IPv6 stack. Thus, we drop packets that are
|
|
to the broadcast address from our own address. */
|
|
if ((pDot11->dot11Mode == DOT11_MODE_ESS) &&
|
|
(DOT11_IS_MCAST(pHeader->addr1)) &&
|
|
(bcmp((char *)pHeader->addr3, (char *)pDot11->macAddr, DOT11_ADDR_LEN) == 0))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Dropping our own bcast packet.\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
netMblkClChainFree(pMblk);
|
|
return OK;
|
|
}
|
|
|
|
/* Check if this is a fragmented packet in need of reassembly. If this
|
|
is a fragmented packet, either the "More fragments" bit will be set,
|
|
indicating this is not the last packet, or the fragment number will be
|
|
greate than zero. If a packet did not have the More frag bit and had a
|
|
fragnum of zero, then it is not fragmented and not our concern. */
|
|
if ((((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) &
|
|
DOT11_FCTL_MORE_FRAG) != 0) ||
|
|
((DOT11_LE_TO_CPU_16(pHeader->seqCtrl)&DOT11_SEQCTL_FRAGNUM) > 0))
|
|
{
|
|
if ((pHeadMblk = dot11DpeReassemble(pDot11, pMblk, pKsl)) == NULL)
|
|
{
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Queued packet\n",0,0,0,0,0,0));
|
|
/* This wasn't the last fragment in a chain. No packet was
|
|
generated, so just leave things be. Pakcet is either on the
|
|
reassembly queue or deallocated. In either case, we're done
|
|
with it. */
|
|
return OK;
|
|
}
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: New formed packet len = %d\n",
|
|
pHeadMblk->mBlkPktHdr.len,0,0,0,0,0));
|
|
|
|
/* Adjust pCluster and pHeader to point to the start of the
|
|
reassembled packet rather than the fragment that triggered the
|
|
reassembly */
|
|
pCluster = (UINT8*)pHeadMblk->mBlkHdr.mData;
|
|
pHeader = (DOT11_HEADER *)pCluster;
|
|
}
|
|
else
|
|
{
|
|
pHeadMblk = pMblk;
|
|
pHeadMblk->mBlkPktHdr.len = pMblk->mBlkHdr.mLen;
|
|
}
|
|
|
|
/* Having gotten this far, we know that pHeadMblk points to the head of a
|
|
reassembled (or only) packet chain. Since the dot11 header and any
|
|
encryption byproducts were stripped from all M-Blks except the first, we
|
|
need to reassemble the ethernet header based on the info in the first
|
|
packet */
|
|
|
|
pDataOffset = sizeof(DOT11_HEADER);
|
|
|
|
if (((DOT11_LE_TO_CPU_16(pHeader->frameCtrl)) & DOT11_FCTL_WEP) != 0)
|
|
{
|
|
/* If hardware encryption is enabled, then the card was nice enough
|
|
to decrypt it for us. We don't even have to do the checksum, since
|
|
the HDD should have discarded packets with a bad checksum. */
|
|
|
|
/* Look at the third byte of the IV - if the EXT IV bit is set, then
|
|
this is either an AES or TKIP packet, and we need to get rid of the
|
|
extended IV header and the MIC fields */
|
|
|
|
if ((*(pCluster + sizeof(DOT11_HEADER) + 3) & DOT11_EXT_IV) != 0)
|
|
{
|
|
pDataOffset += DOT11_WEP_IV_SIZE + DOT11_WEP_EXT_IV_SIZE;
|
|
|
|
pHeadMblk->mBlkHdr.mLen -= DOT11_WEP_IV_SIZE + DOT11_MIC_LEN +
|
|
DOT11_WEP_EXT_IV_SIZE;
|
|
pHeadMblk->mBlkPktHdr.len -= DOT11_WEP_IV_SIZE + DOT11_MIC_LEN +
|
|
DOT11_WEP_EXT_IV_SIZE;
|
|
|
|
/* If this is a TKIP packet, then we also need to account for the
|
|
ICV at the end of the packet. In order to check if this is a
|
|
TKIP packet, we need to determine if it's unicast or multicast,
|
|
and check the appropriate key. */
|
|
if (((!(DOT11_IS_MCAST(pHeader->addr1))) &&
|
|
(pKsl->uniEncryptType == DOT11_KEY_TYPE_TKIP)) ||
|
|
((DOT11_IS_MCAST(pHeader->addr1)) &&
|
|
(pKsl->pBss->multiEncryptType == DOT11_KEY_TYPE_TKIP)))
|
|
{
|
|
pHeadMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE;
|
|
pHeadMblk->mBlkPktHdr.len -= DOT11_WEP_ICV_SIZE;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pDataOffset += DOT11_WEP_IV_SIZE;
|
|
|
|
pHeadMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE + DOT11_WEP_IV_SIZE;
|
|
pHeadMblk->mBlkPktHdr.len -= DOT11_WEP_ICV_SIZE+DOT11_WEP_IV_SIZE;
|
|
}
|
|
}
|
|
|
|
pLlcHeader = (DOT11_LLC_HEADER *)(pCluster + pDataOffset);
|
|
|
|
stripLlc = (((ntohs(pLlcHeader->orgCode) == DOT11_LLC_RFC1024) ||
|
|
(ntohs(pLlcHeader->orgCode) == DOT11_LLC_8021H)) &&
|
|
!((ntohs(pLlcHeader->protocol) == 0x809B) ||
|
|
(ntohs(pLlcHeader->protocol) == 0x80F3)));
|
|
|
|
pDataOffset += (stripLlc ? DOT11_SNAP_HEADER_LEN : 0);
|
|
pDataOffset -= sizeof(UINT16);
|
|
|
|
/* Adjust the length for the missing 802.11 Header and SNAP Header */
|
|
pHeadMblk->mBlkHdr.mLen -= sizeof(DOT11_HEADER) +
|
|
(stripLlc ? DOT11_SNAP_HEADER_LEN : 0);
|
|
pHeadMblk->mBlkPktHdr.len -= sizeof(DOT11_HEADER) +
|
|
(stripLlc ? DOT11_SNAP_HEADER_LEN : 0);
|
|
|
|
|
|
/* If the LLC header has not been removed, the length of packet
|
|
must be filled in at the front of the packet */
|
|
if (!stripLlc)
|
|
{
|
|
*((UINT16*)(pCluster + pDataOffset)) =
|
|
htons(pHeadMblk->mBlkPktHdr.len);
|
|
}
|
|
|
|
/* If required, add in the egress VLAN tag. 802.1X packets are an
|
|
exception */
|
|
if ((pDot11->sme->vlanEnabled) &&
|
|
(pKsl->pBss->vlanId != DOT11_NO_VLAN) &&
|
|
(*(UINT16 *)(pHeadMblk->mBlkHdr.mData + pDataOffset) !=
|
|
(DOT1X_ETHERTYPE)))
|
|
{
|
|
pDataOffset -= DOT11_8021Q_TAG_LEN;
|
|
|
|
|
|
pHeadMblk->mBlkHdr.mLen += DOT11_8021Q_TAG_LEN;
|
|
pHeadMblk->mBlkPktHdr.len += DOT11_8021Q_TAG_LEN;
|
|
|
|
*(UINT16 *)(pCluster + pDataOffset) = htons(DOT11_ETHERTYPE_8021Q);
|
|
*((UINT16 *)(pCluster + pDataOffset + 2)) =
|
|
htons(pKsl->pBss->vlanId);
|
|
}
|
|
|
|
|
|
/* Now that we've calculated the offsets, including WEP, write them to the
|
|
Mblk, leaving room for the first twelve bytes of the ethernet header (the
|
|
ethertype field will be used direct from the SNAP header). */
|
|
pHeadMblk->mBlkHdr.mData += pDataOffset - (2 * DOT11_ADDR_LEN);
|
|
|
|
/* Copy the DA and SA over from the dot11 header, overwriting the non-
|
|
relevent portions of the SNAP header. The ethernet packet starts 14 bytes
|
|
before the pDataOffset. The ethertype remains untouched, as accounted for
|
|
by pDataOffset. */
|
|
switch(pDot11->dot11Mode)
|
|
{
|
|
case DOT11_MODE_ESS:
|
|
/* Find the source and copy it over */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr3,
|
|
(char*)(pCluster + pDataOffset - (1 * DOT11_ADDR_LEN)));
|
|
|
|
/* Find the destination and copy it over */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr1,
|
|
(char*)(pCluster + pDataOffset - (2 * DOT11_ADDR_LEN)));
|
|
break;
|
|
case DOT11_MODE_IBSS:
|
|
/* Find the source and copy it over */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr2,
|
|
(char*)(pCluster + pDataOffset - (1 * DOT11_ADDR_LEN)));
|
|
/* Find the destination and copy it over */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr1,
|
|
(char*)(pCluster + pDataOffset - (2 * DOT11_ADDR_LEN)));
|
|
break;
|
|
case DOT11_MODE_AP:
|
|
/* Find the destination and copy it over. Note that this is an
|
|
overlapping copy, since the DA field of the etherheader extends
|
|
four bytes into the addr3 field. Do a two stage copy on MIPS,
|
|
since there is a known bug (SPR 89530) in MIPS where bcopy does
|
|
not perform overlapping copies correctly. We can use pCluster
|
|
offset 0 as a temporary buffer since this just gets discarded
|
|
anyways. */
|
|
|
|
/* Find the source and copy it over */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr3,
|
|
(char*)pCluster);
|
|
|
|
DOT11_ADDR_COPY((char*)pHeader->addr2,
|
|
(char*)(pCluster + pDataOffset - (1 * DOT11_ADDR_LEN)));
|
|
|
|
DOT11_ADDR_COPY((char*)pCluster,
|
|
(char*)(pCluster + pDataOffset - (2 * DOT11_ADDR_LEN)))
|
|
|
|
|
|
break;
|
|
default:
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Device is in unknown mode\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
netMblkClChainFree(pHeadMblk);
|
|
return ERROR;
|
|
break;
|
|
}
|
|
|
|
pHeadMblk->mBlkHdr.mLen += DOT11_ETHER_HEADER_LEN;
|
|
pHeadMblk->mBlkHdr.mFlags |= M_PKTHDR;
|
|
pHeadMblk->mBlkPktHdr.len += DOT11_ETHER_HEADER_LEN;
|
|
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: called ethertype=%04x len=%d!\n",
|
|
ntohs(*(UINT16 *)(pHeadMblk->mBlkHdr.mData + DOT11_ADDR_LEN*2)),
|
|
pHeadMblk->mBlkPktHdr.len,0,0,0,0));
|
|
|
|
if (!pDot11->externalRsn) { /* MRY: Let external supp handle eapol */
|
|
/* Check if this is an EAPOL-Key message. If so, and if an advanced
|
|
security policy is in place, then pass the packet to the RSN module
|
|
instead of the MUX */
|
|
if ((pKsl->pBss->secPol != DOT11_SECPOL_NONE) && (stripLlc) &&
|
|
(*(UINT16 *)(pHeadMblk->mBlkHdr.mData + DOT11_ADDR_LEN*2) ==
|
|
(DOT1X_ETHERTYPE)))
|
|
{
|
|
if (((DOT11_EAPOL_KEY_PKT *)(pHeadMblk->mBlkHdr.mData +
|
|
DOT11_ETHER_HEADER_LEN))->eapolType
|
|
== DOT11_EAPOL_TYPE_KEY)
|
|
{
|
|
/* This routine will consume the packet regardless of return
|
|
status */
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
if (pDot11->sme->rsn.eapolPktReceive != NULL)
|
|
{
|
|
pDot11->sme->rsn.eapolPktReceive(pDot11, pHeadMblk);
|
|
}
|
|
else
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: RSN Module not present for "
|
|
"EAPOL-Key\n",0,0,0,0,0,0));
|
|
netMblkClChainFree(pHeadMblk);
|
|
}
|
|
return OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If this is an AP, then check the destination address to see if it is
|
|
an associated station. If so, then quickly route it back to the send
|
|
routine. */
|
|
if (pDot11->dot11Mode == DOT11_MODE_AP)
|
|
{
|
|
if (((pBridgeKsl = pDot11->sme->ksl.lookup(pDot11,
|
|
(UINT8 *)pHeadMblk->mBlkHdr.mData)) != NULL) &&
|
|
(pBridgeKsl->type.sta.associated))
|
|
{
|
|
|
|
/* Check that the destination station is on the same VLAN as the
|
|
source, if appropriate */
|
|
if ((!pDot11->sme->vlanEnabled) ||
|
|
(pBridgeKsl->pBss->vlanId == pKsl->pBss->vlanId))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: Quick bridge to destination "
|
|
DOT11_MAC_ADDR_STR "\n",
|
|
DOT11_MAC_ADDR(pBridgeKsl->macAddr)));
|
|
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
return pDot11->dpe->endSend((END_OBJ *)pDot11, pHeadMblk);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pKsl->dot1xControlled)
|
|
{
|
|
/* Check if we are in 802.1X mode. If so, we need to check with the
|
|
802.1X state machine to see if this is a valid ingress packet */
|
|
if ((pKsl->dot1xAllowed) ||
|
|
((stripLlc) &&
|
|
(*(UINT16 *)(pHeadMblk->mBlkHdr.mData + DOT11_ADDR_LEN*2) ==
|
|
(DOT1X_ETHERTYPE))))
|
|
{
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
END_RCV_RTN_CALL(&pDot11->endObj, pHeadMblk);
|
|
}
|
|
else
|
|
{
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndReceive: 802.1X rejected ingress packet\n",
|
|
0,0,0,0,0,0));
|
|
pDot11->stats.rxDot1xDropped ++;
|
|
netMblkClChainFree(pHeadMblk);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
/* Pass the packet up to the vxWorks network stack */
|
|
END_RCV_RTN_CALL(&pDot11->endObj, pHeadMblk);
|
|
}
|
|
|
|
/* Note : the KSL lock was released and the packet consumed in all
|
|
branches of the IF statement above */
|
|
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeEndSend - END Send routine for WLS Framework
|
|
*
|
|
* This is the END Send routine that is called when END wishes to send a packet
|
|
* out the interface. This function will create a new Mblk/cl-blk/cluster
|
|
* chain and put the appropriate 802.11 header into it. The new chain is linked
|
|
* in front of the old chain, and the old header is adjusted to offset behind
|
|
* the ethernet header. The SNAP header is also created in the first MBlk.
|
|
*
|
|
* Note that the entire ethernet header must be in one cluster.
|
|
*
|
|
* RETURNS: OK or ERROR on allocation error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeEndSend
|
|
(
|
|
END_OBJ * pEnd, /* Pointer to END_OBJ */
|
|
M_BLK_ID pDataMblk /* Mblk containing payload */
|
|
)
|
|
{
|
|
DOT11_FW * pDot11 = (DOT11_FW *)pEnd;
|
|
DOT11_KSL_ENTRY * pKsl;
|
|
STATUS status = OK;
|
|
int i;
|
|
M_BLK_ID pMblk;
|
|
UINT16 destVlan;
|
|
UINT16 etherType;
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Called for dest " DOT11_MAC_ADDR_STR "\n",
|
|
DOT11_MAC_ADDR((UINT8 *)pDataMblk->mBlkHdr.mData)));
|
|
|
|
/* Ensure a correct MBlk */
|
|
if ((pDataMblk == NULL) || (pDataMblk->mBlkHdr.mType == MT_FREE))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/* Sanity check. */
|
|
if ((pDot11 == NULL) || (pDot11->hdd == NULL))
|
|
{
|
|
netMblkClChainFree(pDataMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
if (pDot11->dot11Mode != DOT11_MODE_AP)
|
|
{
|
|
/* If this isn't AP mode, we don't need to worry about multiple BSSs */
|
|
etherType = *(UINT16 *)(pDataMblk->mBlkHdr.mData + 2 * DOT11_ADDR_LEN);
|
|
status = dot11DpeEndSendBss(pDot11, pDataMblk, DOT11_DEFAULT_BSS);
|
|
}
|
|
else
|
|
{
|
|
/* Get the VLAN from the VLAN tag, if present */
|
|
if ((pDot11->sme->vlanEnabled) &&
|
|
(*(UINT16 *)(pDataMblk->mBlkHdr.mData +
|
|
DOT11_ADDR_LEN + DOT11_ADDR_LEN) ==
|
|
ntohs(DOT11_ETHERTYPE_8021Q)))
|
|
{
|
|
destVlan = ntohs(*(UINT16 *)(pDataMblk->mBlkHdr.mData +
|
|
DOT11_ETHER_HEADER_LEN)) &
|
|
DOT11_8021Q_VLAN_MASK;
|
|
etherType = *(UINT16 *)(pDataMblk->mBlkHdr.mData +
|
|
DOT11_ETHER_HEADER_LEN + sizeof(UINT16));
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Called for VLAN %d \n", destVlan,
|
|
0,0,0,0,0));
|
|
}
|
|
else
|
|
{
|
|
etherType = *(UINT16 *)(pDataMblk->mBlkHdr.mData + 2 *
|
|
DOT11_ADDR_LEN);
|
|
destVlan = DOT11_NO_VLAN;
|
|
}
|
|
|
|
/* Check if this is a multicast or unicast packet. The destination
|
|
address is at the start of the ethernet header, which is at the start
|
|
of the packet */
|
|
if (DOT11_IS_MCAST(pDataMblk->mBlkHdr.mData))
|
|
{
|
|
/* Send packet to each connected BSS */
|
|
for (i=0; i<DOT11_BSS_MAX; i++)
|
|
{
|
|
if (pDot11->sme->bss[i].inUse)
|
|
{
|
|
/* If VLAN support is enabled, verify that the tagged VLAN
|
|
is that of the destination BSS, and forward */
|
|
if ((pDot11->sme->vlanEnabled) &&
|
|
(pDot11->sme->bss[i].vlanId != destVlan) &&
|
|
(etherType != DOT1X_ETHERTYPE))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Dropping bcast packet "
|
|
"sent to VLAN %d - BSS %d belongs to vlan"
|
|
" %d \n", destVlan, i,
|
|
pDot11->sme->bss[i].vlanId,0,0,0));
|
|
continue;
|
|
}
|
|
|
|
|
|
if ((pMblk = netMblkChainDup(pDot11->endObj.pNetPool,
|
|
pDataMblk, 0, M_COPYALL,
|
|
M_WAIT)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Out of MBlks sending"
|
|
" broadcast packet\n",0,0,0,0,0,0));
|
|
status = ERROR;
|
|
break;
|
|
}
|
|
|
|
status |= dot11DpeEndSendBss(pDot11, pMblk,
|
|
&pDot11->sme->bss[i]);
|
|
}
|
|
}
|
|
|
|
/* Free the original non-duplicated packet */
|
|
netMblkClChainFree(pDataMblk);
|
|
|
|
}
|
|
else
|
|
{
|
|
pKsl = pDot11->sme->ksl.lookup(pDot11,
|
|
(UINT8 *)pDataMblk->mBlkHdr.mData);
|
|
|
|
/* If there is no KSL entry, then we are not connected to the
|
|
destination */
|
|
if (pKsl == NULL)
|
|
{
|
|
/* Drop packet silently */
|
|
netMblkClChainFree(pDataMblk);
|
|
status = OK;
|
|
}
|
|
else
|
|
{
|
|
|
|
/* If VLAN support is enabled, verify that the tagged VLAN
|
|
is that of the destination BSS, and forward */
|
|
if ((pDot11->sme->vlanEnabled) &&
|
|
(pKsl->pBss->vlanId != destVlan) &&
|
|
(etherType != DOT1X_ETHERTYPE))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Dropping UCAST packet "
|
|
"sent to VLAN %d - BSS %d belongs to vlan"
|
|
" %d \n", destVlan, pKsl->pBss->bssNum,
|
|
pKsl->pBss->vlanId, 0,0,0));
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSend: Dropping UCAST to "
|
|
DOT11_MAC_ADDR_STR "\n",
|
|
DOT11_MAC_ADDR(pKsl->macAddr)));
|
|
|
|
netMblkClChainFree(pDataMblk);
|
|
status = OK;
|
|
}
|
|
else
|
|
{
|
|
status = dot11DpeEndSendBss(pDot11, pDataMblk, pKsl->pBss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeEndSendBss - END Send routine for a specific BSS
|
|
*
|
|
* This is the END Send routine that is called when END wishes to send a packet
|
|
* out the interface. This function will create a new Mblk/cl-blk/cluster
|
|
* chain and put the appropriate 802.11 header into it. The new chain is linked
|
|
* in front of the old chain, and the old header is adjusted to offset behind
|
|
* the ethernet header. The SNAP header is also created in the first MBlk.
|
|
*
|
|
* Note that the entire ethernet header must be in one cluster.
|
|
*
|
|
* RETURNS: OK or ERROR on allocation error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeEndSendBss
|
|
(
|
|
DOT11_FW * pDot11, /* Pointer to END_OBJ */
|
|
M_BLK_ID pDataMblk, /* Mblk containing payload */
|
|
DOT11_BSS * pBss /* BSS to send packet to */
|
|
)
|
|
{
|
|
STATUS status = ERROR; /* Status of second-level send function */
|
|
int fragLen; /* Max size of each packet, NOT inc header*/
|
|
int totalLen; /* Total PAYLOAD data to be sent */
|
|
int currentLen; /* Cumulative PAYLOAD data sent */
|
|
int currentFrag; /* Cumulative fragments sent - ZB */
|
|
int pktLen; /* Used when calc indiv packet details */
|
|
M_BLK_ID pCurrentMblk; /* Used when a new MBlk needs allocation */
|
|
M_BLK_ID pNewMblk; /* Used when a new MBlk needs allocation */
|
|
M_BLK_ID pHeadMblk; /* Used when a new MBlk needs allocation */
|
|
CL_BLK_ID pHdrClBlk; /* Cl-Blk containing header info */
|
|
UINT8 * pDstAddr; /* Pointer to DA for all packets */
|
|
UINT8 * pSrcAddr; /* Pointer to SA for all packets */
|
|
|
|
if (pBss->linkStatus == DOT11_LINK_DOWN)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSendBss: Not connected\n",0,0,0,0,0,0));
|
|
|
|
netMblkClChainFree(pDataMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Drop undersized packets */
|
|
if (pDataMblk->mBlkHdr.mLen < DOT11_ETHER_HEADER_LEN)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeEndSendBss: MBlk not formed correctly. EH must "
|
|
"not be split across MBlks!. Len = %d\n",
|
|
pDataMblk->mBlkHdr.mLen, 0, 0, 0, 0,0));
|
|
netMblkClChainFree(pDataMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Store the SA and DA so that we can put it in every packet. Since
|
|
we know that it's in the first cluster by the check above, we just
|
|
increment the refcnt on the first cluster so that nobody frees it
|
|
until we're done with all fragments*/
|
|
pDstAddr = (UINT8*)pDataMblk->mBlkHdr.mData;
|
|
pSrcAddr = (UINT8*)pDataMblk->mBlkHdr.mData + DOT11_ADDR_LEN;
|
|
|
|
/* Check if we need to perform fragmentation */
|
|
if (((pDataMblk->mBlkPktHdr.len + sizeof(DOT11_HEADER) +
|
|
DOT11_SNAP_HEADER_LEN - DOT11_ETHER_HEADER_LEN + DOT11_FCS_SIZE)
|
|
<= pDot11->dpe->fragThreshold) || (DOT11_IS_MCAST(pDstAddr)))
|
|
{
|
|
/* No fragmentation necessary */
|
|
status = dot11DpeFragmentSend
|
|
((DOT11_FW*)pDot11,
|
|
(UINT8*)pDataMblk->mBlkHdr.mData,
|
|
(UINT8*)pDataMblk->mBlkHdr.mData+DOT11_ADDR_LEN,
|
|
(M_BLK_ID)pDataMblk,
|
|
(int)(0 | DOT11_FRAGMENT_LAST), 0,
|
|
pBss);
|
|
}
|
|
else
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeEndSendBss: Fragmenting pkt len %d/%d frag=%d\n",
|
|
pDataMblk->mBlkPktHdr.len,
|
|
pDataMblk->mBlkPktHdr.len + sizeof(DOT11_HEADER) -
|
|
DOT11_ETHER_HEADER_LEN + DOT11_FCS_SIZE,
|
|
pDot11->dpe->fragThreshold,
|
|
0,0,0));
|
|
|
|
if (pDot11->dpe->fragThreshold < DOT11_FRAGMENT_MIN_SIZE)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeEndSendBss: Invalid fragmentation threshold\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pDataMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
pHdrClBlk = pDataMblk->pClBlk;
|
|
pHdrClBlk->clRefCnt ++;
|
|
|
|
/* We need to create appropriately sized fragments. Choose the maximum
|
|
length of fragment based on the fragmentation size. Since
|
|
802.11(2003) 9.4 states that the size must always be even except for
|
|
the last packet, accomodate that condition as well */
|
|
fragLen = (pDot11->dpe->fragThreshold - sizeof(DOT11_HEADER) -
|
|
DOT11_FCS_SIZE) & (~0x00000001);
|
|
totalLen = pDataMblk->mBlkPktHdr.len;
|
|
currentLen = 0;
|
|
currentFrag = 0;
|
|
pNewMblk = pDataMblk;
|
|
|
|
/* This is the main fragment creating loop. The original m-blk chain
|
|
is examined. Anytime an M-blk has a fragment boundary in it, the
|
|
length is adjusted to compensate, and a new Mblk is created for the
|
|
part of the cluster after the boundary with the mData pointer adjusted.
|
|
The reference count field in the Cl-Blk is used to keep track of
|
|
multiple uses of a cluster. */
|
|
while (totalLen > currentLen)
|
|
{
|
|
/* For the first fragment, assume that dot11DpeFragmentSend() is
|
|
going to add a SNAP header, and account for it */
|
|
if (currentLen == 0)
|
|
{
|
|
pktLen = DOT11_SNAP_HEADER_LEN - DOT11_ETHER_HEADER_LEN;
|
|
}
|
|
else
|
|
{
|
|
pktLen = 0;
|
|
}
|
|
|
|
pHeadMblk = pNewMblk;
|
|
pCurrentMblk = pHeadMblk;
|
|
|
|
/* Advance though the current M-Blk chain until we find an M-blk
|
|
with a fragment boundary */
|
|
while ((pCurrentMblk != NULL) &&
|
|
((pktLen + pCurrentMblk->mBlkHdr.mLen) <= fragLen))
|
|
{
|
|
/* Since there's room for the entire mBlk, add it to the
|
|
chain. */
|
|
pktLen += pCurrentMblk->mBlkHdr.mLen;
|
|
pCurrentMblk = pCurrentMblk->mBlkHdr.mNext;
|
|
}
|
|
|
|
/* Getting here means that either we're at a cluster boundary or
|
|
we're at the end of the chain. Either way, fill in the first Mblk
|
|
with the appropriate header details */
|
|
pHeadMblk->mBlkHdr.mFlags |= M_PKTHDR;
|
|
|
|
|
|
if (pCurrentMblk != NULL)
|
|
{
|
|
/* This is not the last fragment. Adjust the last Mblk of this
|
|
fragment to reflect the boundary. */
|
|
pHeadMblk->mBlkPktHdr.len = fragLen;
|
|
currentLen += fragLen;
|
|
|
|
/* Allocate a new mBlk for the start of the next packet */
|
|
if ((pNewMblk = netMblkGet(pDot11->endObj.pNetPool,
|
|
M_DONTWAIT, MT_DATA)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeEndSendBss: Error allocting Mblk ln%d\n",
|
|
__LINE__,0, 0, 0, 0,0));
|
|
|
|
netMblkClChainFree(pHeadMblk);
|
|
/* Free the Cl-Blk that we incremented refCnt earlier */
|
|
netClBlkFree(pDot11->endObj.pNetPool, pHdrClBlk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Join to the same cl-blk and increment the reference count */
|
|
netMblkDup(pCurrentMblk, pNewMblk);
|
|
|
|
/* Offset to the fragmentation point */
|
|
pNewMblk->mBlkHdr.mData = pCurrentMblk->mBlkHdr.mData +
|
|
fragLen - pktLen;
|
|
pNewMblk->mBlkHdr.mLen = pCurrentMblk->mBlkHdr.mLen -
|
|
(fragLen - pktLen);
|
|
|
|
/* Sever the old packet, and connect up the new */
|
|
pNewMblk->mBlkHdr.mNext = pCurrentMblk->mBlkHdr.mNext;
|
|
pCurrentMblk->mBlkHdr.mNext = NULL;
|
|
|
|
/* Adjust the length of the old mblk to reflect the boundary */
|
|
pCurrentMblk->mBlkHdr.mLen = fragLen - pktLen;
|
|
|
|
status = dot11DpeFragmentSend(pDot11, pDstAddr, pSrcAddr,
|
|
pHeadMblk,
|
|
currentFrag,
|
|
min((totalLen - currentLen) + sizeof(DOT11_HEADER) - sizeof(UINT16),
|
|
pDot11->dpe->fragThreshold), pBss);
|
|
currentFrag ++;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
pHeadMblk->mBlkPktHdr.len = totalLen - currentLen;
|
|
currentLen = totalLen;
|
|
/* The end of the chain is simple to deal with. Just send the
|
|
packet */
|
|
status = dot11DpeFragmentSend(pDot11, pDstAddr, pSrcAddr,
|
|
pHeadMblk,
|
|
currentFrag|DOT11_FRAGMENT_LAST,
|
|
0,
|
|
pBss);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/* Free the Cl-Blk that we incremented refCnt on earlier */
|
|
netClBlkFree(pDot11->endObj.pNetPool, pHdrClBlk);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeFragmentSend - Sends a particular fragment out the interface
|
|
*
|
|
* This function does the real work in the transmit. It takes the M-Blk
|
|
* chain that has been fragmented if applicable, adds an 802.11 header and a
|
|
* SNAP header if applicable and sends it to the HDD.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeFragmentSend
|
|
(
|
|
DOT11_FW * pDot11, /* Pointer to device structure */
|
|
UINT8 * pDstAddr, /* Pointer to DA */
|
|
UINT8 * pSrcAddr, /* Pointer to SA */
|
|
M_BLK_ID pDataMblk, /* Mblk containing payload */
|
|
int fragNum, /* Fragment number, bit 15 set if last */
|
|
int nextFragLen, /* Length of the next fragment */
|
|
DOT11_BSS * pBss /* BSS to send the packet to */
|
|
)
|
|
{
|
|
UINT8 * pCluster; /* Cluster with 802.11 Header */
|
|
M_BLK_ID pMblk; /* MBlk for 802.11 header */
|
|
M_BLK_ID pLastMblk; /* Working MBlk */
|
|
DOT11_HEADER * pHeader; /* Dot11 header data structure */
|
|
int length; /* Length of the final packet */
|
|
UINT16 etherType; /* Ptr to location of ethertype */
|
|
DOT11_KSL_ENTRY * pKsl; /* KSL entry for the immediate dest */
|
|
UINT32 txRate; /* Rate at which to transmit */
|
|
DOT11_ENCRYPT_TYPE encryptType; /* Type of encryption to use */
|
|
UINT32 encryptKey; /* key to use */
|
|
UINT32 encryptIndex; /* WEP index, 0 for pw keys */
|
|
UINT32 iv; /* WEP initialization vector */
|
|
UINT8 * pTsc; /* Pointer to packet ctr for TKIP/AES */
|
|
STATUS status = OK;
|
|
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Called first Mblk len = %d framelen=%d "
|
|
"fragment=%04x!\n", pDataMblk->mBlkHdr.mLen ,
|
|
pDataMblk->mBlkPktHdr.len, fragNum, 0,0,0));
|
|
|
|
if ((fragNum & DOT11_FRAGMENT_MASK) == 0)
|
|
{
|
|
/* If this is the first fragment, we need to "remove" the old 802.3
|
|
and get a copy of the ethertype. */
|
|
etherType = *(UINT16 *)(pDataMblk->mBlkHdr.mData +
|
|
(2 * DOT11_ADDR_LEN));
|
|
|
|
/* If this is an 802.1Q tagged packet, strip the tag off, as well */
|
|
if (etherType == htons(DOT11_ETHERTYPE_8021Q))
|
|
{
|
|
/* The correct ethertype follows the 802.1Q tag, which is offset
|
|
two from the end of the EH (the other two bytes were in the
|
|
ethertype field of the EH */
|
|
etherType = *(UINT16 *)(pDataMblk->mBlkHdr.mData +
|
|
(2 * DOT11_ADDR_LEN) + DOT11_8021Q_TAG_LEN);
|
|
|
|
pDataMblk->mBlkHdr.mData = pDataMblk->mBlkHdr.mData +
|
|
DOT11_8021Q_TAG_LEN;
|
|
pDataMblk->mBlkHdr.mLen = pDataMblk->mBlkHdr.mLen -
|
|
DOT11_8021Q_TAG_LEN;
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Called for 802.1Q packet. "
|
|
"Correct ethertype = %04x\n", ntohs(etherType),0,0,0,0,0));
|
|
}
|
|
|
|
/* Advance the "start of data" pointer to ignore the Ethernet header.
|
|
Adjust the Mblk header to reflect that it is no longer the first mblk
|
|
in the chain. */
|
|
pDataMblk->mBlkHdr.mData = pDataMblk->mBlkHdr.mData +
|
|
DOT11_ETHER_HEADER_LEN;
|
|
pDataMblk->mBlkHdr.mLen = pDataMblk->mBlkHdr.mLen -
|
|
DOT11_ETHER_HEADER_LEN;
|
|
}
|
|
else
|
|
{
|
|
/* Since there is no ethernet header present, offset pSrcAddr (which points to the
|
|
original data block) to get the etherType */
|
|
etherType = *(UINT16 *)(pSrcAddr + DOT11_ADDR_LEN);
|
|
if (etherType == htons(DOT11_ETHERTYPE_8021Q))
|
|
{
|
|
etherType = *(UINT16 *)(pSrcAddr + DOT11_ADDR_LEN + DOT11_8021Q_TAG_LEN);
|
|
}
|
|
}
|
|
|
|
/* The payload is no longer the first packet in the Mblk chain if we're
|
|
adding an 802.11 header. */
|
|
pDataMblk->mBlkHdr.mFlags &= (~M_PKTHDR);
|
|
|
|
/* Next, create an Mblk containing the 802.11 Header */
|
|
if ((pMblk = netTupleGet(pDot11->endObj.pNetPool, DOT11_MTU, M_DONTWAIT,
|
|
MT_DATA, FALSE)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Error getting Mblk\n", 0, 0, 0, 0,
|
|
0, 0));
|
|
netMblkClChainFree(pDataMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
pCluster = (UINT8 *)pMblk->mBlkHdr.mData;
|
|
|
|
/* Clear some space for the 802.11 header so that we don't need to set
|
|
fields if their values is zero. */
|
|
bzero((char*)pCluster, sizeof(DOT11_HEADER));
|
|
|
|
pHeader = (DOT11_HEADER *)pCluster;
|
|
|
|
/* Set the frame control and address fields appropriately for our network
|
|
role. See 7.2.2 - Table 2 of IEEE 802.11/2003 for details. */
|
|
switch(pDot11->dot11Mode)
|
|
{
|
|
case DOT11_MODE_ESS:
|
|
pHeader->frameCtrl =
|
|
DOT11_CPU_TO_LE_16(DOT11_TYPE_DATA | DOT11_FCTL_TO_DS);
|
|
DOT11_ADDR_COPY((char*)pBss->bssid, (char*)pHeader->addr1);
|
|
DOT11_ADDR_COPY((char*)pSrcAddr, (char*)pHeader->addr2);
|
|
DOT11_ADDR_COPY((char*)pDstAddr, (char*)pHeader->addr3);
|
|
break;
|
|
case DOT11_MODE_IBSS:
|
|
pHeader->frameCtrl =
|
|
DOT11_CPU_TO_LE_16(DOT11_TYPE_DATA);
|
|
DOT11_ADDR_COPY((char*)pDstAddr, (char*)pHeader->addr1);
|
|
DOT11_ADDR_COPY((char*)pSrcAddr, (char*)pHeader->addr2);
|
|
DOT11_ADDR_COPY((char*)pBss->bssid, (char*)pHeader->addr3);
|
|
break;
|
|
case DOT11_MODE_AP:
|
|
pHeader->frameCtrl =
|
|
DOT11_CPU_TO_LE_16(DOT11_TYPE_DATA | DOT11_FCTL_FROM_DS);
|
|
DOT11_ADDR_COPY((char*)pDstAddr, (char*)pHeader->addr1);
|
|
DOT11_ADDR_COPY((char*)pBss->bssid, (char*)pHeader->addr2);
|
|
DOT11_ADDR_COPY((char*)pSrcAddr, (char*)pHeader->addr3);
|
|
break;
|
|
default:
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Device is in unknown mode\n",0,0,0,0,
|
|
0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
break;
|
|
}
|
|
|
|
/* If this is a fragmented packet, set the more fragment bit and the
|
|
fragment number field appropriately */
|
|
/*If this isn't the only fragment*/
|
|
if (fragNum != (DOT11_FRAGMENT_LAST | 0))
|
|
{
|
|
/* Set the "More Fragments" flag if this isn't the last frag */
|
|
if ((fragNum & DOT11_FRAGMENT_LAST) == 0)
|
|
{
|
|
pHeader->frameCtrl |= DOT11_CPU_TO_LE_16(DOT11_FCTL_MORE_FRAG);
|
|
}
|
|
|
|
/* Fill in the fragment number field */
|
|
pHeader->seqCtrl = DOT11_CPU_TO_LE_16(fragNum & DOT11_FRAGMENT_MASK);
|
|
}
|
|
|
|
/* Start calculating the length of the new MBlk containing the DOT11
|
|
header, SNAP header and IV if applicable */
|
|
length = sizeof(DOT11_HEADER);
|
|
|
|
|
|
encryptIndex = 0;
|
|
encryptKey = DOT11_KEYINDEX_NONE;
|
|
encryptType = DOT11_ENCRYPT_NONE;
|
|
|
|
/* Get the current rate from the KSL entry for the immediate destination,
|
|
aka 802.11 addr 1. The encryption state for the immediate dest. is also
|
|
in the KSL record. */
|
|
if ((pKsl = pDot11->sme->ksl.lookup(pDot11, pHeader->addr1)) == NULL)
|
|
{
|
|
txRate = pBss->bcastRate;
|
|
}
|
|
else /* Found KSL record */
|
|
{
|
|
if (pDot11->sme->ksl.lock(pDot11) != OK)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Cannot get KSL lock.\n", 0, 0, 0, 0,
|
|
0, 0));
|
|
|
|
txRate = pBss->bcastRate;
|
|
encryptType = DOT11_ENCRYPT_NONE;
|
|
/* If we can't get the KSL lock, then we shouldn't use the KSL
|
|
entry */
|
|
pKsl = NULL;
|
|
}
|
|
else /* we got the lock OK */
|
|
{
|
|
txRate = pKsl->currentTxRate;
|
|
|
|
encryptType = pKsl->uniEncryptType;
|
|
|
|
encryptKey = pKsl->uniEncryptIndex;
|
|
encryptIndex = 0;
|
|
|
|
/* Release the KSL protection semaphore */
|
|
pDot11->sme->ksl.unlock(pDot11);
|
|
}
|
|
}
|
|
/* Set pKsl to NULL if this is a multicast packet */
|
|
if ((DOT11_IS_MCAST(pHeader->addr1)) || (pKsl == NULL))
|
|
{
|
|
pKsl = NULL;
|
|
pTsc = pBss->tscMultiTx;
|
|
}
|
|
else
|
|
{
|
|
pTsc = pKsl->tscUniTx;
|
|
}
|
|
|
|
|
|
/* If a key mapping entry wasn't set, then we need to check to see if
|
|
there is a multicast entry */
|
|
if ((pKsl == NULL) || (encryptType == DOT11_ENCRYPT_NONE))
|
|
{
|
|
encryptIndex = pBss->multiKeySlot;
|
|
encryptKey = pBss->multiEncryptIndex;
|
|
|
|
encryptType = pBss->multiEncryptType;
|
|
}
|
|
|
|
/* Check for an exclusion policy for 802.1x. If the packet is an EAPOL
|
|
packet and the 802.1X exclusion policy is set, then don't set the WEP
|
|
flag */
|
|
if ((encryptType != DOT11_ENCRYPT_NONE) &&
|
|
(etherType == DOT1X_ETHERTYPE))
|
|
{
|
|
/* MRY: For WPA/WPA2 (dot1x/PSK), if the 4-way handshake is not complete yet,
|
|
* then don't encrypt dot1x packets.
|
|
*/
|
|
if (pKsl &&
|
|
(((pKsl->negAuthPol == DOT11_AUTHPOL_8021X) || (pKsl->negAuthPol == DOT11_AUTHPOL_PSK)) &&
|
|
(pKsl->fourWayState != DOT11_FOURWAY_ESTABLISHED))
|
|
)
|
|
{
|
|
encryptType = DOT11_ENCRYPT_NONE;
|
|
}
|
|
}
|
|
|
|
/* Check if we need to run encryption on this packet */
|
|
if ((encryptType == DOT11_KEY_TYPE_WEP40) ||
|
|
(encryptType == DOT11_KEY_TYPE_WEP104))
|
|
{
|
|
/* If so, we need to add an IV to the end of the Header cluster, and
|
|
and ICV to the last mblk in the chain, if possible. If there isn't
|
|
room then we'll have to allocate a whole new MBLK-cluster chain just
|
|
for four bytes. C'est la vie.*/
|
|
|
|
iv = ++ pDot11->dpe->currentIV;
|
|
|
|
/* First add the IV. No need to swap, since it's more or less arbitrary
|
|
*/
|
|
*(pCluster + length) = iv & 0x000000ff;
|
|
length ++; nextFragLen ++;
|
|
*(pCluster + length) = (iv & 0x0000ff00) >> 8;
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = (iv & 0x00ff0000) >> 16;
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = encryptIndex << 6;
|
|
length ++;nextFragLen ++;
|
|
|
|
/* Next, adjust the frame control header to indicate we're using WEP*/
|
|
pHeader->frameCtrl |= DOT11_CPU_TO_LE_16(DOT11_FCTL_WEP);
|
|
}
|
|
else if (encryptType == DOT11_KEY_TYPE_TKIP)
|
|
{
|
|
|
|
pHeader->frameCtrl |= DOT11_CPU_TO_LE_16(DOT11_FCTL_WEP);
|
|
|
|
*(pCluster + length) = pTsc[1];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = (pTsc[1] | 0x20) & 0x7f;
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[0];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = DOT11_EXT_IV | (encryptIndex << 6);
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[2];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[3];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[4];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[5];
|
|
length ++;nextFragLen ++;
|
|
|
|
/* increment the packet count */
|
|
DOT11_BYTEARRAY_INC(pTsc, DOT11_TSC_LEN);
|
|
}
|
|
else if (encryptType == DOT11_KEY_TYPE_AES)
|
|
{
|
|
|
|
pHeader->frameCtrl |= DOT11_CPU_TO_LE_16(DOT11_FCTL_WEP);
|
|
|
|
*(pCluster + length) = pTsc[0];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[1];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = 0;
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = DOT11_EXT_IV | (encryptIndex << 6);
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[2];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[3];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[4];
|
|
length ++;nextFragLen ++;
|
|
*(pCluster + length) = pTsc[5];
|
|
length ++;nextFragLen ++;
|
|
|
|
/* increment the packet count */
|
|
DOT11_BYTEARRAY_INC(pTsc, DOT11_TSC_LEN);
|
|
}
|
|
|
|
/* Only add the SNAP header if this is the first ( or only) packet in
|
|
a fragment chain, and there isn't a SNAP header already. */
|
|
if (((fragNum & DOT11_FRAGMENT_MASK) == 0) &&
|
|
(ntohs(etherType) > DOT11_ETHERMTU))
|
|
{
|
|
*(UINT16 *)(pCluster + length) = DOT11_CPU_TO_LE_16(0xaaaa);
|
|
*(UINT16 *)(pCluster + length + 2) = DOT11_CPU_TO_LE_16(0x0003);
|
|
*(UINT16 *)(pCluster + length + 4) = DOT11_CPU_TO_LE_16(0x0000);
|
|
*(UINT16 *)(pCluster + length + 6) = etherType;
|
|
length += DOT11_SNAP_HEADER_LEN;
|
|
}
|
|
|
|
/* Fill in the size, data location and link this Mblk to the payload */
|
|
pMblk->mBlkHdr.mData = (char *)pCluster;
|
|
pMblk->mBlkHdr.mLen = length;
|
|
pMblk->mBlkHdr.mNext = pDataMblk;
|
|
|
|
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
|
|
pMblk->mBlkPktHdr.len = length + pDataMblk->mBlkHdr.mLen;
|
|
|
|
/* Check if 802.1X is enabled. If so, we need to check that this is a
|
|
valid egress packet */
|
|
if (pKsl != NULL)
|
|
{
|
|
/* Drop the packet if the 802.1x port is not open */
|
|
if ((pKsl->dot1xControlled) && (!pKsl->dot1xAllowed) &&
|
|
(etherType != DOT1X_ETHERTYPE))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: 802.1X dropped packet\n",
|
|
0,0,0,0,0,0));
|
|
pDot11->stats.txDot1xDropped ++;
|
|
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/* If encryption is enabled, we need to add the ICV or MIC at this point */
|
|
if (encryptType != DOT11_ENCRYPT_NONE)
|
|
{
|
|
|
|
/* Now, find the last Mblk in the chain to add fake room for the ICV */
|
|
for (pLastMblk = pDataMblk; pLastMblk->mBlkHdr.mNext != NULL;
|
|
pLastMblk = pLastMblk->mBlkHdr.mNext)
|
|
{
|
|
}
|
|
if ((encryptType == DOT11_KEY_TYPE_WEP40) || (encryptType == DOT11_KEY_TYPE_WEP104))
|
|
{
|
|
pLastMblk->mBlkHdr.mLen += DOT11_WEP_ICV_SIZE;
|
|
|
|
/* Regardless of where the ICV is stored, we need to increase the total
|
|
frame length so that it is actually transmitted */
|
|
pMblk->mBlkPktHdr.len += DOT11_WEP_ICV_SIZE;
|
|
nextFragLen += DOT11_WEP_ICV_SIZE;
|
|
}
|
|
else if (encryptType == DOT11_KEY_TYPE_TKIP)
|
|
{
|
|
pLastMblk->mBlkHdr.mLen += DOT11_WEP_ICV_SIZE + DOT11_MIC_LEN;
|
|
pMblk->mBlkPktHdr.len += DOT11_WEP_ICV_SIZE + DOT11_MIC_LEN;
|
|
nextFragLen += DOT11_WEP_ICV_SIZE + DOT11_MIC_LEN;
|
|
}
|
|
else if (encryptType == DOT11_KEY_TYPE_AES)
|
|
{
|
|
pLastMblk->mBlkHdr.mLen += DOT11_MIC_LEN;
|
|
pMblk->mBlkPktHdr.len += DOT11_MIC_LEN;
|
|
nextFragLen += DOT11_MIC_LEN;
|
|
}
|
|
}
|
|
|
|
/* Hide the next fragment length at the end of the first cluster.
|
|
ar521xTxDescSetup() needs to know this to correctly set the duration in
|
|
the frame */
|
|
*(UINT32 *)(pMblk->mBlkHdr.mData + pMblk->mBlkHdr.mLen + sizeof(UINT32)) = nextFragLen;
|
|
|
|
|
|
/* Grab the transmission semaphore. Do this before examining the link
|
|
status, since the device could be in the process of flushing the TX queue.
|
|
We don't want to add to the queue while it's being flushed */
|
|
|
|
if (semTake(pDot11->dpe->transmitSem, DOT11_TX_SEM_WAIT) != OK)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: Unable to get TX Sem!\n", 0, 0, 0, 0,
|
|
0,0));
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Figure out if the link is up. If so, send the packet. If not, queue
|
|
it up for transmission. Each packet will also have an expiration timer
|
|
to prevent all of the MBlks from being used up on the TX queue */
|
|
|
|
if (pBss->linkStatus == DOT11_LINK_SLEEP)
|
|
{
|
|
pMblk->mBlkHdr.mNextPkt = NULL;
|
|
|
|
/* Store the rate and txIndex past the end of the Mblk. Since our
|
|
cluster pool is large enough for a max size 802.11 packet, there is
|
|
guaranteed to be room since we just put the header in this block */
|
|
*(UINT32 *)(pMblk->mBlkHdr.mData + pMblk->mBlkHdr.mLen) = txRate;
|
|
*((UINT32 *)(pMblk->mBlkHdr.mData + pMblk->mBlkHdr.mLen) + 1) =
|
|
encryptKey;
|
|
|
|
/* Special case - no other packets queued */
|
|
if (pDot11->dpe->transmitQueueHead == NULL)
|
|
{
|
|
pDot11->dpe->transmitQueueHead = pMblk;
|
|
pDot11->dpe->transmitQueueTail = pMblk;
|
|
}
|
|
else /* Insert onto tail */
|
|
{
|
|
pDot11->dpe->transmitQueueTail->mBlkHdr.mNextPkt = pMblk;
|
|
pDot11->dpe->transmitQueueTail = pMblk;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Check if there are any queued packets. If so, flush them before
|
|
continuing. This is necessary in case packets were added after the
|
|
queue was flushed but before the link status was changed.*/
|
|
if (pDot11->dpe->transmitQueueHead != NULL)
|
|
{
|
|
pDot11->dpe->transmitQueueFlush(pDot11);
|
|
}
|
|
|
|
/* Send the packet to the HDD, who will perform whatever card-specific
|
|
operations are necessary to transmit the packet in the correct state */
|
|
if (pDot11->hdd->rawPacketSend != NULL)
|
|
{
|
|
status = pDot11->hdd->rawPacketSend(pDot11, pMblk, txRate,
|
|
encryptKey);
|
|
}
|
|
else
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FATAL, DOT11_AREA_DPE,
|
|
("dot11DpeFragmentSend: No hdd.rawSend() implemented\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
semGive(pDot11->dpe->transmitSem);
|
|
netMblkClChainFree(pMblk);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
/* Release the transmit sem */
|
|
semGive(pDot11->dpe->transmitSem);
|
|
|
|
return status;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeTransmitQueueFlush - Flushes the transmit queue
|
|
*
|
|
* This function is called by the SME when the link status changes to connected.
|
|
* When called, it tries to send all packets that were queued since the link
|
|
* was put to sleep.
|
|
*
|
|
* RETURNS: OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeTransmitQueueFlush
|
|
(
|
|
DOT11_FW * pDot11 /* Pointer to device structure */
|
|
)
|
|
{
|
|
M_BLK_ID pMblk;
|
|
M_BLK_ID pNextMblk;
|
|
|
|
/* Grab the transmission semaphore. Do this before examining the link
|
|
status, since the device could be in the process of flushing the TX queue.
|
|
We don't want to add to the queue while it's being flushed */
|
|
|
|
if (semTake(pDot11->dpe->transmitSem, DOT11_TX_SEM_WAIT) != OK)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeTransmitQueueFlush: Unable to get TX Sem!\n", 0, 0, 0, 0,
|
|
0,0));
|
|
return ERROR;
|
|
}
|
|
|
|
pNextMblk = pDot11->dpe->transmitQueueHead;
|
|
|
|
while ((pMblk = pNextMblk) != NULL)
|
|
{
|
|
|
|
pNextMblk = pMblk->mBlkHdr.mNextPkt;
|
|
|
|
/* Send the packet to the HDD, who will perform whatever card-specific
|
|
operations are necessary to transmit the packet in the correct state.
|
|
Retrieve the txRate and the encryptionIndex from above. */
|
|
if (pDot11->hdd->rawPacketSend != NULL)
|
|
{
|
|
pDot11->hdd->rawPacketSend(pDot11, pMblk,
|
|
*(UINT32 *)(pMblk->mBlkHdr.mData + pMblk->mBlkHdr.mLen),
|
|
*((UINT32 *)(pMblk->mBlkHdr.mData + pMblk->mBlkHdr.mLen) + 1));
|
|
}
|
|
else
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FATAL, DOT11_AREA_DPE,
|
|
("dot11DpeTransmitQueueFlush: No hdd.rawSend() implemented\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
}
|
|
}
|
|
|
|
pDot11->dpe->transmitQueueHead = NULL;
|
|
pDot11->dpe->transmitQueueTail = NULL;
|
|
/* Release the transmit sem */
|
|
semGive(pDot11->dpe->transmitSem);
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* dot11DpeFragThresholdSet - Set the fragmentation threshold
|
|
*
|
|
* This fucntion sets the fragmentation threshold. This value is used by
|
|
* tbe
|
|
*
|
|
* RETURNS: Pointer to new END_OBJ (aka DOT11_FW) or NULL on error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeFragThresholdSet
|
|
(
|
|
DOT11_FW * pDot11, /* Pointer to device structure */
|
|
UINT32 fragThresh
|
|
)
|
|
{
|
|
if ((pDot11 == NULL) || (pDot11->dpe == NULL))
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
if (fragThresh > DOT11_MAX_PACKET)
|
|
{
|
|
fragThresh = 2304;
|
|
}
|
|
|
|
SPIN_LOCK_TASK_TAKE(&pDot11->tasLock);
|
|
|
|
pDot11->dpe->fragThreshold = fragThresh;
|
|
|
|
SPIN_LOCK_TASK_GIVE(&pDot11->tasLock);
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dot11DpeFragThresholdGet -
|
|
*
|
|
*
|
|
*
|
|
* RETURNS: Pointer to new END_OBJ (aka DOT11_FW) or NULL on error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeFragThresholdGet
|
|
(
|
|
DOT11_FW * pDot11, /* Pointer to device structure */
|
|
UINT32 * pFragThresh
|
|
)
|
|
{
|
|
if ((pDot11 == NULL) || (pDot11->dpe == NULL) || (pFragThresh == NULL))
|
|
{
|
|
return ERROR;
|
|
}
|
|
*pFragThresh = pDot11->dpe->fragThreshold;
|
|
return OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeEndPollSend - Sends a packet in polled mode
|
|
*
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeEndPollSend
|
|
(
|
|
END_OBJ* pEnd, /* Pointer to device handle */
|
|
M_BLK_ID pMblk /* Buffer containing data to write */
|
|
)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeEndPollRcv - Sends a packet in polled mode
|
|
*
|
|
*
|
|
* RETURNS: OK or ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL STATUS dot11DpeEndPollRcv
|
|
(
|
|
END_OBJ* pEnd, /* Pointer to device handle */
|
|
M_BLK_ID pMblk /* Buffer containing data to write */
|
|
)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeReassemble - Adds a packet to the reassembly queue
|
|
*
|
|
* This routine is given a packet that might be part of a fragmented packet.
|
|
* Its job is to examine the packet and determine if the packet is valid, and
|
|
* add it to the reassembly buffer if so.
|
|
*
|
|
* This routine returns a pointer to MBlk if the reception of the current
|
|
* fragment caused a packet to be completed. Otherwise it returns NULL. When
|
|
* it returns NULL, it is assumed that the packet is either placed on the
|
|
* reassembly queue (and freed when reassembly is complete or timeout occurs)
|
|
* or freed.
|
|
*
|
|
* There are three cases to consider:
|
|
* 1. fragNum == 0 and "More frag" flag is set - start of packet
|
|
* 2. fragNum > 0 and "More frag" flag is set - middle of packet
|
|
* 3. fragNum > 0 but no "More frag" flag - end of packet
|
|
*
|
|
*
|
|
* RETURNS: Pointer to completed packet (MBlk) or NULL
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL M_BLK_ID dot11DpeReassemble
|
|
(
|
|
DOT11_FW * pDot11, /* DOT11 framework root object */
|
|
M_BLK_ID pMblk, /* Packet received */
|
|
DOT11_KSL_ENTRY * pKsl /* Sending station */
|
|
)
|
|
{
|
|
UINT8 * pCluster; /* Cluster containing rx'd packet */
|
|
DOT11_HEADER * pHeader; /* Pointer to 802.11 Hdr */
|
|
DOT11_FRAGMENT * pFrag; /* Pointer to packet entry */
|
|
M_BLK_ID pCompleteMblk;
|
|
|
|
if (pKsl == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: ERROR - pKsl == NULL\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
/* No need for a sanity check - this routine is only called from one
|
|
place (dot11EndReceive()), and the parameters have been validated there */
|
|
|
|
pCluster = (UINT8*)pMblk->mBlkHdr.mData;
|
|
pHeader = (DOT11_HEADER *)pCluster;
|
|
|
|
/* See if this entry exists. Search for a combination of sequence number,
|
|
TA, DA */
|
|
pFrag = dot11DpeReassemblePktGet(pDot11, pHeader);
|
|
|
|
if ((DOT11_LE_TO_CPU_16(pHeader->frameCtrl) &
|
|
DOT11_FCTL_MORE_FRAG) != 0)
|
|
{
|
|
if ((DOT11_LE_TO_CPU_16(pHeader->seqCtrl) &
|
|
DOT11_SEQCTL_FRAGNUM) == 0)
|
|
{
|
|
/* Case 1 - First packet of a chain. */
|
|
|
|
/* Check if we found an entry earlier. If we did, then this is an
|
|
invalid pkt */
|
|
if (pFrag != NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: Multiple first fragments!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
/* Try to grab a reassembly slot. The reassembly timeout timer
|
|
will be started here too */
|
|
if ((pFrag = dot11DpeReassemblePktCreate(pDot11,
|
|
pHeader)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: Error getting frag slot!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
/* Start calculating the total length of this Mblk chain */
|
|
pMblk->mBlkPktHdr.len = pMblk->mBlkHdr.mLen;
|
|
|
|
/* Put the MBlk in as is - leave the 802.11 header on the first
|
|
packet */
|
|
pFrag->pHead = pMblk;
|
|
pFrag->pLast = pMblk;
|
|
}
|
|
else
|
|
{
|
|
/* Case 2 - Possible middle packet. */
|
|
if (pFrag == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: Middle fragment missing slt\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
/* Double check order. Packets are required to be sent in order,
|
|
but it's possible that one got dropped due to errors */
|
|
if ((DOT11_LE_TO_CPU_16(pHeader->seqCtrl) &
|
|
DOT11_SEQCTL_FRAGNUM) != ((pFrag->lastFrag + 1)))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: Middle frag out of order!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Add the packet to the end of the chain */
|
|
pFrag->pLast->mBlkHdr.mNext = pMblk;
|
|
pFrag->pLast = pMblk;
|
|
|
|
pFrag->lastFrag ++;
|
|
|
|
/* Since this is a middle fragment, just discard the 802.11 header,
|
|
since there is no information in it that isn't in the header of
|
|
the first packet */
|
|
pMblk->mBlkHdr.mData += sizeof(DOT11_HEADER);
|
|
pMblk->mBlkHdr.mLen -= sizeof(DOT11_HEADER);
|
|
|
|
/* Get rid of any encryption headers, like IVs */
|
|
if ((DOT11_LE_TO_CPU_16(pHeader->frameCtrl) & DOT11_FCTL_WEP) != 0)
|
|
{
|
|
/* Remove the IV from the head of the packet */
|
|
pMblk->mBlkHdr.mData += DOT11_WEP_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_IV_SIZE;
|
|
|
|
/* Check if there's an extended IV, ie TKIP or AES */
|
|
if ((*(pCluster + sizeof(DOT11_HEADER) + 3) &
|
|
DOT11_EXT_IV) != 0)
|
|
{
|
|
pMblk->mBlkHdr.mData += DOT11_WEP_EXT_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_EXT_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_MIC_LEN;
|
|
|
|
/* If this is a TKIP packet, then we also need to account
|
|
for the ICV at the end of the packet. In order to check
|
|
if this is a TKIP packet, we need to determine if it's
|
|
unicast or multicast, and check the appropriate key. */
|
|
if (((!(DOT11_IS_MCAST(pHeader->addr1))) &&
|
|
(pKsl->uniEncryptType == DOT11_KEY_TYPE_TKIP)) ||
|
|
((DOT11_IS_MCAST(pHeader->addr1)) &&
|
|
(pKsl->pBss->multiEncryptType==DOT11_KEY_TYPE_TKIP)))
|
|
{
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Remove the ICV from the end of the packet */
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE;
|
|
}
|
|
}
|
|
|
|
pFrag->pHead->mBlkPktHdr.len += pMblk->mBlkHdr.mLen;
|
|
|
|
}
|
|
}
|
|
else if ((DOT11_LE_TO_CPU_16(pHeader->seqCtrl) &
|
|
DOT11_SEQCTL_FRAGNUM) > 0)
|
|
{
|
|
/* Case 3 - this is the possible end of a fragment chain */
|
|
|
|
/* Double check order. Packets are required to be sent in order,
|
|
but it's possible that one got dropped due to errors */
|
|
if ((pFrag == NULL) ||
|
|
((DOT11_LE_TO_CPU_16(pHeader->seqCtrl) & DOT11_SEQCTL_FRAGNUM)
|
|
!= ((pFrag->lastFrag + 1))))
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: End frag out of order!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeReassemble: Packet reassembled %08x!\n",
|
|
(int)pFrag->pHead, 0, 0, 0, 0, 0));
|
|
|
|
/* Add the packet to the end of the chain, completing it */
|
|
pFrag->pLast->mBlkHdr.mNext = pMblk;
|
|
|
|
/* Since this not the first fragment, just discard the 802.11 header,
|
|
since there is no information in it that isn't in the header of
|
|
the first packet */
|
|
pMblk->mBlkHdr.mData += sizeof(DOT11_HEADER);
|
|
pMblk->mBlkHdr.mLen -= sizeof(DOT11_HEADER);
|
|
|
|
if ((DOT11_LE_TO_CPU_16(pHeader->frameCtrl) & DOT11_FCTL_WEP) != 0)
|
|
{
|
|
/* Remove the IV from the head of the packet */
|
|
pMblk->mBlkHdr.mData += DOT11_WEP_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_IV_SIZE;
|
|
|
|
/* Check if there's an extended IV, ie TKIP or AES */
|
|
if ((*(pCluster + sizeof(DOT11_HEADER) + 3) &
|
|
DOT11_EXT_IV) != 0)
|
|
{
|
|
pMblk->mBlkHdr.mData += DOT11_WEP_EXT_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_EXT_IV_SIZE;
|
|
pMblk->mBlkHdr.mLen -= DOT11_MIC_LEN;
|
|
|
|
/* If this is a TKIP packet, then we also need to account
|
|
for the ICV at the end of the packet. In order to check
|
|
if this is a TKIP packet, we need to determine if it's
|
|
unicast or multicast, and check the appropriate key. */
|
|
if (((!(DOT11_IS_MCAST(pHeader->addr1))) &&
|
|
(pKsl->uniEncryptType == DOT11_KEY_TYPE_TKIP)) ||
|
|
((DOT11_IS_MCAST(pHeader->addr1)) &&
|
|
(pKsl->pBss->multiEncryptType==DOT11_KEY_TYPE_TKIP)))
|
|
{
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Remove the ICV from the end of the packet */
|
|
pMblk->mBlkHdr.mLen -= DOT11_WEP_ICV_SIZE;
|
|
}
|
|
}
|
|
|
|
pFrag->pHead->mBlkPktHdr.len += pMblk->mBlkHdr.mLen;
|
|
|
|
/* Cancel the timer */
|
|
dot11TimerDel(pFrag->timerId);
|
|
|
|
/* Free the reassembly slot */
|
|
pCompleteMblk = pFrag->pHead;
|
|
|
|
|
|
SPIN_LOCK_TASK_TAKE(&pDot11->tasLock);
|
|
pFrag->pHead = NULL;
|
|
pFrag->used = FALSE;
|
|
|
|
SPIN_LOCK_TASK_GIVE(&pDot11->tasLock);
|
|
|
|
/* Return the completed packet in a single Mblk */
|
|
return dot11DpeMblkCoalesce(pDot11, pCompleteMblk);
|
|
}
|
|
else
|
|
{
|
|
netMblkClChainFree(pMblk);
|
|
}
|
|
/* This is truly an out of order packet that doesn't even fit one of
|
|
the above scenarios. It really shouldn't ever have been passed here,
|
|
but we'll drop it anyways */
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeMblkCoalesce - Copy an Mblk chain to a single Mblk
|
|
*
|
|
* This function copies an Mblk chain to a single Mblk and frees the Mblk
|
|
* chain. The ipnet stack cannot handle Mblk chains.
|
|
*
|
|
* RETURNS: Pointer to completed packet (MBlk)
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL M_BLK_ID dot11DpeMblkCoalesce
|
|
(
|
|
DOT11_FW * pDot11,
|
|
M_BLK_ID pMblkChain
|
|
)
|
|
{
|
|
M_BLK_ID pMblk = NULL;
|
|
M_BLK_ID pMblkWalker = pMblkChain;
|
|
int packetLen = 0;
|
|
|
|
/* Get a new Mblk */
|
|
if ((pMblk = netTupleGet(pDot11->endObj.pNetPool, DOT11_MTU, M_DONTWAIT,
|
|
MT_DATA, FALSE)) == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeMblkCoalesce: Error getting Mblk\n", 0, 0, 0, 0,
|
|
0, 0));
|
|
netMblkClChainFree(pMblk);
|
|
return NULL;
|
|
}
|
|
|
|
while (pMblkWalker) {
|
|
|
|
/* Copy the current Mblk data into the big Mblk */
|
|
netMblkToBufCopy(pMblkWalker, pMblk->mBlkHdr.mData + packetLen, NULL);
|
|
|
|
packetLen += pMblkWalker->mBlkHdr.mLen;
|
|
pMblkWalker = pMblkWalker->mBlkHdr.mNext;
|
|
}
|
|
|
|
/* Set the packet length and rcv interface in the new Mblk */
|
|
pMblk->mBlkPktHdr.len = packetLen;
|
|
pMblk->mBlkHdr.mLen = packetLen;
|
|
pMblk->mBlkPktHdr.rcvif = pMblkChain->mBlkPktHdr.rcvif;
|
|
|
|
/* Free the Chain */
|
|
netMblkClChainFree(pMblkChain);
|
|
|
|
return pMblk;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeReassemblePktGet - Finds the reassembly slot of a given packet
|
|
*
|
|
*
|
|
* RETURNS: Pointer to replacement slot, or NULL if no match
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL DOT11_FRAGMENT * dot11DpeReassemblePktGet
|
|
(
|
|
DOT11_FW * pDot11,
|
|
DOT11_HEADER * pHeader
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<DOT11_MAX_REASSEMBLY; i++)
|
|
{
|
|
/* No need to go any further if this slot's not in use */
|
|
if (!pDot11->dpe->reassemblyBuff.packet[i].used)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* Check sequence number first - has a high probability of being
|
|
unique and we may as well rule out non-matches as soon as possible. */
|
|
if ( ((DOT11_LE_TO_CPU_16(pHeader->seqCtrl) & DOT11_SEQCTL_SEQ) ==
|
|
(pDot11->dpe->reassemblyBuff.packet[i].sequence))
|
|
&& (bcmp((char*)pHeader->addr2,
|
|
(char*)pDot11->dpe->reassemblyBuff.packet[i].addr2,
|
|
DOT11_ADDR_LEN) == 0)
|
|
&& (bcmp((char*)pHeader->addr1,
|
|
(char*)pDot11->dpe->reassemblyBuff.packet[i].addr1,
|
|
DOT11_ADDR_LEN) == 0))
|
|
{
|
|
return &pDot11->dpe->reassemblyBuff.packet[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeReassembleTimeout - Timer expiration callback for reassembly entry
|
|
*
|
|
* If the timer expires on a packet that's started reassembly, then free the
|
|
* slot so that another packet has a chance to use the slot.
|
|
*
|
|
* RETURNS: VOID
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL VOID dot11DpeReassembleTimeout
|
|
(
|
|
DOT11_FW * pDot11,
|
|
int fragSlot
|
|
)
|
|
{
|
|
if (pDot11 == NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_FATAL, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleTimeout: NULL pDot11\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
return;
|
|
}
|
|
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleTimeout: Timeout on fragmented packet\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
/* We need to do this under taskLock() to ensure that if a packet comes
|
|
in while we're marking the slot as free it doesn't get confused */
|
|
|
|
SPIN_LOCK_TASK_TAKE(&pDot11->tasLock);
|
|
|
|
pDot11->dpe->reassemblyBuff.packet[fragSlot].used = FALSE;
|
|
|
|
|
|
/* Release what we've built of the packet so far */
|
|
if (pDot11->dpe->reassemblyBuff.packet[fragSlot].pHead != NULL)
|
|
{
|
|
netMblkClChainFree(pDot11->dpe->reassemblyBuff.packet[fragSlot].pHead);
|
|
pDot11->dpe->reassemblyBuff.packet[fragSlot].pHead = NULL;
|
|
}
|
|
else
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleTimeout: Timeout on NULL packet?\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
}
|
|
|
|
/* Add a receive error */
|
|
pDot11->stats.rxCantReassemble ++;
|
|
|
|
|
|
SPIN_LOCK_TASK_GIVE(&pDot11->tasLock);
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* dot11DpeReassemblePktCreate - Start a fragmentation slot for the packet
|
|
*
|
|
* This routine tries to find an empty reassembly buffer for the packet. It is
|
|
* assumed that pHeader is the 802.11 header that matches the following
|
|
* conditions:
|
|
* 1. The fragNum in the sequenceControl field is 0
|
|
* 2. The "More fragments" bit is set in the frameControl field.
|
|
*
|
|
* Note that if no slots are found, then NULL will be returned and it is
|
|
* expected that the packet will be dropped. This approach was chosen over
|
|
* killing the oldest slot for two reasons:
|
|
* 1. There are already aggressive timeout timers on the buffer
|
|
* 2. In a flood, at least we get *some* packets this way. Otherwise in
|
|
* a flood, we'd just get the first part of each packet.
|
|
*
|
|
* It is also anticipated that the MBlk will be linked into the slot after this
|
|
* routine is called, since the MBlk is not a parameter.
|
|
*
|
|
* RETURNS: Pointer to replacement slot, or NULL if no free slots
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL DOT11_FRAGMENT * dot11DpeReassemblePktCreate
|
|
(
|
|
DOT11_FW * pDot11,
|
|
DOT11_HEADER * pHeader
|
|
)
|
|
{
|
|
DOT11_FRAGMENT * pFrag; /* Shortcut to the reassembly slot */
|
|
|
|
int i;
|
|
/* See if there's a free slot. Perform the check under taskLock() to
|
|
prevent race condition */
|
|
|
|
SPIN_LOCK_TASK_TAKE(&pDot11->tasLock);
|
|
|
|
for (i=0; i<DOT11_MAX_REASSEMBLY; i++)
|
|
{
|
|
/* If this slot's not in use, claim it */
|
|
if (!pDot11->dpe->reassemblyBuff.packet[i].used)
|
|
{
|
|
/* We found an empty slot. Mark it used and quickly get out
|
|
of here */
|
|
pDot11->dpe->reassemblyBuff.packet[i].used = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SPIN_LOCK_TASK_GIVE(&pDot11->tasLock);
|
|
|
|
/* Too bad - no slots open */
|
|
if (i >= DOT11_MAX_REASSEMBLY)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleCreate: No free slots!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
pDot11->stats.rxCantReassemble ++;
|
|
return NULL;
|
|
}
|
|
|
|
DOT11_LOG(DOT11_DEBUG_FLOOD, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleCreate: Free slot %d claimed\n",
|
|
i, 0, 0, 0, 0, 0));
|
|
|
|
pFrag = &pDot11->dpe->reassemblyBuff.packet[i];
|
|
|
|
/* Just do a sanity check for lost packets */
|
|
if (pFrag->pHead != NULL)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_INFO, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleCreate: Lost packet\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
/* We won't free the slot, since it is as likely it's garbage as it's
|
|
a real MBlk and freeing it would probably produce an exception */
|
|
pDot11->stats.rxCantReassemble ++;
|
|
pFrag->pHead = NULL;
|
|
}
|
|
|
|
/* Save the TA, RA, and sequence */
|
|
DOT11_ADDR_COPY((char*)pHeader->addr1, (char*)pFrag->addr1);
|
|
DOT11_ADDR_COPY((char*)pHeader->addr2, (char*)pFrag->addr2);
|
|
pFrag->sequence = DOT11_LE_TO_CPU_16(pHeader->seqCtrl) & DOT11_SEQCTL_SEQ;
|
|
|
|
/* We just received fragment zero - that's what started reassembly.*/
|
|
pFrag->lastFrag = 0;
|
|
|
|
/* Start the timer */
|
|
if ((pFrag->timerId = dot11TimerAdd(DOT11_FRAGMENT_TIMEOUT_TICKS,
|
|
(FUNCPTR)dot11DpeReassembleTimeout,
|
|
(int)pDot11, i)) == ERROR)
|
|
{
|
|
DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_DPE,
|
|
("dot11DpeReassembleCreate: Cannot start timer!\n",
|
|
0, 0, 0, 0, 0, 0));
|
|
pFrag->used = FALSE;
|
|
pFrag->pHead = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
return pFrag;
|
|
}
|
|
|