diff --git a/src/Emulator/Peripherals/Peripherals/Network/SynopsysDWCEthernetQualityOfService/SynopsysDWCEthernetQualityOfService_DMA.cs b/src/Emulator/Peripherals/Peripherals/Network/SynopsysDWCEthernetQualityOfService/SynopsysDWCEthernetQualityOfService_DMA.cs index b9d194819..64f2489cb 100644 --- a/src/Emulator/Peripherals/Peripherals/Network/SynopsysDWCEthernetQualityOfService/SynopsysDWCEthernetQualityOfService_DMA.cs +++ b/src/Emulator/Peripherals/Peripherals/Network/SynopsysDWCEthernetQualityOfService/SynopsysDWCEthernetQualityOfService_DMA.cs @@ -531,9 +531,18 @@ private void StartRx() writeBackStructure.OuterVlanTag = 0x0; writeBackStructure.InnerVlanTag = 0x0; writeBackStructure.OamSubtypeCodeOrMACControlPacketOpcode = (uint)frame.UnderlyingPacket.Type; - writeBackStructure.IpHeaderError = false; writeBackStructure.Ipv4HeaderPresent = frame.UnderlyingPacket.Type == EthernetPacketType.IpV4; writeBackStructure.Ipv6HeaderPresent = frame.UnderlyingPacket.Type == EthernetPacketType.IpV6; + + // Validate IP header checksum if checksum offload is enabled + writeBackStructure.IpHeaderError = false; + writeBackStructure.IpChecksumBypassed = !parent.checksumOffloadEnable.Value; + if(parent.checksumOffloadEnable.Value && writeBackStructure.Ipv4HeaderPresent) + { + var ipv4Packet = (IPv4Packet)frame.UnderlyingPacket.PayloadPacket; + writeBackStructure.IpHeaderError = !ipv4Packet.ValidChecksum; + } + if(writeBackStructure.Ipv4HeaderPresent || writeBackStructure.Ipv6HeaderPresent) { switch(((IpPacket)frame.UnderlyingPacket.PayloadPacket).NextHeader) @@ -622,6 +631,27 @@ private void StartRx() writeBackStructure.ReceiveWatchdogTimeout = false; writeBackStructure.GiantPacket = false; writeBackStructure.CrcError = parent.crcCheckDisable.Value ? false : !EthernetFrame.CheckCRC(bytes); + + // Validate payload checksum if checksum offload is enabled + writeBackStructure.IpPayloadError = false; + if(parent.checksumOffloadEnable.Value && (writeBackStructure.Ipv4HeaderPresent || writeBackStructure.Ipv6HeaderPresent)) + { + var ipPacket = (IpPacket)frame.UnderlyingPacket.PayloadPacket; + if(ipPacket.PayloadPacket is TcpPacket tcpPacket) + { + writeBackStructure.IpPayloadError = !tcpPacket.ValidChecksum; + } + else if(ipPacket.PayloadPacket is UdpPacket udpPacket) + { + // UDP checksum is optional in IPv4, mandatory in IPv6 + if(udpPacket.Checksum != 0 || writeBackStructure.Ipv6HeaderPresent) + { + writeBackStructure.IpPayloadError = !udpPacket.ValidChecksum; + } + } + // Note: ICMP checksum validation could be added here if PacketDotNet supports it + } + writeBackStructure.ErrorSummary = new bool[] { writeBackStructure.DribbleBitError, @@ -777,7 +807,7 @@ private void StartTx() buffer, (uint)maximumSegmentSize.Value, latestTxContext, - parent.checksumOffloadEnable.Value, + true, // TSO always requires checksum offload parent.SendFrame, sourceAddress ); @@ -789,7 +819,7 @@ private void StartTx() frameAssembler = new FrameAssembler( parent, structure.CrcPadControl, - parent.checksumOffloadEnable.Value ? structure.ChecksumControl : ChecksumOperation.None, + structure.ChecksumControl, // TX checksum insertion is controlled by descriptor CIC field, not MACCR.IPC (RX-only) parent.SendFrame ); } @@ -847,6 +877,7 @@ private void StartTx() writeBackStructure.LateCollision = false; writeBackStructure.NoCarrier = false; writeBackStructure.LossOfCarrier = false; + // Payload checksum errors are reported on RX path, not TX writeBackStructure.PayloadChecksumError = false; writeBackStructure.PacketFlushed = false; writeBackStructure.JabberTimeout = false;