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