- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / tcpip / dispatch.c
index 9f846f9..ced62e2 100644 (file)
@@ -8,12 +8,9 @@
  *   CSH 01/08-2000 Created
  * TODO:        Validate device object in all dispatch routines
  */
-#include <tcpip.h>
-#include <dispatch.h>
-#include <routines.h>
-#include <datagram.h>
-#include <info.h>
 
+#include "precomp.h"
+#include <pseh/pseh.h>
 
 NTSTATUS DispPrepareIrpForCancel(
     PTRANSPORT_CONTEXT Context,
@@ -38,7 +35,6 @@ NTSTATUS DispPrepareIrpForCancel(
     if (!Irp->Cancel) {
         IoMarkIrpPending(Irp);
         IoSetCancelRoutine(Irp, CancelRoutine);
-        Context->RefCount++;
         IoReleaseCancelSpinLock(OldIrql);
 
         TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));
@@ -47,19 +43,15 @@ NTSTATUS DispPrepareIrpForCancel(
     }
 
     /* IRP has already been cancelled */
+
     IoReleaseCancelSpinLock(OldIrql);
 
     Irp->IoStatus.Status      = STATUS_CANCELLED;
     Irp->IoStatus.Information = 0;
 
-    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
-
-    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-
     TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));
 
-    return STATUS_CANCELLED;
+    return IRPFinish(Irp, STATUS_CANCELLED);
 }
 
 
@@ -71,35 +63,104 @@ VOID DispCancelComplete(
  *     Context = Pointer to context information (FILE_OBJECT)
  */
 {
-    KIRQL OldIrql;
+    /*KIRQL OldIrql;*/
     PFILE_OBJECT FileObject;
     PTRANSPORT_CONTEXT TranContext;
-    
+
     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
     FileObject  = (PFILE_OBJECT)Context;
     TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
-    
+
+    /* Set the cleanup event */
+    KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
+
+    /* We are expected to release the cancel spin lock */
+    /*IoReleaseCancelSpinLock(OldIrql);*/
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
+}
+
+
+VOID DispDataRequestComplete(
+    PVOID Context,
+    NTSTATUS Status,
+    ULONG Count)
+/*
+ * FUNCTION: Completes a send/receive IRP
+ * ARGUMENTS:
+ *     Context = Pointer to context information (IRP)
+ *     Status  = Status of the request
+ *     Count   = Number of bytes sent or received
+ */
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IrpSp;
+    PTRANSPORT_CONTEXT TranContext;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called for irp %x (%x, %d).\n",
+                           Context, Status, Count));
+
+    Irp         = Context;
+    IrpSp       = IoGetCurrentIrpStackLocation(Irp);
+    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
     IoAcquireCancelSpinLock(&OldIrql);
 
-    /* Remove the reference taken by the cancel routine */
-    TranContext->RefCount--;
+    IoSetCancelRoutine(Irp, NULL);
 
-    if (TranContext->RefCount == 0) {
-        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));
-        /* Set the cleanup event */
-        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
-    }
+    if (Irp->Cancel || TranContext->CancelIrps) {
+        /* The IRP has been cancelled */
+
+        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));
 
-    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));
+        Status = STATUS_CANCELLED;
+        Count  = 0;
+    }
 
     IoReleaseCancelSpinLock(OldIrql);
 
-    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
+    Irp->IoStatus.Status      = Status;
+    Irp->IoStatus.Information = Count;
+
+    TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Status = %x\n",
+                           Irp->IoStatus.Status));
+    TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Information = %d\n",
+                           Irp->IoStatus.Information));
+    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+    IRPFinish(Irp, Irp->IoStatus.Status);
+
+    TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
 }
 
