static char sccsid
[] = "@(#)routed.c 4.2 %G%";
/* casts to keep lint happy */
#define insque(q,p) _insque((caddr_t)q,(caddr_t)p)
#define remque(q) _remque((caddr_t)q)
(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
struct sockaddr_in myaddr
= { AF_INET
, IPPORT_ROUTESERVER
};
int supplier
; /* process should supply updates */
int initializing
; /* stem off broadcast() calls */
int install
= 0; /* if 1 call kernel */
char packet
[MAXPACKETSIZE
];
extern int errno
, exit();
{ int t
= open("/dev/tty", 2);
(void) fopen("trace", "a");
(void) dup(fileno(stdout
));
myaddr
.sin_port
= htons(myaddr
.sin_port
);
s
= socket(SOCK_DGRAM
, 0, &myaddr
, 0);
if (strcmp(*argv
, "-s") == 0)
else if (strcmp(*argv
, "-q") == 0)
* Listen for routing packets
cc
= receive(s
, &from
, packet
, sizeof (packet
));
if (cc
< 0 && errno
!= EINTR
)
* Look in a file for any gateways we should configure
* outside the directly connected ones. This is a kludge,
* but until we can find out about gateways on the "other side"
* of the ARPANET using GGP, it's a must.
* We don't really know the distance to the gateway, so we
* assume it's a neighbor.
struct sockaddr_in dst
, gate
;
FILE *fp
= fopen("/etc/gateways", "r");
bzero((char *)&dst
, sizeof (dst
));
bzero((char *)&gate
, sizeof (gate
));
dst
.sin_family
= AF_INET
;
gate
.sin_family
= AF_INET
;
while (fscanf(fp
, "%x %x", &dst
.sin_addr
.s_addr
,
&gate
.sin_addr
.s_addr
) != EOF
) {
rtadd((struct sockaddr
*)&dst
, (struct sockaddr
*)&gate
, 1);
rt
= rtlookup((struct sockaddr
*)&dst
);
rt
->rt_flags
|= RTF_SILENT
;
register struct ifnet
*ifp
;
(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
if (ifp
->if_addr
.sa_family
!= addr
->sa_family
)
if (same(&ifp
->if_addr
, addr
))
if ((ifp
->if_flags
& IFF_BROADCAST
) &&
same(&ifp
->if_broadaddr
, addr
))
register struct sockaddr
*addr
;
register struct ifnet
*ifp
;
register int af
= addr
->sa_family
;
register int (*netmatch
)();
netmatch
= afswitch
[af
].af_netmatch
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
if (af
!= ifp
->if_addr
.sa_family
)
if ((*netmatch
)(addr
, &ifp
->if_addr
))
addr
= (net
<< 24) | host
;
addr
= (net
<< 16) | host
;
addr
= (net
<< 8) | host
;
return (*(struct in_addr
*)&addr
);
* Find the network interfaces attached to this machine.
* (1) initialize the routing tables, as done by the kernel.
* (2) ignore incoming packets we send.
* (3) figure out broadcast capability and addresses.
* (4) figure out if we're an internetwork gateway.
* We don't handle anything but Internet addresses.
register struct ifnet
**pifp
, *ifp
;
struct in_addr logicaladdr
;
if (nl
[N_IFNET
].n_value
== 0) {
printf("ifnet: symbol not in namelist\n");
kmem
= open("/dev/kmem", 0);
(void) lseek(kmem
, (long)nl
[N_IFNET
].n_value
, 0);
(void) read(kmem
, (char *)&ifnet
, sizeof (ifnet
));
bzero((char *)&net
, sizeof (net
));
net
.sin_family
= AF_INET
;
(void) lseek(kmem
, (long)*pifp
, 0);
ifp
= *pifp
= (struct ifnet
*)malloc(sizeof (struct ifnet
));
printf("routed: out of memory\n");
if (read(kmem
, (char *)ifp
, sizeof (*ifp
)) != sizeof (*ifp
)) {
if (ifp
->if_net
== LOOPBACKNET
)
if ((ifp
->if_flags
& IFF_UP
) == 0)
* Kludge: don't treat logical host pseudo-interface
* as a net route, instead fabricate route
* to get packets back from the gateway.
sin
= (struct sockaddr_in
*)&ifp
->if_addr
;
if (sin
->sin_family
== AF_INET
&& ifp
->if_net
== 10 &&
logicaladdr
= sin
->sin_addr
;
* Before we can handle point-point links, the interface
* structure will have to include an indicator to allow
* us to distinguish entries from "network" entries.
net
.sin_addr
= if_makeaddr(ifp
->if_net
, INADDR_ANY
);
rtadd((struct sockaddr
*)&net
, (struct sockaddr
*)sin
, 0);
if (logicaladdr
.s_addr
) {
net
.sin_addr
= logicaladdr
;
rtadd((struct sockaddr
*)&net
, &ifnet
->if_addr
, 0);
/* yech...yet another logical host kludge */
rt
= rtlookup((struct sockaddr
*)&net
);
rt
->rt_flags
|= RTF_SILENT
;
* Send a request message to all directly
* connected hosts and networks.
register struct rt_entry
*rt
;
register struct rt_hash
*rh
;
struct rt_hash
*base
= hosthash
;
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++)
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if ((rt
->rt_flags
& RTF_SILENT
) || rt
->rt_metric
> 0)
* Broadcast a new, or modified, routing table entry
* to all directly connected hosts and networks.
register struct rt_hash
*rh
;
register struct rt_entry
*rt
;
register struct sockaddr
*dst
;
struct rt_hash
*base
= hosthash
;
struct rip
*msg
= (struct rip
*)packet
;
msg
->rip_cmd
= RIPCMD_RESPONSE
;
msg
->rip_nets
[0].rip_dst
= entry
->rt_dst
;
msg
->rip_nets
[0].rip_metric
= entry
->rt_metric
+ 1;
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++)
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if ((rt
->rt_flags
& RTF_SILENT
) || rt
->rt_metric
> 0)
if (rt
->rt_ifp
&& (rt
->rt_ifp
->if_flags
& IFF_BROADCAST
))
dst
= &rt
->rt_ifp
->if_broadaddr
;
(*afswitch
[dst
->sa_family
].af_output
)(dst
, sizeof (struct rip
));
* Supply all directly connected neighbors with the
* current state of the routing tables.
register struct rt_entry
*rt
;
register struct rt_hash
*rh
;
register struct sockaddr
*dst
;
struct rt_hash
*base
= hosthash
;
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++)
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
if ((rt
->rt_flags
& RTF_SILENT
) || rt
->rt_metric
> 0)
if (rt
->rt_ifp
&& (rt
->rt_ifp
->if_flags
& IFF_BROADCAST
))
dst
= &rt
->rt_ifp
->if_broadaddr
;
* Supply routing information to target "sa".
struct rip
*msg
= (struct rip
*)packet
;
struct netinfo
*n
= msg
->rip_nets
;
register struct rt_hash
*rh
;
register struct rt_entry
*rt
;
struct rt_hash
*base
= hosthash
;
int space
= MAXPACKETSIZE
- sizeof (int), doinghost
= 1;
int (*output
)() = afswitch
[sa
->sa_family
].af_output
;
msg
->rip_cmd
= RIPCMD_RESPONSE
;
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++)
for (rt
= rh
->rt_forw
; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
* Flush packet out if not enough room for
* another routing table entry.
if (space
< sizeof (struct netinfo
)) {
(*output
)(sa
, MAXPACKETSIZE
- space
);
space
= MAXPACKETSIZE
- sizeof (int);
n
->rip_metric
= rt
->rt_metric
+ 1;
n
++, space
-= sizeof (struct netinfo
);
if (space
< MAXPACKETSIZE
- sizeof (int))
(*output
)(sa
, MAXPACKETSIZE
- space
);
register struct rip
*msg
= (struct rip
*)packet
;
msg
->rip_cmd
= RIPCMD_REQUEST
;
msg
->rip_nets
[0].rip_dst
.sa_family
= AF_UNSPEC
;
msg
->rip_nets
[0].rip_metric
= HOPCNT_INFINITY
;
if (rt
->rt_ifp
&& (rt
->rt_ifp
->if_flags
& IFF_BROADCAST
))
dst
= &rt
->rt_ifp
->if_broadaddr
;
(*afswitch
[dst
->sa_family
].af_output
)(dst
, sizeof (struct rip
));
* Respond to a routing info request.
register struct rip
*msg
= (struct rip
*)packet
;
struct netinfo
*np
= msg
->rip_nets
;
if (size
< sizeof (struct netinfo
))
size
-= sizeof (struct netinfo
);
if (np
->rip_dst
.sa_family
== AF_UNSPEC
&&
np
->rip_metric
== HOPCNT_INFINITY
&& size
== 0) {
rt
= rtlookup(&np
->rip_dst
);
np
->rip_metric
= rt
== 0 ? HOPCNT_INFINITY
: rt
->rt_metric
+ 1;
np
++, newsize
+= sizeof (struct netinfo
);
msg
->rip_cmd
= RIPCMD_RESPONSE
;
(*afswitch
[from
->sa_family
].af_output
)(from
, newsize
);
* Handle an incoming routing packet.
register struct rip
*msg
= (struct rip
*)packet
;
if (msg
->rip_cmd
!= RIPCMD_RESPONSE
&&
msg
->rip_cmd
!= RIPCMD_REQUEST
)
* The router port is in the lower 1K of the UDP port space,
* and so is priviledged. Hence we can "authenticate" incoming
* updates simply by checking the source port.
if (msg
->rip_cmd
== RIPCMD_RESPONSE
&&
(*afswitch
[from
->sa_family
].af_portmatch
)(from
) == 0)
if (msg
->rip_cmd
== RIPCMD_REQUEST
) {
* Extraneous information like Internet ports
* must first be purged from the sender's address for
* pattern matching below.
(*afswitch
[from
->sa_family
].af_canon
)(from
);
printf("input from %x\n", from
->sin_addr
);
* If response packet is from ourselves, use it only
* to reset timer on entry. Otherwise, we'd believe
* it as gospel (since it comes from the router) and
* unknowingly update the metric to show the outgoing
* cost (higher than our real cost). I guess the protocol
* spec doesn't address this because Xerox Ethernets
* don't hear their own broadcasts?
if (if_ifwithaddr(from
)) {
for (; size
> 0; size
-= sizeof (struct netinfo
), n
++) {
if (size
< sizeof (struct netinfo
))
printf("dst %x hc %d...", n
->rip_dst
.sin_addr
,
rt
= rtlookup(&n
->rip_dst
);
* Unknown entry, add it to the tables only if
if (n
->rip_metric
< HOPCNT_INFINITY
)
rtadd(&n
->rip_dst
, from
, n
->rip_metric
);
printf("ours: gate %x hc %d timer %d\n",
rt
->rt_metric
, rt
->rt_timer
);
* Update the entry if one of the following is true:
* (1) The update came directly from the gateway.
* (2) A shorter path is provided.
* (3) The entry hasn't been updated in a while
* and a path of equivalent cost is offered.
if (equal(from
, &rt
->rt_gateway
) ||
rt
->rt_metric
> n
->rip_metric
||
(rt
->rt_timer
> (EXPIRE_TIME
/2) &&
rt
->rt_metric
== n
->rip_metric
)) {
rtchange(rt
, from
, n
->rip_metric
);
* Lookup an entry to the appropriate dstination.
register struct rt_entry
*rt
;
register struct rt_hash
*rh
;
register int hash
, (*match
)();
int af
= dst
->sa_family
, doinghost
= 1;
(*afswitch
[af
].af_hash
)(dst
, &h
);
rh
= &hosthash
[hash
% ROUTEHASHSIZ
];
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
))
match
= afswitch
[af
].af_netmatch
;
rh
= &nethash
[hash
% ROUTEHASHSIZ
];
register struct rt_hash
*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
;
struct sockaddr
*dst
, *gate
;
register struct rt_entry
*rt
;
int af
= dst
->sa_family
, flags
, hash
;
(*afswitch
[af
].af_hash
)(dst
, &h
);
flags
= (*afswitch
[af
].af_checkhost
)(dst
) ? RTF_HOST
: 0;
rh
= &hosthash
[hash
% ROUTEHASHSIZ
];
rh
= &nethash
[hash
% ROUTEHASHSIZ
];
rt
= (struct rt_entry
*)malloc(sizeof (*rt
));
rt
->rt_flags
= RTF_UP
| flags
;
rt
->rt_ifp
= if_ifwithnet(&rt
->rt_gateway
);
rt
->rt_flags
|= RTF_DIRECT
;
rt
->rt_flags
|= RTF_ADDRT
;
rt
->rt_retry
= EXPIRE_TIME
/TIMER_RATE
;
* Look to see if a change to an existing entry
* is warranted; if so, make it.
rtchange(rt
, gate
, metric
)
if (!equal(&rt
->rt_gateway
, gate
)) {
* If the hop count has changed, adjust
* the flags in the routing table entry accordingly.
if (metric
!= rt
->rt_metric
) {
rt
->rt_flags
&= ~RTF_DIRECT
;
if (metric
>= HOPCNT_INFINITY
)
rt
->rt_flags
|= RTF_CHGRT
;
rt
->rt_retry
= EXPIRE_TIME
/TIMER_RATE
;
* Delete a routing table entry.
if (ioctl(s
, SIOCDELRT
, (char *)&rt
->rt_hash
) &&
rt
->rt_flags
|= RTF_DELRT
;
* o handle timers on table entries,
* o invalidate entries which haven't been updated in a while,
* o delete entries which are too old,
* o retry ioctl's which weren't successful the first
* time due to the kernel entry being busy
* o if we're an internetwork router, supply routing updates
register struct rt_hash
*rh
;
register struct rt_entry
*rt
;
struct rt_hash
*base
= hosthash
;
printf(">>> time %d >>>\n", timeval
);
for (rh
= base
; rh
< &base
[ROUTEHASHSIZ
]; rh
++) {
for (; rt
!= (struct rt_entry
*)rh
; rt
= rt
->rt_forw
) {
* If the host is indicated to be
* "silent" (i.e. it's a logical host,
* or one we got from the initialization
* file), don't time out it's entry.
if (rt
->rt_flags
& RTF_SILENT
)
rt
->rt_timer
+= TIMER_RATE
;
if (rt
->rt_timer
>= GARBAGE_TIME
||
(rt
->rt_flags
& RTF_DELRT
)) {
if (rt
->rt_timer
>= EXPIRE_TIME
)
rt
->rt_metric
= HOPCNT_INFINITY
;
if (rt
->rt_flags
& RTF_CHGRT
)
if (!ioctl(s
, SIOCCHGRT
,(char *)&rt
->rt_hash
) ||
rt
->rt_flags
&= ~RTF_CHGRT
;
if (rt
->rt_flags
& RTF_ADDRT
)
if (!ioctl(s
, SIOCADDRT
,(char *)&rt
->rt_hash
) ||
rt
->rt_flags
&= ~RTF_ADDRT
;
if (supplier
&& (timeval
% SUPPLY_INTERVAL
) == 0)
printf("<<< time %d <<<\n", timeval
);
struct sockaddr_in
*dst
, *gate
;
{ RTF_DIRECT
, "DIRECT" },
{ RTF_SILENT
, "SILENT" },
register struct flagbits
*p
;
printf("%s ", operation
);
dst
= (struct sockaddr_in
*)&rt
->rt_dst
;
gate
= (struct sockaddr_in
*)&rt
->rt_gateway
;
printf("dst %x, router %x, metric %d, flags ",
dst
->sin_addr
, gate
->sin_addr
, rt
->rt_metric
);
for (first
= 1, p
= bits
; p
->t_bits
> 0; p
++) {
if ((rt
->rt_flags
& p
->t_bits
) == 0)