1793 lines
42 KiB
C
1793 lines
42 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
spxaddr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains code which implements the ADDRESS object.
|
||
|
Routines are provided to create, destroy, reference, and dereference,
|
||
|
transport address objects.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Adam Barr (adamba ) Original Version
|
||
|
Nikhil Kamkolkar (nikhilk) 11-November-1993
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
//#pragma alloc_text( PAGE, SpxAddrFileCreate)
|
||
|
#pragma alloc_text( PAGE, SpxAddrFileClose)
|
||
|
#endif
|
||
|
|
||
|
#ifndef __PREFAST__
|
||
|
#pragma warning(disable:4068)
|
||
|
#endif
|
||
|
#pragma prefast(disable:276, "The assignments are harmless")
|
||
|
|
||
|
|
||
|
// Define module number for event logging entries
|
||
|
#define FILENUM SPXADDR
|
||
|
|
||
|
// Map all generic accesses to the same one.
|
||
|
static GENERIC_MAPPING AddressGenericMapping =
|
||
|
{ READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
|
||
|
|
||
|
#define REORDER(_Socket) ((((_Socket) & 0xff00) >> 8) | (((_Socket) & 0x00ff) << 8))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrOpen(
|
||
|
IN PDEVICE Device,
|
||
|
IN PREQUEST Request
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine opens a file that points to an existing address object, or, if
|
||
|
the object doesn't exist, creates it (note that creation of the address
|
||
|
object includes registering the address, and may take many seconds to
|
||
|
complete, depending upon system configuration).
|
||
|
|
||
|
If the address already exists, and it has an ACL associated with it, the
|
||
|
ACL is checked for access rights before allowing creation of the address.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
DeviceObject - pointer to the device object describing the ST transport.
|
||
|
|
||
|
Request - a pointer to the request used for the creation of the address.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS - status of operation.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PSPX_ADDR pAddr;
|
||
|
PSPX_ADDR_FILE pAddrFile;
|
||
|
PFILE_FULL_EA_INFORMATION ea;
|
||
|
TRANSPORT_ADDRESS UNALIGNED *name;
|
||
|
TA_ADDRESS * AddressName;
|
||
|
USHORT Socket, hostSocket;
|
||
|
ULONG DesiredShareAccess;
|
||
|
CTELockHandle LockHandle, LockHandleAddr;
|
||
|
PACCESS_STATE AccessState;
|
||
|
ACCESS_MASK GrantedAccess;
|
||
|
BOOLEAN AccessAllowed;
|
||
|
int i;
|
||
|
BOOLEAN found = FALSE;
|
||
|
INT Size = 0;
|
||
|
|
||
|
#ifdef ISN_NT
|
||
|
PIRP Irp = (PIRP)Request;
|
||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
#endif
|
||
|
|
||
|
// The network name is in the EA, passed in the request.
|
||
|
ea = OPEN_REQUEST_EA_INFORMATION(Request);
|
||
|
if (ea == NULL)
|
||
|
{
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("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];
|
||
|
|
||
|
if (ea->EaValueLength < (sizeof(TRANSPORT_ADDRESS) -1)) {
|
||
|
|
||
|
DBGPRINT(TDI, ERR, ("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);
|
||
|
}
|
||
|
|
||
|
// The name can be passed with multiple entries; we'll take and use only
|
||
|
// the first one of type IPX.
|
||
|
for (i=0;i<name->TAAddressCount;i++)
|
||
|
{
|
||
|
|
||
|
if (Size > ea->EaValueLength) {
|
||
|
|
||
|
DBGPRINT(TDI, ERR, ("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;
|
||
|
|
||
|
GETSHORT2SHORT(&hostSocket, &Socket);
|
||
|
|
||
|
DBGPRINT(CREATE, DBG,
|
||
|
("SpxAddrOpen: Creating socket %lx.h%lx\n",
|
||
|
Socket, hostSocket ));
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("OpenAddress: REQUEST %lx has no IPX Address\n", Request));
|
||
|
|
||
|
return STATUS_INVALID_ADDRESS_COMPONENT;
|
||
|
}
|
||
|
|
||
|
#ifdef SOCKET_RANGE_OPEN_LIMITATION_REMOVED
|
||
|
// Is the socket in our range if its in the range 0x4000-0x7FFF
|
||
|
if (IN_RANGE(hostSocket, DYNSKT_RANGE_START, DYNSKT_RANGE_END))
|
||
|
{
|
||
|
if (!IN_RANGE(
|
||
|
hostSocket,
|
||
|
PARAM(CONFIG_SOCKET_RANGE_START),
|
||
|
PARAM(CONFIG_SOCKET_RANGE_END)))
|
||
|
{
|
||
|
return(STATUS_INVALID_ADDRESS);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// get an address file structure to represent this address.
|
||
|
status = SpxAddrFileCreate(Device, Request, &pAddrFile);
|
||
|
if (!NT_SUCCESS(status))
|
||
|
return status;
|
||
|
|
||
|
// See if this address is already established. This call automatically
|
||
|
// increments the reference count on the address so that it won't disappear
|
||
|
// from underneath us after this call but before we have a chance to use it.
|
||
|
//
|
||
|
// To ensure that we don't create two address objects for the
|
||
|
// same address, we hold the device context addressResource until
|
||
|
// we have found the address or created a new one.
|
||
|
|
||
|
KeEnterCriticalRegion();
|
||
|
ExAcquireResourceExclusiveLite (&Device->dev_AddrResource, TRUE);
|
||
|
CTEGetLock (&Device->dev_Lock, &LockHandle);
|
||
|
|
||
|
// We checkfor/create sockets within the critical section.
|
||
|
if (Socket == 0)
|
||
|
{
|
||
|
Socket = SpxAddrAssignSocket(Device);
|
||
|
|
||
|
if (Socket == 0)
|
||
|
{
|
||
|
DBGPRINT(ADDRESS, ERR,
|
||
|
("OpenAddress, no unique socket found\n"));
|
||
|
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("OpenAddress, assigned socket %lx\n", Socket));
|
||
|
}
|
||
|
|
||
|
pAddr = SpxAddrLookup(Device, Socket);
|
||
|
|
||
|
if (pAddr == NULL)
|
||
|
{
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
|
||
|
// This address doesn't exist. Create it.
|
||
|
// registering it. It also puts a ref of type ADDR_FILE on address.
|
||
|
pAddr = SpxAddrCreate(
|
||
|
Device,
|
||
|
Socket);
|
||
|
|
||
|
if (pAddr != (PSPX_ADDR)NULL)
|
||
|
{
|
||
|
#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,
|
||
|
&pAddr->u.sa_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,
|
||
|
&pAddr->sa_SecurityDescriptor,
|
||
|
FALSE, // is directory
|
||
|
&AccessState->SubjectSecurityContext,
|
||
|
&AddressGenericMapping,
|
||
|
NonPagedPool);
|
||
|
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
// Error, return status.
|
||
|
IoRemoveShareAccess (IrpSp->FileObject, &pAddr->u.sa_ShareAccess);
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
SpxAddrDereference (pAddr, AREF_ADDR_FILE);
|
||
|
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
|
||
|
// if the adapter isn't ready, we can't do any of this; get out
|
||
|
#if defined(_PNP_POWER)
|
||
|
if (Device->dev_State != DEVICE_STATE_OPEN)
|
||
|
#else
|
||
|
if (Device->dev_State == DEVICE_STATE_STOPPING)
|
||
|
#endif _PNP_POWER
|
||
|
{
|
||
|
SpxAddrDereference (pAddr, AREF_ADDR_FILE);
|
||
|
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
status = STATUS_DEVICE_NOT_READY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
|
||
|
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
|
#ifdef ISN_NT
|
||
|
pAddrFile->saf_FileObject = IrpSp->FileObject;
|
||
|
#endif
|
||
|
CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
|
||
|
pAddrFile->saf_Addr = pAddr;
|
||
|
pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
|
||
|
|
||
|
// Set flags appropriately, note spx/stream flags are set at this
|
||
|
// point.
|
||
|
pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
|
||
|
|
||
|
// Queue in the address list, removed in destroy.
|
||
|
pAddrFile->saf_Next = pAddr->sa_AddrFileList;
|
||
|
pAddr->sa_AddrFileList = pAddrFile;
|
||
|
|
||
|
CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
|
||
|
status = STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
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.
|
||
|
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
|
||
|
DBGPRINT(ADDRESS, ERR,
|
||
|
("Add to address %lx\n", pAddr));
|
||
|
|
||
|
// 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(
|
||
|
pAddr->sa_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->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef ISN_NT
|
||
|
|
||
|
// Now check that we can obtain the desired share
|
||
|
// access. We use read access to control all access.
|
||
|
DesiredShareAccess = (ULONG)
|
||
|
(((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
||
|
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
|
||
|
FILE_SHARE_READ : 0);
|
||
|
|
||
|
status = IoCheckShareAccess(
|
||
|
FILE_READ_DATA,
|
||
|
DesiredShareAccess,
|
||
|
IrpSp->FileObject,
|
||
|
&pAddr->u.sa_ShareAccess,
|
||
|
TRUE);
|
||
|
|
||
|
#else // ISN_NT
|
||
|
|
||
|
status = STATUS_SUCCESS;
|
||
|
|
||
|
#endif // ISN_NT
|
||
|
|
||
|
if (!NT_SUCCESS (status))
|
||
|
{
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
CTEGetLock (&Device->dev_Lock, &LockHandle);
|
||
|
CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
|
||
|
|
||
|
pAddrFile->saf_Addr = pAddr;
|
||
|
pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
|
||
|
#ifdef ISN_NT
|
||
|
pAddrFile->saf_FileObject = IrpSp->FileObject;
|
||
|
#endif
|
||
|
// Set flags appropriately, note spx/stream flags are set at this
|
||
|
// point.
|
||
|
pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
|
||
|
|
||
|
SpxAddrLockReference (pAddr, AREF_ADDR_FILE);
|
||
|
|
||
|
REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
|
||
|
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
|
|
||
|
// Queue in the address list, removed in destroy.
|
||
|
pAddrFile->saf_Next = pAddr->sa_AddrFileList;
|
||
|
pAddr->sa_AddrFileList = pAddrFile;
|
||
|
|
||
|
CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
|
||
|
status = STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove the reference from SpxLookupAddress.
|
||
|
SpxAddrDereference (pAddr, AREF_LOOKUP);
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
|
||
|
} // SpxAddrOpen
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrSetEventHandler(
|
||
|
IN PDEVICE Device,
|
||
|
IN PREQUEST pRequest
|
||
|
)
|
||
|
{
|
||
|
CTELockHandle lockHandle;
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
|
||
|
PSPX_ADDR_FILE
|
||
|
pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
|
||
|
PTDI_REQUEST_KERNEL_SET_EVENT
|
||
|
pParam = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(pRequest);
|
||
|
|
||
|
if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
|
||
|
return(status);
|
||
|
|
||
|
CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
|
||
|
switch (pParam->EventType)
|
||
|
{
|
||
|
|
||
|
case TDI_EVENT_ERROR:
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TDI_EVENT_CONNECT:
|
||
|
|
||
|
pSpxAddrFile->saf_ConnHandler =
|
||
|
(PTDI_IND_CONNECT)(pParam->EventHandler);
|
||
|
pSpxAddrFile->saf_ConnHandlerCtx =
|
||
|
pParam->EventContext;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TDI_EVENT_RECEIVE:
|
||
|
|
||
|
pSpxAddrFile->saf_RecvHandler =
|
||
|
(PTDI_IND_RECEIVE)(pParam->EventHandler);
|
||
|
pSpxAddrFile->saf_RecvHandlerCtx =
|
||
|
pParam->EventContext;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TDI_EVENT_DISCONNECT:
|
||
|
|
||
|
pSpxAddrFile->saf_DiscHandler =
|
||
|
(PTDI_IND_DISCONNECT)(pParam->EventHandler);
|
||
|
pSpxAddrFile->saf_DiscHandlerCtx =
|
||
|
pParam->EventContext;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case TDI_EVENT_SEND_POSSIBLE :
|
||
|
|
||
|
pSpxAddrFile->saf_SendPossibleHandler =
|
||
|
(PTDI_IND_SEND_POSSIBLE)(pParam->EventHandler);
|
||
|
pSpxAddrFile->saf_SendPossibleHandlerCtx =
|
||
|
pParam->EventContext;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TDI_EVENT_RECEIVE_DATAGRAM:
|
||
|
case TDI_EVENT_RECEIVE_EXPEDITED:
|
||
|
default:
|
||
|
|
||
|
status = STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
|
||
|
|
||
|
SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
PSPX_ADDR
|
||
|
SpxAddrCreate(
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR pAddr;
|
||
|
int index;
|
||
|
CTELockHandle lockHandle;
|
||
|
|
||
|
pAddr = (PSPX_ADDR)SpxAllocateZeroedMemory (sizeof(SPX_ADDR));
|
||
|
if (pAddr == NULL)
|
||
|
{
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("Create address %lx failed\n", (ULONG)Socket));
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("Create address %lx (%lx)\n", pAddr, (ULONG)Socket));
|
||
|
|
||
|
pAddr->sa_Type = SPX_ADDRESS_SIGNATURE;
|
||
|
pAddr->sa_Size = sizeof (SPX_ADDR);
|
||
|
pAddr->sa_Flags = 0;
|
||
|
|
||
|
pAddr->sa_Device = Device;
|
||
|
pAddr->sa_DeviceLock = &Device->dev_Lock;
|
||
|
CTEInitLock (&pAddr->sa_Lock);
|
||
|
|
||
|
// This reference is for the address file that will associated with this addr.
|
||
|
pAddr->sa_RefCount = 1;
|
||
|
|
||
|
#if DBG
|
||
|
pAddr->sa_RefTypes[AREF_ADDR_FILE] = 1;
|
||
|
#endif
|
||
|
|
||
|
pAddr->sa_Socket = Socket;
|
||
|
|
||
|
// Insert address into the device hash table.
|
||
|
index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
|
||
|
|
||
|
CTEGetLock (&Device->dev_Lock, &lockHandle);
|
||
|
pAddr->sa_Next = Device->dev_AddrHashTable[index];
|
||
|
Device->dev_AddrHashTable[index] = pAddr;
|
||
|
CTEFreeLock (&Device->dev_Lock, lockHandle);
|
||
|
|
||
|
SpxReferenceDevice (Device, DREF_ADDRESS);
|
||
|
|
||
|
return pAddr;
|
||
|
|
||
|
} // SpxAddrCreate
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileVerify(
|
||
|
IN PSPX_ADDR_FILE pAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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 SPX_ADDR_FILE object
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
CTELockHandle LockHandle;
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
PSPX_ADDR 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 ((pAddrFile->saf_Size == sizeof (SPX_ADDR_FILE)) &&
|
||
|
(pAddrFile->saf_Type == SPX_ADDRESSFILE_SIGNATURE) )
|
||
|
{
|
||
|
Address = pAddrFile->saf_Addr;
|
||
|
|
||
|
if ((Address->sa_Size == sizeof (SPX_ADDR)) &&
|
||
|
(Address->sa_Type == SPX_ADDRESS_SIGNATURE) )
|
||
|
{
|
||
|
CTEGetLock (&Address->sa_Lock, &LockHandle);
|
||
|
|
||
|
if ((Address->sa_Flags & SPX_ADDR_CLOSING) == 0)
|
||
|
{
|
||
|
SpxAddrFileLockReference(pAddrFile, AFREF_VERIFY);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("StVerifyAddressFile: A %lx closing\n", Address));
|
||
|
|
||
|
status = STATUS_INVALID_ADDRESS;
|
||
|
}
|
||
|
|
||
|
CTEFreeLock (&Address->sa_Lock, LockHandle);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("StVerifyAddressFile: A %lx bad signature\n", Address));
|
||
|
|
||
|
status = STATUS_INVALID_ADDRESS;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("StVerifyAddressFile: AF %lx bad signature\n", pAddrFile));
|
||
|
|
||
|
status = STATUS_INVALID_ADDRESS;
|
||
|
}
|
||
|
|
||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
|
||
|
DBGPRINT(TDI, ERR,
|
||
|
("SpxAddrFileVerify: AF %lx exception\n", Address));
|
||
|
|
||
|
return GetExceptionCode();
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
|
||
|
} // SpxAddrFileVerify
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpxAddrDestroy(
|
||
|
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 SpxDerefAddress when
|
||
|
the reference count goes to 0.
|
||
|
|
||
|
This thread is only queued by SpxDerefAddress. 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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR pAddr, *ppAddr;
|
||
|
CTELockHandle LockHandle;
|
||
|
|
||
|
PSPX_ADDR Address = (PSPX_ADDR)Parameter;
|
||
|
PDEVICE Device = Address->sa_Device;
|
||
|
int index = (int)(Address->sa_Socket & NUM_SPXADDR_HASH_MASK);
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("Destroy address %lx\n", Address));
|
||
|
|
||
|
SeDeassignSecurity (&Address->sa_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->dev_Lock, &LockHandle);
|
||
|
for (ppAddr = &Device->dev_AddrHashTable[index]; (pAddr = *ppAddr) != NULL;)
|
||
|
{
|
||
|
if (pAddr == Address)
|
||
|
{
|
||
|
*ppAddr = pAddr->sa_Next;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ppAddr = &pAddr->sa_Next;
|
||
|
}
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
|
||
|
SpxFreeMemory (Address);
|
||
|
SpxDereferenceDevice (Device, DREF_ADDRESS);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
VOID
|
||
|
SpxAddrRef(
|
||
|
IN PSPX_ADDR 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->sa_RefCount > 0); // not perfect, but...
|
||
|
|
||
|
(VOID)SPX_ADD_ULONG (
|
||
|
&Address->sa_RefCount,
|
||
|
1,
|
||
|
Address->sa_DeviceLock);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpxAddrLockRef(
|
||
|
IN PSPX_ADDR 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->sa_RefCount > 0); // not perfect, but...
|
||
|
(VOID)SPX_ADD_ULONG (
|
||
|
&Address->sa_RefCount,
|
||
|
1,
|
||
|
Address->sa_DeviceLock);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpxAddrDeref(
|
||
|
IN PSPX_ADDR 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
|
||
|
SpxDestroyAddress to remove it from the system.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Address - Pointer to a transport address object.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG oldvalue;
|
||
|
|
||
|
oldvalue = SPX_ADD_ULONG (
|
||
|
&Address->sa_RefCount,
|
||
|
(ULONG)-1,
|
||
|
Address->sa_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.sa_DestroyAddrQueueItem,
|
||
|
SpxAddrDestroy,
|
||
|
(PVOID)Address);
|
||
|
ExQueueWorkItem(&Address->u.sa_DestroyAddrQueueItem, DelayedWorkQueue);
|
||
|
#else
|
||
|
SpxAddrDestroy(Address);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileCreate(
|
||
|
IN PDEVICE Device,
|
||
|
IN PREQUEST Request,
|
||
|
OUT PSPX_ADDR_FILE * ppAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
BYTE socketType;
|
||
|
CTELockHandle LockHandle;
|
||
|
PSPX_ADDR_FILE pAddrFile;
|
||
|
|
||
|
// What is the address file type?
|
||
|
if (!NT_SUCCESS(status = SpxUtilGetSocketType(
|
||
|
REQUEST_OPEN_NAME(Request),
|
||
|
&socketType)))
|
||
|
{
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
pAddrFile = (PSPX_ADDR_FILE)SpxAllocateZeroedMemory (sizeof(SPX_ADDR_FILE));
|
||
|
if (pAddrFile == NULL)
|
||
|
{
|
||
|
DBGPRINT(ADDRESS, ERR,
|
||
|
("Create address file failed\n"));
|
||
|
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("Create address file %lx\n", pAddrFile));
|
||
|
|
||
|
CTEGetLock (&Device->dev_Lock, &LockHandle);
|
||
|
|
||
|
pAddrFile->saf_Type = SPX_ADDRESSFILE_SIGNATURE;
|
||
|
pAddrFile->saf_Size = sizeof (SPX_ADDR_FILE);
|
||
|
|
||
|
pAddrFile->saf_Addr = NULL;
|
||
|
|
||
|
#ifdef ISN_NT
|
||
|
pAddrFile->saf_FileObject = NULL;
|
||
|
#endif
|
||
|
|
||
|
pAddrFile->saf_Device = Device;
|
||
|
pAddrFile->saf_Flags = SPX_ADDRFILE_OPENING;
|
||
|
if ((socketType == SOCKET1_TYPE_SEQPKT) ||
|
||
|
(socketType == SOCKET1_TYPE_STREAM))
|
||
|
{
|
||
|
if (socketType == SOCKET1_TYPE_STREAM)
|
||
|
{
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((socketType == SOCKET2_TYPE_SEQPKT) ||
|
||
|
(socketType == SOCKET2_TYPE_STREAM))
|
||
|
{
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_SPX2;
|
||
|
if (socketType == SOCKET2_TYPE_STREAM)
|
||
|
{
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pAddrFile->saf_RefCount = 1;
|
||
|
|
||
|
#if DBG
|
||
|
pAddrFile->saf_RefTypes[AFREF_CREATE] = 1;
|
||
|
#endif
|
||
|
|
||
|
pAddrFile->saf_CloseReq = (PREQUEST)NULL;
|
||
|
|
||
|
// Initialize the request handlers.
|
||
|
pAddrFile->saf_ConnHandler =
|
||
|
pAddrFile->saf_ConnHandlerCtx = NULL;
|
||
|
pAddrFile->saf_DiscHandler =
|
||
|
pAddrFile->saf_DiscHandlerCtx = NULL;
|
||
|
pAddrFile->saf_RecvHandler =
|
||
|
pAddrFile->saf_RecvHandlerCtx = NULL;
|
||
|
pAddrFile->saf_ErrHandler =
|
||
|
pAddrFile->saf_ErrHandlerCtx = NULL;
|
||
|
|
||
|
// Release lock
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle);
|
||
|
|
||
|
// Put in the global list for our reference
|
||
|
spxAddrInsertIntoGlobalList(pAddrFile);
|
||
|
|
||
|
*ppAddrFile = pAddrFile;
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileDestroy(
|
||
|
IN PSPX_ADDR_FILE pAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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 SpxAddrFileDereference. 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:
|
||
|
|
||
|
pAddrFile Pointer to a transport address file structure to be destroyed.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NTSTATUS - status of operation.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
CTELockHandle LockHandle, LockHandle1;
|
||
|
PSPX_ADDR Address;
|
||
|
PDEVICE Device;
|
||
|
PREQUEST CloseRequest;
|
||
|
PSPX_ADDR_FILE pRemAddr, *ppRemAddr;
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("Destroy address file %lx\n", pAddrFile));
|
||
|
|
||
|
Address = pAddrFile->saf_Addr;
|
||
|
Device = pAddrFile->saf_Device;
|
||
|
|
||
|
if (Address)
|
||
|
{
|
||
|
CTEGetLock (&Device->dev_Lock, &LockHandle1);
|
||
|
|
||
|
// This addressfile was associated with an address.
|
||
|
CTEGetLock (&Address->sa_Lock, &LockHandle);
|
||
|
|
||
|
// If the last reference on the address is being removed, set the
|
||
|
// closing flag to prevent further references.
|
||
|
|
||
|
//if (Address->sa_RefCount == 1)
|
||
|
|
||
|
//
|
||
|
// ** The lock passed here is a dummy - it is pre-compiled out.
|
||
|
//
|
||
|
if (SPX_ADD_ULONG(&Address->sa_RefCount, 0, &Address->sa_Lock) == 1) {
|
||
|
Address->sa_Flags |= SPX_ADDR_CLOSING;
|
||
|
}
|
||
|
|
||
|
// Dequeue the address file from the address list.
|
||
|
for (ppRemAddr = &Address->sa_AddrFileList; (pRemAddr = *ppRemAddr) != NULL;)
|
||
|
{
|
||
|
if (pRemAddr == pAddrFile)
|
||
|
{
|
||
|
*ppRemAddr = pRemAddr->saf_Next;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ppRemAddr = &pRemAddr->saf_Next;
|
||
|
}
|
||
|
|
||
|
pAddrFile->saf_Addr = NULL;
|
||
|
|
||
|
#ifdef ISN_NT
|
||
|
pAddrFile->saf_FileObject->FsContext = NULL;
|
||
|
pAddrFile->saf_FileObject->FsContext2 = NULL;
|
||
|
#endif
|
||
|
|
||
|
CTEFreeLock (&Address->sa_Lock, LockHandle);
|
||
|
CTEFreeLock (&Device->dev_Lock, LockHandle1);
|
||
|
|
||
|
// We will already have been removed from the ShareAccess
|
||
|
// of the owning address.
|
||
|
//
|
||
|
// Now dereference the owning address.
|
||
|
SpxAddrDereference(Address, AREF_ADDR_FILE);
|
||
|
}
|
||
|
|
||
|
// Save this for later completion.
|
||
|
CloseRequest = pAddrFile->saf_CloseReq;
|
||
|
|
||
|
// Remove from the global list
|
||
|
spxAddrRemoveFromGlobalList(pAddrFile);
|
||
|
|
||
|
// return the addressFile to the pool of address files
|
||
|
SpxFreeMemory (pAddrFile);
|
||
|
|
||
|
if (CloseRequest != (PREQUEST)NULL)
|
||
|
{
|
||
|
REQUEST_INFORMATION(CloseRequest) = 0;
|
||
|
REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
|
||
|
SpxCompleteRequest (CloseRequest);
|
||
|
SpxFreeRequest (Device, CloseRequest);
|
||
|
}
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
VOID
|
||
|
SpxAddrFileRef(
|
||
|
IN PSPX_ADDR_FILE pAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine increments the reference count on an address file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAddrFile - Pointer to a transport address file object.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
|
||
|
|
||
|
(VOID)SPX_ADD_ULONG (
|
||
|
&pAddrFile->saf_RefCount,
|
||
|
1,
|
||
|
pAddrFile->saf_AddrLock);
|
||
|
|
||
|
} // SpxRefAddressFile
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpxAddrFileLockRef(
|
||
|
IN PSPX_ADDR_FILE pAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine increments the reference count on an address file.
|
||
|
IT IS CALLED WITH THE ADDRESS LOCK HELD.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAddrFile - Pointer to a transport address file object.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
|
||
|
(VOID)SPX_ADD_ULONG (
|
||
|
&pAddrFile->saf_RefCount,
|
||
|
1,
|
||
|
pAddrFile->saf_AddrLock);
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SpxAddrFileDeref(
|
||
|
IN PSPX_ADDR_FILE pAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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
|
||
|
SpxDestroyAddressFile to remove it from the system.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAddrFile - Pointer to a transport address file object.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG oldvalue;
|
||
|
|
||
|
oldvalue = SPX_ADD_ULONG (
|
||
|
&pAddrFile->saf_RefCount,
|
||
|
(ULONG)-1,
|
||
|
pAddrFile->saf_AddrLock);
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
SpxAddrFileDestroy(pAddrFile);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
PSPX_ADDR
|
||
|
SpxAddrLookup(
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR Address;
|
||
|
int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
|
||
|
|
||
|
for (Address = Device->dev_AddrHashTable[index];
|
||
|
Address != NULL;
|
||
|
Address = Address->sa_Next)
|
||
|
{
|
||
|
if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (Address->sa_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.
|
||
|
SpxAddrLockReference(Address, AREF_LOOKUP);
|
||
|
return Address;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The specified address was not found.
|
||
|
return NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
SpxAddrExists(
|
||
|
IN PDEVICE Device,
|
||
|
IN USHORT Socket
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
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:
|
||
|
|
||
|
TRUE if so, else FALSE
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR Address;
|
||
|
int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
|
||
|
|
||
|
for (Address = Device->dev_AddrHashTable[index];
|
||
|
Address != NULL;
|
||
|
Address = Address->sa_Next)
|
||
|
{
|
||
|
if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (Address->sa_Socket == Socket)
|
||
|
{
|
||
|
// We found the match
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The specified address was not found.
|
||
|
return FALSE;
|
||
|
|
||
|
} // SpxAddrExists
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrConnByRemoteIdAddrLock(
|
||
|
IN PSPX_ADDR pSpxAddr,
|
||
|
IN USHORT SrcConnId,
|
||
|
IN PBYTE SrcIpxAddr,
|
||
|
OUT PSPX_CONN_FILE *ppSpxConnFile
|
||
|
)
|
||
|
{
|
||
|
PSPX_CONN_FILE pSpxConnFile;
|
||
|
NTSTATUS status = STATUS_INVALID_CONNECTION;
|
||
|
|
||
|
for (pSpxConnFile = pSpxAddr->sa_ActiveConnList;
|
||
|
pSpxConnFile != NULL;
|
||
|
pSpxConnFile = pSpxConnFile->scf_Next)
|
||
|
{
|
||
|
if ((pSpxConnFile->scf_RemConnId == SrcConnId) &&
|
||
|
(*((UNALIGNED ULONG *)SrcIpxAddr) ==
|
||
|
*((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)) &&
|
||
|
(*(UNALIGNED ULONG *)(SrcIpxAddr+4) ==
|
||
|
*(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4)) &&
|
||
|
(*(UNALIGNED ULONG *)(SrcIpxAddr+8) ==
|
||
|
*(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+8)))
|
||
|
{
|
||
|
SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
|
||
|
*ppSpxConnFile = pSpxConnFile;
|
||
|
status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileStop(
|
||
|
IN PSPX_ADDR_FILE pAddrFile,
|
||
|
IN PSPX_ADDR Address
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called to terminate all activity on an pAddrFile 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:
|
||
|
|
||
|
pAddrFile - pointer to the addressFile to be stopped
|
||
|
|
||
|
Address - the owning address for this addressFile (we do not depend upon
|
||
|
the pointer in the addressFile because we want this routine to be safe)
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
|
||
|
is not for a real address.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_CONN_FILE pSpxConnFile, pSpxConnFileNext;
|
||
|
CTELockHandle LockHandle;
|
||
|
|
||
|
|
||
|
DBGPRINT(ADDRESS, DBG,
|
||
|
("SpxAddrFileStop: %lx\n", pAddrFile));
|
||
|
|
||
|
CTEGetLock (&Address->sa_Lock, &LockHandle);
|
||
|
|
||
|
if (pAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING)
|
||
|
{
|
||
|
CTEFreeLock (&Address->sa_Lock, LockHandle);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
pAddrFile->saf_Flags |= SPX_ADDRFILE_CLOSING;
|
||
|
|
||
|
pSpxConnFileNext = NULL;
|
||
|
if (pSpxConnFile = pAddrFile->saf_AssocConnList)
|
||
|
{
|
||
|
pSpxConnFileNext = pSpxConnFile;
|
||
|
SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
|
||
|
}
|
||
|
|
||
|
while (pSpxConnFile)
|
||
|
{
|
||
|
if (pSpxConnFileNext = pSpxConnFile->scf_AssocNext)
|
||
|
{
|
||
|
SpxConnFileReference(pSpxConnFileNext, CFREF_ADDR);
|
||
|
}
|
||
|
CTEFreeLock (&Address->sa_Lock, LockHandle);
|
||
|
|
||
|
|
||
|
DBGPRINT(CREATE, INFO,
|
||
|
("SpxAddrFileClose: Assoc conn stop %lx when %lx\n",
|
||
|
pSpxConnFile, pSpxConnFile->scf_RefCount));
|
||
|
|
||
|
SpxConnStop(pSpxConnFile);
|
||
|
SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
|
||
|
|
||
|
CTEGetLock (&Address->sa_Lock, &LockHandle);
|
||
|
pSpxConnFile = pSpxConnFileNext;
|
||
|
}
|
||
|
|
||
|
CTEFreeLock (&Address->sa_Lock, LockHandle);
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileCleanup(
|
||
|
IN PDEVICE Device,
|
||
|
IN PREQUEST Request
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR Address;
|
||
|
PSPX_ADDR_FILE pSpxAddrFile;
|
||
|
NTSTATUS status;
|
||
|
|
||
|
pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("SpxAddrFileCleanup: %lx\n", pSpxAddrFile));
|
||
|
|
||
|
status = SpxAddrFileVerify(pSpxAddrFile);
|
||
|
if (!NT_SUCCESS (status))
|
||
|
{
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
// We assume that addressFile has already been verified
|
||
|
// at this point.
|
||
|
Address = pSpxAddrFile->saf_Addr;
|
||
|
CTEAssert (Address);
|
||
|
|
||
|
SpxAddrFileStop(pSpxAddrFile, Address);
|
||
|
SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpxAddrFileClose(
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PSPX_ADDR Address;
|
||
|
PSPX_ADDR_FILE pSpxAddrFile;
|
||
|
NTSTATUS status;
|
||
|
|
||
|
pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
|
||
|
|
||
|
DBGPRINT(ADDRESS, DBG,
|
||
|
("SpxAddrFileClose: %lx\n", pSpxAddrFile));
|
||
|
|
||
|
status = SpxAddrFileVerify(pSpxAddrFile);
|
||
|
|
||
|
if (!NT_SUCCESS (status))
|
||
|
{
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
pSpxAddrFile->saf_CloseReq = Request;
|
||
|
|
||
|
// We assume that addressFile has already been verified
|
||
|
// at this point.
|
||
|
Address = pSpxAddrFile->saf_Addr;
|
||
|
CTEAssert (Address);
|
||
|
|
||
|
// Remove us from the access info for this address.
|
||
|
KeEnterCriticalRegion();
|
||
|
ExAcquireResourceExclusiveLite (&Device->dev_AddrResource, TRUE);
|
||
|
|
||
|
#ifdef ISN_NT
|
||
|
IoRemoveShareAccess (pSpxAddrFile->saf_FileObject, &Address->u.sa_ShareAccess);
|
||
|
#endif
|
||
|
|
||
|
ExReleaseResourceLite (&Device->dev_AddrResource);
|
||
|
KeLeaveCriticalRegion();
|
||
|
|
||
|
|
||
|
SpxAddrFileDereference (pSpxAddrFile, AFREF_CREATE);
|
||
|
SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
|
||
|
return STATUS_PENDING;
|
||
|
|
||
|
} // SpxCloseAddressFile
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
USHORT
|
||
|
SpxAddrAssignSocket(
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
BOOLEAN wrapped = FALSE;
|
||
|
USHORT temp, Socket;
|
||
|
|
||
|
// We have to auto-assign a socket.
|
||
|
temp = Device->dev_CurrentSocket;
|
||
|
PUTSHORT2SHORT(
|
||
|
&Socket,
|
||
|
Device->dev_CurrentSocket);
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
Device->dev_CurrentSocket += (USHORT)PARAM(CONFIG_SOCKET_UNIQUENESS);
|
||
|
if (Device->dev_CurrentSocket > PARAM(CONFIG_SOCKET_RANGE_END))
|
||
|
{
|
||
|
Device->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
|
||
|
wrapped = TRUE;
|
||
|
}
|
||
|
|
||
|
if (!SpxAddrExists (Device, Socket))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
PUTSHORT2SHORT(
|
||
|
&Socket,
|
||
|
Device->dev_CurrentSocket);
|
||
|
|
||
|
if (wrapped && (Device->dev_CurrentSocket >= temp))
|
||
|
{
|
||
|
// If we have checked all possible values given SOCKET_UNIQUENESS...
|
||
|
// This may actually return ERROR even if there are
|
||
|
// available socket numbers although they may be
|
||
|
// implicitly in use due to SOCKET_UNIQUENESS being
|
||
|
// > 1. That is the way it is to work.
|
||
|
|
||
|
Socket = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBGPRINT(ADDRESS, INFO,
|
||
|
("OpenAddress, assigned socket %lx\n", Socket));
|
||
|
|
||
|
return(Socket);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
spxAddrInsertIntoGlobalList(
|
||
|
IN PSPX_ADDR_FILE pSpxAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
CTELockHandle lockHandle;
|
||
|
|
||
|
// Get the global q lock
|
||
|
CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
|
||
|
pSpxAddrFile->saf_GlobalNext = SpxGlobalAddrList;
|
||
|
SpxGlobalAddrList = pSpxAddrFile;
|
||
|
CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
spxAddrRemoveFromGlobalList(
|
||
|
IN PSPX_ADDR_FILE pSpxAddrFile
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
CTELockHandle lockHandle;
|
||
|
PSPX_ADDR_FILE pC, *ppC;
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
|
||
|
// Get the global q lock
|
||
|
CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
|
||
|
for (ppC = &SpxGlobalAddrList;
|
||
|
(pC = *ppC) != NULL;)
|
||
|
{
|
||
|
if (pC == pSpxAddrFile)
|
||
|
{
|
||
|
DBGPRINT(SEND, INFO,
|
||
|
("SpxAddrRemoveFromGlobal: %lx\n", pSpxAddrFile));
|
||
|
|
||
|
// Remove from list
|
||
|
*ppC = pC->saf_GlobalNext;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ppC = &pC->saf_GlobalNext;
|
||
|
}
|
||
|
CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
|
||
|
|
||
|
if (pC == NULL)
|
||
|
status = STATUS_INVALID_ADDRESS;
|
||
|
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|