3745 lines
105 KiB
C
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;
|
|
}
|