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