* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)route.c 6.14 (Berkeley) %G%
int rttrash
; /* routes not in table but not freed */
struct sockaddr wildcard
; /* zero valued cookie for wildcard searches */
int rthashsize
= RTHASHSIZ
; /* for netstat, etc. */
* Packet routing routines.
register struct route
*ro
;
register struct rtentry
*rt
;
struct sockaddr
*dst
= &ro
->ro_dst
;
int (*match
)(), doinghost
, s
;
u_int af
= dst
->sa_family
;
if (ro
->ro_rt
&& ro
->ro_rt
->rt_ifp
&& (ro
->ro_rt
->rt_flags
& RTF_UP
))
(*afswitch
[af
].af_hash
)(dst
, &h
);
match
= afswitch
[af
].af_netmatch
;
hash
= h
.afh_hosthash
, table
= rthost
, doinghost
= 1;
for (m
= table
[RTHASHMOD(hash
)]; m
; m
= m
->m_next
) {
rt
= mtod(m
, struct rtentry
*);
if ((rt
->rt_flags
& RTF_UP
) == 0 ||
(rt
->rt_ifp
->if_flags
& IFF_UP
) == 0)
if (bcmp((caddr_t
)&rt
->rt_dst
, (caddr_t
)dst
,
if (rt
->rt_dst
.sa_family
!= af
||
!(*match
)(&rt
->rt_dst
, dst
))
hash
= h
.afh_nethash
, table
= rtnet
;
* Check for wildcard gateway, by convention network 0.
dst
= &wildcard
, hash
= 0;
register struct rtentry
*rt
;
if (rt
->rt_refcnt
== 0 && (rt
->rt_flags
&RTF_UP
) == 0) {
* Force a routing table entry to the specified
* destination to go through the given gateway.
* Normally called as a result of a routing redirect
* message from the network layer.
* N.B.: must be called at splnet or higher
rtredirect(dst
, gateway
, flags
, src
)
struct sockaddr
*dst
, *gateway
, *src
;
register struct rtentry
*rt
;
/* verify the gateway is directly reachable */
if (ifa_ifwithnet(gateway
) == 0) {
rtstat
.rts_badredirect
++;
(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
* If the redirect isn't from our current router for this dst,
* it's either old or wrong.
if (rt
&& !equal(src
, &rt
->rt_gateway
)) {
rtstat
.rts_badredirect
++;
* Create a new entry if we just got back a wildcard entry
* or the the lookup failed. This is necessary for hosts
* which use routing redirects generated by smart gateways
* to dynamically build the routing tables.
(*afswitch
[dst
->sa_family
].af_netmatch
)(&wildcard
, &rt
->rt_dst
)) {
rtinit(dst
, gateway
, SIOCADDRT
,
(flags
& RTF_HOST
) | RTF_GATEWAY
| RTF_DYNAMIC
);
* Don't listen to the redirect if it's
* for a route to an interface.
if (rt
->rt_flags
& RTF_GATEWAY
) {
if (((rt
->rt_flags
& RTF_HOST
) == 0) && (flags
& RTF_HOST
)) {
* Changing from route to net => route to host.
* Create new route, rather than smashing route to net.
rtinit(dst
, gateway
, SIOCADDRT
, flags
);
* Smash the current notion of the gateway to
* this destination. This is probably not right,
* as it's conceivable a flurry of redirects could
* cause the gateway value to fluctuate wildly during
* dynamic routing reconfiguration.
rt
->rt_gateway
= *gateway
;
rtstat
.rts_badredirect
++;
* Routing table ioctl interface.
if (cmd
!= SIOCADDRT
&& cmd
!= SIOCDELRT
)
return (rtrequest(cmd
, (struct rtentry
*)data
));
* Carry out a request to change the routing table. Called by
* interfaces at boot time to make their ``local routes'' known,
* for ioctl's, and as the result of routing redirects.
register struct rtentry
*entry
;
register struct mbuf
*m
, **mprev
;
register struct rtentry
*rt
;
int s
, error
= 0, (*match
)();
struct ifaddr
*ifa_ifwithdstaddr();
af
= entry
->rt_dst
.sa_family
;
(*afswitch
[af
].af_hash
)(&entry
->rt_dst
, &h
);
if (entry
->rt_flags
& RTF_HOST
) {
mprev
= &rthost
[RTHASHMOD(hash
)];
mprev
= &rtnet
[RTHASHMOD(hash
)];
match
= afswitch
[af
].af_netmatch
;
for (mfirst
= mprev
; m
= *mprev
; mprev
= &m
->m_next
) {
rt
= mtod(m
, struct rtentry
*);
if (entry
->rt_flags
& RTF_HOST
) {
if (!equal(&rt
->rt_dst
, &entry
->rt_dst
))
if (rt
->rt_dst
.sa_family
!= entry
->rt_dst
.sa_family
||
(*match
)(&rt
->rt_dst
, &entry
->rt_dst
) == 0)
if (equal(&rt
->rt_gateway
, &entry
->rt_gateway
))
if ((entry
->rt_flags
& RTF_GATEWAY
) == 0) {
* If we are adding a route to an interface,
* and the interface is a pt to pt link
* we should search for the destination
* as our clue to the interface. Otherwise
* we can use the local address.
if (entry
->rt_flags
& RTF_HOST
)
ifa
= ifa_ifwithdstaddr(&entry
->rt_dst
);
ifa
= ifa_ifwithaddr(&entry
->rt_gateway
);
* If we are adding a route to a remote net
* or host, the gateway may still be on the
* other end of a pt to pt link.
ifa
= ifa_ifwithdstaddr(&entry
->rt_gateway
);
ifa
= ifa_ifwithnet(&entry
->rt_gateway
);
m
= m_get(M_DONTWAIT
, MT_RTABLE
);
m
->m_len
= sizeof (struct rtentry
);
rt
= mtod(m
, struct rtentry
*);
rt
->rt_dst
= entry
->rt_dst
;
rt
->rt_gateway
= entry
->rt_gateway
;
(entry
->rt_flags
& (RTF_HOST
|RTF_GATEWAY
|RTF_DYNAMIC
));
rt
->rt_ifp
= ifa
->ifa_ifp
;
* Set up a routing table entry, normally
rtinit(dst
, gateway
, cmd
, flags
)
struct sockaddr
*dst
, *gateway
;
bzero((caddr_t
)&route
, sizeof (route
));
route
.rt_gateway
= *gateway
;
(void) rtrequest(cmd
, &route
);