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