windows-nt/Source/XPSP1/NT/net/netbeui/sys/nbfdrvr.c

3037 lines
84 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}