xref: /csrg-svn/sbin/XNSrouted/tables.c (revision 30350)
1 /*
2  * Copyright (c) 1985 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  */
7 
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)tables.c	5.6 (Berkeley) 12/30/86";
11 #endif not lint
12 
13 /*
14  * Routing Table Management Daemon
15  */
16 #include "defs.h"
17 #include <sys/ioctl.h>
18 #include <errno.h>
19 
20 #ifndef DEBUG
21 #define	DEBUG	0
22 #endif
23 
24 extern	char *xns_ntoa();
25 
26 int	install = !DEBUG;		/* if 1 call kernel */
27 int	delete = 1;
28 /*
29  * Lookup dst in the tables for an exact match.
30  */
31 struct rt_entry *
32 rtlookup(dst)
33 	struct sockaddr *dst;
34 {
35 	register struct rt_entry *rt;
36 	register struct rthash *rh;
37 	register u_int hash;
38 	struct afhash h;
39 	int doinghost = 1;
40 
41 	if (dst->sa_family >= AF_MAX)
42 		return (0);
43 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
44 	hash = h.afh_hosthash;
45 	rh = &hosthash[hash & ROUTEHASHMASK];
46 again:
47 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
48 		if (rt->rt_hash != hash)
49 			continue;
50 		if (equal(&rt->rt_dst, dst))
51 			return (rt);
52 	}
53 	if (doinghost) {
54 		doinghost = 0;
55 		hash = h.afh_nethash;
56 		rh = &nethash[hash & ROUTEHASHMASK];
57 		goto again;
58 	}
59 	return (0);
60 }
61 
62 /*
63  * Find a route to dst as the kernel would.
64  */
65 struct rt_entry *
66 rtfind(dst)
67 	struct sockaddr *dst;
68 {
69 	register struct rt_entry *rt;
70 	register struct rthash *rh;
71 	register u_int hash;
72 	struct afhash h;
73 	int af = dst->sa_family;
74 	int doinghost = 1, (*match)();
75 
76 	if (af >= AF_MAX)
77 		return (0);
78 	(*afswitch[af].af_hash)(dst, &h);
79 	hash = h.afh_hosthash;
80 	rh = &hosthash[hash & ROUTEHASHMASK];
81 
82 again:
83 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
84 		if (rt->rt_hash != hash)
85 			continue;
86 		if (doinghost) {
87 			if (equal(&rt->rt_dst, dst))
88 				return (rt);
89 		} else {
90 			if (rt->rt_dst.sa_family == af &&
91 			    (*match)(&rt->rt_dst, dst))
92 				return (rt);
93 		}
94 	}
95 	if (doinghost) {
96 		doinghost = 0;
97 		hash = h.afh_nethash;
98 		rh = &nethash[hash & ROUTEHASHMASK];
99 		match = afswitch[af].af_netmatch;
100 		goto again;
101 	}
102 	return (0);
103 }
104 
105 rtadd(dst, gate, metric, state)
106 	struct sockaddr *dst, *gate;
107 	int metric, state;
108 {
109 	struct afhash h;
110 	register struct rt_entry *rt;
111 	struct rthash *rh;
112 	int af = dst->sa_family, flags;
113 	u_int hash;
114 
115 	if (af >= AF_MAX)
116 		return;
117 	(*afswitch[af].af_hash)(dst, &h);
118 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
119 	if (flags & RTF_HOST) {
120 		hash = h.afh_hosthash;
121 		rh = &hosthash[hash & ROUTEHASHMASK];
122 	} else {
123 		hash = h.afh_nethash;
124 		rh = &nethash[hash & ROUTEHASHMASK];
125 	}
126 	rt = (struct rt_entry *)malloc(sizeof (*rt));
127 	if (rt == 0)
128 		return;
129 	rt->rt_hash = hash;
130 	rt->rt_dst = *dst;
131 	rt->rt_router = *gate;
132 	rt->rt_metric = metric;
133 	rt->rt_timer = 0;
134 	rt->rt_flags = RTF_UP | flags;
135 	rt->rt_state = state | RTS_CHANGED;
136 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
137 	if (metric)
138 		rt->rt_flags |= RTF_GATEWAY;
139 	insque(rt, rh);
140 	TRACE_ACTION(ADD, rt);
141 	/*
142 	 * If the ioctl fails because the gateway is unreachable
143 	 * from this host, discard the entry.  This should only
144 	 * occur because of an incorrect entry in /etc/gateways.
145 	 */
146 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
147 		if (errno != EEXIST)
148 			perror("SIOCADDRT");
149 		if (errno == ENETUNREACH) {
150 			TRACE_ACTION(DELETE, rt);
151 			remque(rt);
152 			free((char *)rt);
153 		}
154 	}
155 }
156 
157 rtchange(rt, gate, metric)
158 	struct rt_entry *rt;
159 	struct sockaddr *gate;
160 	short metric;
161 {
162 	int doioctl = 0, metricchanged = 0;
163 	struct rtentry oldroute;
164 
165 	if (!equal(&rt->rt_router, gate))
166 		doioctl++;
167 	if (metric != rt->rt_metric)
168 		metricchanged++;
169 	if (doioctl || metricchanged) {
170 		TRACE_ACTION(CHANGE FROM, rt);
171 		if (doioctl) {
172 			oldroute = rt->rt_rt;
173 			rt->rt_router = *gate;
174 		}
175 		rt->rt_metric = metric;
176 		if ((rt->rt_state & RTS_INTERFACE) && metric) {
177 			rt->rt_state &= ~RTS_INTERFACE;
178 			syslog(LOG_ERR,
179 				"changing route from interface %s (timed out)",
180 				rt->rt_ifp->int_name);
181 		}
182 		if (metric)
183 			rt->rt_flags |= RTF_GATEWAY;
184 		else
185 			rt->rt_flags &= ~RTF_GATEWAY;
186 		rt->rt_state |= RTS_CHANGED;
187 		TRACE_ACTION(CHANGE TO, rt);
188 	}
189 	if (doioctl && install) {
190 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
191 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
192 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
193 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
194 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
195 			perror("SIOCDELRT");
196 	}
197 }
198 
199 rtdelete(rt)
200 	struct rt_entry *rt;
201 {
202 
203 	if (rt->rt_state & RTS_INTERFACE) {
204 		syslog(LOG_ERR, "deleting route to interface %s (timed out)",
205 			rt->rt_ifp->int_name);
206 	}
207 	TRACE_ACTION(DELETE, rt);
208 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
209 		perror("SIOCDELRT");
210 	remque(rt);
211 	free((char *)rt);
212 }
213 
214 rtinit()
215 {
216 	register struct rthash *rh;
217 
218 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
219 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
220 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
221 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
222 }
223