+typedef struct _DISCONNECT_TYPE {
+    UINT Type;
+    PVOID Context;
+    PIRP Irp;
+    PFILE_OBJECT FileObject;
+} DISCONNECT_TYPE, *PDISCONNECT_TYPE;
+
+VOID DispDoDisconnect( PVOID Data ) {
+    PDISCONNECT_TYPE DisType = (PDISCONNECT_TYPE)Data;
+
+    TI_DbgPrint(DEBUG_IRP, ("PostCancel: DoDisconnect\n"));
+    TCPDisconnect
+       ( DisType->Context,
+         DisType->Type,
+         NULL,
+         NULL,
+         DispDataRequestComplete,
+         DisType->Irp );
+    TI_DbgPrint(DEBUG_IRP, ("PostCancel: DoDisconnect done\n"));
 
-VOID DispCancelRequest(
+    DispDataRequestComplete(DisType->Irp, STATUS_CANCELLED, 0);
+
+    DispCancelComplete(DisType->FileObject);
+}
+
+VOID NTAPI DispCancelRequest(
     PDEVICE_OBJECT Device,
     PIRP Irp)
 /*
@@ -113,7 +174,9 @@ VOID DispCancelRequest(
     PTRANSPORT_CONTEXT TranContext;
     PFILE_OBJECT FileObject;
     UCHAR MinorFunction;
-    NTSTATUS Status = STATUS_SUCCESS;
+    DISCONNECT_TYPE DisType;
+    PVOID WorkItem;
+    /*NTSTATUS Status = STATUS_SUCCESS;*/
 
     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
@@ -124,41 +187,48 @@ VOID DispCancelRequest(
 
     TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X)  MinorFunction (0x%X)  IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
 
+    Irp->IoStatus.Status = STATUS_PENDING;
+
 #ifdef DBG
     if (!Irp->Cancel)
         TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
 #endif
 
-    /* Increase reference count to prevent accidential closure
-       of the object while inside the cancel routine */
-    TranContext->RefCount++;
-
-    IoReleaseCancelSpinLock(Irp->CancelIrql);
-
     /* Try canceling the request */
     switch(MinorFunction) {
     case TDI_SEND:
-
     case TDI_RECEIVE:
-        /* FIXME: Close connection */
+       DisType.Type = TDI_DISCONNECT_RELEASE | 
+           ((MinorFunction == TDI_RECEIVE) ? TDI_DISCONNECT_ABORT : 0);
+       DisType.Context = TranContext->Handle.ConnectionContext;
+       DisType.Irp = Irp;
+       DisType.FileObject = FileObject;
+       
+       TCPRemoveIRP( TranContext->Handle.ConnectionContext, Irp );
+
+       if( !ChewCreate( &WorkItem, sizeof(DISCONNECT_TYPE), 
+                        DispDoDisconnect, &DisType ) )
+           ASSERT(0);
         break;
 
     case TDI_SEND_DATAGRAM:
+       Irp->IoStatus.Status = STATUS_CANCELLED;
         if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
             TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
             break;
         }
 
-        DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp);
+        /*DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp);*/
         break;
 
     case TDI_RECEIVE_DATAGRAM:
+       Irp->IoStatus.Status = STATUS_CANCELLED;
         if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
             TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
             break;
         }
 
-        DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp);
+        /*DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp);*/
         break;
 
     default:
@@ -166,64 +236,58 @@ VOID DispCancelRequest(
         break;
     }
 
-    if (Status != STATUS_PENDING)
-        DispCancelComplete(FileObject);
+    if( Irp->IoStatus.Status == STATUS_PENDING )
+       IoMarkIrpPending(Irp);
+
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
 
     TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
 
-VOID DispDataRequestComplete(
-    PVOID Context,
-    NTSTATUS Status,
-    ULONG Count)
+VOID NTAPI DispCancelListenRequest(
+    PDEVICE_OBJECT Device,
+    PIRP Irp)
 /*
- * FUNCTION: Completes a send/receive IRP
+ * FUNCTION: Cancels a listen IRP
  * ARGUMENTS:
- *     Context = Pointer to context information (IRP)
- *     Status  = Status of the request
- *     Count   = Number of bytes sent or received
+ *     Device = Pointer to device object
+ *     Irp    = Pointer to an I/O request packet
  */
 {
-    PIRP Irp;
     PIO_STACK_LOCATION IrpSp;
     PTRANSPORT_CONTEXT TranContext;
-    KIRQL OldIrql;
+    PFILE_OBJECT FileObject;
+    PCONNECTION_ENDPOINT Connection;
+    /*NTSTATUS Status = STATUS_SUCCESS;*/
 
     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
-    Irp         = (PIRP)Context;
-    IrpSp       = IoGetCurrentIrpStackLocation(Irp);
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
-
-    IoAcquireCancelSpinLock(&OldIrql);
-
-    IoSetCancelRoutine(Irp, NULL);
-    TranContext->RefCount--;
-    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));
-    if (TranContext->RefCount == 0) {
-        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));
+    IrpSp         = IoGetCurrentIrpStackLocation(Irp);
+    FileObject    = IrpSp->FileObject;
+    TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+    ASSERT( TDI_LISTEN == IrpSp->MinorFunction);
 
-        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
-    }
+    TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp));
 
-    if (Irp->Cancel || TranContext->CancelIrps) {
-        /* The IRP has been cancelled */
-
-        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));
+#ifdef DBG
+    if (!Irp->Cancel)
+        TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
+#endif
 
-        Status = STATUS_CANCELLED;
-        Count  = 0;
-    }
+    /* Try canceling the request */
+    Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+    TCPAbortListenForSocket(
+           Connection->AddressFile->Listener,
+           Connection );
 
-    IoReleaseCancelSpinLock(OldIrql);
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
 
