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