|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1980, 1986, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)route.c 8.3 (Berkeley) 1/9/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/systm.h>
63: #include <sys/proc.h>
64: #include <sys/mbuf.h>
65: #include <sys/socket.h>
66: #include <sys/socketvar.h>
67: #include <sys/domain.h>
68: #include <sys/protosw.h>
69: #include <sys/ioctl.h>
70: #include <sys/malloc.h>
71:
72: #include <net/if.h>
73: #include <net/route.h>
74: #include <net/raw_cb.h>
75:
76: #include <netinet/in.h>
77: #include <netinet/in_var.h>
78:
79: #if NS
80: #include <netns/ns.h>
81: #endif
82:
83: #define SA(p) ((struct sockaddr *)(p))
84:
85: int rttrash; /* routes not in table but not freed */
86: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
87: struct rtstat rtstat;
88: struct radix_node_head *rt_tables[AF_MAX+1];
89:
90: /* Should be in spl.h */
91: int splimp(void);
92: int splnet(void);
93: int splx(int);
94:
95: void
96: rtable_init(table)
97: void **table;
98: {
99: struct domain *dom;
100: for (dom = domains; dom; dom = dom->dom_next)
101: if (dom->dom_rtattach)
102: dom->dom_rtattach(&table[dom->dom_family],
103: dom->dom_rtoffset);
104: }
105:
106: void
107: route_init()
108: {
109: rn_init(); /* initialize all zeroes, all ones, mask table */
110: rtable_init((void **)rt_tables);
111: }
112:
113: /*
114: * Packet routing routines.
115: */
116: void
117: rtalloc(ro)
118: register struct route *ro;
119: {
120: if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
121: return; /* XXX */
122: ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
123: }
124:
125: struct rtentry *
126: rtalloc1(dst, report)
127: register struct sockaddr *dst;
128: int report;
129: {
130: register struct radix_node_head *rnh = rt_tables[dst->sa_family];
131: register struct rtentry *rt;
132: register struct radix_node *rn;
133: struct rtentry *newrt = 0;
134: struct rt_addrinfo info;
135: int s = splnet(), err = 0, msgtype = RTM_MISS;
136:
137: if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
138: ((rn->rn_flags & RNF_ROOT) == 0)) {
139: newrt = rt = (struct rtentry *)rn;
140: if (report && (rt->rt_flags & RTF_CLONING)) {
141: err = rtrequest(RTM_RESOLVE, dst, SA(0),
142: SA(0), 0, &newrt);
143: if (err) {
144: newrt = rt;
1.1.1.2 ! root 145: RTHOLD(rt);
1.1 root 146: goto miss;
147: }
148: if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
149: msgtype = RTM_RESOLVE;
150: goto miss;
151: }
152: } else
1.1.1.2 ! root 153: RTHOLD(rt);
1.1 root 154: } else {
155: rtstat.rts_unreach++;
156: miss: if (report) {
157: bzero((caddr_t)&info, sizeof(info));
158: info.rti_info[RTAX_DST] = dst;
159: rt_missmsg(msgtype, &info, 0, err);
160: }
161: }
162: splx(s);
163: return (newrt);
164: }
165:
166: void
167: rtfree(rt)
168: register struct rtentry *rt;
169: {
170: register struct ifaddr *ifa;
171:
172: if (rt == 0)
173: panic("rtfree");
174: rt->rt_refcnt--;
175: if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
176: if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
177: panic ("rtfree 2");
178: rttrash--;
179: if (rt->rt_refcnt < 0) {
180: printf("rtfree: %x not freed (neg refs)\n",
181: (unsigned int)rt);
182: return;
183: }
184: ifa = rt->rt_ifa;
185: IFAFREE(ifa);
186: Free(rt_key(rt));
187: Free(rt);
188: }
189: }
190:
191: void
192: ifafree(ifa)
193: register struct ifaddr *ifa;
194: {
195: if (ifa == NULL)
196: panic("ifafree");
197: if (ifa->ifa_refcnt == 0)
198: _FREE(ifa, M_IFADDR);
199: else
200: ifa->ifa_refcnt--;
201: }
202:
203: /*
204: * Force a routing table entry to the specified
205: * destination to go through the given gateway.
206: * Normally called as a result of a routing redirect
207: * message from the network layer.
208: *
209: * N.B.: must be called at splnet
210: */
211: int
212: rtredirect(dst, gateway, netmask, flags, src, rtp)
213: struct sockaddr *dst, *gateway, *netmask, *src;
214: int flags;
215: struct rtentry **rtp;
216: {
217: register struct rtentry *rt;
218: int error = 0;
219: short *stat = 0;
220: struct rt_addrinfo info;
221: struct ifaddr *ifa;
222:
223: /* verify the gateway is directly reachable */
224: if ((ifa = ifa_ifwithnet(gateway)) == 0) {
225: error = ENETUNREACH;
226: goto out;
227: }
228: rt = rtalloc1(dst, 0);
229: /*
230: * If the redirect isn't from our current router for this dst,
231: * it's either old or wrong. If it redirects us to ourselves,
232: * we have a routing loop, perhaps as a result of an interface
233: * going down recently.
234: */
235: #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
236: if (!(flags & RTF_DONE) && rt &&
237: (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
238: error = EINVAL;
239: else if (ifa_ifwithaddr(gateway))
240: error = EHOSTUNREACH;
241: if (error)
242: goto done;
243: /*
244: * Create a new entry if we just got back a wildcard entry
245: * or the the lookup failed. This is necessary for hosts
246: * which use routing redirects generated by smart gateways
247: * to dynamically build the routing tables.
248: */
249: if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
250: goto create;
251: /*
252: * Don't listen to the redirect if it's
253: * for a route to an interface.
254: */
255: if (rt->rt_flags & RTF_GATEWAY) {
256: if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
257: /*
258: * Changing from route to net => route to host.
259: * Create new route, rather than smashing route to net.
260: */
261: create:
262: flags |= RTF_GATEWAY | RTF_DYNAMIC;
263: error = rtrequest((int)RTM_ADD, dst, gateway,
264: netmask, flags,
265: (struct rtentry **)0);
266: stat = &rtstat.rts_dynamic;
267: } else {
268: /*
269: * Smash the current notion of the gateway to
270: * this destination. Should check about netmask!!!
271: */
272: rt->rt_flags |= RTF_MODIFIED;
273: flags |= RTF_MODIFIED;
274: stat = &rtstat.rts_newgateway;
275: rt_setgate(rt, rt_key(rt), gateway);
276: }
277: } else
278: error = EHOSTUNREACH;
279: done:
280: if (rt) {
281: if (rtp && !error)
282: *rtp = rt;
283: else
284: rtfree(rt);
285: }
286: out:
287: if (error)
288: rtstat.rts_badredirect++;
289: else if (stat != NULL)
290: (*stat)++;
291: bzero((caddr_t)&info, sizeof(info));
292: info.rti_info[RTAX_DST] = dst;
293: info.rti_info[RTAX_GATEWAY] = gateway;
294: info.rti_info[RTAX_NETMASK] = netmask;
295: info.rti_info[RTAX_AUTHOR] = src;
296: rt_missmsg(RTM_REDIRECT, &info, flags, error);
297: return(0);
298: }
299:
300: /*
301: * Routing table ioctl interface.
302: */
303: int
304: rtioctl(req, data, p)
305: u_long req;
306: caddr_t data;
307: struct proc *p;
308: {
309: return (EOPNOTSUPP);
310: }
311:
312: struct ifaddr *
313: ifa_ifwithroute(flags, dst, gateway)
314: int flags;
315: struct sockaddr *dst, *gateway;
316: {
317: register struct ifaddr *ifa;
318: if ((flags & RTF_GATEWAY) == 0) {
319: /*
320: * If we are adding a route to an interface,
321: * and the interface is a pt to pt link
322: * we should search for the destination
323: * as our clue to the interface. Otherwise
324: * we can use the local address.
325: */
326: ifa = 0;
327: if (flags & RTF_HOST)
328: ifa = ifa_ifwithdstaddr(dst);
329: if (ifa == 0)
330: ifa = ifa_ifwithaddr(gateway);
331: } else {
332: /*
333: * If we are adding a route to a remote net
334: * or host, the gateway may still be on the
335: * other end of a pt to pt link.
336: */
337: ifa = ifa_ifwithdstaddr(gateway);
338: }
339: if (ifa == 0)
340: ifa = ifa_ifwithnet(gateway);
341: if (ifa == 0) {
342: struct rtentry *rt = rtalloc1(dst, 0);
343: if (rt == 0)
344: return (0);
345: rt->rt_refcnt--;
346: if ((ifa = rt->rt_ifa) == 0)
347: return (0);
348: }
349: if (ifa->ifa_addr->sa_family != dst->sa_family) {
350: struct ifaddr *oifa = ifa;
351: ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
352: if (ifa == 0)
353: ifa = oifa;
354: }
355: return (ifa);
356: }
357:
358: #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
359:
360: int
361: rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
362: int req, flags;
363: struct sockaddr *dst, *gateway, *netmask;
364: struct rtentry **ret_nrt;
365: {
366: int s = splnet(); int error = 0;
367: register struct rtentry *rt;
368: register struct radix_node *rn;
369: register struct radix_node_head *rnh;
370: struct ifaddr *ifa;
371: struct sockaddr *ndst;
372: #define senderr(x) { error = x ; goto bad; }
373:
374: if ((rnh = rt_tables[dst->sa_family]) == 0)
375: senderr(ESRCH);
376: if (flags & RTF_HOST)
377: netmask = 0;
378: switch (req) {
379: case RTM_DELETE:
380: if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
381: senderr(ESRCH);
382: if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
383: panic ("rtrequest delete");
384: rt = (struct rtentry *)rn;
385: rt->rt_flags &= ~RTF_UP;
386: if (rt->rt_gwroute) {
387: rt = rt->rt_gwroute; RTFREE(rt);
388: (rt = (struct rtentry *)rn)->rt_gwroute = 0;
389: }
390: if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
391: ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
392: rttrash++;
393: if (ret_nrt)
394: *ret_nrt = rt;
395: else if (rt->rt_refcnt <= 0) {
1.1.1.2 ! root 396: RTHOLD(rt);
1.1 root 397: rtfree(rt);
398: }
399: break;
400:
401: case RTM_RESOLVE:
402: if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
403: senderr(EINVAL);
404: ifa = rt->rt_ifa;
405: flags = rt->rt_flags & ~RTF_CLONING;
406: gateway = rt->rt_gateway;
407: if ((netmask = rt->rt_genmask) == 0)
408: flags |= RTF_HOST;
409: goto makeroute;
410:
411: case RTM_ADD:
412: if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
413: senderr(ENETUNREACH);
414: makeroute:
415: R_Malloc(rt, struct rtentry *, sizeof(*rt));
416: if (rt == 0)
417: senderr(ENOBUFS);
418: Bzero(rt, sizeof(*rt));
419: rt->rt_flags = RTF_UP | flags;
420: if (rt_setgate(rt, dst, gateway)) {
421: Free(rt);
422: senderr(ENOBUFS);
423: }
424: ndst = rt_key(rt);
425: if (netmask) {
426: rt_maskedcopy(dst, ndst, netmask);
427: } else
428: Bcopy(dst, ndst, dst->sa_len);
429: rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
430: rnh, rt->rt_nodes);
431: if (rn == 0) {
432: if (rt->rt_gwroute)
433: rtfree(rt->rt_gwroute);
434: Free(rt_key(rt));
435: Free(rt);
436: senderr(EEXIST);
437: }
1.1.1.2 ! root 438: if (++ifa->ifa_refcnt <= 0)
! 439: panic("rtrequest ifa_refcnt");
1.1 root 440: rt->rt_ifa = ifa;
441: rt->rt_ifp = ifa->ifa_ifp;
442: if (req == RTM_RESOLVE)
443: rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
444: if (ifa->ifa_rtrequest)
445: ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
446: if (ret_nrt) {
447: *ret_nrt = rt;
1.1.1.2 ! root 448: RTHOLD(rt);
1.1 root 449: }
450: break;
451: }
452: bad:
453: splx(s);
454: return (error);
455: }
456:
457: int
458: rt_setgate(rt0, dst, gate)
459: struct rtentry *rt0;
460: struct sockaddr *dst, *gate;
461: {
462: caddr_t new, old;
463: int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
464: register struct rtentry *rt = rt0;
465:
466: if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
467: old = (caddr_t)rt_key(rt);
468: R_Malloc(new, caddr_t, dlen + glen);
469: if (new == 0)
470: return 1;
471: rt->rt_nodes->rn_key = new;
472: } else {
473: new = rt->rt_nodes->rn_key;
474: old = 0;
475: }
476: Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
477: if (old) {
478: Bcopy(dst, new, dlen);
479: Free(old);
480: }
481: if (rt->rt_gwroute) {
482: rt = rt->rt_gwroute; RTFREE(rt);
483: rt = rt0; rt->rt_gwroute = 0;
484: }
485: if (rt->rt_flags & RTF_GATEWAY) {
486: rt->rt_gwroute = rtalloc1(gate, 1);
487: }
488: return 0;
489: }
490:
491: void
492: rt_maskedcopy(src, dst, netmask)
493: struct sockaddr *src, *dst, *netmask;
494: {
495: register u_char *cp1 = (u_char *)src;
496: register u_char *cp2 = (u_char *)dst;
497: register u_char *cp3 = (u_char *)netmask;
498: u_char *cplim = cp2 + *cp3;
499: u_char *cplim2 = cp2 + *cp1;
500:
501: *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
502: cp3 += 2;
503: if (cplim > cplim2)
504: cplim = cplim2;
505: while (cp2 < cplim)
506: *cp2++ = *cp1++ & *cp3++;
507: if (cp2 < cplim2)
508: bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
509: }
510:
511: /*
512: * Set up a routing table entry, normally
513: * for an interface.
514: */
515: int
516: rtinit(ifa, cmd, flags)
517: register struct ifaddr *ifa;
518: int cmd, flags;
519: {
520: register struct rtentry *rt;
521: register struct sockaddr *dst;
522: register struct sockaddr *deldst;
523: struct mbuf *m = 0;
524: struct rtentry *nrt = 0;
525: int error;
526:
527: dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
528: if (cmd == RTM_DELETE) {
529: if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
530: m = m_get(M_WAIT, MT_SONAME);
531: deldst = mtod(m, struct sockaddr *);
532: rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
533: dst = deldst;
534: }
535: if ((rt = rtalloc1(dst, 0))) {
536: rt->rt_refcnt--;
537: if (rt->rt_ifa != ifa) {
538: if (m)
539: (void) m_free(m);
540: return (flags & RTF_HOST ? EHOSTUNREACH
541: : ENETUNREACH);
542: }
543: }
544: }
545: error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
546: flags | ifa->ifa_flags, &nrt);
547: if (m)
548: (void) m_free(m);
549: if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
550: rt_newaddrmsg(cmd, ifa, error, nrt);
551: if (rt->rt_refcnt <= 0) {
1.1.1.2 ! root 552: RTHOLD(rt);
1.1 root 553: rtfree(rt);
554: }
555: }
556: if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
557: rt->rt_refcnt--;
558: if (rt->rt_ifa != ifa) {
559: printf("rtinit: wrong ifa (%x) was (%x)\n",
560: (unsigned int)ifa, (unsigned int)rt->rt_ifa);
561: if (rt->rt_ifa->ifa_rtrequest)
562: rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
563: IFAFREE(rt->rt_ifa);
564: rt->rt_ifa = ifa;
565: rt->rt_ifp = ifa->ifa_ifp;
1.1.1.2 ! root 566: if (++ifa->ifa_refcnt <= 0)
! 567: panic("rtinit ifa_refcnt");
1.1 root 568: if (ifa->ifa_rtrequest)
569: ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
570: }
571: rt_newaddrmsg(cmd, ifa, error, nrt);
572: }
573: return (error);
574: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.