xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/net/ipsec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ipsec.c - Check xfrm on veth inside a net-ns.
4*4882a593Smuzhiyun  * Copyright (c) 2018 Dmitry Safonov
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define _GNU_SOURCE
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <arpa/inet.h>
10*4882a593Smuzhiyun #include <asm/types.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun #include <fcntl.h>
13*4882a593Smuzhiyun #include <limits.h>
14*4882a593Smuzhiyun #include <linux/limits.h>
15*4882a593Smuzhiyun #include <linux/netlink.h>
16*4882a593Smuzhiyun #include <linux/random.h>
17*4882a593Smuzhiyun #include <linux/rtnetlink.h>
18*4882a593Smuzhiyun #include <linux/veth.h>
19*4882a593Smuzhiyun #include <linux/xfrm.h>
20*4882a593Smuzhiyun #include <netinet/in.h>
21*4882a593Smuzhiyun #include <net/if.h>
22*4882a593Smuzhiyun #include <sched.h>
23*4882a593Smuzhiyun #include <stdbool.h>
24*4882a593Smuzhiyun #include <stdint.h>
25*4882a593Smuzhiyun #include <stdio.h>
26*4882a593Smuzhiyun #include <stdlib.h>
27*4882a593Smuzhiyun #include <string.h>
28*4882a593Smuzhiyun #include <sys/mman.h>
29*4882a593Smuzhiyun #include <sys/socket.h>
30*4882a593Smuzhiyun #include <sys/stat.h>
31*4882a593Smuzhiyun #include <sys/syscall.h>
32*4882a593Smuzhiyun #include <sys/types.h>
33*4882a593Smuzhiyun #include <sys/wait.h>
34*4882a593Smuzhiyun #include <time.h>
35*4882a593Smuzhiyun #include <unistd.h>
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include "../kselftest.h"
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define printk(fmt, ...)						\
40*4882a593Smuzhiyun 	ksft_print_msg("%d[%u] " fmt "\n", getpid(), __LINE__, ##__VA_ARGS__)
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define pr_err(fmt, ...)	printk(fmt ": %m", ##__VA_ARGS__)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
45*4882a593Smuzhiyun #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define IPV4_STR_SZ	16	/* xxx.xxx.xxx.xxx is longest + \0 */
48*4882a593Smuzhiyun #define MAX_PAYLOAD	2048
49*4882a593Smuzhiyun #define XFRM_ALGO_KEY_BUF_SIZE	512
50*4882a593Smuzhiyun #define MAX_PROCESSES	(1 << 14) /* /16 mask divided by /30 subnets */
51*4882a593Smuzhiyun #define INADDR_A	((in_addr_t) 0x0a000000) /* 10.0.0.0 */
52*4882a593Smuzhiyun #define INADDR_B	((in_addr_t) 0xc0a80000) /* 192.168.0.0 */
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* /30 mask for one veth connection */
55*4882a593Smuzhiyun #define PREFIX_LEN	30
56*4882a593Smuzhiyun #define child_ip(nr)	(4*nr + 1)
57*4882a593Smuzhiyun #define grchild_ip(nr)	(4*nr + 2)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define VETH_FMT	"ktst-%d"
60*4882a593Smuzhiyun #define VETH_LEN	12
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static int nsfd_parent	= -1;
63*4882a593Smuzhiyun static int nsfd_childa	= -1;
64*4882a593Smuzhiyun static int nsfd_childb	= -1;
65*4882a593Smuzhiyun static long page_size;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun  * ksft_cnt is static in kselftest, so isn't shared with children.
69*4882a593Smuzhiyun  * We have to send a test result back to parent and count there.
70*4882a593Smuzhiyun  * results_fd is a pipe with test feedback from children.
71*4882a593Smuzhiyun  */
72*4882a593Smuzhiyun static int results_fd[2];
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun const unsigned int ping_delay_nsec	= 50 * 1000 * 1000;
75*4882a593Smuzhiyun const unsigned int ping_timeout		= 300;
76*4882a593Smuzhiyun const unsigned int ping_count		= 100;
77*4882a593Smuzhiyun const unsigned int ping_success		= 80;
78*4882a593Smuzhiyun 
randomize_buffer(void * buf,size_t buflen)79*4882a593Smuzhiyun static void randomize_buffer(void *buf, size_t buflen)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	int *p = (int *)buf;
82*4882a593Smuzhiyun 	size_t words = buflen / sizeof(int);
83*4882a593Smuzhiyun 	size_t leftover = buflen % sizeof(int);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!buflen)
86*4882a593Smuzhiyun 		return;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	while (words--)
89*4882a593Smuzhiyun 		*p++ = rand();
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (leftover) {
92*4882a593Smuzhiyun 		int tmp = rand();
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		memcpy(buf + buflen - leftover, &tmp, leftover);
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
unshare_open(void)100*4882a593Smuzhiyun static int unshare_open(void)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	const char *netns_path = "/proc/self/ns/net";
103*4882a593Smuzhiyun 	int fd;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (unshare(CLONE_NEWNET) != 0) {
106*4882a593Smuzhiyun 		pr_err("unshare()");
107*4882a593Smuzhiyun 		return -1;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	fd = open(netns_path, O_RDONLY);
111*4882a593Smuzhiyun 	if (fd <= 0) {
112*4882a593Smuzhiyun 		pr_err("open(%s)", netns_path);
113*4882a593Smuzhiyun 		return -1;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	return fd;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
switch_ns(int fd)119*4882a593Smuzhiyun static int switch_ns(int fd)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	if (setns(fd, CLONE_NEWNET)) {
122*4882a593Smuzhiyun 		pr_err("setns()");
123*4882a593Smuzhiyun 		return -1;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /*
129*4882a593Smuzhiyun  * Running the test inside a new parent net namespace to bother less
130*4882a593Smuzhiyun  * about cleanup on error-path.
131*4882a593Smuzhiyun  */
init_namespaces(void)132*4882a593Smuzhiyun static int init_namespaces(void)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	nsfd_parent = unshare_open();
135*4882a593Smuzhiyun 	if (nsfd_parent <= 0)
136*4882a593Smuzhiyun 		return -1;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	nsfd_childa = unshare_open();
139*4882a593Smuzhiyun 	if (nsfd_childa <= 0)
140*4882a593Smuzhiyun 		return -1;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (switch_ns(nsfd_parent))
143*4882a593Smuzhiyun 		return -1;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	nsfd_childb = unshare_open();
146*4882a593Smuzhiyun 	if (nsfd_childb <= 0)
147*4882a593Smuzhiyun 		return -1;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (switch_ns(nsfd_parent))
150*4882a593Smuzhiyun 		return -1;
151*4882a593Smuzhiyun 	return 0;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
netlink_sock(int * sock,uint32_t * seq_nr,int proto)154*4882a593Smuzhiyun static int netlink_sock(int *sock, uint32_t *seq_nr, int proto)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	if (*sock > 0) {
157*4882a593Smuzhiyun 		seq_nr++;
158*4882a593Smuzhiyun 		return 0;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	*sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
162*4882a593Smuzhiyun 	if (*sock <= 0) {
163*4882a593Smuzhiyun 		pr_err("socket(AF_NETLINK)");
164*4882a593Smuzhiyun 		return -1;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	randomize_buffer(seq_nr, sizeof(*seq_nr));
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
rtattr_hdr(struct nlmsghdr * nh)172*4882a593Smuzhiyun static inline struct rtattr *rtattr_hdr(struct nlmsghdr *nh)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	return (struct rtattr *)((char *)(nh) + RTA_ALIGN((nh)->nlmsg_len));
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
rtattr_pack(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type,const void * payload,size_t size)177*4882a593Smuzhiyun static int rtattr_pack(struct nlmsghdr *nh, size_t req_sz,
178*4882a593Smuzhiyun 		unsigned short rta_type, const void *payload, size_t size)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	/* NLMSG_ALIGNTO == RTA_ALIGNTO, nlmsg_len already aligned */
181*4882a593Smuzhiyun 	struct rtattr *attr = rtattr_hdr(nh);
182*4882a593Smuzhiyun 	size_t nl_size = RTA_ALIGN(nh->nlmsg_len) + RTA_LENGTH(size);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (req_sz < nl_size) {
185*4882a593Smuzhiyun 		printk("req buf is too small: %zu < %zu", req_sz, nl_size);
186*4882a593Smuzhiyun 		return -1;
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 	nh->nlmsg_len = nl_size;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	attr->rta_len = RTA_LENGTH(size);
191*4882a593Smuzhiyun 	attr->rta_type = rta_type;
192*4882a593Smuzhiyun 	memcpy(RTA_DATA(attr), payload, size);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
_rtattr_begin(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type,const void * payload,size_t size)197*4882a593Smuzhiyun static struct rtattr *_rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
198*4882a593Smuzhiyun 		unsigned short rta_type, const void *payload, size_t size)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	struct rtattr *ret = rtattr_hdr(nh);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (rtattr_pack(nh, req_sz, rta_type, payload, size))
203*4882a593Smuzhiyun 		return 0;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return ret;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
rtattr_begin(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type)208*4882a593Smuzhiyun static inline struct rtattr *rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
209*4882a593Smuzhiyun 		unsigned short rta_type)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	return _rtattr_begin(nh, req_sz, rta_type, 0, 0);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
rtattr_end(struct nlmsghdr * nh,struct rtattr * attr)214*4882a593Smuzhiyun static inline void rtattr_end(struct nlmsghdr *nh, struct rtattr *attr)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	char *nlmsg_end = (char *)nh + nh->nlmsg_len;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	attr->rta_len = nlmsg_end - (char *)attr;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
veth_pack_peerb(struct nlmsghdr * nh,size_t req_sz,const char * peer,int ns)221*4882a593Smuzhiyun static int veth_pack_peerb(struct nlmsghdr *nh, size_t req_sz,
222*4882a593Smuzhiyun 		const char *peer, int ns)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct ifinfomsg pi;
225*4882a593Smuzhiyun 	struct rtattr *peer_attr;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	memset(&pi, 0, sizeof(pi));
228*4882a593Smuzhiyun 	pi.ifi_family	= AF_UNSPEC;
229*4882a593Smuzhiyun 	pi.ifi_change	= 0xFFFFFFFF;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	peer_attr = _rtattr_begin(nh, req_sz, VETH_INFO_PEER, &pi, sizeof(pi));
232*4882a593Smuzhiyun 	if (!peer_attr)
233*4882a593Smuzhiyun 		return -1;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (rtattr_pack(nh, req_sz, IFLA_IFNAME, peer, strlen(peer)))
236*4882a593Smuzhiyun 		return -1;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (rtattr_pack(nh, req_sz, IFLA_NET_NS_FD, &ns, sizeof(ns)))
239*4882a593Smuzhiyun 		return -1;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	rtattr_end(nh, peer_attr);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
netlink_check_answer(int sock)246*4882a593Smuzhiyun static int netlink_check_answer(int sock)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct nlmsgerror {
249*4882a593Smuzhiyun 		struct nlmsghdr hdr;
250*4882a593Smuzhiyun 		int error;
251*4882a593Smuzhiyun 		struct nlmsghdr orig_msg;
252*4882a593Smuzhiyun 	} answer;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (recv(sock, &answer, sizeof(answer), 0) < 0) {
255*4882a593Smuzhiyun 		pr_err("recv()");
256*4882a593Smuzhiyun 		return -1;
257*4882a593Smuzhiyun 	} else if (answer.hdr.nlmsg_type != NLMSG_ERROR) {
258*4882a593Smuzhiyun 		printk("expected NLMSG_ERROR, got %d", (int)answer.hdr.nlmsg_type);
259*4882a593Smuzhiyun 		return -1;
260*4882a593Smuzhiyun 	} else if (answer.error) {
261*4882a593Smuzhiyun 		printk("NLMSG_ERROR: %d: %s",
262*4882a593Smuzhiyun 			answer.error, strerror(-answer.error));
263*4882a593Smuzhiyun 		return answer.error;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
veth_add(int sock,uint32_t seq,const char * peera,int ns_a,const char * peerb,int ns_b)269*4882a593Smuzhiyun static int veth_add(int sock, uint32_t seq, const char *peera, int ns_a,
270*4882a593Smuzhiyun 		const char *peerb, int ns_b)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
273*4882a593Smuzhiyun 	struct {
274*4882a593Smuzhiyun 		struct nlmsghdr		nh;
275*4882a593Smuzhiyun 		struct ifinfomsg	info;
276*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
277*4882a593Smuzhiyun 	} req;
278*4882a593Smuzhiyun 	const char veth_type[] = "veth";
279*4882a593Smuzhiyun 	struct rtattr *link_info, *info_data;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
282*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.info));
283*4882a593Smuzhiyun 	req.nh.nlmsg_type	= RTM_NEWLINK;
284*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= flags;
285*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
286*4882a593Smuzhiyun 	req.info.ifi_family	= AF_UNSPEC;
287*4882a593Smuzhiyun 	req.info.ifi_change	= 0xFFFFFFFF;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), IFLA_IFNAME, peera, strlen(peera)))
290*4882a593Smuzhiyun 		return -1;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), IFLA_NET_NS_FD, &ns_a, sizeof(ns_a)))
293*4882a593Smuzhiyun 		return -1;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	link_info = rtattr_begin(&req.nh, sizeof(req), IFLA_LINKINFO);
296*4882a593Smuzhiyun 	if (!link_info)
297*4882a593Smuzhiyun 		return -1;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), IFLA_INFO_KIND, veth_type, sizeof(veth_type)))
300*4882a593Smuzhiyun 		return -1;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	info_data = rtattr_begin(&req.nh, sizeof(req), IFLA_INFO_DATA);
303*4882a593Smuzhiyun 	if (!info_data)
304*4882a593Smuzhiyun 		return -1;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (veth_pack_peerb(&req.nh, sizeof(req), peerb, ns_b))
307*4882a593Smuzhiyun 		return -1;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	rtattr_end(&req.nh, info_data);
310*4882a593Smuzhiyun 	rtattr_end(&req.nh, link_info);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
313*4882a593Smuzhiyun 		pr_err("send()");
314*4882a593Smuzhiyun 		return -1;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 	return netlink_check_answer(sock);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
ip4_addr_set(int sock,uint32_t seq,const char * intf,struct in_addr addr,uint8_t prefix)319*4882a593Smuzhiyun static int ip4_addr_set(int sock, uint32_t seq, const char *intf,
320*4882a593Smuzhiyun 		struct in_addr addr, uint8_t prefix)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
323*4882a593Smuzhiyun 	struct {
324*4882a593Smuzhiyun 		struct nlmsghdr		nh;
325*4882a593Smuzhiyun 		struct ifaddrmsg	info;
326*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
327*4882a593Smuzhiyun 	} req;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
330*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.info));
331*4882a593Smuzhiyun 	req.nh.nlmsg_type	= RTM_NEWADDR;
332*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= flags;
333*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
334*4882a593Smuzhiyun 	req.info.ifa_family	= AF_INET;
335*4882a593Smuzhiyun 	req.info.ifa_prefixlen	= prefix;
336*4882a593Smuzhiyun 	req.info.ifa_index	= if_nametoindex(intf);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun #ifdef DEBUG
339*4882a593Smuzhiyun 	{
340*4882a593Smuzhiyun 		char addr_str[IPV4_STR_SZ] = {};
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		strncpy(addr_str, inet_ntoa(addr), IPV4_STR_SZ - 1);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 		printk("ip addr set %s", addr_str);
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun #endif
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), IFA_LOCAL, &addr, sizeof(addr)))
349*4882a593Smuzhiyun 		return -1;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), IFA_ADDRESS, &addr, sizeof(addr)))
352*4882a593Smuzhiyun 		return -1;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
355*4882a593Smuzhiyun 		pr_err("send()");
356*4882a593Smuzhiyun 		return -1;
357*4882a593Smuzhiyun 	}
358*4882a593Smuzhiyun 	return netlink_check_answer(sock);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
link_set_up(int sock,uint32_t seq,const char * intf)361*4882a593Smuzhiyun static int link_set_up(int sock, uint32_t seq, const char *intf)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct {
364*4882a593Smuzhiyun 		struct nlmsghdr		nh;
365*4882a593Smuzhiyun 		struct ifinfomsg	info;
366*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
367*4882a593Smuzhiyun 	} req;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
370*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.info));
371*4882a593Smuzhiyun 	req.nh.nlmsg_type	= RTM_NEWLINK;
372*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
373*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
374*4882a593Smuzhiyun 	req.info.ifi_family	= AF_UNSPEC;
375*4882a593Smuzhiyun 	req.info.ifi_change	= 0xFFFFFFFF;
376*4882a593Smuzhiyun 	req.info.ifi_index	= if_nametoindex(intf);
377*4882a593Smuzhiyun 	req.info.ifi_flags	= IFF_UP;
378*4882a593Smuzhiyun 	req.info.ifi_change	= IFF_UP;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
381*4882a593Smuzhiyun 		pr_err("send()");
382*4882a593Smuzhiyun 		return -1;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 	return netlink_check_answer(sock);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
ip4_route_set(int sock,uint32_t seq,const char * intf,struct in_addr src,struct in_addr dst)387*4882a593Smuzhiyun static int ip4_route_set(int sock, uint32_t seq, const char *intf,
388*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct {
391*4882a593Smuzhiyun 		struct nlmsghdr	nh;
392*4882a593Smuzhiyun 		struct rtmsg	rt;
393*4882a593Smuzhiyun 		char		attrbuf[MAX_PAYLOAD];
394*4882a593Smuzhiyun 	} req;
395*4882a593Smuzhiyun 	unsigned int index = if_nametoindex(intf);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
398*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.rt));
399*4882a593Smuzhiyun 	req.nh.nlmsg_type	= RTM_NEWROUTE;
400*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
401*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
402*4882a593Smuzhiyun 	req.rt.rtm_family	= AF_INET;
403*4882a593Smuzhiyun 	req.rt.rtm_dst_len	= 32;
404*4882a593Smuzhiyun 	req.rt.rtm_table	= RT_TABLE_MAIN;
405*4882a593Smuzhiyun 	req.rt.rtm_protocol	= RTPROT_BOOT;
406*4882a593Smuzhiyun 	req.rt.rtm_scope	= RT_SCOPE_LINK;
407*4882a593Smuzhiyun 	req.rt.rtm_type		= RTN_UNICAST;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), RTA_DST, &dst, sizeof(dst)))
410*4882a593Smuzhiyun 		return -1;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), RTA_PREFSRC, &src, sizeof(src)))
413*4882a593Smuzhiyun 		return -1;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), RTA_OIF, &index, sizeof(index)))
416*4882a593Smuzhiyun 		return -1;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
419*4882a593Smuzhiyun 		pr_err("send()");
420*4882a593Smuzhiyun 		return -1;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	return netlink_check_answer(sock);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
tunnel_set_route(int route_sock,uint32_t * route_seq,char * veth,struct in_addr tunsrc,struct in_addr tundst)426*4882a593Smuzhiyun static int tunnel_set_route(int route_sock, uint32_t *route_seq, char *veth,
427*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	if (ip4_addr_set(route_sock, (*route_seq)++, "lo",
430*4882a593Smuzhiyun 			tunsrc, PREFIX_LEN)) {
431*4882a593Smuzhiyun 		printk("Failed to set ipv4 addr");
432*4882a593Smuzhiyun 		return -1;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (ip4_route_set(route_sock, (*route_seq)++, veth, tunsrc, tundst)) {
436*4882a593Smuzhiyun 		printk("Failed to set ipv4 route");
437*4882a593Smuzhiyun 		return -1;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	return 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
init_child(int nsfd,char * veth,unsigned int src,unsigned int dst)443*4882a593Smuzhiyun static int init_child(int nsfd, char *veth, unsigned int src, unsigned int dst)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	struct in_addr intsrc = inet_makeaddr(INADDR_B, src);
446*4882a593Smuzhiyun 	struct in_addr tunsrc = inet_makeaddr(INADDR_A, src);
447*4882a593Smuzhiyun 	struct in_addr tundst = inet_makeaddr(INADDR_A, dst);
448*4882a593Smuzhiyun 	int route_sock = -1, ret = -1;
449*4882a593Smuzhiyun 	uint32_t route_seq;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	if (switch_ns(nsfd))
452*4882a593Smuzhiyun 		return -1;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE)) {
455*4882a593Smuzhiyun 		printk("Failed to open netlink route socket in child");
456*4882a593Smuzhiyun 		return -1;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	if (ip4_addr_set(route_sock, route_seq++, veth, intsrc, PREFIX_LEN)) {
460*4882a593Smuzhiyun 		printk("Failed to set ipv4 addr");
461*4882a593Smuzhiyun 		goto err;
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (link_set_up(route_sock, route_seq++, veth)) {
465*4882a593Smuzhiyun 		printk("Failed to bring up %s", veth);
466*4882a593Smuzhiyun 		goto err;
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (tunnel_set_route(route_sock, &route_seq, veth, tunsrc, tundst)) {
470*4882a593Smuzhiyun 		printk("Failed to add tunnel route on %s", veth);
471*4882a593Smuzhiyun 		goto err;
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 	ret = 0;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun err:
476*4882a593Smuzhiyun 	close(route_sock);
477*4882a593Smuzhiyun 	return ret;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun #define ALGO_LEN	64
481*4882a593Smuzhiyun enum desc_type {
482*4882a593Smuzhiyun 	CREATE_TUNNEL	= 0,
483*4882a593Smuzhiyun 	ALLOCATE_SPI,
484*4882a593Smuzhiyun 	MONITOR_ACQUIRE,
485*4882a593Smuzhiyun 	EXPIRE_STATE,
486*4882a593Smuzhiyun 	EXPIRE_POLICY,
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun const char *desc_name[] = {
489*4882a593Smuzhiyun 	"create tunnel",
490*4882a593Smuzhiyun 	"alloc spi",
491*4882a593Smuzhiyun 	"monitor acquire",
492*4882a593Smuzhiyun 	"expire state",
493*4882a593Smuzhiyun 	"expire policy"
494*4882a593Smuzhiyun };
495*4882a593Smuzhiyun struct xfrm_desc {
496*4882a593Smuzhiyun 	enum desc_type	type;
497*4882a593Smuzhiyun 	uint8_t		proto;
498*4882a593Smuzhiyun 	char		a_algo[ALGO_LEN];
499*4882a593Smuzhiyun 	char		e_algo[ALGO_LEN];
500*4882a593Smuzhiyun 	char		c_algo[ALGO_LEN];
501*4882a593Smuzhiyun 	char		ae_algo[ALGO_LEN];
502*4882a593Smuzhiyun 	unsigned int	icv_len;
503*4882a593Smuzhiyun 	/* unsigned key_len; */
504*4882a593Smuzhiyun };
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun enum msg_type {
507*4882a593Smuzhiyun 	MSG_ACK		= 0,
508*4882a593Smuzhiyun 	MSG_EXIT,
509*4882a593Smuzhiyun 	MSG_PING,
510*4882a593Smuzhiyun 	MSG_XFRM_PREPARE,
511*4882a593Smuzhiyun 	MSG_XFRM_ADD,
512*4882a593Smuzhiyun 	MSG_XFRM_DEL,
513*4882a593Smuzhiyun 	MSG_XFRM_CLEANUP,
514*4882a593Smuzhiyun };
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun struct test_desc {
517*4882a593Smuzhiyun 	enum msg_type type;
518*4882a593Smuzhiyun 	union {
519*4882a593Smuzhiyun 		struct {
520*4882a593Smuzhiyun 			in_addr_t reply_ip;
521*4882a593Smuzhiyun 			unsigned int port;
522*4882a593Smuzhiyun 		} ping;
523*4882a593Smuzhiyun 		struct xfrm_desc xfrm_desc;
524*4882a593Smuzhiyun 	} body;
525*4882a593Smuzhiyun };
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun struct test_result {
528*4882a593Smuzhiyun 	struct xfrm_desc desc;
529*4882a593Smuzhiyun 	unsigned int res;
530*4882a593Smuzhiyun };
531*4882a593Smuzhiyun 
write_test_result(unsigned int res,struct xfrm_desc * d)532*4882a593Smuzhiyun static void write_test_result(unsigned int res, struct xfrm_desc *d)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	struct test_result tr = {};
535*4882a593Smuzhiyun 	ssize_t ret;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	tr.desc = *d;
538*4882a593Smuzhiyun 	tr.res = res;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	ret = write(results_fd[1], &tr, sizeof(tr));
541*4882a593Smuzhiyun 	if (ret != sizeof(tr))
542*4882a593Smuzhiyun 		pr_err("Failed to write the result in pipe %zd", ret);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
write_msg(int fd,struct test_desc * msg,bool exit_of_fail)545*4882a593Smuzhiyun static void write_msg(int fd, struct test_desc *msg, bool exit_of_fail)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	ssize_t bytes = write(fd, msg, sizeof(*msg));
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	/* Make sure that write/read is atomic to a pipe */
550*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(struct test_desc) > PIPE_BUF);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	if (bytes < 0) {
553*4882a593Smuzhiyun 		pr_err("write()");
554*4882a593Smuzhiyun 		if (exit_of_fail)
555*4882a593Smuzhiyun 			exit(KSFT_FAIL);
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	if (bytes != sizeof(*msg)) {
558*4882a593Smuzhiyun 		pr_err("sent part of the message %zd/%zu", bytes, sizeof(*msg));
559*4882a593Smuzhiyun 		if (exit_of_fail)
560*4882a593Smuzhiyun 			exit(KSFT_FAIL);
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun 
read_msg(int fd,struct test_desc * msg,bool exit_of_fail)564*4882a593Smuzhiyun static void read_msg(int fd, struct test_desc *msg, bool exit_of_fail)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	ssize_t bytes = read(fd, msg, sizeof(*msg));
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	if (bytes < 0) {
569*4882a593Smuzhiyun 		pr_err("read()");
570*4882a593Smuzhiyun 		if (exit_of_fail)
571*4882a593Smuzhiyun 			exit(KSFT_FAIL);
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 	if (bytes != sizeof(*msg)) {
574*4882a593Smuzhiyun 		pr_err("got incomplete message %zd/%zu", bytes, sizeof(*msg));
575*4882a593Smuzhiyun 		if (exit_of_fail)
576*4882a593Smuzhiyun 			exit(KSFT_FAIL);
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
udp_ping_init(struct in_addr listen_ip,unsigned int u_timeout,unsigned int * server_port,int sock[2])580*4882a593Smuzhiyun static int udp_ping_init(struct in_addr listen_ip, unsigned int u_timeout,
581*4882a593Smuzhiyun 		unsigned int *server_port, int sock[2])
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	struct sockaddr_in server;
584*4882a593Smuzhiyun 	struct timeval t = { .tv_sec = 0, .tv_usec = u_timeout };
585*4882a593Smuzhiyun 	socklen_t s_len = sizeof(server);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	sock[0] = socket(AF_INET, SOCK_DGRAM, 0);
588*4882a593Smuzhiyun 	if (sock[0] < 0) {
589*4882a593Smuzhiyun 		pr_err("socket()");
590*4882a593Smuzhiyun 		return -1;
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	server.sin_family	= AF_INET;
594*4882a593Smuzhiyun 	server.sin_port		= 0;
595*4882a593Smuzhiyun 	memcpy(&server.sin_addr.s_addr, &listen_ip, sizeof(struct in_addr));
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (bind(sock[0], (struct sockaddr *)&server, s_len)) {
598*4882a593Smuzhiyun 		pr_err("bind()");
599*4882a593Smuzhiyun 		goto err_close_server;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (getsockname(sock[0], (struct sockaddr *)&server, &s_len)) {
603*4882a593Smuzhiyun 		pr_err("getsockname()");
604*4882a593Smuzhiyun 		goto err_close_server;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	*server_port = ntohs(server.sin_port);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (setsockopt(sock[0], SOL_SOCKET, SO_RCVTIMEO, (const char *)&t, sizeof t)) {
610*4882a593Smuzhiyun 		pr_err("setsockopt()");
611*4882a593Smuzhiyun 		goto err_close_server;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	sock[1] = socket(AF_INET, SOCK_DGRAM, 0);
615*4882a593Smuzhiyun 	if (sock[1] < 0) {
616*4882a593Smuzhiyun 		pr_err("socket()");
617*4882a593Smuzhiyun 		goto err_close_server;
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	return 0;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun err_close_server:
623*4882a593Smuzhiyun 	close(sock[0]);
624*4882a593Smuzhiyun 	return -1;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
udp_ping_send(int sock[2],in_addr_t dest_ip,unsigned int port,char * buf,size_t buf_len)627*4882a593Smuzhiyun static int udp_ping_send(int sock[2], in_addr_t dest_ip, unsigned int port,
628*4882a593Smuzhiyun 		char *buf, size_t buf_len)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun 	struct sockaddr_in server;
631*4882a593Smuzhiyun 	const struct sockaddr *dest_addr = (struct sockaddr *)&server;
632*4882a593Smuzhiyun 	char *sock_buf[buf_len];
633*4882a593Smuzhiyun 	ssize_t r_bytes, s_bytes;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	server.sin_family	= AF_INET;
636*4882a593Smuzhiyun 	server.sin_port		= htons(port);
637*4882a593Smuzhiyun 	server.sin_addr.s_addr	= dest_ip;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	s_bytes = sendto(sock[1], buf, buf_len, 0, dest_addr, sizeof(server));
640*4882a593Smuzhiyun 	if (s_bytes < 0) {
641*4882a593Smuzhiyun 		pr_err("sendto()");
642*4882a593Smuzhiyun 		return -1;
643*4882a593Smuzhiyun 	} else if (s_bytes != buf_len) {
644*4882a593Smuzhiyun 		printk("send part of the message: %zd/%zu", s_bytes, sizeof(server));
645*4882a593Smuzhiyun 		return -1;
646*4882a593Smuzhiyun 	}
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	r_bytes = recv(sock[0], sock_buf, buf_len, 0);
649*4882a593Smuzhiyun 	if (r_bytes < 0) {
650*4882a593Smuzhiyun 		if (errno != EAGAIN)
651*4882a593Smuzhiyun 			pr_err("recv()");
652*4882a593Smuzhiyun 		return -1;
653*4882a593Smuzhiyun 	} else if (r_bytes == 0) { /* EOF */
654*4882a593Smuzhiyun 		printk("EOF on reply to ping");
655*4882a593Smuzhiyun 		return -1;
656*4882a593Smuzhiyun 	} else if (r_bytes != buf_len || memcmp(buf, sock_buf, buf_len)) {
657*4882a593Smuzhiyun 		printk("ping reply packet is corrupted %zd/%zu", r_bytes, buf_len);
658*4882a593Smuzhiyun 		return -1;
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
udp_ping_reply(int sock[2],in_addr_t dest_ip,unsigned int port,char * buf,size_t buf_len)664*4882a593Smuzhiyun static int udp_ping_reply(int sock[2], in_addr_t dest_ip, unsigned int port,
665*4882a593Smuzhiyun 		char *buf, size_t buf_len)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	struct sockaddr_in server;
668*4882a593Smuzhiyun 	const struct sockaddr *dest_addr = (struct sockaddr *)&server;
669*4882a593Smuzhiyun 	char *sock_buf[buf_len];
670*4882a593Smuzhiyun 	ssize_t r_bytes, s_bytes;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	server.sin_family	= AF_INET;
673*4882a593Smuzhiyun 	server.sin_port		= htons(port);
674*4882a593Smuzhiyun 	server.sin_addr.s_addr	= dest_ip;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	r_bytes = recv(sock[0], sock_buf, buf_len, 0);
677*4882a593Smuzhiyun 	if (r_bytes < 0) {
678*4882a593Smuzhiyun 		if (errno != EAGAIN)
679*4882a593Smuzhiyun 			pr_err("recv()");
680*4882a593Smuzhiyun 		return -1;
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 	if (r_bytes == 0) { /* EOF */
683*4882a593Smuzhiyun 		printk("EOF on reply to ping");
684*4882a593Smuzhiyun 		return -1;
685*4882a593Smuzhiyun 	}
686*4882a593Smuzhiyun 	if (r_bytes != buf_len || memcmp(buf, sock_buf, buf_len)) {
687*4882a593Smuzhiyun 		printk("ping reply packet is corrupted %zd/%zu", r_bytes, buf_len);
688*4882a593Smuzhiyun 		return -1;
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	s_bytes = sendto(sock[1], buf, buf_len, 0, dest_addr, sizeof(server));
692*4882a593Smuzhiyun 	if (s_bytes < 0) {
693*4882a593Smuzhiyun 		pr_err("sendto()");
694*4882a593Smuzhiyun 		return -1;
695*4882a593Smuzhiyun 	} else if (s_bytes != buf_len) {
696*4882a593Smuzhiyun 		printk("send part of the message: %zd/%zu", s_bytes, sizeof(server));
697*4882a593Smuzhiyun 		return -1;
698*4882a593Smuzhiyun 	}
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun typedef int (*ping_f)(int sock[2], in_addr_t dest_ip, unsigned int port,
704*4882a593Smuzhiyun 		char *buf, size_t buf_len);
do_ping(int cmd_fd,char * buf,size_t buf_len,struct in_addr from,bool init_side,int d_port,in_addr_t to,ping_f func)705*4882a593Smuzhiyun static int do_ping(int cmd_fd, char *buf, size_t buf_len, struct in_addr from,
706*4882a593Smuzhiyun 		bool init_side, int d_port, in_addr_t to, ping_f func)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	struct test_desc msg;
709*4882a593Smuzhiyun 	unsigned int s_port, i, ping_succeeded = 0;
710*4882a593Smuzhiyun 	int ping_sock[2];
711*4882a593Smuzhiyun 	char to_str[IPV4_STR_SZ] = {}, from_str[IPV4_STR_SZ] = {};
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	if (udp_ping_init(from, ping_timeout, &s_port, ping_sock)) {
714*4882a593Smuzhiyun 		printk("Failed to init ping");
715*4882a593Smuzhiyun 		return -1;
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
719*4882a593Smuzhiyun 	msg.type		= MSG_PING;
720*4882a593Smuzhiyun 	msg.body.ping.port	= s_port;
721*4882a593Smuzhiyun 	memcpy(&msg.body.ping.reply_ip, &from, sizeof(from));
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 0);
724*4882a593Smuzhiyun 	if (init_side) {
725*4882a593Smuzhiyun 		/* The other end sends ip to ping */
726*4882a593Smuzhiyun 		read_msg(cmd_fd, &msg, 0);
727*4882a593Smuzhiyun 		if (msg.type != MSG_PING)
728*4882a593Smuzhiyun 			return -1;
729*4882a593Smuzhiyun 		to = msg.body.ping.reply_ip;
730*4882a593Smuzhiyun 		d_port = msg.body.ping.port;
731*4882a593Smuzhiyun 	}
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	for (i = 0; i < ping_count ; i++) {
734*4882a593Smuzhiyun 		struct timespec sleep_time = {
735*4882a593Smuzhiyun 			.tv_sec = 0,
736*4882a593Smuzhiyun 			.tv_nsec = ping_delay_nsec,
737*4882a593Smuzhiyun 		};
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 		ping_succeeded += !func(ping_sock, to, d_port, buf, page_size);
740*4882a593Smuzhiyun 		nanosleep(&sleep_time, 0);
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	close(ping_sock[0]);
744*4882a593Smuzhiyun 	close(ping_sock[1]);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	strncpy(to_str, inet_ntoa(*(struct in_addr *)&to), IPV4_STR_SZ - 1);
747*4882a593Smuzhiyun 	strncpy(from_str, inet_ntoa(from), IPV4_STR_SZ - 1);
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	if (ping_succeeded < ping_success) {
750*4882a593Smuzhiyun 		printk("ping (%s) %s->%s failed %u/%u times",
751*4882a593Smuzhiyun 			init_side ? "send" : "reply", from_str, to_str,
752*4882a593Smuzhiyun 			ping_count - ping_succeeded, ping_count);
753*4882a593Smuzhiyun 		return -1;
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun #ifdef DEBUG
757*4882a593Smuzhiyun 	printk("ping (%s) %s->%s succeeded %u/%u times",
758*4882a593Smuzhiyun 		init_side ? "send" : "reply", from_str, to_str,
759*4882a593Smuzhiyun 		ping_succeeded, ping_count);
760*4882a593Smuzhiyun #endif
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	return 0;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
xfrm_fill_key(char * name,char * buf,size_t buf_len,unsigned int * key_len)765*4882a593Smuzhiyun static int xfrm_fill_key(char *name, char *buf,
766*4882a593Smuzhiyun 		size_t buf_len, unsigned int *key_len)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun 	/* TODO: use set/map instead */
769*4882a593Smuzhiyun 	if (strncmp(name, "digest_null", ALGO_LEN) == 0)
770*4882a593Smuzhiyun 		*key_len = 0;
771*4882a593Smuzhiyun 	else if (strncmp(name, "ecb(cipher_null)", ALGO_LEN) == 0)
772*4882a593Smuzhiyun 		*key_len = 0;
773*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(des)", ALGO_LEN) == 0)
774*4882a593Smuzhiyun 		*key_len = 64;
775*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(md5)", ALGO_LEN) == 0)
776*4882a593Smuzhiyun 		*key_len = 128;
777*4882a593Smuzhiyun 	else if (strncmp(name, "cmac(aes)", ALGO_LEN) == 0)
778*4882a593Smuzhiyun 		*key_len = 128;
779*4882a593Smuzhiyun 	else if (strncmp(name, "xcbc(aes)", ALGO_LEN) == 0)
780*4882a593Smuzhiyun 		*key_len = 128;
781*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(cast5)", ALGO_LEN) == 0)
782*4882a593Smuzhiyun 		*key_len = 128;
783*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(serpent)", ALGO_LEN) == 0)
784*4882a593Smuzhiyun 		*key_len = 128;
785*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(sha1)", ALGO_LEN) == 0)
786*4882a593Smuzhiyun 		*key_len = 160;
787*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(rmd160)", ALGO_LEN) == 0)
788*4882a593Smuzhiyun 		*key_len = 160;
789*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(des3_ede)", ALGO_LEN) == 0)
790*4882a593Smuzhiyun 		*key_len = 192;
791*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(sha256)", ALGO_LEN) == 0)
792*4882a593Smuzhiyun 		*key_len = 256;
793*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(aes)", ALGO_LEN) == 0)
794*4882a593Smuzhiyun 		*key_len = 256;
795*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(camellia)", ALGO_LEN) == 0)
796*4882a593Smuzhiyun 		*key_len = 256;
797*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(twofish)", ALGO_LEN) == 0)
798*4882a593Smuzhiyun 		*key_len = 256;
799*4882a593Smuzhiyun 	else if (strncmp(name, "rfc3686(ctr(aes))", ALGO_LEN) == 0)
800*4882a593Smuzhiyun 		*key_len = 288;
801*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(sha384)", ALGO_LEN) == 0)
802*4882a593Smuzhiyun 		*key_len = 384;
803*4882a593Smuzhiyun 	else if (strncmp(name, "cbc(blowfish)", ALGO_LEN) == 0)
804*4882a593Smuzhiyun 		*key_len = 448;
805*4882a593Smuzhiyun 	else if (strncmp(name, "hmac(sha512)", ALGO_LEN) == 0)
806*4882a593Smuzhiyun 		*key_len = 512;
807*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4106(gcm(aes))-128", ALGO_LEN) == 0)
808*4882a593Smuzhiyun 		*key_len = 160;
809*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4543(gcm(aes))-128", ALGO_LEN) == 0)
810*4882a593Smuzhiyun 		*key_len = 160;
811*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4309(ccm(aes))-128", ALGO_LEN) == 0)
812*4882a593Smuzhiyun 		*key_len = 152;
813*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4106(gcm(aes))-192", ALGO_LEN) == 0)
814*4882a593Smuzhiyun 		*key_len = 224;
815*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4543(gcm(aes))-192", ALGO_LEN) == 0)
816*4882a593Smuzhiyun 		*key_len = 224;
817*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4309(ccm(aes))-192", ALGO_LEN) == 0)
818*4882a593Smuzhiyun 		*key_len = 216;
819*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4106(gcm(aes))-256", ALGO_LEN) == 0)
820*4882a593Smuzhiyun 		*key_len = 288;
821*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4543(gcm(aes))-256", ALGO_LEN) == 0)
822*4882a593Smuzhiyun 		*key_len = 288;
823*4882a593Smuzhiyun 	else if (strncmp(name, "rfc4309(ccm(aes))-256", ALGO_LEN) == 0)
824*4882a593Smuzhiyun 		*key_len = 280;
825*4882a593Smuzhiyun 	else if (strncmp(name, "rfc7539(chacha20,poly1305)-128", ALGO_LEN) == 0)
826*4882a593Smuzhiyun 		*key_len = 0;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	if (*key_len > buf_len) {
829*4882a593Smuzhiyun 		printk("Can't pack a key - too big for buffer");
830*4882a593Smuzhiyun 		return -1;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	randomize_buffer(buf, *key_len);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	return 0;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
xfrm_state_pack_algo(struct nlmsghdr * nh,size_t req_sz,struct xfrm_desc * desc)838*4882a593Smuzhiyun static int xfrm_state_pack_algo(struct nlmsghdr *nh, size_t req_sz,
839*4882a593Smuzhiyun 		struct xfrm_desc *desc)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun 	struct {
842*4882a593Smuzhiyun 		union {
843*4882a593Smuzhiyun 			struct xfrm_algo	alg;
844*4882a593Smuzhiyun 			struct xfrm_algo_aead	aead;
845*4882a593Smuzhiyun 			struct xfrm_algo_auth	auth;
846*4882a593Smuzhiyun 		} u;
847*4882a593Smuzhiyun 		char buf[XFRM_ALGO_KEY_BUF_SIZE];
848*4882a593Smuzhiyun 	} alg = {};
849*4882a593Smuzhiyun 	size_t alen, elen, clen, aelen;
850*4882a593Smuzhiyun 	unsigned short type;
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	alen = strlen(desc->a_algo);
853*4882a593Smuzhiyun 	elen = strlen(desc->e_algo);
854*4882a593Smuzhiyun 	clen = strlen(desc->c_algo);
855*4882a593Smuzhiyun 	aelen = strlen(desc->ae_algo);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	/* Verify desc */
858*4882a593Smuzhiyun 	switch (desc->proto) {
859*4882a593Smuzhiyun 	case IPPROTO_AH:
860*4882a593Smuzhiyun 		if (!alen || elen || clen || aelen) {
861*4882a593Smuzhiyun 			printk("BUG: buggy ah desc");
862*4882a593Smuzhiyun 			return -1;
863*4882a593Smuzhiyun 		}
864*4882a593Smuzhiyun 		strncpy(alg.u.alg.alg_name, desc->a_algo, ALGO_LEN - 1);
865*4882a593Smuzhiyun 		if (xfrm_fill_key(desc->a_algo, alg.u.alg.alg_key,
866*4882a593Smuzhiyun 				sizeof(alg.buf), &alg.u.alg.alg_key_len))
867*4882a593Smuzhiyun 			return -1;
868*4882a593Smuzhiyun 		type = XFRMA_ALG_AUTH;
869*4882a593Smuzhiyun 		break;
870*4882a593Smuzhiyun 	case IPPROTO_COMP:
871*4882a593Smuzhiyun 		if (!clen || elen || alen || aelen) {
872*4882a593Smuzhiyun 			printk("BUG: buggy comp desc");
873*4882a593Smuzhiyun 			return -1;
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 		strncpy(alg.u.alg.alg_name, desc->c_algo, ALGO_LEN - 1);
876*4882a593Smuzhiyun 		if (xfrm_fill_key(desc->c_algo, alg.u.alg.alg_key,
877*4882a593Smuzhiyun 				sizeof(alg.buf), &alg.u.alg.alg_key_len))
878*4882a593Smuzhiyun 			return -1;
879*4882a593Smuzhiyun 		type = XFRMA_ALG_COMP;
880*4882a593Smuzhiyun 		break;
881*4882a593Smuzhiyun 	case IPPROTO_ESP:
882*4882a593Smuzhiyun 		if (!((alen && elen) ^ aelen) || clen) {
883*4882a593Smuzhiyun 			printk("BUG: buggy esp desc");
884*4882a593Smuzhiyun 			return -1;
885*4882a593Smuzhiyun 		}
886*4882a593Smuzhiyun 		if (aelen) {
887*4882a593Smuzhiyun 			alg.u.aead.alg_icv_len = desc->icv_len;
888*4882a593Smuzhiyun 			strncpy(alg.u.aead.alg_name, desc->ae_algo, ALGO_LEN - 1);
889*4882a593Smuzhiyun 			if (xfrm_fill_key(desc->ae_algo, alg.u.aead.alg_key,
890*4882a593Smuzhiyun 						sizeof(alg.buf), &alg.u.aead.alg_key_len))
891*4882a593Smuzhiyun 				return -1;
892*4882a593Smuzhiyun 			type = XFRMA_ALG_AEAD;
893*4882a593Smuzhiyun 		} else {
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 			strncpy(alg.u.alg.alg_name, desc->e_algo, ALGO_LEN - 1);
896*4882a593Smuzhiyun 			type = XFRMA_ALG_CRYPT;
897*4882a593Smuzhiyun 			if (xfrm_fill_key(desc->e_algo, alg.u.alg.alg_key,
898*4882a593Smuzhiyun 						sizeof(alg.buf), &alg.u.alg.alg_key_len))
899*4882a593Smuzhiyun 				return -1;
900*4882a593Smuzhiyun 			if (rtattr_pack(nh, req_sz, type, &alg, sizeof(alg)))
901*4882a593Smuzhiyun 				return -1;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 			strncpy(alg.u.alg.alg_name, desc->a_algo, ALGO_LEN);
904*4882a593Smuzhiyun 			type = XFRMA_ALG_AUTH;
905*4882a593Smuzhiyun 			if (xfrm_fill_key(desc->a_algo, alg.u.alg.alg_key,
906*4882a593Smuzhiyun 						sizeof(alg.buf), &alg.u.alg.alg_key_len))
907*4882a593Smuzhiyun 				return -1;
908*4882a593Smuzhiyun 		}
909*4882a593Smuzhiyun 		break;
910*4882a593Smuzhiyun 	default:
911*4882a593Smuzhiyun 		printk("BUG: unknown proto in desc");
912*4882a593Smuzhiyun 		return -1;
913*4882a593Smuzhiyun 	}
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	if (rtattr_pack(nh, req_sz, type, &alg, sizeof(alg)))
916*4882a593Smuzhiyun 		return -1;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	return 0;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun 
gen_spi(struct in_addr src)921*4882a593Smuzhiyun static inline uint32_t gen_spi(struct in_addr src)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun 	return htonl(inet_lnaof(src));
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun 
xfrm_state_add(int xfrm_sock,uint32_t seq,uint32_t spi,struct in_addr src,struct in_addr dst,struct xfrm_desc * desc)926*4882a593Smuzhiyun static int xfrm_state_add(int xfrm_sock, uint32_t seq, uint32_t spi,
927*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
928*4882a593Smuzhiyun 		struct xfrm_desc *desc)
929*4882a593Smuzhiyun {
930*4882a593Smuzhiyun 	struct {
931*4882a593Smuzhiyun 		struct nlmsghdr		nh;
932*4882a593Smuzhiyun 		struct xfrm_usersa_info	info;
933*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
934*4882a593Smuzhiyun 	} req;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
937*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.info));
938*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_NEWSA;
939*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
940*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	/* Fill selector. */
943*4882a593Smuzhiyun 	memcpy(&req.info.sel.daddr, &dst, sizeof(dst));
944*4882a593Smuzhiyun 	memcpy(&req.info.sel.saddr, &src, sizeof(src));
945*4882a593Smuzhiyun 	req.info.sel.family		= AF_INET;
946*4882a593Smuzhiyun 	req.info.sel.prefixlen_d	= PREFIX_LEN;
947*4882a593Smuzhiyun 	req.info.sel.prefixlen_s	= PREFIX_LEN;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	/* Fill id */
950*4882a593Smuzhiyun 	memcpy(&req.info.id.daddr, &dst, sizeof(dst));
951*4882a593Smuzhiyun 	/* Note: zero-spi cannot be deleted */
952*4882a593Smuzhiyun 	req.info.id.spi = spi;
953*4882a593Smuzhiyun 	req.info.id.proto	= desc->proto;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	memcpy(&req.info.saddr, &src, sizeof(src));
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	/* Fill lifteme_cfg */
958*4882a593Smuzhiyun 	req.info.lft.soft_byte_limit	= XFRM_INF;
959*4882a593Smuzhiyun 	req.info.lft.hard_byte_limit	= XFRM_INF;
960*4882a593Smuzhiyun 	req.info.lft.soft_packet_limit	= XFRM_INF;
961*4882a593Smuzhiyun 	req.info.lft.hard_packet_limit	= XFRM_INF;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	req.info.family		= AF_INET;
964*4882a593Smuzhiyun 	req.info.mode		= XFRM_MODE_TUNNEL;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	if (xfrm_state_pack_algo(&req.nh, sizeof(req), desc))
967*4882a593Smuzhiyun 		return -1;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
970*4882a593Smuzhiyun 		pr_err("send()");
971*4882a593Smuzhiyun 		return -1;
972*4882a593Smuzhiyun 	}
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	return netlink_check_answer(xfrm_sock);
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun 
xfrm_usersa_found(struct xfrm_usersa_info * info,uint32_t spi,struct in_addr src,struct in_addr dst,struct xfrm_desc * desc)977*4882a593Smuzhiyun static bool xfrm_usersa_found(struct xfrm_usersa_info *info, uint32_t spi,
978*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
979*4882a593Smuzhiyun 		struct xfrm_desc *desc)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun 	if (memcmp(&info->sel.daddr, &dst, sizeof(dst)))
982*4882a593Smuzhiyun 		return false;
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	if (memcmp(&info->sel.saddr, &src, sizeof(src)))
985*4882a593Smuzhiyun 		return false;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	if (info->sel.family != AF_INET					||
988*4882a593Smuzhiyun 			info->sel.prefixlen_d != PREFIX_LEN		||
989*4882a593Smuzhiyun 			info->sel.prefixlen_s != PREFIX_LEN)
990*4882a593Smuzhiyun 		return false;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	if (info->id.spi != spi || info->id.proto != desc->proto)
993*4882a593Smuzhiyun 		return false;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	if (memcmp(&info->id.daddr, &dst, sizeof(dst)))
996*4882a593Smuzhiyun 		return false;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	if (memcmp(&info->saddr, &src, sizeof(src)))
999*4882a593Smuzhiyun 		return false;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	if (info->lft.soft_byte_limit != XFRM_INF			||
1002*4882a593Smuzhiyun 			info->lft.hard_byte_limit != XFRM_INF		||
1003*4882a593Smuzhiyun 			info->lft.soft_packet_limit != XFRM_INF		||
1004*4882a593Smuzhiyun 			info->lft.hard_packet_limit != XFRM_INF)
1005*4882a593Smuzhiyun 		return false;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	if (info->family != AF_INET || info->mode != XFRM_MODE_TUNNEL)
1008*4882a593Smuzhiyun 		return false;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	/* XXX: check xfrm algo, see xfrm_state_pack_algo(). */
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	return true;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun 
xfrm_state_check(int xfrm_sock,uint32_t seq,uint32_t spi,struct in_addr src,struct in_addr dst,struct xfrm_desc * desc)1015*4882a593Smuzhiyun static int xfrm_state_check(int xfrm_sock, uint32_t seq, uint32_t spi,
1016*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
1017*4882a593Smuzhiyun 		struct xfrm_desc *desc)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun 	struct {
1020*4882a593Smuzhiyun 		struct nlmsghdr		nh;
1021*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
1022*4882a593Smuzhiyun 	} req;
1023*4882a593Smuzhiyun 	struct {
1024*4882a593Smuzhiyun 		struct nlmsghdr		nh;
1025*4882a593Smuzhiyun 		union {
1026*4882a593Smuzhiyun 			struct xfrm_usersa_info	info;
1027*4882a593Smuzhiyun 			int error;
1028*4882a593Smuzhiyun 		};
1029*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
1030*4882a593Smuzhiyun 	} answer;
1031*4882a593Smuzhiyun 	struct xfrm_address_filter filter = {};
1032*4882a593Smuzhiyun 	bool found = false;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1036*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(0);
1037*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_GETSA;
1038*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_DUMP;
1039*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	/*
1042*4882a593Smuzhiyun 	 * Add dump filter by source address as there may be other tunnels
1043*4882a593Smuzhiyun 	 * in this netns (if tests run in parallel).
1044*4882a593Smuzhiyun 	 */
1045*4882a593Smuzhiyun 	filter.family = AF_INET;
1046*4882a593Smuzhiyun 	filter.splen = 0x1f;	/* 0xffffffff mask see addr_match() */
1047*4882a593Smuzhiyun 	memcpy(&filter.saddr, &src, sizeof(src));
1048*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), XFRMA_ADDRESS_FILTER,
1049*4882a593Smuzhiyun 				&filter, sizeof(filter)))
1050*4882a593Smuzhiyun 		return -1;
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1053*4882a593Smuzhiyun 		pr_err("send()");
1054*4882a593Smuzhiyun 		return -1;
1055*4882a593Smuzhiyun 	}
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	while (1) {
1058*4882a593Smuzhiyun 		if (recv(xfrm_sock, &answer, sizeof(answer), 0) < 0) {
1059*4882a593Smuzhiyun 			pr_err("recv()");
1060*4882a593Smuzhiyun 			return -1;
1061*4882a593Smuzhiyun 		}
1062*4882a593Smuzhiyun 		if (answer.nh.nlmsg_type == NLMSG_ERROR) {
1063*4882a593Smuzhiyun 			printk("NLMSG_ERROR: %d: %s",
1064*4882a593Smuzhiyun 				answer.error, strerror(-answer.error));
1065*4882a593Smuzhiyun 			return -1;
1066*4882a593Smuzhiyun 		} else if (answer.nh.nlmsg_type == NLMSG_DONE) {
1067*4882a593Smuzhiyun 			if (found)
1068*4882a593Smuzhiyun 				return 0;
1069*4882a593Smuzhiyun 			printk("didn't find allocated xfrm state in dump");
1070*4882a593Smuzhiyun 			return -1;
1071*4882a593Smuzhiyun 		} else if (answer.nh.nlmsg_type == XFRM_MSG_NEWSA) {
1072*4882a593Smuzhiyun 			if (xfrm_usersa_found(&answer.info, spi, src, dst, desc))
1073*4882a593Smuzhiyun 				found = true;
1074*4882a593Smuzhiyun 		}
1075*4882a593Smuzhiyun 	}
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun 
xfrm_set(int xfrm_sock,uint32_t * seq,struct in_addr src,struct in_addr dst,struct in_addr tunsrc,struct in_addr tundst,struct xfrm_desc * desc)1078*4882a593Smuzhiyun static int xfrm_set(int xfrm_sock, uint32_t *seq,
1079*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
1080*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst,
1081*4882a593Smuzhiyun 		struct xfrm_desc *desc)
1082*4882a593Smuzhiyun {
1083*4882a593Smuzhiyun 	int err;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	err = xfrm_state_add(xfrm_sock, (*seq)++, gen_spi(src), src, dst, desc);
1086*4882a593Smuzhiyun 	if (err) {
1087*4882a593Smuzhiyun 		printk("Failed to add xfrm state");
1088*4882a593Smuzhiyun 		return -1;
1089*4882a593Smuzhiyun 	}
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	err = xfrm_state_add(xfrm_sock, (*seq)++, gen_spi(src), dst, src, desc);
1092*4882a593Smuzhiyun 	if (err) {
1093*4882a593Smuzhiyun 		printk("Failed to add xfrm state");
1094*4882a593Smuzhiyun 		return -1;
1095*4882a593Smuzhiyun 	}
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	/* Check dumps for XFRM_MSG_GETSA */
1098*4882a593Smuzhiyun 	err = xfrm_state_check(xfrm_sock, (*seq)++, gen_spi(src), src, dst, desc);
1099*4882a593Smuzhiyun 	err |= xfrm_state_check(xfrm_sock, (*seq)++, gen_spi(src), dst, src, desc);
1100*4882a593Smuzhiyun 	if (err) {
1101*4882a593Smuzhiyun 		printk("Failed to check xfrm state");
1102*4882a593Smuzhiyun 		return -1;
1103*4882a593Smuzhiyun 	}
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	return 0;
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun 
xfrm_policy_add(int xfrm_sock,uint32_t seq,uint32_t spi,struct in_addr src,struct in_addr dst,uint8_t dir,struct in_addr tunsrc,struct in_addr tundst,uint8_t proto)1108*4882a593Smuzhiyun static int xfrm_policy_add(int xfrm_sock, uint32_t seq, uint32_t spi,
1109*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst, uint8_t dir,
1110*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst, uint8_t proto)
1111*4882a593Smuzhiyun {
1112*4882a593Smuzhiyun 	struct {
1113*4882a593Smuzhiyun 		struct nlmsghdr			nh;
1114*4882a593Smuzhiyun 		struct xfrm_userpolicy_info	info;
1115*4882a593Smuzhiyun 		char				attrbuf[MAX_PAYLOAD];
1116*4882a593Smuzhiyun 	} req;
1117*4882a593Smuzhiyun 	struct xfrm_user_tmpl tmpl;
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1120*4882a593Smuzhiyun 	memset(&tmpl, 0, sizeof(tmpl));
1121*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.info));
1122*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_NEWPOLICY;
1123*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1124*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 	/* Fill selector. */
1127*4882a593Smuzhiyun 	memcpy(&req.info.sel.daddr, &dst, sizeof(tundst));
1128*4882a593Smuzhiyun 	memcpy(&req.info.sel.saddr, &src, sizeof(tunsrc));
1129*4882a593Smuzhiyun 	req.info.sel.family		= AF_INET;
1130*4882a593Smuzhiyun 	req.info.sel.prefixlen_d	= PREFIX_LEN;
1131*4882a593Smuzhiyun 	req.info.sel.prefixlen_s	= PREFIX_LEN;
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	/* Fill lifteme_cfg */
1134*4882a593Smuzhiyun 	req.info.lft.soft_byte_limit	= XFRM_INF;
1135*4882a593Smuzhiyun 	req.info.lft.hard_byte_limit	= XFRM_INF;
1136*4882a593Smuzhiyun 	req.info.lft.soft_packet_limit	= XFRM_INF;
1137*4882a593Smuzhiyun 	req.info.lft.hard_packet_limit	= XFRM_INF;
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	req.info.dir = dir;
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	/* Fill tmpl */
1142*4882a593Smuzhiyun 	memcpy(&tmpl.id.daddr, &dst, sizeof(dst));
1143*4882a593Smuzhiyun 	/* Note: zero-spi cannot be deleted */
1144*4882a593Smuzhiyun 	tmpl.id.spi = spi;
1145*4882a593Smuzhiyun 	tmpl.id.proto	= proto;
1146*4882a593Smuzhiyun 	tmpl.family	= AF_INET;
1147*4882a593Smuzhiyun 	memcpy(&tmpl.saddr, &src, sizeof(src));
1148*4882a593Smuzhiyun 	tmpl.mode	= XFRM_MODE_TUNNEL;
1149*4882a593Smuzhiyun 	tmpl.aalgos = (~(uint32_t)0);
1150*4882a593Smuzhiyun 	tmpl.ealgos = (~(uint32_t)0);
1151*4882a593Smuzhiyun 	tmpl.calgos = (~(uint32_t)0);
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), XFRMA_TMPL, &tmpl, sizeof(tmpl)))
1154*4882a593Smuzhiyun 		return -1;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1157*4882a593Smuzhiyun 		pr_err("send()");
1158*4882a593Smuzhiyun 		return -1;
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	return netlink_check_answer(xfrm_sock);
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun 
xfrm_prepare(int xfrm_sock,uint32_t * seq,struct in_addr src,struct in_addr dst,struct in_addr tunsrc,struct in_addr tundst,uint8_t proto)1164*4882a593Smuzhiyun static int xfrm_prepare(int xfrm_sock, uint32_t *seq,
1165*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
1166*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst, uint8_t proto)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	if (xfrm_policy_add(xfrm_sock, (*seq)++, gen_spi(src), src, dst,
1169*4882a593Smuzhiyun 				XFRM_POLICY_OUT, tunsrc, tundst, proto)) {
1170*4882a593Smuzhiyun 		printk("Failed to add xfrm policy");
1171*4882a593Smuzhiyun 		return -1;
1172*4882a593Smuzhiyun 	}
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	if (xfrm_policy_add(xfrm_sock, (*seq)++, gen_spi(src), dst, src,
1175*4882a593Smuzhiyun 				XFRM_POLICY_IN, tunsrc, tundst, proto)) {
1176*4882a593Smuzhiyun 		printk("Failed to add xfrm policy");
1177*4882a593Smuzhiyun 		return -1;
1178*4882a593Smuzhiyun 	}
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	return 0;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun 
xfrm_policy_del(int xfrm_sock,uint32_t seq,struct in_addr src,struct in_addr dst,uint8_t dir,struct in_addr tunsrc,struct in_addr tundst)1183*4882a593Smuzhiyun static int xfrm_policy_del(int xfrm_sock, uint32_t seq,
1184*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst, uint8_t dir,
1185*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst)
1186*4882a593Smuzhiyun {
1187*4882a593Smuzhiyun 	struct {
1188*4882a593Smuzhiyun 		struct nlmsghdr			nh;
1189*4882a593Smuzhiyun 		struct xfrm_userpolicy_id	id;
1190*4882a593Smuzhiyun 		char				attrbuf[MAX_PAYLOAD];
1191*4882a593Smuzhiyun 	} req;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1194*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.id));
1195*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_DELPOLICY;
1196*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1197*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	/* Fill id */
1200*4882a593Smuzhiyun 	memcpy(&req.id.sel.daddr, &dst, sizeof(tundst));
1201*4882a593Smuzhiyun 	memcpy(&req.id.sel.saddr, &src, sizeof(tunsrc));
1202*4882a593Smuzhiyun 	req.id.sel.family		= AF_INET;
1203*4882a593Smuzhiyun 	req.id.sel.prefixlen_d		= PREFIX_LEN;
1204*4882a593Smuzhiyun 	req.id.sel.prefixlen_s		= PREFIX_LEN;
1205*4882a593Smuzhiyun 	req.id.dir = dir;
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1208*4882a593Smuzhiyun 		pr_err("send()");
1209*4882a593Smuzhiyun 		return -1;
1210*4882a593Smuzhiyun 	}
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	return netlink_check_answer(xfrm_sock);
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun 
xfrm_cleanup(int xfrm_sock,uint32_t * seq,struct in_addr src,struct in_addr dst,struct in_addr tunsrc,struct in_addr tundst)1215*4882a593Smuzhiyun static int xfrm_cleanup(int xfrm_sock, uint32_t *seq,
1216*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
1217*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun 	if (xfrm_policy_del(xfrm_sock, (*seq)++, src, dst,
1220*4882a593Smuzhiyun 				XFRM_POLICY_OUT, tunsrc, tundst)) {
1221*4882a593Smuzhiyun 		printk("Failed to add xfrm policy");
1222*4882a593Smuzhiyun 		return -1;
1223*4882a593Smuzhiyun 	}
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	if (xfrm_policy_del(xfrm_sock, (*seq)++, dst, src,
1226*4882a593Smuzhiyun 				XFRM_POLICY_IN, tunsrc, tundst)) {
1227*4882a593Smuzhiyun 		printk("Failed to add xfrm policy");
1228*4882a593Smuzhiyun 		return -1;
1229*4882a593Smuzhiyun 	}
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	return 0;
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun 
xfrm_state_del(int xfrm_sock,uint32_t seq,uint32_t spi,struct in_addr src,struct in_addr dst,uint8_t proto)1234*4882a593Smuzhiyun static int xfrm_state_del(int xfrm_sock, uint32_t seq, uint32_t spi,
1235*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst, uint8_t proto)
1236*4882a593Smuzhiyun {
1237*4882a593Smuzhiyun 	struct {
1238*4882a593Smuzhiyun 		struct nlmsghdr		nh;
1239*4882a593Smuzhiyun 		struct xfrm_usersa_id	id;
1240*4882a593Smuzhiyun 		char			attrbuf[MAX_PAYLOAD];
1241*4882a593Smuzhiyun 	} req;
1242*4882a593Smuzhiyun 	xfrm_address_t saddr = {};
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1245*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.id));
1246*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_DELSA;
1247*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1248*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= seq;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	memcpy(&req.id.daddr, &dst, sizeof(dst));
1251*4882a593Smuzhiyun 	req.id.family		= AF_INET;
1252*4882a593Smuzhiyun 	req.id.proto		= proto;
1253*4882a593Smuzhiyun 	/* Note: zero-spi cannot be deleted */
1254*4882a593Smuzhiyun 	req.id.spi = spi;
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	memcpy(&saddr, &src, sizeof(src));
1257*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), XFRMA_SRCADDR, &saddr, sizeof(saddr)))
1258*4882a593Smuzhiyun 		return -1;
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1261*4882a593Smuzhiyun 		pr_err("send()");
1262*4882a593Smuzhiyun 		return -1;
1263*4882a593Smuzhiyun 	}
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	return netlink_check_answer(xfrm_sock);
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun 
xfrm_delete(int xfrm_sock,uint32_t * seq,struct in_addr src,struct in_addr dst,struct in_addr tunsrc,struct in_addr tundst,uint8_t proto)1268*4882a593Smuzhiyun static int xfrm_delete(int xfrm_sock, uint32_t *seq,
1269*4882a593Smuzhiyun 		struct in_addr src, struct in_addr dst,
1270*4882a593Smuzhiyun 		struct in_addr tunsrc, struct in_addr tundst, uint8_t proto)
1271*4882a593Smuzhiyun {
1272*4882a593Smuzhiyun 	if (xfrm_state_del(xfrm_sock, (*seq)++, gen_spi(src), src, dst, proto)) {
1273*4882a593Smuzhiyun 		printk("Failed to remove xfrm state");
1274*4882a593Smuzhiyun 		return -1;
1275*4882a593Smuzhiyun 	}
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	if (xfrm_state_del(xfrm_sock, (*seq)++, gen_spi(src), dst, src, proto)) {
1278*4882a593Smuzhiyun 		printk("Failed to remove xfrm state");
1279*4882a593Smuzhiyun 		return -1;
1280*4882a593Smuzhiyun 	}
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	return 0;
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun 
xfrm_state_allocspi(int xfrm_sock,uint32_t * seq,uint32_t spi,uint8_t proto)1285*4882a593Smuzhiyun static int xfrm_state_allocspi(int xfrm_sock, uint32_t *seq,
1286*4882a593Smuzhiyun 		uint32_t spi, uint8_t proto)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun 	struct {
1289*4882a593Smuzhiyun 		struct nlmsghdr			nh;
1290*4882a593Smuzhiyun 		struct xfrm_userspi_info	spi;
1291*4882a593Smuzhiyun 	} req;
1292*4882a593Smuzhiyun 	struct {
1293*4882a593Smuzhiyun 		struct nlmsghdr			nh;
1294*4882a593Smuzhiyun 		union {
1295*4882a593Smuzhiyun 			struct xfrm_usersa_info	info;
1296*4882a593Smuzhiyun 			int error;
1297*4882a593Smuzhiyun 		};
1298*4882a593Smuzhiyun 	} answer;
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1301*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.spi));
1302*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_ALLOCSPI;
1303*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST;
1304*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= (*seq)++;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	req.spi.info.family	= AF_INET;
1307*4882a593Smuzhiyun 	req.spi.min		= spi;
1308*4882a593Smuzhiyun 	req.spi.max		= spi;
1309*4882a593Smuzhiyun 	req.spi.info.id.proto	= proto;
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1312*4882a593Smuzhiyun 		pr_err("send()");
1313*4882a593Smuzhiyun 		return KSFT_FAIL;
1314*4882a593Smuzhiyun 	}
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	if (recv(xfrm_sock, &answer, sizeof(answer), 0) < 0) {
1317*4882a593Smuzhiyun 		pr_err("recv()");
1318*4882a593Smuzhiyun 		return KSFT_FAIL;
1319*4882a593Smuzhiyun 	} else if (answer.nh.nlmsg_type == XFRM_MSG_NEWSA) {
1320*4882a593Smuzhiyun 		uint32_t new_spi = htonl(answer.info.id.spi);
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 		if (new_spi != spi) {
1323*4882a593Smuzhiyun 			printk("allocated spi is different from requested: %#x != %#x",
1324*4882a593Smuzhiyun 					new_spi, spi);
1325*4882a593Smuzhiyun 			return KSFT_FAIL;
1326*4882a593Smuzhiyun 		}
1327*4882a593Smuzhiyun 		return KSFT_PASS;
1328*4882a593Smuzhiyun 	} else if (answer.nh.nlmsg_type != NLMSG_ERROR) {
1329*4882a593Smuzhiyun 		printk("expected NLMSG_ERROR, got %d", (int)answer.nh.nlmsg_type);
1330*4882a593Smuzhiyun 		return KSFT_FAIL;
1331*4882a593Smuzhiyun 	}
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	printk("NLMSG_ERROR: %d: %s", answer.error, strerror(-answer.error));
1334*4882a593Smuzhiyun 	return (answer.error) ? KSFT_FAIL : KSFT_PASS;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun 
netlink_sock_bind(int * sock,uint32_t * seq,int proto,uint32_t groups)1337*4882a593Smuzhiyun static int netlink_sock_bind(int *sock, uint32_t *seq, int proto, uint32_t groups)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun 	struct sockaddr_nl snl = {};
1340*4882a593Smuzhiyun 	socklen_t addr_len;
1341*4882a593Smuzhiyun 	int ret = -1;
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 	snl.nl_family = AF_NETLINK;
1344*4882a593Smuzhiyun 	snl.nl_groups = groups;
1345*4882a593Smuzhiyun 
1346*4882a593Smuzhiyun 	if (netlink_sock(sock, seq, proto)) {
1347*4882a593Smuzhiyun 		printk("Failed to open xfrm netlink socket");
1348*4882a593Smuzhiyun 		return -1;
1349*4882a593Smuzhiyun 	}
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	if (bind(*sock, (struct sockaddr *)&snl, sizeof(snl)) < 0) {
1352*4882a593Smuzhiyun 		pr_err("bind()");
1353*4882a593Smuzhiyun 		goto out_close;
1354*4882a593Smuzhiyun 	}
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 	addr_len = sizeof(snl);
1357*4882a593Smuzhiyun 	if (getsockname(*sock, (struct sockaddr *)&snl, &addr_len) < 0) {
1358*4882a593Smuzhiyun 		pr_err("getsockname()");
1359*4882a593Smuzhiyun 		goto out_close;
1360*4882a593Smuzhiyun 	}
1361*4882a593Smuzhiyun 	if (addr_len != sizeof(snl)) {
1362*4882a593Smuzhiyun 		printk("Wrong address length %d", addr_len);
1363*4882a593Smuzhiyun 		goto out_close;
1364*4882a593Smuzhiyun 	}
1365*4882a593Smuzhiyun 	if (snl.nl_family != AF_NETLINK) {
1366*4882a593Smuzhiyun 		printk("Wrong address family %d", snl.nl_family);
1367*4882a593Smuzhiyun 		goto out_close;
1368*4882a593Smuzhiyun 	}
1369*4882a593Smuzhiyun 	return 0;
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun out_close:
1372*4882a593Smuzhiyun 	close(*sock);
1373*4882a593Smuzhiyun 	return ret;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun 
xfrm_monitor_acquire(int xfrm_sock,uint32_t * seq,unsigned int nr)1376*4882a593Smuzhiyun static int xfrm_monitor_acquire(int xfrm_sock, uint32_t *seq, unsigned int nr)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun 	struct {
1379*4882a593Smuzhiyun 		struct nlmsghdr nh;
1380*4882a593Smuzhiyun 		union {
1381*4882a593Smuzhiyun 			struct xfrm_user_acquire acq;
1382*4882a593Smuzhiyun 			int error;
1383*4882a593Smuzhiyun 		};
1384*4882a593Smuzhiyun 		char attrbuf[MAX_PAYLOAD];
1385*4882a593Smuzhiyun 	} req;
1386*4882a593Smuzhiyun 	struct xfrm_user_tmpl xfrm_tmpl = {};
1387*4882a593Smuzhiyun 	int xfrm_listen = -1, ret = KSFT_FAIL;
1388*4882a593Smuzhiyun 	uint32_t seq_listen;
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	if (netlink_sock_bind(&xfrm_listen, &seq_listen, NETLINK_XFRM, XFRMNLGRP_ACQUIRE))
1391*4882a593Smuzhiyun 		return KSFT_FAIL;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1394*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.acq));
1395*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_ACQUIRE;
1396*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1397*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= (*seq)++;
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun 	req.acq.policy.sel.family	= AF_INET;
1400*4882a593Smuzhiyun 	req.acq.aalgos	= 0xfeed;
1401*4882a593Smuzhiyun 	req.acq.ealgos	= 0xbaad;
1402*4882a593Smuzhiyun 	req.acq.calgos	= 0xbabe;
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	xfrm_tmpl.family = AF_INET;
1405*4882a593Smuzhiyun 	xfrm_tmpl.id.proto = IPPROTO_ESP;
1406*4882a593Smuzhiyun 	if (rtattr_pack(&req.nh, sizeof(req), XFRMA_TMPL, &xfrm_tmpl, sizeof(xfrm_tmpl)))
1407*4882a593Smuzhiyun 		goto out_close;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1410*4882a593Smuzhiyun 		pr_err("send()");
1411*4882a593Smuzhiyun 		goto out_close;
1412*4882a593Smuzhiyun 	}
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun 	if (recv(xfrm_sock, &req, sizeof(req), 0) < 0) {
1415*4882a593Smuzhiyun 		pr_err("recv()");
1416*4882a593Smuzhiyun 		goto out_close;
1417*4882a593Smuzhiyun 	} else if (req.nh.nlmsg_type != NLMSG_ERROR) {
1418*4882a593Smuzhiyun 		printk("expected NLMSG_ERROR, got %d", (int)req.nh.nlmsg_type);
1419*4882a593Smuzhiyun 		goto out_close;
1420*4882a593Smuzhiyun 	}
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	if (req.error) {
1423*4882a593Smuzhiyun 		printk("NLMSG_ERROR: %d: %s", req.error, strerror(-req.error));
1424*4882a593Smuzhiyun 		ret = req.error;
1425*4882a593Smuzhiyun 		goto out_close;
1426*4882a593Smuzhiyun 	}
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 	if (recv(xfrm_listen, &req, sizeof(req), 0) < 0) {
1429*4882a593Smuzhiyun 		pr_err("recv()");
1430*4882a593Smuzhiyun 		goto out_close;
1431*4882a593Smuzhiyun 	}
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	if (req.acq.aalgos != 0xfeed || req.acq.ealgos != 0xbaad
1434*4882a593Smuzhiyun 			|| req.acq.calgos != 0xbabe) {
1435*4882a593Smuzhiyun 		printk("xfrm_user_acquire has changed  %x %x %x",
1436*4882a593Smuzhiyun 				req.acq.aalgos, req.acq.ealgos, req.acq.calgos);
1437*4882a593Smuzhiyun 		goto out_close;
1438*4882a593Smuzhiyun 	}
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 	ret = KSFT_PASS;
1441*4882a593Smuzhiyun out_close:
1442*4882a593Smuzhiyun 	close(xfrm_listen);
1443*4882a593Smuzhiyun 	return ret;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun 
xfrm_expire_state(int xfrm_sock,uint32_t * seq,unsigned int nr,struct xfrm_desc * desc)1446*4882a593Smuzhiyun static int xfrm_expire_state(int xfrm_sock, uint32_t *seq,
1447*4882a593Smuzhiyun 		unsigned int nr, struct xfrm_desc *desc)
1448*4882a593Smuzhiyun {
1449*4882a593Smuzhiyun 	struct {
1450*4882a593Smuzhiyun 		struct nlmsghdr nh;
1451*4882a593Smuzhiyun 		union {
1452*4882a593Smuzhiyun 			struct xfrm_user_expire expire;
1453*4882a593Smuzhiyun 			int error;
1454*4882a593Smuzhiyun 		};
1455*4882a593Smuzhiyun 	} req;
1456*4882a593Smuzhiyun 	struct in_addr src, dst;
1457*4882a593Smuzhiyun 	int xfrm_listen = -1, ret = KSFT_FAIL;
1458*4882a593Smuzhiyun 	uint32_t seq_listen;
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	src = inet_makeaddr(INADDR_B, child_ip(nr));
1461*4882a593Smuzhiyun 	dst = inet_makeaddr(INADDR_B, grchild_ip(nr));
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	if (xfrm_state_add(xfrm_sock, (*seq)++, gen_spi(src), src, dst, desc)) {
1464*4882a593Smuzhiyun 		printk("Failed to add xfrm state");
1465*4882a593Smuzhiyun 		return KSFT_FAIL;
1466*4882a593Smuzhiyun 	}
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 	if (netlink_sock_bind(&xfrm_listen, &seq_listen, NETLINK_XFRM, XFRMNLGRP_EXPIRE))
1469*4882a593Smuzhiyun 		return KSFT_FAIL;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1472*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.expire));
1473*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_EXPIRE;
1474*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1475*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= (*seq)++;
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	memcpy(&req.expire.state.id.daddr, &dst, sizeof(dst));
1478*4882a593Smuzhiyun 	req.expire.state.id.spi		= gen_spi(src);
1479*4882a593Smuzhiyun 	req.expire.state.id.proto	= desc->proto;
1480*4882a593Smuzhiyun 	req.expire.state.family		= AF_INET;
1481*4882a593Smuzhiyun 	req.expire.hard			= 0xff;
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1484*4882a593Smuzhiyun 		pr_err("send()");
1485*4882a593Smuzhiyun 		goto out_close;
1486*4882a593Smuzhiyun 	}
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	if (recv(xfrm_sock, &req, sizeof(req), 0) < 0) {
1489*4882a593Smuzhiyun 		pr_err("recv()");
1490*4882a593Smuzhiyun 		goto out_close;
1491*4882a593Smuzhiyun 	} else if (req.nh.nlmsg_type != NLMSG_ERROR) {
1492*4882a593Smuzhiyun 		printk("expected NLMSG_ERROR, got %d", (int)req.nh.nlmsg_type);
1493*4882a593Smuzhiyun 		goto out_close;
1494*4882a593Smuzhiyun 	}
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	if (req.error) {
1497*4882a593Smuzhiyun 		printk("NLMSG_ERROR: %d: %s", req.error, strerror(-req.error));
1498*4882a593Smuzhiyun 		ret = req.error;
1499*4882a593Smuzhiyun 		goto out_close;
1500*4882a593Smuzhiyun 	}
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	if (recv(xfrm_listen, &req, sizeof(req), 0) < 0) {
1503*4882a593Smuzhiyun 		pr_err("recv()");
1504*4882a593Smuzhiyun 		goto out_close;
1505*4882a593Smuzhiyun 	}
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	if (req.expire.hard != 0x1) {
1508*4882a593Smuzhiyun 		printk("expire.hard is not set: %x", req.expire.hard);
1509*4882a593Smuzhiyun 		goto out_close;
1510*4882a593Smuzhiyun 	}
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 	ret = KSFT_PASS;
1513*4882a593Smuzhiyun out_close:
1514*4882a593Smuzhiyun 	close(xfrm_listen);
1515*4882a593Smuzhiyun 	return ret;
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun 
xfrm_expire_policy(int xfrm_sock,uint32_t * seq,unsigned int nr,struct xfrm_desc * desc)1518*4882a593Smuzhiyun static int xfrm_expire_policy(int xfrm_sock, uint32_t *seq,
1519*4882a593Smuzhiyun 		unsigned int nr, struct xfrm_desc *desc)
1520*4882a593Smuzhiyun {
1521*4882a593Smuzhiyun 	struct {
1522*4882a593Smuzhiyun 		struct nlmsghdr nh;
1523*4882a593Smuzhiyun 		union {
1524*4882a593Smuzhiyun 			struct xfrm_user_polexpire expire;
1525*4882a593Smuzhiyun 			int error;
1526*4882a593Smuzhiyun 		};
1527*4882a593Smuzhiyun 	} req;
1528*4882a593Smuzhiyun 	struct in_addr src, dst, tunsrc, tundst;
1529*4882a593Smuzhiyun 	int xfrm_listen = -1, ret = KSFT_FAIL;
1530*4882a593Smuzhiyun 	uint32_t seq_listen;
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	src = inet_makeaddr(INADDR_B, child_ip(nr));
1533*4882a593Smuzhiyun 	dst = inet_makeaddr(INADDR_B, grchild_ip(nr));
1534*4882a593Smuzhiyun 	tunsrc = inet_makeaddr(INADDR_A, child_ip(nr));
1535*4882a593Smuzhiyun 	tundst = inet_makeaddr(INADDR_A, grchild_ip(nr));
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	if (xfrm_policy_add(xfrm_sock, (*seq)++, gen_spi(src), src, dst,
1538*4882a593Smuzhiyun 				XFRM_POLICY_OUT, tunsrc, tundst, desc->proto)) {
1539*4882a593Smuzhiyun 		printk("Failed to add xfrm policy");
1540*4882a593Smuzhiyun 		return KSFT_FAIL;
1541*4882a593Smuzhiyun 	}
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	if (netlink_sock_bind(&xfrm_listen, &seq_listen, NETLINK_XFRM, XFRMNLGRP_EXPIRE))
1544*4882a593Smuzhiyun 		return KSFT_FAIL;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	memset(&req, 0, sizeof(req));
1547*4882a593Smuzhiyun 	req.nh.nlmsg_len	= NLMSG_LENGTH(sizeof(req.expire));
1548*4882a593Smuzhiyun 	req.nh.nlmsg_type	= XFRM_MSG_POLEXPIRE;
1549*4882a593Smuzhiyun 	req.nh.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK;
1550*4882a593Smuzhiyun 	req.nh.nlmsg_seq	= (*seq)++;
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	/* Fill selector. */
1553*4882a593Smuzhiyun 	memcpy(&req.expire.pol.sel.daddr, &dst, sizeof(tundst));
1554*4882a593Smuzhiyun 	memcpy(&req.expire.pol.sel.saddr, &src, sizeof(tunsrc));
1555*4882a593Smuzhiyun 	req.expire.pol.sel.family	= AF_INET;
1556*4882a593Smuzhiyun 	req.expire.pol.sel.prefixlen_d	= PREFIX_LEN;
1557*4882a593Smuzhiyun 	req.expire.pol.sel.prefixlen_s	= PREFIX_LEN;
1558*4882a593Smuzhiyun 	req.expire.pol.dir		= XFRM_POLICY_OUT;
1559*4882a593Smuzhiyun 	req.expire.hard			= 0xff;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	if (send(xfrm_sock, &req, req.nh.nlmsg_len, 0) < 0) {
1562*4882a593Smuzhiyun 		pr_err("send()");
1563*4882a593Smuzhiyun 		goto out_close;
1564*4882a593Smuzhiyun 	}
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	if (recv(xfrm_sock, &req, sizeof(req), 0) < 0) {
1567*4882a593Smuzhiyun 		pr_err("recv()");
1568*4882a593Smuzhiyun 		goto out_close;
1569*4882a593Smuzhiyun 	} else if (req.nh.nlmsg_type != NLMSG_ERROR) {
1570*4882a593Smuzhiyun 		printk("expected NLMSG_ERROR, got %d", (int)req.nh.nlmsg_type);
1571*4882a593Smuzhiyun 		goto out_close;
1572*4882a593Smuzhiyun 	}
1573*4882a593Smuzhiyun 
1574*4882a593Smuzhiyun 	if (req.error) {
1575*4882a593Smuzhiyun 		printk("NLMSG_ERROR: %d: %s", req.error, strerror(-req.error));
1576*4882a593Smuzhiyun 		ret = req.error;
1577*4882a593Smuzhiyun 		goto out_close;
1578*4882a593Smuzhiyun 	}
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	if (recv(xfrm_listen, &req, sizeof(req), 0) < 0) {
1581*4882a593Smuzhiyun 		pr_err("recv()");
1582*4882a593Smuzhiyun 		goto out_close;
1583*4882a593Smuzhiyun 	}
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	if (req.expire.hard != 0x1) {
1586*4882a593Smuzhiyun 		printk("expire.hard is not set: %x", req.expire.hard);
1587*4882a593Smuzhiyun 		goto out_close;
1588*4882a593Smuzhiyun 	}
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	ret = KSFT_PASS;
1591*4882a593Smuzhiyun out_close:
1592*4882a593Smuzhiyun 	close(xfrm_listen);
1593*4882a593Smuzhiyun 	return ret;
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun 
child_serv(int xfrm_sock,uint32_t * seq,unsigned int nr,int cmd_fd,void * buf,struct xfrm_desc * desc)1596*4882a593Smuzhiyun static int child_serv(int xfrm_sock, uint32_t *seq,
1597*4882a593Smuzhiyun 		unsigned int nr, int cmd_fd, void *buf, struct xfrm_desc *desc)
1598*4882a593Smuzhiyun {
1599*4882a593Smuzhiyun 	struct in_addr src, dst, tunsrc, tundst;
1600*4882a593Smuzhiyun 	struct test_desc msg;
1601*4882a593Smuzhiyun 	int ret = KSFT_FAIL;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	src = inet_makeaddr(INADDR_B, child_ip(nr));
1604*4882a593Smuzhiyun 	dst = inet_makeaddr(INADDR_B, grchild_ip(nr));
1605*4882a593Smuzhiyun 	tunsrc = inet_makeaddr(INADDR_A, child_ip(nr));
1606*4882a593Smuzhiyun 	tundst = inet_makeaddr(INADDR_A, grchild_ip(nr));
1607*4882a593Smuzhiyun 
1608*4882a593Smuzhiyun 	/* UDP pinging without xfrm */
1609*4882a593Smuzhiyun 	if (do_ping(cmd_fd, buf, page_size, src, true, 0, 0, udp_ping_send)) {
1610*4882a593Smuzhiyun 		printk("ping failed before setting xfrm");
1611*4882a593Smuzhiyun 		return KSFT_FAIL;
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
1615*4882a593Smuzhiyun 	msg.type = MSG_XFRM_PREPARE;
1616*4882a593Smuzhiyun 	memcpy(&msg.body.xfrm_desc, desc, sizeof(*desc));
1617*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1618*4882a593Smuzhiyun 
1619*4882a593Smuzhiyun 	if (xfrm_prepare(xfrm_sock, seq, src, dst, tunsrc, tundst, desc->proto)) {
1620*4882a593Smuzhiyun 		printk("failed to prepare xfrm");
1621*4882a593Smuzhiyun 		goto cleanup;
1622*4882a593Smuzhiyun 	}
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
1625*4882a593Smuzhiyun 	msg.type = MSG_XFRM_ADD;
1626*4882a593Smuzhiyun 	memcpy(&msg.body.xfrm_desc, desc, sizeof(*desc));
1627*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1628*4882a593Smuzhiyun 	if (xfrm_set(xfrm_sock, seq, src, dst, tunsrc, tundst, desc)) {
1629*4882a593Smuzhiyun 		printk("failed to set xfrm");
1630*4882a593Smuzhiyun 		goto delete;
1631*4882a593Smuzhiyun 	}
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	/* UDP pinging with xfrm tunnel */
1634*4882a593Smuzhiyun 	if (do_ping(cmd_fd, buf, page_size, tunsrc,
1635*4882a593Smuzhiyun 				true, 0, 0, udp_ping_send)) {
1636*4882a593Smuzhiyun 		printk("ping failed for xfrm");
1637*4882a593Smuzhiyun 		goto delete;
1638*4882a593Smuzhiyun 	}
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	ret = KSFT_PASS;
1641*4882a593Smuzhiyun delete:
1642*4882a593Smuzhiyun 	/* xfrm delete */
1643*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
1644*4882a593Smuzhiyun 	msg.type = MSG_XFRM_DEL;
1645*4882a593Smuzhiyun 	memcpy(&msg.body.xfrm_desc, desc, sizeof(*desc));
1646*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 	if (xfrm_delete(xfrm_sock, seq, src, dst, tunsrc, tundst, desc->proto)) {
1649*4882a593Smuzhiyun 		printk("failed ping to remove xfrm");
1650*4882a593Smuzhiyun 		ret = KSFT_FAIL;
1651*4882a593Smuzhiyun 	}
1652*4882a593Smuzhiyun 
1653*4882a593Smuzhiyun cleanup:
1654*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
1655*4882a593Smuzhiyun 	msg.type = MSG_XFRM_CLEANUP;
1656*4882a593Smuzhiyun 	memcpy(&msg.body.xfrm_desc, desc, sizeof(*desc));
1657*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1658*4882a593Smuzhiyun 	if (xfrm_cleanup(xfrm_sock, seq, src, dst, tunsrc, tundst)) {
1659*4882a593Smuzhiyun 		printk("failed ping to cleanup xfrm");
1660*4882a593Smuzhiyun 		ret = KSFT_FAIL;
1661*4882a593Smuzhiyun 	}
1662*4882a593Smuzhiyun 	return ret;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun 
child_f(unsigned int nr,int test_desc_fd,int cmd_fd,void * buf)1665*4882a593Smuzhiyun static int child_f(unsigned int nr, int test_desc_fd, int cmd_fd, void *buf)
1666*4882a593Smuzhiyun {
1667*4882a593Smuzhiyun 	struct xfrm_desc desc;
1668*4882a593Smuzhiyun 	struct test_desc msg;
1669*4882a593Smuzhiyun 	int xfrm_sock = -1;
1670*4882a593Smuzhiyun 	uint32_t seq;
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	if (switch_ns(nsfd_childa))
1673*4882a593Smuzhiyun 		exit(KSFT_FAIL);
1674*4882a593Smuzhiyun 
1675*4882a593Smuzhiyun 	if (netlink_sock(&xfrm_sock, &seq, NETLINK_XFRM)) {
1676*4882a593Smuzhiyun 		printk("Failed to open xfrm netlink socket");
1677*4882a593Smuzhiyun 		exit(KSFT_FAIL);
1678*4882a593Smuzhiyun 	}
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	/* Check that seq sock is ready, just for sure. */
1681*4882a593Smuzhiyun 	memset(&msg, 0, sizeof(msg));
1682*4882a593Smuzhiyun 	msg.type = MSG_ACK;
1683*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1684*4882a593Smuzhiyun 	read_msg(cmd_fd, &msg, 1);
1685*4882a593Smuzhiyun 	if (msg.type != MSG_ACK) {
1686*4882a593Smuzhiyun 		printk("Ack failed");
1687*4882a593Smuzhiyun 		exit(KSFT_FAIL);
1688*4882a593Smuzhiyun 	}
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	for (;;) {
1691*4882a593Smuzhiyun 		ssize_t received = read(test_desc_fd, &desc, sizeof(desc));
1692*4882a593Smuzhiyun 		int ret;
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 		if (received == 0) /* EOF */
1695*4882a593Smuzhiyun 			break;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 		if (received != sizeof(desc)) {
1698*4882a593Smuzhiyun 			pr_err("read() returned %zd", received);
1699*4882a593Smuzhiyun 			exit(KSFT_FAIL);
1700*4882a593Smuzhiyun 		}
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 		switch (desc.type) {
1703*4882a593Smuzhiyun 		case CREATE_TUNNEL:
1704*4882a593Smuzhiyun 			ret = child_serv(xfrm_sock, &seq, nr,
1705*4882a593Smuzhiyun 					 cmd_fd, buf, &desc);
1706*4882a593Smuzhiyun 			break;
1707*4882a593Smuzhiyun 		case ALLOCATE_SPI:
1708*4882a593Smuzhiyun 			ret = xfrm_state_allocspi(xfrm_sock, &seq,
1709*4882a593Smuzhiyun 						  -1, desc.proto);
1710*4882a593Smuzhiyun 			break;
1711*4882a593Smuzhiyun 		case MONITOR_ACQUIRE:
1712*4882a593Smuzhiyun 			ret = xfrm_monitor_acquire(xfrm_sock, &seq, nr);
1713*4882a593Smuzhiyun 			break;
1714*4882a593Smuzhiyun 		case EXPIRE_STATE:
1715*4882a593Smuzhiyun 			ret = xfrm_expire_state(xfrm_sock, &seq, nr, &desc);
1716*4882a593Smuzhiyun 			break;
1717*4882a593Smuzhiyun 		case EXPIRE_POLICY:
1718*4882a593Smuzhiyun 			ret = xfrm_expire_policy(xfrm_sock, &seq, nr, &desc);
1719*4882a593Smuzhiyun 			break;
1720*4882a593Smuzhiyun 		default:
1721*4882a593Smuzhiyun 			printk("Unknown desc type %d", desc.type);
1722*4882a593Smuzhiyun 			exit(KSFT_FAIL);
1723*4882a593Smuzhiyun 		}
1724*4882a593Smuzhiyun 		write_test_result(ret, &desc);
1725*4882a593Smuzhiyun 	}
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun 	close(xfrm_sock);
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	msg.type = MSG_EXIT;
1730*4882a593Smuzhiyun 	write_msg(cmd_fd, &msg, 1);
1731*4882a593Smuzhiyun 	exit(KSFT_PASS);
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun 
grand_child_serv(unsigned int nr,int cmd_fd,void * buf,struct test_desc * msg,int xfrm_sock,uint32_t * seq)1734*4882a593Smuzhiyun static void grand_child_serv(unsigned int nr, int cmd_fd, void *buf,
1735*4882a593Smuzhiyun 		struct test_desc *msg, int xfrm_sock, uint32_t *seq)
1736*4882a593Smuzhiyun {
1737*4882a593Smuzhiyun 	struct in_addr src, dst, tunsrc, tundst;
1738*4882a593Smuzhiyun 	bool tun_reply;
1739*4882a593Smuzhiyun 	struct xfrm_desc *desc = &msg->body.xfrm_desc;
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	src = inet_makeaddr(INADDR_B, grchild_ip(nr));
1742*4882a593Smuzhiyun 	dst = inet_makeaddr(INADDR_B, child_ip(nr));
1743*4882a593Smuzhiyun 	tunsrc = inet_makeaddr(INADDR_A, grchild_ip(nr));
1744*4882a593Smuzhiyun 	tundst = inet_makeaddr(INADDR_A, child_ip(nr));
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	switch (msg->type) {
1747*4882a593Smuzhiyun 	case MSG_EXIT:
1748*4882a593Smuzhiyun 		exit(KSFT_PASS);
1749*4882a593Smuzhiyun 	case MSG_ACK:
1750*4882a593Smuzhiyun 		write_msg(cmd_fd, msg, 1);
1751*4882a593Smuzhiyun 		break;
1752*4882a593Smuzhiyun 	case MSG_PING:
1753*4882a593Smuzhiyun 		tun_reply = memcmp(&dst, &msg->body.ping.reply_ip, sizeof(in_addr_t));
1754*4882a593Smuzhiyun 		/* UDP pinging without xfrm */
1755*4882a593Smuzhiyun 		if (do_ping(cmd_fd, buf, page_size, tun_reply ? tunsrc : src,
1756*4882a593Smuzhiyun 				false, msg->body.ping.port,
1757*4882a593Smuzhiyun 				msg->body.ping.reply_ip, udp_ping_reply)) {
1758*4882a593Smuzhiyun 			printk("ping failed before setting xfrm");
1759*4882a593Smuzhiyun 		}
1760*4882a593Smuzhiyun 		break;
1761*4882a593Smuzhiyun 	case MSG_XFRM_PREPARE:
1762*4882a593Smuzhiyun 		if (xfrm_prepare(xfrm_sock, seq, src, dst, tunsrc, tundst,
1763*4882a593Smuzhiyun 					desc->proto)) {
1764*4882a593Smuzhiyun 			xfrm_cleanup(xfrm_sock, seq, src, dst, tunsrc, tundst);
1765*4882a593Smuzhiyun 			printk("failed to prepare xfrm");
1766*4882a593Smuzhiyun 		}
1767*4882a593Smuzhiyun 		break;
1768*4882a593Smuzhiyun 	case MSG_XFRM_ADD:
1769*4882a593Smuzhiyun 		if (xfrm_set(xfrm_sock, seq, src, dst, tunsrc, tundst, desc)) {
1770*4882a593Smuzhiyun 			xfrm_cleanup(xfrm_sock, seq, src, dst, tunsrc, tundst);
1771*4882a593Smuzhiyun 			printk("failed to set xfrm");
1772*4882a593Smuzhiyun 		}
1773*4882a593Smuzhiyun 		break;
1774*4882a593Smuzhiyun 	case MSG_XFRM_DEL:
1775*4882a593Smuzhiyun 		if (xfrm_delete(xfrm_sock, seq, src, dst, tunsrc, tundst,
1776*4882a593Smuzhiyun 					desc->proto)) {
1777*4882a593Smuzhiyun 			xfrm_cleanup(xfrm_sock, seq, src, dst, tunsrc, tundst);
1778*4882a593Smuzhiyun 			printk("failed to remove xfrm");
1779*4882a593Smuzhiyun 		}
1780*4882a593Smuzhiyun 		break;
1781*4882a593Smuzhiyun 	case MSG_XFRM_CLEANUP:
1782*4882a593Smuzhiyun 		if (xfrm_cleanup(xfrm_sock, seq, src, dst, tunsrc, tundst)) {
1783*4882a593Smuzhiyun 			printk("failed to cleanup xfrm");
1784*4882a593Smuzhiyun 		}
1785*4882a593Smuzhiyun 		break;
1786*4882a593Smuzhiyun 	default:
1787*4882a593Smuzhiyun 		printk("got unknown msg type %d", msg->type);
1788*4882a593Smuzhiyun 	};
1789*4882a593Smuzhiyun }
1790*4882a593Smuzhiyun 
grand_child_f(unsigned int nr,int cmd_fd,void * buf)1791*4882a593Smuzhiyun static int grand_child_f(unsigned int nr, int cmd_fd, void *buf)
1792*4882a593Smuzhiyun {
1793*4882a593Smuzhiyun 	struct test_desc msg;
1794*4882a593Smuzhiyun 	int xfrm_sock = -1;
1795*4882a593Smuzhiyun 	uint32_t seq;
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun 	if (switch_ns(nsfd_childb))
1798*4882a593Smuzhiyun 		exit(KSFT_FAIL);
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun 	if (netlink_sock(&xfrm_sock, &seq, NETLINK_XFRM)) {
1801*4882a593Smuzhiyun 		printk("Failed to open xfrm netlink socket");
1802*4882a593Smuzhiyun 		exit(KSFT_FAIL);
1803*4882a593Smuzhiyun 	}
1804*4882a593Smuzhiyun 
1805*4882a593Smuzhiyun 	do {
1806*4882a593Smuzhiyun 		read_msg(cmd_fd, &msg, 1);
1807*4882a593Smuzhiyun 		grand_child_serv(nr, cmd_fd, buf, &msg, xfrm_sock, &seq);
1808*4882a593Smuzhiyun 	} while (1);
1809*4882a593Smuzhiyun 
1810*4882a593Smuzhiyun 	close(xfrm_sock);
1811*4882a593Smuzhiyun 	exit(KSFT_FAIL);
1812*4882a593Smuzhiyun }
1813*4882a593Smuzhiyun 
start_child(unsigned int nr,char * veth,int test_desc_fd[2])1814*4882a593Smuzhiyun static int start_child(unsigned int nr, char *veth, int test_desc_fd[2])
1815*4882a593Smuzhiyun {
1816*4882a593Smuzhiyun 	int cmd_sock[2];
1817*4882a593Smuzhiyun 	void *data_map;
1818*4882a593Smuzhiyun 	pid_t child;
1819*4882a593Smuzhiyun 
1820*4882a593Smuzhiyun 	if (init_child(nsfd_childa, veth, child_ip(nr), grchild_ip(nr)))
1821*4882a593Smuzhiyun 		return -1;
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	if (init_child(nsfd_childb, veth, grchild_ip(nr), child_ip(nr)))
1824*4882a593Smuzhiyun 		return -1;
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	child = fork();
1827*4882a593Smuzhiyun 	if (child < 0) {
1828*4882a593Smuzhiyun 		pr_err("fork()");
1829*4882a593Smuzhiyun 		return -1;
1830*4882a593Smuzhiyun 	} else if (child) {
1831*4882a593Smuzhiyun 		/* in parent - selftest */
1832*4882a593Smuzhiyun 		return switch_ns(nsfd_parent);
1833*4882a593Smuzhiyun 	}
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	if (close(test_desc_fd[1])) {
1836*4882a593Smuzhiyun 		pr_err("close()");
1837*4882a593Smuzhiyun 		return -1;
1838*4882a593Smuzhiyun 	}
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 	/* child */
1841*4882a593Smuzhiyun 	data_map = mmap(0, page_size, PROT_READ | PROT_WRITE,
1842*4882a593Smuzhiyun 			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1843*4882a593Smuzhiyun 	if (data_map == MAP_FAILED) {
1844*4882a593Smuzhiyun 		pr_err("mmap()");
1845*4882a593Smuzhiyun 		return -1;
1846*4882a593Smuzhiyun 	}
1847*4882a593Smuzhiyun 
1848*4882a593Smuzhiyun 	randomize_buffer(data_map, page_size);
1849*4882a593Smuzhiyun 
1850*4882a593Smuzhiyun 	if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, cmd_sock)) {
1851*4882a593Smuzhiyun 		pr_err("socketpair()");
1852*4882a593Smuzhiyun 		return -1;
1853*4882a593Smuzhiyun 	}
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 	child = fork();
1856*4882a593Smuzhiyun 	if (child < 0) {
1857*4882a593Smuzhiyun 		pr_err("fork()");
1858*4882a593Smuzhiyun 		return -1;
1859*4882a593Smuzhiyun 	} else if (child) {
1860*4882a593Smuzhiyun 		if (close(cmd_sock[0])) {
1861*4882a593Smuzhiyun 			pr_err("close()");
1862*4882a593Smuzhiyun 			return -1;
1863*4882a593Smuzhiyun 		}
1864*4882a593Smuzhiyun 		return child_f(nr, test_desc_fd[0], cmd_sock[1], data_map);
1865*4882a593Smuzhiyun 	}
1866*4882a593Smuzhiyun 	if (close(cmd_sock[1])) {
1867*4882a593Smuzhiyun 		pr_err("close()");
1868*4882a593Smuzhiyun 		return -1;
1869*4882a593Smuzhiyun 	}
1870*4882a593Smuzhiyun 	return grand_child_f(nr, cmd_sock[0], data_map);
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun 
exit_usage(char ** argv)1873*4882a593Smuzhiyun static void exit_usage(char **argv)
1874*4882a593Smuzhiyun {
1875*4882a593Smuzhiyun 	printk("Usage: %s [nr_process]", argv[0]);
1876*4882a593Smuzhiyun 	exit(KSFT_FAIL);
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun 
__write_desc(int test_desc_fd,struct xfrm_desc * desc)1879*4882a593Smuzhiyun static int __write_desc(int test_desc_fd, struct xfrm_desc *desc)
1880*4882a593Smuzhiyun {
1881*4882a593Smuzhiyun 	ssize_t ret;
1882*4882a593Smuzhiyun 
1883*4882a593Smuzhiyun 	ret = write(test_desc_fd, desc, sizeof(*desc));
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun 	if (ret == sizeof(*desc))
1886*4882a593Smuzhiyun 		return 0;
1887*4882a593Smuzhiyun 
1888*4882a593Smuzhiyun 	pr_err("Writing test's desc failed %ld", ret);
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun 	return -1;
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun 
write_desc(int proto,int test_desc_fd,char * a,char * e,char * c,char * ae)1893*4882a593Smuzhiyun static int write_desc(int proto, int test_desc_fd,
1894*4882a593Smuzhiyun 		char *a, char *e, char *c, char *ae)
1895*4882a593Smuzhiyun {
1896*4882a593Smuzhiyun 	struct xfrm_desc desc = {};
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	desc.type = CREATE_TUNNEL;
1899*4882a593Smuzhiyun 	desc.proto = proto;
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun 	if (a)
1902*4882a593Smuzhiyun 		strncpy(desc.a_algo, a, ALGO_LEN - 1);
1903*4882a593Smuzhiyun 	if (e)
1904*4882a593Smuzhiyun 		strncpy(desc.e_algo, e, ALGO_LEN - 1);
1905*4882a593Smuzhiyun 	if (c)
1906*4882a593Smuzhiyun 		strncpy(desc.c_algo, c, ALGO_LEN - 1);
1907*4882a593Smuzhiyun 	if (ae)
1908*4882a593Smuzhiyun 		strncpy(desc.ae_algo, ae, ALGO_LEN - 1);
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	return __write_desc(test_desc_fd, &desc);
1911*4882a593Smuzhiyun }
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun int proto_list[] = { IPPROTO_AH, IPPROTO_COMP, IPPROTO_ESP };
1914*4882a593Smuzhiyun char *ah_list[] = {
1915*4882a593Smuzhiyun 	"digest_null", "hmac(md5)", "hmac(sha1)", "hmac(sha256)",
1916*4882a593Smuzhiyun 	"hmac(sha384)", "hmac(sha512)", "hmac(rmd160)",
1917*4882a593Smuzhiyun 	"xcbc(aes)", "cmac(aes)"
1918*4882a593Smuzhiyun };
1919*4882a593Smuzhiyun char *comp_list[] = {
1920*4882a593Smuzhiyun 	"deflate",
1921*4882a593Smuzhiyun #if 0
1922*4882a593Smuzhiyun 	/* No compression backend realization */
1923*4882a593Smuzhiyun 	"lzs", "lzjh"
1924*4882a593Smuzhiyun #endif
1925*4882a593Smuzhiyun };
1926*4882a593Smuzhiyun char *e_list[] = {
1927*4882a593Smuzhiyun 	"ecb(cipher_null)", "cbc(des)", "cbc(des3_ede)", "cbc(cast5)",
1928*4882a593Smuzhiyun 	"cbc(blowfish)", "cbc(aes)", "cbc(serpent)", "cbc(camellia)",
1929*4882a593Smuzhiyun 	"cbc(twofish)", "rfc3686(ctr(aes))"
1930*4882a593Smuzhiyun };
1931*4882a593Smuzhiyun char *ae_list[] = {
1932*4882a593Smuzhiyun #if 0
1933*4882a593Smuzhiyun 	/* not implemented */
1934*4882a593Smuzhiyun 	"rfc4106(gcm(aes))", "rfc4309(ccm(aes))", "rfc4543(gcm(aes))",
1935*4882a593Smuzhiyun 	"rfc7539esp(chacha20,poly1305)"
1936*4882a593Smuzhiyun #endif
1937*4882a593Smuzhiyun };
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun const unsigned int proto_plan = ARRAY_SIZE(ah_list) + ARRAY_SIZE(comp_list) \
1940*4882a593Smuzhiyun 				+ (ARRAY_SIZE(ah_list) * ARRAY_SIZE(e_list)) \
1941*4882a593Smuzhiyun 				+ ARRAY_SIZE(ae_list);
1942*4882a593Smuzhiyun 
write_proto_plan(int fd,int proto)1943*4882a593Smuzhiyun static int write_proto_plan(int fd, int proto)
1944*4882a593Smuzhiyun {
1945*4882a593Smuzhiyun 	unsigned int i;
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	switch (proto) {
1948*4882a593Smuzhiyun 	case IPPROTO_AH:
1949*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ah_list); i++) {
1950*4882a593Smuzhiyun 			if (write_desc(proto, fd, ah_list[i], 0, 0, 0))
1951*4882a593Smuzhiyun 				return -1;
1952*4882a593Smuzhiyun 		}
1953*4882a593Smuzhiyun 		break;
1954*4882a593Smuzhiyun 	case IPPROTO_COMP:
1955*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(comp_list); i++) {
1956*4882a593Smuzhiyun 			if (write_desc(proto, fd, 0, 0, comp_list[i], 0))
1957*4882a593Smuzhiyun 				return -1;
1958*4882a593Smuzhiyun 		}
1959*4882a593Smuzhiyun 		break;
1960*4882a593Smuzhiyun 	case IPPROTO_ESP:
1961*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ah_list); i++) {
1962*4882a593Smuzhiyun 			int j;
1963*4882a593Smuzhiyun 
1964*4882a593Smuzhiyun 			for (j = 0; j < ARRAY_SIZE(e_list); j++) {
1965*4882a593Smuzhiyun 				if (write_desc(proto, fd, ah_list[i],
1966*4882a593Smuzhiyun 							e_list[j], 0, 0))
1967*4882a593Smuzhiyun 					return -1;
1968*4882a593Smuzhiyun 			}
1969*4882a593Smuzhiyun 		}
1970*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ae_list); i++) {
1971*4882a593Smuzhiyun 			if (write_desc(proto, fd, 0, 0, 0, ae_list[i]))
1972*4882a593Smuzhiyun 				return -1;
1973*4882a593Smuzhiyun 		}
1974*4882a593Smuzhiyun 		break;
1975*4882a593Smuzhiyun 	default:
1976*4882a593Smuzhiyun 		printk("BUG: Specified unknown proto %d", proto);
1977*4882a593Smuzhiyun 		return -1;
1978*4882a593Smuzhiyun 	}
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	return 0;
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun 
1983*4882a593Smuzhiyun /*
1984*4882a593Smuzhiyun  * Some structures in xfrm uapi header differ in size between
1985*4882a593Smuzhiyun  * 64-bit and 32-bit ABI:
1986*4882a593Smuzhiyun  *
1987*4882a593Smuzhiyun  *             32-bit UABI               |            64-bit UABI
1988*4882a593Smuzhiyun  *  -------------------------------------|-------------------------------------
1989*4882a593Smuzhiyun  *   sizeof(xfrm_usersa_info)     = 220  |  sizeof(xfrm_usersa_info)     = 224
1990*4882a593Smuzhiyun  *   sizeof(xfrm_userpolicy_info) = 164  |  sizeof(xfrm_userpolicy_info) = 168
1991*4882a593Smuzhiyun  *   sizeof(xfrm_userspi_info)    = 228  |  sizeof(xfrm_userspi_info)    = 232
1992*4882a593Smuzhiyun  *   sizeof(xfrm_user_acquire)    = 276  |  sizeof(xfrm_user_acquire)    = 280
1993*4882a593Smuzhiyun  *   sizeof(xfrm_user_expire)     = 224  |  sizeof(xfrm_user_expire)     = 232
1994*4882a593Smuzhiyun  *   sizeof(xfrm_user_polexpire)  = 168  |  sizeof(xfrm_user_polexpire)  = 176
1995*4882a593Smuzhiyun  *
1996*4882a593Smuzhiyun  * Check the affected by the UABI difference structures.
1997*4882a593Smuzhiyun  */
1998*4882a593Smuzhiyun const unsigned int compat_plan = 4;
write_compat_struct_tests(int test_desc_fd)1999*4882a593Smuzhiyun static int write_compat_struct_tests(int test_desc_fd)
2000*4882a593Smuzhiyun {
2001*4882a593Smuzhiyun 	struct xfrm_desc desc = {};
2002*4882a593Smuzhiyun 
2003*4882a593Smuzhiyun 	desc.type = ALLOCATE_SPI;
2004*4882a593Smuzhiyun 	desc.proto = IPPROTO_AH;
2005*4882a593Smuzhiyun 	strncpy(desc.a_algo, ah_list[0], ALGO_LEN - 1);
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	if (__write_desc(test_desc_fd, &desc))
2008*4882a593Smuzhiyun 		return -1;
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	desc.type = MONITOR_ACQUIRE;
2011*4882a593Smuzhiyun 	if (__write_desc(test_desc_fd, &desc))
2012*4882a593Smuzhiyun 		return -1;
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 	desc.type = EXPIRE_STATE;
2015*4882a593Smuzhiyun 	if (__write_desc(test_desc_fd, &desc))
2016*4882a593Smuzhiyun 		return -1;
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 	desc.type = EXPIRE_POLICY;
2019*4882a593Smuzhiyun 	if (__write_desc(test_desc_fd, &desc))
2020*4882a593Smuzhiyun 		return -1;
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	return 0;
2023*4882a593Smuzhiyun }
2024*4882a593Smuzhiyun 
write_test_plan(int test_desc_fd)2025*4882a593Smuzhiyun static int write_test_plan(int test_desc_fd)
2026*4882a593Smuzhiyun {
2027*4882a593Smuzhiyun 	unsigned int i;
2028*4882a593Smuzhiyun 	pid_t child;
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	child = fork();
2031*4882a593Smuzhiyun 	if (child < 0) {
2032*4882a593Smuzhiyun 		pr_err("fork()");
2033*4882a593Smuzhiyun 		return -1;
2034*4882a593Smuzhiyun 	}
2035*4882a593Smuzhiyun 	if (child) {
2036*4882a593Smuzhiyun 		if (close(test_desc_fd))
2037*4882a593Smuzhiyun 			printk("close(): %m");
2038*4882a593Smuzhiyun 		return 0;
2039*4882a593Smuzhiyun 	}
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 	if (write_compat_struct_tests(test_desc_fd))
2042*4882a593Smuzhiyun 		exit(KSFT_FAIL);
2043*4882a593Smuzhiyun 
2044*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(proto_list); i++) {
2045*4882a593Smuzhiyun 		if (write_proto_plan(test_desc_fd, proto_list[i]))
2046*4882a593Smuzhiyun 			exit(KSFT_FAIL);
2047*4882a593Smuzhiyun 	}
2048*4882a593Smuzhiyun 
2049*4882a593Smuzhiyun 	exit(KSFT_PASS);
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun 
children_cleanup(void)2052*4882a593Smuzhiyun static int children_cleanup(void)
2053*4882a593Smuzhiyun {
2054*4882a593Smuzhiyun 	unsigned ret = KSFT_PASS;
2055*4882a593Smuzhiyun 
2056*4882a593Smuzhiyun 	while (1) {
2057*4882a593Smuzhiyun 		int status;
2058*4882a593Smuzhiyun 		pid_t p = wait(&status);
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun 		if ((p < 0) && errno == ECHILD)
2061*4882a593Smuzhiyun 			break;
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 		if (p < 0) {
2064*4882a593Smuzhiyun 			pr_err("wait()");
2065*4882a593Smuzhiyun 			return KSFT_FAIL;
2066*4882a593Smuzhiyun 		}
2067*4882a593Smuzhiyun 
2068*4882a593Smuzhiyun 		if (!WIFEXITED(status)) {
2069*4882a593Smuzhiyun 			ret = KSFT_FAIL;
2070*4882a593Smuzhiyun 			continue;
2071*4882a593Smuzhiyun 		}
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun 		if (WEXITSTATUS(status) == KSFT_FAIL)
2074*4882a593Smuzhiyun 			ret = KSFT_FAIL;
2075*4882a593Smuzhiyun 	}
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 	return ret;
2078*4882a593Smuzhiyun }
2079*4882a593Smuzhiyun 
2080*4882a593Smuzhiyun typedef void (*print_res)(const char *, ...);
2081*4882a593Smuzhiyun 
check_results(void)2082*4882a593Smuzhiyun static int check_results(void)
2083*4882a593Smuzhiyun {
2084*4882a593Smuzhiyun 	struct test_result tr = {};
2085*4882a593Smuzhiyun 	struct xfrm_desc *d = &tr.desc;
2086*4882a593Smuzhiyun 	int ret = KSFT_PASS;
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	while (1) {
2089*4882a593Smuzhiyun 		ssize_t received = read(results_fd[0], &tr, sizeof(tr));
2090*4882a593Smuzhiyun 		print_res result;
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 		if (received == 0) /* EOF */
2093*4882a593Smuzhiyun 			break;
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun 		if (received != sizeof(tr)) {
2096*4882a593Smuzhiyun 			pr_err("read() returned %zd", received);
2097*4882a593Smuzhiyun 			return KSFT_FAIL;
2098*4882a593Smuzhiyun 		}
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 		switch (tr.res) {
2101*4882a593Smuzhiyun 		case KSFT_PASS:
2102*4882a593Smuzhiyun 			result = ksft_test_result_pass;
2103*4882a593Smuzhiyun 			break;
2104*4882a593Smuzhiyun 		case KSFT_FAIL:
2105*4882a593Smuzhiyun 		default:
2106*4882a593Smuzhiyun 			result = ksft_test_result_fail;
2107*4882a593Smuzhiyun 			ret = KSFT_FAIL;
2108*4882a593Smuzhiyun 		}
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 		result(" %s: [%u, '%s', '%s', '%s', '%s', %u]\n",
2111*4882a593Smuzhiyun 		       desc_name[d->type], (unsigned int)d->proto, d->a_algo,
2112*4882a593Smuzhiyun 		       d->e_algo, d->c_algo, d->ae_algo, d->icv_len);
2113*4882a593Smuzhiyun 	}
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	return ret;
2116*4882a593Smuzhiyun }
2117*4882a593Smuzhiyun 
main(int argc,char ** argv)2118*4882a593Smuzhiyun int main(int argc, char **argv)
2119*4882a593Smuzhiyun {
2120*4882a593Smuzhiyun 	unsigned int nr_process = 1;
2121*4882a593Smuzhiyun 	int route_sock = -1, ret = KSFT_SKIP;
2122*4882a593Smuzhiyun 	int test_desc_fd[2];
2123*4882a593Smuzhiyun 	uint32_t route_seq;
2124*4882a593Smuzhiyun 	unsigned int i;
2125*4882a593Smuzhiyun 
2126*4882a593Smuzhiyun 	if (argc > 2)
2127*4882a593Smuzhiyun 		exit_usage(argv);
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	if (argc > 1) {
2130*4882a593Smuzhiyun 		char *endptr;
2131*4882a593Smuzhiyun 
2132*4882a593Smuzhiyun 		errno = 0;
2133*4882a593Smuzhiyun 		nr_process = strtol(argv[1], &endptr, 10);
2134*4882a593Smuzhiyun 		if ((errno == ERANGE && (nr_process == LONG_MAX || nr_process == LONG_MIN))
2135*4882a593Smuzhiyun 				|| (errno != 0 && nr_process == 0)
2136*4882a593Smuzhiyun 				|| (endptr == argv[1]) || (*endptr != '\0')) {
2137*4882a593Smuzhiyun 			printk("Failed to parse [nr_process]");
2138*4882a593Smuzhiyun 			exit_usage(argv);
2139*4882a593Smuzhiyun 		}
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun 		if (nr_process > MAX_PROCESSES || !nr_process) {
2142*4882a593Smuzhiyun 			printk("nr_process should be between [1; %u]",
2143*4882a593Smuzhiyun 					MAX_PROCESSES);
2144*4882a593Smuzhiyun 			exit_usage(argv);
2145*4882a593Smuzhiyun 		}
2146*4882a593Smuzhiyun 	}
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun 	srand(time(NULL));
2149*4882a593Smuzhiyun 	page_size = sysconf(_SC_PAGESIZE);
2150*4882a593Smuzhiyun 	if (page_size < 1)
2151*4882a593Smuzhiyun 		ksft_exit_skip("sysconf(): %m\n");
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	if (pipe2(test_desc_fd, O_DIRECT) < 0)
2154*4882a593Smuzhiyun 		ksft_exit_skip("pipe(): %m\n");
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	if (pipe2(results_fd, O_DIRECT) < 0)
2157*4882a593Smuzhiyun 		ksft_exit_skip("pipe(): %m\n");
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	if (init_namespaces())
2160*4882a593Smuzhiyun 		ksft_exit_skip("Failed to create namespaces\n");
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
2163*4882a593Smuzhiyun 		ksft_exit_skip("Failed to open netlink route socket\n");
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 	for (i = 0; i < nr_process; i++) {
2166*4882a593Smuzhiyun 		char veth[VETH_LEN];
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 		snprintf(veth, VETH_LEN, VETH_FMT, i);
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun 		if (veth_add(route_sock, route_seq++, veth, nsfd_childa, veth, nsfd_childb)) {
2171*4882a593Smuzhiyun 			close(route_sock);
2172*4882a593Smuzhiyun 			ksft_exit_fail_msg("Failed to create veth device");
2173*4882a593Smuzhiyun 		}
2174*4882a593Smuzhiyun 
2175*4882a593Smuzhiyun 		if (start_child(i, veth, test_desc_fd)) {
2176*4882a593Smuzhiyun 			close(route_sock);
2177*4882a593Smuzhiyun 			ksft_exit_fail_msg("Child %u failed to start", i);
2178*4882a593Smuzhiyun 		}
2179*4882a593Smuzhiyun 	}
2180*4882a593Smuzhiyun 
2181*4882a593Smuzhiyun 	if (close(route_sock) || close(test_desc_fd[0]) || close(results_fd[1]))
2182*4882a593Smuzhiyun 		ksft_exit_fail_msg("close(): %m");
2183*4882a593Smuzhiyun 
2184*4882a593Smuzhiyun 	ksft_set_plan(proto_plan + compat_plan);
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun 	if (write_test_plan(test_desc_fd[1]))
2187*4882a593Smuzhiyun 		ksft_exit_fail_msg("Failed to write test plan to pipe");
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun 	ret = check_results();
2190*4882a593Smuzhiyun 
2191*4882a593Smuzhiyun 	if (children_cleanup() == KSFT_FAIL)
2192*4882a593Smuzhiyun 		exit(KSFT_FAIL);
2193*4882a593Smuzhiyun 
2194*4882a593Smuzhiyun 	exit(ret);
2195*4882a593Smuzhiyun }
2196