* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)tables.c 8.1 (Berkeley) %G%";
* Routing Table Management Daemon
#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
int install
= !DEBUG
; /* if 1 call kernel */
* Lookup dst in the tables for an exact match.
register struct rt_entry
*rt
;
register struct rthash
*rh
;
if (dst
->sa_family
>= AF_MAX
)
(*afswitch
[dst
->sa_family
].af_hash
)(dst
, &h
);
rh
= &hosthash
[hash
& ROUTEHASHMASK
];
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if (equal(&rt
->rt_dst
, dst
))
rh
= &nethash
[hash
& ROUTEHASHMASK
];
* Find a route to dst as the kernel would.
register struct rt_entry
*rt
;
register struct rthash
*rh
;
int doinghost
= 1, (*match
)();
(*afswitch
[af
].af_hash
)(dst
, &h
);
rh
= &hosthash
[hash
& ROUTEHASHMASK
];
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if (equal(&rt
->rt_dst
, dst
))
if (rt
->rt_dst
.sa_family
== af
&&
(*match
)(&rt
->rt_dst
, dst
))
rh
= &nethash
[hash
& ROUTEHASHMASK
];
match
= afswitch
[af
].af_netmatch
;
rtadd(dst
, gate
, metric
, state
)
struct sockaddr
*dst
, *gate
;
register struct rt_entry
*rt
;
int af
= dst
->sa_family
, flags
;
(*afswitch
[af
].af_hash
)(dst
, &h
);
flags
= (*afswitch
[af
].af_ishost
)(dst
) ? RTF_HOST
: 0;
rh
= &hosthash
[hash
& ROUTEHASHMASK
];
rh
= &nethash
[hash
& ROUTEHASHMASK
];
rt
= (struct rt_entry
*)malloc(sizeof (*rt
));
rt
->rt_flags
= RTF_UP
| flags
;
rt
->rt_state
= state
| RTS_CHANGED
;
rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
rt
->rt_flags
|= RTF_GATEWAY
;
* If the ioctl fails because the gateway is unreachable
* from this host, discard the entry. This should only
* occur because of an incorrect entry in /etc/gateways.
if (install
&& rtioctl(ADD
, &rt
->rt_rt
) < 0) {
if (errno
== ENETUNREACH
) {
TRACE_ACTION(DELETE
, rt
);
rtchange(rt
, gate
, metric
)
int doioctl
= 0, metricchanged
= 0;
if (!equal(&rt
->rt_router
, gate
))
if (metric
!= rt
->rt_metric
)
if (doioctl
|| metricchanged
) {
TRACE_ACTION(CHANGE FROM
, rt
);
if ((rt
->rt_state
& RTS_INTERFACE
) && metric
) {
rt
->rt_state
&= ~RTS_INTERFACE
;
"changing route from interface %s (timed out)",
rt
->rt_flags
|= RTF_GATEWAY
;
rt
->rt_flags
&= ~RTF_GATEWAY
;
rt
->rt_state
|= RTS_CHANGED
;
TRACE_ACTION(CHANGE TO
, rt
);
if (doioctl
&& install
) {
if (rtioctl(ADD
, &rt
->rt_rt
) < 0)
syslog(LOG_ERR
, "rtioctl ADD dst %s, gw %s: %m",
xns_ntoa(&((struct sockaddr_ns
*)&rt
->rt_dst
)->sns_addr
),
xns_ntoa(&((struct sockaddr_ns
*)&rt
->rt_router
)->sns_addr
));
if (delete && rtioctl(DELETE
, &oldroute
) < 0)
perror("rtioctl DELETE");
if (rtioctl(ADD
, &rt
->rt_rt
) >= 0)
if (rtioctl(CHANGE
, &rt
->rt_rt
) >= 0)
syslog(LOG_ERR
, "rtioctl ADD dst %s, gw %s: %m",
xns_ntoa(&((struct sockaddr_ns
*)&rt
->rt_dst
)->sns_addr
),
xns_ntoa(&((struct sockaddr_ns
*)&rt
->rt_router
)->sns_addr
));
struct sockaddr
*sa
= &(rt
->rt_rt
.rt_gateway
);
sa
= &(rt
->rt_rt
.rt_dst
);
if (rt
->rt_state
& RTS_INTERFACE
) {
syslog(LOG_ERR
, "deleting route to interface %s (timed out)",
TRACE_ACTION(DELETE
, rt
);
if (install
&& rtioctl(DELETE
, &rt
->rt_rt
) < 0)
perror("rtioctl DELETE");
register struct rthash
*rh
;
for (rh
= nethash
; rh
< &nethash
[ROUTEHASHSIZ
]; rh
++)
rh
->rt_forw
= rh
->rt_back
= (struct rt_entry
*)rh
;
for (rh
= hosthash
; rh
< &hosthash
[ROUTEHASHSIZ
]; rh
++)
rh
->rt_forw
= rh
->rt_back
= (struct rt_entry
*)rh
;
return (ioctl(s
, SIOCADDRT
, (char *)ort
));
return (ioctl(s
, SIOCDELRT
, (char *)ort
));
struct sockaddr_ns w_netmask
;
bzero((char *)&w
, sizeof(w
));
rtm
.rtm_msglen
= sizeof(w
);
rtm
.rtm_version
= RTM_VERSION
;
rtm
.rtm_type
= (action
== ADD
? RTM_ADD
:
(action
== DELETE
? RTM_DELETE
: RTM_CHANGE
));
rtm
.rtm_flags
= ort
->rt_flags
;
rtm
.rtm_addrs
= RTA_DST
|RTA_GATEWAY
;
bcopy((char *)&ort
->rt_dst
, (char *)&w
.w_dst
, sizeof(w
.w_dst
));
bcopy((char *)&ort
->rt_gateway
, (char *)&w
.w_gate
, sizeof(w
.w_gate
));
w
.w_gate
.sa_family
= w
.w_dst
.sa_family
= AF_NS
;
w
.w_gate
.sa_len
= w
.w_dst
.sa_len
= sizeof(w
.w_dst
);
if (rtm
.rtm_flags
& RTF_HOST
) {
rtm
.rtm_msglen
-= sizeof(w
.w_netmask
);
w
.w_netmask
= ns_netmask
;
return write(r
, (char *)&w
, rtm
.rtm_msglen
);