- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / tcpip / fileobjs.c
index 0b24fa5..546df6f 100644 (file)
  * REVISIONS:
  *   CSH 01/08-2000 Created
  */
-#include <tcpip.h>
-#include <datagram.h>
-#include <address.h>
-#include <pool.h>
-#include <rawip.h>
-#include <udp.h>
-#include <ip.h>
-#include <fileobjs.h>
 
+#include "precomp.h"
+
+
+/* List of all address file objects managed by this driver */
 LIST_ENTRY AddressFileListHead;
 KSPIN_LOCK AddressFileListLock;
 
+/* List of all connection endpoint file objects managed by this driver */
+LIST_ENTRY ConnectionEndpointListHead;
+KSPIN_LOCK ConnectionEndpointListLock;
 
 /*
- * FUNCTION: Deletes an address file object
+ * FUNCTION: Searches through address file entries to find the first match
  * ARGUMENTS:
- *     AddrFile = Pointer to address file object to delete
+ *     Address       = IP address
+ *     Port          = Port number
+ *     Protocol      = Protocol number
+ *     SearchContext = Pointer to search context
+ * RETURNS:
+ *     Pointer to address file, NULL if none was found
  */
-VOID DeleteAddress(
-    PADDRESS_FILE AddrFile)
+PADDRESS_FILE AddrSearchFirst(
+    PIP_ADDRESS Address,
+    USHORT Port,
+    USHORT Protocol,
+    PAF_SEARCH SearchContext)
 {
-    KIRQL OldIrql;
-    PLIST_ENTRY CurrentEntry;
-    PLIST_ENTRY NextEntry;
-    PDATAGRAM_SEND_REQUEST SendRequest;
-    PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
-
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));
-
-    /* Remove address file from the global list */
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
-    RemoveEntryList(&AddrFile->ListEntry);
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
-
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-
-    /* FIXME: Kill TCP connections on this address file object */
-
-    /* Return pending requests with error */
-
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
-
-    /* Go through pending receive request list and cancel them all */
-    CurrentEntry = AddrFile->ReceiveQueue.Flink;
-    while (CurrentEntry != &AddrFile->ReceiveQueue) {
-        NextEntry = CurrentEntry->Flink;
-        ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
-        /* Abort the request and free its resources */
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-        (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
-        PoolFreeBuffer(ReceiveRequest);
-        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-        CurrentEntry = NextEntry;
-    }
+    SearchContext->Address  = Address;
+    SearchContext->Port     = Port;
+    SearchContext->Next     = AddressFileListHead.Flink;
+    SearchContext->Protocol = Protocol;
 
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
-
-    /* Go through pending send request list and cancel them all */
-    CurrentEntry = AddrFile->TransmitQueue.Flink;
-    while (CurrentEntry != &AddrFile->TransmitQueue) {
-        NextEntry = CurrentEntry->Flink;
-        SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
-        /* Abort the request and free its resources */
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-        (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
-        PoolFreeBuffer(SendRequest);
-        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-        CurrentEntry = NextEntry;
-    }
-
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-    /* Dereference address entry */
-    DereferenceObject(AddrFile->ADE);
-
-    /* Dereference address cache */
-    if (AddrFile->AddrCache)
-        DereferenceObject(AddrFile->AddrCache);
+    return AddrSearchNext(SearchContext);
+}
 
-#ifdef DBG
-    /* Remove reference provided at creation time */
-    AddrFile->RefCount--;
+BOOLEAN AddrIsBroadcast(
+    PIP_ADDRESS PossibleMatch,
+    PIP_ADDRESS TargetAddress ) {
+    IF_LIST_ITER(IF);
 
-    if (AddrFile->RefCount != 0)
-        TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));
-#endif
-    
-    PoolFreeBuffer(AddrFile);
+    ForEachInterface(IF) {
+        if( AddrIsEqual( &IF->Unicast, PossibleMatch ) &&
+            AddrIsEqual( &IF->Broadcast, TargetAddress ) )
+            return TRUE;
+    } EndFor(IF);
 
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+    return FALSE;
 }
 
-
-VOID RequestWorker(
-    PVOID Context)
 /*
- * FUNCTION: Worker routine for processing address file object requests
+ * FUNCTION: Searches through address file entries to find next match
  * ARGUMENTS:
- *     Context = Pointer to context information (ADDRESS_FILE)
+ *     SearchContext = Pointer to search context
+ * RETURNS:
+ *     Pointer to address file, NULL if none was found
  */
