Home | History | Annotate | Line # | Download | only in routed
input.c revision 1.17
      1 /*	$NetBSD: input.c,v 1.17 1996/08/10 01:29:17 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #if !defined(lint) && !defined(sgi)
     37 #if 0
     38 static char sccsid[] = "@(#)input.c	8.1 (Berkeley) 6/5/93";
     39 #else
     40 static char rcsid[] = "$NetBSD: input.c,v 1.17 1996/08/10 01:29:17 thorpej Exp $";
     41 #endif
     42 #endif /* not lint */
     43 
     44 #include "defs.h"
     45 
     46 static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
     47 static void input_route(struct interface *, naddr,
     48 			naddr, naddr, naddr, struct netinfo *);
     49 
     50 
     51 /* process RIP input
     52  */
     53 void
     54 read_rip(int sock,
     55 	 struct interface *ifp)
     56 {
     57 	struct sockaddr_in from;
     58 	int fromlen, cc;
     59 	union pkt_buf inbuf;
     60 
     61 
     62 	for (;;) {
     63 		fromlen = sizeof(from);
     64 		cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
     65 			      (struct sockaddr*)&from, &fromlen);
     66 		if (cc <= 0) {
     67 			if (cc < 0 && errno != EWOULDBLOCK)
     68 				LOGERR("recvfrom(rip)");
     69 			break;
     70 		}
     71 		if (fromlen != sizeof(struct sockaddr_in))
     72 			logbad(1,"impossible recvfrom(rip) fromlen=%d",
     73 			       fromlen);
     74 
     75 		input(&from,
     76 		      (ifp != 0) ? ifp : iflookup(from.sin_addr.s_addr),
     77 		      &inbuf.rip, cc);
     78 	}
     79 }
     80 
     81 
     82 /* Process a RIP packet
     83  */
     84 static void
     85 input(struct sockaddr_in *from,		/* received from this IP address */
     86       struct interface *ifp,
     87       struct rip *rip,
     88       int size)
     89 {
     90 #	define FROM_NADDR from->sin_addr.s_addr
     91 	static naddr use_auth, bad_len, bad_mask;
     92 	static naddr unk_router, bad_router, bad_nhop;
     93 
     94 	struct rt_entry *rt;
     95 	struct netinfo *n, *lim;
     96 	struct interface *ifp1;
     97 	naddr gate, mask, v1_mask, dst, ddst_h;
     98 	int i;
     99 
    100 
    101 	if (ifp != 0)
    102 		ifp->int_state |= IS_ACTIVE;
    103 
    104 	trace_rip("Recv", "from", from, ifp, rip, size);
    105 
    106 	if (rip->rip_vers == 0) {
    107 		if (from->sin_addr.s_addr != bad_router)
    108 			msglog("RIP version 0, cmd %d, packet received"
    109 			       " from %s",
    110 			       rip->rip_cmd, naddr_ntoa(FROM_NADDR));
    111 		bad_router = from->sin_addr.s_addr;
    112 		return;
    113 	}
    114 	if (size > MAXPACKETSIZE) {
    115 		if (from->sin_addr.s_addr != bad_router)
    116 			msglog("packet at least %d bytes too long received"
    117 			       " from %s",
    118 			       size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
    119 		bad_router = from->sin_addr.s_addr;
    120 		return;
    121 	}
    122 
    123 	n = rip->rip_nets;
    124 	lim = (struct netinfo *)((char*)rip + size);
    125 
    126 	/* Notice authentication.
    127 	 * As required by section 4.2 in RFC 1723, discard authenticated
    128 	 * RIPv2 messages, but only if configured for that silliness.
    129 	 *
    130 	 * RIPv2 authentication is lame, since snooping on the wire makes
    131 	 * its simple passwords evident.  Also, why authenticate queries?
    132 	 * Why should a RIPv2 implementation with authentication disabled
    133 	 * not be able to listen to RIPv2 packets with authenication, while
    134 	 * RIPv1 systems will listen?  Crazy!
    135 	 */
    136 	if (!auth_ok
    137 	    && rip->rip_vers >= RIPv2
    138 	    && n < lim && n->n_family == RIP_AF_AUTH) {
    139 		if (from->sin_addr.s_addr != use_auth)
    140 			msglog("RIPv2 message with authentication"
    141 			       " from %s discarded",
    142 			       naddr_ntoa(FROM_NADDR));
    143 		use_auth = from->sin_addr.s_addr;
    144 		trace_pkt("discard authenticated RIPv2 message\n");
    145 		return;
    146 	}
    147 
    148 	switch (rip->rip_cmd) {
    149 	case RIPCMD_REQUEST:
    150 		/* did the request come from a router?
    151 		 */
    152 		if (from->sin_port == htons(RIP_PORT)) {
    153 			/* yes, ignore it if RIP is off so that it does not
    154 			 * depend on us.
    155 			 */
    156 			if (rip_sock < 0) {
    157 				trace_pkt("ignore request while RIP off\n");
    158 				return;
    159 			}
    160 
    161 			/* Ignore the request if we talking to ourself
    162 			 * (and not a remote gateway).
    163 			 */
    164 			if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
    165 				trace_pkt("discard our own RIP request\n");
    166 				return;
    167 			}
    168 		}
    169 
    170 		/* According to RFC 1723, we should ignore unathenticated
    171 		 * queries.  That is too silly to bother with.  Sheesh!
    172 		 * Are forwarding tables supposed to be secret?  When
    173 		 * a bad guy can infer them with test traffic?
    174 		 * Maybe on firewalls you'd care, but not enough to
    175 		 * give up the diagnostic facilities of remote probing.
    176 		 */
    177 
    178 		if (n >= lim
    179 		    || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
    180 			if (from->sin_addr.s_addr != bad_len)
    181 				msglog("request of bad length (%d) from %s",
    182 				       size, naddr_ntoa(FROM_NADDR));
    183 			bad_len = from->sin_addr.s_addr;
    184 		}
    185 		for (; n < lim; n++) {
    186 			n->n_metric = ntohl(n->n_metric);
    187 
    188 			/* A single entry with family RIP_AF_UNSPEC and
    189 			 * metric HOPCNT_INFINITY means "all routes".
    190 			 * We respond to routers only if we are acting
    191 			 * as a supplier, or to anyone other than a router
    192 			 * (i.e. a query).
    193 			 *
    194 			 * Answer a query from a stray program with all
    195 			 * we know. Filter the answer to a query from a
    196 			 * router in the about same way broadcasts are
    197 			 * filtered.
    198 			 *
    199 			 * Only answer a router if we are a supplier
    200 			 * to keep an unwary host that is just starting
    201 			 * from picking us an a router.
    202 			 */
    203 			if (n->n_family == RIP_AF_UNSPEC
    204 			    && n->n_metric == HOPCNT_INFINITY
    205 			    && n == rip->rip_nets
    206 			    && n+1 == lim) {
    207 				if (from->sin_port != htons(RIP_PORT)) {
    208 					/* query */
    209 					supply(from, ifp,
    210 					       OUT_QUERY, 0, rip->rip_vers);
    211 				} else if (supplier) {
    212 					supply(from, ifp,
    213 					       OUT_UNICAST, 0, rip->rip_vers);
    214 				}
    215 				return;
    216 			}
    217 
    218 			if (n->n_family != RIP_AF_INET) {
    219 				if (from->sin_addr.s_addr != bad_router)
    220 					msglog("request from %s"
    221 					       " for unsupported (af %d) %s",
    222 					       naddr_ntoa(FROM_NADDR),
    223 					       ntohs(n->n_family),
    224 					       naddr_ntoa(n->n_dst));
    225 				bad_router = from->sin_addr.s_addr;
    226 				return;
    227 			}
    228 
    229 			dst = n->n_dst;
    230 			if (!check_dst(dst)) {
    231 				if (from->sin_addr.s_addr != bad_router)
    232 					msglog("bad queried destination"
    233 					       " %s from %s",
    234 					       naddr_ntoa(dst),
    235 					       naddr_ntoa(FROM_NADDR));
    236 				bad_router = from->sin_addr.s_addr;
    237 				return;
    238 			}
    239 
    240 			if (rip->rip_vers == RIPv1
    241 			    || 0 == (mask = ntohl(n->n_mask))
    242 			    || 0 != (ntohl(dst) & ~mask))
    243 				mask = ripv1_mask_host(dst,ifp);
    244 
    245 			rt = rtget(dst, mask);
    246 			if (!rt && dst != RIP_DEFAULT)
    247 				rt = rtfind(n->n_dst);
    248 
    249 			n->n_tag = 0;
    250 			n->n_nhop = 0;
    251 			if (rip->rip_vers == RIPv1) {
    252 				n->n_mask = 0;
    253 			} else {
    254 				n->n_mask = mask;
    255 			}
    256 			if (rt == 0) {
    257 				n->n_metric = HOPCNT_INFINITY;
    258 			} else {
    259 				n->n_metric = rt->rt_metric+1;
    260 				n->n_metric += (ifp!=0) ? ifp->int_metric : 1;
    261 				if (n->n_metric > HOPCNT_INFINITY)
    262 					n->n_metric = HOPCNT_INFINITY;
    263 				if (rip->rip_vers != RIPv1) {
    264 					n->n_tag = rt->rt_tag;
    265 					if (ifp != 0
    266 					    && on_net(rt->rt_gate,
    267 						      ifp->int_net,
    268 						      ifp->int_mask)
    269 					    && rt->rt_gate != ifp->int_addr)
    270 						n->n_nhop = rt->rt_gate;
    271 				}
    272 			}
    273 			HTONL(n->n_metric);
    274 		}
    275 		/* Answer about specific routes.
    276 		 * Only answer a router if we are a supplier
    277 		 * to keep an unwary host that is just starting
    278 		 * from picking us an a router.
    279 		 */
    280 		rip->rip_cmd = RIPCMD_RESPONSE;
    281 		rip->rip_res1 = 0;
    282 		if (rip->rip_vers != RIPv1)
    283 			rip->rip_vers = RIPv2;
    284 		if (from->sin_port != htons(RIP_PORT)) {
    285 			/* query */
    286 			(void)output(OUT_QUERY, from, ifp, rip, size);
    287 		} else if (supplier) {
    288 			(void)output(OUT_UNICAST, from, ifp, rip, size);
    289 		}
    290 		return;
    291 
    292 	case RIPCMD_TRACEON:
    293 	case RIPCMD_TRACEOFF:
    294 		/* verify message came from a privileged port */
    295 		if (ntohs(from->sin_port) > IPPORT_RESERVED) {
    296 			msglog("trace command from untrusted port on %s",
    297 			       naddr_ntoa(FROM_NADDR));
    298 			return;
    299 		}
    300 		if (ifp == 0) {
    301 			msglog("trace command from unknown router %s",
    302 			       naddr_ntoa(FROM_NADDR));
    303 			return;
    304 		}
    305 		if (rip->rip_cmd == RIPCMD_TRACEON) {
    306 			rip->rip_tracefile[size-4] = '\0';
    307 			trace_on(rip->rip_tracefile, 0);
    308 		} else {
    309 			trace_off("tracing turned off by %s\n",
    310 				  naddr_ntoa(FROM_NADDR));
    311 		}
    312 		return;
    313 
    314 	case RIPCMD_RESPONSE:
    315 		if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
    316 			if (from->sin_addr.s_addr != bad_len)
    317 				msglog("response of bad length (%d) from %s",
    318 				       size, naddr_ntoa(FROM_NADDR));
    319 			bad_len = from->sin_addr.s_addr;
    320 		}
    321 
    322 		/* verify message came from a router */
    323 		if (from->sin_port != ntohs(RIP_PORT)) {
    324 			trace_pkt("discard RIP response from unknown port\n");
    325 			return;
    326 		}
    327 
    328 		if (rip_sock < 0) {
    329 			trace_pkt("discard response while RIP off\n");
    330 			return;
    331 		}
    332 
    333 		/* Are we talking to ourself or a remote gateway?
    334 		 */
    335 		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
    336 		if (ifp1) {
    337 			if (ifp1->int_state & IS_REMOTE) {
    338 				if (ifp1->int_state & IS_PASSIVE) {
    339 					msglog("bogus input from %s on"
    340 					       " supposedly passive %s",
    341 					       naddr_ntoa(FROM_NADDR),
    342 					       ifp1->int_name);
    343 				} else {
    344 					ifp1->int_act_time = now.tv_sec;
    345 					if (if_ok(ifp1, "remote "))
    346 						addrouteforif(ifp1);
    347 				}
    348 			} else {
    349 				trace_pkt("discard our own RIP response\n");
    350 			}
    351 			return;
    352 		}
    353 
    354 		/* Check the router from which message originated. We accept
    355 		 * routing packets from routers directly connected via
    356 		 * broadcast or point-to-point networks, and from
    357 		 * those listed in /etc/gateways.
    358 		 */
    359 		if (!ifp) {
    360 			if (from->sin_addr.s_addr != unk_router)
    361 				msglog("packet from unknown router %s"
    362 				       " or via unidentified interface",
    363 				       naddr_ntoa(FROM_NADDR));
    364 			unk_router = from->sin_addr.s_addr;
    365 			return;
    366 		}
    367 		if (ifp->int_state & IS_PASSIVE) {
    368 			trace_act("packet from %s via passive interface %s\n",
    369 				  naddr_ntoa(FROM_NADDR),
    370 				  ifp->int_name);
    371 			return;
    372 		}
    373 
    374 		/* Check required version
    375 		 */
    376 		if (((ifp->int_state & IS_NO_RIPV1_IN)
    377 		     && rip->rip_vers == RIPv1)
    378 		    || ((ifp->int_state & IS_NO_RIPV2_IN)
    379 			&& rip->rip_vers != RIPv1)) {
    380 			trace_pkt("discard RIPv%d response\n",
    381 				  rip->rip_vers);
    382 			return;
    383 		}
    384 
    385 		/* Ignore routes via dead interface.
    386 		 */
    387 		if (ifp->int_state & IS_BROKE) {
    388 			trace_pkt("discard response via broken interface %s\n",
    389 				  ifp->int_name);
    390 			return;
    391 		}
    392 
    393 		/* Authenticate the packet.
    394 		 */
    395 		if (ifp->int_passwd[0] != '\0') {
    396 			if ((n < lim) &&
    397 			    (((struct netauth*)n)->a_type == RIP_AUTH_PW) &&
    398 			    (bcmp(((struct netauth*)n)->au.au_pw,
    399 			    ifp->int_passwd, sizeof(ifp->int_passwd)) == 0))
    400 				goto auth_ok;
    401 
    402 			/*
    403 			 * Authentication failed.
    404 			 */
    405 			if (from->sin_addr.s_addr != use_auth)
    406 				msglog("missing authentication from %s",
    407 				    naddr_ntoa(FROM_NADDR));
    408 			use_auth = from->sin_addr.s_addr;
    409 			return;
    410 		}
    411 
    412  auth_ok:
    413 
    414 		for (; n < lim; n++) {
    415 			if (n->n_family == RIP_AF_AUTH)
    416 				continue;
    417 
    418 			NTOHL(n->n_metric);
    419 			dst = n->n_dst;
    420 			if (n->n_family != RIP_AF_INET
    421 			    && (n->n_family != RIP_AF_UNSPEC
    422 				|| dst != RIP_DEFAULT)) {
    423 				if (from->sin_addr.s_addr != bad_router)
    424 					msglog("route from %s to unsupported"
    425 					       " address family %d,"
    426 					       " destination %s",
    427 					       naddr_ntoa(FROM_NADDR),
    428 					       n->n_family,
    429 					       naddr_ntoa(dst));
    430 				bad_router = from->sin_addr.s_addr;
    431 				continue;
    432 			}
    433 			if (!check_dst(dst)) {
    434 				if (from->sin_addr.s_addr != bad_router)
    435 					msglog("bad destination %s from %s",
    436 					       naddr_ntoa(dst),
    437 					       naddr_ntoa(FROM_NADDR));
    438 				bad_router = from->sin_addr.s_addr;
    439 				return;
    440 			}
    441 			if (n->n_metric == 0
    442 			    || n->n_metric > HOPCNT_INFINITY) {
    443 				if (from->sin_addr.s_addr != bad_router)
    444 					msglog("bad metric %d from %s"
    445 					       " for destination %s",
    446 					       n->n_metric,
    447 					       naddr_ntoa(FROM_NADDR),
    448 					       naddr_ntoa(dst));
    449 				bad_router = from->sin_addr.s_addr;
    450 				return;
    451 			}
    452 
    453 			/* Notice the next-hop.
    454 			 */
    455 			gate = from->sin_addr.s_addr;
    456 			if (n->n_nhop != 0
    457 			    && rip->rip_vers == RIPv2) {
    458 				/* Ignore the route if it points to us */
    459 				if (0 != ifwithaddr(n->n_nhop, 1, 0))
    460 					continue;
    461 
    462 				/* Use it only if it is valid. */
    463 				if (on_net(n->n_nhop,
    464 					   ifp->int_net, ifp->int_mask)
    465 				    && check_dst(n->n_nhop)) {
    466 					gate = n->n_nhop;
    467 				} else {
    468 					if (bad_nhop != from->sin_addr.s_addr)
    469 					    msglog("router %s to %s has"
    470 						   " bad next hop %s",
    471 						   naddr_ntoa(FROM_NADDR),
    472 						   naddr_ntoa(dst),
    473 						   naddr_ntoa(n->n_nhop));
    474 					bad_nhop = from->sin_addr.s_addr;
    475 				}
    476 			}
    477 
    478 			if (rip->rip_vers == RIPv1
    479 			    || 0 == (mask = ntohl(n->n_mask))) {
    480 				mask = ripv1_mask_host(dst,ifp);
    481 			} else if ((ntohl(dst) & ~mask) != 0) {
    482 				if (bad_mask != from->sin_addr.s_addr) {
    483 					msglog("router %s sent bad netmask"
    484 					       " %#x with %s",
    485 					       naddr_ntoa(FROM_NADDR),
    486 					       mask,
    487 					       naddr_ntoa(dst));
    488 					bad_mask = from->sin_addr.s_addr;
    489 				}
    490 				continue;
    491 			}
    492 			if (rip->rip_vers == RIPv1)
    493 				n->n_tag = 0;
    494 
    495 			/* Adjust metric according to incoming interface..
    496 			 */
    497 			n->n_metric += ifp->int_metric;
    498 			if (n->n_metric > HOPCNT_INFINITY)
    499 				n->n_metric = HOPCNT_INFINITY;
    500 
    501 			/* Recognize and ignore a default route we faked
    502 			 * which is being sent back to us by a machine with
    503 			 * broken split-horizon.
    504 			 * Be a little more paranoid than that, and reject
    505 			 * default routes with the same metric we advertised.
    506 			 */
    507 			if (ifp->int_d_metric != 0
    508 			    && dst == RIP_DEFAULT
    509 			    && n->n_metric >= ifp->int_d_metric)
    510 				continue;
    511 
    512 			/* We can receive aggregated RIPv2 routes that must
    513 			 * be broken down before they are transmitted by
    514 			 * RIPv1 via an interface on a subnet.
    515 			 * We might also receive the same routes aggregated
    516 			 * via other RIPv2 interfaces.
    517 			 * This could cause duplicate routes to be sent on
    518 			 * the RIPv1 interfaces.  "Longest matching variable
    519 			 * length netmasks" lets RIPv2 listeners understand,
    520 			 * but breaking down the aggregated routes for RIPv1
    521 			 * listeners can produce duplicate routes.
    522 			 *
    523 			 * Breaking down aggregated routes here bloats
    524 			 * the daemon table, but does not hurt the kernel
    525 			 * table, since routes are always aggregated for
    526 			 * the kernel.
    527 			 *
    528 			 * Notice that this does not break down network
    529 			 * routes corresponding to subnets.  This is part
    530 			 * of the defense against RS_NET_SYN.
    531 			 */
    532 			if (have_ripv1_out
    533 			    && (v1_mask = ripv1_mask_net(dst,0)) > mask
    534 			    && (((rt = rtget(dst,mask)) == 0
    535 				 || !(rt->rt_state & RS_NET_SYN)))) {
    536 				ddst_h = v1_mask & -v1_mask;
    537 				i = (v1_mask & ~mask)/ddst_h;
    538 				if (i >= 1024) {
    539 					/* Punt if we would have to generate
    540 					 * an unreasonable number of routes.
    541 					 */
    542 #ifdef DEBUG
    543 					msglog("accept %s from %s as-is"
    544 					       " instead of as %d routes",
    545 					       addrname(dst,mask,0),
    546 					       naddr_ntoa(FROM_NADDR), i);
    547 #endif
    548 					i = 0;
    549 				} else {
    550 					mask = v1_mask;
    551 				}
    552 			} else {
    553 				i = 0;
    554 			}
    555 
    556 			for (;;) {
    557 				input_route(ifp, FROM_NADDR,
    558 					    dst, mask, gate, n);
    559 				if (i-- == 0)
    560 					break;
    561 				dst = htonl(ntohl(dst) + ddst_h);
    562 			}
    563 		}
    564 		break;
    565 	}
    566 }
    567 
    568 
    569 /* Process a single input route.
    570  */
    571 static void
    572 input_route(struct interface *ifp,
    573 	    naddr from,
    574 	    naddr dst,
    575 	    naddr mask,
    576 	    naddr gate,
    577 	    struct netinfo *n)
    578 {
    579 	int i;
    580 	struct rt_entry *rt;
    581 	struct rt_spare *rts, *rts0;
    582 	struct interface *ifp1;
    583 	time_t new_time;
    584 
    585 
    586 	/* See if the other guy is telling us to send our packets to him.
    587 	 * Sometimes network routes arrive over a point-to-point link for
    588 	 * the network containing the address(es) of the link.
    589 	 *
    590 	 * If our interface is broken, switch to using the other guy.
    591 	 */
    592 	ifp1 = ifwithaddr(dst, 1, 1);
    593 	if (ifp1 != 0
    594 	    && !(ifp1->int_state & IS_BROKE))
    595 		return;
    596 
    597 	/* Look for the route in our table.
    598 	 */
    599 	rt = rtget(dst, mask);
    600 
    601 	/* Consider adding the route if we do not already have it.
    602 	 */
    603 	if (rt == 0) {
    604 		/* Ignore unknown routes being poisoned.
    605 		 */
    606 		if (n->n_metric == HOPCNT_INFINITY)
    607 			return;
    608 
    609 		rtadd(dst, mask, gate, from, n->n_metric, n->n_tag, 0, ifp);
    610 		return;
    611 	}
    612 
    613 	/* We already know about the route.  Consider this update.
    614 	 *
    615 	 * If (rt->rt_state & RS_NET_SYN), then this route
    616 	 * is the same as a network route we have inferred
    617 	 * for subnets we know, in order to tell RIPv1 routers
    618 	 * about the subnets.
    619 	 *
    620 	 * It is impossible to tell if the route is coming
    621 	 * from a distant RIPv2 router with the standard
    622 	 * netmask because that router knows about the entire
    623 	 * network, or if it is a round-about echo of a
    624 	 * synthetic, RIPv1 network route of our own.
    625 	 * The worst is that both kinds of routes might be
    626 	 * received, and the bad one might have the smaller
    627 	 * metric.  Partly solve this problem by faking the
    628 	 * RIPv1 route with a metric that reflects the most
    629 	 * distant part of the subnet.  Also never
    630 	 * aggregate into such a route.  Also keep it
    631 	 * around as long as the interface exists.
    632 	 */
    633 
    634 	rts0 = rt->rt_spares;
    635 	for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
    636 		if (rts->rts_router == from)
    637 			break;
    638 		/* Note the worst slot to reuse,
    639 		 * other than the current slot.
    640 		 */
    641 		if (rts0 == rt->rt_spares
    642 		    || BETTER_LINK(rt, rts0, rts))
    643 			rts0 = rts;
    644 	}
    645 	if (i != 0) {
    646 		/* Found the router
    647 		 */
    648 		int old_metric = rts->rts_metric;
    649 
    650 		/* Keep poisoned routes around only long
    651 		 * enough to pass the poison on.
    652 		 */
    653 		if (old_metric < HOPCNT_INFINITY)
    654 			new_time = now.tv_sec;
    655 
    656 		/* If this is an update for the router we currently prefer,
    657 		 * then note it.
    658 		 */
    659 		if (i == NUM_SPARES) {
    660 			rtchange(rt,rt->rt_state, gate,rt->rt_router,
    661 				 n->n_metric, n->n_tag, ifp, new_time, 0);
    662 			/* If the route got worse, check for something better.
    663 			 */
    664 			if (n->n_metric > old_metric)
    665 				rtswitch(rt, 0);
    666 			return;
    667 		}
    668 
    669 		/* This is an update for a spare route.
    670 		 * Finished if the route is unchanged.
    671 		 */
    672 		if (rts->rts_gate == gate
    673 		    && old_metric == n->n_metric
    674 		    && rts->rts_tag == n->n_tag) {
    675 			rts->rts_time = new_time;
    676 			return;
    677 		}
    678 
    679 	} else {
    680 		/* The update is for a route we know about,
    681 		 * but not from a familiar router.
    682 		 */
    683 		rts = rts0;
    684 
    685 		/* Save the route as a spare only if it has
    686 		 * a better metric than our worst spare.
    687 		 * This also ignores poisoned routes (those
    688 		 * received with metric HOPCNT_INFINITY).
    689 		 */
    690 		if (n->n_metric >= rts->rts_metric)
    691 			return;
    692 
    693 		new_time = now.tv_sec;
    694 	}
    695 
    696 	trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
    697 
    698 	rts->rts_gate = gate;
    699 	rts->rts_router = from;
    700 	rts->rts_metric = n->n_metric;
    701 	rts->rts_tag = n->n_tag;
    702 	rts->rts_time = new_time;
    703 	rts->rts_ifp = ifp;
    704 
    705 	/* try to switch to a better route */
    706 	rtswitch(rt, rts);
    707 }
    708