xref: /original-bsd/sbin/XNSrouted/tables.c (revision e59fb703)
1 /*
2  * Copyright (c) 1985 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)tables.c	5.9 (Berkeley) 06/01/90";
10 #endif /* not lint */
11 
12 /*
13  * Routing Table Management Daemon
14  */
15 #include "defs.h"
16 #include <sys/ioctl.h>
17 #include <errno.h>
18 
19 #ifndef DEBUG
20 #define	DEBUG	0
21 #endif
22 
23 extern	char *xns_ntoa();
24 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
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 	FIXLEN(dst);
116 	FIXLEN(gate);
117 	if (af >= AF_MAX)
118 		return;
119 	(*afswitch[af].af_hash)(dst, &h);
120 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
121 	if (flags & RTF_HOST) {
122 		hash = h.afh_hosthash;
123 		rh = &hosthash[hash & ROUTEHASHMASK];
124 	} else {
125 		hash = h.afh_nethash;
126 		rh = &nethash[hash & ROUTEHASHMASK];
127 	}
128 	rt = (struct rt_entry *)malloc(sizeof (*rt));
129 	if (rt == 0)
130 		return;
131 	rt->rt_hash = hash;
132 	rt->rt_dst = *dst;
133 	rt->rt_router = *gate;
134 	rt->rt_metric = metric;
135 	rt->rt_timer = 0;
136 	rt->rt_flags = RTF_UP | flags;
137 	rt->rt_state = state | RTS_CHANGED;
138 	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
139 	if (metric)
140 		rt->rt_flags |= RTF_GATEWAY;
141 	insque(rt, rh);
142 	TRACE_ACTION(ADD, rt);
143 	/*
144 	 * If the ioctl fails because the gateway is unreachable
145 	 * from this host, discard the entry.  This should only
146 	 * occur because of an incorrect entry in /etc/gateways.
147 	 */
148 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
149 		if (errno != EEXIST)
150 			perror("SIOCADDRT");
151 		if (errno == ENETUNREACH) {
152 			TRACE_ACTION(DELETE, rt);
153 			remque(rt);
154 			free((char *)rt);
155 		}
156 	}
157 }
158 
159 rtchange(rt, gate, metric)
160 	struct rt_entry *rt;
161 	struct sockaddr *gate;
162 	short metric;
163 {
164 	int doioctl = 0, metricchanged = 0;
165 	struct rtentry oldroute;
166 
167 	FIXLEN(gate);
168 	if (!equal(&rt->rt_router, gate))
169 		doioctl++;
170 	if (metric != rt->rt_metric)
171 		metricchanged++;
172 	if (doioctl || metricchanged) {
173 		TRACE_ACTION(CHANGE FROM, rt);
174 		if (doioctl) {
175 			oldroute = rt->rt_rt;
176 			rt->rt_router = *gate;
177 		}
178 		rt->rt_metric = metric;
179 		if ((rt->rt_state & RTS_INTERFACE) && metric) {
180 			rt->rt_state &= ~RTS_INTERFACE;
181 			syslog(LOG_ERR,
182 				"changing route from interface %s (timed out)",
183 				rt->rt_ifp->int_name);
184 		}
185 		if (metric)
186 			rt->rt_flags |= RTF_GATEWAY;
187 		else
188 			rt->rt_flags &= ~RTF_GATEWAY;
189 		rt->rt_state |= RTS_CHANGED;
190 		TRACE_ACTION(CHANGE TO, rt);
191 	}
192 	if (doioctl && install) {
193 #ifndef RTM_ADD
194 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
195 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
196 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
197 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
198 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
199 			perror("SIOCDELRT");
200 #else
201 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
202 			perror("SIOCDELRT");
203 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
204 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
205 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
206 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
207 #endif
208 	}
209 }
210 
211 rtdelete(rt)
212 	struct rt_entry *rt;
213 {
214 
215 	struct sockaddr *sa = &(rt->rt_rt.rt_gateway);
216 	FIXLEN(sa);
217 #undef rt_dst
218 	sa = &(rt->rt_rt.rt_dst);
219 	FIXLEN(sa);
220 	if (rt->rt_state & RTS_INTERFACE) {
221 		syslog(LOG_ERR, "deleting route to interface %s (timed out)",
222 			rt->rt_ifp->int_name);
223 	}
224 	TRACE_ACTION(DELETE, rt);
225 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
226 		perror("SIOCDELRT");
227 	remque(rt);
228 	free((char *)rt);
229 }
230 
231 rtinit()
232 {
233 	register struct rthash *rh;
234 
235 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
236 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
237 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
238 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
239 }
240