add interval for checking "down" interfaces
[unix-history] / usr / src / sbin / routed / routed.c
CommitLineData
7c0bf99b 1#ifndef lint
c5f8709e 2static char sccsid[] = "@(#)routed.c 4.2 %G%";
7c0bf99b
SL
3#endif
4
5#include <sys/param.h>
6#include <sys/protosw.h>
7#include <sys/ioctl.h>
8#include <sys/socket.h>
9#include <net/in.h>
10#define KERNEL
11#include <net/route.h>
12#include <net/if.h>
13#include <errno.h>
14#include <stdio.h>
15#include <nlist.h>
16#include <signal.h>
17#include "rip.h"
18#include "router.h"
19
20#define LOOPBACKNET 0177
21/* casts to keep lint happy */
22#define insque(q,p) _insque((caddr_t)q,(caddr_t)p)
23#define remque(q) _remque((caddr_t)q)
24#define equal(a1, a2) \
25 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
26
27struct nlist nl[] = {
28#define N_IFNET 0
29 { "_ifnet" },
30 0,
31};
32
33struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER };
34
35int s;
36int kmem;
37int supplier; /* process should supply updates */
38int initializing; /* stem off broadcast() calls */
39int install = 0; /* if 1 call kernel */
40int timeval;
41int timer();
42int cleanup();
43int trace = 0;
44
45char packet[MAXPACKETSIZE];
46
47extern char *malloc();
c5f8709e 48extern int errno, exit();
7c0bf99b
SL
49
50main(argc, argv)
51 int argc;
52 char *argv[];
53{
54 int cc;
55 struct sockaddr from;
56
57 { int t = open("/dev/tty", 2);
58 if (t >= 0) {
59 ioctl(t, TIOCNOTTY, 0);
60 close(t);
61 }
62 }
63 if (trace) {
64 (void) fclose(stdout);
65 (void) fclose(stderr);
66 (void) fopen("trace", "a");
67 (void) dup(fileno(stdout));
68 setbuf(stdout, NULL);
69
70 }
71#ifdef vax
72 myaddr.sin_port = htons(myaddr.sin_port);
73#endif
74again:
75 s = socket(SOCK_DGRAM, 0, &myaddr, 0);
76 if (s < 0) {
77 perror("socket");
78 sleep(30);
79 goto again;
80 }
81 rtinit();
82 getothers();
83 getinterfaces();
84 request();
85
86 argv++, argc--;
87 while (argc > 0) {
88 if (strcmp(*argv, "-s") == 0)
89 supplier++;
90 else if (strcmp(*argv, "-q") == 0)
91 supplier = 0;
92 argv++, argc--;
93 }
c5f8709e 94 sigset(SIGTERM, exit);
7c0bf99b
SL
95 sigset(SIGALRM, timer);
96 alarm(TIMER_RATE);
97
98 /*
99 * Listen for routing packets
100 */
101 for (;;) {
102 cc = receive(s, &from, packet, sizeof (packet));
103 if (cc <= 0) {
104 if (cc < 0 && errno != EINTR)
105 perror("receive");
106 continue;
107 }
108 sighold(SIGALRM);
109 rip_input(&from, cc);
110 sigrelse(SIGALRM);
111 }
112}
113
114/*
115 * Look in a file for any gateways we should configure
116 * outside the directly connected ones. This is a kludge,
117 * but until we can find out about gateways on the "other side"
118 * of the ARPANET using GGP, it's a must.
119 *
120 * We don't really know the distance to the gateway, so we
121 * assume it's a neighbor.
122 */
123getothers()
124{
125 struct sockaddr_in dst, gate;
126 FILE *fp = fopen("/etc/gateways", "r");
127 struct rt_entry *rt;
128
129 if (fp == NULL)
130 return;
131 bzero((char *)&dst, sizeof (dst));
132 bzero((char *)&gate, sizeof (gate));
133 dst.sin_family = AF_INET;
134 gate.sin_family = AF_INET;
135 while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr,
136 &gate.sin_addr.s_addr) != EOF) {
137 rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1);
138 rt = rtlookup((struct sockaddr *)&dst);
139 if (rt)
140 rt->rt_flags |= RTF_SILENT;
141 }
142 fclose(fp);
143}
144
145struct ifnet *
146if_ifwithaddr(addr)
147 struct sockaddr *addr;
148{
149 register struct ifnet *ifp;
150
151#define same(a1, a2) \
152 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
153 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
154 if (ifp->if_addr.sa_family != addr->sa_family)
155 continue;
156 if (same(&ifp->if_addr, addr))
157 break;
158 if ((ifp->if_flags & IFF_BROADCAST) &&
159 same(&ifp->if_broadaddr, addr))
160 break;
161 }
162 return (ifp);
163#undef same
164}
165
166struct ifnet *
167if_ifwithnet(addr)
168 register struct sockaddr *addr;
169{
170 register struct ifnet *ifp;
171 register int af = addr->sa_family;
172 register int (*netmatch)();
173
174 if (af >= AF_MAX)
175 return (0);
176 netmatch = afswitch[af].af_netmatch;
177 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
178 if (af != ifp->if_addr.sa_family)
179 continue;
180 if ((*netmatch)(addr, &ifp->if_addr))
181 break;
182 }
183 return (ifp);
184}
185
186struct in_addr
187if_makeaddr(net, host)
188 int net, host;
189{
190 u_long addr;
191
192 if (net < 128)
193 addr = (net << 24) | host;
194 else if (net < 65536)
195 addr = (net << 16) | host;
196 else
197 addr = (net << 8) | host;
198#ifdef vax
199 addr = htonl(addr);
200#endif
201 return (*(struct in_addr *)&addr);
202}
203
204/*
205 * Find the network interfaces attached to this machine.
206 * The info is used to::
207 *
208 * (1) initialize the routing tables, as done by the kernel.
209 * (2) ignore incoming packets we send.
210 * (3) figure out broadcast capability and addresses.
211 * (4) figure out if we're an internetwork gateway.
212 *
213 * We don't handle anything but Internet addresses.
214 */
215getinterfaces()
216{
217 register struct ifnet **pifp, *ifp;
218 struct sockaddr_in net;
219 struct in_addr logicaladdr;
220 int nets;
221
222 nlist("/vmunix", nl);
223 if (nl[N_IFNET].n_value == 0) {
224 printf("ifnet: symbol not in namelist\n");
225 exit(1);
226 }
227 kmem = open("/dev/kmem", 0);
228 if (kmem < 0) {
229 perror("/dev/kmem");
230 exit(1);
231 }
232 (void) lseek(kmem, (long)nl[N_IFNET].n_value, 0);
233 (void) read(kmem, (char *)&ifnet, sizeof (ifnet));
234 bzero((char *)&net, sizeof (net));
235 net.sin_family = AF_INET;
236 logicaladdr.s_addr = 0;
237 nets = 0;
238 pifp = &ifnet;
239 initializing = 1;
240 while (*pifp) {
241 struct sockaddr_in *sin;
242
243 (void) lseek(kmem, (long)*pifp, 0);
244 ifp = *pifp = (struct ifnet *)malloc(sizeof (struct ifnet));
245 if (ifp == 0) {
246 printf("routed: out of memory\n");
247 break;
248 }
249 if (read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) {
250 perror("read");
251 break;
252 }
253 if (ifp->if_net == LOOPBACKNET)
254 goto skip;
255 nets++;
256 if ((ifp->if_flags & IFF_UP) == 0)
257 goto skip;
258
259 /*
260 * Kludge: don't treat logical host pseudo-interface
261 * as a net route, instead fabricate route
262 * to get packets back from the gateway.
263 */
264 sin = (struct sockaddr_in *)&ifp->if_addr;
265 if (sin->sin_family == AF_INET && ifp->if_net == 10 &&
266 sin->sin_addr.s_lh) {
267 logicaladdr = sin->sin_addr;
268 goto skip;
269 }
270
271 /*
272 * Before we can handle point-point links, the interface
273 * structure will have to include an indicator to allow
274 * us to distinguish entries from "network" entries.
275 */
276 net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
277 rtadd((struct sockaddr *)&net, (struct sockaddr *)sin, 0);
278 skip:
279 pifp = &ifp->if_next;
280 }
281 if (logicaladdr.s_addr) {
282 struct rt_entry *rt;
283
284 net.sin_addr = logicaladdr;
285 if (ifnet)
286 rtadd((struct sockaddr *)&net, &ifnet->if_addr, 0);
287 /* yech...yet another logical host kludge */
288 rt = rtlookup((struct sockaddr *)&net);
289 if (rt)
290 rt->rt_flags |= RTF_SILENT;
291 }
292 (void) close(kmem);
293 initializing = 0;
294 supplier = nets > 1;
295}
296
297/*
298 * Send a request message to all directly
299 * connected hosts and networks.
300 */
301request()
302{
303 register struct rt_entry *rt;
304 register struct rt_hash *rh;
305 struct rt_hash *base = hosthash;
306 int doinghost = 1;
307
308again:
309 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
310 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
311 if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
312 continue;
313 getall(rt);
314 }
315 if (doinghost) {
316 base = nethash;
317 doinghost = 0;
318 goto again;
319 }
320}
321
322/*
323 * Broadcast a new, or modified, routing table entry
324 * to all directly connected hosts and networks.
325 */
326broadcast(entry)
327 struct rt_entry *entry;
328{
329 register struct rt_hash *rh;
330 register struct rt_entry *rt;
331 register struct sockaddr *dst;
332 struct rt_hash *base = hosthash;
333 int doinghost = 1;
334 struct rip *msg = (struct rip *)packet;
335
336 if (trace)
337 log("broadcast", entry);
338 msg->rip_cmd = RIPCMD_RESPONSE;
339 msg->rip_nets[0].rip_dst = entry->rt_dst;
340 msg->rip_nets[0].rip_metric = entry->rt_metric + 1;
341
342again:
343 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
344 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
345 if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
346 continue;
347 if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
348 dst = &rt->rt_ifp->if_broadaddr;
349 else
350 dst = &rt->rt_gateway;
351 (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip));
352 }
353 if (doinghost) {
354 doinghost = 0;
355 base = nethash;
356 goto again;
357 }
358}
359
360/*
361 * Supply all directly connected neighbors with the
362 * current state of the routing tables.
363 */
364supplyall()
365{
366 register struct rt_entry *rt;
367 register struct rt_hash *rh;
368 register struct sockaddr *dst;
369 struct rt_hash *base = hosthash;
370 int doinghost = 1;
371
372again:
373 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
374 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
375 if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
376 continue;
377 if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
378 dst = &rt->rt_ifp->if_broadaddr;
379 else
380 dst = &rt->rt_gateway;
381 if (trace)
382 log("supply", rt);
383 supply(dst);
384 }
385 if (doinghost) {
386 base = nethash;
387 doinghost = 0;
388 goto again;
389 }
390}
391
392/*
393 * Supply routing information to target "sa".
394 */
395supply(sa)
396 struct sockaddr *sa;
397{
398 struct rip *msg = (struct rip *)packet;
399 struct netinfo *n = msg->rip_nets;
400 register struct rt_hash *rh;
401 register struct rt_entry *rt;
402 struct rt_hash *base = hosthash;
403 int space = MAXPACKETSIZE - sizeof (int), doinghost = 1;
404 int (*output)() = afswitch[sa->sa_family].af_output;
405
406 msg->rip_cmd = RIPCMD_RESPONSE;
407again:
408 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
409 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
410
411 /*
412 * Flush packet out if not enough room for
413 * another routing table entry.
414 */
415 if (space < sizeof (struct netinfo)) {
416 (*output)(sa, MAXPACKETSIZE - space);
417 space = MAXPACKETSIZE - sizeof (int);
418 n = msg->rip_nets;
419 }
420 n->rip_dst = rt->rt_dst;
421 n->rip_metric = rt->rt_metric + 1;
422 n++, space -= sizeof (struct netinfo);
423 }
424 if (doinghost) {
425 doinghost = 0;
426 base = nethash;
427 goto again;
428 }
429
430 if (space < MAXPACKETSIZE - sizeof (int))
431 (*output)(sa, MAXPACKETSIZE - space);
432}
433
434getall(rt)
435 struct rt_entry *rt;
436{
437 register struct rip *msg = (struct rip *)packet;
438 struct sockaddr *dst;
439
440 msg->rip_cmd = RIPCMD_REQUEST;
441 msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
442 msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
443 if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
444 dst = &rt->rt_ifp->if_broadaddr;
445 else
446 dst = &rt->rt_gateway;
447 (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip));
448}
449
450/*
451 * Respond to a routing info request.
452 */
453rip_respond(from, size)
454 struct sockaddr *from;
455 int size;
456{
457 register struct rip *msg = (struct rip *)packet;
458 struct netinfo *np = msg->rip_nets;
459 struct rt_entry *rt;
460 int newsize = 0;
461
462 size -= sizeof (int);
463 while (size > 0) {
464 if (size < sizeof (struct netinfo))
465 break;
466 size -= sizeof (struct netinfo);
467 if (np->rip_dst.sa_family == AF_UNSPEC &&
468 np->rip_metric == HOPCNT_INFINITY && size == 0) {
469 supply(from);
470 return;
471 }
472 rt = rtlookup(&np->rip_dst);
473 np->rip_metric = rt == 0 ? HOPCNT_INFINITY : rt->rt_metric + 1;
474 np++, newsize += sizeof (struct netinfo);
475 }
476 if (newsize > 0) {
477 msg->rip_cmd = RIPCMD_RESPONSE;
478 newsize += sizeof (int);
479 (*afswitch[from->sa_family].af_output)(from, newsize);
480 }
481}
482
483/*
484 * Handle an incoming routing packet.
485 */
486rip_input(from, size)
487 struct sockaddr *from;
488 int size;
489{
490 register struct rip *msg = (struct rip *)packet;
491 struct rt_entry *rt;
492 struct netinfo *n;
493
494 if (msg->rip_cmd != RIPCMD_RESPONSE &&
495 msg->rip_cmd != RIPCMD_REQUEST)
496 return;
497
498 /*
499 * The router port is in the lower 1K of the UDP port space,
500 * and so is priviledged. Hence we can "authenticate" incoming
501 * updates simply by checking the source port.
502 */
503 if (msg->rip_cmd == RIPCMD_RESPONSE &&
504 (*afswitch[from->sa_family].af_portmatch)(from) == 0)
505 return;
506 if (msg->rip_cmd == RIPCMD_REQUEST) {
507 rip_respond(from, size);
508 return;
509 }
510
511 /*
512 * Process updates.
513 * Extraneous information like Internet ports
514 * must first be purged from the sender's address for
515 * pattern matching below.
516 */
517 (*afswitch[from->sa_family].af_canon)(from);
518 if (trace)
519 printf("input from %x\n", from->sin_addr);
520 /*
521 * If response packet is from ourselves, use it only
522 * to reset timer on entry. Otherwise, we'd believe
523 * it as gospel (since it comes from the router) and
524 * unknowingly update the metric to show the outgoing
525 * cost (higher than our real cost). I guess the protocol
526 * spec doesn't address this because Xerox Ethernets
527 * don't hear their own broadcasts?
528 */
529 if (if_ifwithaddr(from)) {
530 rt = rtlookup(from);
531 if (rt)
532 rt->rt_timer = 0;
533 return;
534 }
535 size -= sizeof (int);
536 n = msg->rip_nets;
537 for (; size > 0; size -= sizeof (struct netinfo), n++) {
538 if (size < sizeof (struct netinfo))
539 break;
540 if (trace)
541 printf("dst %x hc %d...", n->rip_dst.sin_addr,
542 n->rip_metric);
543 rt = rtlookup(&n->rip_dst);
544
545 /*
546 * Unknown entry, add it to the tables only if
547 * its interesting.
548 */
549 if (rt == 0) {
550 if (n->rip_metric < HOPCNT_INFINITY)
551 rtadd(&n->rip_dst, from, n->rip_metric);
552 if (trace)
553 printf("new\n");
554 continue;
555 }
556
557 if (trace)
558 printf("ours: gate %x hc %d timer %d\n",
559 rt->rt_gateway.sin_addr,
560 rt->rt_metric, rt->rt_timer);
561 /*
562 * Update the entry if one of the following is true:
563 *
564 * (1) The update came directly from the gateway.
565 * (2) A shorter path is provided.
566 * (3) The entry hasn't been updated in a while
567 * and a path of equivalent cost is offered.
568 */
569 if (equal(from, &rt->rt_gateway) ||
570 rt->rt_metric > n->rip_metric ||
571 (rt->rt_timer > (EXPIRE_TIME/2) &&
572 rt->rt_metric == n->rip_metric)) {
573 rtchange(rt, from, n->rip_metric);
574 rt->rt_timer = 0;
575 }
576 }
577}
578
579/*
580 * Lookup an entry to the appropriate dstination.
581 */
582struct rt_entry *
583rtlookup(dst)
584 struct sockaddr *dst;
585{
586 register struct rt_entry *rt;
587 register struct rt_hash *rh;
588 register int hash, (*match)();
589 struct afhash h;
590 int af = dst->sa_family, doinghost = 1;
591
592 if (af >= AF_MAX)
593 return (0);
594 (*afswitch[af].af_hash)(dst, &h);
595 hash = h.afh_hosthash;
596 rh = &hosthash[hash % ROUTEHASHSIZ];
597
598again:
599 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
600 if (rt->rt_hash != hash)
601 continue;
602 if (doinghost) {
603 if (equal(&rt->rt_dst, dst))
604 return (rt);
605 } else {
606 if (rt->rt_dst.sa_family == af &&
607 (*match)(&rt->rt_dst, dst))
608 return (rt);
609 }
610 }
611 if (doinghost) {
612 doinghost = 0;
613 hash = h.afh_nethash;
614 match = afswitch[af].af_netmatch;
615 rh = &nethash[hash % ROUTEHASHSIZ];
616 goto again;
617 }
618 return (0);
619}
620
621rtinit()
622{
623 register struct rt_hash *rh;
624
625 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
626 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
627 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
628 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
629}
630
631/*
632 * Add a new entry.
633 */
634rtadd(dst, gate, metric)
635 struct sockaddr *dst, *gate;
636 short metric;
637{
638 struct afhash h;
639 register struct rt_entry *rt;
640 struct rt_hash *rh;
641 int af = dst->sa_family, flags, hash;
642
643 if (af >= AF_MAX)
644 return;
645 (*afswitch[af].af_hash)(dst, &h);
646 flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
647 if (flags & RTF_HOST) {
648 hash = h.afh_hosthash;
649 rh = &hosthash[hash % ROUTEHASHSIZ];
650 } else {
651 hash = h.afh_nethash;
652 rh = &nethash[hash % ROUTEHASHSIZ];
653 }
654 rt = (struct rt_entry *)malloc(sizeof (*rt));
655 if (rt == 0)
656 return;
657 rt->rt_hash = hash;
658 rt->rt_dst = *dst;
659 rt->rt_gateway = *gate;
660 rt->rt_metric = metric;
661 rt->rt_timer = 0;
662 rt->rt_flags = RTF_UP | flags;
663 rt->rt_ifp = if_ifwithnet(&rt->rt_gateway);
664 if (metric == 0)
665 rt->rt_flags |= RTF_DIRECT;
666 insque(rt, rh);
667 if (trace)
668 log("add", rt);
669 if (initializing)
670 return;
671 if (supplier)
672 broadcast(rt);
673 if (install) {
674 rt->rt_flags |= RTF_ADDRT;
675 rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
676 }
677}
678
679/*
680 * Look to see if a change to an existing entry
681 * is warranted; if so, make it.
682 */
683rtchange(rt, gate, metric)
684 struct rt_entry *rt;
685 struct sockaddr *gate;
686 short metric;
687{
688 int change = 0;
689
690 if (!equal(&rt->rt_gateway, gate)) {
691 rt->rt_gateway = *gate;
692 change++;
693 }
694
695 /*
696 * If the hop count has changed, adjust
697 * the flags in the routing table entry accordingly.
698 */
699 if (metric != rt->rt_metric) {
700 if (rt->rt_metric == 0)
701 rt->rt_flags &= ~RTF_DIRECT;
702 rt->rt_metric = metric;
703 if (metric >= HOPCNT_INFINITY)
704 rt->rt_flags &= ~RTF_UP;
705 else
706 rt->rt_flags |= RTF_UP;
707 change++;
708 }
709
710 if (!change)
711 return;
712 if (supplier)
713 broadcast(rt);
714 if (trace)
715 log("change", rt);
716 if (install) {
717 rt->rt_flags |= RTF_CHGRT;
718 rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
719 }
720}
721
722/*
723 * Delete a routing table entry.
724 */
725rtdelete(rt)
726 struct rt_entry *rt;
727{
728 if (trace)
729 log("delete", rt);
730 if (install)
731 if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) &&
732 errno == EBUSY)
733 rt->rt_flags |= RTF_DELRT;
734 remque(rt);
735 free((char *)rt);
736}
737
738/*
739 * Timer routine:
740 *
741 * o handle timers on table entries,
742 * o invalidate entries which haven't been updated in a while,
743 * o delete entries which are too old,
744 * o retry ioctl's which weren't successful the first
745 * time due to the kernel entry being busy
746 * o if we're an internetwork router, supply routing updates
747 * periodically
748 */
749timer()
750{
751 register struct rt_hash *rh;
752 register struct rt_entry *rt;
753 struct rt_hash *base = hosthash;
754 int doinghost = 1;
755
756 if (trace)
757 printf(">>> time %d >>>\n", timeval);
758again:
759 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
760 rt = rh->rt_forw;
761 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
762
763 /*
764 * If the host is indicated to be
765 * "silent" (i.e. it's a logical host,
766 * or one we got from the initialization
767 * file), don't time out it's entry.
768 */
769 if (rt->rt_flags & RTF_SILENT)
770 continue;
771 if (trace)
772 log("", rt);
773 rt->rt_timer += TIMER_RATE;
774 if (rt->rt_timer >= GARBAGE_TIME ||
775 (rt->rt_flags & RTF_DELRT)) {
776 rt = rt->rt_forw;
777 rtdelete(rt->rt_back);
778 rt = rt->rt_back;
779 continue;
780 }
781 if (rt->rt_timer >= EXPIRE_TIME)
782 rt->rt_metric = HOPCNT_INFINITY;
783 if (rt->rt_flags & RTF_CHGRT)
784 if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) ||
785 --rt->rt_retry == 0)
786 rt->rt_flags &= ~RTF_CHGRT;
787 if (rt->rt_flags & RTF_ADDRT)
788 if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash) ||
789 --rt->rt_retry == 0)
790 rt->rt_flags &= ~RTF_ADDRT;
791 }
792 }
793 if (doinghost) {
794 doinghost = 0;
795 base = nethash;
796 goto again;
797 }
798 timeval += TIMER_RATE;
799 if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
800 supplyall();
801 if (trace)
802 printf("<<< time %d <<<\n", timeval);
803 alarm(TIMER_RATE);
804}
805
806log(operation, rt)
807 char *operation;
808 struct rt_entry *rt;
809{
810 time_t t = time(0);
811 struct sockaddr_in *dst, *gate;
812 static struct flagbits {
813 int t_bits;
814 char *t_name;
815 } bits[] = {
816 { RTF_UP, "UP" },
817 { RTF_DIRECT, "DIRECT" },
818 { RTF_HOST, "HOST" },
819 { RTF_DELRT, "DELETE" },
820 { RTF_CHGRT, "CHANGE" },
821 { RTF_SILENT, "SILENT" },
822 { 0 }
823 };
824 register struct flagbits *p;
825 register int first;
826 char *cp;
827
828 printf("%s ", operation);
829 dst = (struct sockaddr_in *)&rt->rt_dst;
830 gate = (struct sockaddr_in *)&rt->rt_gateway;
831 printf("dst %x, router %x, metric %d, flags ",
832 dst->sin_addr, gate->sin_addr, rt->rt_metric);
833 cp = "%s";
834 for (first = 1, p = bits; p->t_bits > 0; p++) {
835 if ((rt->rt_flags & p->t_bits) == 0)
836 continue;
837 printf(cp, p->t_name);
838 if (first) {
839 cp = "|%s";
840 first = 0;
841 }
842 }
843 putchar('\n');
844}