newrouter->oldrouter and state bits mucho different
[unix-history] / usr / src / sbin / routed / routed.c
CommitLineData
7c0bf99b 1#ifndef lint
6db0b3a4 2static char sccsid[] = "@(#)routed.c 4.14 82/06/09";
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;
74d7f201 38int snoroute; /* socket with no routing */
77df73ca 39int kmem = -1;
6db0b3a4 40int supplier = -1; /* process should supply updates */
b7fcdb03 41int install = 1; /* if 1 call kernel */
6db0b3a4 42int timeval = -TIMER_RATE;
7c0bf99b
SL
43int timer();
44int cleanup();
6db0b3a4
BJ
45
46#define tprintf if (trace) printf
7c0bf99b 47int trace = 0;
6d0df65e 48FILE *ftrace;
7c0bf99b 49
6db0b3a4
BJ
50char packet[MAXPACKETSIZE+1];
51struct rip *msg = (struct rip *)packet;
7c0bf99b 52
3cec0c76
SL
53struct in_addr if_makeaddr();
54struct ifnet *if_ifwithaddr(), *if_ifwithnet();
7c0bf99b 55extern char *malloc();
c5f8709e 56extern int errno, exit();
6db0b3a4
BJ
57char **argv0;
58
59int sndmsg(), supply();
7c0bf99b
SL
60
61main(argc, argv)
62 int argc;
63 char *argv[];
64{
65 int cc;
66 struct sockaddr from;
67
6db0b3a4 68 argv0 = argv;
6d0df65e
SL
69#ifndef DEBUG
70 if (fork())
71 exit(0);
72 for (cc = 0; cc < 10; cc++)
73 (void) close(cc);
74 (void) open("/", 0);
75 (void) dup2(0, 1);
76 (void) dup2(0, 2);
77 { int t = open("/dev/tty", 2);
78 if (t >= 0) {
79 ioctl(t, TIOCNOTTY, (char *)0);
80 (void) close(t);
81 }
7c0bf99b 82 }
6d0df65e 83#endif
7c0bf99b 84 if (trace) {
6d0df65e
SL
85 ftrace = fopen("/etc/routerlog", "w");
86 dup2(fileno(ftrace), 1);
87 dup2(fileno(ftrace), 2);
7c0bf99b 88 }
e6b5ed24 89#ifdef vax || pdp11
7c0bf99b
SL
90 myaddr.sin_port = htons(myaddr.sin_port);
91#endif
92again:
93 s = socket(SOCK_DGRAM, 0, &myaddr, 0);
94 if (s < 0) {
95 perror("socket");
96 sleep(30);
97 goto again;
98 }
74d7f201
BJ
99again2:
100 snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE);
101 if (snoroute < 0) {
102 perror("socket");
103 sleep(30);
104 goto again2;
105 }
7c0bf99b 106 argv++, argc--;
6db0b3a4
BJ
107 while (argc > 0 && **argv == '-') {
108 if (!strcmp(*argv, "-s") == 0) {
77df73ca 109 supplier = 1;
6db0b3a4
BJ
110 argv++, argc--;
111 continue;
112 }
113 if (!strcmp(*argv, "-q") == 0) {
7c0bf99b 114 supplier = 0;
6db0b3a4
BJ
115 argv++, argc--;
116 continue;
117 }
118 goto usage;
119 }
120 if (argc > 0) {
121usage:
122 fprintf(stderr, "usage: routed [ -s ]\n");
123 exit(1);
7c0bf99b 124 }
6db0b3a4
BJ
125 rtinit();
126 ifinit();
127 if (supplier < 0)
128 supplier = 0;
129 gwkludge();
130 msg->rip_cmd = RIPCMD_REQUEST;
131 msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
132 msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
133 toall(sendmsg);
7c0bf99b 134 sigset(SIGALRM, timer);
77df73ca 135 timer();
7c0bf99b 136
7c0bf99b
SL
137 for (;;) {
138 cc = receive(s, &from, packet, sizeof (packet));
139 if (cc <= 0) {
140 if (cc < 0 && errno != EINTR)
141 perror("receive");
142 continue;
143 }
144 sighold(SIGALRM);
145 rip_input(&from, cc);
146 sigrelse(SIGALRM);
147 }
148}
149
6db0b3a4 150rtinit()
7c0bf99b 151{
3cec0c76 152 register struct rthash *rh;
7c0bf99b 153
6db0b3a4
BJ
154 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
155 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
156 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
157 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
7c0bf99b
SL
158}
159
3cec0c76 160struct ifnet *ifnet;
6db0b3a4
BJ
161
162ifinit()
7c0bf99b 163{
6db0b3a4 164 struct ifnet *ifp, *next;
77df73ca 165 register struct sockaddr *dst;
6db0b3a4 166 int uniquemultihostinterfaces = 0;
7c0bf99b 167
6db0b3a4
BJ
168 nlist("/vmunix", nl);
169 if (nl[N_IFNET].n_value == 0) {
170 printf("ifnet: not in namelist\n");
171 goto bad;
7c0bf99b 172 }
6db0b3a4 173 kmem = open("/dev/kmem", 0);
7c0bf99b 174 if (kmem < 0) {
6db0b3a4
BJ
175 perror("/dev/kmem");
176 goto bad;
77df73ca
SL
177 }
178 if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
6db0b3a4
BJ
179 read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
180 printf("ifnet: error reading kmem\n");
181 goto bad;
7c0bf99b 182 }
6db0b3a4 183 while (next) {
77df73ca
SL
184 ifp = (struct ifnet *)malloc(sizeof (struct ifnet));
185 if (ifp == 0) {
186 printf("routed: out of memory\n");
187 break;
188 }
6db0b3a4
BJ
189 if (lseek(kmem, (long)next, 0) == -1 ||
190 read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) {
191 perror("read");
192 goto bad;
77df73ca
SL
193 }
194 next = ifp->if_next;
6db0b3a4
BJ
195 if (ifp->if_addr.sa_family != AF_INET)
196 continue;
197 if (ifp->if_net == LOOPBACKNET)
198 continue;
199 if ((ifp->if_flags & IFF_POINTOPOINT) == 0 ||
200 if_ifwithaddr(&ifp->if_dstaddr) == 0)
201 uniquemultihostinterfaces++;
77df73ca
SL
202 ifp->if_next = ifnet;
203 ifnet = ifp;
6db0b3a4
BJ
204 addrouteforif(ifp);
205 }
206 if (uniquemultihostinterfaces > 1 && supplier < 0)
207 supplier = 1;
208 return;
209bad:
210 sleep(60);
211 execv("/etc/routed", argv0);
212 _exit(0177);
213}
74d7f201 214
6db0b3a4
BJ
215addrouteforif(ifp)
216 struct ifnet *ifp;
217{
218 struct sockaddr_in net;
219 struct sockaddr *dst;
220
221 if (ifp->if_flags & IFF_POINTOPOINT)
222 dst = &ifp->if_dstaddr;
223 else {
224 bzero((char *)&net, sizeof (net));
225 net.sin_family = AF_INET;
226 net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
227 dst = (struct sockaddr *)&net;
7c0bf99b 228 }
6db0b3a4 229 rtadd(dst, &ifp->if_addr, 0, RTS_INTERFACE);
74d7f201
BJ
230}
231
6db0b3a4 232gwkludge()
74d7f201
BJ
233{
234 struct sockaddr_in dst, gate;
235 FILE *fp;
236 struct rt_entry *rt;
6db0b3a4 237 char flags[BUFSIZ];
74d7f201
BJ
238
239 fp = fopen("/etc/gateways", "r");
240 if (fp == NULL)
241 return;
242 bzero((char *)&dst, sizeof (dst));
243 bzero((char *)&gate, sizeof (gate));
244 dst.sin_family = AF_INET;
245 gate.sin_family = AF_INET;
6db0b3a4
BJ
246 for (;;) {
247 if (fscanf(fp, "dst %x gateway %x\n", &dst.sin_addr.s_addr,
248 &gate.sin_addr.s_addr, flags) == EOF)
249 break;
250 rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1,
251 RTS_GLOBAL|(!strcmp(flags, "passive") ? RTS_PASSIVE : 0));
74d7f201
BJ
252 }
253 fclose(fp);
7c0bf99b
SL
254}
255
6db0b3a4 256timer()
7c0bf99b 257{
3cec0c76 258 register struct rthash *rh;
7c0bf99b 259 register struct rt_entry *rt;
3cec0c76 260 struct rthash *base = hosthash;
6db0b3a4 261 int doinghost = 1, state;
7c0bf99b 262
6db0b3a4
BJ
263 timeval += TIMER_RATE;
264 tprintf(">>> time %d >>>\n", timeval);
7c0bf99b 265again:
6db0b3a4
BJ
266 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
267 rt = rh->rt_forw;
268 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
269 if (!(rt->rt_state & RTS_GLOBAL))
270 rt->rt_timer += TIMER_RATE;
271 log("", rt);
272 if (rt->rt_timer >= EXPIRE_TIME)
273 rt->rt_metric = HOPCNT_INFINITY;
274 if ((rt->rt_state & RTS_DELRT) ||
275 rt->rt_timer >= GARBAGE_TIME) {
276 if (rt->rt_state&(RTS_INTERFACE|RTS_GLOBAL)) {
277 if (rt->rt_timer > 9999)
278 rt->rt_timer = 9999;
279 continue;
280 }
281 rt = rt->rt_back;
282 rtdelete(rt->rt_forw);
283 continue;
284 }
285 state = rt->rt_state;
286 if (rt->rt_state & RTS_ADDRT) {
287 if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
288 perror("SIOCADDRT");
289 rt->rt_state &= ~RTS_ADDRT;
290 }
291 if (rt->rt_state & RTS_CHGRT) {
292 struct rtentry oldroute;
293
294 oldroute = rt->rt_rt;
295 rt->rt_router = rt->rt_newrouter;
296 if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0)
297 perror("SIOCADDRT");
298 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
299 perror("SIOCDELRT");
300 rt->rt_state &= ~RTS_CHGRT;
301 }
302 if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) {
303 log("broadcast", rt);
304 msg->rip_cmd = RIPCMD_RESPONSE;
305 msg->rip_nets[0].rip_dst = rt->rt_dst;
306 msg->rip_nets[0].rip_metric =
307 min(rt->rt_metric+1, HOPCNT_INFINITY);
308 sendmsgtoall();
309 }
310 }
7c0bf99b
SL
311 }
312 if (doinghost) {
77df73ca 313 doinghost = 0;
6db0b3a4 314 base = nethash;
7c0bf99b
SL
315 goto again;
316 }
6db0b3a4
BJ
317 if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
318 toall(supply);
319 tprintf("<<< time %d <<<\n", timeval);
320 alarm(TIMER_RATE);
7c0bf99b
SL
321}
322
6db0b3a4
BJ
323toall(f)
324 int (*f)();
7c0bf99b 325{
3cec0c76 326 register struct rthash *rh;
6db0b3a4 327 register struct rt_entry *rt;
7c0bf99b 328 register struct sockaddr *dst;
3cec0c76 329 struct rthash *base = hosthash;
7c0bf99b
SL
330 int doinghost = 1;
331
332again:
333 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
334 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
6db0b3a4 335 if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0)
7c0bf99b
SL
336 continue;
337 if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
338 dst = &rt->rt_ifp->if_broadaddr;
339 else
74d7f201 340 dst = &rt->rt_router;
6db0b3a4 341 (*f)(rt, dst);
7c0bf99b
SL
342 }
343 if (doinghost) {
344 base = nethash;
345 doinghost = 0;
346 goto again;
347 }
348}
349
6db0b3a4
BJ
350sendmsg(rt, dst)
351 register struct rt_entry *rt;
352 struct sockaddr *dst;
353{
354
355 (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
356}
357
358supply(rt, sa)
359 register struct rt_entry *rt;
7c0bf99b
SL
360 struct sockaddr *sa;
361{
7c0bf99b 362 struct netinfo *n = msg->rip_nets;
3cec0c76 363 register struct rthash *rh;
3cec0c76 364 struct rthash *base = hosthash;
77df73ca 365 int doinghost = 1, size;
7c0bf99b 366 int (*output)() = afswitch[sa->sa_family].af_output;
6db0b3a4 367 int sto = (rt->rt_state&RTS_INTERFACE) ? snoroute : s;
7c0bf99b 368
6db0b3a4 369 log("supply", rt);
7c0bf99b
SL
370 msg->rip_cmd = RIPCMD_RESPONSE;
371again:
372 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
373 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
77df73ca
SL
374 size = (char *)n - packet;
375 if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
6db0b3a4 376 (*output)(sto, sa, size);
7c0bf99b
SL
377 n = msg->rip_nets;
378 }
379 n->rip_dst = rt->rt_dst;
77df73ca
SL
380 n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
381 n++;
7c0bf99b
SL
382 }
383 if (doinghost) {
384 doinghost = 0;
385 base = nethash;
386 goto again;
387 }
77df73ca 388 if (n != msg->rip_nets)
6db0b3a4 389 (*output)(sto, sa, (char *)n - packet);
7c0bf99b
SL
390}
391
392/*
393 * Respond to a routing info request.
394 */
395rip_respond(from, size)
396 struct sockaddr *from;
397 int size;
398{
7c0bf99b
SL
399 struct netinfo *np = msg->rip_nets;
400 struct rt_entry *rt;
401 int newsize = 0;
402
77df73ca 403 size -= 4 * sizeof (char);
7c0bf99b
SL
404 while (size > 0) {
405 if (size < sizeof (struct netinfo))
406 break;
407 size -= sizeof (struct netinfo);
408 if (np->rip_dst.sa_family == AF_UNSPEC &&
409 np->rip_metric == HOPCNT_INFINITY && size == 0) {
74d7f201 410 supply(s, from);
7c0bf99b
SL
411 return;
412 }
413 rt = rtlookup(&np->rip_dst);
77df73ca
SL
414 np->rip_metric = rt == 0 ?
415 HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY);
7c0bf99b
SL
416 np++, newsize += sizeof (struct netinfo);
417 }
418 if (newsize > 0) {
419 msg->rip_cmd = RIPCMD_RESPONSE;
420 newsize += sizeof (int);
74d7f201 421 (*afswitch[from->sa_family].af_output)(s, from, newsize);
7c0bf99b
SL
422 }
423}
424
425/*
426 * Handle an incoming routing packet.
427 */
428rip_input(from, size)
429 struct sockaddr *from;
430 int size;
431{
7c0bf99b
SL
432 struct rt_entry *rt;
433 struct netinfo *n;
6db0b3a4
BJ
434 struct ifnet *ifp;
435 time_t t;
7c0bf99b 436
e6b5ed24 437 switch (msg->rip_cmd) {
7c0bf99b 438
e6b5ed24 439 default:
7c0bf99b 440 return;
e6b5ed24
SL
441
442 case RIPCMD_REQUEST:
7c0bf99b
SL
443 rip_respond(from, size);
444 return;
e6b5ed24 445
6d0df65e 446 case RIPCMD_TRACEON:
6d0df65e
SL
447 if ((*afswitch[from->sa_family].af_portcheck)(from) == 0)
448 return;
6db0b3a4
BJ
449 if (trace)
450 return;
451 packet[size] = '\0';
452 ftrace = fopen(msg->rip_tracefile, "a");
453 if (ftrace == NULL)
e6b5ed24 454 return;
6db0b3a4
BJ
455 (void) dup2(fileno(ftrace), 1);
456 (void) dup2(fileno(ftrace), 2);
457 trace = 1;
458 t = time(0);
459 printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
7c0bf99b 460 return;
7c0bf99b 461
6db0b3a4
BJ
462 case RIPCMD_TRACEOFF:
463 /* verify message came from a priviledged port */
464 if ((*afswitch[from->sa_family].af_portcheck)(from) == 0)
465 return;
6d0df65e
SL
466 if (!trace)
467 return;
468 t = time(0);
469 printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
470 fflush(stdout), fflush(stderr);
471 if (ftrace)
472 fclose(ftrace);
473 (void) close(1), (void) close(2);
474 trace = 0;
475 return;
6d0df65e 476
6db0b3a4
BJ
477 case RIPCMD_RESPONSE:
478 /* verify message came from a router */
479 if ((*afswitch[from->sa_family].af_portmatch)(from) == 0)
480 return;
481 (*afswitch[from->sa_family].af_canon)(from);
482 tprintf("input from %x\n",
483 ((struct sockaddr_in *)from)->sin_addr);
484 /* are we talking to ourselves? */
485 ifp = if_ifwithaddr(from);
486 if (ifp) {
487 rt = rtfind(from);
488 if (rt)
489 rt->rt_timer = 0;
490 else
491 addrouteforif(ifp);
492 return;
493 }
494 size -= 4 * sizeof (char);
495 n = msg->rip_nets;
496 for (; size > 0; size -= sizeof (struct netinfo), n++) {
497 if (size < sizeof (struct netinfo))
498 break;
499 if (n->rip_metric >= HOPCNT_INFINITY)
500 continue;
501 tprintf("dst %x hc %d...",
502 ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
503 n->rip_metric);
504 rt = rtlookup(&n->rip_dst);
505 if (rt == 0) {
506 rtadd(&n->rip_dst, from, n->rip_metric, 0);
507 tprintf("new\n");
508 continue;
509 }
510 tprintf("ours: gate %x hc %d timer %d\n",
511 ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
512 rt->rt_metric, rt->rt_timer);
513 /*
514 * update if from gateway, shorter, or getting stale
515 * and equivalent.
516 */
517 if (equal(from, &rt->rt_router) ||
518 n->rip_metric < rt->rt_metric ||
519 (rt->rt_timer > (EXPIRE_TIME/2) &&
520 rt->rt_metric == n->rip_metric)) {
521 rtchange(rt, from, n->rip_metric);
522 rt->rt_timer = 0;
523 }
524 }
525 return;
526 }
3cec0c76
SL
527}
528
7c0bf99b
SL
529struct rt_entry *
530rtlookup(dst)
531 struct sockaddr *dst;
532{
533 register struct rt_entry *rt;
3cec0c76 534 register struct rthash *rh;
eae14a37 535 register int hash;
7c0bf99b 536 struct afhash h;
eae14a37
SL
537 int doinghost = 1;
538
539 if (dst->sa_family >= AF_MAX)
540 return (0);
541 (*afswitch[dst->sa_family].af_hash)(dst, &h);
542 hash = h.afh_hosthash;
543 rh = &hosthash[hash % ROUTEHASHSIZ];
544again:
545 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
546 if (rt->rt_hash != hash)
547 continue;
548 if (equal(&rt->rt_dst, dst))
549 return (rt);
550 }
551 if (doinghost) {
552 doinghost = 0;
553 hash = h.afh_nethash;
554 rh = &nethash[hash % ROUTEHASHSIZ];
555 goto again;
556 }
557 return (0);
558}
559
eae14a37
SL
560struct rt_entry *
561rtfind(dst)
562 struct sockaddr *dst;
563{
564 register struct rt_entry *rt;
565 register struct rthash *rh;
566 register int hash;
567 struct afhash h;
568 int af = dst->sa_family;
569 int doinghost = 1, (*match)();
7c0bf99b
SL
570
571 if (af >= AF_MAX)
572 return (0);
573 (*afswitch[af].af_hash)(dst, &h);
574 hash = h.afh_hosthash;
575 rh = &hosthash[hash % ROUTEHASHSIZ];
576
577again:
578 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
579 if (rt->rt_hash != hash)
580 continue;
581 if (doinghost) {
582 if (equal(&rt->rt_dst, dst))
583 return (rt);
584 } else {
585 if (rt->rt_dst.sa_family == af &&
586 (*match)(&rt->rt_dst, dst))
587 return (rt);
588 }
589 }
590 if (doinghost) {
591 doinghost = 0;
592 hash = h.afh_nethash;
7c0bf99b 593 rh = &nethash[hash % ROUTEHASHSIZ];
eae14a37 594 match = afswitch[af].af_netmatch;
7c0bf99b
SL
595 goto again;
596 }
597 return (0);
598}
599
6db0b3a4 600rtadd(dst, gate, metric, iflags)
7c0bf99b 601 struct sockaddr *dst, *gate;
6db0b3a4 602 int metric, iflags;
7c0bf99b
SL
603{
604 struct afhash h;
605 register struct rt_entry *rt;
3cec0c76 606 struct rthash *rh;
7c0bf99b
SL
607 int af = dst->sa_family, flags, hash;
608
609 if (af >= AF_MAX)
610 return;
611 (*afswitch[af].af_hash)(dst, &h);
612 flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0;
613 if (flags & RTF_HOST) {
614 hash = h.afh_hosthash;
615 rh = &hosthash[hash % ROUTEHASHSIZ];
616 } else {
617 hash = h.afh_nethash;
618 rh = &nethash[hash % ROUTEHASHSIZ];
619 }
620 rt = (struct rt_entry *)malloc(sizeof (*rt));
621 if (rt == 0)
622 return;
623 rt->rt_hash = hash;
624 rt->rt_dst = *dst;
74d7f201 625 rt->rt_router = *gate;
7c0bf99b
SL
626 rt->rt_metric = metric;
627 rt->rt_timer = 0;
6db0b3a4 628 rt->rt_flags = RTF_UP | flags | iflags;
e6b5ed24 629 rt->rt_state = 0;
74d7f201
BJ
630 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
631 if (metric)
632 rt->rt_flags |= RTF_GATEWAY;
7c0bf99b 633 insque(rt, rh);
77df73ca 634 log("add", rt);
74d7f201 635 if (install)
e6b5ed24 636 rt->rt_state |= RTS_ADDRT;
7c0bf99b
SL
637}
638
7c0bf99b
SL
639rtchange(rt, gate, metric)
640 struct rt_entry *rt;
641 struct sockaddr *gate;
642 short metric;
643{
644 int change = 0;
645
74d7f201
BJ
646 if (!equal(&rt->rt_router, gate)) {
647 rt->rt_newrouter = *gate;
7c0bf99b
SL
648 change++;
649 }
7c0bf99b 650 if (metric != rt->rt_metric) {
74d7f201
BJ
651 if (metric == 0)
652 rt->rt_flags |= RTF_GATEWAY;
7c0bf99b 653 rt->rt_metric = metric;
7c0bf99b
SL
654 change++;
655 }
7c0bf99b
SL
656 if (!change)
657 return;
77df73ca 658 log("change", rt);
74d7f201 659 if (install)
e6b5ed24 660 rt->rt_state |= RTS_CHGRT;
7c0bf99b
SL
661}
662
7c0bf99b
SL
663rtdelete(rt)
664 struct rt_entry *rt;
665{
6db0b3a4 666
77df73ca 667 log("delete", rt);
74d7f201
BJ
668 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
669 perror("SIOCDELRT");
670 /* don't delete interface entries so we can poll them later */
671 if (rt->rt_state & RTS_INTERFACE)
672 return;
7c0bf99b
SL
673 remque(rt);
674 free((char *)rt);
675}
676
7c0bf99b
SL
677log(operation, rt)
678 char *operation;
679 struct rt_entry *rt;
680{
681 time_t t = time(0);
682 struct sockaddr_in *dst, *gate;
e6b5ed24 683 static struct bits {
7c0bf99b
SL
684 int t_bits;
685 char *t_name;
e6b5ed24 686 } flagbits[] = {
7c0bf99b 687 { RTF_UP, "UP" },
74d7f201 688 { RTF_GATEWAY, "GATEWAY" },
7c0bf99b 689 { RTF_HOST, "HOST" },
e6b5ed24
SL
690 { 0 }
691 }, statebits[] = {
692 { RTS_DELRT, "DELETE" },
693 { RTS_CHGRT, "CHANGE" },
74d7f201
BJ
694 { RTS_PASSIVE, "PASSIVE" },
695 { RTS_INTERFACE,"INTERFACE" },
6db0b3a4 696 { RTS_GLOBAL, "GLOBAL" },
7c0bf99b
SL
697 { 0 }
698 };
e6b5ed24 699 register struct bits *p;
7c0bf99b
SL
700 register int first;
701 char *cp;
702
77df73ca
SL
703 if (trace == 0)
704 return;
7c0bf99b
SL
705 printf("%s ", operation);
706 dst = (struct sockaddr_in *)&rt->rt_dst;
74d7f201 707 gate = (struct sockaddr_in *)&rt->rt_router;
e6b5ed24 708 printf("dst %x, router %x, metric %d, flags",
7c0bf99b 709 dst->sin_addr, gate->sin_addr, rt->rt_metric);
e6b5ed24
SL
710 cp = " %s";
711 for (first = 1, p = flagbits; p->t_bits > 0; p++) {
7c0bf99b
SL
712 if ((rt->rt_flags & p->t_bits) == 0)
713 continue;
714 printf(cp, p->t_name);
715 if (first) {
716 cp = "|%s";
717 first = 0;
718 }
719 }
e6b5ed24
SL
720 printf(" state");
721 cp = " %s";
722 for (first = 1, p = statebits; p->t_bits > 0; p++) {
723 if ((rt->rt_state & p->t_bits) == 0)
724 continue;
725 printf(cp, p->t_name);
726 if (first) {
727 cp = "|%s";
728 first = 0;
729 }
730 }
7c0bf99b
SL
731 putchar('\n');
732}
77df73ca
SL
733
734struct ifnet *
735if_ifwithaddr(addr)
736 struct sockaddr *addr;
737{
738 register struct ifnet *ifp;
739
740#define same(a1, a2) \
741 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
742 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
743 if (ifp->if_addr.sa_family != addr->sa_family)
744 continue;
745 if (same(&ifp->if_addr, addr))
746 break;
747 if ((ifp->if_flags & IFF_BROADCAST) &&
748 same(&ifp->if_broadaddr, addr))
749 break;
750 }
751 return (ifp);
752#undef same
753}
754
755struct ifnet *
756if_ifwithnet(addr)
757 register struct sockaddr *addr;
758{
759 register struct ifnet *ifp;
760 register int af = addr->sa_family;
761 register int (*netmatch)();
762
763 if (af >= AF_MAX)
764 return (0);
765 netmatch = afswitch[af].af_netmatch;
766 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
767 if (af != ifp->if_addr.sa_family)
768 continue;
769 if ((*netmatch)(addr, &ifp->if_addr))
770 break;
771 }
772 return (ifp);
773}
774
775struct in_addr
776if_makeaddr(net, host)
777 int net, host;
778{
779 u_long addr;
780
781 if (net < 128)
782 addr = (net << 24) | host;
783 else if (net < 65536)
784 addr = (net << 16) | host;
785 else
786 addr = (net << 8) | host;
787#ifdef vax
788 addr = htonl(addr);
789#endif
790 return (*(struct in_addr *)&addr);
791}