-    Irp->IoStatus.Status      = Status;
-    Irp->IoStatus.Information = Count;
+    DispDataRequestComplete(Irp, STATUS_CANCELLED, 0);
 
-    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+    DispCancelComplete(FileObject);
 
-    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
 
@@ -239,7 +303,7 @@ NTSTATUS DispTdiAccept(
 {
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
-       return STATUS_NOT_IMPLEMENTED;
+  return STATUS_NOT_IMPLEMENTED;
 }
 
 
@@ -258,7 +322,7 @@ NTSTATUS DispTdiAssociateAddress(
   PIO_STACK_LOCATION IrpSp;
   PCONNECTION_ENDPOINT Connection;
   PFILE_OBJECT FileObject;
-  PADDRESS_FILE AddrFile;
+  PADDRESS_FILE AddrFile = NULL;
   NTSTATUS Status;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
@@ -294,8 +358,8 @@ NTSTATUS DispTdiAssociateAddress(
     (PVOID*)&FileObject,
     NULL);
   if (!NT_SUCCESS(Status)) {
-    TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X).\n",
-      Parameters->AddressHandle));
+    TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n",
+      Parameters->AddressHandle, Status));
     return STATUS_INVALID_PARAMETER;
   }
 
@@ -317,13 +381,11 @@ NTSTATUS DispTdiAssociateAddress(
 
   AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
   if (!AddrFile) {
-    ObDereferenceObject(FileObject);
-    TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
-    return STATUS_INVALID_PARAMETER;
+      ObDereferenceObject(FileObject);
+      TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
+      return STATUS_INVALID_PARAMETER;
   }
 
-  /* The connection endpoint references the address file object */
-  ReferenceObject(AddrFile);
   Connection->AddressFile = AddrFile;
 
   /* Add connection endpoint to the address file */
@@ -332,7 +394,7 @@ NTSTATUS DispTdiAssociateAddress(
   /* FIXME: Maybe do this in DispTdiDisassociateAddress() instead? */
   ObDereferenceObject(FileObject);
 
-  return STATUS_SUCCESS;
+  return Status;
 }
 
 
@@ -350,7 +412,6 @@ NTSTATUS DispTdiConnect(
   PTDI_REQUEST_KERNEL Parameters;
   PTRANSPORT_CONTEXT TranContext;
   PIO_STACK_LOCATION IrpSp;
-  TDI_REQUEST Request;
   NTSTATUS Status;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
@@ -373,15 +434,14 @@ NTSTATUS DispTdiConnect(
 
   Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
 
-  /* Initialize a connect request */
-  Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
-  Request.RequestNotifyObject      = DispDataRequestComplete;
-  Request.RequestContext           = Irp;
-
   Status = TCPConnect(
-    &Request,
-    Parameters->RequestConnectionInformation,
-    Parameters->ReturnConnectionInformation);
+      TranContext->Handle.ConnectionContext,
+      Parameters->RequestConnectionInformation,
+      Parameters->ReturnConnectionInformation,
+      DispDataRequestComplete,
+      Irp );
+
+  TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
 
   return Status;
 }
@@ -400,7 +460,6 @@ NTSTATUS DispTdiDisassociateAddress(
   PCONNECTION_ENDPOINT Connection;
   PTRANSPORT_CONTEXT TranContext;
   PIO_STACK_LOCATION IrpSp;
-  KIRQL OldIrql;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
@@ -425,11 +484,6 @@ NTSTATUS DispTdiDisassociateAddress(
     return STATUS_INVALID_PARAMETER;
   }
 
-  /* Remove the reference put on the address file object */
-  KeAcquireSpinLock(&Connection->Lock, &OldIrql);
-  DereferenceObject(Connection->AddressFile);
-  KeReleaseSpinLock(&Connection->Lock, OldIrql);
-
   return STATUS_SUCCESS;
 }
 
@@ -443,6 +497,150 @@ NTSTATUS DispTdiDisconnect(
  * RETURNS:
  *     Status of operation
  */
+{
+  NTSTATUS Status;
+  PTDI_REQUEST_KERNEL_DISCONNECT DisReq;
+  PCONNECTION_ENDPOINT Connection;
+  PTRANSPORT_CONTEXT TranContext;
+  PIO_STACK_LOCATION IrpSp;
+
+  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+  DisReq = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
+
+  /* Get associated connection endpoint file object. Quit if none exists */
+
+  TranContext = IrpSp->FileObject->FsContext;
+  if (!TranContext) {
+    TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+    return STATUS_INVALID_CONNECTION;
+  }
+
+  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+  if (!Connection) {
+    TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+    return STATUS_INVALID_CONNECTION;
+  }
+
+  Status = TCPDisconnect(
+      TranContext->Handle.ConnectionContext,
+      DisReq->RequestFlags,
+      DisReq->RequestConnectionInformation,
+      DisReq->ReturnConnectionInformation,
+      DispDataRequestComplete,
+      Irp );
+
+  TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
+
+  return Status;
+}
+
+
+NTSTATUS DispTdiListen(
+  PIRP Irp)
+/*
+ * FUNCTION: TDI_LISTEN handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+  PCONNECTION_ENDPOINT Connection;
+  PTDI_REQUEST_KERNEL Parameters;
+  PTRANSPORT_CONTEXT TranContext;
+  PIO_STACK_LOCATION IrpSp;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+  /* Get associated connection endpoint file object. Quit if none exists */
+
+  TranContext = IrpSp->FileObject->FsContext;
+  if (TranContext == NULL)
+    {
+      TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+      return STATUS_INVALID_CONNECTION;
+    }
+
+  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+  if (Connection == NULL)
+    {
+      TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+      return STATUS_INVALID_CONNECTION;
+    }
+
+  Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
+
+  TI_DbgPrint(MIN_TRACE, ("Connection->AddressFile: %x\n",
+                         Connection->AddressFile ));
+  if( Connection->AddressFile ) {
+      TI_DbgPrint(MIN_TRACE, ("Connection->AddressFile->Listener: %x\n",
+                             Connection->AddressFile->Listener));
+  }
+
+  /* Listening will require us to create a listening socket and store it in
+   * the address file.  It will be signalled, and attempt to complete an irp
+   * when a new connection arrives. */
+  /* The important thing to note here is that the irp we'll complete belongs
+   * to the socket to be accepted onto, not the listener */
+  if( !Connection->AddressFile->Listener ) {
+      Connection->AddressFile->Listener =
+         TCPAllocateConnectionEndpoint( NULL );
+
+      if( !Connection->AddressFile->Listener )
+         Status = STATUS_NO_MEMORY;
+
+      if( NT_SUCCESS(Status) ) {
+         Connection->AddressFile->Listener->AddressFile =
+             Connection->AddressFile;
+
+         Status = TCPSocket( Connection->AddressFile->Listener,
+                             Connection->AddressFile->Family,
+                             SOCK_STREAM,
+                             Connection->AddressFile->Protocol );
+      }
+
+      if( NT_SUCCESS(Status) )
+         Status = TCPListen( Connection->AddressFile->Listener, 1024 );
+         /* BACKLOG */
+  }
+  if( NT_SUCCESS(Status) ) {
+      Status = DispPrepareIrpForCancel
+          (TranContext->Handle.ConnectionContext,
+           Irp,
+           (PDRIVER_CANCEL)DispCancelListenRequest);
+  }
+
+  if( NT_SUCCESS(Status) ) {
+      Status = TCPAccept
+         ( (PTDI_REQUEST)Parameters,
+           Connection->AddressFile->Listener,
+           Connection,
+           DispDataRequestComplete,
+           Irp );
+  }
+
+  TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
+
+  return Status;
+}
+
+
+NTSTATUS DispTdiQueryInformation(
+  PDEVICE_OBJECT DeviceObject,
+  PIRP Irp)
+/*
+ * FUNCTION: TDI_QUERY_INFORMATION handler
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to device object structure
+ *     Irp          = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
 {
   PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
   PTRANSPORT_CONTEXT TranContext;
@@ -475,7 +673,9 @@ NTSTATUS DispTdiDisconnect(
             break;
 
           case TDI_CONNECTION_FILE:
-            AddrFile = ((PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext)->AddressFile;
+            AddrFile =
+              ((PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext)->
+              AddressFile;
             break;
 
           default:
@@ -489,55 +689,90 @@ NTSTATUS DispTdiDisconnect(
         }
 
         if (MmGetMdlByteCount(Irp->MdlAddress) <
-            (sizeof(TDI_ADDRESS_INFO) + sizeof(TDI_ADDRESS_IP))) {
+            (FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) +
+             sizeof(TDI_ADDRESS_IP))) {
           TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
           return STATUS_BUFFER_OVERFLOW;
         }
 
-        /* FIXME: Is this count really the one we should return? */
-        AddressInfo->ActivityCount = AddrFile->RefCount;
-
         Address = (PTA_IP_ADDRESS)&AddressInfo->Address;
         Address->TAAddressCount = 1;
         Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
         Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
         Address->Address[0].Address[0].sin_port = AddrFile->Port;
-        Address->Address[0].Address[0].in_addr = AddrFile->ADE->Address->Address.IPv4Address;        
+        Address->Address[0].Address[0].in_addr =
+          AddrFile->Address.Address.IPv4Address;
         RtlZeroMemory(
           &Address->Address[0].Address[0].sin_zero,
           sizeof(Address->Address[0].Address[0].sin_zero));
 
         return STATUS_SUCCESS;
       }
