xref: /freebsd/tools/test/netfibs/reflect.c (revision b3e76948)
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