input.c revision 1.1.1.4 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__)
35 static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
36 #elif defined(__NetBSD__)
37 static char rcsid[] = "$NetBSD: input.c,v 1.1.1.4 1996/09/24 15:11:36 christos Exp $";
38 #endif
39 #ident "$Revision: 1.1.1.4 $"
40
41 #include "defs.h"
42
43 static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
44 static void input_route(struct interface *, naddr,
45 naddr, naddr, naddr, struct netinfo *);
46
47
48 /* process RIP input
49 */
50 void
51 read_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 */
79 static void
80 input(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 */
590 static void
591 input_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