2315 lines
61 KiB
C
2315 lines
61 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1991 Nokia Data Systems Ab
|
||
|
||
Module Name:
|
||
|
||
llcndis.c
|
||
|
||
Abstract:
|
||
|
||
The module binds and unbinds a protocol level module to DLC and binds the
|
||
data link driver to an NDIS driver if it is necessary.
|
||
|
||
All NDIS specific code is also gathered into this module such as the network
|
||
status indications.
|
||
|
||
Note: The DLC driver assumes that all DLC level code assumes a Token Ring
|
||
adapter. If we bind to an ethernet adapter, or the required NDIS medium
|
||
type is Ethernet, then we set up DLC to transform Token Ring addresses and
|
||
packet formats to Ethernet (including DIX ethernet format). However, we can
|
||
build a version of DLC/LLC which understands Ethernet format at the API
|
||
level. Define SUPPORT_ETHERNET_CLIENT in order to build such a DLC
|
||
|
||
NB: As of 07/13/92, SUPPORT_ETHERNET_CLIENT code has not been tested!
|
||
|
||
Contents:
|
||
LlcOpenAdapter
|
||
LlcNdisOpenAdapterComplete
|
||
LlcDisableAdapter
|
||
LlcCloseAdapter
|
||
LlcResetBroadcastAddresses
|
||
InitNdisPackets
|
||
LlcNdisCloseComplete
|
||
NdisStatusHandler
|
||
GetNdisParameter
|
||
SetNdisParameter
|
||
SyncNdisRequest
|
||
WaitAsyncOperation
|
||
LlcNdisRequest
|
||
LlcNdisRequestComplete
|
||
LlcNdisReset
|
||
LlcNdisResetComplete
|
||
UnicodeStringCompare
|
||
PurgeLlcEventQueue
|
||
|
||
Author:
|
||
|
||
Antti Saarenheimo (o-anttis) 30-MAY-1991
|
||
|
||
Revision History:
|
||
|
||
04-AUG-1991, o-anttis
|
||
Rewritten for NDIS 3.0 (and for real use).
|
||
|
||
28-Apr-1994 rfirth
|
||
|
||
* Modified to use single driver-level spinlock
|
||
|
||
* Cleaned-up open/close - found a few bugs when stressing adapter
|
||
open & close
|
||
|
||
04-May-1994 rfirth
|
||
|
||
* Added MAC address caching for TEST/XID/SABME frames when adapter
|
||
opened in LLC_ETHERNET_TYPE_AUTO mode
|
||
|
||
--*/
|
||
|
||
#ifndef i386
|
||
#define LLC_PRIVATE_PROTOTYPES
|
||
#endif
|
||
#include <dlc.h> // need DLC_FILE_CONTEXT for memory allocation charged to handle
|
||
#include <llc.h>
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
BOOLEAN
|
||
UnicodeStringCompare(
|
||
IN PUNICODE_STRING String1,
|
||
IN PUNICODE_STRING String2
|
||
);
|
||
|
||
VOID
|
||
PurgeLlcEventQueue(
|
||
IN PBINDING_CONTEXT pBindingContext
|
||
);
|
||
|
||
//
|
||
// Internal statics used in NDIS 3.1 initialization in NT OS/2
|
||
//
|
||
|
||
KSPIN_LOCK LlcSpinLock;
|
||
PVOID LlcProtocolHandle;
|
||
PADAPTER_CONTEXT pAdapters = NULL;
|
||
|
||
//
|
||
// We do not support FDDI because it is the same as token-ring
|
||
//
|
||
|
||
UINT LlcMediumArray[3] = {
|
||
NdisMedium802_5,
|
||
NdisMedium802_3,
|
||
NdisMediumFddi
|
||
};
|
||
|
||
|
||
DLC_STATUS
|
||
LlcOpenAdapter(
|
||
IN PWSTR pAdapterName,
|
||
IN PVOID hClientContext,
|
||
IN PFLLC_COMMAND_COMPLETE pfCommandComplete,
|
||
IN PFLLC_RECEIVE_INDICATION pfReceiveIndication,
|
||
IN PFLLC_EVENT_INDICATION pfEventIndication,
|
||
IN NDIS_MEDIUM NdisMedium,
|
||
IN LLC_ETHERNET_TYPE EthernetType,
|
||
IN UCHAR AdapterNumber,
|
||
OUT PVOID *phBindingContext,
|
||
OUT PUINT puiOpenStatus,
|
||
OUT PUSHORT pusMaxFrameLength,
|
||
OUT PNDIS_MEDIUM pActualNdisMedium
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The first call to a new adapter initializes the NDIS interface
|
||
and allocates internal data structures for the new adapter.
|
||
|
||
Subsequent opens for the same adapter only increment the reference count
|
||
of that adapter context.
|
||
|
||
The execution is synchronous! The procedure waits (sleeps) until
|
||
the adapter has been opened by the MAC.
|
||
|
||
Special:
|
||
|
||
Must be called IRQL < DPC
|
||
|
||
Arguments:
|
||
|
||
pAdapterName......... MAC adapter name. Zero-terminated, wide-character string
|
||
|
||
hClientContext....... client context for this adapter
|
||
|
||
pfCommandComplete.... send/receive/request command completion handler of the
|
||
client
|
||
|
||
pfReceiveIndication.. receive data indication handler of the client
|
||
|
||
pfEventIndication.... event indication handler of the client
|
||
|
||
NdisMedium........... the NdisMedium used by the protocol driver (ie DLC).
|
||
Only NdisMedium802_5 is supported
|
||
|
||
EthernetType......... type of Ethernet connection - 802.3 or DIX
|
||
|
||
AdapterNumber........ adapter mapping from CCB
|
||
|
||
phBindingContext..... the returned binding context handle used with the file
|
||
context (by DirOpenAdapter)
|
||
|
||
puiOpenStatus........ status of NdisOpenAadapter
|
||
|
||
pusMaxFrameLength.... returned maximum I-frame length
|
||
|
||
pActualNdisMedium.... returned actual NDIS medium; may be different from
|
||
that requested (NdisMedium)
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
Success - STATUS_SUCCESS
|
||
Failure - all NDIS error status from NdisOpenAdapter
|
||
DLC_STATUS_TIMEOUT
|
||
asynchronous NdisOpenAdapter failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
NDIS_STATUS NdisStatus;
|
||
PADAPTER_CONTEXT pAdapterContext;
|
||
UINT OpenStatus = STATUS_SUCCESS;
|
||
PBINDING_CONTEXT pBindingContext;
|
||
UINT MediumIndex;
|
||
KIRQL irql;
|
||
BOOLEAN DoNdisClose = FALSE;
|
||
UNICODE_STRING unicodeString;
|
||
BOOLEAN newAdapter;
|
||
ULONG cacheEntries;
|
||
|
||
|
||
#if DBG
|
||
|
||
PDLC_FILE_CONTEXT pFileContext = (PDLC_FILE_CONTEXT)hClientContext;
|
||
|
||
#endif
|
||
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
|
||
#ifdef SUPPORT_ETHERNET_CLIENT
|
||
|
||
if (NdisMedium != NdisMedium802_3 && NdisMedium != NdisMedium802_5) {
|
||
return DLC_STATUS_UNKNOWN_MEDIUM;
|
||
|
||
}
|
||
|
||
#else
|
||
|
||
if (NdisMedium != NdisMedium802_5) {
|
||
return DLC_STATUS_UNKNOWN_MEDIUM;
|
||
}
|
||
|
||
#endif
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
//
|
||
// RLF 04/19/93
|
||
//
|
||
// The adapter name passed to this routine is a zero-terminated wide
|
||
// character string mapped to system space. Create a UNICODE_STRING for
|
||
// the name and use standard Rtl function to compare with names of adapters
|
||
// already opened by DLC
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeString, pAdapterName);
|
||
|
||
//
|
||
// if the adapter is being opened in LLC_ETHERNET_TYPE_AUTO mode then we
|
||
// get the cache size from the registry
|
||
//
|
||
|
||
if (EthernetType == LLC_ETHERNET_TYPE_AUTO) {
|
||
|
||
static DLC_REGISTRY_PARAMETER framingCacheParameterTemplate = {
|
||
L"AutoFramingCacheSize",
|
||
(PVOID)DEFAULT_AUTO_FRAMING_CACHE_SIZE,
|
||
{
|
||
REG_DWORD,
|
||
PARAMETER_AS_SPECIFIED,
|
||
NULL,
|
||
sizeof(ULONG),
|
||
NULL,
|
||
MIN_AUTO_FRAMING_CACHE_SIZE,
|
||
MAX_AUTO_FRAMING_CACHE_SIZE
|
||
}
|
||
};
|
||
PDLC_REGISTRY_PARAMETER parameterTable;
|
||
|
||
//
|
||
// create a private copy of the parameter table descriptor
|
||
//
|
||
|
||
parameterTable = (PDLC_REGISTRY_PARAMETER)
|
||
ALLOCATE_ZEROMEMORY_DRIVER(sizeof(*parameterTable));
|
||
if (!parameterTable) {
|
||
return DLC_STATUS_NO_MEMORY;
|
||
}
|
||
RtlCopyMemory(parameterTable,
|
||
&framingCacheParameterTemplate,
|
||
sizeof(framingCacheParameterTemplate)
|
||
);
|
||
|
||
//
|
||
// point the Variable field at cacheEntries and set it to the default
|
||
// value then call GetRegistryParameters to retrieve the registry value.
|
||
// (and set it if not already in the registry). Ignore the return value
|
||
// - if GetAdapterParameters failed, cacheEntries will still contain the
|
||
// default value
|
||
//
|
||
|
||
cacheEntries = DEFAULT_AUTO_FRAMING_CACHE_SIZE;
|
||
parameterTable->Descriptor.Variable = (PVOID)&cacheEntries;
|
||
parameterTable->Descriptor.Value = (PVOID)¶meterTable->DefaultValue;
|
||
GetAdapterParameters(&unicodeString, parameterTable, 1, TRUE);
|
||
FREE_MEMORY_DRIVER(parameterTable);
|
||
} else {
|
||
cacheEntries = 0;
|
||
}
|
||
|
||
//
|
||
// allocate a BINDING_CONTEXT with enough additional space to store the
|
||
// required framing discovery cache
|
||
//
|
||
// DEBUG: BINDING_CONTEXT structures are charged to the FILE_CONTEXT
|
||
//
|
||
|
||
#if defined(DEBUG_DISCOVERY)
|
||
|
||
DbgPrint("cacheEntries=%d\n", cacheEntries);
|
||
|
||
#endif
|
||
|
||
pBindingContext = (PBINDING_CONTEXT)
|
||
ALLOCATE_ZEROMEMORY_FILE(sizeof(BINDING_CONTEXT)
|
||
+ cacheEntries
|
||
* sizeof(FRAMING_DISCOVERY_CACHE_ENTRY)
|
||
);
|
||
if (!pBindingContext) {
|
||
return DLC_STATUS_NO_MEMORY;
|
||
}
|
||
|
||
//
|
||
// set the maximum size of the framing discovery cache. Will be zero if the
|
||
// requested ethernet type is not LLC_ETHERNET_TYPE_AUTO
|
||
//
|
||
|
||
pBindingContext->FramingDiscoveryCacheEntries = cacheEntries;
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// we need the FILE_CONTEXT structure in the BINDING_CONTEXT in the event
|
||
// the open fails and we need to deallocate memory. Normally this field is
|
||
// not set til everything has successfully been completed
|
||
//
|
||
|
||
pBindingContext->hClientContext = hClientContext;
|
||
|
||
#endif
|
||
|
||
//
|
||
// RtlUpcaseUnicodeString is a paged routine - lower IRQL
|
||
//
|
||
|
||
//
|
||
// to avoid having to case-insensitive compare unicode strings every time,
|
||
// we do a one-shot convert to upper-cased unicode strings. This also helps
|
||
// out since we do our own unicode string comparison (case-sensitive)
|
||
//
|
||
// Note that this modifies the input parameter
|
||
//
|
||
|
||
RtlUpcaseUnicodeString(&unicodeString, &unicodeString, FALSE);
|
||
|
||
//
|
||
// before we re-acquire the driver spin-lock, we wait on the OpenAdapter
|
||
// semaphore. We serialize access to the following code because simultaneous
|
||
// opens (in different processes) and closes (different threads within
|
||
// same process) check to see if the adapter is on the pAdapters list.
|
||
// We don't want multiple processes creating the same adapter context
|
||
// simultaneously. Similarly, we must protect against the situation where
|
||
// one process is adding a binding and another could be closing what it
|
||
// thinks is the sole binding, thereby deleting the adapter context we
|
||
// are about to update
|
||
// Note that this is a non-optimal solution since it means an app opening
|
||
// or closing an ethernet adapter could get stuck behind another opening
|
||
// a token ring adapter (slow)
|
||
//
|
||
|
||
KeWaitForSingleObject((PVOID)&OpenAdapterSemaphore,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE, // not alertable
|
||
NULL // wait until object is signalled
|
||
);
|
||
|
||
//
|
||
// grab the global LLC spin lock whilst we are looking at/updating the list
|
||
// of adapters
|
||
//
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
//
|
||
// because we are doing the compare within spinlock, we use our own function
|
||
// which checks for an exact match (i.e. case-sensitive). This is ok since
|
||
// always upper-case the string before comparing it or storing it in an
|
||
// ADAPTER_CONTEXT
|
||
//
|
||
|
||
for (pAdapterContext = pAdapters; pAdapterContext; pAdapterContext = pAdapterContext->pNext) {
|
||
if (UnicodeStringCompare(&unicodeString, &pAdapterContext->Name)) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if we didn't locate an adapter context with our adapter name then we're
|
||
// creating a new binding: allocate a new adapter context structure
|
||
//
|
||
|
||
if (!pAdapterContext) {
|
||
|
||
//
|
||
// DEBUG: ADAPTER_CONTEXT structures are charged to the driver
|
||
//
|
||
|
||
pAdapterContext = (PADAPTER_CONTEXT)
|
||
ALLOCATE_ZEROMEMORY_DRIVER(sizeof(ADAPTER_CONTEXT));
|
||
if (!pAdapterContext) {
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
//
|
||
// DEBUG: refund memory charged for BINDING_CONTEXT to FILE_CONTEXT
|
||
//
|
||
|
||
FREE_MEMORY_FILE(pBindingContext);
|
||
|
||
KeReleaseSemaphore(&OpenAdapterSemaphore, 0, 1, FALSE);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
return DLC_STATUS_NO_MEMORY;
|
||
}
|
||
|
||
newAdapter = TRUE;
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// record who owns this memory usage structure and add it to the
|
||
// list of all memory usages created in the driver
|
||
//
|
||
|
||
pAdapterContext->MemoryUsage.Owner = (PVOID)pAdapterContext;
|
||
pAdapterContext->MemoryUsage.OwnerObjectId = AdapterContextObject;
|
||
pAdapterContext->StringUsage.Owner = (PVOID)pAdapterContext;
|
||
pAdapterContext->StringUsage.OwnerObjectId = AdapterContextObject;
|
||
LinkMemoryUsage(&pAdapterContext->MemoryUsage);
|
||
LinkMemoryUsage(&pAdapterContext->StringUsage);
|
||
|
||
#endif
|
||
|
||
//
|
||
// We must allocate all spinlocks immediately after the
|
||
// adapter context has been allocated, because
|
||
// they can also deallocated simultaneously.
|
||
//
|
||
|
||
ALLOCATE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
ALLOCATE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
||
|
||
//
|
||
// allocate space for the adapter name string from non-paged pool
|
||
// and initialize the name in the adapter context structure
|
||
//
|
||
|
||
NdisStatus = LlcInitUnicodeString(&pAdapterContext->Name,
|
||
&unicodeString
|
||
);
|
||
if (NdisStatus != STATUS_SUCCESS) {
|
||
goto CleanUp;
|
||
}
|
||
|
||
pAdapterContext->OpenCompleteStatus = NDIS_STATUS_PENDING;
|
||
|
||
//
|
||
// and release the global spin lock: we have finished updating the
|
||
// adapter list and initializing this adapter context. From now
|
||
// on we use spin locks specific to this adapter context
|
||
//
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
//
|
||
// We must initialize the list heads before we open the adapter!!!
|
||
//
|
||
|
||
InitializeListHead(&pAdapterContext->QueueEvents);
|
||
InitializeListHead(&pAdapterContext->QueueCommands);
|
||
InitializeListHead(&pAdapterContext->NextSendTask);
|
||
|
||
pAdapterContext->OpenErrorStatus = NDIS_STATUS_PENDING;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
KeInitializeEvent(&pAdapterContext->Event, NotificationEvent, FALSE);
|
||
|
||
//
|
||
// when the NDIS level adapter open completes, it will call
|
||
// LlcNdisOpenAdapterComplete which will reset the kernel event that
|
||
// we are now going to wait on (note: this plagiarized from Nbf)
|
||
//
|
||
|
||
NdisOpenAdapter(&NdisStatus,
|
||
&pAdapterContext->OpenErrorStatus,
|
||
&pAdapterContext->NdisBindingHandle,
|
||
&MediumIndex,
|
||
LlcMediumArray,
|
||
sizeof(LlcMediumArray),
|
||
(NDIS_HANDLE)LlcProtocolHandle,
|
||
(NDIS_HANDLE)pAdapterContext,
|
||
&pAdapterContext->Name,
|
||
NDIS_OPEN_RECEIVE_NOT_REENTRANT,
|
||
NULL // no addressing information
|
||
);
|
||
|
||
if (NdisStatus == NDIS_STATUS_PENDING) {
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
KeWaitForSingleObject(&pAdapterContext->Event,
|
||
Executive,
|
||
KernelMode,
|
||
TRUE, // alertable
|
||
(PLARGE_INTEGER)NULL
|
||
);
|
||
|
||
//
|
||
// get the return status from the Ndis adapter open call
|
||
//
|
||
|
||
NdisStatus = pAdapterContext->AsyncOpenStatus;
|
||
|
||
//
|
||
// place the event in not-signalled state. We don't expect to use
|
||
// this event for this adapter context again: currently it's only
|
||
// used for the adapter open at NDIS level
|
||
//
|
||
|
||
KeResetEvent(&pAdapterContext->Event);
|
||
}
|
||
|
||
*puiOpenStatus = (UINT)pAdapterContext->OpenErrorStatus;
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: NdisOpenAdapter failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
} else {
|
||
|
||
//
|
||
// from this point on, if this function fails, we have to call
|
||
// LlcCloseAdapter to close the adapter @ NDIS level
|
||
//
|
||
|
||
DoNdisClose = TRUE;
|
||
}
|
||
|
||
pAdapterContext->NdisMedium = LlcMediumArray[MediumIndex];
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
//
|
||
// fill-in some medium-specific fields
|
||
//
|
||
|
||
switch (pAdapterContext->NdisMedium) {
|
||
case NdisMedium802_5:
|
||
pAdapterContext->cbMaxFrameHeader = 32; // 6 + 6 + 2 + 18
|
||
|
||
//
|
||
// the top bit of the destination address signifies a broadcast
|
||
// frame. On Token Ring, the top bit is bit 7
|
||
//
|
||
|
||
pAdapterContext->IsBroadcast = 0x80;
|
||
|
||
//
|
||
// functional address starts C0-00-... The top 2 bytes are compared
|
||
// as a USHORT = 0x00C0
|
||
//
|
||
|
||
pAdapterContext->usHighFunctionalBits = 0x00C0;
|
||
pAdapterContext->AddressTranslationMode = LLC_SEND_802_5_TO_802_5;
|
||
break;
|
||
|
||
case NdisMedium802_3:
|
||
pAdapterContext->cbMaxFrameHeader = 14; // 6 + 6 + 2
|
||
|
||
//
|
||
// the top bit of the destination address signifies a broadcast
|
||
// frame. On Ethernet, the top bit is bit 0
|
||
//
|
||
|
||
pAdapterContext->IsBroadcast = 0x01;
|
||
|
||
//
|
||
// functional address starts 03-00-... The top 2 bytes are compared as
|
||
// a USHORT = 0x0003
|
||
//
|
||
|
||
pAdapterContext->usHighFunctionalBits = 0x0003;
|
||
pAdapterContext->AddressTranslationMode = LLC_SEND_802_3_TO_802_3;
|
||
break;
|
||
|
||
case NdisMediumFddi:
|
||
pAdapterContext->cbMaxFrameHeader = 13; // 1 + 6 + 6
|
||
|
||
//
|
||
// bits are in same order as for ethernet
|
||
//
|
||
|
||
pAdapterContext->IsBroadcast = 0x01;
|
||
pAdapterContext->usHighFunctionalBits = 0x0003;
|
||
pAdapterContext->AddressTranslationMode = LLC_SEND_FDDI_TO_FDDI;
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// allocate the ndis packets. The NDIS packet must have space
|
||
// for the maximum frame header and the maximum LLC response
|
||
// and its information field (quite small)
|
||
//
|
||
|
||
NdisAllocatePacketPool(&NdisStatus,
|
||
&pAdapterContext->hNdisPacketPool,
|
||
MAX_NDIS_PACKETS + 1,
|
||
sizeof(LLC_NDIS_PACKET) - sizeof(NDIS_MAC_PACKET)
|
||
);
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: NdisAllocatePacketPool failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
NdisStatus = InitNdisPackets(&pAdapterContext->pNdisPacketPool,
|
||
pAdapterContext->hNdisPacketPool
|
||
);
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: InitNdisPackets failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// Initialize the LLC packet pool
|
||
//
|
||
|
||
pAdapterContext->hPacketPool = CREATE_PACKET_POOL_ADAPTER(
|
||
LlcPacketPoolObject,
|
||
sizeof(UNITED_PACKETS),
|
||
8
|
||
);
|
||
if (!pAdapterContext->hPacketPool) {
|
||
NdisStatus = DLC_STATUS_NO_MEMORY;
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: CreatePacketPool failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
pAdapterContext->hLinkPool = CREATE_PACKET_POOL_ADAPTER(
|
||
LlcLinkPoolObject,
|
||
pAdapterContext->cbMaxFrameHeader
|
||
+ sizeof(DATA_LINK),
|
||
2
|
||
);
|
||
|
||
if (!pAdapterContext->hLinkPool) {
|
||
NdisStatus = DLC_STATUS_NO_MEMORY;
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: CreatePacketPool #2 failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// Read the current node address and maximum frame size
|
||
//
|
||
|
||
NdisStatus = GetNdisParameter(pAdapterContext,
|
||
(pAdapterContext->NdisMedium == NdisMedium802_3)
|
||
? OID_802_3_CURRENT_ADDRESS
|
||
: (pAdapterContext->NdisMedium == NdisMediumFddi)
|
||
? OID_FDDI_LONG_CURRENT_ADDR
|
||
: OID_802_5_CURRENT_ADDRESS,
|
||
pAdapterContext->NodeAddress,
|
||
sizeof(pAdapterContext->NodeAddress)
|
||
);
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: GetNdisParameter failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
NdisStatus = GetNdisParameter(pAdapterContext,
|
||
(pAdapterContext->NdisMedium == NdisMedium802_3)
|
||
? OID_802_3_PERMANENT_ADDRESS
|
||
: (pAdapterContext->NdisMedium == NdisMediumFddi)
|
||
? OID_FDDI_LONG_PERMANENT_ADDR
|
||
: OID_802_5_PERMANENT_ADDRESS,
|
||
pAdapterContext->PermanentAddress,
|
||
sizeof(pAdapterContext->PermanentAddress)
|
||
);
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: GetNdisParameter #2 failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
{
|
||
//
|
||
// Mod RLF 07/10/92
|
||
//
|
||
// apparently, TR adapter does not support NDIS_PACKET_TYPE_MULTICAST
|
||
// as a filter. Up to now, it seems to have been reasonably happy
|
||
// with this type. However, we're not going to include it from now on
|
||
//
|
||
|
||
//
|
||
// Mod RLF 01/13/93
|
||
//
|
||
// Similarly, Ethernet doesn't support FUNCTIONAL addresses (Token
|
||
// Ring's functional address is equivalent to Ethernet's multicast
|
||
// address)
|
||
//
|
||
|
||
ULONG PacketFilter = NDIS_PACKET_TYPE_DIRECTED
|
||
| NDIS_PACKET_TYPE_BROADCAST
|
||
| (((pAdapterContext->NdisMedium == NdisMedium802_3)
|
||
|| (pAdapterContext->NdisMedium == NdisMediumFddi))
|
||
? NDIS_PACKET_TYPE_MULTICAST
|
||
: NDIS_PACKET_TYPE_FUNCTIONAL
|
||
);
|
||
|
||
//
|
||
// EndMod
|
||
//
|
||
|
||
NdisStatus = SetNdisParameter(pAdapterContext,
|
||
OID_GEN_CURRENT_PACKET_FILTER,
|
||
&PacketFilter,
|
||
sizeof(PacketFilter)
|
||
);
|
||
#if DBG
|
||
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
DbgPrint("Error: NdisStatus = %x\n", NdisStatus);
|
||
ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
|
||
}
|
||
|
||
#endif
|
||
|
||
}
|
||
|
||
LlcMemCpy(pAdapterContext->Adapter.Node.auchAddress,
|
||
pAdapterContext->NodeAddress,
|
||
6
|
||
);
|
||
|
||
NdisStatus = GetNdisParameter(pAdapterContext,
|
||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||
&pAdapterContext->MaxFrameSize,
|
||
sizeof(pAdapterContext->MaxFrameSize)
|
||
);
|
||
if (NdisStatus == STATUS_SUCCESS) {
|
||
NdisStatus = GetNdisParameter(pAdapterContext,
|
||
OID_GEN_LINK_SPEED,
|
||
&pAdapterContext->LinkSpeed,
|
||
sizeof(pAdapterContext->LinkSpeed)
|
||
);
|
||
}
|
||
if (NdisStatus != STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: GetNdisParameter #3/#4 failed\n");
|
||
}
|
||
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// RLF 04/12/93
|
||
//
|
||
// Here we used to load the LLC_TICKS array from TimerTicks - a global
|
||
// array of timer tick values.
|
||
// Instead, we get any per-adapter configuration information stored in
|
||
// the registry
|
||
//
|
||
|
||
LoadAdapterConfiguration(&pAdapterContext->Name,
|
||
&pAdapterContext->ConfigInfo
|
||
);
|
||
|
||
//
|
||
// RLF 04/02/94
|
||
//
|
||
// if this is not a Token Ring card then check the MaxFrameSize retrieved
|
||
// above. If the UseEthernetFrameSize parameter was set in the registry
|
||
// then we use the smaller of the ethernet size (1514) and the value
|
||
// reported by the MAC. If the parameter was not set then we just use
|
||
// the value already retrieved. If the card is Token Ring then we use
|
||
// the value already retrieved
|
||
//
|
||
|
||
if (pAdapterContext->NdisMedium != NdisMedium802_5
|
||
&& pAdapterContext->ConfigInfo.UseEthernetFrameSize
|
||
&& pAdapterContext->MaxFrameSize > MAX_ETHERNET_FRAME_LENGTH) {
|
||
pAdapterContext->MaxFrameSize = MAX_ETHERNET_FRAME_LENGTH;
|
||
}
|
||
|
||
pAdapterContext->QueueI.pObject = (PVOID)GetI_Packet;
|
||
|
||
InitializeListHead(&pAdapterContext->QueueI.ListHead);
|
||
|
||
pAdapterContext->QueueDirAndU.pObject = (PVOID)BuildDirOrU_Packet;
|
||
|
||
InitializeListHead(&pAdapterContext->QueueDirAndU.ListHead);
|
||
|
||
pAdapterContext->QueueExpidited.pObject = (PVOID)GetLlcCommandPacket;
|
||
|
||
InitializeListHead(&pAdapterContext->QueueExpidited.ListHead);
|
||
|
||
pAdapterContext->AdapterNumber = (UCHAR)AdapterNumber;
|
||
|
||
pAdapterContext->OpenCompleteStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// if we allocated a framing discovery cache, but this adapter is not
|
||
// ethernet or FDDI then disable the cache (BUGBUG - we should free the
|
||
// memory used by the cache in this case!!)
|
||
//
|
||
|
||
if ((pAdapterContext->NdisMedium != NdisMedium802_3)
|
||
&& (pAdapterContext->NdisMedium != NdisMediumFddi)) {
|
||
|
||
pBindingContext->FramingDiscoveryCacheEntries = 0;
|
||
|
||
#if defined(DEBUG_DISCOVERY)
|
||
|
||
DbgPrint("LlcOpenAdapter: setting cache entries to 0 (medium = %s)\n",
|
||
(pAdapterContext->NdisMedium == NdisMedium802_5) ? "802.5" :
|
||
(pAdapterContext->NdisMedium == NdisMediumWan) ? "WAN" :
|
||
(pAdapterContext->NdisMedium == NdisMediumLocalTalk) ? "LocalTalk" :
|
||
(pAdapterContext->NdisMedium == NdisMediumDix) ? "DIX?" :
|
||
(pAdapterContext->NdisMedium == NdisMediumArcnetRaw) ? "ArcnetRaw" :
|
||
(pAdapterContext->NdisMedium == NdisMediumArcnet878_2) ? "Arcnet878_2" :
|
||
"UNKNOWN!"
|
||
);
|
||
|
||
#endif
|
||
|
||
}
|
||
} else {
|
||
newAdapter = FALSE;
|
||
}
|
||
|
||
//
|
||
// at this point, we have an allocated, but as yet not filled in binding
|
||
// context and an adapter context that we either found on the pAdapters
|
||
// list, or we just allocated and filled in. We are currently operating
|
||
// at PASSIVE_LEVEL. Re-acquire the driver lock and fill in the binding
|
||
// context
|
||
//
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
switch (pAdapterContext->NdisMedium) {
|
||
case NdisMedium802_5:
|
||
pBindingContext->EthernetType = LLC_ETHERNET_TYPE_802_3;
|
||
pBindingContext->InternalAddressTranslation = LLC_SEND_802_5_TO_802_5;
|
||
|
||
#ifdef SUPPORT_ETHERNET_CLIENT
|
||
|
||
if (NdisMedium == NdisMedium802_3) {
|
||
pBindingContext->SwapCopiedLanAddresses = TRUE;
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_3_TO_802_5;
|
||
} else {
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_802_5;
|
||
}
|
||
|
||
#else
|
||
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_802_5;
|
||
|
||
#endif
|
||
|
||
pBindingContext->SwapCopiedLanAddresses = FALSE;
|
||
break;
|
||
|
||
case NdisMediumFddi:
|
||
pBindingContext->EthernetType = LLC_ETHERNET_TYPE_802_3;
|
||
pBindingContext->InternalAddressTranslation = LLC_SEND_FDDI_TO_FDDI;
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_FDDI;
|
||
pBindingContext->SwapCopiedLanAddresses = TRUE;
|
||
break;
|
||
|
||
case NdisMedium802_3:
|
||
|
||
//
|
||
// if EthernetType is LLC_ETHERNET_TYPE_DEFAULT then set it to DIX based
|
||
// on the UseDix entry in the registry
|
||
//
|
||
|
||
if (EthernetType == LLC_ETHERNET_TYPE_DEFAULT) {
|
||
EthernetType = pAdapterContext->ConfigInfo.UseDix
|
||
? LLC_ETHERNET_TYPE_DIX
|
||
: LLC_ETHERNET_TYPE_802_3
|
||
;
|
||
}
|
||
pBindingContext->EthernetType = (USHORT)EthernetType;
|
||
|
||
if (EthernetType == LLC_ETHERNET_TYPE_DIX) {
|
||
pBindingContext->InternalAddressTranslation = LLC_SEND_802_3_TO_DIX;
|
||
} else {
|
||
pBindingContext->InternalAddressTranslation = LLC_SEND_802_3_TO_802_3;
|
||
}
|
||
|
||
#ifdef SUPPORT_ETHERNET_CLIENT
|
||
|
||
if (NdisMedium == NdisMedium802_3) {
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_3_TO_802_3;
|
||
if (EthernetType == LLC_ETHERNET_TYPE_DIX) {
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_3_TO_DIX;
|
||
}
|
||
} else {
|
||
pBindingContext->SwapCopiedLanAddresses = TRUE;
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_802_3;
|
||
if (EthernetType == LLC_ETHERNET_TYPE_DIX) {
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_DIX;
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
pBindingContext->SwapCopiedLanAddresses = TRUE;
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_802_3;
|
||
if (EthernetType == LLC_ETHERNET_TYPE_DIX) {
|
||
pBindingContext->AddressTranslation = LLC_SEND_802_5_TO_DIX;
|
||
}
|
||
|
||
#endif
|
||
|
||
}
|
||
|
||
pBindingContext->NdisMedium = NdisMedium;
|
||
pBindingContext->hClientContext = hClientContext;
|
||
pBindingContext->pfCommandComplete = pfCommandComplete;
|
||
pBindingContext->pfReceiveIndication = pfReceiveIndication;
|
||
pBindingContext->pfEventIndication = pfEventIndication;
|
||
*pusMaxFrameLength = (USHORT)pAdapterContext->MaxFrameSize;
|
||
*pActualNdisMedium = pAdapterContext->NdisMedium;
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
//
|
||
// create a new timer tick (or update one that already exists) and add a
|
||
// timer to it for the DLC timer (used by the DIR.TIMER.XXX routines). The
|
||
// DLC timer fires every 0.5 seconds. The LLC timer fires every 40 mSec. The
|
||
// multiplier is therefore 13 (13 * 40 mSec = 520 mSec). We need to add 5
|
||
// because InitializeTimer is expecting DLC timer tick values of 1-5 and
|
||
// 6-10. If the timer tick value is greater than 5, InitializeTimer will
|
||
// subtract 5 and multiply by the second multiplier value
|
||
//
|
||
|
||
NdisStatus = InitializeTimer(pAdapterContext,
|
||
&pBindingContext->DlcTimer,
|
||
(UCHAR)13 + 5,
|
||
(UCHAR)1,
|
||
(UCHAR)1,
|
||
LLC_TIMER_TICK_EVENT,
|
||
pBindingContext,
|
||
0, // ResponseDelay
|
||
FALSE
|
||
);
|
||
if (NdisStatus != STATUS_SUCCESS) {
|
||
|
||
IF_LOCK_CHECK {
|
||
DbgPrint("LlcOpenAdapter: InitializeTimer failed\n");
|
||
}
|
||
|
||
//
|
||
// we failed to initialize the timer. Free up all resources and return
|
||
// the error
|
||
//
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
goto CleanUp;
|
||
} else {
|
||
StartTimer(&pBindingContext->DlcTimer);
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
}
|
||
|
||
//
|
||
// everything worked: point the binding context at the adapter context,
|
||
// point the adapter context at the binding context, incrementing the binding
|
||
// count (note that if this is the first binding, the count field will be
|
||
// zero since we allocated the adapter context from ZeroMemory). Finally add
|
||
// the adapter context to pAdapters if it wasn't already on the list
|
||
//
|
||
|
||
pBindingContext->pAdapterContext = pAdapterContext;
|
||
|
||
IF_LOCK_CHECK {
|
||
if (!pAdapterContext->BindingCount) {
|
||
if (pAdapterContext->pBindings) {
|
||
DbgPrint("**** binding count/pointer mismatch ****\n");
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
|
||
pBindingContext->pNext = pAdapterContext->pBindings;
|
||
pAdapterContext->pBindings = pBindingContext;
|
||
++pAdapterContext->BindingCount;
|
||
|
||
//
|
||
// we can now add this adapter context structure to the global list
|
||
// of adapter contexts
|
||
//
|
||
|
||
if (newAdapter) {
|
||
pAdapterContext->pNext = pAdapters;
|
||
pAdapters = pAdapterContext;
|
||
}
|
||
|
||
//
|
||
// now release the semaphore, allowing any other threads waiting to open an
|
||
// adapter to check the pAdapter list
|
||
//
|
||
|
||
KeReleaseSemaphore(&OpenAdapterSemaphore, 0, 1, FALSE);
|
||
|
||
//
|
||
// return a pointer to the allocated binding context
|
||
//
|
||
|
||
*phBindingContext = (PVOID)pBindingContext;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
CleanUp:
|
||
|
||
//
|
||
// an error occurred. If we just allocated and (partially) filled in an
|
||
// adapter context then close the adapter (if required), release the adapter
|
||
// context resources and free the adapter context.
|
||
// We have a binding context that we just allocated. Deallocate it
|
||
// N.B. We cannot be here if the binding context's timer was successfully
|
||
// initialized/started
|
||
//
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
//
|
||
// if we are to close this adapter then this is the first and only open of
|
||
// this adapter, so we don't need to worry about synchronizing other threads
|
||
// open the same adapter
|
||
//
|
||
|
||
if (DoNdisClose) {
|
||
|
||
NDIS_STATUS status;
|
||
|
||
pAdapterContext->AsyncCloseResetStatus = NDIS_STATUS_PENDING;
|
||
NdisCloseAdapter(&status,
|
||
pAdapterContext->NdisBindingHandle
|
||
);
|
||
WaitAsyncOperation(pAdapterContext,
|
||
&(pAdapterContext->AsyncCloseResetStatus),
|
||
status);
|
||
pAdapterContext->NdisBindingHandle = NULL;
|
||
}
|
||
|
||
//
|
||
// release the semaphore - any other threads can now get in and access
|
||
// pAdapters
|
||
//
|
||
|
||
KeReleaseSemaphore(&OpenAdapterSemaphore, 0, 1, FALSE);
|
||
|
||
//
|
||
// if a newly allocated adapter context, release any resources allocated
|
||
//
|
||
|
||
if (newAdapter) {
|
||
if (pAdapterContext->hNdisPacketPool) {
|
||
|
||
//
|
||
// Free MDLs allocated for each NDIS packet.
|
||
//
|
||
|
||
while (pAdapterContext->pNdisPacketPool) {
|
||
|
||
PLLC_NDIS_PACKET pNdisPacket;
|
||
|
||
pNdisPacket = PopFromList(((PLLC_PACKET)pAdapterContext->pNdisPacketPool));
|
||
IoFreeMdl(pNdisPacket->pMdl);
|
||
|
||
DBG_INTERLOCKED_DECREMENT(AllocatedMdlCount);
|
||
}
|
||
|
||
NdisFreePacketPool(pAdapterContext->hNdisPacketPool);
|
||
}
|
||
|
||
//
|
||
// DEBUG: refund memory charged for UNICODE buffer to driver string usage
|
||
//
|
||
|
||
FREE_STRING_DRIVER(pAdapterContext->Name.Buffer);
|
||
|
||
DELETE_PACKET_POOL_ADAPTER(&pAdapterContext->hLinkPool);
|
||
DELETE_PACKET_POOL_ADAPTER(&pAdapterContext->hPacketPool);
|
||
|
||
CHECK_MEMORY_RETURNED_ADAPTER();
|
||
CHECK_STRING_RETURNED_ADAPTER();
|
||
|
||
UNLINK_MEMORY_USAGE(pAdapterContext);
|
||
UNLINK_STRING_USAGE(pAdapterContext);
|
||
|
||
//
|
||
// free the adapter context
|
||
//
|
||
|
||
FREE_MEMORY_DRIVER(pAdapterContext);
|
||
|
||
}
|
||
|
||
//
|
||
// free the binding context
|
||
//
|
||
|
||
FREE_MEMORY_FILE(pBindingContext);
|
||
|
||
//
|
||
// finally retake the spin lock and return the error status
|
||
//
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
return NdisStatus;
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcNdisOpenAdapterComplete(
|
||
IN PVOID hAdapterContext,
|
||
IN NDIS_STATUS NdisStatus,
|
||
IN NDIS_STATUS OpenErrorStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine completes the adapter opening.
|
||
It only clears and sets the status flags, that are
|
||
polled by the BindToAdapter primitive.
|
||
|
||
Arguments:
|
||
|
||
hAdapterContext - describes adapter being opened
|
||
NdisStatus - the return status of NdisOpenAdapter
|
||
OpenErrorStatus - additional error info from NDIS
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
//
|
||
// set the relevant fields in the adapter context
|
||
//
|
||
|
||
((PADAPTER_CONTEXT)hAdapterContext)->AsyncOpenStatus = NdisStatus;
|
||
((PADAPTER_CONTEXT)hAdapterContext)->OpenErrorStatus = OpenErrorStatus;
|
||
|
||
//
|
||
// signal the event that LlcOpenAdapter is waiting on
|
||
//
|
||
|
||
ASSUME_IRQL(ANY_IRQL);
|
||
|
||
KeSetEvent(&((PADAPTER_CONTEXT)hAdapterContext)->Event, 0L, FALSE);
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcDisableAdapter(
|
||
IN PBINDING_CONTEXT pBindingContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The primitive disables all network indications on a data link binding.
|
||
This routine can be called from a llc indication handler.
|
||
|
||
Arguments:
|
||
|
||
pBindingContext - The context of the current adapter binding.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_CONTEXT pAdapterContext;
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
pAdapterContext = pBindingContext->pAdapterContext;
|
||
if (pAdapterContext) {
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
TerminateTimer(pAdapterContext, &pBindingContext->DlcTimer);
|
||
|
||
//
|
||
// RLF 04/27/94
|
||
//
|
||
// this is a slight hack: we zap the pointer to the timer tick structure
|
||
// so that if this is called again, TerminateTimer will see that the
|
||
// pointer to the timer tick is NULL and will return immediately. We
|
||
// shouldn't have to do this - we shouldn't poke around inside the
|
||
// timer 'object' - but this function can potentially be called from two
|
||
// places on the termination path - from DirCloseAdapter and now from
|
||
// CloseAdapterFileContext.
|
||
// We only do this for the DLC timer; if we did it for all timers - in
|
||
// TerminateTimer - DLC would break (scandalous, I know)
|
||
//
|
||
|
||
pBindingContext->DlcTimer.pTimerTick = NULL;
|
||
|
||
#ifdef LOCK_CHECK
|
||
|
||
pBindingContext->DlcTimer.Disabled = 0xd0bed0be; // do be do be do...
|
||
|
||
#endif
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
LlcCloseAdapter(
|
||
IN PBINDING_CONTEXT pBindingContext,
|
||
IN BOOLEAN CloseAtNdisLevel
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
remove a binding from an adapter. The binding context structure is unlinked
|
||
from the adapter context structure and the count of bindings to the adapter
|
||
context is decremented. The binding context structure is freed. If this is
|
||
the last binding to the adapter then close the adapter at NDIS level, unlink
|
||
the adapter context structure from the global adapter list and free the
|
||
memory used by the adapter context structure
|
||
|
||
Arguments:
|
||
|
||
pBindingContext - describes adapter to close
|
||
CloseAtNdisLevel - TRUE if we need to perform NdisCloseAdapter
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
Success - STATUS_SUCCESS
|
||
Failure - All NDIS error status from NdisCloseAdapter
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_CONTEXT pAdapterContext;
|
||
NDIS_STATUS NdisStatus = STATUS_SUCCESS;
|
||
KIRQL irql;
|
||
USHORT bindingCount;
|
||
|
||
#if DBG
|
||
|
||
PDLC_FILE_CONTEXT pFileContext = (PDLC_FILE_CONTEXT)(pBindingContext->hClientContext);
|
||
|
||
#endif
|
||
|
||
#ifdef LOCK_CHECK
|
||
|
||
PBINDING_CONTEXT p;
|
||
BOOLEAN found = FALSE;
|
||
|
||
#endif
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
pAdapterContext = pBindingContext->pAdapterContext;
|
||
|
||
if (!pAdapterContext) {
|
||
|
||
#if DBG
|
||
|
||
DbgPrint("*** LlcCloseAdapter: NULL adapter context! ***\n");
|
||
DbgBreakPoint();
|
||
|
||
#endif
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// we must wait on the OpenAdapterSemaphore. We need to do this because a
|
||
// thread in another process may be simultaneously generating a new binding
|
||
// to this adapter context - it mustn't be removed until we are certain
|
||
// there are no threads accessing this adapter context
|
||
//
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
KeWaitForSingleObject((PVOID)&OpenAdapterSemaphore,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE, // not alertable
|
||
NULL // wait until object is signalled
|
||
);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
||
|
||
#ifdef LOCK_CHECK
|
||
|
||
for (p = pAdapterContext->pBindings; p; p = p->pNext) {
|
||
if (p == pBindingContext) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if (!found) {
|
||
DbgPrint("\n**** LlcCloseAdapter: can't find BC %x ****\n\n", pBindingContext);
|
||
DbgBreakPoint();
|
||
} else if (p->pNext == p) {
|
||
DbgPrint("\n**** LlcCloseAdapter: circular list ****\n\n");
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
#endif
|
||
|
||
RemoveFromLinkList((PVOID*)&(pAdapterContext->pBindings), pBindingContext);
|
||
bindingCount = --pAdapterContext->BindingCount;
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
|
||
|
||
#ifdef LOCK_CHECK
|
||
|
||
if (!pBindingContext->DlcTimer.Disabled) {
|
||
DbgPrint("LlcCloseAdapter: mashing active timer. bc=%x\n", pBindingContext);
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// RLF 08/20/94
|
||
//
|
||
// here we must kill any events on the adapter context that may access
|
||
// this binding context's event indication function pointer. If not, we
|
||
// can end up with a blue screen (hey! it happened)
|
||
//
|
||
|
||
PurgeLlcEventQueue(pBindingContext);
|
||
|
||
//
|
||
// DEBUG: refund memory charged for BINDING_CONTEXT to FILE_CONTEXT
|
||
//
|
||
|
||
FREE_MEMORY_FILE(pBindingContext);
|
||
|
||
if (!bindingCount) {
|
||
|
||
RemoveFromLinkList((PVOID*)&pAdapters, pAdapterContext);
|
||
|
||
//
|
||
// Now the adapter is isolated from any global connections.
|
||
// We may clear the global spin lock and free all resources
|
||
// allocated for the adapter context.
|
||
//
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
//
|
||
// Out of memory conditions the upper driver cannot properly
|
||
// wait until all pending NDIS packets have been sent.
|
||
// In that case we must poll here.
|
||
// (This should happen only if ExAllocatePool fails, but
|
||
// after an inproper shutdown we will loop here forever)
|
||
//
|
||
|
||
#if DBG
|
||
|
||
if (pAdapterContext->ObjectCount) {
|
||
DbgPrint("Waiting LLC objects to be closed ...\n");
|
||
}
|
||
|
||
#endif
|
||
|
||
while (pAdapterContext->ObjectCount) {
|
||
LlcSleep(1000L); // check the situation after 1 ms
|
||
}
|
||
|
||
//
|
||
// RLF 10/26/92
|
||
//
|
||
// we used to test pAdapterContext->NdisBindingHandle for NULL here,
|
||
// but that is an unreliable test since the NdisBindingHandle can be
|
||
// non-NULL even though the binding was not made. We now use the
|
||
// CloseAtNdisLevel parameter to indicate whether we should call the
|
||
// Ndis function to close the adapter
|
||
//
|
||
|
||
//
|
||
// MunilS 6/13/96
|
||
//
|
||
// Moved NdisFreePacketPool etc after NdisCloseAdapter to prevent
|
||
// bugcheck in NDIS while handling outstanding sends.
|
||
//
|
||
|
||
if (CloseAtNdisLevel)
|
||
{
|
||
pAdapterContext->AsyncCloseResetStatus = NDIS_STATUS_PENDING;
|
||
|
||
NdisCloseAdapter(&NdisStatus,
|
||
pAdapterContext->NdisBindingHandle
|
||
);
|
||
|
||
WaitAsyncOperation(pAdapterContext,
|
||
&(pAdapterContext->AsyncCloseResetStatus),
|
||
NdisStatus);
|
||
pAdapterContext->NdisBindingHandle = NULL;
|
||
}
|
||
|
||
if (pAdapterContext->hNdisPacketPool)
|
||
{
|
||
|
||
//
|
||
// Free MDLs allocated for each NDIS packet.
|
||
//
|
||
|
||
while (pAdapterContext->pNdisPacketPool) {
|
||
|
||
PLLC_NDIS_PACKET pNdisPacket;
|
||
|
||
pNdisPacket = PopFromList(((PLLC_PACKET)pAdapterContext->pNdisPacketPool));
|
||
|
||
IoFreeMdl(pNdisPacket->pMdl);
|
||
|
||
DBG_INTERLOCKED_DECREMENT(AllocatedMdlCount);
|
||
}
|
||
|
||
NdisFreePacketPool(pAdapterContext->hNdisPacketPool);
|
||
}
|
||
|
||
//
|
||
// DEBUG: refund memory charged for UNICODE buffer to driver string usage
|
||
//
|
||
|
||
FREE_STRING_DRIVER(pAdapterContext->Name.Buffer);
|
||
|
||
DELETE_PACKET_POOL_ADAPTER(&pAdapterContext->hLinkPool);
|
||
|
||
DELETE_PACKET_POOL_ADAPTER(&pAdapterContext->hPacketPool);
|
||
|
||
CHECK_MEMORY_RETURNED_ADAPTER();
|
||
|
||
CHECK_STRING_RETURNED_ADAPTER();
|
||
|
||
UNLINK_MEMORY_USAGE(pAdapterContext);
|
||
|
||
UNLINK_STRING_USAGE(pAdapterContext);
|
||
|
||
FREE_MEMORY_DRIVER(pAdapterContext);
|
||
|
||
} else {
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
}
|
||
|
||
//
|
||
// now we can enable any other threads waiting on the open semaphore
|
||
//
|
||
|
||
KeReleaseSemaphore(&OpenAdapterSemaphore, 0, 1, FALSE);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
return NdisStatus;
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
LlcResetBroadcastAddresses(
|
||
IN PBINDING_CONTEXT pBindingContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The primitive deletes the broadcast addresses used by the binding.
|
||
In the case of ethernet it updates multicast address list on
|
||
the adapter, that excludes any addresses set by this binding.
|
||
The last binding actually gives an empty list, that resets
|
||
all addresses set by this protocol binding.
|
||
|
||
Arguments:
|
||
|
||
pBindingContext - The context of the current adapter binding.
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS:
|
||
Success - STATUS_SUCCESS
|
||
Failure - All NDIS error status from NdisCloseAdapter
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_CONTEXT pAdapterContext;
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
pAdapterContext = pBindingContext->pAdapterContext;
|
||
|
||
if (pAdapterContext == NULL) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Reset the functional and group addresses of this binding context.
|
||
// In the case of ethernet, functional and group addresses of
|
||
// binding contexts are mapped to one global multicast list of
|
||
// this NDIS binding. Token-ring may have only one group
|
||
// address, that must be reset, when the application owning it
|
||
// is closing its dlc adapter context. Functional address
|
||
// must also set again in that case.
|
||
//
|
||
|
||
pBindingContext->Functional.ulAddress = 0;
|
||
UpdateFunctionalAddress(pAdapterContext);
|
||
|
||
if (pBindingContext->ulBroadcastAddress != 0) {
|
||
pBindingContext->ulBroadcastAddress = 0;
|
||
UpdateGroupAddress(pAdapterContext, pBindingContext);
|
||
}
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
InitNdisPackets(
|
||
OUT PLLC_NDIS_PACKET* ppLlcPacketPool,
|
||
IN NDIS_HANDLE hNdisPool
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The primitive copies Ndis packets from the NDIS pool to the
|
||
given internal packet pool.
|
||
|
||
Arguments:
|
||
|
||
ppLlcPacketPool - pointer to pointer to packet pool
|
||
hNdisPool - handle of NDIS packet pool
|
||
|
||
Return Value:
|
||
|
||
NDIS_STATUS
|
||
--*/
|
||
|
||
{
|
||
PLLC_NDIS_PACKET pNdisPacket;
|
||
NDIS_STATUS NdisStatus;
|
||
UINT i;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
for (i = 0; i < MAX_NDIS_PACKETS; i++) {
|
||
NdisAllocatePacket(&NdisStatus,
|
||
(PNDIS_PACKET*)&pNdisPacket,
|
||
hNdisPool
|
||
);
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
return NdisStatus;
|
||
}
|
||
|
||
//
|
||
// Every NDIS packet includes a MDL, that has been
|
||
// initialized for the data buffer within the same
|
||
// structure. Thus data link driver does need to
|
||
// do any MDL calls during the runtime
|
||
//
|
||
|
||
pNdisPacket->pMdl = IoAllocateMdl(pNdisPacket->auchLanHeader,
|
||
sizeof(pNdisPacket->auchLanHeader),
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
if (pNdisPacket->pMdl == NULL) {
|
||
return DLC_STATUS_NO_MEMORY;
|
||
}
|
||
|
||
DBG_INTERLOCKED_INCREMENT(AllocatedMdlCount);
|
||
|
||
MmBuildMdlForNonPagedPool(pNdisPacket->pMdl);
|
||
|
||
PushToList(((PLLC_PACKET)*ppLlcPacketPool),
|
||
((PLLC_PACKET)pNdisPacket)
|
||
);
|
||
}
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcNdisCloseComplete(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN NDIS_STATUS NdisStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
call-back from NDIS when the adapter close operation is completed
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - describes the adapter being closed
|
||
NdisStatus - the return status of NdisOpenAdapter
|
||
|
||
Return Value:
|
||
|
||
None
|
||
--*/
|
||
|
||
{
|
||
ASSUME_IRQL(ANY_IRQL);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
pAdapterContext->AsyncCloseResetStatus = NdisStatus;
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
KeSetEvent(&pAdapterContext->Event, 0L, FALSE);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NdisStatusHandler(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN NDIS_STATUS NdisStatus,
|
||
IN PVOID StatusBuffer,
|
||
IN UINT StatusBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
indication handler for all NDIS status events
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - context of the NDIS adapter
|
||
NdisStatus - the major NDIS status code
|
||
StatusBuffer - A buffer holding more status information
|
||
StatusBufferSize - The length of StatusBuffer.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PBINDING_CONTEXT pBinding;
|
||
PEVENT_PACKET pEvent;
|
||
KIRQL irql;
|
||
|
||
//
|
||
// seems that this handler can be called at PASSIVE_LEVEL too
|
||
//
|
||
|
||
ASSUME_IRQL(ANY_IRQL);
|
||
|
||
//
|
||
// We must synchronize the access to the binding list,
|
||
// the reference count will not allow the client
|
||
// to delete or modify the bindings list while
|
||
// we are routing the status indication to the
|
||
// clients.
|
||
//
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
//
|
||
// The NDIS send process is stopped by the reset flag.
|
||
//
|
||
|
||
if (NdisStatus == NDIS_STATUS_RESET_START) {
|
||
pAdapterContext->ResetInProgress = TRUE;
|
||
} else if (NdisStatus == NDIS_STATUS_RESET_END) {
|
||
pAdapterContext->ResetInProgress = FALSE;
|
||
} else if (StatusBufferSize == sizeof(NTSTATUS)) {
|
||
|
||
//
|
||
// ADAMBA - Declare and assign SpecificStatus locally.
|
||
//
|
||
|
||
NTSTATUS SpecificStatus = *(PULONG)StatusBuffer;
|
||
|
||
if ( NdisStatus == NDIS_STATUS_RING_STATUS ) {
|
||
#if DBG
|
||
ASSERT (IS_NDIS_RING_STATUS(SpecificStatus));
|
||
#else // DBG
|
||
if (IS_NDIS_RING_STATUS(SpecificStatus))
|
||
#endif // DBG
|
||
{
|
||
SpecificStatus = NDIS_RING_STATUS_TO_DLC_RING_STATUS(SpecificStatus);
|
||
}
|
||
}
|
||
|
||
//
|
||
// These ndis status codes are indicated to all LLC
|
||
// protocol drivers, that have been bound to this adapter:
|
||
//
|
||
// NDIS_STATUS_ONLINE
|
||
// NDIS_STATUS_CLOSED
|
||
// NDIS_STATUS_RING_STATUS
|
||
//
|
||
|
||
for (pBinding = pAdapterContext->pBindings;
|
||
pBinding;
|
||
pBinding = pBinding->pNext) {
|
||
|
||
pEvent = ALLOCATE_PACKET_LLC_PKT(pAdapterContext->hPacketPool);
|
||
|
||
if (pEvent) {
|
||
pEvent->pBinding = pBinding;
|
||
pEvent->hClientHandle = NULL;
|
||
pEvent->Event = LLC_NETWORK_STATUS;
|
||
pEvent->pEventInformation = (PVOID)NdisStatus;
|
||
pEvent->SecondaryInfo = SpecificStatus;
|
||
LlcInsertTailList(&pAdapterContext->QueueEvents, pEvent);
|
||
}
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
GetNdisParameter(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN NDIS_OID NdisOid,
|
||
IN PVOID pDataBuffer,
|
||
IN UINT DataSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
get parameter from NDIS using OID interface
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - describes adapter
|
||
NdisOid - indentifies the requested NDIS data
|
||
pDataBuffer - the buffer for the returned data
|
||
DataSize - size of pDataBuffer
|
||
|
||
Return Value:
|
||
|
||
NDIS_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
LLC_NDIS_REQUEST Request;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
Request.Ndis.RequestType = NdisRequestQueryInformation;
|
||
Request.Ndis.DATA.QUERY_INFORMATION.Oid = NdisOid;
|
||
Request.Ndis.DATA.QUERY_INFORMATION.InformationBuffer = pDataBuffer;
|
||
Request.Ndis.DATA.QUERY_INFORMATION.InformationBufferLength = DataSize;
|
||
|
||
return SyncNdisRequest(pAdapterContext, &Request);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
SetNdisParameter(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN NDIS_OID NdisOid,
|
||
IN PVOID pRequestInfo,
|
||
IN UINT RequestLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
set NDIS parameter using OID interface
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - describes adapter
|
||
NdisOid - describes info to set
|
||
pRequestInfo - pointer to info
|
||
RequestLength - size of info
|
||
|
||
Return Value:
|
||
|
||
NDIS_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
LLC_NDIS_REQUEST Request;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
Request.Ndis.RequestType = NdisRequestSetInformation;
|
||
Request.Ndis.DATA.SET_INFORMATION.Oid = NdisOid;
|
||
Request.Ndis.DATA.SET_INFORMATION.InformationBuffer = pRequestInfo;
|
||
Request.Ndis.DATA.SET_INFORMATION.InformationBufferLength = RequestLength;
|
||
return SyncNdisRequest(pAdapterContext, &Request);
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
SyncNdisRequest(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN PLLC_NDIS_REQUEST pRequest
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Perform an NDIS request synchronously, even if the actual request would
|
||
be asynchronous
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - pointer to adapter context
|
||
pRequest - pointer to NDIS request structure
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
DLC_STATUS Status;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
pRequest->AsyncStatus = NDIS_STATUS_PENDING;
|
||
NdisRequest(&Status, pAdapterContext->NdisBindingHandle, &pRequest->Ndis);
|
||
return (DLC_STATUS)WaitAsyncOperation(pAdapterContext,
|
||
&(pRequest->AsyncStatus),
|
||
Status);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
WaitAsyncOperation(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN PNDIS_STATUS pAsyncStatus,
|
||
IN NDIS_STATUS NdisStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wait for an asynchronous NDIS operation to complete
|
||
|
||
Arguments:
|
||
|
||
pAsyncStatus - pointer to status returned from NDIS
|
||
NdisStatus - status to wait for. Should be NDIS_STATUS_PENDING
|
||
|
||
Return Value:
|
||
|
||
NDIS_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NDIS_STATUS AsyncStatus;
|
||
|
||
ASSUME_IRQL(PASSIVE_LEVEL);
|
||
|
||
//
|
||
// Check if we got a synchronous status
|
||
//
|
||
|
||
if (NdisStatus != NDIS_STATUS_PENDING) {
|
||
AsyncStatus = NdisStatus;
|
||
}
|
||
|
||
else{
|
||
//
|
||
// Wait until the async status flag has been set
|
||
//
|
||
|
||
for ( ; ; ) {
|
||
|
||
KIRQL irql;
|
||
|
||
KeWaitForSingleObject(&pAdapterContext->Event,
|
||
Executive,
|
||
KernelMode,
|
||
TRUE, // alertable
|
||
(PLARGE_INTEGER)NULL
|
||
);
|
||
|
||
//
|
||
// The result may be undefined, if we read it in a wrong time.
|
||
// Do it interlocked.
|
||
//
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
AsyncStatus = *pAsyncStatus;
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
if (AsyncStatus != NDIS_STATUS_PENDING) {
|
||
break;
|
||
}
|
||
else{
|
||
KeClearEvent(&pAdapterContext->Event);
|
||
}
|
||
|
||
}
|
||
}
|
||
return AsyncStatus;
|
||
}
|
||
|
||
|
||
DLC_STATUS
|
||
LlcNdisRequest(
|
||
IN PVOID hBindingContext,
|
||
IN PLLC_NDIS_REQUEST pDlcParms
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
makes an NDIS request
|
||
|
||
Arguments:
|
||
|
||
hBindingContext - pointer to binding context
|
||
pDlcParms - pointer to request-specific parameters
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
return SyncNdisRequest(((PBINDING_CONTEXT)hBindingContext)->pAdapterContext,
|
||
pDlcParms
|
||
);
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcNdisRequestComplete(
|
||
IN PADAPTER_CONTEXT pAdapterContext,
|
||
IN PNDIS_REQUEST RequestHandle,
|
||
IN NDIS_STATUS NdisStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
receives control when an aync NDIS command completes
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - pointer to ADAPTER_CONTEXT for which request was made
|
||
RequestHandle - handle of request
|
||
NdisStatus - returned status from NDIS
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
PLLC_NDIS_REQUEST pLlcNdisRequest =
|
||
CONTAINING_RECORD ( RequestHandle, LLC_NDIS_REQUEST, Ndis );
|
||
|
||
UNREFERENCED_PARAMETER(pAdapterContext);
|
||
|
||
ASSUME_IRQL(ANY_IRQL);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
ACQUIRE_LLC_LOCK(irql);
|
||
|
||
pLlcNdisRequest->AsyncStatus = NdisStatus;
|
||
|
||
RELEASE_LLC_LOCK(irql);
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
KeSetEvent(&pAdapterContext->Event, 0L, FALSE);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcNdisReset(
|
||
IN PBINDING_CONTEXT pBindingContext,
|
||
IN PLLC_PACKET pPacket
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine issues a hardware reset command for a network adapter.
|
||
|
||
Arguments:
|
||
|
||
pBindingContext - context of protocol module bound to the data link
|
||
pPacket - command packet
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_CONTEXT pAdapterContext = pBindingContext->pAdapterContext;
|
||
BOOLEAN ResetIt;
|
||
NDIS_STATUS Status;
|
||
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
pPacket->pBinding = pBindingContext;
|
||
pPacket->Data.Completion.CompletedCommand = LLC_RESET_COMPLETION;
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
ResetIt = FALSE;
|
||
if (pAdapterContext->pResetPackets != NULL) {
|
||
ResetIt = TRUE;
|
||
}
|
||
pPacket->pNext = pAdapterContext->pResetPackets;
|
||
pAdapterContext->pResetPackets = pPacket;
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
//
|
||
// We don't reset NDIS, if there is already a pending reset command
|
||
//
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
|
||
if (ResetIt) {
|
||
NdisReset(&Status, pAdapterContext->NdisBindingHandle);
|
||
}
|
||
|
||
if (Status != STATUS_PENDING) {
|
||
LlcNdisResetComplete(pAdapterContext, Status);
|
||
}
|
||
|
||
//
|
||
// Note: we will return always a pending status =>
|
||
// multiple protocols may issue simultaneous reset
|
||
// and complete it normally.
|
||
//
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
}
|
||
|
||
|
||
VOID
|
||
LlcNdisResetComplete(
|
||
PADAPTER_CONTEXT pAdapterContext,
|
||
NDIS_STATUS NdisStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine is called when a hard reset command is complete.
|
||
|
||
Arguments:
|
||
|
||
pAdapterContext - describes adapter being reset
|
||
NdisStatus - result of adapter reset operation from NDIS
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLLC_PACKET pPacket;
|
||
|
||
//
|
||
// this function can be called from an NDIS DPC or from LlcNdisReset (above)
|
||
//
|
||
|
||
ASSUME_IRQL(ANY_IRQL);
|
||
|
||
ACQUIRE_DRIVER_LOCK();
|
||
|
||
//
|
||
// Indicate the completed reset command completion to all
|
||
// protocols, that had a pending reset command.
|
||
//
|
||
|
||
for (;;) {
|
||
|
||
ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
pPacket = pAdapterContext->pResetPackets;
|
||
if (pPacket != NULL) {
|
||
pAdapterContext->pResetPackets = pPacket->pNext;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
|
||
|
||
if (pPacket == NULL) {
|
||
break;
|
||
} else {
|
||
pPacket->Data.Completion.Status = NdisStatus;
|
||
pPacket->pBinding->pfCommandComplete(pPacket->pBinding->hClientContext,
|
||
NULL,
|
||
pPacket
|
||
);
|
||
}
|
||
}
|
||
|
||
RELEASE_DRIVER_LOCK();
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
UnicodeStringCompare(
|
||
IN PUNICODE_STRING String1,
|
||
IN PUNICODE_STRING String2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare 2 unicode strings. Difference between this and RtlEqualUnicodeString
|
||
is that this is callable from within spinlocks (i.e. non-pageable)
|
||
|
||
Arguments:
|
||
|
||
String1 - pointer to UNICODE_STRING 1
|
||
String2 - pointer to UNICODE_STRING 2
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN
|
||
TRUE - String1 == String2
|
||
FALSE - String1 != String2
|
||
|
||
--*/
|
||
|
||
{
|
||
if (String1->Length == String2->Length) {
|
||
|
||
USHORT numChars = String1->Length / sizeof(*String1->Buffer);
|
||
PWSTR buf1 = String1->Buffer;
|
||
PWSTR buf2 = String2->Buffer;
|
||
|
||
while (numChars) {
|
||
if (*buf1++ == *buf2++) {
|
||
--numChars;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
VOID
|
||
PurgeLlcEventQueue(
|
||
IN PBINDING_CONTEXT pBindingContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If there are any outstanding events on the adapter context waiting to be
|
||
indicated to the client of the current binding, they are removed
|
||
|
||
Arguments:
|
||
|
||
pBindingContext - pointer to BINDING_CONTEXT about to be deleted
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_CONTEXT pAdapterContext = pBindingContext->pAdapterContext;
|
||
ASSUME_IRQL(DISPATCH_LEVEL);
|
||
|
||
if (!IsListEmpty(&pAdapterContext->QueueEvents)) {
|
||
|
||
PEVENT_PACKET pEventPacket;
|
||
PEVENT_PACKET nextEventPacket;
|
||
|
||
for (pEventPacket = (PEVENT_PACKET)pAdapterContext->QueueEvents.Flink;
|
||
pEventPacket != (PEVENT_PACKET)&pAdapterContext->QueueEvents;
|
||
pEventPacket = nextEventPacket) {
|
||
|
||
nextEventPacket = pEventPacket->pNext;
|
||
if (pEventPacket->pBinding == pBindingContext) {
|
||
RemoveEntryList((PLIST_ENTRY)&pEventPacket->pNext);
|
||
|
||
#if DBG
|
||
DbgPrint("PurgeLlcEventQueue: BC=%x PKT=%x\n", pBindingContext, pEventPacket);
|
||
#endif
|
||
|
||
DEALLOCATE_PACKET_LLC_PKT(pAdapterContext->hPacketPool, pEventPacket);
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|