[BACK]Return to route.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net

Annotation of src/sys/net/route.c, Revision 1.56

1.56    ! darrenr     1: /*     $NetBSD: route.c,v 1.55 2002/11/12 02:10:13 itojun Exp $        */
1.18      kml         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:  */
1.11      cgd        39:
1.1       cgd        40: /*
1.25      itojun     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: /*
1.10      mycroft    70:  * Copyright (c) 1980, 1986, 1991, 1993
                     71:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        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:  *
1.17      christos  101:  *     @(#)route.c     8.3 (Berkeley) 1/9/95
1.1       cgd       102:  */
1.50      lukem     103:
                    104: #include <sys/cdefs.h>
1.56    ! darrenr   105: __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.55 2002/11/12 02:10:13 itojun Exp $");
1.19      jonathan  106:
                    107: #include "opt_ns.h"
1.2       cgd       108:
1.5       mycroft   109: #include <sys/param.h>
                    110: #include <sys/systm.h>
1.35      thorpej   111: #include <sys/callout.h>
1.5       mycroft   112: #include <sys/proc.h>
                    113: #include <sys/mbuf.h>
                    114: #include <sys/socket.h>
                    115: #include <sys/socketvar.h>
                    116: #include <sys/domain.h>
                    117: #include <sys/protosw.h>
1.18      kml       118: #include <sys/kernel.h>
1.5       mycroft   119: #include <sys/ioctl.h>
1.22      thorpej   120: #include <sys/pool.h>
1.1       cgd       121:
1.5       mycroft   122: #include <net/if.h>
                    123: #include <net/route.h>
                    124: #include <net/raw_cb.h>
1.1       cgd       125:
1.5       mycroft   126: #include <netinet/in.h>
                    127: #include <netinet/in_var.h>
1.1       cgd       128:
                    129: #ifdef NS
1.5       mycroft   130: #include <netns/ns.h>
1.1       cgd       131: #endif
1.5       mycroft   132:
1.1       cgd       133: #define        SA(p) ((struct sockaddr *)(p))
1.52      matt      134:
                    135: struct route_cb route_cb;
                    136: struct rtstat  rtstat;
                    137: struct radix_node_head *rt_tables[AF_MAX+1];
1.1       cgd       138:
                    139: int    rttrash;                /* routes not in table but not freed */
                    140: struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
                    141:
1.22      thorpej   142: struct pool rtentry_pool;      /* pool for rtentry structures */
                    143: struct pool rttimer_pool;      /* pool for rttimer structures */
                    144:
1.35      thorpej   145: struct callout rt_timer_ch; /* callout for rt_timer_timer() */
                    146:
1.40      itojun    147: static int rtdeletemsg __P((struct rtentry *));
1.42      itojun    148: static int rtflushclone1 __P((struct radix_node *, void *));
1.41      itojun    149: static void rtflushclone __P((struct radix_node_head *, struct rtentry *));
1.40      itojun    150:
1.10      mycroft   151: void
                    152: rtable_init(table)
                    153:        void **table;
                    154: {
                    155:        struct domain *dom;
                    156:        for (dom = domains; dom; dom = dom->dom_next)
                    157:                if (dom->dom_rtattach)
                    158:                        dom->dom_rtattach(&table[dom->dom_family],
                    159:                            dom->dom_rtoffset);
                    160: }
1.1       cgd       161:
1.9       mycroft   162: void
1.10      mycroft   163: route_init()
1.1       cgd       164: {
1.22      thorpej   165:
                    166:        pool_init(&rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl",
1.51      thorpej   167:            NULL);
1.22      thorpej   168:
1.10      mycroft   169:        rn_init();      /* initialize all zeroes, all ones, mask table */
                    170:        rtable_init((void **)rt_tables);
1.1       cgd       171: }
                    172:
                    173: /*
                    174:  * Packet routing routines.
                    175:  */
1.9       mycroft   176: void
1.1       cgd       177: rtalloc(ro)
1.36      augustss  178:        struct route *ro;
1.1       cgd       179: {
                    180:        if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
                    181:                return;                          /* XXX */
                    182:        ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
                    183: }
1.25      itojun    184:
1.1       cgd       185: struct rtentry *
                    186: rtalloc1(dst, report)
1.36      augustss  187:        struct sockaddr *dst;
1.10      mycroft   188:        int report;
1.1       cgd       189: {
1.36      augustss  190:        struct radix_node_head *rnh = rt_tables[dst->sa_family];
                    191:        struct rtentry *rt;
                    192:        struct radix_node *rn;
1.1       cgd       193:        struct rtentry *newrt = 0;
1.10      mycroft   194:        struct rt_addrinfo info;
1.13      mycroft   195:        int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
1.1       cgd       196:
1.10      mycroft   197:        if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
1.1       cgd       198:            ((rn->rn_flags & RNF_ROOT) == 0)) {
                    199:                newrt = rt = (struct rtentry *)rn;
                    200:                if (report && (rt->rt_flags & RTF_CLONING)) {
1.8       cgd       201:                        err = rtrequest(RTM_RESOLVE, dst, SA(0),
1.10      mycroft   202:                                              SA(0), 0, &newrt);
1.8       cgd       203:                        if (err) {
                    204:                                newrt = rt;
                    205:                                rt->rt_refcnt++;
                    206:                                goto miss;
                    207:                        }
                    208:                        if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
                    209:                                msgtype = RTM_RESOLVE;
                    210:                                goto miss;
                    211:                        }
1.39      itojun    212:                        /* Inform listeners of the new route */
1.44      thorpej   213:                        memset(&info, 0, sizeof(info));
1.39      itojun    214:                        info.rti_info[RTAX_DST] = rt_key(rt);
                    215:                        info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    216:                        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    217:                        if (rt->rt_ifp != NULL) {
                    218:                                info.rti_info[RTAX_IFP] =
1.49      matt      219:                                    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
1.39      itojun    220:                                info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
                    221:                        }
                    222:                        rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0);
