__ip6_tnl_rcv() mirrors its IPv4 counterpart: five distinct failures share a single plain kfree_skb(). Reuse the drop reasons introduced for ip_tunnel_rcv() and the ones the length helpers already return.
Note that skb_vlan_inet_prepare() returns an enum skb_drop_reason that was simply discarded, and that pskb_may_pull_reason() has been available all along. __ip6_tnl_rcv() is reached through ip6_tnl_rcv() from both ip6_tunnel (ip4ip6, ip6ip6) and ip6_gre (ip6gre, ip6gretap, erspan). As on the IPv4 side, only ip6_gre sets the checksum and sequence number bits, so the option mismatch and the old sequence reasons are reachable through it alone. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Anton Danilov <[email protected]> --- net/ipv6/ip6_tunnel.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d5ff50a2ac01..85578fa125bc 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -814,21 +814,29 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, bool log_ecn_err) { const struct ipv6hdr *ipv6h; + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; int nh, err; if (test_bit(IP_TUNNEL_CSUM_BIT, tunnel->parms.i_flags) != test_bit(IP_TUNNEL_CSUM_BIT, tpi->flags)) { DEV_STATS_INC(tunnel->dev, rx_crc_errors); DEV_STATS_INC(tunnel->dev, rx_errors); + reason = SKB_DROP_REASON_IP_TUNNEL_CFG_OPTS_MISMATCH; goto drop; } if (test_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.i_flags)) { - if (!test_bit(IP_TUNNEL_SEQ_BIT, tpi->flags) || - (tunnel->i_seqno && - (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) { + if (!test_bit(IP_TUNNEL_SEQ_BIT, tpi->flags)) { DEV_STATS_INC(tunnel->dev, rx_fifo_errors); DEV_STATS_INC(tunnel->dev, rx_errors); + reason = SKB_DROP_REASON_IP_TUNNEL_CFG_OPTS_MISMATCH; + goto drop; + } + if (tunnel->i_seqno && + (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0) { + DEV_STATS_INC(tunnel->dev, rx_fifo_errors); + DEV_STATS_INC(tunnel->dev, rx_errors); + reason = SKB_DROP_REASON_IP_TUNNEL_OLD_SEQ; goto drop; } tunnel->i_seqno = ntohl(tpi->seq) + 1; @@ -838,7 +846,8 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, /* Warning: All skb pointers will be invalidated! */ if (tunnel->dev->type == ARPHRD_ETHER) { - if (!pskb_may_pull(skb, ETH_HLEN)) { + reason = pskb_may_pull_reason(skb, ETH_HLEN); + if (reason) { DEV_STATS_INC(tunnel->dev, rx_length_errors); DEV_STATS_INC(tunnel->dev, rx_errors); goto drop; @@ -859,7 +868,8 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, skb_reset_network_header(skb); - if (skb_vlan_inet_prepare(skb, true)) { + reason = skb_vlan_inet_prepare(skb, true); + if (reason) { DEV_STATS_INC(tunnel->dev, rx_length_errors); DEV_STATS_INC(tunnel->dev, rx_errors); goto drop; @@ -881,6 +891,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, if (err > 1) { DEV_STATS_INC(tunnel->dev, rx_frame_errors); DEV_STATS_INC(tunnel->dev, rx_errors); + reason = SKB_DROP_REASON_IP_TUNNEL_ECN; goto drop; } } @@ -898,7 +909,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, drop: if (tun_dst) dst_release((struct dst_entry *)tun_dst); - kfree_skb(skb); + kfree_skb_reason(skb, reason); return 0; } -- 2.47.3

