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