1 #ifndef lint 2 static char sccsid[] = "@(#)routed.c 4.25 10/08/82"; 3 #endif 4 5 /* 6 * Routing Table Management Daemon 7 */ 8 #include <sys/types.h> 9 #include <sys/ioctl.h> 10 #include <sys/socket.h> 11 #include <net/in.h> 12 #include <net/if.h> 13 #include <errno.h> 14 #include <stdio.h> 15 #include <nlist.h> 16 #include <signal.h> 17 #include <time.h> 18 #include <netdb.h> 19 #define RIPCMDS 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) 29 #define min(a,b) ((a)>(b)?(b):(a)) 30 31 struct nlist nl[] = { 32 #define N_IFNET 0 33 { "_ifnet" }, 34 0, 35 }; 36 37 struct sockaddr_in routingaddr = { AF_INET }; 38 struct sockaddr_in noroutingaddr = { AF_INET }; 39 40 int s; 41 int snoroute; /* socket with no routing */ 42 int kmem = -1; 43 int supplier = -1; /* process should supply updates */ 44 int install = 1; /* if 1 call kernel */ 45 int lookforinterfaces = 1; 46 int performnlist = 1; 47 int externalinterfaces = 0; /* # of remote and local interfaces */ 48 int timeval = -TIMER_RATE; 49 int timer(); 50 int cleanup(); 51 52 #define tprintf if (trace) printf 53 int trace = 0; 54 FILE *ftrace; 55 56 char packet[MAXPACKETSIZE+1]; 57 struct rip *msg = (struct rip *)packet; 58 59 struct in_addr inet_makeaddr(); 60 struct interface *if_ifwithaddr(), *if_ifwithnet(); 61 extern char *malloc(), *sys_errlist[]; 62 extern int errno, exit(); 63 char **argv0; 64 65 int sendmsg(), supply(); 66 67 main(argc, argv) 68 int argc; 69 char *argv[]; 70 { 71 int cc; 72 struct sockaddr from; 73 struct servent *sp; 74 75 argv0 = argv; 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 } 89 } 90 #endif 91 if (trace) { 92 ftrace = fopen("/etc/routerlog", "w"); 93 dup2(fileno(ftrace), 1); 94 dup2(fileno(ftrace), 2); 95 } 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 */ 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); 115 again: 116 s = socket(SOCK_DGRAM, 0, &routingaddr, 0); 117 if (s < 0) { 118 perror("socket"); 119 sleep(30); 120 goto again; 121 } 122 again2: 123 snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE); 124 if (snoroute < 0) { 125 perror("socket"); 126 sleep(30); 127 goto again2; 128 } 129 argv++, argc--; 130 while (argc > 0 && **argv == '-') { 131 if (!strcmp(*argv, "-s") == 0) { 132 supplier = 1; 133 argv++, argc--; 134 continue; 135 } 136 if (!strcmp(*argv, "-q") == 0) { 137 supplier = 0; 138 argv++, argc--; 139 continue; 140 } 141 goto usage; 142 } 143 if (argc > 0) { 144 usage: 145 fprintf(stderr, "usage: routed [ -sq ]\n"); 146 exit(1); 147 } 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 */ 155 rtinit(); 156 gwkludge(); 157 ifinit(); 158 if (supplier < 0) 159 supplier = 0; 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); 164 sigset(SIGALRM, timer); 165 timer(); 166 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 180 rtinit() 181 { 182 register struct rthash *rh; 183 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; 188 } 189 190 struct interface *ifnet; 191 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 */ 199 ifinit() 200 { 201 struct interface *ifp; 202 struct ifnet ifs, *next; 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; 211 } 212 if (kmem < 0) { 213 kmem = open("/dev/kmem", 0); 214 if (kmem < 0) { 215 perror("/dev/kmem"); 216 goto bad; 217 } 218 } 219 if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 220 read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { 221 printf("ifnet: error reading kmem\n"); 222 goto bad; 223 } 224 lookforinterfaces = 0; 225 while (next) { 226 if (lseek(kmem, (long)next, 0) == -1 || 227 read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) { 228 perror("read"); 229 goto bad; 230 } 231 next = ifs.if_next; 232 if ((ifs.if_flags & IFF_UP) == 0) { 233 lookforinterfaces = 1; 234 continue; 235 } 236 /* already known to us? */ 237 if (if_ifwithaddr(&ifs.if_addr)) 238 continue; 239 /* argh, this'll have to change sometime */ 240 if (ifs.if_addr.sa_family != AF_INET) 241 continue; 242 /* no one cares about software loopback interfaces */ 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 254 * decide if we should be a routing ``supplier''. 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; 266 ifnet = ifp; 267 addrouteforif(ifp); 268 } 269 if (externalinterfaces > 1 && supplier < 0) 270 supplier = 1; 271 return; 272 bad: 273 sleep(60); 274 close(kmem), close(s), close(snoroute); 275 execv("/etc/routed", argv0); 276 _exit(0177); 277 } 278 279 addrouteforif(ifp) 280 struct interface *ifp; 281 { 282 struct sockaddr_in net; 283 struct sockaddr *dst; 284 int state, metric; 285 struct rt_entry *rt; 286 287 if (ifp->int_flags & IFF_POINTOPOINT) 288 dst = &ifp->int_dstaddr; 289 else { 290 bzero((char *)&net, sizeof (net)); 291 net.sin_family = AF_INET; 292 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); 293 dst = (struct sockaddr *)&net; 294 } 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); 300 } 301 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 */ 315 gwkludge() 316 { 317 struct sockaddr_in dst, gate; 318 FILE *fp; 319 char *type, *dname, *gname, *qual, buf[BUFSIZ]; 320 struct interface *ifp; 321 int metric; 322 323 fp = fopen("/etc/gateways", "r"); 324 if (fp == NULL) 325 return; 326 qual = buf; 327 dname = buf + 64; 328 gname = buf + ((BUFSIZ - 64) / 3); 329 type = buf + (((BUFSIZ - 64) * 2) / 3); 330 bzero((char *)&dst, sizeof (dst)); 331 bzero((char *)&gate, sizeof (gate)); 332 dst.sin_family = gate.sin_family = AF_INET; 333 /* format: {net | host} XX gateway XX metric DD [passive]\n */ 334 #define readentry(fp) \ 335 fscanf((fp), "%s %s gateway %s metric %d %s\n", \ 336 type, dname, gname, &metric, qual) 337 for (;;) { 338 struct hostent *host; 339 struct netent *net; 340 341 if (readentry(fp) == EOF) 342 break; 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 354 continue; 355 host = gethostbyname(gname); 356 if (host == 0) 357 continue; 358 bcopy(host->h_addr, &gate.sin_addr, host->h_length); 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 */ 363 ifp->int_net = inet_netof(dst.sin_addr); 364 if (strcmp(type, "host") == 0) { 365 ifp->int_flags |= IFF_POINTOPOINT; 366 ifp->int_dstaddr = *((struct sockaddr *)&dst); 367 } 368 if (strcmp(qual, "passive") == 0) 369 ifp->int_flags |= IFF_PASSIVE; 370 else 371 /* assume no duplicate entries */ 372 externalinterfaces++; 373 ifp->int_addr = *((struct sockaddr *)&gate); 374 ifp->int_metric = metric; 375 ifp->int_next = ifnet; 376 ifnet = ifp; 377 addrouteforif(ifp); 378 } 379 fclose(fp); 380 } 381 382 /* 383 * Timer routine. Performs routing information supply 384 * duties and manages timers on routing table entries. 385 */ 386 timer() 387 { 388 register struct rthash *rh; 389 register struct rt_entry *rt; 390 struct rthash *base = hosthash; 391 int doinghost = 1, timetobroadcast; 392 393 timeval += TIMER_RATE; 394 if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0) 395 ifinit(); 396 timetobroadcast = supplier && (timeval % SUPPLY_INTERVAL) == 0; 397 tprintf(">>> time %d >>>\n", timeval); 398 again: 399 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 400 rt = rh->rt_forw; 401 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 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))) 414 rt->rt_timer += TIMER_RATE; 415 if (rt->rt_timer >= EXPIRE_TIME) 416 rt->rt_metric = HOPCNT_INFINITY; 417 log("", rt); 418 if (rt->rt_timer >= GARBAGE_TIME) { 419 rt = rt->rt_back; 420 rtdelete(rt->rt_forw); 421 continue; 422 } 423 if (rt->rt_state & RTS_CHANGED) { 424 rt->rt_state &= ~RTS_CHANGED; 425 /* don't send extraneous packets */ 426 if (!supplier || timetobroadcast) 427 continue; 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); 433 toall(sendmsg); 434 } 435 } 436 } 437 if (doinghost) { 438 doinghost = 0; 439 base = nethash; 440 goto again; 441 } 442 if (timetobroadcast) 443 toall(supply); 444 tprintf("<<< time %d <<<\n", timeval); 445 alarm(TIMER_RATE); 446 } 447 448 toall(f) 449 int (*f)(); 450 { 451 register struct interface *ifp; 452 register struct sockaddr *dst; 453 454 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 455 if (ifp->int_flags & IFF_PASSIVE) 456 continue; 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); 461 } 462 } 463 464 /*ARGSUSED*/ 465 sendmsg(dst, dontroute) 466 struct sockaddr *dst; 467 int dontroute; 468 { 469 (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip)); 470 } 471 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 */ 476 supply(dst, dontroute) 477 struct sockaddr *dst; 478 int dontroute; 479 { 480 register struct rt_entry *rt; 481 struct netinfo *n = msg->rip_nets; 482 register struct rthash *rh; 483 struct rthash *base = hosthash; 484 int doinghost = 1, size; 485 int (*output)() = afswitch[dst->sa_family].af_output; 486 int sto = dontroute ? snoroute : s; 487 488 msg->rip_cmd = RIPCMD_RESPONSE; 489 again: 490 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 491 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 492 size = (char *)n - packet; 493 if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 494 (*output)(sto, dst, size); 495 n = msg->rip_nets; 496 } 497 n->rip_dst = rt->rt_dst; 498 n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 499 n++; 500 } 501 if (doinghost) { 502 doinghost = 0; 503 base = nethash; 504 goto again; 505 } 506 if (n != msg->rip_nets) 507 (*output)(sto, dst, (char *)n - packet); 508 } 509 510 /* 511 * Handle an incoming routing packet. 512 */ 513 rip_input(from, size) 514 struct sockaddr *from; 515 int size; 516 { 517 struct rt_entry *rt; 518 struct netinfo *n; 519 struct interface *ifp; 520 time_t t; 521 int newsize; 522 struct afswitch *afp; 523 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) 533 return; 534 afp = &afswitch[from->sa_family]; 535 switch (msg->rip_cmd) { 536 537 case RIPCMD_REQUEST: 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) { 552 supply(from, 0); 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 } 565 return; 566 567 case RIPCMD_TRACEON: 568 if ((*afp->af_portcheck)(from) == 0) 569 return; 570 if (trace) 571 return; 572 packet[size] = '\0'; 573 ftrace = fopen(msg->rip_tracefile, "a"); 574 if (ftrace == NULL) 575 return; 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)); 581 return; 582 583 case RIPCMD_TRACEOFF: 584 /* verify message came from a priviledged port */ 585 if ((*afp->af_portcheck)(from) == 0) 586 return; 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; 597 598 case RIPCMD_RESPONSE: 599 /* verify message came from a router */ 600 if ((*afp->af_portmatch)(from) == 0) 601 return; 602 (*afp->af_canon)(from); 603 /* are we talking to ourselves? */ 604 ifp = if_ifwithaddr(from); 605 if (ifp) { 606 rt = rtfind(from); 607 if (rt == 0) 608 addrouteforif(ifp); 609 else 610 rt->rt_timer = 0; 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); 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); 631 632 /* 633 * Update if from gateway, shorter, or getting 634 * stale and equivalent. 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 } 646 tprintf("bad packet, cmd=%x\n", msg->rip_cmd); 647 } 648 649 /* 650 * Lookup dst in the tables for an exact match. 651 */ 652 struct rt_entry * 653 rtlookup(dst) 654 struct sockaddr *dst; 655 { 656 register struct rt_entry *rt; 657 register struct rthash *rh; 658 register int hash; 659 struct afhash h; 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]; 667 again: 668 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 669 if (rt->rt_hash != hash) 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 683 /* 684 * Find a route to dst as the kernel would. 685 */ 686 struct rt_entry * 687 rtfind(dst) 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)(); 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 703 again: 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; 719 rh = &nethash[hash % ROUTEHASHSIZ]; 720 match = afswitch[af].af_netmatch; 721 goto again; 722 } 723 return (0); 724 } 725 726 rtadd(dst, gate, metric, state) 727 struct sockaddr *dst, *gate; 728 int metric, state; 729 { 730 struct afhash h; 731 register struct rt_entry *rt; 732 struct rthash *rh; 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; 751 rt->rt_router = *gate; 752 rt->rt_metric = metric; 753 rt->rt_timer = 0; 754 rt->rt_flags = RTF_UP | flags; 755 rt->rt_state = state | RTS_CHANGED; 756 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 757 if (metric) 758 rt->rt_flags |= RTF_GATEWAY; 759 insque(rt, rh); 760 log("add", rt); 761 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 762 tprintf("SIOCADDRT: %s\n", sys_errlist[errno]); 763 } 764 765 rtchange(rt, gate, metric) 766 struct rt_entry *rt; 767 struct sockaddr *gate; 768 short metric; 769 { 770 int doioctl = 0, metricchanged = 0; 771 struct rtentry oldroute; 772 773 if (!equal(&rt->rt_router, gate)) 774 doioctl++; 775 if (metric != rt->rt_metric) { 776 metricchanged++; 777 rt->rt_metric = metric; 778 } 779 if (doioctl || metricchanged) { 780 log("change", rt); 781 rt->rt_state |= RTS_CHANGED; 782 } 783 if (doioctl) { 784 oldroute = rt->rt_rt; 785 rt->rt_router = *gate; 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 } 792 } 793 } 794 795 rtdelete(rt) 796 struct rt_entry *rt; 797 { 798 log("delete", rt); 799 if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 800 tprintf("SIOCDELRT: %s\n", sys_errlist[errno]); 801 remque(rt); 802 free((char *)rt); 803 } 804 805 log(operation, rt) 806 char *operation; 807 struct rt_entry *rt; 808 { 809 struct sockaddr_in *dst, *gate; 810 static struct bits { 811 int t_bits; 812 char *t_name; 813 } flagbits[] = { 814 { RTF_UP, "UP" }, 815 { RTF_GATEWAY, "GATEWAY" }, 816 { RTF_HOST, "HOST" }, 817 { 0 } 818 }, statebits[] = { 819 { RTS_PASSIVE, "PASSIVE" }, 820 { RTS_REMOTE, "REMOTE" }, 821 { RTS_INTERFACE,"INTERFACE" }, 822 { RTS_CHANGED, "CHANGED" }, 823 { 0 } 824 }; 825 register struct bits *p; 826 register int first; 827 char *cp; 828 829 if (trace == 0) 830 return; 831 printf("%s ", operation); 832 dst = (struct sockaddr_in *)&rt->rt_dst; 833 gate = (struct sockaddr_in *)&rt->rt_router; 834 printf("dst %x, router %x, metric %d, flags", dst->sin_addr, 835 gate->sin_addr, rt->rt_metric); 836 cp = " %s"; 837 for (first = 1, p = flagbits; p->t_bits > 0; p++) { 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 } 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 } 857 putchar('\n'); 858 } 859 860 struct interface * 861 if_ifwithaddr(addr) 862 struct sockaddr *addr; 863 { 864 register struct interface *ifp; 865 866 #define same(a1, a2) \ 867 (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 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) 872 continue; 873 if (same(&ifp->int_addr, addr)) 874 break; 875 if ((ifp->int_flags & IFF_BROADCAST) && 876 same(&ifp->int_broadaddr, addr)) 877 break; 878 } 879 return (ifp); 880 #undef same 881 } 882 883 struct interface * 884 if_ifwithnet(addr) 885 register struct sockaddr *addr; 886 { 887 register struct interface *ifp; 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; 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) 898 continue; 899 if ((*netmatch)(addr, &ifp->int_addr)) 900 break; 901 } 902 return (ifp); 903 } 904