|
|
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
pnp.c
Abstract:
This module contains the PnP and PM routines
Author:
Vadim Eydelman (vadime) Apr-1997
Revision History:
--*/
#include "afdp.h"
NTSTATUS AfdPassQueryDeviceRelation ( IN PFILE_OBJECT FileObject, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp );
NTSTATUS AfdRestartQueryDeviceRelation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfdPnpPower )
#pragma alloc_text( PAGE, AfdPassQueryDeviceRelation )
#pragma alloc_text( PAGEAFD, AfdRestartQueryDeviceRelation )
#endif
NTSTATUS FASTCALL AfdPnpPower ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
This is the dispatch routine for PNP_POWER irp
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PAGED_CODE( );
switch (IrpSp->MinorFunction) {
//
// We only support target device relation query
//
case IRP_MN_QUERY_DEVICE_RELATIONS: if (IrpSp->Parameters.QueryDeviceRelations.Type==TargetDeviceRelation) {
NTSTATUS status; PAFD_ENDPOINT endpoint; PAFD_CONNECTION connection; //
// Set up local variables.
//
endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) ); //
// Dispatch to correct TDI object of underlying transport
// driver depedning on endpoint type
//
switch (endpoint->Type) { case AfdBlockTypeVcConnecting: case AfdBlockTypeVcBoth: connection = AfdGetConnectionReferenceFromEndpoint (endpoint); if (connection!=NULL) { status = AfdPassQueryDeviceRelation (connection->FileObject, Irp, IrpSp); DEREFERENCE_CONNECTION (connection); return status; } // fall through to try address handle if we have one.
case AfdBlockTypeVcListening: case AfdBlockTypeDatagram: if (endpoint->State==AfdEndpointStateBound || endpoint->State==AfdEndpointStateConnected) { return AfdPassQueryDeviceRelation (endpoint->AddressFileObject, Irp, IrpSp); } // fall through to fail
case AfdBlockTypeHelper: case AfdBlockTypeEndpoint: case AfdBlockTypeSanHelper: case AfdBlockTypeSanEndpoint: break; default: ASSERT (!"Unknown endpoint type!"); break; } } default: break; } Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest( Irp, AfdPriorityBoost );
//
// We do not support the rest
//
return STATUS_INVALID_DEVICE_REQUEST; }
NTSTATUS AfdPassQueryDeviceRelation ( IN PFILE_OBJECT FileObject, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
This is the dispatch routine for PNP_POWER irp
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{ PIO_STACK_LOCATION nextIrpSp;
PAGED_CODE ();
nextIrpSp = IoGetNextIrpStackLocation( Irp );
*nextIrpSp = *IrpSp;
//
// Reference file object so it does not go away until this
// IRP completes
//
ObReferenceObject (FileObject); nextIrpSp->FileObject = FileObject;
IoSetCompletionRoutine( Irp, AfdRestartQueryDeviceRelation, FileObject, TRUE, TRUE, TRUE );
#ifdef _AFD_VARIABLE_STACK_
return AfdCallDriverStackIncrease ( IoGetRelatedDeviceObject( FileObject ), Irp ); #else // _AFD_VARIABLE_STACK_
return IoCallDriver ( IoGetRelatedDeviceObject( FileObject ), Irp ); #endif
}
NTSTATUS AfdRestartQueryDeviceRelation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PFILE_OBJECT fileObject = Context;
UNREFERENCED_PARAMETER (DeviceObject); UNREFERENCED_PARAMETER (Irp); //
// Dereference file object that we referenced when calling the
// lower driver
//
ObDereferenceObject (fileObject);
//
// Tell IO system to continue with IRP completion
//
return STATUS_SUCCESS; }
#include <tdiinfo.h>
#include <ntddip.h>
#include <ntddip6.h>
#include <ntddtcp.h>
#include <ipinfo.h>
typedef struct _AFD_PROTOCOL { USHORT AddressType; USHORT AddressLength; LPWSTR NetworkLayerDeviceName; LPWSTR TransportLayerDeviceName; ULONG RtChangeIoctl; ULONG RtChangeDataSize; LONG RoutingQueryRefCount; HANDLE DeviceHandle; PFILE_OBJECT FileObject; } AFD_PROTOCOL, *PAFD_PROTOCOL;
PAFD_PROTOCOL AfdGetProtocolInfo( IN USHORT AddressType );
NTSTATUS AfdOpenDevice ( LPWSTR DeviceNameStr, HANDLE *Handle, PFILE_OBJECT *FileObject );
NTSTATUS AfdGetRoutingQueryReference ( IN PAFD_PROTOCOL Protocol );
VOID AfdDereferenceRoutingQuery ( PAFD_PROTOCOL Protocol );
NTSTATUS AfdTcpQueueRoutingChangeRequest ( IN PAFD_ENDPOINT Endpoint, IN PIRP Irp, IN BOOLEAN Overlapped );
NTSTATUS AfdTcpRestartRoutingChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
NTSTATUS AfdTcpSignalRoutingChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
NTSTATUS AfdTcpRoutingQuery ( PTA_ADDRESS Dest, PTA_ADDRESS Intf );
NTSTATUS AfdTcp6RoutingQuery ( PTA_ADDRESS Dest, PTA_ADDRESS Intf );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfdOpenDevice )
#pragma alloc_text( PAGE, AfdRoutingInterfaceQuery )
#pragma alloc_text( PAGE, AfdTcpRoutingQuery )
#pragma alloc_text( PAGE, AfdTcp6RoutingQuery )
#pragma alloc_text( PAGE, AfdGetRoutingQueryReference )
#pragma alloc_text( PAGE, AfdDereferenceRoutingQuery )
#pragma alloc_text( PAGE, AfdGetProtocolInfo )
#pragma alloc_text( PAGEAFD, AfdTcpQueueRoutingChangeRequest )
#pragma alloc_text( PAGEAFD, AfdTcpRestartRoutingChange )
#pragma alloc_text( PAGEAFD, AfdTcpSignalRoutingChange )
#pragma alloc_text( PAGEAFD, AfdCleanupRoutingChange )
#endif
AFD_PROTOCOL Ip = { TDI_ADDRESS_TYPE_IP, TDI_ADDRESS_LENGTH_IP, DD_IP_DEVICE_NAME, DD_TCP_DEVICE_NAME, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST, sizeof(IPNotifyData), 0, NULL, NULL }; AFD_PROTOCOL Ip6= { TDI_ADDRESS_TYPE_IP6, TDI_ADDRESS_LENGTH_IP6, DD_IPV6_DEVICE_NAME, DD_TCPV6_DEVICE_NAME, IOCTL_IPV6_RTCHANGE_NOTIFY_REQUEST, sizeof(IPV6_RTCHANGE_NOTIFY_REQUEST), 0, NULL, NULL };
const char ZeroString[16] = { 0 };
PAFD_PROTOCOL AfdGetProtocolInfo( IN USHORT AddressType ) { switch (AddressType) { case TDI_ADDRESS_TYPE_IP: return &Ip; case TDI_ADDRESS_TYPE_IP6: return &Ip6; default: return NULL; } }
NTSTATUS AfdRoutingInterfaceQuery ( IN PFILE_OBJECT FileObject, IN ULONG IoctlCode, IN KPROCESSOR_MODE RequestorMode, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG_PTR Information ) /*++
Routine Description:
Processes routing query request. Protocol independent portion.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/ { CHAR addrBuffer[AFD_MAX_FAST_TRANSPORT_ADDRESS]; PTRANSPORT_ADDRESS tempAddr; NTSTATUS status;
UNREFERENCED_PARAMETER (IoctlCode); #if !DBG
UNREFERENCED_PARAMETER (FileObject); #endif
PAGED_CODE ();
//
// Initialize locals for proper cleanup.
//
*Information = 0; tempAddr = (PTRANSPORT_ADDRESS)addrBuffer;
//
// Validate input parameters
//
if( InputBufferLength < sizeof(*tempAddr) ) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdRoutingInterfaceQuery: Endp: %p - invalid input buffer (%p-%d).\n", FileObject->FsContext, InputBuffer, InputBufferLength)); status = STATUS_INVALID_PARAMETER; goto Complete; }
try { //
// Copy input address into the local (or allocated from pool) buffer
//
if (InputBufferLength>sizeof (addrBuffer)) { tempAddr = AFD_ALLOCATE_POOL_WITH_QUOTA (PagedPool, InputBufferLength, AFD_ROUTING_QUERY_POOL_TAG); // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE
}
//
// Validate user mode pointers
//
if (RequestorMode!=KernelMode) { ProbeForRead (InputBuffer, InputBufferLength, sizeof (CHAR)); } RtlCopyMemory (tempAddr, InputBuffer, InputBufferLength);
//
// Validate the internal consistency of the transport address AFTER
// copying it into the internal buffer to prevent malicious app from
// changing it on the fly while we are checking.
//
if (tempAddr->TAAddressCount!=1 || InputBufferLength < (ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[tempAddr->Address[0].AddressLength])) { ExRaiseStatus (STATUS_INVALID_PARAMETER); } } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode (); goto Complete; }
//
// PROBLEM. We only support IP for now
//
switch (tempAddr->Address[0].AddressType) { case TDI_ADDRESS_TYPE_IP: status = AfdTcpRoutingQuery (&tempAddr->Address[0], &tempAddr->Address[0]); break; case TDI_ADDRESS_TYPE_IP6: status = AfdTcp6RoutingQuery (&tempAddr->Address[0], &tempAddr->Address[0]); break; default: status = STATUS_NOT_SUPPORTED; goto Complete; }
//
// Convert output to socket address if we succeeded.
//
if (NT_SUCCESS (status)) { //
// Conversion to sockaddr requires extra bytes for address family
// in addition to TDI_ADDRESS
//
if ((tempAddr->Address[0].AddressLength+sizeof(u_short) <= OutputBufferLength)) { try { //
// Validate user mode pointers
//
if (RequestorMode!=KernelMode) { ProbeForWrite (OutputBuffer, OutputBufferLength, sizeof (CHAR)); } //
// Copy the data from the type on which corresponds
// to the socket address.
//
RtlCopyMemory ( OutputBuffer, &tempAddr->Address[0].AddressType, tempAddr->Address[0].AddressLength+sizeof(u_short)); } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode (); goto Complete; } } else { //
// Output buffer is not big enough, return warning
// and the required buffer size.
//
status = STATUS_BUFFER_OVERFLOW; } *Information = tempAddr->Address[0].AddressLength+sizeof(u_short); }
Complete:
//
// Free address buffer if we allocated one.
//
if (tempAddr!=(PTRANSPORT_ADDRESS)addrBuffer) { AFD_FREE_POOL (tempAddr, AFD_ROUTING_QUERY_POOL_TAG); }
return status; } //AfdRoutingInterfaceQuery
NTSTATUS FASTCALL AfdRoutingInterfaceChange ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++
Routine Description:
Processes routing change IRP
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/ { PTRANSPORT_ADDRESS destAddr; NTSTATUS status; PAFD_ENDPOINT endpoint; BOOLEAN overlapped; AFD_TRANSPORT_IOCTL_INFO ioctlInfo;
PAGED_CODE ();
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdRoutingInterfaceChange: Endp: %p, buf: %p, inlen: %ld, outlen: %ld.\n", IrpSp->FileObject->FsContext, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength)); }
#ifdef _WIN64
if (IoIs32bitProcess (Irp)) { PAFD_TRANSPORT_IOCTL_INFO32 ioctlInfo32; ioctlInfo32 = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (*ioctlInfo32)) { status = STATUS_INVALID_PARAMETER; goto complete; } ioctlInfo.Handle = ioctlInfo32->Handle; ioctlInfo.InputBuffer = UlongToPtr(ioctlInfo32->InputBuffer); ioctlInfo.InputBufferLength = ioctlInfo32->InputBufferLength; ioctlInfo.IoControlCode = ioctlInfo32->IoControlCode; ioctlInfo.AfdFlags = ioctlInfo32->AfdFlags; ioctlInfo.PollEvent = ioctlInfo32->PollEvent; } else #endif // _WIN64
{ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (ioctlInfo)) { status = STATUS_INVALID_PARAMETER; goto complete; } ioctlInfo = *((PAFD_TRANSPORT_IOCTL_INFO)Irp->AssociatedIrp.SystemBuffer); } //
// Setup locals
//
endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) ); //
// Check if request is overlapped
//
overlapped = (BOOLEAN)((ioctlInfo.AfdFlags & AFD_OVERLAPPED)!=0);
//
// Validate input parameters
//
AFD_W4_INIT status = STATUS_SUCCESS; try { ULONG sysBufferLength; sysBufferLength = max ( IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
if (Irp->RequestorMode != KernelMode) { ProbeForRead( ioctlInfo.InputBuffer, ioctlInfo.InputBufferLength, sizeof(UCHAR) ); }
if (ioctlInfo.InputBufferLength>sysBufferLength){ PVOID newSystemBuffer; //
// Don't use AFD allocation routine on this as we are substituting
// system buffer
//
newSystemBuffer = ExAllocatePoolWithQuotaTag ( NonPagedPool|POOL_RAISE_IF_ALLOCATION_FAILURE, ioctlInfo.InputBufferLength, AFD_SYSTEM_BUFFER_POOL_TAG ); if (newSystemBuffer==NULL) { ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); } ExFreePool (Irp->AssociatedIrp.SystemBuffer); Irp->AssociatedIrp.SystemBuffer = newSystemBuffer; }
//
// Copy application data to the system buffer
//
RtlCopyMemory (Irp->AssociatedIrp.SystemBuffer, ioctlInfo.InputBuffer, ioctlInfo.InputBufferLength);
} except( AFD_EXCEPTION_FILTER (status) ) { ASSERT (NT_ERROR (status)); goto complete; }
destAddr = Irp->AssociatedIrp.SystemBuffer;
if(ioctlInfo.InputBufferLength < sizeof(*destAddr) || ioctlInfo.InputBufferLength < (ULONG)FIELD_OFFSET (TRANSPORT_ADDRESS, Address[0].Address[destAddr->Address[0].AddressLength]) ) {
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdRoutingInterfaceChange: Endp: %p - invalid parameter.\n", IrpSp->FileObject->FsContext)); status = STATUS_INVALID_PARAMETER; goto complete;
}
//
// PROBLEM We only support IP for now
//
if (destAddr->Address[0].AddressType!=TDI_ADDRESS_TYPE_IP && destAddr->Address[0].AddressType!=TDI_ADDRESS_TYPE_IP6) { status = STATUS_NOT_SUPPORTED; goto complete; }
//
// Reset the poll bit
//
endpoint->EventsActive &= ~AFD_POLL_ROUTING_IF_CHANGE;
return AfdTcpQueueRoutingChangeRequest (endpoint, Irp, overlapped);
complete: Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, AfdPriorityBoost);
return status;
} // AfdRoutingInterfaceChange
NTSTATUS AfdOpenDevice ( LPWSTR DeviceNameStr, HANDLE *Handle, PFILE_OBJECT *FileObject ) /*++
Routine Description:
Opens specified device driver (control channel) and returns handle and file object
Arguments:
DeviceNameStr - device to open.
Handle - returned handle.
FileObject - returned file object. Return Value:
NTSTATUS -- Indicates whether the device was opened OK
--*/ { NTSTATUS status; UNICODE_STRING DeviceName; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iosb;
PAGED_CODE( );
RtlInitUnicodeString(&DeviceName, DeviceNameStr);
//
// 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, &DeviceName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
NULL, NULL );
status = IoCreateFile( Handle, MAXIMUM_ALLOWED, &objectAttributes, &iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, // create disposition.
0, // create options.
NULL, // eaInfo
0, // eaLength
CreateFileTypeNone, // CreateFileType
NULL, // ExtraCreateParameters
IO_NO_PARAMETER_CHECKING // Options
| IO_FORCE_ACCESS_CHECK );
if (NT_SUCCESS (status)) { status = ObReferenceObjectByHandle ( *Handle, 0L, *IoFileObjectType, KernelMode, (PVOID *)FileObject, NULL ); if (!NT_SUCCESS (status)) { ZwClose (*Handle); *Handle = NULL; } }
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdOpenDevice: Opened %ls, handle: %p, file: %p, status: %lx.\n", DeviceNameStr, *Handle, *FileObject, status)); } return status;
} // AfdOpenDevice
VOID AfdDereferenceRoutingQuery ( PAFD_PROTOCOL Protocol ) {
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(AfdResource, TRUE);
ASSERT(Protocol->RoutingQueryRefCount > 0); ASSERT(Protocol->DeviceHandle != NULL);
if (InterlockedDecrement(&Protocol->RoutingQueryRefCount) == 0) {
HANDLE DeviceHandle = Protocol->DeviceHandle; PFILE_OBJECT FileObject = Protocol->FileObject;
Protocol->DeviceHandle = NULL; Protocol->FileObject = NULL;
ExReleaseResourceLite(AfdResource); KeLeaveCriticalRegion();
ObDereferenceObject(FileObject);
//
// Do this in the context of system process so that it does not
// get closed when applications exit
//
ZwClose(DeviceHandle);
} else {
ExReleaseResourceLite(AfdResource); KeLeaveCriticalRegion();
}
} // AfdDereferenceRoutingQuery
NTSTATUS AfdTcp6RoutingQuery ( PTA_ADDRESS Dest, PTA_ADDRESS Intf ) /*++
Routine Description:
Submits routing query request to TCP6
Arguments:
Dest - destination to query
Intf - interface through which destination can be reached.
Return Value:
NTSTATUS -- Indicates whether operation succeded
--*/ { NTSTATUS status; TDIObjectID *lpObject; CHAR byBuffer[FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context) + sizeof(TDI_ADDRESS_IP6)]; TCP_REQUEST_QUERY_INFORMATION_EX *ptrqiBuffer = (TCP_REQUEST_QUERY_INFORMATION_EX *) byBuffer; IP6RouteEntry routeEntry; IO_STATUS_BLOCK iosb; KEVENT event; PIRP irp; PIO_STACK_LOCATION irpSp; HANDLE tcpDeviceHandle; PFILE_OBJECT tcpFileObject; PDEVICE_OBJECT tcpDeviceObject;
PAGED_CODE ();
if (Dest->AddressLength<TDI_ADDRESS_LENGTH_IP6) { KdPrintEx ((DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdTcp6RoutingQuery: Destination address buffer too small.\n")); return STATUS_BUFFER_TOO_SMALL; }
//
// Open TCP6 driver.
//
status = AfdOpenDevice (DD_TCPV6_DEVICE_NAME, &tcpDeviceHandle, &tcpFileObject); if (!NT_SUCCESS (status)) { return status; } tcpDeviceObject = IoGetRelatedDeviceObject ( tcpFileObject );
//
// Setup the query
//
RtlCopyMemory( (PVOID)ptrqiBuffer->Context, Dest->Address, TDI_ADDRESS_LENGTH_IP6);
lpObject = &ptrqiBuffer->ID; lpObject->toi_id = IP6_GET_BEST_ROUTE_ID; lpObject->toi_class = INFO_CLASS_PROTOCOL; lpObject->toi_type = INFO_TYPE_PROVIDER; lpObject->toi_entity.tei_entity = CL_NL_ENTITY; lpObject->toi_entity.tei_instance = 0;
KeInitializeEvent (&event, NotificationEvent, FALSE);
//
// Build and setup the IRP and call the driver
//
irp = IoBuildDeviceIoControlRequest ( IOCTL_TCP_QUERY_INFORMATION_EX, //Control
tcpDeviceObject, // Device
ptrqiBuffer, // Input buffer
sizeof(byBuffer), // Input buffer size
&routeEntry, // Output buffer
sizeof(routeEntry), // Output buffer size
FALSE, // Internal ?
&event, // Event
&iosb // Status block
); if (irp==NULL) { IF_DEBUG(ROUTING_QUERY) { KdPrintEx ((DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdTcp6RoutingQuery: Could not allocate IRP.\n")); } status = STATUS_INSUFFICIENT_RESOURCES; goto complete; }
irpSp = IoGetNextIrpStackLocation (irp); irpSp->FileObject = tcpFileObject;
status = IoCallDriver (tcpDeviceObject, irp);
if (status==STATUS_PENDING) { status = KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, // Alertable
NULL); // Timeout
}
IF_DEBUG (ROUTING_QUERY) { KdPrintEx ((DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdTcp6RoutingQuery: IP6_GET_BEST_ROUTE_ID - status: %lx.\n", status)); }
if (!NT_SUCCESS (status)) { goto complete; }
if (!NT_SUCCESS (iosb.Status)) { status = iosb.Status; goto complete; }
// Fill in IPv6 address
Intf->AddressType = TDI_ADDRESS_TYPE_IP6; Intf->AddressLength = TDI_ADDRESS_LENGTH_IP6; RtlCopyMemory( ((PTDI_ADDRESS_IP6)Intf->Address)->sin6_addr, &routeEntry.ire_Source, sizeof(routeEntry.ire_Source) ); ((PTDI_ADDRESS_IP6)Intf->Address)->sin6_flowinfo = 0; ((PTDI_ADDRESS_IP6)Intf->Address)->sin6_port = 0; ((PTDI_ADDRESS_IP6)Intf->Address)->sin6_scope_id = routeEntry.ire_ScopeId; status = STATUS_SUCCESS;
complete: ObDereferenceObject (tcpFileObject); ZwClose (tcpDeviceHandle);
return status; }
NTSTATUS AfdTcpRoutingQuery ( PTA_ADDRESS Dest, PTA_ADDRESS Intf ) /*++
Routine Description:
Submits routing query request to TCP
Arguments:
Dest - destination to query Intf - interface through which destination can be reached.
Return Value:
NTSTATUS -- Indicates whether operation succeded
--*/ { NTSTATUS status; TDIObjectID *lpObject; TCP_REQUEST_QUERY_INFORMATION_EX trqiBuffer; ULONG *pIpAddr; ULONG ipSource; IO_STATUS_BLOCK iosb; KEVENT event; PIRP irp; PIO_STACK_LOCATION irpSp; HANDLE tcpDeviceHandle; PFILE_OBJECT tcpFileObject; PDEVICE_OBJECT tcpDeviceObject;
PAGED_CODE ();
if (Dest->AddressLength<TDI_ADDRESS_LENGTH_IP) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdTcpRoutingQuery: Destination address buffer too small.\n")); return STATUS_BUFFER_TOO_SMALL; }
//
// Open TCP driver.
//
status = AfdOpenDevice (DD_TCP_DEVICE_NAME, &tcpDeviceHandle, &tcpFileObject); if (!NT_SUCCESS (status)) { return status; } tcpDeviceObject = IoGetRelatedDeviceObject ( tcpFileObject );
//
// Setup the query
//
RtlZeroMemory (&trqiBuffer, sizeof (trqiBuffer));
pIpAddr = (ULONG *)trqiBuffer.Context; *pIpAddr = ((PTDI_ADDRESS_IP)Dest->Address)->in_addr;
lpObject = &trqiBuffer.ID; lpObject->toi_id = IP_GET_BEST_SOURCE; lpObject->toi_class = INFO_CLASS_PROTOCOL; lpObject->toi_type = INFO_TYPE_PROVIDER; lpObject->toi_entity.tei_entity = CL_NL_ENTITY; lpObject->toi_entity.tei_instance = 0;
KeInitializeEvent (&event, NotificationEvent, FALSE);
//
// Build and setup the IRP and call the driver
//
irp = IoBuildDeviceIoControlRequest ( IOCTL_TCP_QUERY_INFORMATION_EX, //Control
tcpDeviceObject, // Device
&trqiBuffer, // Input buffer
sizeof(trqiBuffer), // Input buffer size
&ipSource, // Output buffer
sizeof(ipSource), // Output buffer size
FALSE, // Internal ?
&event, // Event
&iosb // Status block
); if (irp==NULL) { IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpRoutingQuery: Could not allocate IRP.\n")); } status = STATUS_INSUFFICIENT_RESOURCES; goto complete; }
irpSp = IoGetNextIrpStackLocation (irp); irpSp->FileObject = tcpFileObject;
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpRoutingQuery: Quering for route to %lx.\n", ((PTDI_ADDRESS_IP)Dest->Address)->in_addr)); } status = IoCallDriver (tcpDeviceObject, irp);
if (status==STATUS_PENDING) { status = KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, // Alertable
NULL); // Timeout
}
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpRoutingQuery: IP_GET_BEST_SOURCE - status: %lx.\n", status)); }
if (!NT_SUCCESS (status)) { goto complete; }
if (!NT_SUCCESS (iosb.Status)) { status = iosb.Status; goto complete; }
Intf->AddressType = TDI_ADDRESS_TYPE_IP; Intf->AddressLength = TDI_ADDRESS_LENGTH_IP; ((PTDI_ADDRESS_IP)Intf->Address)->in_addr = ipSource; ((PTDI_ADDRESS_IP)Intf->Address)->sin_port = 0; RtlFillMemory (((PTDI_ADDRESS_IP)Intf->Address)->sin_zero, sizeof (((PTDI_ADDRESS_IP)Intf->Address)->sin_zero), 0); IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpRoutingQuery: Found interface %lx.\n", ((PTDI_ADDRESS_IP)Intf->Address)->in_addr)); } status = STATUS_SUCCESS;
complete: ObDereferenceObject (tcpFileObject); ZwClose (tcpDeviceHandle);
return status; } // AfdTcpRoutingQuery
NTSTATUS AfdGetRoutingQueryReference ( PAFD_PROTOCOL Protocol ) /*++
Routine Description:
Initializes routing query if necessary and references it
Arguments:
None
Return Value:
NTSTATUS -- Indicates whether operation succeded
--*/ {
// KAPC_STATE apcState;
HANDLE DeviceHandle; PFILE_OBJECT FileObject; NTSTATUS status;
status = AfdOpenDevice (Protocol->NetworkLayerDeviceName, &DeviceHandle, &FileObject); if (NT_SUCCESS (status)) {
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion (); ExAcquireResourceExclusiveLite ( AfdResource, TRUE); if (Protocol->DeviceHandle==NULL) { Protocol->DeviceHandle = DeviceHandle; Protocol->FileObject = FileObject; ASSERT (Protocol->RoutingQueryRefCount==0); Protocol->RoutingQueryRefCount = 1; ExReleaseResourceLite( AfdResource ); KeLeaveCriticalRegion (); } else { ASSERT (Protocol->RoutingQueryRefCount>0); InterlockedIncrement (&Protocol->RoutingQueryRefCount);
ExReleaseResourceLite( AfdResource ); KeLeaveCriticalRegion ();
ObDereferenceObject (FileObject); status = ZwClose (DeviceHandle); ASSERT (status==STATUS_SUCCESS); } } else { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdGetRoutingQueryReference: Network layer device open failed, status: %lx.\n", status)); }
return status; } // AfdGetRoutingQueryReference
NTSTATUS AfdTcpQueueRoutingChangeRequest ( IN PAFD_ENDPOINT Endpoint, IN PIRP Irp, BOOLEAN Overlapped ) /*++
Routine Description:
Submits routing change request to TCP
Arguments: Endpoint - endpoint on which request is issued
Irp - the request
Overlapped - whether request is overlapped (and thus should be pended event on non-blocking socket)
Return Value:
NTSTATUS -- Indicates whether operation succeded
--*/ { PTRANSPORT_ADDRESS destAddr; NTSTATUS status; PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; PIO_STACK_LOCATION irpSp; AFD_LOCK_QUEUE_HANDLE lockHandle; struct Notify { ROUTING_NOTIFY Ctx; char Data[1]; } * notify; PIRP irp; PIO_COMPLETION_ROUTINE compRoutine; PAFD_PROTOCOL Protocol;
//
// Set locals for easy cleanup.
//
notify = NULL; irp = NULL;
destAddr = Irp->AssociatedIrp.SystemBuffer;
Protocol = AfdGetProtocolInfo(destAddr->Address[0].AddressType); if (Protocol == NULL) { status = STATUS_INVALID_PARAMETER; goto complete; }
if (destAddr->Address[0].AddressLength < Protocol->AddressLength) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdTcpQueueRoutingChangeRequest: Destination buffer too small.\n")); status = STATUS_INVALID_PARAMETER; goto complete; }
//
// Allocate context structures to keep IRP in the endpoint list in
// case the latter gets closed and we need to cancel the IRP.
// Also allocate buffer for passing data to IP
//
try { notify = AFD_ALLOCATE_POOL_WITH_QUOTA (NonPagedPool, FIELD_OFFSET(struct Notify, Data[Protocol->RtChangeDataSize]), AFD_ROUTING_QUERY_POOL_TAG); // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE
} except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode (); notify = NULL; goto complete; }
//
// Open IP driver if necessary
//
AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle); //
// Check if endpoint was cleaned-up and cancel the request.
//
if (Endpoint->EndpointCleanedUp) {
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); status = STATUS_CANCELLED; goto complete;
}
if (Endpoint->RoutingQueryReferenced) {
//
// Since this endpoint already has a reference to the routing query
// protocol structure, we do not need to add another since we hold
// the endpoint spinlock and the only time the reference is
// decremented is at endpoint cleanup. Similarly, we should not
// decrement the reference in the error path.
//
if (((Protocol->AddressType == TDI_ADDRESS_TYPE_IP) && Endpoint->RoutingQueryIPv6) || ((Protocol->AddressType == TDI_ADDRESS_TYPE_IP6) && !Endpoint->RoutingQueryIPv6)) {
//
// Another thread referenced routing query for a different
// protocol family - we can't support both of the at the
// same time.
//
AfdReleaseSpinLock(&Endpoint->SpinLock, &lockHandle); status = STATUS_INVALID_PARAMETER; goto complete;
}
ASSERT(Protocol->DeviceHandle != NULL); ASSERT(Protocol->FileObject != NULL); ASSERT(Protocol->RoutingQueryRefCount > 0); } else {
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
status = AfdGetRoutingQueryReference(Protocol); if (!NT_SUCCESS(status)) goto complete; ASSERT(Protocol->DeviceHandle != NULL);
AfdAcquireSpinLock(&Endpoint->SpinLock, &lockHandle);
if (Endpoint->EndpointCleanedUp) {
//
// Endpoint was cleaned-up while we were
// referencing routing query. Release the reference.
//
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); AfdDereferenceRoutingQuery(Protocol); status = STATUS_CANCELLED; goto complete;
}
if (Endpoint->RoutingQueryReferenced) {
//
// Another thread referenced routing query for this endpoint.
//
LONG result;
if ((Protocol->AddressType==TDI_ADDRESS_TYPE_IP && Endpoint->RoutingQueryIPv6) || (Protocol->AddressType==TDI_ADDRESS_TYPE_IP6 && !Endpoint->RoutingQueryIPv6)) {
//
// Another thread referenced routing query for a different
// protocol family - we can't support both of the at the
// same time.
//
AfdReleaseSpinLock(&Endpoint->SpinLock, &lockHandle); AfdDereferenceRoutingQuery(Protocol); status = STATUS_INVALID_PARAMETER; goto complete;
}
//
// Since we know that that other's thread reference cannot
// go away while we are holding spinlock, we can simply
// decrement the reference count and be sure that it
// won't go all the way to 0.
//
result = InterlockedDecrement(&Protocol->RoutingQueryRefCount); ASSERT(result > 0);
} else {
Endpoint->RoutingQueryReferenced = TRUE; if (Protocol->AddressType == TDI_ADDRESS_TYPE_IP6) Endpoint->RoutingQueryIPv6 = TRUE;
} // if (Endpoint->RoutingQueryReferenced)
} // if (Endpoint->RoutingQueryReferenced)
fileObject = Protocol->FileObject; deviceObject = IoGetRelatedDeviceObject(fileObject);
if (Endpoint->NonBlocking && !Overlapped) {
//
// For non-blocking socket and non-overlapped requests
// we shall post the query using new IRP,
// so even if thread in which rhe request
// is originated by user exits, our request to IP does not get
// cancelled and we will still signal the event.
//
irp = IoAllocateIrp (deviceObject->StackSize, TRUE); if (irp==NULL) { AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); status = STATUS_INSUFFICIENT_RESOURCES; goto complete; }
//
// Save the endpoint reference in notify context.
//
REFERENCE_ENDPOINT (Endpoint); notify->Ctx.NotifyContext = Endpoint;
//
// Setup completion routine so we can remove the IRP
// from the endpoint list and free it.
//
compRoutine = AfdTcpSignalRoutingChange;
} else {
//
// Blocking endpoint: just pass the original request on to the IP
//
irp = Irp;
//
// Save the original system buffer of the IRP, so we can restore
// it when TCP completes it
//
notify->Ctx.NotifyContext = Irp->AssociatedIrp.SystemBuffer;
//
// Setup completion routine so we can restore the IRP and remove it
// from the endpoint list
//
compRoutine = AfdTcpRestartRoutingChange;
}
//
// Insert notification into the endpoint list
//
InsertTailList (&Endpoint->RoutingNotifications, ¬ify->Ctx.NotifyListLink);
AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
//
// Save pointer to IRP in notify structure
//
notify->Ctx.NotifyIrp = irp;
//
// Setup IP notification request
//
switch(Protocol->AddressType) { case TDI_ADDRESS_TYPE_IP: { IPNotifyData *data = (IPNotifyData *)notify->Data; data->Version = 0; data->Add = ((PTDI_ADDRESS_IP)destAddr->Address[0].Address)->in_addr; break; } case TDI_ADDRESS_TYPE_IP6: { IPV6_RTCHANGE_NOTIFY_REQUEST *data = (IPV6_RTCHANGE_NOTIFY_REQUEST *)notify->Data; data->Flags = 0; data->ScopeId = ((PTDI_ADDRESS_IP6)destAddr->Address[0].Address)->sin6_scope_id; if (RtlEqualMemory(((PTDI_ADDRESS_IP6)destAddr->Address[0].Address)->sin6_addr, ZeroString, 16)) { data->PrefixLength = 0; } else { data->PrefixLength = 128; } RtlCopyMemory( &data->Prefix, ((PTDI_ADDRESS_IP6)destAddr->Address[0].Address)->sin6_addr, 16); break; } default: __assume (0); }
//
// Setup IRP stack location to forward IRP to IP
// Must be METHOD_BUFFERED or we are not setting it up correctly
//
ASSERT ( (Protocol->RtChangeIoctl & 0x03)==METHOD_BUFFERED ); irp->AssociatedIrp.SystemBuffer = notify->Data;
irpSp = IoGetNextIrpStackLocation (irp); irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; irpSp->MinorFunction = 0; irpSp->Flags = 0; irpSp->Control = 0; irpSp->FileObject = fileObject; irpSp->Parameters.DeviceIoControl.InputBufferLength = Protocol->RtChangeDataSize; irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0; irpSp->Parameters.DeviceIoControl.IoControlCode = Protocol->RtChangeIoctl; irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL; IoSetCompletionRoutine( irp, compRoutine, notify, TRUE, TRUE, TRUE );
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpQueueRoutingChangeRequest: Passing Irp %p to IP\n", irp)); }
if (irp==Irp) { //
// Just pass the request through to the driver and return what it
// returns
//
return AfdIoCallDriver (Endpoint, deviceObject, irp); }
IoCallDriver (deviceObject, irp);
status = STATUS_DEVICE_NOT_READY; // To be converted to WSAEWOULDBLOCK
notify = NULL; // So it doesn't get freed below.
//
// Error cases
//
complete: IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpQueueRoutingChangeRequest: completing with status: %lx\n", status)); } if (notify!=NULL) { AFD_FREE_POOL (notify, AFD_ROUTING_QUERY_POOL_TAG); }
Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, AfdPriorityBoost );
return status; } //AfdTcpQueueRoutingChangeRequest
NTSTATUS AfdTcpRestartRoutingChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++
Routine Description:
Completion routing for routing change IRP forwarded to IP
Arguments: DeviceObject - must be our device object
Irp - the request to be completed
Context - completion context
Return Value:
NTSTATUS -- Indicates to the system what to do next with the IRP
--*/ { PROUTING_NOTIFY notifyCtx = Context; PAFD_ENDPOINT endpoint = IoGetCurrentIrpStackLocation (Irp)->FileObject->FsContext;
UNREFERENCED_PARAMETER (DeviceObject); ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpRestartRoutingChange: Irp: %p, status: %lx, info: %ld.\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information)); }
//
// Check if IRP is still on the endpoint's list and remove if it is
//
if (InterlockedExchangePointer ((PVOID *)¬ifyCtx->NotifyIrp, NULL)!=NULL) { AFD_LOCK_QUEUE_HANDLE lockHandle; AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle); RemoveEntryList (¬ifyCtx->NotifyListLink); AfdIndicateEventSelectEvent (endpoint, AFD_POLL_ROUTING_IF_CHANGE, Irp->IoStatus.Status); AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Indicate event as the endpoint is still active
//
AfdIndicatePollEvent (endpoint, AFD_POLL_ROUTING_IF_CHANGE, Irp->IoStatus.Status); }
//
// If pending has be returned for this IRP then mark the current
// stack as pending.
//
if ( Irp->PendingReturned ) { IoMarkIrpPending( Irp ); }
//
// Restore the IRP to its previous glory and free allocated context structure
//
Irp->AssociatedIrp.SystemBuffer = notifyCtx->NotifyContext; AfdCompleteOutstandingIrp (endpoint, Irp);
AFD_FREE_POOL (notifyCtx, AFD_ROUTING_QUERY_POOL_TAG); return STATUS_SUCCESS; }
NTSTATUS AfdTcpSignalRoutingChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++
Routine Description:
Completion routing for routing change IRP submitted to IP
Arguments: DeviceObject - must be our device object
Irp - the request to be completed
Context - completion context
Return Value:
NTSTATUS -- Indicates to the system what to do next with the IRP
--*/ { PROUTING_NOTIFY notifyCtx = Context; PAFD_ENDPOINT endpoint = notifyCtx->NotifyContext;
UNREFERENCED_PARAMETER (DeviceObject); ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
IF_DEBUG (ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdTcpSignalRoutingChange: Irp: %p, status: %lx, info: %ld.\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information)); }
//
// Check if IRP is still on the endpoint's list and remove if it is
//
if (InterlockedExchangePointer ((PVOID *)¬ifyCtx->NotifyIrp, NULL)!=NULL) { AFD_LOCK_QUEUE_HANDLE lockHandle;
AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle); RemoveEntryList (¬ifyCtx->NotifyListLink); AfdIndicateEventSelectEvent (endpoint, AFD_POLL_ROUTING_IF_CHANGE, Irp->IoStatus.Status); AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
//
// Indicate event as the endpoint is still active
//
AfdIndicatePollEvent (endpoint, AFD_POLL_ROUTING_IF_CHANGE, Irp->IoStatus.Status); }
//
// Release previously acquired endpoint reference
//
DEREFERENCE_ENDPOINT (endpoint);
//
// Free allocated irp and context structure
//
IoFreeIrp (Irp); AFD_FREE_POOL (notifyCtx, AFD_ROUTING_QUERY_POOL_TAG);
return STATUS_MORE_PROCESSING_REQUIRED; }
VOID AfdCleanupRoutingChange ( PAFD_ENDPOINT Endpoint ) { AFD_LOCK_QUEUE_HANDLE lockHandle; KIRQL cancelIrql; USHORT addressType; PLIST_ENTRY listEntry; PAFD_PROTOCOL protocol; //
// If there are pending routing notifications on endpoint, cancel them.
// We must hold both cancel and endpoint spinlocks to make
// sure that IRP is not completed as we are cancelling it
//
IoAcquireCancelSpinLock( &cancelIrql ); AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle );
//
// Can only have one cleanup call per endpoint
// So this should be set.
//
ASSERT (Endpoint->RoutingQueryReferenced); Endpoint->RoutingQueryReferenced = FALSE; if (Endpoint->RoutingQueryIPv6) { Endpoint->RoutingQueryIPv6 = FALSE; addressType = TDI_ADDRESS_TYPE_IP6; } else { addressType = TDI_ADDRESS_TYPE_IP; }
listEntry = Endpoint->RoutingNotifications.Flink; while (listEntry!=&Endpoint->RoutingNotifications) { PIRP notifyIrp; PROUTING_NOTIFY notifyCtx = CONTAINING_RECORD (listEntry, ROUTING_NOTIFY, NotifyListLink); listEntry = listEntry->Flink;
//
// Check if IRP has not been completed yet
//
notifyIrp = (PIRP)InterlockedExchangePointer ((PVOID *)¬ifyCtx->NotifyIrp, NULL); if (notifyIrp!=NULL) {
//
// Remove it from the list and call cancel routing while still
// holding cancel spinlock
//
RemoveEntryList (¬ifyCtx->NotifyListLink); AfdReleaseSpinLockFromDpcLevel ( &Endpoint->SpinLock, &lockHandle); notifyIrp->CancelIrql = cancelIrql; AfdCancelIrp (notifyIrp);
//
// Reacquire cancel and endpoint spinlocks
//
IoAcquireCancelSpinLock( &cancelIrql ); AfdAcquireSpinLockAtDpcLevel( &Endpoint->SpinLock, &lockHandle ); } }
AfdReleaseSpinLockFromDpcLevel ( &Endpoint->SpinLock, &lockHandle); IoReleaseCancelSpinLock( cancelIrql ); protocol = AfdGetProtocolInfo(addressType); ASSERT(protocol != NULL); AfdDereferenceRoutingQuery(protocol);
}
VOID AfdCancelAddressListChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
BOOLEAN AfdCleanupAddressListChange ( PAFD_ENDPOINT Endpoint, PAFD_REQUEST_CONTEXT RequestCtx );
NTSTATUS AfdInitializeAddressList (VOID);
VOID AfdAddAddressHandler ( IN PTA_ADDRESS NetworkAddress, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context );
VOID AfdDelAddressHandler ( IN PTA_ADDRESS NetworkAddress, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context );
VOID AfdProcessAddressChangeList ( USHORT AddressType, PUNICODE_STRING DeviceName );
NTSTATUS AfdPnPPowerChange( IN PUNICODE_STRING DeviceName, IN PNET_PNP_EVENT PowerEvent, IN PTDI_PNP_CONTEXT Context1, IN PTDI_PNP_CONTEXT Context2 );
VOID AfdReturnNicsPackets ( PVOID Pdo );
BOOLEAN AfdHasHeldPacketsFromNic ( PAFD_CONNECTION Connection, PVOID Pdo );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfdAddressListQuery )
#pragma alloc_text( PAGEAFD, AfdAddressListChange )
#pragma alloc_text( PAGEAFD, AfdCancelAddressListChange )
#pragma alloc_text( PAGE, AfdInitializeAddressList )
#pragma alloc_text( PAGE, AfdDeregisterPnPHandlers )
#pragma alloc_text( PAGE, AfdAddAddressHandler )
#pragma alloc_text( PAGE, AfdDelAddressHandler )
#pragma alloc_text( PAGEAFD, AfdProcessAddressChangeList )
#pragma alloc_text( PAGE, AfdPnPPowerChange )
#pragma alloc_text( PAGEAFD, AfdReturnNicsPackets )
#pragma alloc_text( PAGEAFD, AfdHasHeldPacketsFromNic )
#endif
//
// Cache the device being brought down as a result of
// removal or power down event, so we do not scan our endpoints
// unnecessarily when more than one transport propagates device down
// event for the same device to us.
//
PVOID AfdLastRemovedPdo = NULL; ULONGLONG AfdLastRemoveTime = 0i64;
NTSTATUS AfdAddressListQuery ( IN PFILE_OBJECT FileObject, IN ULONG IoctlCode, IN KPROCESSOR_MODE RequestorMode, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG_PTR Information ) /*++
Routine Description:
Processes address list query IRP
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/ { NTSTATUS status; PLIST_ENTRY listEntry; PTRANSPORT_ADDRESS addressList; PAFD_ENDPOINT endpoint; PUCHAR addressBuf; ULONG dataLen; PAFD_ADDRESS_ENTRY addressEntry; USHORT addressType;
UNREFERENCED_PARAMETER (IoctlCode); PAGED_CODE ();
*Information = 0; status = STATUS_SUCCESS;
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListQuery: Endp: %p, buf: %p, inlen: %ld, outlen: %ld.\n", FileObject->FsContext, OutputBuffer, InputBufferLength, OutputBufferLength)); }
//
// Validate input parameters
//
if( InputBufferLength < sizeof(USHORT) || OutputBufferLength < FIELD_OFFSET (TRANSPORT_ADDRESS, Address) ) {
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdAddressListQuery: Endp: %p - invalid parameter.\n", FileObject->FsContext)); return STATUS_INVALID_PARAMETER; }
endpoint = FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
try { if (RequestorMode!=KernelMode) { ProbeForReadSmallStructure (InputBuffer, sizeof (addressType), sizeof (USHORT)); ProbeForWrite (OutputBuffer, OutputBufferLength, sizeof (ULONG)); }
addressType = *((PUSHORT)InputBuffer);
addressList = OutputBuffer; addressBuf = (PUCHAR)OutputBuffer; dataLen = FIELD_OFFSET (TRANSPORT_ADDRESS, Address); addressList->TAAddressCount = 0; } except (AFD_EXCEPTION_FILTER (status)) { ASSERT (NT_ERROR (status)); return status; }
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion (); ExAcquireResourceSharedLite( AfdResource, TRUE );
//
// Setup address handlers with TDI if not already done
//
if (AfdBindingHandle==NULL) { ExReleaseResourceLite( AfdResource );
ExAcquireResourceExclusiveLite( AfdResource, TRUE );
if (AfdBindingHandle==NULL) { status = AfdInitializeAddressList (); if (!NT_SUCCESS (status)) { ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion (); return status; } } else status = STATUS_SUCCESS; ASSERT (AfdBindingHandle!=NULL); }
ExAcquireResourceSharedLite( AfdAddressListLock, TRUE ); ExReleaseResourceLite( AfdResource );
//
// Walk the address list and pick up the addresses of matching protocol
// family
//
listEntry = AfdAddressEntryList.Flink; while (listEntry!=&AfdAddressEntryList) { addressEntry = CONTAINING_RECORD (listEntry, AFD_ADDRESS_ENTRY, AddressListLink); listEntry = listEntry->Flink;
//
// Found a match ?
//
if ((addressEntry->Address.AddressType==addressType) //
// Special check for Netbios addresses because
// we have separate protocols for each lana/device
//
&& ((addressType!=TDI_ADDRESS_TYPE_NETBIOS) || endpoint->TransportInfo==NULL || RtlEqualUnicodeString ( &addressEntry->DeviceName, &endpoint->TransportInfo->TransportDeviceName, TRUE))) { ULONG addressLength = FIELD_OFFSET (TA_ADDRESS, Address[addressEntry->Address.AddressLength]); AFD_W4_INIT ASSERT (status==STATUS_SUCCESS || status==STATUS_BUFFER_OVERFLOW); try {
//
// Copy address to the output buffer if it is not full
//
if (status==STATUS_SUCCESS) { if (dataLen+addressLength<=OutputBufferLength) { RtlCopyMemory (&addressBuf[dataLen], &addressEntry->Address, addressLength); IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListQuery: Adding address of type: %d, length: %d.\n", addressEntry->Address.AddressType, addressEntry->Address.AddressLength)); } } else { //
// End of buffer reached. Set error code so we do not
// attempt to copy more data
//
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListQuery: Buffer is full.\n")); } status = STATUS_BUFFER_OVERFLOW; } }
//
// Count the addresses and total buffer length whether we copied
// them or not to the output buffer
//
addressList->TAAddressCount += 1; dataLen += addressLength; } except (AFD_EXCEPTION_FILTER (status)) { ASSERT (NT_ERROR (status)); dataLen = 0; break; } } } ExReleaseResourceLite (AfdAddressListLock); KeLeaveCriticalRegion ();
//
// Return total number of copied/required bytes in the buffer and status
//
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListQuery: Address count: %ld, total buffer size: %ld.\n", addressList->TAAddressCount, dataLen)); } *Information = dataLen;
return status; } //AfdAddressListQuery
//
// Context structure allocated for non-blocking address list change IOCTLs
//
typedef struct _AFD_NBCHANGE_CONTEXT { AFD_REQUEST_CONTEXT Context; // Context to keep track of request
AFD_ADDRESS_CHANGE Change; // Address change parameters
} AFD_NBCHANGE_CONTEXT, *PAFD_NBCHANGE_CONTEXT;
NTSTATUS FASTCALL AfdAddressListChange ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++
Routine Description:
Processes address list change IRP
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/ { NTSTATUS status = STATUS_PENDING; USHORT addressType; PAFD_ADDRESS_CHANGE change; PAFD_REQUEST_CONTEXT requestCtx; PAFD_ENDPOINT endpoint; AFD_LOCK_QUEUE_HANDLE addressLockHandle, endpointLockHandle; KIRQL oldIrql; BOOLEAN overlapped; AFD_TRANSPORT_IOCTL_INFO ioctlInfo;
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListChange: Endp: %p, buf: %p, inlen: %ld, outlen: %ld.\n", IrpSp->FileObject->FsContext, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength)); }
endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
//
// Validate input parameters
//
#ifdef _WIN64
if (IoIs32bitProcess (Irp)) { PAFD_TRANSPORT_IOCTL_INFO32 ioctlInfo32; ioctlInfo32 = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (*ioctlInfo32)) { status = STATUS_INVALID_PARAMETER; goto complete; } ioctlInfo.Handle = ioctlInfo32->Handle; ioctlInfo.InputBuffer = UlongToPtr(ioctlInfo32->InputBuffer); ioctlInfo.InputBufferLength = ioctlInfo32->InputBufferLength; ioctlInfo.IoControlCode = ioctlInfo32->IoControlCode; ioctlInfo.AfdFlags = ioctlInfo32->AfdFlags; ioctlInfo.PollEvent = ioctlInfo32->PollEvent; } else #endif // _WIN64
{
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength<sizeof (ioctlInfo)) { status = STATUS_INVALID_PARAMETER; goto complete; }
//
// Just copy the buffer verified by the IO system
//
ioctlInfo = *((PAFD_TRANSPORT_IOCTL_INFO) Irp->AssociatedIrp.SystemBuffer); }
if( ioctlInfo.InputBufferLength < sizeof(USHORT)) {
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdAddressListChange: Endp: %p - invalid parameter.\n", IrpSp->FileObject->FsContext)); status = STATUS_INVALID_PARAMETER; goto complete; }
try { if (Irp->RequestorMode != KernelMode) { ProbeForRead( ioctlInfo.InputBuffer, ioctlInfo.InputBufferLength, sizeof (USHORT) ); }
addressType = *((PUSHORT)ioctlInfo.InputBuffer); } except( AFD_EXCEPTION_FILTER (status) ) { ASSERT (NT_ERROR (status)); goto complete; }
//
// Check if request is overlapped
//
overlapped = (BOOLEAN)((ioctlInfo.AfdFlags & AFD_OVERLAPPED)!=0);
//
// Reset the poll bit
//
endpoint->EventsActive &= ~AFD_POLL_ADDRESS_LIST_CHANGE;
//
// Setup address handlers with TDI if not already done
//
if (AfdBindingHandle==NULL) { //
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion (); ExAcquireResourceExclusiveLite( AfdResource, TRUE );
if (AfdBindingHandle==NULL) status = AfdInitializeAddressList (); else status = STATUS_SUCCESS;
ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion ();
if (!NT_SUCCESS (status)) { goto complete; } }
//
// Setup locals
//
if (endpoint->NonBlocking && !overlapped) { PAFD_NBCHANGE_CONTEXT nbCtx; //
// If endpoint is non-blocking and request is not overlapped,
// we'll have to complete it right away and remeber that we
// need to set event when address list changes
//
//
// Allocate context to keep track of this request
//
try { nbCtx = AFD_ALLOCATE_POOL_WITH_QUOTA (NonPagedPool, sizeof(AFD_NBCHANGE_CONTEXT), AFD_ADDRESS_CHANGE_POOL_TAG); // AFD_ALLOCATE_POOL_WITH_QUOTA macro sets POOL_RAISE_IF_ALLOCATION_FAILURE
} except (AFD_EXCEPTION_FILTER (status)) { ASSERT (NT_ERROR (status)); nbCtx = NULL; IF_DEBUG(ROUTING_QUERY) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListChange: Endp: %p - can't allocate change strucure.\n", IrpSp->FileObject->FsContext)); } goto complete; }
requestCtx = &nbCtx->Context; change = &nbCtx->Change;
change->Endpoint = endpoint; change->NonBlocking = TRUE; status = STATUS_DEVICE_NOT_READY; } else {
C_ASSERT (sizeof (IrpSp->Parameters.Others)>=sizeof (*requestCtx)); C_ASSERT (sizeof (Irp->Tail.Overlay.DriverContext)>=sizeof (*change));
requestCtx = (PAFD_REQUEST_CONTEXT)&IrpSp->Parameters.Others;
change = (PAFD_ADDRESS_CHANGE)Irp->Tail.Overlay.DriverContext; change->NonBlocking = FALSE; change->Irp = Irp;
}
//
// Remeber the endpoint and address type for the request
//
change->AddressType = addressType; requestCtx->CleanupRoutine = AfdCleanupAddressListChange; requestCtx->Context = change;
//
// Insert change notification into the list
//
KeRaiseIrql (DISPATCH_LEVEL, &oldIrql); AfdAcquireSpinLockAtDpcLevel (&AfdAddressChangeLock, &addressLockHandle);
//
// While holding the address change spinlock acquire endpoint
// spinlock so if notification occurs, neither structure can
// be deallocated or IRP completed while we are queuing
// it to endpoint list
//
AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &endpointLockHandle);
//
// Check if endpoint was cleaned-up and cancel the request.
//
if (endpoint->EndpointCleanedUp) { AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle); AfdReleaseSpinLockFromDpcLevel (&AfdAddressChangeLock, &addressLockHandle); KeLowerIrql (oldIrql);
if (change->NonBlocking) { AFD_FREE_POOL (CONTAINING_RECORD ( requestCtx, AFD_NBCHANGE_CONTEXT, Context), AFD_ADDRESS_CHANGE_POOL_TAG); }
status = STATUS_CANCELLED; goto complete; }
//
// If request is non-blocking, check if we have another non-blocking
// request on the same endpoint. If so, we do not need to have
// two request structures in the list waiting to signal.
//
if (change->NonBlocking) { PLIST_ENTRY listEntry = endpoint->RequestList.Flink; while (listEntry!=&endpoint->RequestList) { PAFD_REQUEST_CONTEXT req = CONTAINING_RECORD ( listEntry, AFD_REQUEST_CONTEXT, EndpointListLink); listEntry = listEntry->Flink; if (req->CleanupRoutine==AfdCleanupAddressListChange) { PAFD_ADDRESS_CHANGE chg = req->Context; if (chg->NonBlocking) { AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle); AfdReleaseSpinLockFromDpcLevel (&AfdAddressChangeLock, &addressLockHandle); KeLowerIrql (oldIrql); AFD_FREE_POOL (CONTAINING_RECORD ( requestCtx, AFD_NBCHANGE_CONTEXT, Context), AFD_ADDRESS_CHANGE_POOL_TAG); KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL, "AfdAddressListChange: Endp: %p - non-blocking request already pending.\n", IrpSp->FileObject->FsContext)); ASSERT (status == STATUS_DEVICE_NOT_READY); goto complete; } } } }
InsertTailList (&AfdAddressChangeList, &change->ChangeListLink); AfdReleaseSpinLockFromDpcLevel (&AfdAddressChangeLock, &addressLockHandle); InsertTailList (&endpoint->RequestList, &requestCtx->EndpointListLink); if (!change->NonBlocking) {
//
// Set cancel routine
//
IoSetCancelRoutine( Irp, AfdCancelAddressListChange ); if ( !Irp->Cancel || IoSetCancelRoutine( Irp, NULL ) == NULL) { IoMarkIrpPending (Irp); //
// Either there was no cancel or cancel routine has
// been invoked already
//
AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle); KeLowerIrql (oldIrql);
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListChange: Queued change IRP: %p on endp: %p .\n", Irp, endpoint)); }
return STATUS_PENDING; } else { RemoveEntryList (&requestCtx->EndpointListLink); AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle); KeLowerIrql (oldIrql); goto complete; } } else { ASSERT (status==STATUS_DEVICE_NOT_READY); } AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &endpointLockHandle); KeLowerIrql (oldIrql);
complete:
Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0;
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddressListChange: Completing IRP: %ld on endp: %p with status: %lx .\n", Irp, IrpSp->FileObject->FsContext, status)); } IoCompleteRequest( Irp, 0 );
return status; }
VOID AfdCancelAddressListChange ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
Cancel routine for pending address list change IRP
Arguments: DeviceObject - must be our device object
Irp - the request to be cancelled
Return Value:
None
--*/ { AFD_LOCK_QUEUE_HANDLE lockHandle; PAFD_ADDRESS_CHANGE change; PAFD_REQUEST_CONTEXT requestCtx; PAFD_ENDPOINT endpoint; PIO_STACK_LOCATION irpSp;
UNREFERENCED_PARAMETER (DeviceObject); //
// We do not use cancel spinlock to manage address list queue, so
// we can release it right away
//
IoReleaseCancelSpinLock( Irp->CancelIrql );
//
// Get the request context and remove it from the queue if not
// already removed.
//
irpSp = IoGetCurrentIrpStackLocation (Irp); endpoint = irpSp->FileObject->FsContext; ASSERT (IS_AFD_ENDPOINT_TYPE (endpoint));
requestCtx = (PAFD_REQUEST_CONTEXT)&irpSp->Parameters.DeviceIoControl; change = requestCtx->Context; ASSERT (change==(PAFD_ADDRESS_CHANGE)Irp->Tail.Overlay.DriverContext); ASSERT (change->NonBlocking==FALSE);
AfdAcquireSpinLock (&AfdAddressChangeLock, &lockHandle); if (change->ChangeListLink.Flink!=NULL) { RemoveEntryList (&change->ChangeListLink); change->ChangeListLink.Flink = NULL; } AfdReleaseSpinLock (&AfdAddressChangeLock, &lockHandle);
AfdAcquireSpinLock (&endpoint->SpinLock, &lockHandle); if (AfdIsRequestInQueue (requestCtx)) { //
// Context is still in the list, just remove it so
// noone can see it anymore and complete the IRP
//
RemoveEntryList (&requestCtx->EndpointListLink); } else if (!AfdIsRequestCompleted (requestCtx)) { //
// During endpoint cleanup, this context was removed from the
// list and cleanup routine is about to be called, don't
// free this IRP until cleanup routine is called
// Also, indicate to the cleanup routine that we are done
// with this IRP and it can free it.
//
AfdMarkRequestCompleted (requestCtx); AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle); return; }
AfdReleaseSpinLock (&endpoint->SpinLock, &lockHandle);
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT);
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdCancelAddressListChange: Cancelled IRP: %p on endp: %p .\n", Irp, endpoint)); } }
BOOLEAN AfdCleanupAddressListChange ( PAFD_ENDPOINT Endpoint, PAFD_REQUEST_CONTEXT RequestCtx ) { AFD_LOCK_QUEUE_HANDLE lockHandle; PAFD_ADDRESS_CHANGE change;
change = RequestCtx->Context;
//
// In no case IRP and request structure
// could have been freed until we mark it as completed as
// the caller of this routine should have marked the request
// as being cancelled
//
ASSERT (RequestCtx->EndpointListLink.Flink==NULL);
AfdAcquireSpinLock (&AfdAddressChangeLock, &lockHandle); if (change->ChangeListLink.Flink!=NULL) { RemoveEntryList (&change->ChangeListLink); change->ChangeListLink.Flink = NULL; } AfdReleaseSpinLock (&AfdAddressChangeLock, &lockHandle);
AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle); //
// The processing routine has either already initiated completion
// of this request and marked it as completed what it saw that the request is
// no longer on the endpoint queue, or the processing routine will
// never see the request since we removed it from the processing list.
// However, it is possible that blocking request is being cancelled in another
// thread as we cleaning up, so we need to sync with the cancel routine.
//
if (AfdIsRequestCompleted (RequestCtx) || change->NonBlocking || IoSetCancelRoutine (change->Irp, NULL)!=NULL) { AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle); if (change->NonBlocking) { ASSERT (CONTAINING_RECORD (RequestCtx, AFD_NBCHANGE_CONTEXT, Context) ==CONTAINING_RECORD (change, AFD_NBCHANGE_CONTEXT, Change)); ASSERT (Endpoint == change->Endpoint); AFD_FREE_POOL (CONTAINING_RECORD (RequestCtx, AFD_NBCHANGE_CONTEXT, Context), AFD_ADDRESS_CHANGE_POOL_TAG); } else { PIRP irp = change->Irp; ASSERT (change==(PAFD_ADDRESS_CHANGE)irp->Tail.Overlay.DriverContext); ASSERT (Endpoint == IoGetCurrentIrpStackLocation (irp)->FileObject->FsContext); ASSERT (RequestCtx == (PAFD_REQUEST_CONTEXT) &IoGetCurrentIrpStackLocation (irp)->Parameters.DeviceIoControl); irp->IoStatus.Status = STATUS_CANCELLED; irp->IoStatus.Information = 0; IoCompleteRequest (irp, IO_NO_INCREMENT); } return TRUE; } else {
//
// AFD has not completed the request before returning
// from cancel routine, mark the request to indicate
// that we are done with it and cancel routine
// can free it
//
AfdMarkRequestCompleted (RequestCtx); AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
return FALSE; }
}
NTSTATUS AfdInitializeAddressList (VOID) /*++
Routine Description:
Register address handler routinges with TDI
Arguments: None
Return Value:
NTSTATUS -- Indicates whether registration succeded
--*/
{ NTSTATUS status; TDI_CLIENT_INTERFACE_INFO info; UNICODE_STRING afdName; PAGED_CODE ();
//
// Do basic initialization if we haven't done this before.
//
if (AfdAddressListLock == NULL) {
//
// Initialize spinlock that protects address change list.
//
AfdInitializeSpinLock(&AfdAddressChangeLock);
//
// Allocate and initialize resource that protects address list
//
AfdAddressListLock = AFD_ALLOCATE_POOL_PRIORITY( NonPagedPool, sizeof(*AfdAddressListLock), AFD_RESOURCE_POOL_TAG, HighPoolPriority );
if (AfdAddressListLock == NULL) return (STATUS_INSUFFICIENT_RESOURCES);
ExInitializeResourceLite(AfdAddressListLock);
//
// Initialize our lists
//
InitializeListHead(&AfdAddressEntryList); InitializeListHead(&AfdAddressChangeList);
}
if (AfdTdiPnPHandlerLock == NULL) {
AfdTdiPnPHandlerLock = AFD_ALLOCATE_POOL_PRIORITY( NonPagedPool, sizeof(*AfdTdiPnPHandlerLock), AFD_RESOURCE_POOL_TAG, HighPoolPriority );
if (AfdTdiPnPHandlerLock == NULL) return (STATUS_INSUFFICIENT_RESOURCES);
ExInitializeResourceLite(AfdTdiPnPHandlerLock);
}
//
// Setup the TDI request structure
//
RtlZeroMemory (&info, sizeof (info)); RtlInitUnicodeString(&afdName, L"AFD"); #ifdef TDI_CURRENT_VERSION
info.TdiVersion = TDI_CURRENT_VERSION; #else
info.MajorTdiVersion = 2; info.MinorTdiVersion = 0; #endif
info.Unused = 0; info.ClientName = &afdName; info.BindingHandler = NULL; info.AddAddressHandlerV2 = AfdAddAddressHandler; info.DelAddressHandlerV2 = AfdDelAddressHandler; info.PnPPowerHandler = AfdPnPPowerChange;
//
// Register handlers with TDI.
// Note, it should be safe to hold AfdResource while registering
// with TDI as it won't have any reason to callback into us.
// However, we need AfdTdiPnPHandlerLock to protect AfdBindingHandle
// between registering and deregistering as we can't hold AfdResource
// while deregistering handlers with TDI because it can callback
// into us and deadlock.
//
ExAcquireResourceExclusiveLite(AfdTdiPnPHandlerLock, TRUE); status = TdiRegisterPnPHandlers(&info, sizeof(info), &AfdBindingHandle); ExReleaseResourceLite(AfdTdiPnPHandlerLock);
if (!NT_SUCCESS (status)) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL, "AfdInitializeAddressList: Failed to register PnP handlers: %lx .\n", status)); return status; }
return STATUS_SUCCESS; }
VOID AfdDeregisterPnPHandlers ( PVOID Param ) {
UNREFERENCED_PARAMETER(Param); ASSERT(AfdAddressListLock == NULL || ExIsResourceAcquiredSharedLite(AfdAddressListLock) == 0 || ExIsResourceAcquiredExclusiveLite(AfdAddressListLock));
KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(AfdResource, TRUE);
//
// Free address list and associated structures
//
if (AfdBindingHandle) {
HANDLE bindingHandle; ASSERT(AfdTdiPnPHandlerLock != NULL); ExAcquireResourceExclusiveLite(AfdTdiPnPHandlerLock, TRUE);
bindingHandle = AfdBindingHandle; AfdBindingHandle = NULL;
ExReleaseResourceLite(AfdResource);
TdiDeregisterPnPHandlers(bindingHandle);
ExReleaseResourceLite(AfdTdiPnPHandlerLock);
//
// RACE CONDITION!
//
ExAcquireResourceExclusiveLite(AfdResource, TRUE); ASSERT(AfdAddressListLock != NULL); ExAcquireResourceExclusiveLite(AfdAddressListLock, TRUE);
while (!IsListEmpty(&AfdAddressEntryList)) {
PAFD_ADDRESS_ENTRY addressEntry; PLIST_ENTRY listEntry;
listEntry = RemoveHeadList(&AfdAddressEntryList); addressEntry = CONTAINING_RECORD( listEntry, AFD_ADDRESS_ENTRY, AddressListLink );
AFD_FREE_POOL( addressEntry, AFD_TRANSPORT_ADDRESS_POOL_TAG );
}
//
// Don't call if endpoint list is empty, since the driver
// may be paged out. There should be no-one to notify anyway
// if there are no sockets there.
//
if (!IsListEmpty (&AfdEndpointListHead)) { //
// Call routine to notify all the clients
//
ASSERT(!IsListEmpty(&AfdTransportInfoListHead)); ASSERT(AfdLoaded);
AfdProcessAddressChangeList(TDI_ADDRESS_TYPE_UNSPEC, NULL);
}
ExReleaseResourceLite(AfdAddressListLock);
}
ExReleaseResourceLite(AfdResource); KeLeaveCriticalRegion();
}
VOID AfdAddAddressHandler ( IN PTA_ADDRESS NetworkAddress, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context ) /*++
Routine Description:
TDI add address handler
Arguments: NetworkAddress - new network address available on the system
Context1 - name of the device to which address belongs
Context2 - PDO to which address belongs
Return Value:
None
--*/ { PAFD_ADDRESS_ENTRY addrEntry; PAGED_CODE ();
UNREFERENCED_PARAMETER (Context); //
// Clear the cached last removed PDO when we get address add notification
// since PDO can now be reused for something else.
//
AfdLastRemovedPdo = NULL;
if (DeviceName==NULL) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL, "AfdAddAddressHandler: " "NO DEVICE NAME SUPPLIED when adding address of type %d., IGNORING IT!!!\n", NetworkAddress->AddressType)); return; }
//
// Allocate memory to keep address in our list
// Note since the address information usually gets
// populated during boot and not used right away, we
// make it a "cold" allocation. The flag has no effect
// after system is booted.
//
addrEntry = AFD_ALLOCATE_POOL_PRIORITY (PagedPool|POOL_COLD_ALLOCATION, ALIGN_UP(FIELD_OFFSET (AFD_ADDRESS_ENTRY, Address.Address[NetworkAddress->AddressLength]), WCHAR) +DeviceName->MaximumLength, AFD_TRANSPORT_ADDRESS_POOL_TAG, HighPoolPriority);
if (addrEntry!=NULL) {
//
// Insert new address in the list
//
RtlCopyMemory (&addrEntry->Address, NetworkAddress, FIELD_OFFSET (TA_ADDRESS, Address[NetworkAddress->AddressLength]));
addrEntry->DeviceName.MaximumLength = DeviceName->MaximumLength; addrEntry->DeviceName.Buffer = ALIGN_UP_POINTER(&addrEntry->Address.Address[NetworkAddress->AddressLength], WCHAR); RtlCopyUnicodeString (&addrEntry->DeviceName, DeviceName);
//
// We shouldn't be calling into TDI while having resource
// acquired in shared mode because it can cause a deadloclk
// rigth here as TDI reenters us and we need to acquire the
// resource exclusive
//
ASSERT ( ExIsResourceAcquiredSharedLite ( AfdAddressListLock )==0 || ExIsResourceAcquiredExclusiveLite( AfdAddressListLock ));
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion ();
//
// Acquire AfdResource since we will be checking if there are endpoints in
// the list to decide whether to call non-pageable routine.
//
ExAcquireResourceSharedLite (AfdResource, TRUE); ExAcquireResourceExclusiveLite( AfdAddressListLock, TRUE );
InsertTailList (&AfdAddressEntryList, &addrEntry->AddressListLink);
//
// Don't call if endpoint list is empty, since the driver
// may be paged out. There should be no-one to notify anyway
// if there are no sockets there.
//
if (!IsListEmpty (&AfdEndpointListHead)) { //
// Call routine to notify all the clietns
//
ASSERT (!IsListEmpty (&AfdTransportInfoListHead)); ASSERT (AfdLoaded);
AfdProcessAddressChangeList (NetworkAddress->AddressType, DeviceName); }
ExReleaseResourceLite (AfdAddressListLock); ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion (); } else { //
// Failed allocation - queue work item to deregister PnP
// handlers and notify all apps.
// When apps come back will re-register and our list will
// get re-populated, or we'll fail the app's call(s);
//
AfdQueueWorkItem (&AfdDeregisterPnPHandlers, &AfdPnPDeregisterWorker); }
IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdAddAddressHandler: Type: %d, length: %d, device: %*ls .\n", NetworkAddress->AddressType, NetworkAddress->AddressLength, DeviceName->Length/2, DeviceName->Buffer)); } }
VOID AfdDelAddressHandler ( IN PTA_ADDRESS NetworkAddress, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context ) /*++
Routine Description:
TDI delete address handler
Arguments: NetworkAddress - network address that is no longer available on the system
Context1 - name of the device to which address belongs
Context2 - PDO to which address belongs
Return Value:
None
--*/ { PAFD_ADDRESS_ENTRY addrEntry; PLIST_ENTRY listEntry;
UNREFERENCED_PARAMETER (Context); PAGED_CODE ();
if (DeviceName==NULL) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL, "AfdDelAddressHandler: " "NO DEVICE NAME SUPPLIED when deleting address of type %d.\n", NetworkAddress->AddressType)); return; }
//
// We shouldn't be calling into TDI while having resource
// acquired in shared mode because it can cause a deadloclk
// rigth here as TDI reenters us and we need to acquire the
// resource exclusive
//
ASSERT ( ExIsResourceAcquiredSharedLite ( AfdAddressListLock )==0 || ExIsResourceAcquiredExclusiveLite( AfdAddressListLock )); //
// Find address in our list
//
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion (); //
// Acquire AfdResource since we will be checking if there are endpoints in
// the list to decide whether to call non-pageable routine.
//
ExAcquireResourceSharedLite (AfdResource, TRUE); ExAcquireResourceExclusiveLite( AfdAddressListLock, TRUE ); listEntry = AfdAddressEntryList.Flink; while (listEntry!=&AfdAddressEntryList) { addrEntry = CONTAINING_RECORD (listEntry, AFD_ADDRESS_ENTRY, AddressListLink); listEntry = listEntry->Flink; if (RtlEqualMemory (&addrEntry->Address, NetworkAddress, FIELD_OFFSET (TA_ADDRESS, Address[NetworkAddress->AddressLength])) && RtlEqualUnicodeString (&addrEntry->DeviceName, DeviceName, TRUE)) {
//
// Remove it and notify the clients
//
RemoveEntryList (&addrEntry->AddressListLink); //
// Don't call if endpoint list is empty, since the driver
// may be paged out. There should be no-one to notify anyway
// if there are no sockets there.
//
if (!IsListEmpty (&AfdEndpointListHead)) {
ASSERT (!IsListEmpty (&AfdTransportInfoListHead)); ASSERT (AfdLoaded);
AfdProcessAddressChangeList (NetworkAddress->AddressType, DeviceName); }
ExReleaseResourceLite (AfdAddressListLock); ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion (); AFD_FREE_POOL (addrEntry, AFD_TRANSPORT_ADDRESS_POOL_TAG); IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdDelAddressHandler: Type: %d, length: %d, device: %*ls .\n", NetworkAddress->AddressType, NetworkAddress->AddressLength, DeviceName->Length/2, DeviceName->Buffer)); } return; } } ExReleaseResourceLite (AfdAddressListLock); ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion (); ASSERT (!"AfdDelAddressHandler: Could not find matching entry"); }
VOID AfdProcessAddressChangeList ( USHORT AddressType, PUNICODE_STRING DeviceName ) /*++
Routine Description:
Notifuis all interested clients of address arrival/deletion
Arguments: AddressType - type of the address that arrived/ was deleted
DeviceName - name of the device to which address belongs
Return Value:
None
--*/ { AFD_LOCK_QUEUE_HANDLE lockHandle; PLIST_ENTRY listEntry; LIST_ENTRY completedChangeList; PAFD_ADDRESS_CHANGE change; PAFD_REQUEST_CONTEXT requestCtx; PIRP irp; PIO_STACK_LOCATION irpSp; PAFD_ENDPOINT endpoint; PAFD_TRANSPORT_INFO transportInfo;
// ASSERT ((AddressType!=TDI_ADDRESS_TYPE_NETBIOS) || (DeviceName!=NULL));
//
// Special check for Netbios addresses because
// we have separate protocols for each lana/device
//
transportInfo = NULL; if ((AddressType==TDI_ADDRESS_TYPE_NETBIOS) && (DeviceName!=NULL)) { BOOLEAN found = FALSE; for ( listEntry = AfdTransportInfoListHead.Flink; listEntry != &AfdTransportInfoListHead; listEntry = listEntry->Flink ) { transportInfo = CONTAINING_RECORD( listEntry, AFD_TRANSPORT_INFO, TransportInfoListEntry ); if (RtlEqualUnicodeString ( DeviceName, &transportInfo->TransportDeviceName, TRUE)) { found = TRUE; break; } } if (!found) return; }
//
// Create local list to process notifications after spinlock is released
//
InitializeListHead (&completedChangeList);
//
// Walk the list and move matching notifications to the local list
//
AfdAcquireSpinLock (&AfdAddressChangeLock, &lockHandle); listEntry = AfdAddressChangeList.Flink; while (listEntry!=&AfdAddressChangeList) { change = CONTAINING_RECORD (listEntry, AFD_ADDRESS_CHANGE, ChangeListLink); if (change->NonBlocking) { endpoint = change->Endpoint; requestCtx = &CONTAINING_RECORD (change, AFD_NBCHANGE_CONTEXT, Change)->Context; AFD_W4_INIT irp = NULL; ASSERT (requestCtx->Context==change); } else { irp = change->Irp; irpSp = IoGetCurrentIrpStackLocation (irp); requestCtx = (PAFD_REQUEST_CONTEXT)&irpSp->Parameters.DeviceIoControl; endpoint = irpSp->FileObject->FsContext; ASSERT (change==(PAFD_ADDRESS_CHANGE)irp->Tail.Overlay.DriverContext); }
listEntry = listEntry->Flink; if (((change->AddressType==AddressType) || (AddressType==TDI_ADDRESS_TYPE_UNSPEC)) //
// Special check for Netbios addresses because
// we have separate protocols for each lana/device
//
&& ((transportInfo==NULL) || (transportInfo==endpoint->TransportInfo)) ) { AFD_LOCK_QUEUE_HANDLE lockHandle2;
RemoveEntryList (&change->ChangeListLink); change->ChangeListLink.Flink = NULL; //
// If request is already canceled, let cancel routine complete it
//
if (!change->NonBlocking && IoSetCancelRoutine (irp, NULL)==NULL) { continue; }
AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle2); if (AfdIsRequestInQueue (requestCtx)) { //
// Context is still in the list, just remove it so
// no-one can see it anymore and complete
//
RemoveEntryList (&requestCtx->EndpointListLink); InsertTailList (&completedChangeList, &change->ChangeListLink); if (change->NonBlocking) { AfdIndicateEventSelectEvent (change->Endpoint, AFD_POLL_ADDRESS_LIST_CHANGE, STATUS_SUCCESS); } } else if (!AfdIsRequestCompleted (requestCtx)) { //
// During endpoint cleanup, this context was removed from the
// list and cleanup routine is about to be called, don't
// free this IRP until cleanup routine is called
// Also, indicate to the cleanup routine that we are done
// with this IRP and it can free it.
//
AfdMarkRequestCompleted (requestCtx); }
AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle2); } } AfdReleaseSpinLock (&AfdAddressChangeLock, &lockHandle);
//
// Signal interested clients and complete IRPs as necessary
//
while (!IsListEmpty (&completedChangeList)) { listEntry = RemoveHeadList (&completedChangeList); change = CONTAINING_RECORD (listEntry, AFD_ADDRESS_CHANGE, ChangeListLink); if (change->NonBlocking) { IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdProcessAddressChangeList: Signalling address list change on endpoint %p .\n", change->Endpoint)); } AfdIndicatePollEvent (change->Endpoint, AFD_POLL_ADDRESS_LIST_CHANGE, STATUS_SUCCESS); AFD_FREE_POOL (CONTAINING_RECORD (change, AFD_NBCHANGE_CONTEXT, Change), AFD_ADDRESS_CHANGE_POOL_TAG); } else { irp = change->Irp; irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = 0; IF_DEBUG (ADDRESS_LIST) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL, "AfdProcessAddressChangeList: Completing change IRP: %p with status: 0 .\n", irp)); } IoCompleteRequest (irp, AfdPriorityBoost); } } }
BOOLEAN AfdHasHeldPacketsFromNic ( PAFD_CONNECTION Connection, PVOID Pdo ) { PLIST_ENTRY le; //
// Scan the list of buffers and check with TDI/NDIS
// if packet belongs to a given card
//
if (!IsListEmpty( &Connection->VcReceiveBufferListHead ) ) { le = Connection->VcReceiveBufferListHead.Flink; while ( le!=&Connection->VcReceiveBufferListHead ) { PAFD_BUFFER afdBuffer; afdBuffer = CONTAINING_RECORD( le, AFD_BUFFER, BufferListEntry ); if ((afdBuffer->BufferLength==AfdBufferTagSize) && afdBuffer->NdisPacket && TdiMatchPdoWithChainedReceiveContext (afdBuffer->Context, Pdo)) { KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL, "AFD: Aborting connection %p due to held packet %p at power down on nic %p\n", Connection, afdBuffer->Context, Pdo)); return TRUE; } le = le->Flink; } } return FALSE; }
VOID AfdReturnNicsPackets ( PVOID Pdo ) { KIRQL oldIrql; AFD_LOCK_QUEUE_HANDLE lockHandle; PLIST_ENTRY listEntry, le; LIST_ENTRY connList;
//
// Don't scan twice for the same PDO if this event
// is less than 3 sec apart from previous.
// Several transports bound to the same NIC may indicate
// the set power event to us
//
if ((AfdLastRemovedPdo!=Pdo) || ((KeQueryInterruptTime()-AfdLastRemoveTime)>30000000i64)) {
//
// Scan the list of endpoints and find packets
// that belong to the NIC.
//
KeEnterCriticalRegion (); ExAcquireResourceExclusiveLite (AfdResource, TRUE);
if (!IsListEmpty (&AfdEndpointListHead)) { KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
listEntry = AfdEndpointListHead.Flink; while (listEntry!=&AfdEndpointListHead) { PAFD_CONNECTION connection; PAFD_ENDPOINT endpoint = CONTAINING_RECORD ( listEntry, AFD_ENDPOINT, GlobalEndpointListEntry); listEntry = listEntry->Flink; switch (endpoint->Type) { case AfdBlockTypeDatagram: //
// Afd currently does not support buffer
// ownership on datagram sockets.
//
// If such support is added, we will need to
// add code here to return all the buffers
// owned by the netcards.
//
break; case AfdBlockTypeVcConnecting: //
// Drop all of the connections that have unreturned packets.
//
AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle); connection = AFD_CONNECTION_FROM_ENDPOINT (endpoint); if (endpoint->State==AfdEndpointStateConnected && !IS_TDI_BUFFERRING(endpoint) && connection!=NULL && AfdHasHeldPacketsFromNic (connection, Pdo)) { REFERENCE_CONNECTION (connection); AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle); AfdBeginAbort (connection); AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle); //
// Make sure we do not have any buffered data
// (could have just checked for netcard owned
// buffers, but connection is going down anyway
// - save memory).
//
connection->VcBufferredReceiveBytes = 0; connection->VcBufferredReceiveCount = 0; connection->VcBufferredExpeditedBytes = 0; connection->VcBufferredExpeditedCount = 0; connection->VcReceiveBytesInTransport = 0; while ( !IsListEmpty( &connection->VcReceiveBufferListHead ) ) { PAFD_BUFFER_HEADER afdBuffer; le = RemoveHeadList( &connection->VcReceiveBufferListHead ); afdBuffer = CONTAINING_RECORD( le, AFD_BUFFER_HEADER, BufferListEntry );
DEBUG afdBuffer->BufferListEntry.Flink = NULL; if (afdBuffer->RefCount==1 || // Can't change once off the list
InterlockedDecrement (&afdBuffer->RefCount)==0) { afdBuffer->ExpeditedData = FALSE; AfdReturnBuffer( afdBuffer, connection->OwningProcess ); } } AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle); DEREFERENCE_CONNECTION (connection); } else { AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle); } break; case AfdBlockTypeVcBoth: case AfdBlockTypeVcListening: if (IS_TDI_BUFFERRING (endpoint)) break;
//
// Drop all unaccepted and/or returned connections that have
// unreturned packets.
//
InitializeListHead (&connList); AfdAcquireSpinLockAtDpcLevel (&endpoint->SpinLock, &lockHandle); le = endpoint->Common.VcListening.UnacceptedConnectionListHead.Flink; while ( le!=&endpoint->Common.VcListening.UnacceptedConnectionListHead ) { connection = CONTAINING_RECORD (le, AFD_CONNECTION, ListEntry); ASSERT( connection->Endpoint == endpoint ); le = le->Flink; if (AfdHasHeldPacketsFromNic (connection, Pdo)) { RemoveEntryList (&connection->ListEntry); InsertTailList (&connList, &connection->ListEntry); InterlockedIncrement (&endpoint->Common.VcListening.FailedConnectionAdds); } }
le = endpoint->Common.VcListening.ReturnedConnectionListHead.Flink; while ( le!=&endpoint->Common.VcListening.ReturnedConnectionListHead ) { connection = CONTAINING_RECORD (le, AFD_CONNECTION, ListEntry); ASSERT( connection->Endpoint == endpoint ); le = le->Flink; if (AfdHasHeldPacketsFromNic (connection, Pdo)) { RemoveEntryList (&connection->ListEntry); InsertTailList (&connList, &connection->ListEntry); InterlockedIncrement (&endpoint->Common.VcListening.FailedConnectionAdds); } } AfdReleaseSpinLockFromDpcLevel (&endpoint->SpinLock, &lockHandle); while (!IsListEmpty (&connList)) { le = RemoveHeadList (&connList); connection = CONTAINING_RECORD (le, AFD_CONNECTION, ListEntry); AfdAbortConnection( connection ); }
if ( endpoint->Common.VcListening.FailedConnectionAdds > 0 ) { AfdInitiateListenBacklogReplenish( endpoint ); } break; } } KeLowerIrql (oldIrql); }
ExReleaseResourceLite (AfdResource); KeLeaveCriticalRegion (); } AfdLastRemovedPdo = Pdo; AfdLastRemoveTime = KeQueryInterruptTime (); }
NTSTATUS AfdPnPPowerChange( IN PUNICODE_STRING DeviceName, IN PNET_PNP_EVENT PowerEvent, IN PTDI_PNP_CONTEXT Context1, IN PTDI_PNP_CONTEXT Context2 ) { UNREFERENCED_PARAMETER (DeviceName); PAGED_CODE (); switch (PowerEvent->NetEvent) { case NetEventSetPower: { NET_DEVICE_POWER_STATE powerState = *((PNET_DEVICE_POWER_STATE)PowerEvent->Buffer); ASSERT (PowerEvent->BufferLength>=sizeof (NET_DEVICE_POWER_STATE));
switch (powerState) { case NetDeviceStateD0: //
// Clear the cached last removed PDO when we get Power UP notification
// since PDO can now be reused for something else.
//
AfdLastRemovedPdo = NULL; goto DoNothing; default: ASSERTMSG ("NIC enters unknown power state", FALSE); case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: case NetDeviceStateUnspecified: //
// Break to execute PDO matching code
//
break; } break; } case NetEventQueryRemoveDevice: //
// Break to execute PDO matching code
//
break; case NetEventCancelRemoveDevice: //
// Clear the cached last removed PDO when we get Power UP notification
// since PDO can now be removed again.
//
AfdLastRemovedPdo = NULL; goto DoNothing; default: goto DoNothing; }
//
// When power is removed or device is disabled, we need to release all
// packets that we may own.
// We can only do this for transports that give us
// PDO, so NDIS can match the packet to the device.
// Note that PDO is usually the second context argument (first one is
// usually the device name), but we check the first one too since
// the TDI spec isn't crystal clear on this (it just says: for example TCP
// usually <does the above>).
//
if ((Context2!=NULL) && (Context2->ContextType==TDI_PNP_CONTEXT_TYPE_PDO) && (Context2->ContextSize==sizeof (PVOID)) ){ AfdReturnNicsPackets (*((PVOID UNALIGNED *)&Context2->ContextData)); } else if ((Context1!=NULL) && (Context1->ContextType==TDI_PNP_CONTEXT_TYPE_PDO) && (Context1->ContextSize==sizeof (PVOID)) ) { AfdReturnNicsPackets (*((PVOID UNALIGNED *)&Context1->ContextData)); }
DoNothing:
return STATUS_SUCCESS; }
|