You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3094 lines
89 KiB
3094 lines
89 KiB
/*++
|
|
|
|
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;
|
|
|
|
//
|
|
// 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 *
|
|
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 * 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 *)(addressName->Address));
|
|
}
|
|
}
|
|
|
|
addressName = (TA_ADDRESS *)(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 * 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 *)(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 *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),
|
|
NBF_MEM_TAG_NETBIOS_NAME);
|
|
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 {
|
|
IF_NBFDBG (NBF_DEBUG_ADDRESS) {
|
|
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.
|
|
//
|
|
|
|
ACQUIRE_RESOURCE_EXCLUSIVE (&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. 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);
|
|
|
|
// Mark as stopping so that someone does not ref it again
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
address->Flags |= ADDRESS_FLAGS_STOPPING;
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
RELEASE_RESOURCE (&DeviceContext->AddressResource);
|
|
NbfDereferenceAddress ("Device context stopping", address, AREF_TEMP_CREATE);
|
|
NbfDereferenceAddressFile (addressFile);
|
|
return status;
|
|
|
|
}
|
|
|
|
RELEASE_RESOURCE (&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 {
|
|
|
|
RELEASE_RESOURCE (&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, // lock tokens
|
|
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;
|
|
|
|
// Transfer the access masks from what is desired to what is granted
|
|
AccessState->PreviouslyGrantedAccess |= GrantedAccess;
|
|
AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
// 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)) {
|
|
|
|
RELEASE_RESOURCE (&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)) {
|
|
|
|
RELEASE_RESOURCE (&DeviceContext->AddressResource);
|
|
|
|
IF_NBFDBG (NBF_DEBUG_ADDRESS) {
|
|
NbfPrint2("OpenAddress A %lx AF %lx: ShareAccess problem.\n",
|
|
address,
|
|
addressFile);
|
|
}
|
|
|
|
NbfDereferenceAddressFile (addressFile);
|
|
|
|
} else {
|
|
|
|
RELEASE_RESOURCE (&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),
|
|
NBF_MEM_TAG_TP_ADDRESS);
|
|
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));
|
|
|
|
// To track packet pools in NDIS allocated on NBF's behalf
|
|
#if NDIS_POOL_TAGGING
|
|
Address->UIFramePoolHandle = (NDIS_HANDLE) NDIS_PACKET_POOL_TAG_FOR_NBF;
|
|
#endif
|
|
|
|
NdisAllocatePacketPoolEx (
|
|
&NdisStatus,
|
|
&Address->UIFramePoolHandle,
|
|
1,
|
|
0,
|
|
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;
|
|
}
|
|
|
|
NdisSetPacketPoolProtocolId (Address->UIFramePoolHandle, NDIS_PROTOCOL_ID_NBF);
|
|
|
|
//
|
|
// This code is similar to NbfAllocateUIFrame.
|
|
//
|
|
|
|
Address->UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
|
|
NonPagedPool,
|
|
DeviceContext->UIFrameLength,
|
|
NBF_MEM_TAG_TP_UI_FRAME);
|
|
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);
|
|
NdisFreePacket (Address->UIFrame->NdisPacket);
|
|
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);
|
|
}
|
|
NdisFreePacket(TransportAddress->UIFrame->NdisPacket);
|
|
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) {
|
|
|
|
ASSERT ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 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),
|
|
NBF_MEM_TAG_TP_ADDRESS_FILE);
|
|
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;
|
|
#if 0
|
|
addressFile->FileObject->FsContext = NULL;
|
|
addressFile->FileObject->FsContext2 = NULL;
|
|
#endif
|
|
|
|
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;
|
|
ULONG fStopping;
|
|
|
|
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 | NBF_DEBUG_PNP) {
|
|
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);
|
|
|
|
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; // Is this needed?
|
|
RemoveEntryList (&connection->AddressList);
|
|
InitializeListHead (&connection->AddressList);
|
|
InitializeListHead (&connection->AddressFileList);
|
|
connection->AddressFile = NULL;
|
|
|
|
fStopping = connection->Flags2 & CONNECTION_FLAGS2_STOPPING;
|
|
|
|
#if _DBG_
|
|
DbgPrint("conn = %p, Flags2 = %08x, fStopping = %08x\n",
|
|
connection,
|
|
connection->Flags2,
|
|
fStopping);
|
|
#endif
|
|
|
|
if (!fStopping) {
|
|
|
|
#if _DBG_
|
|
DbgPrint("Refing BEG\n");
|
|
#endif
|
|
NbfReferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
|
|
#if _DBG_
|
|
DbgPrint("Refing END\n");
|
|
#endif
|
|
}
|
|
|
|
RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
|
|
|
|
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
|
|
|
|
if (!fStopping) {
|
|
#if _DBG_
|
|
DbgPrint("Stopping BEG\n");
|
|
#endif
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
|
|
NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
|
|
KeLowerIrql (oldirql1);
|
|
#if _DBG_
|
|
DbgPrint("Stopping END\n");
|
|
DbgPrint("Derefing BEG\n");
|
|
#endif
|
|
NbfDereferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
|
|
#if _DBG_
|
|
DbgPrint("Derefing END\n");
|
|
#endif
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} /* 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 | NBF_DEBUG_PNP) {
|
|
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.
|
|
//
|
|
|
|
ACQUIRE_RESOURCE_EXCLUSIVE (&addressFile->Provider->AddressResource, TRUE);
|
|
IoRemoveShareAccess (addressFile->FileObject, &address->u.ShareAccess);
|
|
RELEASE_RESOURCE (&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 * 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) +
|
|
(ULONG)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 */
|