+
+    case TDI_QUERY_CONNECTION_INFO:
+      {
+        PTDI_CONNECTION_INFORMATION AddressInfo;
+        PADDRESS_FILE AddrFile;
+        PCONNECTION_ENDPOINT Endpoint = NULL;
+
+        AddressInfo = (PTDI_CONNECTION_INFORMATION)
+          MmGetSystemAddressForMdl(Irp->MdlAddress);
+
+        switch ((ULONG)IrpSp->FileObject->FsContext2) {
+          case TDI_TRANSPORT_ADDRESS_FILE:
+            AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
+            break;
+
+          case TDI_CONNECTION_FILE:
+            Endpoint =
+              (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+            break;
+
+          default:
+            TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        if (!Endpoint) {
+          TI_DbgPrint(MID_TRACE, ("No connection object.\n"));
+          return STATUS_INVALID_PARAMETER;
+        }
+
+        if (MmGetMdlByteCount(Irp->MdlAddress) <
+            (FIELD_OFFSET(TDI_CONNECTION_INFORMATION, RemoteAddress) +
+             sizeof(PVOID))) {
+          TI_DbgPrint(MID_TRACE, ("MDL buffer too small (ptr).\n"));
+          return STATUS_BUFFER_OVERFLOW;
+        }
+
+        return TCPGetPeerAddress( Endpoint, AddressInfo->RemoteAddress );
+      }
   }
 
   return STATUS_NOT_IMPLEMENTED;
 }
 
 