1.1       cgd       223:                } else
                    224:                        rt->rt_refcnt++;
                    225:        } else {
                    226:                rtstat.rts_unreach++;
1.10      mycroft   227:        miss:   if (report) {
1.44      thorpej   228:                        memset((caddr_t)&info, 0, sizeof(info));
1.10      mycroft   229:                        info.rti_info[RTAX_DST] = dst;
                    230:                        rt_missmsg(msgtype, &info, 0, err);
                    231:                }
1.1       cgd       232:        }
                    233:        splx(s);
                    234:        return (newrt);
                    235: }
                    236:
1.9       mycroft   237: void
1.1       cgd       238: rtfree(rt)
1.36      augustss  239:        struct rtentry *rt;
1.1       cgd       240: {
1.36      augustss  241:        struct ifaddr *ifa;
1.10      mycroft   242:
1.1       cgd       243:        if (rt == 0)
                    244:                panic("rtfree");
                    245:        rt->rt_refcnt--;
                    246:        if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
                    247:                if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                    248:                        panic ("rtfree 2");
1.10      mycroft   249:                rttrash--;
                    250:                if (rt->rt_refcnt < 0) {
1.16      christos  251:                        printf("rtfree: %p not freed (neg refs)\n", rt);
1.10      mycroft   252:                        return;
                    253:                }
1.54      itojun    254:                rt_timer_remove_all(rt, 0);
1.10      mycroft   255:                ifa = rt->rt_ifa;
                    256:                IFAFREE(ifa);
                    257:                Free(rt_key(rt));
1.22      thorpej   258:                pool_put(&rtentry_pool, rt);
1.1       cgd       259:        }
                    260: }
                    261:
1.10      mycroft   262: void
                    263: ifafree(ifa)
1.36      augustss  264:        struct ifaddr *ifa;
1.10      mycroft   265: {
1.30      thorpej   266:
                    267: #ifdef DIAGNOSTIC
1.10      mycroft   268:        if (ifa == NULL)
1.30      thorpej   269:                panic("ifafree: null ifa");
                    270:        if (ifa->ifa_refcnt != 0)
                    271:                panic("ifafree: ifa_refcnt != 0 (%d)", ifa->ifa_refcnt);
                    272: #endif
1.31      thorpej   273: #ifdef IFAREF_DEBUG
                    274:        printf("ifafree: freeing ifaddr %p\n", ifa);
                    275: #endif
1.30      thorpej   276:        free(ifa, M_IFADDR);
1.10      mycroft   277: }
                    278:
