1 /* 2 * Copyright (c) 1980, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)route.c 8.2 (Berkeley) 11/15/93 34 * $Id: route.c,v 1.29 1995/12/14 09:53:27 phk Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/proc.h> 41 #include <sys/mbuf.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/domain.h> 45 #include <sys/protosw.h> 46 #include <sys/ioctl.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 #include <net/raw_cb.h> 51 52 #include <netinet/in.h> 53 #include <netinet/in_var.h> 54 #include <netinet/ip_mroute.h> 55 56 #define SA(p) ((struct sockaddr *)(p)) 57 58 struct route_cb route_cb; 59 static struct rtstat rtstat; 60 struct radix_node_head *rt_tables[AF_MAX+1]; 61 62 static int rttrash; /* routes not in table but not freed */ 63 64 static void rt_maskedcopy __P((struct sockaddr *, 65 struct sockaddr *, struct sockaddr *)); 66 static void rtable_init __P((void **)); 67 68 static void 69 rtable_init(table) 70 void **table; 71 { 72 struct domain *dom; 73 for (dom = domains; dom; dom = dom->dom_next) 74 if (dom->dom_rtattach) 75 dom->dom_rtattach(&table[dom->dom_family], 76 dom->dom_rtoffset); 77 } 78 79 void 80 route_init() 81 { 82 rn_init(); /* initialize all zeroes, all ones, mask table */ 83 rtable_init((void **)rt_tables); 84 } 85 86 /* 87 * Packet routing routines. 88 */ 89 void 90 rtalloc(ro) 91 register struct route *ro; 92 { 93 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 94 return; /* XXX */ 95 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL); 96 } 97 98 void 99 rtalloc_ign(ro, ignore) 100 register struct route *ro; 101 u_long ignore; 102 { 103 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 104 return; /* XXX */ 105 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore); 106 } 107 108 struct rtentry * 109 rtalloc1(dst, report, ignflags) 110 register struct sockaddr *dst; 111 int report; 112 u_long ignflags; 113 { 114 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 115 register struct rtentry *rt; 116 register struct radix_node *rn; 117 struct rtentry *newrt = 0; 118 struct rt_addrinfo info; 119 u_long nflags; 120 int s = splnet(), err = 0, msgtype = RTM_MISS; 121 122 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && 123 ((rn->rn_flags & RNF_ROOT) == 0)) { 124 newrt = rt = (struct rtentry *)rn; 125 nflags = rt->rt_flags & ~ignflags; 126 if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) { 127 err = rtrequest(RTM_RESOLVE, dst, SA(0), 128 SA(0), 0, &newrt); 129 if (err) { 130 newrt = rt; 131 rt->rt_refcnt++; 132 goto miss; 133 } 134 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 135 msgtype = RTM_RESOLVE; 136 goto miss; 137 } 138 } else 139 rt->rt_refcnt++; 140 } else { 141 rtstat.rts_unreach++; 142 miss: if (report) { 143 bzero((caddr_t)&info, sizeof(info)); 144 info.rti_info[RTAX_DST] = dst; 145 rt_missmsg(msgtype, &info, 0, err); 146 } 147 } 148 splx(s); 149 return (newrt); 150 } 151 152 void 153 rtfree(rt) 154 register struct rtentry *rt; 155 { 156 register struct radix_node_head *rnh = 157 rt_tables[rt_key(rt)->sa_family]; 158 register struct ifaddr *ifa; 159 160 if (rt == 0 || rnh == 0) 161 panic("rtfree"); 162 rt->rt_refcnt--; 163 if(rnh->rnh_close && rt->rt_refcnt == 0) { 164 rnh->rnh_close((struct radix_node *)rt, rnh); 165 } 166 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 167 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 168 panic ("rtfree 2"); 169 rttrash--; 170 if (rt->rt_refcnt < 0) { 171 printf("rtfree: %p not freed (neg refs)\n", rt); 172 return; 173 } 174 ifa = rt->rt_ifa; 175 IFAFREE(ifa); 176 if (rt->rt_parent) { 177 RTFREE(rt->rt_parent); 178 } 179 Free(rt_key(rt)); 180 Free(rt); 181 } 182 } 183 184 void 185 ifafree(ifa) 186 register struct ifaddr *ifa; 187 { 188 if (ifa == NULL) 189 panic("ifafree"); 190 if (ifa->ifa_refcnt == 0) 191 free(ifa, M_IFADDR); 192 else 193 ifa->ifa_refcnt--; 194 } 195 196 /* 197 * Force a routing table entry to the specified 198 * destination to go through the given gateway. 199 * Normally called as a result of a routing redirect 200 * message from the network layer. 201 * 202 * N.B.: must be called at splnet 203 * 204 */ 205 void 206 rtredirect(dst, gateway, netmask, flags, src, rtp) 207 struct sockaddr *dst, *gateway, *netmask, *src; 208 int flags; 209 struct rtentry **rtp; 210 { 211 register struct rtentry *rt; 212 int error = 0; 213 short *stat = 0; 214 struct rt_addrinfo info; 215 struct ifaddr *ifa; 216 217 /* verify the gateway is directly reachable */ 218 if ((ifa = ifa_ifwithnet(gateway)) == 0) { 219 error = ENETUNREACH; 220 goto out; 221 } 222 rt = rtalloc1(dst, 0, 0UL); 223 /* 224 * If the redirect isn't from our current router for this dst, 225 * it's either old or wrong. If it redirects us to ourselves, 226 * we have a routing loop, perhaps as a result of an interface 227 * going down recently. 228 */ 229 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 230 if (!(flags & RTF_DONE) && rt && 231 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 232 error = EINVAL; 233 else if (ifa_ifwithaddr(gateway)) 234 error = EHOSTUNREACH; 235 if (error) 236 goto done; 237 /* 238 * Create a new entry if we just got back a wildcard entry 239 * or the the lookup failed. This is necessary for hosts 240 * which use routing redirects generated by smart gateways 241 * to dynamically build the routing tables. 242 */ 243 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 244 goto create; 245 /* 246 * Don't listen to the redirect if it's 247 * for a route to an interface. 248 */ 249 if (rt->rt_flags & RTF_GATEWAY) { 250 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 251 /* 252 * Changing from route to net => route to host. 253 * Create new route, rather than smashing route to net. 254 */ 255 create: 256 flags |= RTF_GATEWAY | RTF_DYNAMIC; 257 error = rtrequest((int)RTM_ADD, dst, gateway, 258 netmask, flags, 259 (struct rtentry **)0); 260 stat = &rtstat.rts_dynamic; 261 } else { 262 /* 263 * Smash the current notion of the gateway to 264 * this destination. Should check about netmask!!! 265 */ 266 rt->rt_flags |= RTF_MODIFIED; 267 flags |= RTF_MODIFIED; 268 stat = &rtstat.rts_newgateway; 269 rt_setgate(rt, rt_key(rt), gateway); 270 } 271 } else 272 error = EHOSTUNREACH; 273 done: 274 if (rt) { 275 if (rtp && !error) 276 *rtp = rt; 277 else 278 rtfree(rt); 279 } 280 out: 281 if (error) 282 rtstat.rts_badredirect++; 283 else if (stat != NULL) 284 (*stat)++; 285 bzero((caddr_t)&info, sizeof(info)); 286 info.rti_info[RTAX_DST] = dst; 287 info.rti_info[RTAX_GATEWAY] = gateway; 288 info.rti_info[RTAX_NETMASK] = netmask; 289 info.rti_info[RTAX_AUTHOR] = src; 290 rt_missmsg(RTM_REDIRECT, &info, flags, error); 291 } 292 293 /* 294 * Routing table ioctl interface. 295 */ 296 int 297 rtioctl(req, data, p) 298 int req; 299 caddr_t data; 300 struct proc *p; 301 { 302 #ifdef INET 303 /* Multicast goop, grrr... */ 304 #ifdef MROUTING 305 return mrt_ioctl(req, data); 306 #else 307 return mrt_ioctl(req, data, p); 308 #endif 309 #else /* INET */ 310 return ENXIO; 311 #endif /* INET */ 312 } 313 314 struct ifaddr * 315 ifa_ifwithroute(flags, dst, gateway) 316 int flags; 317 struct sockaddr *dst, *gateway; 318 { 319 register struct ifaddr *ifa; 320 if ((flags & RTF_GATEWAY) == 0) { 321 /* 322 * If we are adding a route to an interface, 323 * and the interface is a pt to pt link 324 * we should search for the destination 325 * as our clue to the interface. Otherwise 326 * we can use the local address. 327 */ 328 ifa = 0; 329 if (flags & RTF_HOST) { 330 ifa = ifa_ifwithdstaddr(dst); 331 } 332 if (ifa == 0) 333 ifa = ifa_ifwithaddr(gateway); 334 } else { 335 /* 336 * If we are adding a route to a remote net 337 * or host, the gateway may still be on the 338 * other end of a pt to pt link. 339 */ 340 ifa = ifa_ifwithdstaddr(gateway); 341 } 342 if (ifa == 0) 343 ifa = ifa_ifwithnet(gateway); 344 if (ifa == 0) { 345 struct rtentry *rt = rtalloc1(dst, 0, 0UL); 346 if (rt == 0) 347 return (0); 348 rt->rt_refcnt--; 349 if ((ifa = rt->rt_ifa) == 0) 350 return (0); 351 } 352 if (ifa->ifa_addr->sa_family != dst->sa_family) { 353 struct ifaddr *oifa = ifa; 354 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 355 if (ifa == 0) 356 ifa = oifa; 357 } 358 return (ifa); 359 } 360 361 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 362 363 static int rt_fixdelete(struct radix_node *, void *); 364 static int rt_fixchange(struct radix_node *, void *); 365 366 struct rtfc_arg { 367 struct rtentry *rt0; 368 struct radix_node_head *rnh; 369 }; 370 371 int 372 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 373 int req, flags; 374 struct sockaddr *dst, *gateway, *netmask; 375 struct rtentry **ret_nrt; 376 { 377 int s = splnet(); int error = 0; 378 register struct rtentry *rt; 379 register struct radix_node *rn; 380 register struct radix_node_head *rnh; 381 struct ifaddr *ifa; 382 struct sockaddr *ndst; 383 #define senderr(x) { error = x ; goto bad; } 384 385 if ((rnh = rt_tables[dst->sa_family]) == 0) 386 senderr(ESRCH); 387 if (flags & RTF_HOST) 388 netmask = 0; 389 switch (req) { 390 case RTM_DELETE: 391 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) 392 senderr(ESRCH); 393 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 394 panic ("rtrequest delete"); 395 rt = (struct rtentry *)rn; 396 397 /* 398 * Now search what's left of the subtree for any cloned 399 * routes which might have been formed from this node. 400 */ 401 if ((rt->rt_flags & RTF_PRCLONING) && netmask) { 402 rnh->rnh_walktree_from(rnh, dst, netmask, 403 rt_fixdelete, rt); 404 } 405 406 /* 407 * NB: RTF_UP must be set during the search above, 408 * because we might delete the last ref, causing 409 * rt to get freed prematurely. 410 */ 411 rt->rt_flags &= ~RTF_UP; 412 413 if (rt->rt_gwroute) { 414 rt = rt->rt_gwroute; RTFREE(rt); 415 (rt = (struct rtentry *)rn)->rt_gwroute = 0; 416 } 417 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 418 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 419 rttrash++; 420 if (ret_nrt) 421 *ret_nrt = rt; 422 else if (rt->rt_refcnt <= 0) { 423 rt->rt_refcnt++; 424 rtfree(rt); 425 } 426 break; 427 428 case RTM_RESOLVE: 429 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 430 senderr(EINVAL); 431 ifa = rt->rt_ifa; 432 flags = rt->rt_flags & 433 ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC); 434 flags |= RTF_WASCLONED; 435 gateway = rt->rt_gateway; 436 if ((netmask = rt->rt_genmask) == 0) 437 flags |= RTF_HOST; 438 goto makeroute; 439 440 case RTM_ADD: 441 if ((flags & RTF_GATEWAY) && !gateway) 442 panic("rtrequest: GATEWAY but no gateway"); 443 444 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 445 senderr(ENETUNREACH); 446 447 makeroute: 448 R_Malloc(rt, struct rtentry *, sizeof(*rt)); 449 if (rt == 0) 450 senderr(ENOBUFS); 451 Bzero(rt, sizeof(*rt)); 452 rt->rt_flags = RTF_UP | flags; 453 if (rt_setgate(rt, dst, gateway)) { 454 Free(rt); 455 senderr(ENOBUFS); 456 } 457 ndst = rt_key(rt); 458 if (netmask) { 459 rt_maskedcopy(dst, ndst, netmask); 460 } else 461 Bcopy(dst, ndst, dst->sa_len); 462 463 /* 464 * This moved from below so that rnh->rnh_addaddr() can 465 * examine the ifa and ifp if it so desires. 466 */ 467 ifa->ifa_refcnt++; 468 rt->rt_ifa = ifa; 469 rt->rt_ifp = ifa->ifa_ifp; 470 471 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, 472 rnh, rt->rt_nodes); 473 if (rn == 0) { 474 struct rtentry *rt2; 475 /* 476 * Uh-oh, we already have one of these in the tree. 477 * We do a special hack: if the route that's already 478 * there was generated by the protocol-cloning 479 * mechanism, then we just blow it away and retry 480 * the insertion of the new one. 481 */ 482 rt2 = rtalloc1(dst, 0, RTF_PRCLONING); 483 if (rt2 && rt2->rt_parent) { 484 rtrequest(RTM_DELETE, 485 (struct sockaddr *)rt_key(rt2), 486 rt2->rt_gateway, 487 rt_mask(rt2), rt2->rt_flags, 0); 488 RTFREE(rt2); 489 rn = rnh->rnh_addaddr((caddr_t)ndst, 490 (caddr_t)netmask, 491 rnh, rt->rt_nodes); 492 } else if (rt2) { 493 RTFREE(rt2); 494 } 495 } 496 497 if (rn == 0) { 498 if (rt->rt_gwroute) 499 rtfree(rt->rt_gwroute); 500 if (rt->rt_ifa) { 501 IFAFREE(rt->rt_ifa); 502 } 503 Free(rt_key(rt)); 504 Free(rt); 505 senderr(EEXIST); 506 } 507 rt->rt_parent = 0; 508 509 if (req == RTM_RESOLVE) { 510 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 511 if ((*ret_nrt)->rt_flags & RTF_PRCLONING) { 512 rt->rt_parent = (*ret_nrt); 513 (*ret_nrt)->rt_refcnt++; 514 } 515 } 516 if (ifa->ifa_rtrequest) 517 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 518 /* 519 * We repeat the same procedure from rt_setgate() here because 520 * it doesn't fire when we call it there because the node 521 * hasn't been added to the tree yet. 522 */ 523 if (!(rt->rt_flags & RTF_HOST)) { 524 struct rtfc_arg arg; 525 arg.rnh = rnh; 526 arg.rt0 = rt; 527 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), 528 rt_fixchange, &arg); 529 } 530 531 if (ret_nrt) { 532 *ret_nrt = rt; 533 rt->rt_refcnt++; 534 } 535 break; 536 } 537 bad: 538 splx(s); 539 return (error); 540 } 541 542 /* 543 * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' 544 * (i.e., the routes related to it by the operation of cloning). This 545 * routine is iterated over all potential former-child-routes by way of 546 * rnh->rnh_walktree_from() above, and those that actually are children of 547 * the late parent (passed in as VP here) are themselves deleted. 548 */ 549 static int 550 rt_fixdelete(struct radix_node *rn, void *vp) 551 { 552 struct rtentry *rt = (struct rtentry *)rn; 553 struct rtentry *rt0 = vp; 554 555 if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) { 556 return rtrequest(RTM_DELETE, rt_key(rt), 557 (struct sockaddr *)0, rt_mask(rt), 558 rt->rt_flags, (struct rtentry **)0); 559 } 560 return 0; 561 } 562 563 /* 564 * This routine is called from rt_setgate() to do the analogous thing for 565 * adds and changes. There is the added complication in this case of a 566 * middle insert; i.e., insertion of a new network route between an older 567 * network route and (cloned) host routes. For this reason, a simple check 568 * of rt->rt_parent is insufficient; each candidate route must be tested 569 * against the (mask, value) of the new route (passed as before in vp) 570 * to see if the new route matches it. Unfortunately, this has the obnoxious 571 * property of also triggering for insertion /above/ a pre-existing network 572 * route and clones. Sigh. This may be fixed some day. 573 * 574 * XXX - it may be possible to do fixdelete() for changes and reserve this 575 * routine just for adds. I'm not sure why I thought it was necessary to do 576 * changes this way. 577 */ 578 #ifdef DEBUG 579 int rtfcdebug = 0; 580 #endif 581 582 static int 583 rt_fixchange(struct radix_node *rn, void *vp) 584 { 585 struct rtentry *rt = (struct rtentry *)rn; 586 struct rtfc_arg *ap = vp; 587 struct rtentry *rt0 = ap->rt0; 588 struct radix_node_head *rnh = ap->rnh; 589 u_char *xk1, *xm1, *xk2; 590 int i, len; 591 592 #ifdef DEBUG 593 if (rtfcdebug) 594 printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0); 595 #endif 596 597 if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) { 598 #ifdef DEBUG 599 if(rtfcdebug) printf("no parent or pinned\n"); 600 #endif 601 return 0; 602 } 603 604 if (rt->rt_parent == rt0) { 605 #ifdef DEBUG 606 if(rtfcdebug) printf("parent match\n"); 607 #endif 608 return rtrequest(RTM_DELETE, rt_key(rt), 609 (struct sockaddr *)0, rt_mask(rt), 610 rt->rt_flags, (struct rtentry **)0); 611 } 612 613 /* 614 * There probably is a function somewhere which does this... 615 * if not, there should be. 616 */ 617 len = imin(((struct sockaddr *)rt_key(rt0))->sa_len, 618 ((struct sockaddr *)rt_key(rt))->sa_len); 619 620 xk1 = (u_char *)rt_key(rt0); 621 xm1 = (u_char *)rt_mask(rt0); 622 xk2 = (u_char *)rt_key(rt); 623 624 for (i = rnh->rnh_treetop->rn_off; i < len; i++) { 625 if ((xk2[i] & xm1[i]) != xk1[i]) { 626 #ifdef DEBUG 627 if(rtfcdebug) printf("no match\n"); 628 #endif 629 return 0; 630 } 631 } 632 633 /* 634 * OK, this node is a clone, and matches the node currently being 635 * changed/added under the node's mask. So, get rid of it. 636 */ 637 #ifdef DEBUG 638 if(rtfcdebug) printf("deleting\n"); 639 #endif 640 return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, 641 rt_mask(rt), rt->rt_flags, (struct rtentry **)0); 642 } 643 644 int 645 rt_setgate(rt0, dst, gate) 646 struct rtentry *rt0; 647 struct sockaddr *dst, *gate; 648 { 649 caddr_t new, old; 650 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); 651 register struct rtentry *rt = rt0; 652 struct radix_node_head *rnh = rt_tables[dst->sa_family]; 653 654 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { 655 old = (caddr_t)rt_key(rt); 656 R_Malloc(new, caddr_t, dlen + glen); 657 if (new == 0) 658 return 1; 659 rt->rt_nodes->rn_key = new; 660 } else { 661 new = rt->rt_nodes->rn_key; 662 old = 0; 663 } 664 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); 665 if (old) { 666 Bcopy(dst, new, dlen); 667 Free(old); 668 } 669 if (rt->rt_gwroute) { 670 rt = rt->rt_gwroute; RTFREE(rt); 671 rt = rt0; rt->rt_gwroute = 0; 672 } 673 /* 674 * Cloning loop avoidance: 675 * In the presence of protocol-cloning and bad configuration, 676 * it is possible to get stuck in bottomless mutual recursion 677 * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing 678 * protocol-cloning to operate for gateways (which is probably the 679 * correct choice anyway), and avoid the resulting reference loops 680 * by disallowing any route to run through itself as a gateway. 681 * This is obviuosly mandatory when we get rt->rt_output(). 682 */ 683 if (rt->rt_flags & RTF_GATEWAY) { 684 rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING); 685 if (rt->rt_gwroute == rt) { 686 RTFREE(rt->rt_gwroute); 687 rt->rt_gwroute = 0; 688 return 1; /* failure */ 689 } 690 } 691 692 /* 693 * This isn't going to do anything useful for host routes, so 694 * don't bother. Also make sure we have a reasonable mask 695 * (we don't yet have one during adds). 696 */ 697 if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { 698 struct rtfc_arg arg; 699 arg.rnh = rnh; 700 arg.rt0 = rt; 701 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), 702 rt_fixchange, &arg); 703 } 704 705 return 0; 706 } 707 708 static void 709 rt_maskedcopy(src, dst, netmask) 710 struct sockaddr *src, *dst, *netmask; 711 { 712 register u_char *cp1 = (u_char *)src; 713 register u_char *cp2 = (u_char *)dst; 714 register u_char *cp3 = (u_char *)netmask; 715 u_char *cplim = cp2 + *cp3; 716 u_char *cplim2 = cp2 + *cp1; 717 718 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 719 cp3 += 2; 720 if (cplim > cplim2) 721 cplim = cplim2; 722 while (cp2 < cplim) 723 *cp2++ = *cp1++ & *cp3++; 724 if (cp2 < cplim2) 725 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 726 } 727 728 /* 729 * Set up a routing table entry, normally 730 * for an interface. 731 */ 732 int 733 rtinit(ifa, cmd, flags) 734 register struct ifaddr *ifa; 735 int cmd, flags; 736 { 737 register struct rtentry *rt; 738 register struct sockaddr *dst; 739 register struct sockaddr *deldst; 740 struct mbuf *m = 0; 741 struct rtentry *nrt = 0; 742 int error; 743 744 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 745 if (cmd == RTM_DELETE) { 746 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 747 m = m_get(M_WAIT, MT_SONAME); 748 deldst = mtod(m, struct sockaddr *); 749 rt_maskedcopy(dst, deldst, ifa->ifa_netmask); 750 dst = deldst; 751 } 752 rt = rtalloc1(dst, 0, 0UL); 753 if (rt) { 754 rt->rt_refcnt--; 755 if (rt->rt_ifa != ifa) { 756 if (m) 757 (void) m_free(m); 758 return (flags & RTF_HOST ? EHOSTUNREACH 759 : ENETUNREACH); 760 } 761 } 762 } 763 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, 764 flags | ifa->ifa_flags, &nrt); 765 if (m) 766 (void) m_free(m); 767 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { 768 rt_newaddrmsg(cmd, ifa, error, nrt); 769 if (rt->rt_refcnt <= 0) { 770 rt->rt_refcnt++; 771 rtfree(rt); 772 } 773 } 774 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { 775 rt->rt_refcnt--; 776 if (rt->rt_ifa != ifa) { 777 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, 778 rt->rt_ifa); 779 if (rt->rt_ifa->ifa_rtrequest) 780 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 781 IFAFREE(rt->rt_ifa); 782 rt->rt_ifa = ifa; 783 rt->rt_ifp = ifa->ifa_ifp; 784 ifa->ifa_refcnt++; 785 if (ifa->ifa_rtrequest) 786 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); 787 } 788 rt_newaddrmsg(cmd, ifa, error, nrt); 789 } 790 return (error); 791 } 792