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