diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/ip/ntirp.c | 1458 |
1 files changed, 1458 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/ip/ntirp.c b/private/ntos/tdi/tcpip/ip/ntirp.c new file mode 100644 index 000000000..3dd34565b --- /dev/null +++ b/private/ntos/tdi/tcpip/ip/ntirp.c @@ -0,0 +1,1458 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ntirp.c + +Abstract: + + NT specific routines for dispatching and handling IRPs. + +Author: + + Mike Massa (mikemas) Aug 13, 1993 + +Revision History: + + Who When What + -------- -------- ---------------------------------------------- + mikemas 08-13-93 created + +Notes: + +--*/ + +#include <oscfg.h> +#include <ndis.h> +#include <cxport.h> +#include <ip.h> +#include "ipdef.h" +#include "ipinit.h" +#include "icmp.h" +#include <ntddip.h> +#include <llipif.h> +#include <ipfilter.h> + + +// +// Local structures. +// +typedef struct pending_irp { + LIST_ENTRY Linkage; + PIRP Irp; + PFILE_OBJECT FileObject; + PVOID Context; +} PENDING_IRP, *PPENDING_IRP; + + +// +// Global variables +// +LIST_ENTRY PendingEchoList; +LIST_ENTRY PendingIPSetNTEAddrList; + + +// +// External prototypes +// +IP_STATUS +ICMPEchoRequest( + void *InputBuffer, + uint InputBufferLength, + EchoControl *ControlBlock, + EchoRtn Callback + ); + +ulong +ICMPEchoComplete( + EchoControl *ControlBlock, + IP_STATUS Status, + void *Data, + uint DataSize, + struct IPOptInfo *OptionInfo + ); + +IP_STATUS +IPSetNTEAddr( + uint Index, + IPAddr Addr, + IPMask Mask, + SetAddrControl *ControlBlock, + SetAddrRtn Callback + ); + +uint +IPAddDynamicNTE( + ushort InterfaceContext, + IPAddr NewAddr, + IPMask NewMask, + ushort *NTEContext, + ulong *NTEInstance + ); + +uint +IPDeleteDynamicNTE( + ushort NTEContext + ); + +uint +IPGetNTEInfo( + ushort NTEContext, + ulong *NTEInstance, + IPAddr *Address, + IPMask *SubnetMask, + ushort *NTEFlags + ); + +uint +SetDHCPNTE( + uint Context + ); + +// +// Local prototypes +// +NTSTATUS +IPDispatch ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +IPDispatchDeviceControl( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +NTSTATUS +IPDispatchInternalDeviceControl( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +NTSTATUS +IPCreate( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +NTSTATUS +IPCleanup( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +NTSTATUS +IPClose( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +NTSTATUS +DispatchEchoRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +void +CompleteEchoRequest( + void *Context, + IP_STATUS Status, + void *Data, + uint DataSize, + struct IPOptInfo *OptionInfo + ); + +NTSTATUS +DispatchIPSetNTEAddrRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ); + +void +CompleteIPSetNTEAddrRequest( + void *Context, + IP_STATUS Status + ); + + +#ifdef _PNP_POWER +extern IP_STATUS IPAddInterface(PNDIS_STRING ConfigName, void *PNPContext, void *Context, LLIPRegRtn RegRtn, LLIPBindInfo *BindInfo) ; +extern void IPDelInterface(void *Context) ; +#endif + + +// +// All of this code is pageable. +// +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, IPDispatch) +#pragma alloc_text(PAGE, IPDispatchDeviceControl) +#pragma alloc_text(PAGE, IPDispatchInternalDeviceControl) +#pragma alloc_text(PAGE, IPCreate) +#pragma alloc_text(PAGE, IPClose) +#pragma alloc_text(PAGE, DispatchEchoRequest) + +#endif // ALLOC_PRAGMA + + +// +// Dispatch function definitions +// +NTSTATUS +IPDispatch ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This is the dispatch routine for IP. + +Arguments: + + DeviceObject - Pointer to device object for target device + Irp - Pointer to I/O request packet + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + PIO_STACK_LOCATION irpSp; + NTSTATUS status; + + + UNREFERENCED_PARAMETER(DeviceObject); + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + switch (irpSp->MajorFunction) { + + case IRP_MJ_DEVICE_CONTROL: + return IPDispatchDeviceControl(Irp, irpSp); + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return IPDispatchDeviceControl(Irp, irpSp); + + case IRP_MJ_CREATE: + status = IPCreate(Irp, irpSp); + break; + + case IRP_MJ_CLEANUP: + status = IPCleanup(Irp, irpSp); + break; + + case IRP_MJ_CLOSE: + status = IPClose(Irp, irpSp); + break; + + default: + CTEPrint("IPDispatch: Invalid major function "); + CTEPrintNum(irpSp->MajorFunction ); + CTEPrintCRLF(); + status = STATUS_NOT_IMPLEMENTED; + break; + } + + Irp->IoStatus.Status = status; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return(status); + +} // IPDispatch + + +NTSTATUS +IPDispatchDeviceControl( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + NTSTATUS status; + ULONG code; + + + PAGED_CODE(); + + Irp->IoStatus.Information = 0; + + code = IrpSp->Parameters.DeviceIoControl.IoControlCode; + + switch(code) { + + case IOCTL_ICMP_ECHO_REQUEST: + return(DispatchEchoRequest(Irp, IrpSp)); + + case IOCTL_IP_SET_ADDRESS: + return(DispatchIPSetNTEAddrRequest(Irp, IrpSp)); + + case IOCTL_IP_ADD_NTE: + { + PIP_ADD_NTE_REQUEST request; + PIP_ADD_NTE_RESPONSE response; + BOOLEAN retval; + + + request = Irp->AssociatedIrp.SystemBuffer; + response = (PIP_ADD_NTE_RESPONSE) request; + + // + // Validate input parameters + // + if ( (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + sizeof(IP_ADD_NTE_REQUEST) + ) + && + (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(IP_ADD_NTE_RESPONSE)) + + ) + { + retval = IPAddDynamicNTE( + request->InterfaceContext, + request->Address, + request->SubnetMask, + &(response->Context), + &(response->Instance) + ); + + if (retval == FALSE) { + status = STATUS_UNSUCCESSFUL; + } + else { + Irp->IoStatus.Information = sizeof(IP_ADD_NTE_RESPONSE); + status = STATUS_SUCCESS; + } + } + else { + status = STATUS_INVALID_PARAMETER; + } + } + break; + + case IOCTL_IP_DELETE_NTE: + { + PIP_DELETE_NTE_REQUEST request; + BOOLEAN retval; + + + request = Irp->AssociatedIrp.SystemBuffer; + + // + // Validate input parameters + // + if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + sizeof(IP_DELETE_NTE_REQUEST) + ) + { + retval = IPDeleteDynamicNTE( + request->Context + ); + + if (retval == FALSE) { + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + } + else { + status = STATUS_INVALID_PARAMETER; + } + } + break; + + case IOCTL_IP_GET_NTE_INFO: + { + PIP_GET_NTE_INFO_REQUEST request; + PIP_GET_NTE_INFO_RESPONSE response; + BOOLEAN retval; + ushort nteFlags; + + + request = Irp->AssociatedIrp.SystemBuffer; + response = (PIP_GET_NTE_INFO_RESPONSE) request; + + // + // Validate input parameters + // + if ( (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + sizeof(IP_GET_NTE_INFO_REQUEST) + ) + && + (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= + sizeof(IP_GET_NTE_INFO_RESPONSE)) + + ) + { + retval = IPGetNTEInfo( + request->Context, + &(response->Instance), + &(response->Address), + &(response->SubnetMask), + &nteFlags + ); + + if (retval == FALSE) { + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + Irp->IoStatus.Information = + sizeof(IP_GET_NTE_INFO_RESPONSE); + response->Flags = 0; + + if (nteFlags & NTE_DYNAMIC) { + response->Flags |= IP_NTE_DYNAMIC; + } + } + } + else { + status = STATUS_INVALID_PARAMETER; + } + } + break; + + case IOCTL_IP_SET_DHCP_INTERFACE: + { + PIP_SET_DHCP_INTERFACE_REQUEST request; + BOOLEAN retval; + + request = Irp->AssociatedIrp.SystemBuffer; + retval = SetDHCPNTE( + request->Context + ); + + if (retval == FALSE) { + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + } + break; + + case IOCTL_IP_SET_IF_CONTEXT: + { + PIP_SET_IF_CONTEXT_INFO info; + + + info = Irp->AssociatedIrp.SystemBuffer; + status = (NTSTATUS) SetIFContext(info->Index, info->Context); + + if (status != IP_SUCCESS) { + ASSERT(status != IP_PENDING); + // + // Map status + // + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + } + break; + + case IOCTL_IP_SET_FILTER_POINTER: + { + PIP_SET_FILTER_HOOK_INFO info; + + if (Irp->RequestorMode != KernelMode) { + status = STATUS_ACCESS_DENIED; + break; + } + + info = Irp->AssociatedIrp.SystemBuffer; + status = (NTSTATUS) SetFilterPtr(info->FilterPtr); + + if (status != IP_SUCCESS) { + ASSERT(status != IP_PENDING); + // + // Map status + // + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + } + break; + + case IOCTL_IP_SET_MAP_ROUTE_POINTER: + { + PIP_SET_MAP_ROUTE_HOOK_INFO info; + + if (Irp->RequestorMode != KernelMode) { + status = STATUS_ACCESS_DENIED; + break; + } + + info = Irp->AssociatedIrp.SystemBuffer; + status = (NTSTATUS) SetMapRoutePtr(info->MapRoutePtr); + + if (status != IP_SUCCESS) { + ASSERT(status != IP_PENDING); + // + // Map status + // + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + } + break; + +#ifdef _PNP_POWER + + case IOCTL_IP_GET_PNP_ARP_POINTERS: + { + PIP_GET_PNP_ARP_POINTERS info = (PIP_GET_PNP_ARP_POINTERS) Irp->AssociatedIrp.SystemBuffer; + + if (Irp->RequestorMode != KernelMode) { + status = STATUS_ACCESS_DENIED; + break; + } + + info->IPAddInterface = (IPAddInterfacePtr)IPAddInterface ; + info->IPDelInterface = (IPDelInterfacePtr)IPDelInterface ; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(IP_GET_PNP_ARP_POINTERS); + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + return STATUS_SUCCESS;; + + } + break; +#endif + + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (status != IP_PENDING) { + Irp->IoStatus.Status = status; + // Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + return status; + +} // IPDispatchDeviceControl + +NTSTATUS +IPDispatchInternalDeviceControl( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + NTSTATUS status; + + + PAGED_CODE(); + + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return status; + +} // IPDispatchDeviceControl + + +NTSTATUS +IPCreate( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + PAGED_CODE(); + + return(STATUS_SUCCESS); + +} // IPCreate + + +NTSTATUS +IPCleanup( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + PPENDING_IRP pendingIrp; + PLIST_ENTRY entry, nextEntry; + KIRQL oldIrql; + LIST_ENTRY completeList; + PIRP cancelledIrp; + + + InitializeListHead(&completeList); + + // + // Collect all of the pending IRPs on this file object. + // + IoAcquireCancelSpinLock(&oldIrql); + + entry = PendingEchoList.Flink; + + while ( entry != &PendingEchoList ) { + pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + + if (pendingIrp->FileObject == IrpSp->FileObject) { + nextEntry = entry->Flink; + RemoveEntryList(entry); + IoSetCancelRoutine(pendingIrp->Irp, NULL); + InsertTailList(&completeList, &(pendingIrp->Linkage)); + entry = nextEntry; + } + else { + entry = entry->Flink; + } + } + + IoReleaseCancelSpinLock(oldIrql); + + // + // Complete them. + // + entry = completeList.Flink; + + while ( entry != &completeList ) { + pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + cancelledIrp = pendingIrp->Irp; + entry = entry->Flink; + + // + // Free the PENDING_IRP structure. The control block will be freed + // when the request completes. + // + CTEFreeMem(pendingIrp); + + // + // Complete the IRP. + // + cancelledIrp->IoStatus.Information = 0; + cancelledIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT); + } + + InitializeListHead(&completeList); + + // + // Collect all of the pending IRPs on this file object. + // + IoAcquireCancelSpinLock(&oldIrql); + + entry = PendingIPSetNTEAddrList.Flink; + + while ( entry != &PendingIPSetNTEAddrList ) { + pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + + if (pendingIrp->FileObject == IrpSp->FileObject) { + nextEntry = entry->Flink; + RemoveEntryList(entry); + IoSetCancelRoutine(pendingIrp->Irp, NULL); + InsertTailList(&completeList, &(pendingIrp->Linkage)); + entry = nextEntry; + } + else { + entry = entry->Flink; + } + } + + IoReleaseCancelSpinLock(oldIrql); + + // + // Complete them. + // + entry = completeList.Flink; + + while ( entry != &completeList ) { + pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + cancelledIrp = pendingIrp->Irp; + entry = entry->Flink; + + // + // Free the PENDING_IRP structure. The control block will be freed + // when the request completes. + // + CTEFreeMem(pendingIrp); + + // + // Complete the IRP. + // + cancelledIrp->IoStatus.Information = 0; + cancelledIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT); + } + + return(STATUS_SUCCESS); + +} // IPCleanup + + +NTSTATUS +IPClose( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether the request was successfully queued. + +--*/ + +{ + PAGED_CODE(); + + return(STATUS_SUCCESS); + +} // IPClose + + +// +// ICMP Echo function definitions +// +VOID +CancelEchoRequest( + IN PDEVICE_OBJECT Device, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + Cancels an outstanding Echo request Irp. + +Arguments: + + Device - The device on which the request was issued. + Irp - Pointer to I/O request packet to cancel. + +Return Value: + + None. + +Notes: + + This function is called with cancel spinlock held. It must be + released before the function returns. + + The echo control block associated with this request cannot be + freed until the request completes. The completion routine will + free it. + +--*/ + +{ + PPENDING_IRP pendingIrp = NULL; + PPENDING_IRP item; + PLIST_ENTRY entry; + + + for ( entry = PendingEchoList.Flink; + entry != &PendingEchoList; + entry = entry->Flink + ) { + item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + if (item->Irp == Irp) { + pendingIrp = item; + RemoveEntryList(entry); + IoSetCancelRoutine(pendingIrp->Irp, NULL); + break; + } + } + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + if (pendingIrp != NULL) { + // + // Free the PENDING_IRP structure. The control block will be freed + // when the request completes. + // + CTEFreeMem(pendingIrp); + + // + // Complete the IRP. + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + + return; + +} // CancelEchoRequest + +// +// IP Set Addr function definitions +// +VOID +CancelIPSetNTEAddrRequest( + IN PDEVICE_OBJECT Device, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + Cancels an outstanding IP Set Addr request Irp. + +Arguments: + + Device - The device on which the request was issued. + Irp - Pointer to I/O request packet to cancel. + +Return Value: + + None. + +Notes: + + This function is called with cancel spinlock held. It must be + released before the function returns. + + The IP Set Addr control block associated with this request cannot be + freed until the request completes. The completion routine will + free it. + +--*/ + +{ + PPENDING_IRP pendingIrp = NULL; + PPENDING_IRP item; + PLIST_ENTRY entry; + + + for ( entry = PendingIPSetNTEAddrList.Flink; + entry != &PendingIPSetNTEAddrList; + entry = entry->Flink + ) { + item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + if (item->Irp == Irp) { + pendingIrp = item; + RemoveEntryList(entry); + IoSetCancelRoutine(pendingIrp->Irp, NULL); + break; + } + } + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + if (pendingIrp != NULL) { + // + // Free the PENDING_IRP structure. The control block will be freed + // when the request completes. + // + CTEFreeMem(pendingIrp); + + // + // Complete the IRP. + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + + return; + +} // CancelIPSetNTEAddrRequest + + +void +CompleteEchoRequest( + void *Context, + IP_STATUS Status, + void *Data, OPTIONAL + uint DataSize, + struct IPOptInfo *OptionInfo OPTIONAL + ) + +/*++ + +Routine Description: + + Handles the completion of an ICMP Echo request + +Arguments: + + Context - Pointer to the EchoControl structure for this request. + Status - The IP status of the transmission. + Data - A pointer to data returned in the echo reply. + DataSize - The length of the returned data. + OptionInfo - A pointer to the IP options in the echo reply. + +Return Value: + + None. + +--*/ + +{ + KIRQL oldIrql; + PIRP irp; + PIO_STACK_LOCATION irpSp; + EchoControl *controlBlock; + PPENDING_IRP pendingIrp = NULL; + PPENDING_IRP item; + PLIST_ENTRY entry; + ULONG bytesReturned; + + + controlBlock = (EchoControl *) Context; + + // + // Find the echo request IRP on the pending list. + // + IoAcquireCancelSpinLock(&oldIrql); + + for ( entry = PendingEchoList.Flink; + entry != &PendingEchoList; + entry = entry->Flink + ) { + item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + if (item->Context == controlBlock) { + pendingIrp = item; + irp = pendingIrp->Irp; + IoSetCancelRoutine(irp, NULL); + RemoveEntryList(entry); + break; + } + } + + IoReleaseCancelSpinLock(oldIrql); + + if (pendingIrp == NULL) { + // + // IRP must have been cancelled. PENDING_IRP struct + // was freed by cancel routine. Free control block. + // + CTEFreeMem(controlBlock); + return; + } + + irpSp = IoGetCurrentIrpStackLocation(irp); + + bytesReturned = ICMPEchoComplete( + controlBlock, + Status, + Data, + DataSize, + OptionInfo + ); + + CTEFreeMem(pendingIrp); + CTEFreeMem(controlBlock); + + // + // Complete the IRP. + // + irp->IoStatus.Information = (ULONG) bytesReturned; + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NETWORK_INCREMENT); + return; + +} // CompleteEchoRequest + +void +CompleteIPSetNTEAddrRequest( + void *Context, + IP_STATUS Status + ) + +/*++ + +Routine Description: + + Handles the completion of an IP Set Addr request + +Arguments: + + Context - Pointer to the SetAddrControl structure for this request. + Status - The IP status of the transmission. + +Return Value: + + None. + +--*/ + +{ + KIRQL oldIrql; + PIRP irp; + PIO_STACK_LOCATION irpSp; + SetAddrControl *controlBlock; + PPENDING_IRP pendingIrp = NULL; + PPENDING_IRP item; + PLIST_ENTRY entry; + ULONG bytesReturned; + + + controlBlock = (SetAddrControl *) Context; + + // + // Find the echo request IRP on the pending list. + // + IoAcquireCancelSpinLock(&oldIrql); + + for ( entry = PendingIPSetNTEAddrList.Flink; + entry != &PendingIPSetNTEAddrList; + entry = entry->Flink + ) { + item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage); + if (item->Context == controlBlock) { + pendingIrp = item; + irp = pendingIrp->Irp; + IoSetCancelRoutine(irp, NULL); + RemoveEntryList(entry); + break; + } + } + + IoReleaseCancelSpinLock(oldIrql); + + if (pendingIrp == NULL) { + // + // IRP must have been cancelled. PENDING_IRP struct + // was freed by cancel routine. Free control block. + // + CTEFreeMem(controlBlock); + return; + } + + CTEFreeMem(pendingIrp); + CTEFreeMem(controlBlock); + + // + // Complete the IRP. + // + irp->IoStatus.Information = 0; + if (Status == IP_SUCCESS) { + irp->IoStatus.Status = STATUS_SUCCESS; + } else { + irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + } + IoCompleteRequest(irp, IO_NETWORK_INCREMENT); + return; + +} // CompleteIPSetNTEAddrRequest + + +BOOLEAN +PrepareEchoIrpForCancel( + PIRP Irp, + PPENDING_IRP PendingIrp + ) +/*++ + +Routine Description: + + Prepares an Echo IRP for cancellation. + +Arguments: + + Irp - Pointer to I/O request packet to initialize for cancellation. + PendingIrp - Pointer to the PENDING_IRP structure for this IRP. + +Return Value: + + TRUE if the IRP was cancelled before this routine was called. + FALSE otherwise. + +--*/ + +{ + BOOLEAN cancelled = TRUE; + KIRQL oldIrql; + + + IoAcquireCancelSpinLock(&oldIrql); + + ASSERT(Irp->CancelRoutine == NULL); + + if (!Irp->Cancel) { + IoSetCancelRoutine(Irp, CancelEchoRequest); + InsertTailList(&PendingEchoList, &(PendingIrp->Linkage)); + cancelled = FALSE; + } + + IoReleaseCancelSpinLock(oldIrql); + + return(cancelled); + +} // PrepareEchoIrpForCancel + +BOOLEAN +PrepareIPSetNTEAddrIrpForCancel( + PIRP Irp, + PPENDING_IRP PendingIrp + ) +/*++ + +Routine Description: + + Prepares an IPSetNTEAddr IRP for cancellation. + +Arguments: + + Irp - Pointer to I/O request packet to initialize for cancellation. + PendingIrp - Pointer to the PENDING_IRP structure for this IRP. + +Return Value: + + TRUE if the IRP was cancelled before this routine was called. + FALSE otherwise. + +--*/ + +{ + BOOLEAN cancelled = TRUE; + KIRQL oldIrql; + + + IoAcquireCancelSpinLock(&oldIrql); + + ASSERT(Irp->CancelRoutine == NULL); + + if (!Irp->Cancel) { + IoSetCancelRoutine(Irp, CancelIPSetNTEAddrRequest); + InsertTailList(&PendingIPSetNTEAddrList, &(PendingIrp->Linkage)); + cancelled = FALSE; + } + + IoReleaseCancelSpinLock(oldIrql); + + return(cancelled); + +} // PrepareIPSetNTEAddrIrpForCancel + + +NTSTATUS +DispatchEchoRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + Processes an ICMP request. + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether NT-specific processing of the request was + successful. The status of the actual request is returned in + the request buffers. + +--*/ + +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + IP_STATUS ipStatus; + PPENDING_IRP pendingIrp; + EchoControl *controlBlock; + PICMP_ECHO_REPLY replyBuffer; + BOOLEAN cancelled; + + + PAGED_CODE(); + + pendingIrp = CTEAllocMem(sizeof(PENDING_IRP)); + + if (pendingIrp == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto echo_error; + } + + controlBlock = CTEAllocMem(sizeof(EchoControl)); + + if (controlBlock == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + CTEFreeMem(pendingIrp); + goto echo_error; + } + + pendingIrp->Irp = Irp; + pendingIrp->FileObject = IrpSp->FileObject; + pendingIrp->Context = controlBlock; + + controlBlock->ec_starttime = CTESystemUpTime(); + controlBlock->ec_replybuf = Irp->AssociatedIrp.SystemBuffer; + controlBlock->ec_replybuflen = + IrpSp->Parameters.DeviceIoControl.InputBufferLength; + + IoMarkIrpPending(Irp); + + cancelled = PrepareEchoIrpForCancel(Irp, pendingIrp); + + if (!cancelled) { + ipStatus = ICMPEchoRequest( + Irp->AssociatedIrp.SystemBuffer, // request buf + IrpSp->Parameters.DeviceIoControl.InputBufferLength, // request len + controlBlock, // echo ctrl + CompleteEchoRequest // cmplt rtn + ); + + if (ipStatus == IP_PENDING) { + ntStatus = STATUS_PENDING; + } + else { + ASSERT(ipStatus != IP_SUCCESS); + + // + // An internal error of some kind occurred. Complete the + // request. + // + CompleteEchoRequest( + controlBlock, + ipStatus, + NULL, + 0, + NULL + ); + + // + // The NT ioctl was successful, even if the request failed. The + // request status was passed back in the first reply block. + // + ntStatus = STATUS_SUCCESS; + } + + return(ntStatus); + } + + // + // Irp has already been cancelled. + // + ntStatus = STATUS_CANCELLED; + CTEFreeMem(pendingIrp); + CTEFreeMem(controlBlock); + + +echo_error: + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return(ntStatus); + +} // DispatchEchoRequest + + +NTSTATUS +DispatchIPSetNTEAddrRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +/*++ + +Routine Description: + + Processes an IP Set Addr request. + +Arguments: + + Irp - Pointer to I/O request packet + IrpSp - Pointer to the current stack location in the Irp. + +Return Value: + + NTSTATUS -- Indicates whether NT-specific processing of the request was + successful. The status of the actual request is returned in + the request buffers. + +--*/ + +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + IP_STATUS ipStatus; + PPENDING_IRP pendingIrp; + SetAddrControl *controlBlock; + BOOLEAN cancelled; + + + PAGED_CODE(); + + pendingIrp = CTEAllocMem(sizeof(PENDING_IRP)); + + if (pendingIrp == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto setnteaddr_error; + } + + controlBlock = CTEAllocMem(sizeof(SetAddrControl)); + + if (controlBlock == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + CTEFreeMem(pendingIrp); + goto setnteaddr_error; + } + + pendingIrp->Irp = Irp; + pendingIrp->FileObject = IrpSp->FileObject; + pendingIrp->Context = controlBlock; + + IoMarkIrpPending(Irp); + + cancelled = PrepareIPSetNTEAddrIrpForCancel(Irp, pendingIrp); + + if (!cancelled) { + + PIP_SET_ADDRESS_REQUEST request; + + request = Irp->AssociatedIrp.SystemBuffer; + ipStatus = IPSetNTEAddr( + request->Context, + request->Address, + request->SubnetMask, + controlBlock, + CompleteIPSetNTEAddrRequest + ); + + if (ipStatus == IP_PENDING) { + ntStatus = STATUS_PENDING; + } + else { + + // + // A request completed which did not pend. + // + CompleteIPSetNTEAddrRequest( + controlBlock, + ipStatus + ); + + // + // The NT ioctl was successful, even if the request failed. The + // request status was passed back in the first reply block. + // + ntStatus = STATUS_SUCCESS; + } + + return(ntStatus); + } + + // + // Irp has already been cancelled. + // + ntStatus = STATUS_CANCELLED; + CTEFreeMem(pendingIrp); + CTEFreeMem(controlBlock); + + +setnteaddr_error: + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return(ntStatus); + +} // DispatchIPSetNTEAddrRequest |