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