windows-nt/Source/XPSP1/NT/net/tcpip/driver/ipv4/ntirp.c

2837 lines
74 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991-2000 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 "precomp.h"
#include "iproute.h"
#include "icmp.h"
#include "arpdef.h"
#include "info.h"
#include "ipstatus.h"
#include "tcpipbuf.h"
//
// Local structures.
//
typedef struct pending_irp {
LIST_ENTRY Linkage;
PIRP Irp;
PFILE_OBJECT FileObject;
PVOID Context;
} PENDING_IRP, *PPENDING_IRP;
DEFINE_LOCK_STRUCTURE(AddChangeLock)
DEFINE_LOCK_STRUCTURE(ClientNotifyLock)
//
// Global variables
//
LIST_ENTRY PendingEchoList;
LIST_ENTRY PendingIPSetNTEAddrList;
PIRP PendingIPGetIPEventRequest;
LIST_ENTRY PendingEnableRouterList;
LIST_ENTRY PendingMediaSenseRequestList;
LIST_ENTRY PendingArpSendList;
IP_STATUS ARPResolve(IPAddr DestAddress, IPAddr SourceAddress,
ARPControlBlock * ControlBlock, ArpRtn Callback);
VOID CompleteArpResolveRequest(void *ControlBlock, IP_STATUS ipstatus);
extern Interface *IFList;
//
// External prototypes
//
IP_STATUS ICMPEchoRequest(void *InputBuffer, uint InputBufferLength,
EchoControl * ControlBlock, EchoRtn Callback);
ulong ICMPEchoComplete(EchoControl * ControlBlock, IP_STATUS Status,
void *Data, uint DataSize, IPOptInfo *OptionInfo);
#if defined(_WIN64)
ulong ICMPEchoComplete32(EchoControl * ControlBlock, IP_STATUS Status,
void *Data, uint DataSize, IPOptInfo *OptionInfo);
#endif // _WIN64
IP_STATUS IPSetNTEAddrEx(uint Index, IPAddr Addr, IPMask Mask,
SetAddrControl * ControlBlock, SetAddrRtn Callback, USHORT Type);
IP_STATUS IPAddDynamicNTE(ulong InterfaceContext, PUNICODE_STRING InterfaceName,
int InterfaceNameLen, IPAddr NewAddr, IPMask NewMask,
ushort * NTEContext, ulong * NTEInstance);
IP_STATUS IPDeleteDynamicNTE(ushort NTEContext);
uint IPGetNTEInfo(ushort NTEContext, ulong * NTEInstance, IPAddr * Address,
IPMask * SubnetMask, ushort * NTEFlags);
uint SetDHCPNTE(uint Context);
NTSTATUS SetIFPromiscuous(ULONG Index, UCHAR Type, UCHAR Add);
extern void NotifyAddrChange(IPAddr Addr, IPMask Mask, void *Context,
ushort IPContext, PVOID * Handle,
PNDIS_STRING ConfigName, PNDIS_STRING IFName,
uint Added);
extern NTSTATUS IPStatusToNTStatus(IP_STATUS ipStatus);
extern int IPEnableRouterRefCount;
extern int IPEnableRouterWithRefCount(LOGICAL Enable);
extern NTSTATUS IPGetCapability(ULONG Context, PULONG buf, uint cap);
extern int IPEnableMediaSense(LOGICAL Enable, KIRQL *irql);
extern uint DisableMediaSense;
NTSTATUS FlushArpTable(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
//
// 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);
NTSTATUS DispatchARPRequest(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
NTSTATUS RtChangeNotifyRequest(PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
NTSTATUS RtChangeNotifyRequestEx(PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
NTSTATUS AddrChangeNotifyRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp);
#if MILLEN
NTSTATUS IfChangeNotifyRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp);
#endif // MILLEN
NTSTATUS IPEnableRouterRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS IPUnenableRouterRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp,
PVOID ApcContext);
VOID CancelIPEnableRouterRequest(IN PDEVICE_OBJECT Device, IN PIRP Irp);
NTSTATUS IPGetBestInterfaceIndex(IN IPAddr Address, OUT PULONG pIndex,
OUT PULONG pMetric);
extern NTSTATUS GetBestInterfaceId(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
extern NTSTATUS IPGetBestInterface(IN IPAddr Address, OUT PVOID * ppIF);
extern NTSTATUS GetInterfaceInfo(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
extern NTSTATUS GetIgmpList(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
extern NTSTATUS DispatchIPSetBlockofRoutes(IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp);
extern NTSTATUS DispatchIPSetRouteWithRef(IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp);
extern NTSTATUS DispatchIPSetMultihopRoute(IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp);
void CompleteEchoRequest(void *Context, IP_STATUS Status, void *Data,
uint DataSize, IPOptInfo *OptionInfo);
NTSTATUS DispatchIPSetNTEAddrRequest(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
void CompleteIPSetNTEAddrRequest(void *Context, IP_STATUS Status);
NTSTATUS IPGetIfIndex(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp);
NTSTATUS IPGetIfName(IN PIRP pIrp, IN PIO_STACK_LOCATION pIrpSp);
NTSTATUS DispatchIPGetIPEvent(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
NTSTATUS IPGetMcastCounters(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
NTSTATUS
IPEnableMediaSenseRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS
IPDisableMediaSenseRequest(PIRP Irp, PIO_STACK_LOCATION IrpSp );
VOID
CancelIPEnableMediaSenseRequest(IN PDEVICE_OBJECT Device, IN PIRP Irp);
//
// All of this code is pageable.
//
#if !MILLEN
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, IPDispatch)
#pragma alloc_text(PAGE, IPDispatchInternalDeviceControl)
#pragma alloc_text(PAGE, IPCreate)
#pragma alloc_text(PAGE, IPClose)
#pragma alloc_text(PAGE, DispatchEchoRequest)
#pragma alloc_text(PAGE, DispatchARPRequest)
#endif // ALLOC_PRAGMA
#endif // !MILLEN
//
// 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);
DEBUGMSG(DBG_TRACE && DBG_IP && DBG_VERBOSE,
(DTEXT("+IPDispatch(%x, %x) MajorFunction %x\n"),
DeviceObject, Irp, irpSp->MajorFunction));
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:
DEBUGMSG(DBG_ERROR,
(DTEXT("IPDispatch: Invalid major function. IRP %x MajorFunc %x\n"),
Irp, irpSp->MajorFunction));
status = STATUS_NOT_IMPLEMENTED;
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
DEBUGMSG(DBG_TRACE && DBG_IP && DBG_VERBOSE, (DTEXT("-IPDispatch [%x]\n"), status));
return (status);
}
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;
Irp->IoStatus.Information = 0;
code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
DEBUGMSG(DBG_TRACE && DBG_IP,
(DTEXT("+IPDispatchDeviceControl(%x, %x) IoControlCode %x\n"),
Irp, IrpSp, code));
switch (code) {
case IOCTL_ICMP_ECHO_REQUEST:
return (DispatchEchoRequest(Irp, IrpSp));
case IOCTL_ARP_SEND_REQUEST:
return (DispatchARPRequest(Irp, IrpSp));
case IOCTL_IP_INTERFACE_INFO:
return (GetInterfaceInfo(Irp, IrpSp));
case IOCTL_IP_GET_IGMPLIST:
return (GetIgmpList(Irp, IrpSp));
case IOCTL_IP_GET_BEST_INTERFACE:
return (GetBestInterfaceId(Irp, IrpSp));
case IOCTL_IP_SET_ADDRESS:
case IOCTL_IP_SET_ADDRESS_DUP:
case IOCTL_IP_SET_ADDRESS_EX:
return (DispatchIPSetNTEAddrRequest(Irp, IrpSp));
case IOCTL_IP_SET_BLOCKOFROUTES:
return (DispatchIPSetBlockofRoutes(Irp, IrpSp));
case IOCTL_IP_SET_ROUTEWITHREF:
return (DispatchIPSetRouteWithRef(Irp, IrpSp));
case IOCTL_IP_SET_MULTIHOPROUTE:
return (DispatchIPSetMultihopRoute(Irp, IrpSp));
case IOCTL_IP_ADD_NTE:
{
PIP_ADD_NTE_REQUEST request;
PIP_ADD_NTE_RESPONSE response;
IP_STATUS ipStatus;
int InterfaceNameLen;
UNICODE_STRING InterfaceName;
BOOLEAN requestValid = FALSE;
request = Irp->AssociatedIrp.SystemBuffer;
response = (PIP_ADD_NTE_RESPONSE) request;
//
// Validate input parameters
//
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(IP_ADD_NTE_REQUEST_OLD)) &&
(IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
sizeof(IP_ADD_NTE_RESPONSE))) {
#if defined(_WIN64)
PIP_ADD_NTE_REQUEST32 request32;
if (IoIs32bitProcess(Irp)) {
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(IP_ADD_NTE_REQUEST32)) {
requestValid = TRUE;
request32 = Irp->AssociatedIrp.SystemBuffer;
InterfaceName.Length = request32->InterfaceName.Length;
InterfaceName.MaximumLength =
request32->InterfaceName.MaximumLength;
InterfaceName.Buffer =
(PWCHAR)request32->InterfaceNameBuffer;
InterfaceNameLen =
IrpSp->Parameters.DeviceIoControl.InputBufferLength
- FIELD_OFFSET(IP_ADD_NTE_REQUEST32,
InterfaceNameBuffer);
}
} else {
#endif // _WIN64
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(IP_ADD_NTE_REQUEST)) {
requestValid = TRUE;
InterfaceName = request->InterfaceName;
InterfaceName.Buffer = (PWCHAR)request->InterfaceNameBuffer;
InterfaceNameLen =
IrpSp->Parameters.DeviceIoControl.InputBufferLength -
FIELD_OFFSET(IP_ADD_NTE_REQUEST, InterfaceNameBuffer);
}
#if defined(_WIN64)
}
#endif // _WIN64
if (requestValid) {
ipStatus = IPAddDynamicNTE(
request->InterfaceContext,
&InterfaceName,
InterfaceNameLen,
request->Address,
request->SubnetMask,
&(response->Context),
&(response->Instance)
);
} else {
ipStatus = IPAddDynamicNTE(
request->InterfaceContext,
NULL,
0,
request->Address,
request->SubnetMask,
&(response->Context),
&(response->Instance)
);
}
status = IPStatusToNTStatus(ipStatus);
if (status == STATUS_SUCCESS) {
Irp->IoStatus.Information = sizeof(IP_ADD_NTE_RESPONSE);
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_IP_DELETE_NTE:
{
PIP_DELETE_NTE_REQUEST request;
IP_STATUS ipStatus;
request = Irp->AssociatedIrp.SystemBuffer;
//
// Validate input parameters
//
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(IP_DELETE_NTE_REQUEST)
) {
ipStatus = IPDeleteDynamicNTE(
request->Context
);
status = IPStatusToNTStatus(ipStatus);
} 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 = (BOOLEAN) 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;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_DHCP_INTERFACE_REQUEST)) {
retval = (BOOLEAN) SetDHCPNTE(
request->Context
);
if (retval == FALSE) {
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_IP_SET_IF_CONTEXT:
{
status = STATUS_NOT_SUPPORTED;
}
break;
case IOCTL_IP_SET_IF_PROMISCUOUS:
{
PIP_SET_IF_PROMISCUOUS_INFO info;
info = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_IF_PROMISCUOUS_INFO)) {
status = SetIFPromiscuous(info->Index,
info->Type,
info->Add);
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
break;
}
case IOCTL_IP_GET_BESTINTFC_FUNC_ADDR:
if (Irp->RequestorMode != KernelMode) {
status = STATUS_ACCESS_DENIED;
break;
}
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL, "ip:Getbestinterfacequery\n"));
status = STATUS_INVALID_PARAMETER;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ulong)) {
PULONG_PTR ptr;
ptr = Irp->AssociatedIrp.SystemBuffer;
if (ptr) {
*ptr = (ULONG_PTR) IPGetBestInterfaceIndex;
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL, "ip:returning address of Getbestinterface %x\n", *ptr));
Irp->IoStatus.Information = sizeof(ULONG_PTR);
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;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_FILTER_HOOK_INFO)) {
status = (NTSTATUS) SetFilterPtr(info->FilterPtr);
if (status != IP_SUCCESS) {
ASSERT(status != IP_PENDING);
//
// Map status
//
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_IP_SET_FIREWALL_HOOK:
{
PIP_SET_FIREWALL_HOOK_INFO info;
if (Irp->RequestorMode != KernelMode) {
status = STATUS_ACCESS_DENIED;
break;
}
info = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_FIREWALL_HOOK_INFO)) {
status = (NTSTATUS) SetFirewallHook(info);
if (status != IP_SUCCESS) {
ASSERT(status != IP_PENDING);
//
// Map status
//
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
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;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_MAP_ROUTE_HOOK_INFO)) {
status = (NTSTATUS) SetMapRoutePtr(info->MapRoutePtr);
if (status != IP_SUCCESS) {
ASSERT(status != IP_PENDING);
//
// Map status
//
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_IP_RTCHANGE_NOTIFY_REQUEST:
{
status = RtChangeNotifyRequest(Irp, IrpSp);
break;
}
case IOCTL_IP_RTCHANGE_NOTIFY_REQUEST_EX:
{
status = RtChangeNotifyRequestEx(Irp, IrpSp);
break;
}
case IOCTL_IP_ADDCHANGE_NOTIFY_REQUEST:
{
status = AddrChangeNotifyRequest(Irp, IrpSp);
break;
}
#if MILLEN
case IOCTL_IP_IFCHANGE_NOTIFY_REQUEST:
{
status = IfChangeNotifyRequest(Irp, IrpSp);
break;
}
// For non-MILLEN, will default and return NOT_IMPLEMENTED.
#endif // MILLEN
case IOCTL_IP_UNIDIRECTIONAL_ADAPTER_ADDRESS:
{
Interface *pIf;
ULONG cUniIF;
ULONG cbRequired;
PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pUniAdapterAddress;
IPAddr *pUniIpAddr;
CTELockHandle Handle;
CTEGetLock(&RouteTableLock.Lock, &Handle);
//
// First off, count the number of unidirectional interfaces
// and bytes required.
//
cUniIF = 0;
cbRequired = FIELD_OFFSET(IP_UNIDIRECTIONAL_ADAPTER_ADDRESS, Address);
for (pIf = IFList; pIf != NULL; pIf = pIf->if_next) {
if (pIf->if_flags & IF_FLAGS_UNI) {
cUniIF++;
}
}
cbRequired = FIELD_OFFSET(IP_UNIDIRECTIONAL_ADAPTER_ADDRESS, Address[cUniIF]);
if (cUniIF == 0) {
cbRequired = sizeof(IP_UNIDIRECTIONAL_ADAPTER_ADDRESS);
}
//
// Validate output buffer length and copy.
//
if (cbRequired <= IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
pUniAdapterAddress = Irp->AssociatedIrp.SystemBuffer;
pUniAdapterAddress->NumAdapters = cUniIF;
pUniIpAddr = &pUniAdapterAddress->Address[0];
if (cUniIF) {
for (pIf = IFList; pIf != NULL; pIf = pIf->if_next) {
if (pIf->if_flags & IF_FLAGS_UNI) {
*pUniIpAddr++ = pIf->if_index;
}
}
}
Irp->IoStatus.Information = cbRequired;
status = STATUS_SUCCESS;
} else {
Irp->IoStatus.Information = 0;
status = STATUS_BUFFER_OVERFLOW;
}
CTEFreeLock(&RouteTableLock.Lock, Handle);
break;
}
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;
case IOCTL_IP_WAKEUP_PATTERN:
{
PIP_WAKEUP_PATTERN_REQUEST Info = (PIP_WAKEUP_PATTERN_REQUEST) Irp->AssociatedIrp.SystemBuffer;
if (Irp->RequestorMode != KernelMode) {
status = STATUS_ACCESS_DENIED;
break;
}
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(IP_WAKEUP_PATTERN_REQUEST)) {
status = IPWakeupPattern(
Info->InterfaceContext,
Info->PtrnDesc,
Info->AddPattern);
} else {
status = STATUS_INVALID_PARAMETER;
}
}
break;
case IOCTL_IP_GET_WOL_CAPABILITY:
case IOCTL_IP_GET_OFFLOAD_CAPABILITY:
{
PULONG request, response;
request = Irp->AssociatedIrp.SystemBuffer;
response = (PULONG) request;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(ULONG) &&
IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
sizeof(ULONG)) {
uint cap;
if (code == IOCTL_IP_GET_WOL_CAPABILITY) {
cap = IF_WOL_CAP;
} else {
cap = IF_OFFLOAD_CAP;
}
status = IPGetCapability(*request, response, cap);
} else {
status = STATUS_INVALID_PARAMETER;
}
if (status == STATUS_SUCCESS) {
Irp->IoStatus.Information = sizeof(ULONG);
}
}
break;
case IOCTL_IP_GET_IP_EVENT:
return (DispatchIPGetIPEvent(Irp, IrpSp));
case IOCTL_IP_FLUSH_ARP_TABLE:
status = FlushArpTable(Irp, IrpSp);
break;
case IOCTL_IP_GET_IF_INDEX:
status = IPGetIfIndex(Irp,
IrpSp);
break;
case IOCTL_IP_GET_IF_NAME:
status = IPGetIfName(Irp,
IrpSp);
break;
case IOCTL_IP_GET_MCAST_COUNTERS:
return (IPGetMcastCounters(Irp,IrpSp));
case IOCTL_IP_ENABLE_ROUTER_REQUEST:
status = IPEnableRouterRequest(Irp, IrpSp);
break;
case IOCTL_IP_UNENABLE_ROUTER_REQUEST: {
PVOID ApcContext;
status = STATUS_SUCCESS;
#if defined(_WIN64)
if (IoIs32bitProcess(Irp)) {
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
sizeof(VOID * POINTER_32) ||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
sizeof(ULONG)) {
status = STATUS_INVALID_BUFFER_SIZE;
} else {
ApcContext =
(PVOID)*(VOID * POINTER_32 *)
Irp->AssociatedIrp.SystemBuffer;
}
} else {
#endif // _WIN64
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
sizeof(PVOID) ||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
sizeof(ULONG)) {
status = STATUS_INVALID_BUFFER_SIZE;
} else {
ApcContext = *(PVOID*)Irp->AssociatedIrp.SystemBuffer;
}
#if defined(_WIN64)
}
#endif // _WIN64
if (NT_SUCCESS(status)) {
status = IPUnenableRouterRequest(Irp, IrpSp, ApcContext);
}
break;
}
#if DBG_MAP_BUFFER
case IOCTL_IP_DBG_TEST_FAIL_MAP_BUFFER:
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG)) {
status = STATUS_INVALID_BUFFER_SIZE;
} else {
PULONG pBuf = (PULONG) Irp->AssociatedIrp.SystemBuffer;
status = DbgTestFailMapBuffers(
*pBuf);
}
break;
#endif // DBG_MAP_BUFFER
case IOCTL_IP_ENABLE_MEDIA_SENSE_REQUEST:
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
sizeof(PVOID) ||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
sizeof(ULONG)) {
status = STATUS_INVALID_BUFFER_SIZE;
} else {
status = IPEnableMediaSenseRequest(Irp, IrpSp);
}
break;
case IOCTL_IP_DISABLE_MEDIA_SENSE_REQUEST:
status = IPDisableMediaSenseRequest(Irp, IrpSp);
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
if ((status != IP_PENDING) && (status != STATUS_PENDING)) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
return status;
}
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;
}
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);
}
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 = PendingArpSendList.Flink;
while (entry != &PendingArpSendList) {
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 = 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);
}
//
// complete the pending irp for media sense
//
cancelledIrp = NULL;
IoAcquireCancelSpinLock(&oldIrql);
if (PendingIPGetIPEventRequest && IoGetCurrentIrpStackLocation(PendingIPGetIPEventRequest)->FileObject == IrpSp->FileObject) {
cancelledIrp = PendingIPGetIPEventRequest;
PendingIPGetIPEventRequest = NULL;
IoSetCancelRoutine(cancelledIrp, NULL);
}
IoReleaseCancelSpinLock(oldIrql);
if (cancelledIrp) {
cancelledIrp->IoStatus.Information = 0;
cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT);
}
return (STATUS_SUCCESS);
}
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);
}
//
// ARP send function definitions
//
VOID
CancelArpSendRequest(
IN PDEVICE_OBJECT Device,
IN PIRP Irp
)
/*++
Routine Description:
Cancels an outstanding ARP 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 ARP 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 = PendingArpSendList.Flink;
entry != &PendingArpSendList;
entry = entry->Flink
) {
item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
if (item->Irp == Irp) {
pendingIrp = item;
RemoveEntryList(entry);
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;
}
NTSTATUS
RtChangeNotifyRequest(
PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
CTELockHandle TableHandle;
KIRQL OldIrq;
NTSTATUS status;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength &&
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(IPNotifyData)) {
status = STATUS_INVALID_PARAMETER;
goto done;
}
#if MILLEN
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength &&
IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(IP_RTCHANGE_NOTIFY)) {
status = STATUS_INVALID_PARAMETER;
goto done;
}
#endif // MILLEN
IoAcquireCancelSpinLock(&OldIrq);
CTEGetLock(&RouteTableLock.Lock, &TableHandle);
InsertTailList(&RtChangeNotifyQueue, &Irp->Tail.Overlay.ListEntry);
if (Irp->Cancel) {
RemoveTailList(&RtChangeNotifyQueue);
status = STATUS_CANCELLED;
} else {
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, RtChangeNotifyCancel);
status = STATUS_PENDING;
}
Irp->IoStatus.Information = 0;
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
IoReleaseCancelSpinLock(OldIrq);
done:
return status;
}
NTSTATUS
RtChangeNotifyRequestEx(
PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
CTELockHandle TableHandle;
KIRQL OldIrq;
NTSTATUS status;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength &&
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(IPNotifyData)) {
status = STATUS_INVALID_PARAMETER;
goto done;
}
#if MILLEN
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength &&
IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(IP_RTCHANGE_NOTIFY)) {
status = STATUS_INVALID_PARAMETER;
goto done;
}
#endif // MILLEN
IoAcquireCancelSpinLock(&OldIrq);
CTEGetLock(&RouteTableLock.Lock, &TableHandle);
InsertTailList(&RtChangeNotifyQueueEx, &Irp->Tail.Overlay.ListEntry);
if (Irp->Cancel) {
RemoveTailList(&RtChangeNotifyQueueEx);
status = STATUS_CANCELLED;
} else {
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, RtChangeNotifyCancelEx);
status = STATUS_PENDING;
}
Irp->IoStatus.Information = 0;
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
IoReleaseCancelSpinLock(OldIrq);
done:
return status;
}
NTSTATUS
AddrChangeNotifyRequest(PIRP Irp, PIO_STACK_LOCATION pIrpSp)
{
CTELockHandle TableHandle;
KIRQL OldIrq;
NTSTATUS status;
DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
(DTEXT("AddrChangeNotifyRequest(%x, %x)\n"), Irp, pIrpSp));
#if MILLEN
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
PIP_ADDCHANGE_NOTIFY pNotify = Irp->AssociatedIrp.SystemBuffer;
DEBUGMSG(DBG_INFO && DBG_NOTIFY,
(DTEXT("AddrChangeNotifyRequest OutputLen %d, MaxCfgName %d\n"),
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
pNotify->ConfigName.MaximumLength));
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
(FIELD_OFFSET(IP_ADDCHANGE_NOTIFY, NameData) + (ULONG) pNotify->ConfigName.MaximumLength)) {
DEBUGMSG(DBG_ERROR,
(DTEXT("AddrChangeNotifyRequest: INVALID output buffer length.\n")));
status = STATUS_INVALID_PARAMETER;
goto done;
}
}
#endif // MILLEN
IoAcquireCancelSpinLock(&OldIrq);
CTEGetLock(&AddChangeLock, &TableHandle);
InsertTailList(
&AddChangeNotifyQueue,
&(Irp->Tail.Overlay.ListEntry)
);
if (Irp->Cancel) {
(VOID) RemoveTailList(&AddChangeNotifyQueue);
status = STATUS_CANCELLED;
} else {
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, AddChangeNotifyCancel);
status = STATUS_PENDING;
}
Irp->IoStatus.Information = 0;
CTEFreeLock(&AddChangeLock, TableHandle);
IoReleaseCancelSpinLock(OldIrq);
#if MILLEN
done:
#endif // MILLEN
DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
(DTEXT("-AddrChangeNotifyRequest [%x]\n"), status));
return status;
}
#if MILLEN
void
IfChangeNotifyCancel(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
(DTEXT("IfChangeNotifyCancel(%x, %x)\n"), pDeviceObject, pIrp));
CancelNotify(pIrp, &IfChangeNotifyQueue, &IfChangeLock);
return;
}
NTSTATUS
IfChangeNotifyRequest(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp
)
{
CTELockHandle TableHandle;
KIRQL OldIrq;
NTSTATUS NtStatus;
DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
(DTEXT("+IfChangeNotifyRequest(%x, %x)\n"), pIrp, pIrpSp));
//
// Check output buffer length. Output buffer will store the
// NTE context and whether the interface was added or deleted.
//
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IP_IFCHANGE_NOTIFY)) {
NtStatus = STATUS_INVALID_PARAMETER;
pIrp->IoStatus.Status = NtStatus;
pIrp->IoStatus.Information = 0;
goto done;
}
//
// Set cancel routine, mark IRP as pending and put on our interface
// notify list.
//
IoAcquireCancelSpinLock(&OldIrq);
IoMarkIrpPending(pIrp);
CTEGetLock(&IfChangeLock, &TableHandle);
InsertTailList(
&IfChangeNotifyQueue,
&(pIrp->Tail.Overlay.ListEntry)
);
if (pIrp->Cancel) {
RemoveTailList(&IfChangeNotifyQueue);
NtStatus = STATUS_CANCELLED;
} else {
IoSetCancelRoutine(pIrp, IfChangeNotifyCancel);
NtStatus = STATUS_PENDING;
}
pIrp->IoStatus.Information = 0;
CTEFreeLock(&IfChangeLock, TableHandle);
IoReleaseCancelSpinLock(OldIrq);
done:
DEBUGMSG(DBG_TRACE && DBG_NOTIFY,
(DTEXT("-IfChangeNotifyRequest [%x]\n"), NtStatus));
return NtStatus;
}
#endif // MILLEN
NTSTATUS
IPEnableRouterRequest(
PIRP Irp,
PIO_STACK_LOCATION IrpSp
)
{
KIRQL OldIrql;
NTSTATUS status;
CTELockHandle TableHandle;
IoAcquireCancelSpinLock(&OldIrql);
if (Irp->Cancel) {
status = STATUS_CANCELLED;
} else {
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, CancelIPEnableRouterRequest);
// Increment the routing-enabled reference count.
// When the count rises above zero routing is enabled.
// This reference will be dropped when the IRP is cancelled.
CTEGetLockAtDPC(&RouteTableLock.Lock, &TableHandle);
Irp->Tail.Overlay.DriverContext[0] = IrpSp->FileObject;
InsertTailList(&PendingEnableRouterList, &Irp->Tail.Overlay.ListEntry);
IPEnableRouterWithRefCount(TRUE);
CTEFreeLockFromDPC(&RouteTableLock.Lock, TableHandle);
status = STATUS_PENDING;
}
Irp->IoStatus.Information = 0;
IoReleaseCancelSpinLock(OldIrql);
return status;
}
VOID
CancelIPEnableRouterRequest(
IN PDEVICE_OBJECT Device,
IN PIRP Irp
)
{
CTELockHandle TableHandle;
IoReleaseCancelSpinLock(Irp->CancelIrql);
// Decrement the routing-enabled reference count.
// If the count drops to zero routing is disabled.
CTEGetLock(&RouteTableLock.Lock, &TableHandle);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
IPEnableRouterWithRefCount(FALSE);
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
NTSTATUS
IPUnenableRouterRequest(
PIRP Irp,
PIO_STACK_LOCATION IrpSp,
PVOID ApcContext
)
{
PLIST_ENTRY entry;
KIRQL CancelIrql;
int RefCount;
CTELockHandle TableHandle;
// Locate the pending IRP for the request corresponding to the caller's
// disable-request. Drop the routing-enabled reference-count, complete
// the corresponding IRP, and tell the caller what the reference-count's
// current value is.
IoAcquireCancelSpinLock(&CancelIrql);
CTEGetLock(&RouteTableLock.Lock, &TableHandle);
for (entry = PendingEnableRouterList.Flink;
entry != &PendingEnableRouterList;
entry = entry->Flink
) {
PIRP EnableIrp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
if (EnableIrp->Tail.Overlay.DriverContext[0] == IrpSp->FileObject &&
EnableIrp->Overlay.AsynchronousParameters.UserApcContext ==
ApcContext) {
RemoveEntryList(&EnableIrp->Tail.Overlay.ListEntry);
RefCount = IPEnableRouterWithRefCount(FALSE);
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
IoSetCancelRoutine(EnableIrp, NULL);
IoReleaseCancelSpinLock(CancelIrql);
EnableIrp->IoStatus.Status = STATUS_SUCCESS;
EnableIrp->IoStatus.Information = 0;
IoCompleteRequest(EnableIrp, IO_NETWORK_INCREMENT);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = (ULONG)RefCount;
Irp->IoStatus.Information = sizeof(ULONG);
return STATUS_SUCCESS;
}
}
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
IoReleaseCancelSpinLock(CancelIrql);
return STATUS_INVALID_PARAMETER;
}
//
// 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);
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;
}
//
// 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);
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;
}
VOID
CancelIPGetIPEventRequest(
IN PDEVICE_OBJECT Device,
IN PIRP Irp
)
/*++
Routine Description:
Cancels IPGetIPEvent function.
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.
--*/
{
PIRP pendingIrp = NULL;
//
// We need to make sure that we are not completing this irp
// while we are in this cancel code. If we are completing
// this irp, the PendingIPGetIPEventRequest will either be
// NULL or contain next irp.
//
if (PendingIPGetIPEventRequest == Irp) {
pendingIrp = Irp;
PendingIPGetIPEventRequest = NULL;
}
IoReleaseCancelSpinLock(Irp->CancelIrql);
if (pendingIrp != NULL) {
pendingIrp->IoStatus.Information = 0;
pendingIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pendingIrp, IO_NETWORK_INCREMENT);
}
return;
}
void
CompleteEchoRequest(
EchoControl *controlBlock,
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;
PPENDING_IRP pendingIrp = NULL;
PPENDING_IRP item;
PLIST_ENTRY entry;
ULONG bytesReturned;
//
// 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);
#if defined(_WIN64)
if (IoIs32bitProcess(irp)) {
bytesReturned = ICMPEchoComplete32(controlBlock, Status, Data, DataSize,
OptionInfo);
} else {
#endif // _WIN64
bytesReturned = ICMPEchoComplete(controlBlock, Status, Data, DataSize,
OptionInfo);
#if defined(_WIN64)
}
#endif // _WIN64
CTEFreeMem(pendingIrp);
CTEFreeMem(controlBlock);
//
// Complete the IRP.
//
irp->IoStatus.Information = (ULONG) bytesReturned;
irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
return;
}
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;
Interface *IF;
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);
//
// Complete the IRP.
//
irp->IoStatus.Information = 0;
Status = IPStatusToNTStatus(Status);
irp->IoStatus.Status = Status;
CTEFreeMem(controlBlock);
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
return;
}
void
CheckSetAddrRequestOnInterface(
Interface *IF
)
/*++
Routine Description:
Handles the completion of an IP Set Addr request on an interface
that is getting unbound
Arguments:
IF - Pointer to the interface whish is getting deleted
Return Value:
None.
--*/
{
KIRQL oldIrql;
PIRP irp;
PIO_STACK_LOCATION irpSp;
PPENDING_IRP pendingIrp = NULL;
PLIST_ENTRY entry, nextEntry;
LIST_ENTRY completeList;
SetAddrControl *controlBlock;
InitializeListHead(&completeList);
//
// Find pending set addr requests on this interface
//
IoAcquireCancelSpinLock(&oldIrql);
entry = PendingIPSetNTEAddrList.Flink;
while (entry != &PendingIPSetNTEAddrList) {
pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
controlBlock = pendingIrp->Context;
if (controlBlock->interface == IF) {
// remove this entry
nextEntry = entry->Flink;
irp = pendingIrp->Irp;
IoSetCancelRoutine(irp, NULL);
RemoveEntryList(entry);
// reinsert this in to completelist
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);
irp = pendingIrp->Irp;
entry = entry->Flink;
//
// Free the PENDING_IRP structure
// control block will be freed
// when addaddrcomplete is called
CTEFreeMem(pendingIrp);
//
// Complete the IRP.
//
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
}
return;
}
BOOLEAN
PrepareArpSendIrpForCancel(
PIRP Irp,
PPENDING_IRP PendingIrp
)
/*++
Routine Description:
Prepares an Arp Send 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, CancelArpSendRequest);
InsertTailList(&PendingArpSendList, &(PendingIrp->Linkage));
cancelled = FALSE;
}
IoReleaseCancelSpinLock(oldIrql);
return (cancelled);
}
void
CompleteArpResolveRequest(
void *Context,
IP_STATUS Status
)
/*++
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.
Return Value:
None.
--*/
{
KIRQL oldIrql;
PIRP irp;
PIO_STACK_LOCATION irpSp;
ARPControlBlock *controlBlock;
PPENDING_IRP pendingIrp = NULL;
PPENDING_IRP item;
PLIST_ENTRY entry;
controlBlock = (ARPControlBlock *) Context;
//
// Find the echo request IRP on the pending list.
//
IoAcquireCancelSpinLock(&oldIrql);
for (entry = PendingArpSendList.Flink;
entry != &PendingArpSendList;
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);
//set the right length
//
// Complete the IRP.
//
irp->IoStatus.Status = IPStatusToNTStatus(Status);
irp->IoStatus.Information = controlBlock->PhyAddrLen;
CTEFreeMem(pendingIrp);
CTEFreeMem(controlBlock);
if (Status != IP_SUCCESS) {
irp->IoStatus.Information = 0;
}
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
return;
}
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);
}
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);
}
NTSTATUS
DispatchARPRequest(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
IP_STATUS ipStatus;
PPENDING_IRP pendingIrp, item;
ARPControlBlock *controlBlock;
IPAddr DestAddress, SourceAddress;
BOOLEAN cancelled;
PARP_SEND_REPLY RequestBuffer;
PLIST_ENTRY entry;
PAGED_CODE();
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ARP_SEND_REPLY)) {
ntStatus = STATUS_INVALID_BUFFER_SIZE;
goto arp_error;
}
pendingIrp = CTEAllocMemN(sizeof(PENDING_IRP), 'gICT');
if (pendingIrp == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto arp_error;
}
controlBlock = CTEAllocMemN(sizeof(ARPControlBlock), 'hICT');
if (controlBlock == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
CTEFreeMem(pendingIrp);
goto arp_error;
}
pendingIrp->Irp = Irp;
pendingIrp->FileObject = IrpSp->FileObject;
pendingIrp->Context = controlBlock;
controlBlock->PhyAddrLen =
IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
RequestBuffer = Irp->AssociatedIrp.SystemBuffer;
controlBlock->PhyAddr = Irp->AssociatedIrp.SystemBuffer;
controlBlock->next = 0;
DestAddress = RequestBuffer->DestAddress;
SourceAddress = RequestBuffer->SrcAddress;
IoMarkIrpPending(Irp);
cancelled = PrepareArpSendIrpForCancel(Irp, pendingIrp);
if (!cancelled) {
ipStatus = ARPResolve(
DestAddress,
SourceAddress,
controlBlock,
CompleteArpResolveRequest
);
if (ipStatus != IP_PENDING) {
//
// An internal error of some kind occurred. Complete the
// request.
//
CompleteArpResolveRequest(controlBlock, ipStatus);
}
return STATUS_PENDING;
}
//
// Irp has already been cancelled.
//
ntStatus = STATUS_CANCELLED;
CTEFreeMem(pendingIrp);
CTEFreeMem(controlBlock);
arp_error:
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return (ntStatus);
}
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;
BOOLEAN cancelled;
PAGED_CODE();
pendingIrp = CTEAllocMemN(sizeof(PENDING_IRP), 'iICT');
if (pendingIrp == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto echo_error;
}
controlBlock = CTEAllocMemN(sizeof(EchoControl), 'jICT');
if (controlBlock == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
CTEFreeMem(pendingIrp);
goto echo_error;
}
#if defined(_WIN64)
if (IoIs32bitProcess(Irp)) {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ICMP_ECHO_REPLY32)) {
ntStatus = STATUS_INVALID_PARAMETER;
CTEFreeMem(controlBlock);
CTEFreeMem(pendingIrp);
goto echo_error;
}
} else {
#endif // _WIN64
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ICMP_ECHO_REPLY)) {
ntStatus = STATUS_INVALID_PARAMETER;
CTEFreeMem(controlBlock);
CTEFreeMem(pendingIrp);
goto echo_error;
}
#if defined(_WIN64)
}
#endif // _WIN64
pendingIrp->Irp = Irp;
pendingIrp->FileObject = IrpSp->FileObject;
pendingIrp->Context = controlBlock;
controlBlock->ec_starttime = KeQueryPerformanceCounter(NULL);
controlBlock->ec_replybuf = Irp->AssociatedIrp.SystemBuffer;
controlBlock->ec_replybuflen =
IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
controlBlock->ec_src = 0;
IoMarkIrpPending(Irp);
cancelled = PrepareEchoIrpForCancel(Irp, pendingIrp);
if (!cancelled) {
ipStatus =
ICMPEchoRequest(Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
controlBlock, CompleteEchoRequest);
if (ipStatus != IP_PENDING) {
//
// An internal error of some kind occurred. Complete the
// request.
//
CompleteEchoRequest(controlBlock, ipStatus, NULL, 0, NULL);
}
return STATUS_PENDING;
}
//
// 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);
}
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 = CTEAllocMemN(sizeof(PENDING_IRP), 'kICT');
if (pendingIrp == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto setnteaddr_error;
}
controlBlock = CTEAllocMemN(sizeof(SetAddrControl), 'lICT');
if (controlBlock == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
CTEFreeMem(pendingIrp);
goto setnteaddr_error;
}
RtlZeroMemory(controlBlock, sizeof(SetAddrControl));
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_IP_SET_ADDRESS_DUP) {
controlBlock->bugcheck_on_duplicate = 1;
}
pendingIrp->Irp = Irp;
pendingIrp->FileObject = IrpSp->FileObject;
pendingIrp->Context = controlBlock;
IoMarkIrpPending(Irp);
cancelled = PrepareIPSetNTEAddrIrpForCancel(Irp, pendingIrp);
if (!cancelled) {
PIP_SET_ADDRESS_REQUEST request;
USHORT AddrType = 0;
request = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_IP_SET_ADDRESS_EX) {
AddrType = ((PIP_SET_ADDRESS_REQUEST_EX)request)->Type;
}
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IP_SET_ADDRESS_REQUEST)) {
ipStatus = IPSetNTEAddrEx(
request->Context,
request->Address,
request->SubnetMask,
controlBlock,
CompleteIPSetNTEAddrRequest,
AddrType
);
} else {
ipStatus = IP_GENERAL_FAILURE;
}
if (ipStatus != IP_PENDING) {
//
// A request completed which did not pend.
//
CompleteIPSetNTEAddrRequest(controlBlock, ipStatus);
}
// Since IoMarkIrpPending was called, return pending.
return STATUS_PENDING;
}
//
// 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);
}
NTSTATUS
DispatchIPGetIPEvent(
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
Registers the ioctl for the clients to receive the media sense
events.
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;
KIRQL oldIrql;
//
// Mark the irp as pending, later when we complete this irp in
// the same thread, we will unmark it.
//
MARK_REQUEST_PENDING(Irp);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_PENDING;
//
// Make sure the buffer size is valid.
//
#if defined(_WIN64)
if (IoIs32bitProcess(Irp)) {
ntStatus = STATUS_NOT_IMPLEMENTED;
} else {
#endif // _WIN64
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(IP_GET_IP_EVENT_RESPONSE)) {
ntStatus = STATUS_INVALID_PARAMETER;
} else {
IoAcquireCancelSpinLock(&oldIrql);
ASSERT(Irp->CancelRoutine == NULL);
//
// Check if the irp is already cancelled or not.
//
if (Irp->Cancel) {
ntStatus = STATUS_CANCELLED;
//
// We only allow one irp pending.
//
} else if (PendingIPGetIPEventRequest) {
ntStatus = STATUS_DEVICE_BUSY;
} else {
IoSetCancelRoutine(Irp, CancelIPGetIPEventRequest);
PendingIPGetIPEventRequest = Irp;
ntStatus = STATUS_SUCCESS;
}
IoReleaseCancelSpinLock(oldIrql);
if (STATUS_SUCCESS == ntStatus) {
//
// IPGetIPEventEx will either complete the request
// or return pending.
//
ntStatus = IPGetIPEventEx(Irp, IrpSp);
if (ntStatus == STATUS_CANCELLED) {
//
// Since the cancel routine has been installed at this point,
// the IRP will have already been completed, and can no longer
// be referenced.
//
ntStatus = STATUS_PENDING;
}
}
}
#if defined(_WIN64)
}
#endif // _WIN64
if (ntStatus != STATUS_PENDING) {
UNMARK_REQUEST_PENDING(Irp);
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
return (ntStatus);
}
VOID
CancelIPEnableMediaSenseRequest(
IN PDEVICE_OBJECT Device,
IN PIRP Irp
)
{
CTELockHandle TableHandle;
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(Irp->CancelIrql);
// Decrement the mediasense-enabled reference count.
// If the count drops to zero media-sense is disabled.
CTEGetLock(&RouteTableLock.Lock, &TableHandle);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
IPEnableMediaSense(TRUE, &TableHandle);
CTEFreeLock(&RouteTableLock.Lock, TableHandle);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
}
NTSTATUS
IPDisableMediaSenseRequest(
PIRP Irp,
PIO_STACK_LOCATION IrpSp
)
{
KIRQL OldIrql;
NTSTATUS status;
CTELockHandle TableHandle;
IoAcquireCancelSpinLock(&OldIrql);
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, CancelIPEnableMediaSenseRequest);
if (Irp->Cancel) {
IoSetCancelRoutine(Irp, NULL);
status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoReleaseCancelSpinLock(OldIrql);
} else {
// Increment the mediasense-enabled reference count.
// When the count rises above zero media-sense is enabled.
// This reference will be dropped when the IRP is cancelled.
CTEGetLockAtDPC(&RouteTableLock.Lock, &TableHandle);
Irp->Tail.Overlay.DriverContext[0] = IrpSp->FileObject;
InsertTailList(&PendingMediaSenseRequestList, &Irp->Tail.Overlay.ListEntry);
Irp->IoStatus.Information = 0;
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
IPEnableMediaSense(FALSE, &OldIrql);
CTEFreeLock(&RouteTableLock.Lock, OldIrql);
status = STATUS_PENDING;
}
return status;
}
NTSTATUS
IPEnableMediaSenseRequest(
PIRP Irp,
PIO_STACK_LOCATION IrpSp
)
{
PLIST_ENTRY entry;
KIRQL CancelIrql;
int RefCount;
CTELockHandle TableHandle;
// Locate the pending IRP for the request corresponding to the caller's
// disable-request. Drop the mediasense-enabled reference-count, complete
// the corresponding IRP, and tell the caller what the reference-count's
// current value is.
IoAcquireCancelSpinLock(&CancelIrql);
CTEGetLockAtDPC(&RouteTableLock.Lock, &TableHandle);
for (entry = PendingMediaSenseRequestList.Flink;
entry != &PendingMediaSenseRequestList;
entry = entry->Flink
) {
PIRP EnableIrp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
if (EnableIrp->Tail.Overlay.DriverContext[0] == IrpSp->FileObject &&
EnableIrp->Overlay.AsynchronousParameters.UserApcContext ==
*(PVOID *) Irp->AssociatedIrp.SystemBuffer) {
RemoveEntryList(&EnableIrp->Tail.Overlay.ListEntry);
IoSetCancelRoutine(EnableIrp, NULL);
EnableIrp->IoStatus.Status = STATUS_SUCCESS;
EnableIrp->IoStatus.Information = 0;
*(PULONG) Irp->AssociatedIrp.SystemBuffer = (ULONG) DisableMediaSense+1;
Irp->IoStatus.Information = sizeof(ULONG);
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
IoCompleteRequest(EnableIrp, IO_NETWORK_INCREMENT);
RefCount = IPEnableMediaSense(TRUE, &CancelIrql);
CTEFreeLock(&RouteTableLock.Lock, CancelIrql);
return STATUS_SUCCESS;
}
}
CTEFreeLockFromDPC(&RouteTableLock.Lock, TableHandle);
IoReleaseCancelSpinLock(CancelIrql);
return STATUS_INVALID_PARAMETER;
}