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