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