1ad2f8eb0SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
2ad2f8eb0SMartin KaFai Lau /* Copyright (c) 2020 Facebook */
3ad2f8eb0SMartin KaFai Lau 
4ad2f8eb0SMartin KaFai Lau #include <stddef.h>
5ad2f8eb0SMartin KaFai Lau #include <errno.h>
6ad2f8eb0SMartin KaFai Lau #include <stdbool.h>
7ad2f8eb0SMartin KaFai Lau #include <sys/types.h>
8ad2f8eb0SMartin KaFai Lau #include <sys/socket.h>
9ad2f8eb0SMartin KaFai Lau #include <linux/tcp.h>
10ad2f8eb0SMartin KaFai Lau #include <linux/socket.h>
11ad2f8eb0SMartin KaFai Lau #include <linux/bpf.h>
12ad2f8eb0SMartin KaFai Lau #include <linux/types.h>
13ad2f8eb0SMartin KaFai Lau #include <bpf/bpf_helpers.h>
14ad2f8eb0SMartin KaFai Lau #include <bpf/bpf_endian.h>
15ad2f8eb0SMartin KaFai Lau #define BPF_PROG_TEST_TCP_HDR_OPTIONS
16ad2f8eb0SMartin KaFai Lau #include "test_tcp_hdr_options.h"
17ad2f8eb0SMartin KaFai Lau 
18ad2f8eb0SMartin KaFai Lau #ifndef sizeof_field
19ad2f8eb0SMartin KaFai Lau #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
20ad2f8eb0SMartin KaFai Lau #endif
21ad2f8eb0SMartin KaFai Lau 
22ad2f8eb0SMartin KaFai Lau __u8 test_kind = TCPOPT_EXP;
23ad2f8eb0SMartin KaFai Lau __u16 test_magic = 0xeB9F;
2496d46c50SMartin KaFai Lau __u32 inherit_cb_flags = 0;
25ad2f8eb0SMartin KaFai Lau 
26ad2f8eb0SMartin KaFai Lau struct bpf_test_option passive_synack_out = {};
27ad2f8eb0SMartin KaFai Lau struct bpf_test_option passive_fin_out	= {};
28ad2f8eb0SMartin KaFai Lau 
29ad2f8eb0SMartin KaFai Lau struct bpf_test_option passive_estab_in = {};
30ad2f8eb0SMartin KaFai Lau struct bpf_test_option passive_fin_in	= {};
31ad2f8eb0SMartin KaFai Lau 
32ad2f8eb0SMartin KaFai Lau struct bpf_test_option active_syn_out	= {};
33ad2f8eb0SMartin KaFai Lau struct bpf_test_option active_fin_out	= {};
34ad2f8eb0SMartin KaFai Lau 
35ad2f8eb0SMartin KaFai Lau struct bpf_test_option active_estab_in	= {};
36ad2f8eb0SMartin KaFai Lau struct bpf_test_option active_fin_in	= {};
37ad2f8eb0SMartin KaFai Lau 
38ad2f8eb0SMartin KaFai Lau struct {
39ad2f8eb0SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_SK_STORAGE);
40ad2f8eb0SMartin KaFai Lau 	__uint(map_flags, BPF_F_NO_PREALLOC);
41ad2f8eb0SMartin KaFai Lau 	__type(key, int);
42ad2f8eb0SMartin KaFai Lau 	__type(value, struct hdr_stg);
43ad2f8eb0SMartin KaFai Lau } hdr_stg_map SEC(".maps");
44ad2f8eb0SMartin KaFai Lau 
skops_want_cookie(const struct bpf_sock_ops * skops)45ad2f8eb0SMartin KaFai Lau static bool skops_want_cookie(const struct bpf_sock_ops *skops)
46ad2f8eb0SMartin KaFai Lau {
47ad2f8eb0SMartin KaFai Lau 	return skops->args[0] == BPF_WRITE_HDR_TCP_SYNACK_COOKIE;
48ad2f8eb0SMartin KaFai Lau }
49ad2f8eb0SMartin KaFai Lau 
skops_current_mss(const struct bpf_sock_ops * skops)50ad2f8eb0SMartin KaFai Lau static bool skops_current_mss(const struct bpf_sock_ops *skops)
51ad2f8eb0SMartin KaFai Lau {
52ad2f8eb0SMartin KaFai Lau 	return skops->args[0] == BPF_WRITE_HDR_TCP_CURRENT_MSS;
53ad2f8eb0SMartin KaFai Lau }
54ad2f8eb0SMartin KaFai Lau 
option_total_len(__u8 flags)55ad2f8eb0SMartin KaFai Lau static __u8 option_total_len(__u8 flags)
56ad2f8eb0SMartin KaFai Lau {
57ad2f8eb0SMartin KaFai Lau 	__u8 i, len = 1; /* +1 for flags */
58ad2f8eb0SMartin KaFai Lau 
59ad2f8eb0SMartin KaFai Lau 	if (!flags)
60ad2f8eb0SMartin KaFai Lau 		return 0;
61ad2f8eb0SMartin KaFai Lau 
62ad2f8eb0SMartin KaFai Lau 	/* RESEND bit does not use a byte */
63ad2f8eb0SMartin KaFai Lau 	for (i = OPTION_RESEND + 1; i < __NR_OPTION_FLAGS; i++)
64ad2f8eb0SMartin KaFai Lau 		len += !!TEST_OPTION_FLAGS(flags, i);
65ad2f8eb0SMartin KaFai Lau 
66ad2f8eb0SMartin KaFai Lau 	if (test_kind == TCPOPT_EXP)
67ad2f8eb0SMartin KaFai Lau 		return len + TCP_BPF_EXPOPT_BASE_LEN;
68ad2f8eb0SMartin KaFai Lau 	else
69ad2f8eb0SMartin KaFai Lau 		return len + 2; /* +1 kind, +1 kind-len */
70ad2f8eb0SMartin KaFai Lau }
71ad2f8eb0SMartin KaFai Lau 
write_test_option(const struct bpf_test_option * test_opt,__u8 * data)72ad2f8eb0SMartin KaFai Lau static void write_test_option(const struct bpf_test_option *test_opt,
73ad2f8eb0SMartin KaFai Lau 			      __u8 *data)
74ad2f8eb0SMartin KaFai Lau {
75ad2f8eb0SMartin KaFai Lau 	__u8 offset = 0;
76ad2f8eb0SMartin KaFai Lau 
77ad2f8eb0SMartin KaFai Lau 	data[offset++] = test_opt->flags;
78ad2f8eb0SMartin KaFai Lau 	if (TEST_OPTION_FLAGS(test_opt->flags, OPTION_MAX_DELACK_MS))
79ad2f8eb0SMartin KaFai Lau 		data[offset++] = test_opt->max_delack_ms;
80ad2f8eb0SMartin KaFai Lau 
81ad2f8eb0SMartin KaFai Lau 	if (TEST_OPTION_FLAGS(test_opt->flags, OPTION_RAND))
82ad2f8eb0SMartin KaFai Lau 		data[offset++] = test_opt->rand;
83ad2f8eb0SMartin KaFai Lau }
84ad2f8eb0SMartin KaFai Lau 
store_option(struct bpf_sock_ops * skops,const struct bpf_test_option * test_opt)85ad2f8eb0SMartin KaFai Lau static int store_option(struct bpf_sock_ops *skops,
86ad2f8eb0SMartin KaFai Lau 			const struct bpf_test_option *test_opt)
87ad2f8eb0SMartin KaFai Lau {
88ad2f8eb0SMartin KaFai Lau 	union {
89ad2f8eb0SMartin KaFai Lau 		struct tcp_exprm_opt exprm;
90ad2f8eb0SMartin KaFai Lau 		struct tcp_opt regular;
91ad2f8eb0SMartin KaFai Lau 	} write_opt;
92ad2f8eb0SMartin KaFai Lau 	int err;
93ad2f8eb0SMartin KaFai Lau 
94ad2f8eb0SMartin KaFai Lau 	if (test_kind == TCPOPT_EXP) {
95ad2f8eb0SMartin KaFai Lau 		write_opt.exprm.kind = TCPOPT_EXP;
96ad2f8eb0SMartin KaFai Lau 		write_opt.exprm.len = option_total_len(test_opt->flags);
97ad2f8eb0SMartin KaFai Lau 		write_opt.exprm.magic = __bpf_htons(test_magic);
98ad2f8eb0SMartin KaFai Lau 		write_opt.exprm.data32 = 0;
99ad2f8eb0SMartin KaFai Lau 		write_test_option(test_opt, write_opt.exprm.data);
100ad2f8eb0SMartin KaFai Lau 		err = bpf_store_hdr_opt(skops, &write_opt.exprm,
101ad2f8eb0SMartin KaFai Lau 					sizeof(write_opt.exprm), 0);
102ad2f8eb0SMartin KaFai Lau 	} else {
103ad2f8eb0SMartin KaFai Lau 		write_opt.regular.kind = test_kind;
104ad2f8eb0SMartin KaFai Lau 		write_opt.regular.len = option_total_len(test_opt->flags);
105ad2f8eb0SMartin KaFai Lau 		write_opt.regular.data32 = 0;
106ad2f8eb0SMartin KaFai Lau 		write_test_option(test_opt, write_opt.regular.data);
107ad2f8eb0SMartin KaFai Lau 		err = bpf_store_hdr_opt(skops, &write_opt.regular,
108ad2f8eb0SMartin KaFai Lau 					sizeof(write_opt.regular), 0);
109ad2f8eb0SMartin KaFai Lau 	}
110ad2f8eb0SMartin KaFai Lau 
111ad2f8eb0SMartin KaFai Lau 	if (err)
112ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(err);
113ad2f8eb0SMartin KaFai Lau 
114ad2f8eb0SMartin KaFai Lau 	return CG_OK;
115ad2f8eb0SMartin KaFai Lau }
116ad2f8eb0SMartin KaFai Lau 
parse_test_option(struct bpf_test_option * opt,const __u8 * start)117ad2f8eb0SMartin KaFai Lau static int parse_test_option(struct bpf_test_option *opt, const __u8 *start)
118ad2f8eb0SMartin KaFai Lau {
119ad2f8eb0SMartin KaFai Lau 	opt->flags = *start++;
120ad2f8eb0SMartin KaFai Lau 
121ad2f8eb0SMartin KaFai Lau 	if (TEST_OPTION_FLAGS(opt->flags, OPTION_MAX_DELACK_MS))
122ad2f8eb0SMartin KaFai Lau 		opt->max_delack_ms = *start++;
123ad2f8eb0SMartin KaFai Lau 
124ad2f8eb0SMartin KaFai Lau 	if (TEST_OPTION_FLAGS(opt->flags, OPTION_RAND))
125ad2f8eb0SMartin KaFai Lau 		opt->rand = *start++;
126ad2f8eb0SMartin KaFai Lau 
127ad2f8eb0SMartin KaFai Lau 	return 0;
128ad2f8eb0SMartin KaFai Lau }
129ad2f8eb0SMartin KaFai Lau 
load_option(struct bpf_sock_ops * skops,struct bpf_test_option * test_opt,bool from_syn)130ad2f8eb0SMartin KaFai Lau static int load_option(struct bpf_sock_ops *skops,
131ad2f8eb0SMartin KaFai Lau 		       struct bpf_test_option *test_opt, bool from_syn)
132ad2f8eb0SMartin KaFai Lau {
133ad2f8eb0SMartin KaFai Lau 	union {
134ad2f8eb0SMartin KaFai Lau 		struct tcp_exprm_opt exprm;
135ad2f8eb0SMartin KaFai Lau 		struct tcp_opt regular;
136ad2f8eb0SMartin KaFai Lau 	} search_opt;
137ad2f8eb0SMartin KaFai Lau 	int ret, load_flags = from_syn ? BPF_LOAD_HDR_OPT_TCP_SYN : 0;
138ad2f8eb0SMartin KaFai Lau 
139ad2f8eb0SMartin KaFai Lau 	if (test_kind == TCPOPT_EXP) {
140ad2f8eb0SMartin KaFai Lau 		search_opt.exprm.kind = TCPOPT_EXP;
141ad2f8eb0SMartin KaFai Lau 		search_opt.exprm.len = 4;
142ad2f8eb0SMartin KaFai Lau 		search_opt.exprm.magic = __bpf_htons(test_magic);
143ad2f8eb0SMartin KaFai Lau 		search_opt.exprm.data32 = 0;
144ad2f8eb0SMartin KaFai Lau 		ret = bpf_load_hdr_opt(skops, &search_opt.exprm,
145ad2f8eb0SMartin KaFai Lau 				       sizeof(search_opt.exprm), load_flags);
146ad2f8eb0SMartin KaFai Lau 		if (ret < 0)
147ad2f8eb0SMartin KaFai Lau 			return ret;
148ad2f8eb0SMartin KaFai Lau 		return parse_test_option(test_opt, search_opt.exprm.data);
149ad2f8eb0SMartin KaFai Lau 	} else {
150ad2f8eb0SMartin KaFai Lau 		search_opt.regular.kind = test_kind;
151ad2f8eb0SMartin KaFai Lau 		search_opt.regular.len = 0;
152ad2f8eb0SMartin KaFai Lau 		search_opt.regular.data32 = 0;
153ad2f8eb0SMartin KaFai Lau 		ret = bpf_load_hdr_opt(skops, &search_opt.regular,
154ad2f8eb0SMartin KaFai Lau 				       sizeof(search_opt.regular), load_flags);
155ad2f8eb0SMartin KaFai Lau 		if (ret < 0)
156ad2f8eb0SMartin KaFai Lau 			return ret;
157ad2f8eb0SMartin KaFai Lau 		return parse_test_option(test_opt, search_opt.regular.data);
158ad2f8eb0SMartin KaFai Lau 	}
159ad2f8eb0SMartin KaFai Lau }
160ad2f8eb0SMartin KaFai Lau 
synack_opt_len(struct bpf_sock_ops * skops)161ad2f8eb0SMartin KaFai Lau static int synack_opt_len(struct bpf_sock_ops *skops)
162ad2f8eb0SMartin KaFai Lau {
163ad2f8eb0SMartin KaFai Lau 	struct bpf_test_option test_opt = {};
164ad2f8eb0SMartin KaFai Lau 	__u8 optlen;
165ad2f8eb0SMartin KaFai Lau 	int err;
166ad2f8eb0SMartin KaFai Lau 
167ad2f8eb0SMartin KaFai Lau 	if (!passive_synack_out.flags)
168ad2f8eb0SMartin KaFai Lau 		return CG_OK;
169ad2f8eb0SMartin KaFai Lau 
170ad2f8eb0SMartin KaFai Lau 	err = load_option(skops, &test_opt, true);
171ad2f8eb0SMartin KaFai Lau 
172ad2f8eb0SMartin KaFai Lau 	/* bpf_test_option is not found */
173ad2f8eb0SMartin KaFai Lau 	if (err == -ENOMSG)
174ad2f8eb0SMartin KaFai Lau 		return CG_OK;
175ad2f8eb0SMartin KaFai Lau 
176ad2f8eb0SMartin KaFai Lau 	if (err)
177ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(err);
178ad2f8eb0SMartin KaFai Lau 
179ad2f8eb0SMartin KaFai Lau 	optlen = option_total_len(passive_synack_out.flags);
180ad2f8eb0SMartin KaFai Lau 	if (optlen) {
181ad2f8eb0SMartin KaFai Lau 		err = bpf_reserve_hdr_opt(skops, optlen, 0);
182ad2f8eb0SMartin KaFai Lau 		if (err)
183ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
184ad2f8eb0SMartin KaFai Lau 	}
185ad2f8eb0SMartin KaFai Lau 
186ad2f8eb0SMartin KaFai Lau 	return CG_OK;
187ad2f8eb0SMartin KaFai Lau }
188ad2f8eb0SMartin KaFai Lau 
write_synack_opt(struct bpf_sock_ops * skops)189ad2f8eb0SMartin KaFai Lau static int write_synack_opt(struct bpf_sock_ops *skops)
190ad2f8eb0SMartin KaFai Lau {
191ad2f8eb0SMartin KaFai Lau 	struct bpf_test_option opt;
192ad2f8eb0SMartin KaFai Lau 
193ad2f8eb0SMartin KaFai Lau 	if (!passive_synack_out.flags)
194ad2f8eb0SMartin KaFai Lau 		/* We should not even be called since no header
195ad2f8eb0SMartin KaFai Lau 		 * space has been reserved.
196ad2f8eb0SMartin KaFai Lau 		 */
197ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
198ad2f8eb0SMartin KaFai Lau 
199ad2f8eb0SMartin KaFai Lau 	opt = passive_synack_out;
200ad2f8eb0SMartin KaFai Lau 	if (skops_want_cookie(skops))
201ad2f8eb0SMartin KaFai Lau 		SET_OPTION_FLAGS(opt.flags, OPTION_RESEND);
202ad2f8eb0SMartin KaFai Lau 
203ad2f8eb0SMartin KaFai Lau 	return store_option(skops, &opt);
204ad2f8eb0SMartin KaFai Lau }
205ad2f8eb0SMartin KaFai Lau 
syn_opt_len(struct bpf_sock_ops * skops)206ad2f8eb0SMartin KaFai Lau static int syn_opt_len(struct bpf_sock_ops *skops)
207ad2f8eb0SMartin KaFai Lau {
208ad2f8eb0SMartin KaFai Lau 	__u8 optlen;
209ad2f8eb0SMartin KaFai Lau 	int err;
210ad2f8eb0SMartin KaFai Lau 
211ad2f8eb0SMartin KaFai Lau 	if (!active_syn_out.flags)
212ad2f8eb0SMartin KaFai Lau 		return CG_OK;
213ad2f8eb0SMartin KaFai Lau 
214ad2f8eb0SMartin KaFai Lau 	optlen = option_total_len(active_syn_out.flags);
215ad2f8eb0SMartin KaFai Lau 	if (optlen) {
216ad2f8eb0SMartin KaFai Lau 		err = bpf_reserve_hdr_opt(skops, optlen, 0);
217ad2f8eb0SMartin KaFai Lau 		if (err)
218ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
219ad2f8eb0SMartin KaFai Lau 	}
220ad2f8eb0SMartin KaFai Lau 
221ad2f8eb0SMartin KaFai Lau 	return CG_OK;
222ad2f8eb0SMartin KaFai Lau }
223ad2f8eb0SMartin KaFai Lau 
write_syn_opt(struct bpf_sock_ops * skops)224ad2f8eb0SMartin KaFai Lau static int write_syn_opt(struct bpf_sock_ops *skops)
225ad2f8eb0SMartin KaFai Lau {
226ad2f8eb0SMartin KaFai Lau 	if (!active_syn_out.flags)
227ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
228ad2f8eb0SMartin KaFai Lau 
229ad2f8eb0SMartin KaFai Lau 	return store_option(skops, &active_syn_out);
230ad2f8eb0SMartin KaFai Lau }
231ad2f8eb0SMartin KaFai Lau 
fin_opt_len(struct bpf_sock_ops * skops)232ad2f8eb0SMartin KaFai Lau static int fin_opt_len(struct bpf_sock_ops *skops)
233ad2f8eb0SMartin KaFai Lau {
234ad2f8eb0SMartin KaFai Lau 	struct bpf_test_option *opt;
235ad2f8eb0SMartin KaFai Lau 	struct hdr_stg *hdr_stg;
236ad2f8eb0SMartin KaFai Lau 	__u8 optlen;
237ad2f8eb0SMartin KaFai Lau 	int err;
238ad2f8eb0SMartin KaFai Lau 
239ad2f8eb0SMartin KaFai Lau 	if (!skops->sk)
240ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
241ad2f8eb0SMartin KaFai Lau 
242ad2f8eb0SMartin KaFai Lau 	hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0);
243ad2f8eb0SMartin KaFai Lau 	if (!hdr_stg)
244ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
245ad2f8eb0SMartin KaFai Lau 
246ad2f8eb0SMartin KaFai Lau 	if (hdr_stg->active)
247ad2f8eb0SMartin KaFai Lau 		opt = &active_fin_out;
248ad2f8eb0SMartin KaFai Lau 	else
249ad2f8eb0SMartin KaFai Lau 		opt = &passive_fin_out;
250ad2f8eb0SMartin KaFai Lau 
251ad2f8eb0SMartin KaFai Lau 	optlen = option_total_len(opt->flags);
252ad2f8eb0SMartin KaFai Lau 	if (optlen) {
253ad2f8eb0SMartin KaFai Lau 		err = bpf_reserve_hdr_opt(skops, optlen, 0);
254ad2f8eb0SMartin KaFai Lau 		if (err)
255ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
256ad2f8eb0SMartin KaFai Lau 	}
257ad2f8eb0SMartin KaFai Lau 
258ad2f8eb0SMartin KaFai Lau 	return CG_OK;
259ad2f8eb0SMartin KaFai Lau }
260ad2f8eb0SMartin KaFai Lau 
write_fin_opt(struct bpf_sock_ops * skops)261ad2f8eb0SMartin KaFai Lau static int write_fin_opt(struct bpf_sock_ops *skops)
262ad2f8eb0SMartin KaFai Lau {
263ad2f8eb0SMartin KaFai Lau 	struct bpf_test_option *opt;
264ad2f8eb0SMartin KaFai Lau 	struct hdr_stg *hdr_stg;
265ad2f8eb0SMartin KaFai Lau 
266ad2f8eb0SMartin KaFai Lau 	if (!skops->sk)
267ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
268ad2f8eb0SMartin KaFai Lau 
269ad2f8eb0SMartin KaFai Lau 	hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0);
270ad2f8eb0SMartin KaFai Lau 	if (!hdr_stg)
271ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
272ad2f8eb0SMartin KaFai Lau 
273ad2f8eb0SMartin KaFai Lau 	if (hdr_stg->active)
274ad2f8eb0SMartin KaFai Lau 		opt = &active_fin_out;
275ad2f8eb0SMartin KaFai Lau 	else
276ad2f8eb0SMartin KaFai Lau 		opt = &passive_fin_out;
277ad2f8eb0SMartin KaFai Lau 
278ad2f8eb0SMartin KaFai Lau 	if (!opt->flags)
279ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
280ad2f8eb0SMartin KaFai Lau 
281ad2f8eb0SMartin KaFai Lau 	return store_option(skops, opt);
282ad2f8eb0SMartin KaFai Lau }
283ad2f8eb0SMartin KaFai Lau 
resend_in_ack(struct bpf_sock_ops * skops)284ad2f8eb0SMartin KaFai Lau static int resend_in_ack(struct bpf_sock_ops *skops)
285ad2f8eb0SMartin KaFai Lau {
286ad2f8eb0SMartin KaFai Lau 	struct hdr_stg *hdr_stg;
287ad2f8eb0SMartin KaFai Lau 
288ad2f8eb0SMartin KaFai Lau 	if (!skops->sk)
289ad2f8eb0SMartin KaFai Lau 		return -1;
290ad2f8eb0SMartin KaFai Lau 
291ad2f8eb0SMartin KaFai Lau 	hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0);
292ad2f8eb0SMartin KaFai Lau 	if (!hdr_stg)
293ad2f8eb0SMartin KaFai Lau 		return -1;
294ad2f8eb0SMartin KaFai Lau 
295ad2f8eb0SMartin KaFai Lau 	return !!hdr_stg->resend_syn;
296ad2f8eb0SMartin KaFai Lau }
297ad2f8eb0SMartin KaFai Lau 
nodata_opt_len(struct bpf_sock_ops * skops)298ad2f8eb0SMartin KaFai Lau static int nodata_opt_len(struct bpf_sock_ops *skops)
299ad2f8eb0SMartin KaFai Lau {
300ad2f8eb0SMartin KaFai Lau 	int resend;
301ad2f8eb0SMartin KaFai Lau 
302ad2f8eb0SMartin KaFai Lau 	resend = resend_in_ack(skops);
303ad2f8eb0SMartin KaFai Lau 	if (resend < 0)
304ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
305ad2f8eb0SMartin KaFai Lau 
306ad2f8eb0SMartin KaFai Lau 	if (resend)
307ad2f8eb0SMartin KaFai Lau 		return syn_opt_len(skops);
308ad2f8eb0SMartin KaFai Lau 
309ad2f8eb0SMartin KaFai Lau 	return CG_OK;
310ad2f8eb0SMartin KaFai Lau }
311ad2f8eb0SMartin KaFai Lau 
write_nodata_opt(struct bpf_sock_ops * skops)312ad2f8eb0SMartin KaFai Lau static int write_nodata_opt(struct bpf_sock_ops *skops)
313ad2f8eb0SMartin KaFai Lau {
314ad2f8eb0SMartin KaFai Lau 	int resend;
315ad2f8eb0SMartin KaFai Lau 
316ad2f8eb0SMartin KaFai Lau 	resend = resend_in_ack(skops);
317ad2f8eb0SMartin KaFai Lau 	if (resend < 0)
318ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
319ad2f8eb0SMartin KaFai Lau 
320ad2f8eb0SMartin KaFai Lau 	if (resend)
321ad2f8eb0SMartin KaFai Lau 		return write_syn_opt(skops);
322ad2f8eb0SMartin KaFai Lau 
323ad2f8eb0SMartin KaFai Lau 	return CG_OK;
324ad2f8eb0SMartin KaFai Lau }
325ad2f8eb0SMartin KaFai Lau 
data_opt_len(struct bpf_sock_ops * skops)326ad2f8eb0SMartin KaFai Lau static int data_opt_len(struct bpf_sock_ops *skops)
327ad2f8eb0SMartin KaFai Lau {
328ad2f8eb0SMartin KaFai Lau 	/* Same as the nodata version.  Mostly to show
329ad2f8eb0SMartin KaFai Lau 	 * an example usage on skops->skb_len.
330ad2f8eb0SMartin KaFai Lau 	 */
331ad2f8eb0SMartin KaFai Lau 	return nodata_opt_len(skops);
332ad2f8eb0SMartin KaFai Lau }
333ad2f8eb0SMartin KaFai Lau 
write_data_opt(struct bpf_sock_ops * skops)334ad2f8eb0SMartin KaFai Lau static int write_data_opt(struct bpf_sock_ops *skops)
335ad2f8eb0SMartin KaFai Lau {
336ad2f8eb0SMartin KaFai Lau 	return write_nodata_opt(skops);
337ad2f8eb0SMartin KaFai Lau }
338ad2f8eb0SMartin KaFai Lau 
current_mss_opt_len(struct bpf_sock_ops * skops)339ad2f8eb0SMartin KaFai Lau static int current_mss_opt_len(struct bpf_sock_ops *skops)
340ad2f8eb0SMartin KaFai Lau {
341ad2f8eb0SMartin KaFai Lau 	/* Reserve maximum that may be needed */
342ad2f8eb0SMartin KaFai Lau 	int err;
343ad2f8eb0SMartin KaFai Lau 
344ad2f8eb0SMartin KaFai Lau 	err = bpf_reserve_hdr_opt(skops, option_total_len(OPTION_MASK), 0);
345ad2f8eb0SMartin KaFai Lau 	if (err)
346ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(err);
347ad2f8eb0SMartin KaFai Lau 
348ad2f8eb0SMartin KaFai Lau 	return CG_OK;
349ad2f8eb0SMartin KaFai Lau }
350ad2f8eb0SMartin KaFai Lau 
handle_hdr_opt_len(struct bpf_sock_ops * skops)351ad2f8eb0SMartin KaFai Lau static int handle_hdr_opt_len(struct bpf_sock_ops *skops)
352ad2f8eb0SMartin KaFai Lau {
353ad2f8eb0SMartin KaFai Lau 	__u8 tcp_flags = skops_tcp_flags(skops);
354ad2f8eb0SMartin KaFai Lau 
355ad2f8eb0SMartin KaFai Lau 	if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK)
356ad2f8eb0SMartin KaFai Lau 		return synack_opt_len(skops);
357ad2f8eb0SMartin KaFai Lau 
358ad2f8eb0SMartin KaFai Lau 	if (tcp_flags & TCPHDR_SYN)
359ad2f8eb0SMartin KaFai Lau 		return syn_opt_len(skops);
360ad2f8eb0SMartin KaFai Lau 
361ad2f8eb0SMartin KaFai Lau 	if (tcp_flags & TCPHDR_FIN)
362ad2f8eb0SMartin KaFai Lau 		return fin_opt_len(skops);
363ad2f8eb0SMartin KaFai Lau 
364ad2f8eb0SMartin KaFai Lau 	if (skops_current_mss(skops))
365ad2f8eb0SMartin KaFai Lau 		/* The kernel is calculating the MSS */
366ad2f8eb0SMartin KaFai Lau 		return current_mss_opt_len(skops);
367ad2f8eb0SMartin KaFai Lau 
368ad2f8eb0SMartin KaFai Lau 	if (skops->skb_len)
369ad2f8eb0SMartin KaFai Lau 		return data_opt_len(skops);
370ad2f8eb0SMartin KaFai Lau 
371ad2f8eb0SMartin KaFai Lau 	return nodata_opt_len(skops);
372ad2f8eb0SMartin KaFai Lau }
373ad2f8eb0SMartin KaFai Lau 
handle_write_hdr_opt(struct bpf_sock_ops * skops)374ad2f8eb0SMartin KaFai Lau static int handle_write_hdr_opt(struct bpf_sock_ops *skops)
375ad2f8eb0SMartin KaFai Lau {
376ad2f8eb0SMartin KaFai Lau 	__u8 tcp_flags = skops_tcp_flags(skops);
377ad2f8eb0SMartin KaFai Lau 	struct tcphdr *th;
378ad2f8eb0SMartin KaFai Lau 
379ad2f8eb0SMartin KaFai Lau 	if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK)
380ad2f8eb0SMartin KaFai Lau 		return write_synack_opt(skops);
381ad2f8eb0SMartin KaFai Lau 
382ad2f8eb0SMartin KaFai Lau 	if (tcp_flags & TCPHDR_SYN)
383ad2f8eb0SMartin KaFai Lau 		return write_syn_opt(skops);
384ad2f8eb0SMartin KaFai Lau 
385ad2f8eb0SMartin KaFai Lau 	if (tcp_flags & TCPHDR_FIN)
386ad2f8eb0SMartin KaFai Lau 		return write_fin_opt(skops);
387ad2f8eb0SMartin KaFai Lau 
388ad2f8eb0SMartin KaFai Lau 	th = skops->skb_data;
389ad2f8eb0SMartin KaFai Lau 	if (th + 1 > skops->skb_data_end)
390ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
391ad2f8eb0SMartin KaFai Lau 
392ad2f8eb0SMartin KaFai Lau 	if (skops->skb_len > tcp_hdrlen(th))
393ad2f8eb0SMartin KaFai Lau 		return write_data_opt(skops);
394ad2f8eb0SMartin KaFai Lau 
395ad2f8eb0SMartin KaFai Lau 	return write_nodata_opt(skops);
396ad2f8eb0SMartin KaFai Lau }
397ad2f8eb0SMartin KaFai Lau 
set_delack_max(struct bpf_sock_ops * skops,__u8 max_delack_ms)398ad2f8eb0SMartin KaFai Lau static int set_delack_max(struct bpf_sock_ops *skops, __u8 max_delack_ms)
399ad2f8eb0SMartin KaFai Lau {
400ad2f8eb0SMartin KaFai Lau 	__u32 max_delack_us = max_delack_ms * 1000;
401ad2f8eb0SMartin KaFai Lau 
402ad2f8eb0SMartin KaFai Lau 	return bpf_setsockopt(skops, SOL_TCP, TCP_BPF_DELACK_MAX,
403ad2f8eb0SMartin KaFai Lau 			      &max_delack_us, sizeof(max_delack_us));
404ad2f8eb0SMartin KaFai Lau }
405ad2f8eb0SMartin KaFai Lau 
set_rto_min(struct bpf_sock_ops * skops,__u8 peer_max_delack_ms)406ad2f8eb0SMartin KaFai Lau static int set_rto_min(struct bpf_sock_ops *skops, __u8 peer_max_delack_ms)
407ad2f8eb0SMartin KaFai Lau {
408ad2f8eb0SMartin KaFai Lau 	__u32 min_rto_us = peer_max_delack_ms * 1000;
409ad2f8eb0SMartin KaFai Lau 
410ad2f8eb0SMartin KaFai Lau 	return bpf_setsockopt(skops, SOL_TCP, TCP_BPF_RTO_MIN, &min_rto_us,
411ad2f8eb0SMartin KaFai Lau 			      sizeof(min_rto_us));
412ad2f8eb0SMartin KaFai Lau }
413ad2f8eb0SMartin KaFai Lau 
handle_active_estab(struct bpf_sock_ops * skops)414ad2f8eb0SMartin KaFai Lau static int handle_active_estab(struct bpf_sock_ops *skops)
415ad2f8eb0SMartin KaFai Lau {
416ad2f8eb0SMartin KaFai Lau 	struct hdr_stg init_stg = {
417ad2f8eb0SMartin KaFai Lau 		.active = true,
418ad2f8eb0SMartin KaFai Lau 	};
419ad2f8eb0SMartin KaFai Lau 	int err;
420ad2f8eb0SMartin KaFai Lau 
421ad2f8eb0SMartin KaFai Lau 	err = load_option(skops, &active_estab_in, false);
422ad2f8eb0SMartin KaFai Lau 	if (err && err != -ENOMSG)
423ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(err);
424ad2f8eb0SMartin KaFai Lau 
425ad2f8eb0SMartin KaFai Lau 	init_stg.resend_syn = TEST_OPTION_FLAGS(active_estab_in.flags,
426ad2f8eb0SMartin KaFai Lau 						OPTION_RESEND);
427ad2f8eb0SMartin KaFai Lau 	if (!skops->sk || !bpf_sk_storage_get(&hdr_stg_map, skops->sk,
428ad2f8eb0SMartin KaFai Lau 					      &init_stg,
429ad2f8eb0SMartin KaFai Lau 					      BPF_SK_STORAGE_GET_F_CREATE))
430ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
431ad2f8eb0SMartin KaFai Lau 
432ad2f8eb0SMartin KaFai Lau 	if (init_stg.resend_syn)
433ad2f8eb0SMartin KaFai Lau 		/* Don't clear the write_hdr cb now because
434ad2f8eb0SMartin KaFai Lau 		 * the ACK may get lost and retransmit may
435ad2f8eb0SMartin KaFai Lau 		 * be needed.
436ad2f8eb0SMartin KaFai Lau 		 *
437ad2f8eb0SMartin KaFai Lau 		 * PARSE_ALL_HDR cb flag is set to learn if this
438ad2f8eb0SMartin KaFai Lau 		 * resend_syn option has received by the peer.
439ad2f8eb0SMartin KaFai Lau 		 *
440ad2f8eb0SMartin KaFai Lau 		 * The header option will be resent until a valid
441ad2f8eb0SMartin KaFai Lau 		 * packet is received at handle_parse_hdr()
442ad2f8eb0SMartin KaFai Lau 		 * and all hdr cb flags will be cleared in
443ad2f8eb0SMartin KaFai Lau 		 * handle_parse_hdr().
444ad2f8eb0SMartin KaFai Lau 		 */
445ad2f8eb0SMartin KaFai Lau 		set_parse_all_hdr_cb_flags(skops);
446ad2f8eb0SMartin KaFai Lau 	else if (!active_fin_out.flags)
447ad2f8eb0SMartin KaFai Lau 		/* No options will be written from now */
448ad2f8eb0SMartin KaFai Lau 		clear_hdr_cb_flags(skops);
449ad2f8eb0SMartin KaFai Lau 
450ad2f8eb0SMartin KaFai Lau 	if (active_syn_out.max_delack_ms) {
451ad2f8eb0SMartin KaFai Lau 		err = set_delack_max(skops, active_syn_out.max_delack_ms);
452ad2f8eb0SMartin KaFai Lau 		if (err)
453ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
454ad2f8eb0SMartin KaFai Lau 	}
455ad2f8eb0SMartin KaFai Lau 
456ad2f8eb0SMartin KaFai Lau 	if (active_estab_in.max_delack_ms) {
457ad2f8eb0SMartin KaFai Lau 		err = set_rto_min(skops, active_estab_in.max_delack_ms);
458ad2f8eb0SMartin KaFai Lau 		if (err)
459ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
460ad2f8eb0SMartin KaFai Lau 	}
461ad2f8eb0SMartin KaFai Lau 
462ad2f8eb0SMartin KaFai Lau 	return CG_OK;
463ad2f8eb0SMartin KaFai Lau }
464ad2f8eb0SMartin KaFai Lau 
handle_passive_estab(struct bpf_sock_ops * skops)465ad2f8eb0SMartin KaFai Lau static int handle_passive_estab(struct bpf_sock_ops *skops)
466ad2f8eb0SMartin KaFai Lau {
467ad2f8eb0SMartin KaFai Lau 	struct hdr_stg init_stg = {};
468ad2f8eb0SMartin KaFai Lau 	struct tcphdr *th;
469ad2f8eb0SMartin KaFai Lau 	int err;
470ad2f8eb0SMartin KaFai Lau 
47196d46c50SMartin KaFai Lau 	inherit_cb_flags = skops->bpf_sock_ops_cb_flags;
47296d46c50SMartin KaFai Lau 
473ad2f8eb0SMartin KaFai Lau 	err = load_option(skops, &passive_estab_in, true);
474ad2f8eb0SMartin KaFai Lau 	if (err == -ENOENT) {
475ad2f8eb0SMartin KaFai Lau 		/* saved_syn is not found. It was in syncookie mode.
476ad2f8eb0SMartin KaFai Lau 		 * We have asked the active side to resend the options
477ad2f8eb0SMartin KaFai Lau 		 * in ACK, so try to find the bpf_test_option from ACK now.
478ad2f8eb0SMartin KaFai Lau 		 */
479ad2f8eb0SMartin KaFai Lau 		err = load_option(skops, &passive_estab_in, false);
480ad2f8eb0SMartin KaFai Lau 		init_stg.syncookie = true;
481ad2f8eb0SMartin KaFai Lau 	}
482ad2f8eb0SMartin KaFai Lau 
483ad2f8eb0SMartin KaFai Lau 	/* ENOMSG: The bpf_test_option is not found which is fine.
484ad2f8eb0SMartin KaFai Lau 	 * Bail out now for all other errors.
485ad2f8eb0SMartin KaFai Lau 	 */
486ad2f8eb0SMartin KaFai Lau 	if (err && err != -ENOMSG)
487ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(err);
488ad2f8eb0SMartin KaFai Lau 
489ad2f8eb0SMartin KaFai Lau 	th = skops->skb_data;
490ad2f8eb0SMartin KaFai Lau 	if (th + 1 > skops->skb_data_end)
491ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
492ad2f8eb0SMartin KaFai Lau 
493ad2f8eb0SMartin KaFai Lau 	if (th->syn) {
494ad2f8eb0SMartin KaFai Lau 		/* Fastopen */
495ad2f8eb0SMartin KaFai Lau 
496ad2f8eb0SMartin KaFai Lau 		/* Cannot clear cb_flags to stop write_hdr cb.
497ad2f8eb0SMartin KaFai Lau 		 * synack is not sent yet for fast open.
498ad2f8eb0SMartin KaFai Lau 		 * Even it was, the synack may need to be retransmitted.
499ad2f8eb0SMartin KaFai Lau 		 *
500ad2f8eb0SMartin KaFai Lau 		 * PARSE_ALL_HDR cb flag is set to learn
501ad2f8eb0SMartin KaFai Lau 		 * if synack has reached the peer.
502ad2f8eb0SMartin KaFai Lau 		 * All cb_flags will be cleared in handle_parse_hdr().
503ad2f8eb0SMartin KaFai Lau 		 */
504ad2f8eb0SMartin KaFai Lau 		set_parse_all_hdr_cb_flags(skops);
505ad2f8eb0SMartin KaFai Lau 		init_stg.fastopen = true;
506ad2f8eb0SMartin KaFai Lau 	} else if (!passive_fin_out.flags) {
507ad2f8eb0SMartin KaFai Lau 		/* No options will be written from now */
508ad2f8eb0SMartin KaFai Lau 		clear_hdr_cb_flags(skops);
509ad2f8eb0SMartin KaFai Lau 	}
510ad2f8eb0SMartin KaFai Lau 
511ad2f8eb0SMartin KaFai Lau 	if (!skops->sk ||
512ad2f8eb0SMartin KaFai Lau 	    !bpf_sk_storage_get(&hdr_stg_map, skops->sk, &init_stg,
513ad2f8eb0SMartin KaFai Lau 				BPF_SK_STORAGE_GET_F_CREATE))
514ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
515ad2f8eb0SMartin KaFai Lau 
516ad2f8eb0SMartin KaFai Lau 	if (passive_synack_out.max_delack_ms) {
517ad2f8eb0SMartin KaFai Lau 		err = set_delack_max(skops, passive_synack_out.max_delack_ms);
518ad2f8eb0SMartin KaFai Lau 		if (err)
519ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
520ad2f8eb0SMartin KaFai Lau 	}
521ad2f8eb0SMartin KaFai Lau 
522ad2f8eb0SMartin KaFai Lau 	if (passive_estab_in.max_delack_ms) {
523ad2f8eb0SMartin KaFai Lau 		err = set_rto_min(skops, passive_estab_in.max_delack_ms);
524ad2f8eb0SMartin KaFai Lau 		if (err)
525ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
526ad2f8eb0SMartin KaFai Lau 	}
527ad2f8eb0SMartin KaFai Lau 
528ad2f8eb0SMartin KaFai Lau 	return CG_OK;
529ad2f8eb0SMartin KaFai Lau }
530ad2f8eb0SMartin KaFai Lau 
handle_parse_hdr(struct bpf_sock_ops * skops)531ad2f8eb0SMartin KaFai Lau static int handle_parse_hdr(struct bpf_sock_ops *skops)
532ad2f8eb0SMartin KaFai Lau {
533ad2f8eb0SMartin KaFai Lau 	struct hdr_stg *hdr_stg;
534ad2f8eb0SMartin KaFai Lau 	struct tcphdr *th;
535ad2f8eb0SMartin KaFai Lau 
536ad2f8eb0SMartin KaFai Lau 	if (!skops->sk)
537ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
538ad2f8eb0SMartin KaFai Lau 
539ad2f8eb0SMartin KaFai Lau 	th = skops->skb_data;
540ad2f8eb0SMartin KaFai Lau 	if (th + 1 > skops->skb_data_end)
541ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
542ad2f8eb0SMartin KaFai Lau 
543ad2f8eb0SMartin KaFai Lau 	hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0);
544ad2f8eb0SMartin KaFai Lau 	if (!hdr_stg)
545ad2f8eb0SMartin KaFai Lau 		RET_CG_ERR(0);
546ad2f8eb0SMartin KaFai Lau 
547ad2f8eb0SMartin KaFai Lau 	if (hdr_stg->resend_syn || hdr_stg->fastopen)
548ad2f8eb0SMartin KaFai Lau 		/* The PARSE_ALL_HDR cb flag was turned on
549ad2f8eb0SMartin KaFai Lau 		 * to ensure that the previously written
550ad2f8eb0SMartin KaFai Lau 		 * options have reached the peer.
551ad2f8eb0SMartin KaFai Lau 		 * Those previously written option includes:
552ad2f8eb0SMartin KaFai Lau 		 *     - Active side: resend_syn in ACK during syncookie
553ad2f8eb0SMartin KaFai Lau 		 *      or
554ad2f8eb0SMartin KaFai Lau 		 *     - Passive side: SYNACK during fastopen
555ad2f8eb0SMartin KaFai Lau 		 *
556ad2f8eb0SMartin KaFai Lau 		 * A valid packet has been received here after
557ad2f8eb0SMartin KaFai Lau 		 * the 3WHS, so the PARSE_ALL_HDR cb flag
558ad2f8eb0SMartin KaFai Lau 		 * can be cleared now.
559ad2f8eb0SMartin KaFai Lau 		 */
560ad2f8eb0SMartin KaFai Lau 		clear_parse_all_hdr_cb_flags(skops);
561ad2f8eb0SMartin KaFai Lau 
562ad2f8eb0SMartin KaFai Lau 	if (hdr_stg->resend_syn && !active_fin_out.flags)
563ad2f8eb0SMartin KaFai Lau 		/* Active side resent the syn option in ACK
564ad2f8eb0SMartin KaFai Lau 		 * because the server was in syncookie mode.
565ad2f8eb0SMartin KaFai Lau 		 * A valid packet has been received, so
566ad2f8eb0SMartin KaFai Lau 		 * clear header cb flags if there is no
567ad2f8eb0SMartin KaFai Lau 		 * more option to send.
568ad2f8eb0SMartin KaFai Lau 		 */
569ad2f8eb0SMartin KaFai Lau 		clear_hdr_cb_flags(skops);
570ad2f8eb0SMartin KaFai Lau 
571ad2f8eb0SMartin KaFai Lau 	if (hdr_stg->fastopen && !passive_fin_out.flags)
572ad2f8eb0SMartin KaFai Lau 		/* Passive side was in fastopen.
573ad2f8eb0SMartin KaFai Lau 		 * A valid packet has been received, so
574ad2f8eb0SMartin KaFai Lau 		 * the SYNACK has reached the peer.
575ad2f8eb0SMartin KaFai Lau 		 * Clear header cb flags if there is no more
576ad2f8eb0SMartin KaFai Lau 		 * option to send.
577ad2f8eb0SMartin KaFai Lau 		 */
578ad2f8eb0SMartin KaFai Lau 		clear_hdr_cb_flags(skops);
579ad2f8eb0SMartin KaFai Lau 
580ad2f8eb0SMartin KaFai Lau 	if (th->fin) {
581ad2f8eb0SMartin KaFai Lau 		struct bpf_test_option *fin_opt;
582ad2f8eb0SMartin KaFai Lau 		int err;
583ad2f8eb0SMartin KaFai Lau 
584ad2f8eb0SMartin KaFai Lau 		if (hdr_stg->active)
585ad2f8eb0SMartin KaFai Lau 			fin_opt = &active_fin_in;
586ad2f8eb0SMartin KaFai Lau 		else
587ad2f8eb0SMartin KaFai Lau 			fin_opt = &passive_fin_in;
588ad2f8eb0SMartin KaFai Lau 
589ad2f8eb0SMartin KaFai Lau 		err = load_option(skops, fin_opt, false);
590ad2f8eb0SMartin KaFai Lau 		if (err && err != -ENOMSG)
591ad2f8eb0SMartin KaFai Lau 			RET_CG_ERR(err);
592ad2f8eb0SMartin KaFai Lau 	}
593ad2f8eb0SMartin KaFai Lau 
594ad2f8eb0SMartin KaFai Lau 	return CG_OK;
595ad2f8eb0SMartin KaFai Lau }
596ad2f8eb0SMartin KaFai Lau 
597*15669e1dSAndrii Nakryiko SEC("sockops")
estab(struct bpf_sock_ops * skops)598ad2f8eb0SMartin KaFai Lau int estab(struct bpf_sock_ops *skops)
599ad2f8eb0SMartin KaFai Lau {
600ad2f8eb0SMartin KaFai Lau 	int true_val = 1;
601ad2f8eb0SMartin KaFai Lau 
602ad2f8eb0SMartin KaFai Lau 	switch (skops->op) {
603ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_TCP_LISTEN_CB:
604ad2f8eb0SMartin KaFai Lau 		bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN,
605ad2f8eb0SMartin KaFai Lau 			       &true_val, sizeof(true_val));
60696d46c50SMartin KaFai Lau 		set_hdr_cb_flags(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
607ad2f8eb0SMartin KaFai Lau 		break;
608ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_TCP_CONNECT_CB:
60996d46c50SMartin KaFai Lau 		set_hdr_cb_flags(skops, 0);
610ad2f8eb0SMartin KaFai Lau 		break;
611ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
612ad2f8eb0SMartin KaFai Lau 		return handle_parse_hdr(skops);
613ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_HDR_OPT_LEN_CB:
614ad2f8eb0SMartin KaFai Lau 		return handle_hdr_opt_len(skops);
615ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_WRITE_HDR_OPT_CB:
616ad2f8eb0SMartin KaFai Lau 		return handle_write_hdr_opt(skops);
617ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
618ad2f8eb0SMartin KaFai Lau 		return handle_passive_estab(skops);
619ad2f8eb0SMartin KaFai Lau 	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
620ad2f8eb0SMartin KaFai Lau 		return handle_active_estab(skops);
621ad2f8eb0SMartin KaFai Lau 	}
622ad2f8eb0SMartin KaFai Lau 
623ad2f8eb0SMartin KaFai Lau 	return CG_OK;
624ad2f8eb0SMartin KaFai Lau }
625ad2f8eb0SMartin KaFai Lau 
626ad2f8eb0SMartin KaFai Lau char _license[] SEC("license") = "GPL";
627