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
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
45 #include <sys/ioctl.h>
54 #define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
56 int install
= !DEBUG
; /* if 1 call kernel */
59 struct rthash nethash
[ROUTEHASHSIZ
];
62 * Lookup dst in the tables for an exact match.
65 rtlookup(struct sockaddr
*dst
)
72 if (dst
->sa_family
>= AF_MAX
)
74 (*afswitch
[dst
->sa_family
].af_hash
)(dst
, &h
);
76 rh
= &nethash
[hash
& ROUTEHASHMASK
];
77 for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
78 if (rt
->rt_hash
!= hash
)
80 if (equal(&rt
->rt_dst
, dst
))
87 * Find a route to dst as the kernel would.
90 rtfind(struct sockaddr
*dst
)
96 int af
= dst
->sa_family
;
101 (*afswitch
[af
].af_hash
)(dst
, &h
);
103 hash
= h
.afh_nethash
;
104 rh
= &nethash
[hash
& ROUTEHASHMASK
];
105 match
= afswitch
[af
].af_netmatch
;
106 for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
107 if (rt
->rt_hash
!= hash
)
109 if (rt
->rt_dst
.sa_family
== af
&&
110 (*match
)(&rt
->rt_dst
, dst
))
117 rtadd(struct sockaddr
*dst
, struct sockaddr
*gate
, short metric
, short ticks
,
123 int af
= dst
->sa_family
, flags
;
130 (*afswitch
[af
].af_hash
)(dst
, &h
);
131 flags
= (*afswitch
[af
].af_ishost
)(dst
) ? RTF_HOST
: 0;
132 hash
= h
.afh_nethash
;
133 rh
= &nethash
[hash
& ROUTEHASHMASK
];
134 rt
= (struct rt_entry
*)malloc(sizeof (*rt
));
139 rt
->rt_router
= *gate
;
140 rt
->rt_metric
= metric
;
141 rt
->rt_ticks
= ticks
;
143 rt
->rt_flags
= RTF_UP
| flags
;
144 rt
->rt_state
= state
| RTS_CHANGED
;
145 rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
148 rt
->rt_flags
|= RTF_GATEWAY
;
150 TRACE_ACTION("ADD", rt
);
152 * If the ioctl fails because the gateway is unreachable
153 * from this host, discard the entry. This should only
154 * occur because of an incorrect entry in /etc/gateways.
156 if (install
&& rtioctl(ADD
, &rt
->rt_rt
) < 0) {
159 if (errno
== ENETUNREACH
) {
160 TRACE_ACTION("DELETE", rt
);
168 rtadd_clone(struct rt_entry
*ort
, struct sockaddr
*dst
, struct sockaddr
*gate
,
169 short metric
, short ticks
, int state
)
174 int af
= dst
->sa_family
, flags
;
181 (*afswitch
[af
].af_hash
)(dst
, &h
);
182 flags
= (*afswitch
[af
].af_ishost
)(dst
) ? RTF_HOST
: 0;
183 hash
= h
.afh_nethash
;
184 rh
= &nethash
[hash
& ROUTEHASHMASK
];
185 rt
= (struct rt_entry
*)malloc(sizeof (*rt
));
190 rt
->rt_router
= *gate
;
191 rt
->rt_metric
= metric
;
192 rt
->rt_ticks
= ticks
;
194 rt
->rt_flags
= RTF_UP
| flags
;
195 rt
->rt_state
= state
| RTS_CHANGED
;
196 rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
201 rt
->rt_flags
|= RTF_GATEWAY
;
203 while(ort
->rt_clone
!= NULL
)
206 TRACE_ACTION("ADD_CLONE", rt
);
210 rtchange(struct rt_entry
*rt
, struct sockaddr
*gate
, short metric
, short ticks
)
212 int doioctl
= 0, metricchanged
= 0;
213 struct rtuentry oldroute
;
217 * Handling of clones.
218 * When the route changed and it had clones, handle it special.
219 * 1. If the new route is cheaper than the clone(s), free the clones.
220 * 2. If the new route is the same cost, it may be one of the clones,
221 * search for it and free it.
222 * 3. If the new route is more expensive than the clone(s), use the
223 * values of the clone(s).
226 if ((ticks
< rt
->rt_clone
->rt_ticks
) ||
227 ((ticks
== rt
->rt_clone
->rt_ticks
) &&
228 (metric
< rt
->rt_clone
->rt_metric
))) {
232 struct rt_entry
*trt
, *nrt
;
241 } else if ((ticks
== rt
->rt_clone
->rt_ticks
) &&
242 (metric
== rt
->rt_clone
->rt_metric
)) {
243 struct rt_entry
*prt
, *trt
;
249 if (equal(&trt
->rt_router
, gate
)) {
250 prt
->rt_clone
= trt
->rt_clone
;
260 * Use the values of the first clone.
261 * Delete the corresponding clone.
263 struct rt_entry
*trt
;
266 rt
->rt_clone
= rt
->rt_clone
->rt_clone
;
267 metric
= trt
->rt_metric
;
268 ticks
= trt
->rt_ticks
;
269 *gate
= trt
->rt_router
;
274 if (!equal(&rt
->rt_router
, gate
))
276 if ((metric
!= rt
->rt_metric
) || (ticks
!= rt
->rt_ticks
))
278 if (doioctl
|| metricchanged
) {
279 TRACE_ACTION("CHANGE FROM", rt
);
281 oldroute
= rt
->rt_rt
;
282 rt
->rt_router
= *gate
;
284 rt
->rt_metric
= metric
;
285 rt
->rt_ticks
= ticks
;
286 if ((rt
->rt_state
& RTS_INTERFACE
) && metric
) {
287 rt
->rt_state
&= ~RTS_INTERFACE
;
290 "changing route from interface %s (timed out)",
291 rt
->rt_ifp
->int_name
);
294 "changing route from interface ??? (timed out)");
297 rt
->rt_flags
|= RTF_GATEWAY
;
299 rt
->rt_flags
&= ~RTF_GATEWAY
;
300 rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
301 rt
->rt_state
|= RTS_CHANGED
;
302 TRACE_ACTION("CHANGE TO", rt
);
304 if (doioctl
&& install
) {
306 if (rtioctl(ADD
, &rt
->rt_rt
) < 0)
307 syslog(LOG_ERR
, "rtioctl ADD dst %s, gw %s: %m",
308 ipx_ntoa(&((struct sockaddr_ipx
*)&rt
->rt_dst
)->sipx_addr
),
309 ipx_ntoa(&((struct sockaddr_ipx
*)&rt
->rt_router
)->sipx_addr
));
310 if (delete && rtioctl(DELETE
, &oldroute
) < 0)
311 perror("rtioctl DELETE");
314 if (rtioctl(ADD
, &rt
->rt_rt
) >= 0)
317 if (rtioctl(CHANGE
, &rt
->rt_rt
) >= 0)
320 syslog(LOG_ERR
, "rtioctl ADD dst %s, gw %s: %m",
321 ipxdp_ntoa(&((struct sockaddr_ipx
*)&rt
->rt_dst
)->sipx_addr
),
322 ipxdp_ntoa(&((struct sockaddr_ipx
*)&rt
->rt_router
)->sipx_addr
));
328 rtdelete(struct rt_entry
*rt
)
330 struct sockaddr
*sa
= &(rt
->rt_router
);
337 * If there is a clone we just do a rt_change to it.
339 struct rt_entry
*trt
= rt
->rt_clone
;
340 rtchange(rt
, &trt
->rt_router
, trt
->rt_metric
, trt
->rt_ticks
);
343 if (rt
->rt_state
& RTS_INTERFACE
) {
346 "deleting route to interface %s (timed out)",
347 rt
->rt_ifp
->int_name
);
350 "deleting route to interface ??? (timed out)");
352 TRACE_ACTION("DELETE", rt
);
353 if (install
&& rtioctl(DELETE
, &rt
->rt_rt
) < 0)
354 perror("rtioctl DELETE");
364 for (rh
= nethash
; rh
< &nethash
[ROUTEHASHSIZ
]; rh
++)
365 rh
->rt_forw
= rh
->rt_back
= (struct rt_entry
*)rh
;
370 rtioctl(int action
, struct rtuentry
*ort
)
376 ort
->rtu_rtflags
= ort
->rtu_flags
;
381 return (ioctl(s
, SIOCADDRT
, (char *)ort
));
384 return (ioctl(s
, SIOCDELRT
, (char *)ort
));
391 struct rt_msghdr w_rtm
;
392 struct sockaddr w_dst
;
393 struct sockaddr w_gate
;
394 struct sockaddr_ipx w_netmask
;
398 bzero((char *)&w
, sizeof(w
));
399 rtm
.rtm_msglen
= sizeof(w
);
400 rtm
.rtm_version
= RTM_VERSION
;
401 rtm
.rtm_type
= (action
== ADD
? RTM_ADD
:
402 (action
== DELETE
? RTM_DELETE
: RTM_CHANGE
));
403 rtm
.rtm_flags
= ort
->rtu_flags
;
404 rtm
.rtm_seq
= ++seqno
;
405 rtm
.rtm_addrs
= RTA_DST
|RTA_GATEWAY
;
406 bcopy((char *)&ort
->rtu_dst
, (char *)&w
.w_dst
, sizeof(w
.w_dst
));
407 bcopy((char *)&ort
->rtu_router
, (char *)&w
.w_gate
, sizeof(w
.w_gate
));
408 w
.w_gate
.sa_family
= w
.w_dst
.sa_family
= AF_IPX
;
409 w
.w_gate
.sa_len
= w
.w_dst
.sa_len
= sizeof(w
.w_dst
);
410 if (rtm
.rtm_flags
& RTF_HOST
) {
411 rtm
.rtm_msglen
-= sizeof(w
.w_netmask
);
413 rtm
.rtm_addrs
|= RTA_NETMASK
;
414 w
.w_netmask
= ipx_netmask
;
415 rtm
.rtm_msglen
-= sizeof(w
.w_netmask
) - ipx_netmask
.sipx_len
;
418 return write(r
, (char *)&w
, rtm
.rtm_msglen
);