+PADDRESS_FILE AddrSearchNext(
+    PAF_SEARCH SearchContext)
 {
-    KIRQL OldIrql;
     PLIST_ENTRY CurrentEntry;
-    PADDRESS_FILE AddrFile = Context;
-
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));
-
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-
-    /* Check it the address file should be deleted */
-    if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {
-        DATAGRAM_COMPLETION_ROUTINE RtnComplete;
-        PVOID RtnContext;
-
-        RtnComplete = AddrFile->Complete;
-        RtnContext  = AddrFile->Context;
-
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-        DeleteAddress(AddrFile);
-
-        (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);
-
-        TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));
-
-        return;
+    PIP_ADDRESS IPAddress;
+    KIRQL OldIrql;
+    PADDRESS_FILE Current = NULL;
+    BOOLEAN Found = FALSE;
+
+    if (IsListEmpty(SearchContext->Next))
+        return NULL;
+
+    CurrentEntry = SearchContext->Next;
+
+    TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+
+    while (CurrentEntry != &AddressFileListHead) {
+        Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
+
+        IPAddress = &Current->Address;
+
+        TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
+            WN2H(Current->Port),
+            Current->Protocol,
+            A2S(IPAddress),
+            WN2H(SearchContext->Port),
+            SearchContext->Protocol,
+            A2S(SearchContext->Address)));
+
+        /* See if this address matches the search criteria */
+        if ((Current->Port    == SearchContext->Port) &&
+            (Current->Protocol == SearchContext->Protocol) &&
+            (AddrIsEqual(IPAddress, SearchContext->Address) ||
+             AddrIsBroadcast(IPAddress, SearchContext->Address) ||
+             AddrIsUnspecified(IPAddress))) {
+            /* We've found a match */
+            Found = TRUE;
+            break;
+        }
+        CurrentEntry = CurrentEntry->Flink;
     }
 
