summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/tcpip/tcp/ntdisp.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/tcpip/tcp/ntdisp.c4063
1 files changed, 4063 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/tcp/ntdisp.c b/private/ntos/tdi/tcpip/tcp/ntdisp.c
new file mode 100644
index 000000000..15c6f10cc
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/ntdisp.c
@@ -0,0 +1,4063 @@
+/*++
+
+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);
+
+}
+