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