xref: /openbsd-src/sys/netinet6/ip6_mroute.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: ip6_mroute.c,v 1.136 2023/04/19 20:03:52 kn Exp $	*/
2 /*	$NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $	*/
3 /*	$KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $	*/
4 
5 /*
6  * Copyright (C) 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*	BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp	*/
35 
36 /*
37  * Copyright (c) 1989 Stephen Deering
38  * Copyright (c) 1992, 1993
39  *      The Regents of the University of California.  All rights reserved.
40  *
41  * This code is derived from software contributed to Berkeley by
42  * Stephen Deering of Stanford University.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  * 3. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  *
68  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
69  */
70 
71 /*
72  * IP multicast forwarding procedures
73  *
74  * Written by David Waitzman, BBN Labs, August 1988.
75  * Modified by Steve Deering, Stanford, February 1989.
76  * Modified by Mark J. Steiglitz, Stanford, May, 1991
77  * Modified by Van Jacobson, LBL, January 1993
78  * Modified by Ajit Thyagarajan, PARC, August 1993
79  * Modified by Bill Fenner, PARC, April 1994
80  *
81  * MROUTING Revision: 3.5.1.2
82  */
83 
84 #include <sys/param.h>
85 #include <sys/malloc.h>
86 #include <sys/systm.h>
87 #include <sys/timeout.h>
88 #include <sys/mbuf.h>
89 #include <sys/socket.h>
90 #include <sys/socketvar.h>
91 #include <sys/protosw.h>
92 #include <sys/kernel.h>
93 #include <sys/ioctl.h>
94 #include <sys/syslog.h>
95 #include <sys/sysctl.h>
96 
97 #include <net/if.h>
98 #include <net/if_var.h>
99 #include <net/route.h>
100 
101 #include <netinet/in.h>
102 #include <netinet6/in6_var.h>
103 #include <netinet/ip.h>
104 #include <netinet/ip6.h>
105 #include <netinet/icmp6.h>
106 #include <netinet6/ip6_var.h>
107 #include <netinet6/ip6_mroute.h>
108 #include <netinet/in_pcb.h>
109 
110 /* #define MCAST_DEBUG */
111 
112 #ifdef MCAST_DEBUG
113 int mcast6_debug = 1;
114 #define DPRINTF(fmt, args...)						\
115 	do {								\
116 		if (mcast6_debug)					\
117 			printf("%s:%d " fmt "\n",			\
118 			    __func__, __LINE__, ## args);		\
119 	} while (0)
120 #else
121 #define DPRINTF(fmt, args...)			\
122 	do { } while (0)
123 #endif
124 
125 int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
126 void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *);
127 
128 /*
129  * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
130  * except for netstat or debugging purposes.
131  */
132 struct socket  *ip6_mrouter[RT_TABLEID_MAX + 1];
133 struct rttimer_queue ip6_mrouterq;
134 int		ip6_mrouter_ver = 0;
135 int		ip6_mrtproto;    /* for netstat only */
136 struct mrt6stat	mrt6stat;
137 
138 #define NO_RTE_FOUND	0x1
139 #define RTE_FOUND	0x2
140 
141 /*
142  * Macros to compute elapsed time efficiently
143  * Borrowed from Van Jacobson's scheduling code
144  */
145 #define TV_DELTA(a, b, delta) do { \
146 	    int xxs; \
147 		\
148 	    delta = (a).tv_usec - (b).tv_usec; \
149 	    if ((xxs = (a).tv_sec - (b).tv_sec)) { \
150 	       switch (xxs) { \
151 		      case 2: \
152 			  delta += 1000000; \
153 			      /* FALLTHROUGH */ \
154 		      case 1: \
155 			  delta += 1000000; \
156 			  break; \
157 		      default: \
158 			  delta += (1000000 * xxs); \
159 	       } \
160 	    } \
161 } while (0)
162 
163 #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
164 	      (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
165 
166 int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
167 int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int);
168 int ip6_mrouter_init(struct socket *, int, int);
169 int add_m6if(struct socket *, struct mif6ctl *);
170 int del_m6if(struct socket *, mifi_t *);
171 int add_m6fc(struct socket *, struct mf6cctl *);
172 int del_m6fc(struct socket *, struct mf6cctl *);
173 struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
174 struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *,
175     struct in6_addr *, unsigned int);
176 struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *,
177     struct sockaddr *);
178 void mrt6_mcast_del(struct rtentry *, unsigned int);
179 
180 /*
181  * Handle MRT setsockopt commands to modify the multicast routing tables.
182  */
183 int
184 ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m)
185 {
186 	struct inpcb	*inp = sotoinpcb(so);
187 
188 	if (cmd != MRT6_INIT && so != ip6_mrouter[inp->inp_rtableid])
189 		return (EPERM);
190 
191 	switch (cmd) {
192 	case MRT6_INIT:
193 		if (m == NULL || m->m_len < sizeof(int))
194 			return (EINVAL);
195 		return (ip6_mrouter_init(so, *mtod(m, int *), cmd));
196 	case MRT6_DONE:
197 		return (ip6_mrouter_done(so));
198 	case MRT6_ADD_MIF:
199 		if (m == NULL || m->m_len < sizeof(struct mif6ctl))
200 			return (EINVAL);
201 		return (add_m6if(so, mtod(m, struct mif6ctl *)));
202 	case MRT6_DEL_MIF:
203 		if (m == NULL || m->m_len < sizeof(mifi_t))
204 			return (EINVAL);
205 		return (del_m6if(so, mtod(m, mifi_t *)));
206 	case MRT6_ADD_MFC:
207 		if (m == NULL || m->m_len < sizeof(struct mf6cctl))
208 			return (EINVAL);
209 		return (add_m6fc(so, mtod(m, struct mf6cctl *)));
210 	case MRT6_DEL_MFC:
211 		if (m == NULL || m->m_len < sizeof(struct mf6cctl))
212 			return (EINVAL);
213 		return (del_m6fc(so, mtod(m,  struct mf6cctl *)));
214 	default:
215 		return (EOPNOTSUPP);
216 	}
217 }
218 
219 /*
220  * Handle MRT getsockopt commands
221  */
222 int
223 ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m)
224 {
225 	struct inpcb	*inp = sotoinpcb(so);
226 
227 	if (so != ip6_mrouter[inp->inp_rtableid])
228 		return (EPERM);
229 
230 	switch (cmd) {
231 	default:
232 		return EOPNOTSUPP;
233 	}
234 }
235 
236 /*
237  * Handle ioctl commands to obtain information from the cache
238  */
239 int
240 mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data)
241 {
242 	struct inpcb *inp = sotoinpcb(so);
243 	int error;
244 
245 	if (inp == NULL)
246 		return (ENOTCONN);
247 
248 	KERNEL_LOCK();
249 
250 	switch (cmd) {
251 	case SIOCGETSGCNT_IN6:
252 		NET_LOCK_SHARED();
253 		error = get_sg6_cnt((struct sioc_sg_req6 *)data,
254 		    inp->inp_rtableid);
255 		NET_UNLOCK_SHARED();
256 		break;
257 	case SIOCGETMIFCNT_IN6:
258 		NET_LOCK_SHARED();
259 		error = get_mif6_cnt((struct sioc_mif_req6 *)data,
260 		    inp->inp_rtableid);
261 		NET_UNLOCK_SHARED();
262 		break;
263 	default:
264 		error = ENOTTY;
265 		break;
266 	}
267 
268 	KERNEL_UNLOCK();
269 	return error;
270 }
271 
272 /*
273  * returns the packet, byte, rpf-failure count for the source group provided
274  */
275 int
276 get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid)
277 {
278 	struct rtentry *rt;
279 	struct mf6c *mf6c;
280 
281 	rt = mf6c_find(NULL, &req->src.sin6_addr, &req->grp.sin6_addr,
282 	    rtableid);
283 	if (rt == NULL) {
284 		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
285 		return EADDRNOTAVAIL;
286 	}
287 
288 	req->pktcnt = req->bytecnt = req->wrong_if = 0;
289 	do {
290 		mf6c = (struct mf6c *)rt->rt_llinfo;
291 		if (mf6c == NULL)
292 			continue;
293 
294 		req->pktcnt += mf6c->mf6c_pkt_cnt;
295 		req->bytecnt += mf6c->mf6c_byte_cnt;
296 		req->wrong_if += mf6c->mf6c_wrong_if;
297 	} while ((rt = rtable_iterate(rt)) != NULL);
298 
299 	return 0;
300 }
301 
302 /*
303  * returns the input and output packet and byte counts on the mif provided
304  */
305 int
306 get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid)
307 {
308 	struct ifnet *ifp;
309 	struct mif6 *m6;
310 
311 	if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL)
312 		return EINVAL;
313 
314 	m6 = (struct mif6 *)ifp->if_mcast6;
315 	req->icount = m6->m6_pkt_in;
316 	req->ocount = m6->m6_pkt_out;
317 	req->ibytes = m6->m6_bytes_in;
318 	req->obytes = m6->m6_bytes_out;
319 
320 	return 0;
321 }
322 
323 int
324 mrt6_sysctl_mif(void *oldp, size_t *oldlenp)
325 {
326 	struct ifnet *ifp;
327 	caddr_t where = oldp;
328 	size_t needed, given;
329 	struct mif6 *mifp;
330 	struct mif6info minfo;
331 
332 	given = *oldlenp;
333 	needed = 0;
334 	memset(&minfo, 0, sizeof minfo);
335 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
336 		if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
337 			continue;
338 
339 		minfo.m6_mifi = mifp->m6_mifi;
340 		minfo.m6_flags = mifp->m6_flags;
341 		minfo.m6_lcl_addr = mifp->m6_lcl_addr;
342 		minfo.m6_ifindex = ifp->if_index;
343 		minfo.m6_pkt_in = mifp->m6_pkt_in;
344 		minfo.m6_pkt_out = mifp->m6_pkt_out;
345 		minfo.m6_bytes_in = mifp->m6_bytes_in;
346 		minfo.m6_bytes_out = mifp->m6_bytes_out;
347 		minfo.m6_rate_limit = mifp->m6_rate_limit;
348 
349 		needed += sizeof(minfo);
350 		if (where && needed <= given) {
351 			int error;
352 
353 			error = copyout(&minfo, where, sizeof(minfo));
354 			if (error)
355 				return (error);
356 			where += sizeof(minfo);
357 		}
358 	}
359 	if (where) {
360 		*oldlenp = needed;
361 		if (given < needed)
362 			return (ENOMEM);
363 	} else
364 		*oldlenp = (11 * needed) / 10;
365 
366 	return (0);
367 }
368 
369 struct mf6csysctlarg {
370 	struct mf6cinfo	*ms6a_minfos;
371 	size_t		 ms6a_len;
372 	size_t		 ms6a_needed;
373 };
374 
375 int
376 mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
377 {
378 	struct mf6c		*mf6c = (struct mf6c *)rt->rt_llinfo;
379 	struct mf6csysctlarg	*msa = arg;
380 	struct ifnet		*ifp;
381 	struct mif6		*m6;
382 	struct mf6cinfo		*minfo;
383 	int			 new = 0;
384 
385 	/* Skip entries being removed. */
386 	if (mf6c == NULL)
387 		return 0;
388 
389 	/* Skip non-multicast routes. */
390 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
391 	    (RTF_HOST | RTF_MULTICAST))
392 		return 0;
393 
394 	/* User just asked for the output size. */
395 	if (msa->ms6a_minfos == NULL) {
396 		msa->ms6a_needed += sizeof(*minfo);
397 		return 0;
398 	}
399 
400 	/* Skip route with invalid interfaces. */
401 	if ((ifp = if_get(rt->rt_ifidx)) == NULL)
402 		return 0;
403 	if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) {
404 		if_put(ifp);
405 		return 0;
406 	}
407 
408 	for (minfo = msa->ms6a_minfos;
409 	     (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len);
410 	     minfo++) {
411 		/* Find a new entry or update old entry. */
412 		if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr,
413 		    &satosin6(rt->rt_gateway)->sin6_addr) ||
414 		    !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr,
415 		    &satosin6(rt_key(rt))->sin6_addr)) {
416 			if (!IN6_IS_ADDR_UNSPECIFIED(
417 			    &minfo->mf6c_origin.sin6_addr) ||
418 			    !IN6_IS_ADDR_UNSPECIFIED(
419 			    &minfo->mf6c_mcastgrp.sin6_addr))
420 				continue;
421 
422 			new = 1;
423 		}
424 
425 		minfo->mf6c_origin = *satosin6(rt->rt_gateway);
426 		minfo->mf6c_mcastgrp = *satosin6(rt_key(rt));
427 		minfo->mf6c_parent = mf6c->mf6c_parent;
428 		minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt;
429 		minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt;
430 		IF_SET(m6->m6_mifi, &minfo->mf6c_ifset);
431 		break;
432 	}
433 
434 	if (new != 0)
435 		msa->ms6a_needed += sizeof(*minfo);
436 
437 	if_put(ifp);
438 
439 	return 0;
440 }
441 
442 int
443 mrt6_sysctl_mfc(void *oldp, size_t *oldlenp)
444 {
445 	unsigned int		 rtableid;
446 	int			 error;
447 	struct mf6csysctlarg	 msa;
448 
449 	if (oldp != NULL && *oldlenp > MAXPHYS)
450 		return EINVAL;
451 
452 	if (oldp != NULL)
453 		msa.ms6a_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
454 	else
455 		msa.ms6a_minfos = NULL;
456 
457 	msa.ms6a_len = *oldlenp;
458 	msa.ms6a_needed = 0;
459 
460 	for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
461 		rtable_walk(rtableid, AF_INET6, NULL, mrt6_rtwalk_mf6csysctl,
462 		    &msa);
463 	}
464 
465 	if (msa.ms6a_minfos != NULL && msa.ms6a_needed > 0 &&
466 	    (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) {
467 		free(msa.ms6a_minfos, M_TEMP, *oldlenp);
468 		return error;
469 	}
470 
471 	free(msa.ms6a_minfos, M_TEMP, *oldlenp);
472 	*oldlenp = msa.ms6a_needed;
473 
474 	return 0;
475 }
476 
477 /*
478  * Enable multicast routing
479  */
480 int
481 ip6_mrouter_init(struct socket *so, int v, int cmd)
482 {
483 	struct inpcb *inp = sotoinpcb(so);
484 	unsigned int rtableid = inp->inp_rtableid;
485 
486 	if (so->so_type != SOCK_RAW ||
487 	    so->so_proto->pr_protocol != IPPROTO_ICMPV6)
488 		return (EOPNOTSUPP);
489 
490 	if (v != 1)
491 		return (ENOPROTOOPT);
492 
493 	if (ip6_mrouter[rtableid] != NULL)
494 		return (EADDRINUSE);
495 
496 	ip6_mrouter[rtableid] = so;
497 	ip6_mrouter_ver = cmd;
498 
499 	return (0);
500 }
501 
502 int
503 mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
504 {
505 	/* Skip non-multicast routes. */
506 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
507 	    (RTF_HOST | RTF_MULTICAST))
508 		return 0;
509 
510 	return EEXIST;
511 }
512 
513 /*
514  * Disable multicast routing
515  */
516 int
517 ip6_mrouter_done(struct socket *so)
518 {
519 	struct inpcb *inp = sotoinpcb(so);
520 	struct ifnet *ifp;
521 	unsigned int rtableid = inp->inp_rtableid;
522 	int error;
523 
524 	NET_ASSERT_LOCKED();
525 
526 	/* Delete all remaining installed multicast routes. */
527 	do {
528 		struct rtentry *rt = NULL;
529 
530 		error = rtable_walk(rtableid, AF_INET6, &rt,
531 		    mrouter6_rtwalk_delete, NULL);
532 		if (rt != NULL && error == EEXIST) {
533 			mrt6_mcast_del(rt, rtableid);
534 			error = EAGAIN;
535 		}
536 		rtfree(rt);
537 	} while (error == EAGAIN);
538 
539 	/* Unregister all interfaces in the domain. */
540 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
541 		if (ifp->if_rdomain != rtableid)
542 			continue;
543 
544 		ip6_mrouter_detach(ifp);
545 	}
546 
547 	ip6_mrouter[inp->inp_rtableid] = NULL;
548 	ip6_mrouter_ver = 0;
549 
550 	return 0;
551 }
552 
553 void
554 ip6_mrouter_detach(struct ifnet *ifp)
555 {
556 	struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6;
557 	struct in6_ifreq ifr;
558 
559 	if (m6 == NULL)
560 		return;
561 
562 	ifp->if_mcast6 = NULL;
563 
564 	memset(&ifr, 0, sizeof(ifr));
565 	ifr.ifr_addr.sin6_family = AF_INET6;
566 	ifr.ifr_addr.sin6_addr = in6addr_any;
567 	KERNEL_LOCK();
568 	(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
569 	KERNEL_UNLOCK();
570 
571 	free(m6, M_MRTABLE, sizeof(*m6));
572 }
573 
574 /*
575  * Add a mif to the mif table
576  */
577 int
578 add_m6if(struct socket *so, struct mif6ctl *mifcp)
579 {
580 	struct inpcb *inp = sotoinpcb(so);
581 	struct mif6 *mifp;
582 	struct ifnet *ifp;
583 	struct in6_ifreq ifr;
584 	int error;
585 	unsigned int rtableid = inp->inp_rtableid;
586 
587 	NET_ASSERT_LOCKED();
588 
589 	if (mifcp->mif6c_mifi >= MAXMIFS)
590 		return EINVAL;
591 
592 	if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL)
593 		return EADDRINUSE; /* XXX: is it appropriate? */
594 
595 	{
596 		ifp = if_get(mifcp->mif6c_pifi);
597 		if (ifp == NULL)
598 			return ENXIO;
599 
600 		/* Make sure the interface supports multicast */
601 		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
602 			if_put(ifp);
603 			return EOPNOTSUPP;
604 		}
605 
606 		/*
607 		 * Enable promiscuous reception of all IPv6 multicasts
608 		 * from the interface.
609 		 */
610 		memset(&ifr, 0, sizeof(ifr));
611 		ifr.ifr_addr.sin6_family = AF_INET6;
612 		ifr.ifr_addr.sin6_addr = in6addr_any;
613 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
614 
615 		if (error) {
616 			if_put(ifp);
617 			return error;
618 		}
619 	}
620 
621 	mifp = malloc(sizeof(*mifp), M_MRTABLE, M_WAITOK | M_ZERO);
622 	ifp->if_mcast6	   = (caddr_t)mifp;
623 	mifp->m6_mifi	   = mifcp->mif6c_mifi;
624 	mifp->m6_flags     = mifcp->mif6c_flags;
625 #ifdef notyet
626 	/* scaling up here allows division by 1024 in critical code */
627 	mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
628 #endif
629 
630 	if_put(ifp);
631 
632 	return 0;
633 }
634 
635 /*
636  * Delete a mif from the mif table
637  */
638 int
639 del_m6if(struct socket *so, mifi_t *mifip)
640 {
641 	struct inpcb *inp = sotoinpcb(so);
642 	struct ifnet *ifp;
643 
644 	NET_ASSERT_LOCKED();
645 
646 	if (*mifip >= MAXMIFS)
647 		return EINVAL;
648 	if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL)
649 		return EINVAL;
650 
651 	ip6_mrouter_detach(ifp);
652 
653 	return 0;
654 }
655 
656 int
657 mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin,
658     struct sockaddr *group, struct mf6cctl *mf6cc, int wait)
659 {
660 	struct rtentry *rt;
661 	struct mf6c *mf6c;
662 	unsigned int rtableid = ifp->if_rdomain;
663 #ifdef MCAST_DEBUG
664 	char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
665 #endif /* MCAST_DEBUG */
666 
667 	rt = mrt6_mcast_add(ifp, origin, group);
668 	if (rt == NULL)
669 		return ENOENT;
670 
671 	mf6c = malloc(sizeof(*mf6c), M_MRTABLE, wait | M_ZERO);
672 	if (mf6c == NULL) {
673 		DPRINTF("origin %s group %s parent %d (%s) malloc failed",
674 		    inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)),
675 		    inet_ntop(AF_INET6, group, bdst, sizeof(bdst)),
676 		    mf6cc->mf6cc_parent, ifp->if_xname);
677 		mrt6_mcast_del(rt, rtableid);
678 		rtfree(rt);
679 		return ENOMEM;
680 	}
681 
682 	rt->rt_llinfo = (caddr_t)mf6c;
683 	rt_timer_add(rt, &ip6_mrouterq, rtableid);
684 	mf6c->mf6c_parent = mf6cc->mf6cc_parent;
685 	rtfree(rt);
686 
687 	return 0;
688 }
689 
690 void
691 mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid)
692 {
693 	struct rtentry *rt;
694 	struct mf6c *mf6c;
695 	struct ifnet *ifp;
696 	struct sockaddr_in6 osin6, gsin6;
697 	mifi_t mifi;
698 #ifdef MCAST_DEBUG
699 	char bdst[INET6_ADDRSTRLEN];
700 #endif /* MCAST_DEBUG */
701 
702 	memset(&osin6, 0, sizeof(osin6));
703 	osin6.sin6_family = AF_INET6;
704 	osin6.sin6_len = sizeof(osin6);
705 	osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr;
706 
707 	memset(&gsin6, 0, sizeof(gsin6));
708 	gsin6.sin6_family = AF_INET6;
709 	gsin6.sin6_len = sizeof(gsin6);
710 	gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr;
711 
712 	for (mifi = 0; mifi < MAXMIFS; mifi++) {
713 		if (mifi == mf6cc->mf6cc_parent)
714 			continue;
715 
716 		/* Test for mif existence and then update the entry. */
717 		if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL)
718 			continue;
719 
720 		rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
721 		    &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid);
722 
723 		/* mif not configured or removed. */
724 		if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)) {
725 			/* Route doesn't exist, nothing to do. */
726 			if (rt == NULL)
727 				continue;
728 
729 			DPRINTF("del route (group %s) for mif %d (%s)",
730 			    inet_ntop(AF_INET6,
731 			    &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
732 			    sizeof(bdst)), mifi, ifp->if_xname);
733 			mrt6_mcast_del(rt, rtableid);
734 			rtfree(rt);
735 			continue;
736 		}
737 
738 		/* Route exists, look for changes. */
739 		if (rt != NULL) {
740 			mf6c = (struct mf6c *)rt->rt_llinfo;
741 			/* Skip route being deleted. */
742 			if (mf6c == NULL) {
743 				rtfree(rt);
744 				continue;
745 			}
746 
747 			/* No new changes to apply. */
748 			if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) {
749 				rtfree(rt);
750 				continue;
751 			}
752 
753 			DPRINTF("update route (group %s) for mif %d (%s)",
754 			    inet_ntop(AF_INET6,
755 			    &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
756 			    sizeof(bdst)), mifi, ifp->if_xname);
757 
758 			mf6c->mf6c_parent = mf6cc->mf6cc_parent;
759 			rtfree(rt);
760 			continue;
761 		}
762 
763 		DPRINTF("add route (group %s) for mif %d (%s)",
764 		    inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
765 		    bdst, sizeof(bdst)), mifi, ifp->if_xname);
766 
767 		mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6),
768 		    mf6cc, wait);
769 	}
770 
771 	/* Create route for the parent interface. */
772 	if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent,
773 	    rtableid)) == NULL) {
774 		DPRINTF("failed to find upstream interface %d",
775 		    mf6cc->mf6cc_parent);
776 		return;
777 	}
778 
779 	/* We already have a route, nothing to do here. */
780 	if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
781 	    &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
782 		rtfree(rt);
783 		return;
784 	}
785 
786 	DPRINTF("add upstream route (group %s) for if %s",
787 	    inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
788 	    bdst, sizeof(bdst)), ifp->if_xname);
789 	mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait);
790 }
791 
792 int
793 mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin,
794     struct in6_addr *group, int vidx, unsigned int rtableid, int wait)
795 {
796 	struct ifnet *ifp;
797 	struct mif6 *m6;
798 	struct mf6cctl mf6cc;
799 
800 	ifp = mrt6_iflookupbymif(vidx, rtableid);
801 	if (ifp == NULL ||
802 	    (m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
803 		return ENOENT;
804 
805 	memset(&mf6cc, 0, sizeof(mf6cc));
806 	if (mfccp == NULL) {
807 		mf6cc.mf6cc_origin.sin6_family = AF_INET6;
808 		mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin);
809 		mf6cc.mf6cc_origin.sin6_addr = *origin;
810 		mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET6;
811 		mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp);
812 		mf6cc.mf6cc_mcastgrp.sin6_addr = *group;
813 		mf6cc.mf6cc_parent = vidx;
814 	} else
815 		memcpy(&mf6cc, mfccp, sizeof(mf6cc));
816 
817 	mf6c_update(&mf6cc, wait, rtableid);
818 
819 	return 0;
820 }
821 
822 int
823 add_m6fc(struct socket *so, struct mf6cctl *mfccp)
824 {
825 	struct inpcb *inp = sotoinpcb(so);
826 	unsigned int rtableid = inp->inp_rtableid;
827 
828 	NET_ASSERT_LOCKED();
829 
830 	return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr,
831 	    &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent,
832 	    rtableid, M_WAITOK);
833 }
834 
835 int
836 del_m6fc(struct socket *so, struct mf6cctl *mfccp)
837 {
838 	struct inpcb *inp = sotoinpcb(so);
839 	struct rtentry *rt;
840 	unsigned int rtableid = inp->inp_rtableid;
841 
842 	NET_ASSERT_LOCKED();
843 
844 	while ((rt = mf6c_find(NULL, &mfccp->mf6cc_origin.sin6_addr,
845 	    &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
846 		mrt6_mcast_del(rt, rtableid);
847 		rtfree(rt);
848 	}
849 
850 	return 0;
851 }
852 
853 int
854 socket6_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
855 {
856 	if (s) {
857 		if (sbappendaddr(s, &s->so_rcv, sin6tosa(src), mm, NULL) != 0) {
858 			sorwakeup(s);
859 			return 0;
860 		}
861 	}
862 	m_freem(mm);
863 	return -1;
864 }
865 
866 /*
867  * IPv6 multicast forwarding function. This function assumes that the packet
868  * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
869  * pointed to by "ifp", and the packet is to be relayed to other networks
870  * that have members of the packet's destination IPv6 multicast group.
871  *
872  * The packet is returned unscathed to the caller, unless it is
873  * erroneous, in which case a non-zero return value tells the caller to
874  * discard it.
875  */
876 int
877 ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
878 {
879 	struct rtentry *rt;
880 	struct mif6 *mifp;
881 	struct mbuf *mm;
882 	struct sockaddr_in6 sin6;
883 	unsigned int rtableid = ifp->if_rdomain;
884 
885 	NET_ASSERT_LOCKED();
886 
887 	/*
888 	 * Don't forward a packet with Hop limit of zero or one,
889 	 * or a packet destined to a local-only group.
890 	 */
891 	if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
892 	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
893 		return 0;
894 	ip6->ip6_hlim--;
895 
896 	/*
897 	 * Source address check: do not forward packets with unspecified
898 	 * source. It was discussed in July 2000, on ipngwg mailing list.
899 	 * This is rather more serious than unicast cases, because some
900 	 * MLD packets can be sent with the unspecified source address
901 	 * (although such packets must normally set 1 to the hop limit field).
902 	 */
903 	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
904 		ip6stat_inc(ip6s_cantforward);
905 		if (ip6_log_time + ip6_log_interval < getuptime()) {
906 			char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
907 
908 			ip6_log_time = getuptime();
909 
910 			inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src));
911 			inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst));
912 			log(LOG_DEBUG, "cannot forward "
913 			    "from %s to %s nxt %d received on interface %u\n",
914 			    src, dst, ip6->ip6_nxt, m->m_pkthdr.ph_ifidx);
915 		}
916 		return 0;
917 	}
918 
919 	/*
920 	 * Determine forwarding mifs from the forwarding cache table
921 	 */
922 	rt = mf6c_find(NULL, &ip6->ip6_src, &ip6->ip6_dst, rtableid);
923 
924 	/* Entry exists, so forward if necessary */
925 	if (rt) {
926 		return (ip6_mdq(m, ifp, rt));
927 	} else {
928 		/*
929 		 * If we don't have a route for packet's origin,
930 		 * Make a copy of the packet &
931 		 * send message to routing daemon
932 		 */
933 
934 		mrt6stat.mrt6s_no_route++;
935 
936 		{
937 			struct mrt6msg *im;
938 
939 			if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
940 				return EHOSTUNREACH;
941 
942 			/*
943 			 * Make a copy of the header to send to the user
944 			 * level process
945 			 */
946 			mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT);
947 			if (mm == NULL)
948 				return ENOBUFS;
949 
950 			/*
951 			 * Send message to routing daemon
952 			 */
953 			(void)memset(&sin6, 0, sizeof(sin6));
954 			sin6.sin6_len = sizeof(sin6);
955 			sin6.sin6_family = AF_INET6;
956 			sin6.sin6_addr = ip6->ip6_src;
957 
958 			im = NULL;
959 			switch (ip6_mrouter_ver) {
960 			case MRT6_INIT:
961 				im = mtod(mm, struct mrt6msg *);
962 				im->im6_msgtype = MRT6MSG_NOCACHE;
963 				im->im6_mbz = 0;
964 				im->im6_mif = mifp->m6_mifi;
965 				break;
966 			default:
967 				m_freem(mm);
968 				return EINVAL;
969 			}
970 
971 			if (socket6_send(ip6_mrouter[rtableid], mm,
972 			    &sin6) < 0) {
973 				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
974 				    "socket queue full\n");
975 				mrt6stat.mrt6s_upq_sockfull++;
976 				return ENOBUFS;
977 			}
978 
979 			mrt6stat.mrt6s_upcalls++;
980 
981 			mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst,
982 			    mifp->m6_mifi, rtableid, M_NOWAIT);
983 		}
984 
985 		return 0;
986 	}
987 }
988 
989 void
990 mf6c_expire_route(struct rtentry *rt, u_int rtableid)
991 {
992 	struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
993 #ifdef MCAST_DEBUG
994 	char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
995 #endif /* MCAST_DEBUG */
996 
997 	/* Skip entry being deleted. */
998 	if (mf6c == NULL)
999 		return;
1000 
1001 	DPRINTF("origin %s group %s interface %d expire %s",
1002 	    inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,
1003 	    bsrc, sizeof(bsrc)),
1004 	    inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,
1005 	    bdst, sizeof(bdst)), rt->rt_ifidx,
1006 	    mf6c->mf6c_expire ? "yes" : "no");
1007 
1008 	if (mf6c->mf6c_expire == 0) {
1009 		mf6c->mf6c_expire = 1;
1010 		rt_timer_add(rt, &ip6_mrouterq, rtableid);
1011 		return;
1012 	}
1013 
1014 	mrt6_mcast_del(rt, rtableid);
1015 }
1016 
1017 /*
1018  * Packet forwarding routine once entry in the cache is made
1019  */
1020 int
1021 ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
1022 {
1023 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1024 	struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6;
1025 	struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
1026 	struct ifnet *ifn;
1027 	int plen = m->m_pkthdr.len;
1028 
1029 	if (mifp == NULL || mf6c == NULL) {
1030 		rtfree(rt);
1031 		return EHOSTUNREACH;
1032 	}
1033 
1034 	/*
1035 	 * Don't forward if it didn't arrive from the parent mif
1036 	 * for its origin.
1037 	 */
1038 	if (mifp->m6_mifi != mf6c->mf6c_parent) {
1039 		/* came in the wrong interface */
1040 		mrt6stat.mrt6s_wrong_if++;
1041 		mf6c->mf6c_wrong_if++;
1042 		rtfree(rt);
1043 		return 0;
1044 	}			/* if wrong iif */
1045 
1046 	/* If I sourced this packet, it counts as output, else it was input. */
1047 	if (m->m_pkthdr.ph_ifidx == 0) {
1048 		/* XXX: is ph_ifidx really 0 when output?? */
1049 		mifp->m6_pkt_out++;
1050 		mifp->m6_bytes_out += plen;
1051 	} else {
1052 		mifp->m6_pkt_in++;
1053 		mifp->m6_bytes_in += plen;
1054 	}
1055 
1056 	/*
1057 	 * For each mif, forward a copy of the packet if there are group
1058 	 * members downstream on the interface.
1059 	 */
1060 	do {
1061 		/* Don't consider non multicast routes. */
1062 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1063 		    (RTF_HOST | RTF_MULTICAST))
1064 			continue;
1065 
1066 		mf6c = (struct mf6c *)rt->rt_llinfo;
1067 		if (mf6c == NULL)
1068 			continue;
1069 
1070 		mf6c->mf6c_pkt_cnt++;
1071 		mf6c->mf6c_byte_cnt += m->m_pkthdr.len;
1072 
1073 		/* Don't let this route expire. */
1074 		mf6c->mf6c_expire = 0;
1075 
1076 		if ((ifn = if_get(rt->rt_ifidx)) == NULL)
1077 			continue;
1078 
1079 		/* Sanity check: did we configure this? */
1080 		if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL) {
1081 			if_put(ifn);
1082 			continue;
1083 		}
1084 
1085 		/* Don't send in the upstream interface. */
1086 		if (mf6c->mf6c_parent == m6->m6_mifi) {
1087 			if_put(ifn);
1088 			continue;
1089 		}
1090 
1091 		/*
1092 		 * check if the outgoing packet is going to break
1093 		 * a scope boundary.
1094 		 */
1095 		if ((mifp->m6_flags & MIFF_REGISTER) == 0 &&
1096 		    (m6->m6_flags & MIFF_REGISTER) == 0 &&
1097 		    (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) !=
1098 		    in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) ||
1099 		    in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) !=
1100 		    in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) {
1101 			if_put(ifn);
1102 			ip6stat_inc(ip6s_badscope);
1103 			continue;
1104 		}
1105 
1106 		m6->m6_pkt_out++;
1107 		m6->m6_bytes_out += plen;
1108 
1109 		phyint_send6(ifn, ip6, m);
1110 		if_put(ifn);
1111 	} while ((rt = rtable_iterate(rt)) != NULL);
1112 
1113 	return 0;
1114 }
1115 
1116 void
1117 phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
1118 {
1119 	struct mbuf *mb_copy;
1120 	struct sockaddr_in6 *dst6, sin6;
1121 	int error = 0;
1122 
1123 	NET_ASSERT_LOCKED();
1124 
1125 	/*
1126 	 * Make a new reference to the packet; make sure that
1127 	 * the IPv6 header is actually copied, not just referenced,
1128 	 * so that ip6_output() only scribbles on the copy.
1129 	 */
1130 	mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1131 	if (mb_copy == NULL)
1132 		return;
1133 	/* set MCAST flag to the outgoing packet */
1134 	mb_copy->m_flags |= M_MCAST;
1135 
1136 	/*
1137 	 * If we sourced the packet, call ip6_output since we may divide
1138 	 * the packet into fragments when the packet is too big for the
1139 	 * outgoing interface.
1140 	 * Otherwise, we can simply send the packet to the interface
1141 	 * sending queue.
1142 	 */
1143 	if (m->m_pkthdr.ph_ifidx == 0) {
1144 		struct ip6_moptions im6o;
1145 
1146 		im6o.im6o_ifidx = ifp->if_index;
1147 		/* XXX: ip6_output will override ip6->ip6_hlim */
1148 		im6o.im6o_hlim = ip6->ip6_hlim;
1149 		im6o.im6o_loop = 1;
1150 		error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
1151 		    NULL);
1152 		return;
1153 	}
1154 
1155 	/*
1156 	 * If we belong to the destination multicast group
1157 	 * on the outgoing interface, loop back a copy.
1158 	 */
1159 	dst6 = &sin6;
1160 	memset(&sin6, 0, sizeof(sin6));
1161 	if (in6_hasmulti(&ip6->ip6_dst, ifp)) {
1162 		dst6->sin6_len = sizeof(struct sockaddr_in6);
1163 		dst6->sin6_family = AF_INET6;
1164 		dst6->sin6_addr = ip6->ip6_dst;
1165 		ip6_mloopback(ifp, m, dst6);
1166 	}
1167 	/*
1168 	 * Put the packet into the sending queue of the outgoing interface
1169 	 * if it would fit in the MTU of the interface.
1170 	 */
1171 	if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
1172 		dst6->sin6_len = sizeof(struct sockaddr_in6);
1173 		dst6->sin6_family = AF_INET6;
1174 		dst6->sin6_addr = ip6->ip6_dst;
1175 		error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL);
1176 	} else {
1177 		if (ip6_mcast_pmtu)
1178 			icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0,
1179 			    ifp->if_mtu);
1180 		else {
1181 			m_freem(mb_copy); /* simply discard the packet */
1182 		}
1183 	}
1184 }
1185 
1186 struct ifnet *
1187 mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid)
1188 {
1189 	struct mif6	*m6;
1190 	struct ifnet	*ifp;
1191 
1192 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1193 		if (ifp->if_rdomain != rtableid)
1194 			continue;
1195 		if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
1196 			continue;
1197 		if (m6->m6_mifi != mifi)
1198 			continue;
1199 
1200 		return ifp;
1201 	}
1202 
1203 	return NULL;
1204 }
1205 
1206 struct rtentry *
1207 mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group,
1208     unsigned int rtableid)
1209 {
1210 	struct rtentry *rt;
1211 	struct sockaddr_in6 msin6;
1212 
1213 	memset(&msin6, 0, sizeof(msin6));
1214 	msin6.sin6_family = AF_INET6;
1215 	msin6.sin6_len = sizeof(msin6);
1216 	msin6.sin6_addr = *group;
1217 
1218 	rt = rtalloc(sin6tosa(&msin6), 0, rtableid);
1219 	do {
1220 		if (!rtisvalid(rt)) {
1221 			rtfree(rt);
1222 			return NULL;
1223 		}
1224 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1225 		    (RTF_HOST | RTF_MULTICAST))
1226 			continue;
1227 		/* Return first occurrence if interface is not specified. */
1228 		if (ifp == NULL)
1229 			return rt;
1230 		if (rt->rt_ifidx == ifp->if_index)
1231 			return rt;
1232 	} while ((rt = rtable_iterate(rt)) != NULL);
1233 
1234 	return NULL;
1235 }
1236 
1237 struct rtentry *
1238 mrt6_mcast_add(struct ifnet *ifp, struct sockaddr *origin,
1239     struct sockaddr *group)
1240 {
1241 	struct ifaddr *ifa;
1242 	int rv;
1243 	unsigned int rtableid = ifp->if_rdomain;
1244 
1245 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1246 		if (ifa->ifa_addr->sa_family == AF_INET6)
1247 			break;
1248 	}
1249 	if (ifa == NULL) {
1250 		DPRINTF("ifa == NULL");
1251 		return NULL;
1252 	}
1253 
1254 	rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH, group,
1255 	    ifp->if_rdomain);
1256 	if (rv != 0) {
1257 		DPRINTF("rt_ifa_add failed %d", rv);
1258 		return NULL;
1259 	}
1260 
1261 	return mf6c_find(ifp, NULL, &satosin6(group)->sin6_addr, rtableid);
1262 }
1263 
1264 void
1265 mrt6_mcast_del(struct rtentry *rt, unsigned int rtableid)
1266 {
1267 	struct ifnet *ifp;
1268 	int error;
1269 
1270 	/* Remove all timers related to this route. */
1271 	rt_timer_remove_all(rt);
1272 
1273 	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mf6c));
1274 	rt->rt_llinfo = NULL;
1275 
1276 	ifp = if_get(rt->rt_ifidx);
1277 	if (ifp == NULL)
1278 		return;
1279 	error = rtdeletemsg(rt, ifp, rtableid);
1280 	if_put(ifp);
1281 
1282 	if (error)
1283 		DPRINTF("delete route error %d\n", error);
1284 }
1285