You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3519 lines
102 KiB
3519 lines
102 KiB
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Module Name:
|
|
|
|
protocol.c
|
|
|
|
Abstract:
|
|
|
|
This module contains all the protocol interface routines.
|
|
|
|
Author:
|
|
|
|
Hakan Berk - Microsoft, Inc. ([email protected]) 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 <tdikrnl.h> // For TdiCopyLookaheadData()
|
|
//
|
|
// VOID
|
|
// TdiCopyLookaheadData(
|
|
// IN PVOID Destination,
|
|
// IN PVOID Source,
|
|
// IN ULONG Length,
|
|
// IN ULONG ReceiveFlags
|
|
// );
|
|
//
|
|
/*
|
|
#ifdef _M_IX86
|
|
#define TdiCopyLookaheadData(_Destination,_Source,_Length,_ReceiveFlags) \
|
|
RtlCopyMemory(_Destination,_Source,_Length)
|
|
#else
|
|
#define TdiCopyLookaheadData(_Destination,_Source,_Length,_ReceiveFlags) { \
|
|
if ((_ReceiveFlags) & TDI_RECEIVE_COPY_LOOKAHEAD) { \
|
|
RtlCopyMemory(_Destination,_Source,_Length); \
|
|
} else { \
|
|
PUCHAR _Src = (PUCHAR)(_Source); \
|
|
PUCHAR _Dest = (PUCHAR)(_Destination); \
|
|
PUCHAR _End = _Dest + (_Length); \
|
|
while (_Dest < _End) { \
|
|
*_Dest++ = *_Src++; \
|
|
} \
|
|
} \
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
#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"
|
|
|
|
extern NPAGED_LOOKASIDE_LIST gl_llistWorkItems;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Variables local to this module
|
|
// They are defined as global only for debugging purposes
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define INVALID_HANDLE_VALUE (NDIS_HANDLE) 0
|
|
|
|
//
|
|
// Handle passed to us by NDIS while registering the protocol
|
|
//
|
|
NDIS_HANDLE gl_hNdisProtocolHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// Controls access for members listed below
|
|
//
|
|
NDIS_SPIN_LOCK gl_lockProtocol;
|
|
|
|
//
|
|
// List of binding contexts that are bound
|
|
//
|
|
LIST_ENTRY gl_linkBindings;
|
|
|
|
//
|
|
// Boolean flag to remember if PrUnload() was called previously
|
|
//
|
|
BOOLEAN gl_fProtocolUnloaded = TRUE;
|
|
|
|
// Boolean flag to decide if we need to set packet filters at bind time
|
|
//
|
|
//
|
|
BOOLEAN gl_fSetPacketFiltersAtBind = FALSE;
|
|
|
|
//
|
|
// Boolean flag set to tell the protocol it is okay to bind
|
|
// This flag is initially FALSE and is only set to true
|
|
// when a tapi client either wants to make an outgoing call
|
|
// or listen for incoming calls
|
|
//
|
|
BOOLEAN gl_fBindProtocol = FALSE;
|
|
|
|
|
|
//
|
|
// Number of binding contexts in linkBindings
|
|
//
|
|
ULONG gl_ulNumBindings;
|
|
|
|
//
|
|
// Keeps the minimum of max frame sizes of bindings.
|
|
// This value is used by miniport and is passed to NDISWAN
|
|
// in OID_WAN_GET_INFO query.
|
|
//
|
|
ULONG gl_ulMaxFrameSize = 0;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Local functions (not exposed) definitions
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
NDIS_STATUS
|
|
InitializeProtocol(
|
|
IN NDIS_HANDLE NdisProtocolHandle,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function initializes the static protocol members.
|
|
NdisRegisterProtocol() must be called before.
|
|
|
|
Parameters:
|
|
|
|
DriverObject:
|
|
Pointer to the driver object.
|
|
|
|
RegistryPath:
|
|
A unicode string that identifies the registry entry. We can use this this retrieve
|
|
value from the registry.
|
|
|
|
Return Values:
|
|
|
|
NDIS_STATUS_SUCCESS:
|
|
Protocol initialized.
|
|
|
|
NDIS_STATUS_XXX:
|
|
Protocol initialization failed, deregister protocol.
|
|
---------------------------------------------------------------------------*/
|
|
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+InitializeProtocol") );
|
|
|
|
//
|
|
// Future: Read values from registry here
|
|
//
|
|
|
|
//
|
|
// Initialize the NdisProtocolHandle
|
|
//
|
|
gl_hNdisProtocolHandle = NdisProtocolHandle;
|
|
|
|
//
|
|
// Allocate the spin lock
|
|
//
|
|
NdisAllocateSpinLock( &gl_lockProtocol );
|
|
|
|
//
|
|
// Initialize list of bindings
|
|
//
|
|
NdisInitializeListHead( &gl_linkBindings );
|
|
|
|
//
|
|
// Initialize number of allocated bindings
|
|
//
|
|
gl_ulNumBindings = 0;
|
|
|
|
//
|
|
// Load the resources
|
|
//
|
|
PrLoad();
|
|
|
|
TRACE( TL_N, TM_Pr, ("-InitializeProtocol=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
PrLoad()
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will allocate the resources for the protocol.
|
|
|
|
Caller must make sure that PrLoad() and PrUnload() are not called simultaneously,
|
|
as well as multiple PrLoad()'s are not called simultanesouly.
|
|
|
|
It will load the resources if they were unloaded, and do nothing otherwise.
|
|
|
|
We need this function because the resources freed by PrUnload() must be loaded
|
|
somehow, and there is no function called prior to PrBindAdapter() once PrUnload()
|
|
is called. So we allocate all the resources for the binding, and once binding is completed,
|
|
we call this function to load the resources if necesarry prior to notifying the completion
|
|
of binding to NDIS.
|
|
|
|
Parameters:
|
|
|
|
None
|
|
|
|
Return Values:
|
|
|
|
- Pointer to the newly allocated binding context.
|
|
- NULL if allocation fails.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
{
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrLoad") );
|
|
|
|
//
|
|
// Make sure we are not trying to initialize resources,
|
|
// unless they are already freed by PrUnload()
|
|
//
|
|
if ( gl_fProtocolUnloaded )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrLoad: Loading the resources" ) );
|
|
|
|
ASSERT( gl_ulNumBindings == 0 );
|
|
|
|
//
|
|
// Allocate packet pool
|
|
//
|
|
PacketPoolInit();
|
|
|
|
gl_fProtocolUnloaded = FALSE;
|
|
}
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrLoad") );
|
|
}
|
|
|
|
|
|
|
|
BINDING*
|
|
AllocBinding()
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will allocate the resources for the binding context.
|
|
|
|
Parameters:
|
|
|
|
pBinding _ A pointer to our binding information structure.
|
|
|
|
fAcquireLock _ Flag that indicates if the function needs to acquire the lock
|
|
or not. If the caller already owns the lock for the binding,
|
|
then it should be supplied as TRUE, otherwise FALSE.
|
|
|
|
Return Values:
|
|
|
|
- Pointer to the newly allocated binding context.
|
|
- NULL if allocation fails.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
BINDING* pBinding = NULL;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+AllocBinding") );
|
|
|
|
if ( ALLOC_BINDING( &pBinding ) != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TRACE( TL_A, TM_Pr, ("AllocBinding: Could not allocate context") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-AllocBinding") );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NdisZeroMemory( pBinding, sizeof(BINDING) );
|
|
|
|
pBinding->tagBinding = MTAG_BINDING;
|
|
|
|
pBinding->stateBinding = BN_stateBindPending;
|
|
|
|
NdisInitializeEvent( &pBinding->RequestCompleted );
|
|
|
|
pBinding->BindAdapterStatus = NDIS_STATUS_FAILURE;
|
|
|
|
NdisInitializeEvent( &pBinding->eventFreeBinding );
|
|
|
|
NdisAllocateSpinLock( &pBinding->lockBinding );
|
|
|
|
InitializeListHead( &pBinding->linkPackets );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-AllocBinding") );
|
|
|
|
return pBinding;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReferenceBinding(
|
|
IN BINDING* pBinding,
|
|
IN BOOLEAN fAcquireLock
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will increment the reference count on the binding.
|
|
|
|
Parameters:
|
|
|
|
pBinding _ A pointer ot our binding information structure.
|
|
|
|
fAcquireLock _ Flag that indicates if the function needs to acquire the lock
|
|
or not. If the caller already owns the lock for the binding,
|
|
then it should be supplied as TRUE, otherwise FALSE.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
LONG lRef;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+ReferenceBinding") );
|
|
|
|
if ( fAcquireLock )
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
lRef = ++pBinding->lRef;
|
|
|
|
if ( fAcquireLock )
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-ReferenceBinding=$%d",lRef) );
|
|
}
|
|
|
|
VOID
|
|
DereferenceBinding(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will decrement the reference count on the binding.
|
|
If the count reaches 0, it will signal pBinding->eventFreeBinding
|
|
so that PrUnbindAdapter() function can free the protocol context.
|
|
|
|
CAUTION: Caller must not be holding any locks.
|
|
|
|
Parameters:
|
|
|
|
pBinding _ A pointer to our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BOOLEAN fSignalFreeBindingEvent = FALSE;
|
|
LONG lRef;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+DereferenceBinding") );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
lRef = --pBinding->lRef;
|
|
|
|
if ( lRef == 0 )
|
|
{
|
|
fSignalFreeBindingEvent = TRUE;
|
|
}
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
if ( fSignalFreeBindingEvent )
|
|
NdisSetEvent( &pBinding->eventFreeBinding );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-DereferenceBinding=$%d",lRef) );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
BindingCleanup(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will free the resources allocated for the binding context.
|
|
|
|
Parameters:
|
|
|
|
pBinding _ A pointer to our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+BindingCleanup") );
|
|
|
|
ASSERT( pBinding->lRef == 0 );
|
|
|
|
NdisFreeSpinLock( &pBinding->lockBinding );
|
|
|
|
FREE_BINDING( pBinding );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-BindingCleanup") );
|
|
}
|
|
|
|
VOID
|
|
DetermineMaxFrameSize()
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called when a new binding is added or removed.
|
|
It will walk thru all the bindings and select the minimum of max frame
|
|
size values, and set it to gl_ulMaxFrameSize.
|
|
|
|
It will be called from 2 places:
|
|
- PrAddBindingToProtocol()
|
|
- PrRemoveBindingFromProtocol()
|
|
|
|
CAUTION: gl_lockProtocol must be acquired before calling this function.
|
|
|
|
Parameters:
|
|
|
|
None
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
LIST_ENTRY* pLink = NULL;
|
|
|
|
pLink = gl_linkBindings.Flink;
|
|
|
|
//
|
|
// See if we have any bindings
|
|
//
|
|
if ( pLink != &gl_linkBindings )
|
|
{
|
|
ULONG MinOfMaxFrameSizes = 0;
|
|
BINDING* pBinding = NULL;
|
|
|
|
//
|
|
// We have at least one binding, so walk thru the list
|
|
// and select the minimum of MaxFrameSize values
|
|
//
|
|
pBinding = ((BINDING*) CONTAINING_RECORD( pLink, BINDING, linkBindings ));
|
|
|
|
MinOfMaxFrameSizes = pBinding->ulMaxFrameSize;
|
|
|
|
//
|
|
// Iterate to the next binding
|
|
//
|
|
pLink = pLink->Flink;
|
|
|
|
while ( pLink != &gl_linkBindings )
|
|
{
|
|
ULONG MaxFrameSize;
|
|
|
|
//
|
|
// Retrieve the MaxFrameSize value of the next binding and
|
|
// select the minimum
|
|
//
|
|
pBinding = ((BINDING*) CONTAINING_RECORD( pLink, BINDING, linkBindings ));
|
|
|
|
MaxFrameSize = pBinding->ulMaxFrameSize;
|
|
|
|
if ( MinOfMaxFrameSizes > MaxFrameSize )
|
|
{
|
|
MinOfMaxFrameSizes = MaxFrameSize;
|
|
}
|
|
|
|
//
|
|
// Iterate to the next binding
|
|
//
|
|
pLink = pLink->Flink;
|
|
}
|
|
|
|
//
|
|
// Set gl_ulMaxFrameSize to the selected minimum value
|
|
//
|
|
gl_ulMaxFrameSize = MinOfMaxFrameSizes;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Binding list is empty, so set it to 0
|
|
//
|
|
gl_ulMaxFrameSize = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AddBindingToProtocol(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will insert a binding to protocols binding table.
|
|
|
|
It will also put a reference on the binding which will go away
|
|
when the binding is removed from this table with a call to
|
|
RemoveBindingFromProtocol().
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+AddBindingToProtocol") );
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
InsertTailList( &gl_linkBindings, &pBinding->linkBindings );
|
|
|
|
gl_ulNumBindings++;
|
|
|
|
//
|
|
// Determine the new max frame size value
|
|
//
|
|
DetermineMaxFrameSize();
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
ReferenceBinding( pBinding, TRUE );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-AddBindingToProtocol") );
|
|
}
|
|
|
|
VOID
|
|
RemoveBindingFromProtocol(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will remove a binding from protocols binding list.
|
|
|
|
Binding will be dereferenced after removal from the list.
|
|
|
|
CAUTION: Caller must not be holding any locks before calling this function.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
|
|
{
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+RemoveBindingFromProtocol") );
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
RemoveHeadList( pBinding->linkBindings.Blink );
|
|
|
|
InitializeListHead( &pBinding->linkBindings );
|
|
|
|
gl_ulNumBindings--;
|
|
|
|
//
|
|
// Determine the new max frame size value
|
|
//
|
|
DetermineMaxFrameSize();
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
DereferenceBinding( pBinding );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-RemoveBindingFromProtocol") );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Interface functions (exposed) definitions
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
PrUnload(
|
|
VOID
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
In response to a user request to uninstall a protocol, NDIS calls a protocol's
|
|
ProtocolUnload function if the protocol has registered an entry point for
|
|
this function in the NDIS_PROTOCOL_CHARACTERISTICS structure that it passed
|
|
to NdisRegisterProtocol. NDIS calls ProtocolUnload after calling the protocol's
|
|
ProtocolUnbindAdapter function once for each bound adapter.
|
|
|
|
ProtocolUnload performs driver-determined cleanup operations. For example,
|
|
ProtocolUnload could request clients to close handles that they have opened
|
|
to device objects exported by the protocol. Until all such handles are closed,
|
|
the I/O Manager will not call the DriverUnload function that the protocol
|
|
registered in the driver object passed to its DriverEntry function. After all
|
|
the handles are closed, ProtocolUnload could call IoDeleteDevice one or more
|
|
times to delete device objects created by the protocol.
|
|
|
|
ProtocolUnload does not have to close a protocol's open bindings. When a
|
|
protocol's DriverUnload function calls NdisDeregisterProtocol, NDIS calls the
|
|
protocol's ProtocolUnbindAdapter function once for each binding that the
|
|
protocol has open. The ProtocolUnbindAdapter function calls NdisCloseAdapter
|
|
to close the binding.
|
|
|
|
ProtocolUnload must be written so that it can run at IRQL PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
None
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("+PrUnload") );
|
|
|
|
if ( !gl_fProtocolUnloaded && gl_ulNumBindings == 0 )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrUnload: Unloading the resources" ) );
|
|
|
|
PacketPoolUninit();
|
|
|
|
gl_fProtocolUnloaded = TRUE;
|
|
}
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrUnlooad") );
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
PrRegisterProtocol(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
OUT NDIS_HANDLE* pNdisProtocolHandle
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will register the protocol with NDIS.
|
|
It must be called from DriverEntry() function before any other in this module
|
|
can be called.
|
|
|
|
Parameters:
|
|
|
|
DriverObject:
|
|
Pointer to the driver object.
|
|
|
|
RegistryPath:
|
|
A unicode string that identifies the registry entry. We can use this this retrieve
|
|
value from the registry.
|
|
|
|
Return Values:
|
|
|
|
NDIS_STATUS_SUCCESS :
|
|
The NDIS library registered the caller as a protocol driver.
|
|
|
|
NDIS_STATUS_BAD_CHARACTERISTICS :
|
|
The CharacteristicsLength is too small for the MajorNdisVersion specified in
|
|
the buffer at ProtocolCharacteristics.
|
|
|
|
NDIS_STATUS_BAD_VERSION :
|
|
The MajorNdisVersion specified in the buffer at ProtocolCharacteristics is
|
|
invalid.
|
|
|
|
NDIS_STATUS_RESOURCES :
|
|
A shortage of resources, possibly memory, prevented the NDIS library from
|
|
registering the caller.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
BOOLEAN fProtocolRegistered = FALSE;
|
|
NDIS_HANDLE NdisProtocolHandle;
|
|
NDIS_PROTOCOL_CHARACTERISTICS npc;
|
|
STRING NameString;
|
|
UNICODE_STRING UnicodeNameString;
|
|
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrRegisterProtocol") );
|
|
|
|
do
|
|
{
|
|
|
|
NdisZeroMemory( &npc, sizeof(npc) );
|
|
|
|
npc.MajorNdisVersion = PR_NDIS_MajorVersion;
|
|
npc.MinorNdisVersion = PR_NDIS_MinorVersion;
|
|
|
|
npc.Reserved = NDIS_USE_WAN_WRAPPER;
|
|
|
|
npc.OpenAdapterCompleteHandler = PrOpenAdapterComplete;
|
|
npc.CloseAdapterCompleteHandler = PrCloseAdapterComplete;
|
|
npc.SendCompleteHandler = PrSendComplete;
|
|
npc.TransferDataCompleteHandler = PrTransferDataComplete;
|
|
// npc.ResetCompleteHandler = PrResetCompleteHandler;
|
|
npc.RequestCompleteHandler = PrRequestComplete;
|
|
npc.ReceiveHandler = PrReceive;
|
|
npc.ReceiveCompleteHandler = PrReceiveComplete;
|
|
npc.StatusHandler = PrStatus;
|
|
npc.StatusCompleteHandler = PrStatusComplete;
|
|
|
|
RtlInitString( &NameString, PR_CHARACTERISTIC_NAME );
|
|
|
|
RtlAnsiStringToUnicodeString( &UnicodeNameString,
|
|
&NameString,
|
|
TRUE );
|
|
|
|
npc.Name.Length = UnicodeNameString.Length;
|
|
npc.Name.Buffer = UnicodeNameString.Buffer;
|
|
|
|
//
|
|
// MajorNdisVersion must be set to 0x04 or 0x05
|
|
// with any of the following members.
|
|
//
|
|
npc.ReceivePacketHandler = PrReceivePacket;
|
|
npc.BindAdapterHandler = PrBindAdapter;
|
|
npc.UnbindAdapterHandler = PrUnbindAdapter;
|
|
npc.PnPEventHandler = PrPnPEvent;
|
|
npc.UnloadHandler = PrUnload;
|
|
|
|
//
|
|
// MajorNdisVersion must be set to 0x05
|
|
// with any of the following members.
|
|
//
|
|
// CoSendCompleteHandler;
|
|
// CoStatusHandler;
|
|
// CoReceivePacketHandler;
|
|
// CoAfRegisterNotifyHandler;
|
|
|
|
NdisRegisterProtocol( &status,
|
|
&NdisProtocolHandle,
|
|
&npc,
|
|
sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) );
|
|
|
|
if ( status != NDIS_STATUS_SUCCESS )
|
|
break;
|
|
|
|
fProtocolRegistered = TRUE;
|
|
|
|
status = InitializeProtocol( NdisProtocolHandle, RegistryPath );
|
|
|
|
if ( status != NDIS_STATUS_SUCCESS )
|
|
break;
|
|
|
|
} while ( FALSE );
|
|
|
|
if ( status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
if ( fProtocolRegistered )
|
|
{
|
|
NDIS_STATUS tempStatus;
|
|
|
|
NdisDeregisterProtocol( &tempStatus, NdisProtocolHandle );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pNdisProtocolHandle = NdisProtocolHandle;
|
|
}
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrRegisterProtocol=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PrBindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE BindContext,
|
|
IN PNDIS_STRING DeviceName,
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID SystemSpecific2
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called by NDIS when an underlying adapter wants to
|
|
bind to us.
|
|
|
|
Parameters:
|
|
|
|
Status
|
|
Points to a variable in which ProtocolBindAdapter returns the status of its
|
|
operation(s), as one of the following:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
The driver completed initialization successfully and bound itself to the
|
|
given NIC driver specified at DeviceName.
|
|
|
|
NDIS_STATUS_PENDING
|
|
The protocol will complete the bind operation asynchronously with a call to
|
|
NdisCompleteBindAdapter when it is ready to accept receives from the
|
|
underlying driver and to send transmit, query, and set requests down to the
|
|
underlying driver.
|
|
|
|
NDIS_STATUS_XXX or NTSTATUS_XXX
|
|
The protocol's attempt to set up a binding failed or the protocol could not
|
|
allocate the resources it needed to carry out network I/O operations. Usually
|
|
, such an error status is propagated from an NdisXxx function or a kernel-
|
|
mode support routine.
|
|
|
|
BindContext
|
|
Specifies a handle, supplied by NDIS, that the protocol passes subsequently
|
|
to NdisCompleteBindAdapter.
|
|
|
|
DeviceName
|
|
Points to a buffered Unicode string naming an underlying NIC driver or
|
|
virtual NIC driver to which ProtocolBindAdapter should bind.
|
|
|
|
SystemSpecific1
|
|
Specifies a registry path pointer that is a required parameter to
|
|
NdisOpenProtocolConfiguration. The caller cannot use this pointer for any
|
|
other purpose.
|
|
|
|
SystemSpecific2
|
|
Reserved for system use. The caller cannot use this pointer for any purpose.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_FAILURE;
|
|
BINDING* pBinding = NULL;
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrBindAdapter") );
|
|
|
|
do
|
|
{
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
if (gl_fBindProtocol == FALSE) {
|
|
|
|
TRACE( TL_I, TM_Pr, ("PrBindAdapter: Not ready to bind!") );
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
status = NDIS_STATUS_FAILURE;
|
|
|
|
break;
|
|
}
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
pBinding = AllocBinding();
|
|
|
|
if ( pBinding == NULL )
|
|
{
|
|
status = NDIS_STATUS_RESOURCES;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Load resources
|
|
//
|
|
PrLoad();
|
|
|
|
//
|
|
// Open adapter, and query it
|
|
//
|
|
if ( !PrOpenAdapter( pBinding, DeviceName ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( !PrQueryAdapterForCurrentAddress( pBinding ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// No need to break if this one fails since it is not critical enough
|
|
//
|
|
PrQueryAdapterForLinkSpeed( pBinding );
|
|
|
|
if ( !PrQueryAdapterForMaxFrameSize( pBinding ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check if we need to set packet filters at bind time
|
|
//
|
|
if ( gl_fSetPacketFiltersAtBind )
|
|
{
|
|
PrSetPacketFilterForAdapter( pBinding, TRUE);
|
|
}
|
|
|
|
//
|
|
// Change the state to bound
|
|
//
|
|
pBinding->stateBinding = BN_stateBound;
|
|
|
|
// AddBindingToProtocol() will insert the new binding to protocols
|
|
// binding list, and reference it
|
|
//
|
|
AddBindingToProtocol( pBinding );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
|
|
} while ( FALSE);
|
|
|
|
if ( pBinding )
|
|
{
|
|
pBinding->ulBindingFlags |= BNBF_BindAdapterCompleted;
|
|
|
|
pBinding->BindAdapterStatus = status;
|
|
|
|
if ( status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// We did not call NdisCompleteBindAdapter() because
|
|
// somethings went wrong
|
|
//
|
|
|
|
//
|
|
// Close the adapter if it was opened succesfully
|
|
//
|
|
if ( ( pBinding->ulBindingFlags & BNBF_OpenAdapterCompleted ) &&
|
|
( pBinding->OpenAdapterStatus == NDIS_STATUS_SUCCESS ) )
|
|
{
|
|
PrCloseAdapter( pBinding );
|
|
}
|
|
|
|
//
|
|
// Clean up the binding context
|
|
//
|
|
BindingCleanup( pBinding );
|
|
}
|
|
}
|
|
|
|
*Status = status;
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrBindAdapter=$%x",status) );
|
|
}
|
|
|
|
BOOLEAN
|
|
PrOpenAdapter(
|
|
IN BINDING* pBinding,
|
|
IN PNDIS_STRING DeviceName
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to open the underlying adapter.
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
DeviceName:
|
|
Name of the device to be opened. This is passed to PrBindAdapter()
|
|
by NDIS.
|
|
|
|
Return Values:
|
|
TRUE:
|
|
If underlying adapter could be opened succesfully.
|
|
|
|
FALSE:
|
|
If underlying adapter could not be opened succesfully.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status;
|
|
NDIS_STATUS openErrorStatus;
|
|
|
|
NDIS_MEDIUM arrayNdisMedium[] = { NdisMedium802_3 };
|
|
UINT sizeNdisMediumArray = sizeof( arrayNdisMedium ) / sizeof( NDIS_MEDIUM );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrOpenAdapter") );
|
|
|
|
NdisOpenAdapter( &status,
|
|
&openErrorStatus,
|
|
&pBinding->NdisBindingHandle,
|
|
&pBinding->uintSelectedMediumIndex,
|
|
arrayNdisMedium,
|
|
sizeNdisMediumArray,
|
|
gl_hNdisProtocolHandle,
|
|
pBinding,
|
|
DeviceName,
|
|
0,
|
|
NULL );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NidsOpenAdapter() completed synchronously,
|
|
// so call PrOpenAdapterComplete() manually.
|
|
//
|
|
PrOpenAdapterComplete( pBinding,
|
|
status,
|
|
openErrorStatus );
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrOpenAdapter") );
|
|
|
|
return pBinding->OpenAdapterStatus == NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
PrOpenAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called after the underlying adapter is opened.
|
|
|
|
We save the result of the Open adapter operation and set the RequestCompleted
|
|
member of the binding context to resume the thread waiting for this to complete.
|
|
|
|
CAUTION: It can be called from PASSIVE_LEVEL or at DISPATCH_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
A pointer ot our binding information structure.
|
|
|
|
Status:
|
|
NDIS_STATUS_SUCCESS:
|
|
Indicates that NdisOpenAdapter() completed succesfully.
|
|
|
|
NDIS_XXX:
|
|
Indicates that NdisOpenAdapter() did not complete succesfully.
|
|
|
|
OpenErrorStatus:
|
|
Specifies additional information about the reason for a failure if the value
|
|
at Status is not NDIS_STATUS_SUCCESS and if the underlying driver supplied
|
|
this information. For example, the driver of a Token Ring NIC might return a
|
|
ring error that NDIS forwards to ProtocolOpenAdapterComplete. This parameter
|
|
can be NULL.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrOpenAdapterComplete") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrOpenAdapterComplete: NdisOpenAdapter() completed=$%x", Status ) );
|
|
|
|
pBinding->ulBindingFlags |= BNBF_OpenAdapterCompleted;
|
|
|
|
pBinding->OpenAdapterStatus = Status;
|
|
|
|
NdisSetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrOpenAdapterComplete") );
|
|
}
|
|
|
|
VOID
|
|
PrStatusComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is a required driver function that completes a status-change
|
|
operation initiated when the underlying driver calls NdisMIndicateStatus.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING *pBinding = (BINDING *) ProtocolBindingContext;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PrQueryAdapterForCurrentAddress(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to query the underlying adapter for current MAC
|
|
address oid.
|
|
|
|
The underlying adapter must have been opened succesfully prior to calling
|
|
this function.
|
|
|
|
We save the result of the request in the binding context and set the
|
|
RequestCompleted member of the binding context to resume the thread
|
|
waiting for this to complete.
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
TRUE:
|
|
If the request was completed succesfully.
|
|
|
|
FALSE:
|
|
If the request was not completed succesfully.
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
NDIS_STATUS status;
|
|
PNDIS_REQUEST pRequest = &pBinding->Request;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrQueryAdapterForCurrentAddress") );
|
|
|
|
//
|
|
// Generate an NDIS_REQUEST for querying current address oid
|
|
//
|
|
NdisZeroMemory( pRequest, sizeof( NDIS_REQUEST ) );
|
|
|
|
pRequest->RequestType = NdisRequestQueryInformation ;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBinding->LocalAddress;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof( CHAR ) * 6;
|
|
|
|
//
|
|
// Request information from the adapter
|
|
//
|
|
NdisRequest( &status,
|
|
pBinding->NdisBindingHandle,
|
|
pRequest );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisRequest() completed synchronously, call PrRequestComplete()
|
|
// manually.
|
|
//
|
|
PrRequestComplete( pBinding,
|
|
pRequest,
|
|
status );
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrQueryAdapterForCurrentAddress") );
|
|
|
|
return pBinding->RequestStatus == NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
PrQueryAdapterForLinkSpeed(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to query the underlying adapter for link speed oid.
|
|
|
|
The underlying adapter must have been opened succesfully prior to calling
|
|
this function.
|
|
|
|
We save the result of the request in the binding context and set the
|
|
RequestCompleted member of the binding context to resume the thread
|
|
waiting for this to complete.
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
TRUE:
|
|
If the request was completed succesfully.
|
|
|
|
FALSE:
|
|
If the request was not completed succesfully.
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
NDIS_STATUS status;
|
|
PNDIS_REQUEST pRequest = &pBinding->Request;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrQueryAdapterForLinkSpeed") );
|
|
|
|
//
|
|
// Generate an NDIS_REQUEST for querying link speed oid
|
|
//
|
|
NdisZeroMemory( pRequest, sizeof( NDIS_REQUEST ) );
|
|
|
|
pRequest->RequestType = NdisRequestQueryInformation ;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBuffer = &pBinding->ulSpeed;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof( pBinding->ulSpeed );
|
|
|
|
//
|
|
// Request information from the adapter
|
|
//
|
|
NdisRequest( &status,
|
|
pBinding->NdisBindingHandle,
|
|
pRequest );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisRequest() completed synchronously, call PrRequestComplete()
|
|
// manually.
|
|
//
|
|
PrRequestComplete( pBinding,
|
|
pRequest,
|
|
status );
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrQueryAdapterForLinkSpeed") );
|
|
|
|
return pBinding->RequestStatus == NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
PrQueryAdapterForMaxFrameSize(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to query the underlying adapter for max frame size
|
|
oid.
|
|
|
|
The underlying adapter must have been opened succesfully prior to calling
|
|
this function.
|
|
|
|
We save the result of the request in the binding context and set the
|
|
RequestCompleted member of the binding context to resume the thread
|
|
waiting for this to complete.
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
Return Values:
|
|
|
|
TRUE:
|
|
If the request was completed succesfully.
|
|
|
|
FALSE:
|
|
If the request was not completed succesfully.
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
NDIS_STATUS status;
|
|
PNDIS_REQUEST pRequest = &pBinding->Request;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrQueryAdapterForMaxFrameSize") );
|
|
|
|
//
|
|
// Generate an NDIS_REQUEST for querying link speed oid
|
|
//
|
|
NdisZeroMemory( pRequest, sizeof( NDIS_REQUEST ) );
|
|
|
|
pRequest->RequestType = NdisRequestQueryInformation ;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBuffer = &pBinding->ulMaxFrameSize;
|
|
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBufferLength = sizeof( pBinding->ulMaxFrameSize );
|
|
|
|
//
|
|
// Request information from the adapter
|
|
//
|
|
NdisRequest( &status,
|
|
pBinding->NdisBindingHandle,
|
|
pRequest );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisRequest() completed synchronously, call PrRequestComplete()
|
|
// manually.
|
|
//
|
|
PrRequestComplete( pBinding,
|
|
pRequest,
|
|
status );
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrQueryAdapterForMaxFrameSize") );
|
|
|
|
return pBinding->RequestStatus == NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
PrSetPacketFilterForAdapter(
|
|
IN BINDING* pBinding,
|
|
IN BOOLEAN fSet
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to set the current generic packet filter for our
|
|
protocol.
|
|
|
|
The underlying adapter must have been opened succesfully prior to calling
|
|
this function.
|
|
|
|
We save the result of the request in the binding context and set the
|
|
RequestCompleted member of the binding context to resume the thread
|
|
waiting for this to complete.
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
fSet:
|
|
Indicates what the filters will be set to.
|
|
TRUE means receive packets, FALSE means set it to 0.
|
|
|
|
Return Values:
|
|
|
|
TRUE:
|
|
If the request was completed succesfully.
|
|
|
|
FALSE:
|
|
If the request was not completed succesfully.
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
|
|
NDIS_STATUS status;
|
|
PNDIS_REQUEST pRequest = &pBinding->Request;
|
|
BOOLEAN fPacketFilterAlreadySet = (BOOLEAN) ( pBinding->ulBindingFlags & BNBF_PacketFilterSet );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrSetPacketFilterForAdapter") );
|
|
|
|
//
|
|
// See if we already are in the state the request wants us to be in
|
|
//
|
|
if ( ( fPacketFilterAlreadySet && fSet ) ||
|
|
( !fPacketFilterAlreadySet && !fSet ) )
|
|
{
|
|
pBinding->RequestStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrSetPacketFilterForAdapter: Already in the requested state") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrSetPacketFilterForAdapter") );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
pBinding->ulPacketFilter = ( fSet ) ? (NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED) : 0;
|
|
|
|
//
|
|
// Generate an NDIS_REQUEST for setting current packet filter
|
|
//
|
|
NdisZeroMemory( pRequest, sizeof( NDIS_REQUEST ) );
|
|
|
|
pRequest->RequestType = NdisRequestSetInformation;
|
|
|
|
pRequest->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
|
|
|
|
pRequest->DATA.SET_INFORMATION.InformationBuffer = &pBinding->ulPacketFilter;
|
|
|
|
pRequest->DATA.SET_INFORMATION.InformationBufferLength = sizeof( ULONG );
|
|
|
|
//
|
|
// Request set info on the adapter
|
|
//
|
|
NdisRequest( &status,
|
|
pBinding->NdisBindingHandle,
|
|
pRequest );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisRequest() completed synchronously, call PrRequestComplete()
|
|
// manually.
|
|
//
|
|
PrRequestComplete( pBinding,
|
|
pRequest,
|
|
status );
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrSetPacketFilterForAdapter") );
|
|
|
|
return pBinding->RequestStatus == NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
PrRequestComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_REQUEST pRequest,
|
|
IN NDIS_STATUS status
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called to indicate that an NDIS request submitted
|
|
previously has completed.
|
|
|
|
We submit 2 requests:
|
|
- OID_802_3_CURRENT_ADDRESS: This is submitted from PrQueryAdapterForCurrentAddress()
|
|
to obtain the current MAC address for the underlying
|
|
adapter.
|
|
|
|
- OID_GEN_LINK_SPEED: This is submitted from PrQueryAdapterForLinkSpeed() to obtain
|
|
the current link speed of the underlying adapter.
|
|
|
|
- OID_GEN_CURRENT_PACKET_FILTER: This is submitted from PrSetPacketFilterForAdapter()
|
|
to set the packet types we are interested in to NDIS.
|
|
|
|
|
|
If the request for MAC address fail, we clean up the binding context and notify
|
|
NDIS that bind adapter failed, otherwise we go ahead and query the adapter for link
|
|
speed.
|
|
|
|
Regardless of the status of request for link speed, we notify NDIS about succesful
|
|
completion of the bind operation as this is not a fatal error.
|
|
|
|
Before calling this function, the underlying adapter must have been opened
|
|
succesfully.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
A pointer ot our binding information structure.
|
|
|
|
pRequest:
|
|
A pointer to the request submitted previously.
|
|
|
|
Status:
|
|
Completion status of the request.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
BOOLEAN fUnknownOid = FALSE;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrRequestComplete") );
|
|
|
|
switch ( pRequest->RequestType )
|
|
{
|
|
|
|
case NdisRequestQueryInformation:
|
|
{
|
|
|
|
switch ( pRequest->DATA.QUERY_INFORMATION.Oid )
|
|
{
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: OID_802_3_CURRENT_ADDRESS=$%x",status) );
|
|
|
|
pBinding->ulBindingFlags |= BNBF_CurrentAddressQueryCompleted;
|
|
|
|
break;
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: OID_GEN_LINK_SPEED=$%x",status) );
|
|
|
|
pBinding->ulBindingFlags |= BNBF_LinkSpeedQueryCompleted;
|
|
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: OID_GEN_MAXIMUM_FRAME_SIZE=$%x",status) );
|
|
|
|
pBinding->ulBindingFlags |= BNBF_MaxFrameSizeQueryCompleted;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: UNKNOWN OID=$%x",pRequest->DATA.QUERY_INFORMATION.Oid) );
|
|
|
|
fUnknownOid = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NdisRequestSetInformation:
|
|
{
|
|
switch ( pRequest->DATA.SET_INFORMATION.Oid )
|
|
{
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: OID_GEN_CURRENT_PACKET_FILTER=$%x",status) );
|
|
|
|
if ( status == NDIS_STATUS_SUCCESS )
|
|
{
|
|
if ( pBinding->ulBindingFlags & BNBF_PacketFilterSet )
|
|
{
|
|
//
|
|
// Packet filter was set, so reset it
|
|
//
|
|
pBinding->ulBindingFlags &= ~BNBF_PacketFilterSet;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Packet filter was reset, so set it
|
|
//
|
|
pBinding->ulBindingFlags |= BNBF_PacketFilterSet;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: UNKNOWN OID=$%x",pRequest->DATA.SET_INFORMATION.Oid) );
|
|
|
|
fUnknownOid = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrRequestComplete: Unknown RequestType=$%x",pRequest->RequestType) );
|
|
|
|
fUnknownOid = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( !fUnknownOid )
|
|
{
|
|
pBinding->RequestStatus = status;
|
|
|
|
NdisSetEvent( &pBinding->RequestCompleted );
|
|
}
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrRequestComplete") );
|
|
}
|
|
|
|
VOID
|
|
PrUnbindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE UnbindContext
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called by NDIS when an underlying adapter wants to
|
|
unbind from us.
|
|
|
|
ArvindM says PrBindAdapter() and PrUnbindAdapter() will be serialized
|
|
by NDIS.
|
|
|
|
This function will not be called if PrBindAdapter() did not succeed.
|
|
|
|
Also this function will not be called as long as there are outstanding
|
|
PrReceivePacket() calls active.
|
|
|
|
However this function may be called while there are outstanding
|
|
PrSend(), PrSendPayload() or PrBroadcast() calls, that's why we keep
|
|
track of such calls with pBinding->nSendPending and wait on the completion
|
|
of these requests. And as we set the state to BN_stateUnbinding, no such
|
|
new requests will be accepted, and pBinding->nSendPending will reach 0
|
|
at some point which will trigger the pBinding->eventSendCompleted.
|
|
|
|
This function is called at IRQL_PASSIVE level by default so we can
|
|
safely wait on events.
|
|
|
|
Parameters:
|
|
|
|
Status
|
|
Points to a variable in which ProtocolBindAdapter returns the status of its
|
|
operation(s), as one of the following:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
The driver completed the unbind operation and deallocated the resources.
|
|
|
|
NDIS_STATUS_PENDING
|
|
The protocol will complete the unbind operation asynchronously with a call to
|
|
NdisCompleteUnbindAdapter when ProtocolCloseAdapterComplete() is called.
|
|
|
|
ProtocolBindingContext
|
|
A pointer to our binding context.
|
|
|
|
UnbindContext:
|
|
This handle is supplied by NDIS and should be used if NdisCloseAdapter() pends.
|
|
Then we will get a call to ProtocolCloseAdapterComplete() which will use this
|
|
handle to notify NDIS about the completion of the initial PrUnbindAdapter()
|
|
request.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrUnbindAdapter") );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
//
|
|
// If there is a sleep request pending, wait for it to complete
|
|
//
|
|
while ( pBinding->stateBinding == BN_stateSleepPending )
|
|
{
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
NdisMSleep( 10000 );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
}
|
|
|
|
//
|
|
// Mark binding as unbind pending
|
|
//
|
|
ASSERT( pBinding->stateBinding == BN_stateSleeping ||
|
|
pBinding->stateBinding == BN_stateBound );
|
|
|
|
pBinding->stateBinding = BN_stateUnbindPending;
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
//
|
|
// Unbind all the active sessions on this binding
|
|
//
|
|
MpNotifyBindingRemoval( pBinding );
|
|
|
|
//
|
|
// Remove Binding from protocols binding table
|
|
//
|
|
RemoveBindingFromProtocol( pBinding );
|
|
|
|
//
|
|
// Wait for all references to be deleted
|
|
//
|
|
NdisWaitEvent( &pBinding->eventFreeBinding, 0 );
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrUnbindAdapter: All references are deleted") );
|
|
|
|
//
|
|
// All references have been removed, now wait for all packets owned by NDIS
|
|
// to be returned.
|
|
//
|
|
// Note that no synchronization is necesarry for reading the value of numPacketsOwnedByNdis
|
|
// at this point since it can only be incremented when there is at least 1 reference on the
|
|
// binding - at this point ref count is 0 -, and because it can not be incremented, it can
|
|
// only reach 0 once.
|
|
//
|
|
while ( pBinding->NumPacketsOwnedByNdis )
|
|
{
|
|
NdisMSleep( 10000 );
|
|
}
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrUnbindAdapter: All NDIS owned packets have been returned") );
|
|
|
|
//
|
|
// Since all references have been deleted, we can close the underlying adapter.
|
|
//
|
|
PrCloseAdapter( pBinding );
|
|
|
|
//
|
|
// Change the binding state to unbound
|
|
//
|
|
pBinding->stateBinding = BN_stateUnbound;
|
|
|
|
//
|
|
// Clean up the binding context
|
|
//
|
|
BindingCleanup( pBinding );
|
|
|
|
*Status = NDIS_STATUS_SUCCESS;
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrUnbindAdapter") );
|
|
}
|
|
|
|
|
|
VOID
|
|
PrCloseAdapter(
|
|
IN BINDING* pBinding
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to close the underlying adapter. It must be called
|
|
either from PrBindAdapter() or PrUnbindAdapter().
|
|
|
|
CAUTION: It must be called from PASSIVE_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
Binding context that owns the adapter to close.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrCloseAdapter") );
|
|
|
|
NdisCloseAdapter( &status, pBinding->NdisBindingHandle );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisCloseAdapter() completed synchronously,
|
|
// complete the request manually
|
|
//
|
|
PrCloseAdapterComplete( pBinding, status );
|
|
|
|
}
|
|
|
|
NdisWaitEvent( &pBinding->RequestCompleted, 0 );
|
|
|
|
NdisResetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrCloseAdapter") );
|
|
}
|
|
|
|
|
|
VOID
|
|
PrCloseAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function can be called from PrCloseAdapter() if NdisCloseAdapter()
|
|
completes synchronously, or it will be called by NDIS at DISPATCH_LEVEL.
|
|
|
|
It sets the BNBF_CloseAdapterCompleted flag and sets the RequestCompleted
|
|
member of the binding context to resume the thread waiting on this event.
|
|
|
|
CAUTION: It can be called from PASSIVE_LEVEL or DISPATCH_LEVEL.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
Specifies the handle to a protocol-allocated context area in which the
|
|
protocol driver maintains per-binding runtime state. The driver supplied this
|
|
handle when it called NdisOpenAdapter.
|
|
|
|
Status:
|
|
Indicates the final status of the close operation in the underlying driver.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = ProtocolBindingContext;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_I, TM_Pr, ("+PrCloseAdapterComplete") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrCloseAdapterComplete: NdisCloseAdapter() completed=$%x", Status ) );
|
|
|
|
pBinding->ulBindingFlags |= BNBF_CloseAdapterCompleted;
|
|
|
|
NdisSetEvent( &pBinding->RequestCompleted );
|
|
|
|
TRACE( TL_I, TM_Pr, ("-PrCloseAdapterComplete") );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PrAddCallToBinding(
|
|
IN BINDING* pBinding,
|
|
IN PCALL pCall
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will put a reference on the binding which will be removed
|
|
when PrRemoveCallFromBinding() is called.
|
|
|
|
It will return TRUE if reference is added succesfully, and FALSE if reference
|
|
could not be added.
|
|
|
|
Reference will not be added if binding is not in bound state.
|
|
|
|
CAUTION: Caller must make sure that the binding is not freed before calling this
|
|
function.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
A pointer ot our binding information structure.
|
|
|
|
pCall:
|
|
A pointer to our call information structure.
|
|
|
|
Return Values:
|
|
|
|
TRUE:
|
|
Binding referenced for the call
|
|
|
|
FALSE:
|
|
Binding not reference for the call
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BOOLEAN fResult;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrAddCallToBinding") );
|
|
|
|
//
|
|
// We have to acquire lock of call first to avoid dead locks
|
|
//
|
|
NdisAcquireSpinLock( &pCall->lockCall );
|
|
|
|
if ( pCall->ulClFlags & CLBF_CallDropped ||
|
|
pCall->ulClFlags & CLBF_CallClosePending )
|
|
{
|
|
NdisReleaseSpinLock( &pCall->lockCall );
|
|
|
|
TRACE( TL_A, TM_Pr, ("PrAddCallToBinding: Call already dropped or close pending") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrAddCallToBinding") );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
//
|
|
// Check the state of the binding, if it is not bound
|
|
// we can not add the call
|
|
//
|
|
if ( pBinding->stateBinding != BN_stateBound )
|
|
{
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
NdisReleaseSpinLock( &pCall->lockCall );
|
|
|
|
TRACE( TL_A, TM_Pr, ("PrAddCallToBinding: Binding state not bound") );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrAddCallToBinding") );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Both binding and call are ready to be bound
|
|
// Go ahead and add the call
|
|
//
|
|
|
|
//
|
|
// Set call's binding context ptr to binding
|
|
//
|
|
pCall->pBinding = pBinding;
|
|
|
|
//
|
|
// Copy the local address of the binding
|
|
//
|
|
NdisMoveMemory( pCall->SrcAddr, pBinding->LocalAddress, 6 * sizeof( CHAR ) );
|
|
|
|
//
|
|
// Set call's link speed
|
|
//
|
|
pCall->ulSpeed = pBinding->ulSpeed;
|
|
|
|
//
|
|
// Pass the MaxFrameSize to call context
|
|
//
|
|
pCall->ulMaxFrameSize = pBinding->ulMaxFrameSize - PPPOE_PACKET_HEADER_LENGTH;
|
|
|
|
//
|
|
// Make a reference on the binding which will be removed when PrRemoveCallFromBinding()
|
|
// is called
|
|
//
|
|
ReferenceBinding( pBinding, FALSE );
|
|
|
|
//
|
|
// Release the locks, and return
|
|
//
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
NdisReleaseSpinLock( &pCall->lockCall );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrAddCallToBinding") );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
PrRemoveCallFromBinding(
|
|
IN BINDING* pBinding,
|
|
IN CALL* pCall
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called to remove a reference added by a PrAddCallToBinding()
|
|
for a call on this binding.
|
|
|
|
Parameters:
|
|
|
|
pBinding:
|
|
Pointer to the binding context that the will be dereferenced.
|
|
|
|
pCall:
|
|
Pointer to the call context being unbound fromthe binding.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrRemoveCallFromBinding") );
|
|
|
|
NdisAcquireSpinLock( &pCall->lockCall );
|
|
|
|
pCall->pBinding = NULL;
|
|
|
|
pCall->ulSpeed = 0;
|
|
|
|
NdisReleaseSpinLock( &pCall->lockCall );
|
|
|
|
DereferenceBinding( pBinding );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrRemoveCallFromBinding") );
|
|
}
|
|
|
|
VOID
|
|
PrSendComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called by NDIS to notify that a previously send operation
|
|
on this packet has been completed.
|
|
|
|
It will notify NDISWAN, if packet was a payload packet.
|
|
|
|
It will remove the references on the packet and binding added by the PrSendXXX()
|
|
functions.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
A pointer to our binding context.
|
|
|
|
pNdisPacket:
|
|
Ndis Packet that was send previously.
|
|
|
|
Status:
|
|
Status of the send operation.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
PPPOE_PACKET* pPacket = NULL;
|
|
USHORT usCode;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrSendComplete($%x,$%x,$%x)",pBinding,pNdisPacket,Status) );
|
|
|
|
//
|
|
// Retrieve the related PPPoE packet context from the NDIS packet
|
|
//
|
|
pPacket = PacketGetRelatedPppoePacket( pNdisPacket );
|
|
|
|
ASSERT( pPacket != NULL );
|
|
|
|
//
|
|
// Set the completion status for the send to be passed back to
|
|
// NDISWAN when the packet is freed (only for Payload packets)
|
|
//
|
|
PacketSetSendCompletionStatus( pPacket, Status );
|
|
|
|
//
|
|
// Remove the reference on the packet added by the sending function
|
|
//
|
|
DereferencePacket( pPacket );
|
|
|
|
//
|
|
// Remove the reference on the binding
|
|
//
|
|
DereferenceBinding( pBinding );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrSendComplete($%x,$%x,$%x)",pBinding,pNdisPacket,Status) );
|
|
}
|
|
|
|
INT
|
|
PrReceivePacket(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called by NDIS when a packet is received over this binding.
|
|
|
|
Packet is converted into a PPPoE packet and notified to Miniport so that miniport
|
|
processes it.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
A pointer to our binding context.
|
|
|
|
Packet:
|
|
An Ndis packet received over this binding.
|
|
|
|
Return Values:
|
|
|
|
The return value represents the number of references NDIS should wait for
|
|
before freeing his copy of the packet, but we will be done by the NDIS packet
|
|
at the end of the function, we always return 0.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
|
|
PPPOE_PACKET* pPacket = NULL;
|
|
INT nRefCount = 0;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrReceivePacket($%x,$%x)",pBinding,Packet) );
|
|
|
|
do
|
|
{
|
|
pPacket = PacketNdis2Pppoe( (PVOID) pBinding,
|
|
Packet,
|
|
&nRefCount );
|
|
|
|
if ( pPacket )
|
|
{
|
|
|
|
TRACE( TL_V, TM_Pr, ("PrReceivePacket: Received PPPoE packet=$%x",pPacket) );
|
|
|
|
//
|
|
// We have a copy of the packet, insert it into our queue of received packets,
|
|
// so that it will be consumed by a call to our PrReceiveComplete() function.
|
|
//
|
|
// It will be freed when it is consumed in PrReceiveComplete().
|
|
//
|
|
|
|
NdisInterlockedInsertTailList( &pBinding->linkPackets,
|
|
&pPacket->linkPackets,
|
|
&pBinding->lockBinding );
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrReceivePacket($%x,$%x)",pBinding,Packet) );
|
|
|
|
return nRefCount;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
PrBroadcast(
|
|
IN PPPOE_PACKET* pPacket
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called by an adapter to broadcast a PADI packet.
|
|
|
|
It clones the packet and schedules a send over each binding that's currrently
|
|
active.
|
|
|
|
The caller can destroy the packet after return from this function.
|
|
|
|
Parameters:
|
|
|
|
pPacket:
|
|
A PPPoE PADI packet ready to be broadcast.
|
|
|
|
Return Values:
|
|
|
|
NDIS_STATUS_SUCCESS:
|
|
At least 1 send operation was scheduled over a binding.
|
|
|
|
NDIS_STATUS_FAILURE:
|
|
No sends could be scheduled.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrBroadcast($%x)",pPacket) );
|
|
|
|
//
|
|
// Check if we have any bindings
|
|
//
|
|
if ( gl_ulNumBindings == 0 )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrBroadcast($%x): No bindings available",pPacket) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrBroadcast($%x)=$%x",pPacket,status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
do
|
|
{
|
|
LIST_ENTRY* pHead = NULL;
|
|
|
|
//
|
|
// We have to do the same check again, as the first one is to make sure
|
|
// we have allocated the spin lock, and this one is to make sure after we acquired
|
|
// it, we still have some bindings
|
|
//
|
|
if ( gl_ulNumBindings == 0 )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrBroadcast($%x): No bindings available",pPacket) );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the head of the bindings list
|
|
//
|
|
pHead = gl_linkBindings.Flink;
|
|
|
|
//
|
|
// Traverse the bindings list and schedule a PrSend() with a clone of pNdisPacket
|
|
//
|
|
while ( pHead != &gl_linkBindings )
|
|
{
|
|
PPPOE_PACKET* pClone = NULL;
|
|
BINDING* pBinding = (BINDING*) CONTAINING_RECORD( pHead,
|
|
BINDING,
|
|
linkBindings );
|
|
//
|
|
// Do not schedule a send if binding is not bound
|
|
//
|
|
if ( pBinding->stateBinding != BN_stateBound )
|
|
{
|
|
pHead = pHead->Flink;
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make a clone of the actual packet
|
|
//
|
|
pClone = PacketMakeClone( pPacket );
|
|
|
|
if ( pClone != NULL )
|
|
{
|
|
WORKITEM* pWorkItem = NULL;
|
|
PVOID Args[4];
|
|
|
|
//
|
|
// Set the source address on the packet to be sent
|
|
//
|
|
PacketSetSrcAddr( pClone, pBinding->LocalAddress );
|
|
|
|
//
|
|
// Set the arguements array
|
|
//
|
|
Args[0] = (PVOID) pBinding;
|
|
Args[1] = (PVOID) pClone;
|
|
|
|
//
|
|
// Allocate work item
|
|
//
|
|
pWorkItem = AllocWorkItem( &gl_llistWorkItems,
|
|
ExecBindingWorkItem,
|
|
NULL,
|
|
Args,
|
|
BWT_workPrSend );
|
|
|
|
if ( pWorkItem != NULL )
|
|
{
|
|
|
|
ReferenceBinding( pBinding, TRUE );
|
|
|
|
ReferencePacket( pClone );
|
|
|
|
//
|
|
// Schedule the send operation
|
|
//
|
|
ScheduleWorkItem( pWorkItem );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// We can free the packet since we have put a reference for scheduling it
|
|
//
|
|
PacketFree( pClone );
|
|
}
|
|
|
|
pHead = pHead->Flink;
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrBroadcast($%x)=$%x",pPacket,status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
ExecBindingWorkItem(
|
|
IN PVOID Args[4],
|
|
IN UINT workType
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function executes the scheduled work items for the binding.
|
|
|
|
|
|
Parameters:
|
|
|
|
Args:
|
|
An array of length 4 keeping PVOIDs
|
|
|
|
workType:
|
|
Indicates the type of the work to be executed.
|
|
We use this to understand what we should do in this function.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
TRACE( TL_V, TM_Pr, ("+ExecBindingWorkItem") );
|
|
|
|
switch( workType )
|
|
{
|
|
|
|
case BWT_workPrStartBinds:
|
|
//
|
|
// Tell NDIS to bind our protocol to any interested miniports.
|
|
// If we need to start an outgoing call then kick that off too.
|
|
//
|
|
{
|
|
ULONG_PTR FilterChangeRequest = (ULONG_PTR) Args[0];
|
|
BOOLEAN fSetFilters = (BOOLEAN) ( FilterChangeRequest != BN_ResetFiltersForCloseLine );
|
|
|
|
switch ( FilterChangeRequest )
|
|
{
|
|
case BN_SetFiltersForMediaDetection:
|
|
{
|
|
//
|
|
// This is a set default media detection request so complete it
|
|
//
|
|
LINE* pLine = (LINE*) Args[1];
|
|
PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION pRequest = (PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) Args[2];
|
|
|
|
PrReEnumerateBindings();
|
|
|
|
ChangePacketFiltersForAdapters( fSetFilters );
|
|
|
|
TpSetDefaultMediaDetectionComplete( pLine, pRequest );
|
|
}
|
|
|
|
break;
|
|
|
|
case BN_SetFiltersForMakeCall:
|
|
{
|
|
//
|
|
// This is a make call request so schedule the real work item and complete it
|
|
//
|
|
CALL* pCall = (CALL*) Args[1];
|
|
PNDIS_TAPI_MAKE_CALL pRequest = (PNDIS_TAPI_MAKE_CALL) Args[2];
|
|
WORKITEM* pWorkItem = (WORKITEM*) Args[3];
|
|
|
|
PrReEnumerateBindings();
|
|
|
|
ChangePacketFiltersForAdapters( fSetFilters );
|
|
|
|
TpMakeCallComplete( pCall, pRequest );
|
|
|
|
ScheduleWorkItem( pWorkItem );
|
|
}
|
|
|
|
break;
|
|
|
|
case BN_ResetFiltersForCloseLine:
|
|
{
|
|
//
|
|
// This is a close line request so dereference it
|
|
//
|
|
LINE* pLine = (LINE*) Args[1];
|
|
|
|
ChangePacketFiltersForAdapters( fSetFilters );
|
|
|
|
DereferenceLine( pLine );
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
{
|
|
//
|
|
// Unknown request
|
|
//
|
|
ASSERT( FALSE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case BWT_workPrSend:
|
|
//
|
|
// Scheduled from PrBroadcast() to send PADI packets
|
|
//
|
|
{
|
|
NDIS_STATUS status;
|
|
|
|
status = PrSend( ( BINDING*) Args[0], (PPPOE_PACKET*) Args[1] );
|
|
|
|
TRACE( TL_N, TM_Pr, ("ExecBindingWorkItem: BWT_workSend=$%x",status) );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BWT_workPrReceiveComplete:
|
|
|
|
//
|
|
// Scheduled from PrReceivePacket() if receive loop on the specific binding is not running
|
|
//
|
|
{
|
|
BINDING* pBinding = ( ( BINDING*) Args[0] );
|
|
|
|
PrReceiveComplete( pBinding );
|
|
|
|
DereferenceBinding( pBinding );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
TRACE( TL_V, TM_Pr, ("-ExecBindingWorkItem") );
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
PrReceive(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID LookaheadBuffer,
|
|
IN UINT LookaheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called by NDIS to indicate the receipt of a new packet.
|
|
|
|
We check if packet is a PPPoE frame, and if it is not, we just return.
|
|
|
|
However if it is then we determine if we have received the whole packet or
|
|
not. If we have received the whole packet, we call PrTransferDataComplete()
|
|
manually, otherwise we initiate the data transfer and return. When transfer
|
|
is completed PrDataTransferComplete() will be called by NDIS.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
Specifies the handle to a protocol-allocated context area in which the
|
|
protocol driver maintains per-binding runtime state. The driver supplied this
|
|
handle when it called NdisOpenAdapter.
|
|
|
|
MacReceiveContext:
|
|
Specifies a context handle that the underlying NIC driver associates with the
|
|
packet received from the network. This handle is opaque to the protocol,
|
|
reserved for use by the underlying driver that made the indication, and a
|
|
required parameter to NdisTransferData.
|
|
|
|
HeaderBuffer:
|
|
Points to the base virtual address of a range containing the buffered packet
|
|
header. The address is valid only within the current call to ProtocolReceive.
|
|
|
|
HeaderBufferSize:
|
|
Specifies the number of bytes in the packet header.
|
|
|
|
LookAheadBuffer:
|
|
Points to the base virtual address of a range that contains
|
|
LookaheadBufferSize bytes of buffered network packet data. This address is
|
|
valid only within the current call to ProtocolReceive.
|
|
|
|
LookaheadBufferSize:
|
|
Specifies the number of bytes of network packet data in the lookahead buffer.
|
|
The indicating driver ensures this number is at least as large as the size it
|
|
returned for the protocol's preceding call to NdisRequest with
|
|
OID_GEN_CURRENT_LOOKAHEAD or the size of the packet, whichever is less.
|
|
|
|
If PacketSize is less than or equal to the given LookaheadBufferSize, the
|
|
kahead buffer contains the entire packet. If the underlying driver made
|
|
the indication with NdisMIndicateReceivePacket, the lookahead buffer always
|
|
contains a full network packet.
|
|
|
|
PacketSize:
|
|
Specifies the size, in bytes, of the network packet data. The length of the
|
|
packet does not include the length of the header.
|
|
ProtocolReceive determines whether the protocol must call NdisTransferData by
|
|
comparing this parameter to the given LookaheadBufferSize.
|
|
|
|
Return Values:
|
|
|
|
NDIS_STATUS_NOT_ACCEPTED:
|
|
The protocol has no use for the indicated packet, that is, it has no current
|
|
clients interested in the indicated network data.
|
|
Returning this status quickly for rejected packets yields higher performance
|
|
for the protocol and the highest possible network I/O throughput for the
|
|
system as a whole.
|
|
|
|
NDIS_STATUS_SUCCESS:
|
|
ProtocolReceive has processed the header information and accepted the packet,
|
|
that is, it has copied the indicated network data from the header and
|
|
lookahead buffers and, possibly, called NdisTransferData to retrieve the
|
|
remaining data if less than a full network packet was indicated.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_NOT_ACCEPTED;
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
PPPOE_PACKET *pPacket = NULL;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrReceive") );
|
|
|
|
//
|
|
// Check if the packet is a PPPoE frame or not
|
|
//
|
|
if ( !PacketFastIsPPPoE( (CHAR*) HeaderBuffer, HeaderBufferSize ) )
|
|
{
|
|
TRACE( TL_V, TM_Pr, ("-PrReceive=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Make sure packet is not too large
|
|
//
|
|
if ( HeaderBufferSize + PacketSize > PPPOE_PACKET_BUFFER_SIZE )
|
|
{
|
|
TRACE( TL_A, TM_Pr, ("PrReceive: Packet too large" ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrReceive=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Let's create our PPPoE packet to keep the copy of the received packet
|
|
//
|
|
pPacket = PacketCreateSimple();
|
|
|
|
if ( pPacket == NULL )
|
|
{
|
|
TRACE( TL_A, TM_Pr, ("PrReceive: Could not allocate context to copy the packet") );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrReceive=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// See if the packet indicated is complete, or not.
|
|
// If it is not the complete packet then we should call NdisTransferData(),
|
|
// otherwise we can do the copy here
|
|
//
|
|
if ( LookaheadBufferSize >= PacketSize )
|
|
{
|
|
TRACE( TL_V, TM_Pr, ("PrReceive: Complete packet indicated, transferring data") );
|
|
|
|
//
|
|
// First copy the header portion
|
|
//
|
|
NdisMoveMemory( pPacket->pHeader,
|
|
HeaderBuffer,
|
|
HeaderBufferSize );
|
|
|
|
//
|
|
// Packet is complete, so let's copy whole data to our own copy
|
|
//
|
|
TdiCopyLookaheadData( pPacket->pHeader + HeaderBufferSize,
|
|
(CHAR*) LookaheadBuffer,
|
|
(ULONG) PacketSize,
|
|
(ULONG) 0 );
|
|
|
|
//
|
|
// Let's call PrTransferDataComplete() manually now.
|
|
//
|
|
PrTransferDataComplete( pBinding,
|
|
pPacket->pNdisPacket,
|
|
NDIS_STATUS_SUCCESS,
|
|
PacketSize );
|
|
|
|
}
|
|
else
|
|
{
|
|
UINT nBytesTransferred = 0;
|
|
|
|
TRACE( TL_V, TM_Pr, ("PrReceive: Partial packet indicated, transferring data") );
|
|
|
|
//
|
|
// Mark the packet for incomplete indication
|
|
//
|
|
pPacket->ulFlags |= PCBF_PacketIndicatedIncomplete;
|
|
|
|
//
|
|
// First copy the header to the end of the packet
|
|
//
|
|
// Note that HeaderBufferSize MUST be equal to ETHERNET_HEADER_LENGTH and
|
|
// this is ensured in PacketIsFastPPPoE().
|
|
//
|
|
NdisMoveMemory( pPacket->pHeader + (PPPOE_PACKET_BUFFER_SIZE - ETHERNET_HEADER_LENGTH),
|
|
HeaderBuffer,
|
|
HeaderBufferSize );
|
|
|
|
//
|
|
// Lookahead buffer does not contain all the packet, we should call NdisTransferData()
|
|
// to receive the full packet
|
|
//
|
|
NdisTransferData( &status,
|
|
pBinding->NdisBindingHandle,
|
|
MacReceiveContext,
|
|
0,
|
|
PacketSize,
|
|
pPacket->pNdisPacket,
|
|
&nBytesTransferred );
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// Call PrTransferDataComplete() manually if transfer data completed
|
|
// synchronously
|
|
//
|
|
PrTransferDataComplete( pBinding,
|
|
pPacket->pNdisPacket,
|
|
status,
|
|
nBytesTransferred );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrReceive=$%x",status) );
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
PrTransferDataComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function is called to post process a received packet when whole data
|
|
is copied into the packet context.
|
|
|
|
It can be called by NDIS, or it can be called manually from inside PrReceive()
|
|
if the indicated packet is a whole packet.
|
|
|
|
If the status is succesfull, it will insert the packet to the end of the
|
|
bindings received packets queue, otherwise it will clean up our copy of
|
|
NDIS packet and return.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext
|
|
Specifies the handle to a protocol-allocated context area in which the
|
|
protocol driver maintains per-binding runtime state. The driver supplied this
|
|
handle when it called NdisOpenAdapter.
|
|
|
|
Packet
|
|
Points to the protocol-allocated packet descriptor the driver originally
|
|
passed to NdisTransferData.
|
|
|
|
Status
|
|
Specifies the final status of the transfer-data operation.
|
|
|
|
BytesTransferred
|
|
Specifies the number of bytes of data that the NIC driver transferred into
|
|
the buffers mapped by buffer descriptors chained to the packet descriptor at
|
|
Packet. The protocol uses this value to determine whether the miniport
|
|
supplied all the requested data for the originally indicated network packet.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
PPPOE_PACKET* pPacket = NULL;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrTransferDataComplete") );
|
|
|
|
do
|
|
{
|
|
//
|
|
// Retrieve the related PPPoE packet first
|
|
//
|
|
pPacket = PacketGetRelatedPppoePacket( Packet );
|
|
|
|
//
|
|
// Make sure the data transfer suceeded
|
|
//
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// Transfer of data to our copy of packet failed, so clean up our packet
|
|
//
|
|
PacketFree( pPacket );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Rearrange the data in the packet if the packet was indicated incomplete
|
|
//
|
|
if ( pPacket->ulFlags & PCBF_PacketIndicatedIncomplete )
|
|
{
|
|
CHAR tempHeader[ ETHERNET_HEADER_LENGTH ];
|
|
|
|
CHAR* srcPos = pPacket->pHeader + BytesTransferred;
|
|
|
|
//
|
|
// Make a copy of the header stored at the end of the packet
|
|
//
|
|
NdisMoveMemory( tempHeader,
|
|
pPacket->pHeader + (PPPOE_PACKET_BUFFER_SIZE - ETHERNET_HEADER_LENGTH),
|
|
ETHERNET_HEADER_LENGTH );
|
|
|
|
//
|
|
// Move the contents of the packet appropriately to make room
|
|
// for the header (slip contents by ETHERNET_HEADER_LENGTH)
|
|
//
|
|
while ( BytesTransferred > 0 )
|
|
{
|
|
#define TEMP_BUFFER_SIZE 100
|
|
CHAR tempBuffer[ TEMP_BUFFER_SIZE ];
|
|
|
|
UINT size = (BytesTransferred < TEMP_BUFFER_SIZE) ?
|
|
BytesTransferred :
|
|
TEMP_BUFFER_SIZE;
|
|
|
|
srcPos -= size;
|
|
|
|
NdisMoveMemory( tempBuffer,
|
|
srcPos,
|
|
size );
|
|
|
|
NdisMoveMemory( srcPos + ETHERNET_HEADER_LENGTH,
|
|
tempBuffer,
|
|
size );
|
|
|
|
BytesTransferred -= size;
|
|
}
|
|
|
|
//
|
|
// Copy the header to the correct position in the packet
|
|
//
|
|
NdisMoveMemory( pPacket->pHeader,
|
|
tempHeader,
|
|
ETHERNET_HEADER_LENGTH );
|
|
|
|
//
|
|
// Clear the incomplete indication flag
|
|
//
|
|
pPacket->ulFlags &= ~PCBF_PacketIndicatedIncomplete;
|
|
}
|
|
|
|
//
|
|
// Data transfer succeeded, insert into our queue of received packets, so that it will
|
|
// be consumed by a call to our PrReceiveComplete() function
|
|
//
|
|
NdisInterlockedInsertTailList( &pBinding->linkPackets,
|
|
&pPacket->linkPackets,
|
|
&pBinding->lockBinding );
|
|
|
|
} while ( FALSE );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrTransferDataComplete=$%x",Status) );
|
|
}
|
|
|
|
VOID
|
|
PrReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called to perform post processing of received packets
|
|
indicated previously. Underlying NIC will call it when it is not busy.
|
|
|
|
We need to serialize the indication of packets to the miniport, since this
|
|
is of vital importance for PPP frames. To achieve this, we use the lock
|
|
protected flag of binding (fRecvLoopRunning).
|
|
|
|
When this function is called, it will return immediately if this flag is
|
|
already set.
|
|
|
|
If flag is not set, then it will set this flag and start processing packets
|
|
from the received queue, and indicate all packets to miniport one by one
|
|
untill all the queue is drained. Then it will reset the flag and return.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext
|
|
Specifies the handle to a protocol-allocated context area in which the
|
|
protocol driver maintains per-binding runtime state. The driver supplied this
|
|
handle when it called NdisOpenAdapter.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
LIST_ENTRY* pLink = NULL;
|
|
PPPOE_PACKET* pPacket = NULL;
|
|
BOOLEAN fStartRecvLoop = FALSE;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrReceiveComplete") );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
//
|
|
// See if recv loop is already running
|
|
//
|
|
if ( !pBinding->fRecvLoopRunning )
|
|
{
|
|
//
|
|
// Indicate the recv loop has started to run
|
|
//
|
|
pBinding->fRecvLoopRunning = TRUE;
|
|
|
|
//
|
|
// Now consume these packet's
|
|
//
|
|
while ( !IsListEmpty( &pBinding->linkPackets ) )
|
|
{
|
|
pLink = RemoveHeadList( &pBinding->linkPackets );
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
pPacket = (PPPOE_PACKET*) CONTAINING_RECORD( pLink, PPPOE_PACKET, linkPackets );
|
|
|
|
InitializeListHead( &pPacket->linkPackets );
|
|
|
|
if ( PacketInitializeFromReceived( pPacket ) == NDIS_STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// Indicate the packet to miniport
|
|
//
|
|
MpRecvPacket( pBinding, pPacket );
|
|
}
|
|
|
|
//
|
|
// Free the packet since we are done with it
|
|
//
|
|
PacketFree( pPacket );
|
|
|
|
//
|
|
// Acquire the lock again
|
|
//
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
}
|
|
|
|
//
|
|
// The queue is drained, so stop the recv loop
|
|
//
|
|
pBinding->fRecvLoopRunning = FALSE;
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrReceiveComplete") );
|
|
}
|
|
|
|
|
|
ULONG
|
|
PrQueryMaxFrameSize()
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called by the miniport to retrieve the current minimum
|
|
of max frame sizes of the bindings, since this is the value passed to
|
|
NDISWAN in an OID_WAN_GET_INFO query as the MaxFrameSize.
|
|
|
|
We adjust the max frame size considering the PPPoE and Ethernet headers.
|
|
|
|
Parameters:
|
|
|
|
None
|
|
|
|
Return Values:
|
|
|
|
Minimum of max frame sizes
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
ULONG ulMaxFrameSize = gl_ulMaxFrameSize;
|
|
|
|
if ( ulMaxFrameSize == 0 )
|
|
{
|
|
ulMaxFrameSize = PACKET_PPP_PAYLOAD_MAX_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
ulMaxFrameSize = ulMaxFrameSize - PPPOE_PACKET_HEADER_LENGTH;
|
|
}
|
|
|
|
return ulMaxFrameSize;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
PrSend(
|
|
IN BINDING* pBinding,
|
|
IN PPPOE_PACKET* pPacket
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
This function will be called to transmit a PPPoE packet.
|
|
|
|
The caller must have referenced the packet and binding before calling this
|
|
function. Then the caller can forget about the references, everything will
|
|
be handled by the protocol. If send operation complets synchrnously then
|
|
the references are removed in the function, otherwise PrSendComplete()
|
|
will be called and references will be removed then.
|
|
|
|
Parameters:
|
|
|
|
pBinding _ Binding to send the packet over.
|
|
|
|
pPacket _ PPPoE packet to be transmitted.
|
|
|
|
Return Values:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_FAILURE
|
|
NDIS_STATUS_XXXXXXX
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_FAILURE;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_V, TM_Pr, ("+PrSend") );
|
|
|
|
//
|
|
// Make sure we are bound before sending the packet.
|
|
//
|
|
// Note: We do not need to acquire the lock here since NDIS should prevent
|
|
// a crash even if we are unbound, and we already have a reference
|
|
// on the binding, so this is not a really strict check..
|
|
//
|
|
if ( pBinding->stateBinding == BN_stateBound )
|
|
{
|
|
//
|
|
// Make sure we are sending a packet not exceeding the max frame size
|
|
// of the underlying NIC
|
|
//
|
|
if ( pBinding->ulMaxFrameSize + ETHERNET_HEADER_LENGTH >=
|
|
(ULONG) ( PacketGetLength( pPacket ) + PPPOE_PACKET_HEADER_LENGTH ) )
|
|
{
|
|
NdisSend( &status,
|
|
pBinding->NdisBindingHandle,
|
|
PacketGetNdisPacket( pPacket ) );
|
|
}
|
|
}
|
|
|
|
if ( status != NDIS_STATUS_PENDING )
|
|
{
|
|
//
|
|
// NdisSend() completed synchronously so call PrSendComplete()
|
|
// manually here.
|
|
//
|
|
PrSendComplete( pBinding, PacketGetNdisPacket( pPacket ), status );
|
|
|
|
}
|
|
|
|
TRACE( TL_V, TM_Pr, ("-PrSend=$%x",status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
PrStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
ProtocolStatus is a required driver function that handles status-change
|
|
notifications raised by an underlying connectionless NIC driver or by NDIS.
|
|
|
|
In this driver, we only use this function to receive Media disconnect
|
|
notifications to disconnect the active calls on that NIC.
|
|
|
|
Parameters:
|
|
|
|
ProtocolBindingContext:
|
|
Specifies the handle to a protocol-allocated context area in which the
|
|
protocol driver maintains per-binding runtime state. The driver supplied this
|
|
handle when it called NdisOpenAdapter.
|
|
|
|
GeneralStatus:
|
|
Indicates the general status code, either raised by NDIS or propagated from
|
|
the underlying driver's call to NdisMIndicateStatus.
|
|
|
|
StatusBuffer:
|
|
Points to a buffer containing medium-specific data that depends on the value
|
|
of GeneralStatus.
|
|
|
|
For example, if the GeneralStatus argument is NDIS_STATUS_RING_STATUS, this
|
|
parameter points to a ULONG-sized bitmask and StatusBufferSize is four. As
|
|
another example, if GeneralStatus is NDIS_STATUS_WAN_LINE_UP, this parameter
|
|
points to an NDIS_WAN_LINE_UP structure and StatusBufferSize is sizeof(
|
|
NDIS_STATUS_WAN_LINE_UP).
|
|
|
|
For some NDIS_STATUS_XXX values, this pointer is NULL and StatusBufferSize is
|
|
set to zero.
|
|
|
|
StatusBufferSize:
|
|
Specifies the number of bytes at StatusBuffer.
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
BINDING* pBinding = (BINDING*) ProtocolBindingContext;
|
|
|
|
ASSERT( VALIDATE_BINDING( pBinding ) );
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrStatus") );
|
|
|
|
switch ( GeneralStatus )
|
|
{
|
|
case NDIS_STATUS_MEDIA_DISCONNECT:
|
|
|
|
//
|
|
// If the underlying media is disconnected, notify miniport of this event.
|
|
// It will appear to the miniport as if the NIC is removed, so it will drop all the
|
|
// active calls
|
|
//
|
|
TRACE( TL_N, TM_Pr, ("PrStatus: Notifying miniport of media disconnect event") );
|
|
|
|
MpNotifyBindingRemoval( pBinding );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrStatus") );
|
|
}
|
|
|
|
NDIS_STATUS
|
|
PrPnPEvent(
|
|
IN NDIS_HANDLE hProtocolBindingContext,
|
|
IN PNET_PNP_EVENT pNetPnPEvent
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
ProtocolPnPEvent is a required function in any protocol driver to support
|
|
Plug and Play and/or Power Management. NDIS calls ProtocolPnPEvent to
|
|
indicate a Plug and Play event or a Power Management event to a protocol
|
|
bound to a NIC.
|
|
|
|
NDIS calls ProtocolPnPEvent to notify a protocol bound to a network NIC that
|
|
the operating system has issued a Plug and Play or Power Management event to
|
|
the device object representing the NIC. NDIS calls the ProtocolPnPEvent
|
|
function of each protocol bound to the NIC.
|
|
|
|
The NET_PNP_EVENT structure passed to ProtocolPnPEvent describes the Plug and
|
|
Play or Power Management event. ProtocolPnPEvent interprets two basic pieces
|
|
of information in the NET_PNP_EVENT structure:
|
|
|
|
A NetEvent code that describes the Plug and Play or Power Management event.
|
|
Event-specific information (for example, for a NetEventSetPower, the device
|
|
power state to which the device is transitioning).
|
|
The protocol should save the NetPnPEvent pointer. This pointer is a required
|
|
input parameter to NdisCompletePnPEvent, which the protocol must subsequently
|
|
call if ProtocolPnPEvent returns NDIS_STATUS_PENDING.
|
|
|
|
Parameters
|
|
|
|
hProtocolBindingContext:
|
|
Specifies the handle to a protocol-allocated context area in which this
|
|
driver maintains per-binding runtime state. The protocol supplied this handle
|
|
when it called NdisOpenAdapter. A NetEventXxx indicated on a NULL
|
|
ProtocolBindingContext pertains to all network bindings. NetEventBindList and
|
|
NetEventBindsComplete are always indicated on a NULL ProtocolBindingContext.
|
|
NetEventReconfigure can be indicated on a particular ProtocolBindingContext
|
|
or a NULL ProtocolBindingContext.
|
|
|
|
pNetPnPEvent:
|
|
Points to a NET_PNP_EVENT structure, which describes the Plug and Play event
|
|
or Power Management event being indicated to the protocol driver.
|
|
|
|
Return Value
|
|
|
|
NDIS_STATUS_SUCCESS:
|
|
The protocol successfully handled the indicated Plug and Play or Power
|
|
Management event. The meaning of this status code depends on the NetEvent
|
|
code in the buffered NET_PNP_EVENT structure at NetPnPEvent.
|
|
|
|
NDIS_STATUS_PENDING
|
|
The protocol will return its response to the indicated event asynchronously
|
|
with a call to NdisCompletePnPEvent.
|
|
|
|
NDIS_STATUS_RESOURCES
|
|
The protocol could not obtain the necessary system resources to satisfy the
|
|
indicated Plug and Play or Power Management event.
|
|
|
|
NDIS_STATUS_NOT_SUPPORTED
|
|
A legacy (non-PnP-aware) protocol can return this status in response to a
|
|
NetEventSetPower to indicate that NDIS should unbind the it from the NIC.
|
|
|
|
NDIS_STATUS_FAILURE
|
|
The protocol failed the indicated Plug and Play or Power Management event.
|
|
The meaning of this status code depends on the NetEvent code in the buffered
|
|
NET_PNP_EVENT structure at NetPnPEvent.
|
|
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
|
|
BINDING *pBinding = (BINDING*) hProtocolBindingContext;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+PrPnpEvent") );
|
|
|
|
switch ( pNetPnPEvent->NetEvent )
|
|
{
|
|
|
|
case NetEventQueryPower:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventQueryPower") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventQueryRemoveDevice:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventQueryRemoveDevice") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventCancelRemoveDevice:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventCancelRemoveDevice") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventReconfigure:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventReconfigure") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventBindsComplete:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventBindsComplete") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventPnPCapabilities:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventPnPCapabilities") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventBindList:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventBindList") );
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case NetEventSetPower:
|
|
{
|
|
BOOLEAN fWakeUp = FALSE;
|
|
BOOLEAN fSleep = FALSE;
|
|
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventSetPower") );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
if ( *( (NDIS_DEVICE_POWER_STATE*) pNetPnPEvent->Buffer ) == NdisDeviceStateD0 )
|
|
{
|
|
if ( pBinding->stateBinding == BN_stateSleeping )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventSetPower - Wake up request") );
|
|
|
|
fWakeUp = TRUE;
|
|
|
|
pBinding->stateBinding = BN_stateBound;
|
|
|
|
}
|
|
|
|
}
|
|
else if ( *( (NDIS_DEVICE_POWER_STATE*) pNetPnPEvent->Buffer ) > NdisDeviceStateD0 )
|
|
{
|
|
if ( pBinding->stateBinding == BN_stateBound )
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventSetPower - Sleep request") );
|
|
|
|
fSleep = TRUE;
|
|
|
|
pBinding->stateBinding = BN_stateSleepPending;
|
|
}
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
if ( fSleep )
|
|
{
|
|
//
|
|
// Since this NIC is going to sleep, drop all the calls on it
|
|
//
|
|
MpNotifyBindingRemoval( pBinding );
|
|
|
|
//
|
|
// Wait for pending operations to be completed
|
|
//
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: NetEventSetPower - Waiting for pending operations to be completed") );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
while ( pBinding->lRef > 1 )
|
|
{
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
NdisMSleep( 10000 );
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
}
|
|
|
|
pBinding->stateBinding = BN_stateSleeping;
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
}
|
|
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("PrPnpEvent: Unknown Event - %x", pNetPnPEvent->NetEvent) );
|
|
|
|
status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrPnpEvent=$%x", status) );
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
PrReEnumerateBindings(
|
|
VOID
|
|
)
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Functional Description:
|
|
|
|
PrReEnumerateBindings causes NDIS to send bind notifications to the pppoe
|
|
protocol section for each miniport that it needs to bind to. It is called
|
|
when a tapi client is interested in either making an outgoing call or
|
|
listening for an incoming call. It is expected that when this function
|
|
returns all of the bindings between the protocol and underlying miniports
|
|
will be finished!
|
|
|
|
|
|
Parameters
|
|
|
|
None
|
|
|
|
Return Value
|
|
|
|
None
|
|
---------------------------------------------------------------------------*/
|
|
{
|
|
TRACE( TL_N, TM_Pr, ("+PrReEnumerateBindings") );
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
gl_fBindProtocol = TRUE;
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
NdisReEnumerateProtocolBindings(gl_hNdisProtocolHandle);
|
|
|
|
TRACE( TL_N, TM_Pr, ("-PrReEnumerateBindings") );
|
|
}
|
|
|
|
VOID
|
|
ChangePacketFiltersForAdapters(
|
|
BOOLEAN fSet
|
|
)
|
|
{
|
|
LIST_ENTRY* pLink = NULL;
|
|
|
|
TRACE( TL_N, TM_Pr, ("+ChangePacketFiltersForAdapters") );
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
gl_fSetPacketFiltersAtBind = fSet;
|
|
|
|
pLink = gl_linkBindings.Flink;
|
|
|
|
//
|
|
// See if we have any bindings
|
|
//
|
|
if ( pLink != &gl_linkBindings )
|
|
{
|
|
|
|
BINDING* pBinding = NULL;
|
|
|
|
TRACE( TL_N, TM_Pr, ("ChangePacketFiltersForAdapters: %s packet filters", ( fSet ) ? "Setting" : "Resetting") );
|
|
|
|
//
|
|
// First reference the bindings in the list and mark their
|
|
// BNBF_ChangePacketFilterInProgress bit
|
|
//
|
|
while ( pLink != &gl_linkBindings )
|
|
{
|
|
//
|
|
// We have at least one binding, so walk thru the list
|
|
// and reference them
|
|
//
|
|
pBinding = ((BINDING*) CONTAINING_RECORD( pLink, BINDING, linkBindings ));
|
|
|
|
NdisAcquireSpinLock( &pBinding->lockBinding );
|
|
|
|
if ( pBinding->stateBinding == BN_stateBound )
|
|
{
|
|
//
|
|
// If the state of the binding is BN_stateBound then
|
|
// set the BNBF_PacketFilterChangeInProgress bit,
|
|
// reference
|
|
// the binding.
|
|
//
|
|
pBinding->ulBindingFlags |= BNBF_PacketFilterChangeInProgress;
|
|
|
|
ReferenceBinding( pBinding, FALSE );
|
|
}
|
|
|
|
NdisReleaseSpinLock( &pBinding->lockBinding );
|
|
|
|
//
|
|
// Iterate to the next binding
|
|
//
|
|
pLink = pLink->Flink;
|
|
}
|
|
|
|
//
|
|
// Now make a second pass and shoot the SetPacket filter request for
|
|
// all the marked items
|
|
//
|
|
pLink = gl_linkBindings.Flink;
|
|
|
|
while ( pLink != &gl_linkBindings )
|
|
{
|
|
//
|
|
// We have at least one binding, so walk thru the list
|
|
// and reference them
|
|
//
|
|
pBinding = ((BINDING*) CONTAINING_RECORD( pLink, BINDING, linkBindings ));
|
|
|
|
//
|
|
// Advance to the next item
|
|
//
|
|
pLink = pLink->Flink;
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
//
|
|
// If we are just marking, check the state of the binding and mark it
|
|
// by setting the BNBF_SetPacketFilterInProgress bit
|
|
//
|
|
if ( pBinding->ulBindingFlags & BNBF_PacketFilterChangeInProgress )
|
|
{
|
|
//
|
|
// This binding is marked by the previous loop so change the filter
|
|
// for this binding
|
|
//
|
|
PrSetPacketFilterForAdapter( pBinding, fSet );
|
|
|
|
//
|
|
// Reset what was done in the first pass
|
|
//
|
|
pBinding->ulBindingFlags &= ~BNBF_PacketFilterChangeInProgress;
|
|
|
|
DereferenceBinding( pBinding );
|
|
|
|
}
|
|
|
|
NdisAcquireSpinLock( &gl_lockProtocol );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NdisReleaseSpinLock( &gl_lockProtocol );
|
|
|
|
TRACE( TL_N, TM_Pr, ("-ChangePacketFiltersForAdapters") );
|
|
|
|
}
|