-    /* Check if there is a pending send request */
-    if (AF_IS_PENDING(AddrFile, AFF_SEND)) {
-        if (!IsListEmpty(&AddrFile->TransmitQueue)) {
-            PDATAGRAM_SEND_REQUEST SendRequest;
+    TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
 
-            CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
-            SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+    if (Found) {
+        SearchContext->Next = CurrentEntry->Flink;
+        return Current;
+    } else
+        return NULL;
+}
 
-            AF_CLR_BUSY(AddrFile);
+VOID AddrFileFree(
+    PVOID Object)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ *     Object = Pointer to address file object to free
+ */
+{
+    ExFreePool(Object);
+}
 
-            ReferenceObject(AddrFile);
 
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+VOID ControlChannelFree(
+    PVOID Object)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ *     Object = Pointer to address file object to free
+ */
+{
+    ExFreePool(Object);
+}
 
-            /* The send routine processes the send requests in
-               the transmit queue on the address file. When the
-               queue is empty the pending send flag is cleared.
-               The routine may return with the pending send flag
-               set. This can happen if there was not enough free
-               resources available to complete all send requests */
-            DGSend(AddrFile, SendRequest);
 
-            KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-            DereferenceObject(AddrFile);
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+VOID DeleteAddress(PADDRESS_FILE AddrFile)
+/*
+ * FUNCTION: Deletes an address file object
+ * ARGUMENTS:
+ *     AddrFile = Pointer to address file object to delete
+ */
+{
+  KIRQL OldIrql;
+  PLIST_ENTRY CurrentEntry;
+  PLIST_ENTRY NextEntry;
+  PDATAGRAM_SEND_REQUEST SendRequest;
+  PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
+
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+  /* Remove address file from the global list */
+  TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+  RemoveEntryList(&AddrFile->ListEntry);
+  TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+  /* FIXME: Kill TCP connections on this address file object */
+
+  /* Return pending requests with error */
+
+  TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
+
+  /* Go through pending receive request list and cancel them all */
+  CurrentEntry = AddrFile->ReceiveQueue.Flink;
+  while (CurrentEntry != &AddrFile->ReceiveQueue) {
+    NextEntry = CurrentEntry->Flink;
+    ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+    /* Abort the request and free its resources */
+    TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+    (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+    TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+    CurrentEntry = NextEntry;
+  }
+
+  TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
+
+  /* Go through pending send request list and cancel them all */
+  CurrentEntry = AddrFile->TransmitQueue.Flink;
+  while (CurrentEntry != &AddrFile->TransmitQueue) {
+    NextEntry = CurrentEntry->Flink;
+    SendRequest = CONTAINING_RECORD(CurrentEntry,
+                                   DATAGRAM_SEND_REQUEST, ListEntry);
+    /* Abort the request and free its resources */
+    TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+    (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+    ExFreePool(SendRequest);
+    TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+    CurrentEntry = NextEntry;
+  }
+
+  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+  (*AddrFile->Free)(AddrFile);
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
 
-            TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));
 
-            return;
-        } else
-            /* There was a pending send, but no send request.
-               Print a debug message and continue */
-            TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));
-    }
+/*
+ * FUNCTION: Deletes a connection endpoint file object
+ * ARGUMENTS:
+ *     Connection = Pointer to connection endpoint to delete
+ */
+VOID DeleteConnectionEndpoint(
+  PCONNECTION_ENDPOINT Connection)
+{
+  KIRQL OldIrql;
 
-    AF_CLR_BUSY(AddrFile);
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  /* Remove connection endpoint from the global list */
+  TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+  RemoveEntryList(&Connection->ListEntry);
+  TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
 
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
-}
+  ExFreePool(Connection);
 
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
 
 /*
  * FUNCTION: Open an address file object
@@ -189,92 +236,106 @@ VOID RequestWorker(
  *     Status of operation
  */
 NTSTATUS FileOpenAddress(
-    PTDI_REQUEST Request,
-    PTA_ADDRESS_IP Address,
-    USHORT Protocol,
-    PVOID Options)
+  PTDI_REQUEST Request,
+  PTA_IP_ADDRESS Address,
+  USHORT Protocol,
+  PVOID Options)
 {
-    PADDRESS_FILE AddrFile;
-    IPv4_RAW_ADDRESS IPv4Address;
+  IPv4_RAW_ADDRESS IPv4Address;
+  BOOLEAN Matched;
+  PADDRESS_FILE AddrFile;
 
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+  TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
 
-    AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE));
-    if (!AddrFile) {
-        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+  AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
+  if (!AddrFile) {
+    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
 
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
+  TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
 
-    RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
+  RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
 
-    /* Make sure address is a local unicast address or 0 */
+  AddrFile->Free = AddrFileFree;
 
-    /* Locate address entry. If specified address is 0, a random address is chosen */
+  /* Make sure address is a local unicast address or 0 */
 
-    IPv4Address = Address->Address[0].Address[0].in_addr;
-    if (IPv4Address == 0)
-        AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
-    else
-        AddrFile->ADE = AddrLocateADEv4(IPv4Address);
+  /* Locate address entry. If specified address is 0, a random address is chosen */
 
-    if (!AddrFile->ADE) {
-        PoolFreeBuffer(AddrFile);
-        TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
-        return STATUS_INVALID_PARAMETER;
-    }
+  /* FIXME: IPv4 only */
+  AddrFile->Family = Address->Address[0].AddressType;
+  IPv4Address = Address->Address[0].Address[0].in_addr;
+  if (IPv4Address == 0)
+      Matched = IPGetDefaultAddress(&AddrFile->Address);
+  else
+      Matched = AddrLocateADEv4(IPv4Address, &AddrFile->Address);
 
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n",
-        DN2H(AddrFile->ADE->Address->Address.IPv4Address)));
-
-    /* Protocol specific handling */
-    switch (Protocol) {
-    case IPPROTO_TCP:
-        /* FIXME: TCP */
-        TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n"));
-        DereferenceObject(AddrFile->ADE);
-        PoolFreeBuffer(AddrFile);
-        return STATUS_INVALID_PARAMETER;
-    case IPPROTO_UDP:
-        /* FIXME: If specified port is 0, a port is chosen dynamically */
-        AddrFile->Port = Address->Address[0].Address[0].sin_port;
-        AddrFile->Send = UDPSendDatagram;
-        break;
-    default:
-        /* Use raw IP for all other protocols */
-        AddrFile->Send = RawIPSendDatagram;
-        break;
-    }
+  if (!Matched) {
+    ExFreePool(AddrFile);
+    TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
+    return STATUS_INVALID_PARAMETER;
+  }
+
+  TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
+    A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
+
+  /* Protocol specific handling */
+  switch (Protocol) {
+  case IPPROTO_TCP:
+      AddrFile->Port =
+          TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+      AddrFile->Send = NULL; /* TCPSendData */
+      break;
+
+  case IPPROTO_UDP:
+      TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
+      AddrFile->Port =
+         UDPAllocatePort(Address->Address[0].Address[0].sin_port);
+      TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
+                             AddrFile->Port,
+                             Address->Address[0].Address[0].sin_port));
+      AddrFile->Send = UDPSendDatagram;
+      break;
 
