hash_open -> db_open, delete R_PUT flag
[unix-history] / usr / src / sbin / routed / tables.c
CommitLineData
5ff67f98 1/*
9c2cb70b 2 * Copyright (c) 1983, 1988 Regents of the University of California.
0eb85d71
KB
3 * All rights reserved.
4 *
d60d530a 5 * %sccs.include.redist.c%
5ff67f98
DF
6 */
7
b9b7b06a 8#ifndef lint
d60d530a 9static char sccsid[] = "@(#)tables.c 5.17 (Berkeley) %G%";
0eb85d71 10#endif /* not lint */
b9b7b06a
SL
11
12/*
13 * Routing Table Management Daemon
14 */
7fe7fe74 15#include "defs.h"
b9b7b06a
SL
16#include <sys/ioctl.h>
17#include <errno.h>
9c2cb70b 18#include <sys/syslog.h>
b9b7b06a
SL
19
20#ifndef DEBUG
21#define DEBUG 0
22#endif
23
a33a5c17
KS
24#ifdef RTM_ADD
25#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
26#else
27#define FIXLEN(s) { }
28#endif
29
b9b7b06a
SL
30int install = !DEBUG; /* if 1 call kernel */
31
32/*
33 * Lookup dst in the tables for an exact match.
34 */
35struct rt_entry *
36rtlookup(dst)
37 struct sockaddr *dst;
38{
39 register struct rt_entry *rt;
40 register struct rthash *rh;
d5568f13 41 register u_int hash;
b9b7b06a
SL
42 struct afhash h;
43 int doinghost = 1;
44
17fe297f 45 if (dst->sa_family >= af_max)
b9b7b06a
SL
46 return (0);
47 (*afswitch[dst->sa_family].af_hash)(dst, &h);
48 hash = h.afh_hosthash;
49139b80 49 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
50again:
51 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
52 if (rt->rt_hash != hash)
53 continue;
54 if (equal(&rt->rt_dst, dst))
55 return (rt);
56 }
57 if (doinghost) {
58 doinghost = 0;
59 hash = h.afh_nethash;
49139b80 60 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
61 goto again;
62 }
63 return (0);
64}
65
9c2cb70b
MK
66struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
67
b9b7b06a
SL
68/*
69 * Find a route to dst as the kernel would.
70 */
71struct rt_entry *
72rtfind(dst)
73 struct sockaddr *dst;
74{
75 register struct rt_entry *rt;
76 register struct rthash *rh;
d5568f13 77 register u_int hash;
b9b7b06a
SL
78 struct afhash h;
79 int af = dst->sa_family;
80 int doinghost = 1, (*match)();
81
17fe297f 82 if (af >= af_max)
b9b7b06a
SL
83 return (0);
84 (*afswitch[af].af_hash)(dst, &h);
85 hash = h.afh_hosthash;
49139b80 86 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
87
88again:
89 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
90 if (rt->rt_hash != hash)
91 continue;
92 if (doinghost) {
93 if (equal(&rt->rt_dst, dst))
94 return (rt);
95 } else {
96 if (rt->rt_dst.sa_family == af &&
97 (*match)(&rt->rt_dst, dst))
98 return (rt);
99 }
100 }
101 if (doinghost) {
102 doinghost = 0;
103 hash = h.afh_nethash;
49139b80 104 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
105 match = afswitch[af].af_netmatch;
106 goto again;
107 }
9c2cb70b
MK
108#ifdef notyet
109 /*
110 * Check for wildcard gateway, by convention network 0.
111 */
112 if (dst != &wildcard) {
113 dst = &wildcard, hash = 0;
114 goto again;
115 }
116#endif
b9b7b06a
SL
117 return (0);
118}
119
120rtadd(dst, gate, metric, state)
121 struct sockaddr *dst, *gate;
122 int metric, state;
123{
124 struct afhash h;
125 register struct rt_entry *rt;
126 struct rthash *rh;
7892134c 127 int af = dst->sa_family, flags;
d5568f13 128 u_int hash;
b9b7b06a 129
17fe297f 130 if (af >= af_max)
b9b7b06a
SL
131 return;
132 (*afswitch[af].af_hash)(dst, &h);
4fad5a6e
MK
133 flags = (*afswitch[af].af_rtflags)(dst);
134 /*
135 * Subnet flag isn't visible to kernel, move to state. XXX
136 */
a33a5c17
KS
137 FIXLEN(dst);
138 FIXLEN(gate);
4fad5a6e
MK
139 if (flags & RTF_SUBNET) {
140 state |= RTS_SUBNET;
141 flags &= ~RTF_SUBNET;
142 }
b9b7b06a
SL
143 if (flags & RTF_HOST) {
144 hash = h.afh_hosthash;
49139b80 145 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
146 } else {
147 hash = h.afh_nethash;
49139b80 148 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
149 }
150 rt = (struct rt_entry *)malloc(sizeof (*rt));
151 if (rt == 0)
152 return;
153 rt->rt_hash = hash;
154 rt->rt_dst = *dst;
155 rt->rt_router = *gate;
b9b7b06a
SL
156 rt->rt_timer = 0;
157 rt->rt_flags = RTF_UP | flags;
158 rt->rt_state = state | RTS_CHANGED;
a33a5c17 159 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
4fad5a6e
MK
160 if (rt->rt_ifp == 0)
161 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
88709531 162 if ((state & RTS_INTERFACE) == 0)
b9b7b06a 163 rt->rt_flags |= RTF_GATEWAY;
7892134c 164 rt->rt_metric = metric;
b9b7b06a 165 insque(rt, rh);
9c2cb70b 166 TRACE_ACTION("ADD", rt);
a8d9e287
SL
167 /*
168 * If the ioctl fails because the gateway is unreachable
169 * from this host, discard the entry. This should only
170 * occur because of an incorrect entry in /etc/gateways.
171 */
4fad5a6e
MK
172 if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
173 ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
7892134c 174 if (errno != EEXIST && gate->sa_family < af_max)
c766cf31
MK
175 syslog(LOG_ERR,
176 "adding route to net/host %s through gateway %s: %m\n",
177 (*afswitch[dst->sa_family].af_format)(dst),
178 (*afswitch[gate->sa_family].af_format)(gate));
b9b7b06a 179 perror("SIOCADDRT");
a8d9e287 180 if (errno == ENETUNREACH) {
9c2cb70b 181 TRACE_ACTION("DELETE", rt);
a8d9e287
SL
182 remque(rt);
183 free((char *)rt);
184 }
185 }
b9b7b06a
SL
186}
187
188rtchange(rt, gate, metric)
189 struct rt_entry *rt;
190 struct sockaddr *gate;
191 short metric;
192{
4033c8f6 193 int add = 0, delete = 0, newgateway = 0;
b9b7b06a
SL
194 struct rtentry oldroute;
195
a33a5c17
KS
196 FIXLEN(gate);
197 FIXLEN(&(rt->rt_router));
198 FIXLEN(&(rt->rt_dst));
4033c8f6
MK
199 if (!equal(&rt->rt_router, gate)) {
200 newgateway++;
201 TRACE_ACTION("CHANGE FROM ", rt);
202 } else if (metric != rt->rt_metric)
203 TRACE_NEWMETRIC(rt, metric);
7892134c
MK
204 if ((rt->rt_state & RTS_INTERNAL) == 0) {
205 /*
206 * If changing to different router, we need to add
207 * new route and delete old one if in the kernel.
208 * If the router is the same, we need to delete
209 * the route if has become unreachable, or re-add
210 * it if it had been unreachable.
211 */
4033c8f6 212 if (newgateway) {
7892134c
MK
213 add++;
214 if (rt->rt_metric != HOPCNT_INFINITY)
215 delete++;
216 } else if (metric == HOPCNT_INFINITY)
eb39c032 217 delete++;
7892134c
MK
218 else if (rt->rt_metric == HOPCNT_INFINITY)
219 add++;
eb39c032 220 }
9c2cb70b
MK
221 if (delete)
222 oldroute = rt->rt_rt;
7892134c
MK
223 if ((rt->rt_state & RTS_INTERFACE) && delete) {
224 rt->rt_state &= ~RTS_INTERFACE;
9c2cb70b
MK
225 rt->rt_flags |= RTF_GATEWAY;
226 if (metric > rt->rt_metric && delete)
227 syslog(LOG_ERR, "%s route to interface %s (timed out)",
228 add? "changing" : "deleting",
229 rt->rt_ifp->int_name);
b9b7b06a 230 }
7892134c
MK
231 if (add) {
232 rt->rt_router = *gate;
233 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
234 if (rt->rt_ifp == 0)
235 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
236 }
237 rt->rt_metric = metric;
238 rt->rt_state |= RTS_CHANGED;
4033c8f6 239 if (newgateway)
9c2cb70b 240 TRACE_ACTION("CHANGE TO ", rt);
a33a5c17 241#ifndef RTM_ADD
7892134c 242 if (add && install)
b7e4f8be
MK
243 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
244 perror("SIOCADDRT");
7892134c 245 if (delete && install)
b7e4f8be
MK
246 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
247 perror("SIOCDELRT");
a33a5c17
KS
248#else
249 if (delete && install)
250 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
251 perror("SIOCDELRT");
252 if (add && install) {
253 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
254 perror("SIOCADDRT");
255 }
256#endif
b9b7b06a
SL
257}
258
259rtdelete(rt)
260 struct rt_entry *rt;
261{
a8d9e287 262
9c2cb70b 263 TRACE_ACTION("DELETE", rt);
a33a5c17
KS
264 FIXLEN(&(rt->rt_router));
265 FIXLEN(&(rt->rt_dst));
9c2cb70b
MK
266 if (rt->rt_metric < HOPCNT_INFINITY) {
267 if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
268 syslog(LOG_ERR,
269 "deleting route to interface %s? (timed out?)",
270 rt->rt_ifp->int_name);
271 if (install &&
272 (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
273 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
274 perror("SIOCDELRT");
275 }
b9b7b06a
SL
276 remque(rt);
277 free((char *)rt);
278}
279
4033c8f6
MK
280rtdeleteall(sig)
281 int sig;
7892134c
MK
282{
283 register struct rthash *rh;
284 register struct rt_entry *rt;
285 struct rthash *base = hosthash;
286 int doinghost = 1;
287
288again:
289 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
290 rt = rh->rt_forw;
291 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
9c2cb70b
MK
292 if (rt->rt_state & RTS_INTERFACE ||
293 rt->rt_metric >= HOPCNT_INFINITY)
7892134c 294 continue;
9c2cb70b 295 TRACE_ACTION("DELETE", rt);
7892134c
MK
296 if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
297 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
298 perror("SIOCDELRT");
299 }
300 }
301 if (doinghost) {
302 doinghost = 0;
303 base = nethash;
304 goto again;
305 }
4033c8f6 306 exit(sig);
7892134c
MK
307}
308
ad34083f
MK
309/*
310 * If we have an interface to the wide, wide world,
311 * add an entry for an Internet default route (wildcard) to the internal
312 * tables and advertise it. This route is not added to the kernel routes,
313 * but this entry prevents us from listening to other people's defaults
314 * and installing them in the kernel here.
315 */
316rtdefault()
317{
ad34083f
MK
318 extern struct sockaddr inet_default;
319
09b9aef2 320 rtadd(&inet_default, &inet_default, 1,
4fad5a6e 321 RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
ad34083f
MK
322}
323
b9b7b06a
SL
324rtinit()
325{
326 register struct rthash *rh;
327
328 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
329 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
330 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
331 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
332}