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