[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.136

1.136   ! roy         1: /*     $NetBSD: route.c,v 1.135 2015/02/25 12:45:34 roy Exp $  */
1.18      kml         2:
                      3: /*-
1.106     ad          4:  * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
1.18      kml         5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
                      9:  * NASA Ames Research Center.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     21:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     22:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     23:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     24:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     25:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     26:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     27:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     28:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     29:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     30:  * POSSIBILITY OF SUCH DAMAGE.
                     31:  */
1.11      cgd        32:
1.1       cgd        33: /*
1.25      itojun     34:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                     35:  * All rights reserved.
1.65      perry      36:  *
1.25      itojun     37:  * Redistribution and use in source and binary forms, with or without
                     38:  * modification, are permitted provided that the following conditions
                     39:  * are met:
                     40:  * 1. Redistributions of source code must retain the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer.
                     42:  * 2. Redistributions in binary form must reproduce the above copyright
                     43:  *    notice, this list of conditions and the following disclaimer in the
                     44:  *    documentation and/or other materials provided with the distribution.
                     45:  * 3. Neither the name of the project nor the names of its contributors
                     46:  *    may be used to endorse or promote products derived from this software
                     47:  *    without specific prior written permission.
1.65      perry      48:  *
1.25      itojun     49:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     52:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     53:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     59:  * SUCH DAMAGE.
                     60:  */
                     61:
                     62: /*
1.10      mycroft    63:  * Copyright (c) 1980, 1986, 1991, 1993
                     64:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        65:  *
                     66:  * Redistribution and use in source and binary forms, with or without
                     67:  * modification, are permitted provided that the following conditions
                     68:  * are met:
                     69:  * 1. Redistributions of source code must retain the above copyright
                     70:  *    notice, this list of conditions and the following disclaimer.
                     71:  * 2. Redistributions in binary form must reproduce the above copyright
                     72:  *    notice, this list of conditions and the following disclaimer in the
                     73:  *    documentation and/or other materials provided with the distribution.
1.58      agc        74:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        75:  *    may be used to endorse or promote products derived from this software
                     76:  *    without specific prior written permission.
                     77:  *
                     78:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     79:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     80:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     81:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     82:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     83:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     84:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     85:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     86:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     87:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     88:  * SUCH DAMAGE.
                     89:  *
1.17      christos   90:  *     @(#)route.c     8.3 (Berkeley) 1/9/95
1.1       cgd        91:  */
1.50      lukem      92:
1.136   ! roy        93: #include "opt_inet.h"
1.90      dyoung     94: #include "opt_route.h"
                     95:
1.50      lukem      96: #include <sys/cdefs.h>
1.136   ! roy        97: __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.135 2015/02/25 12:45:34 roy Exp $");
1.2       cgd        98:
1.5       mycroft    99: #include <sys/param.h>
1.125     dyoung    100: #include <sys/kmem.h>
1.90      dyoung    101: #include <sys/sysctl.h>
1.5       mycroft   102: #include <sys/systm.h>
1.35      thorpej   103: #include <sys/callout.h>
1.5       mycroft   104: #include <sys/proc.h>
                    105: #include <sys/mbuf.h>
                    106: #include <sys/socket.h>
                    107: #include <sys/socketvar.h>
                    108: #include <sys/domain.h>
                    109: #include <sys/protosw.h>
1.18      kml       110: #include <sys/kernel.h>
1.5       mycroft   111: #include <sys/ioctl.h>
1.22      thorpej   112: #include <sys/pool.h>
1.119     elad      113: #include <sys/kauth.h>
1.1       cgd       114:
1.5       mycroft   115: #include <net/if.h>
1.114     dyoung    116: #include <net/if_dl.h>
1.5       mycroft   117: #include <net/route.h>
                    118: #include <net/raw_cb.h>
1.1       cgd       119:
1.5       mycroft   120: #include <netinet/in.h>
                    121: #include <netinet/in_var.h>
1.1       cgd       122:
1.90      dyoung    123: #ifdef RTFLUSH_DEBUG
                    124: #define        rtcache_debug() __predict_false(_rtcache_debug)
                    125: #else /* RTFLUSH_DEBUG */
                    126: #define        rtcache_debug() 0
                    127: #endif /* RTFLUSH_DEBUG */
1.5       mycroft   128:
1.52      matt      129: struct rtstat  rtstat;
1.1       cgd       130:
                    131: int    rttrash;                /* routes not in table but not freed */
                    132:
1.113     pooka     133: struct pool rtentry_pool;
                    134: struct pool rttimer_pool;
1.22      thorpej   135:
1.35      thorpej   136: struct callout rt_timer_ch; /* callout for rt_timer_timer() */
                    137:
1.90      dyoung    138: #ifdef RTFLUSH_DEBUG
                    139: static int _rtcache_debug = 0;
                    140: #endif /* RTFLUSH_DEBUG */
                    141:
1.119     elad      142: static kauth_listener_t route_listener;
                    143:
1.60      matt      144: static int rtdeletemsg(struct rtentry *);
1.92      dyoung    145: static int rtflushclone1(struct rtentry *, void *);
                    146: static void rtflushclone(sa_family_t family, struct rtentry *);
1.40      itojun    147:
1.90      dyoung    148: #ifdef RTFLUSH_DEBUG
1.118     pooka     149: static void sysctl_net_rtcache_setup(struct sysctllog **);
                    150: static void
                    151: sysctl_net_rtcache_setup(struct sysctllog **clog)
1.90      dyoung    152: {
                    153:        const struct sysctlnode *rnode;
                    154:
                    155:        if (sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT,
                    156:            CTLTYPE_NODE,
                    157:            "rtcache", SYSCTL_DESCR("Route cache related settings"),
1.128     pooka     158:            NULL, 0, NULL, 0, CTL_NET, CTL_CREATE, CTL_EOL) != 0)
1.90      dyoung    159:                return;
                    160:        if (sysctl_createv(clog, 0, &rnode, &rnode,
                    161:            CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
                    162:            "debug", SYSCTL_DESCR("Debug route caches"),
                    163:            NULL, 0, &_rtcache_debug, 0, CTL_CREATE, CTL_EOL) != 0)
                    164:                return;
                    165: }
                    166: #endif /* RTFLUSH_DEBUG */
                    167:
1.81      joerg     168: struct ifaddr *
                    169: rt_get_ifa(struct rtentry *rt)
                    170: {
                    171:        struct ifaddr *ifa;
                    172:
                    173:        if ((ifa = rt->rt_ifa) == NULL)
                    174:                return ifa;
                    175:        else if (ifa->ifa_getifa == NULL)
                    176:                return ifa;
                    177: #if 0
                    178:        else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno)
                    179:                return ifa;
                    180: #endif
                    181:        else {
1.94      dyoung    182:                ifa = (*ifa->ifa_getifa)(ifa, rt_getkey(rt));
1.81      joerg     183:                rt_replace_ifa(rt, ifa);
                    184:                return ifa;
                    185:        }
                    186: }
                    187:
1.80      joerg     188: static void
                    189: rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa)
                    190: {
                    191:        rt->rt_ifa = ifa;
                    192:        if (ifa->ifa_seqno != NULL)
                    193:                rt->rt_ifa_seqno = *ifa->ifa_seqno;
                    194: }
                    195:
1.116     roy       196: /*
                    197:  * Is this route the connected route for the ifa?
                    198:  */
                    199: static int
                    200: rt_ifa_connected(const struct rtentry *rt, const struct ifaddr *ifa)
                    201: {
                    202:        const struct sockaddr *key, *dst, *odst;
                    203:        struct sockaddr_storage maskeddst;
                    204:
                    205:        key = rt_getkey(rt);
                    206:        dst = rt->rt_flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
                    207:        if (dst == NULL ||
                    208:            dst->sa_family != key->sa_family ||
                    209:            dst->sa_len != key->sa_len)
                    210:                return 0;
                    211:        if ((rt->rt_flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
                    212:                odst = dst;
                    213:                dst = (struct sockaddr *)&maskeddst;
                    214:                rt_maskedcopy(odst, (struct sockaddr *)&maskeddst,
                    215:                    ifa->ifa_netmask);
                    216:        }
                    217:        return (memcmp(dst, key, dst->sa_len) == 0);
                    218: }
                    219:
1.80      joerg     220: void
                    221: rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa)
                    222: {
1.116     roy       223:        if (rt->rt_ifa &&
                    224:            rt->rt_ifa != ifa &&
                    225:            rt->rt_ifa->ifa_flags & IFA_ROUTE &&
                    226:            rt_ifa_connected(rt, rt->rt_ifa))
                    227:        {
                    228:                RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
                    229:                    "replace deleted IFA_ROUTE\n",
                    230:                    (void *)rt->_rt_key, (void *)rt->rt_ifa);
                    231:                rt->rt_ifa->ifa_flags &= ~IFA_ROUTE;
                    232:                if (rt_ifa_connected(rt, ifa)) {
                    233:                        RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
                    234:                            "replace added IFA_ROUTE\n",
                    235:                            (void *)rt->_rt_key, (void *)ifa);
                    236:                        ifa->ifa_flags |= IFA_ROUTE;
                    237:                }
                    238:        }
                    239:
