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