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 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $FreeBSD: src/usr.sbin/IPXrouted/tables.c,v 1.7 1999/08/28 01:15:05 peter Exp $
33 * @(#)tables.c 8.1 (Berkeley) 6/5/93
37 * Routing Table Management Daemon
40 #include <sys/ioctl.h>
50 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
52 int install = !DEBUG; /* if 1 call kernel */
55 struct rthash nethash[ROUTEHASHSIZ];
58 * Lookup dst in the tables for an exact match.
61 rtlookup(struct sockaddr *dst)
68 if (dst->sa_family >= AF_MAX)
70 (*afswitch[dst->sa_family].af_hash)(dst, &h);
72 rh = &nethash[hash & ROUTEHASHMASK];
73 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
74 if (rt->rt_hash != hash)
76 if (equal(&rt->rt_dst, dst))
83 * Find a route to dst as the kernel would.
86 rtfind(struct sockaddr *dst)
92 int af = dst->sa_family;
93 int (*match)() = NULL;
97 (*afswitch[af].af_hash)(dst, &h);
100 rh = &nethash[hash & ROUTEHASHMASK];
101 match = afswitch[af].af_netmatch;
102 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
103 if (rt->rt_hash != hash)
105 if (rt->rt_dst.sa_family == af &&
106 (*match)(&rt->rt_dst, dst))
113 rtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, short ticks,
119 int af = dst->sa_family, flags;
126 (*afswitch[af].af_hash)(dst, &h);
127 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
128 hash = h.afh_nethash;
129 rh = &nethash[hash & ROUTEHASHMASK];
130 rt = (struct rt_entry *)malloc(sizeof (*rt));
135 rt->rt_router = *gate;
136 rt->rt_metric = metric;
137 rt->rt_ticks = ticks;
139 rt->rt_flags = RTF_UP | flags;
140 rt->rt_state = state | RTS_CHANGED;
141 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
144 rt->rt_flags |= RTF_GATEWAY;
146 TRACE_ACTION("ADD", rt);
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.
152 if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
155 if (errno == ENETUNREACH) {
156 TRACE_ACTION("DELETE", rt);
164 rtadd_clone(struct rt_entry *ort, struct sockaddr *dst, struct sockaddr *gate,
165 short metric, short ticks, int state)
169 int af = dst->sa_family, flags;
176 (*afswitch[af].af_hash)(dst, &h);
177 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
178 hash = h.afh_nethash;
179 rt = (struct rt_entry *)malloc(sizeof (*rt));
184 rt->rt_router = *gate;
185 rt->rt_metric = metric;
186 rt->rt_ticks = ticks;
188 rt->rt_flags = RTF_UP | flags;
189 rt->rt_state = state | RTS_CHANGED;
190 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
195 rt->rt_flags |= RTF_GATEWAY;
197 while(ort->rt_clone != NULL)
200 TRACE_ACTION("ADD_CLONE", rt);
204 rtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, short ticks)
206 int doioctl = 0, metricchanged = 0;
210 * Handling of clones.
211 * When the route changed and it had clones, handle it special.
212 * 1. If the new route is cheaper than the clone(s), free the clones.
213 * 2. If the new route is the same cost, it may be one of the clones,
214 * search for it and free it.
215 * 3. If the new route is more expensive than the clone(s), use the
216 * values of the clone(s).
219 if ((ticks < rt->rt_clone->rt_ticks) ||
220 ((ticks == rt->rt_clone->rt_ticks) &&
221 (metric < rt->rt_clone->rt_metric))) {
225 struct rt_entry *trt, *nrt;
234 } else if ((ticks == rt->rt_clone->rt_ticks) &&
235 (metric == rt->rt_clone->rt_metric)) {
236 struct rt_entry *prt, *trt;
242 if (equal(&trt->rt_router, gate)) {
243 prt->rt_clone = trt->rt_clone;
253 * Use the values of the first clone.
254 * Delete the corresponding clone.
256 struct rt_entry *trt;
259 rt->rt_clone = rt->rt_clone->rt_clone;
260 metric = trt->rt_metric;
261 ticks = trt->rt_ticks;
262 *gate = trt->rt_router;
267 if (!equal(&rt->rt_router, gate))
269 if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
271 if (doioctl || metricchanged) {
272 TRACE_ACTION("CHANGE FROM", rt);
274 rt->rt_router = *gate;
275 rt->rt_metric = metric;
276 rt->rt_ticks = ticks;
277 if ((rt->rt_state & RTS_INTERFACE) && metric) {
278 rt->rt_state &= ~RTS_INTERFACE;
281 "changing route from interface %s (timed out)",
282 rt->rt_ifp->int_name);
285 "changing route from interface ??? (timed out)");
288 rt->rt_flags |= RTF_GATEWAY;
290 rt->rt_flags &= ~RTF_GATEWAY;
291 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
292 rt->rt_state |= RTS_CHANGED;
293 TRACE_ACTION("CHANGE TO", rt);
295 if (doioctl && install) {
297 if (rtioctl(ADD, &rt->rt_rt) >= 0)
300 if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
303 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
304 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
305 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
310 rtdelete(struct rt_entry *rt)
312 struct sockaddr *sa = &(rt->rt_router);
319 * If there is a clone we just do a rt_change to it.
321 struct rt_entry *trt = rt->rt_clone;
322 rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
325 if (rt->rt_state & RTS_INTERFACE) {
328 "deleting route to interface %s (timed out)",
329 rt->rt_ifp->int_name);
332 "deleting route to interface ??? (timed out)");
334 TRACE_ACTION("DELETE", rt);
335 if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
336 perror("rtioctl DELETE");
346 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
347 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
352 rtioctl(int action, struct rtuentry *ort)
355 struct rt_msghdr w_rtm;
356 struct sockaddr w_dst;
357 struct sockaddr w_gate;
358 struct sockaddr_ipx w_netmask;
362 bzero((char *)&w, sizeof(w));
363 rtm.rtm_msglen = sizeof(w);
364 rtm.rtm_version = RTM_VERSION;
365 rtm.rtm_type = (action == ADD ? RTM_ADD :
366 (action == DELETE ? RTM_DELETE : RTM_CHANGE));
367 rtm.rtm_flags = ort->rtu_flags;
368 rtm.rtm_seq = ++seqno;
369 rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
370 bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
371 bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
372 w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
373 w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
374 if (rtm.rtm_flags & RTF_HOST) {
375 rtm.rtm_msglen -= sizeof(w.w_netmask);
377 rtm.rtm_addrs |= RTA_NETMASK;
378 w.w_netmask = ipx_netmask;
379 rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
382 return write(r, (char *)&w, rtm.rtm_msglen);