convert to 4.1c directory layout
[unix-history] / usr / src / sbin / routed / routed.c
CommitLineData
7c0bf99b 1#ifndef lint
3bd9bc1e 2static char sccsid[] = "@(#)routed.c 4.25 %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>
f64bc556 18#include <netdb.h>
baa2dcc8 19#define RIPCMDS
7c0bf99b
SL
20#include "rip.h"
21#include "router.h"
22
23#define LOOPBACKNET 0177
24/* casts to keep lint happy */
25#define insque(q,p) _insque((caddr_t)q,(caddr_t)p)
26#define remque(q) _remque((caddr_t)q)
27#define equal(a1, a2) \
28 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
77df73ca 29#define min(a,b) ((a)>(b)?(b):(a))
7c0bf99b
SL
30
31struct nlist nl[] = {
32#define N_IFNET 0
33 { "_ifnet" },
34 0,
35};
36
d0188ba8
SL
37struct sockaddr_in routingaddr = { AF_INET };
38struct sockaddr_in noroutingaddr = { AF_INET };
7c0bf99b
SL
39
40int s;
74d7f201 41int snoroute; /* socket with no routing */
77df73ca 42int kmem = -1;
6db0b3a4 43int supplier = -1; /* process should supply updates */
b7fcdb03 44int install = 1; /* if 1 call kernel */
e0a3d4f9
SL
45int lookforinterfaces = 1;
46int performnlist = 1;
71535ddb 47int externalinterfaces = 0; /* # of remote and local interfaces */
6db0b3a4 48int timeval = -TIMER_RATE;
7c0bf99b
SL
49int timer();
50int cleanup();
6db0b3a4
BJ
51
52#define tprintf if (trace) printf
7c0bf99b 53int trace = 0;
6d0df65e 54FILE *ftrace;
7c0bf99b 55
6db0b3a4
BJ
56char packet[MAXPACKETSIZE+1];
57struct rip *msg = (struct rip *)packet;
7c0bf99b 58
d0188ba8 59struct in_addr inet_makeaddr();
e0a3d4f9
SL
60struct interface *if_ifwithaddr(), *if_ifwithnet();
61extern char *malloc(), *sys_errlist[];
c5f8709e 62extern int errno, exit();
6db0b3a4
BJ
63char **argv0;
64
baa2dcc8 65int sendmsg(), supply();
7c0bf99b
SL
66
67main(argc, argv)
68 int argc;
69 char *argv[];
70{
71 int cc;
72 struct sockaddr from;
d0188ba8 73 struct servent *sp;
7c0bf99b 74
6db0b3a4 75 argv0 = argv;
6d0df65e
SL
76#ifndef DEBUG
77 if (fork())
78 exit(0);
79 for (cc = 0; cc < 10; cc++)
80 (void) close(cc);
81 (void) open("/", 0);
82 (void) dup2(0, 1);
83 (void) dup2(0, 2);
84 { int t = open("/dev/tty", 2);
85 if (t >= 0) {
86 ioctl(t, TIOCNOTTY, (char *)0);
87 (void) close(t);
88 }
7c0bf99b 89 }
6d0df65e 90#endif
7c0bf99b 91 if (trace) {
6d0df65e
SL
92 ftrace = fopen("/etc/routerlog", "w");
93 dup2(fileno(ftrace), 1);
94 dup2(fileno(ftrace), 2);
7c0bf99b 95 }
71535ddb
SL
96
97 /*
98 * We use two sockets. One for which outgoing
99 * packets are routed and for which they're not.
100 * The latter allows us to delete routing table
101 * entries in the kernel for network interfaces
102 * attached to our host which we believe are down
103 * while still polling it to see when/if it comes
104 * back up. With the new ipc interface we'll be
105 * able to specify ``don't route'' as an option
106 * to send, but until then we utilize a second port.
107 */
d0188ba8
SL
108 sp = getservbyname("router", "udp");
109 if (sp == 0) {
110 fprintf(stderr, "routed: udp/router: unknown service\n");
111 exit(1);
112 }
113 routingaddr.sin_port = htons(sp->s_port);
114 noroutingaddr.sin_port = htons(sp->s_port + 1);
7c0bf99b 115again:
baa2dcc8 116 s = socket(SOCK_DGRAM, 0, &routingaddr, 0);
7c0bf99b
SL
117 if (s < 0) {
118 perror("socket");
119 sleep(30);
120 goto again;
121 }
74d7f201 122again2:
baa2dcc8 123 snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE);
74d7f201
BJ
124 if (snoroute < 0) {
125 perror("socket");
126 sleep(30);
127 goto again2;
128 }
7c0bf99b 129 argv++, argc--;
6db0b3a4
BJ
130 while (argc > 0 && **argv == '-') {
131 if (!strcmp(*argv, "-s") == 0) {
77df73ca 132 supplier = 1;
6db0b3a4
BJ
133 argv++, argc--;
134 continue;
135 }
136 if (!strcmp(*argv, "-q") == 0) {
7c0bf99b 137 supplier = 0;
6db0b3a4
BJ
138 argv++, argc--;
139 continue;
140 }
141 goto usage;
142 }
143 if (argc > 0) {
144usage:
e0a3d4f9 145 fprintf(stderr, "usage: routed [ -sq ]\n");
6db0b3a4 146 exit(1);
7c0bf99b 147 }
71535ddb
SL
148 /*
149 * Collect an initial view of the world by
150 * snooping in the kernel and the gateway kludge
151 * file. Then, send a request packet on all
152 * directly connected networks to find out what
153 * everyone else thinks.
154 */
6db0b3a4 155 rtinit();
71535ddb 156 gwkludge();
6db0b3a4
BJ
157 ifinit();
158 if (supplier < 0)
159 supplier = 0;
6db0b3a4
BJ
160 msg->rip_cmd = RIPCMD_REQUEST;
161 msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
162 msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
163 toall(sendmsg);
7c0bf99b 164 sigset(SIGALRM, timer);
77df73ca 165 timer();
7c0bf99b 166
7c0bf99b
SL
167 for (;;) {
168 cc = receive(s, &from, packet, sizeof (packet));
169 if (cc <= 0) {
170 if (cc < 0 && errno != EINTR)
171 perror("receive");
172 continue;
173 }
174 sighold(SIGALRM);
175 rip_input(&from, cc);
176 sigrelse(SIGALRM);
177 }
178}
179
6db0b3a4 180rtinit()
7c0bf99b 181{
3cec0c76 182 register struct rthash *rh;
7c0bf99b 183
6db0b3a4
BJ
184 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
185 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
186 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
187 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
7c0bf99b
SL
188}
189
e0a3d4f9 190struct interface *ifnet;
6db0b3a4 191
71535ddb
SL
192/*
193 * Probe the kernel through /dev/kmem to find the network
194 * interfaces which have configured themselves. If the
195 * interface is present but not yet up (for example an
196 * ARPANET IMP), set the lookforinterfaces flag so we'll
197 * come back later and look again.
198 */
6db0b3a4 199ifinit()
7c0bf99b 200{
e0a3d4f9
SL
201 struct interface *ifp;
202 struct ifnet ifs, *next;
e0a3d4f9
SL
203
204 if (performnlist) {
205 nlist("/vmunix", nl);
206 if (nl[N_IFNET].n_value == 0) {
207 printf("ifnet: not in namelist\n");
208 goto bad;
209 }
210 performnlist = 0;
7c0bf99b 211 }
7c0bf99b 212 if (kmem < 0) {
e0a3d4f9
SL
213 kmem = open("/dev/kmem", 0);
214 if (kmem < 0) {
215 perror("/dev/kmem");
216 goto bad;
217 }
77df73ca
SL
218 }
219 if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
6db0b3a4
BJ
220 read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
221 printf("ifnet: error reading kmem\n");
222 goto bad;
7c0bf99b 223 }
e0a3d4f9 224 lookforinterfaces = 0;
6db0b3a4 225 while (next) {
6db0b3a4 226 if (lseek(kmem, (long)next, 0) == -1 ||
e0a3d4f9 227 read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) {
6db0b3a4
BJ
228 perror("read");
229 goto bad;
77df73ca 230 }
e0a3d4f9
SL
231 next = ifs.if_next;
232 if ((ifs.if_flags & IFF_UP) == 0) {
233 lookforinterfaces = 1;
6db0b3a4 234 continue;
e0a3d4f9 235 }
71535ddb 236 /* already known to us? */
e0a3d4f9 237 if (if_ifwithaddr(&ifs.if_addr))
6db0b3a4 238 continue;
71535ddb 239 /* argh, this'll have to change sometime */
e0a3d4f9
SL
240 if (ifs.if_addr.sa_family != AF_INET)
241 continue;
71535ddb 242 /* no one cares about software loopback interfaces */
e0a3d4f9
SL
243 if (ifs.if_net == LOOPBACKNET)
244 continue;
245 ifp = (struct interface *)malloc(sizeof (struct interface));
246 if (ifp == 0) {
247 printf("routed: out of memory\n");
248 break;
249 }
250 /*
251 * Count the # of directly connected networks
252 * and point to point links which aren't looped
253 * back to ourself. This is used below to
71535ddb 254 * decide if we should be a routing ``supplier''.
e0a3d4f9
SL
255 */
256 if ((ifs.if_flags & IFF_POINTOPOINT) == 0 ||
257 if_ifwithaddr(&ifs.if_dstaddr) == 0)
258 externalinterfaces++;
259 ifp->int_addr = ifs.if_addr;
260 ifp->int_flags = ifs.if_flags | IFF_INTERFACE;
261 /* this works because broadaddr overlaps dstaddr */
262 ifp->int_broadaddr = ifs.if_broadaddr;
263 ifp->int_net = ifs.if_net;
264 ifp->int_metric = 0;
265 ifp->int_next = ifnet;
77df73ca 266 ifnet = ifp;
6db0b3a4
BJ
267 addrouteforif(ifp);
268 }
e0a3d4f9 269 if (externalinterfaces > 1 && supplier < 0)
6db0b3a4
BJ
270 supplier = 1;
271 return;
272bad:
273 sleep(60);
e0a3d4f9 274 close(kmem), close(s), close(snoroute);
6db0b3a4
BJ
275 execv("/etc/routed", argv0);
276 _exit(0177);
277}
74d7f201 278
6db0b3a4 279addrouteforif(ifp)
e0a3d4f9 280 struct interface *ifp;
6db0b3a4
BJ
281{
282 struct sockaddr_in net;
283 struct sockaddr *dst;
e0a3d4f9 284 int state, metric;
3259727e 285 struct rt_entry *rt;
6db0b3a4 286
e0a3d4f9
SL
287 if (ifp->int_flags & IFF_POINTOPOINT)
288 dst = &ifp->int_dstaddr;
6db0b3a4
BJ
289 else {
290 bzero((char *)&net, sizeof (net));
291 net.sin_family = AF_INET;
d0188ba8 292 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
6db0b3a4 293 dst = (struct sockaddr *)&net;
7c0bf99b 294 }
3259727e
SL
295 rt = rtlookup(dst);
296 rtadd(dst, &ifp->int_addr, ifp->int_metric,
297 ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
298 if (rt)
299 rtdelete(rt);
74d7f201
BJ
300}
301
71535ddb
SL
302/*
303 * As a concession to the ARPANET we read a list of gateways
304 * from /etc/gateways and add them to our tables. This file
305 * exists at each ARPANET gateway and indicates a set of ``remote''
306 * gateways (i.e. a gateway which we can't immediately determine
307 * if it's present or not as we can do for those directly connected
308 * at the hardware level). If a gateway is marked ``passive''
309 * in the file, then we assume it doesn't have a routing process
310 * of our design and simply assume it's always present. Those
311 * not marked passive are treated as if they were directly
312 * connected -- they're added into the interface list so we'll
313 * send them routing updates.
314 */
6db0b3a4 315gwkludge()
74d7f201
BJ
316{
317 struct sockaddr_in dst, gate;
318 FILE *fp;
d0188ba8 319 char *type, *dname, *gname, *qual, buf[BUFSIZ];
e0a3d4f9
SL
320 struct interface *ifp;
321 int metric;
74d7f201
BJ
322
323 fp = fopen("/etc/gateways", "r");
324 if (fp == NULL)
325 return;
d0188ba8
SL
326 qual = buf;
327 dname = buf + 64;
328 gname = buf + ((BUFSIZ - 64) / 3);
329 type = buf + (((BUFSIZ - 64) * 2) / 3);
74d7f201
BJ
330 bzero((char *)&dst, sizeof (dst));
331 bzero((char *)&gate, sizeof (gate));
e0a3d4f9 332 dst.sin_family = gate.sin_family = AF_INET;
3bd9bc1e 333 /* format: {net | host} XX gateway XX metric DD [passive]\n */
e0a3d4f9 334#define readentry(fp) \
3bd9bc1e 335 fscanf((fp), "%s %s gateway %s metric %d %s\n", \
d0188ba8 336 type, dname, gname, &metric, qual)
6db0b3a4 337 for (;;) {
f64bc556 338 struct hostent *host;
d0188ba8 339 struct netent *net;
f64bc556 340
e0a3d4f9 341 if (readentry(fp) == EOF)
6db0b3a4 342 break;
d0188ba8
SL
343 if (strcmp(type, "net") == 0) {
344 net = getnetbyname(dname);
345 if (net == 0 || net->n_addrtype != AF_INET)
346 continue;
347 dst.sin_addr = inet_makeaddr(net->n_net, INADDR_ANY);
348 } else if (strcmp(type, "host") == 0) {
349 host = gethostbyname(dname);
350 if (host == 0)
351 continue;
352 bcopy(host->h_addr, &dst.sin_addr, host->h_length);
353 } else
485547bb 354 continue;
f64bc556
SL
355 host = gethostbyname(gname);
356 if (host == 0)
485547bb 357 continue;
f64bc556 358 bcopy(host->h_addr, &gate.sin_addr, host->h_length);
e0a3d4f9
SL
359 ifp = (struct interface *)malloc(sizeof (*ifp));
360 bzero((char *)ifp, sizeof (*ifp));
361 ifp->int_flags = IFF_REMOTE;
362 /* can't identify broadcast capability */
d0188ba8
SL
363 ifp->int_net = inet_netof(dst.sin_addr);
364 if (strcmp(type, "host") == 0) {
e0a3d4f9 365 ifp->int_flags |= IFF_POINTOPOINT;
e0a3d4f9 366 ifp->int_dstaddr = *((struct sockaddr *)&dst);
c7b4f6e8 367 }
485547bb 368 if (strcmp(qual, "passive") == 0)
e0a3d4f9 369 ifp->int_flags |= IFF_PASSIVE;
71535ddb
SL
370 else
371 /* assume no duplicate entries */
372 externalinterfaces++;
e0a3d4f9
SL
373 ifp->int_addr = *((struct sockaddr *)&gate);
374 ifp->int_metric = metric;
375 ifp->int_next = ifnet;
376 ifnet = ifp;
377 addrouteforif(ifp);
74d7f201
BJ
378 }
379 fclose(fp);
7c0bf99b
SL
380}
381
71535ddb
SL
382/*
383 * Timer routine. Performs routing information supply
384 * duties and manages timers on routing table entries.
385 */
6db0b3a4 386timer()
7c0bf99b 387{
3cec0c76 388 register struct rthash *rh;
7c0bf99b 389 register struct rt_entry *rt;
3cec0c76 390 struct rthash *base = hosthash;
71535ddb 391 int doinghost = 1, timetobroadcast;
7c0bf99b 392
6db0b3a4 393 timeval += TIMER_RATE;
e0a3d4f9
SL
394 if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
395 ifinit();
71535ddb 396 timetobroadcast = supplier && (timeval % SUPPLY_INTERVAL) == 0;
6db0b3a4 397 tprintf(">>> time %d >>>\n", timeval);
7c0bf99b 398again:
6db0b3a4
BJ
399 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
400 rt = rh->rt_forw;
401 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
71535ddb
SL
402 /*
403 * We don't advance time on a routing entry for
404 * a passive gateway or that for our only interface.
405 * The latter is excused because we don't act as
406 * a routing information supplier and hence would
407 * time it out. This is fair as if it's down
408 * we're cut off from the world anyway and it's
409 * not likely we'll grow any new hardware in
410 * the mean time.
411 */
412 if (!(rt->rt_state & RTS_PASSIVE) &&
413 (supplier || !(rt->rt_state & RTS_INTERFACE)))
6db0b3a4 414 rt->rt_timer += TIMER_RATE;
6db0b3a4
BJ
415 if (rt->rt_timer >= EXPIRE_TIME)
416 rt->rt_metric = HOPCNT_INFINITY;
e0a3d4f9
SL
417 log("", rt);
418 if (rt->rt_timer >= GARBAGE_TIME) {
6db0b3a4
BJ
419 rt = rt->rt_back;
420 rtdelete(rt->rt_forw);
421 continue;
422 }
e0a3d4f9
SL
423 if (rt->rt_state & RTS_CHANGED) {
424 rt->rt_state &= ~RTS_CHANGED;
425 /* don't send extraneous packets */
71535ddb 426 if (!supplier || timetobroadcast)
e0a3d4f9 427 continue;
6db0b3a4
BJ
428 log("broadcast", rt);
429 msg->rip_cmd = RIPCMD_RESPONSE;
430 msg->rip_nets[0].rip_dst = rt->rt_dst;
431 msg->rip_nets[0].rip_metric =
432 min(rt->rt_metric+1, HOPCNT_INFINITY);
baa2dcc8 433 toall(sendmsg);
6db0b3a4
BJ
434 }
435 }
7c0bf99b
SL
436 }
437 if (doinghost) {
77df73ca 438 doinghost = 0;
6db0b3a4 439 base = nethash;
7c0bf99b
SL
440 goto again;
441 }
71535ddb 442 if (timetobroadcast)
6db0b3a4
BJ
443 toall(supply);
444 tprintf("<<< time %d <<<\n", timeval);
445 alarm(TIMER_RATE);
7c0bf99b
SL
446}
447
6db0b3a4
BJ
448toall(f)
449 int (*f)();
7c0bf99b 450{
e0a3d4f9 451 register struct interface *ifp;
7c0bf99b 452 register struct sockaddr *dst;
7c0bf99b 453
e0a3d4f9
SL
454 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
455 if (ifp->int_flags & IFF_PASSIVE)
7c0bf99b 456 continue;
e0a3d4f9
SL
457 dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
458 ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
459 &ifp->int_addr;
460 (*f)(dst, ifp->int_flags & IFF_INTERFACE);
7c0bf99b
SL
461 }
462}
463
baa2dcc8
SL
464/*ARGSUSED*/
465sendmsg(dst, dontroute)
6db0b3a4 466 struct sockaddr *dst;
baa2dcc8 467 int dontroute;
6db0b3a4 468{
6db0b3a4
BJ
469 (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
470}
471
71535ddb
SL
472/*
473 * Supply dst with the contents of the routing tables.
474 * If this won't fit in one packet, chop it up into several.
475 */
baa2dcc8
SL
476supply(dst, dontroute)
477 struct sockaddr *dst;
478 int dontroute;
7c0bf99b 479{
baa2dcc8 480 register struct rt_entry *rt;
7c0bf99b 481 struct netinfo *n = msg->rip_nets;
3cec0c76 482 register struct rthash *rh;
3cec0c76 483 struct rthash *base = hosthash;
77df73ca 484 int doinghost = 1, size;
baa2dcc8
SL
485 int (*output)() = afswitch[dst->sa_family].af_output;
486 int sto = dontroute ? snoroute : s;
7c0bf99b 487
c7b4f6e8 488 msg->rip_cmd = RIPCMD_RESPONSE;
7c0bf99b
SL
489again:
490 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
491 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
77df73ca
SL
492 size = (char *)n - packet;
493 if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
baa2dcc8 494 (*output)(sto, dst, size);
7c0bf99b
SL
495 n = msg->rip_nets;
496 }
497 n->rip_dst = rt->rt_dst;
77df73ca
SL
498 n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
499 n++;
7c0bf99b
SL
500 }
501 if (doinghost) {
502 doinghost = 0;
503 base = nethash;
504 goto again;
505 }
77df73ca 506 if (n != msg->rip_nets)
baa2dcc8 507 (*output)(sto, dst, (char *)n - packet);
7c0bf99b
SL
508}
509
510/*
511 * Handle an incoming routing packet.
512 */
513rip_input(from, size)
514 struct sockaddr *from;
515 int size;
516{
7c0bf99b
SL
517 struct rt_entry *rt;
518 struct netinfo *n;
e0a3d4f9 519 struct interface *ifp;
6db0b3a4 520 time_t t;
baa2dcc8
SL
521 int newsize;
522 struct afswitch *afp;
7c0bf99b 523
baa2dcc8
SL
524 if (trace) {
525 if (msg->rip_cmd < RIPCMD_MAX)
526 printf("%s from %x\n", ripcmds[msg->rip_cmd],
527 ((struct sockaddr_in *)from)->sin_addr);
528 else
529 printf("%x from %x\n", msg->rip_cmd,
530 ((struct sockaddr_in *)from)->sin_addr);
531 }
532 if (from->sa_family >= AF_MAX)
7c0bf99b 533 return;
baa2dcc8
SL
534 afp = &afswitch[from->sa_family];
535 switch (msg->rip_cmd) {
e6b5ed24
SL
536
537 case RIPCMD_REQUEST:
baa2dcc8
SL
538 newsize = 0;
539 size -= 4 * sizeof (char);
540 n = msg->rip_nets;
541 while (size > 0) {
542 if (size < sizeof (struct netinfo))
543 break;
544 size -= sizeof (struct netinfo);
545
546 /*
547 * A single entry with sa_family == AF_UNSPEC and
548 * metric ``infinity'' means ``all routes''.
549 */
550 if (n->rip_dst.sa_family == AF_UNSPEC &&
551 n->rip_metric == HOPCNT_INFINITY && size == 0) {
c7b4f6e8 552 supply(from, 0);
baa2dcc8
SL
553 return;
554 }
555 rt = rtlookup(&n->rip_dst);
556 n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
557 min(rt->rt_metric+1, HOPCNT_INFINITY);
558 n++, newsize += sizeof (struct netinfo);
559 }
560 if (newsize > 0) {
561 msg->rip_cmd = RIPCMD_RESPONSE;
562 newsize += sizeof (int);
563 (*afp->af_output)(s, from, newsize);
564 }
7c0bf99b 565 return;
e6b5ed24 566
6d0df65e 567 case RIPCMD_TRACEON:
baa2dcc8 568 if ((*afp->af_portcheck)(from) == 0)
6d0df65e 569 return;
6db0b3a4
BJ
570 if (trace)
571 return;
572 packet[size] = '\0';
573 ftrace = fopen(msg->rip_tracefile, "a");
574 if (ftrace == NULL)
e6b5ed24 575 return;
6db0b3a4
BJ
576 (void) dup2(fileno(ftrace), 1);
577 (void) dup2(fileno(ftrace), 2);
578 trace = 1;
579 t = time(0);
580 printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
7c0bf99b 581 return;
7c0bf99b 582
6db0b3a4
BJ
583 case RIPCMD_TRACEOFF:
584 /* verify message came from a priviledged port */
baa2dcc8 585 if ((*afp->af_portcheck)(from) == 0)
6db0b3a4 586 return;
6d0df65e
SL
587 if (!trace)
588 return;
589 t = time(0);
590 printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
591 fflush(stdout), fflush(stderr);
592 if (ftrace)
593 fclose(ftrace);
594 (void) close(1), (void) close(2);
595 trace = 0;
596 return;
6d0df65e 597
6db0b3a4
BJ
598 case RIPCMD_RESPONSE:
599 /* verify message came from a router */
baa2dcc8 600 if ((*afp->af_portmatch)(from) == 0)
6db0b3a4 601 return;
baa2dcc8 602 (*afp->af_canon)(from);
6db0b3a4
BJ
603 /* are we talking to ourselves? */
604 ifp = if_ifwithaddr(from);
605 if (ifp) {
e0a3d4f9
SL
606 rt = rtfind(from);
607 if (rt == 0)
6db0b3a4 608 addrouteforif(ifp);
e0a3d4f9
SL
609 else
610 rt->rt_timer = 0;
6db0b3a4
BJ
611 return;
612 }
613 size -= 4 * sizeof (char);
614 n = msg->rip_nets;
615 for (; size > 0; size -= sizeof (struct netinfo), n++) {
616 if (size < sizeof (struct netinfo))
617 break;
618 if (n->rip_metric >= HOPCNT_INFINITY)
619 continue;
620 tprintf("dst %x hc %d...",
621 ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
622 n->rip_metric);
623 rt = rtlookup(&n->rip_dst);
624 if (rt == 0) {
625 rtadd(&n->rip_dst, from, n->rip_metric, 0);
6db0b3a4
BJ
626 continue;
627 }
628 tprintf("ours: gate %x hc %d timer %d\n",
629 ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
630 rt->rt_metric, rt->rt_timer);
baa2dcc8 631
6db0b3a4 632 /*
71535ddb 633 * Update if from gateway, shorter, or getting
baa2dcc8 634 * stale and equivalent.
6db0b3a4
BJ
635 */
636 if (equal(from, &rt->rt_router) ||
637 n->rip_metric < rt->rt_metric ||
638 (rt->rt_timer > (EXPIRE_TIME/2) &&
639 rt->rt_metric == n->rip_metric)) {
640 rtchange(rt, from, n->rip_metric);
641 rt->rt_timer = 0;
642 }
643 }
644 return;
645 }
e0a3d4f9 646 tprintf("bad packet, cmd=%x\n", msg->rip_cmd);
3cec0c76
SL
647}
648
71535ddb
SL
649/*
650 * Lookup dst in the tables for an exact match.
651 */
7c0bf99b
SL
652struct rt_entry *
653rtlookup(dst)
654 struct sockaddr *dst;
655{
656 register struct rt_entry *rt;
3cec0c76 657 register struct rthash *rh;
eae14a37 658 register int hash;
7c0bf99b 659 struct afhash h;
eae14a37
SL
660 int doinghost = 1;
661
662 if (dst->sa_family >= AF_MAX)
663 return (0);
664 (*afswitch[dst->sa_family].af_hash)(dst, &h);
665 hash = h.afh_hosthash;
666 rh = &hosthash[hash % ROUTEHASHSIZ];
667again:
668 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
e0a3d4f9 669 if (rt->rt_hash != hash)
eae14a37
SL
670 continue;
671 if (equal(&rt->rt_dst, dst))
672 return (rt);
673 }
674 if (doinghost) {
675 doinghost = 0;
676 hash = h.afh_nethash;
677 rh = &nethash[hash % ROUTEHASHSIZ];
678 goto again;
679 }
680 return (0);
681}
682
71535ddb
SL
683/*
684 * Find a route to dst as the kernel would.
685 */
eae14a37 686struct rt_entry *
e0a3d4f9 687rtfind(dst)
eae14a37
SL
688 struct sockaddr *dst;
689{
690 register struct rt_entry *rt;
691 register struct rthash *rh;
692 register int hash;
693 struct afhash h;
694 int af = dst->sa_family;
695 int doinghost = 1, (*match)();
7c0bf99b
SL
696
697 if (af >= AF_MAX)
698 return (0);
699 (*afswitch[af].af_hash)(dst, &h);
700 hash = h.afh_hosthash;
701 rh = &hosthash[hash % ROUTEHASHSIZ];
702
703again:
704 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
705 if (rt->rt_hash != hash)
706 continue;
707 if (doinghost) {
708 if (equal(&rt->rt_dst, dst))
709 return (rt);
710 } else {
711 if (rt->rt_dst.sa_family == af &&
712 (*match)(&rt->rt_dst, dst))
713 return (rt);
714 }
715 }
716 if (doinghost) {
717 doinghost = 0;
718 hash = h.afh_nethash;
7c0bf99b 719 rh = &nethash[hash % ROUTEHASHSIZ];
eae14a37 720 match = afswitch[af].af_netmatch;
7c0bf99b
SL
721 goto again;
722 }
723 return (0);
724}
725
baa2dcc8 726rtadd(dst, gate, metric, state)
7c0bf99b 727 struct sockaddr *dst, *gate;
baa2dcc8 728 int metric, state;
7c0bf99b
SL
729{
730 struct afhash h;
731 register struct rt_entry *rt;
3cec0c76 732 struct rthash *rh;
7c0bf99b
SL
733 int af = dst->sa_family, flags, hash;
734
735 if (af >= AF_MAX)
736 return;
737 (*afswitch[af].af_hash)(dst, &h);
738 flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
739 if (flags & RTF_HOST) {
740 hash = h.afh_hosthash;
741 rh = &hosthash[hash % ROUTEHASHSIZ];
742 } else {
743 hash = h.afh_nethash;
744 rh = &nethash[hash % ROUTEHASHSIZ];
745 }
746 rt = (struct rt_entry *)malloc(sizeof (*rt));
747 if (rt == 0)
748 return;
749 rt->rt_hash = hash;
750 rt->rt_dst = *dst;
74d7f201 751 rt->rt_router = *gate;
7c0bf99b
SL
752 rt->rt_metric = metric;
753 rt->rt_timer = 0;
baa2dcc8 754 rt->rt_flags = RTF_UP | flags;
e0a3d4f9 755 rt->rt_state = state | RTS_CHANGED;
74d7f201
BJ
756 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
757 if (metric)
758 rt->rt_flags |= RTF_GATEWAY;
7c0bf99b 759 insque(rt, rh);
77df73ca 760 log("add", rt);
e0a3d4f9
SL
761 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
762 tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
7c0bf99b
SL
763}
764
7c0bf99b
SL
765rtchange(rt, gate, metric)
766 struct rt_entry *rt;
767 struct sockaddr *gate;
768 short metric;
769{
baa2dcc8 770 int doioctl = 0, metricchanged = 0;
e0a3d4f9 771 struct rtentry oldroute;
7c0bf99b 772
e0a3d4f9 773 if (!equal(&rt->rt_router, gate))
baa2dcc8 774 doioctl++;
7c0bf99b 775 if (metric != rt->rt_metric) {
baa2dcc8 776 metricchanged++;
7c0bf99b 777 rt->rt_metric = metric;
7c0bf99b 778 }
e0a3d4f9
SL
779 if (doioctl || metricchanged) {
780 log("change", rt);
781 rt->rt_state |= RTS_CHANGED;
782 }
baa2dcc8 783 if (doioctl) {
e0a3d4f9 784 oldroute = rt->rt_rt;
baa2dcc8 785 rt->rt_router = *gate;
e0a3d4f9
SL
786 if (install) {
787 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
788 tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
789 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
790 tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
791 }
baa2dcc8 792 }
7c0bf99b
SL
793}
794
7c0bf99b
SL
795rtdelete(rt)
796 struct rt_entry *rt;
797{
77df73ca 798 log("delete", rt);
74d7f201 799 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
e0a3d4f9 800 tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
7c0bf99b
SL
801 remque(rt);
802 free((char *)rt);
803}
804
7c0bf99b
SL
805log(operation, rt)
806 char *operation;
807 struct rt_entry *rt;
808{
7c0bf99b 809 struct sockaddr_in *dst, *gate;
e6b5ed24 810 static struct bits {
7c0bf99b
SL
811 int t_bits;
812 char *t_name;
e6b5ed24 813 } flagbits[] = {
7c0bf99b 814 { RTF_UP, "UP" },
74d7f201 815 { RTF_GATEWAY, "GATEWAY" },
7c0bf99b 816 { RTF_HOST, "HOST" },
e6b5ed24
SL
817 { 0 }
818 }, statebits[] = {
74d7f201 819 { RTS_PASSIVE, "PASSIVE" },
e0a3d4f9
SL
820 { RTS_REMOTE, "REMOTE" },
821 { RTS_INTERFACE,"INTERFACE" },
822 { RTS_CHANGED, "CHANGED" },
7c0bf99b
SL
823 { 0 }
824 };
e6b5ed24 825 register struct bits *p;
7c0bf99b
SL
826 register int first;
827 char *cp;
828
77df73ca
SL
829 if (trace == 0)
830 return;
7c0bf99b
SL
831 printf("%s ", operation);
832 dst = (struct sockaddr_in *)&rt->rt_dst;
74d7f201 833 gate = (struct sockaddr_in *)&rt->rt_router;
e0a3d4f9
SL
834 printf("dst %x, router %x, metric %d, flags", dst->sin_addr,
835 gate->sin_addr, rt->rt_metric);
e6b5ed24
SL
836 cp = " %s";
837 for (first = 1, p = flagbits; p->t_bits > 0; p++) {
7c0bf99b
SL
838 if ((rt->rt_flags & p->t_bits) == 0)
839 continue;
840 printf(cp, p->t_name);
841 if (first) {
842 cp = "|%s";
843 first = 0;
844 }
845 }
e6b5ed24
SL
846 printf(" state");
847 cp = " %s";
848 for (first = 1, p = statebits; p->t_bits > 0; p++) {
849 if ((rt->rt_state & p->t_bits) == 0)
850 continue;
851 printf(cp, p->t_name);
852 if (first) {
853 cp = "|%s";
854 first = 0;
855 }
856 }
7c0bf99b
SL
857 putchar('\n');
858}
77df73ca 859
e0a3d4f9 860struct interface *
77df73ca
SL
861if_ifwithaddr(addr)
862 struct sockaddr *addr;
863{
e0a3d4f9 864 register struct interface *ifp;
77df73ca
SL
865
866#define same(a1, a2) \
867 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
e0a3d4f9
SL
868 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
869 if (ifp->int_flags & IFF_REMOTE)
870 continue;
871 if (ifp->int_addr.sa_family != addr->sa_family)
77df73ca 872 continue;
e0a3d4f9 873 if (same(&ifp->int_addr, addr))
77df73ca 874 break;
e0a3d4f9
SL
875 if ((ifp->int_flags & IFF_BROADCAST) &&
876 same(&ifp->int_broadaddr, addr))
77df73ca
SL
877 break;
878 }
879 return (ifp);
880#undef same
881}
882
e0a3d4f9 883struct interface *
77df73ca
SL
884if_ifwithnet(addr)
885 register struct sockaddr *addr;
886{
e0a3d4f9 887 register struct interface *ifp;
77df73ca
SL
888 register int af = addr->sa_family;
889 register int (*netmatch)();
890
891 if (af >= AF_MAX)
892 return (0);
893 netmatch = afswitch[af].af_netmatch;
e0a3d4f9
SL
894 for (ifp = ifnet; ifp; ifp = ifp->int_next) {
895 if (ifp->int_flags & IFF_REMOTE)
896 continue;
897 if (af != ifp->int_addr.sa_family)
77df73ca 898 continue;
e0a3d4f9 899 if ((*netmatch)(addr, &ifp->int_addr))
77df73ca
SL
900 break;
901 }
902 return (ifp);
903}