-    /* Set protocol */
-    AddrFile->Protocol = Protocol;
-    
-    /* Initialize receive and transmit queues */
-    InitializeListHead(&AddrFile->ReceiveQueue);
-    InitializeListHead(&AddrFile->TransmitQueue);
+  default:
+    /* Use raw IP for all other protocols */
+    AddrFile->Port = 0;
+    AddrFile->Send = RawIPSendDatagram;
+    break;
+  }
 
-    /* Initialize work queue item. We use this for pending requests */
-    ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);
+  TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
+    Protocol));
 
-    /* Initialize spin lock that protects the address file object */
-    KeInitializeSpinLock(&AddrFile->Lock);
+  TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
+    WN2H(AddrFile->Port)));
 
-    /* Reference the object */
-    AddrFile->RefCount = 1;
+  /* Set protocol */
+  AddrFile->Protocol = Protocol;
 
-    /* Set valid flag so the address can be used */
-    AF_SET_VALID(AddrFile);
+  /* Initialize receive and transmit queues */
+  InitializeListHead(&AddrFile->ReceiveQueue);
+  InitializeListHead(&AddrFile->TransmitQueue);
 
-    /* Return address file object */
-    Request->Handle.AddressHandle = AddrFile;
+  /* Initialize spin lock that protects the address file object */
+  KeInitializeSpinLock(&AddrFile->Lock);
 
-    /* Add address file to global list */
-    ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock);
+  /* Set valid flag so the address can be used */
+  AF_SET_VALID(AddrFile);
 
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+  /* Return address file object */
+  Request->Handle.AddressHandle = AddrFile;
 
-    return STATUS_SUCCESS;
+  /* Add address file to global list */
+  ExInterlockedInsertTailList(
+    &AddressFileListHead,
+    &AddrFile->ListEntry,
+    &AddressFileListLock);
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+  return STATUS_SUCCESS;
 }
 
 
@@ -286,111 +347,198 @@ NTSTATUS FileOpenAddress(
  *     Status of operation
  */
 NTSTATUS FileCloseAddress(
-    PTDI_REQUEST Request)
+  PTDI_REQUEST Request)
 {
-    KIRQL OldIrql;
-    PADDRESS_FILE AddrFile;
-    NTSTATUS Status = STATUS_SUCCESS;
+  KIRQL OldIrql;
+  PADDRESS_FILE AddrFile;
+  NTSTATUS Status = STATUS_SUCCESS;
 
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
-    AddrFile = Request->Handle.AddressHandle;
+  AddrFile = Request->Handle.AddressHandle;
 
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
 
-    if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) {
-        /* Set address file object exclusive to us */
-        AF_SET_BUSY(AddrFile);
-        AF_CLR_VALID(AddrFile);
+  /* Set address file object exclusive to us */
+  AF_SET_BUSY(AddrFile);
+  AF_CLR_VALID(AddrFile);
 
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
 
-        DeleteAddress(AddrFile);
-    } else {
-        if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {
-            AddrFile->Complete = Request->RequestNotifyObject;
-            AddrFile->Context  = Request->RequestContext;
+  /* Protocol specific handling */
+  switch (AddrFile->Protocol) {
+  case IPPROTO_TCP:
+    TCPFreePort( AddrFile->Port );
+    if( AddrFile->Listener )
+       TCPClose( AddrFile->Listener );
+    break;
 
-            /* Shedule address file for deletion */
-            AF_SET_PENDING(AddrFile, AFF_DELETE);
-            AF_CLR_VALID(AddrFile);
+  case IPPROTO_UDP:
+    UDPFreePort( AddrFile->Port );
+    break;
+  }
 
-            if (!AF_IS_BUSY(AddrFile)) {
-                /* Worker function is not running, so shedule it to run */
-                AF_SET_BUSY(AddrFile);
-                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-                ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);
-            } else
-                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  DeleteAddress(AddrFile);
 
-            TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
-            return STATUS_PENDING;
-        } else
-            Status = STATUS_ADDRESS_CLOSED;
-
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-    }
-
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
-
-    return Status;
+  return Status;
 }
 
 
 /*
  * FUNCTION: Opens a connection file object
  * ARGUMENTS:
- *     Request  = Pointer to TDI request structure for this request
+ *     Request       = Pointer to TDI request structure for this request
+ *     ClientContext = Pointer to client context information
  * RETURNS:
  *     Status of operation
  */
 NTSTATUS FileOpenConnection(
-    PTDI_REQUEST Request)
+  PTDI_REQUEST Request,
+  PVOID ClientContext)
 {
-    return STATUS_NOT_IMPLEMENTED;
+  NTSTATUS Status;
+  PCONNECTION_ENDPOINT Connection;
+
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+  Connection = TCPAllocateConnectionEndpoint( ClientContext );
+
+  if( !Connection ) return STATUS_NO_MEMORY;
+
+  Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
+
+  /* Return connection endpoint file object */
+  Request->Handle.ConnectionContext = Connection;
+
+  /* Add connection endpoint to global list */
+  ExInterlockedInsertTailList(
+    &ConnectionEndpointListHead,
+    &Connection->ListEntry,
+    &ConnectionEndpointListLock);
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+  return STATUS_SUCCESS;
 }
 
 