1.133     rmind     240:        ifaref(ifa);
                    241:        ifafree(rt->rt_ifa);
1.80      joerg     242:        rt_set_ifa1(rt, ifa);
                    243: }
                    244:
                    245: static void
                    246: rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa)
                    247: {
1.133     rmind     248:        ifaref(ifa);
1.80      joerg     249:        rt_set_ifa1(rt, ifa);
                    250: }
                    251:
1.119     elad      252: static int
                    253: route_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
                    254:     void *arg0, void *arg1, void *arg2, void *arg3)
                    255: {
                    256:        struct rt_msghdr *rtm;
                    257:        int result;
                    258:
                    259:        result = KAUTH_RESULT_DEFER;
                    260:        rtm = arg1;
                    261:
1.120     elad      262:        if (action != KAUTH_NETWORK_ROUTE)
                    263:                return result;
                    264:
1.119     elad      265:        if (rtm->rtm_type == RTM_GET)
                    266:                result = KAUTH_RESULT_ALLOW;
                    267:
                    268:        return result;
                    269: }
                    270:
1.9       mycroft   271: void
1.124     matt      272: rt_init(void)
1.1       cgd       273: {
1.22      thorpej   274:
1.118     pooka     275: #ifdef RTFLUSH_DEBUG
                    276:        sysctl_net_rtcache_setup(NULL);
                    277: #endif
                    278:
1.113     pooka     279:        pool_init(&rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl",
                    280:            NULL, IPL_SOFTNET);
                    281:        pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",
                    282:            NULL, IPL_SOFTNET);
                    283:
1.10      mycroft   284:        rn_init();      /* initialize all zeroes, all ones, mask table */
1.125     dyoung    285:        rtbl_init();
1.119     elad      286:
                    287:        route_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
                    288:            route_listener_cb, NULL);
1.1       cgd       289: }
                    290:
1.82      dyoung    291: void
                    292: rtflushall(int family)
                    293: {
1.90      dyoung    294:        struct domain *dom;
                    295:
                    296:        if (rtcache_debug())
                    297:                printf("%s: enter\n", __func__);
                    298:
                    299:        if ((dom = pffinddomain(family)) == NULL)
                    300:                return;
1.82      dyoung    301:
1.105     dyoung    302:        rtcache_invalidate(&dom->dom_rtcache);
1.82      dyoung    303: }
                    304:
1.131     rmind     305: static void
1.82      dyoung    306: rtcache(struct route *ro)
                    307: {
1.90      dyoung    308:        struct domain *dom;
1.82      dyoung    309:
1.114     dyoung    310:        rtcache_invariants(ro);
1.99      dyoung    311:        KASSERT(ro->_ro_rt != NULL);
1.105     dyoung    312:        KASSERT(ro->ro_invalid == false);
1.90      dyoung    313:        KASSERT(rtcache_getdst(ro) != NULL);
1.82      dyoung    314:
1.90      dyoung    315:        if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL)
                    316:                return;
                    317:
                    318:        LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next);
1.114     dyoung    319:        rtcache_invariants(ro);
1.82      dyoung    320: }
                    321:
1.1       cgd       322: /*
                    323:  * Packet routing routines.
                    324:  */
                    325: struct rtentry *
1.60      matt      326: rtalloc1(const struct sockaddr *dst, int report)
1.1       cgd       327: {
1.125     dyoung    328:        rtbl_t *rtbl = rt_gettable(dst->sa_family);
1.36      augustss  329:        struct rtentry *rt;
1.68      christos  330:        struct rtentry *newrt = NULL;
1.10      mycroft   331:        struct rt_addrinfo info;
1.13      mycroft   332:        int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
1.1       cgd       333:
1.125     dyoung    334:        if (rtbl != NULL && (rt = rt_matchaddr(rtbl, dst)) != NULL) {
                    335:                newrt = rt;
1.1       cgd       336:                if (report && (rt->rt_flags & RTF_CLONING)) {
1.68      christos  337:                        err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0,
                    338:                            &newrt);
1.8       cgd       339:                        if (err) {
                    340:                                newrt = rt;
                    341:                                rt->rt_refcnt++;
                    342:                                goto miss;
                    343:                        }
1.69      christos  344:                        KASSERT(newrt != NULL);
1.129     maxv      345:                        rt = newrt;
                    346:                        if (rt->rt_flags & RTF_XRESOLVE) {
1.8       cgd       347:                                msgtype = RTM_RESOLVE;
                    348:                                goto miss;
                    349:                        }
1.39      itojun    350:                        /* Inform listeners of the new route */
1.44      thorpej   351:                        memset(&info, 0, sizeof(info));
1.94      dyoung    352:                        info.rti_info[RTAX_DST] = rt_getkey(rt);
1.39      itojun    353:                        info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    354:                        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    355:                        if (rt->rt_ifp != NULL) {
1.65      perry     356:                                info.rti_info[RTAX_IFP] =
1.99      dyoung    357:                                    rt->rt_ifp->if_dl->ifa_addr;
1.39      itojun    358:                                info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
                    359:                        }
                    360:                        rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0);
1.1       cgd       361:                } else
                    362:                        rt->rt_refcnt++;
                    363:        } else {
                    364:                rtstat.rts_unreach++;
1.10      mycroft   365:        miss:   if (report) {
1.87      christos  366:                        memset((void *)&info, 0, sizeof(info));
1.10      mycroft   367:                        info.rti_info[RTAX_DST] = dst;
                    368:                        rt_missmsg(msgtype, &info, 0, err);
                    369:                }
1.1       cgd       370:        }
                    371:        splx(s);
1.95      dyoung    372:        return newrt;
1.1       cgd       373: }
                    374:
1.9       mycroft   375: void
1.60      matt      376: rtfree(struct rtentry *rt)
1.1       cgd       377: {
1.36      augustss  378:        struct ifaddr *ifa;
1.10      mycroft   379:
1.132     rmind     380:        KASSERT(rt != NULL);
                    381:        KASSERT(rt->rt_refcnt > 0);
                    382:
1.1       cgd       383:        rt->rt_refcnt--;
1.132     rmind     384:        if (rt->rt_refcnt == 0 && (rt->rt_flags & RTF_UP) == 0) {
1.125     dyoung    385:                rt_assert_inactive(rt);
1.10      mycroft   386:                rttrash--;
1.54      itojun    387:                rt_timer_remove_all(rt, 0);
1.10      mycroft   388:                ifa = rt->rt_ifa;
1.78      dyoung    389:                rt->rt_ifa = NULL;
1.133     rmind     390:                ifafree(ifa);
1.78      dyoung    391:                rt->rt_ifp = NULL;
1.94      dyoung    392:                rt_destroy(rt);
1.22      thorpej   393:                pool_put(&rtentry_pool, rt);
1.1       cgd       394:        }
                    395: }
                    396:
                    397: /*
                    398:  * Force a routing table entry to the specified
                    399:  * destination to go through the given gateway.
                    400:  * Normally called as a result of a routing redirect
                    401:  * message from the network layer.
                    402:  *
1.13      mycroft   403:  * N.B.: must be called at splsoftnet
1.1       cgd       404:  */
1.14      christos  405: void
1.60      matt      406: rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
                    407:        const struct sockaddr *netmask, int flags, const struct sockaddr *src,
                    408:        struct rtentry **rtp)
1.1       cgd       409: {
1.36      augustss  410:        struct rtentry *rt;
1.1       cgd       411:        int error = 0;
1.121     dyoung    412:        uint64_t *stat = NULL;
1.10      mycroft   413:        struct rt_addrinfo info;
                    414:        struct ifaddr *ifa;
1.1       cgd       415:
                    416:        /* verify the gateway is directly reachable */
1.68      christos  417:        if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
1.1       cgd       418:                error = ENETUNREACH;
1.8       cgd       419:                goto out;
1.1       cgd       420:        }
                    421:        rt = rtalloc1(dst, 0);
                    422:        /*
                    423:         * If the redirect isn't from our current router for this dst,
                    424:         * it's either old or wrong.  If it redirects us to ourselves,
                    425:         * we have a routing loop, perhaps as a result of an interface
                    426:         * going down recently.
                    427:         */
