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