3037 lines
84 KiB
C
3037 lines
84 KiB
C
/*++
|
||
|
||
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
nbfdrvr.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which defines the NetBIOS Frames Protocol
|
||
transport provider's device object.
|
||
|
||
Author:
|
||
|
||
David Beaver (dbeaver) 2-July-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// This is a list of all the device contexts that NBF owns,
|
||
// used while unloading.
|
||
//
|
||
|
||
LIST_ENTRY NbfDeviceList = {0,0}; // initialized for real at runtime.
|
||
|
||
//
|
||
// And a lock that protects the global list of NBF devices
|
||
//
|
||
FAST_MUTEX NbfDevicesLock;
|
||
|
||
//
|
||
// Global variables this is a copy of the path in the registry for
|
||
// configuration data.
|
||
//
|
||
|
||
UNICODE_STRING NbfRegistryPath;
|
||
|
||
//
|
||
// We need the driver object to create device context structures.
|
||
//
|
||
|
||
PDRIVER_OBJECT NbfDriverObject;
|
||
|
||
//
|
||
// A handle to be used in all provider notifications to TDI layer
|
||
//
|
||
HANDLE NbfProviderHandle;
|
||
|
||
//
|
||
// Global Configuration block for the driver ( no lock required )
|
||
//
|
||
PCONFIG_DATA NbfConfig = NULL;
|
||
|
||
#ifdef NBF_LOCKS // see spnlckdb.c
|
||
|
||
extern KSPIN_LOCK NbfGlobalLock;
|
||
|
||
#endif // def NBF_LOCKS
|
||
|
||
//
|
||
// The debugging longword, containing a bitmask as defined in NBFCONST.H.
|
||
// If a bit is set, then debugging is turned on for that component.
|
||
//
|
||
|
||
#if DBG
|
||
|
||
ULONG NbfDebug = 0;
|
||
BOOLEAN NbfDisconnectDebug;
|
||
|
||
NBF_SEND NbfSends[TRACK_TDI_LIMIT+1];
|
||
LONG NbfSendsNext;
|
||
|
||
NBF_SEND_COMPLETE NbfCompletedSends[TRACK_TDI_LIMIT+1];
|
||
LONG NbfCompletedSendsNext;
|
||
|
||
NBF_RECEIVE NbfReceives[TRACK_TDI_LIMIT+1];
|
||
LONG NbfReceivesNext;
|
||
|
||
NBF_RECEIVE_COMPLETE NbfCompletedReceives[TRACK_TDI_LIMIT+1];
|
||
LONG NbfCompletedReceivesNext=0;
|
||
|
||
PVOID * NbfConnectionTable;
|
||
PVOID * NbfRequestTable;
|
||
PVOID * NbfUiFrameTable;
|
||
PVOID * NbfSendPacketTable;
|
||
PVOID * NbfLinkTable;
|
||
PVOID * NbfAddressFileTable;
|
||
PVOID * NbfAddressTable;
|
||
|
||
|
||
LIST_ENTRY NbfGlobalRequestList;
|
||
LIST_ENTRY NbfGlobalLinkList;
|
||
LIST_ENTRY NbfGlobalConnectionList;
|
||
KSPIN_LOCK NbfGlobalInterlock;
|
||
KSPIN_LOCK NbfGlobalHistoryLock;
|
||
|
||
PVOID
|
||
TtdiSend ();
|
||
|
||
PVOID
|
||
TtdiReceive ();
|
||
|
||
PVOID
|
||
TtdiServer ();
|
||
|
||
KEVENT TdiSendEvent;
|
||
KEVENT TdiReceiveEvent;
|
||
KEVENT TdiServerEvent;
|
||
|
||
#endif
|
||
|
||
#if MAGIC
|
||
|
||
BOOLEAN NbfEnableMagic = FALSE; // Controls sending of magic bullets.
|
||
|
||
#endif // MAGIC
|
||
|
||
//
|
||
// This prevents us from having a bss section
|
||
//
|
||
|
||
ULONG _setjmpexused = 0;
|
||
|
||
//
|
||
// Forward declaration of various routines used in this module.
|
||
//
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
VOID
|
||
NbfUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
VOID
|
||
NbfFreeConfigurationInfo (
|
||
IN PCONFIG_DATA ConfigurationInfo
|
||
);
|
||
|
||
NTSTATUS
|
||
NbfDispatchOpenClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbfDispatchInternal(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbfDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbfDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
NbfDispatchPnPPower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
VOID
|
||
NbfDeallocateResources(
|
||
IN PDEVICE_CONTEXT DeviceContext
|
||
);
|
||
|
||
#ifdef RASAUTODIAL
|
||
VOID
|
||
NbfAcdBind();
|
||
|
||
VOID
|
||
NbfAcdUnbind();
|
||
#endif // RASAUTODIAL
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs initialization of the NetBIOS Frames Protocol
|
||
transport driver. It creates the device objects for the transport
|
||
provider and performs other driver initialization.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by the system.
|
||
|
||
RegistryPath - The name of NBF's node in the registry.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG j;
|
||
UNICODE_STRING nameString;
|
||
NTSTATUS status;
|
||
|
||
ASSERT (sizeof (SHORT) == 2);
|
||
|
||
#ifdef MEMPRINT
|
||
MemPrintInitialize ();
|
||
#endif
|
||
|
||
#ifdef NBF_LOCKS
|
||
KeInitializeSpinLock( &NbfGlobalLock );
|
||
#endif
|
||
|
||
#if DBG
|
||
InitializeListHead (&NbfGlobalRequestList);
|
||
InitializeListHead (&NbfGlobalLinkList);
|
||
InitializeListHead (&NbfGlobalConnectionList);
|
||
KeInitializeSpinLock (&NbfGlobalInterlock);
|
||
KeInitializeSpinLock (&NbfGlobalHistoryLock);
|
||
#endif
|
||
|
||
NbfRegistryPath = *RegistryPath;
|
||
NbfRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
|
||
RegistryPath->MaximumLength,
|
||
NBF_MEM_TAG_REGISTRY_PATH);
|
||
|
||
if (NbfRegistryPath.Buffer == NULL) {
|
||
PANIC(" Failed to allocate Registry Path!\n");
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
RtlCopyMemory(NbfRegistryPath.Buffer, RegistryPath->Buffer,
|
||
RegistryPath->MaximumLength);
|
||
NbfDriverObject = DriverObject;
|
||
RtlInitUnicodeString( &nameString, NBF_NAME);
|
||
|
||
|
||
//
|
||
// Initialize the driver object with this driver's entry points.
|
||
//
|
||
|
||
DriverObject->MajorFunction [IRP_MJ_CREATE] = NbfDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbfDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbfDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbfDispatchInternal;
|
||
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbfDispatch;
|
||
|
||
DriverObject->MajorFunction [IRP_MJ_PNP_POWER] = NbfDispatch;
|
||
|
||
DriverObject->DriverUnload = NbfUnload;
|
||
|
||
//
|
||
// Initialize the global list of devices.
|
||
// & the lock guarding this global list
|
||
//
|
||
|
||
InitializeListHead (&NbfDeviceList);
|
||
|
||
ExInitializeFastMutex (&NbfDevicesLock);
|
||
|
||
TdiInitialize();
|
||
|
||
status = NbfRegisterProtocol (&nameString);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// No configuration info read at startup when using PNP
|
||
//
|
||
|
||
ExFreePool(NbfRegistryPath.Buffer);
|
||
PANIC ("NbfInitialize: RegisterProtocol with NDIS failed!\n");
|
||
|
||
NbfWriteGeneralErrorLog(
|
||
(PVOID)DriverObject,
|
||
EVENT_TRANSPORT_REGISTER_FAILED,
|
||
607,
|
||
status,
|
||
NULL,
|
||
0,
|
||
NULL);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString( &nameString, NBF_DEVICE_NAME);
|
||
|
||
//
|
||
// Register as a provider with TDI
|
||
//
|
||
status = TdiRegisterProvider(
|
||
&nameString,
|
||
&NbfProviderHandle);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// Deregister with the NDIS layer as TDI registration failed
|
||
//
|
||
NbfDeregisterProtocol();
|
||
|
||
ExFreePool(NbfRegistryPath.Buffer);
|
||
PANIC ("NbfInitialize: RegisterProtocol with TDI failed!\n");
|
||
|
||
NbfWriteGeneralErrorLog(
|
||
(PVOID)DriverObject,
|
||
EVENT_TRANSPORT_REGISTER_FAILED,
|
||
607,
|
||
status,
|
||
NULL,
|
||
0,
|
||
NULL);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
return(status);
|
||
|
||
}
|
||
|
||
VOID
|
||
NbfUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unloads the NetBIOS Frames Protocol transport driver.
|
||
It unbinds from any NDIS drivers that are open and frees all resources
|
||
associated with the transport. The I/O system will not call us until
|
||
nobody above has NBF open.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by the system.
|
||
|
||
Return Value:
|
||
|
||
None. When the function returns, the driver is unloaded.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
PLIST_ENTRY p;
|
||
KIRQL oldIrql;
|
||
|
||
UNREFERENCED_PARAMETER (DriverObject);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint0 ("ENTER NbfUnload\n");
|
||
}
|
||
|
||
/*
|
||
|
||
#ifdef RASAUTODIAL
|
||
|
||
//
|
||
// Unbind from the automatic connection driver.
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint("Calling NbfAcdUnbind()\n");
|
||
#endif
|
||
|
||
NbfAcdUnbind();
|
||
#endif // RASAUTODIAL
|
||
|
||
*/
|
||
|
||
//
|
||
// Walk the list of device contexts.
|
||
//
|
||
|
||
ACQUIRE_DEVICES_LIST_LOCK();
|
||
|
||
while (!IsListEmpty (&NbfDeviceList)) {
|
||
|
||
// Remove an entry from list and reset its
|
||
// links (as we might try to remove from
|
||
// the list again - when ref goes to zero)
|
||
p = RemoveHeadList (&NbfDeviceList);
|
||
|
||
InitializeListHead(p);
|
||
|
||
DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
|
||
|
||
DeviceContext->State = DEVICECONTEXT_STATE_STOPPING;
|
||
|
||
// Remove creation ref if it has not already been removed
|
||
if (InterlockedExchange(&DeviceContext->CreateRefRemoved, TRUE) == FALSE) {
|
||
|
||
RELEASE_DEVICES_LIST_LOCK();
|
||
|
||
// Stop all internal timers
|
||
NbfStopTimerSystem(DeviceContext);
|
||
|
||
// Remove creation reference
|
||
NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
|
||
|
||
ACQUIRE_DEVICES_LIST_LOCK();
|
||
}
|
||
}
|
||
|
||
RELEASE_DEVICES_LIST_LOCK();
|
||
|
||
//
|
||
// Deregister from TDI layer as a network provider
|
||
//
|
||
TdiDeregisterProvider(NbfProviderHandle);
|
||
|
||
//
|
||
// Then remove ourselves as an NDIS protocol.
|
||
//
|
||
|
||
NbfDeregisterProtocol();
|
||
|
||
//
|
||
// Finally free any memory allocated for config info
|
||
//
|
||
if (NbfConfig != NULL) {
|
||
|
||
// Free configuration block
|
||
NbfFreeConfigurationInfo(NbfConfig);
|
||
|
||
#if DBG
|
||
// Free debugging tables
|
||
ExFreePool(NbfConnectionTable);
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Free memory allocated in DriverEntry for reg path
|
||
//
|
||
|
||
ExFreePool(NbfRegistryPath.Buffer);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint0 ("LEAVE NbfUnload\n");
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
NbfFreeResources (
|
||
IN PDEVICE_CONTEXT DeviceContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by NBF to clean up the data structures associated
|
||
with a given DeviceContext. When this routine exits, the DeviceContext
|
||
should be deleted as it no longer has any assocaited resources.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - Pointer to the DeviceContext we wish to clean up.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY p;
|
||
PSINGLE_LIST_ENTRY s;
|
||
PTP_PACKET packet;
|
||
PTP_UI_FRAME uiFrame;
|
||
PTP_ADDRESS address;
|
||
PTP_CONNECTION connection;
|
||
PTP_REQUEST request;
|
||
PTP_LINK link;
|
||
PTP_ADDRESS_FILE addressFile;
|
||
PNDIS_PACKET ndisPacket;
|
||
PBUFFER_TAG BufferTag;
|
||
KIRQL oldirql;
|
||
PNBF_POOL_LIST_DESC PacketPoolDescCurr;
|
||
PNBF_POOL_LIST_DESC PacketPoolDescNext;
|
||
|
||
//
|
||
// Clean up I-frame packet pool.
|
||
//
|
||
|
||
while ( DeviceContext->PacketPool.Next != NULL ) {
|
||
s = PopEntryList( &DeviceContext->PacketPool );
|
||
packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
|
||
|
||
NbfDeallocateSendPacket (DeviceContext, packet);
|
||
}
|
||
|
||
//
|
||
// Clean up RR-frame packet pool.
|
||
//
|
||
|
||
while ( DeviceContext->RrPacketPool.Next != NULL ) {
|
||
s = PopEntryList( &DeviceContext->RrPacketPool );
|
||
packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
|
||
|
||
NbfDeallocateSendPacket (DeviceContext, packet);
|
||
}
|
||
|
||
//
|
||
// Clean up UI frame pool.
|
||
//
|
||
|
||
while ( !IsListEmpty( &DeviceContext->UIFramePool ) ) {
|
||
p = RemoveHeadList( &DeviceContext->UIFramePool );
|
||
uiFrame = CONTAINING_RECORD (p, TP_UI_FRAME, Linkage );
|
||
|
||
NbfDeallocateUIFrame (DeviceContext, uiFrame);
|
||
}
|
||
|
||
//
|
||
// Clean up address pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
|
||
p = RemoveHeadList (&DeviceContext->AddressPool);
|
||
address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
|
||
|
||
NbfDeallocateAddress (DeviceContext, address);
|
||
}
|
||
|
||
//
|
||
// Clean up address file pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
|
||
p = RemoveHeadList (&DeviceContext->AddressFilePool);
|
||
addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
|
||
|
||
NbfDeallocateAddressFile (DeviceContext, addressFile);
|
||
}
|
||
|
||
//
|
||
// Clean up connection pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
|
||
p = RemoveHeadList (&DeviceContext->ConnectionPool);
|
||
connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
|
||
|
||
NbfDeallocateConnection (DeviceContext, connection);
|
||
}
|
||
|
||
//
|
||
// Clean up link pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->LinkPool) ) {
|
||
p = RemoveHeadList (&DeviceContext->LinkPool);
|
||
link = CONTAINING_RECORD (p, TP_LINK, Linkage);
|
||
|
||
NbfDeallocateLink (DeviceContext, link);
|
||
}
|
||
|
||
//
|
||
// Clean up request pool.
|
||
//
|
||
|
||
while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
|
||
p = RemoveHeadList( &DeviceContext->RequestPool );
|
||
request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
|
||
|
||
NbfDeallocateRequest (DeviceContext, request);
|
||
}
|
||
|
||
//
|
||
// Clean up receive packet pool
|
||
//
|
||
|
||
while ( DeviceContext->ReceivePacketPool.Next != NULL) {
|
||
s = PopEntryList (&DeviceContext->ReceivePacketPool);
|
||
|
||
//
|
||
// HACK: This works because Linkage is the first field in
|
||
// ProtocolReserved for a receive packet.
|
||
//
|
||
|
||
ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
NbfDeallocateReceivePacket (DeviceContext, ndisPacket);
|
||
}
|
||
|
||
|
||
//
|
||
// Clean up receive buffer pool.
|
||
//
|
||
|
||
while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
|
||
s = PopEntryList( &DeviceContext->ReceiveBufferPool );
|
||
BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
|
||
|
||
NbfDeallocateReceiveBuffer (DeviceContext, BufferTag);
|
||
}
|
||
|
||
//
|
||
// Now clean up all NDIS resources -
|
||
// packet pools, buffers and such
|
||
//
|
||
|
||
//
|
||
// Cleanup list of send packet pools
|
||
//
|
||
if (DeviceContext->SendPacketPoolDesc != NULL) {
|
||
|
||
ACQUIRE_SPIN_LOCK (&DeviceContext->SendPoolListLock, &oldirql);
|
||
for (PacketPoolDescCurr = DeviceContext->SendPacketPoolDesc;
|
||
PacketPoolDescCurr != NULL; ) {
|
||
|
||
if (PacketPoolDescCurr->PoolHandle != NULL) {
|
||
|
||
NdisFreePacketPool (PacketPoolDescCurr->PoolHandle);
|
||
DeviceContext->MemoryUsage -=
|
||
(PacketPoolDescCurr->TotalElements * (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG)));
|
||
}
|
||
|
||
PacketPoolDescNext = PacketPoolDescCurr->Next;
|
||
ExFreePool(PacketPoolDescCurr);
|
||
PacketPoolDescCurr = PacketPoolDescNext;
|
||
}
|
||
|
||
DeviceContext->SendPacketPoolDesc = NULL;
|
||
DeviceContext->SendPacketPoolSize = 0;
|
||
|
||
RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
|
||
}
|
||
|
||
//
|
||
// Cleanup list of receive packet pools
|
||
//
|
||
if (DeviceContext->ReceivePacketPoolDesc != NULL) {
|
||
|
||
ACQUIRE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, &oldirql);
|
||
for (PacketPoolDescCurr = DeviceContext->ReceivePacketPoolDesc;
|
||
PacketPoolDescCurr != NULL; ) {
|
||
|
||
if (PacketPoolDescCurr->PoolHandle != NULL) {
|
||
|
||
NdisFreePacketPool (PacketPoolDescCurr->PoolHandle);
|
||
DeviceContext->MemoryUsage -=
|
||
(PacketPoolDescCurr->TotalElements * (sizeof(NDIS_PACKET) + sizeof(RECEIVE_PACKET_TAG)));
|
||
}
|
||
|
||
PacketPoolDescNext = PacketPoolDescCurr->Next;
|
||
ExFreePool(PacketPoolDescCurr);
|
||
PacketPoolDescCurr = PacketPoolDescNext;
|
||
}
|
||
|
||
DeviceContext->ReceivePacketPoolDesc = NULL;
|
||
DeviceContext->ReceivePacketPoolSize = 0;
|
||
|
||
RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
|
||
}
|
||
|
||
//
|
||
// Cleanup list of ndis buffers
|
||
//
|
||
if (DeviceContext->NdisBufferPool != NULL) {
|
||
NdisFreeBufferPool (DeviceContext->NdisBufferPool);
|
||
DeviceContext->NdisBufferPool = NULL;
|
||
}
|
||
|
||
return;
|
||
|
||
} /* NbfFreeResources */
|
||
|
||
|
||
NTSTATUS
|
||
NbfDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the main dispatch routine for the NBF device driver.
|
||
It accepts an I/O Request Packet, performs the request, and then
|
||
returns with the appropriate status.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL DeviceControlIrp = FALSE;
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
|
||
ENTER_NBF;
|
||
|
||
//
|
||
// Check to see if NBF has been initialized; if not, don't allow any use.
|
||
// Note that this only covers any user mode code use; kernel TDI clients
|
||
// will fail on their creation of an endpoint.
|
||
//
|
||
|
||
try {
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
// Reference the device so that it does not go away from under us
|
||
NbfReferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
//
|
||
// Case on the function that is being performed by the requestor. If the
|
||
// operation is a valid one for this device, then make it look like it was
|
||
// successfully completed, where possible.
|
||
//
|
||
|
||
|
||
switch (IrpSp->MajorFunction) {
|
||
|
||
case IRP_MJ_DEVICE_CONTROL:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: IRP_MJ_DEVICE_CONTROL.\n");
|
||
}
|
||
|
||
DeviceControlIrp = TRUE;
|
||
|
||
Status = NbfDeviceControl (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
|
||
case IRP_MJ_PNP:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: IRP_MJ_PNP.\n");
|
||
}
|
||
|
||
Status = NbfDispatchPnPPower (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
|
||
}
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
} /* major function switch */
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
|
||
}
|
||
} else {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
|
||
}
|
||
|
||
//
|
||
// NbfDeviceControl would have completed this IRP already
|
||
//
|
||
|
||
if (!DeviceControlIrp)
|
||
{
|
||
LEAVE_NBF;
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
ENTER_NBF;
|
||
}
|
||
}
|
||
|
||
// Remove the temp use reference on device context added above
|
||
NbfDereferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
LEAVE_NBF;
|
||
return Status;
|
||
} /* NbfDispatch */
|
||
|
||
|
||
NTSTATUS
|
||
NbfDispatchOpenClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the main dispatch routine for the NBF device driver.
|
||
It accepts an I/O Request Packet, performs the request, and then
|
||
returns with the appropriate status.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldirql;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_FULL_EA_INFORMATION openType;
|
||
USHORT i;
|
||
BOOLEAN found;
|
||
PTP_ADDRESS_FILE AddressFile;
|
||
PTP_CONNECTION Connection;
|
||
|
||
ENTER_NBF;
|
||
|
||
//
|
||
// Check to see if NBF has been initialized; if not, don't allow any use.
|
||
// Note that this only covers any user mode code use; kernel TDI clients
|
||
// will fail on their creation of an endpoint.
|
||
//
|
||
|
||
try {
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
// Reference the device so that it does not go away from under us
|
||
NbfReferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
}
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
//
|
||
// Case on the function that is being performed by the requestor. If the
|
||
// operation is a valid one for this device, then make it look like it was
|
||
// successfully completed, where possible.
|
||
//
|
||
|
||
|
||
switch (IrpSp->MajorFunction) {
|
||
|
||
//
|
||
// The Create function opens a transport object (either address or
|
||
// connection). Access checking is performed on the specified
|
||
// address to ensure security of transport-layer addresses.
|
||
//
|
||
|
||
case IRP_MJ_CREATE:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: IRP_MJ_CREATE.\n");
|
||
}
|
||
|
||
openType =
|
||
(PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
if (openType != NULL) {
|
||
|
||
//
|
||
// Address?
|
||
//
|
||
|
||
found = TRUE;
|
||
|
||
if ((USHORT)openType->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH) {
|
||
for (i = 0; i < TDI_TRANSPORT_ADDRESS_LENGTH; i++) {
|
||
if (openType->EaName[i] != TdiTransportAddress[i]) {
|
||
found = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
found = FALSE;
|
||
}
|
||
|
||
if (found) {
|
||
Status = NbfOpenAddress (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Connection?
|
||
//
|
||
|
||
found = TRUE;
|
||
|
||
if ((USHORT)openType->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH) {
|
||
for (i = 0; i < TDI_CONNECTION_CONTEXT_LENGTH; i++) {
|
||
if (openType->EaName[i] != TdiConnectionContext[i]) {
|
||
found = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
found = FALSE;
|
||
}
|
||
|
||
if (found) {
|
||
Status = NbfOpenConnection (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
}
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint2 ("NbfDispatchOpenClose: IRP_MJ_CREATE on invalid type, len: %3d, name: %s\n",
|
||
(USHORT)openType->EaNameLength, openType->EaName);
|
||
}
|
||
|
||
} else {
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchOpenClose: IRP_MJ_CREATE on control channel!\n");
|
||
}
|
||
|
||
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
||
|
||
IrpSp->FileObject->FsContext = (PVOID)(DeviceContext->ControlChannelIdentifier);
|
||
++DeviceContext->ControlChannelIdentifier;
|
||
if (DeviceContext->ControlChannelIdentifier == 0) {
|
||
DeviceContext->ControlChannelIdentifier = 1;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
||
|
||
IrpSp->FileObject->FsContext2 = UlongToPtr(NBF_FILE_TYPE_CONTROL);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MJ_CLOSE:
|
||
|
||
//
|
||
// The Close function closes a transport endpoint, terminates
|
||
// all outstanding transport activity on the endpoint, and unbinds
|
||
// the endpoint from its transport address, if any. If this
|
||
// is the last transport endpoint bound to the address, then
|
||
// the address is removed from the provider.
|
||
//
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: IRP_MJ_CLOSE.\n");
|
||
}
|
||
|
||
switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
||
case TDI_TRANSPORT_ADDRESS_FILE:
|
||
AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
|
||
|
||
//
|
||
// This creates a reference to AddressFile->Address
|
||
// which is removed by NbfCloseAddress.
|
||
//
|
||
|
||
Status = NbfVerifyAddressObject(AddressFile);
|
||
|
||
if (!NT_SUCCESS (Status)) {
|
||
Status = STATUS_INVALID_HANDLE;
|
||
} else {
|
||
Status = NbfCloseAddress (DeviceObject, Irp, IrpSp);
|
||
}
|
||
|
||
break;
|
||
|
||
case TDI_CONNECTION_FILE:
|
||
|
||
//
|
||
// This is a connection
|
||
//
|
||
|
||
Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
|
||
Status = NbfVerifyConnectionObject (Connection);
|
||
if (NT_SUCCESS (Status)) {
|
||
|
||
Status = NbfCloseConnection (DeviceObject, Irp, IrpSp);
|
||
NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case NBF_FILE_TYPE_CONTROL:
|
||
|
||
//
|
||
// this always succeeds
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint1 ("NbfDispatch: IRP_MJ_CLOSE on unknown file type %lx.\n",
|
||
IrpSp->FileObject->FsContext2);
|
||
}
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MJ_CLEANUP:
|
||
|
||
//
|
||
// Handle the two stage IRP for a file close operation. When the first
|
||
// stage hits, run down all activity on the object of interest. This
|
||
// do everything to it but remove the creation hold. Then, when the
|
||
// CLOSE irp hits, actually close the object.
|
||
//
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: IRP_MJ_CLEANUP.\n");
|
||
}
|
||
|
||
switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
||
case TDI_TRANSPORT_ADDRESS_FILE:
|
||
AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
|
||
Status = NbfVerifyAddressObject(AddressFile);
|
||
if (!NT_SUCCESS (Status)) {
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
|
||
} else {
|
||
|
||
NbfStopAddressFile (AddressFile, AddressFile->Address);
|
||
NbfDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address, AREF_VERIFY);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case TDI_CONNECTION_FILE:
|
||
Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
Status = NbfVerifyConnectionObject (Connection);
|
||
if (NT_SUCCESS (Status)) {
|
||
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
||
NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
|
||
KeLowerIrql (oldirql);
|
||
Status = STATUS_SUCCESS;
|
||
NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
|
||
}
|
||
|
||
break;
|
||
|
||
case NBF_FILE_TYPE_CONTROL:
|
||
|
||
NbfStopControlChannel(
|
||
(PDEVICE_CONTEXT)DeviceObject,
|
||
(USHORT)IrpSp->FileObject->FsContext
|
||
);
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint1 ("NbfDispatch: IRP_MJ_CLEANUP on unknown file type %lx.\n",
|
||
IrpSp->FileObject->FsContext2);
|
||
}
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
|
||
}
|
||
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
} /* major function switch */
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
|
||
}
|
||
} else {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
|
||
}
|
||
|
||
LEAVE_NBF;
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
ENTER_NBF;
|
||
}
|
||
|
||
// Remove the temp use reference on device context added above
|
||
NbfDereferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
LEAVE_NBF;
|
||
return Status;
|
||
} /* NbfDispatchOpenClose */
|
||
|
||
|
||
NTSTATUS
|
||
NbfDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dispatches TDI request types to different handlers based
|
||
on the minor IOCTL function code in the IRP's current stack location.
|
||
In addition to cracking the minor function code, this routine also
|
||
reaches into the IRP and passes the packetized parameters stored there
|
||
as parameters to the various TDI request handlers so that they are
|
||
not IRP-dependent.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL InternalIrp = FALSE;
|
||
NTSTATUS Status;
|
||
PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDeviceControl: Entered.\n");
|
||
}
|
||
|
||
//
|
||
// Branch to the appropriate request handler. Preliminary checking of
|
||
// the size of the request block is performed here so that it is known
|
||
// in the handlers that the minimum input parameters are readable. It
|
||
// is *not* determined here whether variable length input fields are
|
||
// passed correctly;this is a check which must be made within each routine.
|
||
//
|
||
|
||
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
||
|
||
#if MAGIC
|
||
case IOCTL_TDI_MAGIC_BULLET:
|
||
|
||
//
|
||
// Special: send the magic bullet (to trigger the Sniffer).
|
||
//
|
||
|
||
NbfPrint1 ("NBF: Sending user MagicBullet on %lx\n", DeviceContext);
|
||
{
|
||
extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
|
||
NbfSendMagicBullet (DeviceContext, NULL);
|
||
}
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer != NULL) {
|
||
NbfPrint0 ("NBF: DbgBreakPoint after MagicBullet\n");
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
#endif
|
||
|
||
#if DBG
|
||
case IOCTL_TDI_SEND_TEST:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start send side test\n");
|
||
}
|
||
|
||
(VOID) KeSetEvent( &TdiSendEvent, 0, FALSE );
|
||
|
||
break;
|
||
|
||
case IOCTL_TDI_RECEIVE_TEST:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
|
||
}
|
||
|
||
(VOID) KeSetEvent( &TdiReceiveEvent, 0, FALSE );
|
||
|
||
break;
|
||
|
||
case IOCTL_TDI_SERVER_TEST:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
|
||
}
|
||
|
||
(VOID) KeSetEvent( &TdiServerEvent, 0, FALSE );
|
||
|
||
break;
|
||
#endif
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDeviceControl: invalid request type.\n");
|
||
}
|
||
|
||
//
|
||
// Convert the user call to the proper internal device call.
|
||
//
|
||
|
||
Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
|
||
//
|
||
// If TdiMapUserRequest returns SUCCESS then the IRP
|
||
// has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
|
||
// IRP, so we dispatch it as usual. The IRP will be
|
||
// completed by this call to NbfDispatchInternal, so we dont
|
||
//
|
||
|
||
InternalIrp = TRUE;
|
||
|
||
Status = NbfDispatchInternal (DeviceObject, Irp);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this IRP got converted to an internal IRP,
|
||
// it will be completed by NbfDispatchInternal.
|
||
//
|
||
|
||
if ((!InternalIrp) && (Status != STATUS_PENDING))
|
||
{
|
||
LEAVE_NBF;
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
ENTER_NBF;
|
||
}
|
||
|
||
return Status;
|
||
} /* NbfDeviceControl */
|
||
|
||
NTSTATUS
|
||
NbfDispatchPnPPower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dispatches PnP request types to different handlers based
|
||
on the minor IOCTL function code in the IRP's current stack location.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_RELATIONS DeviceRelations = NULL;
|
||
PTP_CONNECTION Connection;
|
||
PVOID PnPContext;
|
||
NTSTATUS Status;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchPnPPower: Entered.\n");
|
||
}
|
||
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
switch (IrpSp->MinorFunction) {
|
||
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||
|
||
if (IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation){
|
||
|
||
switch (PtrToUlong(IrpSp->FileObject->FsContext2))
|
||
{
|
||
case TDI_CONNECTION_FILE:
|
||
|
||
// Get the connection object and verify
|
||
Connection = IrpSp->FileObject->FsContext;
|
||
|
||
//
|
||
// This adds a connection reference of type BY_ID if successful.
|
||
//
|
||
|
||
Status = NbfVerifyConnectionObject (Connection);
|
||
|
||
if (NT_SUCCESS (Status)) {
|
||
|
||
//
|
||
// Get the PDO associated with conn's device object
|
||
//
|
||
|
||
PnPContext = Connection->Provider->PnPContext;
|
||
if (PnPContext) {
|
||
|
||
DeviceRelations =
|
||
ExAllocatePoolWithTag(NonPagedPool,
|
||
sizeof(DEVICE_RELATIONS),
|
||
NBF_MEM_TAG_DEVICE_PDO);
|
||
if (DeviceRelations) {
|
||
|
||
//
|
||
// TargetDeviceRelation allows exactly 1 PDO. fill it.
|
||
//
|
||
DeviceRelations->Count = 1;
|
||
DeviceRelations->Objects[0] = PnPContext;
|
||
ObReferenceObject(PnPContext);
|
||
|
||
} else {
|
||
Status = STATUS_NO_MEMORY;
|
||
}
|
||
} else {
|
||
Status = STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
NbfDereferenceConnection ("Temp Rel", Connection, CREF_BY_ID);
|
||
}
|
||
break;
|
||
|
||
case TDI_TRANSPORT_ADDRESS_FILE:
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Invoker of this irp will free the information buffer.
|
||
//
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
Irp->IoStatus.Information = (ULONG_PTR) DeviceRelations;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint1 ("NbfDispatchPnPPower: exiting, status: %lx\n",Status);
|
||
}
|
||
|
||
return Status;
|
||
} /* NbfDispatchPnPPower */
|
||
|
||
|
||
NTSTATUS
|
||
NbfDispatchInternal (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dispatches TDI request types to different handlers based
|
||
on the minor IOCTL function code in the IRP's current stack location.
|
||
In addition to cracking the minor function code, this routine also
|
||
reaches into the IRP and passes the packetized parameters stored there
|
||
as parameters to the various TDI request handlers so that they are
|
||
not IRP-dependent.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
#if DBG
|
||
KIRQL IrqlOnEnter = KeGetCurrentIrql();
|
||
#endif
|
||
|
||
ENTER_NBF;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfInternalDeviceControl: Entered.\n");
|
||
}
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
|
||
try {
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
// Reference the device so that it does not go away from under us
|
||
NbfReferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
LEAVE_NBF;
|
||
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
}
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
{
|
||
PULONG Temp=(PULONG)&IrpSp->Parameters;
|
||
NbfPrint5 ("Got IrpSp %lx %lx %lx %lx %lx\n", Temp++, Temp++,
|
||
Temp++, Temp++, Temp++);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Branch to the appropriate request handler. Preliminary checking of
|
||
// the size of the request block is performed here so that it is known
|
||
// in the handlers that the minimum input parameters are readable. It
|
||
// is *not* determined here whether variable length input fields are
|
||
// passed correctly; this is a check which must be made within each routine.
|
||
//
|
||
|
||
switch (IrpSp->MinorFunction) {
|
||
|
||
case TDI_ACCEPT:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
|
||
}
|
||
|
||
Status = NbfTdiAccept (Irp);
|
||
break;
|
||
|
||
case TDI_ACTION:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiAction request.\n");
|
||
}
|
||
|
||
Status = NbfTdiAction (DeviceContext, Irp);
|
||
break;
|
||
|
||
case TDI_ASSOCIATE_ADDRESS:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
|
||
}
|
||
|
||
Status = NbfTdiAssociateAddress (Irp);
|
||
break;
|
||
|
||
case TDI_DISASSOCIATE_ADDRESS:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiDisassociateAddress request.\n");
|
||
}
|
||
|
||
Status = NbfTdiDisassociateAddress (Irp);
|
||
break;
|
||
|
||
case TDI_CONNECT:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiConnect request\n");
|
||
}
|
||
|
||
Status = NbfTdiConnect (Irp);
|
||
|
||
break;
|
||
|
||
case TDI_DISCONNECT:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiDisconnect request.\n");
|
||
}
|
||
|
||
Status = NbfTdiDisconnect (Irp);
|
||
break;
|
||
|
||
case TDI_LISTEN:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiListen request.\n");
|
||
}
|
||
|
||
Status = NbfTdiListen (Irp);
|
||
break;
|
||
|
||
case TDI_QUERY_INFORMATION:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiQueryInformation request.\n");
|
||
}
|
||
|
||
Status = NbfTdiQueryInformation (DeviceContext, Irp);
|
||
break;
|
||
|
||
case TDI_RECEIVE:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiReceive request.\n");
|
||
}
|
||
|
||
Status = NbfTdiReceive (Irp);
|
||
break;
|
||
|
||
case TDI_RECEIVE_DATAGRAM:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiReceiveDatagram request.\n");
|
||
}
|
||
|
||
Status = NbfTdiReceiveDatagram (Irp);
|
||
break;
|
||
|
||
case TDI_SEND:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiSend request.\n");
|
||
}
|
||
|
||
Status = NbfTdiSend (Irp);
|
||
break;
|
||
|
||
case TDI_SEND_DATAGRAM:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiSendDatagram request.\n");
|
||
}
|
||
|
||
Status = NbfTdiSendDatagram (Irp);
|
||
break;
|
||
|
||
case TDI_SET_EVENT_HANDLER:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiSetEventHandler request.\n");
|
||
}
|
||
|
||
//
|
||
// Because this request will enable direct callouts from the
|
||
// transport provider at DISPATCH_LEVEL to a client-specified
|
||
// routine, this request is only valid in kernel mode, denying
|
||
// access to this request in user mode.
|
||
//
|
||
|
||
Status = NbfTdiSetEventHandler (Irp);
|
||
break;
|
||
|
||
case TDI_SET_INFORMATION:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: TdiSetInformation request.\n");
|
||
}
|
||
|
||
Status = NbfTdiSetInformation (Irp);
|
||
break;
|
||
|
||
#if DBG
|
||
case 0x7f:
|
||
|
||
//
|
||
// Special: send the magic bullet (to trigger the Sniffer).
|
||
//
|
||
|
||
NbfPrint1 ("NBF: Sending MagicBullet on %lx\n", DeviceContext);
|
||
{
|
||
extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
|
||
NbfSendMagicBullet (DeviceContext, NULL);
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
#endif
|
||
|
||
//
|
||
// Something we don't know about was submitted.
|
||
//
|
||
|
||
default:
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint1 ("NbfDispatchInternal: invalid request type %lx\n",
|
||
IrpSp->MinorFunction);
|
||
}
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: request PENDING from handler.\n");
|
||
}
|
||
} else {
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint0 ("NbfDispatchInternal: request COMPLETED by handler.\n");
|
||
}
|
||
|
||
LEAVE_NBF;
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
ENTER_NBF;
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DISPATCH) {
|
||
NbfPrint1 ("NbfDispatchInternal: exiting, status: %lx\n",Status);
|
||
}
|
||
|
||
// Remove the temp use reference on device context added above
|
||
NbfDereferenceDeviceContext ("Temp Use Ref", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
LEAVE_NBF;
|
||
#if DBG
|
||
ASSERT (KeGetCurrentIrql() == IrqlOnEnter);
|
||
#endif
|
||
|
||
return Status;
|
||
|
||
} /* NbfDispatchInternal */
|
||
|
||
|
||
VOID
|
||
NbfWriteResourceErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN NTSTATUS ErrorCode,
|
||
IN ULONG UniqueErrorValue,
|
||
IN ULONG BytesNeeded,
|
||
IN ULONG ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and writes an error log entry indicating
|
||
an out of resources condition. It will handle event codes
|
||
RESOURCE_POOL, RESOURCE_LIMIT, and RESOURCE_SPECIFIC.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - Pointer to the device context.
|
||
|
||
ErrorCode - The transport event code.
|
||
|
||
UniqueErrorValue - Used as the UniqueErrorValue in the error log
|
||
packet.
|
||
|
||
BytesNeeded - If applicable, the number of bytes that could not
|
||
be allocated.
|
||
|
||
ResourceId - The resource ID of the allocated structure.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
UCHAR EntrySize;
|
||
PWSTR SecondString;
|
||
ULONG SecondStringSize;
|
||
PUCHAR StringLoc;
|
||
WCHAR ResourceIdBuffer[3];
|
||
WCHAR SizeBuffer[2];
|
||
WCHAR SpecificMaxBuffer[11];
|
||
ULONG SpecificMax;
|
||
INT i;
|
||
|
||
switch (ErrorCode) {
|
||
|
||
case EVENT_TRANSPORT_RESOURCE_POOL:
|
||
SecondString = NULL;
|
||
SecondStringSize = 0;
|
||
break;
|
||
|
||
case EVENT_TRANSPORT_RESOURCE_LIMIT:
|
||
SecondString = SizeBuffer;
|
||
SecondStringSize = sizeof(SizeBuffer);
|
||
|
||
switch (DeviceContext->MemoryLimit) {
|
||
case 100000: SizeBuffer[0] = L'1'; break;
|
||
case 250000: SizeBuffer[0] = L'2'; break;
|
||
case 0: SizeBuffer[0] = L'3'; break;
|
||
default: SizeBuffer[0] = L'0'; break;
|
||
}
|
||
SizeBuffer[1] = 0;
|
||
break;
|
||
|
||
case EVENT_TRANSPORT_RESOURCE_SPECIFIC:
|
||
switch (ResourceId) {
|
||
case UI_FRAME_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
|
||
case PACKET_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
|
||
case RECEIVE_PACKET_RESOURCE_ID: SpecificMax = DeviceContext->ReceivePacketPoolSize; break;
|
||
case RECEIVE_BUFFER_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize+DeviceContext->ReceivePacketPoolSize; break;
|
||
case ADDRESS_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddresses; break;
|
||
case ADDRESS_FILE_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddressFiles; break;
|
||
case CONNECTION_RESOURCE_ID: SpecificMax = DeviceContext->MaxConnections; break;
|
||
case LINK_RESOURCE_ID: SpecificMax = DeviceContext->MaxLinks; break;
|
||
case REQUEST_RESOURCE_ID: SpecificMax = DeviceContext->MaxRequests; break;
|
||
}
|
||
|
||
for (i=9; i>=0; i--) {
|
||
SpecificMaxBuffer[i] = (WCHAR)((SpecificMax % 10) + L'0');
|
||
SpecificMax /= 10;
|
||
if (SpecificMax == 0) {
|
||
break;
|
||
}
|
||
}
|
||
SecondString = SpecificMaxBuffer + i;
|
||
SecondStringSize = sizeof(SpecificMaxBuffer) - (i * sizeof(WCHAR));
|
||
SpecificMaxBuffer[10] = 0;
|
||
break;
|
||
|
||
default:
|
||
ASSERT (FALSE);
|
||
SecondString = NULL;
|
||
SecondStringSize = 0;
|
||
break;
|
||
}
|
||
|
||
EntrySize = (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
|
||
DeviceContext->DeviceNameLength +
|
||
sizeof(ResourceIdBuffer) +
|
||
SecondStringSize);
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
(PDEVICE_OBJECT)DeviceContext,
|
||
EntrySize
|
||
);
|
||
|
||
//
|
||
// Convert the resource ID into a buffer.
|
||
//
|
||
|
||
ResourceIdBuffer[1] = (WCHAR)((ResourceId % 10) + L'0');
|
||
ResourceId /= 10;
|
||
ASSERT(ResourceId <= 9);
|
||
ResourceIdBuffer[0] = (WCHAR)((ResourceId % 10) + L'0');
|
||
ResourceIdBuffer[2] = 0;
|
||
|
||
if (errorLogEntry != NULL) {
|
||
|
||
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
|
||
errorLogEntry->RetryCount = (UCHAR)-1;
|
||
errorLogEntry->DumpDataSize = sizeof(ULONG);
|
||
errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 2 : 3;
|
||
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
|
||
errorLogEntry->EventCategory = 0;
|
||
errorLogEntry->ErrorCode = ErrorCode;
|
||
errorLogEntry->UniqueErrorValue = 0;
|
||
errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
errorLogEntry->SequenceNumber = (ULONG)-1;
|
||
errorLogEntry->IoControlCode = 0;
|
||
errorLogEntry->DumpData[0] = BytesNeeded;
|
||
|
||
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
|
||
RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
|
||
RtlCopyMemory (StringLoc, ResourceIdBuffer, sizeof(ResourceIdBuffer));
|
||
StringLoc += sizeof(ResourceIdBuffer);
|
||
|
||
if (SecondString) {
|
||
RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
|
||
}
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
} /* NbfWriteResourceErrorLog */
|
||
|
||
|
||
VOID
|
||
NbfWriteGeneralErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN NTSTATUS ErrorCode,
|
||
IN ULONG UniqueErrorValue,
|
||
IN NTSTATUS FinalStatus,
|
||
IN PWSTR SecondString,
|
||
IN ULONG DumpDataCount,
|
||
IN ULONG DumpData[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and writes an error log entry indicating
|
||
a general problem as indicated by the parameters. It handles
|
||
event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
|
||
TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
|
||
events have messages with one or two strings in them.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - Pointer to the device context, or this may be
|
||
a driver object instead.
|
||
|
||
ErrorCode - The transport event code.
|
||
|
||
UniqueErrorValue - Used as the UniqueErrorValue in the error log
|
||
packet.
|
||
|
||
FinalStatus - Used as the FinalStatus in the error log packet.
|
||
|
||
SecondString - If not NULL, the string to use as the %3
|
||
value in the error log packet.
|
||
|
||
DumpDataCount - The number of ULONGs of dump data.
|
||
|
||
DumpData - Dump data for the packet.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
UCHAR EntrySize;
|
||
ULONG SecondStringSize;
|
||
PUCHAR StringLoc;
|
||
PWSTR DriverName;
|
||
|
||
EntrySize = (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
|
||
(DumpDataCount * sizeof(ULONG)));
|
||
|
||
if (DeviceContext->Type == IO_TYPE_DEVICE) {
|
||
EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
|
||
} else {
|
||
DriverName = L"Nbf";
|
||
EntrySize += 4 * sizeof(WCHAR);
|
||
}
|
||
|
||
if (SecondString) {
|
||
SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
|
||
EntrySize += (UCHAR)SecondStringSize;
|
||
}
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
(PDEVICE_OBJECT)DeviceContext,
|
||
EntrySize
|
||
);
|
||
|
||
if (errorLogEntry != NULL) {
|
||
|
||
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
|
||
errorLogEntry->RetryCount = (UCHAR)-1;
|
||
errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
|
||
errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
|
||
errorLogEntry->StringOffset =
|
||
(USHORT)(sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG)));
|
||
errorLogEntry->EventCategory = 0;
|
||
errorLogEntry->ErrorCode = ErrorCode;
|
||
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
||
errorLogEntry->FinalStatus = FinalStatus;
|
||
errorLogEntry->SequenceNumber = (ULONG)-1;
|
||
errorLogEntry->IoControlCode = 0;
|
||
|
||
if (DumpDataCount) {
|
||
RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
|
||
}
|
||
|
||
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
|
||
if (DeviceContext->Type == IO_TYPE_DEVICE) {
|
||
RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
} else {
|
||
RtlCopyMemory (StringLoc, DriverName, 4 * sizeof(WCHAR));
|
||
StringLoc += 4 * sizeof(WCHAR);
|
||
}
|
||
if (SecondString) {
|
||
RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
|
||
}
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
} /* NbfWriteGeneralErrorLog */
|
||
|
||
|
||
VOID
|
||
NbfWriteOidErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN NTSTATUS ErrorCode,
|
||
IN NTSTATUS FinalStatus,
|
||
IN PWSTR AdapterString,
|
||
IN ULONG OidValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and writes an error log entry indicating
|
||
a problem querying or setting an OID on an adapter. It handles
|
||
event codes SET_OID_FAILED and QUERY_OID_FAILED.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - Pointer to the device context.
|
||
|
||
ErrorCode - Used as the ErrorCode in the error log packet.
|
||
|
||
FinalStatus - Used as the FinalStatus in the error log packet.
|
||
|
||
AdapterString - The name of the adapter we were bound to.
|
||
|
||
OidValue - The OID which could not be set or queried.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
ULONG EntrySize;
|
||
PUCHAR StringLoc;
|
||
WCHAR OidBuffer[9];
|
||
INT i;
|
||
UINT CurrentDigit;
|
||
|
||
EntrySize = (sizeof(IO_ERROR_LOG_PACKET) -
|
||
sizeof(ULONG) +
|
||
DeviceContext->DeviceNameLength +
|
||
sizeof(OidBuffer));
|
||
|
||
if (EntrySize > ERROR_LOG_LIMIT_SIZE) {
|
||
return;
|
||
}
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
(PDEVICE_OBJECT)DeviceContext,
|
||
(UCHAR) EntrySize
|
||
);
|
||
|
||
//
|
||
// Convert the OID into a buffer.
|
||
//
|
||
|
||
for (i=7; i>=0; i--) {
|
||
CurrentDigit = OidValue & 0xf;
|
||
OidValue >>= 4;
|
||
if (CurrentDigit >= 0xa) {
|
||
OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
|
||
} else {
|
||
OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
|
||
}
|
||
}
|
||
OidBuffer[8] = 0;
|
||
|
||
if (errorLogEntry != NULL) {
|
||
|
||
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
|
||
errorLogEntry->RetryCount = (UCHAR)-1;
|
||
errorLogEntry->DumpDataSize = 0;
|
||
errorLogEntry->NumberOfStrings = 3;
|
||
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
|
||
errorLogEntry->EventCategory = 0;
|
||
errorLogEntry->ErrorCode = ErrorCode;
|
||
errorLogEntry->UniqueErrorValue = 0;
|
||
errorLogEntry->FinalStatus = FinalStatus;
|
||
errorLogEntry->SequenceNumber = (ULONG)-1;
|
||
errorLogEntry->IoControlCode = 0;
|
||
|
||
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
|
||
RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
|
||
RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
}
|
||
|
||
} /* NbfWriteOidErrorLog */
|
||
|
||
ULONG
|
||
NbfInitializeOneDeviceContext(
|
||
OUT PNDIS_STATUS NdisStatus,
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PCONFIG_DATA NbfConfig,
|
||
IN PUNICODE_STRING BindName,
|
||
IN PUNICODE_STRING ExportName,
|
||
IN PVOID SystemSpecific1,
|
||
IN PVOID SystemSpecific2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates and initializes one nbf device context. In order to
|
||
do this it must successfully open and bind to the adapter described by
|
||
nbfconfig->names[adapterindex].
|
||
|
||
Arguments:
|
||
|
||
NdisStatus - The outputted status of the operations.
|
||
|
||
DriverObject - the nbf driver object.
|
||
|
||
NbfConfig - the transport configuration information from the registry.
|
||
|
||
SystemSpecific1 - SystemSpecific1 argument to ProtocolBindAdapter
|
||
|
||
SystemSpecific2 - SystemSpecific2 argument to ProtocolBindAdapter
|
||
|
||
Return Value:
|
||
|
||
The number of successful binds.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
PTP_REQUEST Request;
|
||
PTP_LINK Link;
|
||
PTP_CONNECTION Connection;
|
||
PTP_ADDRESS_FILE AddressFile;
|
||
PTP_ADDRESS Address;
|
||
PTP_UI_FRAME UIFrame;
|
||
PTP_PACKET Packet;
|
||
PNDIS_PACKET NdisPacket;
|
||
PRECEIVE_PACKET_TAG ReceiveTag;
|
||
PBUFFER_TAG BufferTag;
|
||
KIRQL oldIrql;
|
||
NTSTATUS status;
|
||
UINT MaxUserData;
|
||
ULONG InitReceivePackets;
|
||
BOOLEAN UniProcessor;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
UNICODE_STRING DeviceString;
|
||
UCHAR PermAddr[sizeof(TA_ADDRESS)+TDI_ADDRESS_LENGTH_NETBIOS];
|
||
PTA_ADDRESS pAddress = (PTA_ADDRESS)PermAddr;
|
||
PTDI_ADDRESS_NETBIOS NetBIOSAddress =
|
||
(PTDI_ADDRESS_NETBIOS)pAddress->Address;
|
||
struct {
|
||
TDI_PNP_CONTEXT tdiPnPContextHeader;
|
||
PVOID tdiPnPContextTrailer;
|
||
} tdiPnPContext1, tdiPnPContext2;
|
||
|
||
pAddress->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
||
pAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
NetBIOSAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
|
||
//
|
||
// Determine if we are on a uniprocessor.
|
||
//
|
||
|
||
if (KeNumberProcessors == 1) {
|
||
UniProcessor = TRUE;
|
||
} else {
|
||
UniProcessor = FALSE;
|
||
}
|
||
|
||
//
|
||
// Loop through all the adapters that are in the configuration
|
||
// information structure. Allocate a device object for each
|
||
// one that we find.
|
||
//
|
||
|
||
status = NbfCreateDeviceContext(
|
||
DriverObject,
|
||
ExportName,
|
||
&DeviceContext
|
||
);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint2 ("NbfCreateDeviceContext for %S returned error %08x\n",
|
||
ExportName->Buffer, status);
|
||
}
|
||
|
||
//
|
||
// First check if we already have an object with this name
|
||
// This is because a previous unbind was not done properly.
|
||
//
|
||
|
||
if (status == STATUS_OBJECT_NAME_COLLISION) {
|
||
|
||
// See if we can reuse the binding and device name
|
||
|
||
NbfReInitializeDeviceContext(
|
||
&status,
|
||
DriverObject,
|
||
NbfConfig,
|
||
BindName,
|
||
ExportName,
|
||
SystemSpecific1,
|
||
SystemSpecific2
|
||
);
|
||
|
||
if (status == STATUS_NOT_FOUND)
|
||
{
|
||
// Must have got deleted in the meantime
|
||
|
||
return NbfInitializeOneDeviceContext(
|
||
NdisStatus,
|
||
DriverObject,
|
||
NbfConfig,
|
||
BindName,
|
||
ExportName,
|
||
SystemSpecific1,
|
||
SystemSpecific2
|
||
);
|
||
}
|
||
}
|
||
|
||
*NdisStatus = status;
|
||
|
||
if (!NT_SUCCESS (status))
|
||
{
|
||
NbfWriteGeneralErrorLog(
|
||
(PVOID)DriverObject,
|
||
EVENT_TRANSPORT_BINDING_FAILED,
|
||
707,
|
||
status,
|
||
BindName->Buffer,
|
||
0,
|
||
NULL);
|
||
|
||
return(0);
|
||
}
|
||
|
||
return(1);
|
||
}
|
||
|
||
DeviceContext->UniProcessor = UniProcessor;
|
||
|
||
//
|
||
// Initialize the timer and retry values (note that the link timeouts
|
||
// are converted from NT ticks to NBF ticks). These values may
|
||
// be modified by NbfInitializeNdis.
|
||
//
|
||
DeviceContext->MinimumT1Timeout = NbfConfig->MinimumT1Timeout / SHORT_TIMER_DELTA;
|
||
DeviceContext->DefaultT1Timeout = NbfConfig->DefaultT1Timeout / SHORT_TIMER_DELTA;
|
||
DeviceContext->DefaultT2Timeout = NbfConfig->DefaultT2Timeout / SHORT_TIMER_DELTA;
|
||
DeviceContext->DefaultTiTimeout = NbfConfig->DefaultTiTimeout / LONG_TIMER_DELTA;
|
||
DeviceContext->LlcRetries = NbfConfig->LlcRetries;
|
||
DeviceContext->LlcMaxWindowSize = NbfConfig->LlcMaxWindowSize;
|
||
DeviceContext->MaxConsecutiveIFrames = (UCHAR)NbfConfig->MaximumIncomingFrames;
|
||
DeviceContext->NameQueryRetries = NbfConfig->NameQueryRetries;
|
||
DeviceContext->NameQueryTimeout = NbfConfig->NameQueryTimeout;
|
||
DeviceContext->AddNameQueryRetries = NbfConfig->AddNameQueryRetries;
|
||
DeviceContext->AddNameQueryTimeout = NbfConfig->AddNameQueryTimeout;
|
||
DeviceContext->GeneralRetries = NbfConfig->GeneralRetries;
|
||
DeviceContext->GeneralTimeout = NbfConfig->GeneralTimeout;
|
||
DeviceContext->MinimumSendWindowLimit = NbfConfig->MinimumSendWindowLimit;
|
||
|
||
//
|
||
// Initialize our counter that records memory usage.
|
||
//
|
||
|
||
DeviceContext->MemoryUsage = 0;
|
||
DeviceContext->MemoryLimit = NbfConfig->MaxMemoryUsage;
|
||
|
||
DeviceContext->MaxRequests = NbfConfig->MaxRequests;
|
||
DeviceContext->MaxLinks = NbfConfig->MaxLinks;
|
||
DeviceContext->MaxConnections = NbfConfig->MaxConnections;
|
||
DeviceContext->MaxAddressFiles = NbfConfig->MaxAddressFiles;
|
||
DeviceContext->MaxAddresses = NbfConfig->MaxAddresses;
|
||
|
||
//
|
||
// Now fire up NDIS so this adapter talks
|
||
//
|
||
|
||
status = NbfInitializeNdis (DeviceContext,
|
||
NbfConfig,
|
||
BindName);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// Log an error if we were failed to
|
||
// open this adapter.
|
||
//
|
||
|
||
NbfWriteGeneralErrorLog(
|
||
DeviceContext,
|
||
EVENT_TRANSPORT_BINDING_FAILED,
|
||
601,
|
||
status,
|
||
BindName->Buffer,
|
||
0,
|
||
NULL);
|
||
|
||
if (InterlockedExchange(&DeviceContext->CreateRefRemoved, TRUE) == FALSE) {
|
||
NbfDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext, DCREF_CREATION);
|
||
}
|
||
|
||
*NdisStatus = status;
|
||
return(0);
|
||
|
||
}
|
||
|
||
#if 0
|
||
DbgPrint("Opened %S as %S\n", &NbfConfig->Names[j], &nameString);
|
||
#endif
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint6 ("NbfInitialize: NDIS returned: %x %x %x %x %x %x as local address.\n",
|
||
DeviceContext->LocalAddress.Address[0],
|
||
DeviceContext->LocalAddress.Address[1],
|
||
DeviceContext->LocalAddress.Address[2],
|
||
DeviceContext->LocalAddress.Address[3],
|
||
DeviceContext->LocalAddress.Address[4],
|
||
DeviceContext->LocalAddress.Address[5]);
|
||
}
|
||
|
||
//
|
||
// Initialize our provider information structure; since it
|
||
// doesn't change, we just keep it around and copy it to
|
||
// whoever requests it.
|
||
//
|
||
|
||
|
||
MacReturnMaxDataSize(
|
||
&DeviceContext->MacInfo,
|
||
NULL,
|
||
0,
|
||
DeviceContext->MaxSendPacketSize,
|
||
TRUE,
|
||
&MaxUserData);
|
||
|
||
DeviceContext->Information.Version = 0x0100;
|
||
DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
|
||
DeviceContext->Information.MaxConnectionUserData = 0;
|
||
DeviceContext->Information.MaxDatagramSize =
|
||
MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
|
||
DeviceContext->Information.ServiceFlags = NBF_SERVICE_FLAGS;
|
||
if (DeviceContext->MacInfo.MediumAsync) {
|
||
DeviceContext->Information.ServiceFlags |= TDI_SERVICE_POINT_TO_POINT;
|
||
}
|
||
DeviceContext->Information.MinimumLookaheadData =
|
||
240 - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
|
||
DeviceContext->Information.MaximumLookaheadData =
|
||
DeviceContext->MaxReceivePacketSize - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
|
||
DeviceContext->Information.NumberOfResources = NBF_TDI_RESOURCES;
|
||
KeQuerySystemTime (&DeviceContext->Information.StartTime);
|
||
|
||
|
||
//
|
||
// Allocate various structures we will need.
|
||
//
|
||
|
||
ENTER_NBF;
|
||
|
||
//
|
||
// The TP_UI_FRAME structure has a CHAR[1] field at the end
|
||
// which we expand upon to include all the headers needed;
|
||
// the size of the MAC header depends on what the adapter
|
||
// told us about its max header size.
|
||
//
|
||
|
||
DeviceContext->UIFrameHeaderLength =
|
||
DeviceContext->MacInfo.MaxHeaderLength +
|
||
sizeof(DLC_FRAME) +
|
||
sizeof(NBF_HDR_CONNECTIONLESS);
|
||
|
||
DeviceContext->UIFrameLength =
|
||
FIELD_OFFSET(TP_UI_FRAME, Header[0]) +
|
||
DeviceContext->UIFrameHeaderLength;
|
||
|
||
|
||
//
|
||
// The TP_PACKET structure has a CHAR[1] field at the end
|
||
// which we expand upon to include all the headers needed;
|
||
// the size of the MAC header depends on what the adapter
|
||
// told us about its max header size. TP_PACKETs are used
|
||
// for connection-oriented frame as well as for
|
||
// control frames, but since DLC_I_FRAME and DLC_S_FRAME
|
||
// are the same size, the header is the same size.
|
||
//
|
||
|
||
ASSERT (sizeof(DLC_I_FRAME) == sizeof(DLC_S_FRAME));
|
||
|
||
DeviceContext->PacketHeaderLength =
|
||
DeviceContext->MacInfo.MaxHeaderLength +
|
||
sizeof(DLC_I_FRAME) +
|
||
sizeof(NBF_HDR_CONNECTION);
|
||
|
||
DeviceContext->PacketLength =
|
||
FIELD_OFFSET(TP_PACKET, Header[0]) +
|
||
DeviceContext->PacketHeaderLength;
|
||
|
||
|
||
//
|
||
// The BUFFER_TAG structure has a CHAR[1] field at the end
|
||
// which we expand upong to include all the frame data.
|
||
//
|
||
|
||
DeviceContext->ReceiveBufferLength =
|
||
DeviceContext->MaxReceivePacketSize +
|
||
FIELD_OFFSET(BUFFER_TAG, Buffer[0]);
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: pre-allocating requests.\n");
|
||
}
|
||
for (i=0; i<NbfConfig->InitRequests; i++) {
|
||
|
||
NbfAllocateRequest (DeviceContext, &Request);
|
||
|
||
if (Request == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate requests.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
|
||
#if DBG
|
||
NbfRequestTable[i+1] = (PVOID)Request;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfRequestTable[0] = UlongToPtr(NbfConfig->InitRequests);
|
||
NbfRequestTable[NbfConfig->InitRequests + 1] = (PVOID)
|
||
((NBF_REQUEST_SIGNATURE << 16) | sizeof (TP_REQUEST));
|
||
InitializeListHead (&NbfGlobalRequestList);
|
||
#endif
|
||
|
||
DeviceContext->RequestInitAllocated = NbfConfig->InitRequests;
|
||
DeviceContext->RequestMaxAllocated = NbfConfig->MaxRequests;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d requests, %ld\n", NbfConfig->InitRequests, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating links.\n");
|
||
}
|
||
for (i=0; i<NbfConfig->InitLinks; i++) {
|
||
|
||
NbfAllocateLink (DeviceContext, &Link);
|
||
|
||
if (Link == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate links.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->LinkPool, &Link->Linkage);
|
||
#if DBG
|
||
NbfLinkTable[i+1] = (PVOID)Link;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfLinkTable[0] = UlongToPtr(NbfConfig->InitLinks);
|
||
NbfLinkTable[NbfConfig->InitLinks+1] = (PVOID)
|
||
((NBF_LINK_SIGNATURE << 16) | sizeof (TP_LINK));
|
||
#endif
|
||
|
||
DeviceContext->LinkInitAllocated = NbfConfig->InitLinks;
|
||
DeviceContext->LinkMaxAllocated = NbfConfig->MaxLinks;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d links, %ld\n", NbfConfig->InitLinks, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating connections.\n");
|
||
}
|
||
for (i=0; i<NbfConfig->InitConnections; i++) {
|
||
|
||
NbfAllocateConnection (DeviceContext, &Connection);
|
||
|
||
if (Connection == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate connections.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
|
||
#if DBG
|
||
NbfConnectionTable[i+1] = (PVOID)Connection;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfConnectionTable[0] = UlongToPtr(NbfConfig->InitConnections);
|
||
NbfConnectionTable[NbfConfig->InitConnections+1] = (PVOID)
|
||
((NBF_CONNECTION_SIGNATURE << 16) | sizeof (TP_CONNECTION));
|
||
#endif
|
||
|
||
DeviceContext->ConnectionInitAllocated = NbfConfig->InitConnections;
|
||
DeviceContext->ConnectionMaxAllocated = NbfConfig->MaxConnections;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d connections, %ld\n", NbfConfig->InitConnections, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating AddressFiles.\n");
|
||
}
|
||
for (i=0; i<NbfConfig->InitAddressFiles; i++) {
|
||
|
||
NbfAllocateAddressFile (DeviceContext, &AddressFile);
|
||
|
||
if (AddressFile == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate Address Files.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
|
||
#if DBG
|
||
NbfAddressFileTable[i+1] = (PVOID)AddressFile;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfAddressFileTable[0] = UlongToPtr(NbfConfig->InitAddressFiles);
|
||
NbfAddressFileTable[NbfConfig->InitAddressFiles + 1] = (PVOID)
|
||
((NBF_ADDRESSFILE_SIGNATURE << 16) |
|
||
sizeof (TP_ADDRESS_FILE));
|
||
#endif
|
||
|
||
DeviceContext->AddressFileInitAllocated = NbfConfig->InitAddressFiles;
|
||
DeviceContext->AddressFileMaxAllocated = NbfConfig->MaxAddressFiles;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d address files, %ld\n", NbfConfig->InitAddressFiles, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating addresses.\n");
|
||
}
|
||
for (i=0; i<NbfConfig->InitAddresses; i++) {
|
||
|
||
NbfAllocateAddress (DeviceContext, &Address);
|
||
if (Address == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate addresses.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
|
||
#if DBG
|
||
NbfAddressTable[i+1] = (PVOID)Address;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfAddressTable[0] = UlongToPtr(NbfConfig->InitAddresses);
|
||
NbfAddressTable[NbfConfig->InitAddresses + 1] = (PVOID)
|
||
((NBF_ADDRESS_SIGNATURE << 16) | sizeof (TP_ADDRESS));
|
||
#endif
|
||
|
||
DeviceContext->AddressInitAllocated = NbfConfig->InitAddresses;
|
||
DeviceContext->AddressMaxAllocated = NbfConfig->MaxAddresses;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d addresses, %ld\n", NbfConfig->InitAddresses, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating UI frames.\n");
|
||
}
|
||
|
||
for (i=0; i<NbfConfig->InitUIFrames; i++) {
|
||
|
||
NbfAllocateUIFrame (DeviceContext, &UIFrame);
|
||
|
||
if (UIFrame == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate UI frames.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&(DeviceContext->UIFramePool), &UIFrame->Linkage);
|
||
#if DBG
|
||
NbfUiFrameTable[i+1] = UIFrame;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfUiFrameTable[0] = UlongToPtr(NbfConfig->InitUIFrames);
|
||
#endif
|
||
|
||
DeviceContext->UIFrameInitAllocated = NbfConfig->InitUIFrames;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d UI frames, %ld\n", NbfConfig->InitUIFrames, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating I frames.\n");
|
||
NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->PacketPool);
|
||
}
|
||
|
||
for (i=0; i<NbfConfig->InitPackets; i++) {
|
||
|
||
NbfAllocateSendPacket (DeviceContext, &Packet);
|
||
if (Packet == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
|
||
#if DBG
|
||
NbfSendPacketTable[i+1] = Packet;
|
||
#endif
|
||
}
|
||
#if DBG
|
||
NbfSendPacketTable[0] = UlongToPtr(NbfConfig->InitPackets);
|
||
NbfSendPacketTable[NbfConfig->InitPackets+1] = (PVOID)
|
||
((NBF_PACKET_SIGNATURE << 16) | sizeof (TP_PACKET));
|
||
#endif
|
||
|
||
DeviceContext->PacketInitAllocated = NbfConfig->InitPackets;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d I-frame send packets, %ld\n", NbfConfig->InitPackets, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating RR frames.\n");
|
||
NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->RrPacketPool);
|
||
}
|
||
|
||
for (i=0; i<10; i++) {
|
||
|
||
NbfAllocateSendPacket (DeviceContext, &Packet);
|
||
if (Packet == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
Packet->Action = PACKET_ACTION_RR;
|
||
PushEntryList (&DeviceContext->RrPacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
|
||
}
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d RR-frame send packets, %ld\n", 10, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
|
||
// Allocate receive Ndis packets
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating Ndis Receive packets.\n");
|
||
}
|
||
if (DeviceContext->MacInfo.SingleReceive) {
|
||
InitReceivePackets = 2;
|
||
} else {
|
||
InitReceivePackets = NbfConfig->InitReceivePackets;
|
||
}
|
||
for (i=0; i<InitReceivePackets; i++) {
|
||
|
||
NbfAllocateReceivePacket (DeviceContext, &NdisPacket);
|
||
|
||
if (NdisPacket == NULL) {
|
||
PANIC ("NbfInitialize: insufficient memory to allocate packet MDLs.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
|
||
PushEntryList (&DeviceContext->ReceivePacketPool, &ReceiveTag->Linkage);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
PNDIS_BUFFER NdisBuffer;
|
||
NdisQueryPacket(NdisPacket, NULL, NULL, &NdisBuffer, NULL);
|
||
NbfPrint2 ("NbfInitialize: Created NDIS Pkt: %x Buffer: %x\n",
|
||
NdisPacket, NdisBuffer);
|
||
}
|
||
}
|
||
|
||
DeviceContext->ReceivePacketInitAllocated = InitReceivePackets;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d receive packets, %ld\n", InitReceivePackets, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RESOURCE) {
|
||
NbfPrint0 ("NBFDRVR: allocating Ndis Receive buffers.\n");
|
||
}
|
||
|
||
for (i=0; i<NbfConfig->InitReceiveBuffers; i++) {
|
||
|
||
NbfAllocateReceiveBuffer (DeviceContext, &BufferTag);
|
||
|
||
if (BufferTag == NULL) {
|
||
PANIC ("NbfInitialize: Unable to allocate receive packet.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
PushEntryList (&DeviceContext->ReceiveBufferPool, (PSINGLE_LIST_ENTRY)&BufferTag->Linkage);
|
||
|
||
}
|
||
|
||
DeviceContext->ReceiveBufferInitAllocated = NbfConfig->InitReceiveBuffers;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
|
||
NbfPrint2 ("%d receive buffers, %ld\n", NbfConfig->InitReceiveBuffers, DeviceContext->MemoryUsage);
|
||
}
|
||
|
||
// Store away the PDO for the underlying object
|
||
DeviceContext->PnPContext = SystemSpecific2;
|
||
|
||
DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
|
||
|
||
//
|
||
// Start the link-level timers running.
|
||
//
|
||
|
||
NbfInitializeTimerSystem (DeviceContext);
|
||
|
||
//
|
||
// Now link the device into the global list.
|
||
//
|
||
|
||
ACQUIRE_DEVICES_LIST_LOCK();
|
||
InsertTailList (&NbfDeviceList, &DeviceContext->Linkage);
|
||
RELEASE_DEVICES_LIST_LOCK();
|
||
|
||
DeviceObject = (PDEVICE_OBJECT) DeviceContext;
|
||
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint1 ("TdiRegisterDeviceObject for %S\n", DeviceString.Buffer);
|
||
}
|
||
|
||
status = TdiRegisterDeviceObject(&DeviceString,
|
||
&DeviceContext->TdiDeviceHandle);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
RemoveEntryList(&DeviceContext->Linkage);
|
||
goto cleanup;
|
||
}
|
||
|
||
RtlCopyMemory(NetBIOSAddress->NetbiosName,
|
||
DeviceContext->ReservedNetBIOSAddress, 16);
|
||
|
||
tdiPnPContext1.tdiPnPContextHeader.ContextSize = sizeof(PVOID);
|
||
tdiPnPContext1.tdiPnPContextHeader.ContextType = TDI_PNP_CONTEXT_TYPE_IF_NAME;
|
||
*(PVOID UNALIGNED *) &tdiPnPContext1.tdiPnPContextHeader.ContextData = &DeviceString;
|
||
|
||
tdiPnPContext2.tdiPnPContextHeader.ContextSize = sizeof(PVOID);
|
||
tdiPnPContext2.tdiPnPContextHeader.ContextType = TDI_PNP_CONTEXT_TYPE_PDO;
|
||
*(PVOID UNALIGNED *) &tdiPnPContext2.tdiPnPContextHeader.ContextData = SystemSpecific2;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint1 ("TdiRegisterNetAddress on %S ", DeviceString.Buffer);
|
||
NbfPrint6 ("for %02x%02x%02x%02x%02x%02x\n",
|
||
NetBIOSAddress->NetbiosName[10],
|
||
NetBIOSAddress->NetbiosName[11],
|
||
NetBIOSAddress->NetbiosName[12],
|
||
NetBIOSAddress->NetbiosName[13],
|
||
NetBIOSAddress->NetbiosName[14],
|
||
NetBIOSAddress->NetbiosName[15]);
|
||
}
|
||
|
||
status = TdiRegisterNetAddress(pAddress,
|
||
&DeviceString,
|
||
(TDI_PNP_CONTEXT *) &tdiPnPContext2,
|
||
&DeviceContext->ReservedAddressHandle);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
RemoveEntryList(&DeviceContext->Linkage);
|
||
goto cleanup;
|
||
}
|
||
|
||
NbfReferenceDeviceContext ("Load Succeeded", DeviceContext, DCREF_CREATION);
|
||
|
||
LEAVE_NBF;
|
||
*NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
||
return(1);
|
||
|
||
cleanup:
|
||
|
||
NbfWriteResourceErrorLog(
|
||
DeviceContext,
|
||
EVENT_TRANSPORT_RESOURCE_POOL,
|
||
501,
|
||
DeviceContext->MemoryUsage,
|
||
0);
|
||
|
||
//
|
||
// Cleanup whatever device context we were initializing
|
||
// when we failed.
|
||
//
|
||
*NdisStatus = status;
|
||
ASSERT(status != STATUS_SUCCESS);
|
||
|
||
if (InterlockedExchange(&DeviceContext->CreateRefRemoved, TRUE) == FALSE) {
|
||
|
||
// Stop all internal timers
|
||
NbfStopTimerSystem(DeviceContext);
|
||
|
||
// Remove creation reference
|
||
NbfDereferenceDeviceContext ("Load failed", DeviceContext, DCREF_CREATION);
|
||
}
|
||
|
||
LEAVE_NBF;
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
VOID
|
||
NbfReInitializeDeviceContext(
|
||
OUT PNDIS_STATUS NdisStatus,
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PCONFIG_DATA NbfConfig,
|
||
IN PUNICODE_STRING BindName,
|
||
IN PUNICODE_STRING ExportName,
|
||
IN PVOID SystemSpecific1,
|
||
IN PVOID SystemSpecific2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine re-initializes an existing nbf device context. In order to
|
||
do this, we need to undo whatever is done in the Unbind handler exposed
|
||
to NDIS - recreate the NDIS binding, and re-start the NBF timer system.
|
||
|
||
Arguments:
|
||
|
||
NdisStatus - The outputted status of the operations.
|
||
|
||
DriverObject - the nbf driver object.
|
||
|
||
NbfConfig - the transport configuration information from the registry.
|
||
|
||
SystemSpecific1 - SystemSpecific1 argument to ProtocolBindAdapter
|
||
|
||
SystemSpecific2 - SystemSpecific2 argument to ProtocolBindAdapter
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
KIRQL oldIrql;
|
||
PLIST_ENTRY p;
|
||
NTSTATUS status;
|
||
UNICODE_STRING DeviceString;
|
||
UCHAR PermAddr[sizeof(TA_ADDRESS)+TDI_ADDRESS_LENGTH_NETBIOS];
|
||
PTA_ADDRESS pAddress = (PTA_ADDRESS)PermAddr;
|
||
PTDI_ADDRESS_NETBIOS NetBIOSAddress =
|
||
(PTDI_ADDRESS_NETBIOS)pAddress->Address;
|
||
struct {
|
||
TDI_PNP_CONTEXT tdiPnPContextHeader;
|
||
PVOID tdiPnPContextTrailer;
|
||
} tdiPnPContext1, tdiPnPContext2;
|
||
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint1 ("ENTER NbfReInitializeDeviceContext for %S\n",
|
||
ExportName->Buffer);
|
||
}
|
||
|
||
//
|
||
// Search the list of NBF devices for a matching device name
|
||
//
|
||
|
||
ACQUIRE_DEVICES_LIST_LOCK();
|
||
|
||
for (p = NbfDeviceList.Flink ; p != &NbfDeviceList; p = p->Flink)
|
||
{
|
||
DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
|
||
|
||
RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
|
||
|
||
if (NdisEqualString(&DeviceString, ExportName, TRUE)) {
|
||
|
||
// This has to be a rebind - otherwise something wrong
|
||
|
||
ASSERT(DeviceContext->CreateRefRemoved == TRUE);
|
||
|
||
// Reference within lock so that it is not cleaned up
|
||
|
||
NbfReferenceDeviceContext ("Reload Temp Use", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
RELEASE_DEVICES_LIST_LOCK();
|
||
|
||
if (p == &NbfDeviceList)
|
||
{
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint2 ("LEAVE NbfReInitializeDeviceContext for %S with Status %08x\n",
|
||
ExportName->Buffer,
|
||
STATUS_NOT_FOUND);
|
||
}
|
||
|
||
*NdisStatus = STATUS_NOT_FOUND;
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Fire up NDIS again so this adapter talks
|
||
//
|
||
|
||
status = NbfInitializeNdis (DeviceContext,
|
||
NbfConfig,
|
||
BindName);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
// Store away the PDO for the underlying object
|
||
DeviceContext->PnPContext = SystemSpecific2;
|
||
|
||
DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
|
||
|
||
//
|
||
// Restart the link-level timers on device
|
||
//
|
||
|
||
NbfInitializeTimerSystem (DeviceContext);
|
||
|
||
//
|
||
// Re-Indicate to TDI that new binding has arrived
|
||
//
|
||
|
||
status = TdiRegisterDeviceObject(&DeviceString,
|
||
&DeviceContext->TdiDeviceHandle);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
pAddress->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
|
||
pAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
NetBIOSAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
|
||
RtlCopyMemory(NetBIOSAddress->NetbiosName,
|
||
DeviceContext->ReservedNetBIOSAddress, 16);
|
||
|
||
tdiPnPContext1.tdiPnPContextHeader.ContextSize = sizeof(PVOID);
|
||
tdiPnPContext1.tdiPnPContextHeader.ContextType = TDI_PNP_CONTEXT_TYPE_IF_NAME;
|
||
*(PVOID UNALIGNED *) &tdiPnPContext1.tdiPnPContextHeader.ContextData = &DeviceString;
|
||
|
||
tdiPnPContext2.tdiPnPContextHeader.ContextSize = sizeof(PVOID);
|
||
tdiPnPContext2.tdiPnPContextHeader.ContextType = TDI_PNP_CONTEXT_TYPE_PDO;
|
||
*(PVOID UNALIGNED *) &tdiPnPContext2.tdiPnPContextHeader.ContextData = SystemSpecific2;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint1 ("TdiRegisterNetAddress on %S ", DeviceString.Buffer);
|
||
NbfPrint6 ("for %02x%02x%02x%02x%02x%02x\n",
|
||
NetBIOSAddress->NetbiosName[10],
|
||
NetBIOSAddress->NetbiosName[11],
|
||
NetBIOSAddress->NetbiosName[12],
|
||
NetBIOSAddress->NetbiosName[13],
|
||
NetBIOSAddress->NetbiosName[14],
|
||
NetBIOSAddress->NetbiosName[15]);
|
||
}
|
||
|
||
status = TdiRegisterNetAddress(pAddress,
|
||
&DeviceString,
|
||
(TDI_PNP_CONTEXT *) &tdiPnPContext2,
|
||
&DeviceContext->ReservedAddressHandle);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
// Put the creation reference back again
|
||
NbfReferenceDeviceContext ("Reload Succeeded", DeviceContext, DCREF_CREATION);
|
||
|
||
DeviceContext->CreateRefRemoved = FALSE;
|
||
|
||
status = NDIS_STATUS_SUCCESS;
|
||
|
||
Cleanup:
|
||
|
||
if (status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
// Stop all internal timers
|
||
NbfStopTimerSystem (DeviceContext);
|
||
}
|
||
|
||
NbfDereferenceDeviceContext ("Reload Temp Use", DeviceContext, DCREF_TEMP_USE);
|
||
|
||
*NdisStatus = status;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_PNP) {
|
||
NbfPrint2 ("LEAVE NbfReInitializeDeviceContext for %S with Status %08x\n",
|
||
ExportName->Buffer,
|
||
status);
|
||
}
|
||
|
||
return;
|
||
}
|