1303980Sngie/*	$NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $	*/
2303980Sngie
3303980Sngie/*-
4303980Sngie * Copyright (c) 2014 The NetBSD Foundation, Inc.
5303980Sngie * All rights reserved.
6303980Sngie *
7303980Sngie * This code is derived from software contributed to The NetBSD Foundation
8303980Sngie * by Christos Zoulas.
9303980Sngie *
10303980Sngie * Redistribution and use in source and binary forms, with or without
11303980Sngie * modification, are permitted provided that the following conditions
12303980Sngie * are met:
13303980Sngie * 1. Redistributions of source code must retain the above copyright
14303980Sngie *    notice, this list of conditions and the following disclaimer.
15303980Sngie * 2. Redistributions in binary form must reproduce the above copyright
16303980Sngie *    notice, this list of conditions and the following disclaimer in the
17303980Sngie *    documentation and/or other materials provided with the distribution.
18303980Sngie *
19303980Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20303980Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21303980Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22303980Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23303980Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24303980Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25303980Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26303980Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27303980Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28303980Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29303980Sngie * POSSIBILITY OF SUCH DAMAGE.
30303980Sngie */
31303980Sngie#include <sys/cdefs.h>
32303980Sngie#ifdef __RCSID
33303980Sngie__RCSID("$NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $");
34303980Sngie#else
35303980Sngieextern const char *__progname;
36303980Sngie#define getprogname() __progname
37303980Sngie#endif
38303980Sngie
39303980Sngie#include <sys/types.h>
40303980Sngie#include <sys/socket.h>
41303980Sngie#include <sys/wait.h>
42303980Sngie#include <sys/time.h>
43303980Sngie#include <netinet/in.h>
44303980Sngie
45303980Sngie#include <assert.h>
46303980Sngie#include <netdb.h>
47303980Sngie#include <time.h>
48303980Sngie#include <signal.h>
49303980Sngie#include <stdio.h>
50303980Sngie#include <string.h>
51303980Sngie#include <stdlib.h>
52303980Sngie#include <unistd.h>
53303980Sngie#include <err.h>
54303980Sngie#include <errno.h>
55303980Sngie#include <poll.h>
56303980Sngie#include <stdbool.h>
57303980Sngie
58303980Sngie#ifdef ATF
59303980Sngie#include <atf-c.h>
60303980Sngie
61303980Sngie#define ERRX(ev, msg, ...)	ATF_REQUIRE_MSG(0, msg, __VA_ARGS__)
62303980Sngie#define ERRX0(ev, msg)		ATF_REQUIRE_MSG(0, msg)
63303980Sngie
64303980Sngie#define SKIPX(ev, msg, ...)	do {			\
65303980Sngie	atf_tc_skip(msg, __VA_ARGS__);			\
66303980Sngie	return;						\
67303980Sngie} while(/*CONSTCOND*/0)
68303980Sngie
69303980Sngie#else
70303980Sngie#define ERRX(ev, msg, ...)	errx(ev, msg, __VA_ARGS__)
71303980Sngie#define ERRX0(ev, msg)		errx(ev, msg)
72303980Sngie#define SKIPX(ev, msg, ...)	errx(ev, msg, __VA_ARGS__)
73303980Sngie#endif
74303980Sngie
75303980Sngiestatic int debug;
76303980Sngie
77303980Sngie#define TOTAL 10
78303980Sngie#define PORT_V4MAPPED "6666"
79303980Sngie#define HOST_V4MAPPED "::FFFF:239.1.1.1"
80303980Sngie#define PORT_V4 "6666"
81303980Sngie#define HOST_V4 "239.1.1.1"
82303980Sngie#define PORT_V6 "6666"
83303980Sngie#define HOST_V6 "FF05:1:0:0:0:0:0:1"
84303980Sngie
85303980Sngiestruct message {
86303980Sngie	size_t seq;
87303980Sngie	struct timespec ts;
88303980Sngie};
89303980Sngie
90303980Sngiestatic int
91303980Sngieaddmc(int s, struct addrinfo *ai, bool bug)
92303980Sngie{
93303980Sngie	struct ip_mreq m4;
94303980Sngie	struct ipv6_mreq m6;
95303980Sngie	struct sockaddr_in *s4;
96303980Sngie	struct sockaddr_in6 *s6;
97303980Sngie	unsigned int ifc;
98303980Sngie
99303980Sngie	switch (ai->ai_family) {
100303980Sngie	case AF_INET:
101303980Sngie		s4 = (void *)ai->ai_addr;
102303980Sngie		assert(sizeof(*s4) == ai->ai_addrlen);
103303980Sngie		m4.imr_multiaddr = s4->sin_addr;
104303980Sngie		m4.imr_interface.s_addr = htonl(INADDR_ANY);
105303980Sngie		return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
106303980Sngie		    &m4, sizeof(m4));
107303980Sngie	case AF_INET6:
108303980Sngie		s6 = (void *)ai->ai_addr;
109303980Sngie		/*
110303980Sngie		 * Linux:	Does not support the v6 ioctls on v4 mapped
111303980Sngie		 *		sockets but it does support the v4 ones and
112303980Sngie		 *		it works.
113303980Sngie		 * MacOS/X:	Supports the v6 ioctls on v4 mapped sockets,
114303980Sngie		 *		but does not work and also does not support
115303980Sngie		 *		the v4 ioctls. So no way to make multicasting
116303980Sngie		 *		work with mapped addresses.
117303980Sngie		 * NetBSD:	Supports both and works for both.
118303980Sngie		 */
119303980Sngie		if (bug && IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) {
120303980Sngie			memcpy(&m4.imr_multiaddr, &s6->sin6_addr.s6_addr[12],
121303980Sngie			    sizeof(m4.imr_multiaddr));
122303980Sngie			m4.imr_interface.s_addr = htonl(INADDR_ANY);
123303980Sngie			return setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
124303980Sngie			    &m4, sizeof(m4));
125303980Sngie		}
126303980Sngie		assert(sizeof(*s6) == ai->ai_addrlen);
127303980Sngie		memset(&m6, 0, sizeof(m6));
128303980Sngie#if 0
129303980Sngie		ifc = 1;
130303980Sngie		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
131303980Sngie		    &ifc, sizeof(ifc)) == -1)
132303980Sngie			return -1;
133303980Sngie		ifc = 224;
134303980Sngie		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
135303980Sngie		    &ifc, sizeof(ifc)) == -1)
136303980Sngie			return -1;
137303980Sngie		ifc = 1; /* XXX should pick a proper interface */
138303980Sngie		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifc,
139303980Sngie		    sizeof(ifc)) == -1)
140303980Sngie			return -1;
141303980Sngie#else
142303980Sngie		ifc = 0; /* Let pick an appropriate interface */
143303980Sngie#endif
144303980Sngie		m6.ipv6mr_interface = ifc;
145303980Sngie		m6.ipv6mr_multiaddr = s6->sin6_addr;
146303980Sngie		return setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
147303980Sngie		    &m6, sizeof(m6));
148303980Sngie	default:
149303980Sngie		errno = EOPNOTSUPP;
150303980Sngie		return -1;
151303980Sngie	}
152303980Sngie}
153303980Sngie
154303980Sngiestatic int
155303980Sngieallowv4mapped(int s, struct addrinfo *ai)
156303980Sngie{
157303980Sngie	struct sockaddr_in6 *s6;
158303980Sngie	int zero = 0;
159303980Sngie
160303980Sngie	if (ai->ai_family != AF_INET6)
161303980Sngie		return 0;
162303980Sngie
163303980Sngie	s6 = (void *)ai->ai_addr;
164303980Sngie
165303980Sngie	if (!IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
166303980Sngie		return 0;
167303980Sngie	return setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
168303980Sngie}
169303980Sngie
170303980Sngiestatic struct sockaddr_storage ss;
171303980Sngiestatic int
172303980Sngieconnector(int fd, const struct sockaddr *sa, socklen_t slen)
173303980Sngie{
174303980Sngie	assert(sizeof(ss) > slen);
175303980Sngie	memcpy(&ss, sa, slen);
176303980Sngie	return 0;
177303980Sngie}
178303980Sngie
179303980Sngiestatic void
180303980Sngieshow(const char *prefix, const struct message *msg)
181303980Sngie{
182303980Sngie	printf("%10.10s: %zu [%jd.%ld]\n", prefix, msg->seq, (intmax_t)
183303980Sngie	    msg->ts.tv_sec, msg->ts.tv_nsec);
184303980Sngie}
185303980Sngie
186303980Sngiestatic int
187303980Sngiegetsocket(const char *host, const char *port,
188303980Sngie    int (*f)(int, const struct sockaddr *, socklen_t), socklen_t *slen,
189303980Sngie    bool bug)
190303980Sngie{
191303980Sngie	int e, s, lasterrno = 0;
192303980Sngie	struct addrinfo hints, *ai0, *ai;
193303980Sngie	const char *cause = "?";
194303980Sngie
195303980Sngie	memset(&hints, 0, sizeof(hints));
196303980Sngie	hints.ai_family = AF_UNSPEC;
197303980Sngie	hints.ai_socktype = SOCK_DGRAM;
198303980Sngie	e = getaddrinfo(host, port, &hints, &ai0);
199303980Sngie	if (e)
200303980Sngie		ERRX(EXIT_FAILURE, "Can't resolve %s:%s (%s)", host, port,
201303980Sngie		    gai_strerror(e));
202303980Sngie
203303980Sngie	s = -1;
204303980Sngie	for (ai = ai0; ai; ai = ai->ai_next) {
205303980Sngie		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
206303980Sngie		if (s == -1) {
207303980Sngie			lasterrno = errno;
208303980Sngie			cause = "socket";
209303980Sngie			continue;
210303980Sngie		}
211303980Sngie		if (allowv4mapped(s, ai) == -1) {
212303980Sngie			cause = "allow v4 mapped";
213303980Sngie			goto out;
214303980Sngie		}
215303980Sngie		if ((*f)(s, ai->ai_addr, ai->ai_addrlen) == -1) {
216303980Sngie			cause = f == bind ? "bind" : "connect";
217303980Sngie			goto out;
218303980Sngie		}
219303980Sngie		if ((f == bind || f == connector) && addmc(s, ai, bug) == -1) {
220303980Sngie			cause = "join group";
221303980Sngie			goto out;
222303980Sngie		}
223303980Sngie		*slen = ai->ai_addrlen;
224303980Sngie		break;
225303980Sngieout:
226303980Sngie		lasterrno = errno;
227303980Sngie		close(s);
228303980Sngie		s = -1;
229303980Sngie		continue;
230303980Sngie	}
231303980Sngie	freeaddrinfo(ai0);
232303980Sngie	if (s == -1)
233303980Sngie		ERRX(EXIT_FAILURE, "%s (%s)", cause, strerror(lasterrno));
234303980Sngie	return s;
235303980Sngie}
236303980Sngie
237303980Sngiestatic int
238303980Sngiesynchronize(const int fd, bool waiter)
239303980Sngie{
240303980Sngie	int syncmsg = 0;
241303980Sngie	int r;
242303980Sngie	struct pollfd pfd;
243303980Sngie
244303980Sngie	if (waiter) {
245303980Sngie		pfd.fd = fd;
246303980Sngie		pfd.events = POLLIN;
247303980Sngie
248303980Sngie		/* We use poll to avoid lock up when the peer died unexpectedly */
249303980Sngie		r = poll(&pfd, 1, 10000);
250303980Sngie		if (r == -1)
251303980Sngie			ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno));
252303980Sngie		if (r == 0)
253303980Sngie			/* Timed out */
254303980Sngie			return -1;
255303980Sngie
256303980Sngie		if (read(fd, &syncmsg, sizeof(syncmsg)) == -1)
257303980Sngie			ERRX(EXIT_FAILURE, "read (%s)", strerror(errno));
258303980Sngie	} else {
259303980Sngie		if (write(fd, &syncmsg, sizeof(syncmsg)) == -1)
260303980Sngie			ERRX(EXIT_FAILURE, "write (%s)", strerror(errno));
261303980Sngie	}
262303980Sngie
263303980Sngie	return 0;
264303980Sngie}
265303980Sngie
266303980Sngiestatic int
267303980Sngiesender(const int fd, const char *host, const char *port, size_t n, bool conn,
268303980Sngie    bool bug)
269303980Sngie{
270303980Sngie	int s;
271303980Sngie	ssize_t l;
272303980Sngie	struct message msg;
273303980Sngie
274303980Sngie	socklen_t slen;
275303980Sngie
276303980Sngie	s = getsocket(host, port, conn ? connect : connector, &slen, bug);
277303980Sngie
278303980Sngie	/* Wait until receiver gets ready. */
279303980Sngie	if (synchronize(fd, true) == -1)
280303980Sngie		return -1;
281303980Sngie
282303980Sngie	for (msg.seq = 0; msg.seq < n; msg.seq++) {
283303980Sngie#ifdef CLOCK_MONOTONIC
284303980Sngie		if (clock_gettime(CLOCK_MONOTONIC, &msg.ts) == -1)
285303980Sngie			ERRX(EXIT_FAILURE, "clock (%s)", strerror(errno));
286303980Sngie#else
287303980Sngie		struct timeval tv;
288303980Sngie		if (gettimeofday(&tv, NULL) == -1)
289303980Sngie			ERRX(EXIT_FAILURE, "clock (%s)", strerror(errno));
290303980Sngie		msg.ts.tv_sec = tv.tv_sec;
291303980Sngie		msg.ts.tv_nsec = tv.tv_usec * 1000;
292303980Sngie#endif
293303980Sngie		if (debug)
294303980Sngie			show("sending", &msg);
295303980Sngie		l = conn ? send(s, &msg, sizeof(msg), 0) :
296303980Sngie		    sendto(s, &msg, sizeof(msg), 0, (void *)&ss, slen);
297303980Sngie		if (l == -1)
298303980Sngie			ERRX(EXIT_FAILURE, "send (%s)", strerror(errno));
299303980Sngie		usleep(100);
300303980Sngie	}
301303980Sngie
302303980Sngie	/* Wait until receiver finishes its work. */
303303980Sngie	if (synchronize(fd, true) == -1)
304303980Sngie		return -1;
305303980Sngie
306303980Sngie	return 0;
307303980Sngie}
308303980Sngie
309303980Sngiestatic void
310303980Sngiereceiver(const int fd, const char *host, const char *port, size_t n, bool conn,
311303980Sngie    bool bug)
312303980Sngie{
313303980Sngie	int s;
314303980Sngie	ssize_t l;
315303980Sngie	size_t seq;
316303980Sngie	struct message msg;
317303980Sngie	struct pollfd pfd;
318303980Sngie	socklen_t slen;
319303980Sngie
320303980Sngie	s = getsocket(host, port, bind, &slen, bug);
321303980Sngie	pfd.fd = s;
322303980Sngie	pfd.events = POLLIN;
323303980Sngie
324303980Sngie	/* Tell I'm ready */
325303980Sngie	synchronize(fd, false);
326303980Sngie
327303980Sngie	for (seq = 0; seq < n; seq++) {
328303980Sngie		if (poll(&pfd, 1, 10000) == -1)
329303980Sngie			ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno));
330303980Sngie		l = conn ? recv(s, &msg, sizeof(msg), 0) :
331303980Sngie		    recvfrom(s, &msg, sizeof(msg), 0, (void *)&ss, &slen);
332303980Sngie		if (l == -1)
333303980Sngie			ERRX(EXIT_FAILURE, "recv (%s)", strerror(errno));
334303980Sngie		if (debug)
335303980Sngie			show("got", &msg);
336303980Sngie		if (seq != msg.seq)
337303980Sngie			ERRX(EXIT_FAILURE, "seq: expect=%zu actual=%zu",
338303980Sngie			    seq, msg.seq);
339303980Sngie	}
340303980Sngie
341303980Sngie	/* Tell I'm finished */
342303980Sngie	synchronize(fd, false);
343303980Sngie}
344303980Sngie
345303980Sngiestatic void
346303980Sngierun(const char *host, const char *port, size_t n, bool conn, bool bug)
347303980Sngie{
348303980Sngie	pid_t pid;
349303980Sngie	int status;
350303980Sngie	int syncfds[2];
351303980Sngie	int error;
352303980Sngie
353303980Sngie	if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfds) == -1)
354303980Sngie		ERRX(EXIT_FAILURE, "socketpair (%s)", strerror(errno));
355303980Sngie
356303980Sngie	switch ((pid = fork())) {
357303980Sngie	case 0:
358303980Sngie		receiver(syncfds[0], host, port, n, conn, bug);
359303980Sngie		return;
360303980Sngie	case -1:
361303980Sngie		ERRX(EXIT_FAILURE, "fork (%s)", strerror(errno));
362303980Sngie	default:
363303980Sngie		error = sender(syncfds[1], host, port, n, conn, bug);
364303980Sngie	again:
365303980Sngie		switch (waitpid(pid, &status, WNOHANG)) {
366303980Sngie		case -1:
367303980Sngie			ERRX(EXIT_FAILURE, "wait (%s)", strerror(errno));
368303980Sngie		case 0:
369303980Sngie			if (error == 0)
370303980Sngie				/*
371303980Sngie				 * Receiver is still alive, but we know
372303980Sngie				 * it will exit soon.
373303980Sngie				 */
374303980Sngie				goto again;
375303980Sngie
376303980Sngie			if (kill(pid, SIGTERM) == -1)
377303980Sngie				ERRX(EXIT_FAILURE, "kill (%s)",
378303980Sngie				    strerror(errno));
379303980Sngie			goto again;
380303980Sngie		default:
381303980Sngie			if (WIFSIGNALED(status)) {
382303980Sngie				if (WTERMSIG(status) == SIGTERM)
383303980Sngie					ERRX0(EXIT_FAILURE,
384303980Sngie					    "receiver failed and was killed" \
385303980Sngie					    "by sender");
386303980Sngie				else
387303980Sngie					ERRX(EXIT_FAILURE,
388303980Sngie					    "receiver got signaled (%s)",
389303980Sngie					    strsignal(WTERMSIG(status)));
390303980Sngie			} else if (WIFEXITED(status)) {
391303980Sngie				if (WEXITSTATUS(status) != 0)
392303980Sngie					ERRX(EXIT_FAILURE,
393303980Sngie					    "receiver exited with status %d",
394303980Sngie					    WEXITSTATUS(status));
395303980Sngie			} else {
396303980Sngie				ERRX(EXIT_FAILURE,
397303980Sngie				    "receiver exited with unexpected status %d",
398303980Sngie				    status);
399303980Sngie			}
400303980Sngie			break;
401303980Sngie		}
402303980Sngie		return;
403303980Sngie	}
404303980Sngie}
405303980Sngie
406303980Sngie#ifndef ATF
407303980Sngieint
408303980Sngiemain(int argc, char *argv[])
409303980Sngie{
410303980Sngie	const char *host, *port;
411303980Sngie	int c;
412303980Sngie	size_t n;
413303980Sngie	bool conn, bug;
414303980Sngie
415303980Sngie	host = HOST_V4;
416303980Sngie	port = PORT_V4;
417303980Sngie	n = TOTAL;
418303980Sngie	bug = conn = false;
419303980Sngie
420303980Sngie	while ((c = getopt(argc, argv, "46bcdmn:")) != -1)
421303980Sngie		switch (c) {
422303980Sngie		case '4':
423303980Sngie			host = HOST_V4;
424303980Sngie			port = PORT_V4;
425303980Sngie			break;
426303980Sngie		case '6':
427303980Sngie			host = HOST_V6;
428303980Sngie			port = PORT_V6;
429303980Sngie			break;
430303980Sngie		case 'b':
431303980Sngie			bug = true;
432303980Sngie			break;
433303980Sngie		case 'c':
434303980Sngie			conn = true;
435303980Sngie			break;
436303980Sngie		case 'd':
437303980Sngie			debug++;
438303980Sngie			break;
439303980Sngie		case 'm':
440303980Sngie			host = HOST_V4MAPPED;
441303980Sngie			port = PORT_V4MAPPED;
442303980Sngie			break;
443303980Sngie		case 'n':
444303980Sngie			n = atoi(optarg);
445303980Sngie			break;
446303980Sngie		default:
447303980Sngie			fprintf(stderr, "Usage: %s [-cdm46] [-n <tot>]",
448303980Sngie			    getprogname());
449303980Sngie			return 1;
450303980Sngie		}
451303980Sngie
452303980Sngie	run(host, port, n, conn, bug);
453303980Sngie	return 0;
454303980Sngie}
455303980Sngie#else
456303980Sngie
457303980SngieATF_TC(conninet4);
458303980SngieATF_TC_HEAD(conninet4, tc)
459303980Sngie{
460303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for ipv4");
461303980Sngie}
462303980Sngie
463303980SngieATF_TC_BODY(conninet4, tc)
464303980Sngie{
465303980Sngie	run(HOST_V4, PORT_V4, TOTAL, true, false);
466303980Sngie}
467303980Sngie
468303980SngieATF_TC(connmappedinet4);
469303980SngieATF_TC_HEAD(connmappedinet4, tc)
470303980Sngie{
471303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for mapped ipv4");
472303980Sngie}
473303980Sngie
474303980SngieATF_TC_BODY(connmappedinet4, tc)
475303980Sngie{
476303980Sngie	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, true, false);
477303980Sngie}
478303980Sngie
479303980SngieATF_TC(connmappedbuginet4);
480303980SngieATF_TC_HEAD(connmappedbuginet4, tc)
481303980Sngie{
482303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for mapped ipv4 using the v4 ioctls");
483303980Sngie}
484303980Sngie
485303980SngieATF_TC_BODY(connmappedbuginet4, tc)
486303980Sngie{
487303980Sngie	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, true, true);
488303980Sngie}
489303980Sngie
490303980SngieATF_TC(conninet6);
491303980SngieATF_TC_HEAD(conninet6, tc)
492303980Sngie{
493303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks connected multicast for ipv6");
494303980Sngie}
495303980Sngie
496303980SngieATF_TC_BODY(conninet6, tc)
497303980Sngie{
498303980Sngie	run(HOST_V6, PORT_V6, TOTAL, true, false);
499303980Sngie}
500303980Sngie
501303980SngieATF_TC(unconninet4);
502303980SngieATF_TC_HEAD(unconninet4, tc)
503303980Sngie{
504303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for ipv4");
505303980Sngie}
506303980Sngie
507303980SngieATF_TC_BODY(unconninet4, tc)
508303980Sngie{
509303980Sngie	run(HOST_V4, PORT_V4, TOTAL, false, false);
510303980Sngie}
511303980Sngie
512303980SngieATF_TC(unconnmappedinet4);
513303980SngieATF_TC_HEAD(unconnmappedinet4, tc)
514303980Sngie{
515303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for mapped ipv4");
516303980Sngie}
517303980Sngie
518303980SngieATF_TC_BODY(unconnmappedinet4, tc)
519303980Sngie{
520303980Sngie	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, false, false);
521303980Sngie}
522303980Sngie
523303980SngieATF_TC(unconnmappedbuginet4);
524303980SngieATF_TC_HEAD(unconnmappedbuginet4, tc)
525303980Sngie{
526303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for mapped ipv4 using the v4 ioctls");
527303980Sngie}
528303980Sngie
529303980SngieATF_TC_BODY(unconnmappedbuginet4, tc)
530303980Sngie{
531303980Sngie	run(HOST_V4MAPPED, PORT_V4MAPPED, TOTAL, false, true);
532303980Sngie}
533303980Sngie
534303980SngieATF_TC(unconninet6);
535303980SngieATF_TC_HEAD(unconninet6, tc)
536303980Sngie{
537303980Sngie	atf_tc_set_md_var(tc, "descr", "Checks unconnected multicast for ipv6");
538303980Sngie}
539303980Sngie
540303980SngieATF_TC_BODY(unconninet6, tc)
541303980Sngie{
542303980Sngie	run(HOST_V6, PORT_V6, TOTAL, false, false);
543303980Sngie}
544303980Sngie
545303980SngieATF_TP_ADD_TCS(tp)
546303980Sngie{
547303980Sngie	debug++;
548303980Sngie	ATF_TP_ADD_TC(tp, conninet4);
549303980Sngie	ATF_TP_ADD_TC(tp, connmappedinet4);
550303980Sngie	ATF_TP_ADD_TC(tp, connmappedbuginet4);
551303980Sngie	ATF_TP_ADD_TC(tp, conninet6);
552303980Sngie	ATF_TP_ADD_TC(tp, unconninet4);
553303980Sngie	ATF_TP_ADD_TC(tp, unconnmappedinet4);
554303980Sngie	ATF_TP_ADD_TC(tp, unconnmappedbuginet4);
555303980Sngie	ATF_TP_ADD_TC(tp, unconninet6);
556303980Sngie
557303980Sngie	return atf_no_error();
558303980Sngie}
559303980Sngie#endif
560