- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / tcpip / fileobjs.c
index 3304399..546df6f 100644 (file)
@@ -7,15 +7,9 @@
  * REVISIONS:
  *   CSH 01/08-2000 Created
  */
-#include <tcpip.h>
-#include <datagram.h>
-#include <address.h>
-#include <pool.h>
-#include <rawip.h>
-#include <tcp.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;
@@ -25,6 +19,101 @@ KSPIN_LOCK AddressFileListLock;
 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)
@@ -38,8 +127,19 @@ VOID AddrFileFree(
 }
 
 
-VOID DeleteAddress(
-  PADDRESS_FILE AddrFile)
+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:
@@ -55,11 +155,11 @@ VOID DeleteAddress(
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
   /* Remove address file from the global list */
-  KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+  TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
   RemoveEntryList(&AddrFile->ListEntry);
-  KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+  TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
 
-  KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
 
   /* FIXME: Kill TCP connections on this address file object */
 
@@ -73,10 +173,9 @@ VOID DeleteAddress(
     NextEntry = CurrentEntry->Flink;
     ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
     /* Abort the request and free its resources */
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+    TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
     (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
-    ExFreePool(ReceiveRequest);
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+    TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
     CurrentEntry = NextEntry;
   }
 
@@ -86,32 +185,18 @@ VOID DeleteAddress(
   CurrentEntry = AddrFile->TransmitQueue.Flink;
   while (CurrentEntry != &AddrFile->TransmitQueue) {
     NextEntry = CurrentEntry->Flink;
-    SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+    SendRequest = CONTAINING_RECORD(CurrentEntry,
+                                   DATAGRAM_SEND_REQUEST, ListEntry);
     /* Abort the request and free its resources */
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+    TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
     (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
     ExFreePool(SendRequest);
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+    TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
     CurrentEntry = NextEntry;
   }
 
-  KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-  /* Dereference address entry */
-  DereferenceObject(AddrFile->ADE);
+  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
 
-  /* Dereference address cache */
-  if (AddrFile->AddrCache)
-    DereferenceObject(AddrFile->AddrCache);
-
-#ifdef DBG
-  /* Remove reference provided at creation time */
-  AddrFile->RefCount--;
-
-  if (AddrFile->RefCount != 0)
-    TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));
-#endif
-  
   (*AddrFile->Free)(AddrFile);
 
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
@@ -127,119 +212,19 @@ VOID DeleteConnectionEndpoint(
   PCONNECTION_ENDPOINT Connection)
 {
   KIRQL OldIrql;
-  PLIST_ENTRY CurrentEntry;
-  PLIST_ENTRY NextEntry;
 
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
   /* Remove connection endpoint from the global list */
-  KeAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+  TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
   RemoveEntryList(&Connection->ListEntry);
-  KeReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
-
-  KeAcquireSpinLock(&Connection->Lock, &OldIrql);
-
-  /* Dereference and remove the address file if it exists */
-  if (Connection->AddressFile) {
-    RemoveEntryList(&Connection->AddrFileEntry);
-    DereferenceObject(Connection->AddressFile);
-  }
-
-  KeReleaseSpinLock(&Connection->Lock, OldIrql);
-
-#ifdef DBG
-  /* Remove reference provided at creation time */
-  Connection->RefCount--;
-
-  if (Connection->RefCount != 0)
-    TI_DbgPrint(DEBUG_REFCOUNT, ("Connection->RefCount is (%d) (should be 0).\n",
-      Connection->RefCount));
-#endif
+  TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
 
   ExFreePool(Connection);
 
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
-
-VOID RequestWorker(
-  PVOID Context)
-/*
- * FUNCTION: Worker routine for processing address file object requests
- * ARGUMENTS:
- *     Context = Pointer to context information (ADDRESS_FILE)
- */
-{
-  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;
-  }
-
-  /* Check if there is a pending send request */
-  if (AF_IS_PENDING(AddrFile, AFF_SEND)) {
-    if (!IsListEmpty(&AddrFile->TransmitQueue)) {
-      PDATAGRAM_SEND_REQUEST SendRequest;
-
-      CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
-      SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
-
-      AF_CLR_BUSY(AddrFile);
-
-      ReferenceObject(AddrFile);
-
-      KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-      /* 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);
-
-      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"));
-  }
-
-  AF_CLR_BUSY(AddrFile);
-
-  KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
-}
-
-
 /*
  * FUNCTION: Open an address file object
  * ARGUMENTS:
@@ -252,14 +237,15 @@ VOID RequestWorker(
  */
 NTSTATUS FileOpenAddress(
   PTDI_REQUEST Request,
-  PTA_ADDRESS_IP Address,
+  PTA_IP_ADDRESS Address,
   USHORT Protocol,
   PVOID Options)
 {
-  PADDRESS_FILE AddrFile;
   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 = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
   if (!AddrFile) {
@@ -278,34 +264,39 @@ NTSTATUS FileOpenAddress(
   /* 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)
-    AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
+      Matched = IPGetDefaultAddress(&AddrFile->Address);
   else
-    AddrFile->ADE = AddrLocateADEv4(IPv4Address);
+      Matched = AddrLocateADEv4(IPv4Address, &AddrFile->Address);
 
-  if (!AddrFile->ADE) {
+  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.\n",
-    A2S(AddrFile->ADE->Address)));
+  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:
-    /* FIXME: If specified port is 0, a port is chosen dynamically */
-    AddrFile->Port = Address->Address[0].Address[0].sin_port;
-    AddrFile->Send = TCPSendDatagram;
-    break;
+      AddrFile->Port =
+          TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+      AddrFile->Send = NULL; /* TCPSendData */
+      break;
 
   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;
+      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 */
@@ -317,25 +308,19 @@ NTSTATUS FileOpenAddress(
   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 associated connection list */
-  InitializeListHead(&AddrFile->Connections);
-
-  /* Initialize work queue item. We use this for pending requests */
-  ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);
-
   /* Initialize spin lock that protects the address file object */
   KeInitializeSpinLock(&AddrFile->Lock);
 
-  /* Reference the object */
-  AddrFile->RefCount = 1;
-
   /* Set valid flag so the address can be used */
   AF_SET_VALID(AddrFile);
 
@@ -372,42 +357,29 @@ NTSTATUS FileCloseAddress(
 
   AddrFile = Request->Handle.AddressHandle;
 
-  KeAcquireSpinLock(&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);
-
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
-    DeleteAddress(AddrFile);
-  } else {
-    if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {
-      AddrFile->Complete = Request->RequestNotifyObject;
-      AddrFile->Context  = Request->RequestContext;
-
-      /* Shedule address file for deletion */
-      AF_SET_PENDING(AddrFile, AFF_DELETE);
-      AF_CLR_VALID(AddrFile);
+  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
 
-      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);
+  /* Set address file object exclusive to us */
+  AF_SET_BUSY(AddrFile);
+  AF_CLR_VALID(AddrFile);
 
-      TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
 
-      return STATUS_PENDING;
-    } else
-      Status = STATUS_ADDRESS_CLOSED;
+  /* Protocol specific handling */
+  switch (AddrFile->Protocol) {
+  case IPPROTO_TCP:
+    TCPFreePort( AddrFile->Port );
+    if( AddrFile->Listener )
+       TCPClose( AddrFile->Listener );
+    break;
 
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  case IPPROTO_UDP:
+    UDPFreePort( AddrFile->Port );
+    break;
   }
 
+  DeleteAddress(AddrFile);
+
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
   return Status;
@@ -426,29 +398,16 @@ NTSTATUS FileOpenConnection(
   PTDI_REQUEST Request,
   PVOID ClientContext)
 {
+  NTSTATUS Status;
   PCONNECTION_ENDPOINT Connection;
 
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
-  Connection = ExAllocatePool(NonPagedPool, sizeof(CONNECTION_ENDPOINT));
-  if (!Connection)
-    return STATUS_INSUFFICIENT_RESOURCES;
-
-  TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
+  Connection = TCPAllocateConnectionEndpoint( ClientContext );
 
-  RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
+  if( !Connection ) return STATUS_NO_MEMORY;
 
-  /* Initialize spin lock that protects the connection endpoint file object */
-  KeInitializeSpinLock(&Connection->Lock);
-
-  /* Reference the object */
-  Connection->RefCount = 1;
-
-  /* Put connection in the closed state */
-  Connection->State = ctClosed;
-
-  /* Save client context pointer */
-  Connection->ClientContext = ClientContext;
+  Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
 
   /* Return connection endpoint file object */
   Request->Handle.ConnectionContext = Connection;
@@ -465,6 +424,36 @@ NTSTATUS FileOpenConnection(
 }
 
 
+/*
+ * 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:
@@ -475,7 +464,6 @@ NTSTATUS FileOpenConnection(
 NTSTATUS FileCloseConnection(
   PTDI_REQUEST Request)
 {
-  KIRQL OldIrql;
   PCONNECTION_ENDPOINT Connection;
   NTSTATUS Status = STATUS_SUCCESS;
 
@@ -483,43 +471,11 @@ NTSTATUS FileCloseConnection(
 
   Connection = Request->Handle.ConnectionContext;
 
-  KeAcquireSpinLock(&Connection->Lock, &OldIrql);
-#if 0
-  if ((!AF_IS_BUSY(Connection)) && (Connection->RefCount == 1)) {
-    /* Set connection endpoint file object exclusive to us */
-    AF_SET_BUSY(Connection);
-    AF_CLR_VALID(Connection);
-
-    KeReleaseSpinLock(&Connection->Lock, OldIrql);
-#endif
-    DeleteConnectionEndpoint(Connection);
-#if 0
-  } else {
-    if (!AF_IS_PENDING(Connection, AFF_DELETE)) {
-      Connection->Complete = Request->RequestNotifyObject;
-      Connection->Context  = Request->RequestContext;
-
-      /* Shedule connection endpoint for deletion */
-      AF_SET_PENDING(Connection, AFF_DELETE);
-      AF_CLR_VALID(Connection);
-
-      if (!AF_IS_BUSY(Connection)) {
-        /* Worker function is not running, so shedule it to run */
-        AF_SET_BUSY(Connection);
-        KeReleaseSpinLock(&Connection->Lock, OldIrql);
-        ExQueueWorkItem(&Connection->WorkItem, CriticalWorkQueue);
-      } else
-        KeReleaseSpinLock(&Connection->Lock, OldIrql);
-
-      TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
-
-      return STATUS_PENDING;
-    } else
-      Status = STATUS_ADDRESS_CLOSED;
+  TcpipRecursiveMutexEnter( &TCPLock, TRUE );
+  TCPClose(Connection);
+  DeleteConnectionEndpoint(Connection);
+  TcpipRecursiveMutexLeave( &TCPLock );
 
-    KeReleaseSpinLock(&Connection->Lock, OldIrql);
-  }
-#endif
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
   return Status;
@@ -534,11 +490,37 @@ NTSTATUS FileCloseConnection(
  *     Status of operation
  */
 NTSTATUS FileOpenControlChannel(
-  PTDI_REQUEST Request)
+    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
@@ -550,7 +532,13 @@ NTSTATUS FileOpenControlChannel(
 NTSTATUS FileCloseControlChannel(
   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 */