File:
[DragonFly] /
src /
usr.sbin /
IPXrouted /
tables.c
Revision
1.3:
download - view:
text,
annotated -
select for diffs
Thu Mar 11 09:38:59 2004 UTC (9 years, 2 months ago) by
hmp
Branches:
MAIN
CVS tags:
HEAD,
DragonFly_Stable,
DragonFly_Snap29Sep2004,
DragonFly_Snap13Sep2004,
DragonFly_RELEASE_2_0_Slip,
DragonFly_RELEASE_2_0,
DragonFly_RELEASE_1_8_Slip,
DragonFly_RELEASE_1_8,
DragonFly_RELEASE_1_6_Slip,
DragonFly_RELEASE_1_6,
DragonFly_RELEASE_1_4_Slip,
DragonFly_RELEASE_1_4,
DragonFly_RELEASE_1_2_Slip,
DragonFly_RELEASE_1_2,
DragonFly_RELEASE_1_12_Slip,
DragonFly_RELEASE_1_12,
DragonFly_RELEASE_1_10_Slip,
DragonFly_RELEASE_1_10,
DragonFly_Preview,
DragonFly_1_0_REL,
DragonFly_1_0_RC1,
DragonFly_1_0A_REL
Convert the code to ANSI style, and remove 'register' keywords.
No functional changes.
Submitted by: Chris Pressey <cpressey@catseye.mine.nu>
(cpressey->commit_count++)
1: /*
2: * Copyright (c) 1985, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Copyright (c) 1995 John Hay. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
35: * $FreeBSD: src/usr.sbin/IPXrouted/tables.c,v 1.7 1999/08/28 01:15:05 peter Exp $
36: * $DragonFly: src/usr.sbin/IPXrouted/tables.c,v 1.3 2004/03/11 09:38:59 hmp Exp $
37: *
38: * @(#)tables.c 8.1 (Berkeley) 6/5/93
39: */
40:
41: /*
42: * Routing Table Management Daemon
43: */
44: #include "defs.h"
45: #include <sys/ioctl.h>
46: #include <errno.h>
47: #include <stdlib.h>
48: #include <unistd.h>
49:
50: #ifndef DEBUG
51: #define DEBUG 0
52: #endif
53:
54: #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
55:
56: int install = !DEBUG; /* if 1 call kernel */
57: int delete = 1;
58:
59: struct rthash nethash[ROUTEHASHSIZ];
60:
61: /*
62: * Lookup dst in the tables for an exact match.
63: */
64: struct rt_entry *
65: rtlookup(struct sockaddr *dst)
66: {
67: struct rt_entry *rt;
68: struct rthash *rh;
69: u_int hash;
70: struct afhash h;
71:
72: if (dst->sa_family >= AF_MAX)
73: return (0);
74: (*afswitch[dst->sa_family].af_hash)(dst, &h);
75: hash = h.afh_nethash;
76: rh = &nethash[hash & ROUTEHASHMASK];
77: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
78: if (rt->rt_hash != hash)
79: continue;
80: if (equal(&rt->rt_dst, dst))
81: return (rt);
82: }
83: return (0);
84: }
85:
86: /*
87: * Find a route to dst as the kernel would.
88: */
89: struct rt_entry *
90: rtfind(struct sockaddr *dst)
91: {
92: struct rt_entry *rt;
93: struct rthash *rh;
94: u_int hash;
95: struct afhash h;
96: int af = dst->sa_family;
97: int (*match)() = 0;
98:
99: if (af >= AF_MAX)
100: return (0);
101: (*afswitch[af].af_hash)(dst, &h);
102:
103: hash = h.afh_nethash;
104: rh = &nethash[hash & ROUTEHASHMASK];
105: match = afswitch[af].af_netmatch;
106: for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
107: if (rt->rt_hash != hash)
108: continue;
109: if (rt->rt_dst.sa_family == af &&
110: (*match)(&rt->rt_dst, dst))
111: return (rt);
112: }
113: return (0);
114: }
115:
116: void
117: rtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, short ticks,
118: int state)
119: {
120: struct afhash h;
121: struct rt_entry *rt;
122: struct rthash *rh;
123: int af = dst->sa_family, flags;
124: u_int hash;
125:
126: FIXLEN(dst);
127: FIXLEN(gate);
128: if (af >= AF_MAX)
129: return;
130: (*afswitch[af].af_hash)(dst, &h);
131: flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
132: hash = h.afh_nethash;
133: rh = &nethash[hash & ROUTEHASHMASK];
134: rt = (struct rt_entry *)malloc(sizeof (*rt));
135: if (rt == 0)
136: return;
137: rt->rt_hash = hash;
138: rt->rt_dst = *dst;
139: rt->rt_router = *gate;
140: rt->rt_metric = metric;
141: rt->rt_ticks = ticks;
142: rt->rt_timer = 0;
143: rt->rt_flags = RTF_UP | flags;
144: rt->rt_state = state | RTS_CHANGED;
145: rt->rt_ifp = if_ifwithnet(&rt->rt_router);
146: rt->rt_clone = NULL;
147: if (metric)
148: rt->rt_flags |= RTF_GATEWAY;
149: insque(rt, rh);
150: TRACE_ACTION("ADD", rt);
151: /*
152: * If the ioctl fails because the gateway is unreachable
153: * from this host, discard the entry. This should only
154: * occur because of an incorrect entry in /etc/gateways.
155: */
156: if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
157: if (errno != EEXIST)
158: perror("SIOCADDRT");
159: if (errno == ENETUNREACH) {
160: TRACE_ACTION("DELETE", rt);
161: remque(rt);
162: free((char *)rt);
163: }
164: }
165: }
166:
167: void
168: rtadd_clone(struct rt_entry *ort, struct sockaddr *dst, struct sockaddr *gate,
169: short metric, short ticks, int state)
170: {
171: struct afhash h;
172: struct rt_entry *rt;
173: struct rthash *rh;
174: int af = dst->sa_family, flags;
175: u_int hash;
176:
177: FIXLEN(dst);
178: FIXLEN(gate);
179: if (af >= AF_MAX)
180: return;
181: (*afswitch[af].af_hash)(dst, &h);
182: flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
183: hash = h.afh_nethash;
184: rh = &nethash[hash & ROUTEHASHMASK];
185: rt = (struct rt_entry *)malloc(sizeof (*rt));
186: if (rt == 0)
187: return;
188: rt->rt_hash = hash;
189: rt->rt_dst = *dst;
190: rt->rt_router = *gate;
191: rt->rt_metric = metric;
192: rt->rt_ticks = ticks;
193: rt->rt_timer = 0;
194: rt->rt_flags = RTF_UP | flags;
195: rt->rt_state = state | RTS_CHANGED;
196: rt->rt_ifp = if_ifwithnet(&rt->rt_router);
197: rt->rt_clone = NULL;
198: rt->rt_forw = NULL;
199: rt->rt_back = NULL;
200: if (metric)
201: rt->rt_flags |= RTF_GATEWAY;
202:
203: while(ort->rt_clone != NULL)
204: ort = ort->rt_clone;
205: ort->rt_clone = rt;
206: TRACE_ACTION("ADD_CLONE", rt);
207: }
208:
209: void
210: rtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, short ticks)
211: {
212: int doioctl = 0, metricchanged = 0;
213: struct rtuentry oldroute;
214:
215: FIXLEN(gate);
216: /*
217: * Handling of clones.
218: * When the route changed and it had clones, handle it special.
219: * 1. If the new route is cheaper than the clone(s), free the clones.
220: * 2. If the new route is the same cost, it may be one of the clones,
221: * search for it and free it.
222: * 3. If the new route is more expensive than the clone(s), use the
223: * values of the clone(s).
224: */
225: if (rt->rt_clone) {
226: if ((ticks < rt->rt_clone->rt_ticks) ||
227: ((ticks == rt->rt_clone->rt_ticks) &&
228: (metric < rt->rt_clone->rt_metric))) {
229: /*
230: * Free all clones.
231: */
232: struct rt_entry *trt, *nrt;
233:
234: trt = rt->rt_clone;
235: rt->rt_clone = NULL;
236: while(trt) {
237: nrt = trt->rt_clone;
238: free((char *)trt);
239: trt = nrt;
240: }
241: } else if ((ticks == rt->rt_clone->rt_ticks) &&
242: (metric == rt->rt_clone->rt_metric)) {
243: struct rt_entry *prt, *trt;
244:
245: prt = rt;
246: trt = rt->rt_clone;
247:
248: while(trt) {
249: if (equal(&trt->rt_router, gate)) {
250: prt->rt_clone = trt->rt_clone;
251: free(trt);
252: trt = prt->rt_clone;
253: } else {
254: prt = trt;
255: trt = trt->rt_clone;
256: }
257: }
258: } else {
259: /*
260: * Use the values of the first clone.
261: * Delete the corresponding clone.
262: */
263: struct rt_entry *trt;
264:
265: trt = rt->rt_clone;
266: rt->rt_clone = rt->rt_clone->rt_clone;
267: metric = trt->rt_metric;
268: ticks = trt->rt_ticks;
269: *gate = trt->rt_router;
270: free((char *)trt);
271: }
272: }
273:
274: if (!equal(&rt->rt_router, gate))
275: doioctl++;
276: if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
277: metricchanged++;
278: if (doioctl || metricchanged) {
279: TRACE_ACTION("CHANGE FROM", rt);
280: if (doioctl) {
281: oldroute = rt->rt_rt;
282: rt->rt_router = *gate;
283: }
284: rt->rt_metric = metric;
285: rt->rt_ticks = ticks;
286: if ((rt->rt_state & RTS_INTERFACE) && metric) {
287: rt->rt_state &= ~RTS_INTERFACE;
288: if(rt->rt_ifp)
289: syslog(LOG_ERR,
290: "changing route from interface %s (timed out)",
291: rt->rt_ifp->int_name);
292: else
293: syslog(LOG_ERR,
294: "changing route from interface ??? (timed out)");
295: }
296: if (metric)
297: rt->rt_flags |= RTF_GATEWAY;
298: else
299: rt->rt_flags &= ~RTF_GATEWAY;
300: rt->rt_ifp = if_ifwithnet(&rt->rt_router);
301: rt->rt_state |= RTS_CHANGED;
302: TRACE_ACTION("CHANGE TO", rt);
303: }
304: if (doioctl && install) {
305: #ifndef RTM_ADD
306: if (rtioctl(ADD, &rt->rt_rt) < 0)
307: syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
308: ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
309: ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
310: if (delete && rtioctl(DELETE, &oldroute) < 0)
311: perror("rtioctl DELETE");
312: #else
313: if (delete == 0) {
314: if (rtioctl(ADD, &rt->rt_rt) >= 0)
315: return;
316: } else {
317: if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
318: return;
319: }
320: syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
321: ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
322: ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
323: #endif
324: }
325: }
326:
327: void
328: rtdelete(struct rt_entry *rt)
329: {
330: struct sockaddr *sa = &(rt->rt_router);
331:
332: FIXLEN(sa);
333: sa = &(rt->rt_dst);
334: FIXLEN(sa);
335: if (rt->rt_clone) {
336: /*
337: * If there is a clone we just do a rt_change to it.
338: */
339: struct rt_entry *trt = rt->rt_clone;
340: rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
341: return;
342: }
343: if (rt->rt_state & RTS_INTERFACE) {
344: if (rt->rt_ifp)
345: syslog(LOG_ERR,
346: "deleting route to interface %s (timed out)",
347: rt->rt_ifp->int_name);
348: else
349: syslog(LOG_ERR,
350: "deleting route to interface ??? (timed out)");
351: }
352: TRACE_ACTION("DELETE", rt);
353: if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
354: perror("rtioctl DELETE");
355: remque(rt);
356: free((char *)rt);
357: }
358:
359: void
360: rtinit(void)
361: {
362: struct rthash *rh;
363:
364: for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
365: rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
366: }
367: int seqno;
368:
369: int
370: rtioctl(int action, struct rtuentry *ort)
371: {
372: #ifndef RTM_ADD
373: if (install == 0)
374: return (errno = 0);
375:
376: ort->rtu_rtflags = ort->rtu_flags;
377:
378: switch (action) {
379:
380: case ADD:
381: return (ioctl(s, SIOCADDRT, (char *)ort));
382:
383: case DELETE:
384: return (ioctl(s, SIOCDELRT, (char *)ort));
385:
386: default:
387: return (-1);
388: }
389: #else /* RTM_ADD */
390: struct {
391: struct rt_msghdr w_rtm;
392: struct sockaddr w_dst;
393: struct sockaddr w_gate;
394: struct sockaddr_ipx w_netmask;
395: } w;
396: #define rtm w.w_rtm
397:
398: bzero((char *)&w, sizeof(w));
399: rtm.rtm_msglen = sizeof(w);
400: rtm.rtm_version = RTM_VERSION;
401: rtm.rtm_type = (action == ADD ? RTM_ADD :
402: (action == DELETE ? RTM_DELETE : RTM_CHANGE));
403: rtm.rtm_flags = ort->rtu_flags;
404: rtm.rtm_seq = ++seqno;
405: rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
406: bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
407: bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
408: w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
409: w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
410: if (rtm.rtm_flags & RTF_HOST) {
411: rtm.rtm_msglen -= sizeof(w.w_netmask);
412: } else {
413: rtm.rtm_addrs |= RTA_NETMASK;
414: w.w_netmask = ipx_netmask;
415: rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
416: }
417: errno = 0;
418: return write(r, (char *)&w, rtm.rtm_msglen);
419: #endif /* RTM_ADD */
420: }