1*70a00e2fSMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
2*70a00e2fSMartin KaFai Lau /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3*70a00e2fSMartin KaFai Lau 
4*70a00e2fSMartin KaFai Lau #include "vmlinux.h"
5*70a00e2fSMartin KaFai Lau #include "bpf_tracing_net.h"
6*70a00e2fSMartin KaFai Lau #include <bpf/bpf_helpers.h>
7*70a00e2fSMartin KaFai Lau #include <bpf/bpf_endian.h>
8*70a00e2fSMartin KaFai Lau 
9*70a00e2fSMartin KaFai Lau #define UDP_TEST_PORT 7777
10*70a00e2fSMartin KaFai Lau 
11*70a00e2fSMartin KaFai Lau void *bpf_cast_to_kern_ctx(void *) __ksym;
12*70a00e2fSMartin KaFai Lau bool init_csum_partial = false;
13*70a00e2fSMartin KaFai Lau bool final_csum_none = false;
14*70a00e2fSMartin KaFai Lau bool broken_csum_start = false;
15*70a00e2fSMartin KaFai Lau 
skb_headlen(const struct sk_buff * skb)16*70a00e2fSMartin KaFai Lau static unsigned int skb_headlen(const struct sk_buff *skb)
17*70a00e2fSMartin KaFai Lau {
18*70a00e2fSMartin KaFai Lau 	return skb->len - skb->data_len;
19*70a00e2fSMartin KaFai Lau }
20*70a00e2fSMartin KaFai Lau 
skb_headroom(const struct sk_buff * skb)21*70a00e2fSMartin KaFai Lau static unsigned int skb_headroom(const struct sk_buff *skb)
22*70a00e2fSMartin KaFai Lau {
23*70a00e2fSMartin KaFai Lau 	return skb->data - skb->head;
24*70a00e2fSMartin KaFai Lau }
25*70a00e2fSMartin KaFai Lau 
skb_checksum_start_offset(const struct sk_buff * skb)26*70a00e2fSMartin KaFai Lau static int skb_checksum_start_offset(const struct sk_buff *skb)
27*70a00e2fSMartin KaFai Lau {
28*70a00e2fSMartin KaFai Lau 	return skb->csum_start - skb_headroom(skb);
29*70a00e2fSMartin KaFai Lau }
30*70a00e2fSMartin KaFai Lau 
31*70a00e2fSMartin KaFai Lau SEC("tc")
decap_sanity(struct __sk_buff * skb)32*70a00e2fSMartin KaFai Lau int decap_sanity(struct __sk_buff *skb)
33*70a00e2fSMartin KaFai Lau {
34*70a00e2fSMartin KaFai Lau 	struct sk_buff *kskb;
35*70a00e2fSMartin KaFai Lau 	struct ipv6hdr ip6h;
36*70a00e2fSMartin KaFai Lau 	struct udphdr udph;
37*70a00e2fSMartin KaFai Lau 	int err;
38*70a00e2fSMartin KaFai Lau 
39*70a00e2fSMartin KaFai Lau 	if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6))
40*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
41*70a00e2fSMartin KaFai Lau 
42*70a00e2fSMartin KaFai Lau 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip6h, sizeof(ip6h)))
43*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
44*70a00e2fSMartin KaFai Lau 
45*70a00e2fSMartin KaFai Lau 	if (ip6h.nexthdr != IPPROTO_UDP)
46*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
47*70a00e2fSMartin KaFai Lau 
48*70a00e2fSMartin KaFai Lau 	if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(ip6h), &udph, sizeof(udph)))
49*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
50*70a00e2fSMartin KaFai Lau 
51*70a00e2fSMartin KaFai Lau 	if (udph.dest != __bpf_constant_htons(UDP_TEST_PORT))
52*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
53*70a00e2fSMartin KaFai Lau 
54*70a00e2fSMartin KaFai Lau 	kskb = bpf_cast_to_kern_ctx(skb);
55*70a00e2fSMartin KaFai Lau 	init_csum_partial = (kskb->ip_summed == CHECKSUM_PARTIAL);
56*70a00e2fSMartin KaFai Lau 	err = bpf_skb_adjust_room(skb, -(s32)(ETH_HLEN + sizeof(ip6h) + sizeof(udph)),
57*70a00e2fSMartin KaFai Lau 				  1, BPF_F_ADJ_ROOM_FIXED_GSO);
58*70a00e2fSMartin KaFai Lau 	if (err)
59*70a00e2fSMartin KaFai Lau 		return TC_ACT_SHOT;
60*70a00e2fSMartin KaFai Lau 	final_csum_none = (kskb->ip_summed == CHECKSUM_NONE);
61*70a00e2fSMartin KaFai Lau 	if (kskb->ip_summed == CHECKSUM_PARTIAL &&
62*70a00e2fSMartin KaFai Lau 	    (unsigned int)skb_checksum_start_offset(kskb) >= skb_headlen(kskb))
63*70a00e2fSMartin KaFai Lau 		broken_csum_start = true;
64*70a00e2fSMartin KaFai Lau 
65*70a00e2fSMartin KaFai Lau 	return TC_ACT_SHOT;
66*70a00e2fSMartin KaFai Lau }
67*70a00e2fSMartin KaFai Lau 
68*70a00e2fSMartin KaFai Lau char __license[] SEC("license") = "GPL";
69