xref: /openbsd-src/sys/netinet6/ip6_mroute.c (revision 8550894424f8a4aa4aafb6cd57229dd6ed7cd9dd)
1 /*	$OpenBSD: ip6_mroute.c,v 1.135 2022/09/08 10:22:07 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 	switch (cmd) {
249 	case SIOCGETSGCNT_IN6:
250 		NET_LOCK_SHARED();
251 		error = get_sg6_cnt((struct sioc_sg_req6 *)data,
252 		    inp->inp_rtableid);
253 		NET_UNLOCK_SHARED();
254 		break;
255 	case SIOCGETMIFCNT_IN6:
256 		NET_LOCK_SHARED();
257 		error = get_mif6_cnt((struct sioc_mif_req6 *)data,
258 		    inp->inp_rtableid);
259 		NET_UNLOCK_SHARED();
260 		break;
261 	default:
262 		error = ENOTTY;
263 		break;
264 	}
265 	return error;
266 }
267 
268 /*
269  * returns the packet, byte, rpf-failure count for the source group provided
270  */
271 int
272 get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid)
273 {
274 	struct rtentry *rt;
275 	struct mf6c *mf6c;
276 
277 	rt = mf6c_find(NULL, &req->src.sin6_addr, &req->grp.sin6_addr,
278 	    rtableid);
279 	if (rt == NULL) {
280 		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
281 		return EADDRNOTAVAIL;
282 	}
283 
284 	req->pktcnt = req->bytecnt = req->wrong_if = 0;
285 	do {
286 		mf6c = (struct mf6c *)rt->rt_llinfo;
287 		if (mf6c == NULL)
288 			continue;
289 
290 		req->pktcnt += mf6c->mf6c_pkt_cnt;
291 		req->bytecnt += mf6c->mf6c_byte_cnt;
292 		req->wrong_if += mf6c->mf6c_wrong_if;
293 	} while ((rt = rtable_iterate(rt)) != NULL);
294 
295 	return 0;
296 }
297 
298 /*
299  * returns the input and output packet and byte counts on the mif provided
300  */
301 int
302 get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid)
303 {
304 	struct ifnet *ifp;
305 	struct mif6 *m6;
306 
307 	if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL)
308 		return EINVAL;
309 
310 	m6 = (struct mif6 *)ifp->if_mcast6;
311 	req->icount = m6->m6_pkt_in;
312 	req->ocount = m6->m6_pkt_out;
313 	req->ibytes = m6->m6_bytes_in;
314 	req->obytes = m6->m6_bytes_out;
315 
316 	return 0;
317 }
318 
319 int
320 mrt6_sysctl_mif(void *oldp, size_t *oldlenp)
321 {
322 	struct ifnet *ifp;
323 	caddr_t where = oldp;
324 	size_t needed, given;
325 	struct mif6 *mifp;
326 	struct mif6info minfo;
327 
328 	given = *oldlenp;
329 	needed = 0;
330 	memset(&minfo, 0, sizeof minfo);
331 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
332 		if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
333 			continue;
334 
335 		minfo.m6_mifi = mifp->m6_mifi;
336 		minfo.m6_flags = mifp->m6_flags;
337 		minfo.m6_lcl_addr = mifp->m6_lcl_addr;
338 		minfo.m6_ifindex = ifp->if_index;
339 		minfo.m6_pkt_in = mifp->m6_pkt_in;
340 		minfo.m6_pkt_out = mifp->m6_pkt_out;
341 		minfo.m6_bytes_in = mifp->m6_bytes_in;
342 		minfo.m6_bytes_out = mifp->m6_bytes_out;
343 		minfo.m6_rate_limit = mifp->m6_rate_limit;
344 
345 		needed += sizeof(minfo);
346 		if (where && needed <= given) {
347 			int error;
348 
349 			error = copyout(&minfo, where, sizeof(minfo));
350 			if (error)
351 				return (error);
352 			where += sizeof(minfo);
353 		}
354 	}
355 	if (where) {
356 		*oldlenp = needed;
357 		if (given < needed)
358 			return (ENOMEM);
359 	} else
360 		*oldlenp = (11 * needed) / 10;
361 
362 	return (0);
363 }
364 
365 struct mf6csysctlarg {
366 	struct mf6cinfo	*ms6a_minfos;
367 	size_t		 ms6a_len;
368 	size_t		 ms6a_needed;
369 };
370 
371 int
372 mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
373 {
374 	struct mf6c		*mf6c = (struct mf6c *)rt->rt_llinfo;
375 	struct mf6csysctlarg	*msa = arg;
376 	struct ifnet		*ifp;
377 	struct mif6		*m6;
378 	struct mf6cinfo		*minfo;
379 	int			 new = 0;
380 
381 	/* Skip entries being removed. */
382 	if (mf6c == NULL)
383 		return 0;
384 
385 	/* Skip non-multicast routes. */
386 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
387 	    (RTF_HOST | RTF_MULTICAST))
388 		return 0;
389 
390 	/* User just asked for the output size. */
391 	if (msa->ms6a_minfos == NULL) {
392 		msa->ms6a_needed += sizeof(*minfo);
393 		return 0;
394 	}
395 
396 	/* Skip route with invalid interfaces. */
397 	if ((ifp = if_get(rt->rt_ifidx)) == NULL)
398 		return 0;
399 	if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) {
400 		if_put(ifp);
401 		return 0;
402 	}
403 
404 	for (minfo = msa->ms6a_minfos;
405 	     (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len);
406 	     minfo++) {
407 		/* Find a new entry or update old entry. */
408 		if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr,
409 		    &satosin6(rt->rt_gateway)->sin6_addr) ||
410 		    !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr,
411 		    &satosin6(rt_key(rt))->sin6_addr)) {
412 			if (!IN6_IS_ADDR_UNSPECIFIED(
413 			    &minfo->mf6c_origin.sin6_addr) ||
414 			    !IN6_IS_ADDR_UNSPECIFIED(
415 			    &minfo->mf6c_mcastgrp.sin6_addr))
416 				continue;
417 
418 			new = 1;
419 		}
420 
421 		minfo->mf6c_origin = *satosin6(rt->rt_gateway);
422 		minfo->mf6c_mcastgrp = *satosin6(rt_key(rt));
423 		minfo->mf6c_parent = mf6c->mf6c_parent;
424 		minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt;
425 		minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt;
426 		IF_SET(m6->m6_mifi, &minfo->mf6c_ifset);
427 		break;
428 	}
429 
430 	if (new != 0)
431 		msa->ms6a_needed += sizeof(*minfo);
432 
433 	if_put(ifp);
434 
435 	return 0;
436 }
437 
438 int
439 mrt6_sysctl_mfc(void *oldp, size_t *oldlenp)
440 {
441 	unsigned int		 rtableid;
442 	int			 error;
443 	struct mf6csysctlarg	 msa;
444 
445 	if (oldp != NULL && *oldlenp > MAXPHYS)
446 		return EINVAL;
447 
448 	if (oldp != NULL)
449 		msa.ms6a_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
450 	else
451 		msa.ms6a_minfos = NULL;
452 
453 	msa.ms6a_len = *oldlenp;
454 	msa.ms6a_needed = 0;
455 
456 	for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
457 		rtable_walk(rtableid, AF_INET6, NULL, mrt6_rtwalk_mf6csysctl,
458 		    &msa);
459 	}
460 
461 	if (msa.ms6a_minfos != NULL && msa.ms6a_needed > 0 &&
462 	    (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) {
463 		free(msa.ms6a_minfos, M_TEMP, *oldlenp);
464 		return error;
465 	}
466 
467 	free(msa.ms6a_minfos, M_TEMP, *oldlenp);
468 	*oldlenp = msa.ms6a_needed;
469 
470 	return 0;
471 }
472 
473 /*
474  * Enable multicast routing
475  */
476 int
477 ip6_mrouter_init(struct socket *so, int v, int cmd)
478 {
479 	struct inpcb *inp = sotoinpcb(so);
480 	unsigned int rtableid = inp->inp_rtableid;
481 
482 	if (so->so_type != SOCK_RAW ||
483 	    so->so_proto->pr_protocol != IPPROTO_ICMPV6)
484 		return (EOPNOTSUPP);
485 
486 	if (v != 1)
487 		return (ENOPROTOOPT);
488 
489 	if (ip6_mrouter[rtableid] != NULL)
490 		return (EADDRINUSE);
491 
492 	ip6_mrouter[rtableid] = so;
493 	ip6_mrouter_ver = cmd;
494 
495 	return (0);
496 }
497 
498 int
499 mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
500 {
501 	/* Skip non-multicast routes. */
502 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
503 	    (RTF_HOST | RTF_MULTICAST))
504 		return 0;
505 
506 	return EEXIST;
507 }
508 
509 /*
510  * Disable multicast routing
511  */
512 int
513 ip6_mrouter_done(struct socket *so)
514 {
515 	struct inpcb *inp = sotoinpcb(so);
516 	struct ifnet *ifp;
517 	unsigned int rtableid = inp->inp_rtableid;
518 	int error;
519 
520 	NET_ASSERT_LOCKED();
521 
522 	/* Delete all remaining installed multicast routes. */
523 	do {
524 		struct rtentry *rt = NULL;
525 
526 		error = rtable_walk(rtableid, AF_INET6, &rt,
527 		    mrouter6_rtwalk_delete, NULL);
528 		if (rt != NULL && error == EEXIST) {
529 			mrt6_mcast_del(rt, rtableid);
530 			error = EAGAIN;
531 		}
532 		rtfree(rt);
533 	} while (error == EAGAIN);
534 
535 	/* Unregister all interfaces in the domain. */
536 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
537 		if (ifp->if_rdomain != rtableid)
538 			continue;
539 
540 		ip6_mrouter_detach(ifp);
541 	}
542 
543 	ip6_mrouter[inp->inp_rtableid] = NULL;
544 	ip6_mrouter_ver = 0;
545 
546 	return 0;
547 }
548 
549 void
550 ip6_mrouter_detach(struct ifnet *ifp)
551 {
552 	struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6;
553 	struct in6_ifreq ifr;
554 
555 	if (m6 == NULL)
556 		return;
557 
558 	ifp->if_mcast6 = NULL;
559 
560 	memset(&ifr, 0, sizeof(ifr));
561 	ifr.ifr_addr.sin6_family = AF_INET6;
562 	ifr.ifr_addr.sin6_addr = in6addr_any;
563 	KERNEL_LOCK();
564 	(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
565 	KERNEL_UNLOCK();
566 
567 	free(m6, M_MRTABLE, sizeof(*m6));
568 }
569 
570 /*
571  * Add a mif to the mif table
572  */
573 int
574 add_m6if(struct socket *so, struct mif6ctl *mifcp)
575 {
576 	struct inpcb *inp = sotoinpcb(so);
577 	struct mif6 *mifp;
578 	struct ifnet *ifp;
579 	struct in6_ifreq ifr;
580 	int error;
581 	unsigned int rtableid = inp->inp_rtableid;
582 
583 	NET_ASSERT_LOCKED();
584 
585 	if (mifcp->mif6c_mifi >= MAXMIFS)
586 		return EINVAL;
587 
588 	if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL)
589 		return EADDRINUSE; /* XXX: is it appropriate? */
590 
591 	{
592 		ifp = if_get(mifcp->mif6c_pifi);
593 		if (ifp == NULL)
594 			return ENXIO;
595 
596 		/* Make sure the interface supports multicast */
597 		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
598 			if_put(ifp);
599 			return EOPNOTSUPP;
600 		}
601 
602 		/*
603 		 * Enable promiscuous reception of all IPv6 multicasts
604 		 * from the interface.
605 		 */
606 		memset(&ifr, 0, sizeof(ifr));
607 		ifr.ifr_addr.sin6_family = AF_INET6;
608 		ifr.ifr_addr.sin6_addr = in6addr_any;
609 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
610 
611 		if (error) {
612 			if_put(ifp);
613 			return error;
614 		}
615 	}
616 
617 	mifp = malloc(sizeof(*mifp), M_MRTABLE, M_WAITOK | M_ZERO);
618 	ifp->if_mcast6	   = (caddr_t)mifp;
619 	mifp->m6_mifi	   = mifcp->mif6c_mifi;
620 	mifp->m6_flags     = mifcp->mif6c_flags;
621 #ifdef notyet
622 	/* scaling up here allows division by 1024 in critical code */
623 	mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
624 #endif
625 
626 	if_put(ifp);
627 
628 	return 0;
629 }
630 
631 /*
632  * Delete a mif from the mif table
633  */
634 int
635 del_m6if(struct socket *so, mifi_t *mifip)
636 {
637 	struct inpcb *inp = sotoinpcb(so);
638 	struct ifnet *ifp;
639 
640 	NET_ASSERT_LOCKED();
641 
642 	if (*mifip >= MAXMIFS)
643 		return EINVAL;
644 	if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL)
645 		return EINVAL;
646 
647 	ip6_mrouter_detach(ifp);
648 
649 	return 0;
650 }
651 
652 int
653 mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin,
654     struct sockaddr *group, struct mf6cctl *mf6cc, int wait)
655 {
656 	struct rtentry *rt;
657 	struct mf6c *mf6c;
658 	unsigned int rtableid = ifp->if_rdomain;
659 #ifdef MCAST_DEBUG
660 	char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
661 #endif /* MCAST_DEBUG */
662 
663 	rt = mrt6_mcast_add(ifp, origin, group);
664 	if (rt == NULL)
665 		return ENOENT;
666 
667 	mf6c = malloc(sizeof(*mf6c), M_MRTABLE, wait | M_ZERO);
668 	if (mf6c == NULL) {
669 		DPRINTF("origin %s group %s parent %d (%s) malloc failed",
670 		    inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)),
671 		    inet_ntop(AF_INET6, group, bdst, sizeof(bdst)),
672 		    mf6cc->mf6cc_parent, ifp->if_xname);
673 		mrt6_mcast_del(rt, rtableid);
674 		rtfree(rt);
675 		return ENOMEM;
676 	}
677 
678 	rt->rt_llinfo = (caddr_t)mf6c;
679 	rt_timer_add(rt, &ip6_mrouterq, rtableid);
680 	mf6c->mf6c_parent = mf6cc->mf6cc_parent;
681 	rtfree(rt);
682 
683 	return 0;
684 }
685 
686 void
687 mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid)
688 {
689 	struct rtentry *rt;
690 	struct mf6c *mf6c;
691 	struct ifnet *ifp;
692 	struct sockaddr_in6 osin6, gsin6;
693 	mifi_t mifi;
694 #ifdef MCAST_DEBUG
695 	char bdst[INET6_ADDRSTRLEN];
696 #endif /* MCAST_DEBUG */
697 
698 	memset(&osin6, 0, sizeof(osin6));
699 	osin6.sin6_family = AF_INET6;
700 	osin6.sin6_len = sizeof(osin6);
701 	osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr;
702 
703 	memset(&gsin6, 0, sizeof(gsin6));
704 	gsin6.sin6_family = AF_INET6;
705 	gsin6.sin6_len = sizeof(gsin6);
706 	gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr;
707 
708 	for (mifi = 0; mifi < MAXMIFS; mifi++) {
709 		if (mifi == mf6cc->mf6cc_parent)
710 			continue;
711 
712 		/* Test for mif existence and then update the entry. */
713 		if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL)
714 			continue;
715 
716 		rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
717 		    &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid);
718 
719 		/* mif not configured or removed. */
720 		if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)) {
721 			/* Route doesn't exist, nothing to do. */
722 			if (rt == NULL)
723 				continue;
724 
725 			DPRINTF("del route (group %s) for mif %d (%s)",
726 			    inet_ntop(AF_INET6,
727 			    &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
728 			    sizeof(bdst)), mifi, ifp->if_xname);
729 			mrt6_mcast_del(rt, rtableid);
730 			rtfree(rt);
731 			continue;
732 		}
733 
734 		/* Route exists, look for changes. */
735 		if (rt != NULL) {
736 			mf6c = (struct mf6c *)rt->rt_llinfo;
737 			/* Skip route being deleted. */
738 			if (mf6c == NULL) {
739 				rtfree(rt);
740 				continue;
741 			}
742 
743 			/* No new changes to apply. */
744 			if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) {
745 				rtfree(rt);
746 				continue;
747 			}
748 
749 			DPRINTF("update route (group %s) for mif %d (%s)",
750 			    inet_ntop(AF_INET6,
751 			    &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
752 			    sizeof(bdst)), mifi, ifp->if_xname);
753 
754 			mf6c->mf6c_parent = mf6cc->mf6cc_parent;
755 			rtfree(rt);
756 			continue;
757 		}
758 
759 		DPRINTF("add route (group %s) for mif %d (%s)",
760 		    inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
761 		    bdst, sizeof(bdst)), mifi, ifp->if_xname);
762 
763 		mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6),
764 		    mf6cc, wait);
765 	}
766 
767 	/* Create route for the parent interface. */
768 	if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent,
769 	    rtableid)) == NULL) {
770 		DPRINTF("failed to find upstream interface %d",
771 		    mf6cc->mf6cc_parent);
772 		return;
773 	}
774 
775 	/* We already have a route, nothing to do here. */
776 	if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
777 	    &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
778 		rtfree(rt);
779 		return;
780 	}
781 
782 	DPRINTF("add upstream route (group %s) for if %s",
783 	    inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
784 	    bdst, sizeof(bdst)), ifp->if_xname);
785 	mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait);
786 }
787 
788 int
789 mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin,
790     struct in6_addr *group, int vidx, unsigned int rtableid, int wait)
791 {
792 	struct ifnet *ifp;
793 	struct mif6 *m6;
794 	struct mf6cctl mf6cc;
795 
796 	ifp = mrt6_iflookupbymif(vidx, rtableid);
797 	if (ifp == NULL ||
798 	    (m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
799 		return ENOENT;
800 
801 	memset(&mf6cc, 0, sizeof(mf6cc));
802 	if (mfccp == NULL) {
803 		mf6cc.mf6cc_origin.sin6_family = AF_INET6;
804 		mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin);
805 		mf6cc.mf6cc_origin.sin6_addr = *origin;
806 		mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET6;
807 		mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp);
808 		mf6cc.mf6cc_mcastgrp.sin6_addr = *group;
809 		mf6cc.mf6cc_parent = vidx;
810 	} else
811 		memcpy(&mf6cc, mfccp, sizeof(mf6cc));
812 
813 	mf6c_update(&mf6cc, wait, rtableid);
814 
815 	return 0;
816 }
817 
818 int
819 add_m6fc(struct socket *so, struct mf6cctl *mfccp)
820 {
821 	struct inpcb *inp = sotoinpcb(so);
822 	unsigned int rtableid = inp->inp_rtableid;
823 
824 	NET_ASSERT_LOCKED();
825 
826 	return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr,
827 	    &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent,
828 	    rtableid, M_WAITOK);
829 }
830 
831 int
832 del_m6fc(struct socket *so, struct mf6cctl *mfccp)
833 {
834 	struct inpcb *inp = sotoinpcb(so);
835 	struct rtentry *rt;
836 	unsigned int rtableid = inp->inp_rtableid;
837 
838 	NET_ASSERT_LOCKED();
839 
840 	while ((rt = mf6c_find(NULL, &mfccp->mf6cc_origin.sin6_addr,
841 	    &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
842 		mrt6_mcast_del(rt, rtableid);
843 		rtfree(rt);
844 	}
845 
846 	return 0;
847 }
848 
849 int
850 socket6_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
851 {
852 	if (s) {
853 		if (sbappendaddr(s, &s->so_rcv, sin6tosa(src), mm, NULL) != 0) {
854 			sorwakeup(s);
855 			return 0;
856 		}
857 	}
858 	m_freem(mm);
859 	return -1;
860 }
861 
862 /*
863  * IPv6 multicast forwarding function. This function assumes that the packet
864  * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
865  * pointed to by "ifp", and the packet is to be relayed to other networks
866  * that have members of the packet's destination IPv6 multicast group.
867  *
868  * The packet is returned unscathed to the caller, unless it is
869  * erroneous, in which case a non-zero return value tells the caller to
870  * discard it.
871  */
872 int
873 ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
874 {
875 	struct rtentry *rt;
876 	struct mif6 *mifp;
877 	struct mbuf *mm;
878 	struct sockaddr_in6 sin6;
879 	unsigned int rtableid = ifp->if_rdomain;
880 
881 	NET_ASSERT_LOCKED();
882 
883 	/*
884 	 * Don't forward a packet with Hop limit of zero or one,
885 	 * or a packet destined to a local-only group.
886 	 */
887 	if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
888 	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
889 		return 0;
890 	ip6->ip6_hlim--;
891 
892 	/*
893 	 * Source address check: do not forward packets with unspecified
894 	 * source. It was discussed in July 2000, on ipngwg mailing list.
895 	 * This is rather more serious than unicast cases, because some
896 	 * MLD packets can be sent with the unspecified source address
897 	 * (although such packets must normally set 1 to the hop limit field).
898 	 */
899 	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
900 		ip6stat_inc(ip6s_cantforward);
901 		if (ip6_log_time + ip6_log_interval < getuptime()) {
902 			char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
903 
904 			ip6_log_time = getuptime();
905 
906 			inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src));
907 			inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst));
908 			log(LOG_DEBUG, "cannot forward "
909 			    "from %s to %s nxt %d received on interface %u\n",
910 			    src, dst, ip6->ip6_nxt, m->m_pkthdr.ph_ifidx);
911 		}
912 		return 0;
913 	}
914 
915 	/*
916 	 * Determine forwarding mifs from the forwarding cache table
917 	 */
918 	rt = mf6c_find(NULL, &ip6->ip6_src, &ip6->ip6_dst, rtableid);
919 
920 	/* Entry exists, so forward if necessary */
921 	if (rt) {
922 		return (ip6_mdq(m, ifp, rt));
923 	} else {
924 		/*
925 		 * If we don't have a route for packet's origin,
926 		 * Make a copy of the packet &
927 		 * send message to routing daemon
928 		 */
929 
930 		mrt6stat.mrt6s_no_route++;
931 
932 		{
933 			struct mrt6msg *im;
934 
935 			if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
936 				return EHOSTUNREACH;
937 
938 			/*
939 			 * Make a copy of the header to send to the user
940 			 * level process
941 			 */
942 			mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT);
943 			if (mm == NULL)
944 				return ENOBUFS;
945 
946 			/*
947 			 * Send message to routing daemon
948 			 */
949 			(void)memset(&sin6, 0, sizeof(sin6));
950 			sin6.sin6_len = sizeof(sin6);
951 			sin6.sin6_family = AF_INET6;
952 			sin6.sin6_addr = ip6->ip6_src;
953 
954 			im = NULL;
955 			switch (ip6_mrouter_ver) {
956 			case MRT6_INIT:
957 				im = mtod(mm, struct mrt6msg *);
958 				im->im6_msgtype = MRT6MSG_NOCACHE;
959 				im->im6_mbz = 0;
960 				im->im6_mif = mifp->m6_mifi;
961 				break;
962 			default:
963 				m_freem(mm);
964 				return EINVAL;
965 			}
966 
967 			if (socket6_send(ip6_mrouter[rtableid], mm,
968 			    &sin6) < 0) {
969 				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
970 				    "socket queue full\n");
971 				mrt6stat.mrt6s_upq_sockfull++;
972 				return ENOBUFS;
973 			}
974 
975 			mrt6stat.mrt6s_upcalls++;
976 
977 			mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst,
978 			    mifp->m6_mifi, rtableid, M_NOWAIT);
979 		}
980 
981 		return 0;
982 	}
983 }
984 
985 void
986 mf6c_expire_route(struct rtentry *rt, u_int rtableid)
987 {
988 	struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
989 #ifdef MCAST_DEBUG
990 	char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
991 #endif /* MCAST_DEBUG */
992 
993 	/* Skip entry being deleted. */
994 	if (mf6c == NULL)
995 		return;
996 
997 	DPRINTF("origin %s group %s interface %d expire %s",
998 	    inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,
999 	    bsrc, sizeof(bsrc)),
1000 	    inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,
1001 	    bdst, sizeof(bdst)), rt->rt_ifidx,
1002 	    mf6c->mf6c_expire ? "yes" : "no");
1003 
1004 	if (mf6c->mf6c_expire == 0) {
1005 		mf6c->mf6c_expire = 1;
1006 		rt_timer_add(rt, &ip6_mrouterq, rtableid);
1007 		return;
1008 	}
1009 
1010 	mrt6_mcast_del(rt, rtableid);
1011 }
1012 
1013 /*
1014  * Packet forwarding routine once entry in the cache is made
1015  */
1016 int
1017 ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
1018 {
1019 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1020 	struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6;
1021 	struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
1022 	struct ifnet *ifn;
1023 	int plen = m->m_pkthdr.len;
1024 
1025 	if (mifp == NULL || mf6c == NULL) {
1026 		rtfree(rt);
1027 		return EHOSTUNREACH;
1028 	}
1029 
1030 	/*
1031 	 * Don't forward if it didn't arrive from the parent mif
1032 	 * for its origin.
1033 	 */
1034 	if (mifp->m6_mifi != mf6c->mf6c_parent) {
1035 		/* came in the wrong interface */
1036 		mrt6stat.mrt6s_wrong_if++;
1037 		mf6c->mf6c_wrong_if++;
1038 		rtfree(rt);
1039 		return 0;
1040 	}			/* if wrong iif */
1041 
1042 	/* If I sourced this packet, it counts as output, else it was input. */
1043 	if (m->m_pkthdr.ph_ifidx == 0) {
1044 		/* XXX: is ph_ifidx really 0 when output?? */
1045 		mifp->m6_pkt_out++;
1046 		mifp->m6_bytes_out += plen;
1047 	} else {
1048 		mifp->m6_pkt_in++;
1049 		mifp->m6_bytes_in += plen;
1050 	}
1051 
1052 	/*
1053 	 * For each mif, forward a copy of the packet if there are group
1054 	 * members downstream on the interface.
1055 	 */
1056 	do {
1057 		/* Don't consider non multicast routes. */
1058 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1059 		    (RTF_HOST | RTF_MULTICAST))
1060 			continue;
1061 
1062 		mf6c = (struct mf6c *)rt->rt_llinfo;
1063 		if (mf6c == NULL)
1064 			continue;
1065 
1066 		mf6c->mf6c_pkt_cnt++;
1067 		mf6c->mf6c_byte_cnt += m->m_pkthdr.len;
1068 
1069 		/* Don't let this route expire. */
1070 		mf6c->mf6c_expire = 0;
1071 
1072 		if ((ifn = if_get(rt->rt_ifidx)) == NULL)
1073 			continue;
1074 
1075 		/* Sanity check: did we configure this? */
1076 		if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL) {
1077 			if_put(ifn);
1078 			continue;
1079 		}
1080 
1081 		/* Don't send in the upstream interface. */
1082 		if (mf6c->mf6c_parent == m6->m6_mifi) {
1083 			if_put(ifn);
1084 			continue;
1085 		}
1086 
1087 		/*
1088 		 * check if the outgoing packet is going to break
1089 		 * a scope boundary.
1090 		 */
1091 		if ((mifp->m6_flags & MIFF_REGISTER) == 0 &&
1092 		    (m6->m6_flags & MIFF_REGISTER) == 0 &&
1093 		    (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) !=
1094 		    in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) ||
1095 		    in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) !=
1096 		    in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) {
1097 			if_put(ifn);
1098 			ip6stat_inc(ip6s_badscope);
1099 			continue;
1100 		}
1101 
1102 		m6->m6_pkt_out++;
1103 		m6->m6_bytes_out += plen;
1104 
1105 		phyint_send6(ifn, ip6, m);
1106 		if_put(ifn);
1107 	} while ((rt = rtable_iterate(rt)) != NULL);
1108 
1109 	return 0;
1110 }
1111 
1112 void
1113 phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
1114 {
1115 	struct mbuf *mb_copy;
1116 	struct sockaddr_in6 *dst6, sin6;
1117 	int error = 0;
1118 
1119 	NET_ASSERT_LOCKED();
1120 
1121 	/*
1122 	 * Make a new reference to the packet; make sure that
1123 	 * the IPv6 header is actually copied, not just referenced,
1124 	 * so that ip6_output() only scribbles on the copy.
1125 	 */
1126 	mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1127 	if (mb_copy == NULL)
1128 		return;
1129 	/* set MCAST flag to the outgoing packet */
1130 	mb_copy->m_flags |= M_MCAST;
1131 
1132 	/*
1133 	 * If we sourced the packet, call ip6_output since we may divide
1134 	 * the packet into fragments when the packet is too big for the
1135 	 * outgoing interface.
1136 	 * Otherwise, we can simply send the packet to the interface
1137 	 * sending queue.
1138 	 */
1139 	if (m->m_pkthdr.ph_ifidx == 0) {
1140 		struct ip6_moptions im6o;
1141 
1142 		im6o.im6o_ifidx = ifp->if_index;
1143 		/* XXX: ip6_output will override ip6->ip6_hlim */
1144 		im6o.im6o_hlim = ip6->ip6_hlim;
1145 		im6o.im6o_loop = 1;
1146 		error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
1147 		    NULL);
1148 		return;
1149 	}
1150 
1151 	/*
1152 	 * If we belong to the destination multicast group
1153 	 * on the outgoing interface, loop back a copy.
1154 	 */
1155 	dst6 = &sin6;
1156 	memset(&sin6, 0, sizeof(sin6));
1157 	if (in6_hasmulti(&ip6->ip6_dst, ifp)) {
1158 		dst6->sin6_len = sizeof(struct sockaddr_in6);
1159 		dst6->sin6_family = AF_INET6;
1160 		dst6->sin6_addr = ip6->ip6_dst;
1161 		ip6_mloopback(ifp, m, dst6);
1162 	}
1163 	/*
1164 	 * Put the packet into the sending queue of the outgoing interface
1165 	 * if it would fit in the MTU of the interface.
1166 	 */
1167 	if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
1168 		dst6->sin6_len = sizeof(struct sockaddr_in6);
1169 		dst6->sin6_family = AF_INET6;
1170 		dst6->sin6_addr = ip6->ip6_dst;
1171 		error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL);
1172 	} else {
1173 		if (ip6_mcast_pmtu)
1174 			icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0,
1175 			    ifp->if_mtu);
1176 		else {
1177 			m_freem(mb_copy); /* simply discard the packet */
1178 		}
1179 	}
1180 }
1181 
1182 struct ifnet *
1183 mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid)
1184 {
1185 	struct mif6	*m6;
1186 	struct ifnet	*ifp;
1187 
1188 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1189 		if (ifp->if_rdomain != rtableid)
1190 			continue;
1191 		if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
1192 			continue;
1193 		if (m6->m6_mifi != mifi)
1194 			continue;
1195 
1196 		return ifp;
1197 	}
1198 
1199 	return NULL;
1200 }
1201 
1202 struct rtentry *
1203 mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group,
1204     unsigned int rtableid)
1205 {
1206 	struct rtentry *rt;
1207 	struct sockaddr_in6 msin6;
1208 
1209 	memset(&msin6, 0, sizeof(msin6));
1210 	msin6.sin6_family = AF_INET6;
1211 	msin6.sin6_len = sizeof(msin6);
1212 	msin6.sin6_addr = *group;
1213 
1214 	rt = rtalloc(sin6tosa(&msin6), 0, rtableid);
1215 	do {
1216 		if (!rtisvalid(rt)) {
1217 			rtfree(rt);
1218 			return NULL;
1219 		}
1220 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1221 		    (RTF_HOST | RTF_MULTICAST))
1222 			continue;
1223 		/* Return first occurrence if interface is not specified. */
1224 		if (ifp == NULL)
1225 			return rt;
1226 		if (rt->rt_ifidx == ifp->if_index)
1227 			return rt;
1228 	} while ((rt = rtable_iterate(rt)) != NULL);
1229 
1230 	return NULL;
1231 }
1232 
1233 struct rtentry *
1234 mrt6_mcast_add(struct ifnet *ifp, struct sockaddr *origin,
1235     struct sockaddr *group)
1236 {
1237 	struct ifaddr *ifa;
1238 	int rv;
1239 	unsigned int rtableid = ifp->if_rdomain;
1240 
1241 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1242 		if (ifa->ifa_addr->sa_family == AF_INET6)
1243 			break;
1244 	}
1245 	if (ifa == NULL) {
1246 		DPRINTF("ifa == NULL");
1247 		return NULL;
1248 	}
1249 
1250 	rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH, group,
1251 	    ifp->if_rdomain);
1252 	if (rv != 0) {
1253 		DPRINTF("rt_ifa_add failed %d", rv);
1254 		return NULL;
1255 	}
1256 
1257 	return mf6c_find(ifp, NULL, &satosin6(group)->sin6_addr, rtableid);
1258 }
1259 
1260 void
1261 mrt6_mcast_del(struct rtentry *rt, unsigned int rtableid)
1262 {
1263 	struct ifnet *ifp;
1264 	int error;
1265 
1266 	/* Remove all timers related to this route. */
1267 	rt_timer_remove_all(rt);
1268 
1269 	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mf6c));
1270 	rt->rt_llinfo = NULL;
1271 
1272 	ifp = if_get(rt->rt_ifidx);
1273 	if (ifp == NULL)
1274 		return;
1275 	error = rtdeletemsg(rt, ifp, rtableid);
1276 	if_put(ifp);
1277 
1278 	if (error)
1279 		DPRINTF("delete route error %d\n", error);
1280 }
1281