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