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