windows-nt/Source/XPSP1/NT/net/rras/ndis/raspppoe/packet.c
2020-09-26 16:20:57 +08:00

3745 lines
105 KiB
C

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Module Name:
packet.c
Abstract:
This module contains all the necesarry routines for encapsulating PPPoE
packets and their related NDIS and NDISWAN packets.
Author:
Hakan Berk - Microsoft, Inc. (hakanb@microsoft.com) Feb-2000
Environment:
Windows 2000 kernel mode Miniport driver or equivalent.
Revision History:
---------------------------------------------------------------------------*/
#include <ntddk.h>
#include <ntddndis.h>
#include <ndis.h>
#include <ndiswan.h>
#include <ndistapi.h>
#include <ntverp.h>
#include "debug.h"
#include "timer.h"
#include "bpool.h"
#include "ppool.h"
#include "util.h"
#include "packet.h"
#include "protocol.h"
#include "miniport.h"
#include "tapi.h"
//////////////////////////////////////////////////////////////////////////
//
// Variables local to packet.c
// They are defined global only for debugging purposes.
//
///////////////////////////////////////////////////////////////////////////
//
// Flag that indicates if gl_lockPools is allocated or not
//
BOOLEAN gl_fPoolLockAllocated = FALSE;
//
// Spin lock to synchronize access to gl_ulNumPackets
//
NDIS_SPIN_LOCK gl_lockPools;
//
// Our pool of PPPoE buffer descriptors
//
BUFFERPOOL gl_poolBuffers;
//
// Our pool of PPPoE packet descriptors
//
PACKETPOOL gl_poolPackets;
//
// Ndis pool of buffer descriptors
//
NDIS_HANDLE gl_hNdisBufferPool;
//
// Non-paged lookaside list for PppoePacket structures
//
NPAGED_LOOKASIDE_LIST gl_llistPppoePackets;
//
// This is for debugging purposes. Shows the number of active packets
//
ULONG gl_ulNumPackets = 0;
//
// This defines the broadcast destination address
//
CHAR EthernetBroadcastAddress[6] = { (CHAR) 0xff,
(CHAR) 0xff,
(CHAR) 0xff,
(CHAR) 0xff,
(CHAR) 0xff,
(CHAR) 0xff };
VOID
ReferencePacket(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will increment the reference count on the packet object.
Parameters:
pPacket _ A pointer to the packet context.
Return Values:
None
---------------------------------------------------------------------------*/
{
LONG lRef;
TRACE( TL_V, TM_Pk, ("+ReferencePacket") );
lRef = NdisInterlockedIncrement( &pPacket->lRef );
TRACE( TL_V, TM_Pk, ("-ReferencePacket=$%x",lRef) );
}
VOID
DereferencePacket(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will decrement the reference count on the packet object.
When ref count reaches 0, packet is cleaned up.
Parameters:
pPacket _ A pointer to the packet context.
Return Values:
None
---------------------------------------------------------------------------*/
{
LONG lRef;
TRACE( TL_V, TM_Pk, ("+DereferencePacket") );
lRef = NdisInterlockedDecrement( &pPacket->lRef );
if ( lRef == 0 )
{
if ( pPacket->ulFlags & PCBF_BufferChainedToPacket )
{
//
// Unchain the buffer before freeing any packets
//
TRACE( TL_V, TM_Pk, ("DereferencePacket: Buffer unchained from packet") );
NdisUnchainBufferAtFront( pPacket->pNdisPacket, &pPacket->pNdisBuffer );
}
if ( pPacket->ulFlags & PCBF_BufferAllocatedFromOurBufferPool )
{
//
// Skipping check for pBuffer == NULL as this should never happen
// But call NdisAdjustBufferLength() to set the buffer length to original value
//
TRACE( TL_V, TM_Pk, ("DereferencePacket: Buffer returned to our pool") );
NdisAdjustBufferLength( pPacket->pNdisBuffer, PPPOE_PACKET_BUFFER_SIZE );
FreeBufferToPool( &gl_poolBuffers, pPacket->pHeader, TRUE );
}
if ( pPacket->ulFlags & PCBF_BufferAllocatedFromNdisBufferPool )
{
TRACE( TL_V, TM_Pk, ("DereferencePacket: Buffer returned to ndis pool") );
NdisFreeBuffer( pPacket->pNdisBuffer );
}
if ( pPacket->ulFlags & PCBF_CallNdisMWanSendComplete )
{
//
// Return packet back to NDISWAN
//
TRACE( TL_V, TM_Pk, ("DereferencePacket: Returning packet back to NDISWAN") );
NdisMWanSendComplete( PacketGetMiniportAdapter( pPacket )->MiniportAdapterHandle,
PacketGetRelatedNdiswanPacket( pPacket ),
PacketGetSendCompletionStatus( pPacket ) );
//
// Indicate to miniport that the packet is returned to NDISWAN
//
MpPacketOwnedByNdiswanReturned( PacketGetMiniportAdapter( pPacket ) );
}
if ( pPacket->ulFlags & PCBF_PacketAllocatedFromOurPacketPool )
{
//
// Skipping check for pPacketHead == NULL as this should never happen
//
TRACE( TL_V, TM_Pk, ("DereferencePacket: Packet returned to our pool") );
NdisReinitializePacket( pPacket->pNdisPacket );
FreePacketToPool( &gl_poolPackets, pPacket->pPacketHead, TRUE );
}
if ( pPacket->ulFlags & PCBF_CallNdisReturnPackets )
{
//
// Return packet back to NDIS
//
TRACE( TL_V, TM_Pk, ("DereferencePacket: Returning packet back to NDIS") );
NdisReturnPackets( &pPacket->pNdisPacket, 1 );
//
// Indicate to protocol that the packet is returned to NDIS.
//
PrPacketOwnedByNdisReturned( pPacket->pBinding );
}
//
// Finally return PppoePacket to the lookaside list
//
NdisFreeToNPagedLookasideList( &gl_llistPppoePackets, (PVOID) pPacket );
NdisAcquireSpinLock( &gl_lockPools );
gl_ulNumPackets--;
TRACE( TL_V, TM_Pk, ("DereferencePacket: gl_ulNumPacket=$%x", gl_ulNumPackets) );
NdisReleaseSpinLock( &gl_lockPools );
}
TRACE( TL_V, TM_Pk, ("-DereferencePacket=$%x",lRef) );
}
VOID
RetrieveTag(
IN OUT PPPOE_PACKET* pPacket,
IN PACKET_TAGS tagType,
OUT USHORT * pTagLength,
OUT CHAR** pTagValue,
IN USHORT prevTagLength,
IN CHAR * prevTagValue,
IN BOOLEAN fSetTagInPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
You can call this function on a received packet processed with one of the
PacketInitialize*FromReceived() functions.
It will not operate on a PAYLOAD packet, although you can call it safely.
It will retrieve and return the next length - value pair for a specific tag.
To retrieve the 1st one, pass 0 and NULL for prevTag* parameters.
If you pass fSetTagInPacket as TRUE, and if the next tag is found and the tag is known
to PppoePacket struct, then the fields for the tag in the packet are updated to point
to the found tag.
If there are no next tags, then *pTagValue will point to NULL, and *pTagLength
will point to '0'.
Parameters:
pPacket _ Pointer to a packet context prepared by a PacketInitializeXXXToSend()
function, or PacketInitializeFromReceived().
tagType _ Type of the tag being searched for.
pTagLength _ A pointer to a USHORT var that will keep the length of the returned tag.
pTagValue _ A pointer to the value of the tag which is basically a blob of
length *pTagLength.
prevTagLength _ The length of the value of the previous tag.
prevTagValue _ Points to the beginning of the value of the previous tag.
fSetTagInPacket _ Indicates that if a tag is found and is native to PPPoE packet context,
then PPPoE packet context must be updated to point to this new tag.
Return Values:
None
---------------------------------------------------------------------------*/
{
CHAR* pBuf = NULL;
CHAR* pBufEnd = NULL;
ASSERT( pPacket != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
TRACE( TL_V, TM_Pk, ("+RetrieveTag") );
//
// Initialize the output parameters
//
*pTagLength = (USHORT) 0;
*pTagValue = NULL;
//
// If this is a payload packet, then do not search for any tags
//
if ( PacketGetCode( pPacket ) == PACKET_CODE_PAYLOAD )
{
TRACE( TL_V, TM_Pk, ("-RetrieveTag: No tags. Payload packet") );
return;
}
//
// Find the start point to search for the tag
//
if ( prevTagValue != NULL )
{
//
// Caller wants the next tag, so make pBuf point to end of the prev tag value
//
pBuf = prevTagValue + prevTagLength;
}
else
{
//
// Caller wants the first tag in the packet
//
pBuf = pPacket->pPayload;
}
//
// Find the end point of the tag payload area
//
pBufEnd = pPacket->pPayload + PacketGetLength( pPacket );
//
// Search for the tag until we step outside the boundaries
//
while ( pBuf + PPPOE_TAG_HEADER_LENGTH <= pBufEnd )
{
USHORT usTagLength;
USHORT usTagType;
usTagType = ntohs( *((USHORT UNALIGNED *) pBuf) ) ;
((USHORT*) pBuf)++;
usTagLength = ntohs( *((USHORT UNALIGNED *) pBuf) ) ;
((USHORT*) pBuf)++;
if ( usTagType == tagType )
{
//
// Tag found, retrieve length and values
//
TRACE( TL_N, TM_Pk, ("RetrieveTag: Tag found:$%x", *pTagLength) );
*pTagLength = usTagLength;
*pTagValue = pBuf;
break;
}
pBuf += usTagLength;
}
//
// Check if tag was found
//
if ( *pTagValue != NULL )
{
//
// Tag found. Check if the caller wants to set it in the PppoePacket
//
if ( fSetTagInPacket )
{
TRACE( TL_V, TM_Pk, ("RetrieveTag: Setting tag in packet") );
switch ( tagType )
{
case tagEndOfList:
break;
case tagServiceName:
pPacket->tagServiceNameLength = *pTagLength;
pPacket->tagServiceNameValue = *pTagValue;
break;
case tagACName:
pPacket->tagACNameLength = *pTagLength;
pPacket->tagACNameValue = *pTagValue;
break;
case tagHostUnique:
pPacket->tagHostUniqueLength = *pTagLength;
pPacket->tagHostUniqueValue = *pTagValue;
break;
case tagACCookie:
pPacket->tagACCookieLength = *pTagLength;
pPacket->tagACCookieValue = *pTagValue;
break;
case tagRelaySessionId:
pPacket->tagRelaySessionIdLength = *pTagLength;
pPacket->tagRelaySessionIdValue = *pTagValue;
break;
case tagServiceNameError:
pPacket->tagErrorType = tagServiceNameError;
pPacket->tagErrorTagLength = *pTagLength;
pPacket->tagErrorTagValue = *pTagValue;
break;
case tagACSystemError:
pPacket->tagErrorType = tagACSystemError;
pPacket->tagErrorTagLength = *pTagLength;
pPacket->tagErrorTagValue = *pTagValue;
break;
case tagGenericError:
pPacket->tagErrorType = tagGenericError;
pPacket->tagErrorTagLength = *pTagLength;
pPacket->tagErrorTagValue = *pTagValue;
break;
default:
break;
}
}
}
TRACE( TL_V, TM_Pk, ("-RetrieveTag") );
}
NDIS_STATUS
PreparePacketForWire(
IN OUT PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function prepares the packet for wire.
It must be called inside a PacketInitializeXXXToSend() function after all
processing is done with the packet to prepare it to be transmitted over the wire.
It basically creates and writes the tags into the payload area of the packet,
and finally adjusts the length of the buffer to let Ndis know the extents of the
valid data blob.
Parameters:
pPacket _ Pointer to a packet context prepared by a PacketInitializeXXXToSend()
function.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
---------------------------------------------------------------------------*/
{
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
CHAR* pBuf;
ASSERT( pPacket != NULL );
TRACE( TL_V, TM_Pk, ("+PreparePacketForWire") );
//
// Now insert the tags if packet is a Discovery Ethernet packet
//
switch ( PacketGetCode( pPacket ) )
{
case PACKET_CODE_PADI:
PacketInsertTag( pPacket,
tagServiceName,
pPacket->tagServiceNameLength,
pPacket->tagServiceNameValue,
&pPacket->tagServiceNameValue);
if ( pPacket->tagHostUniqueLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting host unique tag") );
PacketInsertTag( pPacket,
tagHostUnique,
pPacket->tagHostUniqueLength,
pPacket->tagHostUniqueValue,
&pPacket->tagHostUniqueValue );
}
break;
case PACKET_CODE_PADO:
PacketInsertTag( pPacket,
tagServiceName,
pPacket->tagServiceNameLength,
pPacket->tagServiceNameValue,
&pPacket->tagServiceNameValue );
if ( pPacket->tagHostUniqueLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting host unique tag") );
PacketInsertTag( pPacket,
tagHostUnique,
pPacket->tagHostUniqueLength,
pPacket->tagHostUniqueValue,
&pPacket->tagHostUniqueValue );
}
if ( pPacket->tagRelaySessionIdLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting relay sesion id tag") );
PacketInsertTag( pPacket,
tagRelaySessionId,
pPacket->tagRelaySessionIdLength,
pPacket->tagRelaySessionIdValue,
&pPacket->tagRelaySessionIdValue );
}
PacketInsertTag( pPacket,
tagACName,
pPacket->tagACNameLength,
pPacket->tagACNameValue,
&pPacket->tagACNameValue );
PacketInsertTag( pPacket,
tagACCookie,
pPacket->tagACCookieLength,
pPacket->tagACCookieValue,
&pPacket->tagACCookieValue );
break;
case PACKET_CODE_PADR:
PacketInsertTag( pPacket,
tagServiceName,
pPacket->tagServiceNameLength,
pPacket->tagServiceNameValue,
&pPacket->tagServiceNameValue );
if ( pPacket->tagHostUniqueLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting host unique tag") );
PacketInsertTag( pPacket,
tagHostUnique,
pPacket->tagHostUniqueLength,
pPacket->tagHostUniqueValue,
&pPacket->tagHostUniqueValue );
}
if ( pPacket->tagRelaySessionIdLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting relay sesion id tag") );
PacketInsertTag( pPacket,
tagRelaySessionId,
pPacket->tagRelaySessionIdLength,
pPacket->tagRelaySessionIdValue,
&pPacket->tagRelaySessionIdValue );
}
if ( pPacket->tagACCookieLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting ac-ccokie tag") );
PacketInsertTag( pPacket,
tagACCookie,
pPacket->tagACCookieLength,
pPacket->tagACCookieValue,
&pPacket->tagACCookieValue );
}
break;
case PACKET_CODE_PADS:
PacketInsertTag( pPacket,
tagServiceName,
pPacket->tagServiceNameLength,
pPacket->tagServiceNameValue,
&pPacket->tagServiceNameValue );
if ( pPacket->tagHostUniqueLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting host unique tag") );
PacketInsertTag( pPacket,
tagHostUnique,
pPacket->tagHostUniqueLength,
pPacket->tagHostUniqueValue,
&pPacket->tagHostUniqueValue );
}
if ( pPacket->tagRelaySessionIdLength > 0 )
{
TRACE( TL_N, TM_Pk, ("PreparePacketForWire: Inserting relay sesion id tag") );
PacketInsertTag( pPacket,
tagRelaySessionId,
pPacket->tagRelaySessionIdLength,
pPacket->tagRelaySessionIdValue,
&pPacket->tagRelaySessionIdValue );
}
break;
case PACKET_CODE_PADT:
break;
case PACKET_CODE_PAYLOAD:
break;
default:
status = NDIS_STATUS_INVALID_PACKET;
}
if ( status == NDIS_STATUS_SUCCESS )
{
//
// Adjust buffer length
//
NdisAdjustBufferLength( pPacket->pNdisBuffer,
(UINT) ( PacketGetLength( pPacket ) + PPPOE_PACKET_HEADER_LENGTH ) );
}
TRACE( TL_V, TM_Pk, ("-PreparePacketForWire=$%x",status) );
return status;
}
PPPOE_PACKET*
PacketCreateSimple()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function allocates and initializes a simple packet.
A simple packet is mainly used for control packets to be sent.
Its buffer, and packet is allocated from our pools, buffer is chained to
packet.
On return all following values point to valid places and are safe for use:
pHeader
pPayload
pNdisBuffer
pNdisPacket
Parameters:
None
Return Values:
Pointer to an initialized PPPoE packet context.
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
TRACE( TL_V, TM_Pk, ("+PacketCreateSimple") );
//
// Allocate a packet
//
pPacket = PacketAlloc();
if ( pPacket == NULL )
{
TRACE( TL_V, TM_Pk, ("-PacketCreateSimple=$%x",NULL) );
return NULL;
}
//
// Allocate NdisBuffer from our pool
//
pPacket->pHeader = GetBufferFromPool( &gl_poolBuffers );
if ( pPacket->pHeader == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketCreateSimple: Could not get buffer from our pool") );
TRACE( TL_V, TM_Pk, ("-PacketCreateSimple=$%x",NULL) );
PacketFree( pPacket );
return NULL;
}
pPacket->ulFlags |= PCBF_BufferAllocatedFromOurBufferPool;
//
// Clean up the buffer area
//
NdisZeroMemory( pPacket->pHeader, PPPOE_PACKET_BUFFER_SIZE * sizeof( CHAR ) );
//
// Point built-in NDIS buffer pointer to NDIS buffer of buffer from pool
//
pPacket->pNdisBuffer = NdisBufferFromBuffer( pPacket->pHeader );
//
// Allocate an NDIS packet from our pool
//
pPacket->pNdisPacket = GetPacketFromPool( &gl_poolPackets, &pPacket->pPacketHead );
if ( pPacket->pNdisPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketCreateSimple: Could not get packet from our pool") );
TRACE( TL_V, TM_Pk, ("-PacketCreateSimple=$%x",NULL) );
PacketFree( pPacket );
return NULL;
}
pPacket->ulFlags |= PCBF_PacketAllocatedFromOurPacketPool;
//
// Chain buffer to packet
//
NdisChainBufferAtFront( pPacket->pNdisPacket, pPacket->pNdisBuffer );
pPacket->ulFlags |= PCBF_BufferChainedToPacket;
//
// Set the payload and payload length
//
pPacket->pPayload = pPacket->pHeader + PPPOE_PACKET_HEADER_LENGTH;
//
// Set the input NDIS_PACKET to the reserved area so that we can reach it
// when we have to return this packet back to the upper layer.
//
*((PPPOE_PACKET UNALIGNED **)(&pPacket->pNdisPacket->ProtocolReserved[0 * sizeof(PVOID)])) = pPacket;
TRACE( TL_V, TM_Pk, ("-PacketCreateSimple=$%x",pPacket) );
return pPacket;
}
PPPOE_PACKET*
PacketCreateForReceived(
PBINDING pBinding,
PNDIS_PACKET pNdisPacket,
PNDIS_BUFFER pNdisBuffer,
PUCHAR pContents
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function allocates and initializes a packet from a received packet.
This function is used for perf optimization. When the received packet has
a single buffer that we can pass to the miniport.
On return all following values point to valid places and are safe for use:
pHeader
pPayload
pNdisBuffer
pNdisPacket
Parameters:
pBinding _ The binding over which this packet is received.
pNdisPacket _ Ndis Packet descriptor from the received packet.
pNdisBuffer _ Ndis Buffer descriptor from the received packet.
pContents _ Pointer to the contents of the buffer.
Return Values:
Pointer to an initialized PPPoE packet context.
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
TRACE( TL_V, TM_Pk, ("+PacketCreateForReceived") );
//
// Allocate a packet
//
pPacket = PacketAlloc();
if ( pPacket == NULL )
{
TRACE( TL_V, TM_Pk, ("-PacketCreateForReceived=$%x",NULL) );
return NULL;
}
//
// Mark the packet so we return it to NDIS when it is freed
//
pPacket->ulFlags |= PCBF_CallNdisReturnPackets;
//
// Save the binding and indicate to protocol such a packet is created using
// PrPacketOwnedByNdisReceived()
//
pPacket->pBinding = pBinding;
PrPacketOwnedByNdisReceived( pBinding );
//
// Set the pointers
//
pPacket->pHeader = pContents;
pPacket->pNdisBuffer = pNdisBuffer;
pPacket->pNdisPacket = pNdisPacket;
pPacket->pPayload = pPacket->pHeader + PPPOE_PACKET_HEADER_LENGTH;
TRACE( TL_V, TM_Pk, ("-PacketCreateForReceived=$%x",pPacket) );
return pPacket;
}
PPPOE_PACKET*
PacketNdis2Pppoe(
IN PBINDING pBinding,
IN PNDIS_PACKET pNdisPacket,
OUT PINT pRefCount
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to convert only NDIS packets indicated by PrReceivePacket().
If packet is received by PrReceive() then you should not be using this function.
We look at the Ndis buffer, and if it has a single flat buffer, then we exploit it
and use the original Ndis packets buffer descriptors so we do not do any copy,
otherwise we create our own copy of it as PPPoE packet, and operate on it.
( AliD says, 99% of the time the single flat buffer case will be true. )
If we use the original Ndis packet, then we return 1 in the pRefCount parameter,
otherwise we return 0.
On return all following values point to valid places and are safe for use:
pHeader
pPayload
pNdisBuffer
pNdisPacket
Parameters:
pBinding _ The binding over which this packet is received.
pNdisPacket _ Original, unprocessed Ndis packet.
This must be indicated by ProtocolReceivePacket().
pRefCount _ Reference count to be returned to Ndis from ProtocolReceivePacket().
We return 1 if we can use the Ndis packet and buffer descriptors, otherwise
we make our own copy so we won't need the original Ndis packet, so we return 0.
Return Values:
Pointer to an initialized PPPoE packet context.
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
NDIS_BUFFER* pNdisBuffer = NULL;
UINT nBufferCount = 0;
UINT nTotalLength = 0;
PVOID pBufferContents = NULL;
UINT nBufferLength;
UINT nCopiedBufferLength = 0;
BOOLEAN fReturnPacket = FALSE;
TRACE( TL_V, TM_Pk, ("+PacketNdis2Pppoe") );
do
{
//
// Query the packet and get the total length and the pointer to first buffer
//
NdisQueryPacket( pNdisPacket,
NULL,
&nBufferCount,
&pNdisBuffer,
&nTotalLength );
//
// Make sure indicated packet is not larger than expected
//
if ( nTotalLength > (UINT) PPPOE_PACKET_BUFFER_SIZE )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Packet larger than expected") );
break;
}
if ( nBufferCount == 1 &&
NDIS_GET_PACKET_STATUS(pNdisPacket) != NDIS_STATUS_RESOURCES)
{
//
// We can handle this case efficiently
//
//
// Since we will be using the original Ndis packet and buffers, make sure
// length specified in the PPPoE packet does not exceed the total length
// of the Ndis packet
//
USHORT usPppoePacketLength;
NdisQueryBufferSafe( pNdisBuffer,
&pBufferContents,
&nBufferLength,
NormalPagePriority );
if ( pBufferContents == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: System resources low, dropping packet") );
break;
}
if ( nBufferLength < ETHERNET_HEADER_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Packet header smaller than expected") );
break;
}
if ( !PacketFastIsPPPoE( pBufferContents, ETHERNET_HEADER_LENGTH ) )
{
TRACE( TL_V, TM_Pk, ("PacketNdis2Pppoe: Packet is not PPPoE") );
break;
}
usPppoePacketLength = ntohs( * ( USHORT UNALIGNED * ) ( (PUCHAR) pBufferContents + PPPOE_PACKET_LENGTH_OFFSET ) );
if ( (UINT) usPppoePacketLength > nTotalLength )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: PPPoE Packet length larger than Ndis packet length") );
break;
}
//
// Let's create our PPPoE packet to keep the copy of the received packet
//
pPacket = PacketCreateForReceived( pBinding,
pNdisPacket,
pNdisBuffer,
pBufferContents );
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Could not allocate context to copy the packet") );
break;
}
fReturnPacket = TRUE;
*pRefCount = 1;
}
else
{
//
// Since Ndis packet contains multiple buffers, we can not handle this case efficiently.
// We need to allocate a PPPoE packet, copy the contents of the Ndis packet as a flat
// buffer to this packet, and then operate on it.
//
//
// Let's create our PPPoE packet to keep the copy of the received packet
//
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Could not allocate context to copy the packet") );
break;
}
//
// Retrieve the header and check if the packet is a PPPoE frame or not
//
do
{
NdisQueryBufferSafe( pNdisBuffer,
&pBufferContents,
&nBufferLength,
NormalPagePriority );
if ( pBufferContents == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: System resources low, dropping packet") );
break;
}
NdisMoveMemory( pPacket->pHeader + nCopiedBufferLength,
pBufferContents,
nBufferLength );
nCopiedBufferLength += nBufferLength;
} while ( nCopiedBufferLength < ETHERNET_HEADER_LENGTH );
if ( nCopiedBufferLength < ETHERNET_HEADER_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Header could not be retrieved") );
break;
}
if ( !PacketFastIsPPPoE( pPacket->pHeader, ETHERNET_HEADER_LENGTH ) )
{
TRACE( TL_V, TM_Pk, ("PacketNdis2Pppoe: Packet is not PPPoE") );
break;
}
//
// Since we know that the packet is PPPoE, copy the rest of the data to our
// own copy of the packet
//
NdisGetNextBuffer( pNdisBuffer,
&pNdisBuffer );
while ( pNdisBuffer != NULL )
{
NdisQueryBufferSafe( pNdisBuffer,
&pBufferContents,
&nBufferLength,
NormalPagePriority );
if ( pBufferContents == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: System resources low, dropping packet") );
break;
}
NdisMoveMemory( pPacket->pHeader + nCopiedBufferLength,
pBufferContents,
nBufferLength );
nCopiedBufferLength += nBufferLength;
NdisGetNextBuffer( pNdisBuffer,
&pNdisBuffer );
}
//
// Check if we could copy the whole chain of buffers
//
if ( nCopiedBufferLength < nTotalLength )
{
TRACE( TL_A, TM_Pk, ("PacketNdis2Pppoe: Failed to copy the whole data from all buffers") );
break;
}
fReturnPacket = TRUE;
*pRefCount = 0;
}
} while ( FALSE );
if ( !fReturnPacket )
{
if ( pPacket )
{
PacketFree( pPacket );
pPacket = NULL;
}
}
TRACE( TL_V, TM_Pk, ("-PacketNdis2Pppoe=$%x", pPacket) );
return pPacket;
}
BOOLEAN
PacketIsPPPoE(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to understand if the received packet is a PPPoE
packet or not. If it is then, it should be further processed, otherwise it
should be dropped.
Parameters:
pPacket _ Pointer to a packet context prepared.
Return Values:
Pointer to an initialized PPPoE packet context.
---------------------------------------------------------------------------*/
{
BOOLEAN fReturn = FALSE;
TRACE( TL_V, TM_Pk, ("+PacketIsPPPoE") );
do
{
//
// Check packet ether type
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY &&
PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_PAYLOAD )
{
TRACE( TL_A, TM_Pk, ("PacketIsPPPoE: Unknown ether type") );
break;
}
//
// Check packet version
//
if ( PacketGetVersion( pPacket ) != PACKET_VERSION )
{
TRACE( TL_A, TM_Pk, ("PacketIsPPPoE: Unknown packet version") );
break;
}
//
// Check packet type
//
if ( PacketGetType( pPacket ) != PACKET_TYPE )
{
TRACE( TL_A, TM_Pk, ("PacketIsPPPoE: Unknown packet type") );
break;
}
//
// Make sure length does not exceed PACKET_GEN_MAX_LENGTH
//
if ( PacketGetLength( pPacket ) > PACKET_GEN_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketIsPPPoE: Packet larger than expected") );
break;
}
fReturn = TRUE;
} while ( FALSE );
TRACE( TL_V, TM_Pk, ("-PacketIsPPPoE=$%d",fReturn) );
return fReturn;
}
BOOLEAN
PacketFastIsPPPoE(
IN CHAR* HeaderBuffer,
IN UINT HeaderBufferSize
)
{
BOOLEAN fRet = FALSE;
USHORT usEtherType;
TRACE( TL_V, TM_Pk, ("+PacketFastIsPPPoE") );
do
{
if ( HeaderBufferSize != ETHERNET_HEADER_LENGTH )
{
//
// Header is not ethernet, so drop the packet
//
TRACE( TL_A, TM_Pk, ("PacketFastIsPPPoE: Bad packet header") );
break;
}
//
// Retrieve the ether type and see if packet of any interest to us
//
usEtherType = ntohs( * ( USHORT UNALIGNED * ) (HeaderBuffer + PPPOE_PACKET_ETHER_TYPE_OFFSET ) );
if ( usEtherType == PACKET_ETHERTYPE_DISCOVERY ||
usEtherType == PACKET_ETHERTYPE_PAYLOAD )
{
//
// Valid ethertype, so accept the packet
//
fRet = TRUE;
}
} while ( FALSE );
TRACE( TL_V, TM_Pk, ("-PacketFastIsPPPoE") );
return fRet;
}
VOID
RetrieveErrorTags(
IN PPPOE_PACKET* pPacket
)
{
USHORT tagLength = 0;
CHAR* tagValue = NULL;
TRACE( TL_V, TM_Pk, ("+RetrieveErrorTags") );
RetrieveTag( pPacket,
tagServiceNameError,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue != NULL )
{
TRACE( TL_V, TM_Pk, ("RetrieveErrorTags: ServiceNameError tag received") );
pPacket->ulFlags |= PCBF_ErrorTagReceived;
}
if ( !( pPacket->ulFlags & PCBF_ErrorTagReceived ) )
{
RetrieveTag( pPacket,
tagACSystemError,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue != NULL )
{
TRACE( TL_V, TM_Pk, ("RetrieveErrorTags: ACSystemError tag received") );
pPacket->ulFlags |= PCBF_ErrorTagReceived;
}
}
if ( !( pPacket->ulFlags & PCBF_ErrorTagReceived ) )
{
RetrieveTag( pPacket,
tagGenericError,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue != NULL )
{
TRACE( TL_V, TM_Pk, ("RetrieveErrorTags: GenericError tag received") );
pPacket->ulFlags |= PCBF_ErrorTagReceived;
}
}
TRACE( TL_V, TM_Pk, ("-RetrieveErrorTags") );
}
///////////////////////////////////////////////////////////////////////////
//
// Interface functions (exposed outside)
//
///////////////////////////////////////////////////////////////////////////
VOID
PacketPoolInit()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function initializes or incements the ref count on the this module.
Both miniport and protocol will call this function in their register routines
to allocate packet pools. Only then they can call functions from this module.
We create the packet pools if gl_ulNumPackets is 0, otherwise we just increment
gl_ulNumPackets, and that reference will be removed when the caller calls
PacketPoolUninit() later.
Parameters:
None
Return Values:
None
---------------------------------------------------------------------------*/
{
TRACE( TL_N, TM_Pk, ("+PacketPoolInit") );
//
// Make sure global lock is allocated
//
if ( !gl_fPoolLockAllocated )
{
TRACE( TL_N, TM_Pk, ("PacketPoolInit: First call, allocating global lock") );
//
// If global lock is not allocated, then this is the first call,
// so allocate the spin lock
//
NdisAllocateSpinLock( &gl_lockPools );
gl_fPoolLockAllocated = TRUE;
}
NdisAcquireSpinLock( &gl_lockPools );
if ( gl_ulNumPackets == 0 )
{
PacketPoolAlloc();
}
gl_ulNumPackets++;
NdisReleaseSpinLock( &gl_lockPools );
TRACE( TL_N, TM_Pk, ("-PacketPoolInit") );
}
VOID
PacketPoolUninit()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function uninitializes or decrements the ref count on the this module.
Both miniport and protocol will call this function when they are done with
this module, and if ref count has dropped to 0, this function will deallocate
the alloated pools.
Parameters:
None
Return Values:
None
---------------------------------------------------------------------------*/
{
TRACE( TL_N, TM_Pk, ("+PacketPoolUninit") );
//
// Make sure global lock is allocated
//
if ( !gl_fPoolLockAllocated )
{
TRACE( TL_A, TM_Pk, ("PacketPoolUninit: Global not allocated yet") );
TRACE( TL_N, TM_Pk, ("-PacketPoolUninit") );
return;
}
NdisAcquireSpinLock( &gl_lockPools );
gl_ulNumPackets--;
if ( gl_ulNumPackets == 0 )
{
PacketPoolFree();
}
NdisReleaseSpinLock( &gl_lockPools );
TRACE( TL_N, TM_Pk, ("-PacketPoolUninit") );
}
VOID
PacketPoolAlloc()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function wraps the initialization of buffers and packet pools.
It is called from PacketPoolInit().
Parameters:
None
Return Values:
None
---------------------------------------------------------------------------*/
{
NDIS_STATUS status;
TRACE( TL_N, TM_Pk, ("+PacketPoolAlloc") );
//
// Initialize our header pool
//
InitBufferPool( &gl_poolBuffers,
PPPOE_PACKET_BUFFER_SIZE,
0, 10, 0,
TRUE,
MTAG_BUFFERPOOL );
//
// Initialize our packet pool
//
InitPacketPool( &gl_poolPackets,
3 * sizeof( PVOID ), 0, 30, 0,
MTAG_PACKETPOOL );
//
// Initialize the Ndis Buffer Pool
// No need to check for status, as DDK says,
// it always returns NDIS_STATUS_SUCCESS
//
NdisAllocateBufferPool( &status,
&gl_hNdisBufferPool,
30 );
//
// Initialize the control msg lookaside list
//
NdisInitializeNPagedLookasideList(
&gl_llistPppoePackets, // IN PNPAGED_LOOKASIDE_LIST Lookaside,
NULL, // IN PALLOCATE_FUNCTION Allocate OPTIONAL,
NULL, // IN PFREE_FUNCTION Free OPTIONAL,
0, // IN ULONG Flags,
sizeof(PPPOE_PACKET), // IN ULONG Size,
MTAG_PPPOEPACKET, // IN ULONG Tag,
0, // IN USHORT Depth
);
TRACE( TL_N, TM_Pk, ("-PacketPoolAlloc") );
}
VOID
PacketPoolFree()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function wraps the clean up of buffers and packet pools.
It is called from PacketPoolUninit() when gl_ulNumPackets reaches 0.
Parameters:
None
Return Values:
None
---------------------------------------------------------------------------*/
{
TRACE( TL_N, TM_Pk, ("+PacketPoolFree") );
FreeBufferPool( &gl_poolBuffers );
FreePacketPool( &gl_poolPackets );
NdisFreeBufferPool( &gl_hNdisBufferPool );
NdisDeleteNPagedLookasideList( &gl_llistPppoePackets );
TRACE( TL_N, TM_Pk, ("-PacketPoolFree") );
}
PPPOE_PACKET*
PacketAlloc()
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function allocates a PPPoE packet context, but it does not create
the packet and buffer descriptors.
Parameters:
None
Return Values:
NULL or a pointer to a new PPPoE packet context.
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
TRACE( TL_V, TM_Pk, ("+PacketAlloc") );
do
{
//
// Allocate a PppoePacket struct from the lookaside list
//
pPacket = (PPPOE_PACKET*) NdisAllocateFromNPagedLookasideList( &gl_llistPppoePackets );
if ( pPacket == NULL )
break;
NdisAcquireSpinLock( &gl_lockPools );
gl_ulNumPackets++;
NdisReleaseSpinLock( &gl_lockPools );
//
// Initialize the contents of the PppoePacket that will be returned
//
NdisZeroMemory( pPacket, sizeof( PPPOE_PACKET ) );
InitializeListHead( &pPacket->linkPackets );
ReferencePacket( pPacket );
} while ( FALSE );
TRACE( TL_V, TM_Pk, ("-PacketAlloc=$%x",pPacket) );
return pPacket;
}
VOID
PacketFree(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is called to free a packet, but the effect is just decrementing
the ref count on the object.
Parameters:
pPacket _ A pointer to the packet to be freed.
Return Values:
None
---------------------------------------------------------------------------*/
{
TRACE( TL_V, TM_Pk, ("+PacketFree") );
ASSERT( pPacket != NULL );
DereferencePacket( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketFree") );
}
NDIS_STATUS
PacketInsertTag(
IN PPPOE_PACKET* pPacket,
IN PACKET_TAGS tagType,
IN USHORT tagLength,
IN CHAR* tagValue,
OUT CHAR** pNewTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to insert additional tags into a PPPoE packet.
Parameters:
pPacket _ pPacket must be pointing to a packet that was processed using
one of the PacketInitialize*ToSend() functions.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
---------------------------------------------------------------------------*/
{
CHAR *pBuf = NULL;
USHORT usMaxLength = PACKET_GEN_MAX_LENGTH;
ASSERT( pPacket != NULL );
TRACE( TL_V, TM_Pk, ("+PacketInsertTag") );
//
// Check for length restrictions
//
if ( PacketGetCode( pPacket ) == (USHORT) PACKET_CODE_PADI )
usMaxLength = PACKET_PADI_MAX_LENGTH;
if ( PacketGetLength( pPacket ) + PPPOE_TAG_HEADER_LENGTH + tagLength > usMaxLength )
{
TRACE( TL_A, TM_Pk, ("PacketInsertTag: Can not insert tag, exceeding max packet length") );
TRACE( TL_V, TM_Pk, ("-PacketInsertTag") );
return NDIS_STATUS_INVALID_PACKET;
}
//
// Find the end of the payload
//
pBuf = pPacket->pPayload + PacketGetLength( pPacket );
//
// Insert the length - type - value triplet into the packet
//
*((USHORT UNALIGNED *) pBuf) = htons( tagType );
((USHORT*) pBuf)++;
*((USHORT UNALIGNED *) pBuf) = htons( tagLength );
((USHORT*) pBuf)++;
if ( tagLength > 0)
NdisMoveMemory( pBuf, tagValue, tagLength );
if ( pNewTagValue )
{
*pNewTagValue = pBuf;
}
//
// Update the Length field
//
PacketSetLength( pPacket, ( PacketGetLength( pPacket ) + PPPOE_TAG_HEADER_LENGTH + tagLength ) );
//
// Adjust payload buffer length
//
NdisAdjustBufferLength( pPacket->pNdisBuffer,
(UINT) PacketGetLength( pPacket ) + PPPOE_PACKET_HEADER_LENGTH );
TRACE( TL_V, TM_Pk, ("-PacketInsertTag") );
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
PacketInitializePADIToSend(
OUT PPPOE_PACKET** ppPacket,
IN USHORT tagServiceNameLength,
IN CHAR* tagServiceNameValue,
IN USHORT tagHostUniqueLength,
IN CHAR* tagHostUniqueValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PADI packet to send.
MANDATORY TAGS:
===============
tagServiceName:
tagServiceNameLength MUST be non-zero
tagServiceNameValue MUST be non-NULL
OPTIONAL TAGS:
==============
tagHostUnique:
tagHostUniqueLength can be zero
tagHostUniqueValue can be NULL
Parameters:
ppPacket _ A pointer to a PPPoE packet context pointer.
tagServiceNameLength _ Length of tagServiceNameValue blob.
tagServiceNameValue _ A blob that holds a UTF-8 service name string.
tagHostUniqueLength _ Length of tagHostUniqueValue blob.
tagHostUniqueValue _ A blob that contains a unique value to identify a packet.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
USHORT usLength = 0;
NDIS_STATUS status;
TRACE( TL_N, TM_Pk, ("+PacketInitializePADIToSend") );
ASSERT( ppPacket != NULL );
//
// Check if we are safe with length restrictions
//
usLength = tagServiceNameLength +
PPPOE_TAG_HEADER_LENGTH +
tagHostUniqueLength +
( (tagHostUniqueLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) ;
if ( usLength > PACKET_PADI_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADIToSend: Can not init PADI to send, exceeding max length") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADIToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADIToSend: Can not init PADI to send, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADIToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetDestAddr( pPacket, EthernetBroadcastAddress );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_DISCOVERY );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PADI );
PacketSetSessionId( pPacket, PACKET_NULL_SESSION );
PacketSetLength( pPacket, 0 );
pPacket->tagServiceNameLength = tagServiceNameLength;
pPacket->tagServiceNameValue = tagServiceNameValue;
pPacket->tagHostUniqueLength = tagHostUniqueLength;
pPacket->tagHostUniqueValue = tagHostUniqueValue;
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADIToSend: PreparePacketForWire() failed:%x",status) );
PacketFree( pPacket );
pPacket = NULL;
}
*ppPacket = pPacket;
TRACE( TL_N, TM_Pk, ("-PacketInitializePADIToSend=$%x",status) );
return status;
}
NDIS_STATUS
PacketInitializePADOToSend(
IN PPPOE_PACKET* pPADI,
OUT PPPOE_PACKET** ppPacket,
IN CHAR* pSrcAddr,
IN USHORT tagServiceNameLength,
IN CHAR* tagServiceNameValue,
IN USHORT tagACNameLength,
IN CHAR* tagACNameValue,
IN BOOLEAN fInsertACCookieTag
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PADO packet to send as a reply to a received
PADI packet.
Note that a PADI packet does not contain the source address information as PADI
is a broadcast packet.
MANDATORY TAGS:
===============
tagServiceName: ()
tagServiceNameLength MUST be non-zero
tagServiceNameValue MUST be non-NULL
tagACName:
tagACNameNameLength MUST be non-zero
tagACNameNameValue MUST be non-NULL
tagACCookie: (This is optional for RFC)
tagACCookieLength can be zero
tagACCookieValue can be NULL
OPTIONAL TAGS:
==============
tagHostUnique: (Obtained from PADI packet)
tagHostUniqueLength can be zero
tagHostUniqueValue can be NULL
tagRelaySessionId: (Obtained from PADI packet)
tagRelaySessionIdLength can be zero
tagRelaySessionIdValue can be zero
Parameters:
pPADI _ Pointer to a PPPoE packet context holding a PADI packet.
ppPacket _ A pointer to a PPPoE packet context pointer.
pSrcAddr _ Source address for the PADO packet since we can not
get it from the PADI packet.
tagServiceNameLength _ Length of tagServiceNameValue blob.
tagServiceNameValue _ A blob that holds a UTF-8 Service name string.
tagACNameLength _ Length of tagACNameValue blob.
tagACNameValue _ A blob that holds a UTF-8 AC name string.
fInsertACCookieTag _ Indicates we we should also insert an AC Cookie
tag into the PADO packet.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
USHORT usLength = 0;
NDIS_STATUS status;
CHAR tagACCookieValue[PPPOE_AC_COOKIE_TAG_LENGTH];
BOOLEAN fCopyServiceNameTag = FALSE;
TRACE( TL_N, TM_Pk, ("+PacketInitializePADOToSend") );
ASSERT( pPADI != NULL );
ASSERT( ppPacket != NULL );
//
// Check if we are safe with length restrictions
//
usLength = tagServiceNameLength +
PPPOE_TAG_HEADER_LENGTH +
pPADI->tagHostUniqueLength +
( (pPADI->tagHostUniqueLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) +
pPADI->tagRelaySessionIdLength +
( (pPADI->tagRelaySessionIdLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) +
tagACNameLength +
PPPOE_TAG_HEADER_LENGTH +
( fInsertACCookieTag ? ( PPPOE_AC_COOKIE_TAG_LENGTH + PPPOE_TAG_HEADER_LENGTH ) : 0 );
if ( usLength > PACKET_GEN_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADOToSend: Can not init PADO to send, exceeding max length") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADOToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADOToSend: Can not init PADO to send, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADOToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetDestAddr( pPacket, PacketGetSrcAddr( pPADI ) );
PacketSetSrcAddr( pPacket, pSrcAddr );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_DISCOVERY );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PADO );
PacketSetSessionId( pPacket, PACKET_NULL_SESSION );
PacketSetLength( pPacket, 0 );
pPacket->tagServiceNameLength = tagServiceNameLength;
pPacket->tagServiceNameValue = tagServiceNameValue;
pPacket->tagHostUniqueLength = pPADI->tagHostUniqueLength;
pPacket->tagHostUniqueValue = pPADI->tagHostUniqueValue;
pPacket->tagRelaySessionIdLength = pPADI->tagRelaySessionIdLength;
pPacket->tagRelaySessionIdValue = pPADI->tagRelaySessionIdValue;
pPacket->tagACNameLength = tagACNameLength;
pPacket->tagACNameValue = tagACNameValue;
if ( fInsertACCookieTag )
{
PacketGenerateACCookieTag( pPADI, tagACCookieValue );
pPacket->tagACCookieLength = PPPOE_AC_COOKIE_TAG_LENGTH;
pPacket->tagACCookieValue = tagACCookieValue;
}
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADOToSend: PreparePacketForWire() failed:%x",status) );
PacketFree( pPacket );
pPacket = NULL;
}
*ppPacket = pPacket;
TRACE( TL_N, TM_Pk, ("-PacketInitializePADOToSend=$%x",status) );
return status;
}
NDIS_STATUS
PacketInitializePADRToSend(
IN PPPOE_PACKET* pPADO,
OUT PPPOE_PACKET** ppPacket,
IN USHORT tagServiceNameLength,
IN CHAR* tagServiceNameValue,
IN USHORT tagHostUniqueLength,
IN CHAR* tagHostUniqueValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PADR packet to send as a reply to a received
PADO packet.
MANDATORY TAGS:
===============
tagServiceName:
tagServiceNameLength MUST be non-zero
tagServiceNameValue MUST be non-NULL
OPTIONAL TAGS:
==============
tagHostUnique:
tagHostUniqueLength can be zero
tagHostUniqueValue can be NULL
tagACCookie: (Obtained from PADI packet)
tagHostUniqueLength can be zero
tagHostUniqueValue can be NULL
tagRelaySessionId: (Obtained from PADI packet)
tagRelaySessionIdLength can be zero
tagRelaySessionIdValue can be NULL
Parameters:
pPADO _ Pointer to a PPPoE packet context holding a PADO packet.
ppPacket _ A pointer to a PPPoE packet context pointer.
tagServiceNameLength _ Length of tagServiceNameValue blob.
tagServiceNameValue _ A blob that holds a UTF-8 service name string.
tagHostUniqueLength _ Length of tagHostUniqueValue blob.
tagHostUniqueValue _ A blob that contains a unique value to identify a packet.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
USHORT usLength = 0;
NDIS_STATUS status;
TRACE( TL_N, TM_Pk, ("+PacketInitializePADRToSend") );
ASSERT( pPADO != NULL );
ASSERT( ppPacket != NULL );
//
// Check if we are safe with length restrictions
//
usLength = tagServiceNameLength +
PPPOE_TAG_HEADER_LENGTH +
tagHostUniqueLength +
( (tagHostUniqueLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) +
pPADO->tagRelaySessionIdLength +
( (pPADO->tagRelaySessionIdLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) +
pPADO->tagACCookieLength +
( (pPADO->tagACCookieLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH ) ;
if ( usLength > PACKET_GEN_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADRToSend: Can not init PADR to send, exceeding max length") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADRToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADRToSend: Can not init PADR to send, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADRToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetSrcAddr( pPacket, PacketGetDestAddr( pPADO ) );
PacketSetDestAddr( pPacket, PacketGetSrcAddr( pPADO ) );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_DISCOVERY );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PADR );
PacketSetSessionId( pPacket, PACKET_NULL_SESSION );
PacketSetLength( pPacket, 0 );
pPacket->tagServiceNameLength = tagServiceNameLength;
pPacket->tagServiceNameValue = tagServiceNameValue;
pPacket->tagHostUniqueLength = tagHostUniqueLength;
pPacket->tagHostUniqueValue = tagHostUniqueValue;
pPacket->tagRelaySessionIdLength = pPADO->tagRelaySessionIdLength;
pPacket->tagRelaySessionIdValue = pPADO->tagRelaySessionIdValue;
pPacket->tagACCookieLength = pPADO->tagACCookieLength;
pPacket->tagACCookieValue = pPADO->tagACCookieValue;
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADRToSend: PreparePacketForWire() failed:%x",status) );
PacketFree( pPacket );
pPacket = NULL;
}
*ppPacket = pPacket;
TRACE( TL_N, TM_Pk, ("-PacketInitializePADRToSend=$%x",status) );
return status;
}
//
// This function is used to prepare a PADS packet for a received PADR packet.
//
// The PADR packet must be processed using PREPARE_PACKET_FROM_WIRE() macro
// before feeding into this function.
//
// The PADS packet should just be a packet without and associated VCs or linked lists.
//
// If you want to insert other tags to a PADI, PADO, or PADS packet, use specific
// PacketInsertTag() function after calling this function.
//
// MANDATORY TAGS:
// ===============
// tagServiceName:
// tagServiceNameLength MUST be non-zero
// tagServiceNameValue MUST be non-NULL
//
// OPTIONAL TAGS:
// ==============
// tagHostUnique:
// tagHostUniqueLength can be zero
// tagHostUniqueValue can be zero
//
// tagRelaySessionId: (Obtained from PADI packet)
// tagRelaySessionIdLength can be zero
// tagRelaySessionIdValue can be zero
//
NDIS_STATUS
PacketInitializePADSToSend(
IN PPPOE_PACKET* pPADR,
OUT PPPOE_PACKET** ppPacket,
IN USHORT usSessionId
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PADR packet to send as a reply to a received
PADO packet.
MANDATORY TAGS:
===============
tagServiceName: (Obtained from PADR packet)
tagServiceNameLength MUST be non-zero
tagServiceNameValue MUST be non-NULL
OPTIONAL TAGS:
==============
tagHostUnique: (Obtained from PADR packet)
tagHostUniqueLength can be zero
tagHostUniqueValue can be NULL
tagRelaySessionId: (Obtained from PADR packet)
tagRelaySessionIdLength can be zero
tagRelaySessionIdValue can be NULL
Parameters:
pPADR _ Pointer to a PPPoE packet context holding a PADR packet.
ppPacket _ A pointer to a PPPoE packet context pointer.
usSessionId _ Session id assigned to this session
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
USHORT usLength;
NDIS_STATUS status;
TRACE( TL_N, TM_Pk, ("+PacketInitializePADSToSend") );
ASSERT( pPADR != NULL );
ASSERT( ppPacket != NULL );
//
// Check if we are safe with length restrictions
//
usLength = pPADR->tagServiceNameLength +
PPPOE_TAG_HEADER_LENGTH +
pPADR->tagHostUniqueLength +
( (pPADR->tagHostUniqueLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH )+
pPADR->tagRelaySessionIdLength +
( (pPADR->tagRelaySessionIdLength == 0) ? 0 : PPPOE_TAG_HEADER_LENGTH );
if ( usLength > PACKET_GEN_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADSToSend: Can not init PADS to send, exceeding max length") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADSToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADSToSend: Can not init PADS to send, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADSToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetSrcAddr( pPacket, PacketGetDestAddr( pPADR ) );
PacketSetDestAddr( pPacket, PacketGetSrcAddr( pPADR ) );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_DISCOVERY );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PADS );
PacketSetSessionId( pPacket, usSessionId );
PacketSetLength( pPacket, 0 );
pPacket->tagServiceNameLength = pPADR->tagServiceNameLength;
pPacket->tagServiceNameValue = pPADR->tagServiceNameValue;
pPacket->tagHostUniqueLength = pPADR->tagHostUniqueLength;
pPacket->tagHostUniqueValue = pPADR->tagHostUniqueValue;
pPacket->tagRelaySessionIdLength = pPADR->tagRelaySessionIdLength;
pPacket->tagRelaySessionIdValue = pPADR->tagRelaySessionIdValue;
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADSToSend: PreparePacketForWire() failed:%x",status) );
PacketFree( pPacket );
pPacket = NULL;
}
*ppPacket = pPacket;
TRACE( TL_N, TM_Pk, ("-PacketInitializePADSToSend=$%x",status) );
return status;
}
NDIS_STATUS
PacketInitializePADTToSend(
OUT PPPOE_PACKET** ppPacket,
IN CHAR* pSrcAddr,
IN CHAR* pDestAddr,
IN USHORT usSessionId
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PADT packet to send to disconnect a session.
If you want to send additional tags (like error tags), use the PacketInsertTag()
function.
MANDATORY TAGS:
===============
None
OPTIONAL TAGS:
==============
None
Parameters:
ppPacket _ A pointer to a PPPoE packet context pointer.
pSrcAddr _ Buffer pointing to the source MAC addr of length 6
pDestAddr _ Buffer pointing to the dest MAC addr of length 6
usSessionId _ Session id assigned to this session
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pPacket = NULL;
USHORT usLength;
NDIS_STATUS status;
TRACE( TL_N, TM_Pk, ("+PacketInitializePADTToSend") );
ASSERT( ppPacket != NULL );
ASSERT( pDestAddr != NULL );
pPacket = PacketCreateSimple();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADTToSend: Can not init PADT to send, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketInitializePADTToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetSrcAddr( pPacket, pSrcAddr );
PacketSetDestAddr( pPacket, pDestAddr );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_DISCOVERY );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PADT );
PacketSetSessionId( pPacket, usSessionId );
PacketSetLength( pPacket, 0 );
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePADTToSend: PreparePacketForWire() failed:%x",status) );
PacketFree( pPacket );
pPacket = NULL;
}
*ppPacket = pPacket;
TRACE( TL_N, TM_Pk, ("-PacketInitializePADTToSend=$%x",status) );
return status;
}
NDIS_STATUS
PacketInitializePAYLOADToSend(
OUT PPPOE_PACKET** ppPacket,
IN CHAR* pSrcAddr,
IN CHAR* pDestAddr,
IN USHORT usSessionId,
IN NDIS_WAN_PACKET* pWanPacket,
IN PADAPTER MiniportAdapter
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to create a PAYLOAD packet to send.
If you want to send additional tags (like error tags), use the PacketInsertTag()
function.
MANDATORY TAGS:
===============
None
OPTIONAL TAGS:
==============
None
Parameters:
ppPacket _ A pointer to a PPPoE packet context pointer.
pSrcAddr _ Buffer pointing to the source MAC addr of length 6
pDestAddr _ Buffer pointing to the dest MAC addr of length 6
usSessionId _ Session id assigned to this session
pWanPacket _ Pointer to an NDISWAN packet
MiniportAdapter _ This is the pointer to the miniport adapter.
It is used to indicate the completion of async sends back
to Ndiswan.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_INVALID_PACKET
NDIS_STATUS_RESOURCES
---------------------------------------------------------------------------*/
{
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
PPPOE_PACKET* pPacket = NULL;
USHORT usLength = 0;
UINT Length;
TRACE( TL_V, TM_Pk, ("+PacketInitializePAYLOADToSend") );
ASSERT( ppPacket != NULL );
ASSERT( pDestAddr != NULL );
ASSERT( pWanPacket != NULL );
//
// Validate NDISWAN packet
//
if ( pWanPacket->CurrentLength > PACKET_GEN_MAX_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: Can not init PAYLOAD to send, exceeding max length") );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
if ( ( pWanPacket->CurrentBuffer - pWanPacket->StartBuffer ) < PPPOE_PACKET_HEADER_LENGTH )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: Can not init PAYLOAD to send, not enough front padding") );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",NDIS_STATUS_INVALID_PACKET) );
return NDIS_STATUS_INVALID_PACKET;
}
//
// Allocate a packet
//
pPacket = PacketAlloc();
if ( pPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: Can not init PAYLOAD to send, resources unavailable") );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",NDIS_STATUS_RESOURCES) );
return NDIS_STATUS_RESOURCES;
}
//
// Allocate NdisBuffer
//
//
// NOTE : Using (pWanPacket->CurrentBuffer - PPPOE_PACKET_HEADER_LENGTH) instead of
// pWanPacket->StartBuffer directly gives us the flexibility of handling packets
// with different header padding values.
//
NdisAllocateBuffer( &status,
&pPacket->pNdisBuffer,
gl_hNdisBufferPool,
pWanPacket->CurrentBuffer - PPPOE_PACKET_HEADER_LENGTH,
(UINT) ( PPPOE_PACKET_HEADER_LENGTH + pWanPacket->CurrentLength ) );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: NdisAllocateBuffer() failed") );
PacketFree( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",status) );
return status;
}
pPacket->ulFlags |= PCBF_BufferAllocatedFromNdisBufferPool;
//
// Query new buffer descriptor to get hold of the real memory pointer
//
pPacket->pHeader = NULL;
NdisQueryBufferSafe( pPacket->pNdisBuffer,
&pPacket->pHeader,
&Length,
NormalPagePriority );
if ( pPacket->pHeader == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: NdisQueryBufferSafe() failed") );
PacketFree( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",status) );
return NDIS_STATUS_RESOURCES;
}
//
// Allocate an NDIS packet from our pool
//
pPacket->pNdisPacket = GetPacketFromPool( &gl_poolPackets, &pPacket->pPacketHead );
if ( pPacket->pNdisPacket == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: GetPacketFromPool() failed") );
PacketFree( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",status) );
return NDIS_STATUS_RESOURCES;
}
pPacket->ulFlags |= PCBF_PacketAllocatedFromOurPacketPool;
//
// Chain buffer to packet
//
NdisChainBufferAtFront( pPacket->pNdisPacket, pPacket->pNdisBuffer );
pPacket->ulFlags |= PCBF_BufferChainedToPacket;
//
// Set the payload and payload length
//
pPacket->pPayload = pPacket->pHeader + PPPOE_PACKET_HEADER_LENGTH;
usLength = (USHORT) pWanPacket->CurrentLength;
//
// General initialization that applies to all packet codes
//
InitializeListHead( &pPacket->linkPackets );
PacketSetDestAddr( pPacket, pDestAddr );
PacketSetSrcAddr( pPacket, pSrcAddr );
PacketSetEtherType( pPacket, PACKET_ETHERTYPE_PAYLOAD );
PacketSetVersion( pPacket, PACKET_VERSION );
PacketSetType( pPacket, PACKET_TYPE );
PacketSetCode( pPacket, PACKET_CODE_PAYLOAD );
PacketSetSessionId( pPacket, usSessionId );
PacketSetLength( pPacket, usLength );
//
// Set the input NDIS_PACKET to the reserved area so that we can reach it
// when we have to return this packet back to the upper layer.
//
*((PPPOE_PACKET UNALIGNED**)(&pPacket->pNdisPacket->ProtocolReserved[0 * sizeof(PVOID)])) = pPacket;
*((NDIS_WAN_PACKET UNALIGNED**)(&pPacket->pNdisPacket->ProtocolReserved[1 * sizeof(PVOID)])) = pWanPacket;
*((ADAPTER UNALIGNED **)(&pPacket->pNdisPacket->ProtocolReserved[2 * sizeof(PVOID)])) = MiniportAdapter;
status = PreparePacketForWire( pPacket );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializePAYLOADToSend: PreparePacketForWire() failed") );
PacketFree( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",status) );
return status;
}
//
// This must be done here as we do not want to call NdisMWanSendComplete() in PacketFree() if the
// PreparePacketForWire() fails.
//
pPacket->ulFlags |= PCBF_CallNdisMWanSendComplete;
MpPacketOwnedByNdiswanReceived( MiniportAdapter );
*ppPacket = pPacket;
TRACE( TL_V, TM_Pk, ("-PacketInitializePAYLOADToSend=$%x",status) );
return status;
}
NDIS_STATUS
PacketInitializeFromReceived(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function prepares a PPPoE packet by using the Ndis packet from wire.
This function will make sure that the packet is a PPPoE packet, and convert
it to a PPPoE packet context. It tries to do this as efficiently as possible
by trying to use the buffers of the received packet if possible.
It will also do all the validation in the packet to make sure it is
compliant with the RFC. However, it can not perform the checks that need data
from a sent packet. Caller must use various PacketRetrieve*() functions to
retrieve the necesarry data and use it to match and validate to a sent packet.
Parameters:
pPacket _ Pointer to a PPPoE packet context.
Return Values:
NDIS_STATUS_SUCCESS
NDIS_STATUS_RESOURCES
NDIS_STATUS_INVALID_PACKET
---------------------------------------------------------------------------*/
{
NDIS_STATUS status;
ASSERT( pPacket != NULL );
TRACE( TL_V, TM_Pk, ("+PacketInitializeFromReceived") );
if ( !PacketIsPPPoE( pPacket ) )
{
status = NDIS_STATUS_INVALID_PACKET;
TRACE( TL_V, TM_Pk, ("-PacketInitializeFromReceived=$%x",status) );
return status;
}
do
{
status = NDIS_STATUS_INVALID_PACKET;
//
// Validate the tag lenghts inside the packet so that we do not
// step outside buffer boundaries further processing the packet.
// Do this only if the packet is not a payload packet!
//
if ( PacketGetCode( pPacket ) != PACKET_CODE_PAYLOAD )
{
CHAR* pBufStart;
CHAR* pBufEnd;
USHORT tagLength;
pBufStart = pPacket->pPayload;
pBufEnd = pPacket->pPayload + PacketGetLength( pPacket );
while ( pBufStart + PPPOE_TAG_HEADER_LENGTH <= pBufEnd )
{
//
// Skip the tag type field
//
((USHORT*) pBufStart)++;
//
// Retrieve the tag length, and look at the next tag
//
tagLength = ntohs( *((USHORT UNALIGNED *) pBufStart) ) ;
((USHORT*) pBufStart)++;
pBufStart += tagLength;
}
if ( pBufStart != pBufEnd )
break;
}
status = NDIS_STATUS_SUCCESS;
} while ( FALSE );
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Corrupt packet - invalid tags") );
TRACE( TL_V, TM_Pk, ("-PacketInitializeFromReceived=$%x",status) );
return status;
}
switch ( PacketGetCode( pPacket ) )
{
USHORT tagLength;
CHAR* tagValue;
status = NDIS_STATUS_INVALID_PACKET;
case PACKET_CODE_PADI:
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processing PADI") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is PACKET_NULL_SESSION
//
if ( PacketGetSessionId( pPacket ) != PACKET_NULL_SESSION )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
//
// Extract mandatory tags first
//
RetrieveTag( pPacket,
tagServiceName,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Service name tag not found") );
break;
}
//
// Extract optional tags
//
RetrieveTag( pPacket,
tagHostUnique,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
//
// Extract the relay session id tag if it exists
//
RetrieveTag( pPacket,
tagRelaySessionId,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processed PADI succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
case PACKET_CODE_PADO:
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processing PADO") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is PACKET_NULL_SESSION
//
if ( PacketGetSessionId( pPacket ) != PACKET_NULL_SESSION )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
//
// Extract mandatory tags first
//
RetrieveTag( pPacket,
tagServiceName,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Service name tag not found") );
break;
}
RetrieveTag( pPacket,
tagACName,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: AC-Name tag not found") );
break;
}
//
// Extract optional tags
//
RetrieveTag( pPacket,
tagHostUnique,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
RetrieveTag( pPacket,
tagACCookie,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
//
// Extract the relay session id tag if it exists
//
RetrieveTag( pPacket,
tagRelaySessionId,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processed PADO succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
case PACKET_CODE_PADR:
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processing PADR") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is PACKET_NULL_SESSION
//
if ( PacketGetSessionId( pPacket ) != PACKET_NULL_SESSION )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
//
// Extract mandatory tags first
//
RetrieveTag( pPacket,
tagServiceName,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Service name tag not found") );
break;
}
//
// Extract optional tags
//
RetrieveTag( pPacket,
tagHostUnique,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
RetrieveTag( pPacket,
tagACCookie,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
//
// Extract the relay session id tag if it exists
//
RetrieveTag( pPacket,
tagRelaySessionId,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processed PADR succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
case PACKET_CODE_PADS:
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processing PADS") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is NOT PACKET_NULL_SESSION.
// However, if session id is PACKET_NULL_SESSION, then make sure we have
// a an Error tag received as per RFC 2156.
//
if ( PacketGetSessionId( pPacket ) == PACKET_NULL_SESSION )
{
RetrieveErrorTags( pPacket );
if ( !PacketAnyErrorTagsReceived( pPacket ) )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
}
//
// Extract mandatory tags first
//
RetrieveTag( pPacket,
tagServiceName,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
if ( tagValue == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Service name tag not found") );
break;
}
//
// Extract optional tags
//
RetrieveTag( pPacket,
tagHostUnique,
&tagLength,
&tagValue,
0,
NULL,
TRUE );
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processed PADS succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
case PACKET_CODE_PADT:
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processing PADT") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_DISCOVERY )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is not PACKET_NULL_SESSION
//
if ( PacketGetSessionId( pPacket ) == PACKET_NULL_SESSION )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
TRACE( TL_N, TM_Pk, ("PacketInitializeFromReceived: Processed PADT succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
case PACKET_CODE_PAYLOAD:
TRACE( TL_V, TM_Pk, ("PacketInitializeFromReceived: Processing PAYLOAD") );
//
// Make sure we have received the correct ethertype
//
if ( PacketGetEtherType( pPacket ) != PACKET_ETHERTYPE_PAYLOAD )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid ether type") );
break;
}
//
// Make sure session id is not PACKET_NULL_SESSION
//
if ( PacketGetSessionId( pPacket ) == PACKET_NULL_SESSION )
{
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Invalid session id") );
break;
}
TRACE( TL_V, TM_Pk, ("PacketInitializeFromReceived: Processed PAYLOAD succesfully") );
status = NDIS_STATUS_SUCCESS;
break;
default:
//
// Unknown packet code
//
TRACE( TL_A, TM_Pk, ("PacketInitializeFromReceived: Ignoring unknown packet") );
break;
}
if ( status != NDIS_STATUS_SUCCESS )
{
TRACE( TL_V, TM_Pk, ("-PacketInitializeFromReceived=$%x",status) );
return status;
}
//
// The packet was processed succesfuly, now check if we received any error tags
//
RetrieveErrorTags( pPacket );
TRACE( TL_V, TM_Pk, ("-PacketInitializeFromReceived=$%x",status) );
return status;
}
BOOLEAN
PacketAnyErrorTagsReceived(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitialize*FromReceived()
function, one should call this function to understand if an error tag was
noticed in the packet.
If this function yields TRUE, then the caller should call PacketRetrieveErrorTag()
get the error type and value.
Parameters:
pPacket _ A pointer to a PPPoE packet context.
Return Values:
TRUE
FALSE
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
return( pPacket->ulFlags & PCBF_ErrorTagReceived ) ? TRUE : FALSE;
}
VOID
PacketRetrievePayload(
IN PPPOE_PACKET* pPacket,
OUT CHAR** ppPayload,
OUT USHORT* pusLength
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the payload portion of the
packet if the packet is a PAYLOAD packet.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a PAYLOAD packet.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pusLength != NULL );
ASSERT( ppPayload != NULL );
*pusLength = PacketGetLength( pPacket );
*ppPayload = pPacket->pPayload;
}
VOID
PacketRetrieveServiceNameTag(
IN PPPOE_PACKET* pPacket,
OUT USHORT* pTagLength,
OUT CHAR** pTagValue,
IN USHORT prevTagLength,
IN CHAR* prevTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the service name tag from
the packet.
If prevTagValue and prevTagLength are given, then next service name tag will
be returned, otherwise the first service name tag will be returned.
If no such service name tags are found, then 0 and NULL will be returned for
length and value parameters.
CAUTION: Note that a service name tag of length 0 is valid, and one should
check the value of pTagValue to understand if service name tag was
found in the packet or not.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a control packet.
pTagLength _ On return, holds the length of the service name tag found.
pTagValue _ On return, points to the buffer holding the service name.
Will be NULL, if no service name tags could be found.
prevTagLength _ Length of the previously returned service name tag.
prevTagValue _ Points to the buffer holding the previous service name tag.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
if ( prevTagLength == 0 &&
prevTagValue == NULL )
{
//
// Caller asks for the first Service Name Tag, and it should be ready in
// the reserved field of the PPPOE_PACKET
//
*pTagLength = pPacket->tagServiceNameLength;
*pTagValue = pPacket->tagServiceNameValue;
}
else
{
//
// Caller asks for the next Service Name Tag, so try to find and return it
//
RetrieveTag( pPacket,
tagServiceName,
pTagLength,
pTagValue,
prevTagLength,
prevTagValue,
FALSE );
}
}
VOID
PacketRetrieveHostUniqueTag(
IN PPPOE_PACKET* pPacket,
OUT USHORT* pTagLength,
OUT CHAR** pTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the host unique tag from
the packet.
If no host unique tag is found, then 0 and NULL will be returned for
length and value parameters.
CAUTION: Note that a host unique tag of length 0 is valid, and one should
check the value of pTagValue to understand if host unique tag was
found in the packet or not.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a control packet.
pTagLength _ On return, holds the length of the host unique tag found.
pTagValue _ On return, points to the buffer holding the host unique value.
Will be NULL, if no host unique tags could be found.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
//
// Caller asks for the HostUnique, and it should be ready in
// the reserved field of the PPPOE_PACKET
//
*pTagLength = pPacket->tagHostUniqueLength;
*pTagValue = pPacket->tagHostUniqueValue;
}
VOID
PacketRetrieveACNameTag(
IN PPPOE_PACKET* pPacket,
OUT USHORT* pTagLength,
OUT CHAR** pTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the AC name tag from
the packet.
If no AC name tag is found, then 0 and NULL will be returned for
length and value parameters.
CAUTION: Note that an AC name tag of length 0 is valid, and one should
check the value of pTagValue to understand if AC name tag was
found in the packet or not.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a control packet.
pTagLength _ On return, holds the length of the AC name tag found.
pTagValue _ On return, points to the buffer holding the AC name.
Will be NULL, if no AC name tags could be found.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
//
// Caller asks for the AC Name, and it should be ready in
// the reserved field of the PPPOE_PACKET
//
*pTagLength = pPacket->tagACNameLength;
*pTagValue = pPacket->tagACNameValue;
}
VOID
PacketRetrieveACCookieTag(
IN PPPOE_PACKET* pPacket,
OUT USHORT* pTagLength,
OUT CHAR** pTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the AC cookie tag from
the packet.
If no AC cookie tag is found, then 0 and NULL will be returned for
length and value parameters.
CAUTION: Note that an AC cookie tag of length 0 is valid, and one should
check the value of pTagValue to understand if AC cookie tag was
found in the packet or not.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a control packet.
pTagLength _ On return, holds the length of the AC cookie tag found.
pTagValue _ On return, points to the buffer holding the AC cookie.
Will be NULL, if no AC cookie tags could be found.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
//
// Caller asks for the AC Cookie, and it should be ready in
// the reserved field of the PPPOE_PACKET
//
*pTagLength = pPacket->tagACCookieLength;
*pTagValue = pPacket->tagACCookieValue;
}
VOID
PacketRetrieveErrorTag(
IN PPPOE_PACKET* pPacket,
OUT PACKET_TAGS* pTagType,
OUT USHORT* pTagLength,
OUT CHAR** pTagValue
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
After a received packet is first processed by a PacketInitializeFromReceived()
function, one should call this function to retrieve the error information from
the packet.
If no errors were found, then 0 and NULL will be returned for length and value
parameters.
CAUTION: Note that an error tag of length 0 is valid, and one should
check the value of pTagValue to understand if an error tag was
found in the packet or not.
Parameters:
pPacket _ A pointer to a PPPoE packet context holding a control packet.
pTagType _ On return, holds the type of the error tag found.
pTagLength _ On return, holds the length of the error tag found.
pTagValue _ On return, points to the buffer holding the error.
Will be NULL, if no error tags could be found.
Return Values:
None
---------------------------------------------------------------------------*/
{
ASSERT( pPacket != NULL );
ASSERT( pTagType != NULL );
ASSERT( pTagLength != NULL );
ASSERT( pTagValue != NULL );
//
// Caller asks for the received error, and it should be ready in
// the reserved field of the PPPOE_PACKET
//
if ( pPacket->ulFlags & PCBF_ErrorTagReceived )
{
*pTagType = pPacket->tagErrorType;
*pTagLength = pPacket->tagErrorTagLength;
*pTagValue = pPacket->tagErrorTagValue;
}
else
{
*pTagLength = 0;
*pTagValue = NULL;
}
}
PPPOE_PACKET*
PacketMakeClone(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will be used to make a clone of a packet for sending it
over multiple bindings.
CAUTION: This function only clones the NDIS_PACKET portion of PPPOE_PACKET
and leaves other fields untouched, so the clone packets should only
be used with NdisSend(), and disposed there after.
Parameters:
pPacket _ A pointer to a PPPoE packet context that will be cloned.
Return Values:
Pointer to the clone packet if succesfull, NULL otherwise.
---------------------------------------------------------------------------*/
{
PPPOE_PACKET* pClone = NULL;
TRACE( TL_N, TM_Pk, ("+PacketMakeClone") );
//
// Allocate the clone
//
pClone = PacketCreateSimple();
if ( pClone == NULL )
{
TRACE( TL_A, TM_Pk, ("PacketMakeClone: Can not make clone, resources unavailable") );
TRACE( TL_N, TM_Pk, ("-PacketMakeClone=$%x",pClone) );
return pClone;
}
//
// Copy the clone
//
NdisMoveMemory( pClone->pHeader, pPacket->pHeader, PPPOE_PACKET_HEADER_LENGTH );
NdisMoveMemory( pClone->pPayload, pPacket->pPayload, PACKET_GEN_MAX_LENGTH );
NdisAdjustBufferLength( pClone->pNdisBuffer,
(UINT) ( PacketGetLength( pPacket ) + PPPOE_PACKET_HEADER_LENGTH ) );
TRACE( TL_N, TM_Pk, ("-PacketMakeClone=$%x",pClone) );
return pClone;
}
PPPOE_PACKET*
PacketGetRelatedPppoePacket(
IN NDIS_PACKET* pNdisPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will be used to get the owning PPPoE packet context from an
Ndis packet.
Parameters:
pNdisPacket _ A pointer to an Ndis packet that belongs to a PPPoE packet.
Return Values:
A pointer to the owning PPPoE packet.
---------------------------------------------------------------------------*/
{
return (*(PPPOE_PACKET**)(&pNdisPacket->ProtocolReserved[0 * sizeof(PVOID)]));
}
NDIS_WAN_PACKET*
PacketGetRelatedNdiswanPacket(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will be used to get related NDISWAN packet from a PPPoE
payload packet that was perpared and sent.
Parameters:
pPacket _ A pointer to a PPPoE payload packet that was sent.
Return Values:
A pointer to the related NDISWAN packet.
---------------------------------------------------------------------------*/
{
return (*(NDIS_WAN_PACKET**)(&pPacket->pNdisPacket->ProtocolReserved[1 * sizeof(PVOID)])) ;
}
PADAPTER
PacketGetMiniportAdapter(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function will be used to get miniport adapter set in
PacketInitializePAYLOADToSend() function.
Parameters:
pPacket _ A pointer to a PPPoE payload packet that was sent.
Return Values:
Miniport adapter
---------------------------------------------------------------------------*/
{
return (*(ADAPTER**)(&pPacket->pNdisPacket->ProtocolReserved[2 * sizeof(PVOID)]));
}
VOID
PacketGenerateACCookieTag(
IN PPPOE_PACKET* pPacket,
IN CHAR tagACCookieValue[ PPPOE_AC_COOKIE_TAG_LENGTH ]
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to generate the AC Cookie tag based on the PADI
packets sources address.
Parameters:
pPacket _ A pointer to a PADI packet that was received.
Return Values:
None
---------------------------------------------------------------------------*/
{
NdisMoveMemory( tagACCookieValue, PacketGetSrcAddr( pPacket ), 6 );
}
BOOLEAN
PacketValidateACCookieTagInPADR(
IN PPPOE_PACKET* pPacket
)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Functional Description:
This function is used to validate the AC Cookie tag in a received PADR
packet.
It basically uses the source address from the PADR packet to generate the
original AC Cookie tag and compares them. If they are equal TRUE is returned,
otherwise FALSE is returned.
Parameters:
pPacket _ A pointer to a PADR packet that was received.
Return Values:
None
---------------------------------------------------------------------------*/
{
BOOLEAN fRet = FALSE;
CHAR tagACCookie[ PPPOE_AC_COOKIE_TAG_LENGTH ];
CHAR* tagACCookieValue = NULL;
USHORT tagACCookieLength = 0;
PacketRetrieveACCookieTag( pPacket,
&tagACCookieLength,
&tagACCookieValue );
PacketGenerateACCookieTag( pPacket, tagACCookie );
if ( NdisEqualMemory( tagACCookie, tagACCookieValue, PPPOE_AC_COOKIE_TAG_LENGTH ) )
{
fRet = TRUE;
}
return fRet;
}