-NTSTATUS DispTdiListen(
+NTSTATUS DispTdiReceive(
   PIRP Irp)
 /*
- * FUNCTION: TDI_LISTEN handler
+ * FUNCTION: TDI_RECEIVE handler
  * ARGUMENTS:
  *     Irp = Pointer to an I/O request packet
  * RETURNS:
  *     Status of operation
  */
 {
-  PCONNECTION_ENDPOINT Connection;
-  PTDI_REQUEST_KERNEL Parameters;
-  PTRANSPORT_CONTEXT TranContext;
   PIO_STACK_LOCATION IrpSp;
-  PTDI_REQUEST Request;
+  PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
+  PTRANSPORT_CONTEXT TranContext;
   NTSTATUS Status;
-  KIRQL OldIrql;
+  ULONG BytesReceived;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
   IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
-  /* Get associated connection endpoint file object. Quit if none exists */
+  ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
 
   TranContext = IrpSp->FileObject->FsContext;
   if (TranContext == NULL)
@@ -546,84 +781,42 @@ NTSTATUS DispTdiListen(
       return STATUS_INVALID_CONNECTION;
     }
 
-  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
-  if (Connection == NULL)
+  if (TranContext->Handle.ConnectionContext == NULL)
     {
       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
       return STATUS_INVALID_CONNECTION;
     }
 
-  Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
-
-  /* Initialize a listen request */
-  Request = (PTDI_REQUEST) ExAllocatePool(NonPagedPool, sizeof(TDI_REQUEST));
-  if (Request == NULL)
-    {
-      return STATUS_NO_MEMORY;
-    }
+  /* Initialize a receive request */
+  Status = DispPrepareIrpForCancel
+      (TranContext->Handle.ConnectionContext,
+       Irp,
+       (PDRIVER_CANCEL)DispCancelRequest);
 
-  Status = DispPrepareIrpForCancel(TranContext, Irp, NULL);
+  TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
   if (NT_SUCCESS(Status))
     {
-      Request->Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
-      Request->RequestNotifyObject      = DispDataRequestComplete;
-      Request->RequestContext           = Irp;
-
-      Status = TCPListen(
-        Request,
-        Parameters->RequestConnectionInformation,
-        Parameters->ReturnConnectionInformation);
+      Status = TCPReceiveData(
+         TranContext->Handle.ConnectionContext,
+         (PNDIS_BUFFER)Irp->MdlAddress,
+         ReceiveInfo->ReceiveLength,
+         &BytesReceived,
+         ReceiveInfo->ReceiveFlags,
+         DispDataRequestComplete,
+         Irp);
       if (Status != STATUS_PENDING)
-        {
-          IoAcquireCancelSpinLock(&OldIrql);
-          IoSetCancelRoutine(Irp, NULL);
-          IoReleaseCancelSpinLock(OldIrql);
-        }
+      {
+          DispDataRequestComplete(Irp, Status, BytesReceived);
+      } else
+         IoMarkIrpPending(Irp);
     }
 
-  if (Status != STATUS_PENDING)
-    {
-      ExFreePool(Request);
-    }
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
 
   return Status;
 }
 
 
-NTSTATUS DispTdiQueryInformation(
-  PDEVICE_OBJECT DeviceObject,
-  PIRP Irp)
-/*
- * FUNCTION: TDI_QUERY_INFORMATION handler
- * ARGUMENTS:
- *     DeviceObject = Pointer to device object structure
- *     Irp          = Pointer to an I/O request packet
- * RETURNS:
- *     Status of operation
- */
-{
-  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
-
-       return STATUS_NOT_IMPLEMENTED;
-}
-
-
-NTSTATUS DispTdiReceive(
-  PIRP Irp)
-/*
- * FUNCTION: TDI_RECEIVE handler
- * ARGUMENTS:
- *     Irp = Pointer to an I/O request packet
- * RETURNS:
- *     Status of operation
- */
-{
-  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
-
-       return STATUS_NOT_IMPLEMENTED;
-}
-
-
 NTSTATUS DispTdiReceiveDatagram(
     PIRP Irp)
 /*
@@ -647,30 +840,46 @@ NTSTATUS DispTdiReceiveDatagram(
   DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
 
   TranContext = IrpSp->FileObject->FsContext;
+  if (TranContext == NULL)
+    {
+      TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+      return STATUS_INVALID_ADDRESS;
+    }
+
   /* Initialize a receive request */
   Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
   Request.RequestNotifyObject  = DispDataRequestComplete;
   Request.RequestContext       = Irp;
+
   Status = DispPrepareIrpForCancel(
     IrpSp->FileObject->FsContext,
     Irp,
     (PDRIVER_CANCEL)DispCancelRequest);
-  if (NT_SUCCESS(Status)) {
-    Status = UDPReceiveDatagram(
-      &Request,
-      DgramInfo->ReceiveDatagramInformation,
-      (PNDIS_BUFFER)Irp->MdlAddress,
-      DgramInfo->ReceiveLength,
-      DgramInfo->ReceiveFlags,
-      DgramInfo->ReturnDatagramInformation,
-      &BytesReceived);
-    if (Status != STATUS_PENDING) {
-      DispDataRequestComplete(Irp, Status, BytesReceived);
-      /* Return STATUS_PENDING because DispPrepareIrpForCancel marks
-         the Irp as pending */
-      Status = STATUS_PENDING;
+
+  if (NT_SUCCESS(Status))
+    {
+       PCHAR DataBuffer;
+       UINT BufferSize;
+
+       NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
+                        &DataBuffer,
+                        &BufferSize );
+
+      Status = UDPReceiveDatagram(
+         Request.Handle.AddressHandle,
+         DgramInfo->ReceiveDatagramInformation,
+         DataBuffer,
+         DgramInfo->ReceiveLength,
+         DgramInfo->ReceiveFlags,
+         DgramInfo->ReturnDatagramInformation,
+         &BytesReceived,
+         (PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
+         Irp);
+      if (Status != STATUS_PENDING) {
+          DispDataRequestComplete(Irp, Status, BytesReceived);
+      } else
+         IoMarkIrpPending(Irp);
     }
-  }
 
   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
 
@@ -688,9 +897,62 @@ NTSTATUS DispTdiSend(
  *     Status of operation
  */
 {
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+  PIO_STACK_LOCATION IrpSp;
+  PTDI_REQUEST_KERNEL_SEND SendInfo;
+  PTRANSPORT_CONTEXT TranContext;
+  NTSTATUS Status;
+  ULONG BytesSent;
 
-       return STATUS_NOT_IMPLEMENTED;
+  TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+  IrpSp = IoGetCurrentIrpStackLocation(Irp);
+  SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
+
+  TranContext = IrpSp->FileObject->FsContext;
+  if (TranContext == NULL)
+    {
+      TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
+      return STATUS_INVALID_CONNECTION;
+    }
+
+  if (TranContext->Handle.ConnectionContext == NULL)
+    {
+      TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+      return STATUS_INVALID_CONNECTION;
+    }
+
+  Status = DispPrepareIrpForCancel(
+    IrpSp->FileObject->FsContext,
+    Irp,
+    (PDRIVER_CANCEL)DispCancelRequest);
+
+  TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
+  if (NT_SUCCESS(Status))
+    {
+       PCHAR Data;
+       UINT Len;
+
+       NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
+
+       TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
+       Status = TCPSendData(
+           TranContext->Handle.ConnectionContext,
+           Data,
+           SendInfo->SendLength,
+           &BytesSent,
+           SendInfo->SendFlags,
+           DispDataRequestComplete,
+           Irp);
+       if (Status != STATUS_PENDING)
+       {
+           DispDataRequestComplete(Irp, Status, BytesSent);
+       } else
+           IoMarkIrpPending( Irp );
+    }
+
+  TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+  return Status;
 }
 
 
@@ -725,20 +987,40 @@ NTSTATUS DispTdiSendDatagram(
         IrpSp->FileObject->FsContext,
         Irp,
         (PDRIVER_CANCEL)DispCancelRequest);
+
     if (NT_SUCCESS(Status)) {
+       PCHAR DataBuffer;
+       UINT BufferSize;
+
+       TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
 
-        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress 
+       NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
+                        &DataBuffer,
+                        &BufferSize );
+
+        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
            must be of type PTDI_ADDRESS_IP */
+       TI_DbgPrint(MID_TRACE,
+                   ("About to call send routine %x\n",
+                    (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
+
+        if( (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send) )
+            Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
+                Request.Handle.AddressHandle,
+                DgramInfo->SendDatagramInformation,
+                DataBuffer,
+                BufferSize,
+                &Irp->IoStatus.Information);
+        else
+            Status = STATUS_UNSUCCESSFUL;
 
-        Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
-            &Request, DgramInfo->SendDatagramInformation,
-            (PNDIS_BUFFER)Irp->MdlAddress, DgramInfo->SendLength);
         if (Status != STATUS_PENDING) {
-            DispDataRequestComplete(Irp, Status, 0);
+            DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
             /* Return STATUS_PENDING because DispPrepareIrpForCancel
                marks Irp as pending */
             Status = STATUS_PENDING;
-        }
+        } else
+           IoMarkIrpPending( Irp );
     }
 
     TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
@@ -747,8 +1029,7 @@ NTSTATUS DispTdiSendDatagram(
 }
 
 
-NTSTATUS DispTdiSetEventHandler(
-  PIRP Irp)
+NTSTATUS DispTdiSetEventHandler(PIRP Irp)
 /*
  * FUNCTION: TDI_SET_EVENT_HANDER handler
  * ARGUMENTS:
@@ -784,8 +1065,8 @@ NTSTATUS DispTdiSetEventHandler(
 
   Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
   Status     = STATUS_SUCCESS;
-  
-  KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
 
   /* Set the event handler. if an event handler is associated with
      a specific event, it's flag (RegisteredXxxHandler) is TRUE.
@@ -906,7 +1187,7 @@ NTSTATUS DispTdiSetEventHandler(
     Status = STATUS_INVALID_PARAMETER;
   }
 
-  KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
 
   return Status;
 }
@@ -948,16 +1229,18 @@ VOID DispTdiQueryInformationExComplete(
         Count = CopyBufferToBufferChain(
             QueryContext->InputMdl,
             FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
-            (PUCHAR)&QueryContext->QueryInfo.Context,
+            (PCHAR)&QueryContext->QueryInfo.Context,
             CONTEXT_SIZE);
     }
 
     MmUnlockPages(QueryContext->InputMdl);
     IoFreeMdl(QueryContext->InputMdl);
-    MmUnlockPages(QueryContext->OutputMdl);
-    IoFreeMdl(QueryContext->OutputMdl);
+    if( QueryContext->OutputMdl ) {
+       MmUnlockPages(QueryContext->OutputMdl);
+       IoFreeMdl(QueryContext->OutputMdl);
+    }
 
-    QueryContext->Irp->IoStatus.Information = Count;
+    QueryContext->Irp->IoStatus.Information = ByteCount;
     QueryContext->Irp->IoStatus.Status      = Status;
 
     ExFreePool(QueryContext);
@@ -1025,9 +1308,7 @@ NTSTATUS DispTdiQueryInformationEx(
 
         QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT));
         if (QueryContext) {
-#ifdef _MSC_VER
-            try {
-#endif
+           _SEH_TRY {
                 InputMdl = IoAllocateMdl(InputBuffer,
                     sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
                     FALSE, TRUE, NULL);
@@ -1049,14 +1330,12 @@ NTSTATUS DispTdiQueryInformationEx(
 
                     RtlCopyMemory(&QueryContext->QueryInfo,
                         InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
-
                 } else
                     Status = STATUS_INSUFFICIENT_RESOURCES;
-#ifdef _MSC_VER
-            } except(EXCEPTION_EXECUTE_HANDLER) {
-                Status = GetExceptionCode();
-            }
-#endif
+            } _SEH_HANDLE {
+                Status = _SEH_GetExceptionCode();
+            } _SEH_END;
+
             if (NT_SUCCESS(Status)) {
                 Size = MmGetMdlByteCount(OutputMdl);
 
@@ -1093,8 +1372,57 @@ NTSTATUS DispTdiQueryInformationEx(
             ExFreePool(QueryContext);
         } else
             Status = STATUS_INSUFFICIENT_RESOURCES;
-    } else
-        Status = STATUS_INVALID_PARAMETER;
+    } else if( InputBufferLength ==
+              sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) ) {
+       /* Handle the case where the user is probing the buffer for length */
+       TI_DbgPrint(MAX_TRACE, ("InputBufferLength %d OutputBufferLength %d\n",
+                               InputBufferLength, OutputBufferLength));
+        InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
+            IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+       Size = 0;
+
+        QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT));
+        if (!QueryContext) return STATUS_INSUFFICIENT_RESOURCES;
+
+       _SEH_TRY {
+           InputMdl = IoAllocateMdl(InputBuffer,
+                                    sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+                                    FALSE, TRUE, NULL);
+
+           MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
+                               IoModifyAccess);
+
+           InputMdlLocked = TRUE;
+           Status = STATUS_SUCCESS;
+       } _SEH_HANDLE {
+           TI_DbgPrint(MAX_TRACE, ("Failed to acquire client buffer\n"));
+           Status = _SEH_GetExceptionCode();
+       } _SEH_END;
+
+       if( !NT_SUCCESS(Status) || !InputMdl ) {
+           if( InputMdl ) IoFreeMdl( InputMdl );
+           ExFreePool(QueryContext);
+           return Status;
+       }
+
+       RtlCopyMemory(&QueryContext->QueryInfo,
+                     InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
+
+       QueryContext->Irp       = Irp;
+       QueryContext->InputMdl  = InputMdl;
+       QueryContext->OutputMdl = NULL;
+
+       Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
+       Request.RequestContext      = QueryContext;
+       Status = InfoTdiQueryInformationEx(&Request,
+                                          &QueryContext->QueryInfo.ID,
+                                          NULL,
+                                          &Size,
+                                          &QueryContext->QueryInfo.Context);
+       DispTdiQueryInformationExComplete(QueryContext, Status, Size);
+       TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+    } else Status = STATUS_INVALID_PARAMETER;
 
     TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
 
