xref: /original-bsd/sys/netinet/ip_mroute.c (revision e68c4d86)
1 /*
2  * Copyright (c) 1989 Stephen Deering
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Stephen Deering of Stanford University.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)ip_mroute.c	8.2 (Berkeley) 11/15/93
12  */
13 
14 /*
15  * Procedures for the kernel part of DVMRP,
16  * a Distance-Vector Multicast Routing Protocol.
17  * (See RFC-1075.)
18  *
19  * Written by David Waitzman, BBN Labs, August 1988.
20  * Modified by Steve Deering, Stanford, February 1989.
21  *
22  * MROUTING 1.1
23  */
24 
25 #ifndef MROUTING
26 int	ip_mrtproto;				/* for netstat only */
27 #else
28 
29 #include <sys/param.h>
30 #include <sys/errno.h>
31 #include <sys/ioctl.h>
32 #include <sys/malloc.h>
33 #include <sys/mbuf.h>
34 #include <sys/protosw.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/time.h>
38 
39 #include <net/if.h>
40 #include <net/route.h>
41 #include <net/raw_cb.h>
42 
43 #include <netinet/in.h>
44 #include <netinet/in_systm.h>
45 #include <netinet/ip.h>
46 #include <netinet/in_pcb.h>
47 #include <netinet/in_var.h>
48 #include <netinet/ip_var.h>
49 
50 #include <netinet/igmp.h>
51 #include <netinet/igmp_var.h>
52 #include <netinet/ip_mroute.h>
53 
54 /* Static forwards */
55 static	int ip_mrouter_init __P((struct socket *));
56 static	int add_vif __P((struct vifctl *));
57 static	int del_vif __P((vifi_t *vifip));
58 static	int add_lgrp __P((struct lgrplctl *));
59 static	int del_lgrp __P((struct lgrplctl *));
60 static	int grplst_member __P((struct vif *, struct in_addr));
61 static	u_long nethash __P((struct in_addr in));
62 static	int add_mrt __P((struct mrtctl *));
63 static	int del_mrt __P((struct in_addr *));
64 static	struct mrt *mrtfind __P((struct in_addr));
65 static	void phyint_send __P((struct mbuf *, struct vif *));
66 static	void tunnel_send __P((struct mbuf *, struct vif *));
67 
68 #define INSIZ sizeof(struct in_addr)
69 #define	same(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)
70 #define	satosin(sa)	((struct sockaddr_in *)(sa))
71 
72 /*
73  * Globals.  All but ip_mrouter and ip_mrtproto could be static,
74  * except for netstat or debugging purposes.
75  */
76 struct	socket *ip_mrouter = NULL;
77 int	ip_mrtproto = IGMP_DVMRP;		/* for netstat only */
78 
79 struct	mrt *mrttable[MRTHASHSIZ];
80 struct	vif viftable[MAXVIFS];
81 struct	mrtstat	mrtstat;
82 
83 /*
84  * Private variables.
85  */
86 static	vifi_t numvifs = 0;
87 static	struct mrt *cached_mrt = NULL;
88 static	u_long cached_origin;
89 static	u_long cached_originmask;
90 
91 /*
92  * Handle DVMRP setsockopt commands to modify the multicast routing tables.
93  */
94 int
ip_mrouter_cmd(cmd,so,m)95 ip_mrouter_cmd(cmd, so, m)
96 	register int cmd;
97 	register struct socket *so;
98 	register struct mbuf *m;
99 {
100 	register int error = 0;
101 
102 	if (cmd != DVMRP_INIT && so != ip_mrouter)
103 		error = EACCES;
104 	else switch (cmd) {
105 
106 	case DVMRP_INIT:
107 		error = ip_mrouter_init(so);
108 		break;
109 
110 	case DVMRP_DONE:
111 		error = ip_mrouter_done();
112 		break;
113 
114 	case DVMRP_ADD_VIF:
115 		if (m == NULL || m->m_len < sizeof(struct vifctl))
116 			error = EINVAL;
117 		else
118 			error = add_vif(mtod(m, struct vifctl *));
119 		break;
120 
121 	case DVMRP_DEL_VIF:
122 		if (m == NULL || m->m_len < sizeof(short))
123 			error = EINVAL;
124 		else
125 			error = del_vif(mtod(m, vifi_t *));
126 		break;
127 
128 	case DVMRP_ADD_LGRP:
129 		if (m == NULL || m->m_len < sizeof(struct lgrplctl))
130 			error = EINVAL;
131 		else
132 			error = add_lgrp(mtod(m, struct lgrplctl *));
133 		break;
134 
135 	case DVMRP_DEL_LGRP:
136 		if (m == NULL || m->m_len < sizeof(struct lgrplctl))
137 			error = EINVAL;
138 		else
139 			error = del_lgrp(mtod(m, struct lgrplctl *));
140 		break;
141 
142 	case DVMRP_ADD_MRT:
143 		if (m == NULL || m->m_len < sizeof(struct mrtctl))
144 			error = EINVAL;
145 		else
146 			error = add_mrt(mtod(m, struct mrtctl *));
147 		break;
148 
149 	case DVMRP_DEL_MRT:
150 		if (m == NULL || m->m_len < sizeof(struct in_addr))
151 			error = EINVAL;
152 		else
153 			error = del_mrt(mtod(m, struct in_addr *));
154 		break;
155 
156 	default:
157 		error = EOPNOTSUPP;
158 		break;
159 	}
160 	return (error);
161 }
162 
163 /*
164  * Enable multicast routing
165  */
166 static int
ip_mrouter_init(so)167 ip_mrouter_init(so)
168 	register struct socket *so;
169 {
170 	if (so->so_type != SOCK_RAW ||
171 	    so->so_proto->pr_protocol != IPPROTO_IGMP)
172 		return (EOPNOTSUPP);
173 
174 	if (ip_mrouter != NULL)
175 		return (EADDRINUSE);
176 
177 	ip_mrouter = so;
178 
179 	return (0);
180 }
181 
182 /*
183  * Disable multicast routing
184  */
185 int
ip_mrouter_done()186 ip_mrouter_done()
187 {
188 	register vifi_t vifi;
189 	register int i;
190 	register struct ifnet *ifp;
191 	register int s;
192 	struct ifreq ifr;
193 
194 	s = splnet();
195 
196 	/*
197 	 * For each phyint in use, free its local group list and
198 	 * disable promiscuous reception of all IP multicasts.
199 	 */
200 	for (vifi = 0; vifi < numvifs; vifi++) {
201 		if (viftable[vifi].v_lcl_addr.s_addr != 0 &&
202 		    !(viftable[vifi].v_flags & VIFF_TUNNEL)) {
203 			if (viftable[vifi].v_lcl_grps)
204 				free(viftable[vifi].v_lcl_grps, M_MRTABLE);
205 			satosin(&ifr.ifr_addr)->sin_family = AF_INET;
206 			satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
207 			ifp = viftable[vifi].v_ifp;
208 			(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
209 		}
210 	}
211 	bzero((caddr_t)viftable, sizeof(viftable));
212 	numvifs = 0;
213 
214 	/*
215 	 * Free any multicast route entries.
216 	 */
217 	for (i = 0; i < MRTHASHSIZ; i++)
218 		if (mrttable[i])
219 			free(mrttable[i], M_MRTABLE);
220 	bzero((caddr_t)mrttable, sizeof(mrttable));
221 	cached_mrt = NULL;
222 
223 	ip_mrouter = NULL;
224 
225 	splx(s);
226 	return (0);
227 }
228 
229 /*
230  * Add a vif to the vif table
231  */
232 static int
add_vif(vifcp)233 add_vif(vifcp)
234 	register struct vifctl *vifcp;
235 {
236 	register struct vif *vifp = viftable + vifcp->vifc_vifi;
237 	register struct ifaddr *ifa;
238 	register struct ifnet *ifp;
239 	struct ifreq ifr;
240 	register int error, s;
241 	static struct sockaddr_in sin = { sizeof(sin), AF_INET };
242 
243 	if (vifcp->vifc_vifi >= MAXVIFS)
244 		return (EINVAL);
245 	if (vifp->v_lcl_addr.s_addr != 0)
246 		return (EADDRINUSE);
247 
248 	/* Find the interface with an address in AF_INET family */
249 	sin.sin_addr = vifcp->vifc_lcl_addr;
250 	ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
251 	if (ifa == 0)
252 		return (EADDRNOTAVAIL);
253 
254 	s = splnet();
255 
256 	if (vifcp->vifc_flags & VIFF_TUNNEL)
257 		vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
258 	else {
259 		/* Make sure the interface supports multicast */
260 		ifp = ifa->ifa_ifp;
261 		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
262 			splx(s);
263 			return (EOPNOTSUPP);
264 		}
265 		/*
266 		 * Enable promiscuous reception of all IP multicasts
267 		 * from the interface.
268 		 */
269 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
270 		satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
271 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
272 		if (error) {
273 			splx(s);
274 			return (error);
275 		}
276 	}
277 
278 	vifp->v_flags = vifcp->vifc_flags;
279 	vifp->v_threshold = vifcp->vifc_threshold;
280 	vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
281 	vifp->v_ifp = ifa->ifa_ifp;
282 
283 	/* Adjust numvifs up if the vifi is higher than numvifs */
284 	if (numvifs <= vifcp->vifc_vifi)
285 		numvifs = vifcp->vifc_vifi + 1;
286 
287 	splx(s);
288 	return (0);
289 }
290 
291 /*
292  * Delete a vif from the vif table
293  */
294 static int
del_vif(vifip)295 del_vif(vifip)
296 	register vifi_t *vifip;
297 {
298 	register struct vif *vifp = viftable + *vifip;
299 	register struct ifnet *ifp;
300 	register int i, s;
301 	struct ifreq ifr;
302 
303 	if (*vifip >= numvifs)
304 		return (EINVAL);
305 	if (vifp->v_lcl_addr.s_addr == 0)
306 		return (EADDRNOTAVAIL);
307 
308 	s = splnet();
309 
310 	if (!(vifp->v_flags & VIFF_TUNNEL)) {
311 		if (vifp->v_lcl_grps)
312 			free(vifp->v_lcl_grps, M_MRTABLE);
313 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
314 		satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY;
315 		ifp = vifp->v_ifp;
316 		(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
317 	}
318 
319 	bzero((caddr_t)vifp, sizeof (*vifp));
320 
321 	/* Adjust numvifs down */
322 	for (i = numvifs - 1; i >= 0; i--)
323 		if (viftable[i].v_lcl_addr.s_addr != 0)
324 			break;
325 	numvifs = i + 1;
326 
327 	splx(s);
328 	return (0);
329 }
330 
331 /*
332  * Add the multicast group in the lgrpctl to the list of local multicast
333  * group memberships associated with the vif indexed by gcp->lgc_vifi.
334  */
335 static int
add_lgrp(gcp)336 add_lgrp(gcp)
337 	register struct lgrplctl *gcp;
338 {
339 	register struct vif *vifp;
340 	register int s;
341 
342 	if (gcp->lgc_vifi >= numvifs)
343 		return (EINVAL);
344 
345 	vifp = viftable + gcp->lgc_vifi;
346 	if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
347 		return (EADDRNOTAVAIL);
348 
349 	/* If not enough space in existing list, allocate a larger one */
350 	s = splnet();
351 	if (vifp->v_lcl_grps_n + 1 >= vifp->v_lcl_grps_max) {
352 		register int num;
353 		register struct in_addr *ip;
354 
355 		num = vifp->v_lcl_grps_max;
356 		if (num <= 0)
357 			num = 32;	/* initial number */
358 		else
359 			num += num;	/* double last number */
360 		ip = (struct in_addr *)malloc(num * sizeof(*ip),
361 		    M_MRTABLE, M_NOWAIT);
362 		if (ip == NULL) {
363 			splx(s);
364 			return (ENOBUFS);
365 		}
366 
367 		bzero((caddr_t)ip, num * sizeof(*ip));	/* XXX paranoid */
368 		bcopy((caddr_t)vifp->v_lcl_grps, (caddr_t)ip,
369 		    vifp->v_lcl_grps_n * sizeof(*ip));
370 
371 		vifp->v_lcl_grps_max = num;
372 		if (vifp->v_lcl_grps)
373 			free(vifp->v_lcl_grps, M_MRTABLE);
374 		vifp->v_lcl_grps = ip;
375 
376 		splx(s);
377 	}
378 
379 	vifp->v_lcl_grps[vifp->v_lcl_grps_n++] = gcp->lgc_gaddr;
380 
381 	if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
382 		vifp->v_cached_result = 1;
383 
384 	splx(s);
385 	return (0);
386 }
387 
388 /*
389  * Delete the the local multicast group associated with the vif
390  * indexed by gcp->lgc_vifi.
391  */
392 
393 static int
del_lgrp(gcp)394 del_lgrp(gcp)
395 	register struct lgrplctl *gcp;
396 {
397 	register struct vif *vifp;
398 	register int i, error, s;
399 
400 	if (gcp->lgc_vifi >= numvifs)
401 		return (EINVAL);
402 	vifp = viftable + gcp->lgc_vifi;
403 	if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))
404 		return (EADDRNOTAVAIL);
405 
406 	s = splnet();
407 
408 	if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)
409 		vifp->v_cached_result = 0;
410 
411 	error = EADDRNOTAVAIL;
412 	for (i = 0; i < vifp->v_lcl_grps_n; ++i)
413 		if (same(&gcp->lgc_gaddr, &vifp->v_lcl_grps[i])) {
414 			error = 0;
415 			vifp->v_lcl_grps_n--;
416 			bcopy((caddr_t)&vifp->v_lcl_grps[i + 1],
417 			    (caddr_t)&vifp->v_lcl_grps[i],
418 			    (vifp->v_lcl_grps_n - i) * sizeof(struct in_addr));
419 			error = 0;
420 			break;
421 		}
422 
423 	splx(s);
424 	return (error);
425 }
426 
427 /*
428  * Return 1 if gaddr is a member of the local group list for vifp.
429  */
430 static int
grplst_member(vifp,gaddr)431 grplst_member(vifp, gaddr)
432 	register struct vif *vifp;
433 	struct in_addr gaddr;
434 {
435 	register int i, s;
436 	register u_long addr;
437 
438 	mrtstat.mrts_grp_lookups++;
439 
440 	addr = gaddr.s_addr;
441 	if (addr == vifp->v_cached_group)
442 		return (vifp->v_cached_result);
443 
444 	mrtstat.mrts_grp_misses++;
445 
446 	for (i = 0; i < vifp->v_lcl_grps_n; ++i)
447 		if (addr == vifp->v_lcl_grps[i].s_addr) {
448 			s = splnet();
449 			vifp->v_cached_group = addr;
450 			vifp->v_cached_result = 1;
451 			splx(s);
452 			return (1);
453 		}
454 	s = splnet();
455 	vifp->v_cached_group = addr;
456 	vifp->v_cached_result = 0;
457 	splx(s);
458 	return (0);
459 }
460 
461 /*
462  * A simple hash function: returns MRTHASHMOD of the low-order octet of
463  * the argument's network or subnet number.
464  */
465 static u_long
nethash(in)466 nethash(in)
467 	struct in_addr in;
468 {
469 	register u_long n;
470 
471 	n = in_netof(in);
472 	while ((n & 0xff) == 0)
473 		n >>= 8;
474 	return (MRTHASHMOD(n));
475 }
476 
477 /*
478  * Add an mrt entry
479  */
480 static int
add_mrt(mrtcp)481 add_mrt(mrtcp)
482 	register struct mrtctl *mrtcp;
483 {
484 	struct mrt *rt;
485 	u_long hash;
486 	int s;
487 
488 	if (rt = mrtfind(mrtcp->mrtc_origin)) {
489 		/* Just update the route */
490 		s = splnet();
491 		rt->mrt_parent = mrtcp->mrtc_parent;
492 		VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
493 		VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
494 		splx(s);
495 		return (0);
496 	}
497 
498 	s = splnet();
499 
500 	rt = (struct mrt *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
501 	if (rt == NULL) {
502 		splx(s);
503 		return (ENOBUFS);
504 	}
505 
506 	/*
507 	 * insert new entry at head of hash chain
508 	 */
509 	rt->mrt_origin = mrtcp->mrtc_origin;
510 	rt->mrt_originmask = mrtcp->mrtc_originmask;
511 	rt->mrt_parent = mrtcp->mrtc_parent;
512 	VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);
513 	VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);
514 	/* link into table */
515 	hash = nethash(mrtcp->mrtc_origin);
516 	rt->mrt_next = mrttable[hash];
517 	mrttable[hash] = rt;
518 
519 	splx(s);
520 	return (0);
521 }
522 
523 /*
524  * Delete an mrt entry
525  */
526 static int
del_mrt(origin)527 del_mrt(origin)
528 	register struct in_addr *origin;
529 {
530 	register struct mrt *rt, *prev_rt;
531 	register u_long hash = nethash(*origin);
532 	register int s;
533 
534 	for (prev_rt = rt = mrttable[hash]; rt; prev_rt = rt, rt = rt->mrt_next)
535 		if (origin->s_addr == rt->mrt_origin.s_addr)
536 			break;
537 	if (!rt)
538 		return (ESRCH);
539 
540 	s = splnet();
541 
542 	if (rt == cached_mrt)
543 		cached_mrt = NULL;
544 
545 	if (prev_rt == rt)
546 		mrttable[hash] = rt->mrt_next;
547 	else
548 		prev_rt->mrt_next = rt->mrt_next;
549 	free(rt, M_MRTABLE);
550 
551 	splx(s);
552 	return (0);
553 }
554 
555 /*
556  * Find a route for a given origin IP address.
557  */
558 static struct mrt *
mrtfind(origin)559 mrtfind(origin)
560 	struct in_addr origin;
561 {
562 	register struct mrt *rt;
563 	register u_int hash;
564 	register int s;
565 
566 	mrtstat.mrts_mrt_lookups++;
567 
568 	if (cached_mrt != NULL &&
569 	    (origin.s_addr & cached_originmask) == cached_origin)
570 		return (cached_mrt);
571 
572 	mrtstat.mrts_mrt_misses++;
573 
574 	hash = nethash(origin);
575 	for (rt = mrttable[hash]; rt; rt = rt->mrt_next)
576 		if ((origin.s_addr & rt->mrt_originmask.s_addr) ==
577 		    rt->mrt_origin.s_addr) {
578 			s = splnet();
579 			cached_mrt = rt;
580 			cached_origin = rt->mrt_origin.s_addr;
581 			cached_originmask = rt->mrt_originmask.s_addr;
582 			splx(s);
583 			return (rt);
584 		}
585 	return (NULL);
586 }
587 
588 /*
589  * IP multicast forwarding function. This function assumes that the packet
590  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
591  * pointed to by "ifp", and the packet is to be relayed to other networks
592  * that have members of the packet's destination IP multicast group.
593  *
594  * The packet is returned unscathed to the caller, unless it is tunneled
595  * or erroneous, in which case a non-zero return value tells the caller to
596  * discard it.
597  */
598 
599 #define IP_HDR_LEN  20	/* # bytes of fixed IP header (excluding options) */
600 #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
601 
602 int
ip_mforward(m,ifp)603 ip_mforward(m, ifp)
604 	register struct mbuf *m;
605 	register struct ifnet *ifp;
606 {
607 	register struct ip *ip = mtod(m, struct ip *);
608 	register struct mrt *rt;
609 	register struct vif *vifp;
610 	register int vifi;
611 	register u_char *ipoptions;
612 	u_long tunnel_src;
613 
614 	if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
615 	    (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
616 		/*
617 		 * Packet arrived via a physical interface.
618 		 */
619 		tunnel_src = 0;
620 	} else {
621 		/*
622 		 * Packet arrived through a tunnel.
623 		 *
624 		 * A tunneled packet has a single NOP option and a
625 		 * two-element loose-source-and-record-route (LSRR)
626 		 * option immediately following the fixed-size part of
627 		 * the IP header.  At this point in processing, the IP
628 		 * header should contain the following IP addresses:
629 		 *
630 		 * original source          - in the source address field
631 		 * destination group        - in the destination address field
632 		 * remote tunnel end-point  - in the first  element of LSRR
633 		 * one of this host's addrs - in the second element of LSRR
634 		 *
635 		 * NOTE: RFC-1075 would have the original source and
636 		 * remote tunnel end-point addresses swapped.  However,
637 		 * that could cause delivery of ICMP error messages to
638 		 * innocent applications on intermediate routing
639 		 * hosts!  Therefore, we hereby change the spec.
640 		 */
641 
642 		/*
643 		 * Verify that the tunnel options are well-formed.
644 		 */
645 		if (ipoptions[0] != IPOPT_NOP ||
646 		    ipoptions[2] != 11 ||	/* LSRR option length   */
647 		    ipoptions[3] != 12 ||	/* LSRR address pointer */
648 		    (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) {
649 			mrtstat.mrts_bad_tunnel++;
650 			return (1);
651 		}
652 
653 		/*
654 		 * Delete the tunnel options from the packet.
655 		 */
656 		ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions,
657 		    (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN)));
658 		m->m_len -= TUNNEL_LEN;
659 		ip->ip_len -= TUNNEL_LEN;
660 		ip->ip_hl -= TUNNEL_LEN >> 2;
661 	}
662 
663 	/*
664 	 * Don't forward a packet with time-to-live of zero or one,
665 	 * or a packet destined to a local-only group.
666 	 */
667 	if (ip->ip_ttl <= 1 ||
668 	    ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP)
669 		return ((int)tunnel_src);
670 
671 	/*
672 	 * Don't forward if we don't have a route for the packet's origin.
673 	 */
674 	if (!(rt = mrtfind(ip->ip_src))) {
675 		mrtstat.mrts_no_route++;
676 		return ((int)tunnel_src);
677 	}
678 
679 	/*
680 	 * Don't forward if it didn't arrive from the parent vif for its origin.
681 	 */
682 	vifi = rt->mrt_parent;
683 	if (tunnel_src == 0 ) {
684 		if ((viftable[vifi].v_flags & VIFF_TUNNEL) ||
685 		    viftable[vifi].v_ifp != ifp )
686 			return ((int)tunnel_src);
687 	} else {
688 		if (!(viftable[vifi].v_flags & VIFF_TUNNEL) ||
689 		    viftable[vifi].v_rmt_addr.s_addr != tunnel_src )
690 			return ((int)tunnel_src);
691 	}
692 
693 	/*
694 	 * For each vif, decide if a copy of the packet should be forwarded.
695 	 * Forward if:
696 	 *		- the ttl exceeds the vif's threshold AND
697 	 *		- the vif is a child in the origin's route AND
698 	 *		- ( the vif is not a leaf in the origin's route OR
699 	 *		    the destination group has members on the vif )
700 	 *
701 	 * (This might be speeded up with some sort of cache -- someday.)
702 	 */
703 	for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) {
704 		if (ip->ip_ttl > vifp->v_threshold &&
705 		    VIFM_ISSET(vifi, rt->mrt_children) &&
706 		    (!VIFM_ISSET(vifi, rt->mrt_leaves) ||
707 		    grplst_member(vifp, ip->ip_dst))) {
708 			if (vifp->v_flags & VIFF_TUNNEL)
709 				tunnel_send(m, vifp);
710 			else
711 				phyint_send(m, vifp);
712 		}
713 	}
714 
715 	return ((int)tunnel_src);
716 }
717 
718 static void
phyint_send(m,vifp)719 phyint_send(m, vifp)
720 	register struct mbuf *m;
721 	register struct vif *vifp;
722 {
723 	register struct ip *ip = mtod(m, struct ip *);
724 	register struct mbuf *mb_copy;
725 	register struct ip_moptions *imo;
726 	register int error;
727 	struct ip_moptions simo;
728 
729 	mb_copy = m_copy(m, 0, M_COPYALL);
730 	if (mb_copy == NULL)
731 		return;
732 
733 	imo = &simo;
734 	imo->imo_multicast_ifp = vifp->v_ifp;
735 	imo->imo_multicast_ttl = ip->ip_ttl - 1;
736 	imo->imo_multicast_loop = 1;
737 
738 	error = ip_output(mb_copy, NULL, NULL, IP_FORWARDING, imo);
739 }
740 
741 static void
tunnel_send(m,vifp)742 tunnel_send(m, vifp)
743 	register struct mbuf *m;
744 	register struct vif *vifp;
745 {
746 	register struct ip *ip = mtod(m, struct ip *);
747 	register struct mbuf *mb_copy, *mb_opts;
748 	register struct ip *ip_copy;
749 	register int error;
750 	register u_char *cp;
751 
752 	/*
753 	 * Make sure that adding the tunnel options won't exceed the
754 	 * maximum allowed number of option bytes.
755 	 */
756 	if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) {
757 		mrtstat.mrts_cant_tunnel++;
758 		return;
759 	}
760 
761 	/*
762 	 * Get a private copy of the IP header so that changes to some
763 	 * of the IP fields don't damage the original header, which is
764 	 * examined later in ip_input.c.
765 	 */
766 	mb_copy = m_copy(m, IP_HDR_LEN, M_COPYALL);
767 	if (mb_copy == NULL)
768 		return;
769 	MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER);
770 	if (mb_opts == NULL) {
771 		m_freem(mb_copy);
772 		return;
773 	}
774 	/*
775 	 * Make mb_opts be the new head of the packet chain.
776 	 * Any options of the packet were left in the old packet chain head
777 	 */
778 	mb_opts->m_next = mb_copy;
779 	mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;
780 	mb_opts->m_data += MSIZE - mb_opts->m_len;
781 
782 	ip_copy = mtod(mb_opts, struct ip *);
783 	/*
784 	 * Copy the base ip header to the new head mbuf.
785 	 */
786 	*ip_copy = *ip;
787 	ip_copy->ip_ttl--;
788 	ip_copy->ip_dst = vifp->v_rmt_addr;	/* remote tunnel end-point */
789 	/*
790 	 * Adjust the ip header length to account for the tunnel options.
791 	 */
792 	ip_copy->ip_hl += TUNNEL_LEN >> 2;
793 	ip_copy->ip_len += TUNNEL_LEN;
794 	/*
795 	 * Add the NOP and LSRR after the base ip header
796 	 */
797 	cp = (u_char *)(ip_copy + 1);
798 	*cp++ = IPOPT_NOP;
799 	*cp++ = IPOPT_LSRR;
800 	*cp++ = 11;		/* LSRR option length */
801 	*cp++ = 8;		/* LSSR pointer to second element */
802 	*(u_long*)cp = vifp->v_lcl_addr.s_addr;	/* local tunnel end-point */
803 	cp += 4;
804 	*(u_long*)cp = ip->ip_dst.s_addr;		/* destination group */
805 
806 	error = ip_output(mb_opts, NULL, NULL, IP_FORWARDING, NULL);
807 }
808 #endif
809