1 /* $OpenBSD: route.c,v 1.36 2003/06/02 23:28:12 millert Exp $ */ 2 /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1980, 1986, 1991, 1993 35 * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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 * @(#)route.c 8.2 (Berkeley) 11/15/93 62 */ 63 64 /* 65 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 66 * 67 * NRL grants permission for redistribution and use in source and binary 68 * forms, with or without modification, of the software and documentation 69 * created at NRL provided that the following conditions are met: 70 * 71 * 1. Redistributions of source code must retain the above copyright 72 * notice, this list of conditions and the following disclaimer. 73 * 2. Redistributions in binary form must reproduce the above copyright 74 * notice, this list of conditions and the following disclaimer in the 75 * documentation and/or other materials provided with the distribution. 76 * 3. All advertising materials mentioning features or use of this software 77 * must display the following acknowledgements: 78 * This product includes software developed by the University of 79 * California, Berkeley and its contributors. 80 * This product includes software developed at the Information 81 * Technology Division, US Naval Research Laboratory. 82 * 4. Neither the name of the NRL nor the names of its contributors 83 * may be used to endorse or promote products derived from this software 84 * without specific prior written permission. 85 * 86 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 87 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 88 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 89 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 90 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 91 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 92 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 93 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 94 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 95 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 96 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 97 * 98 * The views and conclusions contained in the software and documentation 99 * are those of the authors and should not be interpreted as representing 100 * official policies, either expressed or implied, of the US Naval 101 * Research Laboratory (NRL). 102 */ 103 104 #include <sys/param.h> 105 #include <sys/systm.h> 106 #include <sys/proc.h> 107 #include <sys/mbuf.h> 108 #include <sys/socket.h> 109 #include <sys/socketvar.h> 110 #include <sys/domain.h> 111 #include <sys/protosw.h> 112 #include <sys/ioctl.h> 113 #include <sys/kernel.h> 114 115 #include <net/if.h> 116 #include <net/route.h> 117 #include <net/raw_cb.h> 118 119 #include <netinet/in.h> 120 #include <netinet/in_var.h> 121 122 #ifdef NS 123 #include <netns/ns.h> 124 #endif 125 126 #ifdef IPSEC 127 #include <netinet/ip_ipsp.h> 128 129 extern struct ifnet encif; 130 #endif 131 132 #define SA(p) ((struct sockaddr *)(p)) 133 134 struct route_cb route_cb; 135 struct rtstat rtstat; 136 struct radix_node_head *rt_tables[AF_MAX+1]; 137 138 int rttrash; /* routes not in table but not freed */ 139 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 140 141 static int okaytoclone(u_int, int); 142 143 #ifdef IPSEC 144 145 static struct ifaddr * 146 encap_findgwifa(struct sockaddr *gw) 147 { 148 return (TAILQ_FIRST(&encif.if_addrlist)); 149 } 150 151 #endif 152 153 void 154 rtable_init(table) 155 void **table; 156 { 157 struct domain *dom; 158 for (dom = domains; dom != NULL; dom = dom->dom_next) 159 if (dom->dom_rtattach) 160 dom->dom_rtattach(&table[dom->dom_family], 161 dom->dom_rtoffset); 162 } 163 164 void 165 route_init() 166 { 167 rn_init(); /* initialize all zeroes, all ones, mask table */ 168 rtable_init((void **)rt_tables); 169 } 170 171 void 172 rtalloc_noclone(ro, howstrict) 173 register struct route *ro; 174 int howstrict; 175 { 176 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 177 return; /* XXX */ 178 ro->ro_rt = rtalloc2(&ro->ro_dst, 1, howstrict); 179 } 180 181 static int 182 okaytoclone(flags, howstrict) 183 u_int flags; 184 int howstrict; 185 { 186 if (howstrict == ALL_CLONING) 187 return (1); 188 if (howstrict == ONNET_CLONING && !(flags & RTF_GATEWAY)) 189 return (1); 190 return (0); 191 } 192 193 struct rtentry * 194 rtalloc2(dst, report,howstrict) 195 register struct sockaddr *dst; 196 int report,howstrict; 197 { 198 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 199 register struct rtentry *rt; 200 register struct radix_node *rn; 201 struct rtentry *newrt = 0; 202 struct rt_addrinfo info; 203 int s = splnet(), err = 0, msgtype = RTM_MISS; 204 205 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && 206 ((rn->rn_flags & RNF_ROOT) == 0)) { 207 newrt = rt = (struct rtentry *)rn; 208 if (report && (rt->rt_flags & RTF_CLONING) && 209 okaytoclone(rt->rt_flags, howstrict)) { 210 err = rtrequest(RTM_RESOLVE, dst, SA(0), SA(0), 0, 211 &newrt); 212 if (err) { 213 newrt = rt; 214 rt->rt_refcnt++; 215 goto miss; 216 } 217 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 218 msgtype = RTM_RESOLVE; 219 goto miss; 220 } 221 } else 222 rt->rt_refcnt++; 223 } else { 224 rtstat.rts_unreach++; 225 miss: if (report) { 226 bzero((caddr_t)&info, sizeof(info)); 227 info.rti_info[RTAX_DST] = dst; 228 rt_missmsg(msgtype, &info, 0, err); 229 } 230 } 231 splx(s); 232 return (newrt); 233 } 234 235 /* 236 * Packet routing routines. 237 */ 238 void 239 rtalloc(ro) 240 register struct route *ro; 241 { 242 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 243 return; /* XXX */ 244 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 245 } 246 247 struct rtentry * 248 rtalloc1(dst, report) 249 register struct sockaddr *dst; 250 int report; 251 { 252 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 253 register struct rtentry *rt; 254 register struct radix_node *rn; 255 struct rtentry *newrt = 0; 256 struct rt_addrinfo info; 257 int s = splsoftnet(), err = 0, msgtype = RTM_MISS; 258 259 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && 260 ((rn->rn_flags & RNF_ROOT) == 0)) { 261 newrt = rt = (struct rtentry *)rn; 262 if (report && (rt->rt_flags & RTF_CLONING)) { 263 err = rtrequest(RTM_RESOLVE, dst, SA(NULL), 264 SA(NULL), 0, &newrt); 265 if (err) { 266 newrt = rt; 267 rt->rt_refcnt++; 268 goto miss; 269 } 270 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 271 msgtype = RTM_RESOLVE; 272 goto miss; 273 } 274 /* Inform listeners of the new route */ 275 bzero(&info, sizeof(info)); 276 info.rti_info[RTAX_DST] = rt_key(rt); 277 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 278 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 279 if (rt->rt_ifp != NULL) { 280 info.rti_info[RTAX_IFP] = 281 TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 282 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 283 } 284 rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0); 285 } else 286 rt->rt_refcnt++; 287 } else { 288 if (dst->sa_family != PF_KEY) 289 rtstat.rts_unreach++; 290 /* 291 * IP encapsulation does lots of lookups where we don't need nor want 292 * the RTM_MISSes that would be generated. It causes RTM_MISS storms 293 * sent upward breaking user-level routing queries. 294 */ 295 miss: if (report && dst->sa_family != PF_KEY) { 296 bzero((caddr_t)&info, sizeof(info)); 297 info.rti_info[RTAX_DST] = dst; 298 rt_missmsg(msgtype, &info, 0, err); 299 } 300 } 301 splx(s); 302 return (newrt); 303 } 304 305 void 306 rtfree(rt) 307 register struct rtentry *rt; 308 { 309 register struct ifaddr *ifa; 310 311 if (rt == NULL) 312 panic("rtfree"); 313 rt->rt_refcnt--; 314 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 315 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 316 panic ("rtfree 2"); 317 rttrash--; 318 if (rt->rt_refcnt < 0) { 319 printf("rtfree: %p not freed (neg refs)\n", rt); 320 return; 321 } 322 rt_timer_remove_all(rt); 323 ifa = rt->rt_ifa; 324 if (ifa) 325 IFAFREE(ifa); 326 Free(rt_key(rt)); 327 Free(rt); 328 } 329 } 330 331 void 332 ifafree(ifa) 333 register struct ifaddr *ifa; 334 { 335 if (ifa == NULL) 336 panic("ifafree"); 337 if (ifa->ifa_refcnt == 0) 338 free(ifa, M_IFADDR); 339 else 340 ifa->ifa_refcnt--; 341 } 342 343 /* 344 * Force a routing table entry to the specified 345 * destination to go through the given gateway. 346 * Normally called as a result of a routing redirect 347 * message from the network layer. 348 * 349 * N.B.: must be called at splsoftnet 350 */ 351 void 352 rtredirect(dst, gateway, netmask, flags, src, rtp) 353 struct sockaddr *dst, *gateway, *netmask, *src; 354 int flags; 355 struct rtentry **rtp; 356 { 357 struct rtentry *rt; 358 int error = 0; 359 u_int32_t *stat = NULL; 360 struct rt_addrinfo info; 361 struct ifaddr *ifa; 362 363 splassert(IPL_SOFTNET); 364 365 /* verify the gateway is directly reachable */ 366 if ((ifa = ifa_ifwithnet(gateway)) == NULL) { 367 error = ENETUNREACH; 368 goto out; 369 } 370 rt = rtalloc1(dst, 0); 371 /* 372 * If the redirect isn't from our current router for this dst, 373 * it's either old or wrong. If it redirects us to ourselves, 374 * we have a routing loop, perhaps as a result of an interface 375 * going down recently. 376 */ 377 #define equal(a1, a2) \ 378 ((a1)->sa_len == (a2)->sa_len && \ 379 bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 380 if (!(flags & RTF_DONE) && rt && 381 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 382 error = EINVAL; 383 else if (ifa_ifwithaddr(gateway) != NULL) 384 error = EHOSTUNREACH; 385 if (error) 386 goto done; 387 /* 388 * Create a new entry if we just got back a wildcard entry 389 * or the lookup failed. This is necessary for hosts 390 * which use routing redirects generated by smart gateways 391 * to dynamically build the routing tables. 392 */ 393 if ((rt == NULL) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 394 goto create; 395 /* 396 * Don't listen to the redirect if it's 397 * for a route to an interface. 398 */ 399 if (rt->rt_flags & RTF_GATEWAY) { 400 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 401 /* 402 * Changing from route to net => route to host. 403 * Create new route, rather than smashing route to net. 404 */ 405 create: 406 if (rt) 407 rtfree(rt); 408 flags |= RTF_GATEWAY | RTF_DYNAMIC; 409 info.rti_info[RTAX_DST] = dst; 410 info.rti_info[RTAX_GATEWAY] = gateway; 411 info.rti_info[RTAX_NETMASK] = netmask; 412 info.rti_ifa = ifa; 413 info.rti_flags = flags; 414 rt = NULL; 415 error = rtrequest1(RTM_ADD, &info, &rt); 416 if (rt != NULL) 417 flags = rt->rt_flags; 418 stat = &rtstat.rts_dynamic; 419 } else { 420 /* 421 * Smash the current notion of the gateway to 422 * this destination. Should check about netmask!!! 423 */ 424 rt->rt_flags |= RTF_MODIFIED; 425 flags |= RTF_MODIFIED; 426 stat = &rtstat.rts_newgateway; 427 rt_setgate(rt, rt_key(rt), gateway); 428 } 429 } else 430 error = EHOSTUNREACH; 431 done: 432 if (rt) { 433 if (rtp && !error) 434 *rtp = rt; 435 else 436 rtfree(rt); 437 } 438 out: 439 if (error) 440 rtstat.rts_badredirect++; 441 else if (stat != NULL) 442 (*stat)++; 443 bzero((caddr_t)&info, sizeof(info)); 444 info.rti_info[RTAX_DST] = dst; 445 info.rti_info[RTAX_GATEWAY] = gateway; 446 info.rti_info[RTAX_NETMASK] = netmask; 447 info.rti_info[RTAX_AUTHOR] = src; 448 rt_missmsg(RTM_REDIRECT, &info, flags, error); 449 } 450 451 /* 452 * Routing table ioctl interface. 453 */ 454 int 455 rtioctl(req, data, p) 456 u_long req; 457 caddr_t data; 458 struct proc *p; 459 { 460 return (EOPNOTSUPP); 461 } 462 463 struct ifaddr * 464 ifa_ifwithroute(flags, dst, gateway) 465 int flags; 466 struct sockaddr *dst, *gateway; 467 { 468 register struct ifaddr *ifa; 469 470 #ifdef IPSEC 471 /* 472 * If the destination is a PF_KEY address, we'll look 473 * for the existence of a encap interface number or address 474 * in the options list of the gateway. By default, we'll return 475 * enc0. 476 */ 477 if (dst && (dst->sa_family == PF_KEY)) 478 return encap_findgwifa(gateway); 479 #endif 480 481 if ((flags & RTF_GATEWAY) == 0) { 482 /* 483 * If we are adding a route to an interface, 484 * and the interface is a pt to pt link 485 * we should search for the destination 486 * as our clue to the interface. Otherwise 487 * we can use the local address. 488 */ 489 ifa = NULL; 490 if (flags & RTF_HOST) 491 ifa = ifa_ifwithdstaddr(dst); 492 if (ifa == NULL) 493 ifa = ifa_ifwithaddr(gateway); 494 } else { 495 /* 496 * If we are adding a route to a remote net 497 * or host, the gateway may still be on the 498 * other end of a pt to pt link. 499 */ 500 ifa = ifa_ifwithdstaddr(gateway); 501 } 502 if (ifa == NULL) 503 ifa = ifa_ifwithnet(gateway); 504 if (ifa == NULL) { 505 struct rtentry *rt = rtalloc1(gateway, 0); 506 if (rt == NULL) 507 return (NULL); 508 rt->rt_refcnt--; 509 /* The gateway must be local if the same address family. */ 510 if ((rt->rt_flags & RTF_GATEWAY) && 511 rt_key(rt)->sa_family == dst->sa_family) 512 return (0); 513 if ((ifa = rt->rt_ifa) == NULL) 514 return (NULL); 515 } 516 if (ifa->ifa_addr->sa_family != dst->sa_family) { 517 struct ifaddr *oifa = ifa; 518 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 519 if (ifa == NULL) 520 ifa = oifa; 521 } 522 return (ifa); 523 } 524 525 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 526 527 int 528 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 529 int req, flags; 530 struct sockaddr *dst, *gateway, *netmask; 531 struct rtentry **ret_nrt; 532 { 533 struct rt_addrinfo info; 534 535 bzero(&info, sizeof(info)); 536 info.rti_flags = flags; 537 info.rti_info[RTAX_DST] = dst; 538 info.rti_info[RTAX_GATEWAY] = gateway; 539 info.rti_info[RTAX_NETMASK] = netmask; 540 return (rtrequest1(req, &info, ret_nrt)); 541 } 542 543 /* 544 * These (questionable) definitions of apparent local variables apply 545 * to the next function. XXXXXX!!! 546 */ 547 #define dst info->rti_info[RTAX_DST] 548 #define gateway info->rti_info[RTAX_GATEWAY] 549 #define netmask info->rti_info[RTAX_NETMASK] 550 #define ifaaddr info->rti_info[RTAX_IFA] 551 #define ifpaddr info->rti_info[RTAX_IFP] 552 #define flags info->rti_flags 553 554 int 555 rt_getifa(info) 556 struct rt_addrinfo *info; 557 { 558 struct ifaddr *ifa; 559 int error = 0; 560 561 /* 562 * ifp may be specified by sockaddr_dl when protocol address 563 * is ambiguous 564 */ 565 if (info->rti_ifp == NULL && ifpaddr != NULL 566 && ifpaddr->sa_family == AF_LINK && 567 (ifa = ifa_ifwithnet((struct sockaddr *)ifpaddr)) != NULL) 568 info->rti_ifp = ifa->ifa_ifp; 569 if (info->rti_ifa == NULL && ifaaddr != NULL) 570 info->rti_ifa = ifa_ifwithaddr(ifaaddr); 571 if (info->rti_ifa == NULL) { 572 struct sockaddr *sa; 573 574 sa = ifaaddr != NULL ? ifaaddr : 575 (gateway != NULL ? gateway : dst); 576 if (sa != NULL && info->rti_ifp != NULL) 577 info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 578 else if (dst != NULL && gateway != NULL) 579 info->rti_ifa = ifa_ifwithroute(flags, dst, gateway); 580 else if (sa != NULL) 581 info->rti_ifa = ifa_ifwithroute(flags, sa, sa); 582 } 583 if ((ifa = info->rti_ifa) != NULL) { 584 if (info->rti_ifp == NULL) 585 info->rti_ifp = ifa->ifa_ifp; 586 } else 587 error = ENETUNREACH; 588 return (error); 589 } 590 591 int 592 rtrequest1(req, info, ret_nrt) 593 int req; 594 struct rt_addrinfo *info; 595 struct rtentry **ret_nrt; 596 { 597 int s = splsoftnet(); int error = 0; 598 register struct rtentry *rt; 599 register struct radix_node *rn; 600 register struct radix_node_head *rnh; 601 struct ifaddr *ifa; 602 struct sockaddr *ndst; 603 #define senderr(x) { error = x ; goto bad; } 604 605 if ((rnh = rt_tables[dst->sa_family]) == 0) 606 senderr(EAFNOSUPPORT); 607 if (flags & RTF_HOST) 608 netmask = 0; 609 switch (req) { 610 case RTM_DELETE: 611 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL) 612 senderr(ESRCH); 613 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 614 panic ("rtrequest delete"); 615 rt = (struct rtentry *)rn; 616 if (rt->rt_gwroute) { 617 rt = rt->rt_gwroute; RTFREE(rt); 618 (rt = (struct rtentry *)rn)->rt_gwroute = NULL; 619 } 620 rt->rt_flags &= ~RTF_UP; 621 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 622 ifa->ifa_rtrequest(RTM_DELETE, rt, info); 623 rttrash++; 624 if (ret_nrt) 625 *ret_nrt = rt; 626 else if (rt->rt_refcnt <= 0) { 627 rt->rt_refcnt++; 628 rtfree(rt); 629 } 630 break; 631 632 case RTM_RESOLVE: 633 if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) 634 senderr(EINVAL); 635 ifa = rt->rt_ifa; 636 flags = rt->rt_flags & ~RTF_CLONING; 637 gateway = rt->rt_gateway; 638 if ((netmask = rt->rt_genmask) == NULL) 639 flags |= RTF_HOST; 640 goto makeroute; 641 642 case RTM_ADD: 643 if (info->rti_ifa == 0 && (error = rt_getifa(info))) 644 senderr(error); 645 ifa = info->rti_ifa; 646 makeroute: 647 R_Malloc(rt, struct rtentry *, sizeof(*rt)); 648 if (rt == NULL) 649 senderr(ENOBUFS); 650 Bzero(rt, sizeof(*rt)); 651 rt->rt_flags = RTF_UP | flags; 652 LIST_INIT(&rt->rt_timer); 653 if (rt_setgate(rt, dst, gateway)) { 654 Free(rt); 655 senderr(ENOBUFS); 656 } 657 ndst = rt_key(rt); 658 if (netmask) { 659 rt_maskedcopy(dst, ndst, netmask); 660 } else 661 Bcopy(dst, ndst, dst->sa_len); 662 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, 663 rnh, rt->rt_nodes); 664 if (rn == NULL) { 665 if (rt->rt_gwroute) 666 rtfree(rt->rt_gwroute); 667 Free(rt_key(rt)); 668 Free(rt); 669 senderr(EEXIST); 670 } 671 ifa->ifa_refcnt++; 672 rt->rt_ifa = ifa; 673 rt->rt_ifp = ifa->ifa_ifp; 674 if (req == RTM_RESOLVE) { 675 /* 676 * Copy both metrics and a back pointer to the cloned 677 * route's parent. 678 */ 679 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 680 rt->rt_parent = *ret_nrt; /* Back ptr. to parent. */ 681 } 682 if (ifa->ifa_rtrequest) 683 ifa->ifa_rtrequest(req, rt, info); 684 if (ret_nrt) { 685 *ret_nrt = rt; 686 rt->rt_refcnt++; 687 } 688 break; 689 } 690 bad: 691 splx(s); 692 return (error); 693 } 694 695 #undef dst 696 #undef gateway 697 #undef netmask 698 #undef ifaaddr 699 #undef ifpaddr 700 #undef flags 701 702 int 703 rt_setgate(rt0, dst, gate) 704 struct rtentry *rt0; 705 struct sockaddr *dst, *gate; 706 { 707 caddr_t new, old; 708 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); 709 register struct rtentry *rt = rt0; 710 711 if (rt->rt_gateway == NULL || glen > ROUNDUP(rt->rt_gateway->sa_len)) { 712 old = (caddr_t)rt_key(rt); 713 R_Malloc(new, caddr_t, dlen + glen); 714 if (new == NULL) 715 return 1; 716 rt->rt_nodes->rn_key = new; 717 } else { 718 new = rt->rt_nodes->rn_key; 719 old = NULL; 720 } 721 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); 722 if (old) { 723 Bcopy(dst, new, dlen); 724 Free(old); 725 } 726 if (rt->rt_gwroute != NULL) { 727 rt = rt->rt_gwroute; 728 RTFREE(rt); 729 rt = rt0; 730 rt->rt_gwroute = NULL; 731 } 732 if (rt->rt_flags & RTF_GATEWAY) { 733 rt->rt_gwroute = rtalloc1(gate, 1); 734 /* 735 * If we switched gateways, grab the MTU from the new 736 * gateway route if the current MTU is 0 or greater 737 * than the MTU of gateway. 738 * Note that, if the MTU of gateway is 0, we will reset the 739 * MTU of the route to run PMTUD again from scratch. XXX 740 */ 741 if (rt->rt_gwroute && !(rt->rt_rmx.rmx_locks & RTV_MTU) && 742 rt->rt_rmx.rmx_mtu && 743 rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) { 744 rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; 745 } 746 } 747 return (0); 748 } 749 750 void 751 rt_maskedcopy(src, dst, netmask) 752 struct sockaddr *src, *dst, *netmask; 753 { 754 register u_char *cp1 = (u_char *)src; 755 register u_char *cp2 = (u_char *)dst; 756 register u_char *cp3 = (u_char *)netmask; 757 u_char *cplim = cp2 + *cp3; 758 u_char *cplim2 = cp2 + *cp1; 759 760 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 761 cp3 += 2; 762 if (cplim > cplim2) 763 cplim = cplim2; 764 while (cp2 < cplim) 765 *cp2++ = *cp1++ & *cp3++; 766 if (cp2 < cplim2) 767 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 768 } 769 770 /* 771 * Set up a routing table entry, normally 772 * for an interface. 773 */ 774 int 775 rtinit(ifa, cmd, flags) 776 register struct ifaddr *ifa; 777 int cmd, flags; 778 { 779 register struct rtentry *rt; 780 register struct sockaddr *dst; 781 register struct sockaddr *deldst; 782 struct mbuf *m = NULL; 783 struct rtentry *nrt = NULL; 784 int error; 785 struct rt_addrinfo info; 786 787 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 788 if (cmd == RTM_DELETE) { 789 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 790 m = m_get(M_DONTWAIT, MT_SONAME); 791 if (m == NULL) 792 return (ENOBUFS); 793 deldst = mtod(m, struct sockaddr *); 794 rt_maskedcopy(dst, deldst, ifa->ifa_netmask); 795 dst = deldst; 796 } 797 if ((rt = rtalloc1(dst, 0)) != NULL) { 798 rt->rt_refcnt--; 799 if (rt->rt_ifa != ifa) { 800 if (m != NULL) 801 (void) m_free(m); 802 return (flags & RTF_HOST ? EHOSTUNREACH 803 : ENETUNREACH); 804 } 805 } 806 } 807 bzero(&info, sizeof(info)); 808 info.rti_ifa = ifa; 809 info.rti_flags = flags | ifa->ifa_flags; 810 info.rti_info[RTAX_DST] = dst; 811 info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 812 /* 813 * XXX here, it seems that we are assuming that ifa_netmask is NULL 814 * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate 815 * variable) when RTF_HOST is 1. still not sure if i can safely 816 * change it to meet bsdi4 behavior. 817 */ 818 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; 819 error = rtrequest1(cmd, &info, &nrt); 820 if (cmd == RTM_DELETE && error == 0 && (rt = nrt) != NULL) { 821 rt_newaddrmsg(cmd, ifa, error, nrt); 822 if (rt->rt_refcnt <= 0) { 823 rt->rt_refcnt++; 824 rtfree(rt); 825 } 826 } 827 if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) { 828 rt->rt_refcnt--; 829 if (rt->rt_ifa != ifa) { 830 printf("rtinit: wrong ifa (%p) was (%p)\n", 831 ifa, rt->rt_ifa); 832 if (rt->rt_ifa->ifa_rtrequest) 833 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); 834 IFAFREE(rt->rt_ifa); 835 rt->rt_ifa = ifa; 836 rt->rt_ifp = ifa->ifa_ifp; 837 ifa->ifa_refcnt++; 838 if (ifa->ifa_rtrequest) 839 ifa->ifa_rtrequest(RTM_ADD, rt, NULL); 840 } 841 rt_newaddrmsg(cmd, ifa, error, nrt); 842 } 843 return (error); 844 } 845 846 /* 847 * Route timer routines. These routes allow functions to be called 848 * for various routes at any time. This is useful in supporting 849 * path MTU discovery and redirect route deletion. 850 * 851 * This is similar to some BSDI internal functions, but it provides 852 * for multiple queues for efficiency's sake... 853 */ 854 855 LIST_HEAD(, rttimer_queue) rttimer_queue_head; 856 static int rt_init_done = 0; 857 858 #define RTTIMER_CALLOUT(r) { \ 859 if (r->rtt_func != NULL) { \ 860 (*r->rtt_func)(r->rtt_rt, r); \ 861 } else { \ 862 rtrequest((int) RTM_DELETE, \ 863 (struct sockaddr *)rt_key(r->rtt_rt), \ 864 0, 0, 0, 0); \ 865 } \ 866 } 867 868 /* 869 * Some subtle order problems with domain initialization mean that 870 * we cannot count on this being run from rt_init before various 871 * protocol initializations are done. Therefore, we make sure 872 * that this is run when the first queue is added... 873 */ 874 875 void 876 rt_timer_init() 877 { 878 static struct timeout rt_timer_timeout; 879 880 assert(rt_init_done == 0); 881 882 #if 0 883 pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", 884 NULL); 885 #endif 886 887 LIST_INIT(&rttimer_queue_head); 888 timeout_set(&rt_timer_timeout, rt_timer_timer, &rt_timer_timeout); 889 timeout_add(&rt_timer_timeout, hz); /* every second */ 890 rt_init_done = 1; 891 } 892 893 struct rttimer_queue * 894 rt_timer_queue_create(timeout) 895 u_int timeout; 896 { 897 struct rttimer_queue *rtq; 898 899 if (rt_init_done == 0) 900 rt_timer_init(); 901 902 R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); 903 if (rtq == NULL) 904 return (NULL); 905 Bzero(rtq, sizeof *rtq); 906 907 rtq->rtq_timeout = timeout; 908 rtq->rtq_count = 0; 909 TAILQ_INIT(&rtq->rtq_head); 910 LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); 911 912 return (rtq); 913 } 914 915 void 916 rt_timer_queue_change(rtq, timeout) 917 struct rttimer_queue *rtq; 918 long timeout; 919 { 920 921 rtq->rtq_timeout = timeout; 922 } 923 924 void 925 rt_timer_queue_destroy(rtq, destroy) 926 struct rttimer_queue *rtq; 927 int destroy; 928 { 929 struct rttimer *r; 930 931 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) { 932 LIST_REMOVE(r, rtt_link); 933 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 934 if (destroy) 935 RTTIMER_CALLOUT(r); 936 #if 0 937 pool_put(&rttimer_pool, r); 938 #else 939 free(r, M_RTABLE); 940 #endif 941 if (rtq->rtq_count > 0) 942 rtq->rtq_count--; 943 else 944 printf("rt_timer_queue_destroy: rtq_count reached 0\n"); 945 } 946 947 LIST_REMOVE(rtq, rtq_link); 948 949 /* 950 * Caller is responsible for freeing the rttimer_queue structure. 951 */ 952 } 953 954 unsigned long 955 rt_timer_count(rtq) 956 struct rttimer_queue *rtq; 957 { 958 959 return (rtq->rtq_count); 960 } 961 962 void 963 rt_timer_remove_all(rt) 964 struct rtentry *rt; 965 { 966 struct rttimer *r; 967 968 while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) { 969 LIST_REMOVE(r, rtt_link); 970 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 971 if (r->rtt_queue->rtq_count > 0) 972 r->rtt_queue->rtq_count--; 973 else 974 printf("rt_timer_remove_all: rtq_count reached 0\n"); 975 #if 0 976 pool_put(&rttimer_pool, r); 977 #else 978 free(r, M_RTABLE); 979 #endif 980 } 981 } 982 983 int 984 rt_timer_add(rt, func, queue) 985 struct rtentry *rt; 986 void(*func)(struct rtentry *, struct rttimer *); 987 struct rttimer_queue *queue; 988 { 989 struct rttimer *r; 990 long current_time; 991 992 current_time = mono_time.tv_sec; 993 994 /* 995 * If there's already a timer with this action, destroy it before 996 * we add a new one. 997 */ 998 for (r = LIST_FIRST(&rt->rt_timer); r != NULL; 999 r = LIST_NEXT(r, rtt_link)) { 1000 if (r->rtt_func == func) { 1001 LIST_REMOVE(r, rtt_link); 1002 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); 1003 if (r->rtt_queue->rtq_count > 0) 1004 r->rtt_queue->rtq_count--; 1005 else 1006 printf("rt_timer_add: rtq_count reached 0\n"); 1007 #if 0 1008 pool_put(&rttimer_pool, r); 1009 #else 1010 free(r, M_RTABLE); 1011 #endif 1012 break; /* only one per list, so we can quit... */ 1013 } 1014 } 1015 1016 #if 0 1017 r = pool_get(&rttimer_pool, PR_NOWAIT); 1018 #else 1019 r = (struct rttimer *)malloc(sizeof(*r), M_RTABLE, M_NOWAIT); 1020 #endif 1021 if (r == NULL) 1022 return (ENOBUFS); 1023 Bzero(r, sizeof(*r)); 1024 1025 r->rtt_rt = rt; 1026 r->rtt_time = current_time; 1027 r->rtt_func = func; 1028 r->rtt_queue = queue; 1029 LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); 1030 TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); 1031 r->rtt_queue->rtq_count++; 1032 1033 return (0); 1034 } 1035 1036 /* ARGSUSED */ 1037 void 1038 rt_timer_timer(arg) 1039 void *arg; 1040 { 1041 struct timeout *to = (struct timeout *)arg; 1042 struct rttimer_queue *rtq; 1043 struct rttimer *r; 1044 long current_time; 1045 int s; 1046 1047 current_time = mono_time.tv_sec; 1048 1049 s = splsoftnet(); 1050 for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL; 1051 rtq = LIST_NEXT(rtq, rtq_link)) { 1052 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && 1053 (r->rtt_time + rtq->rtq_timeout) < current_time) { 1054 LIST_REMOVE(r, rtt_link); 1055 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); 1056 RTTIMER_CALLOUT(r); 1057 #if 0 1058 pool_put(&rttimer_pool, r); 1059 #else 1060 free(r, M_RTABLE); 1061 #endif 1062 if (rtq->rtq_count > 0) 1063 rtq->rtq_count--; 1064 else 1065 printf("rt_timer_timer: rtq_count reached 0\n"); 1066 } 1067 } 1068 splx(s); 1069 1070 timeout_add(to, hz); /* every second */ 1071 } 1072