diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isnp/nb/address.c | 2406 |
1 files changed, 2406 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/nb/address.c b/private/ntos/tdi/isnp/nb/address.c new file mode 100644 index 000000000..2eb882b80 --- /dev/null +++ b/private/ntos/tdi/isnp/nb/address.c @@ -0,0 +1,2406 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + address.c + +Abstract: + + This module contains code which implements the ADDRESS object. + Routines are provided to create, destroy, reference, and dereference, + transport address objects. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + + +// +// Map all generic accesses to the same one. +// + +static GENERIC_MAPPING AddressGenericMapping = + { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL }; + + + +TDI_ADDRESS_NETBIOS UNALIGNED * +NbiParseTdiAddress( + IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress, + IN BOOLEAN BroadcastAddressOk + ) + +/*++ + +Routine Description: + + This routine scans a TRANSPORT_ADDRESS, looking for an address + of type TDI_ADDRESS_TYPE_NETBIOS. + +Arguments: + + Transport - The generic TDI address. + + BroadcastAddressOk - TRUE if we should return the broadcast + address if found. If so, a value of (PVOID)-1 indicates + the broadcast address. + +Return Value: + + A pointer to the Netbios address, or NULL if none is found, + or (PVOID)-1 if the broadcast address is found. + +--*/ + +{ + TA_ADDRESS UNALIGNED * addressName; + INT i; + + addressName = &TransportAddress->Address[0]; + + // + // The name can be passed with multiple entries; we'll take and use only + // the Netbios one. + // + + for (i=0;i<TransportAddress->TAAddressCount;i++) { + if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) { + if ((addressName->AddressLength == 0) && + BroadcastAddressOk) { + return (PVOID)-1; + } else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS)) { + return ((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address)); + } + } + addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address + + addressName->AddressLength); + } + return NULL; + +} /* NbiParseTdiAddress */ + + +BOOLEAN +NbiValidateTdiAddress( + IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress, + IN ULONG TransportAddressLength + ) + +/*++ + +Routine Description: + + This routine scans a TRANSPORT_ADDRESS, verifying that the + components of the address do not extend past the specified + length. + +Arguments: + + TransportAddress - The generic TDI address. + + TransportAddressLength - The specific length of TransportAddress. + +Return Value: + + TRUE if the address is valid, FALSE otherwise. + +--*/ + +{ + PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength; + TA_ADDRESS UNALIGNED * addressName; + INT i; + + if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) { + NbiPrint0 ("NbfValidateTdiAddress: runt address\n"); + return FALSE; + } + + addressName = &TransportAddress->Address[0]; + + for (i=0;i<TransportAddress->TAAddressCount;i++) { + if (addressName->Address > AddressEnd) { + NbiPrint0 ("NbiValidateTdiAddress: address too short\n"); + return FALSE; + } + addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address + + addressName->AddressLength); + } + + if ((PUCHAR)addressName > AddressEnd) { + NbiPrint0 ("NbiValidateTdiAddress: address too short\n"); + return FALSE; + } + return TRUE; + +} /* NbiValidateTdiAddress */ + + +NTSTATUS +NbiOpenAddress( + IN PDEVICE Device, + IN PREQUEST Request + ) + +/*++ + +Routine Description: + + This routine opens a file that points to an existing address object, or, if + the object doesn't exist, creates it (note that creation of the address + object includes registering the address, and may take many seconds to + complete, depending upon system configuration). + + If the address already exists, and it has an ACL associated with it, the + ACL is checked for access rights before allowing creation of the address. + +Arguments: + + Device - pointer to the device describing the Netbios transport. + + Request - a pointer to the request used for the creation of the address. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + NTSTATUS status; + PADDRESS Address; + PADDRESS_FILE AddressFile; + PFILE_FULL_EA_INFORMATION ea; + TRANSPORT_ADDRESS UNALIGNED *name; + TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress; + ULONG DesiredShareAccess; + CTELockHandle LockHandle; + PACCESS_STATE AccessState; + ACCESS_MASK GrantedAccess; + BOOLEAN AccessAllowed; + BOOLEAN found = FALSE; +#ifdef ISN_NT + PIRP Irp = (PIRP)Request; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); +#endif +#if 0 + TA_NETBIOS_ADDRESS FakeAddress; +#endif + + + // + // The network name is in the EA, passed in the request. + // + + ea = OPEN_REQUEST_EA_INFORMATION(Request); + if (ea == NULL) { + NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request); + return STATUS_INVALID_ADDRESS_COMPONENT; + } + + // + // this may be a valid name; parse the name from the EA and use it if OK. + // + + name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1]; +#if 0 + TdiBuildNetbiosAddress( + "ADAMBA67 ", + FALSE, + &FakeAddress); + name = (PTRANSPORT_ADDRESS)&FakeAddress; +#endif + + // + // The name can be passed with multiple entries; we'll take and use only + // the first one of type Netbios. This call returns (PVOID)-1 if the + // address is the broadcast address. + // + + NetbiosAddress = NbiParseTdiAddress (name, TRUE); + + if (NetbiosAddress == NULL) { + NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request); + return STATUS_INVALID_ADDRESS_COMPONENT; + } + + // + // get an address file structure to represent this address. + // + + AddressFile = NbiCreateAddressFile (Device); + + if (AddressFile == (PADDRESS_FILE)NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // See if this address is already established. This call automatically + // increments the reference count on the address so that it won't disappear + // from underneath us after this call but before we have a chance to use it. + // + // To ensure that we don't create two address objects for the + // same address, we hold the device context addressResource until + // we have found the address or created a new one. + // + + ExAcquireResourceExclusive (&Device->AddressResource, TRUE); + +#if defined(_PNP_POWER) + + Address = NbiFindAddress ( + Device, + ( NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1 : NetbiosAddress->NetbiosName + ); + + if (Address == NULL) { + +#else + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + Address = NbiLookupAddress (Device, NetbiosAddress); + + if (Address == NULL) { + + NB_FREE_LOCK (&Device->Lock, LockHandle); + +#endif _PNP_POWER + + // + // This address doesn't exist. Create it. + // This initializes the address with a ref + // of type ADDRESS_FILE, so if we fail here + // we need to remove that. + // + + Address = NbiCreateAddress ( + Device, + NetbiosAddress); + + if (Address != (PADDRESS)NULL) { + + // + // Set this now in case we have to deref. + // + + AddressFile->AddressLock = &Address->Lock; + +#ifdef ISN_NT + + // + // Initialize the shared access now. We use read access + // to control all access. + // + + DesiredShareAccess = (ULONG) + (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) || + (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ? + FILE_SHARE_READ : 0); + + IoSetShareAccess( + FILE_READ_DATA, + DesiredShareAccess, + IrpSp->FileObject, + &Address->u.ShareAccess); + + + // + // Assign the security descriptor (need to do this with + // the spinlock released because the descriptor is not + // mapped). + // + + AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + + status = SeAssignSecurity( + NULL, // parent descriptor + AccessState->SecurityDescriptor, + &Address->SecurityDescriptor, + FALSE, // is directory + &AccessState->SubjectSecurityContext, + &AddressGenericMapping, + NonPagedPool); + + if (!NT_SUCCESS(status)) { + + // + // Error, return status. + // + + IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess); + ExReleaseResource (&Device->AddressResource); + NbiDereferenceAddress (Address, AREF_ADDRESS_FILE); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + return status; + + } + +#endif + + ExReleaseResource (&Device->AddressResource); + + // + // if the adapter isn't ready, we can't do any of this; get out + // +#if defined(_PNP_POWER) + if (Device->State != DEVICE_STATE_OPEN) { +#else + if (Device->State == DEVICE_STATE_STOPPING) { +#endif _PNP_POWER + NbiDereferenceAddress (Address, AREF_ADDRESS_FILE); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + status = STATUS_DEVICE_NOT_READY; + + } else { + + REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile; + REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; +#ifdef ISN_NT + AddressFile->FileObject = IrpSp->FileObject; +#endif + AddressFile->Address = Address; + + NB_INSERT_TAIL_LIST( + &Address->AddressFileDatabase, + &AddressFile->Linkage, + &Address->Lock); + + if (NetbiosAddress == (PVOID)-1) { + + AddressFile->OpenRequest = NULL; + AddressFile->State = ADDRESSFILE_STATE_OPEN; + status = STATUS_SUCCESS; + + } else { + + AddressFile->OpenRequest = Request; + AddressFile->State = ADDRESSFILE_STATE_OPENING; + status = STATUS_PENDING; + + NbiStartRegistration (Address); + } + + } + + } else { + + ExReleaseResource (&Device->AddressResource); + + // + // If the address could not be created, and is not in the + // process of being created, then we can't open up an address. + // Since we can't use the AddressLock to deref, we just destroy + // the address file. + // + + NbiDestroyAddressFile (AddressFile); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + } else { + +#if !defined(_PNP_POWER) + NB_FREE_LOCK (&Device->Lock, LockHandle); + +#endif !_PNP_POWER + NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address)); + + // + // Set this now in case we have to deref. + // + + AddressFile->AddressLock = &Address->Lock; + + // + // Make sure the types do not conflict. + // + + if ((NetbiosAddress != (PVOID)-1) && + (NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) { + + NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address)); + ExReleaseResource (&Device->AddressResource); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + status = STATUS_DUPLICATE_NAME; + + } else { + + // + // The address already exists. Check the ACL and see if we + // can access it. If so, simply use this address as our address. + // + +#ifdef ISN_NT + + AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + + AccessAllowed = SeAccessCheck( + Address->SecurityDescriptor, + &AccessState->SubjectSecurityContext, + FALSE, // tokens locked + IrpSp->Parameters.Create.SecurityContext->DesiredAccess, + (ACCESS_MASK)0, // previously granted + NULL, // privileges + &AddressGenericMapping, + Irp->RequestorMode, + &GrantedAccess, + &status); + +#else // ISN_NT + + AccessAllowed = TRUE; + +#endif // ISN_NT + + if (!AccessAllowed) { + + NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address)); + ExReleaseResource (&Device->AddressResource); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + + } else { + +#ifdef ISN_NT + + // + // Now check that we can obtain the desired share + // access. We use read access to control all access. + // + + DesiredShareAccess = (ULONG) + (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) || + (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ? + FILE_SHARE_READ : 0); + + status = IoCheckShareAccess( + FILE_READ_DATA, + DesiredShareAccess, + IrpSp->FileObject, + &Address->u.ShareAccess, + TRUE); + +#else // ISN_NT + + status = STATUS_SUCCESS; + +#endif // ISN_NT + + if (!NT_SUCCESS (status)) { + + NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address)); + ExReleaseResource (&Device->AddressResource); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + + } else { + + ExReleaseResource (&Device->AddressResource); + + NB_GET_LOCK (&Address->Lock, &LockHandle); + + // + // Insert the address file on the address + // list; we will pend this open if the address + // is still registering. If the address has + // already failed as duplicate, then we + // fail the open. + // + + if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) { + + NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address)); + NB_FREE_LOCK (&Address->Lock, LockHandle); + + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + status = STATUS_DUPLICATE_NAME; + + } else { + + InsertTailList ( + &Address->AddressFileDatabase, + &AddressFile->Linkage); + + // + // Start registration unless it is registered or + // it is the broadcast address. + // + + if ((Address->State == ADDRESS_STATE_REGISTERING) && + (NetbiosAddress != (PVOID)-1)) { + + AddressFile->OpenRequest = Request; + AddressFile->State = ADDRESSFILE_STATE_OPENING; + status = STATUS_PENDING; + + } else { + + AddressFile->OpenRequest = NULL; + AddressFile->State = ADDRESSFILE_STATE_OPEN; + status = STATUS_SUCCESS; + } + + AddressFile->Address = Address; +#ifdef ISN_NT + AddressFile->FileObject = IrpSp->FileObject; +#endif + + NbiReferenceAddress (Address, AREF_ADDRESS_FILE); + + REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile; + REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; + + NB_FREE_LOCK (&Address->Lock, LockHandle); + + } + + } + } + } + + // + // Remove the reference from NbiLookupAddress. + // + + NbiDereferenceAddress (Address, AREF_LOOKUP); + } + + return status; + +} /* NbiOpenAddress */ + + +VOID +NbiStartRegistration( + IN PADDRESS Address + ) + +/*++ + +Routine Description: + + This routine starts the registration process for a netbios name + by sending out the first add name packet and starting the timer + so that NbiRegistrationTimeout is called after the correct timeout. + +Arguments: + + Address - The address which is to be registered. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + + NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address)); + + // + // First send out an add name packet. + // + + NbiSendNameFrame( + Address, + (UCHAR)(Address->NameTypeFlag | NB_NAME_USED), + NB_CMD_ADD_NAME, + NULL, + NULL); + + Address->RegistrationCount = 0; + + // + // Now start the timer. + // + + NbiReferenceAddress (Address, AREF_TIMER); + + CTEInitTimer (&Address->RegistrationTimer); + CTEStartTimer( + &Address->RegistrationTimer, + Address->Device->BroadcastTimeout, + NbiRegistrationTimeout, + (PVOID)Address); + +} /* NbiStartRegistration */ + + +VOID +NbiRegistrationTimeout( + IN CTEEvent * Event, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is called when the address registration + timer expires. It sends another add name if needed, or + checks the result if the correct number have been sent. + +Arguments: + + Event - The event used to queue the timer. + + Context - The context, which is the address pointer. + +Return Value: + + None. + +--*/ + +{ + PADDRESS Address = (PADDRESS)Context; + CTELockHandle LockHandle; + PADDRESS_FILE AddressFile, ReferencedAddressFile; + PLIST_ENTRY p; + + ++Address->RegistrationCount; + + if ((Address->RegistrationCount < Address->Device->BroadcastCount) && + ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) { + + NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address)); + + NbiSendNameFrame( + Address, + (UCHAR)(Address->NameTypeFlag | NB_NAME_USED), + NB_CMD_ADD_NAME, + NULL, + NULL); + + CTEStartTimer( + &Address->RegistrationTimer, + Address->Device->BroadcastTimeout, + NbiRegistrationTimeout, + (PVOID)Address); + + } else { + + // + // The correct number of frames have been sent, see what + // happened. + // + + NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address)); + + ReferencedAddressFile = NULL; + + NB_GET_LOCK (&Address->Lock, &LockHandle); + + if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) { + Address->State = ADDRESS_STATE_OPEN; + } else { + Address->State = ADDRESS_STATE_STOPPING; + } + + for (p = Address->AddressFileDatabase.Flink; + p != &Address->AddressFileDatabase; + p = p->Flink) { + + AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage); + CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING); + CTEAssert (AddressFile->OpenRequest != NULL); + + NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT); + + NB_FREE_LOCK (&Address->Lock, LockHandle); + + if (ReferencedAddressFile) { + NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT); + } + + // + // Now see what to do with this address file. + // + + REQUEST_INFORMATION(AddressFile->OpenRequest) = 0; + + if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) { + + NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile)); + REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME; + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + + } else { + + NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile)); + REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS; + AddressFile->State = ADDRESSFILE_STATE_OPEN; + + } + + NbiCompleteRequest (AddressFile->OpenRequest); + NbiFreeRequest (Address->Device, AddressFile->OpenRequest); + + NB_GET_LOCK (&Address->Lock, &LockHandle); + + ReferencedAddressFile = AddressFile; + + } + + NB_FREE_LOCK (&Address->Lock, LockHandle); + + if (ReferencedAddressFile) { + NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT); + } + + NbiDereferenceAddress (Address, AREF_TIMER); + + } + +} /* NbiRegistrationTimeout */ + + +VOID +NbiProcessFindName( + IN PIPX_LOCAL_TARGET RemoteAddress, + IN ULONG MacOptions, + IN PUCHAR PacketBuffer, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine handles NB_CMD_FIND_NAME frames. + +Arguments: + + RemoteAddress - The local target this packet was received from. + + MacOptions - The MAC options for the underlying NDIS binding. + + LookaheadBuffer - The packet data, starting at the IPX + header. + + PacketSize - The total length of the packet, starting at the + IPX header. + +Return Value: + + None. + +--*/ + +{ + PADDRESS Address; + NB_CONNECTIONLESS UNALIGNED * NbConnectionless = + (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer; + PDEVICE Device = NbiDevice; + + if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) { + return; + } + + // + // Quick check for any names starting with this character. + // + + if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) { + return; + } + + // + // Always respond to broadcast requests. + // +#if defined(_PNP_POWER) + if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) { + + NbiSendNameFrame( + NULL, + NB_NAME_DUPLICATED, // this is what Novell machines use + NB_CMD_NAME_RECOGNIZED, + RemoteAddress, + NbConnectionless); + + } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) { + + NbiSendNameFrame( + Address, + (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED), + NB_CMD_NAME_RECOGNIZED, + RemoteAddress, + NbConnectionless); + + NbiDereferenceAddress (Address, AREF_FIND); + + } else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) { + + NbiSendNameFrame( + NULL, + (UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED), + NB_CMD_NAME_RECOGNIZED, + RemoteAddress, + NbConnectionless); + } +#else + if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) { + + NbiSendNameFrame( + NULL, + NB_NAME_DUPLICATED, // this is what Novell machines use + NB_CMD_NAME_RECOGNIZED, + RemoteAddress, + (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork)); + + } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) { + + NbiSendNameFrame( + Address, + (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED), + NB_CMD_NAME_RECOGNIZED, + RemoteAddress, + (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork)); + + NbiDereferenceAddress (Address, AREF_FIND); + + } +#endif _PNP_POWER +} /* NbiProcessFindName */ + + +VOID +NbiProcessAddName( + IN PIPX_LOCAL_TARGET RemoteAddress, + IN ULONG MacOptions, + IN PUCHAR PacketBuffer, + IN UINT PacketSize + ) + +/*++ + +Routine Description: + + This routine handles NB_CMD_ADD_NAME frames. + +Arguments: + + RemoteAddress - The local target this packet was received from. + + MacOptions - The MAC options for the underlying NDIS binding. + + LookaheadBuffer - The packet data, starting at the IPX + header. + + PacketSize - The total length of the packet, starting at the + IPX header. + +Return Value: + + None. + +--*/ + +{ + PADDRESS Address; + NB_CONNECTIONLESS UNALIGNED * NbConnectionless = + (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer; + PDEVICE Device = NbiDevice; + CTELockHandle LockHandle; + BOOLEAN LocalFrame; + + + if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) { + return; + } + + // + // Ignore any frame that came from us, except for the purpose + // of updating the cache. + // + + if ((Device->Bind.QueryHandler)( + IPX_QUERY_IS_ADDRESS_LOCAL, +#if defined(_PNP_POWER) + &RemoteAddress->NicHandle, +#else + RemoteAddress->NicId, +#endif _PNP_POWER + NbConnectionless->IpxHeader.SourceNetwork, + sizeof(TDI_ADDRESS_IPX), + NULL) == STATUS_SUCCESS) { + + LocalFrame = TRUE; + + } else { + + LocalFrame = FALSE; + + } + + if (!LocalFrame) { + + if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) && + (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) { + + if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) { + + // + // If this frame is an add name (identified because it is a + // broadcast frame) then respond if we have it registered + // unique, or we have it group and someone is trying to add + // it unique. + // + + if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) || + ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) && + ((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) { + + // + // According to GeorgeJ's doc, on a name in use we just + // echo back the name type flags from the request. + // + + NbiSendNameFrame( + Address, + NbConnectionless->NameFrame.NameTypeFlag, + NB_CMD_NAME_IN_USE, + RemoteAddress, +#if defined(_PNP_POWER) + NbConnectionless); +#else + (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork)); +#endif _PNP_POWER + } + + } else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork == + *(UNALIGNED ULONG *)Device->Bind.Network) && + NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) { + + // + // If this is an add name response (which will be sent + // directly to us) then we need to mark the address + // as such. + // + + NB_GET_LOCK (&Address->Lock, &LockHandle); + Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME; + NB_FREE_LOCK (&Address->Lock, LockHandle); + } + + NbiDereferenceAddress (Address, AREF_FIND); + + } + + } + + + // + // Pass this frame over to the netbios cache management + // routines to check if they need to update their cache. + // + + CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame); + +} /* NbiProcessAddName */ + + +PADDRESS +NbiCreateAddress( + IN PDEVICE Device, + IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress + ) + +/*++ + +Routine Description: + + This routine creates a transport address and associates it with + the specified transport device context. The reference count in the + address is automatically set to 1, and the reference count of the + device context is incremented. + + NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND + RETURNS WITH IT HELD. + +Arguments: + + Device - Pointer to the device context (which is really just + the device object with its extension) to be associated with the + address. + + NetbiosAddress - The name to assign to this address, or -1 if it + is the broadcast address. + +Return Value: + + The newly created address, or NULL if none can be allocated. + +--*/ + +{ + PADDRESS Address; + + Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address"); + if (Address == NULL) { + NB_DEBUG (ADDRESS, ("Create address %.16s failed\n", + (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName)); + return NULL; + } + + NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address, + (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName)); + RtlZeroMemory (Address, sizeof(ADDRESS)); + + Address->Type = NB_ADDRESS_SIGNATURE; + Address->Size = sizeof (ADDRESS); + Address->State = ADDRESS_STATE_REGISTERING; + Address->Flags = 0; + + Address->Device = Device; + Address->DeviceLock = &Device->Lock; + CTEInitLock (&Address->Lock.Lock); + + InitializeListHead (&Address->AddressFileDatabase); + + Address->ReferenceCount = 1; +#if DBG + Address->RefTypes[AREF_ADDRESS_FILE] = 1; +#endif + + if (NetbiosAddress == (PVOID)-1) { + Address->NetbiosAddress.Broadcast = TRUE; + } else { + Address->NetbiosAddress.Broadcast = FALSE; + Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType; + RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16); + ++Device->AddressCounts[NetbiosAddress->NetbiosName[0]]; + } + + if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) { + Address->NameTypeFlag = NB_NAME_UNIQUE; + } else { + Address->NameTypeFlag = NB_NAME_GROUP; + } + + // + // Now link this address into the specified device context's + // address database. To do this, we need to acquire the spin lock + // on the device context. + // + + InsertTailList (&Device->AddressDatabase, &Address->Linkage); + ++Device->AddressCount; + + NbiReferenceDevice (Device, DREF_ADDRESS); + + return Address; + +} /* NbiCreateAddress */ + + +NTSTATUS +NbiVerifyAddressFile ( +#if defined(_PNP_POWER) + IN PADDRESS_FILE AddressFile, + IN BOOLEAN ConflictIsOk +#else + IN PADDRESS_FILE AddressFile +#endif _PNP_POWER + ) + +/*++ + +Routine Description: + + This routine is called to verify that the pointer given us in a file + object is in fact a valid address file object. We also verify that the + address object pointed to by it is a valid address object, and reference + it to keep it from disappearing while we use it. + +Arguments: + + AddressFile - potential pointer to a ADDRESS_FILE object + + ConflictIsOk - TRUE if we should succeed the verify even if the + corresponding address is in CONFLICT. ( For Close and + cleanup we return STATUS_SUCCESS even if we are in conflict + so that the addressfile can be destroyed) + +Return Value: + + STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise + +--*/ + +{ + CTELockHandle LockHandle; + NTSTATUS status = STATUS_SUCCESS; + PADDRESS Address; + BOOLEAN LockHeld = FALSE; + + // + // try to verify the address file signature. If the signature is valid, + // verify the address pointed to by it and get the address spinlock. + // check the address's state, and increment the reference count if it's + // ok to use it. Note that the only time we return an error for state is + // if the address is closing. + // + + try { + + if ((AddressFile->Size == sizeof (ADDRESS_FILE)) && + (AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) { +// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) { + + Address = AddressFile->Address; + + if ((Address->Size == sizeof (ADDRESS)) && + (Address->Type == NB_ADDRESS_SIGNATURE) ) { + + NB_GET_LOCK (&Address->Lock, &LockHandle); + + LockHeld = TRUE; + +#if defined(_PNP_POWER) + if (Address->State != ADDRESS_STATE_STOPPING && + ( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) { +#else + if (Address->State != ADDRESS_STATE_STOPPING) { +#endif _PNP_POWER + + NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY); + + } else { + + NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address); + status = STATUS_INVALID_ADDRESS; + } + + NB_FREE_LOCK (&Address->Lock, LockHandle); + + } else { + + NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address); + status = STATUS_INVALID_ADDRESS; + } + + } else { + + NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile); + status = STATUS_INVALID_ADDRESS; + } + + } except(EXCEPTION_EXECUTE_HANDLER) { + + NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address); + if (LockHeld) { + NB_FREE_LOCK (&Address->Lock, LockHandle); + } + return GetExceptionCode(); + } + + return status; + +} /* NbiVerifyAddressFile */ + + +VOID +NbiDestroyAddress( + IN PVOID Parameter + ) + +/*++ + +Routine Description: + + This routine destroys a transport address and removes all references + made by it to other objects in the transport. The address structure + is returned to nonpaged system pool. It is assumed + that the caller has already removed all addressfile structures associated + with this address. + + It is called from a worker thread queue by NbiDerefAddress when + the reference count goes to 0. + + This thread is only queued by NbiDerefAddress. The reason for + this is that there may be multiple streams of execution which are + simultaneously referencing the same address object, and it should + not be deleted out from under an interested stream of execution. + +Arguments: + + Address - Pointer to a transport address structure to be destroyed. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + PADDRESS Address = (PADDRESS)Parameter; + PDEVICE Device = Address->Device; + CTELockHandle LockHandle; + + NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address, + Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName)); + + SeDeassignSecurity (&Address->SecurityDescriptor); + + // + // Delink this address from its associated device context's address + // database. To do this we must spin lock on the device context object, + // not on the address. + // + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + if (!Address->NetbiosAddress.Broadcast) { + --Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]]; + } + --Device->AddressCount; + RemoveEntryList (&Address->Linkage); + NB_FREE_LOCK (&Device->Lock, LockHandle); + + NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address"); + + NbiDereferenceDevice (Device, DREF_ADDRESS); + +} /* NbiDestroyAddress */ + + +#if DBG +VOID +NbiRefAddress( + IN PADDRESS Address + ) + +/*++ + +Routine Description: + + This routine increments the reference count on a transport address. + +Arguments: + + Address - Pointer to a transport address object. + +Return Value: + + none. + +--*/ + +{ + + CTEAssert (Address->ReferenceCount > 0); // not perfect, but... + + InterlockedIncrement( &Address->ReferenceCount ); +} /* NbiRefAddress */ + + +VOID +NbiRefAddressLock( + IN PADDRESS Address + ) + +/*++ + +Routine Description: + + This routine increments the reference count on a transport address + when the device lock is already held. + +Arguments: + + Address - Pointer to a transport address object. + +Return Value: + + none. + +--*/ + +{ + + CTEAssert (Address->ReferenceCount > 0); // not perfect, but... + + InterlockedIncrement( &Address->ReferenceCount ); + +} /* NbiRefAddressLock */ +#endif + + +VOID +NbiDerefAddress( + IN PADDRESS Address + ) + +/*++ + +Routine Description: + + This routine dereferences a transport address by decrementing the + reference count contained in the structure. If, after being + decremented, the reference count is zero, then this routine calls + NbiDestroyAddress to remove it from the system. + +Arguments: + + Address - Pointer to a transport address object. + +Return Value: + + none. + +--*/ + +{ + ULONG newvalue; + + newvalue = InterlockedDecrement( &Address->ReferenceCount ); + // + // If we have deleted all references to this address, then we can + // destroy the object. It is okay to have already released the spin + // lock at this point because there is no possible way that another + // stream of execution has access to the address any longer. + // + + CTEAssert (newvalue >= 0); + + if (newvalue == 0) { + +#if ISN_NT + ExInitializeWorkItem( + &Address->u.DestroyAddressQueueItem, + NbiDestroyAddress, + (PVOID)Address); + ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue); +#else + NbiDestroyAddress(Address); +#endif + + } + +} /* NbiDerefAddress */ + + +PADDRESS_FILE +NbiCreateAddressFile( + IN PDEVICE Device + ) + +/*++ + +Routine Description: + + This routine creates an address file from the pool of ther + specified device context. The reference count in the + address is automatically set to 1. + +Arguments: + + Device - Pointer to the device context (which is really just + the device object with its extension) to be associated with the + address. + +Return Value: + + The allocate address file or NULL. + +--*/ + +{ + CTELockHandle LockHandle; + PADDRESS_FILE AddressFile; + UINT i; + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile"); + if (AddressFile == NULL) { + NB_DEBUG (ADDRESS, ("Create address file failed\n")); + NB_FREE_LOCK (&Device->Lock, LockHandle); + return NULL; + } + + NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile)); + + RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE)); + + AddressFile->Type = NB_ADDRESSFILE_SIGNATURE; + AddressFile->Size = sizeof (ADDRESS_FILE); + + InitializeListHead (&AddressFile->ReceiveDatagramQueue); + InitializeListHead (&AddressFile->ConnectionDatabase); + + NB_FREE_LOCK (&Device->Lock, LockHandle); + + AddressFile->Address = NULL; +#ifdef ISN_NT + AddressFile->FileObject = NULL; +#endif + AddressFile->Device = Device; + AddressFile->State = ADDRESSFILE_STATE_OPENING; + AddressFile->ReferenceCount = 1; +#if DBG + AddressFile->RefTypes[AFREF_CREATE] = 1; +#endif + AddressFile->CloseRequest = (PREQUEST)NULL; + + // + // Initialize the request handlers. + // + + for (i = 0; i < 6; i++) { + AddressFile->RegisteredHandler[i] = FALSE; + AddressFile->HandlerContexts[i] = NULL; + AddressFile->Handlers[i] = TdiDefaultHandlers[i]; + } + + CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler); + CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler); + CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler); + CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler); + CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler); + CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler); + + return AddressFile; + +} /* NbiCreateAddressFile */ + + +NTSTATUS +NbiDestroyAddressFile( + IN PADDRESS_FILE AddressFile + ) + +/*++ + +Routine Description: + + This routine destroys an address file and removes all references + made by it to other objects in the transport. + + This routine is only called by NbiDereferenceAddressFile. The reason + for this is that there may be multiple streams of execution which are + simultaneously referencing the same address file object, and it should + not be deleted out from under an interested stream of execution. + +Arguments: + + AddressFile Pointer to a transport address file structure to be destroyed. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + CTELockHandle LockHandle, LockHandle1; + PADDRESS Address; + PDEVICE Device; + PREQUEST CloseRequest; + BOOLEAN StopAddress; + + NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile)); + + Address = AddressFile->Address; + Device = AddressFile->Device; + + if (Address) { + + // + // This addressfile was associated with an address. + // + + NB_GET_LOCK (&Address->Lock, &LockHandle); + + // + // remove this addressfile from the address list and disassociate it from + // the file handle. + // + + RemoveEntryList (&AddressFile->Linkage); + InitializeListHead (&AddressFile->Linkage); + + if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) { + + // + // This is the last open of this address, it will close + // due to normal dereferencing but we have to set the + // CLOSING flag too to stop further references. + // + + NB_GET_LOCK (&Device->Lock, &LockHandle1); + Address->State = ADDRESS_STATE_STOPPING; + NB_FREE_LOCK (&Device->Lock, LockHandle1); + + StopAddress = TRUE; + + } else { + + StopAddress = FALSE; + } + + AddressFile->Address = NULL; + +#ifdef ISN_NT + AddressFile->FileObject->FsContext = NULL; + AddressFile->FileObject->FsContext2 = NULL; +#endif + + NB_FREE_LOCK (&Address->Lock, LockHandle); + + // + // We will already have been removed from the ShareAccess + // of the owning address. + // + + if (StopAddress && (!Address->NetbiosAddress.Broadcast)) { + + NbiSendNameFrame( + Address, + (UCHAR)(Address->NameTypeFlag | + NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED), + NB_CMD_DELETE_NAME, + NULL, + NULL); + } + + // + // Now dereference the owning address. + // + + NbiDereferenceAddress (Address, AREF_ADDRESS_FILE); + + } + + // + // Save this for later completion. + // + + CloseRequest = AddressFile->CloseRequest; + + // + // return the addressFile to the pool of address files + // + + NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile"); + + if (CloseRequest != (PREQUEST)NULL) { + REQUEST_INFORMATION(CloseRequest) = 0; + REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS; + NbiCompleteRequest (CloseRequest); + NbiFreeRequest (Device, CloseRequest); + } + + return STATUS_SUCCESS; + +} /* NbiDestroyAddressFile */ + + +#if DBG +VOID +NbiRefAddressFile( + IN PADDRESS_FILE AddressFile + ) + +/*++ + +Routine Description: + + This routine increments the reference count on an address file. + +Arguments: + + AddressFile - Pointer to a transport address file object. + +Return Value: + + none. + +--*/ + +{ + + CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but... + + + InterlockedIncrement( &AddressFile->ReferenceCount ); +} /* NbiRefAddressFile */ + + +VOID +NbiRefAddressFileLock( + IN PADDRESS_FILE AddressFile + ) + +/*++ + +Routine Description: + + This routine increments the reference count on an address file. + IT IS CALLED WITH THE ADDRESS LOCK HELD. + +Arguments: + + AddressFile - Pointer to a transport address file object. + +Return Value: + + none. + +--*/ + +{ + + CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but... + + + InterlockedIncrement( &AddressFile->ReferenceCount ); + +} /* NbiRefAddressFileLock */ + +#endif + + +VOID +NbiDerefAddressFile( + IN PADDRESS_FILE AddressFile + ) + +/*++ + +Routine Description: + + This routine dereferences an address file by decrementing the + reference count contained in the structure. If, after being + decremented, the reference count is zero, then this routine calls + NbiDestroyAddressFile to remove it from the system. + +Arguments: + + AddressFile - Pointer to a transport address file object. + +Return Value: + + none. + +--*/ + +{ + ULONG newvalue; + + newvalue = InterlockedDecrement( &AddressFile->ReferenceCount ); + + // + // If we have deleted all references to this address file, then we can + // destroy the object. It is okay to have already released the spin + // lock at this point because there is no possible way that another + // stream of execution has access to the address any longer. + // + + CTEAssert (newvalue >= 0); + + if (newvalue == 0) { + NbiDestroyAddressFile (AddressFile); + } + +} /* NbiDerefAddressFile */ + +#if !defined(_PNP_POWER) + +PADDRESS +NbiLookupAddress( + IN PDEVICE Device, + IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress + ) + +/*++ + +Routine Description: + + This routine scans the transport addresses defined for the given + device context and compares them with the specified NETWORK + NAME values. If an exact match is found, then a pointer to the + ADDRESS object is returned, and as a side effect, the reference + count to the address object is incremented. If the address is not + found, then NULL is returned. + + NOTE: This routine must be called with the Device + spinlock held. + +Arguments: + + Device - Pointer to the device object and its extension. + + NetbiosAddress - The name to look up, or -1 if the broadcast + address is being searched for. + +Return Value: + + Pointer to the ADDRESS object found, or NULL if not found. + +--*/ + +{ + PADDRESS Address; + PLIST_ENTRY p; + + p = Device->AddressDatabase.Flink; + + for (p = Device->AddressDatabase.Flink; + p != &Device->AddressDatabase; + p = p->Flink) { + + Address = CONTAINING_RECORD (p, ADDRESS, Linkage); + + if (Address->State == ADDRESS_STATE_STOPPING) { + continue; + } + + if (Address->NetbiosAddress.Broadcast) { + + // + // This address is the broadcast one, so no match + // unless we are looking for that. + // + + if (NetbiosAddress != (PVOID)-1) { + continue; + } + + } else { + + // + // This address is not the broadcast, so if we are + // looking for that then no match, else compare the + // two names. + // + + if (NetbiosAddress == (PVOID)-1) { + continue; + } + + if (!RtlEqualMemory( + Address->NetbiosAddress.NetbiosName, + NetbiosAddress->NetbiosName, + 16)) { + continue; + } + } + + // + // We found the match. Bump the reference count on the address, and + // return a pointer to the address object for the caller to use. + // + + NbiReferenceAddressLock (Address, AREF_LOOKUP); + return Address; + + } /* for */ + + // + // The specified address was not found. + // + + return NULL; + +} /* NbiLookupAddress */ +#endif !_PNP_POWER + + +PADDRESS +NbiFindAddress( + IN PDEVICE Device, + IN PUCHAR NetbiosName + ) + +/*++ + +Routine Description: + + This routine scans the transport addresses defined for the given + device context and compares them with the specified NetbiosName + values. If a match is found, the address is referenced and the + pointer is returned. + + We ignore any addresses which are either STOPPING or are under + CONFLICT state. + + A name in CONFLICT is dead for all practical purposes + except Close. This routine is called by various name service, + datagram and session sevice routines. We hide any names in CONFLICT + from these routines. + + This routine is also called by NbiTdiOpenAddress(). + A name could have been marked in CONFLICT ages ago(but is not closed + yet). We must allow another open of the same name as that might + succeed now. + +Arguments: + + Device - Pointer to the device object and its extension. + + NetbiosName - The name to look up, or -1 for the broadcast name. + +Return Value: + + Pointer to the ADDRESS object found, or NULL if not found. + +--*/ + +{ + PADDRESS Address; + PLIST_ENTRY p; + CTELockHandle LockHandle; + + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + p = Device->AddressDatabase.Flink; + + for (p = Device->AddressDatabase.Flink; + p != &Device->AddressDatabase; + p = p->Flink) { + + Address = CONTAINING_RECORD (p, ADDRESS, Linkage); + +#if defined(_PNP_POWER) + if ( ( Address->State == ADDRESS_STATE_STOPPING ) || + ( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) { +#else + if (Address->State == ADDRESS_STATE_STOPPING) { +#endif _PNP_POWER + continue; + } + + if (Address->NetbiosAddress.Broadcast) { + + // + // This address is the broadcast one, so no match + // unless we are looking for that. + // + + if (NetbiosName != (PVOID)-1) { + continue; + } + + } else { + + // + // This address is not the broadcast, so if we are + // looking for that then no match, else compare the + // two names. + // + + if ((NetbiosName == (PVOID)-1) || + (!RtlEqualMemory( + Address->NetbiosAddress.NetbiosName, + NetbiosName, + 16))) { + continue; + } + } + + + // + // We found the match. Bump the reference count on the address, and + // return a pointer to the address object for the caller to use. + // + + NbiReferenceAddressLock (Address, AREF_FIND); + NB_FREE_LOCK (&Device->Lock, LockHandle); + return Address; + + } /* for */ + + // + // The specified address was not found. + // + + NB_FREE_LOCK (&Device->Lock, LockHandle); + return NULL; + +} /* NbiFindAddress */ + + +NTSTATUS +NbiStopAddressFile( + IN PADDRESS_FILE AddressFile, + IN PADDRESS Address + ) + +/*++ + +Routine Description: + + This routine is called to terminate all activity on an AddressFile and + destroy the object. We remove every connection and datagram associated + with this addressfile from the address database and terminate their + activity. Then, if there are no other outstanding addressfiles open on + this address, the address will go away. + +Arguments: + + AddressFile - pointer to the addressFile to be stopped + + Address - the owning address for this addressFile (we do not depend upon + the pointer in the addressFile because we want this routine to be safe) + +Return Value: + + STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request + is not for a real address. + +--*/ + +{ + PLIST_ENTRY p; + PCONNECTION Connection; + PREQUEST Request; + PDEVICE Device = Address->Device; + CTELockHandle LockHandle1, LockHandle2; + LIST_ENTRY SendDatagramList; + PNB_SEND_RESERVED Reserved; + PREQUEST DatagramRequest; + NB_DEFINE_LOCK_HANDLE (LockHandle3) + CTELockHandle CancelLH; + NB_DEFINE_SYNC_CONTEXT (SyncContext) + LIST_ENTRY DatagramQ; + + + + NB_GET_LOCK (&Address->Lock, &LockHandle1); + + if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) { + NB_FREE_LOCK (&Address->Lock, LockHandle1); + return STATUS_SUCCESS; + } + + + // + // This prevents anybody else from being put on the + // ConnectionDatabase. + // + + AddressFile->State = ADDRESSFILE_STATE_CLOSING; + + while (!IsListEmpty (&AddressFile->ConnectionDatabase)) { + + p = RemoveHeadList (&AddressFile->ConnectionDatabase); + Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage); + + CTEAssert (Connection->AddressFile == AddressFile); + Connection->AddressFileLinked = FALSE; + + NB_GET_LOCK (&Device->Lock, &LockHandle2); + + if (Connection->ReferenceCount == 0) { + + // + // The refcount is already 0, so we can just + // NULL out this field to complete the disassociate. + // + + Connection->AddressFile = NULL; + NB_FREE_LOCK (&Device->Lock, LockHandle2); + NB_FREE_LOCK (&Address->Lock, LockHandle1); + + NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION); + + } else { + + // + // Mark this so we know to disassociate when the + // count goes to 0, but that there is no specific + // request pending on it. We also stop the connection + // to shut it down. + // + + Connection->DisassociatePending = (PVOID)-1; + NbiReferenceConnectionLock (Connection, CREF_DISASSOC); + + NB_FREE_LOCK (&Device->Lock, LockHandle2); + NB_FREE_LOCK (&Address->Lock, LockHandle1); + + NB_BEGIN_SYNC (&SyncContext); + NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3); + + // + // This call frees the connection lock. + // + + NbiStopConnection( + Connection, + STATUS_INVALID_ADDRESS + NB_LOCK_HANDLE_ARG (LockHandle3)); + + NB_END_SYNC (&SyncContext); + + NbiDereferenceConnection (Connection, CREF_DISASSOC); + + } + + NB_GET_LOCK (&Address->Lock, &LockHandle1); + } + + NB_FREE_LOCK (&Address->Lock, LockHandle1); + + + // + // Abort all pending send datagrams. + // + // BUGBUG: Also make them cancellable. + // + + InitializeListHead (&SendDatagramList); + + NB_GET_LOCK (&Device->Lock, &LockHandle2); + + p = Device->WaitingDatagrams.Flink; + + while (p != &Device->WaitingDatagrams) { + + Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage); + + p = p->Flink; + + if (Reserved->u.SR_DG.AddressFile == AddressFile) { + + RemoveEntryList (&Reserved->WaitLinkage); + InsertTailList (&SendDatagramList, &Reserved->WaitLinkage); + + } + + } + + NB_FREE_LOCK (&Device->Lock, LockHandle2); + + for (p = SendDatagramList.Flink; p != &SendDatagramList; ) { + + Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage); + p = p->Flink; + + DatagramRequest = Reserved->u.SR_DG.DatagramRequest; + + NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile)); + + REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS; + + NbiCompleteRequest(DatagramRequest); + NbiFreeRequest (Device, DatagramRequest); + + NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM); + + ExInterlockedPushEntrySList( + &Device->SendPacketList, + &Reserved->PoolLinkage, + &NbiGlobalPoolInterlock); + + } + + + // + // Abort all pending receive datagrams. + // + + InitializeListHead( &DatagramQ ); + + NB_GET_CANCEL_LOCK(&CancelLH); + NB_GET_LOCK (&Address->Lock, &LockHandle1); + + while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) { + + p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue); + Request = LIST_ENTRY_TO_REQUEST (p); + + // Insert it on a private Q, so it can be completed later. + InsertTailList( &DatagramQ, p); + + REQUEST_INFORMATION(Request) = 0; + REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED; + + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + + + + NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM); + + } + + NB_FREE_LOCK (&Address->Lock, LockHandle1); + NB_FREE_CANCEL_LOCK(CancelLH); + + for( p = DatagramQ.Flink; p != &DatagramQ; ) { + Request = LIST_ENTRY_TO_REQUEST ( p ); + + p = p->Flink; + + NbiCompleteRequest (Request); + NbiFreeRequest (Device, Request); + + } + + + return STATUS_SUCCESS; + +} /* NbiStopAddressFile */ + + +NTSTATUS +NbiCloseAddressFile( + IN PDEVICE Device, + IN PREQUEST Request + ) + +/*++ + +Routine Description: + + This routine is called to close the addressfile pointed to by a file + object. If there is any activity to be run down, we will run it down + before we terminate the addressfile. We remove every connection and + datagram associated with this addressfile from the address database + and terminate their activity. Then, if there are no other outstanding + addressfiles open on this address, the address will go away. + +Arguments: + + Request - the close request. + +Return Value: + + STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the + request does not point to a real address. + +--*/ + +{ + PADDRESS Address; + PADDRESS_FILE AddressFile; + + AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request); + AddressFile->CloseRequest = Request; + + // + // We assume that addressFile has already been verified + // at this point. + // + + Address = AddressFile->Address; + CTEAssert (Address); + + // + // Remove us from the access info for this address. + // + + ExAcquireResourceExclusive (&Device->AddressResource, TRUE); +#ifdef ISN_NT + IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess); +#endif + ExReleaseResource (&Device->AddressResource); + + NbiStopAddressFile (AddressFile, Address); + NbiDereferenceAddressFile (AddressFile, AFREF_CREATE); + + return STATUS_PENDING; + +} /* NbiCloseAddressFile */ + +#if defined(_PNP_POWER) + + +PADAPTER_ADDRESS +NbiCreateAdapterAddress( + IN PCHAR AdapterMacAddress + ) + +/*++ + +Routine Description: + + This routine creates an adapter address sttuctures which stores + the netbios name of an adapter. the netbios name has 12 0's + followed by the mac address of the adapter. + +Arguments: + + Device - Pointer to the device context (which is really just + the device object with its extension) to be associated with the + address. + + AdapterMacAddress - pointer to the adapter mac address given to us + by IPX. + +Return Value: + + The newly created address, or NULL if none can be allocated. + THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD. + +--*/ + +{ + PADAPTER_ADDRESS AdapterAddress; + CTELockHandle LockHandle; + PDEVICE Device = NbiDevice; + + AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address"); + if (AdapterAddress == NULL) { + NB_DEBUG (ADDRESS, ("Create Adapter Address %<2.2x><2.2x><2.2x><2.2x><2.2x><2.2x> failed\n", + AdapterMacAddress[0], + AdapterMacAddress[1], + AdapterMacAddress[2], + AdapterMacAddress[3], + AdapterMacAddress[4], + AdapterMacAddress[5] + )); + return NULL; + } + + AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE; + AdapterAddress->Size = sizeof (ADDRESS); + + RtlZeroMemory(AdapterAddress->NetbiosName, 10); + RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6); + + + InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage); + ++Device->AddressCounts[AdapterAddress->NetbiosName[0]]; + + return AdapterAddress; + +} /* NbiCreateAdapterAddress */ + + +NTSTATUS +NbiDestroyAdapterAddress( + IN PADAPTER_ADDRESS AdapterAddress OPTIONAL, + IN PCHAR AdapterMacAddress OPTIONAL + ) + +/*++ + +Routine Description: + + This routine destroys the adapter address structure and removes it + from the list. + +Arguments: + + AdapterAddress - Pointer to an adapter address structure to be destroyed + NULL if AdapterMacAddress is given. + + AdapterMacAddress - Mac Address of the adapter which just got deleted. so find + the corresponding adapter address structure and remove it. + NULL if AdapterAddress is supplied. + +Return Value: + + STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found. + + THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER + +--*/ + +{ + PDEVICE Device = NbiDevice; + CTELockHandle LockHandle; + UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE]; + + + // + + CTEAssert( AdapterAddress || AdapterMacAddress ); + if ( !AdapterAddress ) { + RtlZeroMemory( NetbiosName, 10); + RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 ); + + AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED ); + + if ( !AdapterAddress ) { + return STATUS_UNSUCCESSFUL; + } + } + + NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName)); + RemoveEntryList (&AdapterAddress->Linkage); + ++Device->AddressCounts[AdapterAddress->NetbiosName[0]]; + + NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress"); + + return STATUS_SUCCESS; +} /* NbiDestroyAdapterAddress */ + + +PADAPTER_ADDRESS +NbiFindAdapterAddress( + IN PCHAR NetbiosName, + IN BOOLEAN LockHeld + ) + +/*++ + +Routine Description: + + This routine finds an adapter address ( netbios name ) for the given + AdapterMacAddress and returns a pointer to it. Note that no reference + is done on this address, so if this routine is called without the device + lock, the caller must not use this pointer directly. + +Arguments: + + NetbiosName - NetbiosName to be found. + + LockHeld - is device lock already held or not. + +Return Value: + + Pointer to the adapter address if found, NULL otherwise. + +--*/ + +{ + + PLIST_ENTRY p; + CTELockHandle LockHandle; + PADAPTER_ADDRESS AdapterAddress; + PDEVICE Device = NbiDevice; + + + if ( !LockHeld ) { + NB_GET_LOCK( &Device->Lock, &LockHandle ); + } + for ( p = Device->AdapterAddressDatabase.Flink; + p != &Device->AdapterAddressDatabase; + p = p->Flink ) { + + AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage ); + if ( RtlEqualMemory( + NetbiosName, + AdapterAddress->NetbiosName, + NB_NETBIOS_NAME_SIZE ) ) { + break; + } + } + + + if ( !LockHeld ) { + NB_FREE_LOCK( &Device->Lock, LockHandle ); + } + + if ( p == &Device->AdapterAddressDatabase ) { + return NULL; + } else { + return AdapterAddress; + } + +} /* NbiFindAdapterAddress */ + +#endif _PNP_POWER |