5178 lines
141 KiB
C
5178 lines
141 KiB
C
/*++
|
||
|
||
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 "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
|
||
|
||
//
|
||
// External TDI function prototypes
|
||
//
|
||
extern TDI_STATUS
|
||
TdiOpenAddress(
|
||
PTDI_REQUEST Request,
|
||
TRANSPORT_ADDRESS UNALIGNED * AddrList,
|
||
uint protocol,
|
||
void *Reuse
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiCloseAddress(
|
||
PTDI_REQUEST Request
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiOpenConnection(
|
||
PTDI_REQUEST Request,
|
||
PVOID Context
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiCloseConnection(
|
||
PTDI_REQUEST Request
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiAssociateAddress(
|
||
PTDI_REQUEST Request,
|
||
HANDLE AddrHandle
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiCancelDisAssociateAddress(
|
||
PTDI_REQUEST Request
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiDisAssociateAddress(
|
||
PTDI_REQUEST Request
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiConnect(
|
||
PTDI_REQUEST Request,
|
||
void *Timeout,
|
||
PTDI_CONNECTION_INFORMATION RequestAddr,
|
||
PTDI_CONNECTION_INFORMATION ReturnAddr
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
UDPConnect(
|
||
PTDI_REQUEST Request,
|
||
void *Timeout,
|
||
PTDI_CONNECTION_INFORMATION RequestAddr,
|
||
PTDI_CONNECTION_INFORMATION ReturnAddr
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
UDPDisconnect(
|
||
PTDI_REQUEST Request,
|
||
void *TO,
|
||
PTDI_CONNECTION_INFORMATION DiscConnInfo,
|
||
PTDI_CONNECTION_INFORMATION ReturnInfo
|
||
);
|
||
|
||
|
||
extern TDI_STATUS
|
||
TdiListen(
|
||
PTDI_REQUEST Request,
|
||
ushort Flags,
|
||
PTDI_CONNECTION_INFORMATION AcceptableAddr,
|
||
PTDI_CONNECTION_INFORMATION ConnectedAddr
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiAccept(
|
||
PTDI_REQUEST Request,
|
||
PTDI_CONNECTION_INFORMATION AcceptInfo,
|
||
PTDI_CONNECTION_INFORMATION ConnectedInfo
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiDisconnect(
|
||
PTDI_REQUEST Request,
|
||
void *TO,
|
||
ushort Flags,
|
||
PTDI_CONNECTION_INFORMATION DiscConnInfo,
|
||
PTDI_CONNECTION_INFORMATION ReturnInfo
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiSend(
|
||
PTDI_REQUEST Request,
|
||
ushort Flags,
|
||
uint SendLength,
|
||
PNDIS_BUFFER SendBuffer
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiReceive(
|
||
PTDI_REQUEST Request,
|
||
ushort * Flags,
|
||
uint * RcvLength,
|
||
PNDIS_BUFFER Buffer
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiSendDatagram(
|
||
PTDI_REQUEST Request,
|
||
PTDI_CONNECTION_INFORMATION ConnInfo,
|
||
uint DataSize,
|
||
uint * BytesSent,
|
||
PNDIS_BUFFER Buffer
|
||
);
|
||
|
||
VOID
|
||
TdiCancelSendDatagram(
|
||
AddrObj * SrcAO,
|
||
PVOID Context,
|
||
KIRQL inHandle
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiReceiveDatagram(
|
||
PTDI_REQUEST Request,
|
||
PTDI_CONNECTION_INFORMATION ConnInfo,
|
||
PTDI_CONNECTION_INFORMATION ReturnInfo,
|
||
uint RcvSize,
|
||
uint * BytesRcvd,
|
||
PNDIS_BUFFER Buffer
|
||
);
|
||
|
||
VOID
|
||
TdiCancelReceiveDatagram(
|
||
AddrObj * SrcAO,
|
||
PVOID Context,
|
||
KIRQL inHandle
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiSetEvent(
|
||
PVOID Handle,
|
||
int Type,
|
||
PVOID Handler,
|
||
PVOID Context
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiQueryInformation(
|
||
PTDI_REQUEST Request,
|
||
uint QueryType,
|
||
PNDIS_BUFFER Buffer,
|
||
uint * BytesReturned,
|
||
uint IsConn
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiSetInformation(
|
||
PTDI_REQUEST Request,
|
||
uint SetType,
|
||
PNDIS_BUFFER Buffer,
|
||
uint BufferSize,
|
||
uint IsConn
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiQueryInformationEx(
|
||
PTDI_REQUEST Request,
|
||
struct TDIObjectID *ID,
|
||
PNDIS_BUFFER Buffer,
|
||
uint * Size,
|
||
void *Context
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiSetInformationEx(
|
||
PTDI_REQUEST Request,
|
||
struct TDIObjectID *ID,
|
||
void *Buffer,
|
||
uint Size
|
||
);
|
||
|
||
extern TDI_STATUS
|
||
TdiAction(
|
||
PTDI_REQUEST Request,
|
||
uint ActionType,
|
||
PNDIS_BUFFER Buffer,
|
||
uint BufferSize
|
||
);
|
||
|
||
extern
|
||
NTSTATUS
|
||
TCPDispatchPnPPower(
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
|
||
extern
|
||
uint
|
||
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
|
||
|
||
//
|
||
// 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
|
||
#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;
|
||
PIRP item = NULL;
|
||
CTELockHandle CancelHandle;
|
||
|
||
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)));
|
||
}
|
||
|
||
//
|
||
// Set the cleanup event.
|
||
//
|
||
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
||
}
|
||
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_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;
|
||
KIRQL oldIrql;
|
||
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 oldirql;
|
||
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;
|
||
}
|
||
}
|
||
|
||
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;
|
||
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
|
||
);
|
||
break;
|
||
}
|
||
|
||
if (status != TDI_PENDING) {
|
||
TCPCancelComplete(fileObject, 0, 0);
|
||
}
|
||
return;
|
||
|
||
} // TCPCancelRequest
|
||
|
||
NTSTATUS
|
||
TCPPrepareIrpForCancel(
|
||
PTCP_CONTEXT TcpContext,
|
||
PIRP Irp,
|
||
PDRIVER_CANCEL CancelRoutine
|
||
)
|
||
{
|
||
KIRQL oldIrql;
|
||
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(&CancelId.Value)) == 0) { }
|
||
|
||
CTEFreeLock(&TcpContext->EndpointLock, CancelHandle);
|
||
|
||
Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(LocalCancelId);
|
||
Irp->Tail.Overlay.DriverContext[0] = NULL;
|
||
|
||
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
|
||
);
|
||
|
||
} 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(&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),
|
||
&(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,
|
||
&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,
|
||
&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:
|
||
//ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
|
||
// TDI_CONTROL_CHANNEL_FILE
|
||
// );
|
||
|
||
|
||
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
||
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->QueryType,
|
||
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,
|
||
unsigned int 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;
|
||
|
||
|
||
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)) {
|
||
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 i;
|
||
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;
|
||
ULONG NumberofPorts;
|
||
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 = BlockedPortList, *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
|
||
|
||
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;
|
||
|
||
PAGED_CODE();
|
||
|
||
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCreate \n")));
|
||
|
||
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;
|
||
|
||
//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);
|
||
}
|
||
}
|
||
|
||
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
|
||
|
||
status = TdiOpenAddress(
|
||
&Request,
|
||
(TRANSPORT_ADDRESS UNALIGNED *)
|
||
& (targetEA->EaName[targetEA->EaNameLength + 1]),
|
||
protocol,
|
||
optionsBuffer
|
||
);
|
||
|
||
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 {
|
||
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:
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldIrql;
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldIrql;
|
||
PIRP cancelIrp = NULL;
|
||
PTCP_CONTEXT tcpContext;
|
||
NTSTATUS status;
|
||
TDI_REQUEST request;
|
||
CTELockHandle CancelHandle;
|
||
|
||
DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCleanup \n")));
|
||
|
||
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
||
|
||
CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
|
||
|
||
tcpContext->CancelIrps = TRUE;
|
||
KeResetEvent(&(tcpContext->CleanupEvent));
|
||
|
||
if (tcpContext->Cleanup) {
|
||
#if DBG_VALIDITY_CHECK
|
||
//Double cleanup call!!!
|
||
DbgBreakPoint();
|
||
#endif
|
||
} else {
|
||
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
|
||
));
|
||
}
|
||
|
||
status = KeWaitForSingleObject(
|
||
&(tcpContext->CleanupEvent),
|
||
UserRequest,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
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_RCVWND:
|
||
|
||
// Allow this IOCTL to set the window size only
|
||
// if there are no established connections
|
||
|
||
if (TStats.ts_currestab == 0) {
|
||
PULONG request = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
ULONG tmp = DefaultRcvWin;
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
|
||
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
||
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG)) {
|
||
|
||
if ((LONG)*request > 0) {
|
||
|
||
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"setting global rcv window %d\n", *request));
|
||
|
||
if (!(TcpHostOpts & TCP_FLAG_WS) && *request > 0xFFFF) {
|
||
DefaultRcvWin = 0xFFFF;
|
||
} else {
|
||
uint rcvwinscale=0;
|
||
|
||
//
|
||
// Check for valid window size
|
||
// taking care of window scaling option
|
||
//
|
||
|
||
while ((rcvwinscale < TCP_MAX_WINSHIFT) &&
|
||
((TCP_MAXWIN << rcvwinscale) < (LONG)*request)) {
|
||
rcvwinscale++;
|
||
}
|
||
|
||
if (rcvwinscale == TCP_MAX_WINSHIFT) {
|
||
DefaultRcvWin = TCP_MAXWIN << rcvwinscale;
|
||
} else {
|
||
DefaultRcvWin = *request;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"returning global rcv window %d\n", *request));
|
||
*request = tmp;
|
||
|
||
status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = sizeof(ULONG);
|
||
|
||
break;
|
||
} else {
|
||
status = STATUS_CONNECTION_ACTIVE;
|
||
}
|
||
|
||
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) {
|
||
|
||
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;
|
||
|
||
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:
|
||
TCPTRACE((
|
||
"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:
|
||
TCPTRACE((
|
||
"TCP: Call to unimplemented TDI function 0x%x\n",
|
||
irpSp->MinorFunction
|
||
));
|
||
status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
default:
|
||
TCPTRACE((
|
||
"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:
|
||
TCPTRACE((
|
||
"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;
|
||
USHORT length;
|
||
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);
|
||
|
||
}
|
||
|