mld6.c revision 96116
166458Sdfr/*	$FreeBSD: head/sys/netinet6/mld6.c 96116 2002-05-06 16:28:25Z ume $	*/
266458Sdfr/*	$KAME: mld6.c,v 1.27 2001/04/04 05:17:30 itojun Exp $	*/
366458Sdfr
466458Sdfr/*
566458Sdfr * Copyright (C) 1998 WIDE Project.
666458Sdfr * All rights reserved.
766458Sdfr *
866458Sdfr * Redistribution and use in source and binary forms, with or without
966458Sdfr * modification, are permitted provided that the following conditions
1066458Sdfr * are met:
1166458Sdfr * 1. Redistributions of source code must retain the above copyright
1266458Sdfr *    notice, this list of conditions and the following disclaimer.
1366458Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1466458Sdfr *    notice, this list of conditions and the following disclaimer in the
1566458Sdfr *    documentation and/or other materials provided with the distribution.
1666458Sdfr * 3. Neither the name of the project nor the names of its contributors
1766458Sdfr *    may be used to endorse or promote products derived from this software
1866458Sdfr *    without specific prior written permission.
1966458Sdfr *
2066458Sdfr * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2166458Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2266458Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2366458Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2466458Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2566458Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2666458Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2766458Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2866458Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2966458Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3066458Sdfr * SUCH DAMAGE.
3166458Sdfr */
3266458Sdfr
3366458Sdfr/*
3466458Sdfr * Copyright (c) 1988 Stephen Deering.
3566458Sdfr * Copyright (c) 1992, 1993
3666458Sdfr *	The Regents of the University of California.  All rights reserved.
3766458Sdfr *
3866458Sdfr * This code is derived from software contributed to Berkeley by
3966458Sdfr * Stephen Deering of Stanford University.
4066458Sdfr *
4166458Sdfr * Redistribution and use in source and binary forms, with or without
4266458Sdfr * modification, are permitted provided that the following conditions
4366458Sdfr * are met:
4466458Sdfr * 1. Redistributions of source code must retain the above copyright
4566458Sdfr *    notice, this list of conditions and the following disclaimer.
4666458Sdfr * 2. Redistributions in binary form must reproduce the above copyright
4766458Sdfr *    notice, this list of conditions and the following disclaimer in the
4866458Sdfr *    documentation and/or other materials provided with the distribution.
4966458Sdfr * 3. All advertising materials mentioning features or use of this software
5066458Sdfr *    must display the following acknowledgement:
5166458Sdfr *	This product includes software developed by the University of
5266458Sdfr *	California, Berkeley and its contributors.
5366458Sdfr * 4. Neither the name of the University nor the names of its contributors
5466458Sdfr *    may be used to endorse or promote products derived from this software
5566458Sdfr *    without specific prior written permission.
5666458Sdfr *
5766458Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5866458Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5966458Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6066458Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6166458Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6266458Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6366458Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6466458Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6566458Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6666458Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6766458Sdfr * SUCH DAMAGE.
6866458Sdfr *
6966458Sdfr *	@(#)igmp.c	8.1 (Berkeley) 7/19/93
7066458Sdfr */
7166458Sdfr
7266458Sdfr#include "opt_inet.h"
7366458Sdfr#include "opt_inet6.h"
7466458Sdfr
7566458Sdfr#include <sys/param.h>
7666458Sdfr#include <sys/systm.h>
7766458Sdfr#include <sys/mbuf.h>
7866458Sdfr#include <sys/socket.h>
7966458Sdfr#include <sys/protosw.h>
8066458Sdfr#include <sys/syslog.h>
8166458Sdfr
8266458Sdfr#include <net/if.h>
8366458Sdfr
8466458Sdfr#include <netinet/in.h>
8566458Sdfr#include <netinet/in_var.h>
8666458Sdfr#include <netinet/ip6.h>
8766458Sdfr#include <netinet6/ip6_var.h>
8866458Sdfr#include <netinet/icmp6.h>
8966458Sdfr#include <netinet6/mld6_var.h>
9066458Sdfr
9166458Sdfr#include <net/net_osdep.h>
9266458Sdfr
9366458Sdfr/*
9466458Sdfr * Protocol constants
9566458Sdfr */
9666458Sdfr
9777448Sjhb/* denotes that the MLD max response delay field specifies time in milliseconds */
9877448Sjhb#define MLD6_TIMER_SCALE	1000
9977448Sjhb/*
10077448Sjhb * time between repetitions of a node's initial report of interest in a
10177448Sjhb * multicast address(in seconds)
10277448Sjhb */
10377448Sjhb#define MLD6_UNSOLICITED_REPORT_INTERVAL	10
10477448Sjhb
10566458Sdfrstatic struct ip6_pktopts ip6_opts;
10666458Sdfrstatic int mld6_timers_are_running;
10766458Sdfr/* XXX: These are necessary for KAME's link-local hack */
10866458Sdfrstatic struct in6_addr mld6_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
10966458Sdfrstatic struct in6_addr mld6_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
11066458Sdfr
11166458Sdfrstatic void mld6_sendpkt __P((struct in6_multi *, int, const struct in6_addr *));
11266458Sdfr
11366458Sdfrvoid
11466458Sdfrmld6_init()
11566458Sdfr{
11666458Sdfr	static u_int8_t hbh_buf[8];
11766458Sdfr	struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf;
11866458Sdfr	u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD);
11966458Sdfr
12066458Sdfr	mld6_timers_are_running = 0;
12166458Sdfr
12266458Sdfr	/* ip6h_nxt will be fill in later */
12367017Sdfr	hbh->ip6h_len = 0;	/* (8 >> 3) - 1 */
12467017Sdfr
12566458Sdfr	/* XXX: grotty hard coding... */
12666458Sdfr	hbh_buf[2] = IP6OPT_PADN;	/* 2 byte padding */
12766458Sdfr	hbh_buf[3] = 0;
12866458Sdfr	hbh_buf[4] = IP6OPT_RTALERT;
12966458Sdfr	hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
13066458Sdfr	bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));
13166458Sdfr
13266458Sdfr	init_ip6pktopts(&ip6_opts);
13366458Sdfr	ip6_opts.ip6po_hbh = hbh;
13466458Sdfr}
13566458Sdfr
13666458Sdfrvoid
13766458Sdfrmld6_start_listening(in6m)
13866458Sdfr	struct in6_multi *in6m;
13966458Sdfr{
14066458Sdfr	int s = splnet();
14166458Sdfr
14266458Sdfr	/*
14366458Sdfr	 * RFC2710 page 10:
14466458Sdfr	 * The node never sends a Report or Done for the link-scope all-nodes
14566458Sdfr	 * address.
14666458Sdfr	 * MLD messages are never sent for multicast addresses whose scope is 0
14766458Sdfr	 * (reserved) or 1 (node-local).
14866458Sdfr	 */
14966458Sdfr	mld6_all_nodes_linklocal.s6_addr16[1] =
15066458Sdfr		htons(in6m->in6m_ifp->if_index); /* XXX */
15166458Sdfr	if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal) ||
15266458Sdfr	    IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) {
15366458Sdfr		in6m->in6m_timer = 0;
15466458Sdfr		in6m->in6m_state = MLD6_OTHERLISTENER;
15566458Sdfr	} else {
15666458Sdfr		mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
15766458Sdfr		in6m->in6m_timer = MLD6_RANDOM_DELAY(
15866458Sdfr			MLD6_UNSOLICITED_REPORT_INTERVAL * PR_FASTHZ);
15966458Sdfr		in6m->in6m_state = MLD6_IREPORTEDLAST;
16066458Sdfr		mld6_timers_are_running = 1;
16166458Sdfr	}
16266458Sdfr	splx(s);
16366458Sdfr}
16466458Sdfr
16566458Sdfrvoid
16666458Sdfrmld6_stop_listening(in6m)
16766458Sdfr	struct in6_multi *in6m;
16866458Sdfr{
16966458Sdfr	mld6_all_nodes_linklocal.s6_addr16[1] =
17066458Sdfr		htons(in6m->in6m_ifp->if_index); /* XXX */
17166458Sdfr	mld6_all_routers_linklocal.s6_addr16[1] =
17266458Sdfr		htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */
17366458Sdfr
17466458Sdfr	if (in6m->in6m_state == MLD6_IREPORTEDLAST &&
17566458Sdfr	    (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal)) &&
17666458Sdfr	    IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL)
17766458Sdfr		mld6_sendpkt(in6m, MLD_LISTENER_DONE,
17866458Sdfr			     &mld6_all_routers_linklocal);
17966458Sdfr}
18066458Sdfr
18166458Sdfrvoid
18266458Sdfrmld6_input(m, off)
18366458Sdfr	struct mbuf *m;
18466458Sdfr	int off;
18566458Sdfr{
18666458Sdfr	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
18766458Sdfr	struct mld_hdr *mldh;
18866458Sdfr	struct ifnet *ifp = m->m_pkthdr.rcvif;
18966458Sdfr	struct in6_multi *in6m;
19066458Sdfr	struct in6_ifaddr *ia;
19166458Sdfr	struct ifmultiaddr *ifma;
19266458Sdfr	int timer;		/* timer value in the MLD query header */
19366458Sdfr
19466458Sdfr#ifndef PULLDOWN_TEST
19566458Sdfr	IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
19666458Sdfr	mldh = (struct mld_hdr *)(mtod(m, caddr_t) + off);
19766458Sdfr#else
19866458Sdfr	IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
19966458Sdfr	if (mldh == NULL) {
20066458Sdfr		icmp6stat.icp6s_tooshort++;
20166458Sdfr		return;
20266458Sdfr	}
20366458Sdfr#endif
20466458Sdfr
20566937Sdfr	/* source address validation */
20666458Sdfr	ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
20766937Sdfr	if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
20866937Sdfr		log(LOG_ERR,
20966937Sdfr		    "mld6_input: src %s is not link-local (grp=%s)\n",
21066937Sdfr		    ip6_sprintf(&ip6->ip6_src),
21166937Sdfr		    ip6_sprintf(&mldh->mld_addr));
21266458Sdfr		/*
21366458Sdfr		 * spec (RFC2710) does not explicitly
21466937Sdfr		 * specify to discard the packet from a non link-local
21566937Sdfr		 * source address. But we believe it's expected to do so.
21666937Sdfr		 * XXX: do we have to allow :: as source?
21766937Sdfr		 */
21866937Sdfr		m_freem(m);
21966937Sdfr		return;
22066458Sdfr	}
22166458Sdfr
22266458Sdfr	/*
22366458Sdfr	 * In the MLD6 specification, there are 3 states and a flag.
22466458Sdfr	 *
22583366Sjulian	 * In Non-Listener state, we simply don't have a membership record.
22666458Sdfr	 * In Delaying Listener state, our timer is running (in6m->in6m_timer)
22766458Sdfr	 * In Idle Listener state, our timer is not running (in6m->in6m_timer==0)
22866458Sdfr	 *
22966458Sdfr	 * The flag is in6m->in6m_state, it is set to MLD6_OTHERLISTENER if
23066458Sdfr	 * we have heard a report from another member, or MLD6_IREPORTEDLAST
23166458Sdfr	 * if we sent the last report.
23266458Sdfr	 */
23366458Sdfr	switch(mldh->mld_type) {
23466458Sdfr	case MLD_LISTENER_QUERY:
23566458Sdfr		if (ifp->if_flags & IFF_LOOPBACK)
23666458Sdfr			break;
23766458Sdfr
23866458Sdfr		if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) &&
23966458Sdfr		    !IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
24066458Sdfr			break;	/* print error or log stat? */
24166458Sdfr		if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
24266458Sdfr			mldh->mld_addr.s6_addr16[1] =
24366458Sdfr				htons(ifp->if_index); /* XXX */
24466458Sdfr
24566458Sdfr		/*
24666458Sdfr		 * - Start the timers in all of our membership records
24766458Sdfr		 *   that the query applies to for the interface on
24866458Sdfr		 *   which the query arrived excl. those that belong
24966458Sdfr		 *   to the "all-nodes" group (ff02::1).
25066458Sdfr		 * - Restart any timer that is already running but has
25166458Sdfr		 *   A value longer than the requested timeout.
25266458Sdfr		 * - Use the value specified in the query message as
25366458Sdfr		 *   the maximum timeout.
25466458Sdfr		 */
25566458Sdfr		IFP_TO_IA6(ifp, ia);
25666458Sdfr		if (ia == NULL)
25766458Sdfr			break;
25866458Sdfr
25966458Sdfr		/*
26066458Sdfr		 * XXX: System timer resolution is too low to handle Max
26166458Sdfr		 * Response Delay, so set 1 to the internal timer even if
26266458Sdfr		 * the calculated value equals to zero when Max Response
26366458Sdfr		 * Delay is positive.
26466458Sdfr		 */
26566458Sdfr		timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE;
26666458Sdfr		if (timer == 0 && mldh->mld_maxdelay)
26766458Sdfr			timer = 1;
26866458Sdfr		mld6_all_nodes_linklocal.s6_addr16[1] =
26966458Sdfr			htons(ifp->if_index); /* XXX */
27066458Sdfr
27166458Sdfr		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
27266458Sdfr		{
27366458Sdfr			if (ifma->ifma_addr->sa_family != AF_INET6)
27466458Sdfr				continue;
27566937Sdfr			in6m = (struct in6_multi *)ifma->ifma_protospec;
27666937Sdfr			if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr,
27766937Sdfr					&mld6_all_nodes_linklocal) ||
27866458Sdfr			    IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
27966937Sdfr			    IPV6_ADDR_SCOPE_LINKLOCAL)
28066458Sdfr				continue;
28166458Sdfr
28266458Sdfr			if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) ||
28366458Sdfr			    IN6_ARE_ADDR_EQUAL(&mldh->mld_addr,
28466458Sdfr						&in6m->in6m_addr))
28566458Sdfr			{
28666458Sdfr				if (timer == 0) {
28766458Sdfr					/* send a report immediately */
28866458Sdfr					mld6_sendpkt(in6m, MLD_LISTENER_REPORT,
28966458Sdfr						NULL);
29066458Sdfr					in6m->in6m_timer = 0; /* reset timer */
29166458Sdfr					in6m->in6m_state = MLD6_IREPORTEDLAST;
29266458Sdfr				}
29366458Sdfr				else if (in6m->in6m_timer == 0 || /*idle state*/
29466458Sdfr					in6m->in6m_timer > timer) {
29566458Sdfr					in6m->in6m_timer =
29666458Sdfr						MLD6_RANDOM_DELAY(timer);
29766458Sdfr					mld6_timers_are_running = 1;
29866458Sdfr				}
29966937Sdfr			}
30066458Sdfr		}
30166458Sdfr
30266458Sdfr		if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
30366458Sdfr			mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
30466458Sdfr		break;
30566458Sdfr	case MLD_LISTENER_REPORT:
30666458Sdfr		/*
30766458Sdfr		 * For fast leave to work, we have to know that we are the
30866458Sdfr		 * last person to send a report for this group.  Reports
30966458Sdfr		 * can potentially get looped back if we are a multicast
31066458Sdfr		 * router, so discard reports sourced by me.
31166458Sdfr		 * Note that it is impossible to check IFF_LOOPBACK flag of
31266458Sdfr		 * ifp for this purpose, since ip6_mloopback pass the physical
31366458Sdfr		 * interface to looutput.
31466458Sdfr		 */
31566458Sdfr		if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
31666458Sdfr			break;
31766458Sdfr
31867017Sdfr		if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
31966458Sdfr			break;
32066458Sdfr
32166458Sdfr		if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
32266458Sdfr			mldh->mld_addr.s6_addr16[1] =
32383366Sjulian				htons(ifp->if_index); /* XXX */
32466458Sdfr		/*
32566458Sdfr		 * If we belong to the group being reported, stop
32666458Sdfr		 * our timer for that group.
32766458Sdfr		 */
32866458Sdfr		IN6_LOOKUP_MULTI(mldh->mld_addr, ifp, in6m);
32966458Sdfr		if (in6m) {
33066458Sdfr			in6m->in6m_timer = 0; /* transit to idle state */
33166458Sdfr			in6m->in6m_state = MLD6_OTHERLISTENER; /* clear flag */
33266458Sdfr		}
33366458Sdfr
33466458Sdfr		if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
33566458Sdfr			mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
33666458Sdfr		break;
33766458Sdfr	default:		/* this is impossible */
33866458Sdfr		log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld_type);
33966458Sdfr		break;
34066458Sdfr	}
34166458Sdfr
34266458Sdfr	m_freem(m);
34366458Sdfr}
34466458Sdfr
34566458Sdfrvoid
34666458Sdfrmld6_fasttimeo()
34766458Sdfr{
34866458Sdfr	struct in6_multi *in6m;
34966458Sdfr	struct in6_multistep step;
35066458Sdfr	int s;
35166458Sdfr
35266458Sdfr	/*
35366458Sdfr	 * Quick check to see if any work needs to be done, in order
35466458Sdfr	 * to minimize the overhead of fasttimo processing.
35566458Sdfr	 */
35666458Sdfr	if (!mld6_timers_are_running)
35766458Sdfr		return;
35866458Sdfr
35966458Sdfr	s = splnet();
36066458Sdfr	mld6_timers_are_running = 0;
36166458Sdfr	IN6_FIRST_MULTI(step, in6m);
36266458Sdfr	while (in6m != NULL) {
36366458Sdfr		if (in6m->in6m_timer == 0) {
36466458Sdfr			/* do nothing */
36566458Sdfr		} else if (--in6m->in6m_timer == 0) {
36666458Sdfr			mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
36766458Sdfr			in6m->in6m_state = MLD6_IREPORTEDLAST;
36866458Sdfr		} else {
36966458Sdfr			mld6_timers_are_running = 1;
37066458Sdfr		}
37166458Sdfr		IN6_NEXT_MULTI(step, in6m);
37266458Sdfr	}
37366458Sdfr	splx(s);
37466458Sdfr}
37566458Sdfr
37666458Sdfrstatic void
37766458Sdfrmld6_sendpkt(in6m, type, dst)
37866458Sdfr	struct in6_multi *in6m;
37966458Sdfr	int type;
38080431Speter	const struct in6_addr *dst;
38180431Speter{
38280431Speter	struct mbuf *mh, *md;
38380431Speter	struct mld_hdr *mldh;
38466458Sdfr	struct ip6_hdr *ip6;
38566458Sdfr	struct ip6_moptions im6o;
38666458Sdfr	struct in6_ifaddr *ia;
38766458Sdfr	struct ifnet *ifp = in6m->in6m_ifp;
38866458Sdfr	struct ifnet *outif = NULL;
38966458Sdfr
39066458Sdfr	/*
39166458Sdfr	 * At first, find a link local address on the outgoing interface
39266458Sdfr	 * to use as the source address of the MLD packet.
39366458Sdfr	 */
39466937Sdfr	if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
39566458Sdfr	    == NULL)
39666937Sdfr		return;
39766937Sdfr
39866937Sdfr	/*
39966937Sdfr	 * Allocate mbufs to store ip6 header and MLD header.
40066937Sdfr	 * We allocate 2 mbufs and make chain in advance because
40166937Sdfr	 * it is more convenient when inserting the hop-by-hop option later.
40266458Sdfr	 */
40366458Sdfr	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
40466458Sdfr	if (mh == NULL)
40566458Sdfr		return;
40666458Sdfr	MGET(md, M_DONTWAIT, MT_DATA);
40775668Sdfr	if (md == NULL) {
40866937Sdfr		m_free(mh);
40966937Sdfr		return;
41066458Sdfr	}
41166458Sdfr	mh->m_next = md;
41266458Sdfr
41366458Sdfr	mh->m_pkthdr.rcvif = NULL;
41466458Sdfr	mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
41566937Sdfr	mh->m_len = sizeof(struct ip6_hdr);
41666937Sdfr	MH_ALIGN(mh, sizeof(struct ip6_hdr));
41774903Sjhb
41866937Sdfr	/* fill in the ip6 header */
41975668Sdfr	ip6 = mtod(mh, struct ip6_hdr *);
42066937Sdfr	ip6->ip6_flow = 0;
42166937Sdfr	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
42274903Sjhb	ip6->ip6_vfc |= IPV6_VERSION;
42366937Sdfr	/* ip6_plen will be set later */
42466937Sdfr	ip6->ip6_nxt = IPPROTO_ICMPV6;
42566937Sdfr	/* ip6_hlim will be set by im6o.im6o_multicast_hlim */
42666937Sdfr	ip6->ip6_src = ia->ia_addr.sin6_addr;
42766937Sdfr	ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
42866937Sdfr
42966937Sdfr	/* fill in the MLD header */
43066937Sdfr	md->m_len = sizeof(struct mld_hdr);
43174903Sjhb	mldh = mtod(md, struct mld_hdr *);
43266458Sdfr	mldh->mld_type = type;
43366458Sdfr	mldh->mld_code = 0;
43466458Sdfr	mldh->mld_cksum = 0;
43566937Sdfr	/* XXX: we assume the function will not be called for query messages */
43666458Sdfr	mldh->mld_maxdelay = 0;
43766937Sdfr	mldh->mld_reserved = 0;
43866937Sdfr	mldh->mld_addr = in6m->in6m_addr;
43966937Sdfr	if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
44066937Sdfr		mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
44166937Sdfr	mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
44266937Sdfr				     sizeof(struct ip6_hdr),
44366937Sdfr				     sizeof(struct mld_hdr));
44466937Sdfr
44566937Sdfr	/* construct multicast option */
44666937Sdfr	bzero(&im6o, sizeof(im6o));
44766937Sdfr	im6o.im6o_multicast_ifp = ifp;
44866937Sdfr	im6o.im6o_multicast_hlim = 1;
44966937Sdfr
45066458Sdfr	/*
45166937Sdfr	 * Request loopback of the report if we are acting as a multicast
45266937Sdfr	 * router, so that the process-level routing daemon can hear it.
45366458Sdfr	 */
45466458Sdfr	im6o.im6o_multicast_loop = (ip6_mrouter != NULL);
45566937Sdfr
45666937Sdfr	/* increment output statictics */
45766458Sdfr	icmp6stat.icp6s_outhist[type]++;
45866458Sdfr
45966458Sdfr	ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif);
46066458Sdfr	if (outif) {
46166458Sdfr		icmp6_ifstat_inc(outif, ifs6_out_msg);
46266458Sdfr		switch (type) {
46366458Sdfr		case MLD_LISTENER_QUERY:
46466458Sdfr			icmp6_ifstat_inc(outif, ifs6_out_mldquery);
46566458Sdfr			break;
46666458Sdfr		case MLD_LISTENER_REPORT:
46766458Sdfr			icmp6_ifstat_inc(outif, ifs6_out_mldreport);
46866458Sdfr			break;
46966458Sdfr		case MLD_LISTENER_DONE:
47066458Sdfr			icmp6_ifstat_inc(outif, ifs6_out_mlddone);
47166458Sdfr			break;
47266458Sdfr		}
47366458Sdfr	}
47466458Sdfr}
47566458Sdfr