xref: /openbsd/sys/netinet/ip_mroute.c (revision 73471bf0)
1 /*	$OpenBSD: ip_mroute.c,v 1.131 2021/12/15 17:21:08 deraadt 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 	memset(&vinfo, 0, sizeof vinfo);
357 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
358 		if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
359 			continue;
360 
361 		vinfo.v_vifi = vifp->v_id;
362 		vinfo.v_flags = vifp->v_flags;
363 		vinfo.v_threshold = vifp->v_threshold;
364 		vinfo.v_lcl_addr = vifp->v_lcl_addr;
365 		vinfo.v_rmt_addr = vifp->v_rmt_addr;
366 		vinfo.v_pkt_in = vifp->v_pkt_in;
367 		vinfo.v_pkt_out = vifp->v_pkt_out;
368 		vinfo.v_bytes_in = vifp->v_bytes_in;
369 		vinfo.v_bytes_out = vifp->v_bytes_out;
370 
371 		needed += sizeof(vinfo);
372 		if (where && needed <= given) {
373 			int error;
374 
375 			error = copyout(&vinfo, where, sizeof(vinfo));
376 			if (error)
377 				return (error);
378 			where += sizeof(vinfo);
379 		}
380 	}
381 	if (where) {
382 		*oldlenp = needed;
383 		if (given < needed)
384 			return (ENOMEM);
385 	} else
386 		*oldlenp = (11 * needed) / 10;
387 
388 	return (0);
389 }
390 
391 struct mfcsysctlarg {
392 	struct mfcinfo	*msa_minfos;
393 	size_t		 msa_len;
394 	size_t		 msa_needed;
395 };
396 
397 int
398 mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
399 {
400 	struct mfc		*mfc = (struct mfc *)rt->rt_llinfo;
401 	struct mfcsysctlarg	*msa = (struct mfcsysctlarg *)arg;
402 	struct ifnet		*ifp;
403 	struct vif		*v;
404 	struct mfcinfo		*minfo;
405 	int			 new = 0;
406 
407 	/* Skip entries being removed. */
408 	if (mfc == NULL)
409 		return (0);
410 
411 	/* Skip non-multicast routes. */
412 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
413 	    (RTF_HOST | RTF_MULTICAST))
414 		return (0);
415 
416 	/* User just asked for the output size. */
417 	if (msa->msa_minfos == NULL) {
418 		msa->msa_needed += sizeof(*minfo);
419 		return (0);
420 	}
421 
422 	/* Skip route with invalid interfaces. */
423 	if ((ifp = if_get(rt->rt_ifidx)) == NULL)
424 		return (0);
425 	if ((v = (struct vif *)ifp->if_mcast) == NULL) {
426 		if_put(ifp);
427 		return (0);
428 	}
429 
430 	for (minfo = msa->msa_minfos;
431 	     (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
432 	     minfo++) {
433 		/* Find a new entry or update old entry. */
434 		if (minfo->mfc_origin.s_addr !=
435 		    satosin(rt->rt_gateway)->sin_addr.s_addr ||
436 		    minfo->mfc_mcastgrp.s_addr !=
437 		    satosin(rt_key(rt))->sin_addr.s_addr) {
438 			if (minfo->mfc_origin.s_addr != 0 ||
439 			    minfo->mfc_mcastgrp.s_addr != 0)
440 				continue;
441 
442 			new = 1;
443 		}
444 
445 		minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
446 		minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
447 		minfo->mfc_parent = mfc->mfc_parent;
448 		minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
449 		minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
450 		minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
451 		break;
452 	}
453 
454 	if (new != 0)
455 		msa->msa_needed += sizeof(*minfo);
456 
457 	if_put(ifp);
458 
459 	return (0);
460 }
461 
462 int
463 mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
464 {
465 	unsigned int		 rtableid;
466 	int			 error;
467 	struct mfcsysctlarg	 msa;
468 
469 	if (oldp != NULL && *oldlenp > MAXPHYS)
470 		return (EINVAL);
471 
472 	if (oldp != NULL)
473 		msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
474 	else
475 		msa.msa_minfos = NULL;
476 
477 	msa.msa_len = *oldlenp;
478 	msa.msa_needed = 0;
479 
480 	for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
481 		rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl,
482 		    &msa);
483 	}
484 
485 	if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
486 	    (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
487 		free(msa.msa_minfos, M_TEMP, *oldlenp);
488 		return (error);
489 	}
490 
491 	free(msa.msa_minfos, M_TEMP, *oldlenp);
492 	*oldlenp = msa.msa_needed;
493 
494 	return (0);
495 }
496 
497 /*
498  * Enable multicast routing
499  */
500 int
501 ip_mrouter_init(struct socket *so, struct mbuf *m)
502 {
503 	struct inpcb *inp = sotoinpcb(so);
504 	unsigned int rtableid = inp->inp_rtableid;
505 	int *v;
506 
507 	if (so->so_type != SOCK_RAW ||
508 	    so->so_proto->pr_protocol != IPPROTO_IGMP)
509 		return (EOPNOTSUPP);
510 
511 	if (m == NULL || m->m_len < sizeof(int))
512 		return (EINVAL);
513 
514 	v = mtod(m, int *);
515 	if (*v != 1)
516 		return (EINVAL);
517 
518 	if (ip_mrouter[rtableid] != NULL ||
519 	    mrouterq[rtableid] != NULL)
520 		return (EADDRINUSE);
521 
522 	ip_mrouter[rtableid] = so;
523 	mrouterq[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_FREQUENCY);
524 
525 	return (0);
526 }
527 
528 int
529 mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
530 {
531 	/* Skip non-multicast routes. */
532 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
533 	    (RTF_HOST | RTF_MULTICAST))
534 		return (0);
535 
536 	return EEXIST;
537 }
538 
539 /*
540  * Disable multicast routing
541  */
542 int
543 ip_mrouter_done(struct socket *so)
544 {
545 	struct inpcb *inp = sotoinpcb(so);
546 	struct ifnet *ifp;
547 	unsigned int rtableid = inp->inp_rtableid;
548 	int error;
549 
550 	NET_ASSERT_LOCKED();
551 
552 	/* Delete all remaining installed multicast routes. */
553 	do {
554 		struct rtentry *rt = NULL;
555 
556 		error = rtable_walk(rtableid, AF_INET, &rt,
557 		    mrouter_rtwalk_delete, NULL);
558 		if (rt != NULL && error == EEXIST) {
559 			mrt_mcast_del(rt, rtableid);
560 			error = EAGAIN;
561 		}
562 		rtfree(rt);
563 	} while (error == EAGAIN);
564 
565 	/* Unregister all interfaces in the domain. */
566 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
567 		if (ifp->if_rdomain != rtableid)
568 			continue;
569 
570 		vif_delete(ifp);
571 	}
572 
573 	mrt_api_config = 0;
574 
575 	rt_timer_queue_destroy(mrouterq[rtableid]);
576 	mrouterq[rtableid] = NULL;
577 	ip_mrouter[rtableid] = NULL;
578 	mrt_count[rtableid] = 0;
579 
580 	return (0);
581 }
582 
583 int
584 get_version(struct mbuf *m)
585 {
586 	int *v = mtod(m, int *);
587 
588 	*v = 0x0305;	/* XXX !!!! */
589 	m->m_len = sizeof(int);
590 	return (0);
591 }
592 
593 /*
594  * Configure API capabilities
595  */
596 int
597 set_api_config(struct socket *so, struct mbuf *m)
598 {
599 	struct inpcb *inp = sotoinpcb(so);
600 	struct ifnet *ifp;
601 	u_int32_t *apival;
602 	unsigned int rtableid = inp->inp_rtableid;
603 
604 	if (m == NULL || m->m_len < sizeof(u_int32_t))
605 		return (EINVAL);
606 
607 	apival = mtod(m, u_int32_t *);
608 
609 	/*
610 	 * We can set the API capabilities only if it is the first operation
611 	 * after MRT_INIT. I.e.:
612 	 *  - there are no vifs installed
613 	 *  - the MFC table is empty
614 	 */
615 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
616 		if (ifp->if_rdomain != rtableid)
617 			continue;
618 		if (ifp->if_mcast == NULL)
619 			continue;
620 
621 		*apival = 0;
622 		return (EPERM);
623 	}
624 	if (mrt_count[rtableid] > 0) {
625 		*apival = 0;
626 		return (EPERM);
627 	}
628 
629 	mrt_api_config = *apival & mrt_api_support;
630 	*apival = mrt_api_config;
631 
632 	return (0);
633 }
634 
635 /*
636  * Get API capabilities
637  */
638 int
639 get_api_support(struct mbuf *m)
640 {
641 	u_int32_t *apival;
642 
643 	if (m == NULL || m->m_len < sizeof(u_int32_t))
644 		return (EINVAL);
645 
646 	apival = mtod(m, u_int32_t *);
647 
648 	*apival = mrt_api_support;
649 
650 	return (0);
651 }
652 
653 /*
654  * Get API configured capabilities
655  */
656 int
657 get_api_config(struct mbuf *m)
658 {
659 	u_int32_t *apival;
660 
661 	if (m == NULL || m->m_len < sizeof(u_int32_t))
662 		return (EINVAL);
663 
664 	apival = mtod(m, u_int32_t *);
665 
666 	*apival = mrt_api_config;
667 
668 	return (0);
669 }
670 
671 static struct sockaddr_in sin = { sizeof(sin), AF_INET };
672 
673 int
674 add_vif(struct socket *so, struct mbuf *m)
675 {
676 	struct inpcb *inp = sotoinpcb(so);
677 	struct vifctl *vifcp;
678 	struct vif *vifp;
679 	struct ifaddr *ifa;
680 	struct ifnet *ifp;
681 	struct ifreq ifr;
682 	int error;
683 	unsigned int rtableid = inp->inp_rtableid;
684 
685 	NET_ASSERT_LOCKED();
686 
687 	if (m == NULL || m->m_len < sizeof(struct vifctl))
688 		return (EINVAL);
689 
690 	vifcp = mtod(m, struct vifctl *);
691 	if (vifcp->vifc_vifi >= MAXVIFS)
692 		return (EINVAL);
693 	if (in_nullhost(vifcp->vifc_lcl_addr))
694 		return (EADDRNOTAVAIL);
695 	if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
696 		return (EADDRINUSE);
697 
698 	/* Tunnels are no longer supported use gif(4) instead. */
699 	if (vifcp->vifc_flags & VIFF_TUNNEL)
700 		return (EOPNOTSUPP);
701 	{
702 		sin.sin_addr = vifcp->vifc_lcl_addr;
703 		ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
704 		if (ifa == NULL)
705 			return (EADDRNOTAVAIL);
706 	}
707 
708 	/* Use the physical interface associated with the address. */
709 	ifp = ifa->ifa_ifp;
710 	if (ifp->if_mcast != NULL)
711 		return (EADDRINUSE);
712 
713 	{
714 		/* Make sure the interface supports multicast. */
715 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
716 			return (EOPNOTSUPP);
717 
718 		/* Enable promiscuous reception of all IP multicasts. */
719 		memset(&ifr, 0, sizeof(ifr));
720 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
721 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
722 		satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
723 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
724 		if (error)
725 			return (error);
726 	}
727 
728 	vifp = malloc(sizeof(*vifp), M_MRTABLE, M_WAITOK | M_ZERO);
729 	ifp->if_mcast = (caddr_t)vifp;
730 
731 	vifp->v_id = vifcp->vifc_vifi;
732 	vifp->v_flags = vifcp->vifc_flags;
733 	vifp->v_threshold = vifcp->vifc_threshold;
734 	vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
735 	vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
736 
737 	return (0);
738 }
739 
740 int
741 del_vif(struct socket *so, struct mbuf *m)
742 {
743 	struct inpcb *inp = sotoinpcb(so);
744 	struct ifnet *ifp;
745 	vifi_t *vifip;
746 	unsigned int rtableid = inp->inp_rtableid;
747 
748 	NET_ASSERT_LOCKED();
749 
750 	if (m == NULL || m->m_len < sizeof(vifi_t))
751 		return (EINVAL);
752 
753 	vifip = mtod(m, vifi_t *);
754 	if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL)
755 		return (EADDRNOTAVAIL);
756 
757 	vif_delete(ifp);
758 	return (0);
759 }
760 
761 void
762 vif_delete(struct ifnet *ifp)
763 {
764 	struct vif	*v;
765 	struct ifreq	 ifr;
766 
767 	if ((v = (struct vif *)ifp->if_mcast) == NULL)
768 		return;
769 
770 	ifp->if_mcast = NULL;
771 
772 	memset(&ifr, 0, sizeof(ifr));
773 	satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
774 	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
775 	satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
776 	KERNEL_LOCK();
777 	(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
778 	KERNEL_UNLOCK();
779 
780 	free(v, M_MRTABLE, sizeof(*v));
781 }
782 
783 void
784 mfc_expire_route(struct rtentry *rt, struct rttimer *rtt)
785 {
786 	struct mfc	*mfc = (struct mfc *)rt->rt_llinfo;
787 	unsigned int	 rtableid = rtt->rtt_tableid;
788 
789 	/* Skip entry being deleted. */
790 	if (mfc == NULL)
791 		return;
792 
793 	DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
794 	    "expire %s", rtt->rtt_tableid,
795 	    satosin(rt->rt_gateway)->sin_addr.s_addr,
796 	    satosin(rt_key(rt))->sin_addr.s_addr,
797 	    rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
798 
799 	/* Not expired, add it back to the queue. */
800 	if (mfc->mfc_expire == 0) {
801 		mfc->mfc_expire = 1;
802 		rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
803 		    rtableid);
804 		return;
805 	}
806 
807 	mrt_mcast_del(rt, rtableid);
808 }
809 
810 int
811 mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
812     struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
813 {
814 	struct vif		*v = (struct vif *)ifp->if_mcast;
815 	struct rtentry		*rt;
816 	struct mfc		*mfc;
817 	unsigned int		 rtableid = ifp->if_rdomain;
818 
819 	rt = rt_mcast_add(ifp, origin, group);
820 	if (rt == NULL)
821 		return (EHOSTUNREACH);
822 
823 	mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
824 	if (mfc == NULL) {
825 		DPRINTF("origin %#08X group %#08X parent %d (%s) "
826 		    "malloc failed",
827 		    satosin(origin)->sin_addr.s_addr,
828 		    satosin(group)->sin_addr.s_addr,
829 		    mfccp->mfcc_parent, ifp->if_xname);
830 		mrt_mcast_del(rt, rtableid);
831 		rtfree(rt);
832 		return (ENOMEM);
833 	}
834 
835 	rt->rt_llinfo = (caddr_t)mfc;
836 
837 	rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
838 	    rtableid);
839 
840 	mfc->mfc_parent = mfccp->mfcc_parent;
841 	mfc->mfc_pkt_cnt = 0;
842 	mfc->mfc_byte_cnt = 0;
843 	mfc->mfc_wrong_if = 0;
844 	mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
845 	mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
846 	    MRT_MFC_FLAGS_ALL;
847 	mfc->mfc_expire = 0;
848 
849 	/* set the RP address */
850 	if (mrt_api_config & MRT_MFC_RP)
851 		mfc->mfc_rp = mfccp->mfcc_rp;
852 	else
853 		mfc->mfc_rp = zeroin_addr;
854 
855 	rtfree(rt);
856 
857 	return (0);
858 }
859 
860 void
861 update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
862 {
863 	struct rtentry		*rt;
864 	struct mfc		*mfc;
865 	struct ifnet		*ifp;
866 	int			 i;
867 	struct sockaddr_in	 osin, msin;
868 
869 	memset(&osin, 0, sizeof(osin));
870 	osin.sin_len = sizeof(osin);
871 	osin.sin_family = AF_INET;
872 	osin.sin_addr = mfccp->mfcc_origin;
873 
874 	memset(&msin, 0, sizeof(msin));
875 	msin.sin_len = sizeof(msin);
876 	msin.sin_family = AF_INET;
877 	msin.sin_addr = mfccp->mfcc_mcastgrp;
878 
879 	for (i = 0; i < MAXVIFS; i++) {
880 		/* Don't add/del upstream routes here. */
881 		if (i == mfccp->mfcc_parent)
882 			continue;
883 
884 		/* Test for vif existence and then update the entry. */
885 		if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
886 			continue;
887 
888 		rt = mfc_find(ifp, &mfccp->mfcc_origin,
889 		    &mfccp->mfcc_mcastgrp, rtableid);
890 
891 		/* vif not configured or removed. */
892 		if (mfccp->mfcc_ttls[i] == 0) {
893 			/* Route doesn't exist, nothing to do. */
894 			if (rt == NULL)
895 				continue;
896 
897 			DPRINTF("del route (group %#08X) for vif %d (%s)",
898 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
899 			mrt_mcast_del(rt, rtableid);
900 			rtfree(rt);
901 			continue;
902 		}
903 
904 		/* Route exists, look for changes. */
905 		if (rt != NULL) {
906 			mfc = (struct mfc *)rt->rt_llinfo;
907 			/* Skip route being deleted. */
908 			if (mfc == NULL) {
909 				rtfree(rt);
910 				continue;
911 			}
912 
913 			/* No new changes to apply. */
914 			if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
915 			    mfccp->mfcc_parent == mfc->mfc_parent) {
916 				rtfree(rt);
917 				continue;
918 			}
919 
920 			DPRINTF("update route (group %#08X) for vif %d (%s)",
921 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
922 			mfc->mfc_ttl = mfccp->mfcc_ttls[i];
923 			mfc->mfc_parent = mfccp->mfcc_parent;
924 			rtfree(rt);
925 			continue;
926 		}
927 
928 		DPRINTF("add route (group %#08X) for vif %d (%s)",
929 		    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
930 
931 		mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
932 		    mfccp, wait);
933 	}
934 
935 	/* Create route for the parent interface. */
936 	if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
937 		DPRINTF("failed to find upstream interface %d",
938 		    mfccp->mfcc_parent);
939 		return;
940 	}
941 
942 	/* We already have a route, nothing to do here. */
943 	if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
944 	    &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
945 		rtfree(rt);
946 		return;
947 	}
948 
949 	DPRINTF("add upstream route (group %#08X) for if %s",
950 	    mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
951 	mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
952 }
953 
954 int
955 mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
956     struct in_addr *group, int vidx, unsigned int rtableid, int wait)
957 {
958 	struct ifnet		*ifp;
959 	struct vif		*v;
960 	struct mfcctl2		 mfcctl;
961 
962 	ifp = if_lookupbyvif(vidx, rtableid);
963 	if (ifp == NULL ||
964 	    (v = (struct vif *)ifp->if_mcast) == NULL)
965 		return (EHOSTUNREACH);
966 
967 	memset(&mfcctl, 0, sizeof(mfcctl));
968 	if (mfcctl2 == NULL) {
969 		mfcctl.mfcc_origin = *origin;
970 		mfcctl.mfcc_mcastgrp = *group;
971 		mfcctl.mfcc_parent = vidx;
972 	} else
973 		memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
974 
975 	update_mfc_params(&mfcctl, wait, rtableid);
976 
977 	return (0);
978 }
979 
980 int
981 add_mfc(struct socket *so, struct mbuf *m)
982 {
983 	struct inpcb *inp = sotoinpcb(so);
984 	struct mfcctl2 mfcctl2;
985 	int mfcctl_size = sizeof(struct mfcctl);
986 	unsigned int rtableid = inp->inp_rtableid;
987 
988 	NET_ASSERT_LOCKED();
989 
990 	if (mrt_api_config & MRT_API_FLAGS_ALL)
991 		mfcctl_size = sizeof(struct mfcctl2);
992 
993 	if (m == NULL || m->m_len < mfcctl_size)
994 		return (EINVAL);
995 
996 	/*
997 	 * select data size depending on API version.
998 	 */
999 	if (mrt_api_config & MRT_API_FLAGS_ALL) {
1000 		struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
1001 		memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
1002 	} else {
1003 		struct mfcctl *mp = mtod(m, struct mfcctl *);
1004 		memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1005 		memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1006 		    sizeof(mfcctl2) - sizeof(struct mfcctl));
1007 	}
1008 
1009 	if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1010 	    mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
1011 		return (EINVAL);
1012 
1013 	return (0);
1014 }
1015 
1016 int
1017 del_mfc(struct socket *so, struct mbuf *m)
1018 {
1019 	struct inpcb *inp = sotoinpcb(so);
1020 	struct rtentry *rt;
1021 	struct mfcctl2 mfcctl2;
1022 	int mfcctl_size = sizeof(struct mfcctl);
1023 	struct mfcctl *mp;
1024 	unsigned int rtableid = inp->inp_rtableid;
1025 
1026 	NET_ASSERT_LOCKED();
1027 
1028 	/*
1029 	 * XXX: for deleting MFC entries the information in entries
1030 	 * of size "struct mfcctl" is sufficient.
1031 	 */
1032 
1033 	if (m == NULL || m->m_len < mfcctl_size)
1034 		return (EINVAL);
1035 
1036 	mp = mtod(m, struct mfcctl *);
1037 
1038 	memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1039 	memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1040 	    sizeof(mfcctl2) - sizeof(struct mfcctl));
1041 
1042 	DPRINTF("origin %#08X group %#08X rtableid %d",
1043 	    mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
1044 
1045 	while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
1046 	    &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
1047 		mrt_mcast_del(rt, rtableid);
1048 		rtfree(rt);
1049 	}
1050 
1051 	return (0);
1052 }
1053 
1054 int
1055 socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
1056 {
1057 	if (s != NULL) {
1058 		if (sbappendaddr(s, &s->so_rcv, sintosa(src), mm, NULL) != 0) {
1059 			sorwakeup(s);
1060 			return (0);
1061 		}
1062 	}
1063 	m_freem(mm);
1064 	return (-1);
1065 }
1066 
1067 /*
1068  * IP multicast forwarding function. This function assumes that the packet
1069  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1070  * pointed to by "ifp", and the packet is to be relayed to other networks
1071  * that have members of the packet's destination IP multicast group.
1072  *
1073  * The packet is returned unscathed to the caller, unless it is
1074  * erroneous, in which case a non-zero return value tells the caller to
1075  * discard it.
1076  */
1077 
1078 #define IP_HDR_LEN  20	/* # bytes of fixed IP header (excluding options) */
1079 #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
1080 
1081 int
1082 ip_mforward(struct mbuf *m, struct ifnet *ifp)
1083 {
1084 	struct ip *ip = mtod(m, struct ip *);
1085 	struct vif *v;
1086 	struct rtentry *rt;
1087 	static int srctun = 0;
1088 	struct mbuf *mm;
1089 	unsigned int rtableid = ifp->if_rdomain;
1090 
1091 	if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
1092 	    ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
1093 		/*
1094 		 * Packet arrived via a physical interface or
1095 		 * an encapsulated tunnel or a register_vif.
1096 		 */
1097 	} else {
1098 		/*
1099 		 * Packet arrived through a source-route tunnel.
1100 		 * Source-route tunnels are no longer supported.
1101 		 */
1102 		if ((srctun++ % 1000) == 0)
1103 			log(LOG_ERR, "ip_mforward: received source-routed "
1104 			    "packet from %x\n", ntohl(ip->ip_src.s_addr));
1105 		return (EOPNOTSUPP);
1106 	}
1107 
1108 	/*
1109 	 * Don't forward a packet with time-to-live of zero or one,
1110 	 * or a packet destined to a local-only group.
1111 	 */
1112 	if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
1113 		return (0);
1114 
1115 	/*
1116 	 * Determine forwarding vifs from the forwarding cache table
1117 	 */
1118 	++mrtstat.mrts_mfc_lookups;
1119 	rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
1120 
1121 	/* Entry exists, so forward if necessary */
1122 	if (rt != NULL) {
1123 		return (ip_mdq(m, ifp, rt));
1124 	} else {
1125 		/*
1126 		 * If we don't have a route for packet's origin,
1127 		 * Make a copy of the packet & send message to routing daemon
1128 		 */
1129 		int hlen = ip->ip_hl << 2;
1130 
1131 		++mrtstat.mrts_mfc_misses;
1132 		mrtstat.mrts_no_route++;
1133 
1134 		{
1135 			struct igmpmsg *im;
1136 
1137 			/*
1138 			 * Locate the vifi for the incoming interface for
1139 			 * this packet.
1140 			 * If none found, drop packet.
1141 			 */
1142 			if ((v = (struct vif *)ifp->if_mcast) == NULL)
1143 				return (EHOSTUNREACH);
1144 			/*
1145 			 * Make a copy of the header to send to the user level
1146 			 * process
1147 			 */
1148 			mm = m_copym(m, 0, hlen, M_NOWAIT);
1149 			if (mm == NULL ||
1150 			    (mm = m_pullup(mm, hlen)) == NULL)
1151 				return (ENOBUFS);
1152 
1153 			/*
1154 			 * Send message to routing daemon to install
1155 			 * a route into the kernel table
1156 			 */
1157 
1158 			im = mtod(mm, struct igmpmsg *);
1159 			im->im_msgtype = IGMPMSG_NOCACHE;
1160 			im->im_mbz = 0;
1161 			im->im_vif = v->v_id;
1162 
1163 			mrtstat.mrts_upcalls++;
1164 
1165 			sin.sin_addr = ip->ip_src;
1166 			if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1167 				log(LOG_WARNING, "ip_mforward: ip_mrouter "
1168 				    "socket queue full\n");
1169 				++mrtstat.mrts_upq_sockfull;
1170 				return (ENOBUFS);
1171 			}
1172 
1173 			mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
1174 			    rtableid, M_NOWAIT);
1175 		}
1176 
1177 		return (0);
1178 	}
1179 }
1180 
1181 /*
1182  * Packet forwarding routine once entry in the cache is made
1183  */
1184 int
1185 ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1186 {
1187 	struct ip  *ip = mtod(m, struct ip *);
1188 	struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1189 	struct vif *v = (struct vif *)ifp0->if_mcast;
1190 	struct ifnet *ifp;
1191 	struct mbuf *mc;
1192 	struct ip_moptions imo;
1193 
1194 	/* Sanity check: we have all promised pointers. */
1195 	if (v == NULL || mfc == NULL) {
1196 		rtfree(rt);
1197 		return (EHOSTUNREACH);
1198 	}
1199 
1200 	/*
1201 	 * Don't forward if it didn't arrive from the parent vif for its origin.
1202 	 */
1203 	if (mfc->mfc_parent != v->v_id) {
1204 		/* came in the wrong interface */
1205 		++mrtstat.mrts_wrong_if;
1206 		mfc->mfc_wrong_if++;
1207 		rtfree(rt);
1208 		return (0);
1209 	}
1210 
1211 	/* If I sourced this packet, it counts as output, else it was input. */
1212 	if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
1213 		v->v_pkt_out++;
1214 		v->v_bytes_out += m->m_pkthdr.len;
1215 	} else {
1216 		v->v_pkt_in++;
1217 		v->v_bytes_in += m->m_pkthdr.len;
1218 	}
1219 
1220 	/*
1221 	 * For each vif, decide if a copy of the packet should be forwarded.
1222 	 * Forward if:
1223 	 *		- the ttl exceeds the vif's threshold
1224 	 *		- there are group members downstream on interface
1225 	 */
1226 	do {
1227 		/* Don't consider non multicast routes. */
1228 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1229 		    (RTF_HOST | RTF_MULTICAST))
1230 			continue;
1231 
1232 		mfc = (struct mfc *)rt->rt_llinfo;
1233 		if (mfc == NULL)
1234 			continue;
1235 
1236 		mfc->mfc_pkt_cnt++;
1237 		mfc->mfc_byte_cnt += m->m_pkthdr.len;
1238 
1239 		/* Don't let this route expire. */
1240 		mfc->mfc_expire = 0;
1241 
1242 		if (ip->ip_ttl <= mfc->mfc_ttl)
1243 			continue;
1244 		if ((ifp = if_get(rt->rt_ifidx)) == NULL)
1245 			continue;
1246 
1247 		/* Sanity check: did we configure this? */
1248 		if ((v = (struct vif *)ifp->if_mcast) == NULL) {
1249 			if_put(ifp);
1250 			continue;
1251 		}
1252 
1253 		/* Don't send in the upstream interface. */
1254 		if (mfc->mfc_parent == v->v_id) {
1255 			if_put(ifp);
1256 			continue;
1257 		}
1258 
1259 		v->v_pkt_out++;
1260 		v->v_bytes_out += m->m_pkthdr.len;
1261 
1262 		/*
1263 		 * Make a new reference to the packet; make sure
1264 		 * that the IP header is actually copied, not
1265 		 * just referenced, so that ip_output() only
1266 		 * scribbles on the copy.
1267 		 */
1268 		mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1269 		if (mc == NULL) {
1270 			if_put(ifp);
1271 			rtfree(rt);
1272 			return (ENOBUFS);
1273 		}
1274 
1275 		/*
1276 		 * if physical interface option, extract the options
1277 		 * and then send
1278 		 */
1279 		imo.imo_ifidx = rt->rt_ifidx;
1280 		imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
1281 		imo.imo_loop = 1;
1282 
1283 		ip_output(mc, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
1284 		if_put(ifp);
1285 	} while ((rt = rtable_iterate(rt)) != NULL);
1286 
1287 	return (0);
1288 }
1289 
1290 struct ifnet *
1291 if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1292 {
1293 	struct vif	*v;
1294 	struct ifnet	*ifp;
1295 
1296 	TAILQ_FOREACH(ifp, &ifnet, if_list) {
1297 		if (ifp->if_rdomain != rtableid)
1298 			continue;
1299 		if ((v = (struct vif *)ifp->if_mcast) == NULL)
1300 			continue;
1301 		if (v->v_id != vifi)
1302 			continue;
1303 
1304 		return (ifp);
1305 	}
1306 
1307 	return (NULL);
1308 }
1309 
1310 struct rtentry *
1311 rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1312 {
1313 	struct ifaddr		*ifa;
1314 	int			 rv;
1315 	unsigned int		 rtableid = ifp->if_rdomain;
1316 
1317 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1318 		if (ifa->ifa_addr->sa_family == AF_INET)
1319 			break;
1320 	}
1321 	if (ifa == NULL) {
1322 		DPRINTF("ifa == NULL");
1323 		return (NULL);
1324 	}
1325 
1326 	rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH,
1327 	    group, ifp->if_rdomain);
1328 	if (rv != 0) {
1329 		DPRINTF("rt_ifa_add failed (%d)", rv);
1330 		return (NULL);
1331 	}
1332 
1333 	mrt_count[rtableid]++;
1334 
1335 	return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
1336 }
1337 
1338 void
1339 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1340 {
1341 	struct ifnet		*ifp;
1342 	int			 error;
1343 
1344 	/* Remove all timers related to this route. */
1345 	rt_timer_remove_all(rt);
1346 
1347 	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
1348 	rt->rt_llinfo = NULL;
1349 
1350 	ifp = if_get(rt->rt_ifidx);
1351 	if (ifp == NULL)
1352 		return;
1353 	error = rtdeletemsg(rt, ifp, rtableid);
1354 	if_put(ifp);
1355 
1356 	if (error)
1357 		DPRINTF("delete route error %d\n", error);
1358 
1359 	mrt_count[rtableid]--;
1360 }
1361