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