1.1       cgd       279: /*
                    280:  * Force a routing table entry to the specified
                    281:  * destination to go through the given gateway.
                    282:  * Normally called as a result of a routing redirect
                    283:  * message from the network layer.
                    284:  *
1.13      mycroft   285:  * N.B.: must be called at splsoftnet
1.1       cgd       286:  */
1.14      christos  287: void
1.1       cgd       288: rtredirect(dst, gateway, netmask, flags, src, rtp)
                    289:        struct sockaddr *dst, *gateway, *netmask, *src;
                    290:        int flags;
                    291:        struct rtentry **rtp;
                    292: {
1.36      augustss  293:        struct rtentry *rt;
1.1       cgd       294:        int error = 0;
1.43      itojun    295:        u_quad_t *stat = 0;
1.10      mycroft   296:        struct rt_addrinfo info;
                    297:        struct ifaddr *ifa;
1.1       cgd       298:
                    299:        /* verify the gateway is directly reachable */
1.10      mycroft   300:        if ((ifa = ifa_ifwithnet(gateway)) == 0) {
1.1       cgd       301:                error = ENETUNREACH;
1.8       cgd       302:                goto out;
1.1       cgd       303:        }
                    304:        rt = rtalloc1(dst, 0);
                    305:        /*
                    306:         * If the redirect isn't from our current router for this dst,
                    307:         * it's either old or wrong.  If it redirects us to ourselves,
                    308:         * we have a routing loop, perhaps as a result of an interface
                    309:         * going down recently.
                    310:         */
1.45      itojun    311: #define        equal(a1, a2) \
                    312:        ((a1)->sa_len == (a2)->sa_len && \
                    313:         bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
1.10      mycroft   314:        if (!(flags & RTF_DONE) && rt &&
                    315:             (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
1.1       cgd       316:                error = EINVAL;
                    317:        else if (ifa_ifwithaddr(gateway))
                    318:                error = EHOSTUNREACH;
                    319:        if (error)
                    320:                goto done;
                    321:        /*
                    322:         * Create a new entry if we just got back a wildcard entry
1.33      soren     323:         * or the lookup failed.  This is necessary for hosts
1.1       cgd       324:         * which use routing redirects generated by smart gateways
                    325:         * to dynamically build the routing tables.
                    326:         */
                    327:        if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
                    328:                goto create;
                    329:        /*
                    330:         * Don't listen to the redirect if it's
                    331:         * for a route to an interface.
                    332:         */
                    333:        if (rt->rt_flags & RTF_GATEWAY) {
                    334:                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
                    335:                        /*
                    336:                         * Changing from route to net => route to host.
                    337:                         * Create new route, rather than smashing route to net.
                    338:                         */
                    339:                create:
1.39      itojun    340:                        if (rt)
                    341:                                rtfree(rt);
1.1       cgd       342:                        flags |=  RTF_GATEWAY | RTF_DYNAMIC;
1.39      itojun    343:                        info.rti_info[RTAX_DST] = dst;
                    344:                        info.rti_info[RTAX_GATEWAY] = gateway;
                    345:                        info.rti_info[RTAX_NETMASK] = netmask;
                    346:                        info.rti_ifa = ifa;
                    347:                        info.rti_flags = flags;
                    348:                        rt = NULL;
                    349:                        error = rtrequest1(RTM_ADD, &info, &rt);
                    350:                        if (rt != NULL)
                    351:                                flags = rt->rt_flags;
1.1       cgd       352:                        stat = &rtstat.rts_dynamic;
                    353:                } else {
                    354:                        /*
                    355:                         * Smash the current notion of the gateway to
                    356:                         * this destination.  Should check about netmask!!!
                    357:                         */
1.10      mycroft   358:                        rt->rt_flags |= RTF_MODIFIED;
                    359:                        flags |= RTF_MODIFIED;
                    360:                        stat = &rtstat.rts_newgateway;
                    361:                        rt_setgate(rt, rt_key(rt), gateway);
1.1       cgd       362:                }
                    363:        } else
                    364:                error = EHOSTUNREACH;
                    365: done:
                    366:        if (rt) {
                    367:                if (rtp && !error)
                    368:                        *rtp = rt;
                    369:                else
                    370:                        rtfree(rt);
                    371:        }
1.8       cgd       372: out:
1.1       cgd       373:        if (error)
                    374:                rtstat.rts_badredirect++;
1.8       cgd       375:        else if (stat != NULL)
                    376:                (*stat)++;
1.44      thorpej   377:        memset((caddr_t)&info, 0, sizeof(info));
1.10      mycroft   378:        info.rti_info[RTAX_DST] = dst;
                    379:        info.rti_info[RTAX_GATEWAY] = gateway;
                    380:        info.rti_info[RTAX_NETMASK] = netmask;
                    381:        info.rti_info[RTAX_AUTHOR] = src;
                    382:        rt_missmsg(RTM_REDIRECT, &info, flags, error);
1.1       cgd       383: }
                    384:
                    385: /*
1.40      itojun    386:  * Delete a route and generate a message
                    387:  */
                    388: static int
                    389: rtdeletemsg(rt)
                    390:        struct rtentry *rt;
                    391: {
                    392:        int error;
                    393:        struct rt_addrinfo info;
                    394:
                    395:        /*
                    396:         * Request the new route so that the entry is not actually
                    397:         * deleted.  That will allow the information being reported to
                    398:         * be accurate (and consistent with route_output()).
                    399:         */
1.44      thorpej   400:        memset((caddr_t)&info, 0, sizeof(info));
1.40      itojun    401:        info.rti_info[RTAX_DST] = rt_key(rt);
                    402:        info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    403:        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    404:        info.rti_flags = rt->rt_flags;
                    405:        error = rtrequest1(RTM_DELETE, &info, &rt);
                    406:
                    407:        rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
                    408:
                    409:        /* Adjust the refcount */
                    410:        if (error == 0 && rt->rt_refcnt <= 0) {
                    411:                rt->rt_refcnt++;
                    412:                rtfree(rt);
                    413:        }
                    414:        return (error);
                    415: }
                    416:
1.41      itojun    417: static int
1.42      itojun    418: rtflushclone1(rn, arg)
1.41      itojun    419:        struct radix_node *rn;
                    420:        void *arg;
                    421: {
                    422:        struct rtentry *rt, *parent;
                    423:
                    424:        rt = (struct rtentry *)rn;
                    425:        parent = (struct rtentry *)arg;
                    426:        if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
                    427:                rtdeletemsg(rt);
                    428:        return 0;
                    429: }
                    430:
                    431: static void
                    432: rtflushclone(rnh, parent)
                    433:        struct radix_node_head *rnh;
                    434:        struct rtentry *parent;
                    435: {
                    436:
                    437: #ifdef DIAGNOSTIC
                    438:        if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
                    439:                panic("rtflushclone: called with a non-cloning route");
                    440:        if (!rnh->rnh_walktree)
                    441:                panic("rtflushclone: no rnh_walktree");
                    442: #endif
1.42      itojun    443:        rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent);
1.41      itojun    444: }
                    445:
1.40      itojun    446: /*
1.22      thorpej   447:  * Routing table ioctl interface.
                    448:  */
1.9       mycroft   449: int
1.56    ! darrenr   450: rtioctl(req, data, l)
1.12      cgd       451:        u_long req;
1.1       cgd       452:        caddr_t data;
1.56    ! darrenr   453:        struct lwp *l;
1.1       cgd       454: {
                    455:        return (EOPNOTSUPP);
                    456: }
                    457:
                    458: struct ifaddr *
                    459: ifa_ifwithroute(flags, dst, gateway)
1.10      mycroft   460:        int flags;
                    461:        struct sockaddr *dst, *gateway;
1.1       cgd       462: {
1.36      augustss  463:        struct ifaddr *ifa;
1.1       cgd       464:        if ((flags & RTF_GATEWAY) == 0) {
                    465:                /*
                    466:                 * If we are adding a route to an interface,
                    467:                 * and the interface is a pt to pt link
                    468:                 * we should search for the destination
                    469:                 * as our clue to the interface.  Otherwise
                    470:                 * we can use the local address.
                    471:                 */
                    472:                ifa = 0;
                    473:                if (flags & RTF_HOST)
                    474:                        ifa = ifa_ifwithdstaddr(dst);
                    475:                if (ifa == 0)
                    476:                        ifa = ifa_ifwithaddr(gateway);
                    477:        } else {
                    478:                /*
                    479:                 * If we are adding a route to a remote net
                    480:                 * or host, the gateway may still be on the
                    481:                 * other end of a pt to pt link.
                    482:                 */
                    483:                ifa = ifa_ifwithdstaddr(gateway);
                    484:        }
                    485:        if (ifa == 0)
                    486:                ifa = ifa_ifwithnet(gateway);
                    487:        if (ifa == 0) {
                    488:                struct rtentry *rt = rtalloc1(dst, 0);
                    489:                if (rt == 0)
                    490:                        return (0);
                    491:                rt->rt_refcnt--;
                    492:                if ((ifa = rt->rt_ifa) == 0)
                    493:                        return (0);
                    494:        }
                    495:        if (ifa->ifa_addr->sa_family != dst->sa_family) {
1.10      mycroft   496:                struct ifaddr *oifa = ifa;
1.1       cgd       497:                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
                    498:                if (ifa == 0)
                    499:                        ifa = oifa;
                    500:        }
                    501:        return (ifa);
                    502: }
                    503:
                    504: #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
                    505:
1.9       mycroft   506: int
1.1       cgd       507: rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
                    508:        int req, flags;
                    509:        struct sockaddr *dst, *gateway, *netmask;
                    510:        struct rtentry **ret_nrt;
                    511: {
1.39      itojun    512:        struct rt_addrinfo info;
                    513:
1.44      thorpej   514:        memset(&info, 0, sizeof(info));
1.39      itojun    515:        info.rti_flags = flags;
                    516:        info.rti_info[RTAX_DST] = dst;
                    517:        info.rti_info[RTAX_GATEWAY] = gateway;
                    518:        info.rti_info[RTAX_NETMASK] = netmask;
                    519:        return rtrequest1(req, &info, ret_nrt);
                    520: }
                    521:
                    522: /*
                    523:  * These (questionable) definitions of apparent local variables apply
                    524:  * to the next function.  XXXXXX!!!
                    525:  */
                    526: #define dst    info->rti_info[RTAX_DST]
                    527: #define gateway        info->rti_info[RTAX_GATEWAY]
                    528: #define netmask        info->rti_info[RTAX_NETMASK]
                    529: #define ifaaddr        info->rti_info[RTAX_IFA]
                    530: #define ifpaddr        info->rti_info[RTAX_IFP]
                    531: #define flags  info->rti_flags
                    532:
                    533: int
                    534: rt_getifa(info)
                    535:        struct rt_addrinfo *info;
                    536: {
                    537:        struct ifaddr *ifa;
                    538:        int error = 0;
                    539:
                    540:        /*
                    541:         * ifp may be specified by sockaddr_dl when protocol address
                    542:         * is ambiguous
                    543:         */
                    544:        if (info->rti_ifp == NULL && ifpaddr != NULL
                    545:            && ifpaddr->sa_family == AF_LINK &&
                    546:            (ifa = ifa_ifwithnet((struct sockaddr *)ifpaddr)) != NULL)
                    547:                info->rti_ifp = ifa->ifa_ifp;
                    548:        if (info->rti_ifa == NULL && ifaaddr != NULL)
                    549:                info->rti_ifa = ifa_ifwithaddr(ifaaddr);
                    550:        if (info->rti_ifa == NULL) {
                    551:                struct sockaddr *sa;
                    552:
                    553:                sa = ifaaddr != NULL ? ifaaddr :
                    554:                    (gateway != NULL ? gateway : dst);
                    555:                if (sa != NULL && info->rti_ifp != NULL)
                    556:                        info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
                    557:                else if (dst != NULL && gateway != NULL)
                    558:                        info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
                    559:                else if (sa != NULL)
                    560:                        info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
                    561:        }
                    562:        if ((ifa = info->rti_ifa) != NULL) {
                    563:                if (info->rti_ifp == NULL)
                    564:                        info->rti_ifp = ifa->ifa_ifp;
                    565:        } else
                    566:                error = ENETUNREACH;
                    567:        return (error);
                    568: }
                    569:
                    570: int
                    571: rtrequest1(req, info, ret_nrt)
                    572:        int req;
                    573:        struct rt_addrinfo *info;
                    574:        struct rtentry **ret_nrt;
                    575: {
1.13      mycroft   576:        int s = splsoftnet(); int error = 0;
1.40      itojun    577:        struct rtentry *rt, *crt;
1.36      augustss  578:        struct radix_node *rn;
                    579:        struct radix_node_head *rnh;
1.10      mycroft   580:        struct ifaddr *ifa;
1.1       cgd       581:        struct sockaddr *ndst;
                    582: #define senderr(x) { error = x ; goto bad; }
                    583:
1.10      mycroft   584:        if ((rnh = rt_tables[dst->sa_family]) == 0)
1.1       cgd       585:                senderr(ESRCH);
                    586:        if (flags & RTF_HOST)
                    587:                netmask = 0;
                    588:        switch (req) {
                    589:        case RTM_DELETE:
1.41      itojun    590:                if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == 0)
                    591:                        senderr(ESRCH);
                    592:                rt = (struct rtentry *)rn;
                    593:                if ((rt->rt_flags & RTF_CLONING) != 0) {
                    594:                        /* clean up any cloned children */
                    595:                        rtflushclone(rnh, rt);
                    596:                }
1.10      mycroft   597:                if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
1.1       cgd       598:                        senderr(ESRCH);
                    599:                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                    600:                        panic ("rtrequest delete");
                    601:                rt = (struct rtentry *)rn;
1.10      mycroft   602:                if (rt->rt_gwroute) {
                    603:                        rt = rt->rt_gwroute; RTFREE(rt);
                    604:                        (rt = (struct rtentry *)rn)->rt_gwroute = 0;
1.48      itojun    605:                }
                    606:                if (rt->rt_parent) {
                    607:                        rt->rt_parent->rt_refcnt--;
                    608:                        rt->rt_parent = NULL;
1.10      mycroft   609:                }
1.28      erh       610:                rt->rt_flags &= ~RTF_UP;
1.1       cgd       611:                if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
1.39      itojun    612:                        ifa->ifa_rtrequest(RTM_DELETE, rt, info);
1.1       cgd       613:                rttrash++;
1.10      mycroft   614:                if (ret_nrt)
                    615:                        *ret_nrt = rt;
                    616:                else if (rt->rt_refcnt <= 0) {
                    617:                        rt->rt_refcnt++;
1.1       cgd       618:                        rtfree(rt);
1.10      mycroft   619:                }
1.1       cgd       620:                break;
                    621:
                    622:        case RTM_RESOLVE:
                    623:                if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
                    624:                        senderr(EINVAL);
1.40      itojun    625:                if ((rt->rt_flags & RTF_CLONING) == 0)
                    626:                        senderr(EINVAL);
1.1       cgd       627:                ifa = rt->rt_ifa;
1.40      itojun    628:                flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
                    629:                flags |= RTF_CLONED;
1.1       cgd       630:                gateway = rt->rt_gateway;
                    631:                if ((netmask = rt->rt_genmask) == 0)
                    632:                        flags |= RTF_HOST;
                    633:                goto makeroute;
                    634:
                    635:        case RTM_ADD:
1.39      itojun    636:                if (info->rti_ifa == 0 && (error = rt_getifa(info)))
                    637:                        senderr(error);
                    638:                ifa = info->rti_ifa;
1.1       cgd       639:        makeroute:
1.22      thorpej   640:                rt = pool_get(&rtentry_pool, PR_NOWAIT);
1.1       cgd       641:                if (rt == 0)
                    642:                        senderr(ENOBUFS);
1.10      mycroft   643:                Bzero(rt, sizeof(*rt));
                    644:                rt->rt_flags = RTF_UP | flags;
1.18      kml       645:                LIST_INIT(&rt->rt_timer);
1.10      mycroft   646:                if (rt_setgate(rt, dst, gateway)) {
1.22      thorpej   647:                        pool_put(&rtentry_pool, rt);
1.10      mycroft   648:                        senderr(ENOBUFS);
                    649:                }
                    650:                ndst = rt_key(rt);
1.1       cgd       651:                if (netmask) {
                    652:                        rt_maskedcopy(dst, ndst, netmask);
                    653:                } else
                    654:                        Bcopy(dst, ndst, dst->sa_len);
1.30      thorpej   655:                IFAREF(ifa);
1.1       cgd       656:                rt->rt_ifa = ifa;
                    657:                rt->rt_ifp = ifa->ifa_ifp;
1.27      matt      658:                if (req == RTM_RESOLVE) {
1.1       cgd       659:                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
1.41      itojun    660:                        rt->rt_parent = *ret_nrt;
                    661:                        rt->rt_parent->rt_refcnt++;
1.40      itojun    662:                }
                    663:                rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
                    664:                    rnh, rt->rt_nodes);
                    665:                if (rn == NULL && (crt = rtalloc1(ndst, 0)) != NULL) {
                    666:                        /* overwrite cloned route */
                    667:                        if ((crt->rt_flags & RTF_CLONED) != 0) {
                    668:                                rtdeletemsg(crt);
                    669:                                rn = rnh->rnh_addaddr((caddr_t)ndst,
                    670:                                    (caddr_t)netmask, rnh, rt->rt_nodes);
                    671:                        }
                    672:                        RTFREE(crt);
                    673:                }
                    674:                if (rn == 0) {
                    675:                        IFAFREE(ifa);
1.41      itojun    676:                        if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
                    677:                                rtfree(rt->rt_parent);
1.40      itojun    678:                        if (rt->rt_gwroute)
                    679:                                rtfree(rt->rt_gwroute);
                    680:                        Free(rt_key(rt));
                    681:                        pool_put(&rtentry_pool, rt);
                    682:                        senderr(EEXIST);
1.27      matt      683:                }
1.1       cgd       684:                if (ifa->ifa_rtrequest)
1.39      itojun    685:                        ifa->ifa_rtrequest(req, rt, info);
1.1       cgd       686:                if (ret_nrt) {
                    687:                        *ret_nrt = rt;
                    688:                        rt->rt_refcnt++;
1.41      itojun    689:                }
                    690:                if ((rt->rt_flags & RTF_CLONING) != 0) {
                    691:                        /* clean up any cloned children */
                    692:                        rtflushclone(rnh, rt);
1.1       cgd       693:                }
                    694:                break;
                    695:        }
                    696: bad:
                    697:        splx(s);
                    698:        return (error);
                    699: }
                    700:
