windows-nt/Source/XPSP1/NT/net/netbios/sys/address.c

1386 lines
37 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
address.c
Abstract:
This module contains code which defines the NetBIOS driver's
address object.
Author:
Colin Watson (ColinW) 13-Mar-1991
Environment:
Kernel mode
Revision History:
--*/
#include "nb.h"
//nclude <zwapi.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NbAddName)
#pragma alloc_text(PAGE, NbOpenAddress)
#pragma alloc_text(PAGE, NbAddressClose)
#pragma alloc_text(PAGE, NbSetEventHandler)
#pragma alloc_text(PAGE, SubmitTdiRequest)
#pragma alloc_text(PAGE, NewAb)
#endif
NTSTATUS
NbAddName(
IN PDNCB pdncb,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine is called to add a name to the name table so that the
name is available for listens etc. If the name is already in the table
then reject the request. If an error is found by NewAb then it is
recorded directly in the NCB.
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. This is always
STATUS_SUCCESS because the operations called by this routine are all
synchronous. We must never return an error status since this would
prevent the ncb from being copied back.
--*/
{
PFCB pfcb = IrpSp->FileObject->FsContext2;
PSZ Name = pdncb->ncb_name;
PAGED_CODE();
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint(( "\n** AAAAADDDDDDName *** pdncb %lx\n", pdncb ));
}
//
// NewAb is used in file.c to add the reserved name. Check here
// for an application using a special name.
//
if (( pdncb->ncb_name[0] == '*' ) ||
( pdncb->ncb_name[0] == '\0' )) {
NCB_COMPLETE( pdncb, NRC_NOWILD );
} else {
NewAb( IrpSp, pdncb );
}
return STATUS_SUCCESS;
}
NTSTATUS
NbDeleteName(
IN PDNCB pdncb,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This routine is called to delete a name. To perform this operation
the AddressHandle to the transport is closed and the Address Block
is deleted.
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.
--*/
{
PFCB pfcb = IrpSp->FileObject->FsContext2;
PPAB ppab;
KIRQL OldIrql; // Used when SpinLock held.
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("[NETBIOS] NbDeleteName : FCB : %lx lana: %lx Address:\n",
pfcb, pdncb->ncb_lana_num ));
NbFormattedDump( (PUCHAR) pdncb->ncb_name, sizeof(NAME) );
}
if (( pdncb->ncb_name[0] == '*' ) ||
( pdncb->ncb_name[0] == '\0' )) {
NCB_COMPLETE( pdncb, NRC_NOWILD );
return STATUS_SUCCESS;
}
LOCK( pfcb, OldIrql );
ppab = FindAb( pfcb, pdncb, FALSE );
if ( ppab != NULL ) {
if (( (*ppab)->NameNumber == 0) ||
( (*ppab)->NameNumber == MAXIMUM_ADDRESS)) {
UNLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_NAMERR );
} else {
if ( ((*ppab)->Status & 0x7) != REGISTERED) {
UNLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_TOOMANY ); // Try later.
} else {
if ( FindActiveSession( pfcb, pdncb, ppab ) == TRUE ) {
// When all the sessions close, the name will be deleted.
UNLOCK_SPINLOCK( pfcb, OldIrql );
CleanupAb( ppab, FALSE );
UNLOCK_RESOURCE( pfcb );
NCB_COMPLETE( pdncb, NRC_ACTSES );
} else {
UNLOCK_SPINLOCK( pfcb, OldIrql );
CleanupAb( ppab, TRUE );
UNLOCK_RESOURCE( pfcb );
NCB_COMPLETE( pdncb, NRC_GOODRET );
}
}
}
} else {
UNLOCK( pfcb, OldIrql );
// FindAb has already set the completion code.
}
return STATUS_SUCCESS;
}
NTSTATUS
NbOpenAddress (
OUT PHANDLE FileHandle,
OUT PVOID *Object,
IN PUNICODE_STRING pusDeviceName,
IN UCHAR LanNumber,
IN PDNCB pdncb OPTIONAL
)
/*++
Routine Description:
This routine uses the transport to create an entry in the NetBIOS
table with the value of "Name". It will re-use an existing entry if
"Name" already exists.
Note: This synchronous call may take a number of seconds. If this matters
then the caller should specify ASYNCH and a post routine so that it is
performed by the thread created by the netbios dll routines.
If pdncb == NULL then a special handle is returned that is capable of
administering the transport. For example to execute an ASTAT.
Arguments:
FileHandle - Pointer to where the filehandle is to be returned.
*Object - Pointer to where the file object pointer is to be stored
pfcb - supplies the device names for the lana number.
LanNumber - supplies the network adapter to be opened.
pdncb - Pointer to either an NCB or NULL.
Return Value:
The function value is the status of the operation.
--*/
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
PFILE_FULL_EA_INFORMATION EaBuffer;
ULONG EaLength;
TA_NETBIOS_ADDRESS Address;
ULONG ShareAccess;
KAPC_STATE ApcState;
BOOLEAN ProcessAttached = FALSE;
PAGED_CODE();
IF_NBDBG (NB_DEBUG_ADDRESS) {
if ( pdncb ) {
NbPrint( ("NbOpenAddress: Opening lana: %lx, Address:\n",
LanNumber ));
NbFormattedDump( pdncb->ncb_name, NCBNAMSZ );
if ( pdncb->ncb_command == NCBADDBROADCAST ) {
NbPrint (("NbOpenAddress: Opening Broadcast Address length: %x\n",
pdncb->ncb_length));
}
} else {
NbPrint( ("NbOpenAddress: Opening lana: %lx Control Channel\n",
LanNumber));
}
}
InitializeObjectAttributes (
&ObjectAttributes,
pusDeviceName,
0,
NULL,
NULL);
if ( ARGUMENT_PRESENT( pdncb ) ) {
EaLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
sizeof(TA_NETBIOS_ADDRESS); // EA length
EaBuffer = (PFILE_FULL_EA_INFORMATION)
ExAllocatePoolWithTag( NonPagedPool, EaLength, 'eSBN' );
if (EaBuffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
EaBuffer->NextEntryOffset = 0;
EaBuffer->Flags = 0;
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
RtlMoveMemory( EaBuffer->EaName, TdiTransportAddress, EaBuffer->EaNameLength + 1 );
//
// Create a copy of the NETBIOS address descriptor in a local
// first, in order to avoid alignment problems.
//
Address.TAAddressCount = 1;
Address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
if ( pdncb->ncb_command == NCBADDBROADCAST ) {
Address.Address[0].AddressLength = pdncb->ncb_length;
} else {
Address.Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
}
if (((pdncb->ncb_command & ~ASYNCH) == NCBADDNAME) ||
((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME)) {
ShareAccess = 0; // Exclusive access
if ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME) {
Address.Address[0].Address[0].NetbiosNameType =
TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
} else {
Address.Address[0].Address[0].NetbiosNameType =
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
}
} else {
if ((pdncb->ncb_command & ~ASYNCH) == NCBADDRESERVED) {
//
// NB30 non-conformance!
// We allow multiple applications to use name number 1. This is so that we can
// conveniently run multiple dos applications which all have address 1.
//
ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
Address.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
} else {
// Group names and Broadcast addresses.
ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
if ((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDGRNAME) {
Address.Address[0].Address[0].NetbiosNameType =
TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP;
} else {
Address.Address[0].Address[0].NetbiosNameType =
TDI_ADDRESS_NETBIOS_TYPE_GROUP;
}
}
}
RtlMoveMemory(
Address.Address[0].Address[0].NetbiosName,
pdncb->ncb_name,
NCBNAMSZ
);
RtlMoveMemory (
&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
&Address,
sizeof(TA_NETBIOS_ADDRESS)
);
} else {
ShareAccess = FILE_SHARE_WRITE; // Non-exclusive access
EaBuffer = NULL;
EaLength = 0;
}
if (PsGetCurrentProcess() != NbFspProcess) {
KeStackAttachProcess(NbFspProcess, &ApcState);
ProcessAttached = TRUE;
}
IF_NBDBG( NB_DEBUG_ADDRESS )
{
if ( ARGUMENT_PRESENT( pdncb ) )
{
NbPrint( (
"NbOpenAddress : Create file invoked on lana for : %d\n",
pdncb-> ncb_lana_num
) );
NbFormattedDump( pdncb-> ncb_name, NCBNAMSZ );
}
else
{
NbPrint( (
"NbOpenAddress : Create file invoked for \n"
) );
NbPrint( ( "Control channel\n" ) );
}
}
Status = ZwCreateFile (
FileHandle,
GENERIC_READ | GENERIC_WRITE, // desired access.
&ObjectAttributes, // object attributes.
&IoStatusBlock, // returned status information.
NULL, // Allocation size (unused).
FILE_ATTRIBUTE_NORMAL, // file attributes.
ShareAccess,
FILE_CREATE,
0, // create options.
EaBuffer,
EaLength
);
if ( NT_SUCCESS( Status )) {
Status = IoStatusBlock.Status;
}
// Obtain a referenced pointer to the file object.
if (NT_SUCCESS( Status )) {
Status = ObReferenceObjectByHandle (
*FileHandle,
0,
NULL,
KernelMode,
Object,
NULL
);
if (!NT_SUCCESS(Status)) {
NTSTATUS localstatus;
IF_NBDBG( NB_DEBUG_ADDRESS )
{
if ( ARGUMENT_PRESENT( pdncb ) )
{
NbPrint( (
"NbOpenAddress : error : file closed on lana %d for \n",
pdncb-> ncb_lana_num
) );
NbFormattedDump( pdncb-> ncb_name, NCBNAMSZ );
}
else
{
NbPrint( (
"NbOpenAddress : error : file closed on lana for \n"
) );
NbPrint( ( "Control channel\n" ) );
}
}
localstatus = ZwClose( *FileHandle);
ASSERT(NT_SUCCESS(localstatus));
*FileHandle = NULL;
}
}
if (ProcessAttached) {
KeUnstackDetachProcess(&ApcState);
}
if ( EaBuffer ) {
ExFreePool( EaBuffer );
}
IF_NBDBG (NB_DEBUG_ADDRESS ) {
NbPrint( ("NbOpenAddress Status:%X, IoStatus:%X.\n", Status, IoStatusBlock.Status));
}
if ( NT_SUCCESS( Status )) {
Status = IoStatusBlock.Status;
}
if (!NT_SUCCESS( Status )) {
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("NbOpenAddress: FAILURE, status code=%X.\n", Status));
}
return Status;
}
return Status;
}
PAB
NewAb(
IN PIO_STACK_LOCATION IrpSp,
IN OUT PDNCB pdncb
)
/*++
Routine Description:
Arguments:
`
IrpSp - Pointer to current IRP stack frame.
pdncb - Pointer to the ncb being processed.
Return Value:
The new Cb.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAB pab;
PFCB pfcb = FileObject->FsContext2;
PLANA_INFO plana;
int index;
ULONG NameLength;
UNICODE_STRING usDeviceName;
HANDLE hFileHandle = NULL;
PFILE_OBJECT pfoFileObject = NULL;
PAGED_CODE();
RtlInitUnicodeString( &usDeviceName, NULL);
KeEnterCriticalRegion();
// Prevent resets while we add the name
ExAcquireResourceSharedLite ( &pfcb->AddResource, TRUE );
LOCK_RESOURCE( pfcb );
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("[NETBIOS] NewAb: FCB : %lx lana: %lx Address:\n", pfcb,
pdncb->ncb_lana_num ));
NbFormattedDump( (PUCHAR) pdncb->ncb_name, sizeof(NAME) );
}
if ( ( pfcb == NULL ) ||
( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
( pfcb-> pDriverName[ pdncb-> ncb_lana_num ].MaximumLength == 0 ) ||
( pfcb-> pDriverName[ pdncb-> ncb_lana_num ].Buffer == NULL ) ) {
// no such adapter
NCB_COMPLETE( pdncb, NRC_BRIDGE );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
if ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL ) {
// adapter not installed
NCB_COMPLETE( pdncb, NRC_ENVNOTDEF );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
plana = pfcb->ppLana[pdncb->ncb_lana_num];
if ( pdncb->ncb_command == NCBADDRESERVED ) {
index = 1;
NameLength = NCBNAMSZ;
} else {
if ( pdncb->ncb_command == NCBADDBROADCAST ) {
index = MAXIMUM_ADDRESS;
NameLength = pdncb->ncb_length;
} else {
//
// Ensure that the user has not added too many names or attempted to
// add the same name twice. If not then scan the address table looking
// for the next available slot.
//
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("NewAb: AddressCount: %lx, MaximumAddress %lx\n",
plana->AddressCount,
plana->MaximumAddresses ));
}
//
// If the application has added the number of names requested
// or has filled the table, refuse the request.
//
if ( plana->MaximumAddresses == plana->AddressCount) {
NCB_COMPLETE( pdncb, NRC_NAMTFUL );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
//
// Scan the name table and ensure that the name isn't already
// there.
//
if (( FindAb(pfcb, pdncb, FALSE) != NULL) ||
( pdncb->ncb_retcode != NRC_NOWILD)) {
//
// error is set to DUPNAME iff FindAb found the name
// in all other cases FindAb sets the error code and sets
// returns the address block.
//
NCB_COMPLETE( pdncb, NRC_DUPNAME );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
//
// Find the appropriate name number to use.
//
index = plana->NextAddress;
while ( plana->AddressBlocks[index] != NULL ) {
index++;
if ( index == MAXIMUM_ADDRESS ) {
index = 2;
}
}
// reset retcode so that NCB_COMPLETE will process the NCB.
pdncb->ncb_retcode = NRC_PENDING;
NameLength = NCBNAMSZ;
}
}
if ( plana->AddressBlocks[index] != NULL ) {
NCB_COMPLETE( pdncb, NRC_DUPNAME );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
pab = ExAllocatePoolWithTag (NonPagedPool, sizeof(AB), 'aSBN');
if (pab==NULL) {
NCB_COMPLETE( pdncb, NbMakeNbError( STATUS_INSUFFICIENT_RESOURCES ) );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
pab->AddressHandle = NULL;
pab->AddressObject = NULL;
pab->DeviceObject = NULL;
pab->NameNumber = (UCHAR)index;
pab->pLana = plana;
InitializeListHead(&pab->ReceiveAnyList);
InitializeListHead(&pab->ReceiveDatagramList);
InitializeListHead(&pab->ReceiveBroadcastDatagramList);
pab->NameLength = (UCHAR)NameLength;
RtlMoveMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ);
if (((pdncb->ncb_command & ~ASYNCH) == NCBADDNAME) ||
((pdncb->ncb_command & ~ASYNCH) == NCBQUICKADDNAME)) {
pab->Status = REGISTERING | UNIQUE_NAME;
} else {
pab->Status = REGISTERING | GROUP_NAME;
}
pab->CurrentUsers = 1;
plana->AddressBlocks[index] = pab;
pab->Signature = AB_SIGNATURE;
if (( pdncb->ncb_command != NCBADDRESERVED ) &&
( pdncb->ncb_command != NCBADDBROADCAST )) {
plana->AddressCount++;
plana->NextAddress = index + 1;
if ( plana->NextAddress == MAXIMUM_ADDRESS ) {
plana->NextAddress = 2;
}
}
Status = AllocateAndCopyUnicodeString(
&usDeviceName, &pfcb-> pDriverName[ pdncb-> ncb_lana_num ]
);
if ( !NT_SUCCESS( Status ) )
{
NCB_COMPLETE( pdncb, NRC_NORESOURCES);
ExFreePool( pab );
plana->AddressBlocks[index] = NULL;
if (( pdncb->ncb_command != NCBADDRESERVED ) &&
( pdncb->ncb_command != NCBADDBROADCAST )) {
plana->AddressCount--;
}
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
return NULL;
}
// Unlock so other Ncb's can be processed while adding the name.
UNLOCK_RESOURCE( pfcb );
Status = NbOpenAddress (
&hFileHandle,
(PVOID *)&pfoFileObject,
&usDeviceName,
pdncb->ncb_lana_num,
pdncb
);
LOCK_RESOURCE( pfcb );
//
// In the interval when no locks were held it is possible that
// the Lana could have been unbound. Verify that Lana is still
// present before accessing it.
//
if (!NT_SUCCESS(Status)) {
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint(( "\n FAILED on open of %s %X ******\n",
pdncb->ncb_name,
Status ));
}
if ( pfcb->ppLana[pdncb->ncb_lana_num] == plana )
{
//
// Lana is still available. Do normal error processing
//
NCB_COMPLETE( pdncb, NbMakeNbError( Status ) );
ExFreePool( pab );
plana->AddressBlocks[index] = NULL;
if (( pdncb->ncb_command != NCBADDRESERVED ) &&
( pdncb->ncb_command != NCBADDBROADCAST )) {
plana->AddressCount--;
}
}
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
if ( usDeviceName.Buffer != NULL )
{
ExFreePool( usDeviceName.Buffer );
}
return NULL;
}
else
{
//
// NbOpenAddress succeeded. Make sure Lana is still there.
//
if ( plana == pfcb->ppLana[pdncb->ncb_lana_num] )
{
//
// assume if lana is uncahnged pab points to a valid address
// block entry. Update the fields.
//
pab-> AddressHandle = hFileHandle;
pab-> AddressObject = pfoFileObject;
}
else
{
//
// Lana presumed to be removed on account of an unbind.
//
NCB_COMPLETE( pdncb, NRC_BRIDGE );
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
NbAddressClose( hFileHandle, (PVOID) pfoFileObject );
if ( usDeviceName.Buffer != NULL )
{
ExFreePool( usDeviceName.Buffer );
}
return NULL;
}
}
// Inform the application of the address number.
pdncb->ncb_num = (UCHAR) index;
//
// Register the event handlers for this address.
//
// Get the address of the device object for the endpoint.
pab->DeviceObject = IoGetRelatedDeviceObject(pab->AddressObject);
//
// No connections are made using the broadcast address so don't register disconnect or
// receive indication handlers. The ReceiveDatagram handler will get registered if the
// application requests a receive broadcast datagram. This will cut down the cpu load
// when the application is not interested in broadcasts. We always register the error
// indication handler on the broadcast address because it is the only address which is
// always open to the transport.
//
if ( pdncb->ncb_command != NCBADDBROADCAST ) {
Status = NbSetEventHandler( pab->DeviceObject,
pab->AddressObject,
TDI_EVENT_RECEIVE,
(PVOID)NbTdiReceiveHandler,
pab);
ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
Status = NbSetEventHandler( pab->DeviceObject,
pab->AddressObject,
TDI_EVENT_DISCONNECT,
(PVOID)NbTdiDisconnectHandler,
pab);
ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
Status = NbSetEventHandler( pab->DeviceObject,
pab->AddressObject,
TDI_EVENT_RECEIVE_DATAGRAM,
(PVOID)NbTdiDatagramHandler,
pab);
ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
pab->ReceiveDatagramRegistered = TRUE;
} else {
Status = NbSetEventHandler( pab->DeviceObject,
pab->AddressObject,
TDI_EVENT_ERROR,
(PVOID)NbTdiErrorHandler,
plana);
ASSERT( NT_SUCCESS(Status) || (Status == STATUS_INVALID_DEVICE_STATE) || (Status == STATUS_INSUFFICIENT_RESOURCES));
pab->ReceiveDatagramRegistered = FALSE;
}
pab->Status |= REGISTERED;
UNLOCK_RESOURCE( pfcb );
ExReleaseResourceLite( &pfcb->AddResource );
KeLeaveCriticalRegion();
if ( usDeviceName.Buffer != NULL )
{
ExFreePool( usDeviceName.Buffer );
}
NCB_COMPLETE( pdncb, NRC_GOODRET );
return pab;
}
VOID
CleanupAb(
IN PPAB ppab,
IN BOOLEAN CloseAddress
)
/*++
Routine Description:
This closes the handles in the Ab and deletes the Address Block.
During this routine we need the spinlock held to prevent an indication accessing
a Receive while we are cancelling it.
Note: Resource must be held before calling this routine.
Arguments:
pab - Address of the pointer to the Ab to be destroyed.
CloseAddress - TRUE if Address block is to be destroyed immediately.
Return Value:
nothing.
--*/
{
PAB pab = *ppab;
PAB pab255;
PFCB pfcb = (*ppab)->pLana->pFcb;
PLANA_INFO plana = (*ppab)->pLana;
KIRQL OldIrql; // Used when SpinLock held.
PLIST_ENTRY ReceiveEntry;
LOCK_SPINLOCK( pfcb, OldIrql );
ASSERT( pab->Signature == AB_SIGNATURE );
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("CleanupAb ppab: %lx, pab: %lx, CurrentUsers: %lx, State: %x\n",
ppab,
pab,
pab->CurrentUsers,
pab->Status));
NbFormattedDump( (PUCHAR)&pab->Name, sizeof(NAME) );
}
if ( (pab->Status & 0x7) != DEREGISTERED ) {
PDNCB pdncb;
pab->Status |= DEREGISTERED;
//
// This is the first time through so cancel all the receive datagram
// requests for this address.
while ( (pdncb = DequeueRequest( &pab->ReceiveDatagramList)) != NULL ) {
UNLOCK_SPINLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_NAMERR );
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
LOCK_SPINLOCK( pfcb, OldIrql );
}
while ( (pdncb = DequeueRequest( &pab->ReceiveBroadcastDatagramList)) != NULL ) {
UNLOCK_SPINLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_NAMERR );
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
LOCK_SPINLOCK( pfcb, OldIrql );
}
while ( (pdncb = DequeueRequest( &pab->ReceiveAnyList)) != NULL ) {
UNLOCK_SPINLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_NAMERR );
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
LOCK_SPINLOCK( pfcb, OldIrql );
}
// The IBM Mif081 test requires ReceiveBroadcast Any with this name to be cancelled.
pab255 = plana->AddressBlocks[MAXIMUM_ADDRESS];
//
// check for null pointer. Added to fix stress bug
//
// V Raman
//
if ( pab255 != NULL )
{
ReceiveEntry = pab255->ReceiveBroadcastDatagramList.Flink;
while ( ReceiveEntry != &pab255->ReceiveBroadcastDatagramList ) {
PLIST_ENTRY NextReceiveEntry = ReceiveEntry->Flink;
PDNCB pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
if ( pab->NameNumber == pdncb->ncb_num ) {
PIRP Irp;
RemoveEntryList( &pdncb->ncb_next );
Irp = pdncb->irp;
IoAcquireCancelSpinLock(&Irp->CancelIrql);
//
// Remove the cancel request for this IRP. If its cancelled then its
// ok to just process it because we will be returning it to the caller.
//
Irp->Cancel = FALSE;
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(Irp->CancelIrql);
UNLOCK_SPINLOCK( pfcb, OldIrql );
NCB_COMPLETE( pdncb, NRC_NAMERR );
pdncb->irp->IoStatus.Information = FIELD_OFFSET( DNCB, ncb_cmd_cplt );
NbCompleteRequest( pdncb->irp, STATUS_SUCCESS );
LOCK_SPINLOCK( pfcb, OldIrql );
}
ReceiveEntry = NextReceiveEntry;
}
}
UNLOCK_SPINLOCK( pfcb, OldIrql );
CloseListens( pfcb, ppab );
LOCK_SPINLOCK( pfcb, OldIrql );
}
UNLOCK_SPINLOCK( pfcb, OldIrql );
if ( ( pab->AddressHandle != NULL ) &&
(( CloseAddress == TRUE ) || ( pab->CurrentUsers == 1 )) ){
IF_NBDBG( NB_DEBUG_ADDRESS )
{
NbPrint( (
"CleanupAb : Close file invoked for \n"
) );
NbFormattedDump( (PUCHAR) &pab-> Name, sizeof( NAME ) );
}
NbAddressClose( pab->AddressHandle, pab->AddressObject );
pab->AddressHandle = NULL;
}
DEREFERENCE_AB(ppab);
}
VOID
NbAddressClose(
IN HANDLE AddressHandle,
IN PVOID Object
)
/*++
Routine Description:
Remove close the handle and dereference the address.
Arguments:
AddressHandle
Object
Return Value:
None.
--*/
{
NTSTATUS localstatus;
KAPC_STATE ApcState;
PAGED_CODE();
ObDereferenceObject( Object );
if (PsGetCurrentProcess() != NbFspProcess) {
KeStackAttachProcess(NbFspProcess, &ApcState);
localstatus = ZwClose( AddressHandle);
ASSERT(NT_SUCCESS(localstatus));
KeUnstackDetachProcess(&ApcState);
} else {
localstatus = ZwClose( AddressHandle);
ASSERT(NT_SUCCESS(localstatus));
}
}
PPAB
FindAb(
IN PFCB pfcb,
IN PDNCB pdncb,
IN BOOLEAN IncrementUsers
)
/*++
Routine Description:
This routine uses the callers lana number and Name to find the Address
Block that corresponds to the Ncb. Note, it returns the address of the
relevant plana->AddressBlocks entry so that deletion of the address
block is simpler.
Arguments:
pfcb - Supplies a pointer to the Fcb that Ab is chained onto.
pdncb - Supplies the connection id from the applications point of view.
IncrementUsers - TRUE iff performing a listen or call so increment CurrentUsers
Return Value:
Address of the pointer to the address block or NULL.
--*/
{
PLANA_INFO plana;
PAB pab;
int index;
if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
( pfcb == NULL ) ||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("FindAb pfcb: %lx, lana: %lx Failed, returning NULL\n",
pfcb,
pdncb->ncb_lana_num));
}
NCB_COMPLETE( pdncb, NRC_BRIDGE );
return NULL;
}
ASSERT( pfcb->Signature == FCB_SIGNATURE );
plana = pfcb->ppLana[pdncb->ncb_lana_num];
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("FindAb pfcb: %lx, lana: %lx, lsn: %lx\n",
pfcb,
pdncb->ncb_lana_num,
pdncb->ncb_lsn));
}
for ( index = 0; index <= MAXIMUM_ADDRESS; index++ ) {
pab = plana->AddressBlocks[index];
if (( pab != NULL ) &&
(RtlEqualMemory( &pab->Name, pdncb->ncb_name, NCBNAMSZ))) {
ASSERT( pab->Signature == AB_SIGNATURE );
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("ppab %lx, pab: %lx, state:%x\n",
&plana->AddressBlocks[index],
plana->AddressBlocks[index],
pab->Status));
NbFormattedDump( (PUCHAR)&pab->Name, sizeof(NAME) );
}
if ( (pab->Status & 0x07) != REGISTERED ) {
NCB_COMPLETE( pdncb, NRC_NOWILD );
//
// The name is in a bad state. Tell NewAb not to add the name by
// returning non-null. Don't reference the AB.
//
if (( (pdncb->ncb_command & ~ ASYNCH) == NCBADDNAME ) ||
( (pdncb->ncb_command & ~ ASYNCH) == NCBQUICKADDNAME ) ||
( (pdncb->ncb_command & ~ ASYNCH) == NCBQUICKADDGRNAME ) ||
( (pdncb->ncb_command & ~ ASYNCH) == NCBADDGRNAME )) {
return &plana->AddressBlocks[index];
} else {
// Not NewAb so return Null as usual.
return NULL;
}
}
if ( IncrementUsers == TRUE ) {
REFERENCE_AB(pab);
}
return &plana->AddressBlocks[index];
}
}
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("Failed return NULL\n"));
}
NCB_COMPLETE( pdncb, NRC_NOWILD );
return NULL;
}
PPAB
FindAbUsingNum(
IN PFCB pfcb,
IN PDNCB pdncb,
IN UCHAR NameNumber
)
/*++
Routine Description:
This routine uses the callers lana number and name number to find the
Address Block that corresponds to the Ncb.
Note, it returns the address of the relevant plana->AddressBlocks entry
so that deletion of the address block is simpler.
Arguments:
pfcb - Supplies a pointer to the Fcb that Ab is chained onto.
pdncb - Supplies the applications NCB.
NameNumber - Supplies the name number to look for. This is not equal to pdncb->ncb_num
when manipulating broadcast datagrams.
Return Value:
Address of the pointer to the address block or NULL.
--*/
{
PLANA_INFO plana;
if (( pdncb->ncb_lana_num > pfcb->MaxLana ) ||
( pfcb == NULL ) ||
( pfcb->ppLana[pdncb->ncb_lana_num] == NULL) ||
( pfcb->ppLana[pdncb->ncb_lana_num]->Status != NB_INITIALIZED) ) {
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("FindAbUsingNum pfcb: %lx, lana: %lx Failed, returning NULL\n",
pfcb,
pdncb->ncb_lana_num));
}
NCB_COMPLETE( pdncb, NRC_BRIDGE );
return NULL;
}
ASSERT( pfcb->Signature == FCB_SIGNATURE );
plana = pfcb->ppLana[pdncb->ncb_lana_num];
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("FindAbUsingNum pfcb: %lx, lana: %lx, num: %lx\n",
pfcb,
pdncb->ncb_lana_num,
NameNumber));
}
if (( NameNumber < (UCHAR)MAXIMUM_ADDRESS ) &&
( plana->AddressBlocks[NameNumber] != NULL) &&
(( plana->AddressBlocks[NameNumber]->Status & 0x7) == REGISTERED )) {
return &plana->AddressBlocks[NameNumber];
}
//
// The user is allowed to receive any and receive broadcast
// datagrams on address 255.
//
if ((( NameNumber == MAXIMUM_ADDRESS ) &&
( plana->AddressBlocks[NameNumber] != NULL)) &&
(( (pdncb->ncb_command & ~ASYNCH) == NCBRECVANY ) ||
( (pdncb->ncb_command & ~ASYNCH) == NCBDGRECVBC ) ||
( (pdncb->ncb_command & ~ASYNCH) == NCBDGSENDBC ) ||
( (pdncb->ncb_command & ~ASYNCH) == NCBDGRECV ))) {
return &plana->AddressBlocks[NameNumber];
}
IF_NBDBG (NB_DEBUG_ADDRESS) {
NbPrint( ("Failed return NULL\n"));
}
NCB_COMPLETE( pdncb, NRC_ILLNN );
return NULL;
}
NTSTATUS
NbSetEventHandler (
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject,
IN ULONG EventType,
IN PVOID EventHandler,
IN PVOID Context
)
/*++
Routine Description:
This routine registers an event handler with a TDI transport provider.
Arguments:
IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
IN PFILE_OBJECT FileObject - Supplies the address object's file object.
IN ULONG EventType, - Supplies the type of event.
IN PVOID EventHandler - Supplies the event handler.
IN PVOID Context - Supplies the PAB or PLANA_INFO associated with this event.
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
NTSTATUS Status;
PIRP Irp;
PAGED_CODE();
Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
if (Irp == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
NULL, NULL,
EventType, EventHandler, Context);
Status = SubmitTdiRequest(FileObject, Irp);
IoFreeIrp(Irp);
return Status;
}
NTSTATUS
SubmitTdiRequest (
IN PFILE_OBJECT FileObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine submits a request to TDI and waits for it to complete.
Arguments:
IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
IN PIRP Irp - TDI request to submit.
Return Value:
NTSTATUS - Final status of request.
--*/
{
KEVENT Event;
NTSTATUS Status;
PAGED_CODE();
KeInitializeEvent (&Event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, NbCompletionEvent, &Event, TRUE, TRUE, TRUE);
Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
//
// If it failed immediately, return now, otherwise wait.
//
if (!NT_SUCCESS(Status)) {
return Status;
}
if (Status == STATUS_PENDING) {
Status = KeWaitForSingleObject(&Event, // Object to wait on.
Executive, // Reason for waiting
KernelMode, // Processor mode
FALSE, // Alertable
NULL); // Timeout
if (!NT_SUCCESS(Status)) {
IoFreeIrp ( Irp );
return Status;
}
Status = Irp->IoStatus.Status;
}
return(Status);
}