]> xenbits.xensource.com Git - pvdrivers/win/xenvif.git/commitdiff
Add statistics for checksum validation
authorPaul Durrant <paul.durrant@citrix.com>
Tue, 20 Sep 2016 16:43:27 +0000 (17:43 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Tue, 20 Sep 2016 16:47:17 +0000 (17:47 +0100)
For the transmit side this also entails added code to perform checksum
validation. However, since this may affect performance, validation is
only performed if the registry parameter TransmitterValidateChecksums
(REG_DWORD) is present and set a non-zero value.

Since the index values of the statistics used by XENNET are left
unchanged by this patch, there is no need to bump the XENVIF_VIF
interface version.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
include/vif_interface.h
src/xenvif/frontend.c
src/xenvif/receiver.c
src/xenvif/transmitter.c

index 38872bc28c33f0e198e2e3a502fea01d3c724850..02d9549cff1cfd88db17d9a144d8f4e1d05cfdb2 100644 (file)
@@ -152,20 +152,20 @@ struct _XENVIF_PACKET_CHECKSUM_FLAGS_V1 {
             ULONG   IpChecksumSucceeded:1;
             /*! IPv4 header checksum validation failed */
             ULONG   IpChecksumFailed:1;
-            /*! IPv4 header checksum is present */
-            ULONG   IpChecksumPresent:1;
+            /*! IPv4 header checksum not validated */
+            ULONG   IpChecksumNotValidated:1;
             /*! TCP checksum validation succeeded */
             ULONG   TcpChecksumSucceeded:1;
             /*! TCP checksum validation failed */
             ULONG   TcpChecksumFailed:1;
-            /*! TCP checksum is present */
-            ULONG   TcpChecksumPresent:1;
+            /*! TCP checksum not validated */
+            ULONG   TcpChecksumNotValidated:1;
             /*! UDP checksum validation succeeded */
             ULONG   UdpChecksumSucceeded:1;
             /*! UDP checksum validation failed */
             ULONG   UdpChecksumFailed:1;
-            /*! UDP checksum is present */
-            ULONG   UdpChecksumPresent:1;
+            /*! UDP checksum not validated */
+            ULONG   UdpChecksumNotValidated:1;
             ULONG   Reserved:23;
         };
         /*! Raw representation */
@@ -288,6 +288,10 @@ struct _XENVIF_TRANSMITTER_PACKET_V2 {
     \brief Interface statistics
 */
 typedef enum _XENVIF_VIF_STATISTIC {
+    /*
+     * Statistics required by XENNET
+     */
+
     /*! RFC 2863 ifOutDiscards */
     XENVIF_TRANSMITTER_PACKETS_DROPPED = 0,
     /*! Backend component of RFC 2863 ifOutErrors */
@@ -324,6 +328,77 @@ typedef enum _XENVIF_VIF_STATISTIC {
     XENVIF_RECEIVER_BROADCAST_PACKETS,
     /*! Total number of octets in ifInBroadcastPkts */
     XENVIF_RECEIVER_BROADCAST_OCTETS,
+
+    /*
+     * Miscellaneous statistics
+     */
+
+    /*! Total number of outbound VLAN tagged packets */
+    XENVIF_TRANSMITTER_TAGGED_PACKETS,
+    /*! Total number of outbound LLC/SNAP packets */
+    XENVIF_TRANSMITTER_LLC_SNAP_PACKETS,
+    /*! Total number of outbound IP version 4 packets */
+    XENVIF_TRANSMITTER_IPV4_PACKETS,
+    /*! Total number of outbound IP version 6 packets */
+    XENVIF_TRANSMITTER_IPV6_PACKETS,
+    /*! Total number of outbound TCP packets */
+    XENVIF_TRANSMITTER_TCP_PACKETS,
+    /*! Total number of outbound UDP packets */
+    XENVIF_TRANSMITTER_UDP_PACKETS,
+    /*! Total number of outbound GSO packets */
+    XENVIF_TRANSMITTER_GSO_PACKETS,
+    /*! Total number of outbound IP version 4 packets with good checksum */
+    XENVIF_TRANSMITTER_IPV4_CHECKSUM_SUCCEEDED,
+    /*! Total number of outbound IP version 4 packets with bad checksum */
+    XENVIF_TRANSMITTER_IPV4_CHECKSUM_FAILED,
+    /*! Total number of outbound IP version 4 packets without validated checksum */
+    XENVIF_TRANSMITTER_IPV4_CHECKSUM_NOT_VALIDATED,
+    /*! Total number of outbound TCP packets with good checksum */
+    XENVIF_TRANSMITTER_TCP_CHECKSUM_SUCCEEDED,
+    /*! Total number of outbound TCP packets with bad checksum */
+    XENVIF_TRANSMITTER_TCP_CHECKSUM_FAILED,
+    /*! Total number of outbound TCP packets without validated checksum */
+    XENVIF_TRANSMITTER_TCP_CHECKSUM_NOT_VALIDATED,
+    /*! Total number of outbound UDP packets with good checksum */
+    XENVIF_TRANSMITTER_UDP_CHECKSUM_SUCCEEDED,
+    /*! Total number of outbound UDP packets with bad checksum */
+    XENVIF_TRANSMITTER_UDP_CHECKSUM_FAILED,
+    /*! Total number of outbound UDP packets without validated checksum */
+    XENVIF_TRANSMITTER_UDP_CHECKSUM_NOT_VALIDATED,
+
+
+    /*! Total number of inbound VLAN tagged packets */
+    XENVIF_RECEIVER_TAGGED_PACKETS,
+    /*! Total number of inbound LLC/SNAP packets */
+    XENVIF_RECEIVER_LLC_SNAP_PACKETS,
+    /*! Total number of inbound IP version 4 packets */
+    XENVIF_RECEIVER_IPV4_PACKETS,
+    /*! Total number of inbound IP version 6 packets */
+    XENVIF_RECEIVER_IPV6_PACKETS,
+    /*! Total number of inbound TCP packets */
+    XENVIF_RECEIVER_TCP_PACKETS,
+    /*! Total number of inbound UDP packets */
+    XENVIF_RECEIVER_UDP_PACKETS,
+    /*! Total number of inbound GSO packets */
+    XENVIF_RECEIVER_GSO_PACKETS,
+    /*! Total number of inbound IP version 4 packets with good checksum */
+    XENVIF_RECEIVER_IPV4_CHECKSUM_SUCCEEDED,
+    /*! Total number of inbound IP version 4 packets with bad checksum */
+    XENVIF_RECEIVER_IPV4_CHECKSUM_FAILED,
+    /*! Total number of inbound IP version 4 packets without validated checksum */
+    XENVIF_RECEIVER_IPV4_CHECKSUM_NOT_VALIDATED,
+    /*! Total number of inbound TCP packets with good checksum */
+    XENVIF_RECEIVER_TCP_CHECKSUM_SUCCEEDED,
+    /*! Total number of inbound TCP packets with bad checksum */
+    XENVIF_RECEIVER_TCP_CHECKSUM_FAILED,
+    /*! Total number of inbound TCP packets without validated checksum */
+    XENVIF_RECEIVER_TCP_CHECKSUM_NOT_VALIDATED,
+    /*! Total number of inbound UDP packets with good checksum */
+    XENVIF_RECEIVER_UDP_CHECKSUM_SUCCEEDED,
+    /*! Total number of inbound UDP packets with bad checksum */
+    XENVIF_RECEIVER_UDP_CHECKSUM_FAILED,
+    /*! Total number of inbound UDP packets without validated checksum */
+    XENVIF_RECEIVER_UDP_CHECKSUM_NOT_VALIDATED,
     XENVIF_VIF_STATISTIC_COUNT
 } XENVIF_VIF_STATISTIC, *PXENVIF_VIF_STATISTIC;
 
index d21c798e5055d1ce107603ccaaaa2bc141a8217b..f6570e87f63a57c82240c94322d1bd3725165cb9 100644 (file)
@@ -1672,6 +1672,41 @@ __FrontendStatisticName(
     _FRONTEND_STATISTIC_NAME(RECEIVER_MULTICAST_OCTETS);
     _FRONTEND_STATISTIC_NAME(RECEIVER_BROADCAST_PACKETS);
     _FRONTEND_STATISTIC_NAME(RECEIVER_BROADCAST_OCTETS);
+
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_TAGGED_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_LLC_SNAP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_IPV4_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_IPV6_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_TCP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_UDP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_GSO_PACKETS);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_IPV4_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_IPV4_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_IPV4_CHECKSUM_NOT_VALIDATED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_TCP_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_TCP_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_TCP_CHECKSUM_NOT_VALIDATED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_UDP_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_UDP_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(TRANSMITTER_UDP_CHECKSUM_NOT_VALIDATED);
+
+    _FRONTEND_STATISTIC_NAME(RECEIVER_TAGGED_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_LLC_SNAP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_IPV4_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_IPV6_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_TCP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_UDP_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_GSO_PACKETS);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_IPV4_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_IPV4_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_IPV4_CHECKSUM_NOT_VALIDATED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_TCP_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_TCP_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_TCP_CHECKSUM_NOT_VALIDATED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_UDP_CHECKSUM_SUCCEEDED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_UDP_CHECKSUM_FAILED);
+    _FRONTEND_STATISTIC_NAME(RECEIVER_UDP_CHECKSUM_NOT_VALIDATED);
+
     default:
         break;
     }
@@ -1708,7 +1743,7 @@ FrontendDebugCallback(
 
         XENBUS_DEBUG(Printf,
                      &Frontend->DebugInterface,
-                     " - %40s %lu\n",
+                     " - %40s %llu\n",
                      __FrontendStatisticName(Name),
                      Value);
     }
@@ -2139,16 +2174,9 @@ FrontendConnect(
 
     Trace("====>\n");
 
-    Frontend->StatisticsCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
-    Frontend->Statistics = __FrontendAllocate(sizeof (XENVIF_FRONTEND_STATISTICS) * Frontend->StatisticsCount);
-
-    status = STATUS_NO_MEMORY;
-    if (Frontend->Statistics == NULL)
-        goto fail1;
-
     status = XENBUS_DEBUG(Acquire, &Frontend->DebugInterface);
     if (!NT_SUCCESS(status))
-        goto fail2;
+        goto fail1;
 
     status = XENBUS_DEBUG(Register,
                           &Frontend->DebugInterface,
@@ -2157,26 +2185,26 @@ FrontendConnect(
                           Frontend,
                           &Frontend->DebugCallback);
     if (!NT_SUCCESS(status))
-        goto fail3;
+        goto fail2;
 
     status = MacConnect(__FrontendGetMac(Frontend));
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail3;
 
     FrontendSetNumQueues(Frontend);
     FrontendSetSplit(Frontend);
 
     status = ReceiverConnect(__FrontendGetReceiver(Frontend));
     if (!NT_SUCCESS(status))
-        goto fail5;
+        goto fail4;
 
     status = TransmitterConnect(__FrontendGetTransmitter(Frontend));
     if (!NT_SUCCESS(status))
-        goto fail6;
+        goto fail5;
 
     status = ControllerConnect(__FrontendGetController(Frontend));
     if (!NT_SUCCESS(status))
-        goto fail7;
+        goto fail6;
 
     Attempt = 0;
     do {
@@ -2231,7 +2259,7 @@ abort:
     } while (status == STATUS_RETRY);
 
     if (!NT_SUCCESS(status))
-        goto fail8;
+        goto fail7;
 
     State = XenbusStateUnknown;
     while (State != XenbusStateConnected) {
@@ -2270,7 +2298,7 @@ abort:
 
     status = STATUS_UNSUCCESSFUL;
     if (State != XenbusStateConnected)
-        goto fail9;
+        goto fail8;
 
     ControllerEnable(__FrontendGetController(Frontend));
 
@@ -2279,51 +2307,44 @@ abort:
     Trace("<====\n");
     return STATUS_SUCCESS;
 
-fail9:
-    Error("fail9\n");
-
 fail8:
     Error("fail8\n");
 
-    ControllerDisconnect(__FrontendGetController(Frontend));
-
 fail7:
     Error("fail7\n");
 
-    TransmitterDisconnect(__FrontendGetTransmitter(Frontend));
+    ControllerDisconnect(__FrontendGetController(Frontend));
 
 fail6:
     Error("fail6\n");
 
-    ReceiverDisconnect(__FrontendGetReceiver(Frontend));
+    TransmitterDisconnect(__FrontendGetTransmitter(Frontend));
 
 fail5:
     Error("fail5\n");
 
+    ReceiverDisconnect(__FrontendGetReceiver(Frontend));
+
+fail4:
+    Error("fail4\n");
+
     MacDisconnect(__FrontendGetMac(Frontend));
 
     Frontend->Split = FALSE;
     Frontend->NumQueues = 0;
 
-fail4:
-    Error("fail4\n");
+fail3:
+    Error("fail3\n");
 
     XENBUS_DEBUG(Deregister,
                  &Frontend->DebugInterface,
                  Frontend->DebugCallback);
     Frontend->DebugCallback = NULL;
 
-fail3:
-    Error("fail3\n");
-
-    XENBUS_DEBUG(Release, &Frontend->DebugInterface);
-
 fail2:
     Error("fail2\n");
 
-    __FrontendFree(Frontend->Statistics);
-    Frontend->Statistics = NULL;
-    Frontend->StatisticsCount = 0;
+    XENBUS_DEBUG(Release, &Frontend->DebugInterface);
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -2356,10 +2377,6 @@ FrontendDisconnect(
 
     XENBUS_DEBUG(Release, &Frontend->DebugInterface);
 
-    __FrontendFree(Frontend->Statistics);
-    Frontend->Statistics = NULL;
-    Frontend->StatisticsCount = 0;
-
     Trace("<====\n");
 }
 
@@ -2837,10 +2854,25 @@ FrontendInitialize(
     if (!NT_SUCCESS(status))
         goto fail11;
 
+    (*Frontend)->StatisticsCount = KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
+    (*Frontend)->Statistics = __FrontendAllocate(sizeof (XENVIF_FRONTEND_STATISTICS) *
+                                                 (*Frontend)->StatisticsCount);
+
+    status = STATUS_NO_MEMORY;
+    if ((*Frontend)->Statistics == NULL)
+        goto fail12;
+
     Trace("<====\n");
 
     return STATUS_SUCCESS;
 
+fail12:
+    Error("fail12\n");
+
+    ThreadAlert((*Frontend)->MibThread);
+    ThreadJoin((*Frontend)->MibThread);
+    (*Frontend)->MibThread = NULL;
+
 fail11:
     Error("fail11\n");
 
@@ -2934,6 +2966,10 @@ FrontendTeardown(
 
     ASSERT(Frontend->State == FRONTEND_UNKNOWN);
 
+    __FrontendFree(Frontend->Statistics);
+    Frontend->Statistics = NULL;
+    Frontend->StatisticsCount = 0;
+
     ThreadAlert(Frontend->MibThread);
     ThreadJoin(Frontend->MibThread);
     Frontend->MibThread = NULL;
index 042d55030c0b95815372c626118b10be70f930e5..568eb822580f1592aa33ef93c384f2c40f04f3eb 100644 (file)
@@ -457,6 +457,7 @@ ReceiverRingProcessChecksum(
     )
 {
     PXENVIF_RECEIVER            Receiver;
+    PXENVIF_FRONTEND            Frontend;
     PXENVIF_PACKET_INFO         Info;
     XENVIF_PACKET_PAYLOAD       Payload;
     uint16_t                    flags;
@@ -464,6 +465,7 @@ ReceiverRingProcessChecksum(
     PIP_HEADER                  IpHeader;
 
     Receiver = Ring->Receiver;
+    Frontend = Receiver->Frontend;
 
     Info = &Packet->Info;
 
@@ -500,7 +502,6 @@ ReceiverRingProcessChecksum(
             OffloadChecksum = FALSE;
 
         // IP header checksums are always present and not validated
-
         if (OffloadChecksum) {
             USHORT  Embedded;
             USHORT  Calculated;
@@ -513,14 +514,8 @@ ReceiverRingProcessChecksum(
                 Packet->Flags.IpChecksumSucceeded = 1;
             else
                 Packet->Flags.IpChecksumFailed = 1;
-        }
-
-        if (!OffloadChecksum ||
-            Ring->OffloadOptions.NeedChecksumValue ||
-            Receiver->CalculateChecksums) { // Checksum must be present
-            Packet->Flags.IpChecksumPresent = 1;
         } else {
-            IpHeader->Version4.Checksum = 0;
+            Packet->Flags.IpChecksumNotValidated = 1;
         }
     }
 
@@ -556,21 +551,19 @@ ReceiverRingProcessChecksum(
                 else
                     Packet->Flags.TcpChecksumFailed = 1;
             }
+        } else {
+            Packet->Flags.TcpChecksumNotValidated = 1;
         }
         
-        if (!OffloadChecksum ||
-            Ring->OffloadOptions.NeedChecksumValue ||
-            Receiver->CalculateChecksums) {     // Checksum must be present
-            if (flags & NETRXF_csum_blank) {    // Checksum is not present
-                USHORT  Calculated;
-
-                Calculated = ChecksumPseudoHeader(StartVa, Info);
-                Calculated = ChecksumTcpPacket(StartVa, Info, Calculated, &Payload);
+        if ((Ring->OffloadOptions.NeedChecksumValue ||
+             Receiver->CalculateChecksums != 0) &&
+            (flags & NETRXF_data_validated)) {
+            USHORT  Calculated;
 
-                TcpHeader->Checksum = Calculated;
-            }
+            Calculated = ChecksumPseudoHeader(StartVa, Info);
+            Calculated = ChecksumTcpPacket(StartVa, Info, Calculated, &Payload);
 
-            Packet->Flags.TcpChecksumPresent = 1;
+            TcpHeader->Checksum = Calculated;
         }
     } else if (Info->UdpHeader.Length != 0 && !Info->IsAFragment) {
         PUDP_HEADER     UdpHeader;
@@ -590,46 +583,39 @@ ReceiverRingProcessChecksum(
                 Packet->Flags.UdpChecksumSucceeded = 1;
             } else {                                // Checksum is present but is not validated
                 USHORT  Embedded;
-                USHORT  Calculated;
 
                 ASSERT(~flags & NETRXF_csum_blank);
 
                 Embedded = UdpHeader->Checksum;
 
-                Calculated = ChecksumPseudoHeader(StartVa, Info);
-                Calculated = ChecksumUdpPacket(StartVa, Info, Calculated, &Payload);
-
-                if (IpHeader->Version == 4) {
-                    if (Embedded == 0) {    // Tolarate zero checksum for IPv4/UDP
-                        Packet->Flags.UdpChecksumSucceeded = 1;
-                    } else {
-                        if (ChecksumVerify(Calculated, Embedded))
-                            Packet->Flags.UdpChecksumSucceeded = 1;
-                        else
-                            Packet->Flags.UdpChecksumFailed = 1;
-                    }
+                // Tolarate zero checksum for IPv4/UDP
+                if (IpHeader->Version == 4 && Embedded == 0) {
+                    Packet->Flags.UdpChecksumSucceeded = 1;
                 } else {
+                    USHORT  Calculated;
+
+                    Calculated = ChecksumPseudoHeader(StartVa, Info);
+                    Calculated = ChecksumUdpPacket(StartVa, Info, Calculated, &Payload);
+
                     if (ChecksumVerify(Calculated, Embedded))
                         Packet->Flags.UdpChecksumSucceeded = 1;
                     else
                         Packet->Flags.UdpChecksumFailed = 1;
                 }
             }
+        } else {
+            Packet->Flags.UdpChecksumNotValidated = 1;
         }
 
-        if (!OffloadChecksum ||
-            Ring->OffloadOptions.NeedChecksumValue ||
-            Receiver->CalculateChecksums) {     // Checksum must be present
-            if (flags & NETRXF_csum_blank) {    // Checksum is not present
-                USHORT  Calculated;
-
-                Calculated = ChecksumPseudoHeader(StartVa, Info);
-                Calculated = ChecksumUdpPacket(StartVa, Info, Calculated, &Payload);
+        if ((Ring->OffloadOptions.NeedChecksumValue ||
+             Receiver->CalculateChecksums != 0) &&
+            (flags & NETRXF_data_validated)) {
+            USHORT  Calculated;
 
-                UdpHeader->Checksum = Calculated;
-            }
+            Calculated = ChecksumPseudoHeader(StartVa, Info);
+            Calculated = ChecksumUdpPacket(StartVa, Info, Calculated, &Payload);
 
-            Packet->Flags.UdpChecksumPresent = 1;
+            UdpHeader->Checksum = Calculated;
         }
     }
 }
@@ -758,6 +744,8 @@ __ReceiverRingBuildSegment(
                   Packet,
                   FIELD_OFFSET(XENVIF_RECEIVER_PACKET, Mdl));
 
+    Segment->MaximumSegmentSize = 0;
+
     // The segment contains no data as yet
     Segment->Length = 0;
 
@@ -1193,7 +1181,6 @@ ReceiverRingProcessPacket(
     PUCHAR                          StartVa;
     PETHERNET_HEADER                EthernetHeader;
     PETHERNET_ADDRESS               DestinationAddress;
-    ETHERNET_ADDRESS_TYPE           Type;
     NTSTATUS                        status;
 
     Receiver = Ring->Receiver;
@@ -1264,41 +1251,6 @@ ReceiverRingProcessPacket(
     if (!MacApplyFilters(Mac, DestinationAddress))
         goto fail3;
 
-    Type = GET_ETHERNET_ADDRESS_TYPE(DestinationAddress);
-
-    switch (Type) {
-    case ETHERNET_ADDRESS_UNICAST:
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_UNICAST_PACKETS,
-                                   1);
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_UNICAST_OCTETS,
-                                   Packet->Length);
-        break;
-            
-    case ETHERNET_ADDRESS_MULTICAST:
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_MULTICAST_PACKETS,
-                                   1);
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_MULTICAST_OCTETS,
-                                   Packet->Length);
-        break;
-
-    case ETHERNET_ADDRESS_BROADCAST:
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_BROADCAST_PACKETS,
-                                   1);
-        FrontendIncrementStatistic(Frontend,
-                                   XENVIF_RECEIVER_BROADCAST_OCTETS,
-                                   Packet->Length);
-        break;
-
-    default:
-        ASSERT(FALSE);
-        break;
-    }
-
     if (Packet->MaximumSegmentSize != 0)
         ReceiverRingProcessLargePacket(Ring, Packet, List);
     else
@@ -1428,6 +1380,11 @@ __ReceiverRingReleaseLock(
     while (More) {
         PLIST_ENTRY             ListEntry;
         PXENVIF_RECEIVER_PACKET Packet;
+        PXENVIF_PACKET_INFO     Info;
+        PUCHAR                  StartVa;
+        PETHERNET_HEADER        EthernetHeader;
+        PETHERNET_ADDRESS       DestinationAddress;
+        ETHERNET_ADDRESS_TYPE   Type;
 
         ListEntry = RemoveHeadList(&List);
         ASSERT3P(ListEntry, !=, &List);
@@ -1441,6 +1398,139 @@ __ReceiverRingReleaseLock(
                                    XENVIF_RECEIVER_PACKET,
                                    ListEntry);
 
+        StartVa = MmGetSystemAddressForMdlSafe(&Packet->Mdl,
+                                               NormalPagePriority);
+        ASSERT(StartVa != NULL);
+        StartVa += Packet->Offset;
+
+        Info = &Packet->Info;
+
+        ASSERT(Info->EthernetHeader.Length != 0);
+        EthernetHeader = (PETHERNET_HEADER)(StartVa + Info->EthernetHeader.Offset);
+
+        DestinationAddress = &EthernetHeader->DestinationAddress;
+
+        Type = GET_ETHERNET_ADDRESS_TYPE(DestinationAddress);
+
+        switch (Type) {
+        case ETHERNET_ADDRESS_UNICAST:
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_UNICAST_PACKETS,
+                                       1);
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_UNICAST_OCTETS,
+                                       Packet->Length);
+            break;
+
+        case ETHERNET_ADDRESS_MULTICAST:
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_MULTICAST_PACKETS,
+                                       1);
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_MULTICAST_OCTETS,
+                                       Packet->Length);
+            break;
+
+        case ETHERNET_ADDRESS_BROADCAST:
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_BROADCAST_PACKETS,
+                                       1);
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_BROADCAST_OCTETS,
+                                       Packet->Length);
+            break;
+
+        default:
+            ASSERT(FALSE);
+            break;
+        }
+
+        if (ETHERNET_HEADER_IS_TAGGED(EthernetHeader))
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_TAGGED_PACKETS,
+                                       1);
+
+        if (Info->LLCSnapHeader.Length != 0)
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_LLC_SNAP_PACKETS,
+                                       1);
+
+        if (Info->IpHeader.Length != 0) {
+            PIP_HEADER  IpHeader = (PIP_HEADER)(StartVa + Info->IpHeader.Offset);
+
+            if (IpHeader->Version == 4) {
+                FrontendIncrementStatistic(Frontend,
+                                           XENVIF_RECEIVER_IPV4_PACKETS,
+                                           1);
+            } else {
+                ASSERT3U(IpHeader->Version, ==, 6);
+
+                FrontendIncrementStatistic(Frontend,
+                                           XENVIF_RECEIVER_IPV6_PACKETS,
+                                           1);
+            }
+        }
+
+        if (Info->TcpHeader.Length != 0)
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_TCP_PACKETS,
+                                       1);
+
+        if (Info->UdpHeader.Length != 0)
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_UDP_PACKETS,
+                                       1);
+
+       if (Packet->MaximumSegmentSize != 0)
+            FrontendIncrementStatistic(Frontend,
+                                       XENVIF_RECEIVER_GSO_PACKETS,
+                                       1);
+
+       if (Packet->Flags.IpChecksumSucceeded != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_IPV4_CHECKSUM_SUCCEEDED,
+                                      1);
+
+       if (Packet->Flags.IpChecksumFailed != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_IPV4_CHECKSUM_FAILED,
+                                      1);
+
+       if (Packet->Flags.IpChecksumNotValidated != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_IPV4_CHECKSUM_NOT_VALIDATED,
+                                      1);
+
+       if (Packet->Flags.TcpChecksumSucceeded != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_TCP_CHECKSUM_SUCCEEDED,
+                                      1);
+
+       if (Packet->Flags.TcpChecksumFailed != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_TCP_CHECKSUM_FAILED,
+                                      1);
+
+       if (Packet->Flags.TcpChecksumNotValidated != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_TCP_CHECKSUM_NOT_VALIDATED,
+                                      1);
+
+       if (Packet->Flags.UdpChecksumSucceeded != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_UDP_CHECKSUM_SUCCEEDED,
+                                      1);
+
+       if (Packet->Flags.UdpChecksumFailed != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_UDP_CHECKSUM_FAILED,
+                                      1);
+
+       if (Packet->Flags.UdpChecksumNotValidated != 0)
+           FrontendIncrementStatistic(Frontend,
+                                      XENVIF_RECEIVER_UDP_CHECKSUM_NOT_VALIDATED,
+                                      1);
+
         VifReceiverQueuePacket(Context,
                                Ring->Index,
                                &Packet->Mdl,
index 88add2f256bad1189860b624efb07b8df33b2465..fae7b1b12dbcf9b63d7e3d2eeffeca164d47352c 100644 (file)
@@ -73,7 +73,6 @@ typedef struct _XENVIF_TRANSMITTER_PACKET {
     XENVIF_VIF_OFFLOAD_OPTIONS                  OffloadOptions;
     USHORT                                      MaximumSegmentSize;
     USHORT                                      TagControlInformation;
-    XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO   Completion;
     PMDL                                        Mdl;
     ULONG                                       Offset;
     ULONG                                       Length;
@@ -81,6 +80,8 @@ typedef struct _XENVIF_TRANSMITTER_PACKET {
     XENVIF_PACKET_HASH                          Hash;
     XENVIF_PACKET_INFO                          Info;
     XENVIF_PACKET_PAYLOAD                       Payload;
+    XENVIF_PACKET_CHECKSUM_FLAGS                Flags;
+    XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO   Completion;
 } XENVIF_TRANSMITTER_PACKET, *PXENVIF_TRANSMITTER_PACKET;
 
 typedef struct _XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS {
@@ -220,6 +221,7 @@ struct _XENVIF_TRANSMITTER {
     ULONG                       DisableIpVersion4Gso;
     ULONG                       DisableIpVersion6Gso;
     ULONG                       AlwaysCopy;
+    ULONG                       ValidateChecksums;
     KSPIN_LOCK                  Lock;
     PXENBUS_CACHE               PacketCache;
     XENBUS_STORE_INTERFACE      StoreInterface;
@@ -338,21 +340,23 @@ __TransmitterPutPacket(
 {
     ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof (LIST_ENTRY)));
     ASSERT3U(Packet->Reference, ==, 0);
+    Packet->Cookie = NULL;
 
-    Packet->Mdl = NULL;
-    Packet->Offset = 0;
-    Packet->Length = 0;
     Packet->OffloadOptions.Value = 0;
     Packet->MaximumSegmentSize = 0;
     Packet->TagControlInformation = 0;
-    RtlZeroMemory(&Packet->Completion, sizeof (XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO));
-    Packet->Cookie = NULL;
+    Packet->Mdl = NULL;
+    Packet->Offset = 0;
+    Packet->Length = 0;
 
     RtlZeroMemory(Packet->Header, XENVIF_TRANSMITTER_MAXIMUM_HEADER_LENGTH);
     RtlZeroMemory(&Packet->Info, sizeof (XENVIF_PACKET_INFO));
     RtlZeroMemory(&Packet->Hash, sizeof (XENVIF_PACKET_HASH));
     RtlZeroMemory(&Packet->Payload, sizeof (XENVIF_PACKET_PAYLOAD));
 
+    Packet->Flags.Value = 0;
+    RtlZeroMemory(&Packet->Completion, sizeof (XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO));
+
     XENBUS_CACHE(Put,
                  &Transmitter->CacheInterface,
                  Transmitter->PacketCache,
@@ -1169,6 +1173,7 @@ __TransmitterRingPrepareHeader(
     PUCHAR                          StartVa;
     PFN_NUMBER                      Pfn;
     PETHERNET_HEADER                EthernetHeader;
+    BOOLEAN                         SquashError;
     NTSTATUS                        status;
 
     Transmitter = Ring->Transmitter;
@@ -1181,6 +1186,8 @@ __TransmitterRingPrepareHeader(
     Payload = &Packet->Payload;
     Info = &Packet->Info;
 
+    SquashError = FALSE;
+
     status = STATUS_UNSUCCESSFUL;
     if (Info->Length == 0)
         goto fail1;
@@ -1307,7 +1314,6 @@ __TransmitterRingPrepareHeader(
         Packet->OffloadOptions.OffloadIpVersion4HeaderChecksum = 1;
 
         // TCP checksum calulcation must be offloaded for large packets
-        TcpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
         Packet->OffloadOptions.OffloadIpVersion4TcpChecksum = 1;
 
         // If the MSS is such that the payload would constitute only a single fragment then
@@ -1343,7 +1349,6 @@ __TransmitterRingPrepareHeader(
         IpHeader->Version6.PayloadLength = HTONS((USHORT)Length);
 
         // TCP checksum calulcation must be offloaded for large packets
-        TcpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
         Packet->OffloadOptions.OffloadIpVersion6TcpChecksum = 1;
 
         // If the MSS is such that the payload would constitute only a single fragment then
@@ -1362,24 +1367,110 @@ __TransmitterRingPrepareHeader(
         
         if (Fragment->Length > MaximumFrameSize) {
             status = STATUS_INVALID_PARAMETER;
+            SquashError = TRUE;
             goto fail5;
         }
     }
 
-    if (Packet->OffloadOptions.OffloadIpVersion4HeaderChecksum) {
+    if (Info->IpHeader.Length != 0) {
         PIP_HEADER  IpHeader;
 
-        ASSERT(Info->IpHeader.Length != 0);
         IpHeader = (PIP_HEADER)(StartVa + Info->IpHeader.Offset);
 
-        ASSERT3U(IpHeader->Version, ==, 4);
-        IpHeader->Version4.Checksum = ChecksumIpVersion4Header(StartVa, Info);
+        if (IpHeader->Version == 4) {
+            if (Packet->OffloadOptions.OffloadIpVersion4HeaderChecksum) {
+                IpHeader->Version4.Checksum = ChecksumIpVersion4Header(StartVa, Info);
+
+                Packet->Flags.IpChecksumNotValidated = 1;
+            } else if (Transmitter->ValidateChecksums != 0) {
+                USHORT      Embedded;
+                USHORT      Calculated;
+
+                Embedded = IpHeader->Version4.Checksum;
+
+                Calculated = ChecksumIpVersion4Header(StartVa, Info);
+
+                if (ChecksumVerify(Calculated, Embedded))
+                    Packet->Flags.IpChecksumSucceeded = 1;
+                else
+                    Packet->Flags.IpChecksumFailed = 1;
+            } else {
+                Packet->Flags.IpChecksumNotValidated = 1;
+            }
+        }
+    }
+
+    if (Info->TcpHeader.Length != 0) {
+        PTCP_HEADER TcpHeader;
+
+        TcpHeader = (PTCP_HEADER)(StartVa + Info->TcpHeader.Offset);
+
+        if (Packet->OffloadOptions.OffloadIpVersion4TcpChecksum ||
+            Packet->OffloadOptions.OffloadIpVersion6TcpChecksum) {
+            TcpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
+
+            Packet->Flags.TcpChecksumNotValidated = 1;
+        } else if (Transmitter->ValidateChecksums != 0) {
+            USHORT      Embedded;
+            USHORT      Calculated;
+
+            Embedded = TcpHeader->Checksum;
+
+            Calculated = ChecksumPseudoHeader(StartVa, Info);
+            Calculated = ChecksumTcpPacket(StartVa, Info, Calculated, Payload);
+
+            if (ChecksumVerify(Calculated, Embedded))
+                Packet->Flags.TcpChecksumSucceeded = 1;
+            else
+                Packet->Flags.TcpChecksumFailed = 1;
+        } else {
+            Packet->Flags.TcpChecksumNotValidated = 1;
+        }
+    }
+
+    if (Info->UdpHeader.Length != 0) {
+        PUDP_HEADER UdpHeader;
+
+        UdpHeader = (PUDP_HEADER)(StartVa + Info->UdpHeader.Offset);
+
+        if (Packet->OffloadOptions.OffloadIpVersion4UdpChecksum ||
+            Packet->OffloadOptions.OffloadIpVersion6UdpChecksum) {
+            UdpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
+
+            Packet->Flags.UdpChecksumNotValidated = 1;
+        } else if (Transmitter->ValidateChecksums != 0) {
+            PIP_HEADER  IpHeader;
+            USHORT      Embedded;
+
+            ASSERT(Info->IpHeader.Length != 0);
+            IpHeader = (PIP_HEADER)(StartVa + Info->IpHeader.Offset);
+
+            Embedded = UdpHeader->Checksum;
+
+            // Tolarate zero checksum for IPv4/UDP
+            if (IpHeader->Version == 4 && Embedded == 0) {
+                Packet->Flags.UdpChecksumSucceeded = 1;
+            } else {
+                USHORT  Calculated;
+
+                Calculated = ChecksumPseudoHeader(StartVa, Info);
+                Calculated = ChecksumUdpPacket(StartVa, Info, Calculated, Payload);
+
+                if (ChecksumVerify(Calculated, Embedded))
+                    Packet->Flags.UdpChecksumSucceeded = 1;
+                else
+                    Packet->Flags.UdpChecksumFailed = 1;
+            }
+        } else {
+            Packet->Flags.UdpChecksumNotValidated = 1;
+        }
     }
 
     return STATUS_SUCCESS;
 
 fail5:
-    Error("fail5\n");
+    if (!SquashError)
+        Error("fail5\n");
 
     ASSERT(State->Count != 0);
     --State->Count;
@@ -1398,7 +1489,8 @@ fail5:
     Fragment->Entry = NULL;
 
 fail4:
-    Error("fail4\n");
+    if (!SquashError)
+        Error("fail4\n");
 
     Fragment->Context = NULL;
     Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID;
@@ -1409,7 +1501,8 @@ fail4:
     __TransmitterPutFragment(Ring, Fragment);
 
 fail3:
-    Error("fail3\n");
+    if (!SquashError)
+        Error("fail3\n");
 
     --Packet->Reference;
     Buffer->Context = NULL;
@@ -1417,12 +1510,14 @@ fail3:
     __TransmitterPutBuffer(Ring, Buffer);
 
 fail2:
-    Error("fail2\n");
+    if (!SquashError)
+        Error("fail2\n");
 
     ASSERT3U(Packet->Reference, ==, 0);
 
 fail1:
-    Error("fail1 (%08x)\n", status);
+    if (!SquashError)
+        Error("fail1 (%08x)\n", status);
 
     return status;
 }
@@ -1647,13 +1742,9 @@ __TransmitterRingPreparePacket(
     return STATUS_SUCCESS;
 
 fail2:
-    Error("fail2\n");
-
     __TransmitterRingUnprepareFragments(Ring);
 
 fail1:
-    Error("fail1 (%08x)\n", status);
-
     ASSERT(IsListEmpty(&State->List));
     RtlZeroMemory(&State->List, sizeof (LIST_ENTRY));
 
@@ -2265,26 +2356,7 @@ __TransmitterRingPostFragments(
     ASSERT3U(State->Count, ==, 0);
     RtlZeroMemory(&State->List, sizeof (LIST_ENTRY));
 
-    // Set the initial completion information
     if (Packet != NULL) {
-        PUCHAR                  StartVa;
-        PXENVIF_PACKET_INFO     Info;
-        PXENVIF_PACKET_PAYLOAD  Payload;
-        PETHERNET_HEADER        Header;
-
-        StartVa = Packet->Header;
-        Info = &Packet->Info;
-        Payload = &Packet->Payload;
-
-        ASSERT(IsZeroMemory(&Packet->Completion, sizeof (XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO)));
-
-        ASSERT(Info->EthernetHeader.Length != 0);
-        Header = (PETHERNET_HEADER)(StartVa + Info->EthernetHeader.Offset);
-
-        Packet->Completion.Type = GET_ETHERNET_ADDRESS_TYPE(&Header->Untagged.DestinationAddress);
-        Packet->Completion.PacketLength = (USHORT)Packet->Length;
-        Packet->Completion.PayloadLength = (USHORT)Payload->Length;
-
         State->Packet = NULL;
 
         Ring->PacketsSent++;
@@ -2374,8 +2446,14 @@ __TransmitterRingCompletePacket(
     IN  PXENVIF_TRANSMITTER_PACKET  Packet
     )
 {
-    PXENVIF_TRANSMITTER                 Transmitter;
-    PXENVIF_FRONTEND                    Frontend;
+    PXENVIF_TRANSMITTER             Transmitter;
+    PXENVIF_FRONTEND                Frontend;
+    PXENVIF_PACKET_PAYLOAD          Payload;
+    PXENVIF_PACKET_INFO             Info;
+    PUCHAR                          StartVa;
+    PETHERNET_HEADER                EthernetHeader;
+    PETHERNET_ADDRESS               DestinationAddress;
+    ETHERNET_ADDRESS_TYPE           Type;
 
     Transmitter = Ring->Transmitter;
     Frontend = Transmitter->Frontend;
@@ -2391,45 +2469,145 @@ __TransmitterRingCompletePacket(
             FrontendIncrementStatistic(Frontend,
                                        XENVIF_TRANSMITTER_BACKEND_ERRORS,
                                        1);
-    } else {
-        ULONG   Length;
 
-        Length = (ULONG)Packet->Completion.PacketLength;
+        goto done;
+    }
 
-        switch (Packet->Completion.Type) {
-        case ETHERNET_ADDRESS_UNICAST:
-            FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_UNICAST_PACKETS,
-                                       1);
-            FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_UNICAST_OCTETS,
-                                       Length);
-            break;
-            
-        case ETHERNET_ADDRESS_MULTICAST:
+    StartVa = Packet->Header;
+    Info = &Packet->Info;
+    Payload = &Packet->Payload;
+
+    ASSERT(Info->EthernetHeader.Length != 0);
+    EthernetHeader = (PETHERNET_HEADER)(StartVa + Info->EthernetHeader.Offset);
+
+    DestinationAddress = &EthernetHeader->DestinationAddress;
+
+    Type = GET_ETHERNET_ADDRESS_TYPE(DestinationAddress);
+
+    switch (Type) {
+    case ETHERNET_ADDRESS_UNICAST:
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_UNICAST_PACKETS,
+                                   1);
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_UNICAST_OCTETS,
+                                   Packet->Length);
+        break;
+
+    case ETHERNET_ADDRESS_MULTICAST:
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_MULTICAST_PACKETS,
+                                   1);
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_MULTICAST_OCTETS,
+                                   Packet->Length);
+        break;
+
+    case ETHERNET_ADDRESS_BROADCAST:
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_BROADCAST_PACKETS,
+                                   1);
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_BROADCAST_OCTETS,
+                                   Packet->Length);
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
+    if (ETHERNET_HEADER_IS_TAGGED(EthernetHeader))
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_TAGGED_PACKETS,
+                                   1);
+
+    if (Info->LLCSnapHeader.Length != 0)
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_LLC_SNAP_PACKETS,
+                                   1);
+
+    if (Info->IpHeader.Length != 0) {
+        PIP_HEADER  IpHeader = (PIP_HEADER)(StartVa + Info->IpHeader.Offset);
+
+        if (IpHeader->Version == 4) {
             FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_MULTICAST_PACKETS,
+                                       XENVIF_TRANSMITTER_IPV4_PACKETS,
                                        1);
-            FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_MULTICAST_OCTETS,
-                                       Length);
-            break;
+        } else {
+            ASSERT3U(IpHeader->Version, ==, 6);
 
-        case ETHERNET_ADDRESS_BROADCAST:
             FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_BROADCAST_PACKETS,
+                                       XENVIF_TRANSMITTER_IPV6_PACKETS,
                                        1);
-            FrontendIncrementStatistic(Frontend,
-                                       XENVIF_TRANSMITTER_BROADCAST_OCTETS,
-                                       Length);
-            break;
-
-        default:
-            ASSERT(FALSE);
-            break;
         }
     }
 
+    if (Info->TcpHeader.Length != 0)
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_TCP_PACKETS,
+                                   1);
+
+    if (Info->UdpHeader.Length != 0)
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_UDP_PACKETS,
+                                   1);
+
+    if (Packet->MaximumSegmentSize != 0)
+        FrontendIncrementStatistic(Frontend,
+                                   XENVIF_TRANSMITTER_GSO_PACKETS,
+                                   1);
+
+   if (Packet->Flags.IpChecksumSucceeded != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_IPV4_CHECKSUM_SUCCEEDED,
+                                  1);
+
+   if (Packet->Flags.IpChecksumFailed != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_IPV4_CHECKSUM_FAILED,
+                                  1);
+
+   if (Packet->Flags.IpChecksumNotValidated != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_IPV4_CHECKSUM_NOT_VALIDATED,
+                                  1);
+
+   if (Packet->Flags.TcpChecksumSucceeded != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_TCP_CHECKSUM_SUCCEEDED,
+                                  1);
+
+   if (Packet->Flags.TcpChecksumFailed != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_TCP_CHECKSUM_FAILED,
+                                  1);
+
+   if (Packet->Flags.TcpChecksumNotValidated != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_TCP_CHECKSUM_NOT_VALIDATED,
+                                  1);
+
+   if (Packet->Flags.UdpChecksumSucceeded != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_UDP_CHECKSUM_SUCCEEDED,
+                                  1);
+
+   if (Packet->Flags.UdpChecksumFailed != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_UDP_CHECKSUM_FAILED,
+                                  1);
+
+   if (Packet->Flags.UdpChecksumNotValidated != 0)
+       FrontendIncrementStatistic(Frontend,
+                                  XENVIF_TRANSMITTER_UDP_CHECKSUM_NOT_VALIDATED,
+                                  1);
+
+    Packet->Completion.Type = Type;
+    Packet->Completion.PacketLength = (USHORT)Packet->Length;
+    Packet->Completion.PayloadLength = (USHORT)Payload->Length;
+
+done:
     InsertTailList(&Ring->PacketComplete, &Packet->ListEntry);
     Ring->PacketsCompleted++;
 }
