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