xref: /original-bsd/sbin/XNSrouted/tables.c (revision c02b9ad6)
1 /*
2  * Copyright (c) 1985 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)tables.c	5.7 (Berkeley) 09/20/88";
20 #endif /* not lint */
21 
22 /*
23  * Routing Table Management Daemon
24  */
25 #include "defs.h"
26 #include <sys/ioctl.h>
27 #include <errno.h>
28 
29 #ifndef DEBUG
30 #define	DEBUG	0
31 #endif
32 
33 extern	char *xns_ntoa();
34 
35 int	install = !DEBUG;		/* if 1 call kernel */
36 int	delete = 1;
37 /*
38  * Lookup dst in the tables for an exact match.
39  */
40 struct rt_entry *
41 rtlookup(dst)
42 	struct sockaddr *dst;
43 {
44 	register struct rt_entry *rt;
45 	register struct rthash *rh;
46 	register u_int hash;
47 	struct afhash h;
48 	int doinghost = 1;
49 
50 	if (dst->sa_family >= AF_MAX)
51 		return (0);
52 	(*afswitch[dst->sa_family].af_hash)(dst, &h);
53 	hash = h.afh_hosthash;
54 	rh = &hosthash[hash & ROUTEHASHMASK];
55 again:
56 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
57 		if (rt->rt_hash != hash)
58 			continue;
59 		if (equal(&rt->rt_dst, dst))
60 			return (rt);
61 	}
62 	if (doinghost) {
63 		doinghost = 0;
64 		hash = h.afh_nethash;
65 		rh = &nethash[hash & ROUTEHASHMASK];
66 		goto again;
67 	}
68 	return (0);
69 }
70 
71 /*
72  * Find a route to dst as the kernel would.
73  */
74 struct rt_entry *
75 rtfind(dst)
76 	struct sockaddr *dst;
77 {
78 	register struct rt_entry *rt;
79 	register struct rthash *rh;
80 	register u_int hash;
81 	struct afhash h;
82 	int af = dst->sa_family;
83 	int doinghost = 1, (*match)();
84 
85 	if (af >= AF_MAX)
86 		return (0);
87 	(*afswitch[af].af_hash)(dst, &h);
88 	hash = h.afh_hosthash;
89 	rh = &hosthash[hash & ROUTEHASHMASK];
90 
91 again:
92 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
93 		if (rt->rt_hash != hash)
94 			continue;
95 		if (doinghost) {
96 			if (equal(&rt->rt_dst, dst))
97 				return (rt);
98 		} else {
99 			if (rt->rt_dst.sa_family == af &&
100 			    (*match)(&rt->rt_dst, dst))
101 				return (rt);
102 		}
103 	}
104 	if (doinghost) {
105 		doinghost = 0;
106 		hash = h.afh_nethash;
107 		rh = &nethash[hash & ROUTEHASHMASK];
108 		match = afswitch[af].af_netmatch;
109 		goto again;
110 	}
111 	return (0);
112 }
113 
114 rtadd(dst, gate, metric, state)
115 	struct sockaddr *dst, *gate;
116 	int metric, state;
117 {
118 	struct afhash h;
119 	register struct rt_entry *rt;
120 	struct rthash *rh;
121 	int af = dst->sa_family, flags;
122 	u_int hash;
123 
124 	if (af >= AF_MAX)
125 		return;
126 	(*afswitch[af].af_hash)(dst, &h);
127 	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
128 	if (flags & RTF_HOST) {
129 		hash = h.afh_hosthash;
130 		rh = &hosthash[hash & ROUTEHASHMASK];
131 	} else {
132 		hash = h.afh_nethash;
133 		rh = &nethash[hash & ROUTEHASHMASK];
134 	}
135 	rt = (struct rt_entry *)malloc(sizeof (*rt));
136 	if (rt == 0)
137 		return;
138 	rt->rt_hash = hash;
139 	rt->rt_dst = *dst;
140 	rt->rt_router = *gate;
141 	rt->rt_metric = metric;
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 	if (metric)
147 		rt->rt_flags |= RTF_GATEWAY;
148 	insque(rt, rh);
149 	TRACE_ACTION(ADD, rt);
150 	/*
151 	 * If the ioctl fails because the gateway is unreachable
152 	 * from this host, discard the entry.  This should only
153 	 * occur because of an incorrect entry in /etc/gateways.
154 	 */
155 	if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
156 		if (errno != EEXIST)
157 			perror("SIOCADDRT");
158 		if (errno == ENETUNREACH) {
159 			TRACE_ACTION(DELETE, rt);
160 			remque(rt);
161 			free((char *)rt);
162 		}
163 	}
164 }
165 
166 rtchange(rt, gate, metric)
167 	struct rt_entry *rt;
168 	struct sockaddr *gate;
169 	short metric;
170 {
171 	int doioctl = 0, metricchanged = 0;
172 	struct rtentry oldroute;
173 
174 	if (!equal(&rt->rt_router, gate))
175 		doioctl++;
176 	if (metric != rt->rt_metric)
177 		metricchanged++;
178 	if (doioctl || metricchanged) {
179 		TRACE_ACTION(CHANGE FROM, rt);
180 		if (doioctl) {
181 			oldroute = rt->rt_rt;
182 			rt->rt_router = *gate;
183 		}
184 		rt->rt_metric = metric;
185 		if ((rt->rt_state & RTS_INTERFACE) && metric) {
186 			rt->rt_state &= ~RTS_INTERFACE;
187 			syslog(LOG_ERR,
188 				"changing route from interface %s (timed out)",
189 				rt->rt_ifp->int_name);
190 		}
191 		if (metric)
192 			rt->rt_flags |= RTF_GATEWAY;
193 		else
194 			rt->rt_flags &= ~RTF_GATEWAY;
195 		rt->rt_state |= RTS_CHANGED;
196 		TRACE_ACTION(CHANGE TO, rt);
197 	}
198 	if (doioctl && install) {
199 		if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
200 		  syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
201 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
202 		   xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
203 		if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
204 			perror("SIOCDELRT");
205 	}
206 }
207 
208 rtdelete(rt)
209 	struct rt_entry *rt;
210 {
211 
212 	if (rt->rt_state & RTS_INTERFACE) {
213 		syslog(LOG_ERR, "deleting route to interface %s (timed out)",
214 			rt->rt_ifp->int_name);
215 	}
216 	TRACE_ACTION(DELETE, rt);
217 	if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
218 		perror("SIOCDELRT");
219 	remque(rt);
220 	free((char *)rt);
221 }
222 
223 rtinit()
224 {
225 	register struct rthash *rh;
226 
227 	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
228 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
229 	for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
230 		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
231 }
232