1.39      itojun    701: #undef dst
                    702: #undef gateway
                    703: #undef netmask
                    704: #undef ifaaddr
                    705: #undef ifpaddr
                    706: #undef flags
                    707:
1.10      mycroft   708: int
                    709: rt_setgate(rt0, dst, gate)
                    710:        struct rtentry *rt0;
                    711:        struct sockaddr *dst, *gate;
                    712: {
                    713:        caddr_t new, old;
1.53      thorpej   714:        u_int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
1.36      augustss  715:        struct rtentry *rt = rt0;
1.10      mycroft   716:
                    717:        if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
                    718:                old = (caddr_t)rt_key(rt);
                    719:                R_Malloc(new, caddr_t, dlen + glen);
                    720:                if (new == 0)
                    721:                        return 1;
1.32      itojun    722:                Bzero(new, dlen + glen);
1.10      mycroft   723:                rt->rt_nodes->rn_key = new;
                    724:        } else {
                    725:                new = rt->rt_nodes->rn_key;
                    726:                old = 0;
                    727:        }
                    728:        Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
                    729:        if (old) {
                    730:                Bcopy(dst, new, dlen);
                    731:                Free(old);
                    732:        }
                    733:        if (rt->rt_gwroute) {
                    734:                rt = rt->rt_gwroute; RTFREE(rt);
                    735:                rt = rt0; rt->rt_gwroute = 0;
                    736:        }
                    737:        if (rt->rt_flags & RTF_GATEWAY) {
                    738:                rt->rt_gwroute = rtalloc1(gate, 1);
1.27      matt      739:                /*
                    740:                 * If we switched gateways, grab the MTU from the new
1.47      itojun    741:                 * gateway route if the current MTU, if the current MTU is
                    742:                 * greater than the MTU of gateway.
                    743:                 * Note that, if the MTU of gateway is 0, we will reset the
                    744:                 * MTU of the route to run PMTUD again from scratch. XXX
1.27      matt      745:                 */
                    746:                if (rt->rt_gwroute
                    747:                    && !(rt->rt_rmx.rmx_locks & RTV_MTU)
1.47      itojun    748:                    && rt->rt_rmx.rmx_mtu
                    749:                    && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
1.27      matt      750:                        rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
                    751:                }
1.10      mycroft   752:        }
                    753:        return 0;
                    754: }
                    755:
