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