mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4063 lines
90 KiB
4063 lines
90 KiB
/*++
|
|
|
|
Copyright (c) 1991 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 <oscfg.h>
|
|
#include <ntrtl.h>
|
|
#include <ntddip.h>
|
|
#include <ndis.h>
|
|
#include <cxport.h>
|
|
#include <tdikrnl.h>
|
|
#include <tdint.h>
|
|
#include <tdistat.h>
|
|
#include <tdiinfo.h>
|
|
#include <ip.h>
|
|
#include "queue.h"
|
|
#include "addr.h"
|
|
#include "tcp.h"
|
|
#include "udp.h"
|
|
#include "raw.h"
|
|
#include <tcpinfo.h>
|
|
#include <ntddtcp.h>
|
|
#include "tcpcfg.h"
|
|
#include "secfltr.h"
|
|
#include "tcpconn.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)
|
|
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
extern PDEVICE_OBJECT TCPDeviceObject, UDPDeviceObject;
|
|
extern PDEVICE_OBJECT IPDeviceObject;
|
|
extern PDEVICE_OBJECT RawIPDeviceObject;
|
|
|
|
|
|
//
|
|
// Local types
|
|
//
|
|
typedef struct {
|
|
PIRP Irp;
|
|
PMDL InputMdl;
|
|
PMDL OutputMdl;
|
|
TCP_REQUEST_QUERY_INFORMATION_EX QueryInformation;
|
|
} TCP_QUERY_CONTEXT, *PTCP_QUERY_CONTEXT;
|
|
|
|
|
|
|
|
//
|
|
// General external function prototypes
|
|
//
|
|
extern
|
|
NTSTATUS
|
|
IPDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
//
|
|
// 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
|
|
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
|
|
);
|
|
|
|
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
|
|
);
|
|
|
|
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
|
|
);
|
|
|
|
//
|
|
// Other external functions
|
|
//
|
|
void
|
|
TCPAbortAndIndicateDisconnect(
|
|
uint ConnnectionContext
|
|
);
|
|
|
|
|
|
//
|
|
// 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
|
|
);
|
|
|
|
#ifdef SECFLTR
|
|
|
|
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
|
|
);
|
|
|
|
#endif // SECFLTR
|
|
|
|
NTSTATUS
|
|
TCPEnumerateConnectionList(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
//
|
|
// Local helper routine prototypes.
|
|
//
|
|
ULONG
|
|
TCPGetMdlChainByteCount(
|
|
PMDL Mdl
|
|
);
|
|
|
|
|
|
//
|
|
// All of this code is pageable.
|
|
//
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, TCPDispatchDeviceControl)
|
|
#pragma alloc_text(PAGE, TCPCreate)
|
|
#pragma alloc_text(PAGE, TCPAssociateAddress)
|
|
#pragma alloc_text(PAGE, TCPSetEventHandler)
|
|
#pragma alloc_text(PAGE, FindEA)
|
|
#pragma alloc_text(PAGE, IsDHCPZeroAddress)
|
|
#pragma alloc_text(PAGE, RawExtractProtocolNumber)
|
|
|
|
#ifdef SECFLTR
|
|
|
|
#pragma alloc_text(PAGE, TCPControlSecurityFilter)
|
|
#pragma alloc_text(PAGE, TCPProcessSecurityFilterRequest)
|
|
#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
|
|
|
|
#endif // SECFLTR
|
|
|
|
#pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
|
|
//
|
|
// Generic Irp completion and cancellation routines.
|
|
//
|
|
|
|
void
|
|
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;
|
|
|
|
|
|
irp = (PIRP) Context;
|
|
irpSp = IoGetCurrentIrpStackLocation(irp);
|
|
tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
|
|
PLIST_ENTRY entry, listHead;
|
|
PIRP item = NULL;
|
|
|
|
if (irp->Cancel) {
|
|
CTEAssert(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;
|
|
}
|
|
}
|
|
|
|
CTEAssert(item == irp);
|
|
}
|
|
|
|
#endif
|
|
|
|
IoSetCancelRoutine(irp, NULL);
|
|
|
|
CTEAssert(tcpContext->ReferenceCount > 0);
|
|
|
|
if (--(tcpContext->ReferenceCount) == 0) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
CTEAssert(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 (irp->Cancel || tcpContext->CancelIrps) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE(("TCPDataRequestComplete: Irp %lx was cancelled\n", irp));
|
|
}
|
|
|
|
Status = (unsigned int) STATUS_CANCELLED;
|
|
ByteCount = 0;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
|
|
} // 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;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(Unused1);
|
|
UNREFERENCED_PARAMETER(Unused2);
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
//
|
|
// 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) {
|
|
CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
}
|
|
|
|
//
|
|
// Set the cleanup event.
|
|
//
|
|
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCancelComplete: fileobj %lx refcnt dec to %u\n",
|
|
fileObject,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
fileObject = irpSp->FileObject;
|
|
tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
|
|
minorFunction = irpSp->MinorFunction;
|
|
|
|
CTEAssert(Irp->Cancel);
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCancelRequest: cancelling irp %lx, file object %lx\n",
|
|
Irp,
|
|
fileObject
|
|
));
|
|
}
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
//
|
|
// Verify that the Irp is on the pending 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;
|
|
}
|
|
}
|
|
|
|
CTEAssert(item == Irp);
|
|
|
|
InsertTailList(
|
|
&(tcpContext->CancelledIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//
|
|
// Add a reference so the object can't be closed while the cancel routine
|
|
// is executing.
|
|
//
|
|
CTEAssert(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
|
|
));
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
//
|
|
// Try to cancel the request.
|
|
//
|
|
switch(minorFunction) {
|
|
|
|
case TDI_SEND:
|
|
case TDI_RECEIVE:
|
|
|
|
CTEAssert(((int)fileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
|
|
TCPAbortAndIndicateDisconnect(
|
|
(uint) tcpContext->Handle.ConnectionContext
|
|
);
|
|
break;
|
|
|
|
case TDI_SEND_DATAGRAM:
|
|
|
|
CTEAssert(((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp);
|
|
break;
|
|
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
|
|
CTEAssert(((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
TdiCancelReceiveDatagram(tcpContext->Handle.AddressHandle, Irp);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
|
|
CTEAssert(((int)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.
|
|
//
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Initiate a disconnect to cancel the request.
|
|
//
|
|
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;
|
|
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
CTEAssert(Irp->CancelRoutine == NULL);
|
|
|
|
if (!Irp->Cancel) {
|
|
|
|
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);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
for ( entry = TcpContext->CancelledIrpList.Flink;
|
|
entry != &(TcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(TcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// The IRP has already been cancelled. Complete it now.
|
|
//
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE(("TCP: irp %lx already cancelled, completing.\n", Irp));
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
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,
|
|
NULL,
|
|
KernelMode,
|
|
&fileObject,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if ( (fileObject->DeviceObject == TCPDeviceObject) &&
|
|
(((int)fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
) {
|
|
|
|
tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
|
|
|
|
status = TdiAssociateAddress(
|
|
&request,
|
|
tcpContext->Handle.AddressHandle
|
|
);
|
|
|
|
CTEAssert(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 {
|
|
IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
|
|
TCPTRACE((
|
|
"TCPAssociateAddress: ObReference failed on object %lx, status %lx\n",
|
|
associateInformation->AddressHandle,
|
|
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;
|
|
|
|
IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
|
|
TCPTRACE(("TCP disassociating address\n"));
|
|
}
|
|
|
|
CTEAssert( ((int)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);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPConnect irp %lx, file object %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
CTEAssert( ((int)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;
|
|
}
|
|
|
|
|
|
CTEAssert(millisecondTimeout.HighPart == 0);
|
|
|
|
status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = TdiConnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
if (status != STATUS_PENDING) {
|
|
TCPRequestComplete(Irp, status, 0);
|
|
}
|
|
//
|
|
// return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
|
|
//
|
|
return(STATUS_PENDING);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
CTEAssert( ((int)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)) {
|
|
millisecondTimeout.LowPart = requestTimeout->LowPart;
|
|
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;
|
|
}
|
|
|
|
CTEAssert(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)) {
|
|
status = TdiDisconnect(
|
|
&request,
|
|
((millisecondTimeout.LowPart != 0) ?
|
|
&(millisecondTimeout.LowPart) : NULL),
|
|
(ushort) disconnectRequest->RequestFlags,
|
|
requestInformation,
|
|
returnInformation
|
|
);
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPListen irp %lx on file object %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
CTEAssert( ((int)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);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CONNECT) {
|
|
TCPTRACE((
|
|
"TCPAccept irp %lx on file object %lx\n", Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
CTEAssert( ((int)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);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
CTEAssert( ((int)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;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
CTEAssert(Irp->CancelRoutine == NULL);
|
|
|
|
if (!Irp->Cancel) {
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
IoSetCancelRoutine(Irp, TCPCancelRequest);
|
|
|
|
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);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
for ( entry = tcpContext->CancelledIrpList.Flink;
|
|
entry != &(tcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(tcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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 = TdiSend(
|
|
&request,
|
|
(ushort) requestInformation->SendFlags,
|
|
requestInformation->SendLength,
|
|
(PNDIS_BUFFER) Irp->MdlAddress
|
|
);
|
|
|
|
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) {
|
|
CTEAssert(requestInformation->SendLength == 0);
|
|
|
|
TCPDataRequestComplete(Irp, status, requestInformation->SendLength);
|
|
}
|
|
else {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_SEND) {
|
|
TCPTRACE((
|
|
"TCPSendData - irp %lx send failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
}
|
|
|
|
TCPDataRequestComplete(Irp, status, 0);
|
|
}
|
|
|
|
|
|
}
|
|
else {
|
|
//
|
|
// Irp was cancelled previously.
|
|
//
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
status = STATUS_CANCELLED;
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
CTEAssert( ((int)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;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
CTEAssert(Irp->CancelRoutine == NULL);
|
|
|
|
if (!Irp->Cancel) {
|
|
//
|
|
// Set up for cancellation
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
IoSetCancelRoutine(Irp, TCPCancelRequest);
|
|
|
|
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);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
for ( entry = tcpContext->CancelledIrpList.Flink;
|
|
entry != &(tcpContext->CancelledIrpList);
|
|
entry = entry->Flink
|
|
) {
|
|
|
|
item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
CTEAssert(item != Irp);
|
|
}
|
|
|
|
InsertTailList(
|
|
&(tcpContext->PendingIrpList),
|
|
&(Irp->Tail.Overlay.ListEntry)
|
|
);
|
|
}
|
|
#endif // DBG
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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 = TdiReceive(
|
|
&request,
|
|
(ushort *) &(requestInformation->ReceiveFlags),
|
|
&(requestInformation->ReceiveLength),
|
|
(PNDIS_BUFFER) Irp->MdlAddress
|
|
);
|
|
|
|
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;
|
|
|
|
CTEAssert(status != TDI_SUCCESS);
|
|
|
|
IF_TCPDBG(TCP_DEBUG_RECEIVE) {
|
|
TCPTRACE((
|
|
"TCPReceiveData - irp %lx failed, status %lx\n",
|
|
Irp,
|
|
status
|
|
));
|
|
}
|
|
|
|
TCPDataRequestComplete(Irp, status, 0);
|
|
}
|
|
else {
|
|
//
|
|
// Irp was cancelled previously.
|
|
//
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
status = STATUS_CANCELLED;
|
|
}
|
|
|
|
return status;
|
|
|
|
} // TCPReceiveData
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
datagramInformation = (PTDI_REQUEST_KERNEL_SENDDG) &(IrpSp->Parameters);
|
|
CTEAssert(((int)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 = TdiSendDatagram(
|
|
&request,
|
|
datagramInformation->SendDatagramInformation,
|
|
datagramInformation->SendLength,
|
|
&bytesSent,
|
|
(PNDIS_BUFFER) Irp->MdlAddress
|
|
);
|
|
|
|
if (status == TDI_PENDING) {
|
|
return(status);
|
|
}
|
|
|
|
CTEAssert(status != TDI_SUCCESS);
|
|
CTEAssert(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);
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
datagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG) &(IrpSp->Parameters);
|
|
CTEAssert(((int)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 = TdiReceiveDatagram(
|
|
&request,
|
|
datagramInformation->ReceiveDatagramInformation,
|
|
datagramInformation->ReturnDatagramInformation,
|
|
datagramInformation->ReceiveLength,
|
|
&bytesReceived,
|
|
Irp->MdlAddress
|
|
);
|
|
|
|
if (status == TDI_PENDING) {
|
|
return(status);
|
|
}
|
|
|
|
CTEAssert(status != TDI_SUCCESS);
|
|
CTEAssert(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();
|
|
|
|
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
|
|
);
|
|
|
|
CTEAssert(status != TDI_PENDING);
|
|
|
|
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;
|
|
|
|
|
|
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:
|
|
CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
|
|
TDI_CONTROL_CHANNEL_FILE
|
|
);
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_INFO:
|
|
//
|
|
// NetBT does this. Reinstate the CTEAssert when it is fixed.
|
|
//
|
|
// CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
|
|
// TDI_CONTROL_CHANNEL_FILE
|
|
// );
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
if (((int) 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:
|
|
CTEAssert(((int) IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
|
|
isConn = TRUE;
|
|
request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_STATISTICS:
|
|
CTEAssert( ((int) IrpSp->FileObject->FsContext2) ==
|
|
TDI_CONTROL_CHANNEL_FILE
|
|
);
|
|
request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// 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 = TdiQueryInformation(
|
|
&request,
|
|
queryInformation->QueryType,
|
|
Irp->MdlAddress,
|
|
&dataSize,
|
|
isConn
|
|
);
|
|
|
|
if (status != TDI_PENDING) {
|
|
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);
|
|
|
|
return(status);
|
|
|
|
} // TCPQueryInformation
|
|
|
|
|
|
|
|
void
|
|
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;
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Copy the returned context to the input buffer.
|
|
//
|
|
TdiCopyBufferToMdl(
|
|
&(queryContext->QueryInformation.Context),
|
|
0,
|
|
CONTEXT_SIZE,
|
|
queryContext->InputMdl,
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
|
|
&bytesCopied
|
|
);
|
|
|
|
CTEAssert(bytesCopied == CONTEXT_SIZE);
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//
|
|
TCPDataRequestComplete(queryContext->Irp, Status, ByteCount);
|
|
|
|
CTEFreeMem(queryContext);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE((
|
|
"QueryInformationEx starting - irp %lx fileobj %lx\n",
|
|
Irp,
|
|
IrpSp->FileObject
|
|
));
|
|
}
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
switch ((int) 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:
|
|
CTEAssert(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 ( (InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
|
|
(OutputBufferLength != 0)
|
|
)
|
|
{
|
|
OutputBuffer = Irp->UserBuffer;
|
|
InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
|
|
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
queryContext = CTEAllocMem(sizeof(TCP_QUERY_CONTEXT));
|
|
|
|
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,
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
|
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.
|
|
//
|
|
RtlCopyMemory(
|
|
&(queryContext->QueryInformation),
|
|
InputBuffer,
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)
|
|
);
|
|
}
|
|
else {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_INFO) {
|
|
TCPTRACE(("QueryInfoEx: Couldn't allocate MDL\n"));
|
|
}
|
|
|
|
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)) {
|
|
//
|
|
// 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 = TdiQueryInformationEx(
|
|
&request,
|
|
&(queryContext->QueryInformation.ID),
|
|
outputMdl,
|
|
&size,
|
|
&(queryContext->QueryInformation.Context)
|
|
);
|
|
|
|
if (status != TDI_PENDING) {
|
|
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);
|
|
|
|
TCPDataRequestComplete(Irp, status, 0);
|
|
|
|
return(status);
|
|
|
|
}
|
|
else {
|
|
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);
|
|
|
|
|
|
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();
|
|
|
|
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;
|
|
|
|
switch ((int) 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:
|
|
CTEAssert(0);
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
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) {
|
|
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.
|
|
//
|
|
return(status);
|
|
}
|
|
|
|
|
|
#ifdef SECFLTR
|
|
|
|
|
|
|
|
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 {
|
|
CTEAssert(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 {
|
|
CTEAssert(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);
|
|
}
|
|
|
|
#endif // SECFLTR
|
|
|
|
|
|
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();
|
|
|
|
tcpContext = ExAllocatePool(NonPagedPool, sizeof(TCP_CONTEXT));
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
|
|
if (DeviceObject == TCPDeviceObject) {
|
|
protocol = PROTOCOL_TCP;
|
|
}
|
|
else if (DeviceObject == UDPDeviceObject) {
|
|
protocol = PROTOCOL_UDP;
|
|
|
|
CTEAssert(optionsPointer - optionsBuffer <= 3);
|
|
|
|
if (IsDHCPZeroAddress(
|
|
(TRANSPORT_ADDRESS UNALIGNED *)
|
|
&(targetEA->EaName[targetEA->EaNameLength + 1])
|
|
)) {
|
|
*optionsPointer = TDI_ADDRESS_OPTION_DHCP;
|
|
optionsPointer++;
|
|
}
|
|
|
|
CTEAssert(optionsPointer - optionsBuffer <= 3);
|
|
}
|
|
else {
|
|
//
|
|
// This is a raw ip open
|
|
//
|
|
protocol = RawExtractProtocolNumber(
|
|
&(IrpSp->FileObject->FileName)
|
|
);
|
|
|
|
if (protocol == 0xFFFFFFFF) {
|
|
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
|
|
));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
CTEAssert(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
|
|
));
|
|
}
|
|
|
|
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;
|
|
}
|
|
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);
|
|
}
|
|
|
|
CTEAssert(status != TDI_PENDING);
|
|
|
|
return(status);
|
|
}
|
|
|
|
TCPTRACE(("TCPCreate: didn't find any useful ea's\n"));
|
|
status = STATUS_INVALID_EA_NAME;
|
|
ExFreePool(tcpContext);
|
|
|
|
|
|
CTEAssert(status != TDI_PENDING);
|
|
|
|
return(status);
|
|
|
|
} // TCPCreate
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
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
|
|
));
|
|
}
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
CTEAssert(tcpContext->ReferenceCount > 0);
|
|
CTEAssert(tcpContext->CancelIrps);
|
|
|
|
//
|
|
// Remove the initial reference that was put on by TCPCreate.
|
|
//
|
|
CTEAssert(tcpContext->ReferenceCount > 0);
|
|
|
|
if (--(tcpContext->ReferenceCount) == 0) {
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
}
|
|
|
|
KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
IF_TCPDBG(TCP_DEBUG_IRP) {
|
|
TCPTRACE((
|
|
"TCPCloseObjectComplete: irp %lx fileobj %lx refcnt dec to %u\n",
|
|
irp,
|
|
irpSp,
|
|
tcpContext->ReferenceCount
|
|
));
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
tcpContext->CancelIrps = TRUE;
|
|
KeResetEvent(&(tcpContext->CleanupEvent));
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
//
|
|
// Now call the TDI close routine for this object to force all of its Irps
|
|
// to complete.
|
|
//
|
|
request.RequestNotifyObject = TCPCloseObjectComplete;
|
|
request.RequestContext = Irp;
|
|
|
|
switch ((int) 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.
|
|
//
|
|
CTEAssert(FALSE);
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
tcpContext->CancelIrps = FALSE;
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
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
|
|
);
|
|
|
|
CTEAssert(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.
|
|
//
|
|
|
|
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;
|
|
|
|
|
|
tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
|
|
|
|
#if DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CANCEL) {
|
|
|
|
KIRQL oldIrql;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
CTEAssert(tcpContext->ReferenceCount == 0);
|
|
CTEAssert(IsListEmpty(&(tcpContext->PendingIrpList)));
|
|
CTEAssert(IsListEmpty(&(tcpContext->CancelledIrpList)));
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
}
|
|
#endif // DBG
|
|
|
|
IF_TCPDBG(TCP_DEBUG_CLOSE) {
|
|
TCPTRACE(("TCPClose on file object %lx\n", IrpSp->FileObject));
|
|
}
|
|
|
|
ExFreePool(tcpContext);
|
|
|
|
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;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// 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_QUERY_INFORMATION_EX:
|
|
return(TCPQueryInformationEx(Irp, IrpSp));
|
|
break;
|
|
|
|
case IOCTL_TCP_SET_INFORMATION_EX:
|
|
return(TCPSetInformationEx(Irp, IrpSp));
|
|
break;
|
|
|
|
#ifdef SECFLTR
|
|
|
|
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;
|
|
|
|
#endif // SECFLTR
|
|
|
|
default:
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return status;
|
|
|
|
} // TCPDispatchDeviceControl
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
if (DeviceObject != IPDeviceObject) {
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (((int)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 ( ((int)irpSp->FileObject->FsContext2) ==
|
|
TDI_TRANSPORT_ADDRESS_FILE
|
|
)
|
|
{
|
|
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);
|
|
}
|
|
|
|
//
|
|
// Fall through.
|
|
//
|
|
}
|
|
|
|
CTEAssert(
|
|
(((int)irpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
||
|
|
(((int)irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
|
|
||
|
|
(((int)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;
|
|
}
|
|
|
|
CTEAssert(status != TDI_PENDING);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
if (DeviceObject != IPDeviceObject) {
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
CTEAssert(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));
|
|
}
|
|
|
|
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_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;
|
|
}
|
|
|
|
CTEAssert(status != TDI_PENDING);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
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 += 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 UNALIGNED *CurrentAddr; // Address we're examining and may use.
|
|
|
|
|
|
// First, verify that someplace in Address is an address we can use.
|
|
CurrentAddr = (TA_ADDRESS UNALIGNED *)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 = (TA_ADDRESS UNALIGNED *)
|
|
(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
|
|
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);
|
|
|
|
}
|
|
|