[TCPIP, IP]
[reactos.git] / drivers / network / tcpip / tcpip / fileobjs.c
index 054dd98..62ca63c 100644 (file)
@@ -43,20 +43,52 @@ PADDRESS_FILE AddrSearchFirst(
     return AddrSearchNext(SearchContext);
 }
 
-BOOLEAN AddrIsBroadcast(
-    PIP_ADDRESS PossibleMatch,
-    PIP_ADDRESS TargetAddress ) {
+BOOLEAN AddrIsBroadcastMatch(
+    PIP_ADDRESS UnicastAddress,
+    PIP_ADDRESS BroadcastAddress ) {
     IF_LIST_ITER(IF);
 
     ForEachInterface(IF) {
-        if( AddrIsEqual( &IF->Unicast, PossibleMatch ) &&
-            AddrIsEqual( &IF->Broadcast, TargetAddress ) )
+        if ((AddrIsUnspecified(UnicastAddress) ||
+             AddrIsEqual(&IF->Unicast, UnicastAddress)) &&
+            (AddrIsEqual(&IF->Broadcast, BroadcastAddress)))
             return TRUE;
     } EndFor(IF);
 
     return FALSE;
 }
 
+BOOLEAN AddrReceiveMatch(
+   PIP_ADDRESS LocalAddress,
+   PIP_ADDRESS RemoteAddress)
+{
+   if (AddrIsEqual(LocalAddress, RemoteAddress))
+   {
+       /* Unicast address match */
+       return TRUE;
+   }
+
+   if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress))
+   {
+       /* Broadcast address match */
+       return TRUE;
+   }
+
+   if (AddrIsUnspecified(LocalAddress))
+   {
+       /* Local address unspecified */
+       return TRUE;
+   }
+
+   if (AddrIsUnspecified(RemoteAddress))
+   {
+       /* Remote address unspecified */
+       return TRUE;
+   }
+
+   return FALSE;
+}
+
 /*
  * FUNCTION: Searches through address file entries to find next match
  * ARGUMENTS:
@@ -96,9 +128,7 @@ PADDRESS_FILE AddrSearchNext(
         /* 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))) {
+            (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
             /* We've found a match */
             Found = TRUE;
             break;
@@ -123,34 +153,11 @@ VOID AddrFileFree(
  *     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
- */
-{
+  PADDRESS_FILE AddrFile = Object;
   KIRQL OldIrql;
-  PLIST_ENTRY CurrentEntry;
-  PLIST_ENTRY NextEntry;
-  PDATAGRAM_SEND_REQUEST SendRequest;
   PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
+  PDATAGRAM_SEND_REQUEST SendRequest;
+  PLIST_ENTRY CurrentEntry;
 
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
@@ -159,8 +166,6 @@ VOID DeleteAddress(PADDRESS_FILE AddrFile)
   RemoveEntryList(&AddrFile->ListEntry);
   TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
 
-  TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
-
   /* FIXME: Kill TCP connections on this address file object */
 
   /* Return pending requests with error */
@@ -168,63 +173,50 @@ VOID DeleteAddress(PADDRESS_FILE AddrFile)
   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;
+  while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
     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;
+    (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
+    /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
   }
 
   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;
+  while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
+    SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+    (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
+    ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
   }
 
-  TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+  /* Protocol specific handling */
+  switch (AddrFile->Protocol) {
+  case IPPROTO_TCP:
+    TCPFreePort( AddrFile->Port );
+    break;
+
+  case IPPROTO_UDP:
+    UDPFreePort( AddrFile->Port );
+    break;
+  }
 
-  (*AddrFile->Free)(AddrFile);
+  RemoveEntityByContext(AddrFile);
 
-  TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+  ExFreePoolWithTag(Object, ADDR_FILE_TAG);
 }
 
 
+VOID ControlChannelFree(
+    PVOID Object)
 /*
- * FUNCTION: Deletes a connection endpoint file object
+ * FUNCTION: Frees an address file object
  * ARGUMENTS:
- *     Connection = Pointer to connection endpoint to delete
+ *     Object = Pointer to address file object to free
  */
-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"));
+    ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
 }
 
+
 /*
  * FUNCTION: Open an address file object
  * ARGUMENTS:
@@ -241,13 +233,12 @@ NTSTATUS FileOpenAddress(
   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));
+  AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
+                                   ADDR_FILE_TAG);
   if (!AddrFile) {
     TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
     return STATUS_INSUFFICIENT_RESOURCES;
@@ -257,24 +248,23 @@ NTSTATUS FileOpenAddress(
 
   RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
 
+  AddrFile->RefCount = 1;
   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 */
+  /* Set our default TTL */
+  AddrFile->TTL = 128;
 
