1491 lines
48 KiB
C
1491 lines
48 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bind.c
|
||
|
||
Abstract:
|
||
|
||
Contains AfdBind for binding an endpoint to a transport address.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 25-Feb-1992
|
||
|
||
Revision History:
|
||
Vadim Eydelman (vadime) 1999 - C_ROOT endpoint handling,
|
||
exclusive access endpoints.
|
||
|
||
--*/
|
||
|
||
#include "afdp.h"
|
||
|
||
NTSTATUS
|
||
AfdRestartGetAddress (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
AfdRestartBindGetAddress (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
BOOLEAN
|
||
AfdIsAddressInUse (
|
||
PAFD_ENDPOINT Endpoint,
|
||
BOOLEAN OtherProcessesOnly
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, AfdBind )
|
||
#pragma alloc_text( PAGE, AfdIsAddressInUse )
|
||
#pragma alloc_text( PAGE, AfdGetAddress )
|
||
#pragma alloc_text( PAGEAFD, AfdAreTransportAddressesEqual )
|
||
#pragma alloc_text( PAGEAFD, AfdRestartGetAddress )
|
||
#pragma alloc_text( PAGEAFD, AfdRestartBindGetAddress )
|
||
#endif
|
||
|
||
NTSTATUS
|
||
FASTCALL
|
||
AfdBind (
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles the IOCTL_AFD_BIND IOCTL.
|
||
|
||
Arguments:
|
||
|
||
Irp - Pointer to I/O request packet.
|
||
|
||
IrpSp - pointer to the IO stack location to use for this request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS -- Indicates whether the request was successfully queued.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
ULONG shareAccess, afdShareAccess;
|
||
ULONG tdiAddressLength;
|
||
PAFD_ENDPOINT endpoint;
|
||
|
||
ULONG options;
|
||
PTRANSPORT_ADDRESS localAddress;
|
||
HANDLE addressHandle;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
IO_STATUS_BLOCK iosb;
|
||
PFILE_FULL_EA_INFORMATION eaInfo;
|
||
ULONG eaLength;
|
||
// Local buffer to avoid memory allocation
|
||
PCHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
AFD_MAX_FAST_TRANSPORT_ADDRESS];
|
||
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Initialize returned parameter
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
|
||
//
|
||
// Need to have output buffer at least as long as input buffer
|
||
// to pass the address that was actually used by the transport
|
||
// back.
|
||
//
|
||
|
||
if ( (IrpSp->Parameters.DeviceIoControl.InputBufferLength<
|
||
(ULONG)FIELD_OFFSET (AFD_BIND_INFO, Address.Address)) ||
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength<
|
||
sizeof (TDI_ADDRESS_INFO) ||
|
||
(IrpSp->Parameters.DeviceIoControl.OutputBufferLength-
|
||
(ULONG)FIELD_OFFSET (TDI_ADDRESS_INFO, Address) <
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength-
|
||
(ULONG)FIELD_OFFSET (AFD_BIND_INFO, Address) ) ) {
|
||
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
|
||
//
|
||
// Set up local pointers.
|
||
//
|
||
|
||
endpoint = IrpSp->FileObject->FsContext;
|
||
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
||
|
||
localAddress = NULL;
|
||
addressHandle = NULL;
|
||
|
||
tdiAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength
|
||
- FIELD_OFFSET (AFD_BIND_INFO, Address);
|
||
|
||
//
|
||
// This is a state change operation, there should be no other
|
||
// state changes going at the same time.
|
||
//
|
||
if (!AFD_START_STATE_CHANGE (endpoint, AfdEndpointStateBound)) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
|
||
//
|
||
// Bomb off if this endpoind already has address associated with it
|
||
//
|
||
|
||
if ( endpoint->State != AfdEndpointStateOpen ) {
|
||
status = STATUS_ADDRESS_ALREADY_ASSOCIATED;
|
||
goto complete_wrong_state;
|
||
}
|
||
|
||
|
||
try {
|
||
PAFD_BIND_INFO bindInfo;
|
||
|
||
bindInfo = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
||
if (Irp->RequestorMode!=KernelMode) {
|
||
ProbeForRead (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
|
||
PROBE_ALIGNMENT (AFD_BIND_INFO));
|
||
}
|
||
|
||
//
|
||
// Allocate space for local address
|
||
//
|
||
localAddress = AFD_ALLOCATE_POOL_WITH_QUOTA (
|
||
NonPagedPool,
|
||
tdiAddressLength,
|
||
AFD_LOCAL_ADDRESS_POOL_TAG
|
||
);
|
||
|
||
// AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
|
||
ASSERT ( localAddress != NULL );
|
||
|
||
afdShareAccess = bindInfo->ShareAccess;
|
||
RtlMoveMemory(
|
||
localAddress,
|
||
&bindInfo->Address,
|
||
tdiAddressLength
|
||
);
|
||
//
|
||
// Validate internal consistency of the transport address structure.
|
||
// Note that we HAVE to do this after copying since the malicious
|
||
// application can change the content of the buffer on us any time
|
||
// and our check will be bypassed.
|
||
//
|
||
if ((localAddress->TAAddressCount!=1) ||
|
||
(LONG)tdiAddressLength<
|
||
FIELD_OFFSET (TRANSPORT_ADDRESS,
|
||
Address[0].Address[localAddress->Address[0].AddressLength])) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete_state_change;
|
||
}
|
||
|
||
if (IoAllocateMdl (Irp->UserBuffer,
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
|
||
FALSE, // SecondaryBuffer
|
||
TRUE, // ChargeQuota
|
||
Irp // Irp
|
||
)==NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto complete_state_change;
|
||
}
|
||
MmProbeAndLockPages (Irp->MdlAddress,
|
||
Irp->RequestorMode,
|
||
IoWriteAccess);
|
||
if (MmGetSystemAddressForMdlSafe (Irp->MdlAddress, HighPagePriority)==NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto complete_state_change;
|
||
}
|
||
}
|
||
except (AFD_EXCEPTION_FILTER(&status)) {
|
||
goto complete_state_change;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Make sure we have a valid provider info structure.
|
||
// (we do not take any locks because this is read access only
|
||
// and additional verification will be performed inside of the
|
||
// routine under the lock).
|
||
// If not, attempt to get it from provider
|
||
// (this can happen if when the socket was created, transport
|
||
// was not loaded yet)
|
||
//
|
||
if (!endpoint->TransportInfo->InfoValid) {
|
||
status = AfdGetTransportInfo (
|
||
&endpoint->TransportInfo->TransportDeviceName,
|
||
&endpoint->TransportInfo);
|
||
if (!NT_SUCCESS (status)) {
|
||
goto complete_state_change;
|
||
}
|
||
//
|
||
// Must be valid because we got success.
|
||
//
|
||
ASSERT (endpoint->TransportInfo->InfoValid);
|
||
}
|
||
|
||
//
|
||
// Cache service flags for quick determination of provider characteristics
|
||
// such as bufferring and messaging
|
||
//
|
||
endpoint->TdiServiceFlags = endpoint->TransportInfo->ProviderInfo.ServiceFlags;
|
||
|
||
|
||
//
|
||
// Attempt to take ownership of the address.
|
||
// We have to do this before we start looking for a conflict
|
||
// so if someone does it in parallel with us, will see him or
|
||
// he sees us.
|
||
//
|
||
ASSERT (endpoint->LocalAddress==NULL);
|
||
endpoint->LocalAddress = localAddress;
|
||
endpoint->LocalAddressLength = tdiAddressLength;
|
||
|
||
|
||
|
||
//
|
||
// There are three possibilities here.
|
||
//
|
||
switch (afdShareAccess) {
|
||
case AFD_NORMALADDRUSE:
|
||
//
|
||
// This is the default. Application did not request to reuse
|
||
// the address that is already owned by someone else, so we
|
||
// have to check against all addresses that we know about.
|
||
// There is still a possibility that another TDI client has
|
||
// this address in exclusive use, so the transport can reject
|
||
// our request even if we succeed. Note that we cannot relegate
|
||
// this check to the transport because we request shared access
|
||
// to the transport address: we cannot request exclusive access
|
||
// because this is not what application asked for.
|
||
//
|
||
|
||
if (AfdIsAddressInUse (endpoint, FALSE)) {
|
||
status = STATUS_SHARING_VIOLATION;
|
||
goto complete_state_change;
|
||
}
|
||
shareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||
break;
|
||
case AFD_REUSEADDRESS:
|
||
//
|
||
// We are asked to reuse the existing address
|
||
//
|
||
// Check if we are configured to prevent sharing addresses
|
||
// between applications by default.
|
||
//
|
||
if (AfdDontShareAddresses) {
|
||
if (AfdIsAddressInUse (endpoint, TRUE)) {
|
||
status = STATUS_ACCESS_DENIED;
|
||
goto complete_state_change;
|
||
}
|
||
}
|
||
//
|
||
// Lack of break is intentional.
|
||
//
|
||
case AFD_WILDCARDADDRESS:
|
||
//
|
||
// Application is binding to a wildcard port, so we leave the
|
||
// decision with the transport.
|
||
//
|
||
|
||
shareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||
break;
|
||
case AFD_EXCLUSIVEADDRUSE:
|
||
//
|
||
// Application has requested exclisuve access to the address.
|
||
// We let the transport to decide, but perform a security check
|
||
// so that only admin can take an address for exclusive use.
|
||
// The transport can check for this but not all of them are
|
||
// aware of this new feature.
|
||
//
|
||
|
||
if (!endpoint->AdminAccessGranted) {
|
||
status = STATUS_ACCESS_DENIED;
|
||
goto complete_state_change;
|
||
}
|
||
shareAccess = 0;
|
||
break;
|
||
default:
|
||
ASSERT (!"Invalid share access");
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete_state_change;
|
||
}
|
||
|
||
//
|
||
// Set create options.
|
||
//
|
||
|
||
options = IO_NO_PARAMETER_CHECKING;
|
||
if (IS_TDI_FORCE_ACCESS_CHECK(endpoint)) {
|
||
options |= IO_FORCE_ACCESS_CHECK;
|
||
}
|
||
else {
|
||
//
|
||
// If this is an open of a raw address, fail if user is
|
||
// not an admin and transport does not perform security
|
||
// checking itself.
|
||
//
|
||
if ( endpoint->afdRaw && !AfdDisableRawSecurity) {
|
||
|
||
if (!endpoint->AdminAccessGranted) {
|
||
status = STATUS_ACCESS_DENIED;
|
||
goto complete_state_change;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate memory to hold the EA buffer we'll use to specify the
|
||
// transport address to NtCreateFile.
|
||
//
|
||
|
||
eaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
tdiAddressLength;
|
||
|
||
if (eaLength<=sizeof (eaBuffer)) {
|
||
eaInfo = (PVOID)eaBuffer;
|
||
}
|
||
else {
|
||
try {
|
||
#if DBG
|
||
eaInfo = AFD_ALLOCATE_POOL_WITH_QUOTA(
|
||
NonPagedPool,
|
||
eaLength,
|
||
AFD_EA_POOL_TAG
|
||
);
|
||
#else
|
||
eaInfo = AFD_ALLOCATE_POOL_WITH_QUOTA(
|
||
PagedPool,
|
||
eaLength,
|
||
AFD_EA_POOL_TAG
|
||
);
|
||
#endif
|
||
// AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE flag
|
||
ASSERT ( eaInfo != NULL );
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
status = GetExceptionCode ();
|
||
goto complete_state_change;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the EA.
|
||
//
|
||
|
||
eaInfo->NextEntryOffset = 0;
|
||
eaInfo->Flags = 0;
|
||
eaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
eaInfo->EaValueLength = (USHORT)tdiAddressLength;
|
||
|
||
RtlMoveMemory(
|
||
eaInfo->EaName,
|
||
TdiTransportAddress,
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1
|
||
);
|
||
|
||
RtlMoveMemory(
|
||
&eaInfo->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1],
|
||
localAddress,
|
||
tdiAddressLength
|
||
);
|
||
|
||
//
|
||
// Prepare for opening the address object.
|
||
// We ask to create a kernel handle which is
|
||
// the handle in the context of the system process
|
||
// so that application cannot close it on us while
|
||
// we are creating and referencing it.
|
||
//
|
||
|
||
InitializeObjectAttributes(
|
||
&objectAttributes,
|
||
&endpoint->TransportInfo->TransportDeviceName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
ASSERT (endpoint->AddressHandle==NULL);
|
||
status = IoCreateFile(
|
||
&endpoint->AddressHandle,
|
||
MAXIMUM_ALLOWED,
|
||
&objectAttributes,
|
||
&iosb, // returned status information.
|
||
0, // block size (unused).
|
||
0, // file attributes.
|
||
shareAccess, // share access
|
||
FILE_CREATE, // create disposition.
|
||
0, // create options.
|
||
eaInfo, // EaBuffer
|
||
eaLength, // EaLength
|
||
CreateFileTypeNone, // CreateFileType
|
||
NULL, // ExtraCreateParameters
|
||
options
|
||
);
|
||
|
||
if (eaInfo!=(PVOID)eaBuffer) {
|
||
AFD_FREE_POOL (eaInfo, AFD_EA_POOL_TAG);
|
||
}
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
//
|
||
// Map error code if application requested address
|
||
// reuse, but the transport denied it (due to
|
||
// other client having this address for exclusive use).
|
||
//
|
||
if (((status==STATUS_SHARING_VIOLATION) ||
|
||
(status==STATUS_ADDRESS_ALREADY_EXISTS))
|
||
&&
|
||
(afdShareAccess==AFD_REUSEADDRESS)) {
|
||
status = STATUS_ACCESS_DENIED;
|
||
}
|
||
goto complete_state_change;
|
||
}
|
||
#if DBG
|
||
{
|
||
NTSTATUS status1;
|
||
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
|
||
handleInfo.Inherit = FALSE;
|
||
handleInfo.ProtectFromClose = TRUE;
|
||
status1 = ZwSetInformationObject (
|
||
endpoint->AddressHandle,
|
||
ObjectHandleFlagInformation,
|
||
&handleInfo,
|
||
sizeof (handleInfo)
|
||
);
|
||
ASSERT (NT_SUCCESS (status1));
|
||
}
|
||
#endif
|
||
|
||
AfdRecordAddrOpened();
|
||
|
||
//
|
||
// Get a pointer to the file object of the address.
|
||
//
|
||
|
||
status = ObReferenceObjectByHandle(
|
||
endpoint->AddressHandle,
|
||
0L, // DesiredAccess
|
||
NULL,
|
||
KernelMode,
|
||
(PVOID *)&endpoint->AddressFileObject,
|
||
NULL
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
goto complete_state_change;
|
||
}
|
||
AfdRecordAddrRef();
|
||
|
||
|
||
//
|
||
// Now open the handle for our caller.
|
||
// If transport does not support new TDI_SERVICE_FORCE_ACCESS_CHECK_FLAG
|
||
// we get the maximum possible access for the handle so that helper
|
||
// DLL can do what it wants with it. Of course this compromises the
|
||
// security, but we can't enforce it without the transport cooperation.
|
||
//
|
||
status = ObOpenObjectByPointer(
|
||
endpoint->AddressFileObject,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
MAXIMUM_ALLOWED,
|
||
*IoFileObjectType,
|
||
(KPROCESSOR_MODE)((endpoint->TdiServiceFlags&TDI_SERVICE_FORCE_ACCESS_CHECK)
|
||
? Irp->RequestorMode
|
||
: KernelMode),
|
||
&addressHandle
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
goto complete_state_change;
|
||
}
|
||
//
|
||
// Remember the device object to which we need to give requests for
|
||
// this address object. We can't just use the
|
||
// fileObject->DeviceObject pointer because there may be a device
|
||
// attached to the transport protocol.
|
||
//
|
||
|
||
endpoint->AddressDeviceObject =
|
||
IoGetRelatedDeviceObject( endpoint->AddressFileObject );
|
||
|
||
//
|
||
// Set up indication handlers on the address object. Only set up
|
||
// appropriate event handlers--don't set unnecessary event handlers.
|
||
//
|
||
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_ERROR,
|
||
AfdErrorEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_ERROR: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
|
||
if ( IS_DGRAM_ENDPOINT(endpoint) ) {
|
||
|
||
endpoint->EventsActive = AFD_POLL_SEND;
|
||
|
||
IF_DEBUG(EVENT_SELECT) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
||
"AfdBind: Endp %08lX, Active %08lX\n",
|
||
endpoint,
|
||
endpoint->EventsActive
|
||
));
|
||
}
|
||
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_RECEIVE_DATAGRAM,
|
||
AfdReceiveDatagramEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_RECEIVE_DATAGRAM: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_ERROR_EX,
|
||
AfdErrorExEventHandler,
|
||
endpoint
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status)) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_ERROR_EX: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
//
|
||
// Remember that the endpoint has been bound to a transport address.
|
||
// (this is the fact even though the call below can fail for some reason)
|
||
|
||
endpoint->State = AfdEndpointStateBound;
|
||
} else {
|
||
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_DISCONNECT,
|
||
AfdDisconnectEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_DISCONNECT: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
|
||
if ( IS_TDI_BUFFERRING(endpoint) ) {
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_RECEIVE,
|
||
AfdReceiveEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_RECEIVE: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
//
|
||
// PROBLEM: Why don't we check for this
|
||
// if (IS_TDI_EXPEDITED (endpoint)) {
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_RECEIVE_EXPEDITED,
|
||
AfdReceiveExpeditedEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
DbgPrint( "AfdBind: Transport %*ls failed setting TDI_EVENT_RECEIVE_EXPEDITED: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status );
|
||
}
|
||
#endif
|
||
// }
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_SEND_POSSIBLE,
|
||
AfdSendPossibleEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_SEND_POSSIBLE: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
} else {
|
||
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_RECEIVE,
|
||
AfdBReceiveEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_RECEIVE: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
if (IS_TDI_EXPEDITED (endpoint)) {
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_RECEIVE_EXPEDITED,
|
||
AfdBReceiveExpeditedEventHandler,
|
||
endpoint
|
||
);
|
||
#if DBG
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_RECEIVE_EXPEDITED: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
#endif
|
||
}
|
||
if (!AfdDisableChainedReceive) {
|
||
status = AfdSetEventHandler(
|
||
endpoint->AddressFileObject,
|
||
TDI_EVENT_CHAINED_RECEIVE,
|
||
AfdBChainedReceiveEventHandler,
|
||
endpoint
|
||
);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
|
||
"AfdBind: Transport %*ls failed setting TDI_EVENT_CHAINED_RECEIVE: %lx\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
status ));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (IS_CROOT_ENDPOINT(endpoint)) {
|
||
PAFD_CONNECTION connection;
|
||
//
|
||
// Create root connection
|
||
// This one will be used to send data to all
|
||
// leaf nodes (what if there are none -> the transport
|
||
// should handle this.
|
||
//
|
||
status = AfdCreateConnection(
|
||
&endpoint->TransportInfo->TransportDeviceName,
|
||
endpoint->AddressHandle,
|
||
IS_TDI_BUFFERRING(endpoint),
|
||
endpoint->InLine,
|
||
endpoint->OwningProcess,
|
||
&connection
|
||
);
|
||
if (!NT_SUCCESS (status)) {
|
||
goto complete_state_change;
|
||
}
|
||
//
|
||
// Set up a referenced pointer from the connection to the endpoint.
|
||
// Note that we set up the connection's pointer to the endpoint
|
||
// BEFORE the endpoint's pointer to the connection so that AfdPoll
|
||
// doesn't try to back reference the endpoint from the connection.
|
||
//
|
||
|
||
REFERENCE_ENDPOINT( endpoint );
|
||
connection->Endpoint = endpoint;
|
||
|
||
//
|
||
// Remember that this is now a connecting type of endpoint, and set
|
||
// up a pointer to the connection in the endpoint. This is
|
||
// implicitly a referenced pointer.
|
||
//
|
||
|
||
endpoint->Common.VirtualCircuit.Connection = connection;
|
||
endpoint->Type = AfdBlockTypeVcConnecting;
|
||
|
||
//
|
||
// The root connection is marked as connected immediately upon
|
||
// creation. See the comment above
|
||
//
|
||
|
||
AfdAddConnectedReference (connection);
|
||
endpoint->State = AfdEndpointStateConnected;
|
||
connection->State = AfdConnectionStateConnected;
|
||
|
||
ASSERT( IS_TDI_BUFFERRING(endpoint) == connection->TdiBufferring );
|
||
}
|
||
else {
|
||
//
|
||
// Remember that the endpoint has been bound to a transport address.
|
||
// (this is the fact even though the call below can fail for some reason)
|
||
|
||
endpoint->State = AfdEndpointStateBound;
|
||
}
|
||
}
|
||
|
||
AFD_END_STATE_CHANGE (endpoint);
|
||
|
||
TdiBuildQueryInformation(
|
||
Irp,
|
||
endpoint->AddressDeviceObject,
|
||
endpoint->AddressFileObject,
|
||
AfdRestartBindGetAddress,
|
||
endpoint,
|
||
TDI_QUERY_ADDRESS_INFO,
|
||
Irp->MdlAddress
|
||
);
|
||
|
||
//
|
||
// Save address handle to use in completion routine
|
||
//
|
||
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = addressHandle;
|
||
|
||
IF_DEBUG(BIND) {
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
||
"AfdBind: endpoint at %p (address at %p, address file at %p).\n",
|
||
endpoint,
|
||
endpoint->LocalAddress,
|
||
endpoint->AddressFileObject ));
|
||
}
|
||
|
||
status = AfdIoCallDriver( endpoint, endpoint->AddressDeviceObject, Irp );
|
||
return status;
|
||
|
||
complete_state_change:
|
||
|
||
if (endpoint->AddressFileObject!=NULL) {
|
||
ObDereferenceObject (endpoint->AddressFileObject);
|
||
endpoint->AddressFileObject = NULL;
|
||
ASSERT (endpoint->AddressHandle!=NULL);
|
||
}
|
||
|
||
|
||
if (endpoint->AddressHandle!=NULL) {
|
||
#if DBG
|
||
{
|
||
NTSTATUS status1;
|
||
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
|
||
handleInfo.Inherit = FALSE;
|
||
handleInfo.ProtectFromClose = FALSE;
|
||
status1 = ZwSetInformationObject (
|
||
endpoint->AddressHandle,
|
||
ObjectHandleFlagInformation,
|
||
&handleInfo,
|
||
sizeof (handleInfo)
|
||
);
|
||
ASSERT (NT_SUCCESS (status1));
|
||
}
|
||
#endif
|
||
ZwClose(endpoint->AddressHandle);
|
||
endpoint->AddressHandle = NULL;
|
||
ASSERT (localAddress!=NULL);
|
||
}
|
||
|
||
|
||
if (localAddress!=NULL) {
|
||
|
||
//
|
||
// Need to have exclusive access to make sure no one
|
||
// uses it (to compare) as we are going to free it.
|
||
// We'll use a local variable to free memory
|
||
//
|
||
|
||
//
|
||
// Make sure the thread in which we execute cannot get
|
||
// suspeneded in APC while we own the global resource.
|
||
//
|
||
KeEnterCriticalRegion ();
|
||
ExAcquireResourceExclusiveLite( AfdResource, TRUE);
|
||
|
||
endpoint->LocalAddress = NULL;
|
||
endpoint->LocalAddressLength = 0;
|
||
|
||
ExReleaseResourceLite( AfdResource );
|
||
KeLeaveCriticalRegion ();
|
||
AFD_FREE_POOL (
|
||
localAddress,
|
||
AFD_LOCAL_ADDRESS_POOL_TAG
|
||
);
|
||
}
|
||
|
||
complete_wrong_state:
|
||
|
||
AFD_END_STATE_CHANGE (endpoint);
|
||
|
||
//
|
||
// Free MDL here as IO system can't do it if it is
|
||
// not locked.
|
||
//
|
||
if (Irp->MdlAddress!=NULL) {
|
||
if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
|
||
MmUnlockPages (Irp->MdlAddress);
|
||
}
|
||
IoFreeMdl (Irp->MdlAddress);
|
||
Irp->MdlAddress = NULL;
|
||
}
|
||
|
||
complete:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, AfdPriorityBoost );
|
||
|
||
return status;
|
||
|
||
} // AfdBind
|
||
|
||
|
||
NTSTATUS
|
||
AfdRestartBindGetAddress (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PAFD_ENDPOINT endpoint = Context;
|
||
|
||
ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
|
||
|
||
//
|
||
// If the request succeeded, save the address in the endpoint so
|
||
// we can use it to handle address sharing.
|
||
//
|
||
|
||
if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
|
||
|
||
ULONG addressLength;
|
||
//
|
||
// First determine the length of the address by walking the MDL
|
||
// chain.
|
||
//
|
||
|
||
//
|
||
// We cannot have a chain here.
|
||
//
|
||
ASSERT( Irp->MdlAddress != NULL);
|
||
ASSERT( Irp->MdlAddress->Next == NULL );
|
||
|
||
//
|
||
// If the new address is longer than the original address, allocate
|
||
// a new local address buffer. The +4 accounts for the ActivityCount
|
||
// field that is returned by a query address but is not part
|
||
// of a TRANSPORT_ADDRESS.
|
||
//
|
||
// This cannot happen, in any case msafd does not retry if buffer is
|
||
// insuffucient, so application perceives this as failure to bind
|
||
// or get address.
|
||
//
|
||
|
||
addressLength = MmGetMdlByteCount (Irp->MdlAddress) - FIELD_OFFSET (TDI_ADDRESS_INFO, Address);
|
||
if (addressLength>endpoint->LocalAddressLength) {
|
||
addressLength = (ULONG)Irp->IoStatus.Information - FIELD_OFFSET (TDI_ADDRESS_INFO, Address);
|
||
}
|
||
if ( addressLength <= endpoint->LocalAddressLength) {
|
||
status = TdiCopyMdlToBuffer(
|
||
Irp->MdlAddress,
|
||
FIELD_OFFSET (TDI_ADDRESS_INFO, Address),
|
||
endpoint->LocalAddress,
|
||
0,
|
||
addressLength,
|
||
&endpoint->LocalAddressLength
|
||
);
|
||
ASSERT( NT_SUCCESS(status) );
|
||
}
|
||
else {
|
||
DbgPrint ("AfdRestartBindGetAddress: Endpoint %p transport returned"
|
||
" address is longer than the original one.\n",
|
||
endpoint);
|
||
ASSERT (FALSE);
|
||
}
|
||
|
||
}
|
||
else {
|
||
//
|
||
//
|
||
//
|
||
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
|
||
"AfdRestartBindGetAddress: Transport %*ls failed get address query, status %lx.\n",
|
||
endpoint->TransportInfo->TransportDeviceName.Length/2,
|
||
endpoint->TransportInfo->TransportDeviceName.Buffer,
|
||
Irp->IoStatus.Status));
|
||
}
|
||
|
||
|
||
//
|
||
// If pending has been returned for this irp then mark the current
|
||
// stack as pending.
|
||
//
|
||
|
||
if ( Irp->PendingReturned ) {
|
||
IoMarkIrpPending( Irp );
|
||
}
|
||
|
||
//
|
||
// Retreive and return address handle in the information field
|
||
//
|
||
Irp->IoStatus.Information =
|
||
(ULONG_PTR)IoGetCurrentIrpStackLocation (Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
|
||
|
||
AfdCompleteOutstandingIrp( endpoint, Irp );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // AfdRestartBindGetAddress
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
FASTCALL
|
||
AfdGetAddress (
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles the IOCTL_AFD_BIND IOCTL.
|
||
|
||
Arguments:
|
||
|
||
Irp - Pointer to I/O request packet.
|
||
|
||
IrpSp - pointer to the IO stack location to use for this request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS -- Indicates whether the request was successfully queued.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PAFD_ENDPOINT endpoint;
|
||
PAFD_CONNECTION connection;
|
||
PFILE_OBJECT fileObject;
|
||
PDEVICE_OBJECT deviceObject;
|
||
|
||
PAGED_CODE( );
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength<
|
||
sizeof (TDI_ADDRESS_INFO)) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
try {
|
||
if (IoAllocateMdl (Irp->UserBuffer,
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
|
||
FALSE, // SecondaryBuffer
|
||
TRUE, // ChargeQuota
|
||
Irp // Irp
|
||
)==NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto complete;
|
||
}
|
||
MmProbeAndLockPages (Irp->MdlAddress,
|
||
Irp->RequestorMode,
|
||
IoWriteAccess);
|
||
if (MmGetSystemAddressForMdlSafe (Irp->MdlAddress, HighPagePriority)==NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto complete;
|
||
}
|
||
}
|
||
except (AFD_EXCEPTION_FILTER (&status)) {
|
||
goto complete;
|
||
}
|
||
|
||
//
|
||
// Make sure that the endpoint is in the correct state.
|
||
//
|
||
|
||
endpoint = IrpSp->FileObject->FsContext;
|
||
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
||
|
||
if ( endpoint->State!=AfdEndpointStateBound &&
|
||
endpoint->State != AfdEndpointStateConnected ) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto complete;
|
||
}
|
||
|
||
//
|
||
// If the endpoint is connected, use the connection's file object.
|
||
// Otherwise, use the address file object. Don't use the connection
|
||
// file object if this is a Netbios endpoint because NETBT cannot
|
||
// support this TDI feature.
|
||
//
|
||
|
||
if ( endpoint->LocalAddress->Address[0].AddressType !=
|
||
TDI_ADDRESS_TYPE_NETBIOS &&
|
||
endpoint->Type == AfdBlockTypeVcConnecting &&
|
||
endpoint->State == AfdEndpointStateConnected &&
|
||
((connection=AfdGetConnectionReferenceFromEndpoint (endpoint)) != NULL)
|
||
) {
|
||
ASSERT( connection->Type == AfdBlockTypeConnection );
|
||
fileObject = connection->FileObject;
|
||
deviceObject = connection->DeviceObject;
|
||
DEREFERENCE_CONNECTION (connection);
|
||
} else {
|
||
fileObject = endpoint->AddressFileObject;
|
||
deviceObject = endpoint->AddressDeviceObject;
|
||
}
|
||
|
||
//
|
||
// Set up the query info to the TDI provider.
|
||
//
|
||
|
||
TdiBuildQueryInformation(
|
||
Irp,
|
||
deviceObject,
|
||
fileObject,
|
||
AfdRestartGetAddress,
|
||
endpoint,
|
||
TDI_QUERY_ADDRESS_INFO,
|
||
Irp->MdlAddress
|
||
);
|
||
|
||
//
|
||
// Call the TDI provider to get the address.
|
||
//
|
||
|
||
return AfdIoCallDriver( endpoint, deviceObject, Irp );
|
||
|
||
complete:
|
||
if (Irp->MdlAddress!=NULL) {
|
||
if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
|
||
MmUnlockPages (Irp->MdlAddress);
|
||
}
|
||
IoFreeMdl (Irp->MdlAddress);
|
||
Irp->MdlAddress = NULL;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, AfdPriorityBoost );
|
||
|
||
return status;
|
||
|
||
} // AfdGetAddress
|
||
|
||
|
||
NTSTATUS
|
||
AfdRestartGetAddress (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PAFD_ENDPOINT endpoint = Context;
|
||
|
||
//
|
||
// If the request succeeded, save the address in the endpoint so
|
||
// we can use it to handle address sharing.
|
||
//
|
||
|
||
if ( NT_SUCCESS(Irp->IoStatus.Status) ) {
|
||
|
||
ULONG addressLength;
|
||
//
|
||
// First determine the length of the address by walking the MDL
|
||
// chain.
|
||
//
|
||
|
||
//
|
||
// We cannot have a chain here.
|
||
//
|
||
ASSERT( Irp->MdlAddress != NULL);
|
||
ASSERT( Irp->MdlAddress->Next == NULL );
|
||
|
||
//
|
||
// If the new address is longer than the original address, allocate
|
||
// a new local address buffer. The +4 accounts for the ActivityCount
|
||
// field that is returned by a query address but is not part
|
||
// of a TRANSPORT_ADDRESS.
|
||
//
|
||
// This cannot happen, in any case msafd does not retry if buffer is
|
||
// insuffucient, so application perceives this as failure to bind
|
||
// or get address.
|
||
//
|
||
|
||
addressLength = MmGetMdlByteCount (Irp->MdlAddress) - FIELD_OFFSET (TDI_ADDRESS_INFO, Address);
|
||
|
||
if (addressLength>endpoint->LocalAddressLength) {
|
||
addressLength = (ULONG)Irp->IoStatus.Information - FIELD_OFFSET (TDI_ADDRESS_INFO, Address);
|
||
}
|
||
if ( addressLength <= endpoint->LocalAddressLength) {
|
||
status = TdiCopyMdlToBuffer(
|
||
Irp->MdlAddress,
|
||
FIELD_OFFSET (TDI_ADDRESS_INFO, Address),
|
||
endpoint->LocalAddress,
|
||
0,
|
||
addressLength,
|
||
&endpoint->LocalAddressLength
|
||
);
|
||
ASSERT( NT_SUCCESS(status) );
|
||
}
|
||
else {
|
||
DbgPrint ("AfdRestartGetAddress: Endpoint %p transport returned"
|
||
" address is longer than the original one.\n",
|
||
endpoint);
|
||
ASSERT (FALSE);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If pending has been returned for this irp then mark the current
|
||
// stack as pending.
|
||
//
|
||
|
||
if ( Irp->PendingReturned ) {
|
||
IoMarkIrpPending( Irp );
|
||
}
|
||
|
||
AfdCompleteOutstandingIrp( endpoint, Irp );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // AfdRestartGetAddress
|
||
|
||
const CHAR ZeroNodeAddress[6]={0};
|
||
const CHAR ZeroIP6Address[16]={0};
|
||
|
||
|
||
BOOLEAN
|
||
AfdAreTransportAddressesEqual (
|
||
IN PTRANSPORT_ADDRESS EndpointAddress,
|
||
IN ULONG EndpointAddressLength,
|
||
IN PTRANSPORT_ADDRESS RequestAddress,
|
||
IN ULONG RequestAddressLength,
|
||
IN BOOLEAN HonorWildcardIpPortInEndpointAddress
|
||
)
|
||
{
|
||
//
|
||
// Make sure we can safely access the address type and length fields
|
||
//
|
||
if ((EndpointAddressLength<(ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS,Address[0].Address))
|
||
|| (RequestAddressLength<(ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS,Address[0].Address)) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
if ( EndpointAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP &&
|
||
RequestAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP ) {
|
||
|
||
TDI_ADDRESS_IP UNALIGNED *ipEndpointAddress;
|
||
TDI_ADDRESS_IP UNALIGNED *ipRequestAddress;
|
||
|
||
//
|
||
// They are both IP addresses. If the ports are the same, and
|
||
// the IP addresses are or _could_be_ the same, then the addresses
|
||
// are equal. The "cound be" part is true if either IP address
|
||
// is 0, the "wildcard" IP address.
|
||
//
|
||
|
||
ipEndpointAddress = (TDI_ADDRESS_IP UNALIGNED *)&EndpointAddress->Address[0].Address[0];
|
||
ipRequestAddress = (TDI_ADDRESS_IP UNALIGNED *)&RequestAddress->Address[0].Address[0];
|
||
|
||
if ( (EndpointAddressLength>=(ULONG)FIELD_OFFSET (TA_IP_ADDRESS, Address[0].Address[0].sin_zero)) &&
|
||
(RequestAddressLength>=(ULONG)FIELD_OFFSET (TA_IP_ADDRESS, Address[0].Address[0].sin_zero)) &&
|
||
( ipEndpointAddress->sin_port == ipRequestAddress->sin_port ||
|
||
( HonorWildcardIpPortInEndpointAddress &&
|
||
ipEndpointAddress->sin_port == 0 ) ) &&
|
||
( ipEndpointAddress->in_addr == ipRequestAddress->in_addr ||
|
||
ipEndpointAddress->in_addr == 0 || ipRequestAddress->in_addr == 0 ) ) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// The addresses are not equal.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
if ( EndpointAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP6 &&
|
||
RequestAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP6 ) {
|
||
|
||
TDI_ADDRESS_IP6 UNALIGNED *ipEndpointAddress;
|
||
TDI_ADDRESS_IP6 UNALIGNED *ipRequestAddress;
|
||
C_ASSERT (sizeof (ZeroIP6Address)==sizeof (ipEndpointAddress->sin6_addr));
|
||
|
||
//
|
||
// They are both IPv6 addresses. If the ports are the same, and
|
||
// the IPv6 addresses are or _could_be_ the same, then the addresses
|
||
// are equal. The "could be" part is true if either IPv6 address
|
||
// is the unspecified IPv6 address.
|
||
//
|
||
|
||
ipEndpointAddress = (TDI_ADDRESS_IP6 UNALIGNED *)&EndpointAddress->Address[0].Address;
|
||
ipRequestAddress = (TDI_ADDRESS_IP6 UNALIGNED *)&RequestAddress->Address[0].Address;
|
||
|
||
if ( (EndpointAddressLength>=sizeof (TA_IP6_ADDRESS)) &&
|
||
(RequestAddressLength>=sizeof (TA_IP6_ADDRESS)) &&
|
||
|
||
(ipEndpointAddress->sin6_port == ipRequestAddress->sin6_port ||
|
||
( HonorWildcardIpPortInEndpointAddress &&
|
||
ipEndpointAddress->sin6_port == 0 ) ) &&
|
||
|
||
( RtlEqualMemory(&ipEndpointAddress->sin6_addr,
|
||
&ipRequestAddress->sin6_addr,
|
||
sizeof (ipEndpointAddress->sin6_addr)) ||
|
||
RtlEqualMemory(&ipEndpointAddress->sin6_addr,
|
||
ZeroIP6Address,
|
||
sizeof (ipEndpointAddress->sin6_addr)) ||
|
||
RtlEqualMemory(&ipRequestAddress->sin6_addr,
|
||
ZeroIP6Address,
|
||
sizeof (ipEndpointAddress->sin6_addr)) ) ) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// The addresses are not equal.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
if ( EndpointAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IPX &&
|
||
RequestAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IPX ) {
|
||
|
||
TDI_ADDRESS_IPX UNALIGNED *ipxEndpointAddress;
|
||
TDI_ADDRESS_IPX UNALIGNED *ipxRequestAddress;
|
||
C_ASSERT (sizeof (ZeroNodeAddress)==sizeof (ipxEndpointAddress->NodeAddress));
|
||
|
||
ipxEndpointAddress = (TDI_ADDRESS_IPX UNALIGNED *)&EndpointAddress->Address[0].Address[0];
|
||
ipxRequestAddress = (TDI_ADDRESS_IPX UNALIGNED *)&RequestAddress->Address[0].Address[0];
|
||
|
||
//
|
||
// They are both IPX addresses. Check the network addresses
|
||
// first--if they don't match and both != 0, the addresses
|
||
// are different.
|
||
//
|
||
|
||
if ( (EndpointAddressLength<sizeof (TA_IPX_ADDRESS)) ||
|
||
(RequestAddressLength<sizeof (TA_IPX_ADDRESS)) ||
|
||
( ipxEndpointAddress->NetworkAddress != ipxRequestAddress->NetworkAddress &&
|
||
ipxEndpointAddress->NetworkAddress != 0 &&
|
||
ipxRequestAddress->NetworkAddress != 0 )) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Now check the node addresses. Again, if they don't match
|
||
// and neither is 0, the addresses don't match.
|
||
//
|
||
|
||
ASSERT( ZeroNodeAddress[0] == 0 );
|
||
ASSERT( ZeroNodeAddress[1] == 0 );
|
||
ASSERT( ZeroNodeAddress[2] == 0 );
|
||
ASSERT( ZeroNodeAddress[3] == 0 );
|
||
ASSERT( ZeroNodeAddress[4] == 0 );
|
||
ASSERT( ZeroNodeAddress[5] == 0 );
|
||
|
||
if ( !RtlEqualMemory(
|
||
ipxEndpointAddress->NodeAddress,
|
||
ipxRequestAddress->NodeAddress,
|
||
6 ) &&
|
||
!RtlEqualMemory(
|
||
ipxEndpointAddress->NodeAddress,
|
||
ZeroNodeAddress,
|
||
6 ) &&
|
||
!RtlEqualMemory(
|
||
ipxRequestAddress->NodeAddress,
|
||
ZeroNodeAddress,
|
||
6 ) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Finally, make sure the socket numbers match.
|
||
//
|
||
|
||
if ( ipxEndpointAddress->Socket != ipxRequestAddress->Socket ) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// If either address is not of a known address type, then do a
|
||
// simple memory compare. (Don't go out of bounds on either
|
||
// structure).
|
||
//
|
||
if (RequestAddressLength>EndpointAddressLength)
|
||
RequestAddressLength = EndpointAddressLength;
|
||
|
||
return (EndpointAddressLength == RtlCompareMemory(
|
||
EndpointAddress,
|
||
RequestAddress,
|
||
RequestAddressLength ) );
|
||
} // AfdAreTransportAddressesEqual
|
||
|
||
|
||
|
||
BOOLEAN
|
||
AfdIsAddressInUse (
|
||
PAFD_ENDPOINT Endpoint,
|
||
BOOLEAN OtherProcessesOnly
|
||
)
|
||
{
|
||
PLIST_ENTRY listEntry;
|
||
BOOLEAN res = FALSE;
|
||
|
||
PAGED_CODE ();
|
||
|
||
//
|
||
// We use shared access to the resource because we only need to make
|
||
// sure that endpoint list is not modified while we are accessing it
|
||
// and existing local addresses are not removed (both of these
|
||
// operations are performed under exclusive access).
|
||
//
|
||
//
|
||
// Make sure the thread in which we execute cannot get
|
||
// suspeneded in APC while we own the global resource.
|
||
//
|
||
KeEnterCriticalRegion ();
|
||
ExAcquireResourceSharedLite( AfdResource, TRUE );
|
||
|
||
//
|
||
// Walk the global list of endpoints,
|
||
// and compare this address againat the address on each endpoint.
|
||
//
|
||
|
||
for ( listEntry = AfdEndpointListHead.Flink;
|
||
listEntry != &AfdEndpointListHead;
|
||
listEntry = listEntry->Flink ) {
|
||
|
||
PAFD_ENDPOINT compareEndpoint;
|
||
|
||
compareEndpoint = CONTAINING_RECORD(
|
||
listEntry,
|
||
AFD_ENDPOINT,
|
||
GlobalEndpointListEntry
|
||
);
|
||
|
||
ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) );
|
||
|
||
//
|
||
// Check whether the endpoint has a local address, whether
|
||
// the endpoint has been disconnected, whether the
|
||
// endpoint is in the process of closing, and whether
|
||
// it represents accepted connection. If any of these
|
||
// is true, don't compare addresses with this endpoint.
|
||
//
|
||
|
||
if (compareEndpoint!=Endpoint &&
|
||
compareEndpoint->LocalAddress != NULL &&
|
||
( (compareEndpoint->DisconnectMode &
|
||
(AFD_PARTIAL_DISCONNECT_SEND |
|
||
AFD_ABORTIVE_DISCONNECT) ) == 0 ) &&
|
||
(compareEndpoint->State != AfdEndpointStateClosing) &&
|
||
((compareEndpoint->State != AfdEndpointStateConnected)
|
||
|| (compareEndpoint->Type!=AfdBlockTypeVcConnecting)
|
||
|| (compareEndpoint->Common.VcConnecting.ListenEndpoint==NULL)) &&
|
||
(!OtherProcessesOnly ||
|
||
compareEndpoint->OwningProcess!=Endpoint->OwningProcess)
|
||
) {
|
||
|
||
//
|
||
// Compare the bits in the endpoint's address and the
|
||
// address we're attempting to bind to. Note that we
|
||
// also compare the transport device names on the
|
||
// endpoints, as it is legal to bind to the same address
|
||
// on different transports (e.g. bind to same port in
|
||
// TCP and UDP). We can just compare the transport
|
||
// device name pointers because unique names are stored
|
||
// globally.
|
||
//
|
||
|
||
if ( compareEndpoint->LocalAddressLength == Endpoint->LocalAddressLength &&
|
||
|
||
AfdAreTransportAddressesEqual(
|
||
compareEndpoint->LocalAddress,
|
||
compareEndpoint->LocalAddressLength,
|
||
Endpoint->LocalAddress,
|
||
Endpoint->LocalAddressLength,
|
||
FALSE
|
||
)
|
||
|
||
&&
|
||
|
||
Endpoint->TransportInfo ==
|
||
compareEndpoint->TransportInfo ) {
|
||
|
||
//
|
||
// The addresses are equal.
|
||
//
|
||
res = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
ExReleaseResourceLite( AfdResource );
|
||
KeLeaveCriticalRegion ();
|
||
return res;
|
||
}
|