xref: /openbsd-src/sys/netinet/ip_mroute.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: ip_mroute.c,v 1.130 2020/05/27 11:19:29 mpi Exp $	*/
2 /*	$NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $	*/
3 
4 /*
5  * Copyright (c) 1989 Stephen Deering
6  * Copyright (c) 1992, 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Stephen Deering of Stanford University.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
37  */
38 
39 /*
40  * IP multicast forwarding procedures
41  *
42  * Written by David Waitzman, BBN Labs, August 1988.
43  * Modified by Steve Deering, Stanford, February 1989.
44  * Modified by Mark J. Steiglitz, Stanford, May, 1991
45  * Modified by Van Jacobson, LBL, January 1993
46  * Modified by Ajit Thyagarajan, PARC, August 1993
47  * Modified by Bill Fenner, PARC, April 1994
48  * Modified by Charles M. Hannum, NetBSD, May 1995.
49  * Modified by Ahmed Helmy, SGI, June 1996
50  * Modified by George Edmond Eddy (Rusty), ISI, February 1998
51  * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000
52  * Modified by Hitoshi Asaeda, WIDE, August 2000
53  * Modified by Pavlin Radoslavov, ICSI, October 2002
54  *
55  * MROUTING Revision: 1.2
56  * advanced API support, bandwidth metering and signaling
57  */
58 
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/mbuf.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/protosw.h>
65 #include <sys/ioctl.h>
66 #include <sys/syslog.h>
67 
68 #include <net/if.h>
69 #include <net/if_var.h>
70 #include <net/route.h>
71 
72 #include <netinet/in.h>
73 #include <netinet/ip.h>
74 #include <netinet/ip_var.h>
75 #include <netinet/in_pcb.h>
76 #include <netinet/igmp.h>
77 #include <netinet/ip_mroute.h>
78 
79 /* #define MCAST_DEBUG */
80 
81 #ifdef MCAST_DEBUG
82 int mcast_debug = 1;
83 #define DPRINTF(fmt, args...)						\
84 	do {								\
85 		if (mcast_debug)					\
86 			printf("%s:%d " fmt "\n",			\
87 			    __func__, __LINE__, ## args);		\
88 	} while (0)
89 #else
90 #define DPRINTF(fmt, args...)			\
91 	do { } while (0)
92 #endif
93 
94 /*
95  * Globals.  All but ip_mrouter and ip_mrtproto could be static,
96  * except for netstat or debugging purposes.
97  */
98 struct socket	*ip_mrouter[RT_TABLEID_MAX + 1];
99 struct rttimer_queue *mrouterq[RT_TABLEID_MAX + 1];
100 uint64_t	 mrt_count[RT_TABLEID_MAX + 1];
101 int		ip_mrtproto = IGMP_DVMRP;    /* for netstat only */
102 
103 struct mrtstat	mrtstat;
104 
105 struct rtentry	*mfc_find(struct ifnet *, struct in_addr *,
106     struct in_addr *, unsigned int);
107 int get_sg_cnt(unsigned int, struct sioc_sg_req *);
108 int get_vif_cnt(unsigned int, struct sioc_vif_req *);
109 int mrt_rtwalk_mfcsysctl(struct rtentry *, void *, unsigned int);
110 int ip_mrouter_init(struct socket *, struct mbuf *);
111 int mrouter_rtwalk_delete(struct rtentry *, void *, unsigned int);
112 int get_version(struct mbuf *);
113 int add_vif(struct socket *, struct mbuf *);
114 int del_vif(struct socket *, struct mbuf *);
115 void update_mfc_params(struct mfcctl2 *, int, unsigned int);
116 void mfc_expire_route(struct rtentry *, struct rttimer *);
117 int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
118     int, unsigned int, int);
119 int add_mfc(struct socket *, struct mbuf *);
120 int del_mfc(struct socket *, struct mbuf *);
121 int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
122 int get_api_support(struct mbuf *);
123 int get_api_config(struct mbuf *);
124 int socket_send(struct socket *, struct mbuf *,
125 			    struct sockaddr_in *);
126 int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
127 struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
128 struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
129     struct sockaddr *);
130 void mrt_mcast_del(struct rtentry *, unsigned int);
131 
132 /*
133  * Kernel multicast routing API capabilities and setup.
134  * If more API capabilities are added to the kernel, they should be
135  * recorded in `mrt_api_support'.
136  */
137 static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
138 					  MRT_MFC_RP);
139 static u_int32_t mrt_api_config = 0;
140 
141 /*
142  * Find a route for a given origin IP address and Multicast group address
143  * Type of service parameter to be added in the future!!!
144  * Statistics are updated by the caller if needed
145  * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
146  */
147 struct rtentry *
148 mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
149     unsigned int rtableid)
150 {
151 	struct rtentry		*rt;
152 	struct sockaddr_in	 msin;
153 
154 	memset(&msin, 0, sizeof(msin));
155 	msin.sin_len = sizeof(msin);
156 	msin.sin_family = AF_INET;
157 	msin.sin_addr = *group;
158 
159 	rt = rtalloc(sintosa(&msin), 0, rtableid);
160 	do {
161 		if (!rtisvalid(rt)) {
162 			rtfree(rt);
163 			return NULL;
164 		}
165 		/* Don't consider non multicast routes. */
166 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
167 		    (RTF_HOST | RTF_MULTICAST))
168 			continue;
169 		/* Return first occurrence if interface is not specified. */
170 		if (ifp == NULL)
171 			return (rt);
172 		if (rt->rt_ifidx == ifp->if_index)
173 			return (rt);
174 	} while ((rt = rtable_iterate(rt)) != NULL);
175 
176 	return (NULL);
177 }
178 
179 /*
180  * Handle MRT setsockopt commands to modify the multicast routing tables.
181  */
182 int
183 ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
184 {
185 	struct inpcb *inp = sotoinpcb(so);
186 	int error;
187 
188 	if (optname != MRT_INIT &&
189 	    so != ip_mrouter[inp->inp_rtableid])
190 		error = ENOPROTOOPT;
191 	else
192 		switch (optname) {
193 		case MRT_INIT:
194 			error = ip_mrouter_init(so, m);
195 			break;
196 		case MRT_DONE:
197 			error = ip_mrouter_done(so);
198 			break;
199 		case MRT_ADD_VIF:
200 			error = add_vif(so, m);
201 			break;
202 		case MRT_DEL_VIF:
203 			error = del_vif(so, m);
204 			break;
205 		case MRT_ADD_MFC:
206 			error = add_mfc(so, m);
207 			break;
208 		case MRT_DEL_MFC:
209 			error = del_mfc(so, m);
210 			break;
211 		case MRT_API_CONFIG:
212 			error = set_api_config(so, m);
213 			break;
214 		default:
215 			error = ENOPROTOOPT;
216 			break;
217 		}
218 
219 	return (error);
220 }
221 
222 /*
223  * Handle MRT getsockopt commands
224  */
225 int
226 ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
227 {
228 	struct inpcb *inp = sotoinpcb(so);
229 	int error;
230 
231 	if (so != ip_mrouter[inp->inp_rtableid])
232 		error = ENOPROTOOPT;
233 	else {
234 		switch (optname) {
235 		case MRT_VERSION:
236 			error = get_version(m);
237 			break;
238 		case MRT_API_SUPPORT:
239 			error = get_api_support(m);
240 			break;
241 		case MRT_API_CONFIG:
242 			error = get_api_config(m);
243 			break;
244 		default:
245 			error = ENOPROTOOPT;
246 			break;
247 		}
248 	}
249 
250 	return (error);
251 }
252 
253 /*
254  * Handle ioctl commands to obtain information from the cache
255  */
256 int
257 mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
258 {
259 	struct inpcb *inp = sotoinpcb(so);
260 	int error;
261 
262 	if (inp == NULL)
263 		return (ENOTCONN);
264 
265 	if (so != ip_mrouter[inp->inp_rtableid])
266 		error = EINVAL;
267 	else
268 		switch (cmd) {
269 		case SIOCGETVIFCNT:
270 			NET_RLOCK_IN_IOCTL();
271 			error = get_vif_cnt(inp->inp_rtableid,
272 			    (struct sioc_vif_req *)data);
273 			NET_RUNLOCK_IN_IOCTL();
274 			break;
275 		case SIOCGETSGCNT:
276 			NET_RLOCK_IN_IOCTL();
277 			error = get_sg_cnt(inp->inp_rtableid,
278 			    (struct sioc_sg_req *)data);
279 			NET_RUNLOCK_IN_IOCTL();
280 			break;
281 		default:
282 			error = ENOTTY;
283 			break;
284 		}
285 
286 	return (error);
287 }
288 
289 /*
290  * returns the packet, byte, rpf-failure count for the source group provided
291  */
292 int
293 get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
294 {
295 	struct rtentry *rt;
296 	struct mfc *mfc;
297 
298 	rt = mfc_find(NULL, &req->src, &req->grp, rtableid);
299 	if (rt == NULL) {
300 		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
301 		return (EADDRNOTAVAIL);
302 	}
303 
304 	req->pktcnt = req->bytecnt = req->wrong_if = 0;
305 	do {
306 		/* Don't consider non multicast routes. */
307 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
308 		    (RTF_HOST | RTF_MULTICAST))
309 			continue;
310 
311 		mfc = (struct mfc *)rt->rt_llinfo;
312 		if (mfc == NULL)
313 			continue;
314 
315 		req->pktcnt += mfc->mfc_pkt_cnt;
316 		req->bytecnt += mfc->mfc_byte_cnt;
317 		req->wrong_if += mfc->mfc_wrong_if;
318 	} while ((rt = rtable_iterate(rt)) != NULL);
319 
320 	return (0);
321 }
322 
323 /*
324  * returns the input and output packet and byte counts on the vif provided
325  */
326 int
327 get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
328 {
329 	struct ifnet	*ifp;
330 	struct vif	*v;
331 	vifi_t		 vifi = req->vifi;
332 
333 	if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL)
334 		return (EINVAL);
335 
336 	v = (struct vif *)ifp->if_mcast;
337 	req->icount = v->v_pkt_in;
338 	req->ocount = v->v_pkt_out;
339 	req->ibytes = v->v_bytes_in;
340 	req->obytes = v->v_bytes_out;
341 
342 	return (0);
343 }
344 
345 int
346 mrt_sysctl_vif(void *oldp, size_t *oldlenp)
347 {
348 	caddr_t where = oldp;
349 	size_t needed, given;
350 	struct ifnet *ifp;
351 	struct vif *vifp;
352 	struct vifinfo vinfo;
353 
354 	given = *oldlenp;
355 	needed = 0;
356 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
357 		if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
358 			continue;
359 
360 		vinfo.v_vifi = vifp->v_id;
361 		vinfo.v_flags = vifp->v_flags;
362 		vinfo.v_threshold = vifp->v_threshold;
363 		vinfo.v_lcl_addr = vifp->v_lcl_addr;
364 		vinfo.v_rmt_addr = vifp->v_rmt_addr;
365 		vinfo.v_pkt_in = vifp->v_pkt_in;
366 		vinfo.v_pkt_out = vifp->v_pkt_out;
367 		vinfo.v_bytes_in = vifp->v_bytes_in;
368 		vinfo.v_bytes_out = vifp->v_bytes_out;
369 
370 		needed += sizeof(vinfo);
371 		if (where && needed <= given) {
372 			int error;
373 
374 			error = copyout(&vinfo, where, sizeof(vinfo));
375 			if (error)
376 				return (error);
377 			where += sizeof(vinfo);
378 		}
379 	}
380 	if (where) {
381 		*oldlenp = needed;
382 		if (given < needed)
383 			return (ENOMEM);
384 	} else
385 		*oldlenp = (11 * needed) / 10;
386 
387 	return (0);
388 }
389 
390 struct mfcsysctlarg {
391 	struct mfcinfo	*msa_minfos;
392 	size_t		 msa_len;
393 	size_t		 msa_needed;
394 };
395 
396 int
397 mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
398 {
399 	struct mfc		*mfc = (struct mfc *)rt->rt_llinfo;
400 	struct mfcsysctlarg	*msa = (struct mfcsysctlarg *)arg;
401 	struct ifnet		*ifp;
402 	struct vif		*v;
403 	struct mfcinfo		*minfo;
404 	int			 new = 0;
405 
406 	/* Skip entries being removed. */
407 	if (mfc == NULL)
408 		return (0);
409 
410 	/* Skip non-multicast routes. */
411 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
412 	    (RTF_HOST | RTF_MULTICAST))
413 		return (0);
414 
415 	/* User just asked for the output size. */
416 	if (msa->msa_minfos == NULL) {
417 		msa->msa_needed += sizeof(*minfo);
418 		return (0);
419 	}
420 
421 	/* Skip route with invalid interfaces. */
422 	if ((ifp = if_get(rt->rt_ifidx)) == NULL)
423 		return (0);
424 	if ((v = (struct vif *)ifp->if_mcast) == NULL) {
425 		if_put(ifp);
426 		return (0);
427 	}
428 
429 	for (minfo = msa->msa_minfos;
430 	     (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
431 	     minfo++) {
432 		/* Find a new entry or update old entry. */
433 		if (minfo->mfc_origin.s_addr !=
434 		    satosin(rt->rt_gateway)->sin_addr.s_addr ||
435 		    minfo->mfc_mcastgrp.s_addr !=
436 		    satosin(rt_key(rt))->sin_addr.s_addr) {
437 			if (minfo->mfc_origin.s_addr != 0 ||
438 			    minfo->mfc_mcastgrp.s_addr != 0)
439 				continue;
440 
441 			new = 1;
442 		}
443 
444 		minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
445 		minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
446 		minfo->mfc_parent = mfc->mfc_parent;
447 		minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
448 		minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
449 		minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
450 		break;
451 	}
452 
453 	if (new != 0)
454 		msa->msa_needed += sizeof(*minfo);
455 
456 	if_put(ifp);
457 
458 	return (0);
459 }
460 
461 int
462 mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
463 {
464 	unsigned int		 rtableid;
465 	int			 error;
466 	struct mfcsysctlarg	 msa;
467 
468 	if (oldp != NULL && *oldlenp > MAXPHYS)
469 		return (EINVAL);
470 
471 	if (oldp != NULL)
472 		msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
473 	else
474 		msa.msa_minfos = NULL;
475 
476 	msa.msa_len = *oldlenp;
477 	msa.msa_needed = 0;
478 
479 	for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
480 		rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl,
481 		    &msa);
482 	}
483 
484 	if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
485 	    (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
486 		free(msa.msa_minfos, M_TEMP, *oldlenp);
487 		return (error);
488 	}
489 
490 	free(msa.msa_minfos, M_TEMP, *oldlenp);
491 	*oldlenp = msa.msa_needed;
492 
493 	return (0);
494 }
495 
496 /*
497  * Enable multicast routing
498  */
499 int
500 ip_mrouter_init(struct socket *so, struct mbuf *m)
501 {
502 	struct inpcb *inp = sotoinpcb(so);
503 	unsigned int rtableid = inp->inp_rtableid;
504 	int *v;
505 
506 	if (so->so_type != SOCK_RAW ||
507 	    so->so_proto->pr_protocol != IPPROTO_IGMP)
508 		return (EOPNOTSUPP);
509 
510 	if (m == NULL || m->m_len < sizeof(int))
511 		return (EINVAL);
512 
513 	v = mtod(m, int *);
514 	if (*v != 1)
515 		return (EINVAL);
516 
517 	if (ip_mrouter[rtableid] != NULL ||
518 	    mrouterq[rtableid] != NULL)
519 		return (EADDRINUSE);
520 
521 	ip_mrouter[rtableid] = so;
522 	mrouterq[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_FREQUENCY);
523 
524 	return (0);
525 }
526 
527 int
528 mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
529 {
530 	/* Skip non-multicast routes. */
531 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
532 	    (RTF_HOST | RTF_MULTICAST))
533 		return (0);
534 
535 	return EEXIST;
536 }
537 
538 /*
539  * Disable multicast routing
540  */
541 int
542 ip_mrouter_done(struct socket *so)
543 {
544 	struct inpcb *inp = sotoinpcb(so);
545 	struct ifnet *ifp;
546 	unsigned int rtableid = inp->inp_rtableid;
547 	int error;
548 
549 	NET_ASSERT_LOCKED();
550 
551 	/* Delete all remaining installed multicast routes. */
552 	do {
553 		struct rtentry *rt = NULL;
554 
555 		error = rtable_walk(rtableid, AF_INET, &rt,
556 		    mrouter_rtwalk_delete, NULL);
557 		if (rt != NULL && error == EEXIST) {
558 			mrt_mcast_del(rt, rtableid);
559 			error = EAGAIN;
560 		}
561 		rtfree(rt);
562 	} while (error == EAGAIN);
563 
564 	/* Unregister all interfaces in the domain. */
565 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
566 		if (ifp->if_rdomain != rtableid)
567 			continue;
568 
569 		vif_delete(ifp);
570 	}
571 
572 	mrt_api_config = 0;
573 
574 	rt_timer_queue_destroy(mrouterq[rtableid]);
575 	mrouterq[rtableid] = NULL;
576 	ip_mrouter[rtableid] = NULL;
577 	mrt_count[rtableid] = 0;
578 
579 	return (0);
580 }
581 
582 int
583 get_version(struct mbuf *m)
584 {
585 	int *v = mtod(m, int *);
586 
587 	*v = 0x0305;	/* XXX !!!! */
588 	m->m_len = sizeof(int);
589 	return (0);
590 }
591 
592 /*
593  * Configure API capabilities
594  */
595 int
596 set_api_config(struct socket *so, struct mbuf *m)
597 {
598 	struct inpcb *inp = sotoinpcb(so);
599 	struct ifnet *ifp;
600 	u_int32_t *apival;
601 	unsigned int rtableid = inp->inp_rtableid;
602 
603 	if (m == NULL || m->m_len < sizeof(u_int32_t))
604 		return (EINVAL);
605 
606 	apival = mtod(m, u_int32_t *);
607 
608 	/*
609 	 * We can set the API capabilities only if it is the first operation
610 	 * after MRT_INIT. I.e.:
611 	 *  - there are no vifs installed
612 	 *  - the MFC table is empty
613 	 */
614 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
615 		if (ifp->if_rdomain != rtableid)
616 			continue;
617 		if (ifp->if_mcast == NULL)
618 			continue;
619 
620 		*apival = 0;
621 		return (EPERM);
622 	}
623 	if (mrt_count[rtableid] > 0) {
624 		*apival = 0;
625 		return (EPERM);
626 	}
627 
628 	mrt_api_config = *apival & mrt_api_support;
629 	*apival = mrt_api_config;
630 
631 	return (0);
632 }
633 
634 /*
635  * Get API capabilities
636  */
637 int
638 get_api_support(struct mbuf *m)
639 {
640 	u_int32_t *apival;
641 
642 	if (m == NULL || m->m_len < sizeof(u_int32_t))
643 		return (EINVAL);
644 
645 	apival = mtod(m, u_int32_t *);
646 
647 	*apival = mrt_api_support;
648 
649 	return (0);
650 }
651 
652 /*
653  * Get API configured capabilities
654  */
655 int
656 get_api_config(struct mbuf *m)
657 {
658 	u_int32_t *apival;
659 
660 	if (m == NULL || m->m_len < sizeof(u_int32_t))
661 		return (EINVAL);
662 
663 	apival = mtod(m, u_int32_t *);
664 
665 	*apival = mrt_api_config;
666 
667 	return (0);
668 }
669 
670 static struct sockaddr_in sin = { sizeof(sin), AF_INET };
671 
672 int
673 add_vif(struct socket *so, struct mbuf *m)
674 {
675 	struct inpcb *inp = sotoinpcb(so);
676 	struct vifctl *vifcp;
677 	struct vif *vifp;
678 	struct ifaddr *ifa;
679 	struct ifnet *ifp;
680 	struct ifreq ifr;
681 	int error;
682 	unsigned int rtableid = inp->inp_rtableid;
683 
684 	NET_ASSERT_LOCKED();
685 
686 	if (m == NULL || m->m_len < sizeof(struct vifctl))
687 		return (EINVAL);
688 
689 	vifcp = mtod(m, struct vifctl *);
690 	if (vifcp->vifc_vifi >= MAXVIFS)
691 		return (EINVAL);
692 	if (in_nullhost(vifcp->vifc_lcl_addr))
693 		return (EADDRNOTAVAIL);
694 	if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
695 		return (EADDRINUSE);
696 
697 	/* Tunnels are no longer supported use gif(4) instead. */
698 	if (vifcp->vifc_flags & VIFF_TUNNEL)
699 		return (EOPNOTSUPP);
700 	{
701 		sin.sin_addr = vifcp->vifc_lcl_addr;
702 		ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
703 		if (ifa == NULL)
704 			return (EADDRNOTAVAIL);
705 	}
706 
707 	/* Use the physical interface associated with the address. */
708 	ifp = ifa->ifa_ifp;
709 	if (ifp->if_mcast != NULL)
710 		return (EADDRINUSE);
711 
712 	{
713 		/* Make sure the interface supports multicast. */
714 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
715 			return (EOPNOTSUPP);
716 
717 		/* Enable promiscuous reception of all IP multicasts. */
718 		memset(&ifr, 0, sizeof(ifr));
719 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
720 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
721 		satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
722 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
723 		if (error)
724 			return (error);
725 	}
726 
727 	vifp = malloc(sizeof(*vifp), M_MRTABLE, M_WAITOK | M_ZERO);
728 	ifp->if_mcast = (caddr_t)vifp;
729 
730 	vifp->v_id = vifcp->vifc_vifi;
731 	vifp->v_flags = vifcp->vifc_flags;
732 	vifp->v_threshold = vifcp->vifc_threshold;
733 	vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
734 	vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
735 
736 	return (0);
737 }
738 
739 int
740 del_vif(struct socket *so, struct mbuf *m)
741 {
742 	struct inpcb *inp = sotoinpcb(so);
743 	struct ifnet *ifp;
744 	vifi_t *vifip;
745 	unsigned int rtableid = inp->inp_rtableid;
746 
747 	NET_ASSERT_LOCKED();
748 
749 	if (m == NULL || m->m_len < sizeof(vifi_t))
750 		return (EINVAL);
751 
752 	vifip = mtod(m, vifi_t *);
753 	if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL)
754 		return (EADDRNOTAVAIL);
755 
756 	vif_delete(ifp);
757 	return (0);
758 }
759 
760 void
761 vif_delete(struct ifnet *ifp)
762 {
763 	struct vif	*v;
764 	struct ifreq	 ifr;
765 
766 	if ((v = (struct vif *)ifp->if_mcast) == NULL)
767 		return;
768 
769 	ifp->if_mcast = NULL;
770 
771 	memset(&ifr, 0, sizeof(ifr));
772 	satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
773 	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
774 	satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
775 	KERNEL_LOCK();
776 	(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
777 	KERNEL_UNLOCK();
778 
779 	free(v, M_MRTABLE, sizeof(*v));
780 }
781 
782 void
783 mfc_expire_route(struct rtentry *rt, struct rttimer *rtt)
784 {
785 	struct mfc	*mfc = (struct mfc *)rt->rt_llinfo;
786 	unsigned int	 rtableid = rtt->rtt_tableid;
787 
788 	/* Skip entry being deleted. */
789 	if (mfc == NULL)
790 		return;
791 
792 	DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
793 	    "expire %s", rtt->rtt_tableid,
794 	    satosin(rt->rt_gateway)->sin_addr.s_addr,
795 	    satosin(rt_key(rt))->sin_addr.s_addr,
796 	    rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
797 
798 	/* Not expired, add it back to the queue. */
799 	if (mfc->mfc_expire == 0) {
800 		mfc->mfc_expire = 1;
801 		rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
802 		    rtableid);
803 		return;
804 	}
805 
806 	mrt_mcast_del(rt, rtableid);
807 }
808 
809 int
810 mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
811     struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
812 {
813 	struct vif		*v = (struct vif *)ifp->if_mcast;
814 	struct rtentry		*rt;
815 	struct mfc		*mfc;
816 	unsigned int		 rtableid = ifp->if_rdomain;
817 
818 	rt = rt_mcast_add(ifp, origin, group);
819 	if (rt == NULL)
820 		return (EHOSTUNREACH);
821 
822 	mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
823 	if (mfc == NULL) {
824 		DPRINTF("origin %#08X group %#08X parent %d (%s) "
825 		    "malloc failed",
826 		    satosin(origin)->sin_addr.s_addr,
827 		    satosin(group)->sin_addr.s_addr,
828 		    mfccp->mfcc_parent, ifp->if_xname);
829 		mrt_mcast_del(rt, rtableid);
830 		rtfree(rt);
831 		return (ENOMEM);
832 	}
833 
834 	rt->rt_llinfo = (caddr_t)mfc;
835 
836 	rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
837 	    rtableid);
838 
839 	mfc->mfc_parent = mfccp->mfcc_parent;
840 	mfc->mfc_pkt_cnt = 0;
841 	mfc->mfc_byte_cnt = 0;
842 	mfc->mfc_wrong_if = 0;
843 	mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
844 	mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
845 	    MRT_MFC_FLAGS_ALL;
846 	mfc->mfc_expire = 0;
847 
848 	/* set the RP address */
849 	if (mrt_api_config & MRT_MFC_RP)
850 		mfc->mfc_rp = mfccp->mfcc_rp;
851 	else
852 		mfc->mfc_rp = zeroin_addr;
853 
854 	rtfree(rt);
855 
856 	return (0);
857 }
858 
859 void
860 update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
861 {
862 	struct rtentry		*rt;
863 	struct mfc		*mfc;
864 	struct ifnet		*ifp;
865 	int			 i;
866 	struct sockaddr_in	 osin, msin;
867 
868 	memset(&osin, 0, sizeof(osin));
869 	osin.sin_len = sizeof(osin);
870 	osin.sin_family = AF_INET;
871 	osin.sin_addr = mfccp->mfcc_origin;
872 
873 	memset(&msin, 0, sizeof(msin));
874 	msin.sin_len = sizeof(msin);
875 	msin.sin_family = AF_INET;
876 	msin.sin_addr = mfccp->mfcc_mcastgrp;
877 
878 	for (i = 0; i < MAXVIFS; i++) {
879 		/* Don't add/del upstream routes here. */
880 		if (i == mfccp->mfcc_parent)
881 			continue;
882 
883 		/* Test for vif existence and then update the entry. */
884 		if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
885 			continue;
886 
887 		rt = mfc_find(ifp, &mfccp->mfcc_origin,
888 		    &mfccp->mfcc_mcastgrp, rtableid);
889 
890 		/* vif not configured or removed. */
891 		if (mfccp->mfcc_ttls[i] == 0) {
892 			/* Route doesn't exist, nothing to do. */
893 			if (rt == NULL)
894 				continue;
895 
896 			DPRINTF("del route (group %#08X) for vif %d (%s)",
897 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
898 			mrt_mcast_del(rt, rtableid);
899 			rtfree(rt);
900 			continue;
901 		}
902 
903 		/* Route exists, look for changes. */
904 		if (rt != NULL) {
905 			mfc = (struct mfc *)rt->rt_llinfo;
906 			/* Skip route being deleted. */
907 			if (mfc == NULL) {
908 				rtfree(rt);
909 				continue;
910 			}
911 
912 			/* No new changes to apply. */
913 			if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
914 			    mfccp->mfcc_parent == mfc->mfc_parent) {
915 				rtfree(rt);
916 				continue;
917 			}
918 
919 			DPRINTF("update route (group %#08X) for vif %d (%s)",
920 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
921 			mfc->mfc_ttl = mfccp->mfcc_ttls[i];
922 			mfc->mfc_parent = mfccp->mfcc_parent;
923 			rtfree(rt);
924 			continue;
925 		}
926 
927 		DPRINTF("add route (group %#08X) for vif %d (%s)",
928 		    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
929 
930 		mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
931 		    mfccp, wait);
932 	}
933 
934 	/* Create route for the parent interface. */
935 	if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
936 		DPRINTF("failed to find upstream interface %d",
937 		    mfccp->mfcc_parent);
938 		return;
939 	}
940 
941 	/* We already have a route, nothing to do here. */
942 	if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
943 	    &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
944 		rtfree(rt);
945 		return;
946 	}
947 
948 	DPRINTF("add upstream route (group %#08X) for if %s",
949 	    mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
950 	mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
951 }
952 
953 int
954 mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
955     struct in_addr *group, int vidx, unsigned int rtableid, int wait)
956 {
957 	struct ifnet		*ifp;
958 	struct vif		*v;
959 	struct mfcctl2		 mfcctl;
960 
961 	ifp = if_lookupbyvif(vidx, rtableid);
962 	if (ifp == NULL ||
963 	    (v = (struct vif *)ifp->if_mcast) == NULL)
964 		return (EHOSTUNREACH);
965 
966 	memset(&mfcctl, 0, sizeof(mfcctl));
967 	if (mfcctl2 == NULL) {
968 		mfcctl.mfcc_origin = *origin;
969 		mfcctl.mfcc_mcastgrp = *group;
970 		mfcctl.mfcc_parent = vidx;
971 	} else
972 		memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
973 
974 	update_mfc_params(&mfcctl, wait, rtableid);
975 
976 	return (0);
977 }
978 
979 int
980 add_mfc(struct socket *so, struct mbuf *m)
981 {
982 	struct inpcb *inp = sotoinpcb(so);
983 	struct mfcctl2 mfcctl2;
984 	int mfcctl_size = sizeof(struct mfcctl);
985 	unsigned int rtableid = inp->inp_rtableid;
986 
987 	NET_ASSERT_LOCKED();
988 
989 	if (mrt_api_config & MRT_API_FLAGS_ALL)
990 		mfcctl_size = sizeof(struct mfcctl2);
991 
992 	if (m == NULL || m->m_len < mfcctl_size)
993 		return (EINVAL);
994 
995 	/*
996 	 * select data size depending on API version.
997 	 */
998 	if (mrt_api_config & MRT_API_FLAGS_ALL) {
999 		struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
1000 		memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
1001 	} else {
1002 		struct mfcctl *mp = mtod(m, struct mfcctl *);
1003 		memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1004 		memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1005 		    sizeof(mfcctl2) - sizeof(struct mfcctl));
1006 	}
1007 
1008 	if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1009 	    mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
1010 		return (EINVAL);
1011 
1012 	return (0);
1013 }
1014 
1015 int
1016 del_mfc(struct socket *so, struct mbuf *m)
1017 {
1018 	struct inpcb *inp = sotoinpcb(so);
1019 	struct rtentry *rt;
1020 	struct mfcctl2 mfcctl2;
1021 	int mfcctl_size = sizeof(struct mfcctl);
1022 	struct mfcctl *mp;
1023 	unsigned int rtableid = inp->inp_rtableid;
1024 
1025 	NET_ASSERT_LOCKED();
1026 
1027 	/*
1028 	 * XXX: for deleting MFC entries the information in entries
1029 	 * of size "struct mfcctl" is sufficient.
1030 	 */
1031 
1032 	if (m == NULL || m->m_len < mfcctl_size)
1033 		return (EINVAL);
1034 
1035 	mp = mtod(m, struct mfcctl *);
1036 
1037 	memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1038 	memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1039 	    sizeof(mfcctl2) - sizeof(struct mfcctl));
1040 
1041 	DPRINTF("origin %#08X group %#08X rtableid %d",
1042 	    mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
1043 
1044 	while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
1045 	    &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
1046 		mrt_mcast_del(rt, rtableid);
1047 		rtfree(rt);
1048 	}
1049 
1050 	return (0);
1051 }
1052 
1053 int
1054 socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
1055 {
1056 	if (s != NULL) {
1057 		if (sbappendaddr(s, &s->so_rcv, sintosa(src), mm, NULL) != 0) {
1058 			sorwakeup(s);
1059 			return (0);
1060 		}
1061 	}
1062 	m_freem(mm);
1063 	return (-1);
1064 }
1065 
1066 /*
1067  * IP multicast forwarding function. This function assumes that the packet
1068  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1069  * pointed to by "ifp", and the packet is to be relayed to other networks
1070  * that have members of the packet's destination IP multicast group.
1071  *
1072  * The packet is returned unscathed to the caller, unless it is
1073  * erroneous, in which case a non-zero return value tells the caller to
1074  * discard it.
1075  */
1076 
1077 #define IP_HDR_LEN  20	/* # bytes of fixed IP header (excluding options) */
1078 #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
1079 
1080 int
1081 ip_mforward(struct mbuf *m, struct ifnet *ifp)
1082 {
1083 	struct ip *ip = mtod(m, struct ip *);
1084 	struct vif *v;
1085 	struct rtentry *rt;
1086 	static int srctun = 0;
1087 	struct mbuf *mm;
1088 	unsigned int rtableid = ifp->if_rdomain;
1089 
1090 	if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
1091 	    ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
1092 		/*
1093 		 * Packet arrived via a physical interface or
1094 		 * an encapsulated tunnel or a register_vif.
1095 		 */
1096 	} else {
1097 		/*
1098 		 * Packet arrived through a source-route tunnel.
1099 		 * Source-route tunnels are no longer supported.
1100 		 */
1101 		if ((srctun++ % 1000) == 0)
1102 			log(LOG_ERR, "ip_mforward: received source-routed "
1103 			    "packet from %x\n", ntohl(ip->ip_src.s_addr));
1104 		return (EOPNOTSUPP);
1105 	}
1106 
1107 	/*
1108 	 * Don't forward a packet with time-to-live of zero or one,
1109 	 * or a packet destined to a local-only group.
1110 	 */
1111 	if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
1112 		return (0);
1113 
1114 	/*
1115 	 * Determine forwarding vifs from the forwarding cache table
1116 	 */
1117 	++mrtstat.mrts_mfc_lookups;
1118 	rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
1119 
1120 	/* Entry exists, so forward if necessary */
1121 	if (rt != NULL) {
1122 		return (ip_mdq(m, ifp, rt));
1123 	} else {
1124 		/*
1125 		 * If we don't have a route for packet's origin,
1126 		 * Make a copy of the packet & send message to routing daemon
1127 		 */
1128 		int hlen = ip->ip_hl << 2;
1129 
1130 		++mrtstat.mrts_mfc_misses;
1131 		mrtstat.mrts_no_route++;
1132 
1133 		{
1134 			struct igmpmsg *im;
1135 
1136 			/*
1137 			 * Locate the vifi for the incoming interface for
1138 			 * this packet.
1139 			 * If none found, drop packet.
1140 			 */
1141 			if ((v = (struct vif *)ifp->if_mcast) == NULL)
1142 				return (EHOSTUNREACH);
1143 			/*
1144 			 * Make a copy of the header to send to the user level
1145 			 * process
1146 			 */
1147 			mm = m_copym(m, 0, hlen, M_NOWAIT);
1148 			if (mm == NULL ||
1149 			    (mm = m_pullup(mm, hlen)) == NULL)
1150 				return (ENOBUFS);
1151 
1152 			/*
1153 			 * Send message to routing daemon to install
1154 			 * a route into the kernel table
1155 			 */
1156 
1157 			im = mtod(mm, struct igmpmsg *);
1158 			im->im_msgtype = IGMPMSG_NOCACHE;
1159 			im->im_mbz = 0;
1160 			im->im_vif = v->v_id;
1161 
1162 			mrtstat.mrts_upcalls++;
1163 
1164 			sin.sin_addr = ip->ip_src;
1165 			if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1166 				log(LOG_WARNING, "ip_mforward: ip_mrouter "
1167 				    "socket queue full\n");
1168 				++mrtstat.mrts_upq_sockfull;
1169 				return (ENOBUFS);
1170 			}
1171 
1172 			mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
1173 			    rtableid, M_NOWAIT);
1174 		}
1175 
1176 		return (0);
1177 	}
1178 }
1179 
1180 /*
1181  * Packet forwarding routine once entry in the cache is made
1182  */
1183 int
1184 ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1185 {
1186 	struct ip  *ip = mtod(m, struct ip *);
1187 	struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1188 	struct vif *v = (struct vif *)ifp0->if_mcast;
1189 	struct ifnet *ifp;
1190 	struct mbuf *mc;
1191 	struct ip_moptions imo;
1192 
1193 	/* Sanity check: we have all promised pointers. */
1194 	if (v == NULL || mfc == NULL) {
1195 		rtfree(rt);
1196 		return (EHOSTUNREACH);
1197 	}
1198 
1199 	/*
1200 	 * Don't forward if it didn't arrive from the parent vif for its origin.
1201 	 */
1202 	if (mfc->mfc_parent != v->v_id) {
1203 		/* came in the wrong interface */
1204 		++mrtstat.mrts_wrong_if;
1205 		mfc->mfc_wrong_if++;
1206 		rtfree(rt);
1207 		return (0);
1208 	}
1209 
1210 	/* If I sourced this packet, it counts as output, else it was input. */
1211 	if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
1212 		v->v_pkt_out++;
1213 		v->v_bytes_out += m->m_pkthdr.len;
1214 	} else {
1215 		v->v_pkt_in++;
1216 		v->v_bytes_in += m->m_pkthdr.len;
1217 	}
1218 
1219 	/*
1220 	 * For each vif, decide if a copy of the packet should be forwarded.
1221 	 * Forward if:
1222 	 *		- the ttl exceeds the vif's threshold
1223 	 *		- there are group members downstream on interface
1224 	 */
1225 	do {
1226 		/* Don't consider non multicast routes. */
1227 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1228 		    (RTF_HOST | RTF_MULTICAST))
1229 			continue;
1230 
1231 		mfc = (struct mfc *)rt->rt_llinfo;
1232 		if (mfc == NULL)
1233 			continue;
1234 
1235 		mfc->mfc_pkt_cnt++;
1236 		mfc->mfc_byte_cnt += m->m_pkthdr.len;
1237 
1238 		/* Don't let this route expire. */
1239 		mfc->mfc_expire = 0;
1240 
1241 		if (ip->ip_ttl <= mfc->mfc_ttl)
1242 			continue;
1243 		if ((ifp = if_get(rt->rt_ifidx)) == NULL)
1244 			continue;
1245 
1246 		/* Sanity check: did we configure this? */
1247 		if ((v = (struct vif *)ifp->if_mcast) == NULL) {
1248 			if_put(ifp);
1249 			continue;
1250 		}
1251 
1252 		/* Don't send in the upstream interface. */
1253 		if (mfc->mfc_parent == v->v_id) {
1254 			if_put(ifp);
1255 			continue;
1256 		}
1257 
1258 		v->v_pkt_out++;
1259 		v->v_bytes_out += m->m_pkthdr.len;
1260 
1261 		/*
1262 		 * Make a new reference to the packet; make sure
1263 		 * that the IP header is actually copied, not
1264 		 * just referenced, so that ip_output() only
1265 		 * scribbles on the copy.
1266 		 */
1267 		mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1268 		if (mc == NULL) {
1269 			if_put(ifp);
1270 			rtfree(rt);
1271 			return (ENOBUFS);
1272 		}
1273 
1274 		/*
1275 		 * if physical interface option, extract the options
1276 		 * and then send
1277 		 */
1278 		imo.imo_ifidx = rt->rt_ifidx;
1279 		imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
1280 		imo.imo_loop = 1;
1281 
1282 		ip_output(mc, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
1283 		if_put(ifp);
1284 	} while ((rt = rtable_iterate(rt)) != NULL);
1285 
1286 	return (0);
1287 }
1288 
1289 struct ifnet *
1290 if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1291 {
1292 	struct vif	*v;
1293 	struct ifnet	*ifp;
1294 
1295 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
1296 		if (ifp->if_rdomain != rtableid)
1297 			continue;
1298 		if ((v = (struct vif *)ifp->if_mcast) == NULL)
1299 			continue;
1300 		if (v->v_id != vifi)
1301 			continue;
1302 
1303 		return (ifp);
1304 	}
1305 
1306 	return (NULL);
1307 }
1308 
1309 struct rtentry *
1310 rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1311 {
1312 	struct ifaddr		*ifa;
1313 	int			 rv;
1314 	unsigned int		 rtableid = ifp->if_rdomain;
1315 
1316 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1317 		if (ifa->ifa_addr->sa_family == AF_INET)
1318 			break;
1319 	}
1320 	if (ifa == NULL) {
1321 		DPRINTF("ifa == NULL");
1322 		return (NULL);
1323 	}
1324 
1325 	rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH,
1326 	    group, ifp->if_rdomain);
1327 	if (rv != 0) {
1328 		DPRINTF("rt_ifa_add failed (%d)", rv);
1329 		return (NULL);
1330 	}
1331 
1332 	mrt_count[rtableid]++;
1333 
1334 	return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
1335 }
1336 
1337 void
1338 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1339 {
1340 	struct ifnet		*ifp;
1341 	int			 error;
1342 
1343 	/* Remove all timers related to this route. */
1344 	rt_timer_remove_all(rt);
1345 
1346 	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
1347 	rt->rt_llinfo = NULL;
1348 
1349 	ifp = if_get(rt->rt_ifidx);
1350 	if (ifp == NULL)
1351 		return;
1352 	error = rtdeletemsg(rt, ifp, rtableid);
1353 	if_put(ifp);
1354 
1355 	if (error)
1356 		DPRINTF("delete route error %d\n", error);
1357 
1358 	mrt_count[rtableid]--;
1359 }
1360