1.10      mycroft   428:        if (!(flags & RTF_DONE) && rt &&
1.115     yamt      429:             (sockaddr_cmp(src, rt->rt_gateway) != 0 || rt->rt_ifa != ifa))
1.1       cgd       430:                error = EINVAL;
                    431:        else if (ifa_ifwithaddr(gateway))
                    432:                error = EHOSTUNREACH;
                    433:        if (error)
                    434:                goto done;
                    435:        /*
                    436:         * Create a new entry if we just got back a wildcard entry
1.33      soren     437:         * or the lookup failed.  This is necessary for hosts
1.1       cgd       438:         * which use routing redirects generated by smart gateways
                    439:         * to dynamically build the routing tables.
                    440:         */
1.95      dyoung    441:        if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
1.1       cgd       442:                goto create;
                    443:        /*
                    444:         * Don't listen to the redirect if it's
1.65      perry     445:         * for a route to an interface.
1.1       cgd       446:         */
                    447:        if (rt->rt_flags & RTF_GATEWAY) {
                    448:                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
                    449:                        /*
                    450:                         * Changing from route to net => route to host.
                    451:                         * Create new route, rather than smashing route to net.
                    452:                         */
                    453:                create:
1.95      dyoung    454:                        if (rt != NULL)
1.39      itojun    455:                                rtfree(rt);
1.1       cgd       456:                        flags |=  RTF_GATEWAY | RTF_DYNAMIC;
1.122     kefren    457:                        memset(&info, 0, sizeof(info));
1.39      itojun    458:                        info.rti_info[RTAX_DST] = dst;
                    459:                        info.rti_info[RTAX_GATEWAY] = gateway;
                    460:                        info.rti_info[RTAX_NETMASK] = netmask;
                    461:                        info.rti_ifa = ifa;
                    462:                        info.rti_flags = flags;
                    463:                        rt = NULL;
                    464:                        error = rtrequest1(RTM_ADD, &info, &rt);
                    465:                        if (rt != NULL)
                    466:                                flags = rt->rt_flags;
1.1       cgd       467:                        stat = &rtstat.rts_dynamic;
                    468:                } else {
                    469:                        /*
                    470:                         * Smash the current notion of the gateway to
                    471:                         * this destination.  Should check about netmask!!!
                    472:                         */
1.10      mycroft   473:                        rt->rt_flags |= RTF_MODIFIED;
                    474:                        flags |= RTF_MODIFIED;
                    475:                        stat = &rtstat.rts_newgateway;
1.94      dyoung    476:                        rt_setgate(rt, gateway);
1.1       cgd       477:                }
                    478:        } else
                    479:                error = EHOSTUNREACH;
                    480: done:
                    481:        if (rt) {
1.95      dyoung    482:                if (rtp != NULL && !error)
1.1       cgd       483:                        *rtp = rt;
                    484:                else
                    485:                        rtfree(rt);
                    486:        }
1.8       cgd       487: out:
1.1       cgd       488:        if (error)
                    489:                rtstat.rts_badredirect++;
1.8       cgd       490:        else if (stat != NULL)
                    491:                (*stat)++;
1.95      dyoung    492:        memset(&info, 0, sizeof(info));
1.10      mycroft   493:        info.rti_info[RTAX_DST] = dst;
                    494:        info.rti_info[RTAX_GATEWAY] = gateway;
                    495:        info.rti_info[RTAX_NETMASK] = netmask;
                    496:        info.rti_info[RTAX_AUTHOR] = src;
                    497:        rt_missmsg(RTM_REDIRECT, &info, flags, error);
1.1       cgd       498: }
                    499:
                    500: /*
1.40      itojun    501:  * Delete a route and generate a message
                    502:  */
                    503: static int
1.60      matt      504: rtdeletemsg(struct rtentry *rt)
1.40      itojun    505: {
                    506:        int error;
                    507:        struct rt_addrinfo info;
                    508:
                    509:        /*
                    510:         * Request the new route so that the entry is not actually
                    511:         * deleted.  That will allow the information being reported to
                    512:         * be accurate (and consistent with route_output()).
                    513:         */
1.95      dyoung    514:        memset(&info, 0, sizeof(info));
1.94      dyoung    515:        info.rti_info[RTAX_DST] = rt_getkey(rt);
1.40      itojun    516:        info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    517:        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    518:        info.rti_flags = rt->rt_flags;
                    519:        error = rtrequest1(RTM_DELETE, &info, &rt);
                    520:
                    521:        rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
                    522:
                    523:        /* Adjust the refcount */
                    524:        if (error == 0 && rt->rt_refcnt <= 0) {
                    525:                rt->rt_refcnt++;
                    526:                rtfree(rt);
                    527:        }
1.95      dyoung    528:        return error;
1.40      itojun    529: }
                    530:
1.41      itojun    531: static int
1.92      dyoung    532: rtflushclone1(struct rtentry *rt, void *arg)
1.41      itojun    533: {
1.92      dyoung    534:        struct rtentry *parent;
1.41      itojun    535:
                    536:        parent = (struct rtentry *)arg;
                    537:        if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
                    538:                rtdeletemsg(rt);
                    539:        return 0;
                    540: }
                    541:
                    542: static void
1.92      dyoung    543: rtflushclone(sa_family_t family, struct rtentry *parent)
1.41      itojun    544: {
                    545:
                    546: #ifdef DIAGNOSTIC
                    547:        if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
                    548:                panic("rtflushclone: called with a non-cloning route");
                    549: #endif
1.92      dyoung    550:        rt_walktree(family, rtflushclone1, (void *)parent);
1.41      itojun    551: }
                    552:
1.1       cgd       553: struct ifaddr *
1.60      matt      554: ifa_ifwithroute(int flags, const struct sockaddr *dst,
                    555:        const struct sockaddr *gateway)
1.1       cgd       556: {
1.36      augustss  557:        struct ifaddr *ifa;
1.1       cgd       558:        if ((flags & RTF_GATEWAY) == 0) {
                    559:                /*
                    560:                 * If we are adding a route to an interface,
                    561:                 * and the interface is a pt to pt link
                    562:                 * we should search for the destination
                    563:                 * as our clue to the interface.  Otherwise
                    564:                 * we can use the local address.
                    565:                 */
1.68      christos  566:                ifa = NULL;
1.127     christos  567:                if ((flags & RTF_HOST) && gateway->sa_family != AF_LINK)
1.1       cgd       568:                        ifa = ifa_ifwithdstaddr(dst);
1.68      christos  569:                if (ifa == NULL)
1.1       cgd       570:                        ifa = ifa_ifwithaddr(gateway);
                    571:        } else {
                    572:                /*
                    573:                 * If we are adding a route to a remote net
                    574:                 * or host, the gateway may still be on the
                    575:                 * other end of a pt to pt link.
                    576:                 */
                    577:                ifa = ifa_ifwithdstaddr(gateway);
                    578:        }
1.68      christos  579:        if (ifa == NULL)
1.1       cgd       580:                ifa = ifa_ifwithnet(gateway);
1.68      christos  581:        if (ifa == NULL) {
1.1       cgd       582:                struct rtentry *rt = rtalloc1(dst, 0);
1.68      christos  583:                if (rt == NULL)
                    584:                        return NULL;
1.1       cgd       585:                rt->rt_refcnt--;
1.68      christos  586:                if ((ifa = rt->rt_ifa) == NULL)
                    587:                        return NULL;
1.1       cgd       588:        }
                    589:        if (ifa->ifa_addr->sa_family != dst->sa_family) {
1.10      mycroft   590:                struct ifaddr *oifa = ifa;
1.1       cgd       591:                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
1.127     christos  592:                if (ifa == NULL)
1.1       cgd       593:                        ifa = oifa;
                    594:        }
1.95      dyoung    595:        return ifa;
1.1       cgd       596: }
                    597:
1.9       mycroft   598: int
1.60      matt      599: rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway,
                    600:        const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
1.1       cgd       601: {
1.39      itojun    602:        struct rt_addrinfo info;
                    603:
1.44      thorpej   604:        memset(&info, 0, sizeof(info));
1.39      itojun    605:        info.rti_flags = flags;
                    606:        info.rti_info[RTAX_DST] = dst;
                    607:        info.rti_info[RTAX_GATEWAY] = gateway;
                    608:        info.rti_info[RTAX_NETMASK] = netmask;
                    609:        return rtrequest1(req, &info, ret_nrt);
                    610: }
                    611:
                    612: int
