|
|
1.1 root 1: /*
2: * Copyright (c) 1980, 1986 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: *
17: * @(#)route.c 7.4 (Berkeley) 6/27/88
18: */
19:
20: #include "param.h"
21: #include "systm.h"
22: #include "mbuf.h"
23: #include "protosw.h"
24: #include "socket.h"
25: #include "dir.h"
26: #include "user.h"
27: #include "ioctl.h"
28: #include "errno.h"
29:
30: #include "if.h"
31: #include "af.h"
32: #include "route.h"
33:
34: int rttrash; /* routes not in table but not freed */
35: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
36: int rthashsize = RTHASHSIZ; /* for netstat, etc. */
37:
38: /*
39: * Packet routing routines.
40: */
41: rtalloc(ro)
42: register struct route *ro;
43: {
44: register struct rtentry *rt;
45: register struct mbuf *m;
46: register u_long hash;
47: struct sockaddr *dst = &ro->ro_dst;
48: int (*match)(), doinghost, s;
49: struct afhash h;
50: u_int af = dst->sa_family;
51: struct mbuf **table;
52:
53: if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
54: return; /* XXX */
55: if (af >= AF_MAX)
56: return;
57: (*afswitch[af].af_hash)(dst, &h);
58: match = afswitch[af].af_netmatch;
59: hash = h.afh_hosthash, table = rthost, doinghost = 1;
60: s = splnet();
61: again:
62: for (m = table[RTHASHMOD(hash)]; m; m = m->m_next) {
63: rt = mtod(m, struct rtentry *);
64: if (rt->rt_hash != hash)
65: continue;
66: if ((rt->rt_flags & RTF_UP) == 0 ||
67: (rt->rt_ifp->if_flags & IFF_UP) == 0)
68: continue;
69: if (doinghost) {
70: if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst,
71: sizeof (*dst)))
72: continue;
73: } else {
74: if (rt->rt_dst.sa_family != af ||
75: !(*match)(&rt->rt_dst, dst))
76: continue;
77: }
78: rt->rt_refcnt++;
79: splx(s);
80: if (dst == &wildcard)
81: rtstat.rts_wildcard++;
82: ro->ro_rt = rt;
83: return;
84: }
85: if (doinghost) {
86: doinghost = 0;
87: hash = h.afh_nethash, table = rtnet;
88: goto again;
89: }
90: /*
91: * Check for wildcard gateway, by convention network 0.
92: */
93: if (dst != &wildcard) {
94: dst = &wildcard, hash = 0;
95: goto again;
96: }
97: splx(s);
98: rtstat.rts_unreach++;
99: }
100:
101: rtfree(rt)
102: register struct rtentry *rt;
103: {
104:
105: if (rt == 0)
106: panic("rtfree");
107: rt->rt_refcnt--;
108: if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
109: rttrash--;
110: (void) m_free(dtom(rt));
111: }
112: }
113:
114: /*
115: * Force a routing table entry to the specified
116: * destination to go through the given gateway.
117: * Normally called as a result of a routing redirect
118: * message from the network layer.
119: *
120: * N.B.: must be called at splnet or higher
121: *
122: */
123: rtredirect(dst, gateway, flags, src)
124: struct sockaddr *dst, *gateway, *src;
125: int flags;
126: {
127: struct route ro;
128: register struct rtentry *rt;
129:
130: /* verify the gateway is directly reachable */
131: if (ifa_ifwithnet(gateway) == 0) {
132: rtstat.rts_badredirect++;
133: return;
134: }
135: ro.ro_dst = *dst;
136: ro.ro_rt = 0;
137: rtalloc(&ro);
138: rt = ro.ro_rt;
139: #define equal(a1, a2) \
140: (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
141: /*
142: * If the redirect isn't from our current router for this dst,
143: * it's either old or wrong. If it redirects us to ourselves,
144: * we have a routing loop, perhaps as a result of an interface
145: * going down recently.
146: */
147: if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
148: rtstat.rts_badredirect++;
149: if (rt)
150: rtfree(rt);
151: return;
152: }
153: /*
154: * Create a new entry if we just got back a wildcard entry
155: * or the the lookup failed. This is necessary for hosts
156: * which use routing redirects generated by smart gateways
157: * to dynamically build the routing tables.
158: */
159: if (rt &&
160: (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
161: rtfree(rt);
162: rt = 0;
163: }
164: if (rt == 0) {
165: rtinit(dst, gateway, (int)SIOCADDRT,
166: (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
167: rtstat.rts_dynamic++;
168: return;
169: }
170: /*
171: * Don't listen to the redirect if it's
172: * for a route to an interface.
173: */
174: if (rt->rt_flags & RTF_GATEWAY) {
175: if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
176: /*
177: * Changing from route to net => route to host.
178: * Create new route, rather than smashing route to net.
179: */
180: rtinit(dst, gateway, (int)SIOCADDRT,
181: flags | RTF_DYNAMIC);
182: rtstat.rts_dynamic++;
183: } else {
184: /*
185: * Smash the current notion of the gateway to
186: * this destination.
187: */
188: rt->rt_gateway = *gateway;
189: rt->rt_flags |= RTF_MODIFIED;
190: rtstat.rts_newgateway++;
191: }
192: } else
193: rtstat.rts_badredirect++;
194: rtfree(rt);
195: }
196:
197: /*
198: * Routing table ioctl interface.
199: */
200: rtioctl(cmd, data)
201: int cmd;
202: caddr_t data;
203: {
204:
205: if (cmd != SIOCADDRT && cmd != SIOCDELRT)
206: return (EINVAL);
207: if (!suser())
208: return (u.u_error);
209: return (rtrequest(cmd, (struct rtentry *)data));
210: }
211:
212: /*
213: * Carry out a request to change the routing table. Called by
214: * interfaces at boot time to make their ``local routes'' known,
215: * for ioctl's, and as the result of routing redirects.
216: */
217: rtrequest(req, entry)
218: int req;
219: register struct rtentry *entry;
220: {
221: register struct mbuf *m, **mprev;
222: struct mbuf **mfirst;
223: register struct rtentry *rt;
224: struct afhash h;
225: int s, error = 0, (*match)();
226: u_int af;
227: u_long hash;
228: struct ifaddr *ifa;
229: struct ifaddr *ifa_ifwithdstaddr();
230:
231: af = entry->rt_dst.sa_family;
232: if (af >= AF_MAX)
233: return (EAFNOSUPPORT);
234: (*afswitch[af].af_hash)(&entry->rt_dst, &h);
235: if (entry->rt_flags & RTF_HOST) {
236: hash = h.afh_hosthash;
237: mprev = &rthost[RTHASHMOD(hash)];
238: } else {
239: hash = h.afh_nethash;
240: mprev = &rtnet[RTHASHMOD(hash)];
241: }
242: match = afswitch[af].af_netmatch;
243: s = splimp();
244: for (mfirst = mprev; m = *mprev; mprev = &m->m_next) {
245: rt = mtod(m, struct rtentry *);
246: if (rt->rt_hash != hash)
247: continue;
248: if (entry->rt_flags & RTF_HOST) {
249: if (!equal(&rt->rt_dst, &entry->rt_dst))
250: continue;
251: } else {
252: if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
253: (*match)(&rt->rt_dst, &entry->rt_dst) == 0)
254: continue;
255: }
256: if (equal(&rt->rt_gateway, &entry->rt_gateway))
257: break;
258: }
259: switch (req) {
260:
261: case SIOCDELRT:
262: if (m == 0) {
263: error = ESRCH;
264: goto bad;
265: }
266: *mprev = m->m_next;
267: if (rt->rt_refcnt > 0) {
268: rt->rt_flags &= ~RTF_UP;
269: rttrash++;
270: m->m_next = 0;
271: } else
272: (void) m_free(m);
273: break;
274:
275: case SIOCADDRT:
276: if (m) {
277: error = EEXIST;
278: goto bad;
279: }
280: if ((entry->rt_flags & RTF_GATEWAY) == 0) {
281: /*
282: * If we are adding a route to an interface,
283: * and the interface is a pt to pt link
284: * we should search for the destination
285: * as our clue to the interface. Otherwise
286: * we can use the local address.
287: */
288: ifa = 0;
289: if (entry->rt_flags & RTF_HOST)
290: ifa = ifa_ifwithdstaddr(&entry->rt_dst);
291: if (ifa == 0)
292: ifa = ifa_ifwithaddr(&entry->rt_gateway);
293: } else {
294: /*
295: * If we are adding a route to a remote net
296: * or host, the gateway may still be on the
297: * other end of a pt to pt link.
298: */
299: ifa = ifa_ifwithdstaddr(&entry->rt_gateway);
300: }
301: if (ifa == 0) {
302: ifa = ifa_ifwithnet(&entry->rt_gateway);
303: if (ifa == 0) {
304: error = ENETUNREACH;
305: goto bad;
306: }
307: }
308: m = m_get(M_DONTWAIT, MT_RTABLE);
309: if (m == 0) {
310: error = ENOBUFS;
311: goto bad;
312: }
313: m->m_next = *mfirst;
314: *mfirst = m;
315: m->m_off = MMINOFF;
316: m->m_len = sizeof (struct rtentry);
317: rt = mtod(m, struct rtentry *);
318: rt->rt_hash = hash;
319: rt->rt_dst = entry->rt_dst;
320: rt->rt_gateway = entry->rt_gateway;
321: rt->rt_flags = RTF_UP |
322: (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
323: rt->rt_refcnt = 0;
324: rt->rt_use = 0;
325: rt->rt_ifp = ifa->ifa_ifp;
326: break;
327: }
328: bad:
329: splx(s);
330: return (error);
331: }
332:
333: /*
334: * Set up a routing table entry, normally
335: * for an interface.
336: */
337: rtinit(dst, gateway, cmd, flags)
338: struct sockaddr *dst, *gateway;
339: int cmd, flags;
340: {
341: struct rtentry route;
342:
343: bzero((caddr_t)&route, sizeof (route));
344: route.rt_dst = *dst;
345: route.rt_gateway = *gateway;
346: route.rt_flags = flags;
347: (void) rtrequest(cmd, &route);
348: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.