+  /* Make sure address is a local unicast address or 0 */
   /* 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;
+  AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
+  AddrFile->Address.Type = IP_ADDRESS_V4;
+
+  if (!AddrIsUnspecified(&AddrFile->Address) &&
+      !AddrLocateInterface(&AddrFile->Address)) {
+         ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+         TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
+         return STATUS_INVALID_PARAMETER;
   }
 
   TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
@@ -285,6 +275,17 @@ NTSTATUS FileOpenAddress(
   case IPPROTO_TCP:
       AddrFile->Port =
           TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+
+      if ((Address->Address[0].Address[0].sin_port &&
+           AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
+           AddrFile->Port == 0xffff)
+      {
+          ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+          return STATUS_INVALID_PARAMETER;
+      }
+
+      AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
+
       AddrFile->Send = NULL; /* TCPSendData */
       break;
 
@@ -292,16 +293,39 @@ NTSTATUS FileOpenAddress(
       TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
       AddrFile->Port =
          UDPAllocatePort(Address->Address[0].Address[0].sin_port);
+
+      if ((Address->Address[0].Address[0].sin_port &&
+           AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
+           AddrFile->Port == 0xffff)
+      {
+          ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
+          return STATUS_INVALID_PARAMETER;
+      }
+
       TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
                              AddrFile->Port,
                              Address->Address[0].Address[0].sin_port));
+
+      AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
+
       AddrFile->Send = UDPSendDatagram;
       break;
 
+  case IPPROTO_ICMP:
+    AddrFile->Port = 0;
+    AddrFile->Send = ICMPSendDatagram;
+
+    /* FIXME: Verify this */
+    AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
+    break;
+
   default:
     /* Use raw IP for all other protocols */
     AddrFile->Port = 0;
     AddrFile->Send = RawIPSendDatagram;
+
+    /* FIXME: Verify this */
+    AddEntity(CL_TL_ENTITY, AddrFile, 0);
     break;
   }
 
@@ -321,9 +345,6 @@ NTSTATUS FileOpenAddress(
   /* 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;
 
@@ -349,40 +370,24 @@ NTSTATUS FileOpenAddress(
 NTSTATUS FileCloseAddress(
   PTDI_REQUEST Request)
 {
+  PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
   KIRQL OldIrql;
-  PADDRESS_FILE AddrFile;
-  NTSTATUS Status = STATUS_SUCCESS;
 
-  TI_DbgPrint(MID_TRACE, ("Called.\n"));
+  if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER;
 
-  AddrFile = Request->Handle.AddressHandle;
+  LockObject(AddrFile, &OldIrql);
+  /* We have to close this connection because we started it */
+  if( AddrFile->Listener )
+      TCPClose( AddrFile->Listener );
+  if( AddrFile->Connection )
+      DereferenceObject( AddrFile->Connection );
+  UnlockObject(AddrFile, OldIrql);
 
-  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);
+  DereferenceObject(AddrFile);
 
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
-  return Status;
+  return STATUS_SUCCESS;
 }
 
 
@@ -410,55 +415,18 @@ NTSTATUS FileOpenConnection(
   Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
 
   if( !NT_SUCCESS(Status) ) {
-      TCPFreeConnectionEndpoint( Connection );
+      DereferenceObject( Connection );
       return Status;
   }
 
   /* 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:
@@ -470,23 +438,22 @@ 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 );
+  if (!Connection) return STATUS_INVALID_PARAMETER;
+
+  TCPClose( Connection );
+
+  Request->Handle.ConnectionContext = NULL;
 
   TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 
-  return Status;
+  return STATUS_SUCCESS;
 }
 
-
 /*
  * FUNCTION: Opens a control channel file object
  * ARGUMENTS:
@@ -500,7 +467,8 @@ NTSTATUS FileOpenControlChannel(
   PCONTROL_CHANNEL ControlChannel;
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
-  ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
+  ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
+                                         CONTROL_CHANNEL_TAG);
 
   if (!ControlChannel) {
     TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
@@ -519,6 +487,9 @@ NTSTATUS FileOpenControlChannel(
   /* Initialize spin lock that protects the address file object */
   KeInitializeSpinLock(&ControlChannel->Lock);
 
+  ControlChannel->RefCount = 1;
+  ControlChannel->Free = ControlChannelFree;
+
   /* Return address file object */
   Request->Handle.ControlChannel = ControlChannel;
 
@@ -537,13 +508,13 @@ NTSTATUS FileOpenControlChannel(
 NTSTATUS FileCloseControlChannel(
   PTDI_REQUEST Request)
 {
-  PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
-  NTSTATUS Status = STATUS_SUCCESS;
+  if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER;
+
+  DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel);
 
-  ExFreePool(ControlChannel);
   Request->Handle.ControlChannel = NULL;
 
-  return Status;
+  return STATUS_SUCCESS;
 }
 
 /* EOF */