Fix firefox exit. Implement a simple work queue for possibly dispatch level
[reactos.git] / reactos / drivers / net / tcpip / tcpip / dispatch.c
index c07dde5..c3fe3c6 100644 (file)
@@ -10,7 +10,9 @@
  */
 
 #include "precomp.h"
-#include <pseh.h>
+#include <pseh/pseh.h>
+
+extern VOID DeleteConnectionEndpoint( PCONNECTION_ENDPOINT Endpoint );
 
 NTSTATUS DispPrepareIrpForCancel(
     PTRANSPORT_CONTEXT Context,
@@ -43,7 +45,7 @@ NTSTATUS DispPrepareIrpForCancel(
     }
 
     /* IRP has already been cancelled */
+
     IoReleaseCancelSpinLock(OldIrql);
 
     Irp->IoStatus.Status      = STATUS_CANCELLED;
@@ -63,10 +65,10 @@ 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;
@@ -76,12 +78,115 @@ VOID DispCancelComplete(
     KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
 
     /* We are expected to release the cancel spin lock */
-    IoReleaseCancelSpinLock(OldIrql);
+    /*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);
+
+    IoSetCancelRoutine(Irp, NULL);
+
+    if (Irp->Cancel || TranContext->CancelIrps) {
+        /* The IRP has been cancelled */
+
+        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));
+
+        Status = STATUS_CANCELLED;
+        Count  = 0;
+    }
+
+    IoReleaseCancelSpinLock(OldIrql);
+
+    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"));
+}
+
+VOID DDKAPI CancelQueuePassiveHandler( PVOID CancelRequestVoid ) 
+{
+    KIRQL OldIrql;
+    PCANCEL_REQUEST CancelReq;
+    PLIST_ENTRY CqEntry;
+
+    KeAcquireSpinLock( &CancelQueueLock, &OldIrql );
+
+    TI_DbgPrint(DEBUG_IRP,("CANCEL QUEUE: Starting\n"));
+
+    for( CqEntry = CancelQueue.Flink;
+        CqEntry != &CancelQueue;
+       ) {
+       CancelReq = CONTAINING_RECORD(CqEntry, CANCEL_REQUEST, Entry);
+       ExInterlockedRemoveHeadList( &CancelQueue, &CancelQueueLock );
+       CqEntry = CancelQueue.Flink;
+
+       KeReleaseSpinLock( &CancelQueueLock, OldIrql );
+
+       TI_DbgPrint(DEBUG_IRP,("CANCEL QUEUE: Executing %x\n", CancelReq));
+
+       switch( CancelReq->Type ) {
+       case TCP_CANCEL_DISCONNECT:
+           TCPDisconnect
+               ( CancelReq->Context,
+                 CancelReq->Flags,
+                 NULL,
+                 NULL,
+                 DispDataRequestComplete,
+                 CancelReq->Irp );
+           break;
+
+       case TCP_CANCEL_CLOSE:
+           TCPClose( CancelReq->Context );
+           DeleteConnectionEndpoint( CancelReq->Context );
+           break;
+       }
+
+       TCPMarkForDisconnect( CancelReq->Context, FALSE );
+
+       ExFreePool( CancelReq );
+
+       KeAcquireSpinLock( &CancelQueueLock, &OldIrql );
+    }
+
+    TI_DbgPrint(DEBUG_IRP,("CANCEL QUEUE: Ending\n"));
+
+    KeReleaseSpinLock( &CancelQueueLock, OldIrql );
+}
+
 VOID DDKAPI DispCancelRequest(
     PDEVICE_OBJECT Device,
     PIRP Irp)
