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