xref: /openbsd-src/regress/sys/netinet/in_pcbbind/runtest.c (revision 93aefe23b3a72ebdbbf1c04ba4c059ad97c0f884)
1*93aefe23Sclaudio /* $OpenBSD: runtest.c,v 1.7 2022/04/10 14:08:35 claudio Exp $ */
292cb773aSvgross /*
392cb773aSvgross  * Copyright (c) 2015 Vincent Gross <vincent.gross@kilob.yt>
492cb773aSvgross  *
592cb773aSvgross  * Permission to use, copy, modify, and distribute this software for any
692cb773aSvgross  * purpose with or without fee is hereby granted, provided that the above
792cb773aSvgross  * copyright notice and this permission notice appear in all copies.
892cb773aSvgross  *
992cb773aSvgross  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1092cb773aSvgross  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1192cb773aSvgross  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1292cb773aSvgross  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1392cb773aSvgross  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1492cb773aSvgross  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1592cb773aSvgross  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1692cb773aSvgross  */
1792cb773aSvgross 
1892cb773aSvgross #include <errno.h>
1992cb773aSvgross #include <stdio.h>
2092cb773aSvgross #include <stdlib.h>
2192cb773aSvgross #include <unistd.h>
2292cb773aSvgross #include <string.h>
2392cb773aSvgross #include <err.h>
2492cb773aSvgross #include <netdb.h>
2592cb773aSvgross 
2692cb773aSvgross #include <sys/types.h>
2792cb773aSvgross #include <sys/socket.h>
28f80fdc7eSvgross #include <netinet/in.h>
29f80fdc7eSvgross #include <net/if.h>
30f80fdc7eSvgross #include <ifaddrs.h>
3192cb773aSvgross 
3292cb773aSvgross int
runtest(int * sockp,struct addrinfo * ai,int reuseaddr,int reuseport,void * mreq,int expected)3392cb773aSvgross runtest(int *sockp, struct addrinfo *ai, int reuseaddr, int reuseport,
34f80fdc7eSvgross     void *mreq, int expected)
3592cb773aSvgross {
3692cb773aSvgross 	int error, optval;
37f80fdc7eSvgross 	struct ip_mreq imr;
3892cb773aSvgross 
3992cb773aSvgross 	*sockp = socket(ai->ai_family, ai->ai_socktype, 0);
4092cb773aSvgross 	if (*sockp == -1) {
4192cb773aSvgross 		warn("%s : socket()", ai->ai_canonname);
4292cb773aSvgross 		return (3);
4392cb773aSvgross 	}
4492cb773aSvgross 
4592cb773aSvgross 	if (reuseaddr) {
4692cb773aSvgross 		optval = 1;
4792cb773aSvgross 		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEADDR,
4892cb773aSvgross 		    &optval, sizeof(int));
4992cb773aSvgross 		if (error) {
5092cb773aSvgross 			warn("%s : setsockopt(SO_REUSEADDR)", ai->ai_canonname);
5192cb773aSvgross 			return (2);
5292cb773aSvgross 		}
5392cb773aSvgross 	}
5492cb773aSvgross 
5592cb773aSvgross 	if (reuseport) {
5692cb773aSvgross 		optval = 1;
5792cb773aSvgross 		error = setsockopt(*sockp, SOL_SOCKET, SO_REUSEPORT,
5892cb773aSvgross 		    &optval, sizeof(int));
5992cb773aSvgross 		if (error) {
6092cb773aSvgross 			warn("%s : setsockopt(SO_REUSEPORT)", ai->ai_canonname);
6192cb773aSvgross 			return (2);
6292cb773aSvgross 		}
6392cb773aSvgross 	}
6492cb773aSvgross 
65f80fdc7eSvgross 	if (mreq) {
66f80fdc7eSvgross 		switch (ai->ai_family) {
67f80fdc7eSvgross 		case AF_INET6:
68f80fdc7eSvgross 			error = setsockopt(*sockp, IPPROTO_IPV6, IPV6_JOIN_GROUP,
69f80fdc7eSvgross 			    mreq, sizeof(struct ipv6_mreq));
70f80fdc7eSvgross 			if (error) {
71f80fdc7eSvgross 				warn("%s : setsockopt(IPV6_JOIN_GROUP)",
72f80fdc7eSvgross 				    ai->ai_canonname);
73f80fdc7eSvgross 				return (2);
74f80fdc7eSvgross 			}
75f80fdc7eSvgross 			break;
76f80fdc7eSvgross 		case AF_INET:
77f80fdc7eSvgross 			error = setsockopt(*sockp, IPPROTO_IP, IP_ADD_MEMBERSHIP,
78f80fdc7eSvgross 			    mreq, sizeof(struct ip_mreq));
79f80fdc7eSvgross 			if (error) {
80f80fdc7eSvgross 				warn("%s : setsockopt(IP_ADD_MEMBERSHIP)",
81f80fdc7eSvgross 				    ai->ai_canonname);
82f80fdc7eSvgross 				return (2);
83f80fdc7eSvgross 			}
84f80fdc7eSvgross 			break;
85f80fdc7eSvgross 		default:
86f80fdc7eSvgross 			warnx("%s : trying to join multicast group in unknown AF",
87f80fdc7eSvgross 			    ai->ai_canonname);
88f80fdc7eSvgross 			return (2);
89f80fdc7eSvgross 		}
90f80fdc7eSvgross 	}
91f80fdc7eSvgross 
92f80fdc7eSvgross 
9392cb773aSvgross 	error = bind(*sockp, ai->ai_addr, ai->ai_addrlen);
9492cb773aSvgross 	if (error && (expected == 0 || expected != errno)) {
9592cb773aSvgross 		warn("bind(%s,%s,%s)", ai->ai_canonname,
96f80fdc7eSvgross 		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "");
9792cb773aSvgross 		return (1);
9892cb773aSvgross 	}
9992cb773aSvgross 	if (error == 0 && expected != 0) {
100f80fdc7eSvgross 		warnx("bind(%s,%s,%s) succeeded, expected : %s", ai->ai_canonname,
101f80fdc7eSvgross 		    reuseaddr ? "REUSEADDR" : "", reuseport ? "REUSEPORT" : "",
102*93aefe23Sclaudio 		    strerror(expected));
10392cb773aSvgross 		return (1);
10492cb773aSvgross 	}
10592cb773aSvgross 
10692cb773aSvgross 	return (0);
10792cb773aSvgross }
10892cb773aSvgross 
10992cb773aSvgross void
cleanup(int * fds,int num_fds)11092cb773aSvgross cleanup(int *fds, int num_fds)
11192cb773aSvgross {
11292cb773aSvgross 	while (num_fds-- > 0)
11392cb773aSvgross 		if (close(*fds++) && errno != EBADF)
11492cb773aSvgross 			err(2, "unable to clean up sockets, aborting");
11592cb773aSvgross }
11692cb773aSvgross 
11792cb773aSvgross int
unicast_testsuite(struct addrinfo * local,struct addrinfo * any)118f80fdc7eSvgross unicast_testsuite(struct addrinfo *local, struct addrinfo *any)
119f80fdc7eSvgross {
120f80fdc7eSvgross 	int test_rc, rc, *s;
121f80fdc7eSvgross 	int sockets[4];
122f80fdc7eSvgross 
123b12e34d8Sbluhm 	test_rc = 0;
124f80fdc7eSvgross 	rc = 0; s = sockets;
125f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, NULL, 0);
126f80fdc7eSvgross 	rc |= runtest(s++, any,   0, 0, NULL, EADDRINUSE);
127f80fdc7eSvgross 	rc |= runtest(s++, any,   1, 0, NULL, 0);
128f80fdc7eSvgross 	cleanup(sockets, 3);
129f80fdc7eSvgross 	test_rc |= rc;
130f80fdc7eSvgross 	if (rc)
131f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 1);
132f80fdc7eSvgross 
133f80fdc7eSvgross 	rc = 0; s = sockets;
134f80fdc7eSvgross 	rc |= runtest(s++, any,   0, 0, NULL, 0);
135f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
136f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, NULL, 0);
137f80fdc7eSvgross 	cleanup(sockets, 3);
138f80fdc7eSvgross 	test_rc |= rc;
139f80fdc7eSvgross 	if (rc)
140f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 2);
141f80fdc7eSvgross 
142f80fdc7eSvgross 	rc = 0; s = sockets;
143f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, NULL, 0);
144f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, NULL, 0);
145f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
146f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, NULL, EADDRINUSE);
147f80fdc7eSvgross 	cleanup(sockets, 4);
148f80fdc7eSvgross 	test_rc |= rc;
149f80fdc7eSvgross 	if (rc)
150f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 3);
151f80fdc7eSvgross 
152f80fdc7eSvgross 	rc = 0; s = sockets;
153f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 1, NULL, 0);
154f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 1, NULL, 0);
155f80fdc7eSvgross 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
156f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 0, NULL, EADDRINUSE);
157f80fdc7eSvgross 	cleanup(sockets, 4);
158f80fdc7eSvgross 	test_rc |= rc;
159f80fdc7eSvgross 	if (rc)
160f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 4);
161f80fdc7eSvgross 
162f80fdc7eSvgross 	rc = 0; s = sockets;
163f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, NULL, 0);
164f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, NULL, EADDRINUSE);
165f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, NULL, EADDRINUSE);
166f80fdc7eSvgross 	cleanup(sockets, 3);
167f80fdc7eSvgross 	test_rc |= rc;
168f80fdc7eSvgross 	if (rc)
169f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 5);
170f80fdc7eSvgross 
171f80fdc7eSvgross 	rc = 0; s = sockets;
172f80fdc7eSvgross 	rc |= runtest(s++, any, 1, 0, NULL, 0);
173f80fdc7eSvgross 	rc |= runtest(s++, any, 1, 0, NULL, EADDRINUSE);
174f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 1, NULL, EADDRINUSE);
175f80fdc7eSvgross 	cleanup(sockets, 3);
176f80fdc7eSvgross 	test_rc |= rc;
177f80fdc7eSvgross 	if (rc)
178f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 6);
179f80fdc7eSvgross 
180f80fdc7eSvgross 	return (test_rc);
181f80fdc7eSvgross }
182f80fdc7eSvgross 
183f80fdc7eSvgross int
mcast_reuse_testsuite(struct addrinfo * local,void * mr)184f80fdc7eSvgross mcast_reuse_testsuite(struct addrinfo *local, void *mr)
185f80fdc7eSvgross {
186f80fdc7eSvgross 	int test_rc, rc, *s;
187f80fdc7eSvgross 	int sockets[6];
188f80fdc7eSvgross 	int testnum = 1;
189f80fdc7eSvgross 
190b12e34d8Sbluhm 	test_rc = 0;
191f80fdc7eSvgross 	rc = 0; s = sockets;
192f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, mr, 0);
193f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, EADDRINUSE);
194f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, EADDRINUSE);
195f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, EADDRINUSE);
196f80fdc7eSvgross 	cleanup(sockets, 4);
197f80fdc7eSvgross 	test_rc |= rc;
198f80fdc7eSvgross 	if (rc)
199f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 1);
200f80fdc7eSvgross 
201f80fdc7eSvgross 	rc = 0; s = sockets;
202f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
203f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
204f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
205f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
206f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
207f80fdc7eSvgross 	cleanup(sockets, 5);
208f80fdc7eSvgross 	test_rc |= rc;
209f80fdc7eSvgross 	if (rc)
210f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 2);
211f80fdc7eSvgross 
212f80fdc7eSvgross 	rc = 0; s = sockets;
213f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
214f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
215f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
216f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
217f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
218f80fdc7eSvgross 	cleanup(sockets, 5);
219f80fdc7eSvgross 	test_rc |= rc;
220f80fdc7eSvgross 	if (rc)
221f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 3);
222f80fdc7eSvgross 
223f80fdc7eSvgross 	rc = 0; s = sockets;
224f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
225f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, mr, EADDRINUSE);
226f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
227f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
228f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
229f80fdc7eSvgross 	cleanup(sockets, 5);
230f80fdc7eSvgross 	test_rc |= rc;
231f80fdc7eSvgross 	if (rc)
232f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 4);
233f80fdc7eSvgross 
234bf308977Svgross #if 0
235f80fdc7eSvgross 	rc = 0; s = sockets;
236f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
237f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
238f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
239f80fdc7eSvgross 	cleanup(sockets, 3);
240f80fdc7eSvgross 	test_rc |= rc;
241f80fdc7eSvgross 	if (rc)
242f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 5);
243f80fdc7eSvgross 
244f80fdc7eSvgross 	rc = 0; s = sockets;
245f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
246f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
247f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
248f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
249f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
250f80fdc7eSvgross 	cleanup(sockets, 5);
251f80fdc7eSvgross 	test_rc |= rc;
252f80fdc7eSvgross 	if (rc)
253f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 6);
254f80fdc7eSvgross 
255f80fdc7eSvgross 	rc = 0; s = sockets;
256f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
257f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
258f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 1, mr, 0);
259f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, mr, 0);
260bf308977Svgross 	rc |= runtest(s++, local, 0, 1, mr, 0);
261f80fdc7eSvgross 	cleanup(sockets, 5);
262f80fdc7eSvgross 	test_rc |= rc;
263f80fdc7eSvgross 	if (rc)
264f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 7);
265f80fdc7eSvgross #endif
266f80fdc7eSvgross 	return (test_rc);
267f80fdc7eSvgross }
268f80fdc7eSvgross 
269f80fdc7eSvgross int
mcast6_testsuite(struct addrinfo * local,struct ipv6_mreq * local_mreq,struct addrinfo * any,struct ipv6_mreq * any_mreq)270f80fdc7eSvgross mcast6_testsuite(struct addrinfo *local, struct ipv6_mreq *local_mreq,
271f80fdc7eSvgross     struct addrinfo *any, struct ipv6_mreq *any_mreq)
272f80fdc7eSvgross {
273f80fdc7eSvgross 	int test_rc, rc, *s;
274f80fdc7eSvgross 	int sockets[4];
275f80fdc7eSvgross 	int testnum = 1;
276f80fdc7eSvgross 
277b12e34d8Sbluhm 	test_rc = 0;
278f80fdc7eSvgross 	rc = 0; s = sockets;
279f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, local_mreq, 0);
280f80fdc7eSvgross 	rc |= runtest(s++, any,   0, 0, any_mreq,   EADDRINUSE);
281f80fdc7eSvgross 	rc |= runtest(s++, any,   1, 0, any_mreq,   0);
282f80fdc7eSvgross 	cleanup(sockets, 3);
283f80fdc7eSvgross 	test_rc |= rc;
284f80fdc7eSvgross 	if (rc)
285f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 1);
286f80fdc7eSvgross 
287f80fdc7eSvgross 	rc = 0; s = sockets;
288f80fdc7eSvgross 	rc |= runtest(s++, any,   0, 0, any_mreq,   0);
289f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
290f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
291f80fdc7eSvgross 	cleanup(sockets, 3);
292f80fdc7eSvgross 	test_rc |= rc;
293f80fdc7eSvgross 	if (rc)
294f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 2);
295f80fdc7eSvgross 
296f80fdc7eSvgross 	rc = 0; s = sockets;
297f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
298f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
299f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
300f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
301f80fdc7eSvgross 	cleanup(sockets, 4);
302f80fdc7eSvgross 	test_rc |= rc;
303f80fdc7eSvgross 	if (rc)
304f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 3);
305f80fdc7eSvgross 
306bf308977Svgross 	/*
307bf308977Svgross 	 * :: is not a multicast address, SO_REUSEADDR and SO_REUSEPORT
308bf308977Svgross 	 * keep their unicast semantics although we are binding on multicast
309bf308977Svgross 	 */
310bf308977Svgross 
311f80fdc7eSvgross 	rc = 0; s = sockets;
312f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
313f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 1, any_mreq, 0);
314bf308977Svgross 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
315f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
316f80fdc7eSvgross 	cleanup(sockets, 4);
317f80fdc7eSvgross 	test_rc |= rc;
318f80fdc7eSvgross 	if (rc)
319f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 4);
320f80fdc7eSvgross 
321f80fdc7eSvgross 	rc = 0; s = sockets;
322f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
323f80fdc7eSvgross 	rc |= runtest(s++, local, 1, 0, local_mreq, 0);
324bf308977Svgross 	rc |= runtest(s++, local, 0, 1, local_mreq, 0);
325f80fdc7eSvgross 	rc |= runtest(s++, local, 0, 0, local_mreq, EADDRINUSE);
326bf308977Svgross 	cleanup(sockets, 4);
327f80fdc7eSvgross 	test_rc |= rc;
328f80fdc7eSvgross 	if (rc)
329f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 5);
330f80fdc7eSvgross 
331bf308977Svgross 	/* See above */
332bf308977Svgross 
333f80fdc7eSvgross 	rc = 0; s = sockets;
334f80fdc7eSvgross 	rc |= runtest(s++, any, 1, 0, any_mreq, 0);
335bf308977Svgross 	rc |= runtest(s++, any, 1, 0, any_mreq, EADDRINUSE);
336bf308977Svgross 	rc |= runtest(s++, any, 0, 1, any_mreq, EADDRINUSE);
337f80fdc7eSvgross 	rc |= runtest(s++, any, 0, 0, any_mreq, EADDRINUSE);
338bf308977Svgross 	cleanup(sockets, 4);
339f80fdc7eSvgross 	test_rc |= rc;
340f80fdc7eSvgross 	if (rc)
341f80fdc7eSvgross 		warnx("%s : test #%d failed", __func__, 6);
342f80fdc7eSvgross 
343f80fdc7eSvgross 	return (test_rc);
344f80fdc7eSvgross }
345f80fdc7eSvgross 
346f80fdc7eSvgross int
main(int argc,char * argv[])34792cb773aSvgross main(int argc, char *argv[])
34892cb773aSvgross {
349f80fdc7eSvgross 	int error, rc;
350c214498eSvgross 	char *baddr_s, *bport_s, *bmifa_s;
351c214498eSvgross 	struct addrinfo hints, *baddr, *any, *mifa;
352f80fdc7eSvgross 	struct ifaddrs *ifap, *curifa;
353f80fdc7eSvgross 	struct ip_mreq local_imr, any_imr;
354f80fdc7eSvgross 	struct ipv6_mreq local_i6mr, any_i6mr;
355f80fdc7eSvgross 	struct sockaddr_in *sin;
356f80fdc7eSvgross 	struct sockaddr_in6 *sin6;
35792cb773aSvgross 	int *s;
35892cb773aSvgross 
35992cb773aSvgross 	memset(&hints, 0, sizeof(hints));
36092cb773aSvgross 	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV | \
36192cb773aSvgross 	    AI_PASSIVE;
36292cb773aSvgross 	hints.ai_socktype = SOCK_DGRAM;
363f80fdc7eSvgross 
364c214498eSvgross 	baddr_s = argv[1];
365c214498eSvgross 	bport_s = argv[2];
366c214498eSvgross 
367c214498eSvgross 	if ((error = getaddrinfo(baddr_s, bport_s, &hints, &baddr)))
368c214498eSvgross 		errx(2, "getaddrinfo(%s,%s): %s", baddr_s, bport_s,
36992cb773aSvgross 		    gai_strerror(error));
370c214498eSvgross 	baddr->ai_canonname = baddr_s;
37192cb773aSvgross 
372c214498eSvgross 	hints.ai_family = baddr->ai_family;
373c214498eSvgross 	if ((error = getaddrinfo(NULL, bport_s, &hints, &any)))
374c214498eSvgross 		errx(2, "getaddrinfo(NULL,%s): %s", bport_s,
37592cb773aSvgross 		    gai_strerror(error));
376c214498eSvgross 	any->ai_canonname = "*";
37792cb773aSvgross 
378c214498eSvgross 	switch (baddr->ai_family) {
379f80fdc7eSvgross 	case AF_INET:
380c214498eSvgross 		sin = (struct sockaddr_in *)baddr->ai_addr;
381c214498eSvgross 		if (!IN_MULTICAST( ntohl(sin->sin_addr.s_addr) )) {
382c214498eSvgross 			puts("executing unicast testsuite");
383c214498eSvgross 			return unicast_testsuite(baddr, any);
384c214498eSvgross 		}
385c214498eSvgross 		bmifa_s = argv[3];
386c214498eSvgross 		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
387c214498eSvgross 
388c214498eSvgross 		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
389c214498eSvgross 			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
390c214498eSvgross 			    gai_strerror(error));
391c214498eSvgross 
392c214498eSvgross 		local_imr.imr_interface =
393c214498eSvgross 		    ((struct sockaddr_in *)mifa->ai_addr)->sin_addr;
394c214498eSvgross 		local_imr.imr_multiaddr =
395c214498eSvgross 		    ((struct sockaddr_in *)baddr->ai_addr)->sin_addr;
396c214498eSvgross 
397c214498eSvgross 		puts("executing ipv4 multicast testsuite");
39892cb773aSvgross 
399f80fdc7eSvgross 		/* no 'any' mcast group in ipv4 */
400c214498eSvgross 		return mcast_reuse_testsuite(baddr, &local_imr);
401f80fdc7eSvgross 	case AF_INET6:
402c214498eSvgross 		sin6 = (struct sockaddr_in6 *)baddr->ai_addr;
403c214498eSvgross 		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
404c214498eSvgross 			puts("executing unicast testsuite");
405c214498eSvgross 			return unicast_testsuite(baddr, any);
406c214498eSvgross 		}
407c214498eSvgross 		bmifa_s = argv[3];
408c214498eSvgross 		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
409c214498eSvgross 
410c214498eSvgross 		if ((error = getaddrinfo(bmifa_s, NULL, &hints, &mifa)))
411c214498eSvgross 			errx(2, "getaddrinfo(%s,NULL): %s", bmifa_s,
412c214498eSvgross 			    gai_strerror(error));
413c214498eSvgross 
414f80fdc7eSvgross 		if (getifaddrs(&ifap))
415f80fdc7eSvgross 			err(2, "getifaddrs()");
416f80fdc7eSvgross 		curifa = ifap;
417f80fdc7eSvgross 		while (curifa) {
418a3bb2ea1Sbenno 			if (curifa->ifa_addr != NULL &&
419a3bb2ea1Sbenno 			    memcmp(curifa->ifa_addr,
420f80fdc7eSvgross 			    mifa->ai_addr,
421f80fdc7eSvgross 			    mifa->ai_addrlen) == 0)
422f80fdc7eSvgross 				break;
423f80fdc7eSvgross 			curifa = curifa->ifa_next;
424f80fdc7eSvgross 		}
425f80fdc7eSvgross 		if (curifa == NULL)
426f80fdc7eSvgross 			errx(2, "no interface configured with %s", argv[4]);
427f80fdc7eSvgross 		local_i6mr.ipv6mr_interface =
428f80fdc7eSvgross 		    if_nametoindex(curifa->ifa_name);
429f80fdc7eSvgross 		if (local_i6mr.ipv6mr_interface == 0)
430f80fdc7eSvgross 			errx(2, "unable to get \"%s\" index",
431f80fdc7eSvgross 			    curifa->ifa_name);
432f80fdc7eSvgross 		freeifaddrs(ifap);
433f80fdc7eSvgross 
434c214498eSvgross 		local_i6mr.ipv6mr_multiaddr =
435c214498eSvgross 		    ((struct sockaddr_in6 *)baddr->ai_addr)->sin6_addr;
436f80fdc7eSvgross 
437f80fdc7eSvgross 		any_i6mr.ipv6mr_interface = local_i6mr.ipv6mr_interface;
438c214498eSvgross 		any_i6mr.ipv6mr_multiaddr =
439c214498eSvgross 		    ((struct sockaddr_in6 *)any->ai_addr)->sin6_addr;
440c214498eSvgross 
441c214498eSvgross 		puts("executing ipv6 multicast testsuite");
442f80fdc7eSvgross 
443f80fdc7eSvgross 		rc = 0;
444c214498eSvgross 		rc |= mcast_reuse_testsuite(baddr, &local_i6mr);
445f80fdc7eSvgross 		if (geteuid() == 0)
446c214498eSvgross 			rc |= mcast6_testsuite(baddr, &local_i6mr, any, &any_i6mr);
447f80fdc7eSvgross 		else
448f80fdc7eSvgross 			warnx("skipping mcast6_testsuite() due to insufficient privs, please run again as root");
449f80fdc7eSvgross 		return (rc);
450f80fdc7eSvgross 	default:
451c214498eSvgross 		errx(2,"unknown AF");
452f80fdc7eSvgross 	}
453f80fdc7eSvgross 
454f80fdc7eSvgross 	return (2);
45592cb773aSvgross }
456