1.60      matt      613: rt_getifa(struct rt_addrinfo *info)
1.39      itojun    614: {
                    615:        struct ifaddr *ifa;
1.68      christos  616:        const struct sockaddr *dst = info->rti_info[RTAX_DST];
                    617:        const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
                    618:        const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
                    619:        const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
                    620:        int flags = info->rti_flags;
1.39      itojun    621:
                    622:        /*
                    623:         * ifp may be specified by sockaddr_dl when protocol address
                    624:         * is ambiguous
                    625:         */
                    626:        if (info->rti_ifp == NULL && ifpaddr != NULL
                    627:            && ifpaddr->sa_family == AF_LINK &&
1.101     dyoung    628:            (ifa = ifa_ifwithnet(ifpaddr)) != NULL)
1.39      itojun    629:                info->rti_ifp = ifa->ifa_ifp;
                    630:        if (info->rti_ifa == NULL && ifaaddr != NULL)
                    631:                info->rti_ifa = ifa_ifwithaddr(ifaaddr);
                    632:        if (info->rti_ifa == NULL) {
1.59      matt      633:                const struct sockaddr *sa;
1.39      itojun    634:
                    635:                sa = ifaaddr != NULL ? ifaaddr :
                    636:                    (gateway != NULL ? gateway : dst);
                    637:                if (sa != NULL && info->rti_ifp != NULL)
                    638:                        info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
                    639:                else if (dst != NULL && gateway != NULL)
                    640:                        info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
                    641:                else if (sa != NULL)
                    642:                        info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
                    643:        }
1.74      dyoung    644:        if ((ifa = info->rti_ifa) == NULL)
                    645:                return ENETUNREACH;
                    646:        if (ifa->ifa_getifa != NULL)
                    647:                info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
                    648:        if (info->rti_ifp == NULL)
                    649:                info->rti_ifp = ifa->ifa_ifp;
                    650:        return 0;
1.39      itojun    651: }
                    652:
                    653: int
1.60      matt      654: rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
1.39      itojun    655: {
1.60      matt      656:        int s = splsoftnet();
1.125     dyoung    657:        int error = 0, rc;
1.40      itojun    658:        struct rtentry *rt, *crt;
1.125     dyoung    659:        rtbl_t *rtbl;
1.122     kefren    660:        struct ifaddr *ifa, *ifa2;
1.94      dyoung    661:        struct sockaddr_storage maskeddst;
1.68      christos  662:        const struct sockaddr *dst = info->rti_info[RTAX_DST];
                    663:        const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
                    664:        const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
                    665:        int flags = info->rti_flags;
1.1       cgd       666: #define senderr(x) { error = x ; goto bad; }
                    667:
1.125     dyoung    668:        if ((rtbl = rt_gettable(dst->sa_family)) == NULL)
1.1       cgd       669:                senderr(ESRCH);
                    670:        if (flags & RTF_HOST)
1.68      christos  671:                netmask = NULL;
1.1       cgd       672:        switch (req) {
                    673:        case RTM_DELETE:
1.63      christos  674:                if (netmask) {
1.94      dyoung    675:                        rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                    676:                            netmask);
                    677:                        dst = (struct sockaddr *)&maskeddst;
1.63      christos  678:                }
1.125     dyoung    679:                if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.41      itojun    680:                        senderr(ESRCH);
                    681:                if ((rt->rt_flags & RTF_CLONING) != 0) {
                    682:                        /* clean up any cloned children */
1.92      dyoung    683:                        rtflushclone(dst->sa_family, rt);
1.41      itojun    684:                }
1.125     dyoung    685:                if ((rt = rt_deladdr(rtbl, dst, netmask)) == NULL)
1.1       cgd       686:                        senderr(ESRCH);
1.10      mycroft   687:                if (rt->rt_gwroute) {
1.131     rmind     688:                        rtfree(rt->rt_gwroute);
1.68      christos  689:                        rt->rt_gwroute = NULL;
1.48      itojun    690:                }
                    691:                if (rt->rt_parent) {
                    692:                        rt->rt_parent->rt_refcnt--;
                    693:                        rt->rt_parent = NULL;
1.10      mycroft   694:                }
1.28      erh       695:                rt->rt_flags &= ~RTF_UP;
1.116     roy       696:                if ((ifa = rt->rt_ifa)) {
                    697:                        if (ifa->ifa_flags & IFA_ROUTE &&
                    698:                            rt_ifa_connected(rt, ifa)) {
                    699:                                RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
                    700:                                    "deleted IFA_ROUTE\n",
                    701:                                    (void *)rt->_rt_key, (void *)ifa);
                    702:                                ifa->ifa_flags &= ~IFA_ROUTE;
                    703:                        }
                    704:                        if (ifa->ifa_rtrequest)
                    705:                                ifa->ifa_rtrequest(RTM_DELETE, rt, info);
                    706:                }
1.1       cgd       707:                rttrash++;
1.10      mycroft   708:                if (ret_nrt)
                    709:                        *ret_nrt = rt;
                    710:                else if (rt->rt_refcnt <= 0) {
                    711:                        rt->rt_refcnt++;
1.1       cgd       712:                        rtfree(rt);
1.10      mycroft   713:                }
1.1       cgd       714:                break;
                    715:
                    716:        case RTM_RESOLVE:
1.68      christos  717:                if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
1.1       cgd       718:                        senderr(EINVAL);
1.40      itojun    719:                if ((rt->rt_flags & RTF_CLONING) == 0)
                    720:                        senderr(EINVAL);
1.1       cgd       721:                ifa = rt->rt_ifa;
1.40      itojun    722:                flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
                    723:                flags |= RTF_CLONED;
1.1       cgd       724:                gateway = rt->rt_gateway;
1.94      dyoung    725:                flags |= RTF_HOST;
1.1       cgd       726:                goto makeroute;
                    727:
                    728:        case RTM_ADD:
1.68      christos  729:                if (info->rti_ifa == NULL && (error = rt_getifa(info)))
1.39      itojun    730:                        senderr(error);
                    731:                ifa = info->rti_ifa;
1.1       cgd       732:        makeroute:
1.72      tls       733:                /* Already at splsoftnet() so pool_get/pool_put are safe */
1.22      thorpej   734:                rt = pool_get(&rtentry_pool, PR_NOWAIT);
1.68      christos  735:                if (rt == NULL)
1.1       cgd       736:                        senderr(ENOBUFS);
1.109     dyoung    737:                memset(rt, 0, sizeof(*rt));
1.10      mycroft   738:                rt->rt_flags = RTF_UP | flags;
1.18      kml       739:                LIST_INIT(&rt->rt_timer);
1.110     dyoung    740:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.96      dyoung    741:                if (rt_setkey(rt, dst, M_NOWAIT) == NULL ||
1.94      dyoung    742:                    rt_setgate(rt, gateway) != 0) {
1.22      thorpej   743:                        pool_put(&rtentry_pool, rt);
1.10      mycroft   744:                        senderr(ENOBUFS);
                    745:                }
1.110     dyoung    746:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1       cgd       747:                if (netmask) {
1.94      dyoung    748:                        rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                    749:                            netmask);
1.96      dyoung    750:                        rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT);
1.110     dyoung    751:                        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94      dyoung    752:                } else {
1.96      dyoung    753:                        rt_setkey(rt, dst, M_NOWAIT);
1.110     dyoung    754:                        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94      dyoung    755:                }
1.74      dyoung    756:                rt_set_ifa(rt, ifa);
1.123     kefren    757:                if (info->rti_info[RTAX_TAG] != NULL)
                    758:                        rt_settag(rt, info->rti_info[RTAX_TAG]);
1.110     dyoung    759:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.122     kefren    760:                if (info->rti_info[RTAX_IFP] != NULL &&
                    761:                    (ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP])) != NULL &&
                    762:                    ifa2->ifa_ifp != NULL)
                    763:                        rt->rt_ifp = ifa2->ifa_ifp;
                    764:                else
                    765:                        rt->rt_ifp = ifa->ifa_ifp;
