summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isnp/nb/address.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/isnp/nb/address.c2406
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