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