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