@@ -2826,6 +3004,8 @@ TransmitterRingSchedule(
 
             Packet->Reference = 0;
 
+            ASSERT3U(Packet->Completion.Status, ==, 0);
+
             status = __TransmitterRingPreparePacket(Ring, Packet);
             if (!NT_SUCCESS(status)) {
                 PXENVIF_TRANSMITTER Transmitter;
@@ -2843,10 +3023,6 @@ TransmitterRingSchedule(
 
                 Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_DROPPED;
 
-                FrontendIncrementStatistic(Frontend,
-                                           XENVIF_TRANSMITTER_FRONTEND_ERRORS,
-                                           1);
-
                 __TransmitterRingCompletePacket(Ring, Packet);
             }
 
@@ -4263,11 +4439,13 @@ TransmitterInitialize(
     (*Transmitter)->DisableIpVersion4Gso = 0;
     (*Transmitter)->DisableIpVersion6Gso = 0;
     (*Transmitter)->AlwaysCopy = 0;
+    (*Transmitter)->ValidateChecksums = 0;
 
     if (ParametersKey != NULL) {
         ULONG   TransmitterDisableIpVersion4Gso;
         ULONG   TransmitterDisableIpVersion6Gso;
         ULONG   TransmitterAlwaysCopy;
+        ULONG   TransmitterValidateChecksums;
 
         status = RegistryQueryDwordValue(ParametersKey,
                                          "TransmitterDisableIpVersion4Gso",
@@ -4286,6 +4464,12 @@ TransmitterInitialize(
                                          &TransmitterAlwaysCopy);
         if (NT_SUCCESS(status))
             (*Transmitter)->AlwaysCopy = TransmitterAlwaysCopy;
+
+        status = RegistryQueryDwordValue(ParametersKey,
+                                         "TransmitterValidateChecksums",
+                                         &TransmitterValidateChecksums);
+        if (NT_SUCCESS(status))
+            (*Transmitter)->ValidateChecksums = TransmitterValidateChecksums;
     }
 
     FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
@@ -4370,6 +4554,7 @@ fail2:
     (*Transmitter)->DisableIpVersion4Gso = 0;
     (*Transmitter)->DisableIpVersion6Gso = 0;
     (*Transmitter)->AlwaysCopy = 0;
+    (*Transmitter)->ValidateChecksums = 0;
     
     ASSERT(IsZeroMemory(*Transmitter, sizeof (XENVIF_TRANSMITTER)));
     __TransmitterFree(*Transmitter);
@@ -4783,6 +4968,7 @@ TransmitterTeardown(
     Transmitter->DisableIpVersion4Gso = 0;
     Transmitter->DisableIpVersion6Gso = 0;
     Transmitter->AlwaysCopy = 0;
+    Transmitter->ValidateChecksums = 0;
 
     ASSERT(IsZeroMemory(Transmitter, sizeof (XENVIF_TRANSMITTER)));
     __TransmitterFree(Transmitter);