18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2018 Facebook
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#define _GNU_SOURCE
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <stdio.h>
78c2ecf20Sopenharmony_ci#include <stdlib.h>
88c2ecf20Sopenharmony_ci#include <unistd.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <arpa/inet.h>
118c2ecf20Sopenharmony_ci#include <netinet/in.h>
128c2ecf20Sopenharmony_ci#include <sys/types.h>
138c2ecf20Sopenharmony_ci#include <sys/select.h>
148c2ecf20Sopenharmony_ci#include <sys/socket.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/filter.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
198c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "cgroup_helpers.h"
228c2ecf20Sopenharmony_ci#include "bpf_rlimit.h"
238c2ecf20Sopenharmony_ci#include "bpf_util.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#ifndef ENOTSUPP
268c2ecf20Sopenharmony_ci# define ENOTSUPP 524
278c2ecf20Sopenharmony_ci#endif
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define CG_PATH	"/foo"
308c2ecf20Sopenharmony_ci#define CONNECT4_PROG_PATH	"./connect4_prog.o"
318c2ecf20Sopenharmony_ci#define CONNECT6_PROG_PATH	"./connect6_prog.o"
328c2ecf20Sopenharmony_ci#define SENDMSG4_PROG_PATH	"./sendmsg4_prog.o"
338c2ecf20Sopenharmony_ci#define SENDMSG6_PROG_PATH	"./sendmsg6_prog.o"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define SERV4_IP		"192.168.1.254"
368c2ecf20Sopenharmony_ci#define SERV4_REWRITE_IP	"127.0.0.1"
378c2ecf20Sopenharmony_ci#define SRC4_IP			"172.16.0.1"
388c2ecf20Sopenharmony_ci#define SRC4_REWRITE_IP		"127.0.0.4"
398c2ecf20Sopenharmony_ci#define SERV4_PORT		4040
408c2ecf20Sopenharmony_ci#define SERV4_REWRITE_PORT	4444
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define SERV6_IP		"face:b00c:1234:5678::abcd"
438c2ecf20Sopenharmony_ci#define SERV6_REWRITE_IP	"::1"
448c2ecf20Sopenharmony_ci#define SERV6_V4MAPPED_IP	"::ffff:192.168.0.4"
458c2ecf20Sopenharmony_ci#define SRC6_IP			"::1"
468c2ecf20Sopenharmony_ci#define SRC6_REWRITE_IP		"::6"
478c2ecf20Sopenharmony_ci#define WILDCARD6_IP		"::"
488c2ecf20Sopenharmony_ci#define SERV6_PORT		6060
498c2ecf20Sopenharmony_ci#define SERV6_REWRITE_PORT	6666
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define INET_NTOP_BUF	40
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct sock_addr_test;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_citypedef int (*load_fn)(const struct sock_addr_test *test);
568c2ecf20Sopenharmony_citypedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cichar bpf_log_buf[BPF_LOG_BUF_SIZE];
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct sock_addr_test {
618c2ecf20Sopenharmony_ci	const char *descr;
628c2ecf20Sopenharmony_ci	/* BPF prog properties */
638c2ecf20Sopenharmony_ci	load_fn loadfn;
648c2ecf20Sopenharmony_ci	enum bpf_attach_type expected_attach_type;
658c2ecf20Sopenharmony_ci	enum bpf_attach_type attach_type;
668c2ecf20Sopenharmony_ci	/* Socket properties */
678c2ecf20Sopenharmony_ci	int domain;
688c2ecf20Sopenharmony_ci	int type;
698c2ecf20Sopenharmony_ci	/* IP:port pairs for BPF prog to override */
708c2ecf20Sopenharmony_ci	const char *requested_ip;
718c2ecf20Sopenharmony_ci	unsigned short requested_port;
728c2ecf20Sopenharmony_ci	const char *expected_ip;
738c2ecf20Sopenharmony_ci	unsigned short expected_port;
748c2ecf20Sopenharmony_ci	const char *expected_src_ip;
758c2ecf20Sopenharmony_ci	/* Expected test result */
768c2ecf20Sopenharmony_ci	enum {
778c2ecf20Sopenharmony_ci		LOAD_REJECT,
788c2ecf20Sopenharmony_ci		ATTACH_REJECT,
798c2ecf20Sopenharmony_ci		ATTACH_OKAY,
808c2ecf20Sopenharmony_ci		SYSCALL_EPERM,
818c2ecf20Sopenharmony_ci		SYSCALL_ENOTSUPP,
828c2ecf20Sopenharmony_ci		SUCCESS,
838c2ecf20Sopenharmony_ci	} expected_result;
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int bind4_prog_load(const struct sock_addr_test *test);
878c2ecf20Sopenharmony_cistatic int bind6_prog_load(const struct sock_addr_test *test);
888c2ecf20Sopenharmony_cistatic int connect4_prog_load(const struct sock_addr_test *test);
898c2ecf20Sopenharmony_cistatic int connect6_prog_load(const struct sock_addr_test *test);
908c2ecf20Sopenharmony_cistatic int sendmsg_allow_prog_load(const struct sock_addr_test *test);
918c2ecf20Sopenharmony_cistatic int sendmsg_deny_prog_load(const struct sock_addr_test *test);
928c2ecf20Sopenharmony_cistatic int recvmsg_allow_prog_load(const struct sock_addr_test *test);
938c2ecf20Sopenharmony_cistatic int recvmsg_deny_prog_load(const struct sock_addr_test *test);
948c2ecf20Sopenharmony_cistatic int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
958c2ecf20Sopenharmony_cistatic int recvmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
968c2ecf20Sopenharmony_cistatic int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test);
978c2ecf20Sopenharmony_cistatic int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
988c2ecf20Sopenharmony_cistatic int recvmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
998c2ecf20Sopenharmony_cistatic int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test);
1008c2ecf20Sopenharmony_cistatic int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test);
1018c2ecf20Sopenharmony_cistatic int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic struct sock_addr_test tests[] = {
1048c2ecf20Sopenharmony_ci	/* bind */
1058c2ecf20Sopenharmony_ci	{
1068c2ecf20Sopenharmony_ci		"bind4: load prog with wrong expected attach type",
1078c2ecf20Sopenharmony_ci		bind4_prog_load,
1088c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1098c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1108c2ecf20Sopenharmony_ci		AF_INET,
1118c2ecf20Sopenharmony_ci		SOCK_STREAM,
1128c2ecf20Sopenharmony_ci		NULL,
1138c2ecf20Sopenharmony_ci		0,
1148c2ecf20Sopenharmony_ci		NULL,
1158c2ecf20Sopenharmony_ci		0,
1168c2ecf20Sopenharmony_ci		NULL,
1178c2ecf20Sopenharmony_ci		LOAD_REJECT,
1188c2ecf20Sopenharmony_ci	},
1198c2ecf20Sopenharmony_ci	{
1208c2ecf20Sopenharmony_ci		"bind4: attach prog with wrong attach type",
1218c2ecf20Sopenharmony_ci		bind4_prog_load,
1228c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1238c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1248c2ecf20Sopenharmony_ci		AF_INET,
1258c2ecf20Sopenharmony_ci		SOCK_STREAM,
1268c2ecf20Sopenharmony_ci		NULL,
1278c2ecf20Sopenharmony_ci		0,
1288c2ecf20Sopenharmony_ci		NULL,
1298c2ecf20Sopenharmony_ci		0,
1308c2ecf20Sopenharmony_ci		NULL,
1318c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1328c2ecf20Sopenharmony_ci	},
1338c2ecf20Sopenharmony_ci	{
1348c2ecf20Sopenharmony_ci		"bind4: rewrite IP & TCP port in",
1358c2ecf20Sopenharmony_ci		bind4_prog_load,
1368c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1378c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1388c2ecf20Sopenharmony_ci		AF_INET,
1398c2ecf20Sopenharmony_ci		SOCK_STREAM,
1408c2ecf20Sopenharmony_ci		SERV4_IP,
1418c2ecf20Sopenharmony_ci		SERV4_PORT,
1428c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
1438c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
1448c2ecf20Sopenharmony_ci		NULL,
1458c2ecf20Sopenharmony_ci		SUCCESS,
1468c2ecf20Sopenharmony_ci	},
1478c2ecf20Sopenharmony_ci	{
1488c2ecf20Sopenharmony_ci		"bind4: rewrite IP & UDP port in",
1498c2ecf20Sopenharmony_ci		bind4_prog_load,
1508c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1518c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1528c2ecf20Sopenharmony_ci		AF_INET,
1538c2ecf20Sopenharmony_ci		SOCK_DGRAM,
1548c2ecf20Sopenharmony_ci		SERV4_IP,
1558c2ecf20Sopenharmony_ci		SERV4_PORT,
1568c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
1578c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
1588c2ecf20Sopenharmony_ci		NULL,
1598c2ecf20Sopenharmony_ci		SUCCESS,
1608c2ecf20Sopenharmony_ci	},
1618c2ecf20Sopenharmony_ci	{
1628c2ecf20Sopenharmony_ci		"bind6: load prog with wrong expected attach type",
1638c2ecf20Sopenharmony_ci		bind6_prog_load,
1648c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1658c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1668c2ecf20Sopenharmony_ci		AF_INET6,
1678c2ecf20Sopenharmony_ci		SOCK_STREAM,
1688c2ecf20Sopenharmony_ci		NULL,
1698c2ecf20Sopenharmony_ci		0,
1708c2ecf20Sopenharmony_ci		NULL,
1718c2ecf20Sopenharmony_ci		0,
1728c2ecf20Sopenharmony_ci		NULL,
1738c2ecf20Sopenharmony_ci		LOAD_REJECT,
1748c2ecf20Sopenharmony_ci	},
1758c2ecf20Sopenharmony_ci	{
1768c2ecf20Sopenharmony_ci		"bind6: attach prog with wrong attach type",
1778c2ecf20Sopenharmony_ci		bind6_prog_load,
1788c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1798c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_BIND,
1808c2ecf20Sopenharmony_ci		AF_INET,
1818c2ecf20Sopenharmony_ci		SOCK_STREAM,
1828c2ecf20Sopenharmony_ci		NULL,
1838c2ecf20Sopenharmony_ci		0,
1848c2ecf20Sopenharmony_ci		NULL,
1858c2ecf20Sopenharmony_ci		0,
1868c2ecf20Sopenharmony_ci		NULL,
1878c2ecf20Sopenharmony_ci		ATTACH_REJECT,
1888c2ecf20Sopenharmony_ci	},
1898c2ecf20Sopenharmony_ci	{
1908c2ecf20Sopenharmony_ci		"bind6: rewrite IP & TCP port in",
1918c2ecf20Sopenharmony_ci		bind6_prog_load,
1928c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1938c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
1948c2ecf20Sopenharmony_ci		AF_INET6,
1958c2ecf20Sopenharmony_ci		SOCK_STREAM,
1968c2ecf20Sopenharmony_ci		SERV6_IP,
1978c2ecf20Sopenharmony_ci		SERV6_PORT,
1988c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
1998c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
2008c2ecf20Sopenharmony_ci		NULL,
2018c2ecf20Sopenharmony_ci		SUCCESS,
2028c2ecf20Sopenharmony_ci	},
2038c2ecf20Sopenharmony_ci	{
2048c2ecf20Sopenharmony_ci		"bind6: rewrite IP & UDP port in",
2058c2ecf20Sopenharmony_ci		bind6_prog_load,
2068c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
2078c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_BIND,
2088c2ecf20Sopenharmony_ci		AF_INET6,
2098c2ecf20Sopenharmony_ci		SOCK_DGRAM,
2108c2ecf20Sopenharmony_ci		SERV6_IP,
2118c2ecf20Sopenharmony_ci		SERV6_PORT,
2128c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
2138c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
2148c2ecf20Sopenharmony_ci		NULL,
2158c2ecf20Sopenharmony_ci		SUCCESS,
2168c2ecf20Sopenharmony_ci	},
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* connect */
2198c2ecf20Sopenharmony_ci	{
2208c2ecf20Sopenharmony_ci		"connect4: load prog with wrong expected attach type",
2218c2ecf20Sopenharmony_ci		connect4_prog_load,
2228c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
2238c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2248c2ecf20Sopenharmony_ci		AF_INET,
2258c2ecf20Sopenharmony_ci		SOCK_STREAM,
2268c2ecf20Sopenharmony_ci		NULL,
2278c2ecf20Sopenharmony_ci		0,
2288c2ecf20Sopenharmony_ci		NULL,
2298c2ecf20Sopenharmony_ci		0,
2308c2ecf20Sopenharmony_ci		NULL,
2318c2ecf20Sopenharmony_ci		LOAD_REJECT,
2328c2ecf20Sopenharmony_ci	},
2338c2ecf20Sopenharmony_ci	{
2348c2ecf20Sopenharmony_ci		"connect4: attach prog with wrong attach type",
2358c2ecf20Sopenharmony_ci		connect4_prog_load,
2368c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2378c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
2388c2ecf20Sopenharmony_ci		AF_INET,
2398c2ecf20Sopenharmony_ci		SOCK_STREAM,
2408c2ecf20Sopenharmony_ci		NULL,
2418c2ecf20Sopenharmony_ci		0,
2428c2ecf20Sopenharmony_ci		NULL,
2438c2ecf20Sopenharmony_ci		0,
2448c2ecf20Sopenharmony_ci		NULL,
2458c2ecf20Sopenharmony_ci		ATTACH_REJECT,
2468c2ecf20Sopenharmony_ci	},
2478c2ecf20Sopenharmony_ci	{
2488c2ecf20Sopenharmony_ci		"connect4: rewrite IP & TCP port",
2498c2ecf20Sopenharmony_ci		connect4_prog_load,
2508c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2518c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2528c2ecf20Sopenharmony_ci		AF_INET,
2538c2ecf20Sopenharmony_ci		SOCK_STREAM,
2548c2ecf20Sopenharmony_ci		SERV4_IP,
2558c2ecf20Sopenharmony_ci		SERV4_PORT,
2568c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
2578c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
2588c2ecf20Sopenharmony_ci		SRC4_REWRITE_IP,
2598c2ecf20Sopenharmony_ci		SUCCESS,
2608c2ecf20Sopenharmony_ci	},
2618c2ecf20Sopenharmony_ci	{
2628c2ecf20Sopenharmony_ci		"connect4: rewrite IP & UDP port",
2638c2ecf20Sopenharmony_ci		connect4_prog_load,
2648c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2658c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2668c2ecf20Sopenharmony_ci		AF_INET,
2678c2ecf20Sopenharmony_ci		SOCK_DGRAM,
2688c2ecf20Sopenharmony_ci		SERV4_IP,
2698c2ecf20Sopenharmony_ci		SERV4_PORT,
2708c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
2718c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
2728c2ecf20Sopenharmony_ci		SRC4_REWRITE_IP,
2738c2ecf20Sopenharmony_ci		SUCCESS,
2748c2ecf20Sopenharmony_ci	},
2758c2ecf20Sopenharmony_ci	{
2768c2ecf20Sopenharmony_ci		"connect6: load prog with wrong expected attach type",
2778c2ecf20Sopenharmony_ci		connect6_prog_load,
2788c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2798c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
2808c2ecf20Sopenharmony_ci		AF_INET6,
2818c2ecf20Sopenharmony_ci		SOCK_STREAM,
2828c2ecf20Sopenharmony_ci		NULL,
2838c2ecf20Sopenharmony_ci		0,
2848c2ecf20Sopenharmony_ci		NULL,
2858c2ecf20Sopenharmony_ci		0,
2868c2ecf20Sopenharmony_ci		NULL,
2878c2ecf20Sopenharmony_ci		LOAD_REJECT,
2888c2ecf20Sopenharmony_ci	},
2898c2ecf20Sopenharmony_ci	{
2908c2ecf20Sopenharmony_ci		"connect6: attach prog with wrong attach type",
2918c2ecf20Sopenharmony_ci		connect6_prog_load,
2928c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
2938c2ecf20Sopenharmony_ci		BPF_CGROUP_INET4_CONNECT,
2948c2ecf20Sopenharmony_ci		AF_INET,
2958c2ecf20Sopenharmony_ci		SOCK_STREAM,
2968c2ecf20Sopenharmony_ci		NULL,
2978c2ecf20Sopenharmony_ci		0,
2988c2ecf20Sopenharmony_ci		NULL,
2998c2ecf20Sopenharmony_ci		0,
3008c2ecf20Sopenharmony_ci		NULL,
3018c2ecf20Sopenharmony_ci		ATTACH_REJECT,
3028c2ecf20Sopenharmony_ci	},
3038c2ecf20Sopenharmony_ci	{
3048c2ecf20Sopenharmony_ci		"connect6: rewrite IP & TCP port",
3058c2ecf20Sopenharmony_ci		connect6_prog_load,
3068c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
3078c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
3088c2ecf20Sopenharmony_ci		AF_INET6,
3098c2ecf20Sopenharmony_ci		SOCK_STREAM,
3108c2ecf20Sopenharmony_ci		SERV6_IP,
3118c2ecf20Sopenharmony_ci		SERV6_PORT,
3128c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
3138c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
3148c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
3158c2ecf20Sopenharmony_ci		SUCCESS,
3168c2ecf20Sopenharmony_ci	},
3178c2ecf20Sopenharmony_ci	{
3188c2ecf20Sopenharmony_ci		"connect6: rewrite IP & UDP port",
3198c2ecf20Sopenharmony_ci		connect6_prog_load,
3208c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
3218c2ecf20Sopenharmony_ci		BPF_CGROUP_INET6_CONNECT,
3228c2ecf20Sopenharmony_ci		AF_INET6,
3238c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3248c2ecf20Sopenharmony_ci		SERV6_IP,
3258c2ecf20Sopenharmony_ci		SERV6_PORT,
3268c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
3278c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
3288c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
3298c2ecf20Sopenharmony_ci		SUCCESS,
3308c2ecf20Sopenharmony_ci	},
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* sendmsg */
3338c2ecf20Sopenharmony_ci	{
3348c2ecf20Sopenharmony_ci		"sendmsg4: load prog with wrong expected attach type",
3358c2ecf20Sopenharmony_ci		sendmsg4_rw_asm_prog_load,
3368c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
3378c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3388c2ecf20Sopenharmony_ci		AF_INET,
3398c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3408c2ecf20Sopenharmony_ci		NULL,
3418c2ecf20Sopenharmony_ci		0,
3428c2ecf20Sopenharmony_ci		NULL,
3438c2ecf20Sopenharmony_ci		0,
3448c2ecf20Sopenharmony_ci		NULL,
3458c2ecf20Sopenharmony_ci		LOAD_REJECT,
3468c2ecf20Sopenharmony_ci	},
3478c2ecf20Sopenharmony_ci	{
3488c2ecf20Sopenharmony_ci		"sendmsg4: attach prog with wrong attach type",
3498c2ecf20Sopenharmony_ci		sendmsg4_rw_asm_prog_load,
3508c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3518c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
3528c2ecf20Sopenharmony_ci		AF_INET,
3538c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3548c2ecf20Sopenharmony_ci		NULL,
3558c2ecf20Sopenharmony_ci		0,
3568c2ecf20Sopenharmony_ci		NULL,
3578c2ecf20Sopenharmony_ci		0,
3588c2ecf20Sopenharmony_ci		NULL,
3598c2ecf20Sopenharmony_ci		ATTACH_REJECT,
3608c2ecf20Sopenharmony_ci	},
3618c2ecf20Sopenharmony_ci	{
3628c2ecf20Sopenharmony_ci		"sendmsg4: rewrite IP & port (asm)",
3638c2ecf20Sopenharmony_ci		sendmsg4_rw_asm_prog_load,
3648c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3658c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3668c2ecf20Sopenharmony_ci		AF_INET,
3678c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3688c2ecf20Sopenharmony_ci		SERV4_IP,
3698c2ecf20Sopenharmony_ci		SERV4_PORT,
3708c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
3718c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
3728c2ecf20Sopenharmony_ci		SRC4_REWRITE_IP,
3738c2ecf20Sopenharmony_ci		SUCCESS,
3748c2ecf20Sopenharmony_ci	},
3758c2ecf20Sopenharmony_ci	{
3768c2ecf20Sopenharmony_ci		"sendmsg4: rewrite IP & port (C)",
3778c2ecf20Sopenharmony_ci		sendmsg4_rw_c_prog_load,
3788c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3798c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3808c2ecf20Sopenharmony_ci		AF_INET,
3818c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3828c2ecf20Sopenharmony_ci		SERV4_IP,
3838c2ecf20Sopenharmony_ci		SERV4_PORT,
3848c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
3858c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
3868c2ecf20Sopenharmony_ci		SRC4_REWRITE_IP,
3878c2ecf20Sopenharmony_ci		SUCCESS,
3888c2ecf20Sopenharmony_ci	},
3898c2ecf20Sopenharmony_ci	{
3908c2ecf20Sopenharmony_ci		"sendmsg4: deny call",
3918c2ecf20Sopenharmony_ci		sendmsg_deny_prog_load,
3928c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3938c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
3948c2ecf20Sopenharmony_ci		AF_INET,
3958c2ecf20Sopenharmony_ci		SOCK_DGRAM,
3968c2ecf20Sopenharmony_ci		SERV4_IP,
3978c2ecf20Sopenharmony_ci		SERV4_PORT,
3988c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
3998c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
4008c2ecf20Sopenharmony_ci		SRC4_REWRITE_IP,
4018c2ecf20Sopenharmony_ci		SYSCALL_EPERM,
4028c2ecf20Sopenharmony_ci	},
4038c2ecf20Sopenharmony_ci	{
4048c2ecf20Sopenharmony_ci		"sendmsg6: load prog with wrong expected attach type",
4058c2ecf20Sopenharmony_ci		sendmsg6_rw_asm_prog_load,
4068c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
4078c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4088c2ecf20Sopenharmony_ci		AF_INET6,
4098c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4108c2ecf20Sopenharmony_ci		NULL,
4118c2ecf20Sopenharmony_ci		0,
4128c2ecf20Sopenharmony_ci		NULL,
4138c2ecf20Sopenharmony_ci		0,
4148c2ecf20Sopenharmony_ci		NULL,
4158c2ecf20Sopenharmony_ci		LOAD_REJECT,
4168c2ecf20Sopenharmony_ci	},
4178c2ecf20Sopenharmony_ci	{
4188c2ecf20Sopenharmony_ci		"sendmsg6: attach prog with wrong attach type",
4198c2ecf20Sopenharmony_ci		sendmsg6_rw_asm_prog_load,
4208c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4218c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_SENDMSG,
4228c2ecf20Sopenharmony_ci		AF_INET6,
4238c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4248c2ecf20Sopenharmony_ci		NULL,
4258c2ecf20Sopenharmony_ci		0,
4268c2ecf20Sopenharmony_ci		NULL,
4278c2ecf20Sopenharmony_ci		0,
4288c2ecf20Sopenharmony_ci		NULL,
4298c2ecf20Sopenharmony_ci		ATTACH_REJECT,
4308c2ecf20Sopenharmony_ci	},
4318c2ecf20Sopenharmony_ci	{
4328c2ecf20Sopenharmony_ci		"sendmsg6: rewrite IP & port (asm)",
4338c2ecf20Sopenharmony_ci		sendmsg6_rw_asm_prog_load,
4348c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4358c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4368c2ecf20Sopenharmony_ci		AF_INET6,
4378c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4388c2ecf20Sopenharmony_ci		SERV6_IP,
4398c2ecf20Sopenharmony_ci		SERV6_PORT,
4408c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
4418c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
4428c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
4438c2ecf20Sopenharmony_ci		SUCCESS,
4448c2ecf20Sopenharmony_ci	},
4458c2ecf20Sopenharmony_ci	{
4468c2ecf20Sopenharmony_ci		"sendmsg6: rewrite IP & port (C)",
4478c2ecf20Sopenharmony_ci		sendmsg6_rw_c_prog_load,
4488c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4498c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4508c2ecf20Sopenharmony_ci		AF_INET6,
4518c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4528c2ecf20Sopenharmony_ci		SERV6_IP,
4538c2ecf20Sopenharmony_ci		SERV6_PORT,
4548c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
4558c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
4568c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
4578c2ecf20Sopenharmony_ci		SUCCESS,
4588c2ecf20Sopenharmony_ci	},
4598c2ecf20Sopenharmony_ci	{
4608c2ecf20Sopenharmony_ci		"sendmsg6: IPv4-mapped IPv6",
4618c2ecf20Sopenharmony_ci		sendmsg6_rw_v4mapped_prog_load,
4628c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4638c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4648c2ecf20Sopenharmony_ci		AF_INET6,
4658c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4668c2ecf20Sopenharmony_ci		SERV6_IP,
4678c2ecf20Sopenharmony_ci		SERV6_PORT,
4688c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
4698c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
4708c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
4718c2ecf20Sopenharmony_ci		SYSCALL_ENOTSUPP,
4728c2ecf20Sopenharmony_ci	},
4738c2ecf20Sopenharmony_ci	{
4748c2ecf20Sopenharmony_ci		"sendmsg6: set dst IP = [::] (BSD'ism)",
4758c2ecf20Sopenharmony_ci		sendmsg6_rw_wildcard_prog_load,
4768c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4778c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4788c2ecf20Sopenharmony_ci		AF_INET6,
4798c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4808c2ecf20Sopenharmony_ci		SERV6_IP,
4818c2ecf20Sopenharmony_ci		SERV6_PORT,
4828c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
4838c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
4848c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
4858c2ecf20Sopenharmony_ci		SUCCESS,
4868c2ecf20Sopenharmony_ci	},
4878c2ecf20Sopenharmony_ci	{
4888c2ecf20Sopenharmony_ci		"sendmsg6: preserve dst IP = [::] (BSD'ism)",
4898c2ecf20Sopenharmony_ci		sendmsg_allow_prog_load,
4908c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4918c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
4928c2ecf20Sopenharmony_ci		AF_INET6,
4938c2ecf20Sopenharmony_ci		SOCK_DGRAM,
4948c2ecf20Sopenharmony_ci		WILDCARD6_IP,
4958c2ecf20Sopenharmony_ci		SERV6_PORT,
4968c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
4978c2ecf20Sopenharmony_ci		SERV6_PORT,
4988c2ecf20Sopenharmony_ci		SRC6_IP,
4998c2ecf20Sopenharmony_ci		SUCCESS,
5008c2ecf20Sopenharmony_ci	},
5018c2ecf20Sopenharmony_ci	{
5028c2ecf20Sopenharmony_ci		"sendmsg6: deny call",
5038c2ecf20Sopenharmony_ci		sendmsg_deny_prog_load,
5048c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
5058c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_SENDMSG,
5068c2ecf20Sopenharmony_ci		AF_INET6,
5078c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5088c2ecf20Sopenharmony_ci		SERV6_IP,
5098c2ecf20Sopenharmony_ci		SERV6_PORT,
5108c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
5118c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
5128c2ecf20Sopenharmony_ci		SRC6_REWRITE_IP,
5138c2ecf20Sopenharmony_ci		SYSCALL_EPERM,
5148c2ecf20Sopenharmony_ci	},
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* recvmsg */
5178c2ecf20Sopenharmony_ci	{
5188c2ecf20Sopenharmony_ci		"recvmsg4: return code ok",
5198c2ecf20Sopenharmony_ci		recvmsg_allow_prog_load,
5208c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5218c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5228c2ecf20Sopenharmony_ci		AF_INET,
5238c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5248c2ecf20Sopenharmony_ci		NULL,
5258c2ecf20Sopenharmony_ci		0,
5268c2ecf20Sopenharmony_ci		NULL,
5278c2ecf20Sopenharmony_ci		0,
5288c2ecf20Sopenharmony_ci		NULL,
5298c2ecf20Sopenharmony_ci		ATTACH_OKAY,
5308c2ecf20Sopenharmony_ci	},
5318c2ecf20Sopenharmony_ci	{
5328c2ecf20Sopenharmony_ci		"recvmsg4: return code !ok",
5338c2ecf20Sopenharmony_ci		recvmsg_deny_prog_load,
5348c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5358c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5368c2ecf20Sopenharmony_ci		AF_INET,
5378c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5388c2ecf20Sopenharmony_ci		NULL,
5398c2ecf20Sopenharmony_ci		0,
5408c2ecf20Sopenharmony_ci		NULL,
5418c2ecf20Sopenharmony_ci		0,
5428c2ecf20Sopenharmony_ci		NULL,
5438c2ecf20Sopenharmony_ci		LOAD_REJECT,
5448c2ecf20Sopenharmony_ci	},
5458c2ecf20Sopenharmony_ci	{
5468c2ecf20Sopenharmony_ci		"recvmsg6: return code ok",
5478c2ecf20Sopenharmony_ci		recvmsg_allow_prog_load,
5488c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5498c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5508c2ecf20Sopenharmony_ci		AF_INET6,
5518c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5528c2ecf20Sopenharmony_ci		NULL,
5538c2ecf20Sopenharmony_ci		0,
5548c2ecf20Sopenharmony_ci		NULL,
5558c2ecf20Sopenharmony_ci		0,
5568c2ecf20Sopenharmony_ci		NULL,
5578c2ecf20Sopenharmony_ci		ATTACH_OKAY,
5588c2ecf20Sopenharmony_ci	},
5598c2ecf20Sopenharmony_ci	{
5608c2ecf20Sopenharmony_ci		"recvmsg6: return code !ok",
5618c2ecf20Sopenharmony_ci		recvmsg_deny_prog_load,
5628c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5638c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5648c2ecf20Sopenharmony_ci		AF_INET6,
5658c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5668c2ecf20Sopenharmony_ci		NULL,
5678c2ecf20Sopenharmony_ci		0,
5688c2ecf20Sopenharmony_ci		NULL,
5698c2ecf20Sopenharmony_ci		0,
5708c2ecf20Sopenharmony_ci		NULL,
5718c2ecf20Sopenharmony_ci		LOAD_REJECT,
5728c2ecf20Sopenharmony_ci	},
5738c2ecf20Sopenharmony_ci	{
5748c2ecf20Sopenharmony_ci		"recvmsg4: rewrite IP & port (asm)",
5758c2ecf20Sopenharmony_ci		recvmsg4_rw_asm_prog_load,
5768c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5778c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP4_RECVMSG,
5788c2ecf20Sopenharmony_ci		AF_INET,
5798c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5808c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
5818c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
5828c2ecf20Sopenharmony_ci		SERV4_REWRITE_IP,
5838c2ecf20Sopenharmony_ci		SERV4_REWRITE_PORT,
5848c2ecf20Sopenharmony_ci		SERV4_IP,
5858c2ecf20Sopenharmony_ci		SUCCESS,
5868c2ecf20Sopenharmony_ci	},
5878c2ecf20Sopenharmony_ci	{
5888c2ecf20Sopenharmony_ci		"recvmsg6: rewrite IP & port (asm)",
5898c2ecf20Sopenharmony_ci		recvmsg6_rw_asm_prog_load,
5908c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5918c2ecf20Sopenharmony_ci		BPF_CGROUP_UDP6_RECVMSG,
5928c2ecf20Sopenharmony_ci		AF_INET6,
5938c2ecf20Sopenharmony_ci		SOCK_DGRAM,
5948c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
5958c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
5968c2ecf20Sopenharmony_ci		SERV6_REWRITE_IP,
5978c2ecf20Sopenharmony_ci		SERV6_REWRITE_PORT,
5988c2ecf20Sopenharmony_ci		SERV6_IP,
5998c2ecf20Sopenharmony_ci		SUCCESS,
6008c2ecf20Sopenharmony_ci	},
6018c2ecf20Sopenharmony_ci};
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic int mk_sockaddr(int domain, const char *ip, unsigned short port,
6048c2ecf20Sopenharmony_ci		       struct sockaddr *addr, socklen_t addr_len)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6;
6078c2ecf20Sopenharmony_ci	struct sockaddr_in *addr4;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (domain != AF_INET && domain != AF_INET6) {
6108c2ecf20Sopenharmony_ci		log_err("Unsupported address family");
6118c2ecf20Sopenharmony_ci		return -1;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	memset(addr, 0, addr_len);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (domain == AF_INET) {
6178c2ecf20Sopenharmony_ci		if (addr_len < sizeof(struct sockaddr_in))
6188c2ecf20Sopenharmony_ci			return -1;
6198c2ecf20Sopenharmony_ci		addr4 = (struct sockaddr_in *)addr;
6208c2ecf20Sopenharmony_ci		addr4->sin_family = domain;
6218c2ecf20Sopenharmony_ci		addr4->sin_port = htons(port);
6228c2ecf20Sopenharmony_ci		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
6238c2ecf20Sopenharmony_ci			log_err("Invalid IPv4: %s", ip);
6248c2ecf20Sopenharmony_ci			return -1;
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci	} else if (domain == AF_INET6) {
6278c2ecf20Sopenharmony_ci		if (addr_len < sizeof(struct sockaddr_in6))
6288c2ecf20Sopenharmony_ci			return -1;
6298c2ecf20Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)addr;
6308c2ecf20Sopenharmony_ci		addr6->sin6_family = domain;
6318c2ecf20Sopenharmony_ci		addr6->sin6_port = htons(port);
6328c2ecf20Sopenharmony_ci		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
6338c2ecf20Sopenharmony_ci			log_err("Invalid IPv6: %s", ip);
6348c2ecf20Sopenharmony_ci			return -1;
6358c2ecf20Sopenharmony_ci		}
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return 0;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic int load_insns(const struct sock_addr_test *test,
6428c2ecf20Sopenharmony_ci		      const struct bpf_insn *insns, size_t insns_cnt)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct bpf_load_program_attr load_attr;
6458c2ecf20Sopenharmony_ci	int ret;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
6488c2ecf20Sopenharmony_ci	load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
6498c2ecf20Sopenharmony_ci	load_attr.expected_attach_type = test->expected_attach_type;
6508c2ecf20Sopenharmony_ci	load_attr.insns = insns;
6518c2ecf20Sopenharmony_ci	load_attr.insns_cnt = insns_cnt;
6528c2ecf20Sopenharmony_ci	load_attr.license = "GPL";
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE);
6558c2ecf20Sopenharmony_ci	if (ret < 0 && test->expected_result != LOAD_REJECT) {
6568c2ecf20Sopenharmony_ci		log_err(">>> Loading program error.\n"
6578c2ecf20Sopenharmony_ci			">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	return ret;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/* [1] These testing programs try to read different context fields, including
6648c2ecf20Sopenharmony_ci * narrow loads of different sizes from user_ip4 and user_ip6, and write to
6658c2ecf20Sopenharmony_ci * those allowed to be overridden.
6668c2ecf20Sopenharmony_ci *
6678c2ecf20Sopenharmony_ci * [2] BPF_LD_IMM64 & BPF_JMP_REG are used below whenever there is a need to
6688c2ecf20Sopenharmony_ci * compare a register with unsigned 32bit integer. BPF_JMP_IMM can't be used
6698c2ecf20Sopenharmony_ci * in such cases since it accepts only _signed_ 32bit integer as IMM
6708c2ecf20Sopenharmony_ci * argument. Also note that BPF_LD_IMM64 contains 2 instructions what matters
6718c2ecf20Sopenharmony_ci * to count jumps properly.
6728c2ecf20Sopenharmony_ci */
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic int bind4_prog_load(const struct sock_addr_test *test)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	union {
6778c2ecf20Sopenharmony_ci		uint8_t u4_addr8[4];
6788c2ecf20Sopenharmony_ci		uint16_t u4_addr16[2];
6798c2ecf20Sopenharmony_ci		uint32_t u4_addr32;
6808c2ecf20Sopenharmony_ci	} ip4, port;
6818c2ecf20Sopenharmony_ci	struct sockaddr_in addr4_rw;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (inet_pton(AF_INET, SERV4_IP, (void *)&ip4) != 1) {
6848c2ecf20Sopenharmony_ci		log_err("Invalid IPv4: %s", SERV4_IP);
6858c2ecf20Sopenharmony_ci		return -1;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	port.u4_addr32 = htons(SERV4_PORT);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
6918c2ecf20Sopenharmony_ci			(struct sockaddr *)&addr4_rw, sizeof(addr4_rw)) == -1)
6928c2ecf20Sopenharmony_ci		return -1;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/* See [1]. */
6958c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
6968c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET && */
6998c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
7008c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
7018c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 32),
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		/*     (sk.type == SOCK_DGRAM || sk.type == SOCK_STREAM) && */
7048c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
7058c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, type)),
7068c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 1),
7078c2ecf20Sopenharmony_ci		BPF_JMP_A(1),
7088c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_STREAM, 28),
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		/*     1st_byte_of_user_ip4 == expected && */
7118c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
7128c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
7138c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[0], 26),
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci		/*     2nd_byte_of_user_ip4 == expected && */
7168c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
7178c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4) + 1),
7188c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[1], 24),
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		/*     3rd_byte_of_user_ip4 == expected && */
7218c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
7228c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4) + 2),
7238c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[2], 22),
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		/*     4th_byte_of_user_ip4 == expected && */
7268c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
7278c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4) + 3),
7288c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[3], 20),
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		/*     1st_half_of_user_ip4 == expected && */
7318c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
7328c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
7338c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[0], 18),
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		/*     2nd_half_of_user_ip4 == expected && */
7368c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
7378c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4) + 2),
7388c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[1], 16),
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci		/*     whole_user_ip4 == expected && */
7418c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
7428c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
7438c2ecf20Sopenharmony_ci		BPF_LD_IMM64(BPF_REG_8, ip4.u4_addr32), /* See [2]. */
7448c2ecf20Sopenharmony_ci		BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 12),
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		/*     1st_byte_of_user_port == expected && */
7478c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
7488c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
7498c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, port.u4_addr8[0], 10),
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		/*     1st_half_of_user_port == expected && */
7528c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
7538c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
7548c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, port.u4_addr16[0], 8),
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci		/*     user_port == expected) { */
7578c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
7588c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
7598c2ecf20Sopenharmony_ci		BPF_LD_IMM64(BPF_REG_8, port.u4_addr32), /* See [2]. */
7608c2ecf20Sopenharmony_ci		BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 4),
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		/*      user_ip4 = addr4_rw.sin_addr */
7638c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_addr.s_addr),
7648c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
7658c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		/*      user_port = addr4_rw.sin_port */
7688c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_port),
7698c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
7708c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
7718c2ecf20Sopenharmony_ci		/* } */
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		/* return 1 */
7748c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
7758c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
7768c2ecf20Sopenharmony_ci	};
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic int bind6_prog_load(const struct sock_addr_test *test)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct sockaddr_in6 addr6_rw;
7848c2ecf20Sopenharmony_ci	struct in6_addr ip6;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (inet_pton(AF_INET6, SERV6_IP, (void *)&ip6) != 1) {
7878c2ecf20Sopenharmony_ci		log_err("Invalid IPv6: %s", SERV6_IP);
7888c2ecf20Sopenharmony_ci		return -1;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET6, SERV6_REWRITE_IP, SERV6_REWRITE_PORT,
7928c2ecf20Sopenharmony_ci			(struct sockaddr *)&addr6_rw, sizeof(addr6_rw)) == -1)
7938c2ecf20Sopenharmony_ci		return -1;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	/* See [1]. */
7968c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
7978c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET6 && */
8008c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
8018c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
8028c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci		/*            5th_byte_of_user_ip6 == expected && */
8058c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6,
8068c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip6[1])),
8078c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr[4], 16),
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci		/*            3rd_half_of_user_ip6 == expected && */
8108c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6,
8118c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip6[1])),
8128c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr16[2], 14),
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		/*            last_word_of_user_ip6 == expected) { */
8158c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
8168c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip6[3])),
8178c2ecf20Sopenharmony_ci		BPF_LD_IMM64(BPF_REG_8, ip6.s6_addr32[3]),  /* See [2]. */
8188c2ecf20Sopenharmony_ci		BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 10),
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci#define STORE_IPV6_WORD(N)						       \
8228c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_addr.s6_addr32[N]),     \
8238c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,		       \
8248c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip6[N]))
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		/*      user_ip6 = addr6_rw.sin6_addr */
8278c2ecf20Sopenharmony_ci		STORE_IPV6_WORD(0),
8288c2ecf20Sopenharmony_ci		STORE_IPV6_WORD(1),
8298c2ecf20Sopenharmony_ci		STORE_IPV6_WORD(2),
8308c2ecf20Sopenharmony_ci		STORE_IPV6_WORD(3),
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		/*      user_port = addr6_rw.sin6_port */
8338c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_port),
8348c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
8358c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		/* } */
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		/* return 1 */
8408c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
8418c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
8428c2ecf20Sopenharmony_ci	};
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int load_path(const struct sock_addr_test *test, const char *path)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct bpf_prog_load_attr attr;
8508c2ecf20Sopenharmony_ci	struct bpf_object *obj;
8518c2ecf20Sopenharmony_ci	int prog_fd;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
8548c2ecf20Sopenharmony_ci	attr.file = path;
8558c2ecf20Sopenharmony_ci	attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
8568c2ecf20Sopenharmony_ci	attr.expected_attach_type = test->expected_attach_type;
8578c2ecf20Sopenharmony_ci	attr.prog_flags = BPF_F_TEST_RND_HI32;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
8608c2ecf20Sopenharmony_ci		if (test->expected_result != LOAD_REJECT)
8618c2ecf20Sopenharmony_ci			log_err(">>> Loading program (%s) error.\n", path);
8628c2ecf20Sopenharmony_ci		return -1;
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	return prog_fd;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic int connect4_prog_load(const struct sock_addr_test *test)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	return load_path(test, CONNECT4_PROG_PATH);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic int connect6_prog_load(const struct sock_addr_test *test)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	return load_path(test, CONNECT6_PROG_PATH);
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic int xmsg_ret_only_prog_load(const struct sock_addr_test *test,
8798c2ecf20Sopenharmony_ci				   int32_t rc)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
8828c2ecf20Sopenharmony_ci		/* return rc */
8838c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, rc),
8848c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
8858c2ecf20Sopenharmony_ci	};
8868c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
8878c2ecf20Sopenharmony_ci}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic int sendmsg_allow_prog_load(const struct sock_addr_test *test)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_cistatic int sendmsg_deny_prog_load(const struct sock_addr_test *test)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic int recvmsg_allow_prog_load(const struct sock_addr_test *test)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic int recvmsg_deny_prog_load(const struct sock_addr_test *test)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	struct sockaddr_in dst4_rw_addr;
9128c2ecf20Sopenharmony_ci	struct in_addr src4_rw_ip;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) {
9158c2ecf20Sopenharmony_ci		log_err("Invalid IPv4: %s", SRC4_REWRITE_IP);
9168c2ecf20Sopenharmony_ci		return -1;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
9208c2ecf20Sopenharmony_ci			(struct sockaddr *)&dst4_rw_addr,
9218c2ecf20Sopenharmony_ci			sizeof(dst4_rw_addr)) == -1)
9228c2ecf20Sopenharmony_ci		return -1;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
9258c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET && */
9288c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
9298c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
9308c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8),
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		/*     sk.type == SOCK_DGRAM)  { */
9338c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
9348c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, type)),
9358c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6),
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci		/*      msg_src_ip4 = src4_rw_ip */
9388c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr),
9398c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
9408c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, msg_src_ip4)),
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		/*      user_ip4 = dst4_rw_addr.sin_addr */
9438c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr),
9448c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
9458c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		/*      user_port = dst4_rw_addr.sin_port */
9488c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port),
9498c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
9508c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
9518c2ecf20Sopenharmony_ci		/* } */
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci		/* return 1 */
9548c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
9558c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
9568c2ecf20Sopenharmony_ci	};
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic int recvmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct sockaddr_in src4_rw_addr;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET, SERV4_IP, SERV4_PORT,
9668c2ecf20Sopenharmony_ci			(struct sockaddr *)&src4_rw_addr,
9678c2ecf20Sopenharmony_ci			sizeof(src4_rw_addr)) == -1)
9688c2ecf20Sopenharmony_ci		return -1;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
9718c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET && */
9748c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
9758c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
9768c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 6),
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		/*     sk.type == SOCK_DGRAM)  { */
9798c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
9808c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, type)),
9818c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 4),
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		/*      user_ip4 = src4_rw_addr.sin_addr */
9848c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, src4_rw_addr.sin_addr.s_addr),
9858c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
9868c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_ip4)),
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		/*      user_port = src4_rw_addr.sin_port */
9898c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, src4_rw_addr.sin_port),
9908c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
9918c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
9928c2ecf20Sopenharmony_ci		/* } */
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		/* return 1 */
9958c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
9968c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
9978c2ecf20Sopenharmony_ci	};
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	return load_path(test, SENDMSG4_PROG_PATH);
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test,
10088c2ecf20Sopenharmony_ci					 const char *rw_dst_ip)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	struct sockaddr_in6 dst6_rw_addr;
10118c2ecf20Sopenharmony_ci	struct in6_addr src6_rw_ip;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) {
10148c2ecf20Sopenharmony_ci		log_err("Invalid IPv6: %s", SRC6_REWRITE_IP);
10158c2ecf20Sopenharmony_ci		return -1;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT,
10198c2ecf20Sopenharmony_ci			(struct sockaddr *)&dst6_rw_addr,
10208c2ecf20Sopenharmony_ci			sizeof(dst6_rw_addr)) == -1)
10218c2ecf20Sopenharmony_ci		return -1;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
10248c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET6) { */
10278c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
10288c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
10298c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci#define STORE_IPV6_WORD_N(DST, SRC, N)					       \
10328c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, SRC[N]),			       \
10338c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,		       \
10348c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, DST[N]))
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci#define STORE_IPV6(DST, SRC)						       \
10378c2ecf20Sopenharmony_ci		STORE_IPV6_WORD_N(DST, SRC, 0),				       \
10388c2ecf20Sopenharmony_ci		STORE_IPV6_WORD_N(DST, SRC, 1),				       \
10398c2ecf20Sopenharmony_ci		STORE_IPV6_WORD_N(DST, SRC, 2),				       \
10408c2ecf20Sopenharmony_ci		STORE_IPV6_WORD_N(DST, SRC, 3)
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci		STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32),
10438c2ecf20Sopenharmony_ci		STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32),
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		/*      user_port = dst6_rw_addr.sin6_port */
10468c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port),
10478c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
10488c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci		/* } */
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		/* return 1 */
10538c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
10548c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
10558c2ecf20Sopenharmony_ci	};
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP);
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic int recvmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct sockaddr_in6 src6_rw_addr;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	if (mk_sockaddr(AF_INET6, SERV6_IP, SERV6_PORT,
10708c2ecf20Sopenharmony_ci			(struct sockaddr *)&src6_rw_addr,
10718c2ecf20Sopenharmony_ci			sizeof(src6_rw_addr)) == -1)
10728c2ecf20Sopenharmony_ci		return -1;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	struct bpf_insn insns[] = {
10758c2ecf20Sopenharmony_ci		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		/* if (sk.family == AF_INET6) { */
10788c2ecf20Sopenharmony_ci		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
10798c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, family)),
10808c2ecf20Sopenharmony_ci		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 10),
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		STORE_IPV6(user_ip6, src6_rw_addr.sin6_addr.s6_addr32),
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		/*      user_port = dst6_rw_addr.sin6_port */
10858c2ecf20Sopenharmony_ci		BPF_MOV32_IMM(BPF_REG_7, src6_rw_addr.sin6_port),
10868c2ecf20Sopenharmony_ci		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
10878c2ecf20Sopenharmony_ci			    offsetof(struct bpf_sock_addr, user_port)),
10888c2ecf20Sopenharmony_ci		/* } */
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci		/* return 1 */
10918c2ecf20Sopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 1),
10928c2ecf20Sopenharmony_ci		BPF_EXIT_INSN(),
10938c2ecf20Sopenharmony_ci	};
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn));
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP);
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP);
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	return load_path(test, SENDMSG6_PROG_PATH);
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic int cmp_addr(const struct sockaddr_storage *addr1,
11148c2ecf20Sopenharmony_ci		    const struct sockaddr_storage *addr2, int cmp_port)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	const struct sockaddr_in *four1, *four2;
11178c2ecf20Sopenharmony_ci	const struct sockaddr_in6 *six1, *six2;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (addr1->ss_family != addr2->ss_family)
11208c2ecf20Sopenharmony_ci		return -1;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	if (addr1->ss_family == AF_INET) {
11238c2ecf20Sopenharmony_ci		four1 = (const struct sockaddr_in *)addr1;
11248c2ecf20Sopenharmony_ci		four2 = (const struct sockaddr_in *)addr2;
11258c2ecf20Sopenharmony_ci		return !((four1->sin_port == four2->sin_port || !cmp_port) &&
11268c2ecf20Sopenharmony_ci			 four1->sin_addr.s_addr == four2->sin_addr.s_addr);
11278c2ecf20Sopenharmony_ci	} else if (addr1->ss_family == AF_INET6) {
11288c2ecf20Sopenharmony_ci		six1 = (const struct sockaddr_in6 *)addr1;
11298c2ecf20Sopenharmony_ci		six2 = (const struct sockaddr_in6 *)addr2;
11308c2ecf20Sopenharmony_ci		return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
11318c2ecf20Sopenharmony_ci			 !memcmp(&six1->sin6_addr, &six2->sin6_addr,
11328c2ecf20Sopenharmony_ci				 sizeof(struct in6_addr)));
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	return -1;
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic int cmp_sock_addr(info_fn fn, int sock1,
11398c2ecf20Sopenharmony_ci			 const struct sockaddr_storage *addr2, int cmp_port)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct sockaddr_storage addr1;
11428c2ecf20Sopenharmony_ci	socklen_t len1 = sizeof(addr1);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	memset(&addr1, 0, len1);
11458c2ecf20Sopenharmony_ci	if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
11468c2ecf20Sopenharmony_ci		return -1;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	return cmp_addr(&addr1, addr2, cmp_port);
11498c2ecf20Sopenharmony_ci}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_cistatic int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0);
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1);
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_cistatic int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2)
11628c2ecf20Sopenharmony_ci{
11638c2ecf20Sopenharmony_ci	return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1);
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cistatic int start_server(int type, const struct sockaddr_storage *addr,
11678c2ecf20Sopenharmony_ci			socklen_t addr_len)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	int fd;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	fd = socket(addr->ss_family, type, 0);
11728c2ecf20Sopenharmony_ci	if (fd == -1) {
11738c2ecf20Sopenharmony_ci		log_err("Failed to create server socket");
11748c2ecf20Sopenharmony_ci		goto out;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) {
11788c2ecf20Sopenharmony_ci		log_err("Failed to bind server socket");
11798c2ecf20Sopenharmony_ci		goto close_out;
11808c2ecf20Sopenharmony_ci	}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (type == SOCK_STREAM) {
11838c2ecf20Sopenharmony_ci		if (listen(fd, 128) == -1) {
11848c2ecf20Sopenharmony_ci			log_err("Failed to listen on server socket");
11858c2ecf20Sopenharmony_ci			goto close_out;
11868c2ecf20Sopenharmony_ci		}
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	goto out;
11908c2ecf20Sopenharmony_ciclose_out:
11918c2ecf20Sopenharmony_ci	close(fd);
11928c2ecf20Sopenharmony_ci	fd = -1;
11938c2ecf20Sopenharmony_ciout:
11948c2ecf20Sopenharmony_ci	return fd;
11958c2ecf20Sopenharmony_ci}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_cistatic int connect_to_server(int type, const struct sockaddr_storage *addr,
11988c2ecf20Sopenharmony_ci			     socklen_t addr_len)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	int domain;
12018c2ecf20Sopenharmony_ci	int fd = -1;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	domain = addr->ss_family;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (domain != AF_INET && domain != AF_INET6) {
12068c2ecf20Sopenharmony_ci		log_err("Unsupported address family");
12078c2ecf20Sopenharmony_ci		goto err;
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	fd = socket(domain, type, 0);
12118c2ecf20Sopenharmony_ci	if (fd == -1) {
12128c2ecf20Sopenharmony_ci		log_err("Failed to create client socket");
12138c2ecf20Sopenharmony_ci		goto err;
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
12178c2ecf20Sopenharmony_ci		log_err("Fail to connect to server");
12188c2ecf20Sopenharmony_ci		goto err;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	goto out;
12228c2ecf20Sopenharmony_cierr:
12238c2ecf20Sopenharmony_ci	close(fd);
12248c2ecf20Sopenharmony_ci	fd = -1;
12258c2ecf20Sopenharmony_ciout:
12268c2ecf20Sopenharmony_ci	return fd;
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ciint init_pktinfo(int domain, struct cmsghdr *cmsg)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	struct in6_pktinfo *pktinfo6;
12328c2ecf20Sopenharmony_ci	struct in_pktinfo *pktinfo4;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if (domain == AF_INET) {
12358c2ecf20Sopenharmony_ci		cmsg->cmsg_level = SOL_IP;
12368c2ecf20Sopenharmony_ci		cmsg->cmsg_type = IP_PKTINFO;
12378c2ecf20Sopenharmony_ci		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
12388c2ecf20Sopenharmony_ci		pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg);
12398c2ecf20Sopenharmony_ci		memset(pktinfo4, 0, sizeof(struct in_pktinfo));
12408c2ecf20Sopenharmony_ci		if (inet_pton(domain, SRC4_IP,
12418c2ecf20Sopenharmony_ci			      (void *)&pktinfo4->ipi_spec_dst) != 1)
12428c2ecf20Sopenharmony_ci			return -1;
12438c2ecf20Sopenharmony_ci	} else if (domain == AF_INET6) {
12448c2ecf20Sopenharmony_ci		cmsg->cmsg_level = SOL_IPV6;
12458c2ecf20Sopenharmony_ci		cmsg->cmsg_type = IPV6_PKTINFO;
12468c2ecf20Sopenharmony_ci		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
12478c2ecf20Sopenharmony_ci		pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
12488c2ecf20Sopenharmony_ci		memset(pktinfo6, 0, sizeof(struct in6_pktinfo));
12498c2ecf20Sopenharmony_ci		if (inet_pton(domain, SRC6_IP,
12508c2ecf20Sopenharmony_ci			      (void *)&pktinfo6->ipi6_addr) != 1)
12518c2ecf20Sopenharmony_ci			return -1;
12528c2ecf20Sopenharmony_ci	} else {
12538c2ecf20Sopenharmony_ci		return -1;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return 0;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
12608c2ecf20Sopenharmony_ci			     socklen_t addr_len, int set_cmsg, int flags,
12618c2ecf20Sopenharmony_ci			     int *syscall_err)
12628c2ecf20Sopenharmony_ci{
12638c2ecf20Sopenharmony_ci	union {
12648c2ecf20Sopenharmony_ci		char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
12658c2ecf20Sopenharmony_ci		struct cmsghdr align;
12668c2ecf20Sopenharmony_ci	} control6;
12678c2ecf20Sopenharmony_ci	union {
12688c2ecf20Sopenharmony_ci		char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
12698c2ecf20Sopenharmony_ci		struct cmsghdr align;
12708c2ecf20Sopenharmony_ci	} control4;
12718c2ecf20Sopenharmony_ci	struct msghdr hdr;
12728c2ecf20Sopenharmony_ci	struct iovec iov;
12738c2ecf20Sopenharmony_ci	char data = 'a';
12748c2ecf20Sopenharmony_ci	int domain;
12758c2ecf20Sopenharmony_ci	int fd = -1;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	domain = addr->ss_family;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (domain != AF_INET && domain != AF_INET6) {
12808c2ecf20Sopenharmony_ci		log_err("Unsupported address family");
12818c2ecf20Sopenharmony_ci		goto err;
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	fd = socket(domain, type, 0);
12858c2ecf20Sopenharmony_ci	if (fd == -1) {
12868c2ecf20Sopenharmony_ci		log_err("Failed to create client socket");
12878c2ecf20Sopenharmony_ci		goto err;
12888c2ecf20Sopenharmony_ci	}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	memset(&iov, 0, sizeof(iov));
12918c2ecf20Sopenharmony_ci	iov.iov_base = &data;
12928c2ecf20Sopenharmony_ci	iov.iov_len = sizeof(data);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	memset(&hdr, 0, sizeof(hdr));
12958c2ecf20Sopenharmony_ci	hdr.msg_name = (void *)addr;
12968c2ecf20Sopenharmony_ci	hdr.msg_namelen = addr_len;
12978c2ecf20Sopenharmony_ci	hdr.msg_iov = &iov;
12988c2ecf20Sopenharmony_ci	hdr.msg_iovlen = 1;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (set_cmsg) {
13018c2ecf20Sopenharmony_ci		if (domain == AF_INET) {
13028c2ecf20Sopenharmony_ci			hdr.msg_control = &control4;
13038c2ecf20Sopenharmony_ci			hdr.msg_controllen = sizeof(control4.buf);
13048c2ecf20Sopenharmony_ci		} else if (domain == AF_INET6) {
13058c2ecf20Sopenharmony_ci			hdr.msg_control = &control6;
13068c2ecf20Sopenharmony_ci			hdr.msg_controllen = sizeof(control6.buf);
13078c2ecf20Sopenharmony_ci		}
13088c2ecf20Sopenharmony_ci		if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) {
13098c2ecf20Sopenharmony_ci			log_err("Fail to init pktinfo");
13108c2ecf20Sopenharmony_ci			goto err;
13118c2ecf20Sopenharmony_ci		}
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
13158c2ecf20Sopenharmony_ci		log_err("Fail to send message to server");
13168c2ecf20Sopenharmony_ci		*syscall_err = errno;
13178c2ecf20Sopenharmony_ci		goto err;
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	goto out;
13218c2ecf20Sopenharmony_cierr:
13228c2ecf20Sopenharmony_ci	close(fd);
13238c2ecf20Sopenharmony_ci	fd = -1;
13248c2ecf20Sopenharmony_ciout:
13258c2ecf20Sopenharmony_ci	return fd;
13268c2ecf20Sopenharmony_ci}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_cistatic int fastconnect_to_server(const struct sockaddr_storage *addr,
13298c2ecf20Sopenharmony_ci				 socklen_t addr_len)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	int sendmsg_err;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
13348c2ecf20Sopenharmony_ci				 MSG_FASTOPEN, &sendmsg_err);
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cistatic int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct timeval tv;
13408c2ecf20Sopenharmony_ci	struct msghdr hdr;
13418c2ecf20Sopenharmony_ci	struct iovec iov;
13428c2ecf20Sopenharmony_ci	char data[64];
13438c2ecf20Sopenharmony_ci	fd_set rfds;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	FD_ZERO(&rfds);
13468c2ecf20Sopenharmony_ci	FD_SET(sockfd, &rfds);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	tv.tv_sec = 2;
13498c2ecf20Sopenharmony_ci	tv.tv_usec = 0;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 ||
13528c2ecf20Sopenharmony_ci	    !FD_ISSET(sockfd, &rfds))
13538c2ecf20Sopenharmony_ci		return -1;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	memset(&iov, 0, sizeof(iov));
13568c2ecf20Sopenharmony_ci	iov.iov_base = data;
13578c2ecf20Sopenharmony_ci	iov.iov_len = sizeof(data);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	memset(&hdr, 0, sizeof(hdr));
13608c2ecf20Sopenharmony_ci	hdr.msg_name = src_addr;
13618c2ecf20Sopenharmony_ci	hdr.msg_namelen = sizeof(struct sockaddr_storage);
13628c2ecf20Sopenharmony_ci	hdr.msg_iov = &iov;
13638c2ecf20Sopenharmony_ci	hdr.msg_iovlen = 1;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	return recvmsg(sockfd, &hdr, 0);
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_cistatic int init_addrs(const struct sock_addr_test *test,
13698c2ecf20Sopenharmony_ci		      struct sockaddr_storage *requested_addr,
13708c2ecf20Sopenharmony_ci		      struct sockaddr_storage *expected_addr,
13718c2ecf20Sopenharmony_ci		      struct sockaddr_storage *expected_src_addr)
13728c2ecf20Sopenharmony_ci{
13738c2ecf20Sopenharmony_ci	socklen_t addr_len = sizeof(struct sockaddr_storage);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port,
13768c2ecf20Sopenharmony_ci			(struct sockaddr *)expected_addr, addr_len) == -1)
13778c2ecf20Sopenharmony_ci		goto err;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port,
13808c2ecf20Sopenharmony_ci			(struct sockaddr *)requested_addr, addr_len) == -1)
13818c2ecf20Sopenharmony_ci		goto err;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	if (test->expected_src_ip &&
13848c2ecf20Sopenharmony_ci	    mk_sockaddr(test->domain, test->expected_src_ip, 0,
13858c2ecf20Sopenharmony_ci			(struct sockaddr *)expected_src_addr, addr_len) == -1)
13868c2ecf20Sopenharmony_ci		goto err;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	return 0;
13898c2ecf20Sopenharmony_cierr:
13908c2ecf20Sopenharmony_ci	return -1;
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic int run_bind_test_case(const struct sock_addr_test *test)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	socklen_t addr_len = sizeof(struct sockaddr_storage);
13968c2ecf20Sopenharmony_ci	struct sockaddr_storage requested_addr;
13978c2ecf20Sopenharmony_ci	struct sockaddr_storage expected_addr;
13988c2ecf20Sopenharmony_ci	int clientfd = -1;
13998c2ecf20Sopenharmony_ci	int servfd = -1;
14008c2ecf20Sopenharmony_ci	int err = 0;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (init_addrs(test, &requested_addr, &expected_addr, NULL))
14038c2ecf20Sopenharmony_ci		goto err;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	servfd = start_server(test->type, &requested_addr, addr_len);
14068c2ecf20Sopenharmony_ci	if (servfd == -1)
14078c2ecf20Sopenharmony_ci		goto err;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	if (cmp_local_addr(servfd, &expected_addr))
14108c2ecf20Sopenharmony_ci		goto err;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/* Try to connect to server just in case */
14138c2ecf20Sopenharmony_ci	clientfd = connect_to_server(test->type, &expected_addr, addr_len);
14148c2ecf20Sopenharmony_ci	if (clientfd == -1)
14158c2ecf20Sopenharmony_ci		goto err;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	goto out;
14188c2ecf20Sopenharmony_cierr:
14198c2ecf20Sopenharmony_ci	err = -1;
14208c2ecf20Sopenharmony_ciout:
14218c2ecf20Sopenharmony_ci	close(clientfd);
14228c2ecf20Sopenharmony_ci	close(servfd);
14238c2ecf20Sopenharmony_ci	return err;
14248c2ecf20Sopenharmony_ci}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_cistatic int run_connect_test_case(const struct sock_addr_test *test)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	socklen_t addr_len = sizeof(struct sockaddr_storage);
14298c2ecf20Sopenharmony_ci	struct sockaddr_storage expected_src_addr;
14308c2ecf20Sopenharmony_ci	struct sockaddr_storage requested_addr;
14318c2ecf20Sopenharmony_ci	struct sockaddr_storage expected_addr;
14328c2ecf20Sopenharmony_ci	int clientfd = -1;
14338c2ecf20Sopenharmony_ci	int servfd = -1;
14348c2ecf20Sopenharmony_ci	int err = 0;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	if (init_addrs(test, &requested_addr, &expected_addr,
14378c2ecf20Sopenharmony_ci		       &expected_src_addr))
14388c2ecf20Sopenharmony_ci		goto err;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	/* Prepare server to connect to */
14418c2ecf20Sopenharmony_ci	servfd = start_server(test->type, &expected_addr, addr_len);
14428c2ecf20Sopenharmony_ci	if (servfd == -1)
14438c2ecf20Sopenharmony_ci		goto err;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	clientfd = connect_to_server(test->type, &requested_addr, addr_len);
14468c2ecf20Sopenharmony_ci	if (clientfd == -1)
14478c2ecf20Sopenharmony_ci		goto err;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	/* Make sure src and dst addrs were overridden properly */
14508c2ecf20Sopenharmony_ci	if (cmp_peer_addr(clientfd, &expected_addr))
14518c2ecf20Sopenharmony_ci		goto err;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	if (cmp_local_ip(clientfd, &expected_src_addr))
14548c2ecf20Sopenharmony_ci		goto err;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (test->type == SOCK_STREAM) {
14578c2ecf20Sopenharmony_ci		/* Test TCP Fast Open scenario */
14588c2ecf20Sopenharmony_ci		clientfd = fastconnect_to_server(&requested_addr, addr_len);
14598c2ecf20Sopenharmony_ci		if (clientfd == -1)
14608c2ecf20Sopenharmony_ci			goto err;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		/* Make sure src and dst addrs were overridden properly */
14638c2ecf20Sopenharmony_ci		if (cmp_peer_addr(clientfd, &expected_addr))
14648c2ecf20Sopenharmony_ci			goto err;
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci		if (cmp_local_ip(clientfd, &expected_src_addr))
14678c2ecf20Sopenharmony_ci			goto err;
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	goto out;
14718c2ecf20Sopenharmony_cierr:
14728c2ecf20Sopenharmony_ci	err = -1;
14738c2ecf20Sopenharmony_ciout:
14748c2ecf20Sopenharmony_ci	close(clientfd);
14758c2ecf20Sopenharmony_ci	close(servfd);
14768c2ecf20Sopenharmony_ci	return err;
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_cistatic int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	socklen_t addr_len = sizeof(struct sockaddr_storage);
14828c2ecf20Sopenharmony_ci	struct sockaddr_storage expected_addr;
14838c2ecf20Sopenharmony_ci	struct sockaddr_storage server_addr;
14848c2ecf20Sopenharmony_ci	struct sockaddr_storage sendmsg_addr;
14858c2ecf20Sopenharmony_ci	struct sockaddr_storage recvmsg_addr;
14868c2ecf20Sopenharmony_ci	int clientfd = -1;
14878c2ecf20Sopenharmony_ci	int servfd = -1;
14888c2ecf20Sopenharmony_ci	int set_cmsg;
14898c2ecf20Sopenharmony_ci	int err = 0;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	if (test->type != SOCK_DGRAM)
14928c2ecf20Sopenharmony_ci		goto err;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr))
14958c2ecf20Sopenharmony_ci		goto err;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	/* Prepare server to sendmsg to */
14988c2ecf20Sopenharmony_ci	servfd = start_server(test->type, &server_addr, addr_len);
14998c2ecf20Sopenharmony_ci	if (servfd == -1)
15008c2ecf20Sopenharmony_ci		goto err;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) {
15038c2ecf20Sopenharmony_ci		if (clientfd >= 0)
15048c2ecf20Sopenharmony_ci			close(clientfd);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci		clientfd = sendmsg_to_server(test->type, &sendmsg_addr,
15078c2ecf20Sopenharmony_ci					     addr_len, set_cmsg, /*flags*/0,
15088c2ecf20Sopenharmony_ci					     &err);
15098c2ecf20Sopenharmony_ci		if (err)
15108c2ecf20Sopenharmony_ci			goto out;
15118c2ecf20Sopenharmony_ci		else if (clientfd == -1)
15128c2ecf20Sopenharmony_ci			goto err;
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci		/* Try to receive message on server instead of using
15158c2ecf20Sopenharmony_ci		 * getpeername(2) on client socket, to check that client's
15168c2ecf20Sopenharmony_ci		 * destination address was rewritten properly, since
15178c2ecf20Sopenharmony_ci		 * getpeername(2) doesn't work with unconnected datagram
15188c2ecf20Sopenharmony_ci		 * sockets.
15198c2ecf20Sopenharmony_ci		 *
15208c2ecf20Sopenharmony_ci		 * Get source address from recvmsg(2) as well to make sure
15218c2ecf20Sopenharmony_ci		 * source was rewritten properly: getsockname(2) can't be used
15228c2ecf20Sopenharmony_ci		 * since socket is unconnected and source defined for one
15238c2ecf20Sopenharmony_ci		 * specific packet may differ from the one used by default and
15248c2ecf20Sopenharmony_ci		 * returned by getsockname(2).
15258c2ecf20Sopenharmony_ci		 */
15268c2ecf20Sopenharmony_ci		if (recvmsg_from_client(servfd, &recvmsg_addr) == -1)
15278c2ecf20Sopenharmony_ci			goto err;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci		if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0))
15308c2ecf20Sopenharmony_ci			goto err;
15318c2ecf20Sopenharmony_ci	}
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	goto out;
15348c2ecf20Sopenharmony_cierr:
15358c2ecf20Sopenharmony_ci	err = -1;
15368c2ecf20Sopenharmony_ciout:
15378c2ecf20Sopenharmony_ci	close(clientfd);
15388c2ecf20Sopenharmony_ci	close(servfd);
15398c2ecf20Sopenharmony_ci	return err;
15408c2ecf20Sopenharmony_ci}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_cistatic int run_test_case(int cgfd, const struct sock_addr_test *test)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	int progfd = -1;
15458c2ecf20Sopenharmony_ci	int err = 0;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	printf("Test case: %s .. ", test->descr);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	progfd = test->loadfn(test);
15508c2ecf20Sopenharmony_ci	if (test->expected_result == LOAD_REJECT && progfd < 0)
15518c2ecf20Sopenharmony_ci		goto out;
15528c2ecf20Sopenharmony_ci	else if (test->expected_result == LOAD_REJECT || progfd < 0)
15538c2ecf20Sopenharmony_ci		goto err;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	err = bpf_prog_attach(progfd, cgfd, test->attach_type,
15568c2ecf20Sopenharmony_ci			      BPF_F_ALLOW_OVERRIDE);
15578c2ecf20Sopenharmony_ci	if (test->expected_result == ATTACH_REJECT && err) {
15588c2ecf20Sopenharmony_ci		err = 0; /* error was expected, reset it */
15598c2ecf20Sopenharmony_ci		goto out;
15608c2ecf20Sopenharmony_ci	} else if (test->expected_result == ATTACH_REJECT || err) {
15618c2ecf20Sopenharmony_ci		goto err;
15628c2ecf20Sopenharmony_ci	} else if (test->expected_result == ATTACH_OKAY) {
15638c2ecf20Sopenharmony_ci		err = 0;
15648c2ecf20Sopenharmony_ci		goto out;
15658c2ecf20Sopenharmony_ci	}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	switch (test->attach_type) {
15688c2ecf20Sopenharmony_ci	case BPF_CGROUP_INET4_BIND:
15698c2ecf20Sopenharmony_ci	case BPF_CGROUP_INET6_BIND:
15708c2ecf20Sopenharmony_ci		err = run_bind_test_case(test);
15718c2ecf20Sopenharmony_ci		break;
15728c2ecf20Sopenharmony_ci	case BPF_CGROUP_INET4_CONNECT:
15738c2ecf20Sopenharmony_ci	case BPF_CGROUP_INET6_CONNECT:
15748c2ecf20Sopenharmony_ci		err = run_connect_test_case(test);
15758c2ecf20Sopenharmony_ci		break;
15768c2ecf20Sopenharmony_ci	case BPF_CGROUP_UDP4_SENDMSG:
15778c2ecf20Sopenharmony_ci	case BPF_CGROUP_UDP6_SENDMSG:
15788c2ecf20Sopenharmony_ci		err = run_xmsg_test_case(test, 1);
15798c2ecf20Sopenharmony_ci		break;
15808c2ecf20Sopenharmony_ci	case BPF_CGROUP_UDP4_RECVMSG:
15818c2ecf20Sopenharmony_ci	case BPF_CGROUP_UDP6_RECVMSG:
15828c2ecf20Sopenharmony_ci		err = run_xmsg_test_case(test, 0);
15838c2ecf20Sopenharmony_ci		break;
15848c2ecf20Sopenharmony_ci	default:
15858c2ecf20Sopenharmony_ci		goto err;
15868c2ecf20Sopenharmony_ci	}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (test->expected_result == SYSCALL_EPERM && err == EPERM) {
15898c2ecf20Sopenharmony_ci		err = 0; /* error was expected, reset it */
15908c2ecf20Sopenharmony_ci		goto out;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) {
15948c2ecf20Sopenharmony_ci		err = 0; /* error was expected, reset it */
15958c2ecf20Sopenharmony_ci		goto out;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	if (err || test->expected_result != SUCCESS)
15998c2ecf20Sopenharmony_ci		goto err;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	goto out;
16028c2ecf20Sopenharmony_cierr:
16038c2ecf20Sopenharmony_ci	err = -1;
16048c2ecf20Sopenharmony_ciout:
16058c2ecf20Sopenharmony_ci	/* Detaching w/o checking return code: best effort attempt. */
16068c2ecf20Sopenharmony_ci	if (progfd != -1)
16078c2ecf20Sopenharmony_ci		bpf_prog_detach(cgfd, test->attach_type);
16088c2ecf20Sopenharmony_ci	close(progfd);
16098c2ecf20Sopenharmony_ci	printf("[%s]\n", err ? "FAIL" : "PASS");
16108c2ecf20Sopenharmony_ci	return err;
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_cistatic int run_tests(int cgfd)
16148c2ecf20Sopenharmony_ci{
16158c2ecf20Sopenharmony_ci	int passes = 0;
16168c2ecf20Sopenharmony_ci	int fails = 0;
16178c2ecf20Sopenharmony_ci	int i;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
16208c2ecf20Sopenharmony_ci		if (run_test_case(cgfd, &tests[i]))
16218c2ecf20Sopenharmony_ci			++fails;
16228c2ecf20Sopenharmony_ci		else
16238c2ecf20Sopenharmony_ci			++passes;
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
16268c2ecf20Sopenharmony_ci	return fails ? -1 : 0;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ciint main(int argc, char **argv)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	int cgfd = -1;
16328c2ecf20Sopenharmony_ci	int err = 0;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	if (argc < 2) {
16358c2ecf20Sopenharmony_ci		fprintf(stderr,
16368c2ecf20Sopenharmony_ci			"%s has to be run via %s.sh. Skip direct run.\n",
16378c2ecf20Sopenharmony_ci			argv[0], argv[0]);
16388c2ecf20Sopenharmony_ci		exit(err);
16398c2ecf20Sopenharmony_ci	}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	cgfd = cgroup_setup_and_join(CG_PATH);
16428c2ecf20Sopenharmony_ci	if (cgfd < 0)
16438c2ecf20Sopenharmony_ci		goto err;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	if (run_tests(cgfd))
16468c2ecf20Sopenharmony_ci		goto err;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	goto out;
16498c2ecf20Sopenharmony_cierr:
16508c2ecf20Sopenharmony_ci	err = -1;
16518c2ecf20Sopenharmony_ciout:
16528c2ecf20Sopenharmony_ci	close(cgfd);
16538c2ecf20Sopenharmony_ci	cleanup_cgroup_environment();
16548c2ecf20Sopenharmony_ci	return err;
16558c2ecf20Sopenharmony_ci}
1656