|
|
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: ! 76: #ifndef MROUTING ! 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.