1.27      matt      766:                if (req == RTM_RESOLVE) {
1.1       cgd       767:                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
1.41      itojun    768:                        rt->rt_parent = *ret_nrt;
                    769:                        rt->rt_parent->rt_refcnt++;
1.40      itojun    770:                }
1.110     dyoung    771:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125     dyoung    772:                rc = rt_addaddr(rtbl, rt, netmask);
1.110     dyoung    773:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125     dyoung    774:                if (rc != 0 && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) {
1.40      itojun    775:                        /* overwrite cloned route */
                    776:                        if ((crt->rt_flags & RTF_CLONED) != 0) {
                    777:                                rtdeletemsg(crt);
1.125     dyoung    778:                                rc = rt_addaddr(rtbl, rt, netmask);
1.40      itojun    779:                        }
1.131     rmind     780:                        rtfree(crt);
1.110     dyoung    781:                        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.40      itojun    782:                }
1.110     dyoung    783:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125     dyoung    784:                if (rc != 0) {
1.133     rmind     785:                        ifafree(ifa);
1.41      itojun    786:                        if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
                    787:                                rtfree(rt->rt_parent);
1.40      itojun    788:                        if (rt->rt_gwroute)
                    789:                                rtfree(rt->rt_gwroute);
1.94      dyoung    790:                        rt_destroy(rt);
1.40      itojun    791:                        pool_put(&rtentry_pool, rt);
1.125     dyoung    792:                        senderr(rc);
1.27      matt      793:                }
1.110     dyoung    794:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1       cgd       795:                if (ifa->ifa_rtrequest)
1.39      itojun    796:                        ifa->ifa_rtrequest(req, rt, info);
1.110     dyoung    797:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1       cgd       798:                if (ret_nrt) {
                    799:                        *ret_nrt = rt;
                    800:                        rt->rt_refcnt++;
1.41      itojun    801:                }
                    802:                if ((rt->rt_flags & RTF_CLONING) != 0) {
                    803:                        /* clean up any cloned children */
1.92      dyoung    804:                        rtflushclone(dst->sa_family, rt);
1.1       cgd       805:                }
1.82      dyoung    806:                rtflushall(dst->sa_family);
1.1       cgd       807:                break;
1.92      dyoung    808:        case RTM_GET:
1.94      dyoung    809:                if (netmask != NULL) {
                    810:                        rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                    811:                            netmask);
                    812:                        dst = (struct sockaddr *)&maskeddst;
                    813:                }
1.125     dyoung    814:                if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.92      dyoung    815:                        senderr(ESRCH);
                    816:                if (ret_nrt != NULL) {
                    817:                        *ret_nrt = rt;
                    818:                        rt->rt_refcnt++;
                    819:                }
                    820:                break;
1.1       cgd       821:        }
                    822: bad:
                    823:        splx(s);
1.95      dyoung    824:        return error;
1.1       cgd       825: }
                    826:
1.10      mycroft   827: int
1.94      dyoung    828: rt_setgate(struct rtentry *rt, const struct sockaddr *gate)
1.10      mycroft   829: {
1.94      dyoung    830:        KASSERT(rt != rt->rt_gwroute);
                    831:
                    832:        KASSERT(rt->_rt_key != NULL);
1.110     dyoung    833:        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94      dyoung    834:
1.10      mycroft   835:        if (rt->rt_gwroute) {
1.131     rmind     836:                rtfree(rt->rt_gwroute);
1.68      christos  837:                rt->rt_gwroute = NULL;
1.10      mycroft   838:        }
1.94      dyoung    839:        KASSERT(rt->_rt_key != NULL);
1.110     dyoung    840:        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94      dyoung    841:        if (rt->rt_gateway != NULL)
                    842:                sockaddr_free(rt->rt_gateway);
                    843:        KASSERT(rt->_rt_key != NULL);
1.110     dyoung    844:        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.134     christos  845:        if ((rt->rt_gateway = sockaddr_dup(gate, M_ZERO | M_NOWAIT)) == NULL)
1.94      dyoung    846:                return ENOMEM;
                    847:        KASSERT(rt->_rt_key != NULL);
1.110     dyoung    848:        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94      dyoung    849:
1.10      mycroft   850:        if (rt->rt_flags & RTF_GATEWAY) {
1.94      dyoung    851:                KASSERT(rt->_rt_key != NULL);
1.110     dyoung    852:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10      mycroft   853:                rt->rt_gwroute = rtalloc1(gate, 1);
1.27      matt      854:                /*
                    855:                 * If we switched gateways, grab the MTU from the new
1.47      itojun    856:                 * gateway route if the current MTU, if the current MTU is
                    857:                 * greater than the MTU of gateway.
                    858:                 * Note that, if the MTU of gateway is 0, we will reset the
                    859:                 * MTU of the route to run PMTUD again from scratch. XXX
1.27      matt      860:                 */
1.94      dyoung    861:                KASSERT(rt->_rt_key != NULL);
1.110     dyoung    862:                RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.27      matt      863:                if (rt->rt_gwroute
                    864:                    && !(rt->rt_rmx.rmx_locks & RTV_MTU)
1.47      itojun    865:                    && rt->rt_rmx.rmx_mtu
                    866:                    && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
1.27      matt      867:                        rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
                    868:                }
1.10      mycroft   869:        }
1.94      dyoung    870:        KASSERT(rt->_rt_key != NULL);
1.110     dyoung    871:        RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10      mycroft   872:        return 0;
                    873: }
                    874:
1.9       mycroft   875: void
1.60      matt      876: rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
                    877:        const struct sockaddr *netmask)
1.1       cgd       878: {
1.94      dyoung    879:        const char *netmaskp = &netmask->sa_data[0],
                    880:                   *srcp = &src->sa_data[0];
                    881:        char *dstp = &dst->sa_data[0];
1.126     christos  882:        const char *maskend = (char *)dst + MIN(netmask->sa_len, src->sa_len);
                    883:        const char *srcend = (char *)dst + src->sa_len;
1.94      dyoung    884:
                    885:        dst->sa_len = src->sa_len;
                    886:        dst->sa_family = src->sa_family;
                    887:
                    888:        while (dstp < maskend)
                    889:                *dstp++ = *srcp++ & *netmaskp++;
                    890:        if (dstp < srcend)
                    891:                memset(dstp, 0, (size_t)(srcend - dstp));
1.1       cgd       892: }
1.10      mycroft   893:
1.1       cgd       894: /*
1.135     roy       895:  * Inform the routing socket of a route change.
                    896:  */
                    897: void
                    898: rt_newmsg(int cmd, struct rtentry *rt)
                    899: {
                    900:        struct rt_addrinfo info;
                    901:
                    902:        memset((void *)&info, 0, sizeof(info));
                    903:        info.rti_info[RTAX_DST] = rt_getkey(rt);
                    904:        info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    905:        info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    906:        if (rt->rt_ifp) {
                    907:                info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr;
                    908:                info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
                    909:        }
                    910:
                    911:        rt_missmsg(cmd, &info, rt->rt_flags, 0);
                    912: }
                    913:
                    914: /*
1.29      sommerfe  915:  * Set up or tear down a routing table entry, normally
1.1       cgd       916:  * for an interface.
                    917:  */
1.9       mycroft   918: int
1.60      matt      919: rtinit(struct ifaddr *ifa, int cmd, int flags)
1.1       cgd       920: {
1.36      augustss  921:        struct rtentry *rt;
                    922:        struct sockaddr *dst, *odst;
1.94      dyoung    923:        struct sockaddr_storage maskeddst;
1.68      christos  924:        struct rtentry *nrt = NULL;
1.1       cgd       925:        int error;
1.39      itojun    926:        struct rt_addrinfo info;
1.114     dyoung    927:        struct sockaddr_dl *sdl;
                    928:        const struct sockaddr_dl *ifsdl;
1.1       cgd       929:
                    930:        dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
                    931:        if (cmd == RTM_DELETE) {
                    932:                if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1.29      sommerfe  933:                        /* Delete subnet route for this interface */
                    934:                        odst = dst;
1.94      dyoung    935:                        dst = (struct sockaddr *)&maskeddst;
1.29      sommerfe  936:                        rt_maskedcopy(odst, dst, ifa->ifa_netmask);
1.1       cgd       937:                }
1.14      christos  938:                if ((rt = rtalloc1(dst, 0)) != NULL) {
1.1       cgd       939:                        rt->rt_refcnt--;
1.29      sommerfe  940:                        if (rt->rt_ifa != ifa)
1.85      dyoung    941:                                return (flags & RTF_HOST) ? EHOSTUNREACH
                    942:                                                        : ENETUNREACH;
1.1       cgd       943:                }
                    944:        }
1.44      thorpej   945:        memset(&info, 0, sizeof(info));
1.39      itojun    946:        info.rti_ifa = ifa;
                    947:        info.rti_flags = flags | ifa->ifa_flags;
                    948:        info.rti_info[RTAX_DST] = dst;
                    949:        info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
                    950:        /*
                    951:         * XXX here, it seems that we are assuming that ifa_netmask is NULL
                    952:         * for RTF_HOST.  bsdi4 passes NULL explicitly (via intermediate
                    953:         * variable) when RTF_HOST is 1.  still not sure if i can safely
                    954:         * change it to meet bsdi4 behavior.
                    955:         */
