2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1995 John Hay. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static const char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
43 * Routing Table Management Daemon
46 #include <sys/ioctl.h>
56 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
58 int install = !DEBUG; /* if 1 call kernel */
61 struct rthash nethash[ROUTEHASHSIZ];
64 * Lookup dst in the tables for an exact match.
70 register struct rt_entry *rt;
71 register struct rthash *rh;
75 if (dst->sa_family >= AF_MAX)
77 (*afswitch[dst->sa_family].af_hash)(dst, &h);
79 rh = &nethash[hash & ROUTEHASHMASK];
80 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
81 if (rt->rt_hash != hash)
83 if (equal(&rt->rt_dst, dst))
90 * Find a route to dst as the kernel would.
96 register struct rt_entry *rt;
97 register struct rthash *rh;
100 int af = dst->sa_family;
105 (*afswitch[af].af_hash)(dst, &h);
107 hash = h.afh_nethash;
108 rh = &nethash[hash & ROUTEHASHMASK];
109 match = afswitch[af].af_netmatch;
110 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
111 if (rt->rt_hash != hash)
113 if (rt->rt_dst.sa_family == af &&
114 (*match)(&rt->rt_dst, dst))
121 rtadd(dst, gate, metric, ticks, state)
122 struct sockaddr *dst, *gate;
127 register struct rt_entry *rt;
129 int af = dst->sa_family, flags;
136 (*afswitch[af].af_hash)(dst, &h);
137 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
138 hash = h.afh_nethash;
139 rh = &nethash[hash & ROUTEHASHMASK];
140 rt = (struct rt_entry *)malloc(sizeof (*rt));
145 rt->rt_router = *gate;
146 rt->rt_metric = metric;
147 rt->rt_ticks = ticks;
149 rt->rt_flags = RTF_UP | flags;
150 rt->rt_state = state | RTS_CHANGED;
151 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
154 rt->rt_flags |= RTF_GATEWAY;
156 TRACE_ACTION("ADD", rt);
158 * If the ioctl fails because the gateway is unreachable
159 * from this host, discard the entry. This should only
160 * occur because of an incorrect entry in /etc/gateways.
162 if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
165 if (errno == ENETUNREACH) {
166 TRACE_ACTION("DELETE", rt);
174 rtadd_clone(ort, dst, gate, metric, ticks, state)
175 struct rt_entry *ort;
176 struct sockaddr *dst, *gate;
181 register struct rt_entry *rt;
183 int af = dst->sa_family, flags;
190 (*afswitch[af].af_hash)(dst, &h);
191 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
192 hash = h.afh_nethash;
193 rh = &nethash[hash & ROUTEHASHMASK];
194 rt = (struct rt_entry *)malloc(sizeof (*rt));
199 rt->rt_router = *gate;
200 rt->rt_metric = metric;
201 rt->rt_ticks = ticks;
203 rt->rt_flags = RTF_UP | flags;
204 rt->rt_state = state | RTS_CHANGED;
205 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
210 rt->rt_flags |= RTF_GATEWAY;
212 while(ort->rt_clone != NULL)
215 TRACE_ACTION("ADD_CLONE", rt);
219 rtchange(rt, gate, metric, ticks)
221 struct sockaddr *gate;
224 int doioctl = 0, metricchanged = 0;
225 struct rtuentry oldroute;
229 * Handling of clones.
230 * When the route changed and it had clones, handle it special.
231 * 1. If the new route is cheaper than the clone(s), free the clones.
232 * 2. If the new route is the same cost, it may be one of the clones,
233 * search for it and free it.
234 * 3. If the new route is more expensive than the clone(s), use the
235 * values of the clone(s).
238 if ((ticks < rt->rt_clone->rt_ticks) ||
239 ((ticks == rt->rt_clone->rt_ticks) &&
240 (metric < rt->rt_clone->rt_metric))) {
244 struct rt_entry *trt, *nrt;
253 } else if ((ticks == rt->rt_clone->rt_ticks) &&
254 (metric == rt->rt_clone->rt_metric)) {
255 struct rt_entry *prt, *trt;
261 if (equal(&trt->rt_router, gate)) {
262 prt->rt_clone = trt->rt_clone;
272 * Use the values of the first clone.
273 * Delete the corresponding clone.
275 struct rt_entry *trt;
278 rt->rt_clone = rt->rt_clone->rt_clone;
279 metric = trt->rt_metric;
280 ticks = trt->rt_ticks;
281 *gate = trt->rt_router;
286 if (!equal(&rt->rt_router, gate))
288 if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
290 if (doioctl || metricchanged) {
291 TRACE_ACTION("CHANGE FROM", rt);
293 oldroute = rt->rt_rt;
294 rt->rt_router = *gate;
296 rt->rt_metric = metric;
297 rt->rt_ticks = ticks;
298 if ((rt->rt_state & RTS_INTERFACE) && metric) {
299 rt->rt_state &= ~RTS_INTERFACE;
302 "changing route from interface %s (timed out)",
303 rt->rt_ifp->int_name);
306 "changing route from interface ??? (timed out)");
309 rt->rt_flags |= RTF_GATEWAY;
311 rt->rt_flags &= ~RTF_GATEWAY;
312 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
313 rt->rt_state |= RTS_CHANGED;
314 TRACE_ACTION("CHANGE TO", rt);
316 if (doioctl && install) {
318 if (rtioctl(ADD, &rt->rt_rt) < 0)
319 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
320 ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
321 ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
322 if (delete && rtioctl(DELETE, &oldroute) < 0)
323 perror("rtioctl DELETE");
326 if (rtioctl(ADD, &rt->rt_rt) >= 0)
329 if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
332 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
333 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
334 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
344 struct sockaddr *sa = &(rt->rt_router);
350 * If there is a clone we just do a rt_change to it.
352 struct rt_entry *trt = rt->rt_clone;
353 rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
356 if (rt->rt_state & RTS_INTERFACE) {
359 "deleting route to interface %s (timed out)",
360 rt->rt_ifp->int_name);
363 "deleting route to interface ??? (timed out)");
365 TRACE_ACTION("DELETE", rt);
366 if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
367 perror("rtioctl DELETE");
375 register struct rthash *rh;
377 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
378 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
385 struct rtuentry *ort;
391 ort->rtu_rtflags = ort->rtu_flags;
396 return (ioctl(s, SIOCADDRT, (char *)ort));
399 return (ioctl(s, SIOCDELRT, (char *)ort));
406 struct rt_msghdr w_rtm;
407 struct sockaddr w_dst;
408 struct sockaddr w_gate;
409 struct sockaddr_ipx w_netmask;
413 bzero((char *)&w, sizeof(w));
414 rtm.rtm_msglen = sizeof(w);
415 rtm.rtm_version = RTM_VERSION;
416 rtm.rtm_type = (action == ADD ? RTM_ADD :
417 (action == DELETE ? RTM_DELETE : RTM_CHANGE));
418 rtm.rtm_flags = ort->rtu_flags;
419 rtm.rtm_seq = ++seqno;
420 rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
421 bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
422 bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
423 w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
424 w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
425 if (rtm.rtm_flags & RTF_HOST) {
426 rtm.rtm_msglen -= sizeof(w.w_netmask);
428 rtm.rtm_addrs |= RTA_NETMASK;
429 w.w_netmask = ipx_netmask;
430 rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
433 return write(r, (char *)&w, rtm.rtm_msglen);