xref: /openbsd/sys/netinet/ip_mroute.c (revision 85fbf21a)
1 /*	$OpenBSD: ip_mroute.c,v 1.142 2024/04/06 14:23:27 bluhm 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 ip_mrouterq;
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 int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
117     int, unsigned int, int);
118 int add_mfc(struct socket *, struct mbuf *);
119 int del_mfc(struct socket *, struct mbuf *);
120 int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
121 int get_api_support(struct mbuf *);
122 int get_api_config(struct mbuf *);
123 int socket_send(struct socket *, struct mbuf *,
124 			    struct sockaddr_in *);
125 int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
126 struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
127 struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
128     struct sockaddr *);
129 void mrt_mcast_del(struct rtentry *, unsigned int);
130 
131 /*
132  * Kernel multicast routing API capabilities and setup.
133  * If more API capabilities are added to the kernel, they should be
134  * recorded in `mrt_api_support'.
135  */
136 static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
137 					  MRT_MFC_RP);
138 static u_int32_t mrt_api_config = 0;
139 
140 /*
141  * Find a route for a given origin IP address and Multicast group address
142  * Type of service parameter to be added in the future!!!
143  * Statistics are updated by the caller if needed
144  * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
145  */
146 struct rtentry *
mfc_find(struct ifnet * ifp,struct in_addr * origin,struct in_addr * group,unsigned int rtableid)147 mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
148     unsigned int rtableid)
149 {
150 	struct rtentry		*rt;
151 	struct sockaddr_in	 msin;
152 
153 	memset(&msin, 0, sizeof(msin));
154 	msin.sin_len = sizeof(msin);
155 	msin.sin_family = AF_INET;
156 	msin.sin_addr = *group;
157 
158 	rt = rtalloc(sintosa(&msin), 0, rtableid);
159 	do {
160 		if (!rtisvalid(rt)) {
161 			rtfree(rt);
162 			return NULL;
163 		}
164 		/* Don't consider non multicast routes. */
165 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
166 		    (RTF_HOST | RTF_MULTICAST))
167 			continue;
168 		/* Return first occurrence if interface is not specified. */
169 		if (ifp == NULL)
170 			return (rt);
171 		if (rt->rt_ifidx == ifp->if_index)
172 			return (rt);
173 	} while ((rt = rtable_iterate(rt)) != NULL);
174 
175 	return (NULL);
176 }
177 
178 /*
179  * Handle MRT setsockopt commands to modify the multicast routing tables.
180  */
181 int
ip_mrouter_set(struct socket * so,int optname,struct mbuf * m)182 ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
183 {
184 	struct inpcb *inp = sotoinpcb(so);
185 	int error;
186 
187 	if (optname != MRT_INIT &&
188 	    so != ip_mrouter[inp->inp_rtableid])
189 		error = ENOPROTOOPT;
190 	else
191 		switch (optname) {
192 		case MRT_INIT:
193 			error = ip_mrouter_init(so, m);
194 			break;
195 		case MRT_DONE:
196 			error = ip_mrouter_done(so);
197 			break;
198 		case MRT_ADD_VIF:
199 			error = add_vif(so, m);
200 			break;
201 		case MRT_DEL_VIF:
202 			error = del_vif(so, m);
203 			break;
204 		case MRT_ADD_MFC:
205 			error = add_mfc(so, m);
206 			break;
207 		case MRT_DEL_MFC:
208 			error = del_mfc(so, m);
209 			break;
210 		case MRT_API_CONFIG:
211 			error = set_api_config(so, m);
212 			break;
213 		default:
214 			error = ENOPROTOOPT;
215 			break;
216 		}
217 
218 	return (error);
219 }
220 
221 /*
222  * Handle MRT getsockopt commands
223  */
224 int
ip_mrouter_get(struct socket * so,int optname,struct mbuf * m)225 ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
226 {
227 	struct inpcb *inp = sotoinpcb(so);
228 	int error;
229 
230 	if (so != ip_mrouter[inp->inp_rtableid])
231 		error = ENOPROTOOPT;
232 	else {
233 		switch (optname) {
234 		case MRT_VERSION:
235 			error = get_version(m);
236 			break;
237 		case MRT_API_SUPPORT:
238 			error = get_api_support(m);
239 			break;
240 		case MRT_API_CONFIG:
241 			error = get_api_config(m);
242 			break;
243 		default:
244 			error = ENOPROTOOPT;
245 			break;
246 		}
247 	}
248 
249 	return (error);
250 }
251 
252 /*
253  * Handle ioctl commands to obtain information from the cache
254  */
255 int
mrt_ioctl(struct socket * so,u_long cmd,caddr_t data)256 mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
257 {
258 	struct inpcb *inp = sotoinpcb(so);
259 	int error;
260 
261 	if (inp == NULL)
262 		return (ENOTCONN);
263 
264 	KERNEL_LOCK();
265 
266 	if (so != ip_mrouter[inp->inp_rtableid])
267 		error = EINVAL;
268 	else
269 		switch (cmd) {
270 		case SIOCGETVIFCNT:
271 			NET_LOCK_SHARED();
272 			error = get_vif_cnt(inp->inp_rtableid,
273 			    (struct sioc_vif_req *)data);
274 			NET_UNLOCK_SHARED();
275 			break;
276 		case SIOCGETSGCNT:
277 			NET_LOCK_SHARED();
278 			error = get_sg_cnt(inp->inp_rtableid,
279 			    (struct sioc_sg_req *)data);
280 			NET_UNLOCK_SHARED();
281 			break;
282 		default:
283 			error = ENOTTY;
284 			break;
285 		}
286 
287 	KERNEL_UNLOCK();
288 	return (error);
289 }
290 
291 /*
292  * returns the packet, byte, rpf-failure count for the source group provided
293  */
294 int
get_sg_cnt(unsigned int rtableid,struct sioc_sg_req * req)295 get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
296 {
297 	struct rtentry *rt;
298 	struct mfc *mfc;
299 
300 	rt = mfc_find(NULL, &req->src, &req->grp, rtableid);
301 	if (rt == NULL) {
302 		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
303 		return (EADDRNOTAVAIL);
304 	}
305 
306 	req->pktcnt = req->bytecnt = req->wrong_if = 0;
307 	do {
308 		/* Don't consider non multicast routes. */
309 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
310 		    (RTF_HOST | RTF_MULTICAST))
311 			continue;
312 
313 		mfc = (struct mfc *)rt->rt_llinfo;
314 		if (mfc == NULL)
315 			continue;
316 
317 		req->pktcnt += mfc->mfc_pkt_cnt;
318 		req->bytecnt += mfc->mfc_byte_cnt;
319 		req->wrong_if += mfc->mfc_wrong_if;
320 	} while ((rt = rtable_iterate(rt)) != NULL);
321 
322 	return (0);
323 }
324 
325 /*
326  * returns the input and output packet and byte counts on the vif provided
327  */
328 int
get_vif_cnt(unsigned int rtableid,struct sioc_vif_req * req)329 get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
330 {
331 	struct ifnet	*ifp;
332 	struct vif	*v;
333 	vifi_t		 vifi = req->vifi;
334 
335 	if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL)
336 		return (EINVAL);
337 
338 	v = (struct vif *)ifp->if_mcast;
339 	req->icount = v->v_pkt_in;
340 	req->ocount = v->v_pkt_out;
341 	req->ibytes = v->v_bytes_in;
342 	req->obytes = v->v_bytes_out;
343 
344 	return (0);
345 }
346 
347 int
mrt_sysctl_vif(void * oldp,size_t * oldlenp)348 mrt_sysctl_vif(void *oldp, size_t *oldlenp)
349 {
350 	caddr_t where = oldp;
351 	size_t needed, given;
352 	struct ifnet *ifp;
353 	struct vif *vifp;
354 	struct vifinfo vinfo;
355 
356 	given = *oldlenp;
357 	needed = 0;
358 	memset(&vinfo, 0, sizeof vinfo);
359 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
360 		if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
361 			continue;
362 
363 		vinfo.v_vifi = vifp->v_id;
364 		vinfo.v_flags = vifp->v_flags;
365 		vinfo.v_threshold = vifp->v_threshold;
366 		vinfo.v_lcl_addr = vifp->v_lcl_addr;
367 		vinfo.v_rmt_addr = vifp->v_rmt_addr;
368 		vinfo.v_pkt_in = vifp->v_pkt_in;
369 		vinfo.v_pkt_out = vifp->v_pkt_out;
370 		vinfo.v_bytes_in = vifp->v_bytes_in;
371 		vinfo.v_bytes_out = vifp->v_bytes_out;
372 
373 		needed += sizeof(vinfo);
374 		if (where && needed <= given) {
375 			int error;
376 
377 			error = copyout(&vinfo, where, sizeof(vinfo));
378 			if (error)
379 				return (error);
380 			where += sizeof(vinfo);
381 		}
382 	}
383 	if (where) {
384 		*oldlenp = needed;
385 		if (given < needed)
386 			return (ENOMEM);
387 	} else
388 		*oldlenp = (11 * needed) / 10;
389 
390 	return (0);
391 }
392 
393 struct mfcsysctlarg {
394 	struct mfcinfo	*msa_minfos;
395 	size_t		 msa_len;
396 	size_t		 msa_needed;
397 };
398 
399 int
mrt_rtwalk_mfcsysctl(struct rtentry * rt,void * arg,unsigned int rtableid)400 mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
401 {
402 	struct mfc		*mfc = (struct mfc *)rt->rt_llinfo;
403 	struct mfcsysctlarg	*msa = (struct mfcsysctlarg *)arg;
404 	struct ifnet		*ifp;
405 	struct vif		*v;
406 	struct mfcinfo		*minfo;
407 	int			 new = 0;
408 
409 	/* Skip entries being removed. */
410 	if (mfc == NULL)
411 		return (0);
412 
413 	/* Skip non-multicast routes. */
414 	if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
415 	    (RTF_HOST | RTF_MULTICAST))
416 		return (0);
417 
418 	/* User just asked for the output size. */
419 	if (msa->msa_minfos == NULL) {
420 		msa->msa_needed += sizeof(*minfo);
421 		return (0);
422 	}
423 
424 	/* Skip route with invalid interfaces. */
425 	if ((ifp = if_get(rt->rt_ifidx)) == NULL)
426 		return (0);
427 	if ((v = (struct vif *)ifp->if_mcast) == NULL) {
428 		if_put(ifp);
429 		return (0);
430 	}
431 
432 	for (minfo = msa->msa_minfos;
433 	    (uint8_t *)(minfo + 1) <=
434 	    (uint8_t *)msa->msa_minfos + msa->msa_len;
435 	    minfo++) {
436 		/* Find a new entry or update old entry. */
437 		if (minfo->mfc_origin.s_addr !=
438 		    satosin(rt->rt_gateway)->sin_addr.s_addr ||
439 		    minfo->mfc_mcastgrp.s_addr !=
440 		    satosin(rt_key(rt))->sin_addr.s_addr) {
441 			if (minfo->mfc_origin.s_addr != 0 ||
442 			    minfo->mfc_mcastgrp.s_addr != 0)
443 				continue;
444 
445 			new = 1;
446 		}
447 
448 		minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
449 		minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
450 		minfo->mfc_parent = mfc->mfc_parent;
451 		minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
452 		minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
453 		minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
454 		break;
455 	}
456 
457 	if (new != 0)
458 		msa->msa_needed += sizeof(*minfo);
459 
460 	if_put(ifp);
461 
462 	return (0);
463 }
464 
465 int
mrt_sysctl_mfc(void * oldp,size_t * oldlenp)466 mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
467 {
468 	unsigned int		 rtableid;
469 	int			 error;
470 	struct mfcsysctlarg	 msa;
471 
472 	if (oldp != NULL && *oldlenp > MAXPHYS)
473 		return (EINVAL);
474 
475 	memset(&msa, 0, sizeof(msa));
476 	if (oldp != NULL && *oldlenp > 0) {
477 		msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
478 		msa.msa_len = *oldlenp;
479 	}
480 
481 	for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
482 		rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl,
483 		    &msa);
484 	}
485 
486 	if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
487 	    (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
488 		free(msa.msa_minfos, M_TEMP, msa.msa_len);
489 		return (error);
490 	}
491 
492 	free(msa.msa_minfos, M_TEMP, msa.msa_len);
493 	*oldlenp = msa.msa_needed;
494 
495 	return (0);
496 }
497 
498 /*
499  * Enable multicast routing
500  */
501 int
ip_mrouter_init(struct socket * so,struct mbuf * m)502 ip_mrouter_init(struct socket *so, struct mbuf *m)
503 {
504 	struct inpcb *inp = sotoinpcb(so);
505 	unsigned int rtableid = inp->inp_rtableid;
506 	int *v;
507 
508 	if (so->so_type != SOCK_RAW ||
509 	    so->so_proto->pr_protocol != IPPROTO_IGMP)
510 		return (EOPNOTSUPP);
511 
512 	if (m == NULL || m->m_len < sizeof(int))
513 		return (EINVAL);
514 
515 	v = mtod(m, int *);
516 	if (*v != 1)
517 		return (EINVAL);
518 
519 	if (ip_mrouter[rtableid] != NULL)
520 		return (EADDRINUSE);
521 
522 	ip_mrouter[rtableid] = so;
523 
524 	return (0);
525 }
526 
527 int
mrouter_rtwalk_delete(struct rtentry * rt,void * arg,unsigned int rtableid)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
ip_mrouter_done(struct socket * so)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, &ifnetlist, if_list) {
566 		if (ifp->if_rdomain != rtableid)
567 			continue;
568 
569 		vif_delete(ifp);
570 	}
571 
572 	mrt_api_config = 0;
573 
574 	ip_mrouter[rtableid] = NULL;
575 	mrt_count[rtableid] = 0;
576 
577 	return (0);
578 }
579 
580 int
get_version(struct mbuf * m)581 get_version(struct mbuf *m)
582 {
583 	int *v = mtod(m, int *);
584 
585 	*v = 0x0305;	/* XXX !!!! */
586 	m->m_len = sizeof(int);
587 	return (0);
588 }
589 
590 /*
591  * Configure API capabilities
592  */
593 int
set_api_config(struct socket * so,struct mbuf * m)594 set_api_config(struct socket *so, struct mbuf *m)
595 {
596 	struct inpcb *inp = sotoinpcb(so);
597 	struct ifnet *ifp;
598 	u_int32_t *apival;
599 	unsigned int rtableid = inp->inp_rtableid;
600 
601 	if (m == NULL || m->m_len < sizeof(u_int32_t))
602 		return (EINVAL);
603 
604 	apival = mtod(m, u_int32_t *);
605 
606 	/*
607 	 * We can set the API capabilities only if it is the first operation
608 	 * after MRT_INIT. I.e.:
609 	 *  - there are no vifs installed
610 	 *  - the MFC table is empty
611 	 */
612 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
613 		if (ifp->if_rdomain != rtableid)
614 			continue;
615 		if (ifp->if_mcast == NULL)
616 			continue;
617 
618 		*apival = 0;
619 		return (EPERM);
620 	}
621 	if (mrt_count[rtableid] > 0) {
622 		*apival = 0;
623 		return (EPERM);
624 	}
625 
626 	mrt_api_config = *apival & mrt_api_support;
627 	*apival = mrt_api_config;
628 
629 	return (0);
630 }
631 
632 /*
633  * Get API capabilities
634  */
635 int
get_api_support(struct mbuf * m)636 get_api_support(struct mbuf *m)
637 {
638 	u_int32_t *apival;
639 
640 	if (m == NULL || m->m_len < sizeof(u_int32_t))
641 		return (EINVAL);
642 
643 	apival = mtod(m, u_int32_t *);
644 
645 	*apival = mrt_api_support;
646 
647 	return (0);
648 }
649 
650 /*
651  * Get API configured capabilities
652  */
653 int
get_api_config(struct mbuf * m)654 get_api_config(struct mbuf *m)
655 {
656 	u_int32_t *apival;
657 
658 	if (m == NULL || m->m_len < sizeof(u_int32_t))
659 		return (EINVAL);
660 
661 	apival = mtod(m, u_int32_t *);
662 
663 	*apival = mrt_api_config;
664 
665 	return (0);
666 }
667 
668 static struct sockaddr_in sin = { sizeof(sin), AF_INET };
669 
670 int
add_vif(struct socket * so,struct mbuf * m)671 add_vif(struct socket *so, struct mbuf *m)
672 {
673 	struct inpcb *inp = sotoinpcb(so);
674 	struct vifctl *vifcp;
675 	struct vif *vifp;
676 	struct ifaddr *ifa;
677 	struct ifnet *ifp;
678 	struct ifreq ifr;
679 	int error;
680 	unsigned int rtableid = inp->inp_rtableid;
681 
682 	NET_ASSERT_LOCKED();
683 
684 	if (m == NULL || m->m_len < sizeof(struct vifctl))
685 		return (EINVAL);
686 
687 	vifcp = mtod(m, struct vifctl *);
688 	if (vifcp->vifc_vifi >= MAXVIFS)
689 		return (EINVAL);
690 	if (in_nullhost(vifcp->vifc_lcl_addr))
691 		return (EADDRNOTAVAIL);
692 	if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
693 		return (EADDRINUSE);
694 
695 	/* Tunnels are no longer supported use gif(4) instead. */
696 	if (vifcp->vifc_flags & VIFF_TUNNEL)
697 		return (EOPNOTSUPP);
698 	{
699 		sin.sin_addr = vifcp->vifc_lcl_addr;
700 		ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
701 		if (ifa == NULL)
702 			return (EADDRNOTAVAIL);
703 	}
704 
705 	/* Use the physical interface associated with the address. */
706 	ifp = ifa->ifa_ifp;
707 	if (ifp->if_mcast != NULL)
708 		return (EADDRINUSE);
709 
710 	{
711 		/* Make sure the interface supports multicast. */
712 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
713 			return (EOPNOTSUPP);
714 
715 		/* Enable promiscuous reception of all IP multicasts. */
716 		memset(&ifr, 0, sizeof(ifr));
717 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
718 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
719 		satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
720 		KERNEL_LOCK();
721 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
722 		KERNEL_UNLOCK();
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
del_vif(struct socket * so,struct mbuf * m)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
vif_delete(struct ifnet * ifp)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
mfc_expire_route(struct rtentry * rt,u_int rtableid)783 mfc_expire_route(struct rtentry *rt, u_int rtableid)
784 {
785 	struct mfc	*mfc = (struct mfc *)rt->rt_llinfo;
786 
787 	/* Skip entry being deleted. */
788 	if (mfc == NULL)
789 		return;
790 
791 	DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
792 	    "expire %s", rtableid, satosin(rt->rt_gateway)->sin_addr.s_addr,
793 	    satosin(rt_key(rt))->sin_addr.s_addr,
794 	    rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
795 
796 	/* Not expired, add it back to the queue. */
797 	if (mfc->mfc_expire == 0) {
798 		mfc->mfc_expire = 1;
799 		rt_timer_add(rt, &ip_mrouterq, rtableid);
800 		return;
801 	}
802 
803 	mrt_mcast_del(rt, rtableid);
804 }
805 
806 int
mfc_add_route(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group,struct mfcctl2 * mfccp,int wait)807 mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
808     struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
809 {
810 	struct vif		*v = (struct vif *)ifp->if_mcast;
811 	struct rtentry		*rt;
812 	struct mfc		*mfc;
813 	unsigned int		 rtableid = ifp->if_rdomain;
814 
815 	rt = rt_mcast_add(ifp, origin, group);
816 	if (rt == NULL)
817 		return (EHOSTUNREACH);
818 
819 	mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
820 	if (mfc == NULL) {
821 		DPRINTF("origin %#08X group %#08X parent %d (%s) "
822 		    "malloc failed",
823 		    satosin(origin)->sin_addr.s_addr,
824 		    satosin(group)->sin_addr.s_addr,
825 		    mfccp->mfcc_parent, ifp->if_xname);
826 		mrt_mcast_del(rt, rtableid);
827 		rtfree(rt);
828 		return (ENOMEM);
829 	}
830 
831 	rt->rt_llinfo = (caddr_t)mfc;
832 
833 	rt_timer_add(rt, &ip_mrouterq, rtableid);
834 
835 	mfc->mfc_parent = mfccp->mfcc_parent;
836 	mfc->mfc_pkt_cnt = 0;
837 	mfc->mfc_byte_cnt = 0;
838 	mfc->mfc_wrong_if = 0;
839 	mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
840 	mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
841 	    MRT_MFC_FLAGS_ALL;
842 	mfc->mfc_expire = 0;
843 
844 	/* set the RP address */
845 	if (mrt_api_config & MRT_MFC_RP)
846 		mfc->mfc_rp = mfccp->mfcc_rp;
847 	else
848 		mfc->mfc_rp = zeroin_addr;
849 
850 	rtfree(rt);
851 
852 	return (0);
853 }
854 
855 void
update_mfc_params(struct mfcctl2 * mfccp,int wait,unsigned int rtableid)856 update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
857 {
858 	struct rtentry		*rt;
859 	struct mfc		*mfc;
860 	struct ifnet		*ifp;
861 	int			 i;
862 	struct sockaddr_in	 osin, msin;
863 
864 	memset(&osin, 0, sizeof(osin));
865 	osin.sin_len = sizeof(osin);
866 	osin.sin_family = AF_INET;
867 	osin.sin_addr = mfccp->mfcc_origin;
868 
869 	memset(&msin, 0, sizeof(msin));
870 	msin.sin_len = sizeof(msin);
871 	msin.sin_family = AF_INET;
872 	msin.sin_addr = mfccp->mfcc_mcastgrp;
873 
874 	for (i = 0; i < MAXVIFS; i++) {
875 		/* Don't add/del upstream routes here. */
876 		if (i == mfccp->mfcc_parent)
877 			continue;
878 
879 		/* Test for vif existence and then update the entry. */
880 		if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
881 			continue;
882 
883 		rt = mfc_find(ifp, &mfccp->mfcc_origin,
884 		    &mfccp->mfcc_mcastgrp, rtableid);
885 
886 		/* vif not configured or removed. */
887 		if (mfccp->mfcc_ttls[i] == 0) {
888 			/* Route doesn't exist, nothing to do. */
889 			if (rt == NULL)
890 				continue;
891 
892 			DPRINTF("del route (group %#08X) for vif %d (%s)",
893 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
894 			mrt_mcast_del(rt, rtableid);
895 			rtfree(rt);
896 			continue;
897 		}
898 
899 		/* Route exists, look for changes. */
900 		if (rt != NULL) {
901 			mfc = (struct mfc *)rt->rt_llinfo;
902 			/* Skip route being deleted. */
903 			if (mfc == NULL) {
904 				rtfree(rt);
905 				continue;
906 			}
907 
908 			/* No new changes to apply. */
909 			if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
910 			    mfccp->mfcc_parent == mfc->mfc_parent) {
911 				rtfree(rt);
912 				continue;
913 			}
914 
915 			DPRINTF("update route (group %#08X) for vif %d (%s)",
916 			    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
917 			mfc->mfc_ttl = mfccp->mfcc_ttls[i];
918 			mfc->mfc_parent = mfccp->mfcc_parent;
919 			rtfree(rt);
920 			continue;
921 		}
922 
923 		DPRINTF("add route (group %#08X) for vif %d (%s)",
924 		    mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
925 
926 		mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
927 		    mfccp, wait);
928 	}
929 
930 	/* Create route for the parent interface. */
931 	if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
932 		DPRINTF("failed to find upstream interface %d",
933 		    mfccp->mfcc_parent);
934 		return;
935 	}
936 
937 	/* We already have a route, nothing to do here. */
938 	if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
939 	    &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
940 		rtfree(rt);
941 		return;
942 	}
943 
944 	DPRINTF("add upstream route (group %#08X) for if %s",
945 	    mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
946 	mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
947 }
948 
949 int
mfc_add(struct mfcctl2 * mfcctl2,struct in_addr * origin,struct in_addr * group,int vidx,unsigned int rtableid,int wait)950 mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
951     struct in_addr *group, int vidx, unsigned int rtableid, int wait)
952 {
953 	struct ifnet		*ifp;
954 	struct vif		*v;
955 	struct mfcctl2		 mfcctl;
956 
957 	ifp = if_lookupbyvif(vidx, rtableid);
958 	if (ifp == NULL ||
959 	    (v = (struct vif *)ifp->if_mcast) == NULL)
960 		return (EHOSTUNREACH);
961 
962 	memset(&mfcctl, 0, sizeof(mfcctl));
963 	if (mfcctl2 == NULL) {
964 		mfcctl.mfcc_origin = *origin;
965 		mfcctl.mfcc_mcastgrp = *group;
966 		mfcctl.mfcc_parent = vidx;
967 	} else
968 		memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
969 
970 	update_mfc_params(&mfcctl, wait, rtableid);
971 
972 	return (0);
973 }
974 
975 int
add_mfc(struct socket * so,struct mbuf * m)976 add_mfc(struct socket *so, struct mbuf *m)
977 {
978 	struct inpcb *inp = sotoinpcb(so);
979 	struct mfcctl2 mfcctl2;
980 	int mfcctl_size = sizeof(struct mfcctl);
981 	unsigned int rtableid = inp->inp_rtableid;
982 
983 	NET_ASSERT_LOCKED();
984 
985 	if (mrt_api_config & MRT_API_FLAGS_ALL)
986 		mfcctl_size = sizeof(struct mfcctl2);
987 
988 	if (m == NULL || m->m_len < mfcctl_size)
989 		return (EINVAL);
990 
991 	/*
992 	 * select data size depending on API version.
993 	 */
994 	if (mrt_api_config & MRT_API_FLAGS_ALL) {
995 		struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
996 		memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
997 	} else {
998 		struct mfcctl *mp = mtod(m, struct mfcctl *);
999 		memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1000 		memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1001 		    sizeof(mfcctl2) - sizeof(struct mfcctl));
1002 	}
1003 
1004 	if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1005 	    mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
1006 		return (EINVAL);
1007 
1008 	return (0);
1009 }
1010 
1011 int
del_mfc(struct socket * so,struct mbuf * m)1012 del_mfc(struct socket *so, struct mbuf *m)
1013 {
1014 	struct inpcb *inp = sotoinpcb(so);
1015 	struct rtentry *rt;
1016 	struct mfcctl2 mfcctl2;
1017 	int mfcctl_size = sizeof(struct mfcctl);
1018 	struct mfcctl *mp;
1019 	unsigned int rtableid = inp->inp_rtableid;
1020 
1021 	NET_ASSERT_LOCKED();
1022 
1023 	/*
1024 	 * XXX: for deleting MFC entries the information in entries
1025 	 * of size "struct mfcctl" is sufficient.
1026 	 */
1027 
1028 	if (m == NULL || m->m_len < mfcctl_size)
1029 		return (EINVAL);
1030 
1031 	mp = mtod(m, struct mfcctl *);
1032 
1033 	memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1034 	memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1035 	    sizeof(mfcctl2) - sizeof(struct mfcctl));
1036 
1037 	DPRINTF("origin %#08X group %#08X rtableid %d",
1038 	    mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
1039 
1040 	while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
1041 	    &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
1042 		mrt_mcast_del(rt, rtableid);
1043 		rtfree(rt);
1044 	}
1045 
1046 	return (0);
1047 }
1048 
1049 int
socket_send(struct socket * so,struct mbuf * mm,struct sockaddr_in * src)1050 socket_send(struct socket *so, struct mbuf *mm, struct sockaddr_in *src)
1051 {
1052 	if (so != NULL) {
1053 		int ret;
1054 
1055 		mtx_enter(&so->so_rcv.sb_mtx);
1056 		ret = sbappendaddr(so, &so->so_rcv, sintosa(src), mm, NULL);
1057 		mtx_leave(&so->so_rcv.sb_mtx);
1058 
1059 		if (ret != 0) {
1060 			sorwakeup(so);
1061 			return (0);
1062 		}
1063 	}
1064 	m_freem(mm);
1065 	return (-1);
1066 }
1067 
1068 /*
1069  * IP multicast forwarding function. This function assumes that the packet
1070  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1071  * pointed to by "ifp", and the packet is to be relayed to other networks
1072  * that have members of the packet's destination IP multicast group.
1073  *
1074  * The packet is returned unscathed to the caller, unless it is
1075  * erroneous, in which case a non-zero return value tells the caller to
1076  * discard it.
1077  */
1078 
1079 #define IP_HDR_LEN  20	/* # bytes of fixed IP header (excluding options) */
1080 #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
1081 
1082 int
ip_mforward(struct mbuf * m,struct ifnet * ifp)1083 ip_mforward(struct mbuf *m, struct ifnet *ifp)
1084 {
1085 	struct ip *ip = mtod(m, struct ip *);
1086 	struct vif *v;
1087 	struct rtentry *rt;
1088 	static int srctun = 0;
1089 	struct mbuf *mm;
1090 	unsigned int rtableid = ifp->if_rdomain;
1091 
1092 	if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
1093 	    ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
1094 		/*
1095 		 * Packet arrived via a physical interface or
1096 		 * an encapsulated tunnel or a register_vif.
1097 		 */
1098 	} else {
1099 		/*
1100 		 * Packet arrived through a source-route tunnel.
1101 		 * Source-route tunnels are no longer supported.
1102 		 */
1103 		if ((srctun++ % 1000) == 0)
1104 			log(LOG_ERR, "ip_mforward: received source-routed "
1105 			    "packet from %x\n", ntohl(ip->ip_src.s_addr));
1106 		return (EOPNOTSUPP);
1107 	}
1108 
1109 	/*
1110 	 * Don't forward a packet with time-to-live of zero or one,
1111 	 * or a packet destined to a local-only group.
1112 	 */
1113 	if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
1114 		return (0);
1115 
1116 	/*
1117 	 * Determine forwarding vifs from the forwarding cache table
1118 	 */
1119 	++mrtstat.mrts_mfc_lookups;
1120 	rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
1121 
1122 	/* Entry exists, so forward if necessary */
1123 	if (rt != NULL) {
1124 		return (ip_mdq(m, ifp, rt));
1125 	} else {
1126 		/*
1127 		 * If we don't have a route for packet's origin,
1128 		 * Make a copy of the packet & send message to routing daemon
1129 		 */
1130 		int hlen = ip->ip_hl << 2;
1131 
1132 		++mrtstat.mrts_mfc_misses;
1133 		mrtstat.mrts_no_route++;
1134 
1135 		{
1136 			struct igmpmsg *im;
1137 
1138 			/*
1139 			 * Locate the vifi for the incoming interface for
1140 			 * this packet.
1141 			 * If none found, drop packet.
1142 			 */
1143 			if ((v = (struct vif *)ifp->if_mcast) == NULL)
1144 				return (EHOSTUNREACH);
1145 			/*
1146 			 * Make a copy of the header to send to the user level
1147 			 * process
1148 			 */
1149 			mm = m_copym(m, 0, hlen, M_NOWAIT);
1150 			if (mm == NULL ||
1151 			    (mm = m_pullup(mm, hlen)) == NULL)
1152 				return (ENOBUFS);
1153 
1154 			/*
1155 			 * Send message to routing daemon to install
1156 			 * a route into the kernel table
1157 			 */
1158 
1159 			im = mtod(mm, struct igmpmsg *);
1160 			im->im_msgtype = IGMPMSG_NOCACHE;
1161 			im->im_mbz = 0;
1162 			im->im_vif = v->v_id;
1163 
1164 			mrtstat.mrts_upcalls++;
1165 
1166 			sin.sin_addr = ip->ip_src;
1167 			if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1168 				log(LOG_WARNING, "ip_mforward: ip_mrouter "
1169 				    "socket queue full\n");
1170 				++mrtstat.mrts_upq_sockfull;
1171 				return (ENOBUFS);
1172 			}
1173 
1174 			mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
1175 			    rtableid, M_NOWAIT);
1176 		}
1177 
1178 		return (0);
1179 	}
1180 }
1181 
1182 /*
1183  * Packet forwarding routine once entry in the cache is made
1184  */
1185 int
ip_mdq(struct mbuf * m,struct ifnet * ifp0,struct rtentry * rt)1186 ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1187 {
1188 	struct ip  *ip = mtod(m, struct ip *);
1189 	struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1190 	struct vif *v = (struct vif *)ifp0->if_mcast;
1191 	struct ifnet *ifp;
1192 	struct mbuf *mc;
1193 	struct ip_moptions imo;
1194 
1195 	/* Sanity check: we have all promised pointers. */
1196 	if (v == NULL || mfc == NULL) {
1197 		rtfree(rt);
1198 		return (EHOSTUNREACH);
1199 	}
1200 
1201 	/*
1202 	 * Don't forward if it didn't arrive from the parent vif for its origin.
1203 	 */
1204 	if (mfc->mfc_parent != v->v_id) {
1205 		/* came in the wrong interface */
1206 		++mrtstat.mrts_wrong_if;
1207 		mfc->mfc_wrong_if++;
1208 		rtfree(rt);
1209 		return (0);
1210 	}
1211 
1212 	/* If I sourced this packet, it counts as output, else it was input. */
1213 	if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
1214 		v->v_pkt_out++;
1215 		v->v_bytes_out += m->m_pkthdr.len;
1216 	} else {
1217 		v->v_pkt_in++;
1218 		v->v_bytes_in += m->m_pkthdr.len;
1219 	}
1220 
1221 	/*
1222 	 * For each vif, decide if a copy of the packet should be forwarded.
1223 	 * Forward if:
1224 	 *		- the ttl exceeds the vif's threshold
1225 	 *		- there are group members downstream on interface
1226 	 */
1227 	do {
1228 		/* Don't consider non multicast routes. */
1229 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1230 		    (RTF_HOST | RTF_MULTICAST))
1231 			continue;
1232 
1233 		mfc = (struct mfc *)rt->rt_llinfo;
1234 		if (mfc == NULL)
1235 			continue;
1236 
1237 		mfc->mfc_pkt_cnt++;
1238 		mfc->mfc_byte_cnt += m->m_pkthdr.len;
1239 
1240 		/* Don't let this route expire. */
1241 		mfc->mfc_expire = 0;
1242 
1243 		if (ip->ip_ttl <= mfc->mfc_ttl)
1244 			continue;
1245 		if ((ifp = if_get(rt->rt_ifidx)) == NULL)
1246 			continue;
1247 
1248 		/* Sanity check: did we configure this? */
1249 		if ((v = (struct vif *)ifp->if_mcast) == NULL) {
1250 			if_put(ifp);
1251 			continue;
1252 		}
1253 
1254 		/* Don't send in the upstream interface. */
1255 		if (mfc->mfc_parent == v->v_id) {
1256 			if_put(ifp);
1257 			continue;
1258 		}
1259 
1260 		v->v_pkt_out++;
1261 		v->v_bytes_out += m->m_pkthdr.len;
1262 
1263 		/*
1264 		 * Make a new reference to the packet; make sure
1265 		 * that the IP header is actually copied, not
1266 		 * just referenced, so that ip_output() only
1267 		 * scribbles on the copy.
1268 		 */
1269 		mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1270 		if (mc == NULL) {
1271 			if_put(ifp);
1272 			rtfree(rt);
1273 			return (ENOBUFS);
1274 		}
1275 
1276 		/*
1277 		 * if physical interface option, extract the options
1278 		 * and then send
1279 		 */
1280 		imo.imo_ifidx = rt->rt_ifidx;
1281 		imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
1282 		imo.imo_loop = 1;
1283 
1284 		ip_output(mc, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
1285 		if_put(ifp);
1286 	} while ((rt = rtable_iterate(rt)) != NULL);
1287 
1288 	return (0);
1289 }
1290 
1291 struct ifnet *
if_lookupbyvif(vifi_t vifi,unsigned int rtableid)1292 if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1293 {
1294 	struct vif	*v;
1295 	struct ifnet	*ifp;
1296 
1297 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1298 		if (ifp->if_rdomain != rtableid)
1299 			continue;
1300 		if ((v = (struct vif *)ifp->if_mcast) == NULL)
1301 			continue;
1302 		if (v->v_id != vifi)
1303 			continue;
1304 
1305 		return (ifp);
1306 	}
1307 
1308 	return (NULL);
1309 }
1310 
1311 struct rtentry *
rt_mcast_add(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group)1312 rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1313 {
1314 	struct ifaddr		*ifa;
1315 	int			 rv;
1316 	unsigned int		 rtableid = ifp->if_rdomain;
1317 
1318 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1319 		if (ifa->ifa_addr->sa_family == AF_INET)
1320 			break;
1321 	}
1322 	if (ifa == NULL) {
1323 		DPRINTF("ifa == NULL");
1324 		return (NULL);
1325 	}
1326 
1327 	rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH,
1328 	    group, ifp->if_rdomain);
1329 	if (rv != 0) {
1330 		DPRINTF("rt_ifa_add failed (%d)", rv);
1331 		return (NULL);
1332 	}
1333 
1334 	mrt_count[rtableid]++;
1335 
1336 	return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
1337 }
1338 
1339 void
mrt_mcast_del(struct rtentry * rt,unsigned int rtableid)1340 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1341 {
1342 	struct ifnet		*ifp;
1343 	int			 error;
1344 
1345 	/* Remove all timers related to this route. */
1346 	rt_timer_remove_all(rt);
1347 
1348 	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
1349 	rt->rt_llinfo = NULL;
1350 
1351 	ifp = if_get(rt->rt_ifidx);
1352 	if (ifp == NULL)
1353 		return;
1354 	error = rtdeletemsg(rt, ifp, rtableid);
1355 	if_put(ifp);
1356 
1357 	if (error)
1358 		DPRINTF("delete route error %d\n", error);
1359 
1360 	mrt_count[rtableid]--;
1361 }
1362