* Copyright (c) 1983, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
static char sccsid
[] = "@(#)input.c 5.16 (Berkeley) %G%";
* Routing Table Management Daemon
* Process a newly received packet.
register struct rt_entry
*rt
;
register struct netinfo
*n
;
register struct interface
*ifp
;
struct interface
*if_ifwithdstaddr();
register struct afswitch
*afp
;
static struct sockaddr badfrom
;
TRACE_INPUT(ifp
, from
, size
);
if (from
->sa_family
>= af_max
||
(afp
= &afswitch
[from
->sa_family
])->af_hash
== (int (*)())0) {
"\"from\" address in unsupported address family (%d), cmd %d\n",
from
->sa_family
, msg
->rip_cmd
);
size
-= 4 * sizeof (char);
if (size
< sizeof (struct netinfo
))
size
-= sizeof (struct netinfo
);
ntohs(n
->rip_dst
.sa_family
);
n
->rip_metric
= ntohl(n
->rip_metric
);
* A single entry with sa_family == AF_UNSPEC and
* metric ``infinity'' means ``all routes''.
* We respond to routers only if we are acting
* as a supplier, or to anyone other than a router
if (n
->rip_dst
.sa_family
== AF_UNSPEC
&&
n
->rip_metric
== HOPCNT_INFINITY
&& size
== 0) {
if (supplier
|| (*afp
->af_portmatch
)(from
) == 0)
if (n
->rip_dst
.sa_family
< af_max
&&
afswitch
[n
->rip_dst
.sa_family
].af_hash
)
rt
= rtlookup(&n
->rip_dst
);
n
->rip_metric
= rt
== 0 ? HOPCNT_INFINITY
:
min(rt
->rt_metric
+ 1, HOPCNT_INFINITY
);
htons(n
->rip_dst
.sa_family
);
n
->rip_metric
= htonl(n
->rip_metric
);
n
++, newsize
+= sizeof (struct netinfo
);
msg
->rip_cmd
= RIPCMD_RESPONSE
;
(*afp
->af_output
)(s
, 0, from
, newsize
);
/* verify message came from a privileged port */
if ((*afp
->af_portcheck
)(from
) == 0)
if ((ifp
= if_iflookup(from
)) == 0 || (ifp
->int_flags
&
(IFF_BROADCAST
| IFF_POINTOPOINT
| IFF_REMOTE
)) == 0 ||
ifp
->int_flags
& IFF_PASSIVE
) {
syslog(LOG_ERR
, "trace command from unknown router, %s",
(*afswitch
[from
->sa_family
].af_format
)(from
));
if (msg
->rip_cmd
== RIPCMD_TRACEON
)
traceon(msg
->rip_tracefile
);
/* verify message came from a router */
if ((*afp
->af_portmatch
)(from
) == 0)
/* are we talking to ourselves? */
ifp
= if_ifwithaddr(from
);
if (ifp
->int_flags
& IFF_PASSIVE
) {
"bogus input (from passive interface, %s)",
(*afswitch
[from
->sa_family
].af_format
)(from
));
if (rt
== 0 || ((rt
->rt_state
& RTS_INTERFACE
) == 0) &&
rt
->rt_metric
>= ifp
->int_metric
)
* Update timer for interface on which the packet arrived.
* If from other end of a point-to-point link that isn't
* in the routing tables, (re-)add the route.
if ((rt
= rtfind(from
)) &&
(rt
->rt_state
& (RTS_INTERFACE
| RTS_REMOTE
)))
else if ((ifp
= if_ifwithdstaddr(from
)) &&
(rt
== 0 || rt
->rt_metric
>= ifp
->int_metric
))
* "Authenticate" router from which message originated.
* We accept routing packets from routers directly connected
* via broadcast or point-to-point networks,
* and from those listed in /etc/gateways.
if ((ifp
= if_iflookup(from
)) == 0 || (ifp
->int_flags
&
(IFF_BROADCAST
| IFF_POINTOPOINT
| IFF_REMOTE
)) == 0 ||
ifp
->int_flags
& IFF_PASSIVE
) {
if (bcmp((char *)from
, (char *)&badfrom
,
"packet from unknown router, %s",
(*afswitch
[from
->sa_family
].af_format
)(from
));
size
-= 4 * sizeof (char);
for (; size
> 0; size
-= sizeof (struct netinfo
), n
++) {
if (size
< sizeof (struct netinfo
))
ntohs(n
->rip_dst
.sa_family
);
n
->rip_metric
= ntohl(n
->rip_metric
);
if (n
->rip_dst
.sa_family
>= af_max
||
(afp
= &afswitch
[n
->rip_dst
.sa_family
])->af_hash
==
"route in unsupported address family (%d), from %s (af %d)\n",
(*afswitch
[from
->sa_family
].af_format
)(from
),
if (((*afp
->af_checkhost
)(&n
->rip_dst
)) == 0) {
"bad host in route from %s (af %d)\n",
(*afswitch
[from
->sa_family
].af_format
)(from
),
* Adjust metric according to incoming interface.
if ((unsigned) n
->rip_metric
< HOPCNT_INFINITY
)
n
->rip_metric
+= ifp
->int_metric
;
if ((unsigned) n
->rip_metric
> HOPCNT_INFINITY
)
n
->rip_metric
= HOPCNT_INFINITY
;
rt
= rtlookup(&n
->rip_dst
);
(rt
->rt_state
& (RTS_INTERNAL
|RTS_INTERFACE
)) ==
(RTS_INTERNAL
|RTS_INTERFACE
)) {
* If we're hearing a logical network route
* back from a peer to which we sent it,
if (rt
&& rt
->rt_state
& RTS_SUBNET
&&
(*afp
->af_sendroute
)(rt
, from
))
if ((unsigned)n
->rip_metric
< HOPCNT_INFINITY
) {
* Look for an equivalent route that
* includes this one before adding
rt
= rtfind(&n
->rip_dst
);
if (rt
&& equal(from
, &rt
->rt_router
))
rtadd(&n
->rip_dst
, from
, n
->rip_metric
, 0);
* Update if from gateway and different,
* shorter, or equivalent but old route
if (equal(from
, &rt
->rt_router
)) {
if (n
->rip_metric
!= rt
->rt_metric
) {
rtchange(rt
, from
, n
->rip_metric
);
if (rt
->rt_metric
>= HOPCNT_INFINITY
)
GARBAGE_TIME
- EXPIRE_TIME
;
} else if (rt
->rt_metric
< HOPCNT_INFINITY
)
} else if ((unsigned) n
->rip_metric
< rt
->rt_metric
||
(rt
->rt_metric
== n
->rip_metric
&&
rt
->rt_timer
> (EXPIRE_TIME
/2) &&
(unsigned) n
->rip_metric
< HOPCNT_INFINITY
)) {
rtchange(rt
, from
, n
->rip_metric
);