1.9       mycroft   756: void
1.1       cgd       757: rt_maskedcopy(src, dst, netmask)
1.9       mycroft   758:        struct sockaddr *src, *dst, *netmask;
1.1       cgd       759: {
1.36      augustss  760:        u_char *cp1 = (u_char *)src;
                    761:        u_char *cp2 = (u_char *)dst;
                    762:        u_char *cp3 = (u_char *)netmask;
1.1       cgd       763:        u_char *cplim = cp2 + *cp3;
                    764:        u_char *cplim2 = cp2 + *cp1;
                    765:
                    766:        *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
                    767:        cp3 += 2;
                    768:        if (cplim > cplim2)
                    769:                cplim = cplim2;
                    770:        while (cp2 < cplim)
                    771:                *cp2++ = *cp1++ & *cp3++;
                    772:        if (cp2 < cplim2)
1.44      thorpej   773:                memset((caddr_t)cp2, 0, (unsigned)(cplim2 - cp2));
1.1       cgd       774: }
1.10      mycroft   775:
1.1       cgd       776: /*
1.29      sommerfe  777:  * Set up or tear down a routing table entry, normally
1.1       cgd       778:  * for an interface.
                    779:  */
1.9       mycroft   780: int
1.1       cgd       781: rtinit(ifa, cmd, flags)
1.36      augustss  782:        struct ifaddr *ifa;
1.1       cgd       783:        int cmd, flags;
                    784: {
1.36      augustss  785:        struct rtentry *rt;
                    786:        struct sockaddr *dst, *odst;
1.29      sommerfe  787:        struct sockaddr_storage deldst;
1.10      mycroft   788:        struct rtentry *nrt = 0;
1.1       cgd       789:        int error;
1.39      itojun    790:        struct rt_addrinfo info;
1.1       cgd       791:
                    792:        dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
                    793:        if (cmd == RTM_DELETE) {
                    794:                if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1.29      sommerfe  795:                        /* Delete subnet route for this interface */
                    796:                        odst = dst;
                    797:                        dst = (struct sockaddr *)&deldst;
                    798:                        rt_maskedcopy(odst, dst, ifa->ifa_netmask);
1.1       cgd       799:                }
1.14      christos  800:                if ((rt = rtalloc1(dst, 0)) != NULL) {
1.1       cgd       801:                        rt->rt_refcnt--;
1.29      sommerfe  802:                        if (rt->rt_ifa != ifa)
1.1       cgd       803:                                return (flags & RTF_HOST ? EHOSTUNREACH
                    804:                                                        : ENETUNREACH);
                    805:                }
                    806:        }
