|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1980, 1986, 1991, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)route.c 8.2 (Berkeley) 11/15/93 ! 55: */ ! 56: ! 57: #if NOTFB31 ! 58: #include "opt_inet.h" ! 59: #include "opt_mrouting.h" ! 60: #endif ! 61: ! 62: #include <sys/param.h> ! 63: #include <sys/systm.h> ! 64: #include <sys/malloc.h> ! 65: #include <sys/mbuf.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/domain.h> ! 68: ! 69: #include <net/if.h> ! 70: #include <net/route.h> ! 71: ! 72: #include <netinet/in.h> ! 73: #include <netinet/ip_mroute.h> ! 74: ! 75: #define SA(p) ((struct sockaddr *)(p)) ! 76: ! 77: struct route_cb route_cb; ! 78: static struct rtstat rtstat; ! 79: struct radix_node_head *rt_tables[AF_MAX+1]; ! 80: ! 81: static int rttrash; /* routes not in table but not freed */ ! 82: ! 83: static void rt_maskedcopy __P((struct sockaddr *, ! 84: struct sockaddr *, struct sockaddr *)); ! 85: static void rtable_init __P((void **)); ! 86: ! 87: static void ! 88: rtable_init(table) ! 89: void **table; ! 90: { ! 91: struct domain *dom; ! 92: for (dom = domains; dom; dom = dom->dom_next) ! 93: if (dom->dom_rtattach) ! 94: dom->dom_rtattach(&table[dom->dom_family], ! 95: dom->dom_rtoffset); ! 96: } ! 97: ! 98: void ! 99: route_init() ! 100: { ! 101: rn_init(); /* initialize all zeroes, all ones, mask table */ ! 102: rtable_init((void **)rt_tables); ! 103: } ! 104: ! 105: /* ! 106: * Packet routing routines. ! 107: */ ! 108: void ! 109: rtalloc(ro) ! 110: register struct route *ro; ! 111: { ! 112: if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) ! 113: return; /* XXX */ ! 114: ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL); ! 115: } ! 116: ! 117: void ! 118: rtalloc_ign(ro, ignore) ! 119: register struct route *ro; ! 120: u_long ignore; ! 121: { ! 122: if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) ! 123: return; /* XXX */ ! 124: ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore); ! 125: } ! 126: ! 127: /* ! 128: * Look up the route that matches the address given ! 129: * Or, at least try.. Create a cloned route if needed. ! 130: */ ! 131: struct rtentry * ! 132: rtalloc1(dst, report, ignflags) ! 133: register struct sockaddr *dst; ! 134: int report; ! 135: u_long ignflags; ! 136: { ! 137: register struct radix_node_head *rnh = rt_tables[dst->sa_family]; ! 138: register struct rtentry *rt; ! 139: register struct radix_node *rn; ! 140: struct rtentry *newrt = 0; ! 141: struct rt_addrinfo info; ! 142: u_long nflags; ! 143: int s = splnet(), err = 0, msgtype = RTM_MISS; ! 144: ! 145: /* ! 146: * Look up the address in the table for that Address Family ! 147: */ ! 148: if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ! 149: ((rn->rn_flags & RNF_ROOT) == 0)) { ! 150: /* ! 151: * If we find it and it's not the root node, then ! 152: * get a refernce on the rtentry associated. ! 153: */ ! 154: newrt = rt = (struct rtentry *)rn; ! 155: nflags = rt->rt_flags & ~ignflags; ! 156: if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) { ! 157: /* ! 158: * We are apparently adding (report = 0 in delete). ! 159: * If it requires that it be cloned, do so. ! 160: * (This implies it wasn't a HOST route.) ! 161: */ ! 162: err = rtrequest(RTM_RESOLVE, dst, SA(0), ! 163: SA(0), 0, &newrt); ! 164: if (err) { ! 165: /* ! 166: * If the cloning didn't succeed, maybe ! 167: * what we have will do. Return that. ! 168: */ ! 169: newrt = rt; ! 170: rt->rt_refcnt++; ! 171: goto miss; ! 172: } ! 173: if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { ! 174: /* ! 175: * If the new route specifies it be ! 176: * externally resolved, then go do that. ! 177: */ ! 178: msgtype = RTM_RESOLVE; ! 179: goto miss; ! 180: } ! 181: } else ! 182: rt->rt_refcnt++; ! 183: } else { ! 184: /* ! 185: * Either we hit the root or couldn't find any match, ! 186: * Which basically means ! 187: * "caint get there frm here" ! 188: */ ! 189: rtstat.rts_unreach++; ! 190: miss: if (report) { ! 191: /* ! 192: * If required, report the failure to the supervising ! 193: * Authorities. ! 194: * For a delete, this is not an error. (report == 0) ! 195: */ ! 196: bzero((caddr_t)&info, sizeof(info)); ! 197: info.rti_info[RTAX_DST] = dst; ! 198: rt_missmsg(msgtype, &info, 0, err); ! 199: } ! 200: } ! 201: splx(s); ! 202: return (newrt); ! 203: } ! 204: ! 205: /* ! 206: * Remove a reference count from an rtentry. ! 207: * If the count gets low enough, take it out of the routing table ! 208: */ ! 209: void ! 210: rtfree(rt) ! 211: register struct rtentry *rt; ! 212: { ! 213: /* ! 214: * find the tree for that address family ! 215: */ ! 216: register struct radix_node_head *rnh = ! 217: rt_tables[rt_key(rt)->sa_family]; ! 218: register struct ifaddr *ifa; ! 219: ! 220: if (rt == 0 || rnh == 0) ! 221: panic("rtfree"); ! 222: ! 223: /* ! 224: * decrement the reference count by one and if it reaches 0, ! 225: * and there is a close function defined, call the close function ! 226: */ ! 227: rt->rt_refcnt--; ! 228: if(rnh->rnh_close && rt->rt_refcnt == 0) { ! 229: rnh->rnh_close((struct radix_node *)rt, rnh); ! 230: } ! 231: ! 232: /* ! 233: * If we are no longer "up" (and ref == 0) ! 234: * then we can free the resources associated ! 235: * with the route. ! 236: */ ! 237: if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { ! 238: if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) ! 239: panic ("rtfree 2"); ! 240: /* ! 241: * the rtentry must have been removed from the routing table ! 242: * so it is represented in rttrash.. remove that now. ! 243: */ ! 244: rttrash--; ! 245: ! 246: #ifdef DIAGNOSTIC ! 247: if (rt->rt_refcnt < 0) { ! 248: printf("rtfree: %p not freed (neg refs)\n", rt); ! 249: return; ! 250: } ! 251: #endif ! 252: ! 253: /* ! 254: * release references on items we hold them on.. ! 255: * e.g other routes and ifaddrs. ! 256: */ ! 257: if((ifa = rt->rt_ifa)) ! 258: IFAFREE(ifa); ! 259: if (rt->rt_parent) { ! 260: RTFREE(rt->rt_parent); ! 261: } ! 262: ! 263: /* ! 264: * The key is separatly alloc'd so free it (see rt_setgate()). ! 265: * This also frees the gateway, as they are always malloc'd ! 266: * together. ! 267: */ ! 268: Free(rt_key(rt)); ! 269: ! 270: /* ! 271: * and the rtentry itself of course ! 272: */ ! 273: Free(rt); ! 274: } ! 275: } ! 276: ! 277: void ! 278: ifafree(ifa) ! 279: register struct ifaddr *ifa; ! 280: { ! 281: if (ifa == NULL) ! 282: panic("ifafree"); ! 283: if (ifa->ifa_refcnt == 0) ! 284: FREE(ifa, M_IFADDR); ! 285: else ! 286: ifa->ifa_refcnt--; ! 287: } ! 288: ! 289: /* ! 290: * Force a routing table entry to the specified ! 291: * destination to go through the given gateway. ! 292: * Normally called as a result of a routing redirect ! 293: * message from the network layer. ! 294: * ! 295: * N.B.: must be called at splnet ! 296: * ! 297: */ ! 298: void ! 299: rtredirect(dst, gateway, netmask, flags, src, rtp) ! 300: struct sockaddr *dst, *gateway, *netmask, *src; ! 301: int flags; ! 302: struct rtentry **rtp; ! 303: { ! 304: register struct rtentry *rt; ! 305: int error = 0; ! 306: short *stat = 0; ! 307: struct rt_addrinfo info; ! 308: struct ifaddr *ifa; ! 309: ! 310: /* verify the gateway is directly reachable */ ! 311: if ((ifa = ifa_ifwithnet(gateway)) == 0) { ! 312: error = ENETUNREACH; ! 313: goto out; ! 314: } ! 315: rt = rtalloc1(dst, 0, 0UL); ! 316: /* ! 317: * If the redirect isn't from our current router for this dst, ! 318: * it's either old or wrong. If it redirects us to ourselves, ! 319: * we have a routing loop, perhaps as a result of an interface ! 320: * going down recently. ! 321: */ ! 322: #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) ! 323: if (!(flags & RTF_DONE) && rt && ! 324: (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) ! 325: error = EINVAL; ! 326: else if (ifa_ifwithaddr(gateway)) ! 327: error = EHOSTUNREACH; ! 328: if (error) ! 329: goto done; ! 330: /* ! 331: * Create a new entry if we just got back a wildcard entry ! 332: * or the the lookup failed. This is necessary for hosts ! 333: * which use routing redirects generated by smart gateways ! 334: * to dynamically build the routing tables. ! 335: */ ! 336: if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) ! 337: goto create; ! 338: /* ! 339: * Don't listen to the redirect if it's ! 340: * for a route to an interface. ! 341: */ ! 342: if (rt->rt_flags & RTF_GATEWAY) { ! 343: if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { ! 344: /* ! 345: * Changing from route to net => route to host. ! 346: * Create new route, rather than smashing route to net. ! 347: */ ! 348: create: ! 349: flags |= RTF_GATEWAY | RTF_DYNAMIC; ! 350: error = rtrequest((int)RTM_ADD, dst, gateway, ! 351: netmask, flags, ! 352: (struct rtentry **)0); ! 353: stat = &rtstat.rts_dynamic; ! 354: } else { ! 355: /* ! 356: * Smash the current notion of the gateway to ! 357: * this destination. Should check about netmask!!! ! 358: */ ! 359: rt->rt_flags |= RTF_MODIFIED; ! 360: flags |= RTF_MODIFIED; ! 361: stat = &rtstat.rts_newgateway; ! 362: /* ! 363: * add the key and gateway (in one malloc'd chunk). ! 364: */ ! 365: rt_setgate(rt, rt_key(rt), gateway); ! 366: } ! 367: } else ! 368: error = EHOSTUNREACH; ! 369: done: ! 370: if (rt) { ! 371: if (rtp && !error) ! 372: *rtp = rt; ! 373: else ! 374: rtfree(rt); ! 375: } ! 376: out: ! 377: if (error) ! 378: rtstat.rts_badredirect++; ! 379: else if (stat != NULL) ! 380: (*stat)++; ! 381: bzero((caddr_t)&info, sizeof(info)); ! 382: info.rti_info[RTAX_DST] = dst; ! 383: info.rti_info[RTAX_GATEWAY] = gateway; ! 384: info.rti_info[RTAX_NETMASK] = netmask; ! 385: info.rti_info[RTAX_AUTHOR] = src; ! 386: rt_missmsg(RTM_REDIRECT, &info, flags, error); ! 387: } ! 388: ! 389: /* ! 390: * Routing table ioctl interface. ! 391: */ ! 392: int ! 393: rtioctl(req, data, p) ! 394: int req; ! 395: caddr_t data; ! 396: struct proc *p; ! 397: { ! 398: #if INET ! 399: /* Multicast goop, grrr... */ ! 400: #if MROUTING ! 401: return mrt_ioctl(req, data); ! 402: #else ! 403: return mrt_ioctl(req, data, p); ! 404: #endif ! 405: #else /* INET */ ! 406: return ENXIO; ! 407: #endif /* INET */ ! 408: } ! 409: ! 410: struct ifaddr * ! 411: ifa_ifwithroute(flags, dst, gateway) ! 412: int flags; ! 413: struct sockaddr *dst, *gateway; ! 414: { ! 415: register struct ifaddr *ifa; ! 416: if ((flags & RTF_GATEWAY) == 0) { ! 417: /* ! 418: * If we are adding a route to an interface, ! 419: * and the interface is a pt to pt link ! 420: * we should search for the destination ! 421: * as our clue to the interface. Otherwise ! 422: * we can use the local address. ! 423: */ ! 424: ifa = 0; ! 425: if (flags & RTF_HOST) { ! 426: ifa = ifa_ifwithdstaddr(dst); ! 427: } ! 428: if (ifa == 0) ! 429: ifa = ifa_ifwithaddr(gateway); ! 430: } else { ! 431: /* ! 432: * If we are adding a route to a remote net ! 433: * or host, the gateway may still be on the ! 434: * other end of a pt to pt link. ! 435: */ ! 436: ifa = ifa_ifwithdstaddr(gateway); ! 437: } ! 438: if (ifa == 0) ! 439: ifa = ifa_ifwithnet(gateway); ! 440: if (ifa == 0) { ! 441: struct rtentry *rt = rtalloc1(dst, 0, 0UL); ! 442: if (rt == 0) ! 443: return (0); ! 444: rt->rt_refcnt--; ! 445: if ((ifa = rt->rt_ifa) == 0) ! 446: return (0); ! 447: } ! 448: if (ifa->ifa_addr->sa_family != dst->sa_family) { ! 449: struct ifaddr *oifa = ifa; ! 450: ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); ! 451: if (ifa == 0) ! 452: ifa = oifa; ! 453: } ! 454: return (ifa); ! 455: } ! 456: ! 457: #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) ! 458: ! 459: static int rt_fixdelete __P((struct radix_node *, void *)); ! 460: static int rt_fixchange __P((struct radix_node *, void *)); ! 461: ! 462: struct rtfc_arg { ! 463: struct rtentry *rt0; ! 464: struct radix_node_head *rnh; ! 465: }; ! 466: ! 467: /* ! 468: * Do appropriate manipulations of a routing tree given ! 469: * all the bits of info needed ! 470: */ ! 471: int ! 472: rtrequest(req, dst, gateway, netmask, flags, ret_nrt) ! 473: int req, flags; ! 474: struct sockaddr *dst, *gateway, *netmask; ! 475: struct rtentry **ret_nrt; ! 476: { ! 477: int s = splnet(); int error = 0; ! 478: register struct rtentry *rt; ! 479: register struct radix_node *rn; ! 480: register struct radix_node_head *rnh; ! 481: struct ifaddr *ifa; ! 482: struct sockaddr *ndst; ! 483: #define senderr(x) { error = x ; goto bad; } ! 484: ! 485: /* ! 486: * Find the correct routing tree to use for this Address Family ! 487: */ ! 488: if ((rnh = rt_tables[dst->sa_family]) == 0) ! 489: senderr(ESRCH); ! 490: /* ! 491: * If we are adding a host route then we don't want to put ! 492: * a netmask in the tree ! 493: */ ! 494: if (flags & RTF_HOST) ! 495: netmask = 0; ! 496: switch (req) { ! 497: case RTM_DELETE: ! 498: /* ! 499: * Remove the item from the tree and return it. ! 500: * Complain if it is not there and do no more processing. ! 501: */ ! 502: if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) ! 503: senderr(ESRCH); ! 504: if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) ! 505: panic ("rtrequest delete"); ! 506: rt = (struct rtentry *)rn; ! 507: ! 508: /* ! 509: * Now search what's left of the subtree for any cloned ! 510: * routes which might have been formed from this node. ! 511: */ ! 512: if ((rt->rt_flags & RTF_PRCLONING) && netmask) { ! 513: rnh->rnh_walktree_from(rnh, dst, netmask, ! 514: rt_fixdelete, rt); ! 515: } ! 516: ! 517: /* ! 518: * Remove any external references we may have. ! 519: * This might result in another rtentry being freed if ! 520: * we held its last reference. ! 521: */ ! 522: if (rt->rt_gwroute) { ! 523: rt = rt->rt_gwroute; ! 524: RTFREE(rt); ! 525: (rt = (struct rtentry *)rn)->rt_gwroute = 0; ! 526: } ! 527: ! 528: /* ! 529: * NB: RTF_UP must be set during the search above, ! 530: * because we might delete the last ref, causing ! 531: * rt to get freed prematurely. ! 532: * eh? then why not just add a reference? ! 533: * I'm not sure how RTF_UP helps matters. (JRE) ! 534: */ ! 535: rt->rt_flags &= ~RTF_UP; ! 536: ! 537: /* ! 538: * give the protocol a chance to keep things in sync. ! 539: */ ! 540: if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) ! 541: ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); ! 542: ! 543: /* ! 544: * one more rtentry floating around that is not ! 545: * linked to the routing table. ! 546: */ ! 547: rttrash++; ! 548: ! 549: /* ! 550: * If the caller wants it, then it can have it, ! 551: * but it's up to it to free the rtentry as we won't be ! 552: * doing it. ! 553: */ ! 554: if (ret_nrt) ! 555: *ret_nrt = rt; ! 556: else if (rt->rt_refcnt <= 0) { ! 557: rt->rt_refcnt++; ! 558: rtfree(rt); ! 559: } ! 560: break; ! 561: ! 562: case RTM_RESOLVE: ! 563: if (ret_nrt == 0 || (rt = *ret_nrt) == 0) ! 564: senderr(EINVAL); ! 565: ifa = rt->rt_ifa; ! 566: flags = rt->rt_flags & ! 567: ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC); ! 568: flags |= RTF_WASCLONED; ! 569: gateway = rt->rt_gateway; ! 570: if ((netmask = rt->rt_genmask) == 0) ! 571: flags |= RTF_HOST; ! 572: goto makeroute; ! 573: ! 574: case RTM_ADD: ! 575: if ((flags & RTF_GATEWAY) && !gateway) ! 576: panic("rtrequest: GATEWAY but no gateway"); ! 577: ! 578: if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) ! 579: senderr(ENETUNREACH); ! 580: ! 581: makeroute: ! 582: R_Malloc(rt, struct rtentry *, sizeof(*rt)); ! 583: if (rt == 0) ! 584: senderr(ENOBUFS); ! 585: Bzero(rt, sizeof(*rt)); ! 586: rt->rt_flags = RTF_UP | flags; ! 587: /* ! 588: * Add the gateway. Possibly re-malloc-ing the storage for it ! 589: * also add the rt_gwroute if possible. ! 590: */ ! 591: if (error = rt_setgate(rt, dst, gateway)) { ! 592: Free(rt); ! 593: senderr(error); ! 594: } ! 595: ! 596: /* ! 597: * point to the (possibly newly malloc'd) dest address. ! 598: */ ! 599: ndst = rt_key(rt); ! 600: ! 601: /* ! 602: * make sure it contains the value we want (masked if needed). ! 603: */ ! 604: if (netmask) { ! 605: rt_maskedcopy(dst, ndst, netmask); ! 606: } else ! 607: Bcopy(dst, ndst, dst->sa_len); ! 608: ! 609: /* ! 610: * Note that we now have a reference to the ifa. ! 611: * This moved from below so that rnh->rnh_addaddr() can ! 612: * examine the ifa and ifa->ifa_ifp if it so desires. ! 613: */ ! 614: ifa->ifa_refcnt++; ! 615: rt->rt_ifa = ifa; ! 616: rt->rt_ifp = ifa->ifa_ifp; ! 617: rt->rt_dlt = ifa->ifa_dlt; ! 618: rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, ! 619: rnh, rt->rt_nodes); ! 620: if (rn == 0) { ! 621: struct rtentry *rt2; ! 622: /* ! 623: * Uh-oh, we already have one of these in the tree. ! 624: * We do a special hack: if the route that's already ! 625: * there was generated by the protocol-cloning ! 626: * mechanism, then we just blow it away and retry ! 627: * the insertion of the new one. ! 628: */ ! 629: rt2 = rtalloc1(dst, 0, RTF_PRCLONING); ! 630: if (rt2 && rt2->rt_parent) { ! 631: rtrequest(RTM_DELETE, ! 632: (struct sockaddr *)rt_key(rt2), ! 633: rt2->rt_gateway, ! 634: rt_mask(rt2), rt2->rt_flags, 0); ! 635: RTFREE(rt2); ! 636: rn = rnh->rnh_addaddr((caddr_t)ndst, ! 637: (caddr_t)netmask, ! 638: rnh, rt->rt_nodes); ! 639: } else if (rt2) { ! 640: /* undo the extra ref we got */ ! 641: RTFREE(rt2); ! 642: } ! 643: } ! 644: ! 645: /* ! 646: * If it still failed to go into the tree, ! 647: * then un-make it (this should be a function) ! 648: */ ! 649: if (rn == 0) { ! 650: if (rt->rt_gwroute) ! 651: rtfree(rt->rt_gwroute); ! 652: if (rt->rt_ifa) { ! 653: IFAFREE(rt->rt_ifa); ! 654: } ! 655: Free(rt_key(rt)); ! 656: Free(rt); ! 657: senderr(EEXIST); ! 658: } ! 659: ! 660: rt->rt_parent = 0; ! 661: ! 662: /* ! 663: * If we got here from RESOLVE, then we are cloning ! 664: * so clone the rest, and note that we ! 665: * are a clone (and increment the parent's references) ! 666: */ ! 667: if (req == RTM_RESOLVE) { ! 668: rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ ! 669: if ((*ret_nrt)->rt_flags & RTF_PRCLONING) { ! 670: rt->rt_parent = (*ret_nrt); ! 671: (*ret_nrt)->rt_refcnt++; ! 672: } ! 673: } ! 674: ! 675: /* ! 676: * if this protocol has something to add to this then ! 677: * allow it to do that as well. ! 678: */ ! 679: if (ifa->ifa_rtrequest) ! 680: ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); ! 681: ! 682: /* ! 683: * We repeat the same procedure from rt_setgate() here because ! 684: * it doesn't fire when we call it there because the node ! 685: * hasn't been added to the tree yet. ! 686: */ ! 687: if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { ! 688: struct rtfc_arg arg; ! 689: arg.rnh = rnh; ! 690: arg.rt0 = rt; ! 691: rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), ! 692: rt_fixchange, &arg); ! 693: } ! 694: ! 695: /* ! 696: * actually return a resultant rtentry and ! 697: * give the caller a single reference. ! 698: */ ! 699: if (ret_nrt) { ! 700: *ret_nrt = rt; ! 701: rt->rt_refcnt++; ! 702: } ! 703: break; ! 704: } ! 705: bad: ! 706: splx(s); ! 707: return (error); ! 708: } ! 709: ! 710: /* ! 711: * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' ! 712: * (i.e., the routes related to it by the operation of cloning). This ! 713: * routine is iterated over all potential former-child-routes by way of ! 714: * rnh->rnh_walktree_from() above, and those that actually are children of ! 715: * the late parent (passed in as VP here) are themselves deleted. ! 716: */ ! 717: static int ! 718: rt_fixdelete(rn, vp) ! 719: struct radix_node *rn; ! 720: void *vp; ! 721: { ! 722: struct rtentry *rt = (struct rtentry *)rn; ! 723: struct rtentry *rt0 = vp; ! 724: ! 725: if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) { ! 726: return rtrequest(RTM_DELETE, rt_key(rt), ! 727: (struct sockaddr *)0, rt_mask(rt), ! 728: rt->rt_flags, (struct rtentry **)0); ! 729: } ! 730: return 0; ! 731: } ! 732: ! 733: /* ! 734: * This routine is called from rt_setgate() to do the analogous thing for ! 735: * adds and changes. There is the added complication in this case of a ! 736: * middle insert; i.e., insertion of a new network route between an older ! 737: * network route and (cloned) host routes. For this reason, a simple check ! 738: * of rt->rt_parent is insufficient; each candidate route must be tested ! 739: * against the (mask, value) of the new route (passed as before in vp) ! 740: * to see if the new route matches it. Unfortunately, this has the obnoxious ! 741: * property of also triggering for insertion /above/ a pre-existing network ! 742: * route and clones. Sigh. This may be fixed some day. ! 743: * ! 744: * XXX - it may be possible to do fixdelete() for changes and reserve this ! 745: * routine just for adds. I'm not sure why I thought it was necessary to do ! 746: * changes this way. ! 747: */ ! 748: #ifdef DEBUG ! 749: static int rtfcdebug = 0; ! 750: #endif ! 751: ! 752: static int ! 753: rt_fixchange(rn, vp) ! 754: struct radix_node *rn; ! 755: void *vp; ! 756: { ! 757: struct rtentry *rt = (struct rtentry *)rn; ! 758: struct rtfc_arg *ap = vp; ! 759: struct rtentry *rt0 = ap->rt0; ! 760: struct radix_node_head *rnh = ap->rnh; ! 761: u_char *xk1, *xm1, *xk2; ! 762: int i, len; ! 763: ! 764: #ifdef DEBUG ! 765: if (rtfcdebug) ! 766: printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0); ! 767: #endif ! 768: ! 769: if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) { ! 770: #ifdef DEBUG ! 771: if(rtfcdebug) printf("no parent or pinned\n"); ! 772: #endif ! 773: return 0; ! 774: } ! 775: ! 776: if (rt->rt_parent == rt0) { ! 777: #ifdef DEBUG ! 778: if(rtfcdebug) printf("parent match\n"); ! 779: #endif ! 780: return rtrequest(RTM_DELETE, rt_key(rt), ! 781: (struct sockaddr *)0, rt_mask(rt), ! 782: rt->rt_flags, (struct rtentry **)0); ! 783: } ! 784: ! 785: /* ! 786: * There probably is a function somewhere which does this... ! 787: * if not, there should be. ! 788: */ ! 789: len = imin(((struct sockaddr *)rt_key(rt0))->sa_len, ! 790: ((struct sockaddr *)rt_key(rt))->sa_len); ! 791: ! 792: xk1 = (u_char *)rt_key(rt0); ! 793: xm1 = (u_char *)rt_mask(rt0); ! 794: xk2 = (u_char *)rt_key(rt); ! 795: ! 796: for (i = rnh->rnh_treetop->rn_off; i < len; i++) { ! 797: if ((xk2[i] & xm1[i]) != xk1[i]) { ! 798: #ifdef DEBUG ! 799: if(rtfcdebug) printf("no match\n"); ! 800: #endif ! 801: return 0; ! 802: } ! 803: } ! 804: ! 805: /* ! 806: * OK, this node is a clone, and matches the node currently being ! 807: * changed/added under the node's mask. So, get rid of it. ! 808: */ ! 809: #ifdef DEBUG ! 810: if(rtfcdebug) printf("deleting\n"); ! 811: #endif ! 812: return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, ! 813: rt_mask(rt), rt->rt_flags, (struct rtentry **)0); ! 814: } ! 815: ! 816: int ! 817: rt_setgate(rt0, dst, gate) ! 818: struct rtentry *rt0; ! 819: struct sockaddr *dst, *gate; ! 820: { ! 821: caddr_t new, old; ! 822: int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); ! 823: register struct rtentry *rt = rt0; ! 824: struct radix_node_head *rnh = rt_tables[dst->sa_family]; ! 825: ! 826: /* ! 827: * A host route with the destination equal to the gateway ! 828: * will interfere with keeping LLINFO in the routing ! 829: * table, so disallow it. ! 830: */ ! 831: if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) == ! 832: (RTF_HOST|RTF_GATEWAY)) && ! 833: (dst->sa_len == gate->sa_len) && ! 834: (bcmp(dst, gate, dst->sa_len) == 0)) { ! 835: /* ! 836: * The route might already exist if this is an RTM_CHANGE ! 837: * or a routing redirect, so try to delete it. ! 838: */ ! 839: if (rt_key(rt0)) ! 840: rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0), ! 841: rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0); ! 842: return EADDRNOTAVAIL; ! 843: } ! 844: ! 845: /* ! 846: * Both dst and gateway are stored in the same malloc'd chunk ! 847: * (If I ever get my hands on....) ! 848: * if we need to malloc a new chunk, then keep the old one around ! 849: * till we don't need it any more. ! 850: */ ! 851: if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { ! 852: old = (caddr_t)rt_key(rt); ! 853: R_Malloc(new, caddr_t, dlen + glen); ! 854: if (new == 0) ! 855: return ENOBUFS; ! 856: rt->rt_nodes->rn_key = new; ! 857: } else { ! 858: /* ! 859: * otherwise just overwrite the old one ! 860: */ ! 861: new = rt->rt_nodes->rn_key; ! 862: old = 0; ! 863: } ! 864: ! 865: /* ! 866: * copy the new gateway value into the memory chunk ! 867: */ ! 868: Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); ! 869: ! 870: /* ! 871: * if we are replacing the chunk (or it's new) we need to ! 872: * replace the dst as well ! 873: */ ! 874: if (old) { ! 875: Bcopy(dst, new, dlen); ! 876: Free(old); ! 877: } ! 878: ! 879: /* ! 880: * If there is already a gwroute, it's now almost definitly wrong ! 881: * so drop it. ! 882: */ ! 883: if (rt->rt_gwroute) { ! 884: rt = rt->rt_gwroute; RTFREE(rt); ! 885: rt = rt0; rt->rt_gwroute = 0; ! 886: } ! 887: /* ! 888: * Cloning loop avoidance: ! 889: * In the presence of protocol-cloning and bad configuration, ! 890: * it is possible to get stuck in bottomless mutual recursion ! 891: * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing ! 892: * protocol-cloning to operate for gateways (which is probably the ! 893: * correct choice anyway), and avoid the resulting reference loops ! 894: * by disallowing any route to run through itself as a gateway. ! 895: * This is obviously mandatory when we get rt->rt_output(). ! 896: */ ! 897: if (rt->rt_flags & RTF_GATEWAY) { ! 898: rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING); ! 899: if (rt->rt_gwroute == rt) { ! 900: RTFREE(rt->rt_gwroute); ! 901: rt->rt_gwroute = 0; ! 902: return EDQUOT; /* failure */ ! 903: } ! 904: } ! 905: ! 906: /* ! 907: * This isn't going to do anything useful for host routes, so ! 908: * don't bother. Also make sure we have a reasonable mask ! 909: * (we don't yet have one during adds). ! 910: */ ! 911: if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { ! 912: struct rtfc_arg arg; ! 913: arg.rnh = rnh; ! 914: arg.rt0 = rt; ! 915: rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), ! 916: rt_fixchange, &arg); ! 917: } ! 918: ! 919: return 0; ! 920: } ! 921: ! 922: static void ! 923: rt_maskedcopy(src, dst, netmask) ! 924: struct sockaddr *src, *dst, *netmask; ! 925: { ! 926: register u_char *cp1 = (u_char *)src; ! 927: register u_char *cp2 = (u_char *)dst; ! 928: register u_char *cp3 = (u_char *)netmask; ! 929: u_char *cplim = cp2 + *cp3; ! 930: u_char *cplim2 = cp2 + *cp1; ! 931: ! 932: *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ ! 933: cp3 += 2; ! 934: if (cplim > cplim2) ! 935: cplim = cplim2; ! 936: while (cp2 < cplim) ! 937: *cp2++ = *cp1++ & *cp3++; ! 938: if (cp2 < cplim2) ! 939: bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); ! 940: } ! 941: ! 942: /* ! 943: * Set up a routing table entry, normally ! 944: * for an interface. ! 945: */ ! 946: int ! 947: rtinit(ifa, cmd, flags) ! 948: register struct ifaddr *ifa; ! 949: int cmd, flags; ! 950: { ! 951: register struct rtentry *rt; ! 952: register struct sockaddr *dst; ! 953: register struct sockaddr *deldst; ! 954: struct mbuf *m = 0; ! 955: struct rtentry *nrt = 0; ! 956: int error; ! 957: ! 958: dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; ! 959: /* ! 960: * If it's a delete, check that if it exists, it's on the correct ! 961: * interface or we might scrub a route to another ifa which would ! 962: * be confusing at best and possibly worse. ! 963: */ ! 964: if (cmd == RTM_DELETE) { ! 965: /* ! 966: * It's a delete, so it should already exist.. ! 967: * If it's a net, mask off the host bits ! 968: * (Assuming we have a mask) ! 969: */ ! 970: if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { ! 971: m = m_get(M_WAIT, MT_SONAME); ! 972: deldst = mtod(m, struct sockaddr *); ! 973: rt_maskedcopy(dst, deldst, ifa->ifa_netmask); ! 974: dst = deldst; ! 975: } ! 976: /* ! 977: * Get an rtentry that is in the routing tree and ! 978: * contains the correct info. (if this fails, can't get there). ! 979: * We set "report" to FALSE so that if it doesn't exist, ! 980: * it doesn't report an error or clone a route, etc. etc. ! 981: */ ! 982: rt = rtalloc1(dst, 0, 0UL); ! 983: if (rt) { ! 984: /* ! 985: * Ok so we found the rtentry. it has an extra reference ! 986: * for us at this stage. we won't need that so ! 987: * lop that off now. ! 988: */ ! 989: rt->rt_refcnt--; ! 990: if (rt->rt_ifa != ifa) { ! 991: /* ! 992: * If the interface in the rtentry doesn't match ! 993: * the interface we are using, then we don't ! 994: * want to delete it, so return an error. ! 995: * This seems to be the only point of ! 996: * this whole RTM_DELETE clause. ! 997: */ ! 998: if (m) ! 999: (void) m_free(m); ! 1000: return (flags & RTF_HOST ? EHOSTUNREACH ! 1001: : ENETUNREACH); ! 1002: } ! 1003: } ! 1004: /* XXX */ ! 1005: #if 0 ! 1006: else { ! 1007: /* ! 1008: * One would think that as we are deleting, and we know ! 1009: * it doesn't exist, we could just return at this point ! 1010: * with an "ELSE" clause, but apparently not.. ! 1011: */ ! 1012: return (flags & RTF_HOST ? EHOSTUNREACH ! 1013: : ENETUNREACH); ! 1014: } ! 1015: #endif ! 1016: } ! 1017: /* ! 1018: * Do the actual request ! 1019: */ ! 1020: error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, ! 1021: flags | ifa->ifa_flags, &nrt); ! 1022: if (m) ! 1023: (void) m_free(m); ! 1024: /* ! 1025: * If we are deleting, and we found an entry, then ! 1026: * it's been removed from the tree.. now throw it away. ! 1027: */ ! 1028: if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { ! 1029: /* ! 1030: * notify any listenning routing agents of the change ! 1031: */ ! 1032: rt_newaddrmsg(cmd, ifa, error, nrt); ! 1033: if (rt->rt_refcnt <= 0) { ! 1034: rt->rt_refcnt++; ! 1035: rtfree(rt); ! 1036: } ! 1037: } ! 1038: ! 1039: /* ! 1040: * We are adding, and we have a returned routing entry. ! 1041: * We need to sanity check the result. ! 1042: */ ! 1043: if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { ! 1044: /* ! 1045: * We just wanted to add it.. we don't actually need a reference ! 1046: */ ! 1047: rt->rt_refcnt--; ! 1048: /* ! 1049: * If it came back with an unexpected interface, then it must ! 1050: * have already existed or something. (XXX) ! 1051: */ ! 1052: if (rt->rt_ifa != ifa) { ! 1053: printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, ! 1054: rt->rt_ifa); ! 1055: /* ! 1056: * Ask that the protocol in question ! 1057: * remove anything it has associated with ! 1058: * this route and ifaddr. ! 1059: */ ! 1060: if (rt->rt_ifa->ifa_rtrequest) ! 1061: rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); ! 1062: /* ! 1063: * Remove the referenve to the it's ifaddr. ! 1064: */ ! 1065: IFAFREE(rt->rt_ifa); ! 1066: /* ! 1067: * And substitute in references to the ifaddr ! 1068: * we are adding. ! 1069: */ ! 1070: rt->rt_ifa = ifa; ! 1071: rt->rt_ifp = ifa->ifa_ifp; ! 1072: rt->rt_dlt = ifa->ifa_dlt; ! 1073: ifa->ifa_refcnt++; ! 1074: /* ! 1075: * Now ask the protocol to check if it needs ! 1076: * any special processing in its new form. ! 1077: */ ! 1078: if (ifa->ifa_rtrequest) ! 1079: ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); ! 1080: } ! 1081: /* ! 1082: * notify any listenning routing agents of the change ! 1083: */ ! 1084: rt_newaddrmsg(cmd, ifa, error, nrt); ! 1085: } ! 1086: return (error); ! 1087: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.