Files
m241Neelima/vxworks-6.9/target/src/drv/wlan/dot11DpeLib.c
T
2026-07-30 11:19:44 +05:30

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;
}