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>