summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/address.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/nbf/address.c')
-rw-r--r--private/ntos/tdi/nbf/address.c3046
1 files changed, 3046 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/address.c b/private/ntos/tdi/nbf/address.c
new file mode 100644
index 000000000..f5bda0cc7
--- /dev/null
+++ b/private/ntos/tdi/nbf/address.c
@@ -0,0 +1,3046 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the TP_ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+#define NbfDbgShowAddr(TNA)\
+ { \
+ if ((TNA) == NULL) { \
+ NbfPrint0("<NetBios broadcast>\n"); \
+ } else { \
+ NbfPrint6("%c %c %c %c %d (%c)\n", \
+ (TNA)->NetbiosName[0], \
+ (TNA)->NetbiosName[1], \
+ (TNA)->NetbiosName[4], \
+ (TNA)->NetbiosName[6], \
+ (TNA)->NetbiosName[15], \
+ (TNA)->NetbiosNameType + 'A'); \
+ } \
+ }
+#else
+#define NbfDbgShowAddr(TNA)
+#endif
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+VOID
+AddressTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is executed as a DPC at DISPATCH_LEVEL when the timeout
+ period for the ADD_NAME_QUERY/ADD_NAME_RECOGNIZED protocol expires.
+ The retry count in the Address object is decremented, and if it reaches 0,
+ the address is registered. If the retry count has not reached zero,
+ then the ADD NAME QUERY is retried.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_ADDRESS block representing the
+ address that is being registered.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+ LARGE_INTEGER timeout;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+
+ address = (PTP_ADDRESS)DeferredContext;
+ DeviceContext = address->Provider;
+
+ //
+ // We are waiting for an ADD_NAME_RECOGNIZED indicating that there is a
+ // conflict. Decrement the retry count, and if it dropped to zero,
+ // then we've waited a sufficiently long time. If there was no conflict,
+ // complete all waiting file opens for the address.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((address->Flags & ADDRESS_FLAGS_QUICK_REREGISTER) != 0) {
+
+ BOOLEAN DuplicateName;
+ PTP_CONNECTION Connection;
+
+ DuplicateName = ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0);
+
+ for (p=address->ConnectionDatabase.Flink;
+ p != &address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+ continue;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_W_ADDRESS) != 0) {
+
+ if (DuplicateName) {
+
+ NbfStopConnection (Connection, STATUS_DUPLICATE_NAME);
+
+ } else {
+
+ //
+ // Continue with the connection attempt.
+ //
+ ULONG NameQueryTimeout;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_W_ADDRESS;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ KeQueryTickCount (&Connection->ConnectStartTime);
+
+ NameQueryTimeout = Connection->Provider->NameQueryTimeout;
+ if (Connection->Provider->MacInfo.MediumAsync &&
+ !Connection->Provider->MediumSpeedAccurate) {
+ NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
+ }
+
+ NbfSendNameQuery (
+ Connection,
+ TRUE);
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ NameQueryTimeout);
+ }
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_QUICK_REREGISTER;
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else if ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ PIRP irp;
+
+ //
+ // the address registration has failed. We signal the user in
+ // the normal way (by failing the open of the address). Now clean up
+ // the transport's data structures.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: duplicate\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+// address->Flags |= ADDRESS_FLAGS_STOPPING;
+
+ //
+ // BUGBUG: This is probably all overkill, the
+ // uframes handler will already have called
+ // NbfStopAddress, which will tear off all
+ // the address files etc., and set the
+ // STOPPING flag which prevents further opens.
+ //
+
+ p = address->AddressFileDatabase.Flink;
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ NbfStopAddressFile (addressFile, address);
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // There will be no more timer events happening, so we dereference the
+ // address to account for the timer.
+ //
+
+ NbfStopAddress (address);
+ NbfDereferenceAddress ("Timer, dup address", address, AREF_TIMER);
+
+ } else {
+
+ //
+ // has the address registration succeeded?
+ //
+
+ if (--(address->Retries) <= 0) { // if retry count exhausted.
+ PIRP irp;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: successful.\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+
+ p = address->AddressFileDatabase.Flink;
+
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("AddressTimeoutHandler %lx: Completing IRP %lx for file %lx\n",
+ address,
+ addressFile->Irp,
+ addressFile);
+ }
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("AddressTimeoutHandler %lx: step %x.\n",
+ address,
+ DeviceContext->AddNameQueryRetries - address->Retries);
+ }
+
+ //
+ // restart the timer if we haven't yet completed registration
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ timeout.LowPart = (ULONG)(-(LONG)DeviceContext->AddNameQueryTimeout);
+ timeout.HighPart = -1;
+ KeSetTimer (&address->Timer,*(PTIME)&timeout, &address->Dpc);
+ (VOID)NbfSendAddNameQuery (address); // send another ADD_NAME_QUERY.
+ }
+
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* AddressTimeoutHandler */
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbfParseTdiAddress(
+ 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;
+
+} /* NbfParseTdiAddress */
+
+
+BOOLEAN
+NbfValidateTdiAddress(
+ 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)) {
+ NbfPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbfValidateTdiAddress */
+
+
+NTSTATUS
+NbfOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+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:
+
+ DeviceObject - pointer to the device object describing the NBF transport.
+
+ Irp - a pointer to the Irp used for the creation of the address.
+
+ IrpSp - a pointer to the Irp stack location.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PNBF_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN QuickAdd = FALSE;
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // The network name is in the EA, passed in AssociatedIrp.SystemBuffer
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ if (ea == NULL) {
+ NbfPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (TRANSPORT_ADDRESS UNALIGNED *)&ea->EaName[ea->EaNameLength+1];
+
+ if (!NbfValidateTdiAddress(name, ea->EaValueLength)) {
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // The name can have with multiple entries; we'll use the Netbios one.
+ // This call returns NULL if not Netbios address is found, (PVOID)-1
+ // if it is the broadcast address, and a pointer to a Netbios
+ // address otherwise.
+ //
+
+ netbiosName = NbfParseTdiAddress(name, TRUE);
+
+ if (netbiosName != NULL) {
+ if (netbiosName != (PVOID)-1) {
+ networkName = (PNBF_NETBIOS_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (NBF_NETBIOS_ADDRESS),
+ 'nFBN');
+ if (networkName == NULL) {
+ PANIC ("NbfOpenAddress: PANIC! could not allocate networkName!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 1,
+ sizeof(TA_NETBIOS_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get the name to local storage
+ //
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+ } else {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ }
+ RtlCopyMemory (networkName->NetbiosName, netbiosName->NetbiosName, 16);
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ QuickAdd = TRUE;
+ }
+ } else {
+ networkName = NULL;
+ }
+
+ } else {
+ NbfPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("OpenAddress %s: ",
+ ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ "shared" : "exclusive");
+ NbfDbgShowAddr (networkName);
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = NbfCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+ return status;
+ }
+
+ //
+ // 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 (&DeviceContext->AddressResource, TRUE);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ address = NbfLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = NbfCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (NT_SUCCESS (status)) {
+
+ //
+ // 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. BUGBUG: Need to synchronize Assign and Access).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ PagedPool);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("Assign security A %lx AF %lx, status %lx\n",
+ address,
+ addressFile,
+ status);
+ }
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ NbfDereferenceAddress ("Device context stopping", address, AREF_TEMP_CREATE);
+ NbfDereferenceAddressFile (addressFile);
+ return status;
+
+ }
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: DeviceContext %lx not open\n",
+ address,
+ addressFile,
+ DeviceContext);
+ }
+ NbfDereferenceAddressFile (addressFile);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+
+ NbfReferenceAddress("Opened new", address, AREF_OPEN);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: created.\n",
+ address,
+ addressFile);
+ }
+
+ ExInterlockedInsertTailList(
+ &address->AddressFileDatabase,
+ &addressFile->Linkage,
+ &address->SpinLock);
+
+
+ //
+ // Begin address registration unless this is the broadcast
+ // address (which is a "fake" address with no corresponding
+ // Netbios address) or the reserved address, which we know
+ // is unique since it is based on the adapter address.
+ //
+ // Also, for "quick" add names, do not register.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) &&
+ (!QuickAdd)) {
+
+ NbfRegisterAddress (address); // begin address registration.
+ status = STATUS_PENDING;
+
+ } else {
+
+ address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ }
+
+ NbfDereferenceAddress("temp create", address, AREF_TEMP_CREATE);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->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.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+ 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);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint4 ("Access check A %lx AF %lx, %s (%lx)\n",
+ address,
+ addressFile,
+ AccessAllowed ? "allowed" : "not allowed",
+ status);
+ }
+
+ if (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // BUGBUG: Compare DesiredAccess to GrantedAccess?
+ //
+
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+ // BUGBUG: This code is structured funny, the only reason
+ // this is inside this if is to avoid indenting too much.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("Address types differ: old %c, new %c\n",
+ address->NetworkName->NetbiosNameType + 'A',
+ networkName->NetbiosNameType + 'A');
+ }
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ACL bad.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ //
+ // 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);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ShareAccess problem.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // now, if the address registered, we simply return success after
+ // pointing the file object at the address file (which points to
+ // the address). If the address registration is pending, we mark
+ // the registration pending and let the registration completion
+ // routine complete the open. If the address is bad, we simply
+ // fail the open.
+ //
+
+ if ((address->Flags &
+ (ADDRESS_FLAGS_CONFLICT |
+ ADDRESS_FLAGS_REGISTERING |
+ ADDRESS_FLAGS_DEREGISTERING |
+ ADDRESS_FLAGS_DUPLICATE_NAME |
+ ADDRESS_FLAGS_NEEDS_REG |
+ ADDRESS_FLAGS_STOPPING |
+ ADDRESS_FLAGS_BAD_ADDRESS |
+ ADDRESS_FLAGS_CLOSED)) == 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = NULL;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ NbfReferenceAddress("open ready", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address ready.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // if the address is still registering, make the open pending.
+ //
+
+ if ((address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_NEEDS_REG)) != 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+
+ NbfReferenceAddress("open registering", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address registering.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ if ((address->Flags & ADDRESS_FLAGS_CONFLICT) != 0) {
+ status = STATUS_DUPLICATE_NAME;
+ } else {
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: address flags %lx.\n",
+ address,
+ addressFile,
+ address->Flags);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // This isn't needed since it was not used in the
+ // creation of the address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ //
+ // Remove the reference from NbfLookupAddress.
+ //
+
+ NbfDereferenceAddress ("Done opening", address, AREF_LOOKUP);
+ }
+
+ return status;
+} /* NbfOpenAddress */
+
+
+VOID
+NbfAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport address. Some minimal
+ initialization is done on the address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure. Returns NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ PSEND_PACKET_TAG SendTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 101,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS),
+ 'aFBN');
+ if (Address == NULL) {
+ PANIC("NBF: Could not allocate address: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 201,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &Address->UIFramePoolHandle,
+ 1,
+ sizeof(SEND_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC("NBF: Could not allocate address UI frame pool: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 311,
+ sizeof(SEND_PACKET_TAG),
+ ADDRESS_RESOURCE_ID);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+
+ //
+ // This code is similar to NbfAllocateUIFrame.
+ //
+
+ Address->UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->UIFrameLength,
+ 'uFBN');
+ if (Address->UIFrame == NULL) {
+ PANIC("NBF: Could not allocate address UI frame: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 411,
+ DeviceContext->UIFrameLength,
+ ADDRESS_RESOURCE_ID);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address->UIFrame, DeviceContext->UIFrameLength);
+
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ Address->UIFramePoolHandle);
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+ Address->UIFrame->NdisPacket = NdisPacket;
+ Address->UIFrame->DataBuffer = NULL;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_ADDRESS_FRAME;
+ SendTag->Owner = (PVOID)Address;
+ SendTag->Frame = Address->UIFrame;
+
+ //
+ // Make the packet header known to the packet descriptor
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ Address->UIFrame->Header,
+ DeviceContext->UIFrameHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ PANIC("NBF: Could not allocate address UI frame buffer: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 511,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+ ExFreePool (Address->UIFrame);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ DeviceContext->MemoryUsage +=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+ ++DeviceContext->AddressAllocated;
+
+ Address->Type = NBF_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+// KeInitializeSpinLock (&Address->Interlock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ KeInitializeDpc (&Address->Dpc, AddressTimeoutHandler, (PVOID)Address);
+ KeInitializeTimer (&Address->Timer);
+
+ //
+ // For each address, allocate a receive packet and a receive buffer.
+ //
+
+ NbfAddReceivePacket (DeviceContext);
+ NbfAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* NbfAllocateAddress */
+
+
+VOID
+NbfDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a transport address structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (TransportAddress->UIFrame->NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+ ExFreePool (TransportAddress->UIFrame);
+ NdisFreePacketPool (TransportAddress->UIFramePoolHandle);
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+
+ DeviceContext->MemoryUsage -=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ NbfRemoveReceivePacket (DeviceContext);
+ NbfRemoveReceiveBuffer (DeviceContext);
+
+} /* NbfDeallocateAddress */
+
+
+NTSTATUS
+NbfCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ )
+
+/*++
+
+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 must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+ NOTE: This has only the basic NetbiosNameType values, not the
+ QUICK_ ones.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS pAddress;
+ PLIST_ENTRY p;
+
+
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ if (p == &DeviceContext->AddressPool) {
+
+ if ((DeviceContext->AddressMaxAllocated == 0) ||
+ (DeviceContext->AddressAllocated < DeviceContext->AddressMaxAllocated)) {
+
+ NbfAllocateAddress (DeviceContext, &pAddress);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address at %lx\n", pAddress);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 401,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("NbfCreateAddress: Could not allocate address object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ pAddress = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ }
+
+ ++DeviceContext->AddressInUse;
+ if (DeviceContext->AddressInUse > DeviceContext->AddressMaxInUse) {
+ ++DeviceContext->AddressMaxInUse;
+ }
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("NbfCreateAddress %lx: ", pAddress);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_AREFS; Counter++) {
+ pAddress->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by the caller.
+
+ pAddress->RefTypes[AREF_TEMP_CREATE] = 1;
+ }
+#endif
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_GROUP;
+
+ }
+
+ if (NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) {
+ ++DeviceContext->AddressCounts[NetworkName->NetbiosName[0]];
+ }
+
+ //
+ // 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 (&DeviceContext->AddressDatabase, &pAddress->Linkage);
+ pAddress->Provider = DeviceContext;
+ NbfReferenceDeviceContext ("Create Address", DeviceContext, DCREF_ADDRESS); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* NbfCreateAddress */
+
+
+VOID
+NbfRegisterAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process of the transport address
+ specified, if it has not already been started.
+
+Arguments:
+
+ Address - Pointer to a transport address object to begin registering
+ on the network.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ LARGE_INTEGER Timeout;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: NEEDS_REG 0.\n", Address);
+ }
+
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: registering.\n", Address);
+ }
+
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ RtlZeroMemory (Address->UniqueResponseAddress, 6);
+
+ //
+ // Keep a reference on this address until the registration process
+ // completes or is aborted. It will be aborted in UFRAMES.C, in
+ // either the NAME_IN_CONFLICT or ADD_NAME_RESPONSE frame handlers.
+ //
+
+ NbfReferenceAddress ("start registration", Address, AREF_TIMER);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now start registration process by starting up a retransmission timer
+ // and begin sending ADD_NAME_QUERY NetBIOS frames.
+ //
+ // On an async line that is disconnected, we only send one packet
+ // with a short timeout.
+ //
+
+ if (Address->Provider->MacInfo.MediumAsync && !Address->Provider->MediumSpeedAccurate) {
+ Address->Retries = 1;
+ Timeout.LowPart = (ULONG)(-(ADD_NAME_QUERY_TIMEOUT / 10));
+ } else {
+ Address->Retries = Address->Provider->AddNameQueryRetries;
+ Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
+ }
+ Timeout.HighPart = -1;
+ KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
+
+ (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
+} /* NbfRegisterAddress */
+
+
+NTSTATUS
+NbfVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+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 TP_ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+ PTP_ADDRESS address;
+
+ //
+ // 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 != (PTP_ADDRESS_FILE)NULL) &&
+ (AddressFile->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == NBF_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address != (PTP_ADDRESS)NULL) &&
+ (address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == NBF_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ NbfReferenceAddress ("verify", address, AREF_VERIFY);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+NbfDestroyAddress(
+ 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 or our lookaside list. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ The routine is called from a worker thread so that the security
+ descriptor can be accessed.
+
+ This worked thread is only queued by NbfDerefAddress. 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.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address = (PTP_ADDRESS)Parameter;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfDestroyAddress %lx:.\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ 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.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (Address->NetworkName) {
+ --DeviceContext->AddressCounts[Address->NetworkName->NetbiosName[0]];
+ }
+
+ RemoveEntryList (&Address->Linkage);
+
+ if (Address->NetworkName != NULL) {
+ ExFreePool (Address->NetworkName);
+ Address->NetworkName = NULL;
+ }
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ NbfDeallocateAddress (DeviceContext, Address);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address at %lx\n", Address);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ NbfDereferenceDeviceContext ("Destroy Address", DeviceContext, DCREF_ADDRESS); // just housekeeping.
+
+} /* NbfDestroyAddress */
+
+
+#if DBG
+VOID
+NbfRefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Address->ReferenceCount);
+
+} /* NbfRefAddress */
+#endif
+
+
+VOID
+NbfDerefAddress(
+ IN PTP_ADDRESS 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
+ NbfDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = 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.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbfDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* NbfDerefAddress */
+
+
+
+VOID
+NbfAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for an address file. Some
+ minimal initialization is done on the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a place where this routine will return
+ a pointer to a transport address file structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_ADDRESS_FILE AddressFile;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS_FILE)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address file: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 102,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS_FILE),
+ 'fFBN');
+ if (AddressFile == NULL) {
+ PANIC("NBF: Could not allocate address file: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 202,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = NBF_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* NbfAllocateAddressFile */
+
+
+VOID
+NbfDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for an address file.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a transport address file structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportAddressFile);
+ --DeviceContext->AddressFileAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS_FILE);
+
+} /* NbfDeallocateAddressFile */
+
+
+NTSTATUS
+NbfCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ )
+
+/*++
+
+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:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AddressFile - Pointer to a place where this routine will return a pointer
+ to a transport address file structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ if (p == &DeviceContext->AddressFilePool) {
+
+ if ((DeviceContext->AddressFileMaxAllocated == 0) ||
+ (DeviceContext->AddressFileAllocated < DeviceContext->AddressFileMaxAllocated)) {
+
+ NbfAllocateAddressFile (DeviceContext, &addressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address file at %lx\n", addressFile);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 402,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateAddressFile: Could not allocate address file object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ }
+
+ ++DeviceContext->AddressFileInUse;
+ if (DeviceContext->AddressFileInUse > DeviceContext->AddressFileMaxInUse) {
+ ++DeviceContext->AddressFileMaxInUse;
+ }
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ InitializeListHead (&addressFile->ConnectionDatabase);
+ addressFile->Address = NULL;
+ addressFile->FileObject = NULL;
+ addressFile->Provider = DeviceContext;
+ addressFile->State = ADDRESSFILE_STATE_OPENING;
+ addressFile->ConnectIndicationInProgress = FALSE;
+ addressFile->ReferenceCount = 1;
+ addressFile->CloseIrp = (PIRP)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ addressFile->RegisteredConnectionHandler = FALSE;
+ addressFile->ConnectionHandler = TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ addressFile->DisconnectHandler = TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ addressFile->ReceiveHandler = TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ addressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ addressFile->ExpeditedDataHandler = TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ addressFile->ErrorHandler = TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+
+
+ *AddressFile = addressFile;
+ return STATUS_SUCCESS;
+
+} /* NbfCreateAddress */
+
+
+NTSTATUS
+NbfDestroyAddressFile(
+ IN PTP_ADDRESS_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 NbfDereferenceAddressFile. 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.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+
+ address = AddressFile->Address;
+ DeviceContext = AddressFile->Provider;
+
+ if (address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // 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.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbfDereferenceAddress ("Close", address, AREF_OPEN); // remove the creation hold
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseIrp = AddressFile->CloseIrp;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+ --DeviceContext->AddressFileInUse;
+
+ if ((DeviceContext->AddressFileAllocated - DeviceContext->AddressFileInUse) >
+ DeviceContext->AddressFileInitAllocated) {
+ NbfDeallocateAddressFile (DeviceContext, AddressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address file at %lx\n", AddressFile);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ if (CloseIrp != (PIRP)NULL) {
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyAddressFile */
+
+
+VOID
+NbfReferenceAddressFile(
+ IN PTP_ADDRESS_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.
+
+--*/
+
+{
+
+ ASSERT (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&AddressFile->ReferenceCount);
+
+} /* NbfReferenceAddressFile */
+
+
+VOID
+NbfDereferenceAddressFile(
+ IN PTP_ADDRESS_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
+ NbfDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = 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.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyAddressFile (AddressFile);
+ }
+} /* NbfDerefAddressFile */
+
+
+PTP_ADDRESS
+NbfLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName
+ )
+
+/*++
+
+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
+ TP_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 DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device object and its extension.
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS structure containing the
+ network name.
+
+Return Value:
+
+ Pointer to the TP_ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PLIST_ENTRY p;
+ ULONG i;
+
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // If the network name is specified and the network names don't match,
+ // then the addresses don't match.
+ //
+
+ i = NETBIOS_NAME_LENGTH; // length of a Netbios name
+
+ if (address->NetworkName != NULL) {
+ if (NetworkName != NULL) {
+ if (!RtlEqualMemory (
+ address->NetworkName->NetbiosName,
+ NetworkName->NetbiosName,
+ i)) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+
+ } else {
+ if (NetworkName != NULL) {
+ 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.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("NbfLookupAddress DC %lx: found %lx ", DeviceContext, address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ NbfReferenceAddress ("lookup", address, AREF_LOOKUP);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfLookupAddress DC %lx: did not find ", address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ return NULL;
+
+} /* NbfLookupAddress */
+
+
+PTP_CONNECTION
+NbfLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN UCHAR RemoteSessionNumber
+ )
+
+/*++
+
+Routine Description:
+
+
+ This routine scans the connections associated with the
+ given address, and determines if there is an connection
+ associated with the specific remote address and session
+ number which is becoming active. This is used
+ in determining whether name queries should be processed,
+ or ignored as duplicates.
+
+Arguments:
+
+ Address - Pointer to the address object.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+ RemoteSessionNumber - The session number assigned to this
+ connection by the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+ BOOLEAN Found = FALSE;
+
+
+ //
+ // Hold the spinlock so the connection database doesn't
+ // change.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) == 0)) {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, and the connection's RSN is
+ // the same (or zero, which is a temporary condition where
+ // we should err on the side of caution), then return the
+ // connection, which will cause the NAME_QUERY to be ignored.
+ //
+
+ if ((RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) &&
+ ((connection->Rsn == RemoteSessionNumber) || (connection->Rsn == 0))) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ NbfReferenceConnection ("Lookup found", connection, CREF_LISTENING);
+ Found = TRUE;
+
+ }
+
+ } else {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupRemoteName\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ return (PTP_CONNECTION)NULL;
+ }
+
+ if (Found) {
+ return connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+NbfMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN UCHAR NameType,
+ IN PUCHAR NetBIOSName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to compare the addressing information in a
+ TP_ADDRESS object with the 16-byte NetBIOS name in a frame header.
+ If they match, then this routine returns TRUE, else it returns FALSE.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+ NameType - One of NETBIOS_NAME_TYPE_GROUP, NETBIOS_NAME_TYPE_UNIQUE,
+ or NETBIOS_NAME_TYPE_EITHER. Controls what type we are matching
+ on, if it matters.
+
+ NetBIOSName - Pointer to a 16-byte character string (non-terminated),
+ or NULL if this is a received broadcast address.
+
+Return Value:
+
+ BOOLEAN, TRUE if match, FALSE if not.
+
+--*/
+
+{
+
+ PULONG AddressNamePointer;
+ ULONG UNALIGNED * NetbiosNamePointer;
+
+ //
+ // If this is address is the Netbios broadcast address, the comparison
+ // succeeds only if the passed in address is also NULL.
+ //
+
+ if (Address->NetworkName == NULL) {
+
+ if (NetBIOSName == NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else if (NetBIOSName == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Do a quick check of the first character in the names.
+ //
+
+ if (Address->NetworkName->NetbiosName[0] != NetBIOSName[0]) {
+ return FALSE;
+ }
+
+ //
+ // If name type is important and it doesn't match
+ // this address' type, fail.
+ //
+
+ if (NameType != NETBIOS_NAME_TYPE_EITHER) {
+
+ if (Address->NetworkName->NetbiosNameType != (USHORT)NameType) {
+
+ return FALSE;
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint2 ("MatchNetbiosAddress %lx: compare %.16s to ", Address, NetBIOSName);
+ NbfDbgShowAddr (Address->NetworkName);
+ }
+
+ //
+ // Now compare the 16-character Netbios names as ULONGs
+ // for speed. We know the one stored in the address
+ // structure is aligned.
+ //
+
+ AddressNamePointer = (PULONG)(Address->NetworkName->NetbiosName);
+ NetbiosNamePointer = (ULONG UNALIGNED *)NetBIOSName;
+
+ if ((AddressNamePointer[0] == NetbiosNamePointer[0]) &&
+ (AddressNamePointer[1] == NetbiosNamePointer[1]) &&
+ (AddressNamePointer[2] == NetbiosNamePointer[2]) &&
+ (AddressNamePointer[3] == NetbiosNamePointer[3])) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+} /* NbfMatchNetbiosAddress */
+
+
+VOID
+NbfStopAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an address and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding addressfiles are removed from the addressfile database, and
+ all their activities are shut down.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS_FILE addressFile;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // If we're already stopping this address, then don't try to do it again.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_STOPPING)) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: stopping\n", Address);
+ }
+
+ NbfReferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ Address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ //
+ // Run down all addressfiles on this address. This
+ // will leave the address with no references
+ // potentially, but we don't need a temp one
+ // because every place that calls NbfStopAddress
+ // already has a temp reference.
+ //
+
+ while (!IsListEmpty (&Address->AddressFileDatabase)) {
+ p = RemoveHeadList (&Address->AddressFileDatabase);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ addressFile->Address = NULL;
+ addressFile->FileObject->FsContext = NULL;
+ addressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Run-down this addressFile without the lock on.
+ // We don't care about removing ourselves from
+ // the address' ShareAccess because we are
+ // tearing it down.
+ //
+
+ NbfStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbfDereferenceAddressFile (addressFile);
+
+ NbfDereferenceAddress ("stop address", Address, AREF_OPEN);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: already stopping\n", Address);
+ }
+
+ }
+
+} /* NbfStopAddress */
+
+
+NTSTATUS
+NbfStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS 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 Irp does not
+ point to a real address.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ LIST_ENTRY localIrpList;
+ PLIST_ENTRY p, pFlink;
+ PIRP irp;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: already closing.\n", AddressFile);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: closing.\n", AddressFile);
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localIrpList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of NbfDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 |= CONNECTION_FLAGS2_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ NbfReferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfStopAddressFile\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "TpStopEndpoint stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ KeLowerIrql (oldirql1);
+ NbfDereferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+
+ NbfDereferenceAddress ("Destroy association", Address, AREF_CONNECTION);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ //
+ // If the address has a datagram send in progress, skip the
+ // first one, it will complete when the NdisSend completes.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ if (Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS) {
+ ASSERT (p != &Address->SendDatagramQueue);
+ p = p->Flink;
+ }
+
+ for ( ;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (IoGetCurrentIrpStackLocation(irp)->FileObject->FsContext == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ //
+ // and finally, signal failure if the address file was waiting for a
+ // registration to complete (Irp is set to NULL when this succeeds).
+ //
+
+ if (AddressFile->Irp != NULL) {
+ PIRP irp=AddressFile->Irp;
+#if DBG
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ DbgPrint ("NBF: AddressFile %lx closed while opening!!\n", AddressFile);
+ DbgBreakPoint();
+ }
+#endif
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localIrpList)) {
+ KIRQL cancelIrql;
+
+ p = RemoveHeadList (&localIrpList);
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_NETWORK_NAME_DELETED;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Datagram aborted", Address, AREF_REQUEST);
+ }
+
+} /* NbfStopAddressFile */
+
+
+NTSTATUS
+NbfCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+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:
+
+ Irp - the Irp Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+
+ addressFile = IrpSp->FileObject->FsContext;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfCloseAddress AF %lx:\n", addressFile);
+ }
+
+ addressFile->CloseIrp = Irp;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ address = addressFile->Address;
+ ASSERT (address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&addressFile->Provider->AddressResource, TRUE);
+ IoRemoveShareAccess (addressFile->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ NbfStopAddressFile (addressFile, address);
+ NbfDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ NbfDereferenceAddress ("IRP_MJ_CLOSE", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* NbfCloseAddress */
+
+
+NTSTATUS
+NbfSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to acquire a hold on the SendDatagramQueue of
+ the specified address, prepare the next datagram for shipment, and
+ call NbfSendUIMdlFrame to actually do the work. When NbfSendUIMdlFrame
+ is finished, it will cause an I/O completion routine in UFRAMES.C to
+ be called, at which time this routine is called again to handle the
+ next datagram in the pipeline.
+
+ NOTE: This routine must be called at a point where the address
+ has another reference that will keep it around.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ PUCHAR LocalName;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfSendDatagramsOnAddress %lx:\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (!(Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS)) {
+
+ //
+ // If the queue is empty, don't do anything.
+ //
+
+ if (IsListEmpty (&Address->SendDatagramQueue)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and NBF header will not be used for two requests at the
+ // same time.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_SEND_IN_PROGRESS;
+
+ //
+ // We own the hold, and we've released the spinlock. So pick off the
+ // next datagram to be sent, and ship it.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // If there is no remote Address specified (the Address specified has
+ // length 0), this is a broadcast datagram. If anything is specified, it
+ // will be used as a netbios address.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ remoteAddress = NbfParseTdiAddress (
+ ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress,
+ TRUE);
+ ASSERT (remoteAddress != NULL);
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->UIFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS) +
+ Irp->IoStatus.Information,
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&(Address->UIFrame->Header[HeaderLength]));
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the correct Netbios header.
+ //
+
+ if (Address->NetworkName != NULL) {
+ LocalName = Address->NetworkName->NetbiosName;
+ } else {
+ LocalName = DeviceContext->ReservedNetBIOSAddress;
+ }
+
+ if (remoteAddress == (PVOID)-1) {
+
+ ConstructDatagramBroadcast (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ LocalName);
+
+ } else {
+
+ ConstructDatagram (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ (PNAME)remoteAddress->NetbiosName,
+ LocalName);
+
+ }
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DatagramBytesSent,
+ Irp->IoStatus.Information);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ NbfSetNdisPacketLength(Address->UIFrame->NdisPacket, HeaderLength);
+
+ if (Irp->MdlAddress) {
+ NdisChainBufferAtBack (Address->UIFrame->NdisPacket, (PNDIS_BUFFER)Irp->MdlAddress);
+ }
+
+ NbfSendUIMdlFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler in
+ // UFRAMES.C. At that time, if there is another outstanding datagram
+ // to send, it will reset the hold and call this routine again.
+ //
+
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ return STATUS_SUCCESS;
+} /* NbfSendDatagramsOnAddress */