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