You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5024 lines
142 KiB
5024 lines
142 KiB
/*++
|
|
|
|
Copyright (c) 1991-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntdisp.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 "addr.h"
|
|
#include "tcp.h"
|
|
#include "udp.h"
|
|
#include "raw.h"
|
|
#include "info.h"
|
|
#include <tcpinfo.h>
|
|
#include "tcpcfg.h"
|
|
#include "secfltr.h"
|
|
#include "tcpconn.h"
|
|
#include "tcpsend.h"
|
|
#include "pplasl.h"
|
|
#include "tcpdeliv.h"
|
|
#include "dgram.h"
|
|
#include "mdl2ndis.h"
|
|
//
|
|
// Macros
|
|
//
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// CTEConvert100nsToMilliseconds(
|
|
// IN LARGE_INTEGER HnsTime
|
|
// );
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Converts time expressed in hundreds of nanoseconds to milliseconds.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// HnsTime - Time in hundreds of nanoseconds.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Time in milliseconds.
|
|
//
|
|
//--
|
|
|
|
#define SHIFT10000 13
|
|
static LARGE_INTEGER Magic10000 =
|
|
{0xe219652c, 0xd1b71758};
|
|
|
|
#define CTEConvert100nsToMilliseconds(HnsTime) \
|
|
RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
|
|
|
|
#if ACC
|
|
GENERIC_MAPPING AddressGenericMapping =
|
|
{READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL};
|
|
extern PSECURITY_DESCRIPTOR TcpAdminSecurityDescriptor;
|
|
uint AllowUserRawAccess;
|
|
#endif
|
|
//
|
|
// Global variables
|
|
//
|
|
extern PDEVICE_OBJECT TCPDeviceObject, UDPDeviceObject;
|
|
extern PDEVICE_OBJECT IPDeviceObject;
|
|
|
|
#if IPMCAST
|
|
|
|
extern PDEVICE_OBJECT IpMcastDeviceObject;
|
|
|
|
#endif
|
|
|
|
extern PDEVICE_OBJECT RawIPDeviceObject;
|
|
|
|
AddrObj *FindAddrObjWithPort(ushort Port);
|
|
ReservedPortListEntry *BlockedPortList = NULL;
|
|
extern uint LogPerPartitionSize;
|
|
extern CTELock *pTWTCBTableLock;
|
|
#define GET_PARTITION(i) (i >> (ulong) LogPerPartitionSize)
|
|
|
|
extern ReservedPortListEntry *PortRangeList;
|
|
extern uint TcpHostOpts;
|
|
extern TCPInternalStats TStats;
|
|
|
|
CACHE_LINE_ULONG CancelId = { 1 };
|
|
|
|
//
|
|
// Local types
|
|
//
|
|
typedef struct {
|
|
PIRP Irp;
|
|
PMDL InputMdl;
|
|
PMDL OutputMdl;
|
|
TCP_REQUEST_QUERY_INFORMATION_EX QueryInformation;
|
|
} TCP_QUERY_CONTEXT, *PTCP_QUERY_CONTEXT;
|
|
|
|
extern POBJECT_TYPE *IoFileObjectType;
|
|
|
|
#if TRACE_EVENT
|
|
//
|
|
// CP Handler routine set/unset by WMI through IRP_MN_SET_TRACE_NOTIFY
|
|
//
|
|
PTDI_DATA_REQUEST_NOTIFY_ROUTINE TCPCPHandlerRoutine;
|
|
#endif
|
|
|
|
PIRP CanceledIrp = NULL;
|
|
|
|
//
|
|
// General external function prototypes
|
|
//
|
|
extern
|
|
NTSTATUS
|
|
IPDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#if IPMCAST
|
|
|
|
NTSTATUS
|
|
IpMcastDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#endif
|
|
|
|
extern
|
|
NTSTATUS
|
|
TCPDispatchPnPPower(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
|
|
extern
|
|
NTSTATUS
|
|
GetTCBInfo(
|
|
PTCP_FINDTCB_RESPONSE TCBInfo,
|
|
IPAddr Dest,
|
|
IPAddr Src,
|
|
ushort DestPort,
|
|
ushort SrcPort
|
|
);
|
|
|
|
//
|
|
// Other external functions
|
|
//
|
|
BOOLEAN
|
|
TCPAbortAndIndicateDisconnect(
|
|
uint ConnnectionContext, PVOID reqcontext, uint receive, KIRQL Handle
|
|
);
|
|
|
|
//
|
|
// Local pageable function prototypes
|
|
//
|
|
NTSTATUS
|
|
TCPDispatchDeviceControl(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPAssociateAddress(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPSetEventHandler(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPQueryInformation(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
FILE_FULL_EA_INFORMATION UNALIGNED *
|
|
FindEA(
|
|
PFILE_FULL_EA_INFORMATION StartEA,
|
|
CHAR * TargetName,
|
|
USHORT TargetNameLength
|
|
);
|
|
|
|
BOOLEAN
|
|
IsDHCPZeroAddress(
|
|
TRANSPORT_ADDRESS UNALIGNED * AddrList
|
|
);
|
|
|
|
ULONG
|
|
RawExtractProtocolNumber(
|
|
IN PUNICODE_STRING FileName
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
TCPControlSecurityFilter(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPProcessSecurityFilterRequest(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
TCPEnumerateSecurityFilter(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
TCPEnumerateConnectionList(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
//
|
|
// Local helper routine prototypes.
|
|
//
|
|
ULONG
|
|
TCPGetMdlChainByteCount(
|
|
PMDL Mdl
|
|
);
|
|
|
|
ULONG
|
|
TCPGetNdisBufferChainByteCount(
|
|
PNDIS_BUFFER pBuffer
|
|
);
|
|
|
|
#if ACC
|
|
BOOLEAN
|
|
IsAdminIoRequest(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp
|
|
);
|
|
#endif
|
|
|
|
NTSTATUS
|
|
CaptureCreatorSD(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp,
|
|
OUT PSECURITY_DESCRIPTOR* CreatorSD
|
|
);
|
|
|
|
//
|
|
// All of this code is pageable.
|
|
//
|
|
#if !MILLEN
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, TCPCreate)
|
|
#pragma alloc_text(PAGE, TCPSetEventHandler)
|
|
#pragma alloc_text(PAGE, FindEA)
|
|
#pragma alloc_text(PAGE, IsDHCPZeroAddress)
|
|
#pragma alloc_text(PAGE, RawExtractProtocolNumber)
|
|
|
|
|
|
#pragma alloc_text(PAGE, TCPControlSecurityFilter)
|
|
#pragma alloc_text(PAGE, TCPProcessSecurityFilterRequest)
|
|
#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
|
|
|
|
|
|
#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
|
|
|
|
#if ACC
|
|
#pragma alloc_text(PAGE, IsAdminIoRequest)
|
|
#endif
|
|
#pragma alloc_text(PAGE, CaptureCreatorSD)
|
|
#endif
|
|
|
|
#endif // !MILLEN
|
|
|
|
|
|
//
|
|
// Generic Irp completion and cancellation routines.
|
|
//
|
|
|
|
NTSTATUS
|
|
TCPDataRequestComplete(
|
|
void *Context,
|
|
unsigned int Status,
|
|
unsigned int ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a UDP/TCP send/receive request.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - The final TDI status of the request.
|
|
ByteCount - Bytes sent/received information.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldIrql;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PTCP_CONTEXT tcpContext;
|
|
CTELockHandle CancelHandle;
|
|
BOOLEAN Cleanup = FALSE;
|
|
|
|
irp = (PIRP) Context;
|
|
irpSp = IoGetCurrentIrpStackLocation(irp);
|
|
tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
|
|
|
|
FreeMdlToNdisBufferChain(irp);
|
|
|
|
if (IoSetCancelRoutine(irp, NULL) == NULL) {
|
|
|
|
// Cancel routine have been invoked and can possibly
|
|
// still be running. However, it won't find this IRP
|
|
// on the list (TCB or AO). Just make sure the cancel
|
|
// routine got far enough to acquire the endpoint lock
|
|
// before proceeding to do this ourselves.
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
}
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
|
|
PLIST_ENTRY entry, listHead;
|
|
PIRP item = NULL;
|
|
|
|
if (irp->Cancel) {
|
|
ASSERT(irp->CancelRoutine == NULL);
|
|
listHead = &(tcpContext->CancelledIrpList);
|
|
} else {
|
|
listHead = &(tcpContext->PendingIrpList);
|
|
}
|
|
|
|
//
|
|
// Verify that the Irp is on the appropriate list
|
|
//
|
|
for (entry = listHead->Flink;
|
|
entry != listHead;
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
if (item == irp) {
|
|
RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((item == NULL) && irp->Cancel) {
|
|
|
|
listHead = &(tcpContext->PendingIrpList);
|
|
|
|
for (entry = listHead->Flink; entry != listHead; entry = entry->Flink) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
if (item == irp) {
|
|
RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//note that if we are not holding cancel spinlock
|
|
//cancel can be in progress already
|
|
//it should be still okay since this irp is already dequeued
|
|
//from ao/tcb
|
|
|
|
ASSERT(tcpContext->ReferenceCount > 0);
|
|
|
|
if (--(tcpContext->ReferenceCount) == 0) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
}
|
|
Cleanup = TRUE;
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPDataRequestComplete: Irp %lx fileobj %lx refcnt dec to %u\n",
|
|
irp,
|
|
irpSp->FileObject,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
if (!((Status == TDI_CANCELLED) && ByteCount)) {
|
|
|
|
if (irp->Cancel || tcpContext->CancelIrps) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE(("TCPDataRequestComplete: Irp %lx was cancelled\n", irp));
|
|
}
|
|
|
|
irp->IoStatus.Status = Status = (unsigned int)STATUS_CANCELLED;
|
|
ByteCount = 0;
|
|
}
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
if (Cleanup) {
|
|
//
|
|
// Make sure we do not touch tcpContext after cleanup
|
|
// event is set
|
|
//
|
|
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPDataRequestComplete: completing irp %lx, status %lx, byte count %lx\n",
|
|
irp,
|
|
Status,
|
|
ByteCount
|
|
));
|
|
}
|
|
|
|
irp->IoStatus.Status = (NTSTATUS) Status;
|
|
irp->IoStatus.Information = ByteCount;
|
|
|
|
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
|
|
|
|
return Status;
|
|
|
|
} // TCPDataRequestComplete
|
|
|
|
void
|
|
TCPRequestComplete(
|
|
void *Context,
|
|
unsigned int Status,
|
|
unsigned int UnUsed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a cancellable TDI request which returns no data by
|
|
calling TCPDataRequestComplete with a ByteCount of zero.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - The final TDI status of the request.
|
|
UnUsed - An unused parameter
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(UnUsed);
|
|
|
|
TCPDataRequestComplete(Context, Status, 0);
|
|
|
|
} // TCPRequestComplete
|
|
|
|
void
|
|
TCPNonCancellableRequestComplete(
|
|
void *Context,
|
|
unsigned int Status,
|
|
unsigned int UnUsed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a TDI request which cannot be cancelled.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - The final TDI status of the request.
|
|
UnUsed - An unused parameter
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
UNREFERENCED_PARAMETER(UnUsed);
|
|
|
|
irp = (PIRP) Context;
|
|
irpSp = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE((
|
|
"TCPNonCancellableRequestComplete: irp %lx status %lx\n",
|
|
irp,
|
|
Status
|
|
));
|
|
}
|
|
|
|
//
|
|
// Complete the IRP
|
|
//
|
|
irp->IoStatus.Status = (NTSTATUS) Status;
|
|
irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
|
|
|
|
return;
|
|
|
|
} // TCPNonCancellableRequestComplete
|
|
|
|
void
|
|
TCPCancelComplete(
|
|
void *Context,
|
|
unsigned int Unused1,
|
|
unsigned int Unused2
|
|
)
|
|
{
|
|
PFILE_OBJECT fileObject = (PFILE_OBJECT) Context;
|
|
PTCP_CONTEXT tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
|
|
CTELockHandle CancelHandle;
|
|
|
|
UNREFERENCED_PARAMETER(Unused1);
|
|
UNREFERENCED_PARAMETER(Unused2);
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
//
|
|
// Remove the reference placed on the endpoint by the cancel routine.
|
|
// The cancelled Irp will be completed by the completion routine for the
|
|
// request.
|
|
//
|
|
if (--(tcpContext->ReferenceCount) == 0) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
}
|
|
|
|
//
|
|
// Set the cleanup event after releasing the lock
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
|
|
|
return;
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCancelComplete: fileobj %lx refcnt dec to %u\n",
|
|
fileObject,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
return;
|
|
|
|
} // TCPCancelComplete
|
|
|
|
VOID
|
|
TCPCancelRequest(
|
|
PDEVICE_OBJECT Device,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancels an outstanding Irp.
|
|
|
|
Arguments:
|
|
|
|
Device - Pointer to the device object for this request.
|
|
Irp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PTCP_CONTEXT tcpContext;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PFILE_OBJECT fileObject;
|
|
UCHAR minorFunction;
|
|
TDI_REQUEST request;
|
|
CTELockHandle CancelHandle;
|
|
KIRQL UserIrql;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
fileObject = irpSp->FileObject;
|
|
tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
|
|
minorFunction = irpSp->MinorFunction;
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
ASSERT(Irp->Cancel);
|
|
|
|
UserIrql = Irp->CancelIrql;
|
|
IoReleaseCancelSpinLock(CancelHandle);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCancelRequest: cancelling irp %lx, file object %lx\n",
|
|
Irp,
|
|
fileObject
|
|
));
|
|
}
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
//
|
|
// Remove the Irp if it is on the pending list and place it on
|
|
// the cancel list.
|
|
//
|
|
PLIST_ENTRY entry;
|
|
PIRP item = NULL;
|
|
|
|
for (entry = tcpContext->PendingIrpList.Flink;
|
|
entry != &(tcpContext->PendingIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
if (item == Irp) {
|
|
RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (item == Irp) {
|
|
InsertTailList(
|
|
&(tcpContext->CancelledIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//
|
|
// Add a reference so the object can't be closed while the cancel routine
|
|
// is executing.
|
|
//
|
|
ASSERT(tcpContext->ReferenceCount > 0);
|
|
tcpContext->ReferenceCount++;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCancelRequest: Irp %lx fileobj %lx refcnt inc to %u\n",
|
|
Irp,
|
|
fileObject,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
|
|
//
|
|
// Try to cancel the request.
|
|
//
|
|
switch (minorFunction) {
|
|
|
|
case TDI_SEND:
|
|
case TDI_RECEIVE:
|
|
|
|
ASSERT((PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
|
|
(PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE));
|
|
|
|
|
|
if (PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
if (TCPAbortAndIndicateDisconnect(
|
|
PtrToUlong(tcpContext->Handle.ConnectionContext), Irp, (minorFunction == TDI_RECEIVE) ? 1 : 0, UserIrql)) { //
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
#if DBG
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
|
|
// Remove this Irp from CancelledIrpList
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
}
|
|
#endif // DBG
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
}
|
|
break;
|
|
|
|
} else if (PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
|
|
|
|
TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
|
|
|
|
break;
|
|
|
|
} else {
|
|
CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect on neither address/connect file\n"));
|
|
break;
|
|
}
|
|
|
|
case TDI_SEND_DATAGRAM:
|
|
|
|
ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
|
|
break;
|
|
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
|
|
ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
TdiCancelReceiveDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
|
|
ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
//
|
|
// This pends but is not cancellable. We put it thru the cancel code
|
|
// anyway so a reference is made for it and so it can be tracked in
|
|
// a debug build.
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Initiate a disconnect to cancel the request.
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
|
|
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPCancelComplete;
|
|
request.RequestContext = fileObject;
|
|
|
|
status = TdiDisconnect(&request, NULL, TDI_DISCONNECT_ABORT, NULL, NULL,
|
|
NULL);
|
|
break;
|
|
}
|
|
|
|
if (status != TDI_PENDING) {
|
|
TCPCancelComplete(fileObject, 0, 0);
|
|
}
|
|
return;
|
|
|
|
} // TCPCancelRequest
|
|
|
|
NTSTATUS
|
|
TCPPrepareIrpForCancel(
|
|
PTCP_CONTEXT TcpContext,
|
|
PIRP Irp,
|
|
PDRIVER_CANCEL CancelRoutine
|
|
)
|
|
{
|
|
CTELockHandle CancelHandle;
|
|
ULONG LocalCancelId;
|
|
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
|
|
CTEGetLock(&TcpContext->EndpointLock, &CancelHandle);
|
|
|
|
ASSERT(Irp->CancelRoutine == NULL);
|
|
|
|
if (!Irp->Cancel && !TcpContext->Cleanup) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
IoSetCancelRoutine(Irp, CancelRoutine);
|
|
TcpContext->ReferenceCount++;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPPrepareIrpForCancel: irp %lx fileobj %lx refcnt inc to %u\n",
|
|
Irp,
|
|
(IoGetCurrentIrpStackLocation(Irp))->FileObject,
|
|
TcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
#if DBG
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
PLIST_ENTRY entry;
|
|
PIRP item = NULL;
|
|
|
|
//
|
|
// Verify that the Irp has not already been submitted.
|
|
//
|
|
for (entry = TcpContext->PendingIrpList.Flink;
|
|
entry != &(TcpContext->PendingIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
for (entry = TcpContext->CancelledIrpList.Flink;
|
|
entry != &(TcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(TcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
//Update monotonically increasing cancel ID and
|
|
//remember this for later use
|
|
|
|
while ((LocalCancelId = InterlockedIncrement((PLONG)&CancelId.Value)) == 0) { }
|
|
|
|
Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(LocalCancelId);
|
|
Irp->Tail.Overlay.DriverContext[0] = NULL;
|
|
CTEFreeLock(&TcpContext->EndpointLock, CancelHandle);
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
//
|
|
// The IRP has already been cancelled or endpoint in cleanup phase. Complete it now.
|
|
//
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE(("TCP: irp %lx already cancelled, completing.\n", Irp));
|
|
}
|
|
|
|
CTEFreeLock(&TcpContext->EndpointLock, CancelHandle);
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (STATUS_CANCELLED);
|
|
|
|
} // TCPPrepareIrpForCancel
|
|
|
|
//
|
|
// TDI functions
|
|
//
|
|
NTSTATUS
|
|
TCPAssociateAddress(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_ASSOCIATE associateInformation;
|
|
PFILE_OBJECT fileObject;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPAssociateAddress(%x, %x)\n"),
|
|
Irp, IrpSp));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
associateInformation = (PTDI_REQUEST_KERNEL_ASSOCIATE) & (IrpSp->Parameters);
|
|
|
|
//
|
|
// Get the file object for the address. Then extract the Address Handle
|
|
// from the TCP_CONTEXT associated with it.
|
|
//
|
|
|
|
|
|
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
associateInformation->AddressHandle,
|
|
0,
|
|
*IoFileObjectType,
|
|
Irp->RequestorMode,
|
|
&fileObject,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if ((fileObject->DeviceObject == TCPDeviceObject) &&
|
|
(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
) {
|
|
BOOLEAN cleanup;
|
|
CTELockHandle CancelHandle;
|
|
|
|
tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
|
|
|
|
//if cleanup in progress, do not allow this operation.
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
cleanup = tcpContext->Cleanup;
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
|
|
if (!cleanup)
|
|
status = TdiAssociateAddress(
|
|
&request,
|
|
tcpContext->Handle.AddressHandle
|
|
);
|
|
|
|
ASSERT(status != STATUS_PENDING);
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
|
|
TCPTRACE((
|
|
"TCPAssociateAddress complete on file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
} else {
|
|
ObDereferenceObject(fileObject);
|
|
status = STATUS_INVALID_HANDLE;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
|
|
TCPTRACE((
|
|
"TCPAssociateAddress: ObReference failed on object %lx, status %lx\n",
|
|
associateInformation->AddressHandle,
|
|
status
|
|
));
|
|
}
|
|
}
|
|
} else {
|
|
DEBUGMSG(DBG_ERROR && DBG_TDI,
|
|
(DTEXT("TdiAssociateAddress: ObReference failure %x on handle %x\n"),
|
|
status, associateInformation->AddressHandle));
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPAssociateAddress [%x]\n"), status));
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPDisassociateAddress(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
|
|
|
|
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 successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDisassociateAddress \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
|
|
TCPTRACE(("TCP disassociating address\n"));
|
|
}
|
|
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = TdiDisAssociateAddress(&request);
|
|
|
|
if (status != TDI_PENDING) {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDisassociateAddress \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPDisassociateAddress
|
|
|
|
NTSTATUS
|
|
TCPConnect(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Connect IRP into a call to TdiConnect.
|
|
|
|
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;
|
|
PTCP_CONTEXT tcpContext;
|
|
TDI_REQUEST request;
|
|
PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
|
|
PTDI_REQUEST_KERNEL_CONNECT connectRequest;
|
|
LARGE_INTEGER millisecondTimeout;
|
|
PLARGE_INTEGER requestTimeout;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPConnect \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPConnect irp %lx, file object %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
ASSERT((PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
|
|
(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE));
|
|
|
|
|
|
connectRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
|
|
requestInformation = connectRequest->RequestConnectionInformation;
|
|
returnInformation = connectRequest->ReturnConnectionInformation;
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
requestTimeout = (PLARGE_INTEGER) connectRequest->RequestSpecific;
|
|
|
|
if (requestTimeout != NULL) {
|
|
//
|
|
// NT relative timeouts are negative. Negate first to get a positive
|
|
// value to pass to the transport.
|
|
//
|
|
millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
|
|
millisecondTimeout = CTEConvert100nsToMilliseconds(
|
|
millisecondTimeout
|
|
);
|
|
} else {
|
|
millisecondTimeout.LowPart = 0;
|
|
millisecondTimeout.HighPart = 0;
|
|
}
|
|
|
|
ASSERT(millisecondTimeout.HighPart == 0);
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
|
|
if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
|
|
status = TdiConnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
} else if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
|
|
|
|
status = UDPConnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect on neither address/connect file\n"));
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
if (status != STATUS_PENDING) {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (STATUS_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPConnect \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPConnect
|
|
|
|
NTSTATUS
|
|
TCPDisconnect(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Disconnect IRP into a call to TdiDisconnect.
|
|
|
|
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.
|
|
|
|
Notes:
|
|
|
|
Abortive disconnects may pend, but cannot be cancelled.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTCP_CONTEXT tcpContext;
|
|
TDI_REQUEST request;
|
|
PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
|
|
PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
|
|
LARGE_INTEGER millisecondTimeout;
|
|
PLARGE_INTEGER requestTimeout;
|
|
BOOLEAN abortive = FALSE;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDisconnect \n")));
|
|
|
|
ASSERT((PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
|
|
(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE));
|
|
|
|
|
|
disconnectRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
|
|
requestInformation = disconnectRequest->RequestConnectionInformation;
|
|
returnInformation = disconnectRequest->ReturnConnectionInformation;
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestContext = Irp;
|
|
|
|
//
|
|
// Set up the timeout value.
|
|
//
|
|
if (disconnectRequest->RequestSpecific != NULL) {
|
|
requestTimeout = (PLARGE_INTEGER) disconnectRequest->RequestSpecific;
|
|
|
|
if ((requestTimeout->LowPart == -1) && (requestTimeout->HighPart == -1)) {
|
|
|
|
// This is infinite time timeout period
|
|
// Just use 0 timeout value
|
|
|
|
millisecondTimeout.LowPart = 0;
|
|
millisecondTimeout.HighPart = 0;
|
|
} else {
|
|
//
|
|
// NT relative timeouts are negative. Negate first to get a
|
|
// positive value to pass to the transport.
|
|
//
|
|
millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
|
|
millisecondTimeout = CTEConvert100nsToMilliseconds(
|
|
millisecondTimeout
|
|
);
|
|
}
|
|
} else {
|
|
millisecondTimeout.LowPart = 0;
|
|
millisecondTimeout.HighPart = 0;
|
|
}
|
|
|
|
|
|
if (disconnectRequest->RequestFlags & TDI_DISCONNECT_ABORT) {
|
|
//
|
|
// Abortive disconnects cannot be cancelled and must use
|
|
// a specific completion routine.
|
|
//
|
|
abortive = TRUE;
|
|
IoMarkIrpPending(Irp);
|
|
request.RequestNotifyObject = TCPNonCancellableRequestComplete;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
//
|
|
// Non-abortive disconnects can use the generic cancellation and
|
|
// completion routines.
|
|
//
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
request.RequestNotifyObject = TCPRequestComplete;
|
|
}
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE((
|
|
"TCPDisconnect irp %lx, flags %lx, fileobj %lx, abortive = %d\n",
|
|
Irp,
|
|
disconnectRequest->RequestFlags,
|
|
IrpSp->FileObject,
|
|
abortive
|
|
));
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
status = TdiDisconnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
(ushort) disconnectRequest->RequestFlags,
|
|
requestInformation,
|
|
returnInformation,
|
|
(TCPAbortReq*)&Irp->Tail.Overlay.DriverContext[0]
|
|
);
|
|
|
|
} else if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
|
|
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"DisConnect on address file Irp %x \n", Irp));
|
|
|
|
status = UDPDisconnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
} else {
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"DisConnect on neither address/connect file\n"));
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
if (status != STATUS_PENDING) {
|
|
if (abortive) {
|
|
TCPNonCancellableRequestComplete(Irp, status, 0);
|
|
} else {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
} else {
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE(("TCPDisconnect pending irp %lx\n", Irp));
|
|
}
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (STATUS_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDisconnect \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPDisconnect
|
|
|
|
NTSTATUS
|
|
TCPListen(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Listen IRP into a call to TdiListen.
|
|
|
|
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 successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTCP_CONTEXT tcpContext;
|
|
TDI_REQUEST request;
|
|
PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
|
|
PTDI_REQUEST_KERNEL_LISTEN listenRequest;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPListen \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPListen irp %lx on file object %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
|
|
listenRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
|
|
requestInformation = listenRequest->RequestConnectionInformation;
|
|
returnInformation = listenRequest->ReturnConnectionInformation;
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = TdiListen(
|
|
&request,
|
|
(ushort) listenRequest->RequestFlags,
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
if (status != TDI_PENDING) {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPListen \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPListen
|
|
|
|
NTSTATUS
|
|
TCPAccept(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Accept IRP into a call to TdiAccept.
|
|
|
|
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;
|
|
PTCP_CONTEXT tcpContext;
|
|
TDI_REQUEST request;
|
|
PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
|
|
PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPAccept \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPAccept irp %lx on file object %lx\n", Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
|
|
acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT) & (IrpSp->Parameters);
|
|
requestInformation = acceptRequest->RequestConnectionInformation;
|
|
returnInformation = acceptRequest->ReturnConnectionInformation;
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = TdiAccept(
|
|
&request,
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
if (status != TDI_PENDING) {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPAccept \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPAccept
|
|
|
|
NTSTATUS
|
|
TCPSendData(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Send IRP into a call to TdiSend.
|
|
|
|
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 successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_STATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_SEND requestInformation;
|
|
KIRQL oldIrql;
|
|
CTELockHandle CancelHandle;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
ULONG LocalCancelId;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSendData \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
requestInformation = (PTDI_REQUEST_KERNEL_SEND) & (IrpSp->Parameters);
|
|
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
ASSERT(Irp->CancelRoutine == NULL);
|
|
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
IoSetCancelRoutine(Irp, TCPCancelRequest);
|
|
|
|
if (!Irp->Cancel) {
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
tcpContext->ReferenceCount++;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPSendData: irp %lx fileobj %lx refcnt inc to %u\n",
|
|
Irp,
|
|
IrpSp,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
#if DBG
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
PLIST_ENTRY entry;
|
|
PIRP item = NULL;
|
|
|
|
//
|
|
// Verify that the Irp has not already been submitted.
|
|
//
|
|
for (entry = tcpContext->PendingIrpList.Flink;
|
|
entry != &(tcpContext->PendingIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
for (entry = tcpContext->CancelledIrpList.Flink;
|
|
entry != &(tcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(tcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
//Update monotonically increasing cancel ID and
|
|
//remember this for later use
|
|
|
|
while ((LocalCancelId = InterlockedIncrement((PLONG)&CancelId.Value)) == 0) { }
|
|
|
|
Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(LocalCancelId);
|
|
Irp->Tail.Overlay.DriverContext[0] = NULL;
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE((
|
|
"TCPSendData irp %lx sending %d bytes, flags %lx, fileobj %lx\n",
|
|
Irp,
|
|
requestInformation->SendLength,
|
|
requestInformation->SendFlags,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiSend(
|
|
&request,
|
|
(ushort) requestInformation->SendFlags,
|
|
requestInformation->SendLength,
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
if (status == TDI_PENDING) {
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE(("TCPSendData pending irp %lx\n", Irp));
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
//
|
|
// The status is not pending. We reset the pending bit
|
|
//
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
ASSERT(requestInformation->SendLength == 0);
|
|
|
|
status = TCPDataRequestComplete(Irp, status, requestInformation->SendLength);
|
|
} else {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE((
|
|
"TCPSendData - irp %lx send failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
}
|
|
|
|
status = TCPDataRequestComplete(Irp, status, 0);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Irp was cancelled previously.
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
//Let cancel routine run
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE((
|
|
"TCPSendData: Irp %lx on fileobj %lx was cancelled\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
status = STATUS_CANCELLED;
|
|
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSendData \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPSendData
|
|
|
|
NTSTATUS
|
|
TCPReceiveData(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Receive IRP into a call to TdiReceive.
|
|
|
|
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 successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_STATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_RECEIVE requestInformation;
|
|
KIRQL oldIrql;
|
|
CTELockHandle CancelHandle;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPReceiveData \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
requestInformation = (PTDI_REQUEST_KERNEL_RECEIVE) & (IrpSp->Parameters);
|
|
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
ASSERT(Irp->CancelRoutine == NULL);
|
|
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
IoSetCancelRoutine(Irp, TCPCancelRequest);
|
|
|
|
if (!Irp->Cancel) {
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
tcpContext->ReferenceCount++;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPReceiveData: irp %lx fileobj %lx refcnt inc to %u\n",
|
|
Irp,
|
|
IrpSp->FileObject,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
#if DBG
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
PLIST_ENTRY entry;
|
|
PIRP item = NULL;
|
|
|
|
//
|
|
// Verify that the Irp has not already been submitted.
|
|
//
|
|
for (entry = tcpContext->PendingIrpList.Flink;
|
|
entry != &(tcpContext->PendingIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
for (entry = tcpContext->CancelledIrpList.Flink;
|
|
entry != &(tcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
ASSERT(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(tcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
IF_TCPDBG(TCP_DEBUG_RECEIVE) {
|
|
TCPTRACE((
|
|
"TCPReceiveData irp %lx receiving %d bytes flags %lx filobj %lx\n",
|
|
Irp,
|
|
requestInformation->ReceiveLength,
|
|
requestInformation->ReceiveFlags,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiReceive(
|
|
&request,
|
|
(ushort *) & (requestInformation->ReceiveFlags),
|
|
(uint*)&(requestInformation->ReceiveLength),
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
if (status == TDI_PENDING) {
|
|
IF_TCPDBG(TCP_DEBUG_RECEIVE) {
|
|
TCPTRACE(("TCPReceiveData: pending irp %lx\n", Irp));
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
//
|
|
// The status is not pending. We reset the pending bit
|
|
//
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
// ASSERT(status != TDI_SUCCESS);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_RECEIVE) {
|
|
TCPTRACE((
|
|
"TCPReceiveData - irp %lx failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
}
|
|
|
|
status = TCPDataRequestComplete(Irp, status, 0);
|
|
} else {
|
|
//
|
|
// Irp was cancelled previously.
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
//Synchoronize with cancel routine by using both iocancelspinlocks
|
|
//and endpoint locks
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE((
|
|
"TCPReceiveData: Irp %lx on fileobj %lx was cancelled\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
status = STATUS_CANCELLED;
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPReceiveData \n")));
|
|
|
|
return status;
|
|
|
|
} // TCPReceiveData
|
|
|
|
|
|
NTSTATUS
|
|
UDPSendData(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TDI_STATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_SEND datagramInformation;
|
|
ULONG bytesSent = 0;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+UDPSendData \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
datagramInformation = (PTDI_REQUEST_KERNEL_SEND) & (IrpSp->Parameters);
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
|
|
TCPTRACE((
|
|
"UDPSendData irp %lx sending %d bytes\n",
|
|
Irp,
|
|
datagramInformation->SendLength
|
|
));
|
|
}
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
AddrObj *AO = request.Handle.AddressHandle;
|
|
|
|
if (AO && (AO->ao_flags & AO_CONNUDP_FLAG)) {
|
|
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiSendDatagram(
|
|
&request,
|
|
NULL,
|
|
datagramInformation->SendLength,
|
|
(uint*)&bytesSent,
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
if (status == TDI_PENDING) {
|
|
return (status);
|
|
}
|
|
} else {
|
|
|
|
status = TDI_ADDR_INVALID;
|
|
}
|
|
|
|
ASSERT(status != TDI_SUCCESS);
|
|
ASSERT(bytesSent == 0);
|
|
|
|
TCPTRACE((
|
|
"UDPSendData - irp %lx send failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
|
|
TCPDataRequestComplete(Irp, status, bytesSent);
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
UDPSendDatagram(
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_STATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_SENDDG datagramInformation;
|
|
ULONG bytesSent = 0;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_TX, (DTEXT("+UDPSendDatagram\n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
datagramInformation = (PTDI_REQUEST_KERNEL_SENDDG) & (IrpSp->Parameters);
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
|
|
TCPTRACE((
|
|
"UDPSendDatagram irp %lx sending %d bytes\n",
|
|
Irp,
|
|
datagramInformation->SendLength
|
|
));
|
|
}
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiSendDatagram(
|
|
&request,
|
|
datagramInformation->SendDatagramInformation,
|
|
datagramInformation->SendLength,
|
|
(uint*)&bytesSent,
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
if (status == TDI_PENDING) {
|
|
return (status);
|
|
}
|
|
ASSERT(status != TDI_SUCCESS);
|
|
ASSERT(bytesSent == 0);
|
|
|
|
TCPTRACE((
|
|
"UDPSendDatagram - irp %lx send failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
|
|
TCPDataRequestComplete(Irp, status, bytesSent);
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-UDPSendDatagram \n")));
|
|
|
|
return status;
|
|
|
|
} // UDPSendDatagram
|
|
|
|
NTSTATUS
|
|
UDPReceiveDatagram(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI ReceiveDatagram IRP into a call to TdiReceiveDatagram.
|
|
|
|
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 successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_STATUS status;
|
|
TDI_REQUEST request;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_RECEIVEDG datagramInformation;
|
|
uint bytesReceived = 0;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+UDPReceiveDatagram \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
datagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG) & (IrpSp->Parameters);
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_RECEIVE_DGRAM) {
|
|
TCPTRACE((
|
|
"UDPReceiveDatagram: irp %lx receiveing %d bytes\n",
|
|
Irp,
|
|
datagramInformation->ReceiveLength
|
|
));
|
|
}
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiReceiveDatagram(
|
|
&request,
|
|
datagramInformation->ReceiveDatagramInformation,
|
|
datagramInformation->ReturnDatagramInformation,
|
|
datagramInformation->ReceiveLength,
|
|
&bytesReceived,
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
if (status == TDI_PENDING) {
|
|
return (status);
|
|
}
|
|
ASSERT(status != TDI_SUCCESS);
|
|
ASSERT(bytesReceived == 0);
|
|
|
|
TCPTRACE((
|
|
"UDPReceiveDatagram: irp %lx send failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
|
|
TCPDataRequestComplete(Irp, status, bytesReceived);
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return (TDI_PENDING);
|
|
}
|
|
return status;
|
|
|
|
} // UDPReceiveDatagram
|
|
|
|
|
|
NTSTATUS
|
|
TCPSetEventHandler(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI SetEventHandler IRP into a call to TdiSetEventHandler.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PTDI_REQUEST_KERNEL_SET_EVENT event;
|
|
PTCP_CONTEXT tcpContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSetEventHandler \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
event = (PTDI_REQUEST_KERNEL_SET_EVENT) & (IrpSp->Parameters);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_EVENT_HANDLER) {
|
|
TCPTRACE((
|
|
"TCPSetEventHandler: irp %lx event %lx handler %lx context %lx\n",
|
|
Irp,
|
|
event->EventType,
|
|
event->EventHandler,
|
|
event->EventContext
|
|
));
|
|
}
|
|
|
|
status = TdiSetEvent(
|
|
tcpContext->Handle.AddressHandle,
|
|
event->EventType,
|
|
event->EventHandler,
|
|
event->EventContext
|
|
);
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSetEventHandler \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPSetEventHandler
|
|
|
|
|
|
NTSTATUS
|
|
TCPQueryInformation(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI QueryInformation IRP into a call to TdiQueryInformation.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_REQUEST request;
|
|
TDI_STATUS status = STATUS_SUCCESS;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTDI_REQUEST_KERNEL_QUERY_INFORMATION queryInformation;
|
|
uint isConn = FALSE;
|
|
uint dataSize = 0;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPQueryInformation \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
queryInformation = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
|
|
& (IrpSp->Parameters);
|
|
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
switch (queryInformation->QueryType) {
|
|
|
|
case TDI_QUERY_BROADCAST_ADDRESS:
|
|
ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
|
|
TDI_CONTROL_CHANNEL_FILE
|
|
);
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_INFO:
|
|
//
|
|
// NetBT does this. Reinstate the ASSERT when it is fixed.
|
|
//
|
|
// ASSERT( ((int) IrpSp->FileObject->FsContext2) ==
|
|
// TDI_CONTROL_CHANNEL_FILE
|
|
// );
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
//
|
|
// This is a TCP connection object.
|
|
//
|
|
isConn = TRUE;
|
|
request.Handle.ConnectionContext =
|
|
tcpContext->Handle.ConnectionContext;
|
|
} else {
|
|
//
|
|
// This is an address object
|
|
//
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
}
|
|
break;
|
|
|
|
case TDI_QUERY_CONNECTION_INFO:
|
|
|
|
if (PtrToUlong(IrpSp->FileObject->FsContext2) != TDI_CONNECTION_FILE){
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
isConn = TRUE;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
}
|
|
break;
|
|
|
|
|
|
case TDI_QUERY_PROVIDER_STATISTICS:
|
|
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_ROUTING_INFO:
|
|
if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
isConn = TRUE;
|
|
} else if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
|
|
//
|
|
// This request isn't cancellable, but we put it through
|
|
// the cancel path because it handles some checks for us
|
|
// and tracks the irp.
|
|
//
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
dataSize = TCPGetMdlChainByteCount(Irp->MdlAddress);
|
|
status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiQueryInformation(
|
|
&request,
|
|
queryInformation,
|
|
pNdisBuffer,
|
|
&dataSize,
|
|
isConn
|
|
);
|
|
}
|
|
|
|
if (status != TDI_PENDING) {
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
status = TCPDataRequestComplete(Irp, status, dataSize);
|
|
return (status);
|
|
}
|
|
|
|
return (STATUS_PENDING);
|
|
}
|
|
return (status);
|
|
}
|
|
Irp->IoStatus.Status = (NTSTATUS) status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformation \n")));
|
|
return (status);
|
|
|
|
} // TCPQueryInformation
|
|
|
|
NTSTATUS
|
|
TCPQueryInformationExComplete(
|
|
void *Context,
|
|
NTSTATUS Status,
|
|
unsigned int ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a TdiQueryInformationEx request.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - The final TDI status of the request.
|
|
ByteCount - Bytes returned in output buffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
{
|
|
PTCP_QUERY_CONTEXT queryContext = (PTCP_QUERY_CONTEXT) Context;
|
|
ULONG bytesCopied;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI,
|
|
(DTEXT("+TCPQueryInformationExComplete(%x, %x, %d)\n"),
|
|
Context, Status, ByteCount));
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Copy the returned context to the input buffer.
|
|
//
|
|
#if defined(_WIN64)
|
|
if (IoIs32bitProcess(queryContext->Irp)) {
|
|
TdiCopyBufferToMdl(
|
|
&queryContext->QueryInformation.Context,
|
|
0,
|
|
CONTEXT_SIZE,
|
|
queryContext->InputMdl,
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context),
|
|
&bytesCopied
|
|
);
|
|
} else {
|
|
#endif // _WIN64
|
|
TdiCopyBufferToMdl(
|
|
&(queryContext->QueryInformation.Context),
|
|
0,
|
|
CONTEXT_SIZE,
|
|
queryContext->InputMdl,
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
|
|
&bytesCopied
|
|
);
|
|
#if defined(_WIN64)
|
|
}
|
|
#endif // _WIN64
|
|
|
|
if (bytesCopied != CONTEXT_SIZE) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ByteCount = 0;
|
|
}
|
|
}
|
|
//
|
|
// Unlock the user's buffers and free the MDLs describing them.
|
|
//
|
|
MmUnlockPages(queryContext->InputMdl);
|
|
IoFreeMdl(queryContext->InputMdl);
|
|
MmUnlockPages(queryContext->OutputMdl);
|
|
IoFreeMdl(queryContext->OutputMdl);
|
|
|
|
//
|
|
// Complete the request
|
|
//
|
|
Status = TCPDataRequestComplete(queryContext->Irp, Status, ByteCount);
|
|
|
|
CTEFreeMem(queryContext);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformationExComplete \n")));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPQueryInformationEx(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI QueryInformationEx IRP into a call to TdiQueryInformationEx.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_REQUEST request;
|
|
TDI_STATUS status = STATUS_SUCCESS;
|
|
PTCP_CONTEXT tcpContext;
|
|
uint size;
|
|
PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
|
|
PVOID OutputBuffer;
|
|
PMDL inputMdl = NULL;
|
|
PMDL outputMdl = NULL;
|
|
ULONG InputBufferLength, OutputBufferLength;
|
|
PTCP_QUERY_CONTEXT queryContext;
|
|
BOOLEAN inputLocked = FALSE;
|
|
BOOLEAN outputLocked = FALSE;
|
|
#if defined(_WIN64)
|
|
BOOLEAN is32bitProcess = FALSE;
|
|
#endif // _WIN64
|
|
BOOLEAN inputBufferValid = FALSE;
|
|
ULONG AllocSize = 0;
|
|
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPQueryInformationEx \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInformationEx starting - irp %lx fileobj %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
|
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
//
|
|
// Validate the input parameters
|
|
//
|
|
#if defined(_WIN64)
|
|
if ((is32bitProcess = IoIs32bitProcess(Irp)) != 0) {
|
|
if (InputBufferLength >= sizeof(TCP_REQUEST_QUERY_INFORMATION_EX32) &&
|
|
InputBufferLength < MAXLONG) {
|
|
inputBufferValid = TRUE;
|
|
AllocSize =
|
|
FIELD_OFFSET(TCP_QUERY_CONTEXT, QueryInformation.Context) +
|
|
InputBufferLength -
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context);
|
|
} else {
|
|
inputBufferValid = FALSE;
|
|
}
|
|
} else {
|
|
#endif // _WIN64
|
|
if (InputBufferLength >= sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) &&
|
|
InputBufferLength < MAXLONG) {
|
|
inputBufferValid = TRUE;
|
|
AllocSize =
|
|
FIELD_OFFSET(TCP_QUERY_CONTEXT, QueryInformation) +
|
|
InputBufferLength;
|
|
} else {
|
|
inputBufferValid = FALSE;
|
|
}
|
|
#if defined(_WIN64)
|
|
}
|
|
#endif // _WIN64
|
|
if (inputBufferValid && OutputBufferLength != 0) {
|
|
|
|
OutputBuffer = Irp->UserBuffer;
|
|
InputBuffer =
|
|
(PTCP_REQUEST_QUERY_INFORMATION_EX)
|
|
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
queryContext = CTEAllocMem(AllocSize);
|
|
|
|
if (queryContext != NULL) {
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CTEFreeMem(queryContext);
|
|
return (status);
|
|
}
|
|
//
|
|
// Allocate Mdls to describe the input and output buffers.
|
|
// Probe and lock the buffers.
|
|
//
|
|
try {
|
|
inputMdl = IoAllocateMdl(
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
FALSE,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
outputMdl = IoAllocateMdl(
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
FALSE,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if ((inputMdl != NULL) && (outputMdl != NULL)) {
|
|
|
|
MmProbeAndLockPages(
|
|
inputMdl,
|
|
Irp->RequestorMode,
|
|
IoModifyAccess
|
|
);
|
|
|
|
inputLocked = TRUE;
|
|
|
|
MmProbeAndLockPages(
|
|
outputMdl,
|
|
Irp->RequestorMode,
|
|
IoWriteAccess
|
|
);
|
|
|
|
outputLocked = TRUE;
|
|
|
|
//
|
|
// Copy the input parameter to our pool block so
|
|
// TdiQueryInformationEx can manipulate it directly.
|
|
//
|
|
#if defined(_WIN64)
|
|
if (is32bitProcess) {
|
|
RtlCopyMemory(
|
|
&queryContext->QueryInformation,
|
|
InputBuffer,
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context)
|
|
);
|
|
RtlCopyMemory(
|
|
&queryContext->QueryInformation.Context,
|
|
(PUCHAR)InputBuffer +
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context),
|
|
InputBufferLength -
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context)
|
|
);
|
|
} else {
|
|
#endif // _WIN64
|
|
RtlCopyMemory(
|
|
&queryContext->QueryInformation,
|
|
InputBuffer,
|
|
InputBufferLength
|
|
);
|
|
#if defined(_WIN64)
|
|
}
|
|
#endif // _WIN64
|
|
} else {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE(("QueryInfoEx: Couldn't allocate MDL\n"));
|
|
}
|
|
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInfoEx: exception copying input params %lx\n",
|
|
GetExceptionCode()
|
|
));
|
|
}
|
|
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PNDIS_BUFFER OutputNdisBuf;
|
|
|
|
//
|
|
// It's finally time to do this thing.
|
|
//
|
|
size = TCPGetMdlChainByteCount(outputMdl);
|
|
|
|
queryContext->Irp = Irp;
|
|
queryContext->InputMdl = inputMdl;
|
|
queryContext->OutputMdl = outputMdl;
|
|
|
|
request.RequestNotifyObject = TCPQueryInformationExComplete;
|
|
request.RequestContext = queryContext;
|
|
|
|
status = ConvertMdlToNdisBuffer(Irp, outputMdl, &OutputNdisBuf);
|
|
|
|
if (status == TDI_SUCCESS) {
|
|
status = TdiQueryInformationEx(
|
|
&request,
|
|
&(queryContext->QueryInformation.ID),
|
|
OutputNdisBuf,
|
|
&size,
|
|
&(queryContext->QueryInformation.Context)
|
|
);
|
|
}
|
|
|
|
if (status != TDI_PENDING) {
|
|
|
|
// Since status is not pending, clear the
|
|
// control flag to keep IO verifier happy.
|
|
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
status = TCPQueryInformationExComplete(
|
|
queryContext,
|
|
status,
|
|
size
|
|
);
|
|
return (status);
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInformationEx - pending irp %lx fileobj %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
return (STATUS_PENDING);
|
|
}
|
|
//
|
|
// If we get here, something failed. Clean up.
|
|
//
|
|
if (inputMdl != NULL) {
|
|
if (inputLocked) {
|
|
MmUnlockPages(inputMdl);
|
|
}
|
|
IoFreeMdl(inputMdl);
|
|
}
|
|
if (outputMdl != NULL) {
|
|
if (outputLocked) {
|
|
MmUnlockPages(outputMdl);
|
|
}
|
|
IoFreeMdl(outputMdl);
|
|
}
|
|
CTEFreeMem(queryContext);
|
|
|
|
// Since status is not pending, clear the
|
|
// control flag to keep IO verifier happy.
|
|
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
// This Irp may be in the process of cancellation
|
|
// get the real status used in irp completion
|
|
|
|
status = TCPDataRequestComplete(Irp, status, 0);
|
|
|
|
return (status);
|
|
|
|
} else {
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE(("QueryInfoEx: Unable to allocate query context\n"));
|
|
}
|
|
}
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInfoEx: Bad buffer len, OBufLen %d, InBufLen %d\n",
|
|
OutputBufferLength, InputBufferLength
|
|
));
|
|
}
|
|
}
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInformationEx complete - irp %lx, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
}
|
|
|
|
Irp->IoStatus.Status = (NTSTATUS) status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformationEx \n")));
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPSetInformationEx(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI SetInformationEx IRP into a call to TdiSetInformationEx.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_REQUEST request;
|
|
TDI_STATUS status;
|
|
PTCP_CONTEXT tcpContext;
|
|
PTCP_REQUEST_SET_INFORMATION_EX setInformation;
|
|
|
|
PAGED_CODE();
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSetInformationEx \n")));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"SetInformationEx - irp %lx fileobj %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
setInformation = (PTCP_REQUEST_SET_INFORMATION_EX)
|
|
Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) ||
|
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength -
|
|
FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) < setInformation->BufferSize) {
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
|
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_TCP_WSH_SET_INFORMATION_EX) {
|
|
uint Entity;
|
|
|
|
Entity = setInformation->ID.toi_entity.tei_entity;
|
|
|
|
if ((Entity != CO_TL_ENTITY) && (Entity != CL_TL_ENTITY) ) {
|
|
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_ACCESS_DENIED);
|
|
}
|
|
|
|
}
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
request.RequestNotifyObject = TCPDataRequestComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
status = TdiSetInformationEx(
|
|
&request,
|
|
&(setInformation->ID),
|
|
&(setInformation->Buffer[0]),
|
|
setInformation->BufferSize
|
|
);
|
|
|
|
if (status != TDI_PENDING) {
|
|
|
|
DEBUGMSG(status != TDI_SUCCESS && DBG_ERROR && DBG_SETINFO,
|
|
(DTEXT("TCPSetInformationEx: TdiSetInformationEx failure %x\n"),
|
|
status));
|
|
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
status = TCPDataRequestComplete(
|
|
Irp,
|
|
status,
|
|
0
|
|
);
|
|
|
|
return (status);
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"SetInformationEx - pending irp %lx fileobj %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
return (STATUS_PENDING);
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"SetInformationEx complete - irp %lx\n",
|
|
Irp
|
|
));
|
|
}
|
|
|
|
//
|
|
// The irp has already been completed.
|
|
//
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSetInformationEx \n")));
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TCPControlSecurityFilter(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes a request to query or set the status of security filtering.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PTCP_SECURITY_FILTER_STATUS request;
|
|
ULONG requestLength;
|
|
ULONG requestCode;
|
|
TDI_STATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
request = (PTCP_SECURITY_FILTER_STATUS) Irp->AssociatedIrp.SystemBuffer;
|
|
requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
if (requestCode == IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS) {
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
request->FilteringEnabled = IsSecurityFilteringEnabled();
|
|
Irp->IoStatus.Information = sizeof(TCP_SECURITY_FILTER_STATUS);
|
|
}
|
|
} else {
|
|
ASSERT(requestCode == IOCTL_TCP_SET_SECURITY_FILTER_STATUS);
|
|
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
ControlSecurityFiltering(request->FilteringEnabled);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPProcessSecurityFilterRequest(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes a request to add or delete a transport security filter.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCPSecurityFilterEntry *request;
|
|
ULONG requestLength;
|
|
ULONG requestCode;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
if (requestLength < sizeof(TCPSecurityFilterEntry)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
if (requestCode == IOCTL_TCP_ADD_SECURITY_FILTER) {
|
|
status = AddValueSecurityFilter(
|
|
net_long(request->tsf_address),
|
|
request->tsf_protocol,
|
|
request->tsf_value
|
|
);
|
|
} else {
|
|
ASSERT(requestCode == IOCTL_TCP_DELETE_SECURITY_FILTER);
|
|
status = DeleteValueSecurityFilter(
|
|
net_long(request->tsf_address),
|
|
request->tsf_protocol,
|
|
request->tsf_value
|
|
);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPEnumerateSecurityFilter(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes a request to enumerate a transport security filter list.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TCPSecurityFilterEntry *request;
|
|
TCPSecurityFilterEnum *response;
|
|
ULONG requestLength, responseLength;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
|
|
response = (TCPSecurityFilterEnum *) request;
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (requestLength < sizeof(TCPSecurityFilterEntry)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
} else if (responseLength < sizeof(TCPSecurityFilterEnum)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
Irp->IoStatus.Information = 0;
|
|
} else {
|
|
EnumerateSecurityFilters(
|
|
net_long(request->tsf_address),
|
|
request->tsf_protocol,
|
|
request->tsf_value,
|
|
(uchar *) (response + 1),
|
|
responseLength - sizeof(TCPSecurityFilterEnum),
|
|
&(response->tfe_entries_returned),
|
|
&(response->tfe_entries_available)
|
|
);
|
|
|
|
status = TDI_SUCCESS;
|
|
Irp->IoStatus.Information =
|
|
sizeof(TCPSecurityFilterEnum) +
|
|
(response->tfe_entries_returned * sizeof(TCPSecurityFilterEntry));
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TCPReservePorts(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
{
|
|
ULONG requestLength;
|
|
ULONG requestCode;
|
|
TDI_STATUS status = STATUS_SUCCESS;
|
|
PTCP_RESERVE_PORT_RANGE request;
|
|
CTELockHandle Handle;
|
|
|
|
//PAGED_CODE();
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
request = (PTCP_RESERVE_PORT_RANGE) Irp->AssociatedIrp.SystemBuffer;
|
|
requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
if (requestLength < sizeof(TCP_RESERVE_PORT_RANGE)) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
|
|
}
|
|
if ((request->UpperRange >= request->LowerRange) &&
|
|
(request->LowerRange >= MIN_USER_PORT) &&
|
|
(request->UpperRange <= MaxUserPort)) {
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TCP_RESERVE_PORT_RANGE) {
|
|
ReservedPortListEntry *ListEntry;
|
|
|
|
ListEntry = CTEAllocMem(sizeof(ReservedPortListEntry));
|
|
|
|
if (ListEntry) {
|
|
|
|
ListEntry->UpperRange = request->UpperRange;
|
|
ListEntry->LowerRange = request->LowerRange;
|
|
|
|
CTEGetLock(&AddrObjTableLock.Lock, &Handle);
|
|
ListEntry->next = PortRangeList;
|
|
PortRangeList = ListEntry;
|
|
CTEFreeLock(&AddrObjTableLock.Lock, Handle);
|
|
} else
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else if (PortRangeList) {
|
|
//UNRESERVE
|
|
|
|
|
|
ReservedPortListEntry *ListEntry, *PrevEntry;
|
|
|
|
CTEGetLock(&AddrObjTableLock.Lock, &Handle);
|
|
|
|
ListEntry = PortRangeList;
|
|
PrevEntry = ListEntry;
|
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
while (ListEntry) {
|
|
|
|
if ((request->LowerRange <= ListEntry->LowerRange) &&
|
|
(request->UpperRange >= ListEntry->UpperRange)) {
|
|
//This list should be deleted.
|
|
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Deleting port range %d to %d\n", request->LowerRange, request->UpperRange));
|
|
|
|
if (PrevEntry == PortRangeList) {
|
|
PortRangeList = ListEntry->next;
|
|
CTEFreeMem(ListEntry);
|
|
ListEntry = PortRangeList;
|
|
} else {
|
|
PrevEntry->next = ListEntry->next;
|
|
CTEFreeMem(ListEntry);
|
|
ListEntry = PrevEntry->next;
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
} else {
|
|
PrevEntry = ListEntry;
|
|
ListEntry = ListEntry->next;
|
|
}
|
|
|
|
}
|
|
CTEFreeLock(&AddrObjTableLock.Lock, Handle);
|
|
|
|
}
|
|
} else
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (status);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
BlockTCPPorts(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
{
|
|
TDI_STATUS status = STATUS_SUCCESS;
|
|
BOOLEAN ReservePorts;
|
|
CTELockHandle Handle;
|
|
ULONG requestLength, responseLength;
|
|
PTCP_BLOCKPORTS_REQUEST request;
|
|
PULONG response;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
request = (PTCP_BLOCKPORTS_REQUEST) Irp->AssociatedIrp.SystemBuffer;
|
|
response = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (requestLength < sizeof(TCP_BLOCKPORTS_REQUEST)) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
ReservePorts = (uchar) request->ReservePorts;
|
|
|
|
if (ReservePorts) {
|
|
|
|
ushort LowerRange = MaxUserPort + 1;
|
|
ushort UpperRange = 65534;
|
|
uint NumberofPorts = request->NumberofPorts;
|
|
ReservedPortListEntry *tmpEntry, *ListEntry, *prevEntry = NULL;
|
|
AddrObj *ExistingAO;
|
|
uint PortsRemaining;
|
|
ushort Start;
|
|
ushort netStart;
|
|
ushort LeftEdge;
|
|
|
|
if (responseLength < sizeof(ULONG)) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
if ((UpperRange - LowerRange + 1) < (ushort) NumberofPorts) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
if (!NumberofPorts) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
CTEGetLock(&AddrObjTableLock.Lock, &Handle);
|
|
|
|
// its assumed that BlockedPortList is sorted in the order of port number range
|
|
|
|
tmpEntry = BlockedPortList;
|
|
Start = LowerRange;
|
|
PortsRemaining = NumberofPorts;
|
|
LeftEdge = Start;
|
|
|
|
while (Start < UpperRange) {
|
|
// check whether the current port lies in the reserved range
|
|
|
|
if ((tmpEntry) && ((Start >= tmpEntry->LowerRange) && (Start <= tmpEntry->UpperRange))) {
|
|
Start = tmpEntry->UpperRange + 1;
|
|
PortsRemaining = NumberofPorts;
|
|
LeftEdge = Start;
|
|
prevEntry = tmpEntry;
|
|
tmpEntry = tmpEntry->next;
|
|
} else {
|
|
|
|
// Start port doesn't lie in the current blocked range
|
|
// check whether somebody has done a bind to it
|
|
|
|
netStart = net_short(Start);
|
|
ExistingAO = FindAddrObjWithPort(netStart);
|
|
|
|
if (ExistingAO) {
|
|
Start++;
|
|
PortsRemaining = NumberofPorts;
|
|
LeftEdge = Start;
|
|
} else {
|
|
PortsRemaining--;
|
|
Start++;
|
|
if (!PortsRemaining) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// we have either found the range
|
|
// or we couldn't find a contiguous range
|
|
|
|
if (!PortsRemaining) {
|
|
// we found the range
|
|
// return the range
|
|
// LeftEdge <-> LeftEdge + NumberofPorts - 1
|
|
ListEntry = CTEAllocMem(sizeof(ReservedPortListEntry));
|
|
|
|
if (ListEntry) {
|
|
ListEntry->LowerRange = LeftEdge;
|
|
ListEntry->UpperRange = LeftEdge + NumberofPorts - 1;
|
|
|
|
// BlockedPortList is a sorted list
|
|
|
|
if (prevEntry) {
|
|
// insert it after prevEntry
|
|
ListEntry->next = prevEntry->next;
|
|
prevEntry->next = ListEntry;
|
|
} else {
|
|
// this has to be the first element in the list
|
|
ListEntry->next = BlockedPortList;
|
|
BlockedPortList = ListEntry;
|
|
}
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
*response = LeftEdge;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
// no resources
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
} else {
|
|
// couldn't find the range
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
} else {
|
|
// unreserve the ports;
|
|
ReservedPortListEntry *CurrEntry = BlockedPortList;
|
|
ReservedPortListEntry *PrevEntry = NULL;
|
|
ULONG StartHandle;
|
|
|
|
StartHandle = request->StartHandle;
|
|
|
|
CTEGetLock(&AddrObjTableLock.Lock, &Handle);
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
while (CurrEntry) {
|
|
if (CurrEntry->LowerRange == StartHandle) {
|
|
// delete the entry
|
|
if (PrevEntry == NULL) {
|
|
// this is the first entry
|
|
BlockedPortList = CurrEntry->next;
|
|
} else {
|
|
// this is intermediate entry
|
|
PrevEntry->next = CurrEntry->next;
|
|
}
|
|
// free the current entry
|
|
CTEFreeMem(CurrEntry);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
} else if (StartHandle > CurrEntry->UpperRange) {
|
|
PrevEntry = CurrEntry;
|
|
CurrEntry = CurrEntry->next;
|
|
} else {
|
|
// the list is sorted can't find the handle
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CTEFreeLock(&AddrObjTableLock.Lock, Handle);
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPEnumerateConnectionList(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Processes a request to enumerate the workstation connection list.
|
|
|
|
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 successful.
|
|
|
|
Notes:
|
|
|
|
This routine does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TCPConnectionListEntry *request;
|
|
TCPConnectionListEnum *response;
|
|
ULONG requestLength, responseLength;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
request = (TCPConnectionListEntry *) Irp->AssociatedIrp.SystemBuffer;
|
|
response = (TCPConnectionListEnum *) request;
|
|
requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (responseLength < sizeof(TCPConnectionListEnum)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
Irp->IoStatus.Information = 0;
|
|
} else {
|
|
EnumerateConnectionList(
|
|
(uchar *) (response + 1),
|
|
responseLength - sizeof(TCPConnectionListEnum),
|
|
&(response->tce_entries_returned),
|
|
&(response->tce_entries_available)
|
|
);
|
|
|
|
status = TDI_SUCCESS;
|
|
Irp->IoStatus.Information =
|
|
sizeof(TCPConnectionListEnum) +
|
|
(response->tce_entries_returned * sizeof(TCPConnectionListEntry));
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this request.
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
TDI_REQUEST Request;
|
|
NTSTATUS status;
|
|
FILE_FULL_EA_INFORMATION *ea;
|
|
FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
|
|
PTCP_CONTEXT tcpContext;
|
|
uint protocol;
|
|
BOOLEAN IsRawOpen = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCreate \n")));
|
|
|
|
RtlZeroMemory(&Request, sizeof(TDI_REQUEST));
|
|
tcpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TCP_CONTEXT), 'cPCT');
|
|
|
|
if (tcpContext == NULL) {
|
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
#if DBG
|
|
InitializeListHead(&(tcpContext->PendingIrpList));
|
|
InitializeListHead(&(tcpContext->CancelledIrpList));
|
|
#endif
|
|
|
|
tcpContext->ReferenceCount = 1; // put initial reference on open object
|
|
|
|
tcpContext->CancelIrps = FALSE;
|
|
KeInitializeEvent(&(tcpContext->CleanupEvent), SynchronizationEvent, FALSE);
|
|
CTEInitLock(&(tcpContext->EndpointLock));
|
|
|
|
tcpContext->Cleanup = FALSE;
|
|
|
|
ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// See if this is a Control Channel open.
|
|
//
|
|
if (!ea) {
|
|
IF_TCPDBG(TCP_DEBUG_OPEN) {
|
|
TCPTRACE((
|
|
"TCPCreate: Opening control channel for file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
tcpContext->Handle.ControlChannel = NULL;
|
|
IrpSp->FileObject->FsContext = tcpContext;
|
|
IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
//
|
|
// See if this is an Address Object open.
|
|
//
|
|
targetEA = FindEA(
|
|
ea,
|
|
TdiTransportAddress,
|
|
TDI_TRANSPORT_ADDRESS_LENGTH
|
|
);
|
|
|
|
if (targetEA != NULL) {
|
|
UCHAR optionsBuffer[3];
|
|
PUCHAR optionsPointer = optionsBuffer;
|
|
PSECURITY_DESCRIPTOR addrSD = NULL;
|
|
|
|
//Sanity check the address list. Should be bound by EaValueLength
|
|
{
|
|
TA_ADDRESS *tmpTA;
|
|
TRANSPORT_ADDRESS UNALIGNED *tmpTAList;
|
|
LONG Count = 1;
|
|
UINT tmpLen = 0;
|
|
UINT sizeof_TransportAddress = FIELD_OFFSET(TRANSPORT_ADDRESS, Address);
|
|
UINT sizeof_TAAddress = FIELD_OFFSET(TA_ADDRESS, Address);
|
|
|
|
if (ea->EaValueLength >= sizeof_TransportAddress + sizeof_TAAddress) {
|
|
|
|
tmpTAList = (TRANSPORT_ADDRESS UNALIGNED *)
|
|
& (targetEA->EaName[targetEA->EaNameLength + 1]);
|
|
|
|
Count = tmpTAList->TAAddressCount;
|
|
tmpLen = sizeof_TransportAddress;
|
|
tmpTA = (PTA_ADDRESS) tmpTAList->Address;
|
|
|
|
while (Count && ((tmpLen += sizeof_TAAddress) <= ea->EaValueLength)) {
|
|
|
|
tmpLen += tmpTA->AddressLength;
|
|
tmpTA = (PTA_ADDRESS) (tmpTA->Address + tmpTA->AddressLength);
|
|
Count--;
|
|
}
|
|
|
|
if (tmpLen > ea->EaValueLength) {
|
|
Count = 1;
|
|
}
|
|
}
|
|
if (Count) {
|
|
//Does not match what is stated in EA. Bail out
|
|
|
|
TCPTRACE(("TCPCreate: ea count and Ea Val length does not match for transport address's\n"));
|
|
status = STATUS_INVALID_EA_NAME;
|
|
ExFreePool(tcpContext);
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
return (status);
|
|
|
|
}
|
|
}
|
|
|
|
if (DeviceObject == TCPDeviceObject) {
|
|
protocol = PROTOCOL_TCP;
|
|
} else if (DeviceObject == UDPDeviceObject) {
|
|
protocol = PROTOCOL_UDP;
|
|
|
|
ASSERT(optionsPointer - optionsBuffer <= 3);
|
|
|
|
if (IsDHCPZeroAddress(
|
|
(TRANSPORT_ADDRESS UNALIGNED *)
|
|
& (targetEA->EaName[targetEA->EaNameLength + 1])
|
|
)) {
|
|
#if ACC
|
|
if (!IsAdminIoRequest(Irp, IrpSp)) {
|
|
ExFreePool(tcpContext);
|
|
return (STATUS_ACCESS_DENIED);
|
|
}
|
|
#endif
|
|
*optionsPointer = TDI_ADDRESS_OPTION_DHCP;
|
|
optionsPointer++;
|
|
}
|
|
ASSERT(optionsPointer - optionsBuffer <= 3);
|
|
} else {
|
|
//
|
|
// This is a raw ip open
|
|
//
|
|
#if ACC
|
|
//
|
|
// Only administrators can create raw addresses
|
|
// unless this is allowed through registry
|
|
//
|
|
if (!AllowUserRawAccess && !IsAdminIoRequest(Irp, IrpSp)) {
|
|
ExFreePool(tcpContext);
|
|
return (STATUS_ACCESS_DENIED);
|
|
}
|
|
#endif // ACC
|
|
|
|
protocol = RawExtractProtocolNumber(
|
|
&(IrpSp->FileObject->FileName)
|
|
);
|
|
|
|
if ((protocol == 0xFFFFFFFF) || (protocol == PROTOCOL_TCP)) {
|
|
ExFreePool(tcpContext);
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
IsRawOpen = TRUE;
|
|
}
|
|
|
|
if ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
|
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)
|
|
) {
|
|
*optionsPointer = TDI_ADDRESS_OPTION_REUSE;
|
|
optionsPointer++;
|
|
}
|
|
*optionsPointer = TDI_OPTION_EOL;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_OPEN) {
|
|
TCPTRACE((
|
|
"TCPCreate: Opening address for file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
#if ACC
|
|
Request.RequestContext = Irp;
|
|
#endif
|
|
if (protocol == PROTOCOL_TCP || protocol == PROTOCOL_UDP) {
|
|
status = CaptureCreatorSD(Irp, IrpSp, &addrSD);
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = TdiOpenAddress(
|
|
&Request,
|
|
(TRANSPORT_ADDRESS UNALIGNED *)
|
|
& (targetEA->EaName[targetEA->EaNameLength + 1]),
|
|
protocol,
|
|
optionsBuffer,
|
|
addrSD,
|
|
IsRawOpen
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// Save off the handle to the AO passed back.
|
|
//
|
|
tcpContext->Handle.AddressHandle = Request.Handle.AddressHandle;
|
|
IrpSp->FileObject->FsContext = tcpContext;
|
|
IrpSp->FileObject->FsContext2 =
|
|
(PVOID) TDI_TRANSPORT_ADDRESS_FILE;
|
|
} else {
|
|
if (addrSD != NULL) {
|
|
ObDereferenceSecurityDescriptor(addrSD, 1);
|
|
}
|
|
ExFreePool(tcpContext);
|
|
//TCPTRACE(("TdiOpenAddress failed, status %lx\n", status));
|
|
if (status == STATUS_ADDRESS_ALREADY_EXISTS) {
|
|
status = STATUS_SHARING_VIOLATION;
|
|
}
|
|
}
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
return (status);
|
|
}
|
|
//
|
|
// See if this is a Connection Object open.
|
|
//
|
|
targetEA = FindEA(
|
|
ea,
|
|
TdiConnectionContext,
|
|
TDI_CONNECTION_CONTEXT_LENGTH
|
|
);
|
|
|
|
if (targetEA != NULL) {
|
|
//
|
|
// This is an open of a Connection Object.
|
|
//
|
|
|
|
if (DeviceObject == TCPDeviceObject) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_OPEN) {
|
|
TCPTRACE((
|
|
"TCPCreate: Opening connection for file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
if (targetEA->EaValueLength < sizeof(CONNECTION_CONTEXT)) {
|
|
status = STATUS_EA_LIST_INCONSISTENT;
|
|
} else {
|
|
status = TdiOpenConnection(
|
|
&Request,
|
|
*((CONNECTION_CONTEXT UNALIGNED *)
|
|
& (targetEA->EaName[targetEA->EaNameLength + 1]))
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// Save off the Connection Context passed back.
|
|
//
|
|
tcpContext->Handle.ConnectionContext =
|
|
Request.Handle.ConnectionContext;
|
|
IrpSp->FileObject->FsContext = tcpContext;
|
|
IrpSp->FileObject->FsContext2 =
|
|
(PVOID) TDI_CONNECTION_FILE;
|
|
|
|
tcpContext->Conn = (UINT_PTR) Request.RequestContext;
|
|
} else {
|
|
ExFreePool(tcpContext);
|
|
TCPTRACE((
|
|
"TdiOpenConnection failed, status %lx\n",
|
|
status
|
|
));
|
|
}
|
|
} else {
|
|
TCPTRACE((
|
|
"TCP: TdiOpenConnection issued on UDP device!\n"
|
|
));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
ExFreePool(tcpContext);
|
|
}
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
return (status);
|
|
}
|
|
TCPTRACE(("TCPCreate: didn't find any useful ea's\n"));
|
|
status = STATUS_INVALID_EA_NAME;
|
|
ExFreePool(tcpContext);
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPCreate \n")));
|
|
|
|
return (status);
|
|
|
|
} // TCPCreate
|
|
|
|
#if ACC
|
|
|
|
BOOLEAN
|
|
IsAdminIoRequest(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Lifted from AFD - AfdPerformSecurityCheck)
|
|
Compares security context of the endpoint creator to that
|
|
of the administrator and local system.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - the socket creator has admin or local system privilige
|
|
FALSE - the socket creator is just a plain user
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN accessGranted;
|
|
PACCESS_STATE accessState;
|
|
PIO_SECURITY_CONTEXT securityContext;
|
|
PPRIVILEGE_SET privileges = NULL;
|
|
ACCESS_MASK grantedAccess;
|
|
PGENERIC_MAPPING GenericMapping;
|
|
ACCESS_MASK AccessMask = GENERIC_ALL;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Enable access to all the globally defined SIDs
|
|
//
|
|
|
|
GenericMapping = IoGetFileObjectGenericMapping();
|
|
|
|
RtlMapGenericMask(&AccessMask, GenericMapping);
|
|
|
|
securityContext = IrpSp->Parameters.Create.SecurityContext;
|
|
accessState = securityContext->AccessState;
|
|
|
|
SeLockSubjectContext(&accessState->SubjectSecurityContext);
|
|
|
|
accessGranted = SeAccessCheck(
|
|
TcpAdminSecurityDescriptor,
|
|
&accessState->SubjectSecurityContext,
|
|
TRUE,
|
|
AccessMask,
|
|
0,
|
|
&privileges,
|
|
IoGetFileObjectGenericMapping(),
|
|
(KPROCESSOR_MODE) ((IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
|
|
? UserMode
|
|
: Irp->RequestorMode),
|
|
&grantedAccess,
|
|
&Status
|
|
);
|
|
|
|
if (privileges) {
|
|
(VOID) SeAppendPrivileges(
|
|
accessState,
|
|
privileges
|
|
);
|
|
SeFreePrivileges(privileges);
|
|
}
|
|
if (accessGranted) {
|
|
accessState->PreviouslyGrantedAccess |= grantedAccess;
|
|
accessState->RemainingDesiredAccess &= ~(grantedAccess | MAXIMUM_ALLOWED);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
} else {
|
|
ASSERT(!NT_SUCCESS(Status));
|
|
}
|
|
SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
|
|
|
|
return accessGranted;
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
TCPCloseObjectComplete(
|
|
void *Context,
|
|
unsigned int Status,
|
|
unsigned int UnUsed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a TdiCloseConnectoin or TdiCloseAddress request.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - The final status of the operation.
|
|
UnUsed - An unused parameter
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PTCP_CONTEXT tcpContext;
|
|
CTELockHandle CancelHandle;
|
|
|
|
UNREFERENCED_PARAMETER(UnUsed);
|
|
|
|
irp = (PIRP) Context;
|
|
irpSp = IoGetCurrentIrpStackLocation(irp);
|
|
tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
|
|
irp->IoStatus.Status = Status;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLEANUP) {
|
|
TCPTRACE((
|
|
"TCPCloseObjectComplete on file object %lx\n",
|
|
irpSp->FileObject
|
|
));
|
|
}
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
ASSERT(tcpContext->ReferenceCount > 0);
|
|
ASSERT(tcpContext->CancelIrps);
|
|
|
|
//
|
|
// Remove the initial reference that was put on by TCPCreate.
|
|
//
|
|
ASSERT(tcpContext->ReferenceCount > 0);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCloseObjectComplete: irp %lx fileobj %lx refcnt dec to %u\n",
|
|
irp,
|
|
irpSp,
|
|
tcpContext->ReferenceCount - 1
|
|
));
|
|
}
|
|
|
|
|
|
if (--(tcpContext->ReferenceCount) == 0) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
}
|
|
|
|
//
|
|
// Free the EndpointLock before setting CleanupEvent,
|
|
// as tcpContext can go away as soon as the event is signalled.
|
|
//
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
|
return;
|
|
}
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
return;
|
|
|
|
} // TCPCleanupComplete
|
|
|
|
NTSTATUS
|
|
TCPCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancels all outstanding Irps on a TDI object by calling the close
|
|
routine for the object. It then waits for them to be completed
|
|
before returning.
|
|
|
|
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.
|
|
|
|
Notes:
|
|
|
|
This routine blocks, but does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCP_CONTEXT tcpContext;
|
|
NTSTATUS status;
|
|
TDI_REQUEST request;
|
|
CTELockHandle CancelHandle;
|
|
CTEBlockTracker Tracker;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCleanup \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
tcpContext->CancelIrps = TRUE;
|
|
KeResetEvent(&(tcpContext->CleanupEvent));
|
|
|
|
|
|
ASSERT(!tcpContext->Cleanup);
|
|
tcpContext->Cleanup = TRUE;
|
|
tcpContext->Irp = Irp;
|
|
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
//
|
|
// Now call the TDI close routine for this object to force all of its Irps
|
|
// to complete.
|
|
//
|
|
request.RequestNotifyObject = TCPCloseObjectComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
|
|
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE((
|
|
"TCPCleanup: Closing address object on file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
|
|
status = TdiCloseAddress(&request);
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE((
|
|
"TCPCleanup: Closing Connection object on file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
status = TdiCloseConnection(&request);
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE((
|
|
"TCPCleanup: Closing Control Channel object on file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// This should never happen.
|
|
//
|
|
ASSERT(FALSE);
|
|
|
|
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
|
|
|
tcpContext->CancelIrps = FALSE;
|
|
|
|
CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
|
|
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (status != TDI_PENDING) {
|
|
TCPCloseObjectComplete(Irp, status, 0);
|
|
}
|
|
IF_TCPDBG(TCP_DEBUG_CLEANUP) {
|
|
TCPTRACE((
|
|
"TCPCleanup: waiting for completion of Irps on file object %lx\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
CTEInsertBlockTracker(&Tracker, IrpSp->FileObject);
|
|
status = KeWaitForSingleObject(
|
|
&(tcpContext->CleanupEvent),
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
CTERemoveBlockTracker(&Tracker);
|
|
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLEANUP) {
|
|
TCPTRACE((
|
|
"TCPCleanup: Wait on file object %lx finished\n",
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
//
|
|
// The cleanup Irp will be completed by the dispatch routine.
|
|
//
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPCleanup \n")));
|
|
|
|
return (Irp->IoStatus.Status);
|
|
|
|
} // TCPCleanup
|
|
|
|
NTSTATUS
|
|
TCPClose(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
|
|
open endpoint.
|
|
|
|
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.
|
|
|
|
Notes:
|
|
|
|
This request does not pend.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCP_CONTEXT tcpContext;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPClose \n")));
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
|
|
KIRQL oldIrql;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
ASSERT(tcpContext->ReferenceCount == 0);
|
|
ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
}
|
|
#endif // DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE(("TCPClose on file object %lx\n", IrpSp->FileObject));
|
|
}
|
|
|
|
ExFreePool(tcpContext);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPClose \n")));
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
} // TCPClose
|
|
|
|
NTSTATUS
|
|
TCPDispatchDeviceControl(
|
|
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;
|
|
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDispatchDeviceControl \n")));
|
|
|
|
//
|
|
// Set this in advance. Any IOCTL dispatch routine that cares about it
|
|
// will modify it itself.
|
|
//
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_TCP_FINDTCB:
|
|
{
|
|
IPAddr Src;
|
|
IPAddr Dest;
|
|
ushort DestPort;
|
|
ushort SrcPort;
|
|
PTCP_FINDTCB_REQUEST request;
|
|
PTCP_FINDTCB_RESPONSE TCBInfo;
|
|
ULONG InfoBufferLen;
|
|
|
|
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(TCP_FINDTCB_REQUEST)
|
|
)
|
|
||
|
|
(IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(TCP_FINDTCB_RESPONSE))
|
|
) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
request = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Src = request->Src;
|
|
Dest = request->Dest;
|
|
DestPort = request->DestPort;
|
|
SrcPort = request->SrcPort;
|
|
|
|
InfoBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
TCBInfo = Irp->AssociatedIrp.SystemBuffer;
|
|
NdisZeroMemory(TCBInfo, sizeof(TCP_FINDTCB_RESPONSE));
|
|
|
|
status = GetTCBInfo(TCBInfo, Dest, Src, DestPort, SrcPort);
|
|
if (status == STATUS_SUCCESS) {
|
|
Irp->IoStatus.Information = sizeof(TCP_FINDTCB_RESPONSE);
|
|
} else {
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return status;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_TCP_QUERY_INFORMATION_EX:
|
|
return (TCPQueryInformationEx(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_WSH_SET_INFORMATION_EX:
|
|
case IOCTL_TCP_SET_INFORMATION_EX:
|
|
return (TCPSetInformationEx(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS:
|
|
case IOCTL_TCP_SET_SECURITY_FILTER_STATUS:
|
|
return (TCPControlSecurityFilter(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_ADD_SECURITY_FILTER:
|
|
case IOCTL_TCP_DELETE_SECURITY_FILTER:
|
|
return (TCPProcessSecurityFilterRequest(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_ENUMERATE_SECURITY_FILTER:
|
|
return (TCPEnumerateSecurityFilter(Irp, IrpSp));
|
|
break;
|
|
|
|
|
|
case IOCTL_TCP_RESERVE_PORT_RANGE:
|
|
case IOCTL_TCP_UNRESERVE_PORT_RANGE:
|
|
return (TCPReservePorts(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_BLOCK_PORTS:
|
|
return (BlockTCPPorts(Irp, IrpSp));
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDispatchDeviceControl \n")));
|
|
|
|
return status;
|
|
|
|
} // TCPDispatchDeviceControl
|
|
|
|
#if TRACE_EVENT
|
|
NTSTATUS
|
|
TCPEventTraceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles any WMI requests for enabling/disabling Event
|
|
tracing.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Context for the activity.
|
|
Irp - The device control argument block.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG retSize;
|
|
|
|
if (DeviceObject != IPDeviceObject) {
|
|
|
|
PIO_STACK_LOCATION irpSp;
|
|
ULONG bufferSize;
|
|
PVOID buffer;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
bufferSize = irpSp->Parameters.WMI.BufferSize;
|
|
buffer = irpSp->Parameters.WMI.Buffer;
|
|
|
|
switch (irpSp->MinorFunction) {
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4055) // cast from a data pointer to a function pointer
|
|
case IRP_MN_SET_TRACE_NOTIFY:
|
|
if (bufferSize < sizeof(PTDI_DATA_REQUEST_NOTIFY_ROUTINE)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
TCPCPHandlerRoutine = (PTDI_DATA_REQUEST_NOTIFY_ROUTINE)
|
|
* ((PVOID *) buffer);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
retSize = 0;
|
|
break;
|
|
#pragma warning(pop)
|
|
case IRP_MN_REGINFO:
|
|
{
|
|
//
|
|
// Stub for now. TCP can register its Guids with WMI here
|
|
//
|
|
PWMIREGINFOW WmiRegInfo;
|
|
ULONG WmiRegInfoSize = sizeof(WMIREGINFOW);
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (bufferSize >= WmiRegInfoSize) {
|
|
WmiRegInfo = (PWMIREGINFOW) buffer;
|
|
RtlZeroMemory(WmiRegInfo, WmiRegInfoSize);
|
|
WmiRegInfo->BufferSize = WmiRegInfoSize;
|
|
|
|
retSize = WmiRegInfoSize;
|
|
} else {
|
|
*(ULONG *) buffer = WmiRegInfoSize;
|
|
retSize = sizeof(ULONG);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
|
|
"TCPDispatch: Irp %lx unsupported minor function 0x%lx\n",
|
|
irpSp,
|
|
irpSp->MinorFunction
|
|
));
|
|
retSize = 0;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
} else {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
retSize = 0;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = retSize;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
TCPDispatchInternalDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for Internal Device Control IRPs.
|
|
This is the hot path for kernel-mode clients.
|
|
|
|
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;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE,
|
|
(DTEXT("+TCPDispatchInternalDeviceControl \n")));
|
|
|
|
#if IPMCAST
|
|
|
|
if (DeviceObject == IpMcastDeviceObject) {
|
|
return IpMcastDispatch(DeviceObject,
|
|
Irp);
|
|
}
|
|
#endif
|
|
|
|
if (DeviceObject != IPDeviceObject) {
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
|
|
//
|
|
// Send and receive are the performance path, so check for them
|
|
// right away.
|
|
//
|
|
if (irpSp->MinorFunction == TDI_SEND) {
|
|
return (TCPSendData(Irp, irpSp));
|
|
}
|
|
if (irpSp->MinorFunction == TDI_RECEIVE) {
|
|
return (TCPReceiveData(Irp, irpSp));
|
|
}
|
|
switch (irpSp->MinorFunction) {
|
|
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
status = TCPAssociateAddress(Irp, irpSp);
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
return (TCPDisassociateAddress(Irp, irpSp));
|
|
|
|
case TDI_CONNECT:
|
|
return (TCPConnect(Irp, irpSp));
|
|
|
|
case TDI_DISCONNECT:
|
|
return (TCPDisconnect(Irp, irpSp));
|
|
|
|
case TDI_LISTEN:
|
|
return (TCPListen(Irp, irpSp));
|
|
|
|
case TDI_ACCEPT:
|
|
return (TCPAccept(Irp, irpSp));
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fall through.
|
|
//
|
|
} else if (PtrToUlong(irpSp->FileObject->FsContext2) ==
|
|
TDI_TRANSPORT_ADDRESS_FILE
|
|
) {
|
|
|
|
if (irpSp->MinorFunction == TDI_SEND) {
|
|
return (UDPSendData(Irp, irpSp));
|
|
}
|
|
if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
|
|
return (UDPSendDatagram(Irp, irpSp));
|
|
}
|
|
if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
|
|
return (UDPReceiveDatagram(Irp, irpSp));
|
|
}
|
|
if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
|
|
status = TCPSetEventHandler(Irp, irpSp);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return (status);
|
|
}
|
|
if (irpSp->MinorFunction == TDI_CONNECT) {
|
|
|
|
return (TCPConnect(Irp, irpSp));
|
|
}
|
|
if (irpSp->MinorFunction == TDI_DISCONNECT) {
|
|
|
|
return (TCPDisconnect(Irp, irpSp));
|
|
}
|
|
//
|
|
// Fall through.
|
|
//
|
|
}
|
|
ASSERT(
|
|
(PtrToUlong(irpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
||
|
|
(PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
|
|
||
|
|
(PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONTROL_CHANNEL_FILE)
|
|
);
|
|
|
|
//
|
|
// These functions are common to all endpoint types.
|
|
//
|
|
switch (irpSp->MinorFunction) {
|
|
|
|
case TDI_QUERY_INFORMATION:
|
|
return (TCPQueryInformation(Irp, irpSp));
|
|
|
|
case TDI_SET_INFORMATION:
|
|
case TDI_ACTION:
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
|
|
"TCP: Call to unimplemented TDI function 0x%x\n",
|
|
irpSp->MinorFunction
|
|
));
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
default:
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
|
|
"TCP: call to invalid TDI function 0x%x\n",
|
|
irpSp->MinorFunction
|
|
));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE, (DTEXT("-TCPDispatchInternalDeviceControl \n")));
|
|
|
|
return (IPDispatch(DeviceObject, Irp));
|
|
}
|
|
|
|
NTSTATUS
|
|
TCPDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the generic dispatch routine for TCP/UDP/RawIP.
|
|
|
|
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;
|
|
|
|
DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE, (DTEXT("+TCPDispatch(%x, %x) \n"), DeviceObject, Irp));
|
|
|
|
#if IPMCAST
|
|
|
|
if (DeviceObject == IpMcastDeviceObject) {
|
|
return IpMcastDispatch(DeviceObject,
|
|
Irp);
|
|
}
|
|
#endif
|
|
|
|
if (DeviceObject != IPDeviceObject) {
|
|
|
|
#if MILLEN
|
|
// Ensure that the driver context is zero'd for our use.
|
|
Irp->Tail.Overlay.DriverContext[0] = NULL;
|
|
#endif // MILLEN
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ASSERT(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
|
|
|
switch (irpSp->MajorFunction) {
|
|
|
|
case IRP_MJ_CREATE:
|
|
status = TCPCreate(DeviceObject, Irp, irpSp);
|
|
break;
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
status = TCPCleanup(DeviceObject, Irp, irpSp);
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
status = TCPClose(Irp, irpSp);
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
status = TdiMapUserRequest(DeviceObject, Irp, irpSp);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
return (TCPDispatchInternalDeviceControl(DeviceObject, Irp));
|
|
}
|
|
if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) {
|
|
|
|
PULONG_PTR EntryPoint;
|
|
|
|
EntryPoint = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
try {
|
|
|
|
// Type3InputBuffer must be writeable by the caller.
|
|
|
|
if (Irp->RequestorMode != KernelMode) {
|
|
ProbeForWrite(EntryPoint,
|
|
sizeof(ULONG_PTR),
|
|
PROBE_ALIGNMENT(ULONG_PTR));
|
|
}
|
|
*EntryPoint = (ULONG_PTR) TCPSendData;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
return (TCPDispatchDeviceControl(
|
|
Irp,
|
|
IoGetCurrentIrpStackLocation(Irp)
|
|
));
|
|
break;
|
|
|
|
case IRP_MJ_QUERY_SECURITY:
|
|
//
|
|
// This is generated on Raw endpoints. We don't do anything
|
|
// for it.
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
|
|
case IRP_MJ_PNP:
|
|
status = TCPDispatchPnPPower(Irp, irpSp);
|
|
break;
|
|
|
|
|
|
#if TRACE_EVENT
|
|
case IRP_MJ_SYSTEM_CONTROL:
|
|
return TCPEventTraceControl(DeviceObject, Irp);
|
|
#endif
|
|
|
|
case IRP_MJ_WRITE:
|
|
case IRP_MJ_READ:
|
|
|
|
default:
|
|
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
|
|
"TCPDispatch: Irp %lx unsupported major function 0x%lx\n",
|
|
irpSp,
|
|
irpSp->MajorFunction
|
|
));
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
ASSERT(status != TDI_PENDING);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
return (IPDispatch(DeviceObject, Irp));
|
|
} // TCPDispatch
|
|
|
|
//
|
|
// Private utility functions
|
|
//
|
|
FILE_FULL_EA_INFORMATION UNALIGNED *
|
|
FindEA(
|
|
PFILE_FULL_EA_INFORMATION StartEA,
|
|
CHAR * TargetName,
|
|
USHORT TargetNameLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses and extended attribute list for a given target attribute.
|
|
|
|
Arguments:
|
|
|
|
StartEA - the first extended attribute in the list.
|
|
TargetName - the name of the target attribute.
|
|
TargetNameLength - the length of the name of the target attribute.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the requested attribute or NULL if the target wasn't found.
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT i;
|
|
BOOLEAN found;
|
|
FILE_FULL_EA_INFORMATION UNALIGNED *CurrentEA;
|
|
|
|
PAGED_CODE();
|
|
|
|
do {
|
|
found = TRUE;
|
|
|
|
CurrentEA = StartEA;
|
|
|
|
StartEA = (FILE_FULL_EA_INFORMATION *) ((PUCHAR) StartEA + CurrentEA->NextEntryOffset);
|
|
|
|
if (CurrentEA->EaNameLength != TargetNameLength) {
|
|
continue;
|
|
}
|
|
for (i = 0; i < CurrentEA->EaNameLength; i++) {
|
|
if (CurrentEA->EaName[i] == TargetName[i]) {
|
|
continue;
|
|
}
|
|
found = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (found) {
|
|
return (CurrentEA);
|
|
}
|
|
} while (CurrentEA->NextEntryOffset != 0);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
BOOLEAN
|
|
IsDHCPZeroAddress(
|
|
TRANSPORT_ADDRESS UNALIGNED * AddrList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks a TDI IP address list for an address from DHCP binding
|
|
to the IP address zero. Normally, binding to zero means wildcard.
|
|
For DHCP, it really means bind to an interface with an address of
|
|
zero. This semantic is flagged by a special value in an unused
|
|
portion of the address structure (ie. this is a kludge).
|
|
|
|
Arguments:
|
|
|
|
AddrList - The TDI transport address list passed in the create IRP.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the first IP address found had the flag set. FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
int i; // Index variable.
|
|
TA_ADDRESS *CurrentAddr; // Address we're examining and may use.
|
|
|
|
// First, verify that someplace in Address is an address we can use.
|
|
CurrentAddr = (PTA_ADDRESS) AddrList->Address;
|
|
|
|
for (i = 0; i < AddrList->TAAddressCount; i++) {
|
|
if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
|
|
if (CurrentAddr->AddressLength == TDI_ADDRESS_LENGTH_IP) {
|
|
TDI_ADDRESS_IP UNALIGNED *ValidAddr;
|
|
|
|
ValidAddr = (TDI_ADDRESS_IP UNALIGNED *) CurrentAddr->Address;
|
|
|
|
if (*((ULONG UNALIGNED *) ValidAddr->sin_zero) == 0x12345678) {
|
|
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
return FALSE; // Wrong length for address.
|
|
|
|
}
|
|
} else {
|
|
CurrentAddr = (PTA_ADDRESS)
|
|
(CurrentAddr->Address + CurrentAddr->AddressLength);
|
|
}
|
|
}
|
|
|
|
return FALSE; // Didn't find a match.
|
|
|
|
}
|
|
|
|
ULONG
|
|
TCPGetMdlChainByteCount(
|
|
PMDL Mdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sums the byte counts of each MDL in a chain.
|
|
|
|
Arguments:
|
|
|
|
Mdl - Pointer to the MDL chain to sum.
|
|
|
|
Return Value:
|
|
|
|
The byte count of the MDL chain.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG count = 0;
|
|
|
|
while (Mdl != NULL) {
|
|
count += MmGetMdlByteCount(Mdl);
|
|
Mdl = Mdl->Next;
|
|
}
|
|
|
|
return (count);
|
|
}
|
|
|
|
ULONG
|
|
TCPGetNdisBufferChainByteCount(
|
|
PNDIS_BUFFER pBuffer
|
|
)
|
|
{
|
|
ULONG cb = 0;
|
|
|
|
while (pBuffer != NULL) {
|
|
cb += NdisBufferLength(pBuffer);
|
|
pBuffer = NDIS_BUFFER_LINKAGE(pBuffer);
|
|
}
|
|
|
|
return cb;
|
|
}
|
|
|
|
ULONG
|
|
RawExtractProtocolNumber(
|
|
IN PUNICODE_STRING FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extracts the protocol number from the file object name.
|
|
|
|
Arguments:
|
|
|
|
FileName - The unicode file name.
|
|
|
|
Return Value:
|
|
|
|
The protocol number or 0xFFFFFFFF on error.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR name;
|
|
UNICODE_STRING unicodeString;
|
|
ULONG protocol;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
name = FileName->Buffer;
|
|
|
|
if (FileName->Length <
|
|
(sizeof(OBJ_NAME_PATH_SEPARATOR) + sizeof(WCHAR))
|
|
) {
|
|
return (0xFFFFFFFF);
|
|
}
|
|
//
|
|
// Step over separator
|
|
//
|
|
if (*name++ != OBJ_NAME_PATH_SEPARATOR) {
|
|
return (0xFFFFFFFF);
|
|
}
|
|
if (*name == UNICODE_NULL) {
|
|
return (0xFFFFFFFF);
|
|
}
|
|
//
|
|
// Convert the remaining name into a number.
|
|
//
|
|
RtlInitUnicodeString(&unicodeString, name);
|
|
|
|
status = RtlUnicodeStringToInteger(
|
|
&unicodeString,
|
|
10,
|
|
&protocol
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return (0xFFFFFFFF);
|
|
}
|
|
if (protocol > 255) {
|
|
return (0xFFFFFFFF);
|
|
}
|
|
return (protocol);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
CaptureCreatorSD(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp,
|
|
OUT PSECURITY_DESCRIPTOR* CreatorSD
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Captures the security-descriptor associated with an IRP_MJ_CREATE request.
|
|
|
|
Arguments:
|
|
|
|
Irp - supplies the I/O request packet.
|
|
|
|
IrpSp - specifies the I/O stack location containing the IRP_MJ_CREATE.
|
|
|
|
CreatorSD - on success, receives the captured security descriptor.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - indicates success/failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PSECURITY_DESCRIPTOR mergedSD;
|
|
PACCESS_STATE accessState =
|
|
IrpSp->Parameters.Create.SecurityContext->AccessState;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Irp->RequestorMode == KernelMode &&
|
|
IrpSp->Parameters.Create.ShareAccess == 0 &&
|
|
accessState->SecurityDescriptor == NULL) {
|
|
*CreatorSD = NULL;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
// Take a read-lock on the subject security context for the request,
|
|
// and merge the request's SD into a new SD.
|
|
|
|
SeLockSubjectContext(&accessState->SubjectSecurityContext);
|
|
status = SeAssignSecurity(NULL, accessState->SecurityDescriptor,
|
|
&mergedSD, FALSE,
|
|
&accessState->SubjectSecurityContext,
|
|
IoGetFileObjectGenericMapping(), PagedPool);
|
|
SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
|
|
if (NT_SUCCESS(status)) {
|
|
// Request a tracked and referenced copy of the merged SD.
|
|
|
|
status = ObLogSecurityDescriptor(mergedSD, CreatorSD, 1);
|
|
ExFreePool(mergedSD);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|