1.114     dyoung    956:        if (cmd != RTM_LLINFO_UPD)
                    957:                info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
                    958:        error = rtrequest1((cmd == RTM_LLINFO_UPD) ? RTM_GET : cmd, &info,
                    959:            &nrt);
                    960:        if (error != 0 || (rt = nrt) == NULL)
                    961:                ;
                    962:        else switch (cmd) {
                    963:        case RTM_DELETE:
1.136   ! roy       964:                rt_newmsg(cmd, nrt);
1.10      mycroft   965:                if (rt->rt_refcnt <= 0) {
                    966:                        rt->rt_refcnt++;
                    967:                        rtfree(rt);
                    968:                }
1.114     dyoung    969:                break;
                    970:        case RTM_LLINFO_UPD:
                    971:                rt->rt_refcnt--;
                    972:                RT_DPRINTF("%s: updating%s\n", __func__,
                    973:                    ((rt->rt_flags & RTF_LLINFO) == 0) ? " (no llinfo)" : "");
                    974:
                    975:                ifsdl = ifa->ifa_ifp->if_sadl;
                    976:
                    977:                if ((rt->rt_flags & RTF_LLINFO) != 0 &&
                    978:                    (sdl = satosdl(rt->rt_gateway)) != NULL &&
                    979:                    sdl->sdl_family == AF_LINK &&
                    980:                    sockaddr_dl_setaddr(sdl, sdl->sdl_len, CLLADDR(ifsdl),
                    981:                                        ifa->ifa_ifp->if_addrlen) == NULL) {
                    982:                        error = EINVAL;
                    983:                        break;
                    984:                }
                    985:
                    986:                if (cmd == RTM_LLINFO_UPD && ifa->ifa_rtrequest != NULL)
                    987:                        ifa->ifa_rtrequest(RTM_LLINFO_UPD, rt, &info);
1.136   ! roy       988:                rt_newmsg(RTM_CHANGE, nrt);
1.114     dyoung    989:                break;
                    990:        case RTM_ADD:
1.10      mycroft   991:                rt->rt_refcnt--;
                    992:                if (rt->rt_ifa != ifa) {
1.17      christos  993:                        printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
                    994:                                rt->rt_ifa);
1.114     dyoung    995:                        if (rt->rt_ifa->ifa_rtrequest != NULL) {
                    996:                                rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
                    997:                                    &info);
                    998:                        }
1.74      dyoung    999:                        rt_replace_ifa(rt, ifa);
1.10      mycroft  1000:                        rt->rt_ifp = ifa->ifa_ifp;
1.114     dyoung   1001:                        if (ifa->ifa_rtrequest != NULL)
                   1002:                                ifa->ifa_rtrequest(RTM_ADD, rt, &info);
1.10      mycroft  1003:                }
1.136   ! roy      1004:                rt_newmsg(cmd, nrt);
1.114     dyoung   1005:                break;
1.1       cgd      1006:        }
1.85      dyoung   1007:        return error;
1.18      kml      1008: }
                   1009:
1.136   ! roy      1010: static const struct in_addr inmask32 = {.s_addr = INADDR_BROADCAST};
        !          1011:
        !          1012: /* Subroutine for rt_ifa_addlocal() and rt_ifa_remlocal() */
        !          1013: static int
        !          1014: rt_ifa_localrequest(int cmd, struct ifaddr *ifa)
        !          1015: {
        !          1016:        struct sockaddr *all1_sa;
        !          1017:        struct sockaddr_in all1_sin;
        !          1018: #ifdef INET6
        !          1019:        struct sockaddr_in6 all1_sin6;
        !          1020: #endif
        !          1021:        struct rtentry *nrt = NULL;
        !          1022:        int flags, e;
        !          1023:
        !          1024:        switch(ifa->ifa_addr->sa_family) {
        !          1025:        case AF_INET:
        !          1026:                sockaddr_in_init(&all1_sin, &inmask32, 0);
        !          1027:                all1_sa = (struct sockaddr *)&all1_sin;
        !          1028:                break;
        !          1029: #ifdef INET6
        !          1030:        case AF_INET6:
        !          1031:                sockaddr_in6_init(&all1_sin6, &in6mask128, 0, 0, 0);
        !          1032:                all1_sa = (struct sockaddr *)&all1_sin6;
        !          1033:                break;
        !          1034: #endif
        !          1035:        default:
        !          1036:                return 0;
        !          1037:        }
        !          1038:
        !          1039:        flags = RTF_UP | RTF_HOST | RTF_LOCAL;
        !          1040:        if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
        !          1041:                flags |= RTF_LLINFO;
        !          1042:        e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, all1_sa, flags, &nrt);
        !          1043:
        !          1044:        /* Make sure rt_ifa be equal to IFA, the second argument of the
        !          1045:         * function. */
        !          1046:        if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa)
        !          1047:                rt_replace_ifa(nrt, ifa);
        !          1048:
        !          1049:        rt_newaddrmsg(cmd, ifa, e, nrt);
        !          1050:        if (nrt) {
        !          1051:                if (cmd == RTM_DELETE) {
        !          1052:                        if (nrt->rt_refcnt <= 0) {
        !          1053:                                /* XXX: we should free the entry ourselves. */
        !          1054:                                nrt->rt_refcnt++;
        !          1055:                                rtfree(nrt);
        !          1056:                        }
        !          1057:                } else {
        !          1058:                        /* the cmd must be RTM_ADD here */
        !          1059:                        nrt->rt_refcnt--;
        !          1060:                }
        !          1061:        }
        !          1062:        return e;
        !          1063: }
        !          1064:
        !          1065: /*
        !          1066:  * Create a local route entry for the address.
        !          1067:  * Announce the addition of the address and the route to the routing socket.
        !          1068:  */
        !          1069: int
        !          1070: rt_ifa_addlocal(struct ifaddr *ifa)
        !          1071: {
        !          1072:        struct rtentry *rt;
        !          1073:        int e;
        !          1074:
        !          1075:        /* If there is no loopback entry, allocate one. */
        !          1076:        rt = rtalloc1(ifa->ifa_addr, 0);
        !          1077:        if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
        !          1078:            (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
        !          1079:                e = rt_ifa_localrequest(RTM_ADD, ifa);
        !          1080:        else {
        !          1081:                e = 0;
        !          1082:                rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
        !          1083:        }
        !          1084:        if (rt != NULL)
        !          1085:                rt->rt_refcnt--;
        !          1086:        return e;
        !          1087: }
        !          1088:
        !          1089: /*
        !          1090:  * Remove the local route entry for the address.
        !          1091:  * Announce the removal of the address and the route to the routing socket.
        !          1092:  */
        !          1093: int
        !          1094: rt_ifa_remlocal(struct ifaddr *ifa, struct ifaddr *alt_ifa)
        !          1095: {
        !          1096:        struct rtentry *rt;
        !          1097:        int e = 0;
        !          1098:
        !          1099:        rt = rtalloc1(ifa->ifa_addr, 0);
        !          1100:
        !          1101:        /*
        !          1102:         * Before deleting, check if a corresponding loopbacked
        !          1103:         * host route surely exists.  With this check, we can avoid
        !          1104:         * deleting an interface direct route whose destination is
        !          1105:         * the same as the address being removed.  This can happen
        !          1106:         * when removing a subnet-router anycast address on an
        !          1107:         * interface attached to a shared medium.
        !          1108:         */
        !          1109:        if (rt != NULL &&
        !          1110:            (rt->rt_flags & RTF_HOST) &&
        !          1111:            (rt->rt_ifp->if_flags & IFF_LOOPBACK))
        !          1112:        {
        !          1113:                /* If we cannot replace the route's ifaddr with the equivalent
        !          1114:                 * ifaddr of another interface, I believe it is safest to
        !          1115:                 * delete the route.
        !          1116:                 */
        !          1117:                if (alt_ifa == NULL)
        !          1118:                        e = rt_ifa_localrequest(RTM_DELETE, ifa);
        !          1119:                else {
        !          1120:                        rt_replace_ifa(rt, alt_ifa);
        !          1121:                        rt_newmsg(RTM_CHANGE, rt);
        !          1122:                }
        !          1123:        } else
        !          1124:                rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
        !          1125:        if (rt != NULL)
        !          1126:                rt->rt_refcnt--;
        !          1127:        return e;
        !          1128: }
        !          1129:
1.18      kml      1130: /*
                   1131:  * Route timer routines.  These routes allow functions to be called
                   1132:  * for various routes at any time.  This is useful in supporting
                   1133:  * path MTU discovery and redirect route deletion.
                   1134:  *
                   1135:  * This is similar to some BSDI internal functions, but it provides
                   1136:  * for multiple queues for efficiency's sake...
                   1137:  */
                   1138:
                   1139: LIST_HEAD(, rttimer_queue) rttimer_queue_head;
                   1140: static int rt_init_done = 0;
                   1141:
1.60      matt     1142: #define RTTIMER_CALLOUT(r)     do {                                    \
                   1143:                if (r->rtt_func != NULL) {                              \
                   1144:                        (*r->rtt_func)(r->rtt_rt, r);                   \
                   1145:                } else {                                                \
                   1146:                        rtrequest((int) RTM_DELETE,                     \
1.94      dyoung   1147:                                  rt_getkey(r->rtt_rt),                 \
1.60      matt     1148:                                  0, 0, 0, 0);                          \
                   1149:                }                                                       \
                   1150:        } while (/*CONSTCOND*/0)
