- Implement UDP checksum calculation

- 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
This commit is contained in:
Cameron Gutman 2009-10-20 05:24:37 +00:00
parent 6f08578e3c
commit 31ba6d7556
3 changed files with 78 additions and 9 deletions

View 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)))

View 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);
}

View 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);