761 lines
19 KiB
C
761 lines
19 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
file.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which defines the NetBIOS driver's
|
||
file control block object.
|
||
|
||
Author:
|
||
|
||
Colin Watson (ColinW) 13-Mar-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "nb.h"
|
||
//#include "ntos.h"
|
||
//#include <zwapi.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, NewFcb)
|
||
#pragma alloc_text(PAGE, CleanupFcb)
|
||
#pragma alloc_text(PAGE, OpenLana)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
NewFcb(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the dll opens \Device\Netbios. It
|
||
creates all the lana structures and adds the name for the "burnt
|
||
in" prom address on each adapter. Note the similarity to the routine
|
||
NbAstat when looking at this function.
|
||
|
||
Arguments:
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Allocate the user context and store it in the DeviceObject.
|
||
//
|
||
|
||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||
PFCB NewFcb = NULL;
|
||
ULONG index;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
NewFcb = ExAllocatePoolWithTag (NonPagedPool, sizeof(FCB), 'fSBN');
|
||
FileObject->FsContext2 = NewFcb;
|
||
|
||
if ( NewFcb == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
NewFcb->Signature = FCB_SIGNATURE;
|
||
|
||
NewFcb->TimerRunning = FALSE;
|
||
|
||
NewFcb->LanaEnum.length = 0;
|
||
|
||
//
|
||
// Initializes Fcb fields read from the registry, including
|
||
// the DriverName and LanaEnum entry (for each lana) if appropriate.
|
||
//
|
||
//
|
||
Status = ReadRegistry(DeviceContext, NewFcb);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
ExFreePool( NewFcb );
|
||
FileObject->FsContext2 = NULL;
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// Get memory for the LanaInfo array and then initialize
|
||
//
|
||
NewFcb->ppLana = ExAllocatePoolWithTag (NonPagedPool,
|
||
sizeof(PLANA_INFO) * (NewFcb->MaxLana+1),
|
||
'fSBN');
|
||
|
||
if ( NewFcb->ppLana == NULL ) {
|
||
//
|
||
// Allocated by ReadRegistry
|
||
//
|
||
ExFreePool( NewFcb->RegistrySpace );
|
||
|
||
ExFreePool( NewFcb );
|
||
FileObject->FsContext2 = NULL;
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
for ( index = 0; index <= NewFcb->MaxLana; index++ ) {
|
||
NewFcb->ppLana[index] = NULL;
|
||
}
|
||
|
||
|
||
KeInitializeSpinLock( &NewFcb->SpinLock );
|
||
ExInitializeResource( &NewFcb->Resource );
|
||
ExInitializeResource( &NewFcb->AddResource );
|
||
ExInitializeWorkItem( &NewFcb->WorkEntry, NbTimer, NewFcb );
|
||
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Enumeration of transports completed:\n"));
|
||
NbFormattedDump( (PUCHAR)&NewFcb->LanaEnum, sizeof(LANA_ENUM));
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
} /* NewFcb */
|
||
|
||
VOID
|
||
OpenLana(
|
||
IN PDNCB pdncb,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when an application resets an adapter allocating
|
||
resources. It creates all the lana structure and adds the name for the
|
||
"burnt in" prom address as well as finding the broadcast address.
|
||
|
||
Note the similarity to the routine NbAstat when looking at this function.
|
||
|
||
Arguments:
|
||
|
||
pdncb - Pointer to the NCB.
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||
PFCB pfcb = IrpSp->FileObject->FsContext2;
|
||
KEVENT Event1;
|
||
PLANA_INFO plana;
|
||
HANDLE TdiHandle;
|
||
PFILE_OBJECT TdiObject;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
PMDL SaveMdl;
|
||
int temp;
|
||
PRESET_PARAMETERS InParameters;
|
||
PRESET_PARAMETERS OutParameters;
|
||
UCHAR Sessions;
|
||
UCHAR Commands;
|
||
UCHAR Names;
|
||
BOOLEAN Exclusive;
|
||
|
||
//
|
||
// Ncb and associated buffer to be used in adapter status to get the
|
||
// prom address.
|
||
//
|
||
|
||
DNCB ncb;
|
||
struct _AdapterStatus {
|
||
ADAPTER_STATUS AdapterInformation;
|
||
NAME_BUFFER Nb;
|
||
} AdapterStatus;
|
||
PMDL AdapterStatusMdl = NULL;
|
||
|
||
struct _BroadcastName {
|
||
TRANSPORT_ADDRESS Address;
|
||
UCHAR Padding[NCBNAMSZ];
|
||
} BroadcastName;
|
||
PMDL BroadcastMdl = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
if ( pdncb->ncb_lana_num > pfcb->MaxLana) {
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Calculate the lana limits from the users NCB.
|
||
//
|
||
|
||
InParameters = (PRESET_PARAMETERS)&pdncb->ncb_callname;
|
||
OutParameters = (PRESET_PARAMETERS)&pdncb->ncb_name;
|
||
|
||
if ( InParameters->sessions == 0 ) {
|
||
Sessions = 16;
|
||
} else {
|
||
if ( InParameters->sessions > MAXIMUM_CONNECTION ) {
|
||
Sessions = MAXIMUM_CONNECTION;
|
||
} else {
|
||
Sessions = InParameters->sessions;
|
||
}
|
||
}
|
||
|
||
if ( InParameters->commands == 0 ) {
|
||
Commands = 16;
|
||
} else {
|
||
Commands = InParameters->commands;
|
||
}
|
||
|
||
if ( InParameters->names == 0 ) {
|
||
Names = 8;
|
||
} else {
|
||
if ( InParameters->names > MAXIMUM_ADDRESS-2 ) {
|
||
Names = MAXIMUM_ADDRESS-2;
|
||
} else {
|
||
Names = InParameters->names;
|
||
}
|
||
}
|
||
|
||
Exclusive = (BOOLEAN)(InParameters->name0_reserved != 0);
|
||
|
||
// Copy the parameters back into the NCB
|
||
|
||
ASSERT( sizeof(RESET_PARAMETERS) == 16);
|
||
RtlZeroMemory( OutParameters, sizeof( RESET_PARAMETERS ));
|
||
|
||
OutParameters->sessions = Sessions;
|
||
OutParameters->commands = Commands;
|
||
OutParameters->names = Names;
|
||
OutParameters->name0_reserved = (UCHAR)Exclusive;
|
||
|
||
// Set all the configuration limits to their maximum.
|
||
|
||
OutParameters->load_sessions = 255;
|
||
OutParameters->load_commands = 255;
|
||
OutParameters->load_names = MAXIMUM_ADDRESS;
|
||
OutParameters->load_stations = 255;
|
||
OutParameters->load_remote_names = 255;
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Lana:%x Sessions:%x Names:%x Commands:%x Reserved:%x\n",
|
||
pdncb->ncb_lana_num,
|
||
Sessions,
|
||
Names,
|
||
Commands,
|
||
Exclusive));
|
||
}
|
||
|
||
//
|
||
// Build the internal datastructures.
|
||
//
|
||
|
||
AdapterStatusMdl = IoAllocateMdl( &AdapterStatus,
|
||
sizeof( AdapterStatus ),
|
||
FALSE, // Secondary Buffer
|
||
FALSE, // Charge Quota
|
||
NULL);
|
||
|
||
if ( AdapterStatusMdl == NULL ) {
|
||
NCB_COMPLETE( pdncb, NRC_NORESOURCES );
|
||
return;
|
||
}
|
||
|
||
BroadcastMdl = IoAllocateMdl( &BroadcastName,
|
||
sizeof( BroadcastName ),
|
||
FALSE, // Secondary Buffer
|
||
FALSE, // Charge Quota
|
||
NULL);
|
||
|
||
if ( BroadcastMdl == NULL ) {
|
||
IoFreeMdl( AdapterStatusMdl );
|
||
NCB_COMPLETE( pdncb, NRC_NORESOURCES );
|
||
return;
|
||
}
|
||
|
||
MmBuildMdlForNonPagedPool (AdapterStatusMdl);
|
||
|
||
MmBuildMdlForNonPagedPool (BroadcastMdl);
|
||
|
||
KeInitializeEvent (
|
||
&Event1,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
//
|
||
// For each potential network, open the device driver and
|
||
// obtain the reserved name and the broadcast address.
|
||
//
|
||
|
||
|
||
// Open a handle for doing control functions
|
||
Status = NbOpenAddress ( &TdiHandle, (PVOID*)&TdiObject, pfcb, pdncb->ncb_lana_num, NULL );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
// Adapter not installed
|
||
NCB_COMPLETE( pdncb, NRC_BRIDGE );
|
||
goto exit;
|
||
}
|
||
|
||
LOCK_RESOURCE( pfcb );
|
||
|
||
if ( pfcb->ppLana[pdncb->ncb_lana_num] != NULL ) {
|
||
// Attempting to open the lana twice in 2 threads.
|
||
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_TOOMANY );
|
||
goto exit;
|
||
}
|
||
plana = pfcb->ppLana[pdncb->ncb_lana_num] =
|
||
ExAllocatePoolWithTag (NonPagedPool,
|
||
sizeof(LANA_INFO), 'lSBN');
|
||
|
||
if ( plana == (PLANA_INFO) NULL ) {
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_NORESOURCES );
|
||
goto exit;
|
||
}
|
||
|
||
plana->Signature = LANA_INFO_SIGNATURE;
|
||
plana->Status = NB_INITIALIZING;
|
||
plana->pFcb = pfcb;
|
||
plana->ControlChannel = TdiHandle;
|
||
|
||
for ( temp = 0; temp <= MAXIMUM_CONNECTION; temp++ ) {
|
||
plana->ConnectionBlocks[temp] = NULL;
|
||
}
|
||
|
||
for ( temp = 0; temp <= MAXIMUM_ADDRESS; temp++ ) {
|
||
plana->AddressBlocks[temp] = NULL;
|
||
}
|
||
|
||
InitializeListHead( &plana->LanAlertList);
|
||
|
||
// Record the user specified limits in the Lana datastructure.
|
||
|
||
plana->NextConnection = 1;
|
||
plana->ConnectionCount = 0;
|
||
plana->MaximumConnection = Sessions;
|
||
plana->NextAddress = 2;
|
||
plana->AddressCount = 0;
|
||
plana->MaximumAddresses = Names;
|
||
|
||
DeviceObject = IoGetRelatedDeviceObject( TdiObject );
|
||
plana->ControlFileObject = TdiObject;
|
||
plana->ControlDeviceObject = DeviceObject;
|
||
|
||
SaveMdl = Irp->MdlAddress; // TdiBuildQuery modifies MdlAddress
|
||
|
||
if ( Exclusive == TRUE ) {
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Query adapter status\n" ));
|
||
}
|
||
TdiBuildQueryInformation( Irp,
|
||
DeviceObject,
|
||
TdiObject,
|
||
NbCompletionEvent,
|
||
&Event1,
|
||
TDI_QUERY_ADAPTER_STATUS,
|
||
AdapterStatusMdl);
|
||
|
||
Status = IoCallDriver (DeviceObject, Irp);
|
||
if ( Status == STATUS_PENDING ) {
|
||
Status = KeWaitForSingleObject (&Event1,
|
||
Executive,
|
||
KernelMode,
|
||
TRUE,
|
||
NULL);
|
||
if (!NT_SUCCESS(Status)) {
|
||
NbAddressClose( TdiHandle, TdiObject );
|
||
ExFreePool( plana );
|
||
pfcb->ppLana[pdncb->ncb_lana_num] = NULL;
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
goto exit;
|
||
}
|
||
Status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// The transport may have extra names added so the buffer may be too short.
|
||
// Ignore the too short problem since we will have all the data we require.
|
||
//
|
||
|
||
if (Status == STATUS_BUFFER_OVERFLOW) {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now discover the broadcast address.
|
||
//
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Query broadcast address\n" ));
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
TdiBuildQueryInformation( Irp,
|
||
DeviceObject,
|
||
TdiObject,
|
||
NbCompletionEvent,
|
||
&Event1,
|
||
TDI_QUERY_BROADCAST_ADDRESS,
|
||
BroadcastMdl);
|
||
|
||
Status = IoCallDriver (DeviceObject, Irp);
|
||
if ( Status == STATUS_PENDING ) {
|
||
Status = KeWaitForSingleObject (&Event1,
|
||
Executive,
|
||
KernelMode,
|
||
TRUE,
|
||
NULL);
|
||
if (!NT_SUCCESS(Status)) {
|
||
NbAddressClose( TdiHandle, TdiObject );
|
||
ExFreePool( plana );
|
||
pfcb->ppLana[pdncb->ncb_lana_num] = NULL;
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
goto exit;
|
||
}
|
||
Status = Irp->IoStatus.Status;
|
||
}
|
||
}
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Query broadcast address returned:\n" ));
|
||
NbFormattedDump(
|
||
(PUCHAR)&BroadcastName,
|
||
sizeof(BroadcastName) );
|
||
}
|
||
|
||
// Cleanup the callers Irp
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->MdlAddress = SaveMdl;
|
||
|
||
|
||
if ( !NT_SUCCESS( Status )) {
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint((" Astat or query broadcast returned error: %lx\n", Status ));
|
||
}
|
||
|
||
NbAddressClose( TdiHandle, TdiObject );
|
||
ExFreePool( plana );
|
||
pfcb->ppLana[pdncb->ncb_lana_num] = NULL;
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
goto exit;
|
||
}
|
||
|
||
if ( Exclusive == TRUE) {
|
||
int i;
|
||
//
|
||
// Grab exclusive access to the reserved address
|
||
//
|
||
//
|
||
// We now have an adapter status structure containing the
|
||
// prom address. Move the address to where NewAb looks and
|
||
// pretend an addname has just been requested.
|
||
//
|
||
|
||
ncb.ncb_command = NCBADDRESERVED;
|
||
ncb.ncb_lana_num = pdncb->ncb_lana_num;
|
||
ncb.ncb_retcode = NRC_PENDING;
|
||
|
||
for ( i=0; i<10 ; i++ ) {
|
||
ncb.ncb_name[i] = '\0';
|
||
}
|
||
RtlMoveMemory( ncb.ncb_name+10,
|
||
AdapterStatus.AdapterInformation.adapter_address,
|
||
6);
|
||
|
||
NewAb( IrpSp, &ncb );
|
||
|
||
if ( ncb.ncb_retcode != NRC_GOODRET ) {
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint((" Add of reserved name failed Lana:%x\n", pdncb->ncb_lana_num));
|
||
}
|
||
|
||
plana->Status = NB_ABANDONED;
|
||
CleanupLana( pfcb, pdncb->ncb_lana_num, TRUE);
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Add the broadcast address. Use a special command code
|
||
// to ensure address 255 is used.
|
||
//
|
||
|
||
ncb.ncb_length = BroadcastName.Address.Address[0].AddressLength;
|
||
ncb.ncb_command = NCBADDBROADCAST;
|
||
ncb.ncb_lana_num = pdncb->ncb_lana_num;
|
||
ncb.ncb_retcode = NRC_PENDING;
|
||
ncb.ncb_cmd_cplt = NRC_PENDING;
|
||
RtlMoveMemory( ncb.ncb_name,
|
||
((PTDI_ADDRESS_NETBIOS)&BroadcastName.Address.Address[0].Address)->NetbiosName,
|
||
NCBNAMSZ );
|
||
|
||
|
||
NewAb( IrpSp, &ncb );
|
||
|
||
if ( ncb.ncb_retcode != NRC_GOODRET ) {
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint((" Add of broadcast name failed Lana:%x\n", pdncb->ncb_lana_num));
|
||
}
|
||
|
||
plana->Status = NB_ABANDONED;
|
||
CleanupLana( pfcb, pdncb->ncb_lana_num, TRUE);
|
||
UNLOCK_RESOURCE( pfcb );
|
||
NCB_COMPLETE( pdncb, NRC_SYSTEM );
|
||
goto exit;
|
||
}
|
||
|
||
plana->Status = NB_INITIALIZED;
|
||
NCB_COMPLETE( pdncb, NRC_GOODRET );
|
||
UNLOCK_RESOURCE( pfcb );
|
||
|
||
exit:
|
||
IoFreeMdl( AdapterStatusMdl );
|
||
IoFreeMdl( BroadcastMdl );
|
||
return;
|
||
|
||
}
|
||
|
||
VOID
|
||
CleanupFcb(
|
||
IN PIO_STACK_LOCATION IrpSp,
|
||
IN PFCB pfcb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This deletes any Connection Blocks pointed to by the File Control Block
|
||
and then deletes the File Control Block. This routine is only called
|
||
when a close IRP has been received.
|
||
|
||
Arguments:
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
pfcb - Pointer to the Fcb to be deallocated.
|
||
|
||
Return Value:
|
||
|
||
nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG lana_index;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// To receive a Close Irp, the IO system has determined that there
|
||
// are no handles open in the driver. To avoid some race conditions
|
||
// in this area, we always have an Irp when queueing work to the Fsp.
|
||
// this prevents structures disappearing on the Fsp and also makes
|
||
// it easier to cleanup in this routine.
|
||
//
|
||
|
||
//
|
||
// for each network adapter that is allocated, close all addresses
|
||
// and connections, deleting any memory that is allocated.
|
||
//
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("CleanupFcb:%lx\n", pfcb ));
|
||
}
|
||
|
||
LOCK_RESOURCE( pfcb );
|
||
if ( pfcb->TimerRunning == TRUE ) {
|
||
|
||
KEVENT TimerCancelled;
|
||
|
||
KeInitializeEvent (
|
||
&TimerCancelled,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
|
||
pfcb->TimerCancelled = &TimerCancelled;
|
||
pfcb->TimerRunning = FALSE;
|
||
UNLOCK_RESOURCE( pfcb );
|
||
|
||
if ( KeCancelTimer (&pfcb->Timer) == FALSE ) {
|
||
|
||
//
|
||
// The timeout was in the Dpc queue. Wait for it to be
|
||
// processed before continuing.
|
||
//
|
||
|
||
KeWaitForSingleObject (&TimerCancelled,
|
||
Executive,
|
||
KernelMode,
|
||
TRUE,
|
||
NULL);
|
||
}
|
||
|
||
} else {
|
||
UNLOCK_RESOURCE( pfcb );
|
||
}
|
||
|
||
for ( lana_index = 0; lana_index <= pfcb->MaxLana; lana_index++ ) {
|
||
CleanupLana( pfcb, lana_index, TRUE);
|
||
}
|
||
|
||
ExDeleteResource( &pfcb->Resource );
|
||
ExDeleteResource( &pfcb->AddResource );
|
||
|
||
NbFreeRegistryInfo ( pfcb );
|
||
|
||
IrpSp->FileObject->FsContext2 = NULL;
|
||
|
||
ExFreePool( pfcb->ppLana );
|
||
ExFreePool( pfcb );
|
||
|
||
}
|
||
|
||
VOID
|
||
CleanupLana(
|
||
IN PFCB pfcb,
|
||
IN ULONG lana_index,
|
||
IN BOOLEAN delete
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine completes all the requests on a particular adapter. It
|
||
removes all connections and addresses.
|
||
Arguments:
|
||
|
||
pfcb - Pointer to the Fcb to be deallocated.
|
||
|
||
lana_index - supplies the adapter to be cleaned.
|
||
|
||
delete - if TRUE the memory for the lana structure should be freed.
|
||
|
||
Return Value:
|
||
|
||
nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLANA_INFO plana;
|
||
int index;
|
||
KIRQL OldIrql; // Used when SpinLock held.
|
||
PDNCB pdncb;
|
||
|
||
LOCK( pfcb, OldIrql );
|
||
|
||
plana = pfcb->ppLana[lana_index];
|
||
|
||
if ( plana != NULL ) {
|
||
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint((" CleanupLana pfcb: %lx lana %lx\n", pfcb, lana_index ));
|
||
}
|
||
|
||
if (( plana->Status == NB_INITIALIZING ) ||
|
||
( plana->Status == NB_DELETING )) {
|
||
// Possibly trying to reset it twice?
|
||
UNLOCK( pfcb, OldIrql );
|
||
return;
|
||
}
|
||
plana->Status = NB_DELETING;
|
||
|
||
// Cleanup the control channel and abandon any tdi-action requests.
|
||
|
||
|
||
if ( plana->ControlChannel != NULL ) {
|
||
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
NbAddressClose( plana->ControlChannel, plana->ControlFileObject );
|
||
|
||
LOCK_SPINLOCK( pfcb, OldIrql );
|
||
|
||
plana->ControlChannel = NULL;
|
||
|
||
}
|
||
|
||
while ( (pdncb = DequeueRequest( &plana->LanAlertList)) != NULL ) {
|
||
|
||
//
|
||
// Any error will do since the user is closing \Device\Netbios
|
||
// and is therefore exiting.
|
||
//
|
||
|
||
NCB_COMPLETE( pdncb, NRC_SCLOSED );
|
||
|
||
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
|
||
NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
|
||
}
|
||
|
||
|
||
for ( index = 0; index <= MAXIMUM_CONNECTION; index++) {
|
||
if ( plana->ConnectionBlocks[index] != NULL ) {
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint(("Call CleanupCb Lana:%x Lsn: %x\n", lana_index, index ));
|
||
}
|
||
plana->ConnectionBlocks[index]->DisconnectReported = TRUE;
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql ); // Allow NtClose in Cleanup routines.
|
||
CleanupCb( &plana->ConnectionBlocks[index], NULL );
|
||
LOCK_SPINLOCK( pfcb, OldIrql ); // Allow NtClose in Cleanup routines.
|
||
}
|
||
}
|
||
|
||
for ( index = 0; index <= MAXIMUM_ADDRESS; index++ ) {
|
||
if ( plana->AddressBlocks[index] != NULL ) {
|
||
IF_NBDBG (NB_DEBUG_FILE) {
|
||
NbPrint((" CleanupAb Lana:%x index: %x\n", lana_index, index ));
|
||
}
|
||
UNLOCK_SPINLOCK( pfcb, OldIrql ); // Allow NtClose in Cleanup routines.
|
||
CleanupAb( &plana->AddressBlocks[index], TRUE );
|
||
LOCK_SPINLOCK( pfcb, OldIrql ); // Allow NtClose in Cleanup routines.
|
||
}
|
||
}
|
||
|
||
if ( delete == TRUE ) {
|
||
pfcb->ppLana[lana_index] = NULL;
|
||
ExFreePool( plana );
|
||
}
|
||
|
||
}
|
||
|
||
UNLOCK( pfcb, OldIrql );
|
||
}
|