1.44      thorpej   807:        memset(&info, 0, sizeof(info));
1.39      itojun    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);
1.10      mycroft   820:        if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
                    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)) {
                    828:                rt->rt_refcnt--;
                    829:                if (rt->rt_ifa != ifa) {
1.17      christos  830:                        printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
                    831:                                rt->rt_ifa);
1.10      mycroft   832:                        if (rt->rt_ifa->ifa_rtrequest)
1.39      itojun    833:                                rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL);
1.10      mycroft   834:                        IFAFREE(rt->rt_ifa);
                    835:                        rt->rt_ifa = ifa;
                    836:                        rt->rt_ifp = ifa->ifa_ifp;
1.30      thorpej   837:                        IFAREF(ifa);
1.10      mycroft   838:                        if (ifa->ifa_rtrequest)
1.39      itojun    839:                                ifa->ifa_rtrequest(RTM_ADD, rt, NULL);
1.10      mycroft   840:                }
                    841:                rt_newaddrmsg(cmd, ifa, error, nrt);
1.1       cgd       842:        }
                    843:        return (error);
1.18      kml       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) {                              \
1.20      thorpej   860:                (*r->rtt_func)(r->rtt_rt, r);                   \
1.18      kml       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:        assert(rt_init_done == 0);
                    879:
1.23      veego     880:        pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",
1.51      thorpej   881:            NULL);
1.22      thorpej   882:
1.18      kml       883:        LIST_INIT(&rttimer_queue_head);
1.35      thorpej   884:        callout_init(&rt_timer_ch);
                    885:        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.18      kml       886:        rt_init_done = 1;
                    887: }
                    888:
                    889: struct rttimer_queue *
                    890: rt_timer_queue_create(timeout)
                    891:        u_int   timeout;
                    892: {
                    893:        struct rttimer_queue *rtq;
                    894:
                    895:        if (rt_init_done == 0)
                    896:                rt_timer_init();
                    897:
                    898:        R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
                    899:        if (rtq == NULL)
1.24      thorpej   900:                return (NULL);
1.32      itojun    901:        Bzero(rtq, sizeof *rtq);
1.18      kml       902:
                    903:        rtq->rtq_timeout = timeout;
1.37      itojun    904:        rtq->rtq_count = 0;
1.24      thorpej   905:        TAILQ_INIT(&rtq->rtq_head);
1.18      kml       906:        LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
                    907:
1.24      thorpej   908:        return (rtq);
1.18      kml       909: }
                    910:
                    911: void
                    912: rt_timer_queue_change(rtq, timeout)
                    913:        struct rttimer_queue *rtq;
                    914:        long timeout;
                    915: {
1.24      thorpej   916:
1.18      kml       917:        rtq->rtq_timeout = timeout;
                    918: }
                    919:
                    920: void
