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