packets: Fix UDP over IPv6 checksum
authorThadeu Lima de Souza Cascardo <cascardo@redhat.com>
Thu, 4 Feb 2016 16:14:30 +0000 (14:14 -0200)
committerThadeu Lima de Souza Cascardo <cascardo@redhat.com>
Thu, 10 Mar 2016 17:03:57 +0000 (14:03 -0300)
Fix the IPv6 pseudoheader checksum. Requires that the payload length is given to
the function.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
lib/netdev-vport.c
lib/packets.c
lib/packets.h

index df6d8cf..1cc30f5 100644 (file)
@@ -1009,15 +1009,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
 
     if (udp->udp_csum) {
         uint32_t csum;
+        size_t udp_len;
+        udp_len = dp_packet_size(packet) -
+                 ((const unsigned char *) udp -
+                   (const unsigned char *) dp_packet_l2(packet));
         if (is_header_ipv6(dp_packet_data(packet))) {
-            csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
+            csum = packet_csum_pseudoheader6(dp_packet_l3(packet),
+                                             htonl(udp_len));
         } else {
             csum = packet_csum_pseudoheader(dp_packet_l3(packet));
         }
 
-        csum = csum_continue(csum, udp, dp_packet_size(packet) -
-                             ((const unsigned char *)udp -
-                              (const unsigned char *)dp_packet_l2(packet)));
+        csum = csum_continue(csum, udp, udp_len);
         if (csum_finish(csum)) {
             return NULL;
         }
@@ -1057,7 +1060,8 @@ push_udp_header(struct dp_packet *packet,
     if (udp->udp_csum) {
         uint32_t csum;
         if (is_header_ipv6(dp_packet_data(packet))) {
-            csum = packet_csum_pseudoheader6(ipv6_hdr(dp_packet_data(packet)));
+            csum = packet_csum_pseudoheader6(ipv6_hdr(dp_packet_data(packet)),
+                                             htonl(ip_tot_size));
         } else {
             csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
         }
index daca1b3..b5d141a 100644 (file)
@@ -1334,7 +1334,8 @@ packet_csum_pseudoheader(const struct ip_header *ip)
 
 #ifndef __CHECKER__
 uint32_t
-packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6)
+packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6,
+                          ovs_be32 plen)
 {
     uint32_t partial = 0;
 
@@ -1347,10 +1348,9 @@ packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *ip6)
     partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[2])));
     partial = csum_add32(partial, get_16aligned_be32(&(ip6->ip6_dst.be32[3])));
 
+    partial = csum_add32(partial, plen);
     partial = csum_add16(partial, 0);
-    partial = csum_add16(partial, ip6->ip6_plen);
-    partial = csum_add16(partial, 0);
-    partial = csum_add16(partial, ip6->ip6_nxt);
+    partial = csum_add16(partial, htons(ip6->ip6_nxt));
 
     return partial;
 }
index bf12937..d2a9b51 100644 (file)
@@ -843,7 +843,7 @@ struct icmp6_header {
 };
 BUILD_ASSERT_DECL(ICMP6_HEADER_LEN == sizeof(struct icmp6_header));
 
-uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *);
+uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *, ovs_be32);
 
 /* Neighbor Discovery option field.
  * ND options are always a multiple of 8 bytes in size. */