1ad2f8eb0SMartin KaFai Lau /* SPDX-License-Identifier: GPL-2.0 */
2ad2f8eb0SMartin KaFai Lau /* Copyright (c) 2020 Facebook */
3ad2f8eb0SMartin KaFai Lau 
4ad2f8eb0SMartin KaFai Lau #ifndef _TEST_TCP_HDR_OPTIONS_H
5ad2f8eb0SMartin KaFai Lau #define _TEST_TCP_HDR_OPTIONS_H
6ad2f8eb0SMartin KaFai Lau 
7ad2f8eb0SMartin KaFai Lau struct bpf_test_option {
8ad2f8eb0SMartin KaFai Lau 	__u8 flags;
9ad2f8eb0SMartin KaFai Lau 	__u8 max_delack_ms;
10ad2f8eb0SMartin KaFai Lau 	__u8 rand;
11ad2f8eb0SMartin KaFai Lau } __attribute__((packed));
12ad2f8eb0SMartin KaFai Lau 
13ad2f8eb0SMartin KaFai Lau enum {
14ad2f8eb0SMartin KaFai Lau 	OPTION_RESEND,
15ad2f8eb0SMartin KaFai Lau 	OPTION_MAX_DELACK_MS,
16ad2f8eb0SMartin KaFai Lau 	OPTION_RAND,
17ad2f8eb0SMartin KaFai Lau 	__NR_OPTION_FLAGS,
18ad2f8eb0SMartin KaFai Lau };
19ad2f8eb0SMartin KaFai Lau 
20ad2f8eb0SMartin KaFai Lau #define OPTION_F_RESEND		(1 << OPTION_RESEND)
21ad2f8eb0SMartin KaFai Lau #define OPTION_F_MAX_DELACK_MS	(1 << OPTION_MAX_DELACK_MS)
22ad2f8eb0SMartin KaFai Lau #define OPTION_F_RAND		(1 << OPTION_RAND)
23ad2f8eb0SMartin KaFai Lau #define OPTION_MASK		((1 << __NR_OPTION_FLAGS) - 1)
24ad2f8eb0SMartin KaFai Lau 
25ad2f8eb0SMartin KaFai Lau #define TEST_OPTION_FLAGS(flags, option) (1 & ((flags) >> (option)))
26ad2f8eb0SMartin KaFai Lau #define SET_OPTION_FLAGS(flags, option)	((flags) |= (1 << (option)))
27ad2f8eb0SMartin KaFai Lau 
28ad2f8eb0SMartin KaFai Lau /* Store in bpf_sk_storage */
29ad2f8eb0SMartin KaFai Lau struct hdr_stg {
30ad2f8eb0SMartin KaFai Lau 	bool active;
31ad2f8eb0SMartin KaFai Lau 	bool resend_syn; /* active side only */
32ad2f8eb0SMartin KaFai Lau 	bool syncookie;  /* passive side only */
33ad2f8eb0SMartin KaFai Lau 	bool fastopen;	/* passive side only */
34ad2f8eb0SMartin KaFai Lau };
35ad2f8eb0SMartin KaFai Lau 
36ad2f8eb0SMartin KaFai Lau struct linum_err {
37ad2f8eb0SMartin KaFai Lau 	unsigned int linum;
38ad2f8eb0SMartin KaFai Lau 	int err;
39ad2f8eb0SMartin KaFai Lau };
40ad2f8eb0SMartin KaFai Lau 
41ad2f8eb0SMartin KaFai Lau #define TCPHDR_FIN 0x01
42ad2f8eb0SMartin KaFai Lau #define TCPHDR_SYN 0x02
43ad2f8eb0SMartin KaFai Lau #define TCPHDR_RST 0x04
44ad2f8eb0SMartin KaFai Lau #define TCPHDR_PSH 0x08
45ad2f8eb0SMartin KaFai Lau #define TCPHDR_ACK 0x10
46ad2f8eb0SMartin KaFai Lau #define TCPHDR_URG 0x20
47ad2f8eb0SMartin KaFai Lau #define TCPHDR_ECE 0x40
48ad2f8eb0SMartin KaFai Lau #define TCPHDR_CWR 0x80
49ad2f8eb0SMartin KaFai Lau #define TCPHDR_SYNACK (TCPHDR_SYN | TCPHDR_ACK)
50ad2f8eb0SMartin KaFai Lau 
51ad2f8eb0SMartin KaFai Lau #define TCPOPT_EOL		0
52ad2f8eb0SMartin KaFai Lau #define TCPOPT_NOP		1
53*cfa7b011SJoanne Koong #define TCPOPT_MSS		2
54ad2f8eb0SMartin KaFai Lau #define TCPOPT_WINDOW		3
55ad2f8eb0SMartin KaFai Lau #define TCPOPT_EXP		254
56ad2f8eb0SMartin KaFai Lau 
57ad2f8eb0SMartin KaFai Lau #define TCP_BPF_EXPOPT_BASE_LEN 4
58ad2f8eb0SMartin KaFai Lau #define MAX_TCP_HDR_LEN		60
59ad2f8eb0SMartin KaFai Lau #define MAX_TCP_OPTION_SPACE	40
60ad2f8eb0SMartin KaFai Lau 
61ad2f8eb0SMartin KaFai Lau #ifdef BPF_PROG_TEST_TCP_HDR_OPTIONS
62ad2f8eb0SMartin KaFai Lau 
63ad2f8eb0SMartin KaFai Lau #define CG_OK	1
64ad2f8eb0SMartin KaFai Lau #define CG_ERR	0
65ad2f8eb0SMartin KaFai Lau 
66ad2f8eb0SMartin KaFai Lau #ifndef SOL_TCP
67ad2f8eb0SMartin KaFai Lau #define SOL_TCP 6
68ad2f8eb0SMartin KaFai Lau #endif
69ad2f8eb0SMartin KaFai Lau 
70ad2f8eb0SMartin KaFai Lau struct tcp_exprm_opt {
71ad2f8eb0SMartin KaFai Lau 	__u8 kind;
72ad2f8eb0SMartin KaFai Lau 	__u8 len;
73ad2f8eb0SMartin KaFai Lau 	__u16 magic;
74ad2f8eb0SMartin KaFai Lau 	union {
75ad2f8eb0SMartin KaFai Lau 		__u8 data[4];
76ad2f8eb0SMartin KaFai Lau 		__u32 data32;
77ad2f8eb0SMartin KaFai Lau 	};
78ad2f8eb0SMartin KaFai Lau } __attribute__((packed));
79ad2f8eb0SMartin KaFai Lau 
80ad2f8eb0SMartin KaFai Lau struct tcp_opt {
81ad2f8eb0SMartin KaFai Lau 	__u8 kind;
82ad2f8eb0SMartin KaFai Lau 	__u8 len;
83ad2f8eb0SMartin KaFai Lau 	union {
84ad2f8eb0SMartin KaFai Lau 		__u8 data[4];
85ad2f8eb0SMartin KaFai Lau 		__u32 data32;
86ad2f8eb0SMartin KaFai Lau 	};
87ad2f8eb0SMartin KaFai Lau } __attribute__((packed));
88ad2f8eb0SMartin KaFai Lau 
89ad2f8eb0SMartin KaFai Lau struct {
90ad2f8eb0SMartin KaFai Lau 	__uint(type, BPF_MAP_TYPE_HASH);
91ad2f8eb0SMartin KaFai Lau 	__uint(max_entries, 2);
92ad2f8eb0SMartin KaFai Lau 	__type(key, int);
93ad2f8eb0SMartin KaFai Lau 	__type(value, struct linum_err);
94ad2f8eb0SMartin KaFai Lau } lport_linum_map SEC(".maps");
95ad2f8eb0SMartin KaFai Lau 
tcp_hdrlen(const struct tcphdr * th)96ad2f8eb0SMartin KaFai Lau static inline unsigned int tcp_hdrlen(const struct tcphdr *th)
97ad2f8eb0SMartin KaFai Lau {
98ad2f8eb0SMartin KaFai Lau 	return th->doff << 2;
99ad2f8eb0SMartin KaFai Lau }
100ad2f8eb0SMartin KaFai Lau 
skops_tcp_flags(const struct bpf_sock_ops * skops)101ad2f8eb0SMartin KaFai Lau static inline __u8 skops_tcp_flags(const struct bpf_sock_ops *skops)
102ad2f8eb0SMartin KaFai Lau {
103ad2f8eb0SMartin KaFai Lau 	return skops->skb_tcp_flags;
104ad2f8eb0SMartin KaFai Lau }
105ad2f8eb0SMartin KaFai Lau 
clear_hdr_cb_flags(struct bpf_sock_ops * skops)106ad2f8eb0SMartin KaFai Lau static inline void clear_hdr_cb_flags(struct bpf_sock_ops *skops)
107ad2f8eb0SMartin KaFai Lau {
108ad2f8eb0SMartin KaFai Lau 	bpf_sock_ops_cb_flags_set(skops,
109ad2f8eb0SMartin KaFai Lau 				  skops->bpf_sock_ops_cb_flags &
110ad2f8eb0SMartin KaFai Lau 				  ~(BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
111ad2f8eb0SMartin KaFai Lau 				    BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG));
112ad2f8eb0SMartin KaFai Lau }
113ad2f8eb0SMartin KaFai Lau 
set_hdr_cb_flags(struct bpf_sock_ops * skops,__u32 extra)11496d46c50SMartin KaFai Lau static inline void set_hdr_cb_flags(struct bpf_sock_ops *skops, __u32 extra)
115ad2f8eb0SMartin KaFai Lau {
116ad2f8eb0SMartin KaFai Lau 	bpf_sock_ops_cb_flags_set(skops,
117ad2f8eb0SMartin KaFai Lau 				  skops->bpf_sock_ops_cb_flags |
118ad2f8eb0SMartin KaFai Lau 				  BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
11996d46c50SMartin KaFai Lau 				  BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
12096d46c50SMartin KaFai Lau 				  extra);
121ad2f8eb0SMartin KaFai Lau }
122ad2f8eb0SMartin KaFai Lau static inline void
clear_parse_all_hdr_cb_flags(struct bpf_sock_ops * skops)123ad2f8eb0SMartin KaFai Lau clear_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops)
124ad2f8eb0SMartin KaFai Lau {
125ad2f8eb0SMartin KaFai Lau 	bpf_sock_ops_cb_flags_set(skops,
126ad2f8eb0SMartin KaFai Lau 				  skops->bpf_sock_ops_cb_flags &
127ad2f8eb0SMartin KaFai Lau 				  ~BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG);
128ad2f8eb0SMartin KaFai Lau }
129ad2f8eb0SMartin KaFai Lau 
130ad2f8eb0SMartin KaFai Lau static inline void
set_parse_all_hdr_cb_flags(struct bpf_sock_ops * skops)131ad2f8eb0SMartin KaFai Lau set_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops)
132ad2f8eb0SMartin KaFai Lau {
133ad2f8eb0SMartin KaFai Lau 	bpf_sock_ops_cb_flags_set(skops,
134ad2f8eb0SMartin KaFai Lau 				  skops->bpf_sock_ops_cb_flags |
135ad2f8eb0SMartin KaFai Lau 				  BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG);
136ad2f8eb0SMartin KaFai Lau }
137ad2f8eb0SMartin KaFai Lau 
138ad2f8eb0SMartin KaFai Lau #define RET_CG_ERR(__err) ({			\
139ad2f8eb0SMartin KaFai Lau 	struct linum_err __linum_err;		\
140ad2f8eb0SMartin KaFai Lau 	int __lport;				\
141ad2f8eb0SMartin KaFai Lau 						\
142ad2f8eb0SMartin KaFai Lau 	__linum_err.linum = __LINE__;		\
143ad2f8eb0SMartin KaFai Lau 	__linum_err.err = __err;		\
144ad2f8eb0SMartin KaFai Lau 	__lport = skops->local_port;		\
145ad2f8eb0SMartin KaFai Lau 	bpf_map_update_elem(&lport_linum_map, &__lport, &__linum_err, BPF_NOEXIST); \
146ad2f8eb0SMartin KaFai Lau 	clear_hdr_cb_flags(skops);					\
147ad2f8eb0SMartin KaFai Lau 	clear_parse_all_hdr_cb_flags(skops);				\
148ad2f8eb0SMartin KaFai Lau 	return CG_ERR;							\
149ad2f8eb0SMartin KaFai Lau })
150ad2f8eb0SMartin KaFai Lau 
151ad2f8eb0SMartin KaFai Lau #endif /* BPF_PROG_TEST_TCP_HDR_OPTIONS */
152ad2f8eb0SMartin KaFai Lau 
153ad2f8eb0SMartin KaFai Lau #endif /* _TEST_TCP_HDR_OPTIONS_H */
154