1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Inject packets with all sorts of encapsulation into the kernel.
4  *
5  * IPv4/IPv6	outer layer 3
6  * GRE/GUE/BARE outer layer 4, where bare is IPIP/SIT/IPv4-in-IPv6/..
7  * IPv4/IPv6    inner layer 3
8  */
9 
10 #define _GNU_SOURCE
11 
12 #include <stddef.h>
13 #include <arpa/inet.h>
14 #include <asm/byteorder.h>
15 #include <error.h>
16 #include <errno.h>
17 #include <linux/if_packet.h>
18 #include <linux/if_ether.h>
19 #include <linux/if_packet.h>
20 #include <linux/ipv6.h>
21 #include <netinet/ip.h>
22 #include <netinet/in.h>
23 #include <netinet/udp.h>
24 #include <poll.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 
37 #define CFG_PORT_INNER	8000
38 
39 /* Add some protocol definitions that do not exist in userspace */
40 
41 struct grehdr {
42 	uint16_t unused;
43 	uint16_t protocol;
44 } __attribute__((packed));
45 
46 struct guehdr {
47 	union {
48 		struct {
49 #if defined(__LITTLE_ENDIAN_BITFIELD)
50 			__u8	hlen:5,
51 				control:1,
52 				version:2;
53 #elif defined (__BIG_ENDIAN_BITFIELD)
54 			__u8	version:2,
55 				control:1,
56 				hlen:5;
57 #else
58 #error  "Please fix <asm/byteorder.h>"
59 #endif
60 			__u8	proto_ctype;
61 			__be16	flags;
62 		};
63 		__be32	word;
64 	};
65 };
66 
67 static uint8_t	cfg_dsfield_inner;
68 static uint8_t	cfg_dsfield_outer;
69 static uint8_t	cfg_encap_proto;
70 static bool	cfg_expect_failure = false;
71 static int	cfg_l3_extra = AF_UNSPEC;	/* optional SIT prefix */
72 static int	cfg_l3_inner = AF_UNSPEC;
73 static int	cfg_l3_outer = AF_UNSPEC;
74 static int	cfg_num_pkt = 10;
75 static int	cfg_num_secs = 0;
76 static char	cfg_payload_char = 'a';
77 static int	cfg_payload_len = 100;
78 static int	cfg_port_gue = 6080;
79 static bool	cfg_only_rx;
80 static bool	cfg_only_tx;
81 static int	cfg_src_port = 9;
82 
83 static char	buf[ETH_DATA_LEN];
84 
85 #define INIT_ADDR4(name, addr4, port)				\
86 	static struct sockaddr_in name = {			\
87 		.sin_family = AF_INET,				\
88 		.sin_port = __constant_htons(port),		\
89 		.sin_addr.s_addr = __constant_htonl(addr4),	\
90 	};
91 
92 #define INIT_ADDR6(name, addr6, port)				\
93 	static struct sockaddr_in6 name = {			\
94 		.sin6_family = AF_INET6,			\
95 		.sin6_port = __constant_htons(port),		\
96 		.sin6_addr = addr6,				\
97 	};
98 
99 INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER)
100 INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0)
101 INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0)
102 INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0)
103 INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0)
104 INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0)
105 
106 INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER)
107 INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
108 INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
109 INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
110 INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0)
111 INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0)
112 
113 static unsigned long util_gettime(void)
114 {
115 	struct timeval tv;
116 
117 	gettimeofday(&tv, NULL);
118 	return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
119 }
120 
121 static void util_printaddr(const char *msg, struct sockaddr *addr)
122 {
123 	unsigned long off = 0;
124 	char nbuf[INET6_ADDRSTRLEN];
125 
126 	switch (addr->sa_family) {
127 	case PF_INET:
128 		off = __builtin_offsetof(struct sockaddr_in, sin_addr);
129 		break;
130 	case PF_INET6:
131 		off = __builtin_offsetof(struct sockaddr_in6, sin6_addr);
132 		break;
133 	default:
134 		error(1, 0, "printaddr: unsupported family %u\n",
135 		      addr->sa_family);
136 	}
137 
138 	if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf,
139 		       sizeof(nbuf)))
140 		error(1, errno, "inet_ntop");
141 
142 	fprintf(stderr, "%s: %s\n", msg, nbuf);
143 }
144 
145 static unsigned long add_csum_hword(const uint16_t *start, int num_u16)
146 {
147 	unsigned long sum = 0;
148 	int i;
149 
150 	for (i = 0; i < num_u16; i++)
151 		sum += start[i];
152 
153 	return sum;
154 }
155 
156 static uint16_t build_ip_csum(const uint16_t *start, int num_u16,
157 			      unsigned long sum)
158 {
159 	sum += add_csum_hword(start, num_u16);
160 
161 	while (sum >> 16)
162 		sum = (sum & 0xffff) + (sum >> 16);
163 
164 	return ~sum;
165 }
166 
167 static void build_ipv4_header(void *header, uint8_t proto,
168 			      uint32_t src, uint32_t dst,
169 			      int payload_len, uint8_t tos)
170 {
171 	struct iphdr *iph = header;
172 
173 	iph->ihl = 5;
174 	iph->version = 4;
175 	iph->tos = tos;
176 	iph->ttl = 8;
177 	iph->tot_len = htons(sizeof(*iph) + payload_len);
178 	iph->id = htons(1337);
179 	iph->protocol = proto;
180 	iph->saddr = src;
181 	iph->daddr = dst;
182 	iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0);
183 }
184 
185 static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield)
186 {
187 	uint16_t val, *ptr = (uint16_t *)ip6h;
188 
189 	val = ntohs(*ptr);
190 	val &= 0xF00F;
191 	val |= ((uint16_t) dsfield) << 4;
192 	*ptr = htons(val);
193 }
194 
195 static void build_ipv6_header(void *header, uint8_t proto,
196 			      struct sockaddr_in6 *src,
197 			      struct sockaddr_in6 *dst,
198 			      int payload_len, uint8_t dsfield)
199 {
200 	struct ipv6hdr *ip6h = header;
201 
202 	ip6h->version = 6;
203 	ip6h->payload_len = htons(payload_len);
204 	ip6h->nexthdr = proto;
205 	ip6h->hop_limit = 8;
206 	ipv6_set_dsfield(ip6h, dsfield);
207 
208 	memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr));
209 	memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr));
210 }
211 
212 static uint16_t build_udp_v4_csum(const struct iphdr *iph,
213 				  const struct udphdr *udph,
214 				  int num_words)
215 {
216 	unsigned long pseudo_sum;
217 	int num_u16 = sizeof(iph->saddr);	/* halfwords: twice byte len */
218 
219 	pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16);
220 	pseudo_sum += htons(IPPROTO_UDP);
221 	pseudo_sum += udph->len;
222 	return build_ip_csum((void *) udph, num_words, pseudo_sum);
223 }
224 
225 static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h,
226 				  const struct udphdr *udph,
227 				  int num_words)
228 {
229 	unsigned long pseudo_sum;
230 	int num_u16 = sizeof(ip6h->saddr);	/* halfwords: twice byte len */
231 
232 	pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16);
233 	pseudo_sum += htons(ip6h->nexthdr);
234 	pseudo_sum += ip6h->payload_len;
235 	return build_ip_csum((void *) udph, num_words, pseudo_sum);
236 }
237 
238 static void build_udp_header(void *header, int payload_len,
239 			     uint16_t dport, int family)
240 {
241 	struct udphdr *udph = header;
242 	int len = sizeof(*udph) + payload_len;
243 
244 	udph->source = htons(cfg_src_port);
245 	udph->dest = htons(dport);
246 	udph->len = htons(len);
247 	udph->check = 0;
248 	if (family == AF_INET)
249 		udph->check = build_udp_v4_csum(header - sizeof(struct iphdr),
250 						udph, len >> 1);
251 	else
252 		udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr),
253 						udph, len >> 1);
254 }
255 
256 static void build_gue_header(void *header, uint8_t proto)
257 {
258 	struct guehdr *gueh = header;
259 
260 	gueh->proto_ctype = proto;
261 }
262 
263 static void build_gre_header(void *header, uint16_t proto)
264 {
265 	struct grehdr *greh = header;
266 
267 	greh->protocol = htons(proto);
268 }
269 
270 static int l3_length(int family)
271 {
272 	if (family == AF_INET)
273 		return sizeof(struct iphdr);
274 	else
275 		return sizeof(struct ipv6hdr);
276 }
277 
278 static int build_packet(void)
279 {
280 	int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0;
281 	int el3_len = 0;
282 
283 	if (cfg_l3_extra)
284 		el3_len = l3_length(cfg_l3_extra);
285 
286 	/* calculate header offsets */
287 	if (cfg_encap_proto) {
288 		ol3_len = l3_length(cfg_l3_outer);
289 
290 		if (cfg_encap_proto == IPPROTO_GRE)
291 			ol4_len = sizeof(struct grehdr);
292 		else if (cfg_encap_proto == IPPROTO_UDP)
293 			ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr);
294 	}
295 
296 	il3_len = l3_length(cfg_l3_inner);
297 	il4_len = sizeof(struct udphdr);
298 
299 	if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >=
300 	    sizeof(buf))
301 		error(1, 0, "packet too large\n");
302 
303 	/*
304 	 * Fill packet from inside out, to calculate correct checksums.
305 	 * But create ip before udp headers, as udp uses ip for pseudo-sum.
306 	 */
307 	memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len,
308 	       cfg_payload_char, cfg_payload_len);
309 
310 	/* add zero byte for udp csum padding */
311 	buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0;
312 
313 	switch (cfg_l3_inner) {
314 	case PF_INET:
315 		build_ipv4_header(buf + el3_len + ol3_len + ol4_len,
316 				  IPPROTO_UDP,
317 				  in_saddr4.sin_addr.s_addr,
318 				  in_daddr4.sin_addr.s_addr,
319 				  il4_len + cfg_payload_len,
320 				  cfg_dsfield_inner);
321 		break;
322 	case PF_INET6:
323 		build_ipv6_header(buf + el3_len + ol3_len + ol4_len,
324 				  IPPROTO_UDP,
325 				  &in_saddr6, &in_daddr6,
326 				  il4_len + cfg_payload_len,
327 				  cfg_dsfield_inner);
328 		break;
329 	}
330 
331 	build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len,
332 			 cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner);
333 
334 	if (!cfg_encap_proto)
335 		return il3_len + il4_len + cfg_payload_len;
336 
337 	switch (cfg_l3_outer) {
338 	case PF_INET:
339 		build_ipv4_header(buf + el3_len, cfg_encap_proto,
340 				  out_saddr4.sin_addr.s_addr,
341 				  out_daddr4.sin_addr.s_addr,
342 				  ol4_len + il3_len + il4_len + cfg_payload_len,
343 				  cfg_dsfield_outer);
344 		break;
345 	case PF_INET6:
346 		build_ipv6_header(buf + el3_len, cfg_encap_proto,
347 				  &out_saddr6, &out_daddr6,
348 				  ol4_len + il3_len + il4_len + cfg_payload_len,
349 				  cfg_dsfield_outer);
350 		break;
351 	}
352 
353 	switch (cfg_encap_proto) {
354 	case IPPROTO_UDP:
355 		build_gue_header(buf + el3_len + ol3_len + ol4_len -
356 				 sizeof(struct guehdr),
357 				 cfg_l3_inner == PF_INET ? IPPROTO_IPIP
358 							 : IPPROTO_IPV6);
359 		build_udp_header(buf + el3_len + ol3_len,
360 				 sizeof(struct guehdr) + il3_len + il4_len +
361 				 cfg_payload_len,
362 				 cfg_port_gue, cfg_l3_outer);
363 		break;
364 	case IPPROTO_GRE:
365 		build_gre_header(buf + el3_len + ol3_len,
366 				 cfg_l3_inner == PF_INET ? ETH_P_IP
367 							 : ETH_P_IPV6);
368 		break;
369 	}
370 
371 	switch (cfg_l3_extra) {
372 	case PF_INET:
373 		build_ipv4_header(buf,
374 				  cfg_l3_outer == PF_INET ? IPPROTO_IPIP
375 							  : IPPROTO_IPV6,
376 				  extra_saddr4.sin_addr.s_addr,
377 				  extra_daddr4.sin_addr.s_addr,
378 				  ol3_len + ol4_len + il3_len + il4_len +
379 				  cfg_payload_len, 0);
380 		break;
381 	case PF_INET6:
382 		build_ipv6_header(buf,
383 				  cfg_l3_outer == PF_INET ? IPPROTO_IPIP
384 							  : IPPROTO_IPV6,
385 				  &extra_saddr6, &extra_daddr6,
386 				  ol3_len + ol4_len + il3_len + il4_len +
387 				  cfg_payload_len, 0);
388 		break;
389 	}
390 
391 	return el3_len + ol3_len + ol4_len + il3_len + il4_len +
392 	       cfg_payload_len;
393 }
394 
395 /* sender transmits encapsulated over RAW or unencap'd over UDP */
396 static int setup_tx(void)
397 {
398 	int family, fd, ret;
399 
400 	if (cfg_l3_extra)
401 		family = cfg_l3_extra;
402 	else if (cfg_l3_outer)
403 		family = cfg_l3_outer;
404 	else
405 		family = cfg_l3_inner;
406 
407 	fd = socket(family, SOCK_RAW, IPPROTO_RAW);
408 	if (fd == -1)
409 		error(1, errno, "socket tx");
410 
411 	if (cfg_l3_extra) {
412 		if (cfg_l3_extra == PF_INET)
413 			ret = connect(fd, (void *) &extra_daddr4,
414 				      sizeof(extra_daddr4));
415 		else
416 			ret = connect(fd, (void *) &extra_daddr6,
417 				      sizeof(extra_daddr6));
418 		if (ret)
419 			error(1, errno, "connect tx");
420 	} else if (cfg_l3_outer) {
421 		/* connect to destination if not encapsulated */
422 		if (cfg_l3_outer == PF_INET)
423 			ret = connect(fd, (void *) &out_daddr4,
424 				      sizeof(out_daddr4));
425 		else
426 			ret = connect(fd, (void *) &out_daddr6,
427 				      sizeof(out_daddr6));
428 		if (ret)
429 			error(1, errno, "connect tx");
430 	} else {
431 		/* otherwise using loopback */
432 		if (cfg_l3_inner == PF_INET)
433 			ret = connect(fd, (void *) &in_daddr4,
434 				      sizeof(in_daddr4));
435 		else
436 			ret = connect(fd, (void *) &in_daddr6,
437 				      sizeof(in_daddr6));
438 		if (ret)
439 			error(1, errno, "connect tx");
440 	}
441 
442 	return fd;
443 }
444 
445 /* receiver reads unencapsulated UDP */
446 static int setup_rx(void)
447 {
448 	int fd, ret;
449 
450 	fd = socket(cfg_l3_inner, SOCK_DGRAM, 0);
451 	if (fd == -1)
452 		error(1, errno, "socket rx");
453 
454 	if (cfg_l3_inner == PF_INET)
455 		ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4));
456 	else
457 		ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6));
458 	if (ret)
459 		error(1, errno, "bind rx");
460 
461 	return fd;
462 }
463 
464 static int do_tx(int fd, const char *pkt, int len)
465 {
466 	int ret;
467 
468 	ret = write(fd, pkt, len);
469 	if (ret == -1)
470 		error(1, errno, "send");
471 	if (ret != len)
472 		error(1, errno, "send: len (%d < %d)\n", ret, len);
473 
474 	return 1;
475 }
476 
477 static int do_poll(int fd, short events, int timeout)
478 {
479 	struct pollfd pfd;
480 	int ret;
481 
482 	pfd.fd = fd;
483 	pfd.events = events;
484 
485 	ret = poll(&pfd, 1, timeout);
486 	if (ret == -1)
487 		error(1, errno, "poll");
488 	if (ret && !(pfd.revents & POLLIN))
489 		error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents);
490 
491 	return ret;
492 }
493 
494 static int do_rx(int fd)
495 {
496 	char rbuf;
497 	int ret, num = 0;
498 
499 	while (1) {
500 		ret = recv(fd, &rbuf, 1, MSG_DONTWAIT);
501 		if (ret == -1 && errno == EAGAIN)
502 			break;
503 		if (ret == -1)
504 			error(1, errno, "recv");
505 		if (rbuf != cfg_payload_char)
506 			error(1, 0, "recv: payload mismatch");
507 		num++;
508 	};
509 
510 	return num;
511 }
512 
513 static int do_main(void)
514 {
515 	unsigned long tstop, treport, tcur;
516 	int fdt = -1, fdr = -1, len, tx = 0, rx = 0;
517 
518 	if (!cfg_only_tx)
519 		fdr = setup_rx();
520 	if (!cfg_only_rx)
521 		fdt = setup_tx();
522 
523 	len = build_packet();
524 
525 	tcur = util_gettime();
526 	treport = tcur + 1000;
527 	tstop = tcur + (cfg_num_secs * 1000);
528 
529 	while (1) {
530 		if (!cfg_only_rx)
531 			tx += do_tx(fdt, buf, len);
532 
533 		if (!cfg_only_tx)
534 			rx += do_rx(fdr);
535 
536 		if (cfg_num_secs) {
537 			tcur = util_gettime();
538 			if (tcur >= tstop)
539 				break;
540 			if (tcur >= treport) {
541 				fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
542 				tx = 0;
543 				rx = 0;
544 				treport = tcur + 1000;
545 			}
546 		} else {
547 			if (tx == cfg_num_pkt)
548 				break;
549 		}
550 	}
551 
552 	/* read straggler packets, if any */
553 	if (rx < tx) {
554 		tstop = util_gettime() + 100;
555 		while (rx < tx) {
556 			tcur = util_gettime();
557 			if (tcur >= tstop)
558 				break;
559 
560 			do_poll(fdr, POLLIN, tstop - tcur);
561 			rx += do_rx(fdr);
562 		}
563 	}
564 
565 	fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx);
566 
567 	if (fdr != -1 && close(fdr))
568 		error(1, errno, "close rx");
569 	if (fdt != -1 && close(fdt))
570 		error(1, errno, "close tx");
571 
572 	/*
573 	 * success (== 0) only if received all packets
574 	 * unless failure is expected, in which case none must arrive.
575 	 */
576 	if (cfg_expect_failure)
577 		return rx != 0;
578 	else
579 		return rx != tx;
580 }
581 
582 
583 static void __attribute__((noreturn)) usage(const char *filepath)
584 {
585 	fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] "
586 			"[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] "
587 			"[-s <osrc> [-d <odst>] [-S <isrc>] [-D <idst>] "
588 			"[-x <otos>] [-X <itos>] [-f <isport>] [-F]\n",
589 		filepath);
590 	exit(1);
591 }
592 
593 static void parse_addr(int family, void *addr, const char *optarg)
594 {
595 	int ret;
596 
597 	ret = inet_pton(family, optarg, addr);
598 	if (ret == -1)
599 		error(1, errno, "inet_pton");
600 	if (ret == 0)
601 		error(1, 0, "inet_pton: bad string");
602 }
603 
604 static void parse_addr4(struct sockaddr_in *addr, const char *optarg)
605 {
606 	parse_addr(AF_INET, &addr->sin_addr, optarg);
607 }
608 
609 static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg)
610 {
611 	parse_addr(AF_INET6, &addr->sin6_addr, optarg);
612 }
613 
614 static int parse_protocol_family(const char *filepath, const char *optarg)
615 {
616 	if (!strcmp(optarg, "4"))
617 		return PF_INET;
618 	if (!strcmp(optarg, "6"))
619 		return PF_INET6;
620 
621 	usage(filepath);
622 }
623 
624 static void parse_opts(int argc, char **argv)
625 {
626 	int c;
627 
628 	while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) {
629 		switch (c) {
630 		case 'd':
631 			if (cfg_l3_outer == AF_UNSPEC)
632 				error(1, 0, "-d must be preceded by -o");
633 			if (cfg_l3_outer == AF_INET)
634 				parse_addr4(&out_daddr4, optarg);
635 			else
636 				parse_addr6(&out_daddr6, optarg);
637 			break;
638 		case 'D':
639 			if (cfg_l3_inner == AF_UNSPEC)
640 				error(1, 0, "-D must be preceded by -i");
641 			if (cfg_l3_inner == AF_INET)
642 				parse_addr4(&in_daddr4, optarg);
643 			else
644 				parse_addr6(&in_daddr6, optarg);
645 			break;
646 		case 'e':
647 			if (!strcmp(optarg, "gre"))
648 				cfg_encap_proto = IPPROTO_GRE;
649 			else if (!strcmp(optarg, "gue"))
650 				cfg_encap_proto = IPPROTO_UDP;
651 			else if (!strcmp(optarg, "bare"))
652 				cfg_encap_proto = IPPROTO_IPIP;
653 			else if (!strcmp(optarg, "none"))
654 				cfg_encap_proto = IPPROTO_IP;	/* == 0 */
655 			else
656 				usage(argv[0]);
657 			break;
658 		case 'f':
659 			cfg_src_port = strtol(optarg, NULL, 0);
660 			break;
661 		case 'F':
662 			cfg_expect_failure = true;
663 			break;
664 		case 'h':
665 			usage(argv[0]);
666 			break;
667 		case 'i':
668 			if (!strcmp(optarg, "4"))
669 				cfg_l3_inner = PF_INET;
670 			else if (!strcmp(optarg, "6"))
671 				cfg_l3_inner = PF_INET6;
672 			else
673 				usage(argv[0]);
674 			break;
675 		case 'l':
676 			cfg_payload_len = strtol(optarg, NULL, 0);
677 			break;
678 		case 'n':
679 			cfg_num_pkt = strtol(optarg, NULL, 0);
680 			break;
681 		case 'o':
682 			cfg_l3_outer = parse_protocol_family(argv[0], optarg);
683 			break;
684 		case 'O':
685 			cfg_l3_extra = parse_protocol_family(argv[0], optarg);
686 			break;
687 		case 'R':
688 			cfg_only_rx = true;
689 			break;
690 		case 's':
691 			if (cfg_l3_outer == AF_INET)
692 				parse_addr4(&out_saddr4, optarg);
693 			else
694 				parse_addr6(&out_saddr6, optarg);
695 			break;
696 		case 'S':
697 			if (cfg_l3_inner == AF_INET)
698 				parse_addr4(&in_saddr4, optarg);
699 			else
700 				parse_addr6(&in_saddr6, optarg);
701 			break;
702 		case 't':
703 			cfg_num_secs = strtol(optarg, NULL, 0);
704 			break;
705 		case 'T':
706 			cfg_only_tx = true;
707 			break;
708 		case 'x':
709 			cfg_dsfield_outer = strtol(optarg, NULL, 0);
710 			break;
711 		case 'X':
712 			cfg_dsfield_inner = strtol(optarg, NULL, 0);
713 			break;
714 		}
715 	}
716 
717 	if (cfg_only_rx && cfg_only_tx)
718 		error(1, 0, "options: cannot combine rx-only and tx-only");
719 
720 	if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC)
721 		error(1, 0, "options: must specify outer with encap");
722 	else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC)
723 		error(1, 0, "options: cannot combine no-encap and outer");
724 	else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC)
725 		error(1, 0, "options: cannot combine no-encap and extra");
726 
727 	if (cfg_l3_inner == AF_UNSPEC)
728 		cfg_l3_inner = AF_INET6;
729 	if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP)
730 		cfg_encap_proto = IPPROTO_IPV6;
731 
732 	/* RFC 6040 4.2:
733 	 *   on decap, if outer encountered congestion (CE == 0x3),
734 	 *   but inner cannot encode ECN (NoECT == 0x0), then drop packet.
735 	 */
736 	if (((cfg_dsfield_outer & 0x3) == 0x3) &&
737 	    ((cfg_dsfield_inner & 0x3) == 0x0))
738 		cfg_expect_failure = true;
739 }
740 
741 static void print_opts(void)
742 {
743 	if (cfg_l3_inner == PF_INET6) {
744 		util_printaddr("inner.dest6", (void *) &in_daddr6);
745 		util_printaddr("inner.source6", (void *) &in_saddr6);
746 	} else {
747 		util_printaddr("inner.dest4", (void *) &in_daddr4);
748 		util_printaddr("inner.source4", (void *) &in_saddr4);
749 	}
750 
751 	if (!cfg_l3_outer)
752 		return;
753 
754 	fprintf(stderr, "encap proto:   %u\n", cfg_encap_proto);
755 
756 	if (cfg_l3_outer == PF_INET6) {
757 		util_printaddr("outer.dest6", (void *) &out_daddr6);
758 		util_printaddr("outer.source6", (void *) &out_saddr6);
759 	} else {
760 		util_printaddr("outer.dest4", (void *) &out_daddr4);
761 		util_printaddr("outer.source4", (void *) &out_saddr4);
762 	}
763 
764 	if (!cfg_l3_extra)
765 		return;
766 
767 	if (cfg_l3_outer == PF_INET6) {
768 		util_printaddr("extra.dest6", (void *) &extra_daddr6);
769 		util_printaddr("extra.source6", (void *) &extra_saddr6);
770 	} else {
771 		util_printaddr("extra.dest4", (void *) &extra_daddr4);
772 		util_printaddr("extra.source4", (void *) &extra_saddr4);
773 	}
774 
775 }
776 
777 int main(int argc, char **argv)
778 {
779 	parse_opts(argc, argv);
780 	print_opts();
781 	return do_main();
782 }
783