- Forgot to commit these for MSVC build...
[reactos.git] / reactos / drivers / net / tcpip / tcpip / fileobjs.c
index 26a0eda..546df6f 100644 (file)
@@ -43,6 +43,20 @@ PADDRESS_FILE AddrSearchFirst(
     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:
@@ -64,12 +78,12 @@ PADDRESS_FILE AddrSearchNext(
 
     CurrentEntry = SearchContext->Next;
 
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+    TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
 
     while (CurrentEntry != &AddressFileListHead) {
         Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
 
-        IPAddress = Current->ADE->Address;
+        IPAddress = &Current->Address;
 
         TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
             WN2H(Current->Port),
@@ -80,10 +94,11 @@ PADDRESS_FILE AddrSearchNext(
             A2S(SearchContext->Address)));
 
         /* See if this address matches the search criteria */
-        if (((Current->Port    == SearchContext->Port) &&
+        if ((Current->Port    == SearchContext->Port) &&
             (Current->Protocol == SearchContext->Protocol) &&
-            (AddrIsEqual(IPAddress, SearchContext->Address))) ||
-            (AddrIsUnspecified(IPAddress))) {
+            (AddrIsEqual(IPAddress, SearchContext->Address) ||
+             AddrIsBroadcast(IPAddress, SearchContext->Address) ||
+             AddrIsUnspecified(IPAddress))) {
             /* We've found a match */
             Found = TRUE;
             break;
@@ -91,7 +106,7 @@ PADDRESS_FILE AddrSearchNext(
         CurrentEntry = CurrentEntry->Flink;
     }
 
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+    TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
 
     if (Found) {
         SearchContext->Next = CurrentEntry->Flink;
@@ -124,8 +139,7 @@ VOID ControlChannelFree(
 }
 
 
-VOID DeleteAddress(
-  PADDRESS_FILE AddrFile)
+VOID DeleteAddress(PADDRESS_FILE AddrFile)
 /*
  * FUNCTION: Deletes an address file object
  * ARGUMENTS:
@@ -141,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 */
 
@@ -159,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;
   }
 
@@ -172,33 +185,18 @@ VOID DeleteAddress(
   CurrentEntry = AddrFile->TransmitQueue.Flink;
   while (CurrentEntry != &AddrFile->TransmitQueue) {
     NextEntry = CurrentEntry->Flink;
-    SendRequest = CONTAINING_RECORD(CurrentEntry, 
+    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"));
@@ -218,112 +216,15 @@ VOID DeleteConnectionEndpoint(
   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) {
-    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 STDCALL 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:
@@ -340,10 +241,11 @@ NTSTATUS FileOpenAddress(
   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) {
@@ -362,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 = NULL; /* TCPSendData */
-    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 */
@@ -406,20 +313,14 @@ NTSTATUS FileOpenAddress(
 
   /* Set protocol */
   AddrFile->Protocol = Protocol;
-  
+
   /* Initialize receive and transmit queues */
   InitializeListHead(&AddrFile->ReceiveQueue);
   InitializeListHead(&AddrFile->TransmitQueue);
 
-  /* 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);
 
@@ -456,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;
@@ -515,17 +403,11 @@ NTSTATUS FileOpenConnection(
 
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
-  
-  Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
-  DbgPrint("STATUS from OSKITTCP was %08x\n", Status);
-
-  /* Initialize received segments queue */
-  InitializeListHead(&Connection->ReceivedSegments);
+  Connection = TCPAllocateConnectionEndpoint( ClientContext );
 
-TI_DbgPrint(MIN_TRACE, ("X1 cur 0x%x\n", &Connection->ReceivedSegments));
-TI_DbgPrint(MIN_TRACE, ("X1 Flink 0x%x\n", Connection->ReceivedSegments.Flink));
-TI_DbgPrint(MIN_TRACE, ("X1 Blink 0x%x\n", Connection->ReceivedSegments.Blink));
+  if( !Connection ) return STATUS_NO_MEMORY;
 
+  Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
 
   /* Return connection endpoint file object */
   Request->Handle.ConnectionContext = Connection;
@@ -542,6 +424,36 @@ TI_DbgPrint(MIN_TRACE, ("X1 Blink 0x%x\n", Connection->ReceivedSegments.Blink));
 }
 
 
+/*
+ * 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:
@@ -559,8 +471,10 @@ NTSTATUS FileCloseConnection(
 
   Connection = Request->Handle.ConnectionContext;
 
+  TcpipRecursiveMutexEnter( &TCPLock, TRUE );
   TCPClose(Connection);
   DeleteConnectionEndpoint(Connection);
+  TcpipRecursiveMutexLeave( &TCPLock );
 
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
@@ -600,9 +514,6 @@ NTSTATUS FileOpenControlChannel(
   /* Initialize spin lock that protects the address file object */
   KeInitializeSpinLock(&ControlChannel->Lock);
 
-  /* Reference the object */
-  ControlChannel->RefCount = 1;
-
   /* Return address file object */
   Request->Handle.ControlChannel = ControlChannel;
 
@@ -611,7 +522,6 @@ NTSTATUS FileOpenControlChannel(
   return STATUS_SUCCESS;
 }
 
-
 /*
  * FUNCTION: Closes a control channel file object
  * ARGUMENTS: