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