1.55      itojun    921: rt_timer_queue_remove_all(rtq, destroy)
1.18      kml       922:        struct rttimer_queue *rtq;
                    923:        int destroy;
                    924: {
1.24      thorpej   925:        struct rttimer *r;
1.18      kml       926:
1.24      thorpej   927:        while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
1.18      kml       928:                LIST_REMOVE(r, rtt_link);
1.24      thorpej   929:                TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                    930:                if (destroy)
1.18      kml       931:                        RTTIMER_CALLOUT(r);
1.22      thorpej   932:                pool_put(&rttimer_pool, r);
1.37      itojun    933:                if (rtq->rtq_count > 0)
                    934:                        rtq->rtq_count--;
                    935:                else
1.55      itojun    936:                        printf("rt_timer_queue_remove_all: "
                    937:                            "rtq_count reached 0\n");
1.18      kml       938:        }
1.55      itojun    939: }
                    940:
                    941: void
                    942: rt_timer_queue_destroy(rtq, destroy)
                    943:        struct rttimer_queue *rtq;
                    944:        int destroy;
                    945: {
                    946:
                    947:        rt_timer_queue_remove_all(rtq, destroy);
1.18      kml       948:
                    949:        LIST_REMOVE(rtq, rtq_link);
1.22      thorpej   950:
                    951:        /*
                    952:         * Caller is responsible for freeing the rttimer_queue structure.
                    953:         */
1.18      kml       954: }
                    955:
