- Add locking to ICMPSendDatagram
[reactos.git] / lib / drivers / ip / network / icmp.c
index 3eeb98c..fb3387d 100644 (file)
 
 #include "precomp.h"
 
+NTSTATUS ICMPStartup()
+{
+    IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS ICMPShutdown()
+{
+    IPRegisterProtocol(IPPROTO_ICMP, NULL);
+
+    return STATUS_SUCCESS;
+}
 
 VOID SendICMPComplete(
     PVOID Context,
@@ -34,7 +47,7 @@ VOID SendICMPComplete(
 }
 
 
-PIP_PACKET PrepareICMPPacket(
+BOOLEAN PrepareICMPPacket(
     PIP_INTERFACE Interface,
     PIP_PACKET IPPacket,
     PIP_ADDRESS Destination,
@@ -57,28 +70,29 @@ PIP_PACKET PrepareICMPPacket(
 
     TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize));
 
+    IPInitializePacket(IPPacket, IP_ADDRESS_V4);
+
     /* No special flags */
     IPPacket->Flags = 0;
 
-    Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) + DataSize;
+    Size = sizeof(IPv4_HEADER) + DataSize;
 
     /* Allocate NDIS packet */
     NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
 
-    if( !NT_SUCCESS(NdisStatus) ) return NULL;
+    if( !NT_SUCCESS(NdisStatus) ) return FALSE;
 
     IPPacket->NdisPacket = NdisPacket;
 
-    GetDataPtr( IPPacket->NdisPacket, MaxLLHeaderSize,
+    GetDataPtr( IPPacket->NdisPacket, 0,
                (PCHAR *)&IPPacket->Header, &IPPacket->ContigSize );
 
-    IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
-
     TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data));
     TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket));
 
     IPPacket->HeaderSize = sizeof(IPv4_HEADER);
-    IPPacket->TotalSize  = Size - MaxLLHeaderSize;
+    IPPacket->TotalSize  = Size;
+    IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
 
     TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n",
                             &IPPacket->DstAddr, Destination));
@@ -114,9 +128,112 @@ PIP_PACKET PrepareICMPPacket(
 
     TI_DbgPrint(MID_TRACE,("Leaving\n"));
 
-    return IPPacket;
+    return TRUE;
 }
 
+VOID ICMPSendPacketComplete
+( PVOID Context, PNDIS_PACKET Packet, NDIS_STATUS Status ) {
+    FreeNdisPacket( Packet );
+}
+
+NTSTATUS ICMPSendDatagram(
+    PADDRESS_FILE AddrFile,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PCHAR BufferData,
+    ULONG DataSize,
+    PULONG DataUsed )
+/*
+ * FUNCTION: Sends an ICMP datagram to a remote address
+ * ARGUMENTS:
+ *     Request   = Pointer to TDI request
+ *     ConnInfo  = Pointer to connection information
+ *     Buffer    = Pointer to NDIS buffer with data
+ *     DataSize  = Size in bytes of data to be sent
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    IP_PACKET Packet;
+    PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
+    IP_ADDRESS RemoteAddress,  LocalAddress;
+    USHORT RemotePort;
+    NTSTATUS Status;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
+                          AddrFile, ConnInfo, BufferData, DataSize));
+    TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa));
+
+    switch( RemoteAddressTa->Address[0].AddressType ) {
+    case TDI_ADDRESS_TYPE_IP:
+       RemoteAddress.Type = IP_ADDRESS_V4;
+       RemoteAddress.Address.IPv4Address =
+           RemoteAddressTa->Address[0].Address[0].in_addr;
+       RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port;
+       break;
+
+    default:
+       return STATUS_UNSUCCESSFUL;
+    }
+
+    TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
+
+    LockObject(AddrFile, &OldIrql);
+
+    LocalAddress = AddrFile->Address;
+    if (AddrIsUnspecified(&LocalAddress))
+    {
+        /* If the local address is unspecified (0),
+         * then use the unicast address of the
+         * interface we're sending over
+         */
+        if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
+        {
+             UnlockObject(AddrFile, OldIrql);
+            return STATUS_NETWORK_UNREACHABLE;
+        }
+
+        LocalAddress = NCE->Interface->Unicast;
+    }
+    else
+    {
+        if(!(NCE = NBLocateNeighbor( &LocalAddress )))
+        {
+             UnlockObject(AddrFile, OldIrql);
+            return STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    Status = PrepareICMPPacket( NCE->Interface,
+                                &Packet,
+                                &RemoteAddress,
+                                BufferData,
+                                DataSize );
+
+    if( !NT_SUCCESS(Status) )
+    {
+        UnlockObject(AddrFile, OldIrql);
+       return Status;
+    }
+
+    TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
+
+    if (!NT_SUCCESS(Status = IPSendDatagram( &Packet, NCE, ICMPSendPacketComplete, NULL )))
+    {
+        UnlockObject(AddrFile, OldIrql);
+        FreeNdisPacket(Packet.NdisPacket);
+        return Status;
+    }
+
+    TI_DbgPrint(MID_TRACE,("Leaving\n"));
+
+    UnlockObject(AddrFile, OldIrql);
+
+    return STATUS_SUCCESS;
+}
+
+
 
 VOID ICMPReceive(
     PIP_INTERFACE Interface,
@@ -144,6 +261,8 @@ VOID ICMPReceive(
 
     TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum));
 
+    RawIpReceive(Interface, IPPacket);
+
     /* Checksum ICMP header and data */
     if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) {
         TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n"));
@@ -181,6 +300,7 @@ VOID ICMPTransmit(
  */
 {
     PNEIGHBOR_CACHE_ENTRY NCE;
+    NTSTATUS Status;
 
     TI_DbgPrint(DEBUG_ICMP, ("Called.\n"));
 
@@ -191,7 +311,11 @@ VOID ICMPTransmit(
     /* Get a route to the destination address */
     if ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) {
         /* Send the packet */
-       IPSendDatagram(IPPacket, NCE, Complete, Context);
+       Status = IPSendDatagram(IPPacket, NCE, Complete, Context);
+       if (!NT_SUCCESS(Status))
+       {
+               Complete(Context, IPPacket->NdisPacket, Status);
+       }
     } else {
         /* No route to destination (or no free resources) */
         TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n",
@@ -221,17 +345,12 @@ VOID ICMPReply(
  *     notify him of the problem
  */
 {
-    UINT DataSize, PayloadSize;
+    UINT DataSize;
     IP_PACKET NewPacket = *IPPacket;
 
     TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d)  Code (%d).\n", Type, Code));
 
     DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
-    PayloadSize = DataSize - sizeof(ICMP_HEADER);
-    if ((PayloadSize) > 576) {
-       PayloadSize = 576;
-        DataSize = PayloadSize + sizeof(ICMP_HEADER);
-    }
 
     if( !PrepareICMPPacket(Interface, &NewPacket, &IPPacket->SrcAddr,
                           IPPacket->Data, DataSize) ) return;