1d3373029SBjoern A. Zeeb /*-
2d3373029SBjoern A. Zeeb * Copyright (c) 2012 Cisco Systems, Inc.
3d3373029SBjoern A. Zeeb * All rights reserved.
4d3373029SBjoern A. Zeeb *
5d3373029SBjoern A. Zeeb * This software was developed by Bjoern Zeeb under contract to
6d3373029SBjoern A. Zeeb * Cisco Systems, Inc..
7d3373029SBjoern A. Zeeb *
8d3373029SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without
9d3373029SBjoern A. Zeeb * modification, are permitted provided that the following conditions
10d3373029SBjoern A. Zeeb * are met:
11d3373029SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright
12d3373029SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer.
13d3373029SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright
14d3373029SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the
15d3373029SBjoern A. Zeeb * documentation and/or other materials provided with the distribution.
16d3373029SBjoern A. Zeeb *
17d3373029SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d3373029SBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d3373029SBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d3373029SBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d3373029SBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d3373029SBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d3373029SBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d3373029SBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d3373029SBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d3373029SBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d3373029SBjoern A. Zeeb * SUCH DAMAGE.
28d3373029SBjoern A. Zeeb */
29d3373029SBjoern A. Zeeb
30d3373029SBjoern A. Zeeb #include <sys/socket.h>
31d3373029SBjoern A. Zeeb #include <sys/types.h>
32d3373029SBjoern A. Zeeb
33d3373029SBjoern A. Zeeb #include <arpa/inet.h>
34d3373029SBjoern A. Zeeb
35d3373029SBjoern A. Zeeb #include <netinet/in.h>
36d3373029SBjoern A. Zeeb
37d3373029SBjoern A. Zeeb
38d3373029SBjoern A. Zeeb #include <err.h>
39d3373029SBjoern A. Zeeb #include <errno.h>
40d3373029SBjoern A. Zeeb #include <limits.h>
41d3373029SBjoern A. Zeeb #include <stdio.h>
42d3373029SBjoern A. Zeeb #include <stdlib.h>
43d3373029SBjoern A. Zeeb #include <string.h>
44d3373029SBjoern A. Zeeb #include <sysexits.h>
45d3373029SBjoern A. Zeeb #include <unistd.h>
46d3373029SBjoern A. Zeeb
47d3373029SBjoern A. Zeeb static char *testcase;
48d3373029SBjoern A. Zeeb static int accepts;
49d3373029SBjoern A. Zeeb static int debug;
50d3373029SBjoern A. Zeeb static u_int fib = -1;
51d3373029SBjoern A. Zeeb static u_int reflectfib = -1;
52d3373029SBjoern A. Zeeb static uint16_t port = 6666;
53d3373029SBjoern A. Zeeb static char *addr;
54d3373029SBjoern A. Zeeb static int nostart;
55d3373029SBjoern A. Zeeb
56d3373029SBjoern A. Zeeb static int
reflect_conn(int s,char * buf,size_t buflen,ssize_t l,struct sockaddr * sa,socklen_t salen)57d3373029SBjoern A. Zeeb reflect_conn(int s, char *buf, size_t buflen, ssize_t l, struct sockaddr *sa,
58d3373029SBjoern A. Zeeb socklen_t salen)
59d3373029SBjoern A. Zeeb {
60d3373029SBjoern A. Zeeb ssize_t m;
61d3373029SBjoern A. Zeeb
62d3373029SBjoern A. Zeeb if (l == -1)
63d3373029SBjoern A. Zeeb err(EX_OSERR, "read()");
64d3373029SBjoern A. Zeeb if (l == 0)
65d3373029SBjoern A. Zeeb errx(EX_NOINPUT, "EOF");
66d3373029SBjoern A. Zeeb if ((size_t)l > (buflen - 1))
67d3373029SBjoern A. Zeeb errx(EX_DATAERR, "Input too long");
68d3373029SBjoern A. Zeeb /* Nuke the \n from echo | netcat. */
69d3373029SBjoern A. Zeeb buf[l-1] = '\0';
70d3373029SBjoern A. Zeeb
71d3373029SBjoern A. Zeeb /*
72d3373029SBjoern A. Zeeb * Match three cases: (1) START, (2) DONE, (3) anything else.
73d3373029SBjoern A. Zeeb * For anything but START and DONE we just reflect everything.
74d3373029SBjoern A. Zeeb */
75d3373029SBjoern A. Zeeb /*
76d3373029SBjoern A. Zeeb * We expected a "START testcase" on first connect. Otherwise it means
77d3373029SBjoern A. Zeeb * that we are out of sync. Exit to not produce weird results.
78d3373029SBjoern A. Zeeb */
79d3373029SBjoern A. Zeeb if (accepts == 0 && nostart == 0) {
80d3373029SBjoern A. Zeeb if (strncmp(buf, "START ", 6) != 0)
81d3373029SBjoern A. Zeeb errx(EX_PROTOCOL, "Not received START on first "
82d3373029SBjoern A. Zeeb "connect: %s", buf);
83d3373029SBjoern A. Zeeb if (l < 8)
84d3373029SBjoern A. Zeeb errx(EX_PROTOCOL, "START without test case name: %s",
85d3373029SBjoern A. Zeeb buf);
86d3373029SBjoern A. Zeeb if (strcmp(buf+6, testcase) != 0)
87d3373029SBjoern A. Zeeb errx(EX_PROTOCOL, "START test case does not match "
88d3373029SBjoern A. Zeeb "'%s': '%s'", testcase, buf+6);
89d3373029SBjoern A. Zeeb }
90d3373029SBjoern A. Zeeb /* If debug is on, log. */
91d3373029SBjoern A. Zeeb if (debug > 0)
92d3373029SBjoern A. Zeeb fprintf(stderr, "<< %s: %s\n", testcase, buf);
93d3373029SBjoern A. Zeeb
94d3373029SBjoern A. Zeeb if (reflectfib != (u_int)-1)
9581e6c8e7SXin LI l = snprintf(buf, buflen, "FIB %u\n", reflectfib);
96d3373029SBjoern A. Zeeb
97d3373029SBjoern A. Zeeb /* If debug is on, log. */
98d3373029SBjoern A. Zeeb if (debug > 0) {
99d3373029SBjoern A. Zeeb buf[l-1] = '\0';
100d3373029SBjoern A. Zeeb fprintf(stderr, ">> %s: %s\n", testcase, buf);
101d3373029SBjoern A. Zeeb }
102d3373029SBjoern A. Zeeb
103d3373029SBjoern A. Zeeb /* Reflect data with \n again. */
104d3373029SBjoern A. Zeeb buf[l-1] = '\n';
105d3373029SBjoern A. Zeeb
106d3373029SBjoern A. Zeeb if (sa != NULL) {
107d3373029SBjoern A. Zeeb m = sendto(s, buf, l, 0, sa, salen);
108d3373029SBjoern A. Zeeb } else
109d3373029SBjoern A. Zeeb m = write(s, buf, l);
110d3373029SBjoern A. Zeeb /* XXX This is simplified handling. */
111d3373029SBjoern A. Zeeb if (m == -1 && sa != NULL && errno == EHOSTUNREACH)
112d3373029SBjoern A. Zeeb warn("ignored expected: sendto(%s, %zd)", buf, l);
113d3373029SBjoern A. Zeeb else if (m == -1 && (sa == NULL || errno != EHOSTUNREACH))
114d3373029SBjoern A. Zeeb err(EX_OSERR, "write(%s, %zd)", buf, l);
115d3373029SBjoern A. Zeeb else if (m != l)
116d3373029SBjoern A. Zeeb err(EX_OSERR, "short write(%s, %zd) %zd", buf, l, m);
117d3373029SBjoern A. Zeeb
118d3373029SBjoern A. Zeeb
119d3373029SBjoern A. Zeeb accepts++;
120d3373029SBjoern A. Zeeb
121d3373029SBjoern A. Zeeb /* See if we got an end signal. */
122d3373029SBjoern A. Zeeb if (strncmp(buf, "DONE", 4) == 0)
123d3373029SBjoern A. Zeeb return (-2);
124d3373029SBjoern A. Zeeb return (0);
125d3373029SBjoern A. Zeeb }
126d3373029SBjoern A. Zeeb
127d3373029SBjoern A. Zeeb static int
reflect_tcp6_conn(int as)128d3373029SBjoern A. Zeeb reflect_tcp6_conn(int as)
129d3373029SBjoern A. Zeeb {
130d3373029SBjoern A. Zeeb char buf[1500];
131d3373029SBjoern A. Zeeb ssize_t l;
132d3373029SBjoern A. Zeeb int error, s;
133d3373029SBjoern A. Zeeb
134d3373029SBjoern A. Zeeb s = accept(as, NULL, NULL);
135d3373029SBjoern A. Zeeb if (s == -1)
136d3373029SBjoern A. Zeeb err(EX_OSERR, "accept()");
137d3373029SBjoern A. Zeeb
138d3373029SBjoern A. Zeeb l = read(s, buf, sizeof(buf));
139d3373029SBjoern A. Zeeb error = reflect_conn(s, buf, sizeof(buf), l, NULL, 0);
140d3373029SBjoern A. Zeeb close(s);
141d3373029SBjoern A. Zeeb
142d3373029SBjoern A. Zeeb return (error);
143d3373029SBjoern A. Zeeb }
144d3373029SBjoern A. Zeeb
145d3373029SBjoern A. Zeeb static int
reflect_udp6_conn(int s)146d3373029SBjoern A. Zeeb reflect_udp6_conn(int s)
147d3373029SBjoern A. Zeeb {
148d3373029SBjoern A. Zeeb char buf[1500];
149d3373029SBjoern A. Zeeb struct sockaddr_in6 from;
150d3373029SBjoern A. Zeeb socklen_t fromlen;
151d3373029SBjoern A. Zeeb ssize_t l;
152d3373029SBjoern A. Zeeb int error;
153d3373029SBjoern A. Zeeb
154d3373029SBjoern A. Zeeb fromlen = sizeof(from);
155d3373029SBjoern A. Zeeb l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from,
156d3373029SBjoern A. Zeeb &fromlen);
157d3373029SBjoern A. Zeeb #if 0
158d3373029SBjoern A. Zeeb if (l != -1) {
159d3373029SBjoern A. Zeeb rc = connect(s, (struct sockaddr *)&from, fromlen);
160d3373029SBjoern A. Zeeb if (rc == -1) {
161d3373029SBjoern A. Zeeb if (inet_ntop(PF_INET6, &from, buf, sizeof(buf)) == NULL)
162d3373029SBjoern A. Zeeb buf[0] = '\0';
163d3373029SBjoern A. Zeeb err(EX_OSERR, "connect(%d, %s, %u)", s, buf, fromlen);
164d3373029SBjoern A. Zeeb }
165d3373029SBjoern A. Zeeb }
166d3373029SBjoern A. Zeeb #endif
167d3373029SBjoern A. Zeeb error = reflect_conn(s, buf, sizeof(buf), l, (struct sockaddr *)&from,
168d3373029SBjoern A. Zeeb fromlen);
169d3373029SBjoern A. Zeeb #if 0
170d3373029SBjoern A. Zeeb if (l != -1) {
171d3373029SBjoern A. Zeeb /* Undo the connect binding again. */
172d3373029SBjoern A. Zeeb fromlen = sizeof(from);
173d3373029SBjoern A. Zeeb bzero(&from, fromlen);
174d3373029SBjoern A. Zeeb from.sin6_len = fromlen;
175d3373029SBjoern A. Zeeb from.sin6_family = AF_INET6;
176d3373029SBjoern A. Zeeb from.sin6_port = htons(port); /* This only gives us a ::1:port ::1:port binding */
177d3373029SBjoern A. Zeeb rc = connect(s, (struct sockaddr *)&from, fromlen);
178d3373029SBjoern A. Zeeb if (rc == -1) {
179d3373029SBjoern A. Zeeb if (inet_ntop(PF_INET6, &from.sin6_addr, buf,
180d3373029SBjoern A. Zeeb sizeof(buf)) == NULL)
181d3373029SBjoern A. Zeeb buf[0] = '\0';
182d3373029SBjoern A. Zeeb err(EX_OSERR, "un-connect(%d, %s, %u)", s, buf, fromlen);
183d3373029SBjoern A. Zeeb }
184d3373029SBjoern A. Zeeb }
185d3373029SBjoern A. Zeeb #endif
186d3373029SBjoern A. Zeeb
187d3373029SBjoern A. Zeeb return (error);
188d3373029SBjoern A. Zeeb }
189d3373029SBjoern A. Zeeb
190d3373029SBjoern A. Zeeb static int
reflect_6(int domain,int type)191d3373029SBjoern A. Zeeb reflect_6(int domain, int type)
192d3373029SBjoern A. Zeeb {
193d3373029SBjoern A. Zeeb struct sockaddr_in6 sin6;
194d3373029SBjoern A. Zeeb fd_set rset;
195d3373029SBjoern A. Zeeb int i, rc, s;
196d3373029SBjoern A. Zeeb
197d3373029SBjoern A. Zeeb /* Get us a listen socket. */
198d3373029SBjoern A. Zeeb s = socket(domain, type, 0);
199d3373029SBjoern A. Zeeb if (s == -1)
200d3373029SBjoern A. Zeeb err(EX_OSERR, "socket()");
201d3373029SBjoern A. Zeeb
202d3373029SBjoern A. Zeeb /*
203d3373029SBjoern A. Zeeb * In case a FIB was given on cmd line, set it. Let the kernel do the
204d3373029SBjoern A. Zeeb * the bounds check.
205d3373029SBjoern A. Zeeb */
206d3373029SBjoern A. Zeeb if (fib != (u_int)-1) {
207d3373029SBjoern A. Zeeb rc = setsockopt(s, SOL_SOCKET, SO_SETFIB, &fib, sizeof(fib));
208d3373029SBjoern A. Zeeb if (rc == -1)
209d3373029SBjoern A. Zeeb err(EX_OSERR, "setsockopt(SO_SETFIB)");
210d3373029SBjoern A. Zeeb }
211d3373029SBjoern A. Zeeb
212d3373029SBjoern A. Zeeb /* Allow re-use. Otherwise restarting for the next test might error. */
213d3373029SBjoern A. Zeeb i = 1;
214d3373029SBjoern A. Zeeb rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
215d3373029SBjoern A. Zeeb if (rc == -1)
216d3373029SBjoern A. Zeeb err(EX_OSERR, "setsockopt(SO_REUSEADDR)");
217d3373029SBjoern A. Zeeb i = 1;
218d3373029SBjoern A. Zeeb rc = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &i, sizeof(i));
219d3373029SBjoern A. Zeeb if (rc == -1)
220d3373029SBjoern A. Zeeb err(EX_OSERR, "setsockopt(SO_REUSEPORT)");
221d3373029SBjoern A. Zeeb
222d3373029SBjoern A. Zeeb /* Bind address and port or just port. */
223d3373029SBjoern A. Zeeb sin6.sin6_len = sizeof(sin6);
224d3373029SBjoern A. Zeeb sin6.sin6_family = AF_INET6;
225d3373029SBjoern A. Zeeb sin6.sin6_port = htons(port);
226d3373029SBjoern A. Zeeb sin6.sin6_flowinfo = 0;
227d3373029SBjoern A. Zeeb bzero(&sin6.sin6_addr, sizeof(sin6.sin6_addr));
228d3373029SBjoern A. Zeeb if (addr != NULL) {
229d3373029SBjoern A. Zeeb rc = inet_pton(PF_INET6, addr, &sin6.sin6_addr);
230d3373029SBjoern A. Zeeb if (rc == 0)
231d3373029SBjoern A. Zeeb errx(EX_USAGE, "inet_pton()");
232d3373029SBjoern A. Zeeb else if (rc == -1)
233d3373029SBjoern A. Zeeb err(EX_OSERR, "inet_pton()");
234d3373029SBjoern A. Zeeb else if (rc != 1)
235d3373029SBjoern A. Zeeb errx(EX_SOFTWARE, "inet_pton()");
236d3373029SBjoern A. Zeeb }
237d3373029SBjoern A. Zeeb sin6.sin6_scope_id = 0;
238d3373029SBjoern A. Zeeb rc = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
239d3373029SBjoern A. Zeeb if (rc == -1)
240d3373029SBjoern A. Zeeb err(EX_OSERR, "bind(%d)", s);
241d3373029SBjoern A. Zeeb
242d3373029SBjoern A. Zeeb if (type == SOCK_STREAM) {
243d3373029SBjoern A. Zeeb rc = listen(s, port);
244d3373029SBjoern A. Zeeb if (rc == -1)
245d3373029SBjoern A. Zeeb err(EX_OSERR, "listen(%d, %u)", s, port);
246d3373029SBjoern A. Zeeb }
247d3373029SBjoern A. Zeeb
248d3373029SBjoern A. Zeeb /*
249d3373029SBjoern A. Zeeb * We shall never do more than one connection in parallel so can keep
250d3373029SBjoern A. Zeeb * it simple.
251d3373029SBjoern A. Zeeb */
252d3373029SBjoern A. Zeeb do {
253d3373029SBjoern A. Zeeb FD_ZERO(&rset);
254d3373029SBjoern A. Zeeb FD_SET(s, &rset);
255d3373029SBjoern A. Zeeb rc = select(s + 1, &rset, NULL, NULL, NULL);
256d3373029SBjoern A. Zeeb if (rc == -1 && errno != EINTR)
257d3373029SBjoern A. Zeeb err(EX_OSERR, "select()");
258d3373029SBjoern A. Zeeb
259d3373029SBjoern A. Zeeb if (rc == 0 || errno == EINTR)
260d3373029SBjoern A. Zeeb continue;
261d3373029SBjoern A. Zeeb
262d3373029SBjoern A. Zeeb if (rc != 1)
263d3373029SBjoern A. Zeeb errx(EX_OSERR, "select() miscounted 1 to %d", rc);
264d3373029SBjoern A. Zeeb if (!FD_ISSET(s, &rset))
265d3373029SBjoern A. Zeeb errx(EX_OSERR, "select() did not return our socket");
266d3373029SBjoern A. Zeeb
267d3373029SBjoern A. Zeeb if (type == SOCK_STREAM)
268d3373029SBjoern A. Zeeb rc = reflect_tcp6_conn(s);
269d3373029SBjoern A. Zeeb else if (type == SOCK_DGRAM)
270d3373029SBjoern A. Zeeb rc = reflect_udp6_conn(s);
271d3373029SBjoern A. Zeeb else
272d3373029SBjoern A. Zeeb errx(EX_SOFTWARE, "Unsupported socket type %d", type);
273d3373029SBjoern A. Zeeb } while (rc == 0);
274d3373029SBjoern A. Zeeb /* Turn end flagging into no error. */
275d3373029SBjoern A. Zeeb if (rc == -2)
276d3373029SBjoern A. Zeeb rc = 0;
277d3373029SBjoern A. Zeeb
278d3373029SBjoern A. Zeeb /* Close listen socket. */
279d3373029SBjoern A. Zeeb close(s);
280d3373029SBjoern A. Zeeb
281d3373029SBjoern A. Zeeb return (rc);
282d3373029SBjoern A. Zeeb }
283d3373029SBjoern A. Zeeb
284d3373029SBjoern A. Zeeb static int
reflect_tcp6(void)285d3373029SBjoern A. Zeeb reflect_tcp6(void)
286d3373029SBjoern A. Zeeb {
287d3373029SBjoern A. Zeeb
288d3373029SBjoern A. Zeeb return (reflect_6(PF_INET6, SOCK_STREAM));
289d3373029SBjoern A. Zeeb }
290d3373029SBjoern A. Zeeb
291d3373029SBjoern A. Zeeb static int
reflect_udp6(void)292d3373029SBjoern A. Zeeb reflect_udp6(void)
293d3373029SBjoern A. Zeeb {
294d3373029SBjoern A. Zeeb
295d3373029SBjoern A. Zeeb return (reflect_6(PF_INET6, SOCK_DGRAM));
296d3373029SBjoern A. Zeeb }
297d3373029SBjoern A. Zeeb
298d3373029SBjoern A. Zeeb int
main(int argc,char * argv[])299d3373029SBjoern A. Zeeb main(int argc, char *argv[])
300d3373029SBjoern A. Zeeb {
301d3373029SBjoern A. Zeeb long long l;
302d3373029SBjoern A. Zeeb char *dummy, *afname;
303d3373029SBjoern A. Zeeb int ch, rc;
304d3373029SBjoern A. Zeeb
305d3373029SBjoern A. Zeeb afname = NULL;
306d3373029SBjoern A. Zeeb while ((ch = getopt(argc, argv, "A:dF:f:Np:t:T:")) != -1) {
307d3373029SBjoern A. Zeeb switch (ch) {
308d3373029SBjoern A. Zeeb case 'A':
309d3373029SBjoern A. Zeeb addr = optarg;
310d3373029SBjoern A. Zeeb break;
311d3373029SBjoern A. Zeeb case 'd':
312d3373029SBjoern A. Zeeb debug++;
313d3373029SBjoern A. Zeeb break;
314d3373029SBjoern A. Zeeb case 'F':
315d3373029SBjoern A. Zeeb l = strtoll(optarg, &dummy, 10);
316d3373029SBjoern A. Zeeb if (*dummy != '\0' || l < 0)
317d3373029SBjoern A. Zeeb errx(EX_USAGE, "Invalid FIB number");
318d3373029SBjoern A. Zeeb fib = (u_int)l;
319d3373029SBjoern A. Zeeb break;
320d3373029SBjoern A. Zeeb case 'f':
321d3373029SBjoern A. Zeeb l = strtoll(optarg, &dummy, 10);
322d3373029SBjoern A. Zeeb if (*dummy != '\0' || l < 0)
323d3373029SBjoern A. Zeeb errx(EX_USAGE, "Invalid FIB number");
324d3373029SBjoern A. Zeeb reflectfib = (u_int)l;
325d3373029SBjoern A. Zeeb break;
326d3373029SBjoern A. Zeeb case 'N':
327d3373029SBjoern A. Zeeb nostart=1;
328d3373029SBjoern A. Zeeb break;
329d3373029SBjoern A. Zeeb case 'p':
330d3373029SBjoern A. Zeeb l = strtoll(optarg, &dummy, 10);
331d3373029SBjoern A. Zeeb if (*dummy != '\0' || l < 0)
332d3373029SBjoern A. Zeeb errx(EX_USAGE, "Invalid port number");
333d3373029SBjoern A. Zeeb port = (uint16_t)l;
334d3373029SBjoern A. Zeeb break;
335d3373029SBjoern A. Zeeb case 't':
336d3373029SBjoern A. Zeeb testcase = optarg;
337d3373029SBjoern A. Zeeb break;
338d3373029SBjoern A. Zeeb case 'T':
339d3373029SBjoern A. Zeeb afname = optarg;
340d3373029SBjoern A. Zeeb break;
341d3373029SBjoern A. Zeeb case '?':
342d3373029SBjoern A. Zeeb default:
343d3373029SBjoern A. Zeeb errx(EX_USAGE, "Unknown command line option at '%c'",
344d3373029SBjoern A. Zeeb optopt);
345d3373029SBjoern A. Zeeb /* NOTREACHED */
346d3373029SBjoern A. Zeeb }
347d3373029SBjoern A. Zeeb }
348d3373029SBjoern A. Zeeb
349d3373029SBjoern A. Zeeb if (testcase == NULL)
350d3373029SBjoern A. Zeeb errx(EX_USAGE, "Mandatory option -t <testcase> not given");
351d3373029SBjoern A. Zeeb if (afname == NULL)
352d3373029SBjoern A. Zeeb errx(EX_USAGE, "Mandatory option -T <afname> not given");
353d3373029SBjoern A. Zeeb
354d3373029SBjoern A. Zeeb if (strcmp(afname, "TCP6") == 0)
355d3373029SBjoern A. Zeeb rc = reflect_tcp6();
356d3373029SBjoern A. Zeeb else if (strcmp(afname, "UDP6") == 0)
357d3373029SBjoern A. Zeeb rc = reflect_udp6();
358d3373029SBjoern A. Zeeb else
359d3373029SBjoern A. Zeeb errx(EX_USAGE, "Mandatory option -T %s not a valid option",
360d3373029SBjoern A. Zeeb afname);
361d3373029SBjoern A. Zeeb
362d3373029SBjoern A. Zeeb return (rc);
363d3373029SBjoern A. Zeeb }
364