1956 lines
48 KiB
C
1956 lines
48 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
address.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which implements the ADDRESS object.
|
||
Routines are provided to create, destroy, reference, and dereference,
|
||
transport address objects.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
Sanjay Anand (SanjayAn) - 22-Sept-1995
|
||
BackFill optimization changes added under #if BACK_FILL
|
||
|
||
Sanjay Anand (SanjayAn) 3-Oct-1995
|
||
Changes to support transfer of buffer ownership to transports - tagged [CH]
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
//
|
||
// Map all generic accesses to the same one.
|
||
//
|
||
|
||
static GENERIC_MAPPING AddressGenericMapping =
|
||
{ READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
|
||
|
||
|
||
|
||
TDI_ADDRESS_IPX UNALIGNED *
|
||
IpxParseTdiAddress(
|
||
IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans a TRANSPORT_ADDRESS, looking for an address
|
||
of type TDI_ADDRESS_TYPE_IPX.
|
||
|
||
Arguments:
|
||
|
||
Transport - The generic TDI address.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the IPX address, or NULL if none 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 IPX one.
|
||
//
|
||
|
||
for (i=0;i<TransportAddress->TAAddressCount;i++) {
|
||
if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
|
||
if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
|
||
return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
|
||
}
|
||
}
|
||
addressName = (TA_ADDRESS *)(addressName->Address +
|
||
addressName->AddressLength);
|
||
}
|
||
return NULL;
|
||
|
||
} /* IpxParseTdiAddress */
|
||
|
||
|
||
BOOLEAN
|
||
IpxValidateTdiAddress(
|
||
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)) {
|
||
IpxPrint0 ("IpxValidateTdiAddress: runt address\n");
|
||
return FALSE;
|
||
}
|
||
|
||
addressName = &TransportAddress->Address[0];
|
||
|
||
for (i=0;i<TransportAddress->TAAddressCount;i++) {
|
||
if (addressName->Address > AddressEnd) {
|
||
IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
|
||
return FALSE;
|
||
}
|
||
addressName = (TA_ADDRESS *)(addressName->Address +
|
||
addressName->AddressLength);
|
||
}
|
||
|
||
if ((PUCHAR)addressName > AddressEnd) {
|
||
IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
|
||
} /* IpxValidateTdiAddress */
|
||
|
||
#if DBG
|
||
|
||
VOID
|
||
IpxBuildTdiAddress(
|
||
IN PVOID AddressBuffer,
|
||
IN ULONG Network,
|
||
IN UCHAR Node[6],
|
||
IN USHORT Socket
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine fills in a TRANSPORT_ADDRESS in the specified
|
||
buffer, given the socket, network and node.
|
||
|
||
Arguments:
|
||
|
||
AddressBuffer - The buffer that will hold the address.
|
||
|
||
Network - The network number.
|
||
|
||
Node - The node address.
|
||
|
||
Socket - The socket.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
TA_IPX_ADDRESS UNALIGNED * IpxAddress;
|
||
|
||
IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
|
||
|
||
IpxAddress->TAAddressCount = 1;
|
||
IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
|
||
IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
|
||
IpxAddress->Address[0].Address[0].NetworkAddress = Network;
|
||
IpxAddress->Address[0].Address[0].Socket = Socket;
|
||
RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
|
||
|
||
} /* IpxBuildTdiAddress */
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
IpxOpenAddress(
|
||
IN PDEVICE Device,
|
||
IN PREQUEST Request
|
||
)
|
||
|
||
{
|
||
return(IpxOpenAddressM(Device, Request, 0));
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
IpxOpenAddressM(
|
||
IN PDEVICE Device,
|
||
IN PREQUEST Request,
|
||
IN ULONG Index
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a file that points to an existing address object, or, if
|
||
the object doesn't exist, creates it (note that creation of the address
|
||
object includes registering the address, and may take many seconds to
|
||
complete, depending upon system configuration).
|
||
|
||
If the address already exists, and it has an ACL associated with it, the
|
||
ACL is checked for access rights before allowing creation of the address.
|
||
|
||
Arguments:
|
||
|
||
Device - pointer to the device describing the IPX transport.
|
||
|
||
Request - a pointer to the request used for the creation of the address.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PADDRESS Address;
|
||
PADDRESS_FILE AddressFile;
|
||
PFILE_FULL_EA_INFORMATION ea;
|
||
TRANSPORT_ADDRESS UNALIGNED *name;
|
||
TA_ADDRESS *AddressName;
|
||
USHORT Socket;
|
||
ULONG DesiredShareAccess;
|
||
CTELockHandle LockHandle;
|
||
PACCESS_STATE AccessState;
|
||
ACCESS_MASK GrantedAccess;
|
||
BOOLEAN AccessAllowed;
|
||
int i;
|
||
BOOLEAN found = FALSE;
|
||
#ifdef ISN_NT
|
||
PIRP Irp = (PIRP)Request;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
#endif
|
||
INT Size = 0;
|
||
|
||
//
|
||
// If we are a dedicated router, we cannot let addresses
|
||
// be opened.
|
||
//
|
||
|
||
if (Device->DedicatedRouter && (REQUEST_CODE(Request) != MIPX_RT_CREATE)) {
|
||
return STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
//
|
||
// The network name is in the EA, passed in the request.
|
||
//
|
||
|
||
ea = OPEN_REQUEST_EA_INFORMATION(Request);
|
||
if (ea == NULL) {
|
||
IpxPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
|
||
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];
|
||
|
||
//
|
||
// 126042
|
||
//
|
||
if (ea->EaValueLength < (sizeof(TRANSPORT_ADDRESS) -1)) {
|
||
|
||
IPX_DEBUG(ADDRESS, ("The ea value length does not match the TA address length\n"));
|
||
DbgPrint("IPX: STATUS_INVALID_EA_NAME - 1\n");
|
||
return STATUS_INVALID_EA_NAME;
|
||
|
||
}
|
||
|
||
AddressName = (PTA_ADDRESS)&name->Address[0];
|
||
Size = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) + FIELD_OFFSET(TA_ADDRESS, Address) + AddressName->AddressLength;
|
||
|
||
//
|
||
// The name can be passed with multiple entries; we'll take and use only
|
||
// the first one of type IPX.
|
||
//
|
||
|
||
//DbgPrint("Size (%d) & EaValueLength (%d)", Size, ea->EaValueLength);
|
||
if (Size > ea->EaValueLength) {
|
||
DbgPrint("EA:%lx, Name:%lx, AddressName:%lx\n", ea, name, AddressName);
|
||
CTEAssert(FALSE);
|
||
}
|
||
|
||
for (i=0;i<name->TAAddressCount;i++) {
|
||
|
||
//
|
||
// 126042
|
||
//
|
||
if (Size > ea->EaValueLength) {
|
||
|
||
IPX_DEBUG(ADDRESS, ("The EA value length does not match the TA address length (2)\n"));
|
||
|
||
DbgPrint("IPX: STATUS_INVALID_EA_NAME - 2\n");
|
||
|
||
return STATUS_INVALID_EA_NAME;
|
||
|
||
}
|
||
|
||
if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
|
||
if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
|
||
Socket = ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
|
||
found = TRUE;
|
||
}
|
||
break;
|
||
|
||
} else {
|
||
|
||
AddressName = (PTA_ADDRESS)(AddressName->Address +
|
||
AddressName->AddressLength);
|
||
|
||
Size += FIELD_OFFSET(TA_ADDRESS, Address);
|
||
|
||
if (Size < ea->EaValueLength) {
|
||
|
||
Size += AddressName->AddressLength;
|
||
|
||
} else {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
if (!found) {
|
||
IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request));
|
||
return STATUS_NONEXISTENT_EA_ENTRY;
|
||
}
|
||
|
||
if (Socket == 0) {
|
||
|
||
Socket = IpxAssignSocket (Device);
|
||
|
||
if (Socket == 0) {
|
||
IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n"));
|
||
#ifdef SNMP
|
||
++IPX_MIB_ENTRY(Device, SysOpenSocketFails);
|
||
#endif SNMP
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
} else {
|
||
IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket)));
|
||
}
|
||
|
||
} else {
|
||
|
||
IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket)));
|
||
|
||
}
|
||
|
||
//
|
||
// get an address file structure to represent this address.
|
||
//
|
||
|
||
AddressFile = IpxCreateAddressFile (Device);
|
||
|
||
if (AddressFile == (PADDRESS_FILE)NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// We mark this socket specially.
|
||
//
|
||
|
||
if (Socket == SAP_SOCKET) {
|
||
AddressFile->IsSapSocket = TRUE;
|
||
AddressFile->SpecialReceiveProcessing = TRUE;
|
||
}
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
KeEnterCriticalRegion();
|
||
|
||
ExAcquireResourceExclusiveLite (&Device->AddressResource, TRUE);
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
|
||
Address = IpxLookupAddress (Device, Socket);
|
||
|
||
if (Address == NULL) {
|
||
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
//
|
||
// This address doesn't exist. Create it.
|
||
// registering it.
|
||
//
|
||
|
||
Address = IpxCreateAddress (
|
||
Device,
|
||
Socket);
|
||
|
||
if (Address != (PADDRESS)NULL) {
|
||
|
||
//
|
||
// Set this now in case we have to deref.
|
||
//
|
||
|
||
AddressFile->AddressLock = &Address->Lock;
|
||
|
||
if (REQUEST_CODE(Request) == MIPX_RT_CREATE) {
|
||
Address->RtAdd = TRUE;
|
||
Address->Index = Index;
|
||
} else {
|
||
Address->RtAdd = FALSE;
|
||
}
|
||
|
||
#ifdef ISN_NT
|
||
|
||
//
|
||
// Initialize the shared access now. We use read access
|
||
// to control all access.
|
||
//
|
||
|
||
DesiredShareAccess = (ULONG)
|
||
(((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
||
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
|
||
FILE_SHARE_READ : 0);
|
||
|
||
IoSetShareAccess(
|
||
FILE_READ_DATA,
|
||
DesiredShareAccess,
|
||
IrpSp->FileObject,
|
||
&Address->u.ShareAccess);
|
||
|
||
|
||
//
|
||
// Assign the security descriptor (need to do this with
|
||
// the spinlock released because the descriptor is not
|
||
// mapped).
|
||
//
|
||
|
||
AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||
|
||
status = SeAssignSecurity(
|
||
NULL, // parent descriptor
|
||
AccessState->SecurityDescriptor,
|
||
&Address->SecurityDescriptor,
|
||
FALSE, // is directory
|
||
&AccessState->SubjectSecurityContext,
|
||
&AddressGenericMapping,
|
||
NonPagedPool);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Error, return status.
|
||
//
|
||
|
||
IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
return status;
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
//
|
||
// if the adapter isn't ready, we can't do any of this; get out
|
||
//
|
||
|
||
if (Device->State == DEVICE_STATE_STOPPING) {
|
||
IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
status = STATUS_DEVICE_NOT_READY;
|
||
|
||
} else {
|
||
|
||
REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
|
||
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject = IrpSp->FileObject;
|
||
#endif
|
||
AddressFile->Request = Request;
|
||
AddressFile->Address = Address;
|
||
|
||
CTEGetLock (&Address->Lock, &LockHandle);
|
||
InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage);
|
||
CTEFreeLock (&Address->Lock, LockHandle);
|
||
|
||
AddressFile->Request = NULL;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPEN;
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
//
|
||
// If the address could not be created, and is not in the
|
||
// process of being created, then we can't open up an address.
|
||
// Since we can't use the AddressLock to deref, we just destroy
|
||
// the address file.
|
||
//
|
||
|
||
IpxDestroyAddressFile (AddressFile);
|
||
|
||
// 288208
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address));
|
||
|
||
//
|
||
// We never allow shared access to a RT address. So, check that
|
||
// we don't have a "RT address create" request and also that the
|
||
// address has not only been taken up by a RT Address request. If
|
||
// and only if both the above
|
||
//
|
||
if ((REQUEST_CODE(Request) != MIPX_RT_CREATE) && (!Address->RtAdd))
|
||
{
|
||
//
|
||
// Set this now in case we have to deref.
|
||
//
|
||
|
||
AddressFile->AddressLock = &Address->Lock;
|
||
|
||
//
|
||
// The address already exists. Check the ACL and see if we
|
||
// can access it. If so, simply use this address as our address.
|
||
//
|
||
|
||
#ifdef ISN_NT
|
||
|
||
AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||
|
||
AccessAllowed = SeAccessCheck(
|
||
Address->SecurityDescriptor,
|
||
&AccessState->SubjectSecurityContext,
|
||
FALSE, // tokens locked
|
||
IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
|
||
(ACCESS_MASK)0, // previously granted
|
||
NULL, // privileges
|
||
&AddressGenericMapping,
|
||
Irp->RequestorMode,
|
||
&GrantedAccess,
|
||
&status);
|
||
|
||
#else // ISN_NT
|
||
|
||
AccessAllowed = TRUE;
|
||
|
||
#endif // ISN_NT
|
||
|
||
if (!AccessAllowed) {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
} else {
|
||
|
||
#ifdef ISN_NT
|
||
|
||
//
|
||
// NtBug: 132051. Make sure you dont give more access than reqd.
|
||
//
|
||
AccessState->PreviouslyGrantedAccess |= GrantedAccess;
|
||
AccessState->RemainingDesiredAccess &= ~( GrantedAccess | MAXIMUM_ALLOWED );
|
||
|
||
//
|
||
// Now check that we can obtain the desired share
|
||
// access. We use read access to control all access.
|
||
//
|
||
|
||
DesiredShareAccess = (ULONG)
|
||
(((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
||
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
|
||
FILE_SHARE_READ : 0);
|
||
|
||
status = IoCheckShareAccess(
|
||
FILE_READ_DATA,
|
||
DesiredShareAccess,
|
||
IrpSp->FileObject,
|
||
&Address->u.ShareAccess,
|
||
TRUE);
|
||
|
||
#else // ISN_NT
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
#endif // ISN_NT
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
} else {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
CTEGetLock (&Address->Lock, &LockHandle);
|
||
|
||
InsertTailList (
|
||
&Address->AddressFileDatabase,
|
||
&AddressFile->Linkage);
|
||
|
||
AddressFile->Request = NULL;
|
||
AddressFile->Address = Address;
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject = IrpSp->FileObject;
|
||
#endif
|
||
AddressFile->State = ADDRESSFILE_STATE_OPEN;
|
||
|
||
IpxReferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
|
||
REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
|
||
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
|
||
CTEFreeLock (&Address->Lock, LockHandle);
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DbgPrint("IpxOpenAddress: ACCESS DENIED - duplicate address\n");
|
||
status = STATUS_ACCESS_DENIED;
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
}
|
||
|
||
//
|
||
// Remove the reference from IpxLookupAddress.
|
||
//
|
||
|
||
IpxDereferenceAddress (Address, AREF_LOOKUP);
|
||
}
|
||
|
||
return status;
|
||
|
||
} /* IpxOpenAddress */
|
||
|
||
|
||
|
||
USHORT
|
||
IpxAssignSocket(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine assigns a socket that is unique within a range
|
||
of SocketUniqueness.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context.
|
||
|
||
Return Value:
|
||
|
||
The assigned socket number, or 0 if a unique one cannot
|
||
be found.
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT InitialSocket, CurrentSocket, AddressSocket;
|
||
ULONG CurrentHash;
|
||
BOOLEAN Conflict;
|
||
PLIST_ENTRY p;
|
||
PADDRESS Address;
|
||
CTELockHandle LockHandle;
|
||
|
||
//
|
||
// Loop through all possible sockets, starting at
|
||
// Device->CurrentSocket, looking for a suitable one.
|
||
// Device->CurrentSocket rotates through the possible
|
||
// sockets to improve the chances of finding one
|
||
// quickly.
|
||
//
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
|
||
InitialSocket = Device->CurrentSocket;
|
||
Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness);
|
||
if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
|
||
Device->CurrentSocket = Device->SocketStart;
|
||
}
|
||
|
||
CurrentSocket = InitialSocket;
|
||
|
||
do {
|
||
|
||
//
|
||
// Scan all addresses; if we find one with a socket
|
||
// that conflicts with this one, we can't use it.
|
||
//
|
||
// NOTE: Device->Lock is acquired here.
|
||
//
|
||
|
||
Conflict = FALSE;
|
||
|
||
for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
|
||
|
||
for (p = Device->AddressDatabases[CurrentHash].Flink;
|
||
p != &Device->AddressDatabases[CurrentHash];
|
||
p = p->Flink) {
|
||
|
||
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
|
||
AddressSocket = REORDER_USHORT(Address->Socket);
|
||
|
||
if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) &&
|
||
(AddressSocket < CurrentSocket + Device->SocketUniqueness)) {
|
||
Conflict = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we've found a conflict, no need to check the other
|
||
// queues.
|
||
//
|
||
|
||
if (Conflict) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
//
|
||
// We intentionally free the lock here so that we
|
||
// never spend too much time with it held.
|
||
//
|
||
|
||
if (!Conflict) {
|
||
|
||
//
|
||
// We went through the address list without
|
||
// finding a conflict; use this socket.
|
||
//
|
||
|
||
return REORDER_USHORT(CurrentSocket);
|
||
}
|
||
|
||
CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness);
|
||
if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
|
||
CurrentSocket = Device->SocketStart;
|
||
}
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
|
||
} while (CurrentSocket != InitialSocket);
|
||
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
//
|
||
// Could not find one to assign.
|
||
//
|
||
|
||
return (USHORT)0;
|
||
|
||
} /* IpxAssignSocket */
|
||
|
||
|
||
PADDRESS
|
||
IpxCreateAddress(
|
||
IN PDEVICE Device,
|
||
IN USHORT Socket
|
||
)
|
||
|
||
/*++
|
||
|
||
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 Device
|
||
spinlock held.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context (which is really just
|
||
the device object with its extension) to be associated with the
|
||
address.
|
||
|
||
Socket - The socket to assign to this address.
|
||
|
||
Return Value:
|
||
|
||
The newly created address, or NULL if none can be allocated.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PIPX_SEND_RESERVED SendReserved;
|
||
PIPX_RECEIVE_RESERVED ReceiveReserved;
|
||
NDIS_STATUS Status;
|
||
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
||
|
||
Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
|
||
if (Address == NULL) {
|
||
IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket)));
|
||
return NULL;
|
||
}
|
||
|
||
IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket)));
|
||
RtlZeroMemory (Address, sizeof(ADDRESS));
|
||
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status);
|
||
if (Status != NDIS_STATUS_SUCCESS) {
|
||
goto Fail1;
|
||
}
|
||
#endif
|
||
|
||
if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) {
|
||
#ifndef IPX_OWN_PACKETS
|
||
Fail1:
|
||
#endif
|
||
Address->SendPacketInUse = TRUE;
|
||
} else {
|
||
SendReserved = SEND_RESERVED(&Address->SendPacket);
|
||
SendReserved->Address = Address;
|
||
SendReserved->OwnedByAddress = TRUE;
|
||
Address->SendPacketInUse = FALSE;
|
||
#ifdef IPX_TRACK_POOL
|
||
SendReserved->Pool = NULL;
|
||
#endif
|
||
}
|
||
|
||
|
||
#if BACK_FILL
|
||
{
|
||
PIPX_SEND_RESERVED BackFillReserved;
|
||
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status);
|
||
if (Status != NDIS_STATUS_SUCCESS) {
|
||
goto Fail2;
|
||
}
|
||
#endif
|
||
if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) {
|
||
#ifndef IPX_OWN_PACKETS
|
||
Fail2:
|
||
#endif
|
||
Address->BackFillPacketInUse = TRUE;
|
||
} else {
|
||
BackFillReserved = SEND_RESERVED(&Address->BackFillPacket);
|
||
BackFillReserved->Address = Address;
|
||
Address->BackFillPacketInUse = FALSE;
|
||
BackFillReserved->OwnedByAddress = TRUE;
|
||
#ifdef IPX_TRACK_POOL
|
||
BackFillReserved->Pool = NULL;
|
||
#endif
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status);
|
||
if (Status != NDIS_STATUS_SUCCESS) {
|
||
goto Fail3;
|
||
}
|
||
#endif
|
||
if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) {
|
||
#ifndef IPX_OWN_PACKETS
|
||
Fail3:
|
||
#endif
|
||
Address->ReceivePacketInUse = TRUE;
|
||
} else {
|
||
ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket);
|
||
ReceiveReserved->Address = Address;
|
||
ReceiveReserved->OwnedByAddress = TRUE;
|
||
Address->ReceivePacketInUse = FALSE;
|
||
#ifdef IPX_TRACK_POOL
|
||
ReceiveReserved->Pool = NULL;
|
||
#endif
|
||
}
|
||
|
||
Address->Type = IPX_ADDRESS_SIGNATURE;
|
||
Address->Size = sizeof (ADDRESS);
|
||
|
||
Address->Device = Device;
|
||
Address->DeviceLock = &Device->Lock;
|
||
CTEInitLock (&Address->Lock);
|
||
|
||
InitializeListHead (&Address->AddressFileDatabase);
|
||
|
||
Address->ReferenceCount = 1;
|
||
#if DBG
|
||
Address->RefTypes[AREF_ADDRESS_FILE] = 1;
|
||
#endif
|
||
Address->Socket = Socket;
|
||
Address->SendSourceSocket = Socket;
|
||
|
||
//
|
||
// Save our local address for building datagrams quickly.
|
||
//
|
||
|
||
RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
|
||
Address->LocalAddress.Socket = Socket;
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
||
InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage);
|
||
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
||
|
||
IpxReferenceDevice (Device, DREF_ADDRESS);
|
||
|
||
return Address;
|
||
|
||
} /* IpxCreateAddress */
|
||
|
||
|
||
NTSTATUS
|
||
IpxVerifyAddressFile(
|
||
IN PADDRESS_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 ADDRESS_FILE object
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PADDRESS 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 (ADDRESS_FILE)) &&
|
||
(AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) ) {
|
||
// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
|
||
|
||
Address = AddressFile->Address;
|
||
|
||
if ((Address->Size == sizeof (ADDRESS)) &&
|
||
(Address->Type == IPX_ADDRESS_SIGNATURE) ) {
|
||
|
||
CTEGetLock (&Address->Lock, &LockHandle);
|
||
|
||
if (!Address->Stopping) {
|
||
|
||
IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
|
||
|
||
} else {
|
||
|
||
IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
CTEFreeLock (&Address->Lock, LockHandle);
|
||
|
||
} else {
|
||
|
||
IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
} else {
|
||
|
||
IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address);
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
return status;
|
||
|
||
} /* IpxVerifyAddressFile */
|
||
|
||
|
||
VOID
|
||
IpxDestroyAddress(
|
||
IN PVOID Parameter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys a transport address and removes all references
|
||
made by it to other objects in the transport. The address structure
|
||
is returned to nonpaged system pool. It is assumed
|
||
that the caller has already removed all addressfile structures associated
|
||
with this address.
|
||
|
||
It is called from a worker thread queue by IpxDerefAddress when
|
||
the reference count goes to 0.
|
||
|
||
This thread is only queued by IpxDerefAddress. The reason for
|
||
this is that there may be multiple streams of execution which are
|
||
simultaneously referencing the same address object, and it should
|
||
not be deleted out from under an interested stream of execution.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address structure to be destroyed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address = (PADDRESS)Parameter;
|
||
PDEVICE Device = Address->Device;
|
||
CTELockHandle LockHandle;
|
||
|
||
IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket)));
|
||
|
||
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.
|
||
//
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
RemoveEntryList (&Address->Linkage);
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
if (!Address->SendPacketInUse) {
|
||
IpxDeinitializeSendPacket (Device, &Address->SendPacket);
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxFreeSingleSendPacket (Device, Address->SendPacket);
|
||
#endif
|
||
}
|
||
|
||
if (!Address->ReceivePacketInUse) {
|
||
IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket);
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxFreeSingleReceivePacket (Device, Address->ReceivePacket);
|
||
#endif
|
||
}
|
||
|
||
#if BACK_FILL
|
||
if (!Address->BackFillPacketInUse) {
|
||
IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket);
|
||
#ifndef IPX_OWN_PACKETS
|
||
IpxFreeSingleSendPacket (Device, Address->BackFillPacket);
|
||
#endif
|
||
}
|
||
#endif
|
||
IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
|
||
|
||
IpxDereferenceDevice (Device, DREF_ADDRESS);
|
||
|
||
} /* IpxDestroyAddress */
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
IpxRefAddress(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on a transport address.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
|
||
|
||
(VOID)InterlockedIncrement(&Address->ReferenceCount);
|
||
|
||
} /* IpxRefAddress */
|
||
|
||
|
||
VOID
|
||
IpxRefAddressLock(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on a transport address
|
||
when the device lock is already held.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
|
||
|
||
// ++Address->ReferenceCount;
|
||
(VOID)InterlockedIncrement(&Address->ReferenceCount);
|
||
|
||
} /* IpxRefAddressLock */
|
||
#endif
|
||
|
||
|
||
VOID
|
||
IpxDerefAddress(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences a transport address by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
IpxDestroyAddress to remove it from the system.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG oldvalue;
|
||
|
||
oldvalue = IPX_ADD_ULONG (
|
||
&Address->ReferenceCount,
|
||
(ULONG)-1,
|
||
Address->DeviceLock);
|
||
|
||
//
|
||
// If we have deleted all references to this address, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert (oldvalue != 0);
|
||
|
||
if (oldvalue == 1) {
|
||
|
||
#if ISN_NT
|
||
ExInitializeWorkItem(
|
||
&Address->u.DestroyAddressQueueItem,
|
||
IpxDestroyAddress,
|
||
(PVOID)Address);
|
||
ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
|
||
#else
|
||
IpxDestroyAddress(Address);
|
||
#endif
|
||
|
||
}
|
||
|
||
} /* IpxDerefAddress */
|
||
|
||
|
||
VOID
|
||
IpxDerefAddressSync(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences a transport address by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
IpxDestroyAddress to remove it from the system. This routine can
|
||
only be called when we are synchronized (inside an IPX_SYNC_START/
|
||
IPX_SYNC_END pair, with a lock held, or in an indication).
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG oldvalue;
|
||
|
||
oldvalue = IPX_ADD_ULONG (
|
||
&Address->ReferenceCount,
|
||
(ULONG)-1,
|
||
Address->DeviceLock);
|
||
|
||
//
|
||
// If we have deleted all references to this address, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert (oldvalue != 0);
|
||
|
||
if (oldvalue == 1) {
|
||
|
||
#if ISN_NT
|
||
ExInitializeWorkItem(
|
||
&Address->u.DestroyAddressQueueItem,
|
||
IpxDestroyAddress,
|
||
(PVOID)Address);
|
||
ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
|
||
#else
|
||
IpxDestroyAddress(Address);
|
||
#endif
|
||
|
||
}
|
||
|
||
} /* IpxDerefAddressSync */
|
||
|
||
|
||
PADDRESS_FILE
|
||
IpxCreateAddressFile(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates an address file from the pool of ther
|
||
specified device context. The reference count in the
|
||
address is automatically set to 1.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context (which is really just
|
||
the device object with its extension) to be associated with the
|
||
address.
|
||
|
||
Return Value:
|
||
|
||
The allocate address file or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle;
|
||
PADDRESS_FILE AddressFile;
|
||
|
||
AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
|
||
if (AddressFile == NULL) {
|
||
IPX_DEBUG (ADDRESS, ("Create address file failed\n"));
|
||
return NULL;
|
||
}
|
||
|
||
IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile));
|
||
|
||
RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
|
||
|
||
AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE;
|
||
AddressFile->Size = sizeof (ADDRESS_FILE);
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
|
||
InitializeListHead (&AddressFile->ReceiveDatagramQueue);
|
||
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
|
||
#if 0
|
||
AddressFile->SpecialReceiveProcessing = FALSE;
|
||
AddressFile->ExtendedAddressing = FALSE;
|
||
AddressFile->ReceiveIpxHeader = FALSE;
|
||
AddressFile->FilterOnPacketType = FALSE;
|
||
AddressFile->DefaultPacketType = 0;
|
||
AddressFile->Address = NULL;
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject = NULL;
|
||
#endif
|
||
#endif
|
||
|
||
AddressFile->Device = Device;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPENING;
|
||
AddressFile->ReferenceCount = 1;
|
||
#if DBG
|
||
AddressFile->RefTypes[AFREF_CREATE] = 1;
|
||
#endif
|
||
AddressFile->CloseRequest = (PREQUEST)NULL;
|
||
|
||
//
|
||
// Initialize the request handlers.
|
||
//
|
||
|
||
AddressFile->RegisteredReceiveDatagramHandler = FALSE;
|
||
AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
|
||
AddressFile->ReceiveDatagramHandlerContext = NULL;
|
||
|
||
//
|
||
// [CH] Added these handlers for chained buffer receives
|
||
//
|
||
AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
|
||
AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler;
|
||
AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
|
||
|
||
AddressFile->RegisteredErrorHandler = FALSE;
|
||
AddressFile->ErrorHandler = TdiDefaultErrorHandler;
|
||
AddressFile->ErrorHandlerContext = NULL;
|
||
|
||
return AddressFile;
|
||
|
||
} /* IpxCreateAddressFile */
|
||
|
||
|
||
NTSTATUS
|
||
IpxDestroyAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys an address file and removes all references
|
||
made by it to other objects in the transport.
|
||
|
||
This routine is only called by IpxDereferenceAddressFile. The reason
|
||
for this is that there may be multiple streams of execution which are
|
||
simultaneously referencing the same address file object, and it should
|
||
not be deleted out from under an interested stream of execution.
|
||
|
||
Arguments:
|
||
|
||
AddressFile Pointer to a transport address file structure to be destroyed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle, LockHandle1;
|
||
PADDRESS Address;
|
||
PDEVICE Device;
|
||
PREQUEST CloseRequest;
|
||
|
||
IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile));
|
||
|
||
Address = AddressFile->Address;
|
||
Device = AddressFile->Device;
|
||
|
||
if (Address) {
|
||
|
||
//
|
||
// This addressfile was associated with an address.
|
||
//
|
||
|
||
CTEGetLock (&Address->Lock, &LockHandle);
|
||
|
||
//
|
||
// remove this addressfile from the address list and disassociate it from
|
||
// the file handle.
|
||
//
|
||
|
||
RemoveEntryList (&AddressFile->Linkage);
|
||
InitializeListHead (&AddressFile->Linkage);
|
||
|
||
if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
|
||
|
||
//
|
||
// This is the last open of this address, it will close
|
||
// due to normal dereferencing but we have to set the
|
||
// CLOSING flag too to stop further references.
|
||
//
|
||
|
||
CTEGetLock (&Device->Lock, &LockHandle1);
|
||
Address->Stopping = TRUE;
|
||
if (Device->LastAddress == Address) {
|
||
Device->LastAddress = NULL;
|
||
}
|
||
CTEFreeLock (&Device->Lock, LockHandle1);
|
||
|
||
}
|
||
|
||
AddressFile->Address = NULL;
|
||
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject->FsContext = NULL;
|
||
AddressFile->FileObject->FsContext2 = NULL;
|
||
#endif
|
||
|
||
CTEFreeLock (&Address->Lock, LockHandle);
|
||
|
||
//
|
||
// We will already have been removed from the ShareAccess
|
||
// of the owning address.
|
||
//
|
||
|
||
//
|
||
// Now dereference the owning address.
|
||
//
|
||
|
||
IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
|
||
}
|
||
|
||
//
|
||
// Save this for later completion.
|
||
//
|
||
|
||
CloseRequest = AddressFile->CloseRequest;
|
||
|
||
//
|
||
// return the addressFile to the pool of address files
|
||
//
|
||
|
||
IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
|
||
|
||
if (CloseRequest != (PREQUEST)NULL) {
|
||
REQUEST_INFORMATION(CloseRequest) = 0;
|
||
REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
|
||
IpxCompleteRequest (CloseRequest);
|
||
IpxFreeRequest (Device, CloseRequest);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} /* IpxDestroyAddressFile */
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
IpxRefAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on an address file.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
|
||
|
||
(VOID)IPX_ADD_ULONG (
|
||
&AddressFile->ReferenceCount,
|
||
1,
|
||
AddressFile->AddressLock);
|
||
|
||
} /* IpxRefAddressFile */
|
||
|
||
|
||
VOID
|
||
IpxRefAddressFileLock(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on an address file.
|
||
IT IS CALLED WITH THE ADDRESS LOCK HELD.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
|
||
|
||
//++AddressFile->ReferenceCount;
|
||
(VOID)InterlockedIncrement(&AddressFile->ReferenceCount);
|
||
|
||
} /* IpxRefAddressFileLock */
|
||
|
||
|
||
VOID
|
||
IpxRefAddressFileSync(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on an address file.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
|
||
|
||
(VOID)IPX_ADD_ULONG (
|
||
&AddressFile->ReferenceCount,
|
||
1,
|
||
AddressFile->AddressLock);
|
||
|
||
} /* IpxRefAddressFileSync */
|
||
|
||
|
||
VOID
|
||
IpxDerefAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences an address file by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
IpxDestroyAddressFile to remove it from the system.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG oldvalue;
|
||
|
||
oldvalue = IPX_ADD_ULONG (
|
||
&AddressFile->ReferenceCount,
|
||
(ULONG)-1,
|
||
AddressFile->AddressLock);
|
||
|
||
//
|
||
// If we have deleted all references to this address file, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert (oldvalue > 0);
|
||
|
||
if (oldvalue == 1) {
|
||
IpxDestroyAddressFile (AddressFile);
|
||
}
|
||
|
||
} /* IpxDerefAddressFile */
|
||
|
||
|
||
VOID
|
||
IpxDerefAddressFileSync(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences an address file by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
IpxDestroyAddressFile to remove it from the system. This routine
|
||
can only be called when we are synchronized (inside an IPX_SYNC_START/
|
||
IPX_SYNC_END pair, with a lock held, or in an indication).
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG oldvalue;
|
||
|
||
oldvalue = IPX_ADD_ULONG (
|
||
&AddressFile->ReferenceCount,
|
||
(ULONG)-1,
|
||
AddressFile->AddressLock);
|
||
|
||
//
|
||
// If we have deleted all references to this address file, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert (oldvalue > 0);
|
||
|
||
if (oldvalue == 1) {
|
||
IpxDestroyAddressFile (AddressFile);
|
||
}
|
||
|
||
} /* IpxDerefAddressFileSync */
|
||
#endif
|
||
|
||
|
||
PADDRESS
|
||
IpxLookupAddress(
|
||
IN PDEVICE Device,
|
||
IN USHORT Socket
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the transport addresses defined for the given
|
||
device context and compares them with the specified NETWORK
|
||
NAME values. If an exact match is found, then a pointer to the
|
||
ADDRESS object is returned, and as a side effect, the reference
|
||
count to the address object is incremented. If the address is not
|
||
found, then NULL is returned.
|
||
|
||
NOTE: This routine must be called with the Device
|
||
spinlock held.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device object and its extension.
|
||
|
||
Socket - The socket to look up.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the ADDRESS object found, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PLIST_ENTRY p;
|
||
ULONG Hash = IPX_HASH_SOCKET (Socket);
|
||
|
||
p = Device->AddressDatabases[Hash].Flink;
|
||
|
||
for (p = Device->AddressDatabases[Hash].Flink;
|
||
p != &Device->AddressDatabases[Hash];
|
||
p = p->Flink) {
|
||
|
||
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
|
||
|
||
if (Address->Stopping) {
|
||
continue;
|
||
}
|
||
|
||
if (Address->Socket == Socket) {
|
||
|
||
//
|
||
// We found the match. Bump the reference count on the address, and
|
||
// return a pointer to the address object for the caller to use.
|
||
//
|
||
|
||
IpxReferenceAddressLock (Address, AREF_LOOKUP);
|
||
return Address;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// The specified address was not found.
|
||
//
|
||
|
||
return NULL;
|
||
|
||
} /* IpxLookupAddress */
|
||
|
||
|
||
NTSTATUS
|
||
IpxStopAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
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
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
|
||
is not for a real address.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle;
|
||
PREQUEST Request;
|
||
PADDRESS Address = AddressFile->Address;
|
||
PLIST_ENTRY p;
|
||
KIRQL irql;
|
||
|
||
|
||
IoAcquireCancelSpinLock( &irql );
|
||
CTEGetLock (&Address->Lock, &LockHandle);
|
||
|
||
if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
|
||
CTEFreeLock (&Address->Lock, LockHandle);
|
||
IoReleaseCancelSpinLock( irql );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
AddressFile->State = ADDRESSFILE_STATE_CLOSING;
|
||
|
||
while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) {
|
||
|
||
p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
|
||
Request = LIST_ENTRY_TO_REQUEST (p);
|
||
|
||
REQUEST_INFORMATION(Request) = 0;
|
||
REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
|
||
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
||
|
||
CTEFreeLock(&Address->Lock, LockHandle);
|
||
IoReleaseCancelSpinLock( irql );
|
||
|
||
IpxCompleteRequest (Request);
|
||
IpxFreeRequest (Device, Request);
|
||
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
|
||
|
||
IoAcquireCancelSpinLock( &irql );
|
||
CTEGetLock(&Address->Lock, &LockHandle);
|
||
|
||
}
|
||
|
||
CTEFreeLock(&Address->Lock, LockHandle);
|
||
IoReleaseCancelSpinLock( irql );
|
||
|
||
return STATUS_SUCCESS;
|
||
} /* IpxStopAddressFile */
|
||
|
||
|
||
NTSTATUS
|
||
IpxCloseAddressFile(
|
||
IN PDEVICE Device,
|
||
IN PREQUEST Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to close the addressfile pointed to by a file
|
||
object. If there is any activity to be run down, we will run it down
|
||
before we terminate the addressfile. We remove every connection and
|
||
datagram associated with this addressfile from the address database
|
||
and terminate their activity. Then, if there are no other outstanding
|
||
addressfiles open on this address, the address will go away.
|
||
|
||
Arguments:
|
||
|
||
Request - the close request.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
|
||
request does not point to a real address.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PADDRESS_FILE AddressFile;
|
||
CTELockHandle LockHandle;
|
||
|
||
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
|
||
AddressFile->CloseRequest = Request;
|
||
|
||
//
|
||
// We assume that addressFile has already been verified
|
||
// at this point.
|
||
//
|
||
|
||
Address = AddressFile->Address;
|
||
CTEAssert (Address);
|
||
|
||
//
|
||
// Remove us from the access info for this address.
|
||
//
|
||
|
||
KeEnterCriticalRegion();
|
||
|
||
ExAcquireResourceExclusiveLite (&Device->AddressResource, TRUE);
|
||
#ifdef ISN_NT
|
||
IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
|
||
#endif
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
|
||
KeLeaveCriticalRegion();
|
||
|
||
//
|
||
// If this address file had broadcasts enabled, turn it off.
|
||
//
|
||
|
||
//
|
||
// Not needed anymore
|
||
//
|
||
/*
|
||
CTEGetLock (&Device->Lock, &LockHandle);
|
||
if (AddressFile->EnableBroadcast) {
|
||
AddressFile->EnableBroadcast = FALSE;
|
||
IpxRemoveBroadcast (Device);
|
||
}
|
||
CTEFreeLock (&Device->Lock, LockHandle);
|
||
*/
|
||
IpxStopAddressFile (AddressFile);
|
||
IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
return STATUS_PENDING;
|
||
|
||
} /* IpxCloseAddressFile */
|
||
|
||
|