162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) Meta Platforms, Inc. and affiliates. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "vmlinux.h"
562306a36Sopenharmony_ci#include "bpf_tracing_net.h"
662306a36Sopenharmony_ci#include <bpf/bpf_core_read.h>
762306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
862306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef ARRAY_SIZE
1162306a36Sopenharmony_ci#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
1262306a36Sopenharmony_ci#endif
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciextern unsigned long CONFIG_HZ __kconfig;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciconst volatile char veth[IFNAMSIZ];
1762306a36Sopenharmony_ciconst volatile int veth_ifindex;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint nr_listen;
2062306a36Sopenharmony_ciint nr_passive;
2162306a36Sopenharmony_ciint nr_active;
2262306a36Sopenharmony_ciint nr_connect;
2362306a36Sopenharmony_ciint nr_binddev;
2462306a36Sopenharmony_ciint nr_socket_post_create;
2562306a36Sopenharmony_ciint nr_fin_wait1;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct sockopt_test {
2862306a36Sopenharmony_ci	int opt;
2962306a36Sopenharmony_ci	int new;
3062306a36Sopenharmony_ci	int restore;
3162306a36Sopenharmony_ci	int expected;
3262306a36Sopenharmony_ci	int tcp_expected;
3362306a36Sopenharmony_ci	unsigned int flip:1;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const char not_exist_cc[] = "not_exist";
3762306a36Sopenharmony_cistatic const char cubic_cc[] = "cubic";
3862306a36Sopenharmony_cistatic const char reno_cc[] = "reno";
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic const struct sockopt_test sol_socket_tests[] = {
4162306a36Sopenharmony_ci	{ .opt = SO_REUSEADDR, .flip = 1, },
4262306a36Sopenharmony_ci	{ .opt = SO_SNDBUF, .new = 8123, .expected = 8123 * 2, },
4362306a36Sopenharmony_ci	{ .opt = SO_RCVBUF, .new = 8123, .expected = 8123 * 2, },
4462306a36Sopenharmony_ci	{ .opt = SO_KEEPALIVE, .flip = 1, },
4562306a36Sopenharmony_ci	{ .opt = SO_PRIORITY, .new = 0xeb9f, .expected = 0xeb9f, },
4662306a36Sopenharmony_ci	{ .opt = SO_REUSEPORT, .flip = 1, },
4762306a36Sopenharmony_ci	{ .opt = SO_RCVLOWAT, .new = 8123, .expected = 8123, },
4862306a36Sopenharmony_ci	{ .opt = SO_MARK, .new = 0xeb9f, .expected = 0xeb9f, },
4962306a36Sopenharmony_ci	{ .opt = SO_MAX_PACING_RATE, .new = 0xeb9f, .expected = 0xeb9f, },
5062306a36Sopenharmony_ci	{ .opt = SO_TXREHASH, .flip = 1, },
5162306a36Sopenharmony_ci	{ .opt = 0, },
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic const struct sockopt_test sol_tcp_tests[] = {
5562306a36Sopenharmony_ci	{ .opt = TCP_NODELAY, .flip = 1, },
5662306a36Sopenharmony_ci	{ .opt = TCP_KEEPIDLE, .new = 123, .expected = 123, .restore = 321, },
5762306a36Sopenharmony_ci	{ .opt = TCP_KEEPINTVL, .new = 123, .expected = 123, .restore = 321, },
5862306a36Sopenharmony_ci	{ .opt = TCP_KEEPCNT, .new = 123, .expected = 123, .restore = 124, },
5962306a36Sopenharmony_ci	{ .opt = TCP_SYNCNT, .new = 123, .expected = 123, .restore = 124, },
6062306a36Sopenharmony_ci	{ .opt = TCP_WINDOW_CLAMP, .new = 8123, .expected = 8123, .restore = 8124, },
6162306a36Sopenharmony_ci	{ .opt = TCP_CONGESTION, },
6262306a36Sopenharmony_ci	{ .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, },
6362306a36Sopenharmony_ci	{ .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, },
6462306a36Sopenharmony_ci	{ .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, },
6562306a36Sopenharmony_ci	{ .opt = 0, },
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const struct sockopt_test sol_ip_tests[] = {
6962306a36Sopenharmony_ci	{ .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
7062306a36Sopenharmony_ci	{ .opt = 0, },
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic const struct sockopt_test sol_ipv6_tests[] = {
7462306a36Sopenharmony_ci	{ .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },
7562306a36Sopenharmony_ci	{ .opt = IPV6_AUTOFLOWLABEL, .flip = 1, },
7662306a36Sopenharmony_ci	{ .opt = 0, },
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct loop_ctx {
8062306a36Sopenharmony_ci	void *ctx;
8162306a36Sopenharmony_ci	struct sock *sk;
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int bpf_test_sockopt_flip(void *ctx, struct sock *sk,
8562306a36Sopenharmony_ci				 const struct sockopt_test *t,
8662306a36Sopenharmony_ci				 int level)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	int old, tmp, new, opt = t->opt;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	opt = t->opt;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)))
9362306a36Sopenharmony_ci		return 1;
9462306a36Sopenharmony_ci	/* kernel initialized txrehash to 255 */
9562306a36Sopenharmony_ci	if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1)
9662306a36Sopenharmony_ci		old = 1;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	new = !old;
9962306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
10062306a36Sopenharmony_ci		return 1;
10162306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
10262306a36Sopenharmony_ci	    tmp != new)
10362306a36Sopenharmony_ci		return 1;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
10662306a36Sopenharmony_ci		return 1;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int bpf_test_sockopt_int(void *ctx, struct sock *sk,
11262306a36Sopenharmony_ci				const struct sockopt_test *t,
11362306a36Sopenharmony_ci				int level)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int old, tmp, new, expected, opt;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	opt = t->opt;
11862306a36Sopenharmony_ci	new = t->new;
11962306a36Sopenharmony_ci	if (sk->sk_type == SOCK_STREAM && t->tcp_expected)
12062306a36Sopenharmony_ci		expected = t->tcp_expected;
12162306a36Sopenharmony_ci	else
12262306a36Sopenharmony_ci		expected = t->expected;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) ||
12562306a36Sopenharmony_ci	    old == new)
12662306a36Sopenharmony_ci		return 1;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))
12962306a36Sopenharmony_ci		return 1;
13062306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||
13162306a36Sopenharmony_ci	    tmp != expected)
13262306a36Sopenharmony_ci		return 1;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (t->restore)
13562306a36Sopenharmony_ci		old = t->restore;
13662306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))
13762306a36Sopenharmony_ci		return 1;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	const struct sockopt_test *t;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (i >= ARRAY_SIZE(sol_socket_tests))
14762306a36Sopenharmony_ci		return 1;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	t = &sol_socket_tests[i];
15062306a36Sopenharmony_ci	if (!t->opt)
15162306a36Sopenharmony_ci		return 1;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (t->flip)
15462306a36Sopenharmony_ci		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	const struct sockopt_test *t;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (i >= ARRAY_SIZE(sol_ip_tests))
16462306a36Sopenharmony_ci		return 1;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	t = &sol_ip_tests[i];
16762306a36Sopenharmony_ci	if (!t->opt)
16862306a36Sopenharmony_ci		return 1;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (t->flip)
17162306a36Sopenharmony_ci		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	const struct sockopt_test *t;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (i >= ARRAY_SIZE(sol_ipv6_tests))
18162306a36Sopenharmony_ci		return 1;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	t = &sol_ipv6_tests[i];
18462306a36Sopenharmony_ci	if (!t->opt)
18562306a36Sopenharmony_ci		return 1;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (t->flip)
18862306a36Sopenharmony_ci		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	const struct sockopt_test *t;
19662306a36Sopenharmony_ci	struct sock *sk;
19762306a36Sopenharmony_ci	void *ctx;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (i >= ARRAY_SIZE(sol_tcp_tests))
20062306a36Sopenharmony_ci		return 1;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	t = &sol_tcp_tests[i];
20362306a36Sopenharmony_ci	if (!t->opt)
20462306a36Sopenharmony_ci		return 1;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	ctx = lc->ctx;
20762306a36Sopenharmony_ci	sk = lc->sk;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (t->opt == TCP_CONGESTION) {
21062306a36Sopenharmony_ci		char old_cc[16], tmp_cc[16];
21162306a36Sopenharmony_ci		const char *new_cc;
21262306a36Sopenharmony_ci		int new_cc_len;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION,
21562306a36Sopenharmony_ci				    (void *)not_exist_cc, sizeof(not_exist_cc)))
21662306a36Sopenharmony_ci			return 1;
21762306a36Sopenharmony_ci		if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
21862306a36Sopenharmony_ci			return 1;
21962306a36Sopenharmony_ci		if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) {
22062306a36Sopenharmony_ci			new_cc = reno_cc;
22162306a36Sopenharmony_ci			new_cc_len = sizeof(reno_cc);
22262306a36Sopenharmony_ci		} else {
22362306a36Sopenharmony_ci			new_cc = cubic_cc;
22462306a36Sopenharmony_ci			new_cc_len = sizeof(cubic_cc);
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci		if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc,
22762306a36Sopenharmony_ci				   new_cc_len))
22862306a36Sopenharmony_ci			return 1;
22962306a36Sopenharmony_ci		if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc)))
23062306a36Sopenharmony_ci			return 1;
23162306a36Sopenharmony_ci		if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc))
23262306a36Sopenharmony_ci			return 1;
23362306a36Sopenharmony_ci		if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))
23462306a36Sopenharmony_ci			return 1;
23562306a36Sopenharmony_ci		return 0;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (t->flip)
23962306a36Sopenharmony_ci		return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int bpf_test_sockopt(void *ctx, struct sock *sk)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct loop_ctx lc = { .ctx = ctx, .sk = sk, };
24762306a36Sopenharmony_ci	__u16 family, proto;
24862306a36Sopenharmony_ci	int n;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	family = sk->sk_family;
25162306a36Sopenharmony_ci	proto = sk->sk_protocol;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0);
25462306a36Sopenharmony_ci	if (n != ARRAY_SIZE(sol_socket_tests))
25562306a36Sopenharmony_ci		return -1;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (proto == IPPROTO_TCP) {
25862306a36Sopenharmony_ci		n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0);
25962306a36Sopenharmony_ci		if (n != ARRAY_SIZE(sol_tcp_tests))
26062306a36Sopenharmony_ci			return -1;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (family == AF_INET) {
26462306a36Sopenharmony_ci		n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0);
26562306a36Sopenharmony_ci		if (n != ARRAY_SIZE(sol_ip_tests))
26662306a36Sopenharmony_ci			return -1;
26762306a36Sopenharmony_ci	} else {
26862306a36Sopenharmony_ci		n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0);
26962306a36Sopenharmony_ci		if (n != ARRAY_SIZE(sol_ipv6_tests))
27062306a36Sopenharmony_ci			return -1;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int binddev_test(void *ctx)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	const char empty_ifname[] = "";
27962306a36Sopenharmony_ci	int ifindex, zero = 0;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
28262306a36Sopenharmony_ci			   (void *)veth, sizeof(veth)))
28362306a36Sopenharmony_ci		return -1;
28462306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
28562306a36Sopenharmony_ci			   &ifindex, sizeof(int)) ||
28662306a36Sopenharmony_ci	    ifindex != veth_ifindex)
28762306a36Sopenharmony_ci		return -1;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
29062306a36Sopenharmony_ci			   (void *)empty_ifname, sizeof(empty_ifname)))
29162306a36Sopenharmony_ci		return -1;
29262306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
29362306a36Sopenharmony_ci			   &ifindex, sizeof(int)) ||
29462306a36Sopenharmony_ci	    ifindex != 0)
29562306a36Sopenharmony_ci		return -1;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
29862306a36Sopenharmony_ci			   (void *)&veth_ifindex, sizeof(int)))
29962306a36Sopenharmony_ci		return -1;
30062306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
30162306a36Sopenharmony_ci			   &ifindex, sizeof(int)) ||
30262306a36Sopenharmony_ci	    ifindex != veth_ifindex)
30362306a36Sopenharmony_ci		return -1;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
30662306a36Sopenharmony_ci			   &zero, sizeof(int)))
30762306a36Sopenharmony_ci		return -1;
30862306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
30962306a36Sopenharmony_ci			   &ifindex, sizeof(int)) ||
31062306a36Sopenharmony_ci	    ifindex != 0)
31162306a36Sopenharmony_ci		return -1;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic int test_tcp_maxseg(void *ctx, struct sock *sk)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	int val = 1314, tmp;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (sk->sk_state != TCP_ESTABLISHED)
32162306a36Sopenharmony_ci		return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG,
32262306a36Sopenharmony_ci				      &val, sizeof(val));
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) ||
32562306a36Sopenharmony_ci	    tmp > val)
32662306a36Sopenharmony_ci		return -1;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic int test_tcp_saved_syn(void *ctx, struct sock *sk)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	__u8 saved_syn[20];
33462306a36Sopenharmony_ci	int one = 1;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (sk->sk_state == TCP_LISTEN)
33762306a36Sopenharmony_ci		return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN,
33862306a36Sopenharmony_ci				      &one, sizeof(one));
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN,
34162306a36Sopenharmony_ci			      saved_syn, sizeof(saved_syn));
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ciSEC("lsm_cgroup/socket_post_create")
34562306a36Sopenharmony_ciint BPF_PROG(socket_post_create, struct socket *sock, int family,
34662306a36Sopenharmony_ci	     int type, int protocol, int kern)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (!sk)
35162306a36Sopenharmony_ci		return 1;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	nr_socket_post_create += !bpf_test_sockopt(sk, sk);
35462306a36Sopenharmony_ci	nr_binddev += !binddev_test(sk);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return 1;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciSEC("sockops")
36062306a36Sopenharmony_ciint skops_sockopt(struct bpf_sock_ops *skops)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct bpf_sock *bpf_sk = skops->sk;
36362306a36Sopenharmony_ci	struct sock *sk;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (!bpf_sk)
36662306a36Sopenharmony_ci		return 1;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk);
36962306a36Sopenharmony_ci	if (!sk)
37062306a36Sopenharmony_ci		return 1;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	switch (skops->op) {
37362306a36Sopenharmony_ci	case BPF_SOCK_OPS_TCP_LISTEN_CB:
37462306a36Sopenharmony_ci		nr_listen += !(bpf_test_sockopt(skops, sk) ||
37562306a36Sopenharmony_ci			       test_tcp_maxseg(skops, sk) ||
37662306a36Sopenharmony_ci			       test_tcp_saved_syn(skops, sk));
37762306a36Sopenharmony_ci		break;
37862306a36Sopenharmony_ci	case BPF_SOCK_OPS_TCP_CONNECT_CB:
37962306a36Sopenharmony_ci		nr_connect += !(bpf_test_sockopt(skops, sk) ||
38062306a36Sopenharmony_ci				test_tcp_maxseg(skops, sk));
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
38362306a36Sopenharmony_ci		nr_active += !(bpf_test_sockopt(skops, sk) ||
38462306a36Sopenharmony_ci			       test_tcp_maxseg(skops, sk));
38562306a36Sopenharmony_ci		break;
38662306a36Sopenharmony_ci	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
38762306a36Sopenharmony_ci		nr_passive += !(bpf_test_sockopt(skops, sk) ||
38862306a36Sopenharmony_ci				test_tcp_maxseg(skops, sk) ||
38962306a36Sopenharmony_ci				test_tcp_saved_syn(skops, sk));
39062306a36Sopenharmony_ci		bpf_sock_ops_cb_flags_set(skops,
39162306a36Sopenharmony_ci					  skops->bpf_sock_ops_cb_flags |
39262306a36Sopenharmony_ci					  BPF_SOCK_OPS_STATE_CB_FLAG);
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	case BPF_SOCK_OPS_STATE_CB:
39562306a36Sopenharmony_ci		if (skops->args[1] == BPF_TCP_CLOSE_WAIT)
39662306a36Sopenharmony_ci			nr_fin_wait1 += !bpf_test_sockopt(skops, sk);
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return 1;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
404