/*++
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