summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/address.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/address.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/tdi/st/address.c')
-rw-r--r--private/ntos/tdi/st/address.c2247
1 files changed, 2247 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/address.c b/private/ntos/tdi/st/address.c
new file mode 100644
index 000000000..3a4434a95
--- /dev/null
+++ b/private/ntos/tdi/st/address.c
@@ -0,0 +1,2247 @@
+/*++
+
+Copyright (c) 1989-1993 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.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+VOID
+StDestroyAddress(
+ IN PVOID Parameter
+ );
+
+
+NTSTATUS
+StOpenAddress(
+ 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 ST 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;
+ PST_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *addressName;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = 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) {
+ StPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // 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];
+ addressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if (addressName->AddressLength != 0) {
+ netbiosName = (PTDI_ADDRESS_NETBIOS)&addressName->Address[0];
+ networkName = (PST_NETBIOS_ADDRESS)ExAllocatePool (
+ NonPagedPool,
+ sizeof (ST_NETBIOS_ADDRESS));
+ if (networkName == NULL) {
+ PANIC ("StOpenAddress: PANIC! could not allocate networkName!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 1);
+ 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);
+
+ found = TRUE;
+ } else {
+ networkName = NULL;
+ found = TRUE;
+ }
+
+ break;
+
+ } else {
+
+ addressName = (PTA_ADDRESS)(addressName->Address +
+ addressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ StPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = StCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ 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 = StLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = StCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ 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->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 (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (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_STOPPING) {
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (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;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+ InsertTailList (&address->AddressFileDatabase, &addressFile->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+
+ //
+ // 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.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ StRegisterAddress (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;
+
+ }
+
+ }
+
+ } 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);
+ }
+
+ StDereferenceAddressFile (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 (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (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->ShareAccess,
+ TRUE);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (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;
+
+ StReferenceAddress("open ready", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ 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;
+
+ StReferenceAddress("open registering", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ StDereferenceAddressFile (addressFile);
+
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+
+ }
+ }
+ }
+ }
+
+ //
+ // Remove the reference from StLookupAddress.
+ //
+
+ StDereferenceAddress ("Done opening", address);
+ }
+
+ return status;
+} /* StOpenAddress */
+
+
+VOID
+StAllocateAddress(
+ 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;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate address: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 101);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS));
+ if (Address == NULL) {
+ PANIC("ST: Could not allocate address: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 201);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS);
+ ++DeviceContext->AddressAllocated;
+
+ StAllocateSendPacket (DeviceContext, &(Address->Packet));
+ if (Address->Packet == NULL) {
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ --DeviceContext->PacketAllocated; // AllocatePacket added one
+
+ //
+ // Need to modify the address packets to belong to
+ // the address, not the device context.
+ //
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+
+ Address->Type = ST_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ //
+ // For each address, allocate a receive packet, a receive buffer,
+ // and a UI frame.
+ //
+
+ StAddReceivePacket (DeviceContext);
+ StAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* StAllocateAddress */
+
+
+VOID
+StDeallocateAddress(
+ 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.
+
+--*/
+
+{
+
+ if (TransportAddress->NetworkName != NULL) {
+ ExFreePool (TransportAddress->NetworkName);
+ }
+ StDeallocateSendPacket (DeviceContext, TransportAddress->Packet);
+ ++DeviceContext->PacketAllocated;
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS);
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ StRemoveReceivePacket (DeviceContext);
+ StRemoveReceiveBuffer (DeviceContext);
+
+} /* StDeallocateAddress */
+
+
+NTSTATUS
+StCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_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 ST_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+
+ 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)) {
+
+ StAllocateAddress (DeviceContext, &pAddress);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 401);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("StCreateConnection: 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;
+
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ ExInitializeWorkItem(
+ &pAddress->DestroyAddressQueueItem,
+ StDestroyAddress,
+ (PVOID)pAddress);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PST_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_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 (&DeviceContext->AddressDatabase, &pAddress->Linkage);
+ pAddress->Provider = DeviceContext;
+ StReferenceDeviceContext ("Create Address", DeviceContext); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* StCreateAddress */
+
+
+VOID
+StRegisterAddress(
+ 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;
+ PLIST_ENTRY p;
+ PIRP irp;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return;
+ }
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ //
+ // 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.
+ //
+
+ StReferenceAddress ("start registration", Address);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Normally we would add the name on the network, then
+ // do the following in our timeout logic, but for ST
+ // we assume that all names are OK.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ 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 (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ StDereferenceAddress ("Timer, registered", Address);
+
+} /* StRegisterAddress */
+
+
+NTSTATUS
+StVerifyAddressObject (
+ 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->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == ST_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == ST_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ StReferenceAddress ("verify", address);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ StPrint1("StVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ StPrint1("StVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+StDestroyAddress(
+ 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 StfDerefAddress. 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;
+
+ 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);
+
+ RemoveEntryList (&Address->Linkage);
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ StDeallocateAddress (DeviceContext, Address);
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ StDereferenceDeviceContext ("Destroy Address", DeviceContext); // just housekeeping.
+
+} /* StDestroyAddress */
+
+
+VOID
+StRefAddress(
+ 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);
+
+} /* StRefAddress */
+
+
+VOID
+StDerefAddress(
+ 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
+ StDestroyAddress 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);
+
+ //
+ // Defer the actual call to StDestroyAddress to a thread
+ // so the paged security descriptor can be accessed at IRQL 0.
+ //
+
+ if (result == 0) {
+ ExQueueWorkItem(&Address->DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* StDerefAddress */
+
+
+
+VOID
+StAllocateAddressFile(
+ 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("ST: Could not allocate address file: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 102);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS_FILE));
+ if (AddressFile == NULL) {
+ PANIC("ST: Could not allocate address file: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 202);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = ST_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* StAllocateAddressFile */
+
+
+VOID
+StDeallocateAddressFile(
+ 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);
+
+} /* StDeallocateAddressFile */
+
+
+NTSTATUS
+StCreateAddressFile(
+ 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)) {
+
+ StAllocateAddressFile (DeviceContext, &addressFile);
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 402);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: 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;
+
+} /* StCreateAddress */
+
+
+NTSTATUS
+StDestroyAddressFile(
+ 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 StDereferenceAddressFile. 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.
+ //
+
+ StDereferenceAddress ("Close", address); // 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) {
+ StDeallocateAddressFile (DeviceContext, 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;
+
+} /* StDestroyAddress */
+
+
+VOID
+StReferenceAddressFile(
+ 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);
+
+} /* StReferenceAddressFile */
+
+
+VOID
+StDereferenceAddressFile(
+ 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
+ StDestroyAddressFile 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) {
+ StDestroyAddressFile (AddressFile);
+ }
+} /* StDerefAddressFile */
+
+
+PTP_ADDRESS
+StLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_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 ST_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.
+ //
+
+ StReferenceAddress ("lookup", address);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* StLookupAddress */
+
+
+PTP_CONNECTION
+StLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connections associated with an
+ address, and determines if there is an connection
+ associated with the specific remote address.
+
+Arguments:
+
+ Address - Pointer to the address.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+
+
+ //
+ // 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);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) != 0)) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, then return the
+ // connection.
+ //
+
+ if (RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ StReferenceConnection ("Lookup found", connection);
+ return connection;
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+StMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ 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.
+
+ 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;
+ }
+
+ //
+ // 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;
+ }
+
+} /* StMatchNetbiosAddress */
+
+
+VOID
+StStopAddress(
+ 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)) {
+
+ 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 StStopAddress
+ // 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.
+ //
+
+ StStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ StDereferenceAddressFile (addressFile);
+
+ StDereferenceAddress ("stop address", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return;
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+} /* StStopAddress */
+
+
+NTSTATUS
+StStopAddressFile(
+ 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 localList;
+ PLIST_ENTRY p, pFlink;
+ PTP_REQUEST request;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of StDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags |= CONNECTION_FLAGS_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ StReferenceConnection ("Close AddressFile", connection);
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ StDereferenceConnection ("Close AddressFile", connection);
+
+ StDereferenceAddress ("Destroy association", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ for (p = Address->SendDatagramQueue.Flink;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if ((PTP_ADDRESS_FILE)(request->Owner) == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, 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;
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localList)) {
+
+ p = RemoveHeadList (&localList);
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ StCompleteRequest (request, STATUS_NETWORK_NAME_DELETED, 0);
+
+ }
+
+
+} /* StStopAddressFile */
+
+
+NTSTATUS
+StCloseAddress(
+ 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;
+ 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->ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ StStopAddressFile (addressFile, address);
+ StDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ StDereferenceAddress ("IRP_MJ_CLOSE", address);
+
+ return STATUS_PENDING;
+
+} /* StCloseAddress */
+
+
+NTSTATUS
+StSendDatagramsOnAddress(
+ 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 StSendUIMdlFrame to actually do the work. When StSendUIMdlFrame
+ 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.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PTA_NETBIOS_ADDRESS remoteTA;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PST_HEADER StHeader;
+ PSEND_PACKET_TAG SendTag;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ StReferenceAddress ("Send datagram", Address); // keep it around
+
+ 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);
+ StDereferenceAddress ("Queue empty", Address);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and ST 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);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ //
+ // 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 (request->IoRequestPacket);
+
+ remoteTA = ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress;
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER) + request->Buffer2Length,
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+ //
+ // Build the header: 'G', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Address->Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_DATAGRAM;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Source, Address->NetworkName->NetbiosName, 16);
+
+ if (remoteTA->Address[0].AddressLength == 0) {
+
+ //
+ // A broadcast datagram
+ //
+
+ RtlZeroMemory (StHeader->Destination, 16);
+ StHeader->Flags |= ST_FLAGS_BROADCAST;
+
+ } else {
+
+ RtlCopyMemory (StHeader->Destination, remoteTA->Address[0].Address[0].NetbiosName, 16);
+
+ }
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->DatagramBytesSent,
+ request->Buffer2Length);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ StSetNdisPacketLength(Address->Packet->NdisPacket, HeaderLength);
+
+ if (request->Buffer2) {
+ NdisChainBufferAtBack (Address->Packet->NdisPacket, (PNDIS_BUFFER)request->Buffer2);
+ }
+
+ (VOID)StSendAddressFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler.
+ // 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);
+ }
+
+ StDereferenceAddress ("Sent datagram", Address); // all done
+
+ return STATUS_SUCCESS;
+
+} /* StSendDatagramsOnAddress */