+/*
+ * FUNCTION: Find a connection by examining the context field.  This
+ * is needed in some situations where a FIN reply is needed after a
+ * socket is formally broken.
+ * ARGUMENTS:
+ *     Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+PCONNECTION_ENDPOINT FileFindConnectionByContext( PVOID Context ) {
+    PLIST_ENTRY Entry;
+    KIRQL OldIrql;
+    PCONNECTION_ENDPOINT Connection = NULL;
+
+    TcpipAcquireSpinLock( &ConnectionEndpointListLock, &OldIrql );
+
+    for( Entry = ConnectionEndpointListHead.Flink;
+        Entry != &ConnectionEndpointListHead;
+        Entry = Entry->Flink ) {
+       Connection =
+           CONTAINING_RECORD( Entry, CONNECTION_ENDPOINT, ListEntry );
+       if( Connection->SocketContext == Context ) break;
+       else Connection = NULL;
+    }
+
+    TcpipReleaseSpinLock( &ConnectionEndpointListLock, OldIrql );
+
+    return Connection;
+}
+
 /*
  * FUNCTION: Closes an connection file object
  * ARGUMENTS:
- *     Request  = Pointer to TDI request structure for this request
+ *     Request = Pointer to TDI request structure for this request
  * RETURNS:
  *     Status of operation
  */
 NTSTATUS FileCloseConnection(
-    PTDI_REQUEST Request)
+  PTDI_REQUEST Request)
 {
-    return STATUS_NOT_IMPLEMENTED;
+  PCONNECTION_ENDPOINT Connection;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+  Connection = Request->Handle.ConnectionContext;
+
+  TcpipRecursiveMutexEnter( &TCPLock, TRUE );
+  TCPClose(Connection);
+  DeleteConnectionEndpoint(Connection);
+  TcpipRecursiveMutexLeave( &TCPLock );
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+  return Status;
 }
 
 
 /*
  * FUNCTION: Opens a control channel file object
  * ARGUMENTS:
- *     Request  = Pointer to TDI request structure for this request
+ *     Request = Pointer to TDI request structure for this request
  * RETURNS:
  *     Status of operation
  */
 NTSTATUS FileOpenControlChannel(
     PTDI_REQUEST Request)
 {
-    return STATUS_NOT_IMPLEMENTED;
-}
+  PCONTROL_CHANNEL ControlChannel;
+  TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
+  ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
+
+  if (!ControlChannel) {
+    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+
+  RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
+
+  /* Make sure address is a local unicast address or 0 */
+
+  /* Locate address entry. If specified address is 0, a random address is chosen */
+
+  /* Initialize receive and transmit queues */
+  InitializeListHead(&ControlChannel->ListEntry);
+
+  /* Initialize spin lock that protects the address file object */
+  KeInitializeSpinLock(&ControlChannel->Lock);
+
+  /* Return address file object */
+  Request->Handle.ControlChannel = ControlChannel;
+
+  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+  return STATUS_SUCCESS;
+}
 
 /*
  * FUNCTION: Closes a control channel file object
  * ARGUMENTS:
- *     Request  = Pointer to TDI request structure for this request
+ *     Request = Pointer to TDI request structure for this request
  * RETURNS:
  *     Status of operation
  */
 NTSTATUS FileCloseControlChannel(
-    PTDI_REQUEST Request)
+  PTDI_REQUEST Request)
 {
-    return STATUS_NOT_IMPLEMENTED;
+  PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  ExFreePool(ControlChannel);
+  Request->Handle.ControlChannel = NULL;
+
+  return Status;
 }
 
 /* EOF */