1 /* $NetBSD: route.c,v 1.112 2008/05/13 20:49:33 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2008 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the project nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 /* 63 * Copyright (c) 1980, 1986, 1991, 1993 64 * The Regents of the University of California. All rights reserved. 65 * 66 * Redistribution and use in source and binary forms, with or without 67 * modification, are permitted provided that the following conditions 68 * are met: 69 * 1. Redistributions of source code must retain the above copyright 70 * notice, this list of conditions and the following disclaimer. 71 * 2. Redistributions in binary form must reproduce the above copyright 72 * notice, this list of conditions and the following disclaimer in the 73 * documentation and/or other materials provided with the distribution. 74 * 3. Neither the name of the University nor the names of its contributors 75 * may be used to endorse or promote products derived from this software 76 * without specific prior written permission. 77 * 78 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 88 * SUCH DAMAGE. 89 * 90 * @(#)route.c 8.3 (Berkeley) 1/9/95 91 */ 92 93 #include "opt_route.h" 94 95 #include <sys/cdefs.h> 96 __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.112 2008/05/13 20:49:33 dyoung Exp $"); 97 98 #include <sys/param.h> 99 #include <sys/sysctl.h> 100 #include <sys/systm.h> 101 #include <sys/callout.h> 102 #include <sys/proc.h> 103 #include <sys/mbuf.h> 104 #include <sys/socket.h> 105 #include <sys/socketvar.h> 106 #include <sys/domain.h> 107 #include <sys/protosw.h> 108 #include <sys/kernel.h> 109 #include <sys/ioctl.h> 110 #include <sys/pool.h> 111 112 #include <net/if.h> 113 #include <net/route.h> 114 #include <net/raw_cb.h> 115 116 #include <netinet/in.h> 117 #include <netinet/in_var.h> 118 119 #ifdef RTFLUSH_DEBUG 120 #define rtcache_debug() __predict_false(_rtcache_debug) 121 #else /* RTFLUSH_DEBUG */ 122 #define rtcache_debug() 0 123 #endif /* RTFLUSH_DEBUG */ 124 125 struct route_cb route_cb; 126 struct rtstat rtstat; 127 struct radix_node_head *rt_tables[AF_MAX+1]; 128 129 int rttrash; /* routes not in table but not freed */ 130 131 POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL, 132 IPL_SOFTNET); 133 POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL, 134 IPL_SOFTNET); 135 136 struct callout rt_timer_ch; /* callout for rt_timer_timer() */ 137 138 #ifdef RTFLUSH_DEBUG 139 static int _rtcache_debug = 0; 140 #endif /* RTFLUSH_DEBUG */ 141 142 static int rtdeletemsg(struct rtentry *); 143 static int rtflushclone1(struct rtentry *, void *); 144 static void rtflushclone(sa_family_t family, struct rtentry *); 145 146 #ifdef RTFLUSH_DEBUG 147 SYSCTL_SETUP(sysctl_net_rtcache_setup, "sysctl net.rtcache.debug setup") 148 { 149 const struct sysctlnode *rnode; 150 151 /* XXX do not duplicate */ 152 if (sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, 153 CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL) != 0) 154 return; 155 if (sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, 156 CTLTYPE_NODE, 157 "rtcache", SYSCTL_DESCR("Route cache related settings"), 158 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0) 159 return; 160 if (sysctl_createv(clog, 0, &rnode, &rnode, 161 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 162 "debug", SYSCTL_DESCR("Debug route caches"), 163 NULL, 0, &_rtcache_debug, 0, CTL_CREATE, CTL_EOL) != 0) 164 return; 165 } 166 #endif /* RTFLUSH_DEBUG */ 167 168 struct ifaddr * 169 rt_get_ifa(struct rtentry *rt) 170 { 171 struct ifaddr *ifa; 172 173 if ((ifa = rt->rt_ifa) == NULL) 174 return ifa; 175 else if (ifa->ifa_getifa == NULL) 176 return ifa; 177 #if 0 178 else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno) 179 return ifa; 180 #endif 181 else { 182 ifa = (*ifa->ifa_getifa)(ifa, rt_getkey(rt)); 183 rt_replace_ifa(rt, ifa); 184 return ifa; 185 } 186 } 187 188 static void 189 rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa) 190 { 191 rt->rt_ifa = ifa; 192 if (ifa->ifa_seqno != NULL) 193 rt->rt_ifa_seqno = *ifa->ifa_seqno; 194 } 195 196 void 197 rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa) 198 { 199 IFAREF(ifa); 200 IFAFREE(rt->rt_ifa); 201 rt_set_ifa1(rt, ifa); 202 } 203 204 static void 205 rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa) 206 { 207 IFAREF(ifa); 208 rt_set_ifa1(rt, ifa); 209 } 210 211 void 212 rtable_init(void **table) 213 { 214 struct domain *dom; 215 DOMAIN_FOREACH(dom) 216 if (dom->dom_rtattach) 217 dom->dom_rtattach(&table[dom->dom_family], 218 dom->dom_rtoffset); 219 } 220 221 void 222 route_init(void) 223 { 224 225 rt_init(); 226 rn_init(); /* initialize all zeroes, all ones, mask table */ 227 rtable_init((void **)rt_tables); 228 } 229 230 void 231 rtflushall(int family) 232 { 233 struct domain *dom; 234 235 if (rtcache_debug()) 236 printf("%s: enter\n", __func__); 237 238 if ((dom = pffinddomain(family)) == NULL) 239 return; 240 241 rtcache_invalidate(&dom->dom_rtcache); 242 } 243 244 void 245 rtcache(struct route *ro) 246 { 247 struct domain *dom; 248 249 KASSERT(ro->_ro_rt != NULL); 250 KASSERT(ro->ro_invalid == false); 251 KASSERT(rtcache_getdst(ro) != NULL); 252 253 if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL) 254 return; 255 256 LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next); 257 } 258 259 /* 260 * Packet routing routines. 261 */ 262 struct rtentry * 263 rtalloc1(const struct sockaddr *dst, int report) 264 { 265 struct radix_node_head *rnh = rt_tables[dst->sa_family]; 266 struct rtentry *rt; 267 struct radix_node *rn; 268 struct rtentry *newrt = NULL; 269 struct rt_addrinfo info; 270 int s = splsoftnet(), err = 0, msgtype = RTM_MISS; 271 272 if (rnh && (rn = rnh->rnh_matchaddr(dst, rnh)) && 273 ((rn->rn_flags & RNF_ROOT) == 0)) { 274 newrt = rt = (struct rtentry *)rn; 275 if (report && (rt->rt_flags & RTF_CLONING)) { 276 err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, 277 &newrt); 278 if (err) { 279 newrt = rt; 280 rt->rt_refcnt++; 281 goto miss; 282 } 283 KASSERT(newrt != NULL); 284 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 285 msgtype = RTM_RESOLVE; 286 goto miss; 287 } 288 /* Inform listeners of the new route */ 289 memset(&info, 0, sizeof(info)); 290 info.rti_info[RTAX_DST] = rt_getkey(rt); 291 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 292 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 293 if (rt->rt_ifp != NULL) { 294 info.rti_info[RTAX_IFP] = 295 rt->rt_ifp->if_dl->ifa_addr; 296 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 297 } 298 rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0); 299 } else 300 rt->rt_refcnt++; 301 } else { 302 rtstat.rts_unreach++; 303 miss: if (report) { 304 memset((void *)&info, 0, sizeof(info)); 305 info.rti_info[RTAX_DST] = dst; 306 rt_missmsg(msgtype, &info, 0, err); 307 } 308 } 309 splx(s); 310 return newrt; 311 } 312 313 void 314 rtfree(struct rtentry *rt) 315 { 316 struct ifaddr *ifa; 317 318 if (rt == NULL) 319 panic("rtfree"); 320 rt->rt_refcnt--; 321 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 322 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 323 panic ("rtfree 2"); 324 rttrash--; 325 if (rt->rt_refcnt < 0) { 326 printf("rtfree: %p not freed (neg refs)\n", rt); 327 return; 328 } 329 rt_timer_remove_all(rt, 0); 330 ifa = rt->rt_ifa; 331 rt->rt_ifa = NULL; 332 IFAFREE(ifa); 333 rt->rt_ifp = NULL; 334 rt_destroy(rt); 335 pool_put(&rtentry_pool, rt); 336 } 337 } 338 339 void 340 ifafree(struct ifaddr *ifa) 341 { 342 343 #ifdef DIAGNOSTIC 344 if (ifa == NULL) 345 panic("ifafree: null ifa"); 346 if (ifa->ifa_refcnt != 0) 347 panic("ifafree: ifa_refcnt != 0 (%d)", ifa->ifa_refcnt); 348 #endif 349 #ifdef IFAREF_DEBUG 350 printf("ifafree: freeing ifaddr %p\n", ifa); 351 #endif 352 free(ifa, M_IFADDR); 353 } 354 355 static inline int 356 equal(const struct sockaddr *sa1, const struct sockaddr *sa2) 357 { 358 return sockaddr_cmp(sa1, sa2) == 0; 359 } 360 361 /* 362 * Force a routing table entry to the specified 363 * destination to go through the given gateway. 364 * Normally called as a result of a routing redirect 365 * message from the network layer. 366 * 367 * N.B.: must be called at splsoftnet 368 */ 369 void 370 rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway, 371 const struct sockaddr *netmask, int flags, const struct sockaddr *src, 372 struct rtentry **rtp) 373 { 374 struct rtentry *rt; 375 int error = 0; 376 u_quad_t *stat = NULL; 377 struct rt_addrinfo info; 378 struct ifaddr *ifa; 379 380 /* verify the gateway is directly reachable */ 381 if ((ifa = ifa_ifwithnet(gateway)) == NULL) { 382 error = ENETUNREACH; 383 goto out; 384 } 385 rt = rtalloc1(dst, 0); 386 /* 387 * If the redirect isn't from our current router for this dst, 388 * it's either old or wrong. If it redirects us to ourselves, 389 * we have a routing loop, perhaps as a result of an interface 390 * going down recently. 391 */ 392 if (!(flags & RTF_DONE) && rt && 393 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 394 error = EINVAL; 395 else if (ifa_ifwithaddr(gateway)) 396 error = EHOSTUNREACH; 397 if (error) 398 goto done; 399 /* 400 * Create a new entry if we just got back a wildcard entry 401 * or the lookup failed. This is necessary for hosts 402 * which use routing redirects generated by smart gateways 403 * to dynamically build the routing tables. 404 */ 405 if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 406 goto create; 407 /* 408 * Don't listen to the redirect if it's 409 * for a route to an interface. 410 */ 411 if (rt->rt_flags & RTF_GATEWAY) { 412 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 413 /* 414 * Changing from route to net => route to host. 415 * Create new route, rather than smashing route to net. 416 */ 417 create: 418 if (rt != NULL) 419 rtfree(rt); 420 flags |= RTF_GATEWAY | RTF_DYNAMIC; 421 info.rti_info[RTAX_DST] = dst; 422 info.rti_info[RTAX_GATEWAY] = gateway; 423 info.rti_info[RTAX_NETMASK] = netmask; 424 info.rti_ifa = ifa; 425 info.rti_flags = flags; 426 rt = NULL; 427 error = rtrequest1(RTM_ADD, &info, &rt); 428 if (rt != NULL) 429 flags = rt->rt_flags; 430 stat = &rtstat.rts_dynamic; 431 } else { 432 /* 433 * Smash the current notion of the gateway to 434 * this destination. Should check about netmask!!! 435 */ 436 rt->rt_flags |= RTF_MODIFIED; 437 flags |= RTF_MODIFIED; 438 stat = &rtstat.rts_newgateway; 439 rt_setgate(rt, gateway); 440 } 441 } else 442 error = EHOSTUNREACH; 443 done: 444 if (rt) { 445 if (rtp != NULL && !error) 446 *rtp = rt; 447 else 448 rtfree(rt); 449 } 450 out: 451 if (error) 452 rtstat.rts_badredirect++; 453 else if (stat != NULL) 454 (*stat)++; 455 memset(&info, 0, sizeof(info)); 456 info.rti_info[RTAX_DST] = dst; 457 info.rti_info[RTAX_GATEWAY] = gateway; 458 info.rti_info[RTAX_NETMASK] = netmask; 459 info.rti_info[RTAX_AUTHOR] = src; 460 rt_missmsg(RTM_REDIRECT, &info, flags, error); 461 } 462 463 /* 464 * Delete a route and generate a message 465 */ 466 static int 467 rtdeletemsg(struct rtentry *rt) 468 { 469 int error; 470 struct rt_addrinfo info; 471 472 /* 473 * Request the new route so that the entry is not actually 474 * deleted. That will allow the information being reported to 475 * be accurate (and consistent with route_output()). 476 */ 477 memset(&info, 0, sizeof(info)); 478 info.rti_info[RTAX_DST] = rt_getkey(rt); 479 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 480 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 481 info.rti_flags = rt->rt_flags; 482 error = rtrequest1(RTM_DELETE, &info, &rt); 483 484 rt_missmsg(RTM_DELETE, &info, info.rti_flags, error); 485 486 /* Adjust the refcount */ 487 if (error == 0 && rt->rt_refcnt <= 0) { 488 rt->rt_refcnt++; 489 rtfree(rt); 490 } 491 return error; 492 } 493 494 static int 495 rtflushclone1(struct rtentry *rt, void *arg) 496 { 497 struct rtentry *parent; 498 499 parent = (struct rtentry *)arg; 500 if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) 501 rtdeletemsg(rt); 502 return 0; 503 } 504 505 static void 506 rtflushclone(sa_family_t family, struct rtentry *parent) 507 { 508 509 #ifdef DIAGNOSTIC 510 if (!parent || (parent->rt_flags & RTF_CLONING) == 0) 511 panic("rtflushclone: called with a non-cloning route"); 512 #endif 513 rt_walktree(family, rtflushclone1, (void *)parent); 514 } 515 516 /* 517 * Routing table ioctl interface. 518 */ 519 int 520 rtioctl(u_long req, void *data, struct lwp *l) 521 { 522 return EOPNOTSUPP; 523 } 524 525 struct ifaddr * 526 ifa_ifwithroute(int flags, const struct sockaddr *dst, 527 const struct sockaddr *gateway) 528 { 529 struct ifaddr *ifa; 530 if ((flags & RTF_GATEWAY) == 0) { 531 /* 532 * If we are adding a route to an interface, 533 * and the interface is a pt to pt link 534 * we should search for the destination 535 * as our clue to the interface. Otherwise 536 * we can use the local address. 537 */ 538 ifa = NULL; 539 if (flags & RTF_HOST) 540 ifa = ifa_ifwithdstaddr(dst); 541 if (ifa == NULL) 542 ifa = ifa_ifwithaddr(gateway); 543 } else { 544 /* 545 * If we are adding a route to a remote net 546 * or host, the gateway may still be on the 547 * other end of a pt to pt link. 548 */ 549 ifa = ifa_ifwithdstaddr(gateway); 550 } 551 if (ifa == NULL) 552 ifa = ifa_ifwithnet(gateway); 553 if (ifa == NULL) { 554 struct rtentry *rt = rtalloc1(dst, 0); 555 if (rt == NULL) 556 return NULL; 557 rt->rt_refcnt--; 558 if ((ifa = rt->rt_ifa) == NULL) 559 return NULL; 560 } 561 if (ifa->ifa_addr->sa_family != dst->sa_family) { 562 struct ifaddr *oifa = ifa; 563 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 564 if (ifa == 0) 565 ifa = oifa; 566 } 567 return ifa; 568 } 569 570 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 571 572 int 573 rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway, 574 const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt) 575 { 576 struct rt_addrinfo info; 577 578 memset(&info, 0, sizeof(info)); 579 info.rti_flags = flags; 580 info.rti_info[RTAX_DST] = dst; 581 info.rti_info[RTAX_GATEWAY] = gateway; 582 info.rti_info[RTAX_NETMASK] = netmask; 583 return rtrequest1(req, &info, ret_nrt); 584 } 585 586 int 587 rt_getifa(struct rt_addrinfo *info) 588 { 589 struct ifaddr *ifa; 590 const struct sockaddr *dst = info->rti_info[RTAX_DST]; 591 const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; 592 const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA]; 593 const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP]; 594 int flags = info->rti_flags; 595 596 /* 597 * ifp may be specified by sockaddr_dl when protocol address 598 * is ambiguous 599 */ 600 if (info->rti_ifp == NULL && ifpaddr != NULL 601 && ifpaddr->sa_family == AF_LINK && 602 (ifa = ifa_ifwithnet(ifpaddr)) != NULL) 603 info->rti_ifp = ifa->ifa_ifp; 604 if (info->rti_ifa == NULL && ifaaddr != NULL) 605 info->rti_ifa = ifa_ifwithaddr(ifaaddr); 606 if (info->rti_ifa == NULL) { 607 const struct sockaddr *sa; 608 609 sa = ifaaddr != NULL ? ifaaddr : 610 (gateway != NULL ? gateway : dst); 611 if (sa != NULL && info->rti_ifp != NULL) 612 info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 613 else if (dst != NULL && gateway != NULL) 614 info->rti_ifa = ifa_ifwithroute(flags, dst, gateway); 615 else if (sa != NULL) 616 info->rti_ifa = ifa_ifwithroute(flags, sa, sa); 617 } 618 if ((ifa = info->rti_ifa) == NULL) 619 return ENETUNREACH; 620 if (ifa->ifa_getifa != NULL) 621 info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst); 622 if (info->rti_ifp == NULL) 623 info->rti_ifp = ifa->ifa_ifp; 624 return 0; 625 } 626 627 int 628 rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) 629 { 630 int s = splsoftnet(); 631 int error = 0; 632 struct rtentry *rt, *crt; 633 struct radix_node *rn; 634 struct radix_node_head *rnh; 635 struct ifaddr *ifa; 636 struct sockaddr_storage maskeddst; 637 const struct sockaddr *dst = info->rti_info[RTAX_DST]; 638 const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; 639 const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK]; 640 int flags = info->rti_flags; 641 #define senderr(x) { error = x ; goto bad; } 642 643 if ((rnh = rt_tables[dst->sa_family]) == NULL) 644 senderr(ESRCH); 645 if (flags & RTF_HOST) 646 netmask = NULL; 647 switch (req) { 648 case RTM_DELETE: 649 if (netmask) { 650 rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, 651 netmask); 652 dst = (struct sockaddr *)&maskeddst; 653 } 654 if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL) 655 senderr(ESRCH); 656 rt = (struct rtentry *)rn; 657 if ((rt->rt_flags & RTF_CLONING) != 0) { 658 /* clean up any cloned children */ 659 rtflushclone(dst->sa_family, rt); 660 } 661 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL) 662 senderr(ESRCH); 663 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 664 panic ("rtrequest delete"); 665 rt = (struct rtentry *)rn; 666 if (rt->rt_gwroute) { 667 RTFREE(rt->rt_gwroute); 668 rt->rt_gwroute = NULL; 669 } 670 if (rt->rt_parent) { 671 rt->rt_parent->rt_refcnt--; 672 rt->rt_parent = NULL; 673 } 674 rt->rt_flags &= ~RTF_UP; 675 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 676 ifa->ifa_rtrequest(RTM_DELETE, rt, info); 677 rttrash++; 678 if (ret_nrt) 679 *ret_nrt = rt; 680 else if (rt->rt_refcnt <= 0) { 681 rt->rt_refcnt++; 682 rtfree(rt); 683 } 684 break; 685 686 case RTM_RESOLVE: 687 if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) 688 senderr(EINVAL); 689 if ((rt->rt_flags & RTF_CLONING) == 0) 690 senderr(EINVAL); 691 ifa = rt->rt_ifa; 692 flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC); 693 flags |= RTF_CLONED; 694 gateway = rt->rt_gateway; 695 flags |= RTF_HOST; 696 goto makeroute; 697 698 case RTM_ADD: 699 if (info->rti_ifa == NULL && (error = rt_getifa(info))) 700 senderr(error); 701 ifa = info->rti_ifa; 702 makeroute: 703 /* Already at splsoftnet() so pool_get/pool_put are safe */ 704 rt = pool_get(&rtentry_pool, PR_NOWAIT); 705 if (rt == NULL) 706 senderr(ENOBUFS); 707 memset(rt, 0, sizeof(*rt)); 708 rt->rt_flags = RTF_UP | flags; 709 LIST_INIT(&rt->rt_timer); 710 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 711 if (rt_setkey(rt, dst, M_NOWAIT) == NULL || 712 rt_setgate(rt, gateway) != 0) { 713 pool_put(&rtentry_pool, rt); 714 senderr(ENOBUFS); 715 } 716 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 717 if (netmask) { 718 rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, 719 netmask); 720 rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT); 721 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 722 } else { 723 rt_setkey(rt, dst, M_NOWAIT); 724 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 725 } 726 rt_set_ifa(rt, ifa); 727 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 728 rt->rt_ifp = ifa->ifa_ifp; 729 if (req == RTM_RESOLVE) { 730 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 731 rt->rt_parent = *ret_nrt; 732 rt->rt_parent->rt_refcnt++; 733 } 734 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 735 rn = rnh->rnh_addaddr(rt_getkey(rt), netmask, rnh, 736 rt->rt_nodes); 737 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 738 if (rn == NULL && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) { 739 /* overwrite cloned route */ 740 if ((crt->rt_flags & RTF_CLONED) != 0) { 741 rtdeletemsg(crt); 742 rn = rnh->rnh_addaddr(rt_getkey(rt), 743 netmask, rnh, rt->rt_nodes); 744 } 745 RTFREE(crt); 746 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 747 } 748 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 749 if (rn == NULL) { 750 IFAFREE(ifa); 751 if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) 752 rtfree(rt->rt_parent); 753 if (rt->rt_gwroute) 754 rtfree(rt->rt_gwroute); 755 rt_destroy(rt); 756 pool_put(&rtentry_pool, rt); 757 senderr(EEXIST); 758 } 759 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 760 if (ifa->ifa_rtrequest) 761 ifa->ifa_rtrequest(req, rt, info); 762 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 763 if (ret_nrt) { 764 *ret_nrt = rt; 765 rt->rt_refcnt++; 766 } 767 if ((rt->rt_flags & RTF_CLONING) != 0) { 768 /* clean up any cloned children */ 769 rtflushclone(dst->sa_family, rt); 770 } 771 rtflushall(dst->sa_family); 772 break; 773 case RTM_GET: 774 if (netmask != NULL) { 775 rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, 776 netmask); 777 dst = (struct sockaddr *)&maskeddst; 778 } 779 rn = rnh->rnh_lookup(dst, netmask, rnh); 780 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) 781 senderr(ESRCH); 782 if (ret_nrt != NULL) { 783 rt = (struct rtentry *)rn; 784 *ret_nrt = rt; 785 rt->rt_refcnt++; 786 } 787 break; 788 } 789 bad: 790 splx(s); 791 return error; 792 } 793 794 int 795 rt_setgate(struct rtentry *rt, const struct sockaddr *gate) 796 { 797 KASSERT(rt != rt->rt_gwroute); 798 799 KASSERT(rt->_rt_key != NULL); 800 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 801 802 if (rt->rt_gwroute) { 803 RTFREE(rt->rt_gwroute); 804 rt->rt_gwroute = NULL; 805 } 806 KASSERT(rt->_rt_key != NULL); 807 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 808 if (rt->rt_gateway != NULL) 809 sockaddr_free(rt->rt_gateway); 810 KASSERT(rt->_rt_key != NULL); 811 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 812 if ((rt->rt_gateway = sockaddr_dup(gate, M_NOWAIT)) == NULL) 813 return ENOMEM; 814 KASSERT(rt->_rt_key != NULL); 815 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 816 817 if (rt->rt_flags & RTF_GATEWAY) { 818 KASSERT(rt->_rt_key != NULL); 819 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 820 rt->rt_gwroute = rtalloc1(gate, 1); 821 /* 822 * If we switched gateways, grab the MTU from the new 823 * gateway route if the current MTU, if the current MTU is 824 * greater than the MTU of gateway. 825 * Note that, if the MTU of gateway is 0, we will reset the 826 * MTU of the route to run PMTUD again from scratch. XXX 827 */ 828 KASSERT(rt->_rt_key != NULL); 829 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 830 if (rt->rt_gwroute 831 && !(rt->rt_rmx.rmx_locks & RTV_MTU) 832 && rt->rt_rmx.rmx_mtu 833 && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) { 834 rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; 835 } 836 } 837 KASSERT(rt->_rt_key != NULL); 838 RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); 839 return 0; 840 } 841 842 void 843 rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst, 844 const struct sockaddr *netmask) 845 { 846 const char *netmaskp = &netmask->sa_data[0], 847 *srcp = &src->sa_data[0]; 848 char *dstp = &dst->sa_data[0]; 849 const char *maskend = dstp + MIN(netmask->sa_len, src->sa_len); 850 const char *srcend = dstp + src->sa_len; 851 852 dst->sa_len = src->sa_len; 853 dst->sa_family = src->sa_family; 854 855 while (dstp < maskend) 856 *dstp++ = *srcp++ & *netmaskp++; 857 if (dstp < srcend) 858 memset(dstp, 0, (size_t)(srcend - dstp)); 859 } 860 861 /* 862 * Set up or tear down a routing table entry, normally 863 * for an interface. 864 */ 865 int 866 rtinit(struct ifaddr *ifa, int cmd, int flags) 867 { 868 struct rtentry *rt; 869 struct sockaddr *dst, *odst; 870 struct sockaddr_storage maskeddst; 871 struct rtentry *nrt = NULL; 872 int error; 873 struct rt_addrinfo info; 874 875 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 876 if (cmd == RTM_DELETE) { 877 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 878 /* Delete subnet route for this interface */ 879 odst = dst; 880 dst = (struct sockaddr *)&maskeddst; 881 rt_maskedcopy(odst, dst, ifa->ifa_netmask); 882 } 883 if ((rt = rtalloc1(dst, 0)) != NULL) { 884 rt->rt_refcnt--; 885 if (rt->rt_ifa != ifa) 886 return (flags & RTF_HOST) ? EHOSTUNREACH 887 : ENETUNREACH; 888 } 889 } 890 memset(&info, 0, sizeof(info)); 891 info.rti_ifa = ifa; 892 info.rti_flags = flags | ifa->ifa_flags; 893 info.rti_info[RTAX_DST] = dst; 894 info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 895 /* 896 * XXX here, it seems that we are assuming that ifa_netmask is NULL 897 * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate 898 * variable) when RTF_HOST is 1. still not sure if i can safely 899 * change it to meet bsdi4 behavior. 900 */ 901 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 902 error = rtrequest1(cmd, &info, &nrt); 903 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { 904 rt_newaddrmsg(cmd, ifa, error, nrt); 905 if (rt->rt_refcnt <= 0) { 906 rt->rt_refcnt++; 907 rtfree(rt); 908 } 909 } 910 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { 911 rt->rt_refcnt--; 912 if (rt->rt_ifa != ifa) { 913 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, 914 rt->rt_ifa); 915 if (rt->rt_ifa->ifa_rtrequest) 916 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); 917 rt_replace_ifa(rt, ifa); 918 rt->rt_ifp = ifa->ifa_ifp; 919 if (ifa->ifa_rtrequest) 920 ifa->ifa_rtrequest(RTM_ADD, rt, NULL); 921 } 922 rt_newaddrmsg(cmd, ifa, error, nrt); 923 } 924 return error; 925 } 926 927 /* 928 * Route timer routines. These routes allow functions to be called 929 * for various routes at any time. This is useful in supporting 930 * path MTU discovery and redirect route deletion. 931 * 932 * This is similar to some BSDI internal functions, but it provides 933 * for multiple queues for efficiency's sake... 934 */ 935 936 LIST_HEAD(, rttimer_queue) rttimer_queue_head; 937 static int rt_init_done = 0; 938 939 #define RTTIMER_CALLOUT(r) do { \ 940 if (r->rtt_func != NULL) { \ 941 (*r->rtt_func)(r->rtt_rt, r); \ 942 } else { \ 943 rtrequest((int) RTM_DELETE, \ 944 rt_getkey(r->rtt_rt), \ 945 0, 0, 0, 0); \ 946 } \ 947 } while (/*CONSTCOND*/0) 948 949 /* 950 * Some subtle order problems with domain initialization mean that 951 * we cannot count on this being run from rt_init before various 952 * protocol initializations are done. Therefore, we make sure 953 * that this is run when the first queue is added... 954 */ 955 956 void 957 rt_timer_init(void) 958 { 959 assert(rt_init_done == 0); 960 961 LIST_INIT(&rttimer_queue_head); 962 callout_init(&rt_timer_ch, 0); 963 callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); 964 rt_init_done = 1; 965 } 966 967 struct rttimer_queue * 968 rt_timer_queue_create(u_int timeout) 969 { 970 struct rttimer_queue *rtq; 971 972 if (rt_init_done == 0) 973 rt_timer_init(); 974 975 R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); 976 if (rtq == NULL) 977 return NULL; 978 memset(rtq, 0, sizeof(*rtq)); 979 980 rtq->rtq_timeout = timeout; 981 TAILQ_INIT(&rtq->rtq_head); 982 LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); 983 984 return rtq; 985 } 986 987 void 988 rt_timer_queue_change(struct rttimer_queue *rtq, long timeout) 989 { 990 991 rtq->rtq_timeout = timeout; 992 } 993 994 void 995 rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy) 996 { 997 struct rttimer *r; 998 999 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) { 1000 LIST_REMOVE(r, rtt_link); 1001 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 1002 if (destroy) 1003 RTTIMER_CALLOUT(r); 1004 /* we are already at splsoftnet */ 1005 pool_put(&rttimer_pool, r); 1006 if (rtq->rtq_count > 0) 1007 rtq->rtq_count--; 1008 else 1009 printf("rt_timer_queue_remove_all: " 1010 "rtq_count reached 0\n"); 1011 } 1012 } 1013 1014 void 1015 rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy) 1016 { 1017 1018 rt_timer_queue_remove_all(rtq, destroy); 1019 1020 LIST_REMOVE(rtq, rtq_link); 1021 1022 /* 1023 * Caller is responsible for freeing the rttimer_queue structure. 1024 */ 1025 } 1026 1027 unsigned long 1028 rt_timer_count(struct rttimer_queue *rtq) 1029 { 1030 return rtq->rtq_count; 1031 } 1032 1033 void 1034 rt_timer_remove_all(struct rtentry *rt, int destroy) 1035 { 1036 struct rttimer *r; 1037 1038 while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) { 1039 LIST_REMOVE(r, rtt_link); 1040 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 1041 if (destroy) 1042 RTTIMER_CALLOUT(r); 1043 if (r->rtt_queue->rtq_count > 0) 1044 r->rtt_queue->rtq_count--; 1045 else 1046 printf("rt_timer_remove_all: rtq_count reached 0\n"); 1047 /* we are already at splsoftnet */ 1048 pool_put(&rttimer_pool, r); 1049 } 1050 } 1051 1052 int 1053 rt_timer_add(struct rtentry *rt, 1054 void (*func)(struct rtentry *, struct rttimer *), 1055 struct rttimer_queue *queue) 1056 { 1057 struct rttimer *r; 1058 int s; 1059 1060 /* 1061 * If there's already a timer with this action, destroy it before 1062 * we add a new one. 1063 */ 1064 LIST_FOREACH(r, &rt->rt_timer, rtt_link) { 1065 if (r->rtt_func == func) 1066 break; 1067 } 1068 if (r != NULL) { 1069 LIST_REMOVE(r, rtt_link); 1070 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 1071 if (r->rtt_queue->rtq_count > 0) 1072 r->rtt_queue->rtq_count--; 1073 else 1074 printf("rt_timer_add: rtq_count reached 0\n"); 1075 } else { 1076 s = splsoftnet(); 1077 r = pool_get(&rttimer_pool, PR_NOWAIT); 1078 splx(s); 1079 if (r == NULL) 1080 return ENOBUFS; 1081 } 1082 1083 memset(r, 0, sizeof(*r)); 1084 1085 r->rtt_rt = rt; 1086 r->rtt_time = time_uptime; 1087 r->rtt_func = func; 1088 r->rtt_queue = queue; 1089 LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); 1090 TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); 1091 r->rtt_queue->rtq_count++; 1092 1093 return 0; 1094 } 1095 1096 /* ARGSUSED */ 1097 void 1098 rt_timer_timer(void *arg) 1099 { 1100 struct rttimer_queue *rtq; 1101 struct rttimer *r; 1102 int s; 1103 1104 s = splsoftnet(); 1105 LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) { 1106 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && 1107 (r->rtt_time + rtq->rtq_timeout) < time_uptime) { 1108 LIST_REMOVE(r, rtt_link); 1109 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 1110 RTTIMER_CALLOUT(r); 1111 pool_put(&rttimer_pool, r); 1112 if (rtq->rtq_count > 0) 1113 rtq->rtq_count--; 1114 else 1115 printf("rt_timer_timer: rtq_count reached 0\n"); 1116 } 1117 } 1118 splx(s); 1119 1120 callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); 1121 } 1122 1123 static struct rtentry * 1124 _rtcache_init(struct route *ro, int flag) 1125 { 1126 KASSERT(ro->_ro_rt == NULL); 1127 1128 if (rtcache_getdst(ro) == NULL) 1129 return NULL; 1130 ro->ro_invalid = false; 1131 if ((ro->_ro_rt = rtalloc1(rtcache_getdst(ro), flag)) != NULL) 1132 rtcache(ro); 1133 1134 return ro->_ro_rt; 1135 } 1136 1137 struct rtentry * 1138 rtcache_init(struct route *ro) 1139 { 1140 return _rtcache_init(ro, 1); 1141 } 1142 1143 struct rtentry * 1144 rtcache_init_noclone(struct route *ro) 1145 { 1146 return _rtcache_init(ro, 0); 1147 } 1148 1149 struct rtentry * 1150 rtcache_update(struct route *ro, int clone) 1151 { 1152 rtcache_clear(ro); 1153 return _rtcache_init(ro, clone); 1154 } 1155 1156 void 1157 rtcache_copy(struct route *new_ro, const struct route *old_ro) 1158 { 1159 struct rtentry *rt; 1160 1161 KASSERT(new_ro != old_ro); 1162 1163 if ((rt = rtcache_validate(old_ro)) != NULL) 1164 rt->rt_refcnt++; 1165 1166 if (rtcache_getdst(old_ro) == NULL || 1167 rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0) 1168 return; 1169 1170 new_ro->ro_invalid = false; 1171 if ((new_ro->_ro_rt = rt) != NULL) 1172 rtcache(new_ro); 1173 } 1174 1175 static struct dom_rtlist invalid_routes = LIST_HEAD_INITIALIZER(dom_rtlist); 1176 1177 void 1178 rtcache_invalidate(struct dom_rtlist *rtlist) 1179 { 1180 struct route *ro; 1181 1182 while ((ro = LIST_FIRST(rtlist)) != NULL) { 1183 KASSERT(ro->_ro_rt != NULL); 1184 ro->ro_invalid = true; 1185 LIST_REMOVE(ro, ro_rtcache_next); 1186 LIST_INSERT_HEAD(&invalid_routes, ro, ro_rtcache_next); 1187 } 1188 } 1189 1190 void 1191 rtcache_clear(struct route *ro) 1192 { 1193 if (ro->_ro_rt == NULL) 1194 return; 1195 1196 KASSERT(rtcache_getdst(ro) != NULL); 1197 1198 LIST_REMOVE(ro, ro_rtcache_next); 1199 1200 RTFREE(ro->_ro_rt); 1201 ro->_ro_rt = NULL; 1202 } 1203 1204 struct rtentry * 1205 rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone, 1206 int *hitp) 1207 { 1208 const struct sockaddr *odst; 1209 struct rtentry *rt = NULL; 1210 1211 odst = rtcache_getdst(ro); 1212 1213 if (odst == NULL) 1214 ; 1215 else if (sockaddr_cmp(odst, dst) != 0) 1216 rtcache_free(ro); 1217 else if ((rt = rtcache_validate(ro)) == NULL) 1218 rtcache_clear(ro); 1219 1220 if (rt == NULL) { 1221 *hitp = 0; 1222 if (rtcache_setdst(ro, dst) == 0) 1223 rt = _rtcache_init(ro, clone); 1224 } else 1225 *hitp = 1; 1226 1227 return rt; 1228 } 1229 1230 void 1231 rtcache_free(struct route *ro) 1232 { 1233 rtcache_clear(ro); 1234 if (ro->ro_sa != NULL) { 1235 sockaddr_free(ro->ro_sa); 1236 ro->ro_sa = NULL; 1237 KASSERT(ro->_ro_rt == NULL); 1238 } 1239 } 1240 1241 int 1242 rtcache_setdst(struct route *ro, const struct sockaddr *sa) 1243 { 1244 KASSERT(sa != NULL); 1245 1246 if (ro->ro_sa != NULL && ro->ro_sa->sa_family == sa->sa_family) { 1247 rtcache_clear(ro); 1248 if (sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa) != NULL) 1249 return 0; 1250 sockaddr_free(ro->ro_sa); 1251 } else if (ro->ro_sa != NULL) 1252 rtcache_free(ro); /* free ro_sa, wrong family */ 1253 1254 KASSERT(ro->_ro_rt == NULL); 1255 1256 if ((ro->ro_sa = sockaddr_dup(sa, M_NOWAIT)) == NULL) { 1257 return ENOMEM; 1258 } 1259 return 0; 1260 } 1261 1262 static int 1263 rt_walktree_visitor(struct radix_node *rn, void *v) 1264 { 1265 struct rtwalk *rw = (struct rtwalk *)v; 1266 1267 return (*rw->rw_f)((struct rtentry *)rn, rw->rw_v); 1268 } 1269 1270 int 1271 rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v) 1272 { 1273 struct radix_node_head *rnh = rt_tables[family]; 1274 struct rtwalk rw; 1275 1276 if (rnh == NULL) 1277 return 0; 1278 1279 rw.rw_f = f; 1280 rw.rw_v = v; 1281 1282 return rn_walktree(rnh, rt_walktree_visitor, &rw); 1283 } 1284