1 /* $NetBSD: route.c,v 1.32 2000/03/10 14:47:12 itojun Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 42 * All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. Neither the name of the project nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 /* 70 * Copyright (c) 1980, 1986, 1991, 1993 71 * The Regents of the University of California. All rights reserved. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 1. Redistributions of source code must retain the above copyright 77 * notice, this list of conditions and the following disclaimer. 78 * 2. Redistributions in binary form must reproduce the above copyright 79 * notice, this list of conditions and the following disclaimer in the 80 * documentation and/or other materials provided with the distribution. 81 * 3. All advertising materials mentioning features or use of this software 82 * must display the following acknowledgement: 83 * This product includes software developed by the University of 84 * California, Berkeley and its contributors. 85 * 4. Neither the name of the University nor the names of its contributors 86 * may be used to endorse or promote products derived from this software 87 * without specific prior written permission. 88 * 89 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 90 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 91 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 92 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 93 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 94 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 95 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 96 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 97 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 98 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 99 * SUCH DAMAGE. 100 * 101 * @(#)route.c 8.3 (Berkeley) 1/9/95 102 */ 103 104 #include "opt_ns.h" 105 106 #include <sys/param.h> 107 #include <sys/systm.h> 108 #include <sys/proc.h> 109 #include <sys/mbuf.h> 110 #include <sys/socket.h> 111 #include <sys/socketvar.h> 112 #include <sys/domain.h> 113 #include <sys/protosw.h> 114 #include <sys/kernel.h> 115 #include <sys/ioctl.h> 116 #include <sys/pool.h> 117 118 #include <net/if.h> 119 #include <net/route.h> 120 #include <net/raw_cb.h> 121 122 #include <netinet/in.h> 123 #include <netinet/in_var.h> 124 125 #ifdef NS 126 #include <netns/ns.h> 127 #endif 128 129 #define SA(p) ((struct sockaddr *)(p)) 130 131 int rttrash; /* routes not in table but not freed */ 132 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 133 134 struct pool rtentry_pool; /* pool for rtentry structures */ 135 struct pool rttimer_pool; /* pool for rttimer structures */ 136 137 void 138 rtable_init(table) 139 void **table; 140 { 141 struct domain *dom; 142 for (dom = domains; dom; dom = dom->dom_next) 143 if (dom->dom_rtattach) 144 dom->dom_rtattach(&table[dom->dom_family], 145 dom->dom_rtoffset); 146 } 147 148 void 149 route_init() 150 { 151 152 pool_init(&rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", 153 0, NULL, NULL, M_RTABLE); 154 155 rn_init(); /* initialize all zeroes, all ones, mask table */ 156 rtable_init((void **)rt_tables); 157 } 158 159 /* 160 * Packet routing routines. 161 */ 162 void 163 rtalloc(ro) 164 register struct route *ro; 165 { 166 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 167 return; /* XXX */ 168 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 169 } 170 171 struct rtentry * 172 rtalloc1(dst, report) 173 register struct sockaddr *dst; 174 int report; 175 { 176 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 177 register struct rtentry *rt; 178 register struct radix_node *rn; 179 struct rtentry *newrt = 0; 180 struct rt_addrinfo info; 181 int s = splsoftnet(), err = 0, msgtype = RTM_MISS; 182 183 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && 184 ((rn->rn_flags & RNF_ROOT) == 0)) { 185 newrt = rt = (struct rtentry *)rn; 186 if (report && (rt->rt_flags & RTF_CLONING)) { 187 err = rtrequest(RTM_RESOLVE, dst, SA(0), 188 SA(0), 0, &newrt); 189 if (err) { 190 newrt = rt; 191 rt->rt_refcnt++; 192 goto miss; 193 } 194 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 195 msgtype = RTM_RESOLVE; 196 goto miss; 197 } 198 } else 199 rt->rt_refcnt++; 200 } else { 201 rtstat.rts_unreach++; 202 miss: if (report) { 203 bzero((caddr_t)&info, sizeof(info)); 204 info.rti_info[RTAX_DST] = dst; 205 rt_missmsg(msgtype, &info, 0, err); 206 } 207 } 208 splx(s); 209 return (newrt); 210 } 211 212 void 213 rtfree(rt) 214 register struct rtentry *rt; 215 { 216 register struct ifaddr *ifa; 217 218 if (rt == 0) 219 panic("rtfree"); 220 rt->rt_refcnt--; 221 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 222 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 223 panic ("rtfree 2"); 224 rttrash--; 225 if (rt->rt_refcnt < 0) { 226 printf("rtfree: %p not freed (neg refs)\n", rt); 227 return; 228 } 229 rt_timer_remove_all(rt); 230 ifa = rt->rt_ifa; 231 IFAFREE(ifa); 232 Free(rt_key(rt)); 233 pool_put(&rtentry_pool, rt); 234 } 235 } 236 237 void 238 ifafree(ifa) 239 register struct ifaddr *ifa; 240 { 241 242 #ifdef DIAGNOSTIC 243 if (ifa == NULL) 244 panic("ifafree: null ifa"); 245 if (ifa->ifa_refcnt != 0) 246 panic("ifafree: ifa_refcnt != 0 (%d)", ifa->ifa_refcnt); 247 #endif 248 #ifdef IFAREF_DEBUG 249 printf("ifafree: freeing ifaddr %p\n", ifa); 250 #endif 251 free(ifa, M_IFADDR); 252 } 253 254 /* 255 * Force a routing table entry to the specified 256 * destination to go through the given gateway. 257 * Normally called as a result of a routing redirect 258 * message from the network layer. 259 * 260 * N.B.: must be called at splsoftnet 261 */ 262 void 263 rtredirect(dst, gateway, netmask, flags, src, rtp) 264 struct sockaddr *dst, *gateway, *netmask, *src; 265 int flags; 266 struct rtentry **rtp; 267 { 268 register struct rtentry *rt; 269 int error = 0; 270 short *stat = 0; 271 struct rt_addrinfo info; 272 struct ifaddr *ifa; 273 274 /* verify the gateway is directly reachable */ 275 if ((ifa = ifa_ifwithnet(gateway)) == 0) { 276 error = ENETUNREACH; 277 goto out; 278 } 279 rt = rtalloc1(dst, 0); 280 /* 281 * If the redirect isn't from our current router for this dst, 282 * it's either old or wrong. If it redirects us to ourselves, 283 * we have a routing loop, perhaps as a result of an interface 284 * going down recently. 285 */ 286 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 287 if (!(flags & RTF_DONE) && rt && 288 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 289 error = EINVAL; 290 else if (ifa_ifwithaddr(gateway)) 291 error = EHOSTUNREACH; 292 if (error) 293 goto done; 294 /* 295 * Create a new entry if we just got back a wildcard entry 296 * or the the lookup failed. This is necessary for hosts 297 * which use routing redirects generated by smart gateways 298 * to dynamically build the routing tables. 299 */ 300 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 301 goto create; 302 /* 303 * Don't listen to the redirect if it's 304 * for a route to an interface. 305 */ 306 if (rt->rt_flags & RTF_GATEWAY) { 307 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 308 /* 309 * Changing from route to net => route to host. 310 * Create new route, rather than smashing route to net. 311 */ 312 create: 313 flags |= RTF_GATEWAY | RTF_DYNAMIC; 314 error = rtrequest((int)RTM_ADD, dst, gateway, 315 netmask, flags, 316 (struct rtentry **)0); 317 stat = &rtstat.rts_dynamic; 318 } else { 319 /* 320 * Smash the current notion of the gateway to 321 * this destination. Should check about netmask!!! 322 */ 323 rt->rt_flags |= RTF_MODIFIED; 324 flags |= RTF_MODIFIED; 325 stat = &rtstat.rts_newgateway; 326 rt_setgate(rt, rt_key(rt), gateway); 327 } 328 } else 329 error = EHOSTUNREACH; 330 done: 331 if (rt) { 332 if (rtp && !error) 333 *rtp = rt; 334 else 335 rtfree(rt); 336 } 337 out: 338 if (error) 339 rtstat.rts_badredirect++; 340 else if (stat != NULL) 341 (*stat)++; 342 bzero((caddr_t)&info, sizeof(info)); 343 info.rti_info[RTAX_DST] = dst; 344 info.rti_info[RTAX_GATEWAY] = gateway; 345 info.rti_info[RTAX_NETMASK] = netmask; 346 info.rti_info[RTAX_AUTHOR] = src; 347 rt_missmsg(RTM_REDIRECT, &info, flags, error); 348 } 349 350 /* 351 * Routing table ioctl interface. 352 */ 353 int 354 rtioctl(req, data, p) 355 u_long req; 356 caddr_t data; 357 struct proc *p; 358 { 359 return (EOPNOTSUPP); 360 } 361 362 struct ifaddr * 363 ifa_ifwithroute(flags, dst, gateway) 364 int flags; 365 struct sockaddr *dst, *gateway; 366 { 367 register struct ifaddr *ifa; 368 if ((flags & RTF_GATEWAY) == 0) { 369 /* 370 * If we are adding a route to an interface, 371 * and the interface is a pt to pt link 372 * we should search for the destination 373 * as our clue to the interface. Otherwise 374 * we can use the local address. 375 */ 376 ifa = 0; 377 if (flags & RTF_HOST) 378 ifa = ifa_ifwithdstaddr(dst); 379 if (ifa == 0) 380 ifa = ifa_ifwithaddr(gateway); 381 } else { 382 /* 383 * If we are adding a route to a remote net 384 * or host, the gateway may still be on the 385 * other end of a pt to pt link. 386 */ 387 ifa = ifa_ifwithdstaddr(gateway); 388 } 389 if (ifa == 0) 390 ifa = ifa_ifwithnet(gateway); 391 if (ifa == 0) { 392 struct rtentry *rt = rtalloc1(dst, 0); 393 if (rt == 0) 394 return (0); 395 rt->rt_refcnt--; 396 if ((ifa = rt->rt_ifa) == 0) 397 return (0); 398 } 399 if (ifa->ifa_addr->sa_family != dst->sa_family) { 400 struct ifaddr *oifa = ifa; 401 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 402 if (ifa == 0) 403 ifa = oifa; 404 } 405 return (ifa); 406 } 407 408 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 409 410 int 411 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 412 int req, flags; 413 struct sockaddr *dst, *gateway, *netmask; 414 struct rtentry **ret_nrt; 415 { 416 int s = splsoftnet(); int error = 0; 417 register struct rtentry *rt; 418 register struct radix_node *rn; 419 register struct radix_node_head *rnh; 420 struct ifaddr *ifa; 421 struct sockaddr *ndst; 422 #define senderr(x) { error = x ; goto bad; } 423 424 if ((rnh = rt_tables[dst->sa_family]) == 0) 425 senderr(ESRCH); 426 if (flags & RTF_HOST) 427 netmask = 0; 428 switch (req) { 429 case RTM_DELETE: 430 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) 431 senderr(ESRCH); 432 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 433 panic ("rtrequest delete"); 434 rt = (struct rtentry *)rn; 435 if (rt->rt_gwroute) { 436 rt = rt->rt_gwroute; RTFREE(rt); 437 (rt = (struct rtentry *)rn)->rt_gwroute = 0; 438 } 439 rt->rt_flags &= ~RTF_UP; 440 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 441 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 442 rttrash++; 443 if (ret_nrt) 444 *ret_nrt = rt; 445 else if (rt->rt_refcnt <= 0) { 446 rt->rt_refcnt++; 447 rtfree(rt); 448 } 449 break; 450 451 case RTM_RESOLVE: 452 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 453 senderr(EINVAL); 454 ifa = rt->rt_ifa; 455 flags = rt->rt_flags & ~RTF_CLONING; 456 gateway = rt->rt_gateway; 457 if ((netmask = rt->rt_genmask) == 0) 458 flags |= RTF_HOST; 459 goto makeroute; 460 461 case RTM_ADD: 462 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 463 senderr(ENETUNREACH); 464 465 /* The interface found in the previous statement may 466 * be overridden later by rt_setif. See the code 467 * for case RTM_ADD in rtsock.c:route_output. 468 */ 469 makeroute: 470 rt = pool_get(&rtentry_pool, PR_NOWAIT); 471 if (rt == 0) 472 senderr(ENOBUFS); 473 Bzero(rt, sizeof(*rt)); 474 rt->rt_flags = RTF_UP | flags; 475 LIST_INIT(&rt->rt_timer); 476 if (rt_setgate(rt, dst, gateway)) { 477 pool_put(&rtentry_pool, rt); 478 senderr(ENOBUFS); 479 } 480 ndst = rt_key(rt); 481 if (netmask) { 482 rt_maskedcopy(dst, ndst, netmask); 483 } else 484 Bcopy(dst, ndst, dst->sa_len); 485 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, 486 rnh, rt->rt_nodes); 487 if (rn == 0) { 488 if (rt->rt_gwroute) 489 rtfree(rt->rt_gwroute); 490 Free(rt_key(rt)); 491 pool_put(&rtentry_pool, rt); 492 senderr(EEXIST); 493 } 494 IFAREF(ifa); 495 rt->rt_ifa = ifa; 496 rt->rt_ifp = ifa->ifa_ifp; 497 if (req == RTM_RESOLVE) { 498 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 499 } else if (rt->rt_rmx.rmx_mtu == 0 500 && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { /* XXX */ 501 if (rt->rt_gwroute != NULL) { 502 rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; 503 } else { 504 rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; 505 } 506 } 507 if (ifa->ifa_rtrequest) 508 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 509 if (ret_nrt) { 510 *ret_nrt = rt; 511 rt->rt_refcnt++; 512 } 513 break; 514 } 515 bad: 516 splx(s); 517 return (error); 518 } 519 520 int 521 rt_setgate(rt0, dst, gate) 522 struct rtentry *rt0; 523 struct sockaddr *dst, *gate; 524 { 525 caddr_t new, old; 526 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); 527 register struct rtentry *rt = rt0; 528 529 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { 530 old = (caddr_t)rt_key(rt); 531 R_Malloc(new, caddr_t, dlen + glen); 532 if (new == 0) 533 return 1; 534 Bzero(new, dlen + glen); 535 rt->rt_nodes->rn_key = new; 536 } else { 537 new = rt->rt_nodes->rn_key; 538 old = 0; 539 } 540 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); 541 if (old) { 542 Bcopy(dst, new, dlen); 543 Free(old); 544 } 545 if (rt->rt_gwroute) { 546 rt = rt->rt_gwroute; RTFREE(rt); 547 rt = rt0; rt->rt_gwroute = 0; 548 } 549 if (rt->rt_flags & RTF_GATEWAY) { 550 rt->rt_gwroute = rtalloc1(gate, 1); 551 /* 552 * If we switched gateways, grab the MTU from the new 553 * gateway route if the current MTU is 0 or greater 554 * than the MTU of gateway. 555 */ 556 if (rt->rt_gwroute 557 && !(rt->rt_rmx.rmx_locks & RTV_MTU) 558 && (rt->rt_rmx.rmx_mtu == 0 559 || rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu)) { /* XXX */ 560 rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; 561 } 562 } 563 return 0; 564 } 565 566 void 567 rt_maskedcopy(src, dst, netmask) 568 struct sockaddr *src, *dst, *netmask; 569 { 570 register u_char *cp1 = (u_char *)src; 571 register u_char *cp2 = (u_char *)dst; 572 register u_char *cp3 = (u_char *)netmask; 573 u_char *cplim = cp2 + *cp3; 574 u_char *cplim2 = cp2 + *cp1; 575 576 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 577 cp3 += 2; 578 if (cplim > cplim2) 579 cplim = cplim2; 580 while (cp2 < cplim) 581 *cp2++ = *cp1++ & *cp3++; 582 if (cp2 < cplim2) 583 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 584 } 585 586 /* 587 * Set up or tear down a routing table entry, normally 588 * for an interface. 589 */ 590 int 591 rtinit(ifa, cmd, flags) 592 register struct ifaddr *ifa; 593 int cmd, flags; 594 { 595 register struct rtentry *rt; 596 register struct sockaddr *dst, *odst; 597 struct sockaddr_storage deldst; 598 struct rtentry *nrt = 0; 599 int error; 600 601 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 602 if (cmd == RTM_DELETE) { 603 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 604 /* Delete subnet route for this interface */ 605 odst = dst; 606 dst = (struct sockaddr *)&deldst; 607 rt_maskedcopy(odst, dst, ifa->ifa_netmask); 608 } 609 if ((rt = rtalloc1(dst, 0)) != NULL) { 610 rt->rt_refcnt--; 611 if (rt->rt_ifa != ifa) 612 return (flags & RTF_HOST ? EHOSTUNREACH 613 : ENETUNREACH); 614 } 615 } 616 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, 617 flags | ifa->ifa_flags, &nrt); 618 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { 619 rt_newaddrmsg(cmd, ifa, error, nrt); 620 if (rt->rt_refcnt <= 0) { 621 rt->rt_refcnt++; 622 rtfree(rt); 623 } 624 } 625 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { 626 rt->rt_refcnt--; 627 if (rt->rt_ifa != ifa) { 628 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, 629 rt->rt_ifa); 630 if (rt->rt_ifa->ifa_rtrequest) 631 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 632 IFAFREE(rt->rt_ifa); 633 rt->rt_ifa = ifa; 634 rt->rt_ifp = ifa->ifa_ifp; 635 rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; /*XXX*/ 636 IFAREF(ifa); 637 if (ifa->ifa_rtrequest) 638 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); 639 } 640 rt_newaddrmsg(cmd, ifa, error, nrt); 641 } 642 return (error); 643 } 644 645 /* 646 * Route timer routines. These routes allow functions to be called 647 * for various routes at any time. This is useful in supporting 648 * path MTU discovery and redirect route deletion. 649 * 650 * This is similar to some BSDI internal functions, but it provides 651 * for multiple queues for efficiency's sake... 652 */ 653 654 LIST_HEAD(, rttimer_queue) rttimer_queue_head; 655 static int rt_init_done = 0; 656 657 #define RTTIMER_CALLOUT(r) { \ 658 if (r->rtt_func != NULL) { \ 659 (*r->rtt_func)(r->rtt_rt, r); \ 660 } else { \ 661 rtrequest((int) RTM_DELETE, \ 662 (struct sockaddr *)rt_key(r->rtt_rt), \ 663 0, 0, 0, 0); \ 664 } \ 665 } 666 667 /* 668 * Some subtle order problems with domain initialization mean that 669 * we cannot count on this being run from rt_init before various 670 * protocol initializations are done. Therefore, we make sure 671 * that this is run when the first queue is added... 672 */ 673 674 void 675 rt_timer_init() 676 { 677 assert(rt_init_done == 0); 678 679 pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", 680 0, NULL, NULL, M_RTABLE); 681 682 LIST_INIT(&rttimer_queue_head); 683 timeout(rt_timer_timer, NULL, hz); /* every second */ 684 rt_init_done = 1; 685 } 686 687 struct rttimer_queue * 688 rt_timer_queue_create(timeout) 689 u_int timeout; 690 { 691 struct rttimer_queue *rtq; 692 693 if (rt_init_done == 0) 694 rt_timer_init(); 695 696 R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); 697 if (rtq == NULL) 698 return (NULL); 699 Bzero(rtq, sizeof *rtq); 700 701 rtq->rtq_timeout = timeout; 702 TAILQ_INIT(&rtq->rtq_head); 703 LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); 704 705 return (rtq); 706 } 707 708 void 709 rt_timer_queue_change(rtq, timeout) 710 struct rttimer_queue *rtq; 711 long timeout; 712 { 713 714 rtq->rtq_timeout = timeout; 715 } 716 717 718 void 719 rt_timer_queue_destroy(rtq, destroy) 720 struct rttimer_queue *rtq; 721 int destroy; 722 { 723 struct rttimer *r; 724 725 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) { 726 LIST_REMOVE(r, rtt_link); 727 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 728 if (destroy) 729 RTTIMER_CALLOUT(r); 730 pool_put(&rttimer_pool, r); 731 } 732 733 LIST_REMOVE(rtq, rtq_link); 734 735 /* 736 * Caller is responsible for freeing the rttimer_queue structure. 737 */ 738 } 739 740 void 741 rt_timer_remove_all(rt) 742 struct rtentry *rt; 743 { 744 struct rttimer *r; 745 746 while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) { 747 LIST_REMOVE(r, rtt_link); 748 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 749 pool_put(&rttimer_pool, r); 750 } 751 } 752 753 int 754 rt_timer_add(rt, func, queue) 755 struct rtentry *rt; 756 void(*func) __P((struct rtentry *, struct rttimer *)); 757 struct rttimer_queue *queue; 758 { 759 struct rttimer *r; 760 long current_time; 761 int s; 762 763 s = splclock(); 764 current_time = mono_time.tv_sec; 765 splx(s); 766 767 /* 768 * If there's already a timer with this action, destroy it before 769 * we add a new one. 770 */ 771 for (r = LIST_FIRST(&rt->rt_timer); r != NULL; 772 r = LIST_NEXT(r, rtt_link)) { 773 if (r->rtt_func == func) { 774 LIST_REMOVE(r, rtt_link); 775 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 776 pool_put(&rttimer_pool, r); 777 break; /* only one per list, so we can quit... */ 778 } 779 } 780 781 r = pool_get(&rttimer_pool, PR_NOWAIT); 782 if (r == NULL) 783 return (ENOBUFS); 784 Bzero(r, sizeof(*r)); 785 786 r->rtt_rt = rt; 787 r->rtt_time = current_time; 788 r->rtt_func = func; 789 r->rtt_queue = queue; 790 LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); 791 TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); 792 793 return (0); 794 } 795 796 /* ARGSUSED */ 797 void 798 rt_timer_timer(arg) 799 void *arg; 800 { 801 struct rttimer_queue *rtq; 802 struct rttimer *r; 803 long current_time; 804 int s; 805 806 s = splclock(); 807 current_time = mono_time.tv_sec; 808 splx(s); 809 810 s = splsoftnet(); 811 for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL; 812 rtq = LIST_NEXT(rtq, rtq_link)) { 813 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && 814 (r->rtt_time + rtq->rtq_timeout) < current_time) { 815 LIST_REMOVE(r, rtt_link); 816 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 817 RTTIMER_CALLOUT(r); 818 pool_put(&rttimer_pool, r); 819 } 820 } 821 splx(s); 822 823 timeout(rt_timer_timer, NULL, hz); /* every second */ 824 } 825