@@ -1144,9 +1472,7 @@ NTSTATUS DispTdiSetInformationEx(
 
         TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
 
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
-
-        return STATUS_INVALID_PARAMETER;
+        return IRPFinish(Irp, STATUS_INVALID_PARAMETER);
     }
 
     Status = DispPrepareIrpForCancel(TranContext, Irp, NULL);
@@ -1167,4 +1493,66 @@ NTSTATUS DispTdiSetInformationEx(
     return Status;
 }
 
+/* TODO: Support multiple addresses per interface.
+ * For now just set the nte context to the interface index.
+ *
+ * Later on, create an NTE context and NTE instance
+ */
+
+NTSTATUS DispTdiSetIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
+    NTSTATUS Status = STATUS_DEVICE_DOES_NOT_EXIST;
+    PIP_SET_ADDRESS IpAddrChange =
+        (PIP_SET_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
+    IF_LIST_ITER(IF);
+
+    ForEachInterface(IF) {
+        if( IF->Unicast.Address.IPv4Address == IpAddrChange->Address ) {
+            Status = STATUS_DUPLICATE_OBJECTID;
+            break;
+        }
+        if( IF->Index == IpAddrChange->NteIndex ) {
+            IPRemoveInterfaceRoute( IF );
+
+            IF->Unicast.Type = IP_ADDRESS_V4;
+            IF->Unicast.Address.IPv4Address = IpAddrChange->Address;
+            IF->Netmask.Type = IP_ADDRESS_V4;
+            IF->Netmask.Address.IPv4Address = IpAddrChange->Netmask;
+
+            TI_DbgPrint(MID_TRACE,("New Unicast Address: %x\n",
+                                   IF->Unicast.Address.IPv4Address));
+            TI_DbgPrint(MID_TRACE,("New Netmask        : %x\n",
+                                   IF->Netmask.Address.IPv4Address));
+
+            IPAddInterfaceRoute( IF );
+
+            IpAddrChange->Address = IF->Index;
+            Status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = IF->Index;
+            break;
+        }
+    } EndFor(IF);
+
+    Irp->IoStatus.Status = Status;
+    return Status;
+}
+
+NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    PUSHORT NteIndex = Irp->AssociatedIrp.SystemBuffer;
+    IF_LIST_ITER(IF);
+
+    ForEachInterface(IF) {
+        if( IF->Index == *NteIndex ) {
+            IF->Unicast.Type = IP_ADDRESS_V4;
+            IF->Unicast.Address.IPv4Address = 0;
+            IF->Netmask.Type = IP_ADDRESS_V4;
+            IF->Netmask.Address.IPv4Address = 0;
+            Status = STATUS_SUCCESS;
+        }
+    } EndFor(IF);
+
+    Irp->IoStatus.Status = Status;
+    return Status;
+}
+
 /* EOF */