@@ -96,7 +201,8 @@ VOID DDKAPI DispCancelRequest(
     PTRANSPORT_CONTEXT TranContext;
     PFILE_OBJECT FileObject;
     UCHAR MinorFunction;
-    NTSTATUS Status = STATUS_SUCCESS;
+    PCANCEL_REQUEST CancelRequest;
+    /*NTSTATUS Status = STATUS_SUCCESS;*/
 
     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
@@ -112,13 +218,24 @@ VOID DDKAPI DispCancelRequest(
         TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
 #endif
 
-    IoReleaseCancelSpinLock(Irp->CancelIrql);
-
     /* Try canceling the request */
     switch(MinorFunction) {
     case TDI_SEND:
     case TDI_RECEIVE:
-        /* FIXME: Close connection */
+       CancelRequest = ExAllocatePoolWithTag
+           ( sizeof(CANCEL_REQUEST), NonPagedPool, FOURCC('T','c','k','O') );
+       TCPMarkForDisconnect( TranContext->Handle.ConnectionContext, TRUE );
+       if( CancelRequest ) {
+           TI_DbgPrint(DEBUG_IRP,("CANCEL QUEUE:-> %x\n", CancelRequest));
+           CancelRequest->Flags = TDI_DISCONNECT_RELEASE |
+               (MinorFunction == TDI_RECEIVE) ? TDI_DISCONNECT_ABORT : 0;
+           CancelRequest->Context = TranContext->Handle.ConnectionContext;
+           CancelRequest->Irp = Irp;
+           CancelRequest->Type = TCP_CANCEL_DISCONNECT;
+           ExInterlockedInsertTailList
+               ( &CancelQueue, &CancelRequest->Entry, &CancelQueueLock );
+           ExQueueWorkItem( &CancelQueueWork, CriticalWorkQueue );
+       }
         break;
 
     case TDI_SEND_DATAGRAM:
@@ -144,63 +261,57 @@ VOID DDKAPI DispCancelRequest(
         break;
     }
 
-    if (Status != STATUS_PENDING)
-        DispCancelComplete(FileObject);
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    DispCancelComplete(FileObject);
 
     TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
-VOID DispDataRequestComplete(
-    PVOID Context,
-    NTSTATUS Status,
-    ULONG Count)
+
+VOID DDKAPI 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;
-
-    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);
+    PFILE_OBJECT FileObject;
+    PCONNECTION_ENDPOINT Connection;
+    /*NTSTATUS Status = STATUS_SUCCESS;*/
 
-    IoSetCancelRoutine(Irp, NULL);
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
-    if (Irp->Cancel || TranContext->CancelIrps) {
-        /* The IRP has been cancelled */
+    IrpSp         = IoGetCurrentIrpStackLocation(Irp);
+    FileObject    = IrpSp->FileObject;
+    TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+    ASSERT( TDI_LISTEN == IrpSp->MinorFunction);
 
-        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));
+    TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp));
 
-        Status = STATUS_CANCELLED;
-        Count  = 0;
-    }
+#ifdef DBG
+    if (!Irp->Cancel)
+        TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
+#endif
 
-    IoReleaseCancelSpinLock(OldIrql);
+    /* Try canceling the request */
+    Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+    TCPAbortListenForSocket(
+           Connection->AddressFile->Listener,
+           Connection );
 
-    Irp->IoStatus.Status      = Status;
-    Irp->IoStatus.Information = Count;
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
 
-    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));
+    DispDataRequestComplete(Irp, STATUS_CANCELLED, 0);
 
-    IRPFinish(Irp, Irp->IoStatus.Status);
+    DispCancelComplete(FileObject);
 
-    TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
 
@@ -271,8 +382,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;
   }
 
@@ -353,7 +464,7 @@ NTSTATUS DispTdiConnect(
       Parameters->ReturnConnectionInformation,
       DispDataRequestComplete,
       Irp );
-  
+
   TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
 
   return Status;
