1
0
Files
irix-657m-src/eoe/cmd/bsd/gated/rt_egp.c
2022-09-29 17:59:04 +03:00

789 lines
28 KiB
C

/*
* CENTER FOR THEORY AND SIMULATION IN SCIENCE AND ENGINEERING
* CORNELL UNIVERSITY
*
* Portions of this software may fall under the following
* copyrights:
*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* GATED - based on Kirton's EGP, UC Berkeley's routing daemon (routed),
* and DCN's HELLO routing Protocol.
*/
#ifndef lint
static char *rcsid = "$Header: /proj/irix6.5.7m/isms/eoe/cmd/bsd/gated/RCS/rt_egp.c,v 1.1 1989/09/18 19:02:15 jleong Exp $";
#endif not lint
/*
* rt_egp.c
*
* EGP route update and processing and preparation functions.
*
* Functions: rt_NRnets, rt_NRupdate
*/
#include "include.h"
/*
* rt_NRnets() prepares the network part of the EGP Network Reachability
* update message with respect to the shared network of the EGP peer.
* This only includes the networks in the interior routing table (direct
* networks, and remote networks of non-routing gateways of this autonomous
* system) other than the net shared by the EGP peer. If the user has
* specified that only certain networks are allowed to be advised all others
* are excluded from outgoing NR update messages.
* If the interior routing table includes other interior gateways on the
* network shared with the EGP peer (i.e. indirect neighbors), they are
* included in updates as the appropriate first hop to their attached
* networks.
* This function checks the status of routes and if down sets the
* distance as unreachable.
*
* Returns the length of the EGP NR packet in octets or ERROR if an error
* has occurred.
*/
rt_NRnets(nrpkt, ngp)
struct egpnr *nrpkt; /* start of NR message */
struct egpngh *ngp; /* Pointer to entry in neighbor table */
{
struct rt_entry *rt;
struct rthash *rh;
struct net_order { /* temporary linked list for ordering nets */
struct net_order *next;
struct in_addr net; /* net # */
struct in_addr gateway;
int distance;
} *start_net, *free_net;
register struct net_order *net_pt, *this_net; /* current search point */
int n_bytes;
struct in_addr current_gw;
register u_char *nrp; /* next octet of NR message */
u_char *n_distance, *distance, *n_nets;
int this_metric;
u_long current_net;
#ifndef NSS
struct interface *tifp;
struct sockaddr_in tsock;
bzero((char *)&tsock, sizeof(tsock));
tsock.sin_family = AF_INET;
tsock.sin_addr.s_addr = ngp->ng_myaddr.s_addr;
if ((tifp = if_ifwithaddr((struct sockaddr *)&tsock)) <= (struct interface *)0) {
TRACE_INT("No interface for egp, %s wanted\n", inet_ntoa(ngp->ng_myaddr));
syslog(LOG_ERR, "No interface for egp, %s wanted", inet_ntoa(ngp->ng_myaddr));
return(ERROR);
}
#else NSS
struct rt_entry *rt_igp;
struct rt_entry *rt_egp;
#endif NSS
/*
* Reorder the interior routes as required for the NR message with respect to
* the given shared net. Uses a temporary linked list terminated by NULL
* pointer. The first element of the list is a dummy so insertions can be done
* before the first true entry. The route status is checked and if down the
* distance is set as unreachable. The required order groups nets by gateway
* and in order of increasing metric. This gateway is listed first (with all
* nets not reached by gateways on the shared net) and then neighbor gateways
* on the shared net, in any order. As there are few nets to be reported by a
* stub gateway, each route is copied from the interior routing table and
* inserted in the temporary reordered list using a linear search.
*
* Use the total number of networks to be sure we allocate a large enough
* buffer.
*/
start_net = (struct net_order *)malloc((unsigned)((n_routes +
n_interfaces) * sizeof(struct net_order)));
if (start_net == NULL) {
syslog(LOG_ERR, "rt_NRnets: malloc: out of memory");
TRACE_TRC("rt_NRnets: malloc: out of memory\n");
return(ERROR);
}
start_net->next = NULL;
/*
* ensures first gateway listed is self
*/
start_net->gateway = ngp->ng_myaddr;
free_net = start_net + 1; /* first element dummy to ease insertion code */
/*
* check all interior routes of route table
*/
for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
/*
* extra sanity check cause we don't want to EGP out
* subnets.
*/
if (rt->rt_state & RTS_SUBNET) {
continue;
}
TRACE_EGPUPD("EGP: net %-15s AS %5d - ",inet_ntoa(sock_inaddr(&rt->rt_dst)), rt->rt_as);
/*
* Don't allow the DEFAULT net through, unless we are allowed to
* send DEFAULT and this is the internally generated default.
*/
if ((sock_inaddr(&rt->rt_dst).s_addr == DEFAULTNET) && (rt->rt_proto != RTPROTO_DEFAULT) ) {
TRACE_EGPUPD("not propogating default.\n");
continue;
}
/*
* ignore nets that are not Class A, B or C
*/
current_net = sock_inaddr(&rt->rt_dst).s_addr;
if ( gd_inet_class((u_char *)&current_net) == 0 ) {
TRACE_EGPUPD("not Class A, B or C\n");
syslog(LOG_ERR, "rt_NRnets: net not class A, B or C: %s",
inet_ntoa(sock_inaddr(&rt->rt_dst)));
continue;
}
/*
* ignore nets not to be advised
*/
if (adlist && !(rt->rt_proto & RTPROTO_DEFAULT) && !(rt->rt_proto & RTPROTO_EGP)) {
register struct advlist *ad;
register int OK = 0;
for (ad = adlist; ad; ad = ad->next) {
if (sock_inaddr(&rt->rt_dst).s_addr == ad->destnet.s_addr) {
OK++;
}
}
if (!OK) {
TRACE_EGPUPD("not on egpnetsreachable list\n");
continue;
}
}
switch (rt->rt_proto) {
case RTPROTO_DIRECT:
/*
* Direct routes use the lowest metric of interfaces to this net
*/
#ifdef EGP_SKIP_SHARED
/*
* ignore shared net
*/
if (gd_inet_wholenetof(sock_inaddr(&rt->rt_dst)) == gd_inet_wholenetof(ngp->ng_myaddr)) {
TRACE_EGPUPD("shared net.\n");
continue;
}
#endif EGP_SKIP_SHARED
if (sendAS(ngp->ng_aslist, mysystem) == 0) {
TRACE_EGPUPD("direct routes not valid for this AS.\n");
goto Continue;
}
if (adlist || is_valid(rt, RTPROTO_EGP, tifp)) {
if (rt->rt_flags & RTF_UP) {
if (rt->rt_announcelist) {
this_metric = rt->rt_announcelist->regpmetric;
} else {
#ifdef notdef
this_metric = mapmetric(HELLO_TO_EGP, (u_short)rt->rt_metric);
#else notdef
this_metric = conv_factor; /* Default metric specified in 'defaultegpmetric' clauase */
#endif notdef
}
} else {
this_metric = HOPCNT_INFINITY;
}
} else {
TRACE_EGPUPD("restrictions prohibit announcement\n");
goto Continue;
}
break;
#ifndef NSS
case RTPROTO_RIP:
case RTPROTO_HELLO:
if ((rt->rt_state & RTS_INTERIOR) == 0) {
TRACE_EGPUPD("exterior routes not announced\n");
continue;
}
if (sendAS(ngp->ng_aslist, mysystem) == 0) {
TRACE_EGPUPD("interior routes not valid for this AS.\n");
goto Continue;
}
if (adlist || is_valid(rt, RTPROTO_EGP, tifp)) {
if (rt->rt_metric < DELAY_INFINITY) {
if (rt->rt_announcelist) {
this_metric = rt->rt_announcelist->regpmetric;
} else {
this_metric = conv_factor;
}
} else {
this_metric = HOPCNT_INFINITY;
}
} else {
TRACE_EGPUPD("restrictions prohibit announcement\n");
goto Continue;
}
break;
#endif NSS
case RTPROTO_DEFAULT:
if ( !(ngp->ng_flags & NG_DEFAULTOUT) ) {
TRACE_EGPUPD("not originating default\n");
goto Continue;
}
break;
#ifdef NSS
case RTPROTO_IGP:
if (as_reach(rt->rt_as) != TRUE) {
TRACE_EGPUPD("Autonomous System %d is unreachable\n", rt->rt_as);
goto Continue;
}
if (rt->rt_as == ngp->ng_asin) {
TRACE_EGPUPD("split horizon\n");
goto Continue;
}
switch (sendAS(ngp->ng_aslist, rt->rt_as)) {
case 0: /* not valid for this AS */
TRACE_EGPUPD("not valid for this AS\n");
goto Continue;
case 2: /* valid to send - announce clauses apply */
if (is_valid(rt, RTPROTO_EGP, tifp)) {
if (rt->rt_metric < DELAY_INFINITY) {
if (rt->rt_announcelist) {
this_metric = rt->rt_announcelist->regpmetric;
} else {
#ifdef notdef
this_metric = mapmetric(HELLO_TO_EGP, (u_short)rt->rt_metric); /* What metric should I use? */
#else notdef
this_metric = conv_factor; /* No metric specified, use 'defaultegpmetric' */
#endif notdef
}
} else {
this_metric = HOPCNT_INFINITY;
}
} else {
TRACE_EGPUPD("restrictions prohibit announcement\n");
goto Continue;
}
break;
case 1: /* valid to send - announce clauses do not apply */
case -1: /* no AS restrictions */
#ifdef notdef
this_metric = mapmetric(HELLO_TO_EGP, (u_short)rt->rt_metric); /* What metric should I use? */
#else notdef
this_metric = conv_factor; /* No metric specified, use 'defaultegpmetric' */
#endif notdef
break;
}
/*
* If we have both IGP and EGP learned route, do
* not bother to advertize it twice.
*/
if ((rt_egp = rt_locate((int) EXTERIOR, (struct sockaddr_in *) &rt->rt_dst,RTPROTO_EGP)) != NULL) {
if ((rt_egp->rt_metric <= rt->rt_metric) && (rt_egp->rt_as != ngp->ng_asin) &&
(as_reach(rt_egp->rt_as) == TRUE) && (sendAS(ngp->ng_aslist, rt_egp->rt_as) != 0)) {
TRACE_EGPUPD("Have both IGP and EGP learned route... ignoring IGP\n");
goto Continue;
}
}
break;
#endif NSS
case RTPROTO_EGP:
if (rt->rt_as == ngp->ng_asin) {
TRACE_EGPUPD("split horizon\n");
goto Continue;
}
switch (sendAS(ngp->ng_aslist, rt->rt_as)) {
case 0: /* not valid to send */
TRACE_EGPUPD("not valid for this AS\n");
goto Continue;
case 2: /* valid to send - announce clauses apply */
if (is_valid(rt, RTPROTO_EGP, tifp)) {
if (rt->rt_metric < DELAY_INFINITY) {
if (rt->rt_announcelist) {
this_metric = rt->rt_announcelist->regpmetric;
} else {
#ifdef notdef
this_metric = mapmetric(HELLO_TO_EGP, (u_short)rt->rt_metric);
#else notdef
this_metric = rt->rt_metric_exterior; /* Propogate EGP metric? */
#endif notdef
}
} else {
this_metric = HOPCNT_INFINITY;
}
} else {
TRACE_EGPUPD("restrictions prohibit announcement\n");
goto Continue;
}
break;
case 1: /* valid to send - announce clauses do not apply */
#ifdef notdef
this_metric = mapmetric(HELLO_TO_EGP, (u_short)rt->rt_metric);
#else notdef
this_metric = rt->rt_metric_exterior; /* Propogate EGP metric? */
#endif notdef
break;
case -1: /* no AS restrictions */
TRACE_EGPUPD("no AS restrictions\n");
goto Continue;
}
#ifdef NSS
/*
* If we have both IGP and EGP learned route, do
* not bother to advertize it twice.
*/
if ((rt_egp = rt_locate((int) EXTERIOR, (struct sockaddr_in *) &rt->rt_dst, RTPROTO_EGP)) != NULL) {
if ((rt_egp->rt_metric <= rt->rt_metric) && (rt_egp->rt_as != ngp->ng_asin) &&
(as_reach(rt_egp->rt_as) == TRUE) && (sendAS(ngp->ng_aslist, rt_egp->rt_as) != 0)) {
TRACE_EGPUPD("Have both IGP and EGP learned route... ignoring IGP\n");
goto Continue;
}
}
#endif NSS
break;
case RTPROTO_KERNEL:
TRACE_EGPUPD("not sending kernel routes\n");
goto Continue;
case RTPROTO_REDIRECT:
TRACE_EGPUPD("not sending redirected routes\n");
goto Continue;
default:
TRACE_EGPUPD("unknown protocol %d\n", rt->rt_proto);
goto Continue;
} /* switch (rt->rt_proto) */
/*
* committed to advertising net
*/
this_net = free_net++;
this_net->net.s_addr = sock_inaddr(&rt->rt_dst).s_addr;
this_net->distance = this_metric;
/*
* assign gw on shared net
*/
if (gd_inet_wholenetof(sock_inaddr(&rt->rt_router)) != gd_inet_wholenetof(ngp->ng_myaddr)) {
this_net->gateway = ngp->ng_myaddr; /* gw is self */
} else {
this_net->gateway = sock_inaddr(&rt->rt_router); /* gw is neighbor */
}
/*
* If this is the DEFAULT net, set the specified metric, we are
* the gateway.
*/
if ( this_net->net.s_addr == DEFAULTNET ) {
this_net->gateway = ngp->ng_myaddr;
this_net->distance = ngp->ng_defaultmetric;
TRACE_EGPUPD(" DEFAULT - ");
}
TRACE_EGPUPD("metric %3d ..", this_net->distance);
/*
* insert net in ordered list
*/
for (net_pt = start_net; net_pt->next; net_pt = net_pt->next) {
if (this_net->gateway.s_addr == net_pt->next->gateway.s_addr) {
if (this_net->distance <= net_pt->next->distance)
break;
} else {
if (this_net->gateway.s_addr == net_pt->gateway.s_addr) {
break;
}
}
} /* for (all nets to be announced) */
/*
* insert this net after search net
*/
this_net->next = net_pt->next;
net_pt->next = this_net;
TRACE_EGPUPD("added to update distance %3d gateway %s\n",
this_net->distance, inet_ntoa(this_net->gateway));
Continue: ;
} /* end for all interior routes */
/*
* copy nets into NR message
*/
nrpkt->en_igw = 0; /* init # interior gateways */
nrp = (u_char *)(nrpkt + 1); /* start nets part NR msg */
current_gw.s_addr = 0; /* ensure first gateway addr copied */
for (net_pt = start_net->next; net_pt != NULL; net_pt = net_pt->next) {
if ( (net_pt->distance < HOPCNT_INFINITY) && (ngp->ng_flags & NG_METRICOUT) ) {
net_pt->distance = ngp->ng_metricout;
}
if (net_pt->gateway.s_addr != current_gw.s_addr) {
/* new gateway */
current_gw.s_addr = net_pt->gateway.s_addr;
current_net = current_gw.s_addr;
n_bytes = 4 - gd_inet_class((u_char *)&current_net);
bcopy((char *)&current_net + 4 - n_bytes, (char *)nrp, n_bytes);
nrp += n_bytes;
nrpkt->en_igw++;
n_distance = nrp++;
*n_distance = 1;
distance = nrp++;
*distance = net_pt->distance;
n_nets = nrp++;
*n_nets = 1;
} else if ( (net_pt->distance != *distance) || (*n_nets == 255) ) {
/* New distance or this distance if ull */
(*n_distance)++;
distance = nrp++;
*distance = net_pt->distance;
n_nets = nrp++;
*n_nets = 1;
} else {
(*n_nets)++;
}
current_net = net_pt->net.s_addr;
n_bytes = gd_inet_class((u_char *)&current_net);
bcopy((char *)&current_net, (char *)nrp, n_bytes);
nrp += n_bytes;
} /* end for each net */
free((char *)start_net);
return(nrp - (u_char *)nrpkt); /* length of NR message */
}
/*
* rt_NRupdate() updates the exterior routing tables on receipt of an NR
* update message from an EGP neighbor. It first checks for valid NR counts
* before updating the routing tables.
*
* EGP Updates are used to update the exterior routing table if one of the
* following is satisfied:
* - No routing table entry exists for the destination network and the
* metric indicates the route is reachable (< 255).
* - The advised gateway is the same as the current route.
* - The advised distance metric is less than the current metric.
* - The current route is older (plus a margin) than the maximum poll
* interval for all acquired EGP neighbors. That is, the route was
* omitted from the last Update.
*
* Returns 1 if there is an error in NR message data, 0 otherwise.
*/
rt_NRupdate(ngp, pkt, egplen)
struct egpngh *ngp; /* pointer to neighbor state table */
struct egppkt *pkt;
int egplen; /* length EGP NR packet */
{
register u_char *nrb;
struct egpnr *nrp = (struct egpnr *)pkt;
struct sockaddr_in destination, gateway;
u_char gw[4]; /* gateway internet address */
int gw_class,
net_class,
ng,
nd,
nn,
n_gw,
n_dist,
n_net,
metric,
state,
checkingNR = TRUE,
change = FALSE,
NR_nets = 0;
u_short distance;
struct rt_entry *rt;
u_short pkt_system;
#ifndef NSS
struct interface *ifp;
#else NSS
struct rt_entry *rt_igp;
int flood = FALSE;
#endif NSS
bzero((char *)&destination, sizeof(destination));
bzero((char *)&gateway, sizeof(gateway));
gateway.sin_family = AF_INET;
destination.sin_family = AF_INET;
#ifndef NSS
gateway.sin_addr.s_addr = ngp->ng_myaddr.s_addr;
if ((ifp = if_ifwithaddr((struct sockaddr *)&gateway)) <= (struct interface *)0) {
TRACE_INT("No interface for egp, %s wanted\n", inet_ntoa(ngp->ng_myaddr));
syslog(LOG_ERR, "No interface for egp, %s wanted", inet_ntoa(ngp->ng_myaddr));
return(EUNSPEC);
}
#endif NSS
/*
* check class of shared net
*/
*(u_long *)gw = nrp->en_net.s_addr; /* set net part of gateways */
if ( (gw_class = gd_inet_class((u_char *)&gw[0])) == 0 ) {
return(EBADDATA); /* NR message error */
}
pkt_system = htons(pkt->egp_system);
n_gw = nrp->en_igw + nrp->en_egw;
/*
* First check NR message for valid counts, then repeat and update routing
* tables
*/
repeat:
nrb = (u_char *)nrp + sizeof(struct egpnr); /* start first gw */
for (ng = 0; ng < n_gw; ng++) { /* all gateways */
switch (gw_class) { /* fill gateway local address */
case CLAA: gw[1] = *nrb++;
case CLAB: gw[2] = *nrb++;
case CLAC: gw[3] = *nrb++;
}
gateway.sin_addr.s_addr = (ngp->ng_flags & NG_GATEWAY) ? ngp->ng_gateway.s_addr : *(u_long *)gw;
n_dist = *nrb++;
for (nd = 0; nd < n_dist; nd++) { /* all distances this gateway */
distance = (u_short)(*nrb++);
#ifdef NSS
metric = mapmetric(EGP_TO_HELLO, distance); /* Is there a value to use as default metric? */
if ( ngp->ng_flags & NG_METRICIN ) {
metric = ngp->ng_metricin;
}
#else NSS
metric = mapmetric(RIP_TO_HELLO, (unsigned short) ifp->int_metric);
if ( (metric < TDHOPCNT_INFINITY) && (ngp->ng_flags & NG_METRICIN) ) {
metric = ngp->ng_metricin;
}
#endif NSS
n_net = *nrb++;
if ( !checkingNR ) {
NR_nets += n_net;
}
for (nn = 0; nn < n_net; nn++) { /* all nets this distance */
if ( (net_class = gd_inet_class(nrb)) == 0 ) {
net_class = 3;
}
destination.sin_addr.s_addr = 0; /* zero unused bytes*/
bcopy((char *)nrb, (char *)&destination.sin_addr.s_addr, net_class);
nrb += net_class;
if ( !gd_inet_class((u_char *)&destination.sin_addr.s_addr) ) {
char badgate[16], badvia[16];
(void) strcpy(badgate, inet_ntoa(ngp->ng_addr));
(void) strcpy(badvia, inet_ntoa(gateway.sin_addr));
if ( checkingNR ) {
TRACE_EXT("rt_NRupdate: net %-15s not class A, B or C from %-15s via %-15s at %s",
inet_ntoa(destination.sin_addr), badgate, badvia, strtime);
change = TRUE;
syslog(LOG_ERR,
"rt_NRupdate: net %s not class A, B or C from %s via %s\n",
inet_ntoa(destination.sin_addr), badgate, badvia);
}
#ifdef notdef
return(EBADDATA); /* Ignore complete NR packet */
#else notdef
continue; /* Ignore only this route */
#endif notdef
}
if ( is_martian(destination.sin_addr) ) {
char badgate[16], badvia[16];
(void) strcpy(badgate, inet_ntoa(ngp->ng_addr));
(void) strcpy(badvia, inet_ntoa(gateway.sin_addr));
if ( checkingNR ) {
TRACE_EXT("rt_NRupdate: ignoring invalid net %-15s from %-15s via %-15s at %s",
inet_ntoa(destination.sin_addr), badgate, badvia, strtime);
change = TRUE;
syslog(LOG_WARNING, "rt_NRupdate: ignoring invalid net %s from %s via %s",
inet_ntoa(destination.sin_addr), badgate, badvia);
}
continue;
}
if ( (destination.sin_addr.s_addr == DEFAULTNET) && !(ngp->ng_flags & NG_DEFAULTIN) ) {
char badgate[16], badvia[16];
(void) strcpy(badgate, inet_ntoa(ngp->ng_addr));
(void) strcpy(badvia, inet_ntoa(gateway.sin_addr));
if ( checkingNR ) {
TRACE_EXT("rt_NRupdate: ignoring net %-15s from %-15s via %-15s at %s",
inet_ntoa(destination.sin_addr), badgate, badvia, strtime);
change = TRUE;
syslog(LOG_WARNING, "rt_NRupdate: ignoring net %s from %s via %s",
inet_ntoa(destination.sin_addr), badgate, badvia);
}
continue;
}
if (checkingNR) { /* first check counts only */
if (nrb > (u_char *)nrp + egplen + 1)
return(EBADDATA); /* erroneous counts in NR */
} else { /* update routing table */
if (gateway.sin_addr.s_addr == ngp->ng_myaddr.s_addr)
continue;
/*
* If the validas list exists, check if this net/AS combination is on it.
*/
if (ngp->ng_flags & NG_VALIDATE) {
int valid = 0;
if (validas) {
struct as_valid *tmp_valid;
for (tmp_valid = validas; tmp_valid; tmp_valid = tmp_valid->next) {
if ( (tmp_valid->as == pkt_system) &&
(tmp_valid->dst.s_addr == destination.sin_addr.s_addr) ) {
valid++;
if ( metric < TDHOPCNT_INFINITY ) {
metric = tmp_valid->metric;
}
break;
}
}
}
if (!valid) {
if ( tracing & TR_EGP ) {
printf("rt_NRupdate: net %-15s not valid from AS %5d at %s",
inet_ntoa(destination.sin_addr), pkt_system, strtime);
change = TRUE;
}
#ifdef notdef
syslog(LOG_WARNING, "rt_NRupdate: net %s not valid from AS %d",
inet_ntoa(destination.sin_addr), pkt_system);
#endif notdef
continue;
}
}
/*
* check for internal route
*/
state = 0;
if ((rt = rt_lookup((int)INTERIOR, &destination)) != NULL) {
/*
* assume INTERIOR route is better ,
* if it's there at all.
*
* Extra sanity check to keep duplicate routes
* out of the kernel. Makes things neater.
*/
while (rt = rt_lookup((int)EXTERIOR, &destination)) {
rt_delete(rt, KERNEL_INTR);
}
continue;
}
#ifdef NSS
rt = rt_locate((int)EXTERIOR, &destination, RTPROTO_EGP);
#else NSS
rt = rt_lookup((int)EXTERIOR, &destination);
#endif NSS
if (rt == NULL) { /* new route */
if (metric >= TDHOPCNT_INFINITY) {
continue;
}
if (rt = rt_add((int)EXTERIOR, (struct sockaddr *)&destination, (struct sockaddr *)&gateway, metric, state,
RTPROTO_EGP, RTPROTO_EGP, ngp->ng_as, distance) ) {
#ifdef NSS
psp_egp_rtadd(&destination, &gateway, ngp->ng_myaddr);
rt_igp = rt_locate((int) EXTERIOR, &destination, RTPROTO_IGP);
if (rt_igp != NULL) {
if (rt_igp->rt_metric >= metric) {
es_rtdel(&destination);
es_rtadd(&destination, ngp->ng_as);
}
} else {
es_rtadd(&destination, pkt_ngp->ng_as);
}
flood = TRUE;
#endif NSS
change = TRUE;
}
} else { /* existing route */
if (equal(&rt->rt_router, &gateway) && (rt->rt_as == ngp->ng_as)) { /* same gw */
if (metric < TDHOPCNT_INFINITY) {
if (metric < rt->rt_metric) {
if (rt_change(rt, (struct sockaddr *)&gateway, metric, RTPROTO_EGP, RTPROTO_EGP, ngp->ng_as, distance)) {
#ifdef NSS
flood = TRUE;
#endif NSS
change = TRUE;
}
}
rt->rt_timer = 0;
} else {
change = rt_unreach(rt);
}
} else { /* different gateway */
if (rt->rt_as == ngp->ng_as) {
/* Same Autonotmous system */
if (distance < rt->rt_metric_exterior) {
#ifdef NSS
struct sockaddr old_gateway = rt->rt_router;
/* Advertized metric is better */
#endif NSS
if (rt_change(rt, (struct sockaddr *)&gateway, metric, RTPROTO_EGP, RTPROTO_EGP, ngp->ng_as, distance)) {
#ifdef NSS
psp_egp_rtdel(&rt->rt_dst, &old_gateway);
psp_egp_rtadd(&destination, &gateway, ngp->ng_myaddr);
#endif NSS
rt->rt_timer = 0;
change = TRUE;
}
}
} else
if ((metric < rt->rt_metric) ||
( (metric >= rt->rt_metric) && (rt->rt_timer > maxpollint) && !(rt->rt_state & RTS_CHANGED)) ) {
#ifdef NSS
int egp_metric = rt->rt_metric;
psp_egp_rtdel(&rt->rt_dst, &rt->rt_router);
psp_egp_rtadd(&destination, &gateway, ngp->ng_myaddr);
#endif NSS
if (rt_change(rt, (struct sockaddr *)&gateway, metric, RTPROTO_EGP, RTPROTO_EGP, ngp->ng_as, distance)) {
#ifdef NSS
rt_igp = rt_locate((int) EXTERIOR, &destination, RTPROTO_IGP);
/*
* Check whether we have to replace IGP route (if exists)
* with EGP learned route.
* We'll do it if either there is not IGP route or
* IGP route is more expensive.
*/
if (((rt_igp != NULL) && (metric <= rt_igp->rt_metric)) || (rt_igp == NULL)) {
TRACE_INT("rt_NRupdate: Replacing IGP route with EGP route\n");
es_rtdel(&destination);
es_rtadd(&destination, ngp->ng_as);
}
/*
* Check whether we have to replace EGP route with IGP
* route (if exists).
* We'll do it if IGP metric is less than new EGP metric
* and greater than the old EGP metric
*/
if ((rt_igp != NULL) && (metric > rt_igp->rt_metric) && (rt_igp->rt_metric > egp_metric)) {
TRACE_INT("rt_NRupdate: Replacing EGP route with IGP route\n");
es_rtdel(&destination);
es_rtadd(&destination, rt_igp->rt_as);
}
flood = TRUE;
#endif NSS
change = TRUE;
rt->rt_timer = 0;
}
}
}
} /* end else existing route */
} /* end else update routing table */
} /* end for all nets */
} /* end for all distances */
} /* end for all gateways */
if (checkingNR) {
if (nrb > (u_char *)nrp + egplen) {
return(EBADDATA); /* erroneous counts */
} else {
checkingNR = FALSE;
}
goto repeat;
}
/*
* Generate default if not prohibited and the NR packet
* contains more than one route
*/
if (!(ngp->ng_flags & NG_NOGENDEFAULT) && (NR_nets > 1)) {
change += rt_default("ADD");
}
if (change) {
TRACE_RT("rt_NRupdate: above %d routes from %s updated %s\n",
NR_nets, inet_ntoa(ngp->ng_addr), strtime);
}
#ifdef NSS
if (flood) {
egp2esrec();
}
#endif NSS
return(NOERROR);
}