1.37      itojun    956: unsigned long
                    957: rt_timer_count(rtq)
                    958:        struct rttimer_queue *rtq;
                    959: {
                    960:
                    961:        return rtq->rtq_count;
                    962: }
                    963:
1.18      kml       964: void
1.54      itojun    965: rt_timer_remove_all(rt, destroy)
1.18      kml       966:        struct rtentry *rt;
1.54      itojun    967:        int destroy;
1.18      kml       968: {
1.24      thorpej   969:        struct rttimer *r;
1.18      kml       970:
1.24      thorpej   971:        while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
1.18      kml       972:                LIST_REMOVE(r, rtt_link);
1.24      thorpej   973:                TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1.54      itojun    974:                if (destroy)
                    975:                        RTTIMER_CALLOUT(r);
1.37      itojun    976:                if (r->rtt_queue->rtq_count > 0)
                    977:                        r->rtt_queue->rtq_count--;
                    978:                else
                    979:                        printf("rt_timer_remove_all: rtq_count reached 0\n");
1.38      itojun    980:                pool_put(&rttimer_pool, r);
1.18      kml       981:        }
                    982: }
                    983:
                    984: int
                    985: rt_timer_add(rt, func, queue)
                    986:        struct rtentry *rt;
                    987:        void(*func) __P((struct rtentry *, struct rttimer *));
                    988:        struct rttimer_queue *queue;
                    989: {
1.24      thorpej   990:        struct rttimer *r;
                    991:        long current_time;
1.18      kml       992:        int s;
                    993:
                    994:        s = splclock();
                    995:        current_time = mono_time.tv_sec;
                    996:        splx(s);
                    997:
1.24      thorpej   998:        /*
                    999:         * If there's already a timer with this action, destroy it before
                   1000:         * we add a new one.
                   1001:         */
                   1002:        for (r = LIST_FIRST(&rt->rt_timer); r != NULL;
                   1003:             r = LIST_NEXT(r, rtt_link)) {
1.18      kml      1004:                if (r->rtt_func == func) {
                   1005:                        LIST_REMOVE(r, rtt_link);
1.24      thorpej  1006:                        TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1.37      itojun   1007:                        if (r->rtt_queue->rtq_count > 0)
                   1008:                                r->rtt_queue->rtq_count--;
                   1009:                        else
                   1010:                                printf("rt_timer_add: rtq_count reached 0\n");
1.38      itojun   1011:                        pool_put(&rttimer_pool, r);
1.18      kml      1012:                        break;  /* only one per list, so we can quit... */
                   1013:                }
                   1014:        }
                   1015:
1.24      thorpej  1016:        r = pool_get(&rttimer_pool, PR_NOWAIT);
                   1017:        if (r == NULL)
                   1018:                return (ENOBUFS);
1.32      itojun   1019:        Bzero(r, sizeof(*r));
1.24      thorpej  1020:
                   1021:        r->rtt_rt = rt;
                   1022:        r->rtt_time = current_time;
                   1023:        r->rtt_func = func;
                   1024:        r->rtt_queue = queue;
                   1025:        LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
                   1026:        TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1.37      itojun   1027:        r->rtt_queue->rtq_count++;
1.24      thorpej  1028:
                   1029:        return (0);
1.18      kml      1030: }
                   1031:
                   1032: /* ARGSUSED */
                   1033: void
                   1034: rt_timer_timer(arg)
                   1035:        void *arg;
                   1036: {
1.24      thorpej  1037:        struct rttimer_queue *rtq;
                   1038:        struct rttimer *r;
1.18      kml      1039:        long current_time;
1.24      thorpej  1040:        int s;
1.21      kml      1041:
1.24      thorpej  1042:        s = splclock();
1.18      kml      1043:        current_time = mono_time.tv_sec;
1.24      thorpej  1044:        splx(s);
1.18      kml      1045:
1.24      thorpej  1046:        s = splsoftnet();
1.18      kml      1047:        for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
                   1048:             rtq = LIST_NEXT(rtq, rtq_link)) {
1.24      thorpej  1049:                while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
                   1050:                    (r->rtt_time + rtq->rtq_timeout) < current_time) {
                   1051:                        LIST_REMOVE(r, rtt_link);
                   1052:                        TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                   1053:                        RTTIMER_CALLOUT(r);
                   1054:                        pool_put(&rttimer_pool, r);
1.37      itojun   1055:                        if (rtq->rtq_count > 0)
                   1056:                                rtq->rtq_count--;
                   1057:                        else
                   1058:                                printf("rt_timer_timer: rtq_count reached 0\n");
1.18      kml      1059:                }
                   1060:        }
1.24      thorpej  1061:        splx(s);
1.18      kml      1062:
1.35      thorpej  1063:        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.1       cgd      1064: }

CVSweb <webmaster@jp.NetBSD.org>