- Implement UDP checksum calculation
authorCameron Gutman <aicommander@gmail.com>
Tue, 20 Oct 2009 05:24:37 +0000 (05:24 +0000)
committerCameron Gutman <aicommander@gmail.com>
Tue, 20 Oct 2009 05:24:37 +0000 (05:24 +0000)
 - Fixes issues with DHCP (and any other UDP traffic) over bridged networking on vbox and issues with other hardware that doesn't like a checksum of 0
 - See bug #4754

svn path=/trunk/; revision=43637

reactos/drivers/network/tcpip/include/checksum.h
reactos/lib/drivers/ip/network/checksum.c
reactos/lib/drivers/ip/transport/udp/udp.c

index 2157c50..3ee66ae 100644 (file)
@@ -22,6 +22,12 @@ csum_partial(
   int len,
   unsigned int sum);
 
+ULONG
+UDPv4ChecksumCalculate(
+  PIPv4_HEADER IPHeader,
+  PUCHAR PacketBuffer,
+  ULONG DataLength);
+
 #define IPv4Checksum(Data, Count, Seed)(~ChecksumFold(ChecksumCompute(Data, Count, Seed)))
 #define TCPv4Checksum(Data, Count, Seed)(~ChecksumFold(csum_partial(Data, Count, Seed)))
 //#define TCPv4Checksum(Data, Count, Seed)(~ChecksumFold(ChecksumCompute(Data, Count, Seed)))
index 7f11c1a..18f81d9 100644 (file)
@@ -55,3 +55,53 @@ ULONG ChecksumCompute(
 
   return Sum;
 }
+
+ULONG
+UDPv4ChecksumCalculate(
+  PIPv4_HEADER IPHeader,
+  PUCHAR PacketBuffer,
+  ULONG DataLength)
+{
+  ULONG Sum = 0;
+  USHORT TmpSum;
+  ULONG i;
+  BOOLEAN Pad;
+
+  /* Pad the data if needed */
+  Pad = (DataLength & 1);
+  if (Pad) {
+      DbgPrint("Odd\n");
+      DataLength++;
+  } else DbgPrint("Even\n");
+
+  /* Add from the UDP header and data */
+  for (i = 0; i < DataLength; i += 2)
+  {
+       TmpSum = ((PacketBuffer[i] << 8) & 0xFF00) +
+                ((Pad && i == DataLength - 1) ? 0 : (PacketBuffer[i+1] & 0x00FF));
+       Sum += TmpSum;
+  }
+
+  /* Add the source address */
+  for (i = 0; i < sizeof(IPv4_RAW_ADDRESS); i += 2)
+  {
+       TmpSum = ((((PUCHAR)&IPHeader->SrcAddr)[i] << 8) & 0xFF00) +
+                (((PUCHAR)&IPHeader->SrcAddr)[i+1] & 0x00FF);
+       Sum += TmpSum;
+  }
+
+  /* Add the destination address */
+  for (i = 0; i < sizeof(IPv4_RAW_ADDRESS); i += 2)
+  {
+       TmpSum = ((((PUCHAR)&IPHeader->DstAddr)[i] << 8) & 0xFF00) +
+                (((PUCHAR)&IPHeader->DstAddr)[i+1] & 0x00FF);
+       Sum += TmpSum;
+  }
+
+  /* Add the proto number and length */
+  Sum += IPPROTO_UDP + (DataLength - (Pad ? 1 : 0));
+
+  /* Fold the checksum and return the one's complement */
+  return ~ChecksumFold(Sum);
+}
+
index 1f8bdf6..b6ad0d0 100644 (file)
@@ -19,6 +19,7 @@ NTSTATUS AddUDPHeaderIPv4(
     PIP_ADDRESS LocalAddress,
     USHORT LocalPort,
     PIP_PACKET IPPacket,
+    PVOID Data,
     UINT DataLength)
 /*
  * FUNCTION: Adds an IPv4 and UDP header to an IP packet
@@ -49,11 +50,21 @@ NTSTATUS AddUDPHeaderIPv4(
     /* Port values are already big-endian values */
     UDPHeader->SourcePort = LocalPort;
     UDPHeader->DestPort   = RemotePort;
-    /* FIXME: Calculate UDP checksum and put it in UDP header */
     UDPHeader->Checksum   = 0;
     /* Length of UDP header and data */
     UDPHeader->Length     = WH2N(DataLength + sizeof(UDP_HEADER));
 
+    TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
+                           IPPacket->Header, IPPacket->Data,
+                           (PCHAR)IPPacket->Data - (PCHAR)IPPacket->Header));
+
+    RtlCopyMemory(IPPacket->Data, Data, DataLength);
+
+    UDPHeader->Checksum = UDPv4ChecksumCalculate((PIPv4_HEADER)IPPacket->Header,
+                                                 (PUCHAR)UDPHeader,
+                                                 DataLength + sizeof(UDP_HEADER));
+    UDPHeader->Checksum = WH2N(UDPHeader->Checksum);
+
     TI_DbgPrint(MID_TRACE, ("Packet: %d ip %d udp %d payload\n",
                            (PCHAR)UDPHeader - (PCHAR)IPPacket->Header,
                            (PCHAR)IPPacket->Data - (PCHAR)UDPHeader,
@@ -105,7 +116,7 @@ NTSTATUS BuildUDPPacket(
     switch (RemoteAddress->Type) {
     case IP_ADDRESS_V4:
        Status = AddUDPHeaderIPv4(RemoteAddress, RemotePort,
-                                 LocalAddress, LocalPort, Packet, DataLen);
+                                 LocalAddress, LocalPort, Packet, DataBuffer, DataLen);
        break;
     case IP_ADDRESS_V6:
        /* FIXME: Support IPv6 */
@@ -121,12 +132,6 @@ NTSTATUS BuildUDPPacket(
        return Status;
     }
 
-    TI_DbgPrint(MID_TRACE, ("Copying data (hdr %x data %x (%d))\n",
-                           Packet->Header, Packet->Data,
-                           (PCHAR)Packet->Data - (PCHAR)Packet->Header));
-
-    RtlCopyMemory( Packet->Data, DataBuffer, DataLen );
-
     TI_DbgPrint(MID_TRACE, ("Displaying packet\n"));
 
     DISPLAY_IP_PACKET(Packet);
@@ -258,7 +263,15 @@ VOID UDPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
 
   UDPHeader = (PUDP_HEADER)IPPacket->Data;
 
-  /* FIXME: Calculate and validate UDP checksum */
+  /* Calculate and validate UDP checksum */
+  i = UDPv4ChecksumCalculate(IPv4Header,
+                             (PUCHAR)UDPHeader,
+                             WH2N(UDPHeader->Length));
+  if (i != DH2N(0x0000FFFF))
+  {
+      TI_DbgPrint(MIN_TRACE, ("Bad checksum on packet received.\n"));
+      return;
+  }
 
   /* Sanity checks */
   i = WH2N(UDPHeader->Length);