@@ -411,14 +522,18 @@ NTSTATUS DispTdiDisconnect(
  *     Status of operation
  */
 {
-  PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
+  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);
-  Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+  DisReq = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
+
+  /* Get associated connection endpoint file object. Quit if none exists */
 
   TranContext = IrpSp->FileObject->FsContext;
   if (!TranContext) {
@@ -426,56 +541,23 @@ NTSTATUS DispTdiDisconnect(
     return STATUS_INVALID_CONNECTION;
   }
 
-  switch (Parameters->QueryType)
-  {
-    case TDI_QUERY_ADDRESS_INFO:
-      {
-        PTDI_ADDRESS_INFO AddressInfo;
-        PADDRESS_FILE AddrFile;
-        PTA_IP_ADDRESS Address;
-
-        AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress);
-
-        switch ((ULONG)IrpSp->FileObject->FsContext2) {
-          case TDI_TRANSPORT_ADDRESS_FILE:
-            AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
-            break;
-
-          case TDI_CONNECTION_FILE:
-            AddrFile = ((PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext)->AddressFile;
-            break;
-
-          default:
-            TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
-            return STATUS_INVALID_PARAMETER;
-        }
-
-        if (!AddrFile) {
-          TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
-          return STATUS_INVALID_PARAMETER;
-        }
-
-        if (MmGetMdlByteCount(Irp->MdlAddress) <
-            (sizeof(TDI_ADDRESS_INFO) + sizeof(TDI_ADDRESS_IP))) {
-          TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
-          return STATUS_BUFFER_OVERFLOW;
-        }
+  Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
+  if (!Connection) {
+    TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
+    return STATUS_INVALID_CONNECTION;
+  }
 
-        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->Address.Address.IPv4Address;        
-        RtlZeroMemory(
-          &Address->Address[0].Address[0].sin_zero,
-          sizeof(Address->Address[0].Address[0].sin_zero));
+  Status = TCPDisconnect(
+      TranContext->Handle.ConnectionContext,
+      DisReq->RequestFlags,
+      DisReq->RequestConnectionInformation,
+      DisReq->ReturnConnectionInformation,
+      DispDataRequestComplete,
+      Irp );
 
-        return STATUS_SUCCESS;
-      }
-  }
+  TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
 
-  return STATUS_NOT_IMPLEMENTED;
+  return Status;
 }
 
 
@@ -493,7 +575,7 @@ NTSTATUS DispTdiListen(
   PTDI_REQUEST_KERNEL Parameters;
   PTRANSPORT_CONTEXT TranContext;
   PIO_STACK_LOCATION IrpSp;
-  NTSTATUS Status;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
@@ -517,9 +599,56 @@ NTSTATUS DispTdiListen(
 
   Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
 
-  Status = TCPListen( Connection, 1024 /* BACKLOG */,
-                     DispDataRequestComplete,
-                     Irp );
+  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;
 }
@@ -568,7 +697,9 @@ NTSTATUS DispTdiQueryInformation(
             break;
 
           case TDI_CONNECTION_FILE:
-            AddrFile = ((PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext)->AddressFile;
+            AddrFile =
+              ((PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext)->
+              AddressFile;
             break;
 
           default:
@@ -582,7 +713,8 @@ NTSTATUS DispTdiQueryInformation(
         }
 
         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;
         }
@@ -592,13 +724,53 @@ NTSTATUS DispTdiQueryInformation(
         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->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;
@@ -641,8 +813,8 @@ NTSTATUS DispTdiReceive(
 
   /* Initialize a receive request */
   Status = DispPrepareIrpForCancel
-      (TranContext->Handle.ConnectionContext, 
-       Irp, 
+      (TranContext->Handle.ConnectionContext,
+       Irp,
        (PDRIVER_CANCEL)DispCancelRequest);
 
   TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
@@ -719,11 +891,11 @@ NTSTATUS DispTdiReceiveDatagram(
 
       Status = UDPReceiveDatagram(
          Request.Handle.AddressHandle,
-         DgramInfo->ReceiveDatagramInformation->RemoteAddress,
+         DgramInfo->ReceiveDatagramInformation,
          DataBuffer,
          DgramInfo->ReceiveLength,
          DgramInfo->ReceiveFlags,
-         DgramInfo->ReturnDatagramInformation->RemoteAddress,
+         DgramInfo->ReturnDatagramInformation,
          &BytesReceived,
          (PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
          Irp);
@@ -785,7 +957,7 @@ NTSTATUS DispTdiSend(
        UINT Len;
 
        NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
-       
+
        TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
        Status = TCPSendData(
            TranContext->Handle.ConnectionContext,
@@ -796,7 +968,7 @@ NTSTATUS DispTdiSend(
        if (Status != STATUS_PENDING)
        {
            DispDataRequestComplete(Irp, Status, BytesReceived);
-       } else 
+       } else
            IoMarkIrpPending( Irp );
     }
 
@@ -841,25 +1013,28 @@ NTSTATUS DispTdiSendDatagram(
     if (NT_SUCCESS(Status)) {
        PCHAR DataBuffer;
        UINT BufferSize;
-       
+
        TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
 
        NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
                         &DataBuffer,
                         &BufferSize );
-       
-        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress 
+
+        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
            must be of type PTDI_ADDRESS_IP */
        TI_DbgPrint(MID_TRACE,
-                   ("About to call send routine %x\n", 
+                   ("About to call send routine %x\n",
                     (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
-       
-        Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
-            Request.Handle.AddressHandle, 
-           DgramInfo->SendDatagramInformation,
-           DataBuffer,
-           BufferSize,
-           &Irp->IoStatus.Information);
+
+        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;
 
         if (Status != STATUS_PENDING) {
             DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
@@ -912,7 +1087,7 @@ NTSTATUS DispTdiSetEventHandler(PIRP Irp)
 
   Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
   Status     = STATUS_SUCCESS;
-  
+
   TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
 
   /* Set the event handler. if an event handler is associated with
@@ -1076,7 +1251,7 @@ VOID DispTdiQueryInformationExComplete(
         Count = CopyBufferToBufferChain(
             QueryContext->InputMdl,
             FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
-            (PUCHAR)&QueryContext->QueryInfo.Context,
+            (PCHAR)&QueryContext->QueryInfo.Context,
             CONTEXT_SIZE);
     }
 
@@ -1219,7 +1394,7 @@ NTSTATUS DispTdiQueryInformationEx(
             ExFreePool(QueryContext);
         } else
             Status = STATUS_INSUFFICIENT_RESOURCES;
-    } else if( InputBufferLength == 
+    } 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",
@@ -1239,7 +1414,7 @@ NTSTATUS DispTdiQueryInformationEx(
 
            MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
                                IoModifyAccess);
-           
+
            InputMdlLocked = TRUE;
            Status = STATUS_SUCCESS;
        } _SEH_HANDLE {
@@ -1263,9 +1438,9 @@ NTSTATUS DispTdiQueryInformationEx(
        Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
        Request.RequestContext      = QueryContext;
        Status = InfoTdiQueryInformationEx(&Request,
-                                          &QueryContext->QueryInfo.ID, 
+                                          &QueryContext->QueryInfo.ID,
                                           NULL,
-                                          &Size, 
+                                          &Size,
                                           &QueryContext->QueryInfo.Context);
        DispTdiQueryInformationExComplete(QueryContext, Status, Size);
        TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
@@ -1340,4 +1515,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 */