* Copyright (c) 1983, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)tables.c 5.17 (Berkeley) 6/1/90";
* 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
];
struct sockaddr wildcard
; /* zero valued cookie for wildcard searches */
* 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
;
* Check for wildcard gateway, by convention network 0.
dst
= &wildcard
, hash
= 0;
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_rtflags
)(dst
);
* Subnet flag isn't visible to kernel, move to state. XXX
if (flags
& RTF_SUBNET
) {
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_ifwithdstaddr(&rt
->rt_dst
);
rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
* seems like we can't figure out the interface for the
* IP address of the local side of a point to point
* connection, we just don't add that entry in the
* table. (it seems to already be there anyway)
"rtadd: can't get interface for %s",
(*afswitch
[dst
->sa_family
].af_format
)(dst
));
if ((state
& RTS_INTERFACE
) == 0)
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
&& (rt
->rt_state
& (RTS_INTERNAL
| RTS_EXTERNAL
)) == 0 &&
ioctl(s
, SIOCADDRT
, (char *)&rt
->rt_rt
) < 0) {
if (errno
!= EEXIST
&& gate
->sa_family
< af_max
)
"adding route to net/host %s through gateway %s: %m\n",
(*afswitch
[dst
->sa_family
].af_format
)(dst
),
(*afswitch
[gate
->sa_family
].af_format
)(gate
));
if (errno
== ENETUNREACH
) {
TRACE_ACTION("DELETE", rt
);
rtchange(rt
, gate
, metric
)
int add
= 0, delete = 0, newgateway
= 0;
FIXLEN(&(rt
->rt_router
));
if (!equal(&rt
->rt_router
, gate
)) {
TRACE_ACTION("CHANGE FROM ", rt
);
} else if (metric
!= rt
->rt_metric
)
TRACE_NEWMETRIC(rt
, metric
);
if ((rt
->rt_state
& RTS_INTERNAL
) == 0) {
* If changing to different router, we need to add
* new route and delete old one if in the kernel.
* If the router is the same, we need to delete
* the route if has become unreachable, or re-add
* it if it had been unreachable.
if (rt
->rt_metric
!= HOPCNT_INFINITY
)
} else if (metric
== HOPCNT_INFINITY
)
else if (rt
->rt_metric
== HOPCNT_INFINITY
)
if ((rt
->rt_state
& RTS_INTERFACE
) && delete) {
rt
->rt_state
&= ~RTS_INTERFACE
;
rt
->rt_flags
|= RTF_GATEWAY
;
if (metric
> rt
->rt_metric
&& delete)
syslog(LOG_ERR
, "%s route to interface %s (timed out)",
add
? "changing" : "deleting",
rt
->rt_ifp
= if_ifwithdstaddr(&rt
->rt_router
);
rt
->rt_ifp
= if_ifwithnet(&rt
->rt_router
);
* seems like we can't figure out the interface for the
* IP address of the local side of a point to point
* connection, we just don't add that entry in the
* table. (it seems to already be there anyway)
struct sockaddr
*dst
= &(rt
->rt_dst
);
"rtchange: can't get interface for %s",
(*afswitch
[dst
->sa_family
].af_format
)(dst
));
rt
->rt_state
|= RTS_CHANGED
;
TRACE_ACTION("CHANGE TO ", rt
);
if (ioctl(s
, SIOCADDRT
, (char *)&rt
->rt_rt
) < 0)
if (ioctl(s
, SIOCDELRT
, (char *)&oldroute
) < 0)
if (ioctl(s
, SIOCDELRT
, (char *)&oldroute
) < 0)
if (ioctl(s
, SIOCADDRT
, (char *)&rt
->rt_rt
) < 0)
TRACE_ACTION("DELETE", rt
);
FIXLEN(&(rt
->rt_router
));
if (rt
->rt_metric
< HOPCNT_INFINITY
) {
if ((rt
->rt_state
& (RTS_INTERFACE
|RTS_INTERNAL
)) == RTS_INTERFACE
)
"deleting route to interface %s? (timed out?)",
(rt
->rt_state
& (RTS_INTERNAL
| RTS_EXTERNAL
)) == 0 &&
ioctl(s
, SIOCDELRT
, (char *)&rt
->rt_rt
))
register struct rthash
*rh
;
register struct rt_entry
*rt
;
struct rthash
*base
= hosthash
;
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++) {
for (; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if (rt
->rt_state
& RTS_INTERFACE
||
rt
->rt_metric
>= HOPCNT_INFINITY
)
TRACE_ACTION("DELETE", rt
);
if ((rt
->rt_state
& (RTS_INTERNAL
|RTS_EXTERNAL
)) == 0 &&
ioctl(s
, SIOCDELRT
, (char *)&rt
->rt_rt
))
* If we have an interface to the wide, wide world,
* add an entry for an Internet default route (wildcard) to the internal
* tables and advertise it. This route is not added to the kernel routes,
* but this entry prevents us from listening to other people's defaults
* and installing them in the kernel here.
extern struct sockaddr inet_default
;
rtadd(&inet_default
, &inet_default
, 1,
RTS_CHANGED
| RTS_PASSIVE
| RTS_INTERNAL
);
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
;
/* ffrom /sys/i386/i386/machdep.c */
* insert an element into a queue
register struct rthash
*element
, *head
;
element
->rt_forw
= head
->rt_forw
;
head
->rt_forw
= (struct rt_entry
*)element
;
element
->rt_back
= (struct rt_entry
*)head
;
((struct rthash
*)(element
->rt_forw
))->rt_back
=(struct rt_entry
*)element
;
* remove an element from a queue
register struct rthash
*element
;
((struct rthash
*)(element
->rt_forw
))->rt_back
= element
->rt_back
;
((struct rthash
*)(element
->rt_back
))->rt_forw
= element
->rt_forw
;
element
->rt_back
= (struct rt_entry
*)0;