The ESP and AH cases in get_ipv6_ext_hdrs() used IPPROTO_FRAGMENT instead of OFPIEH12_FRAG when checking for out-of-order extension headers, causing the fragment header to not be recognised as a valid predecessor. The original code used IPPROTO_FRAGMENT (44) as a bitmask constant where OFPIEH12_FRAG (1 << 4 = 16) was intended. IPPROTO_FRAGMENT encodes bits 2, 3 and 5 (OFPIEH12_AUTH | OFPIEH12_DEST | OFPIEH12_ROUTER), but not bit 4 (OFPIEH12_FRAG). This caused incorrect OFPIEH12_UNSEQ verdicts in both the ESP and AH arms: the ESP arm failed to whitelist OFPIEH12_FRAG, while the AH arm accidentally whitelisted OFPIEH12_AUTH. With the fix, a packet with two AH headers now also gets OFPIEH12_UNSEQ in addition to OFPIEH12_UNREP, matching the ESP arm which already sets UNSEQ on a repeat, which is the intended behavior. Fixes: 28a3f0601727 ("net: openvswitch: IPv6: Add IPv6 extension header support") Reported-by: Paolo Abeni Reviewed-by: Aaron Conole Reviewed-by: Ilya Maximets Signed-off-by: Eelco Chaudron --- v2 changes: - Updated commit message as requested by Sashiko. --- net/openvswitch/flow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 46c1d66aad8c..868d9fdf3afd 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -288,7 +288,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh, if (*ext_hdrs & OFPIEH12_ESP) *ext_hdrs |= OFPIEH12_UNREP; if ((*ext_hdrs & ~(OFPIEH12_HOP | OFPIEH12_DEST | - OFPIEH12_ROUTER | IPPROTO_FRAGMENT | + OFPIEH12_ROUTER | OFPIEH12_FRAG | OFPIEH12_AUTH | OFPIEH12_UNREP)) || dest_options_header_count >= 2) { *ext_hdrs |= OFPIEH12_UNSEQ; @@ -301,7 +301,7 @@ static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh, *ext_hdrs |= OFPIEH12_UNREP; if ((*ext_hdrs & ~(OFPIEH12_HOP | OFPIEH12_DEST | OFPIEH12_ROUTER | - IPPROTO_FRAGMENT | OFPIEH12_UNREP)) || + OFPIEH12_FRAG | OFPIEH12_UNREP)) || dest_options_header_count >= 2) { *ext_hdrs |= OFPIEH12_UNSEQ; } -- 2.54.0