1.18      kml      1151:
1.65      perry    1152: /*
1.18      kml      1153:  * Some subtle order problems with domain initialization mean that
                   1154:  * we cannot count on this being run from rt_init before various
                   1155:  * protocol initializations are done.  Therefore, we make sure
                   1156:  * that this is run when the first queue is added...
                   1157:  */
                   1158:
1.65      perry    1159: void
1.60      matt     1160: rt_timer_init(void)
1.18      kml      1161: {
                   1162:        assert(rt_init_done == 0);
                   1163:
                   1164:        LIST_INIT(&rttimer_queue_head);
1.93      ad       1165:        callout_init(&rt_timer_ch, 0);
1.35      thorpej  1166:        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.18      kml      1167:        rt_init_done = 1;
                   1168: }
                   1169:
                   1170: struct rttimer_queue *
1.60      matt     1171: rt_timer_queue_create(u_int timeout)
1.18      kml      1172: {
                   1173:        struct rttimer_queue *rtq;
                   1174:
                   1175:        if (rt_init_done == 0)
                   1176:                rt_timer_init();
                   1177:
                   1178:        R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
                   1179:        if (rtq == NULL)
1.85      dyoung   1180:                return NULL;
1.109     dyoung   1181:        memset(rtq, 0, sizeof(*rtq));
1.18      kml      1182:
                   1183:        rtq->rtq_timeout = timeout;
1.24      thorpej  1184:        TAILQ_INIT(&rtq->rtq_head);
1.18      kml      1185:        LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
                   1186:
1.85      dyoung   1187:        return rtq;
1.18      kml      1188: }
                   1189:
                   1190: void
1.60      matt     1191: rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
1.18      kml      1192: {
1.24      thorpej  1193:
1.18      kml      1194:        rtq->rtq_timeout = timeout;
                   1195: }
                   1196:
                   1197: void
1.60      matt     1198: rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy)
1.18      kml      1199: {
1.24      thorpej  1200:        struct rttimer *r;
1.18      kml      1201:
1.24      thorpej  1202:        while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
1.18      kml      1203:                LIST_REMOVE(r, rtt_link);
1.24      thorpej  1204:                TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                   1205:                if (destroy)
1.18      kml      1206:                        RTTIMER_CALLOUT(r);
1.72      tls      1207:                /* we are already at splsoftnet */
1.22      thorpej  1208:                pool_put(&rttimer_pool, r);
1.37      itojun   1209:                if (rtq->rtq_count > 0)
                   1210:                        rtq->rtq_count--;
                   1211:                else
1.55      itojun   1212:                        printf("rt_timer_queue_remove_all: "
                   1213:                            "rtq_count reached 0\n");
1.18      kml      1214:        }
1.55      itojun   1215: }
                   1216:
                   1217: void
1.60      matt     1218: rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy)
1.55      itojun   1219: {
                   1220:
                   1221:        rt_timer_queue_remove_all(rtq, destroy);
1.18      kml      1222:
                   1223:        LIST_REMOVE(rtq, rtq_link);
1.22      thorpej  1224:
                   1225:        /*
                   1226:         * Caller is responsible for freeing the rttimer_queue structure.
                   1227:         */
1.18      kml      1228: }
                   1229:
1.37      itojun   1230: unsigned long
1.60      matt     1231: rt_timer_count(struct rttimer_queue *rtq)
1.37      itojun   1232: {
                   1233:        return rtq->rtq_count;
                   1234: }
                   1235:
1.65      perry    1236: void
1.60      matt     1237: rt_timer_remove_all(struct rtentry *rt, int destroy)
1.18      kml      1238: {
1.24      thorpej  1239:        struct rttimer *r;
1.18      kml      1240:
1.24      thorpej  1241:        while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
1.18      kml      1242:                LIST_REMOVE(r, rtt_link);
1.24      thorpej  1243:                TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1.54      itojun   1244:                if (destroy)
                   1245:                        RTTIMER_CALLOUT(r);
1.37      itojun   1246:                if (r->rtt_queue->rtq_count > 0)
                   1247:                        r->rtt_queue->rtq_count--;
                   1248:                else
                   1249:                        printf("rt_timer_remove_all: rtq_count reached 0\n");
1.72      tls      1250:                /* we are already at splsoftnet */
1.38      itojun   1251:                pool_put(&rttimer_pool, r);
1.18      kml      1252:        }
                   1253: }
                   1254:
1.65      perry    1255: int
1.60      matt     1256: rt_timer_add(struct rtentry *rt,
                   1257:        void (*func)(struct rtentry *, struct rttimer *),
                   1258:        struct rttimer_queue *queue)
1.18      kml      1259: {
1.24      thorpej  1260:        struct rttimer *r;
1.72      tls      1261:        int s;
1.18      kml      1262:
1.24      thorpej  1263:        /*
                   1264:         * If there's already a timer with this action, destroy it before
                   1265:         * we add a new one.
                   1266:         */
1.85      dyoung   1267:        LIST_FOREACH(r, &rt->rt_timer, rtt_link) {
                   1268:                if (r->rtt_func == func)
                   1269:                        break;
                   1270:        }
                   1271:        if (r != NULL) {
                   1272:                LIST_REMOVE(r, rtt_link);
                   1273:                TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
                   1274:                if (r->rtt_queue->rtq_count > 0)
                   1275:                        r->rtt_queue->rtq_count--;
                   1276:                else
                   1277:                        printf("rt_timer_add: rtq_count reached 0\n");
                   1278:        } else {
                   1279:                s = splsoftnet();
                   1280:                r = pool_get(&rttimer_pool, PR_NOWAIT);
                   1281:                splx(s);
                   1282:                if (r == NULL)
                   1283:                        return ENOBUFS;
1.18      kml      1284:        }
                   1285:
1.85      dyoung   1286:        memset(r, 0, sizeof(*r));
1.24      thorpej  1287:
                   1288:        r->rtt_rt = rt;
1.70      kardel   1289:        r->rtt_time = time_uptime;
1.24      thorpej  1290:        r->rtt_func = func;
                   1291:        r->rtt_queue = queue;
                   1292:        LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
                   1293:        TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1.37      itojun   1294:        r->rtt_queue->rtq_count++;
1.65      perry    1295:
1.95      dyoung   1296:        return 0;
1.18      kml      1297: }
                   1298:
                   1299: /* ARGSUSED */
                   1300: void
1.76      christos 1301: rt_timer_timer(void *arg)
1.18      kml      1302: {
1.24      thorpej  1303:        struct rttimer_queue *rtq;
                   1304:        struct rttimer *r;
                   1305:        int s;
1.21      kml      1306:
1.24      thorpej  1307:        s = splsoftnet();
1.85      dyoung   1308:        LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) {
1.24      thorpej  1309:                while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1.70      kardel   1310:                    (r->rtt_time + rtq->rtq_timeout) < time_uptime) {
1.24      thorpej  1311:                        LIST_REMOVE(r, rtt_link);
                   1312:                        TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                   1313:                        RTTIMER_CALLOUT(r);
                   1314:                        pool_put(&rttimer_pool, r);
1.37      itojun   1315:                        if (rtq->rtq_count > 0)
                   1316:                                rtq->rtq_count--;
                   1317:                        else
                   1318:                                printf("rt_timer_timer: rtq_count reached 0\n");
1.18      kml      1319:                }
                   1320:        }
