456 lines
12 KiB
C
456 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
device.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which implements the DEVICE object.
|
||
Routines are provided to reference, and dereference transport device
|
||
context objects.
|
||
|
||
The transport device context object is a structure which contains a
|
||
system-defined DEVICE_OBJECT followed by information which is maintained
|
||
by the transport provider, called the context.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,NbiCreateDevice)
|
||
#endif
|
||
|
||
|
||
VOID
|
||
NbiRefDevice(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on a device context.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to a transport device context object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
|
||
|
||
(VOID)InterlockedIncrement (&Device->ReferenceCount);
|
||
|
||
} /* NbiRefDevice */
|
||
|
||
|
||
VOID
|
||
NbiDerefDevice(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences a device context by decrementing the
|
||
reference count contained in the structure. Currently, we don't
|
||
do anything special when the reference count drops to zero, but
|
||
we could dynamically unload stuff then.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to a transport device context object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG result;
|
||
|
||
result = InterlockedDecrement (&Device->ReferenceCount);
|
||
|
||
CTEAssert (result >= 0);
|
||
|
||
if (result == 0) {
|
||
NbiDestroyDevice (Device);
|
||
}
|
||
|
||
} /* NbiDerefDevice */
|
||
|
||
|
||
NTSTATUS
|
||
NbiCreateDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING DeviceName,
|
||
IN OUT PDEVICE *DevicePtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates and initializes a device context structure.
|
||
|
||
Arguments:
|
||
|
||
|
||
DriverObject - pointer to the IO subsystem supplied driver object.
|
||
|
||
Device - Pointer to a pointer to a transport device context object.
|
||
|
||
DeviceName - pointer to the name of the device this device object points to.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE Device;
|
||
ULONG DeviceSize;
|
||
UINT i;
|
||
|
||
|
||
//
|
||
// Create the device object for the sample transport, allowing
|
||
// room at the end for the device name to be stored (for use
|
||
// in logging errors) and the RIP fields.
|
||
//
|
||
|
||
DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
|
||
DeviceName->Length + sizeof(UNICODE_NULL);
|
||
|
||
status = IoCreateDevice(
|
||
DriverObject,
|
||
DeviceSize,
|
||
DeviceName,
|
||
FILE_DEVICE_TRANSPORT,
|
||
FILE_DEVICE_SECURE_OPEN,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
NB_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
|
||
return status;
|
||
}
|
||
|
||
deviceObject->Flags |= DO_DIRECT_IO;
|
||
|
||
Device = (PDEVICE)deviceObject;
|
||
|
||
NB_DEBUG2 (DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer, Device));
|
||
|
||
//
|
||
// Initialize our part of the device context.
|
||
//
|
||
|
||
RtlZeroMemory(((PUCHAR)Device)+sizeof(DEVICE_OBJECT), sizeof(DEVICE)-sizeof(DEVICE_OBJECT));
|
||
|
||
//
|
||
// Copy over the device name.
|
||
//
|
||
Device->DeviceString.Length = DeviceName->Length;
|
||
Device->DeviceString.MaximumLength = DeviceName->Length + sizeof(WCHAR);
|
||
Device->DeviceString.Buffer = (PWCHAR)(Device+1);
|
||
|
||
RtlCopyMemory (Device->DeviceString.Buffer, DeviceName->Buffer, DeviceName->Length);
|
||
Device->DeviceString.Buffer[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||
|
||
//
|
||
// Initialize the reference count.
|
||
//
|
||
Device->ReferenceCount = 1;
|
||
#if DBG
|
||
Device->RefTypes[DREF_CREATE] = 1;
|
||
#endif
|
||
|
||
#if DBG
|
||
RtlCopyMemory(Device->Signature1, "NDC1", 4);
|
||
RtlCopyMemory(Device->Signature2, "NDC2", 4);
|
||
#endif
|
||
|
||
Device->Information.Version = 0x0100;
|
||
Device->Information.MaxSendSize = 65535;
|
||
Device->Information.MaxConnectionUserData = 0;
|
||
Device->Information.MaxDatagramSize = 500;
|
||
Device->Information.ServiceFlags =
|
||
TDI_SERVICE_CONNECTION_MODE | TDI_SERVICE_ERROR_FREE_DELIVERY |
|
||
TDI_SERVICE_MULTICAST_SUPPORTED | TDI_SERVICE_BROADCAST_SUPPORTED |
|
||
TDI_SERVICE_DELAYED_ACCEPTANCE | TDI_SERVICE_CONNECTIONLESS_MODE |
|
||
TDI_SERVICE_MESSAGE_MODE | TDI_SERVICE_FORCE_ACCESS_CHECK;
|
||
Device->Information.MinimumLookaheadData = 128;
|
||
Device->Information.MaximumLookaheadData = 1500;
|
||
Device->Information.NumberOfResources = 0;
|
||
KeQuerySystemTime (&Device->Information.StartTime);
|
||
|
||
Device->Statistics.Version = 0x0100;
|
||
Device->Statistics.MaximumSendWindow = 4;
|
||
Device->Statistics.AverageSendWindow = 4;
|
||
|
||
#ifdef _PNP_POWER_
|
||
Device->NetAddressRegistrationHandle = NULL; // We have not yet registered the Net Address
|
||
#endif // _PNP_POWER_
|
||
|
||
//
|
||
// Set this so we won't ignore the broadcast name.
|
||
//
|
||
|
||
Device->AddressCounts['*'] = 1;
|
||
|
||
//
|
||
// Initialize the resource that guards address ACLs.
|
||
//
|
||
|
||
ExInitializeResourceLite (&Device->AddressResource);
|
||
|
||
//
|
||
// initialize the various fields in the device context
|
||
//
|
||
|
||
CTEInitLock (&Device->Interlock.Lock);
|
||
CTEInitLock (&Device->Lock.Lock);
|
||
|
||
CTEInitTimer (&Device->FindNameTimer);
|
||
|
||
Device->ControlChannelIdentifier = 1;
|
||
|
||
InitializeListHead (&Device->GlobalSendPacketList);
|
||
InitializeListHead (&Device->GlobalReceivePacketList);
|
||
InitializeListHead (&Device->GlobalReceiveBufferList);
|
||
|
||
InitializeListHead (&Device->AddressDatabase);
|
||
#if defined(_PNP_POWER)
|
||
InitializeListHead (&Device->AdapterAddressDatabase);
|
||
#endif _PNP_POWER
|
||
|
||
InitializeListHead (&Device->WaitingFindNames);
|
||
|
||
InitializeListHead (&Device->WaitingConnects);
|
||
InitializeListHead (&Device->WaitingDatagrams);
|
||
|
||
InitializeListHead (&Device->WaitingAdapterStatus);
|
||
InitializeListHead (&Device->ActiveAdapterStatus);
|
||
|
||
InitializeListHead (&Device->WaitingNetbiosFindName);
|
||
|
||
InitializeListHead (&Device->ReceiveDatagrams);
|
||
InitializeListHead (&Device->ConnectIndicationInProgress);
|
||
|
||
InitializeListHead (&Device->ListenQueue);
|
||
|
||
InitializeListHead (&Device->ReceiveCompletionQueue);
|
||
|
||
InitializeListHead (&Device->WaitPacketConnections);
|
||
InitializeListHead (&Device->PacketizeConnections);
|
||
InitializeListHead (&Device->DataAckConnections);
|
||
|
||
Device->MemoryUsage = 0;
|
||
|
||
InitializeListHead (&Device->SendPoolList);
|
||
InitializeListHead (&Device->ReceivePoolList);
|
||
InitializeListHead (&Device->ReceiveBufferPoolList);
|
||
|
||
ExInitializeSListHead( &Device->SendPacketList );
|
||
ExInitializeSListHead( &Device->ReceivePacketList );
|
||
Device->ReceiveBufferList.Next = NULL;
|
||
|
||
for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
|
||
Device->ConnectionHash[i].Connections = NULL;
|
||
Device->ConnectionHash[i].ConnectionCount = 0;
|
||
Device->ConnectionHash[i].NextConnectionId = 1;
|
||
}
|
||
|
||
KeQuerySystemTime (&Device->NbiStartTime);
|
||
|
||
Device->State = DEVICE_STATE_CLOSED;
|
||
|
||
Device->Type = NB_DEVICE_SIGNATURE;
|
||
Device->Size = sizeof (DEVICE);
|
||
|
||
*DevicePtr = Device;
|
||
return STATUS_SUCCESS;
|
||
|
||
} /* NbiCreateDevice */
|
||
|
||
|
||
VOID
|
||
NbiDestroyDevice(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys a device context structure.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to a pointer to a transport device context object.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY p;
|
||
PNB_SEND_POOL SendPool;
|
||
PNB_SEND_PACKET SendPacket;
|
||
UINT SendPoolSize;
|
||
PNB_RECEIVE_POOL ReceivePool;
|
||
PNB_RECEIVE_PACKET ReceivePacket;
|
||
UINT ReceivePoolSize;
|
||
PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
|
||
PNB_RECEIVE_BUFFER ReceiveBuffer;
|
||
UINT ReceiveBufferPoolSize;
|
||
ULONG HeaderLength;
|
||
UINT i;
|
||
|
||
NB_DEBUG2 (DEVICE, ("Destroy device %lx\n", Device));
|
||
|
||
//
|
||
// Take all the connectionless packets out of its pools.
|
||
//
|
||
|
||
HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
|
||
|
||
SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
|
||
(sizeof(NB_SEND_PACKET) * Device->InitPackets) +
|
||
(HeaderLength * Device->InitPackets);
|
||
|
||
while (!IsListEmpty (&Device->SendPoolList)) {
|
||
|
||
p = RemoveHeadList (&Device->SendPoolList);
|
||
SendPool = CONTAINING_RECORD (p, NB_SEND_POOL, Linkage);
|
||
|
||
for (i = 0; i < SendPool->PacketCount; i++) {
|
||
|
||
SendPacket = &SendPool->Packets[i];
|
||
NbiDeinitializeSendPacket (Device, SendPacket, HeaderLength);
|
||
|
||
}
|
||
|
||
NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", SendPool));
|
||
|
||
#if !defined(NB_OWN_PACKETS)
|
||
NdisFreePacketPool(SendPool->PoolHandle);
|
||
#endif
|
||
|
||
NbiFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
|
||
}
|
||
|
||
|
||
ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
|
||
(sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
|
||
|
||
while (!IsListEmpty (&Device->ReceivePoolList)) {
|
||
|
||
p = RemoveHeadList (&Device->ReceivePoolList);
|
||
ReceivePool = CONTAINING_RECORD (p, NB_RECEIVE_POOL, Linkage);
|
||
|
||
for (i = 0; i < ReceivePool->PacketCount; i++) {
|
||
|
||
ReceivePacket = &ReceivePool->Packets[i];
|
||
NbiDeinitializeReceivePacket (Device, ReceivePacket);
|
||
|
||
}
|
||
|
||
NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", ReceivePool));
|
||
#if !defined(NB_OWN_PACKETS)
|
||
NdisFreePacketPool(ReceivePool->PoolHandle);
|
||
#endif
|
||
NbiFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
|
||
}
|
||
|
||
#if defined(_PNP_POWER)
|
||
NbiDestroyReceiveBufferPools( Device );
|
||
|
||
//
|
||
// Destroy adapter address list.
|
||
//
|
||
while(!IsListEmpty( &Device->AdapterAddressDatabase ) ){
|
||
PADAPTER_ADDRESS AdapterAddress;
|
||
AdapterAddress = CONTAINING_RECORD( Device->AdapterAddressDatabase.Flink, ADAPTER_ADDRESS, Linkage );
|
||
NbiDestroyAdapterAddress( AdapterAddress, NULL );
|
||
}
|
||
#else
|
||
ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
|
||
(sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
|
||
(Device->Bind.LineInfo.MaximumPacketSize * Device->InitPackets);
|
||
|
||
while (!IsListEmpty (&Device->ReceiveBufferPoolList)) {
|
||
|
||
p = RemoveHeadList (&Device->ReceiveBufferPoolList);
|
||
ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
|
||
|
||
for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
|
||
|
||
ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
|
||
NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
|
||
|
||
}
|
||
|
||
NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
|
||
NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
|
||
}
|
||
#endif _PNP_POWER
|
||
|
||
NB_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
|
||
|
||
#if DBG
|
||
for (i = 0; i < MEMORY_MAX; i++) {
|
||
if (NbiMemoryTag[i].BytesAllocated != 0) {
|
||
NB_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, NbiMemoryTag[i].BytesAllocated));
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// If we are being unloaded then someone is waiting for this
|
||
// event to finish the cleanup, since we may be at DISPATCH_LEVEL;
|
||
// otherwise it is during load and we can just kill ourselves here.
|
||
//
|
||
|
||
if (Device->UnloadWaiting) {
|
||
|
||
KeSetEvent(
|
||
&Device->UnloadEvent,
|
||
0L,
|
||
FALSE);
|
||
|
||
} else {
|
||
|
||
CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
||
ExDeleteResourceLite (&Device->AddressResource);
|
||
IoDeleteDevice ((PDEVICE_OBJECT)Device);
|
||
}
|
||
|
||
} /* NbiDestroyDevice */
|
||
|