/*++ 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 #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****** Start of AddName ****** 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(( "\n****** Start of NbDeleteName ****** pdncb %lx\n", pdncb )); } 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 PFCB pfcb, 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; 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, &pfcb->pDriverName[LanNumber], 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) { KeAttachProcess(NbFspProcess); ProcessAttached = TRUE; } 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; localstatus = ZwClose( *FileHandle); ASSERT(NT_SUCCESS(localstatus)); *FileHandle = NULL; } } if (ProcessAttached) { KeDetachProcess(); } 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; PAGED_CODE(); // Prevent resets while we add the name ExAcquireResourceShared ( &pfcb->AddResource, TRUE ); LOCK_RESOURCE( pfcb ); IF_NBDBG (NB_DEBUG_ADDRESS) { NbPrint( ("NewAb: lana: %lx Address:\n", pdncb->ncb_lana_num )); NbFormattedDump( (PUCHAR) pdncb->ncb_name, sizeof(NAME) ); } if ( pdncb->ncb_lana_num > pfcb->MaxLana ) { // no such adapter NCB_COMPLETE( pdncb, NRC_BRIDGE ); UNLOCK_RESOURCE( pfcb ); ExReleaseResource( &pfcb->AddResource ); return NULL; } if (( pfcb == NULL ) || ( pfcb->ppLana[pdncb->ncb_lana_num] == NULL )) { // adapter not installed NCB_COMPLETE( pdncb, NRC_ENVNOTDEF ); UNLOCK_RESOURCE( pfcb ); ExReleaseResource( &pfcb->AddResource ); 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 ); ExReleaseResource( &pfcb->AddResource ); 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 ); ExReleaseResource( &pfcb->AddResource ); 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 ); ExReleaseResource( &pfcb->AddResource ); return NULL; } pab = ExAllocatePoolWithTag (NonPagedPool, sizeof(AB), 'aSBN'); if (pab==NULL) { NCB_COMPLETE( pdncb, NbMakeNbError( STATUS_INSUFFICIENT_RESOURCES ) ); UNLOCK_RESOURCE( pfcb ); ExReleaseResource( &pfcb->AddResource ); 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; } } // Unlock so other Ncb's can be processed while adding the name. UNLOCK_RESOURCE( pfcb ); Status = NbOpenAddress (&pab->AddressHandle, (PVOID *)&pab->AddressObject, pfcb, pdncb->ncb_lana_num, pdncb); LOCK_RESOURCE( pfcb ); if (!NT_SUCCESS(Status)) { IF_NBDBG (NB_DEBUG_ADDRESS) { NbPrint(( "\n FAILED on open of %s %X ******\n", pdncb->ncb_name, Status )); } 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 ); ExReleaseResource( &pfcb->AddResource ); 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 = NbSetEventHandler( pab->DeviceObject, pab->AddressObject, TDI_EVENT_DISCONNECT, (PVOID)NbTdiDisconnectHandler, pab); ASSERT( NT_SUCCESS(Status) ); Status = NbSetEventHandler( pab->DeviceObject, pab->AddressObject, TDI_EVENT_RECEIVE_DATAGRAM, (PVOID)NbTdiDatagramHandler, pab); ASSERT( NT_SUCCESS(Status) ); pab->ReceiveDatagramRegistered = TRUE; } else { Status = NbSetEventHandler( pab->DeviceObject, pab->AddressObject, TDI_EVENT_ERROR, (PVOID)NbTdiErrorHandler, plana); ASSERT( NT_SUCCESS(Status) ); pab->ReceiveDatagramRegistered = FALSE; } pab->Status |= REGISTERED; UNLOCK_RESOURCE( pfcb ); ExReleaseResource( &pfcb->AddResource ); 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 )) ){ 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; PAGED_CODE(); ObDereferenceObject( Object ); if (PsGetCurrentProcess() != NbFspProcess) { KeAttachProcess(NbFspProcess); localstatus = ZwClose( AddressHandle); ASSERT(NT_SUCCESS(localstatus)); KeDetachProcess(); } 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 ", 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); }