1.24      thorpej  1321:        splx(s);
1.18      kml      1322:
1.35      thorpej  1323:        callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.1       cgd      1324: }
1.83      joerg    1325:
1.102     dyoung   1326: static struct rtentry *
1.84      joerg    1327: _rtcache_init(struct route *ro, int flag)
                   1328: {
1.114     dyoung   1329:        rtcache_invariants(ro);
1.99      dyoung   1330:        KASSERT(ro->_ro_rt == NULL);
1.84      joerg    1331:
1.90      dyoung   1332:        if (rtcache_getdst(ro) == NULL)
1.102     dyoung   1333:                return NULL;
1.105     dyoung   1334:        ro->ro_invalid = false;
                   1335:        if ((ro->_ro_rt = rtalloc1(rtcache_getdst(ro), flag)) != NULL)
                   1336:                rtcache(ro);
1.103     dyoung   1337:
1.114     dyoung   1338:        rtcache_invariants(ro);
1.102     dyoung   1339:        return ro->_ro_rt;
1.84      joerg    1340: }
                   1341:
1.102     dyoung   1342: struct rtentry *
1.83      joerg    1343: rtcache_init(struct route *ro)
                   1344: {
1.102     dyoung   1345:        return _rtcache_init(ro, 1);
1.83      joerg    1346: }
                   1347:
1.102     dyoung   1348: struct rtentry *
1.83      joerg    1349: rtcache_init_noclone(struct route *ro)
                   1350: {
1.102     dyoung   1351:        return _rtcache_init(ro, 0);
1.83      joerg    1352: }
1.90      dyoung   1353:
1.102     dyoung   1354: struct rtentry *
1.90      dyoung   1355: rtcache_update(struct route *ro, int clone)
                   1356: {
                   1357:        rtcache_clear(ro);
1.102     dyoung   1358:        return _rtcache_init(ro, clone);
1.90      dyoung   1359: }
1.83      joerg    1360:
                   1361: void
1.90      dyoung   1362: rtcache_copy(struct route *new_ro, const struct route *old_ro)
1.83      joerg    1363: {
1.103     dyoung   1364:        struct rtentry *rt;
                   1365:
                   1366:        KASSERT(new_ro != old_ro);
1.114     dyoung   1367:        rtcache_invariants(new_ro);
                   1368:        rtcache_invariants(old_ro);
1.103     dyoung   1369:
1.104     dyoung   1370:        if ((rt = rtcache_validate(old_ro)) != NULL)
1.103     dyoung   1371:                rt->rt_refcnt++;
                   1372:
1.90      dyoung   1373:        if (rtcache_getdst(old_ro) == NULL ||
                   1374:            rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0)
                   1375:                return;
1.103     dyoung   1376:
1.105     dyoung   1377:        new_ro->ro_invalid = false;
1.103     dyoung   1378:        if ((new_ro->_ro_rt = rt) != NULL)
1.86      dyoung   1379:                rtcache(new_ro);
1.114     dyoung   1380:        rtcache_invariants(new_ro);
1.83      joerg    1381: }
                   1382:
1.105     dyoung   1383: static struct dom_rtlist invalid_routes = LIST_HEAD_INITIALIZER(dom_rtlist);
                   1384:
1.89      xtraeme  1385: void
1.105     dyoung   1386: rtcache_invalidate(struct dom_rtlist *rtlist)
1.83      joerg    1387: {
1.105     dyoung   1388:        struct route *ro;
1.99      dyoung   1389:
1.105     dyoung   1390:        while ((ro = LIST_FIRST(rtlist)) != NULL) {
1.114     dyoung   1391:                rtcache_invariants(ro);
1.105     dyoung   1392:                KASSERT(ro->_ro_rt != NULL);
                   1393:                ro->ro_invalid = true;
1.99      dyoung   1394:                LIST_REMOVE(ro, ro_rtcache_next);
1.105     dyoung   1395:                LIST_INSERT_HEAD(&invalid_routes, ro, ro_rtcache_next);
1.114     dyoung   1396:                rtcache_invariants(ro);
1.84      joerg    1397:        }
1.105     dyoung   1398: }
                   1399:
                   1400: void
                   1401: rtcache_clear(struct route *ro)
                   1402: {
1.114     dyoung   1403:        rtcache_invariants(ro);
1.105     dyoung   1404:        if (ro->_ro_rt == NULL)
                   1405:                return;
                   1406:
                   1407:        LIST_REMOVE(ro, ro_rtcache_next);
                   1408:
1.131     rmind    1409:        rtfree(ro->_ro_rt);
1.105     dyoung   1410:        ro->_ro_rt = NULL;
1.114     dyoung   1411:        ro->ro_invalid = false;
                   1412:        rtcache_invariants(ro);
1.83      joerg    1413: }
                   1414:
1.90      dyoung   1415: struct rtentry *
1.91      dyoung   1416: rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone,
                   1417:     int *hitp)
1.90      dyoung   1418: {
                   1419:        const struct sockaddr *odst;
1.104     dyoung   1420:        struct rtentry *rt = NULL;
1.90      dyoung   1421:
1.114     dyoung   1422:        rtcache_invariants(ro);
                   1423:
1.90      dyoung   1424:        odst = rtcache_getdst(ro);
                   1425:
                   1426:        if (odst == NULL)
                   1427:                ;
                   1428:        else if (sockaddr_cmp(odst, dst) != 0)
                   1429:                rtcache_free(ro);
1.104     dyoung   1430:        else if ((rt = rtcache_validate(ro)) == NULL)
1.91      dyoung   1431:                rtcache_clear(ro);
1.90      dyoung   1432:
1.104     dyoung   1433:        if (rt == NULL) {
1.91      dyoung   1434:                *hitp = 0;
1.104     dyoung   1435:                if (rtcache_setdst(ro, dst) == 0)
                   1436:                        rt = _rtcache_init(ro, clone);
1.91      dyoung   1437:        } else
                   1438:                *hitp = 1;
1.90      dyoung   1439:
1.114     dyoung   1440:        rtcache_invariants(ro);
                   1441:
1.104     dyoung   1442:        return rt;
1.90      dyoung   1443: }
                   1444:
1.83      joerg    1445: void
1.86      dyoung   1446: rtcache_free(struct route *ro)
                   1447: {
                   1448:        rtcache_clear(ro);
                   1449:        if (ro->ro_sa != NULL) {
                   1450:                sockaddr_free(ro->ro_sa);
                   1451:                ro->ro_sa = NULL;
                   1452:        }
1.114     dyoung   1453:        rtcache_invariants(ro);
1.86      dyoung   1454: }
                   1455:
1.90      dyoung   1456: int
                   1457: rtcache_setdst(struct route *ro, const struct sockaddr *sa)
1.83      joerg    1458: {
1.90      dyoung   1459:        KASSERT(sa != NULL);
                   1460:
1.114     dyoung   1461:        rtcache_invariants(ro);
1.90      dyoung   1462:        if (ro->ro_sa != NULL && ro->ro_sa->sa_family == sa->sa_family) {
                   1463:                rtcache_clear(ro);
1.114     dyoung   1464:                if (sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa) != NULL) {
                   1465:                        rtcache_invariants(ro);
1.96      dyoung   1466:                        return 0;
1.114     dyoung   1467:                }
1.96      dyoung   1468:                sockaddr_free(ro->ro_sa);
1.90      dyoung   1469:        } else if (ro->ro_sa != NULL)
                   1470:                rtcache_free(ro);       /* free ro_sa, wrong family */
                   1471:
1.107     dyoung   1472:        KASSERT(ro->_ro_rt == NULL);
                   1473:
1.134     christos 1474:        if ((ro->ro_sa = sockaddr_dup(sa, M_ZERO | M_NOWAIT)) == NULL) {
1.114     dyoung   1475:                rtcache_invariants(ro);
1.90      dyoung   1476:                return ENOMEM;
1.107     dyoung   1477:        }
1.114     dyoung   1478:        rtcache_invariants(ro);
1.90      dyoung   1479:        return 0;
1.83      joerg    1480: }
1.92      dyoung   1481:
1.123     kefren   1482: const struct sockaddr *
                   1483: rt_settag(struct rtentry *rt, const struct sockaddr *tag)
                   1484: {
                   1485:        if (rt->rt_tag != tag) {
                   1486:                if (rt->rt_tag != NULL)
                   1487:                        sockaddr_free(rt->rt_tag);
1.134     christos 1488:                rt->rt_tag = sockaddr_dup(tag, M_ZERO | M_NOWAIT);
1.123     kefren   1489:        }
                   1490:        return rt->rt_tag;
                   1491: }
                   1492:
                   1493: struct sockaddr *
                   1494: rt_gettag(struct rtentry *rt)
                   1495: {
                   1496:        return rt->rt_tag;
                   1497: }

CVSweb <webmaster@jp.NetBSD.org>