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