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