IPXrouted(8): Fix some amd64 warnings.
[dragonfly.git] / usr.sbin / IPXrouted / tables.c
blob77aeb151183a3e37aa88fe340063af18f51323d0
1 /*
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
9 * are met:
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
33 * SUCH DAMAGE.
35 * $FreeBSD: src/usr.sbin/IPXrouted/tables.c,v 1.7 1999/08/28 01:15:05 peter Exp $
36 * $DragonFly: src/usr.sbin/IPXrouted/tables.c,v 1.3 2004/03/11 09:38:59 hmp Exp $
38 * @(#)tables.c 8.1 (Berkeley) 6/5/93
42 * Routing Table Management Daemon
44 #include "defs.h"
45 #include <sys/ioctl.h>
46 #include <errno.h>
47 #include <search.h>
48 #include <stdlib.h>
49 #include <unistd.h>
51 #ifndef DEBUG
52 #define DEBUG 0
53 #endif
55 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
57 int install = !DEBUG; /* if 1 call kernel */
58 int delete = 1;
60 struct rthash nethash[ROUTEHASHSIZ];
63 * Lookup dst in the tables for an exact match.
65 struct rt_entry *
66 rtlookup(struct sockaddr *dst)
68 struct rt_entry *rt;
69 struct rthash *rh;
70 u_int hash;
71 struct afhash h;
73 if (dst->sa_family >= AF_MAX)
74 return (0);
75 (*afswitch[dst->sa_family].af_hash)(dst, &h);
76 hash = h.afh_nethash;
77 rh = &nethash[hash & ROUTEHASHMASK];
78 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
79 if (rt->rt_hash != hash)
80 continue;
81 if (equal(&rt->rt_dst, dst))
82 return (rt);
84 return (0);
88 * Find a route to dst as the kernel would.
90 struct rt_entry *
91 rtfind(struct sockaddr *dst)
93 struct rt_entry *rt;
94 struct rthash *rh;
95 u_int hash;
96 struct afhash h;
97 int af = dst->sa_family;
98 int (*match)() = 0;
100 if (af >= AF_MAX)
101 return (0);
102 (*afswitch[af].af_hash)(dst, &h);
104 hash = h.afh_nethash;
105 rh = &nethash[hash & ROUTEHASHMASK];
106 match = afswitch[af].af_netmatch;
107 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
108 if (rt->rt_hash != hash)
109 continue;
110 if (rt->rt_dst.sa_family == af &&
111 (*match)(&rt->rt_dst, dst))
112 return (rt);
114 return (0);
117 void
118 rtadd(struct sockaddr *dst, struct sockaddr *gate, short metric, short ticks,
119 int state)
121 struct afhash h;
122 struct rt_entry *rt;
123 struct rthash *rh;
124 int af = dst->sa_family, flags;
125 u_int hash;
127 FIXLEN(dst);
128 FIXLEN(gate);
129 if (af >= AF_MAX)
130 return;
131 (*afswitch[af].af_hash)(dst, &h);
132 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
133 hash = h.afh_nethash;
134 rh = &nethash[hash & ROUTEHASHMASK];
135 rt = (struct rt_entry *)malloc(sizeof (*rt));
136 if (rt == 0)
137 return;
138 rt->rt_hash = hash;
139 rt->rt_dst = *dst;
140 rt->rt_router = *gate;
141 rt->rt_metric = metric;
142 rt->rt_ticks = ticks;
143 rt->rt_timer = 0;
144 rt->rt_flags = RTF_UP | flags;
145 rt->rt_state = state | RTS_CHANGED;
146 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
147 rt->rt_clone = NULL;
148 if (metric)
149 rt->rt_flags |= RTF_GATEWAY;
150 insque(rt, rh);
151 TRACE_ACTION("ADD", rt);
153 * If the ioctl fails because the gateway is unreachable
154 * from this host, discard the entry. This should only
155 * occur because of an incorrect entry in /etc/gateways.
157 if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
158 if (errno != EEXIST)
159 perror("SIOCADDRT");
160 if (errno == ENETUNREACH) {
161 TRACE_ACTION("DELETE", rt);
162 remque(rt);
163 free((char *)rt);
168 void
169 rtadd_clone(struct rt_entry *ort, struct sockaddr *dst, struct sockaddr *gate,
170 short metric, short ticks, int state)
172 struct afhash h;
173 struct rt_entry *rt;
174 struct rthash *rh;
175 int af = dst->sa_family, flags;
176 u_int hash;
178 FIXLEN(dst);
179 FIXLEN(gate);
180 if (af >= AF_MAX)
181 return;
182 (*afswitch[af].af_hash)(dst, &h);
183 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
184 hash = h.afh_nethash;
185 rh = &nethash[hash & ROUTEHASHMASK];
186 rt = (struct rt_entry *)malloc(sizeof (*rt));
187 if (rt == 0)
188 return;
189 rt->rt_hash = hash;
190 rt->rt_dst = *dst;
191 rt->rt_router = *gate;
192 rt->rt_metric = metric;
193 rt->rt_ticks = ticks;
194 rt->rt_timer = 0;
195 rt->rt_flags = RTF_UP | flags;
196 rt->rt_state = state | RTS_CHANGED;
197 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
198 rt->rt_clone = NULL;
199 rt->rt_forw = NULL;
200 rt->rt_back = NULL;
201 if (metric)
202 rt->rt_flags |= RTF_GATEWAY;
204 while(ort->rt_clone != NULL)
205 ort = ort->rt_clone;
206 ort->rt_clone = rt;
207 TRACE_ACTION("ADD_CLONE", rt);
210 void
211 rtchange(struct rt_entry *rt, struct sockaddr *gate, short metric, short ticks)
213 int doioctl = 0, metricchanged = 0;
214 struct rtuentry oldroute;
216 FIXLEN(gate);
218 * Handling of clones.
219 * When the route changed and it had clones, handle it special.
220 * 1. If the new route is cheaper than the clone(s), free the clones.
221 * 2. If the new route is the same cost, it may be one of the clones,
222 * search for it and free it.
223 * 3. If the new route is more expensive than the clone(s), use the
224 * values of the clone(s).
226 if (rt->rt_clone) {
227 if ((ticks < rt->rt_clone->rt_ticks) ||
228 ((ticks == rt->rt_clone->rt_ticks) &&
229 (metric < rt->rt_clone->rt_metric))) {
231 * Free all clones.
233 struct rt_entry *trt, *nrt;
235 trt = rt->rt_clone;
236 rt->rt_clone = NULL;
237 while(trt) {
238 nrt = trt->rt_clone;
239 free((char *)trt);
240 trt = nrt;
242 } else if ((ticks == rt->rt_clone->rt_ticks) &&
243 (metric == rt->rt_clone->rt_metric)) {
244 struct rt_entry *prt, *trt;
246 prt = rt;
247 trt = rt->rt_clone;
249 while(trt) {
250 if (equal(&trt->rt_router, gate)) {
251 prt->rt_clone = trt->rt_clone;
252 free(trt);
253 trt = prt->rt_clone;
254 } else {
255 prt = trt;
256 trt = trt->rt_clone;
259 } else {
261 * Use the values of the first clone.
262 * Delete the corresponding clone.
264 struct rt_entry *trt;
266 trt = rt->rt_clone;
267 rt->rt_clone = rt->rt_clone->rt_clone;
268 metric = trt->rt_metric;
269 ticks = trt->rt_ticks;
270 *gate = trt->rt_router;
271 free((char *)trt);
275 if (!equal(&rt->rt_router, gate))
276 doioctl++;
277 if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
278 metricchanged++;
279 if (doioctl || metricchanged) {
280 TRACE_ACTION("CHANGE FROM", rt);
281 if (doioctl) {
282 oldroute = rt->rt_rt;
283 rt->rt_router = *gate;
285 rt->rt_metric = metric;
286 rt->rt_ticks = ticks;
287 if ((rt->rt_state & RTS_INTERFACE) && metric) {
288 rt->rt_state &= ~RTS_INTERFACE;
289 if(rt->rt_ifp)
290 syslog(LOG_ERR,
291 "changing route from interface %s (timed out)",
292 rt->rt_ifp->int_name);
293 else
294 syslog(LOG_ERR,
295 "changing route from interface ??? (timed out)");
297 if (metric)
298 rt->rt_flags |= RTF_GATEWAY;
299 else
300 rt->rt_flags &= ~RTF_GATEWAY;
301 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
302 rt->rt_state |= RTS_CHANGED;
303 TRACE_ACTION("CHANGE TO", rt);
305 if (doioctl && install) {
306 #ifndef RTM_ADD
307 if (rtioctl(ADD, &rt->rt_rt) < 0)
308 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
309 ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
310 ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
311 if (delete && rtioctl(DELETE, &oldroute) < 0)
312 perror("rtioctl DELETE");
313 #else
314 if (delete == 0) {
315 if (rtioctl(ADD, &rt->rt_rt) >= 0)
316 return;
317 } else {
318 if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
319 return;
321 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
322 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
323 ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
324 #endif
328 void
329 rtdelete(struct rt_entry *rt)
331 struct sockaddr *sa = &(rt->rt_router);
333 FIXLEN(sa);
334 sa = &(rt->rt_dst);
335 FIXLEN(sa);
336 if (rt->rt_clone) {
338 * If there is a clone we just do a rt_change to it.
340 struct rt_entry *trt = rt->rt_clone;
341 rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
342 return;
344 if (rt->rt_state & RTS_INTERFACE) {
345 if (rt->rt_ifp)
346 syslog(LOG_ERR,
347 "deleting route to interface %s (timed out)",
348 rt->rt_ifp->int_name);
349 else
350 syslog(LOG_ERR,
351 "deleting route to interface ??? (timed out)");
353 TRACE_ACTION("DELETE", rt);
354 if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
355 perror("rtioctl DELETE");
356 remque(rt);
357 free((char *)rt);
360 void
361 rtinit(void)
363 struct rthash *rh;
365 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
366 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
368 int seqno;
371 rtioctl(int action, struct rtuentry *ort)
373 #ifndef RTM_ADD
374 if (install == 0)
375 return (errno = 0);
377 ort->rtu_rtflags = ort->rtu_flags;
379 switch (action) {
381 case ADD:
382 return (ioctl(s, SIOCADDRT, (char *)ort));
384 case DELETE:
385 return (ioctl(s, SIOCDELRT, (char *)ort));
387 default:
388 return (-1);
390 #else /* RTM_ADD */
391 struct {
392 struct rt_msghdr w_rtm;
393 struct sockaddr w_dst;
394 struct sockaddr w_gate;
395 struct sockaddr_ipx w_netmask;
396 } w;
397 #define rtm w.w_rtm
399 bzero((char *)&w, sizeof(w));
400 rtm.rtm_msglen = sizeof(w);
401 rtm.rtm_version = RTM_VERSION;
402 rtm.rtm_type = (action == ADD ? RTM_ADD :
403 (action == DELETE ? RTM_DELETE : RTM_CHANGE));
404 rtm.rtm_flags = ort->rtu_flags;
405 rtm.rtm_seq = ++seqno;
406 rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
407 bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
408 bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
409 w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
410 w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
411 if (rtm.rtm_flags & RTF_HOST) {
412 rtm.rtm_msglen -= sizeof(w.w_netmask);
413 } else {
414 rtm.rtm_addrs |= RTA_NETMASK;
415 w.w_netmask = ipx_netmask;
416 rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
418 errno = 0;
419 return write(r, (char *)&w, rtm.rtm_msglen);
420 #endif /* RTM_ADD */