aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2020-02-05 11:46:40 -0600
committerDave Wallace <dwallacelf@gmail.com>2020-03-10 14:21:06 +0000
commitcd88ca366c18dbf6761199f1f2f935895497d82f (patch)
tree59452bd079521359c4e8c7e33cee387e1a48b262
parent24064d02aa9810ebc64c16dc778a179bb0ef5483 (diff)
ip6: fix l4 checksum with hop-by-hop header
L4 checksums for IPv6 should be calculated using a pseudo header that includes the source/destination addresses, payload length, and payload protocol. ip6_tcp_udp_icmp_compute_checksum() was using the payload length and protocol from the IPv6 header. If there is a hop-by-hop header (or any other extension header), the payload length used for the pseudo header should only include the upper layer header and payload and not the extension header bytes. Same deal with the protocol, the upper layer next header value should be used instead of the extension header. Type: fix Fixes: cb9cadad57 Change-Id: Ifa2c9ad41c0fc4eea674f0671255b637c8e01f71 Signed-off-by: Matthew Smith <mgsmith@netgate.com> (cherry picked from commit 97677a26f7c857e7ee0acbdb2c13eef214aa70a8)
-rw-r--r--src/vnet/ip/ip6_forward.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index 69ae86d5b2c..f7f7b780fc8 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -1021,31 +1021,23 @@ u16
ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
ip6_header_t * ip0, int *bogus_lengthp)
{
- ip_csum_t sum0;
- u16 payload_length_host_byte_order;
+ ip_csum_t sum0 = 0;
+ u16 payload_length, payload_length_host_byte_order;
u32 i;
u32 headers_size = sizeof (ip0[0]);
u8 *data_this_buffer;
+ u8 next_hdr = ip0->protocol;
ASSERT (bogus_lengthp);
*bogus_lengthp = 0;
- /* Initialize checksum with ip header. */
- sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
data_this_buffer = (u8 *) (ip0 + 1);
-
- for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
- {
- sum0 = ip_csum_with_carry
- (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
- sum0 = ip_csum_with_carry
- (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
- }
+ payload_length = ip0->payload_length;
/* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
* or UDP-Ping packets */
- if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
+ if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
{
u32 skip_bytes;
ip6_hop_by_hop_ext_t *ext_hdr =
@@ -1060,6 +1052,24 @@ ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
payload_length_host_byte_order -= skip_bytes;
headers_size += skip_bytes;
+
+ /* pseudo-header adjustments:
+ * exclude ext header bytes from payload length
+ * use payload IP proto rather than ext header IP proto
+ */
+ payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
+ next_hdr = ext_hdr->next_hdr;
+ }
+
+ /* Initialize checksum with ip pseudo-header. */
+ sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
+
+ for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
+ {
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
}
if (p0)