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