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