16920Ssam #ifndef lint 2*7139Ssam static char sccsid[] = "@(#)routed.c 4.15 82/06/09"; 36920Ssam #endif 46920Ssam 56934Ssam /* 66934Ssam * Routing Table Management Daemon 76934Ssam */ 86934Ssam #include <sys/types.h> 96920Ssam #include <sys/ioctl.h> 106920Ssam #include <sys/socket.h> 116920Ssam #include <net/in.h> 126920Ssam #include <net/if.h> 136920Ssam #include <errno.h> 146920Ssam #include <stdio.h> 156920Ssam #include <nlist.h> 166920Ssam #include <signal.h> 177029Ssam #include <time.h> 18*7139Ssam #define RIPCMDS 196920Ssam #include "rip.h" 206920Ssam #include "router.h" 216920Ssam 226920Ssam #define LOOPBACKNET 0177 236920Ssam /* casts to keep lint happy */ 246920Ssam #define insque(q,p) _insque((caddr_t)q,(caddr_t)p) 256920Ssam #define remque(q) _remque((caddr_t)q) 266920Ssam #define equal(a1, a2) \ 276920Ssam (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 286929Ssam #define min(a,b) ((a)>(b)?(b):(a)) 296920Ssam 306920Ssam struct nlist nl[] = { 316920Ssam #define N_IFNET 0 326920Ssam { "_ifnet" }, 336920Ssam 0, 346920Ssam }; 356920Ssam 36*7139Ssam struct sockaddr_in routingaddr = { AF_INET, IPPORT_ROUTESERVER }; 37*7139Ssam struct sockaddr_in noroutingaddr = { AF_INET, IPPORT_ROUTESERVER+1 }; 386920Ssam 396920Ssam int s; 407130Swnj int snoroute; /* socket with no routing */ 416929Ssam int kmem = -1; 427133Swnj int supplier = -1; /* process should supply updates */ 436962Ssam int install = 1; /* if 1 call kernel */ 447133Swnj int timeval = -TIMER_RATE; 456920Ssam int timer(); 466920Ssam int cleanup(); 477133Swnj 487133Swnj #define tprintf if (trace) printf 496920Ssam int trace = 0; 507029Ssam FILE *ftrace; 516920Ssam 527133Swnj char packet[MAXPACKETSIZE+1]; 537133Swnj struct rip *msg = (struct rip *)packet; 546920Ssam 556934Ssam struct in_addr if_makeaddr(); 566934Ssam struct ifnet *if_ifwithaddr(), *if_ifwithnet(); 576920Ssam extern char *malloc(); 586922Ssam extern int errno, exit(); 597133Swnj char **argv0; 606920Ssam 61*7139Ssam int sendmsg(), supply(); 627133Swnj 636920Ssam main(argc, argv) 646920Ssam int argc; 656920Ssam char *argv[]; 666920Ssam { 676920Ssam int cc; 686920Ssam struct sockaddr from; 696920Ssam 707133Swnj argv0 = argv; 717029Ssam #ifndef DEBUG 727029Ssam if (fork()) 737029Ssam exit(0); 747029Ssam for (cc = 0; cc < 10; cc++) 757029Ssam (void) close(cc); 767029Ssam (void) open("/", 0); 777029Ssam (void) dup2(0, 1); 787029Ssam (void) dup2(0, 2); 797029Ssam { int t = open("/dev/tty", 2); 807029Ssam if (t >= 0) { 817029Ssam ioctl(t, TIOCNOTTY, (char *)0); 827029Ssam (void) close(t); 837029Ssam } 846920Ssam } 857029Ssam #endif 866920Ssam if (trace) { 877029Ssam ftrace = fopen("/etc/routerlog", "w"); 887029Ssam dup2(fileno(ftrace), 1); 897029Ssam dup2(fileno(ftrace), 2); 906920Ssam } 916937Ssam #ifdef vax || pdp11 92*7139Ssam routingaddr.sin_port = htons(routingaddr.sin_port); 93*7139Ssam noroutingaddr.sin_port = htons(noroutingaddr.sin_port); 946920Ssam #endif 956920Ssam again: 96*7139Ssam s = socket(SOCK_DGRAM, 0, &routingaddr, 0); 976920Ssam if (s < 0) { 986920Ssam perror("socket"); 996920Ssam sleep(30); 1006920Ssam goto again; 1016920Ssam } 1027130Swnj again2: 103*7139Ssam snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE); 1047130Swnj if (snoroute < 0) { 1057130Swnj perror("socket"); 1067130Swnj sleep(30); 1077130Swnj goto again2; 1087130Swnj } 1096920Ssam argv++, argc--; 1107133Swnj while (argc > 0 && **argv == '-') { 1117133Swnj if (!strcmp(*argv, "-s") == 0) { 1126929Ssam supplier = 1; 1137133Swnj argv++, argc--; 1147133Swnj continue; 1157133Swnj } 1167133Swnj if (!strcmp(*argv, "-q") == 0) { 1176920Ssam supplier = 0; 1187133Swnj argv++, argc--; 1197133Swnj continue; 1207133Swnj } 1217133Swnj goto usage; 1226920Ssam } 1237133Swnj if (argc > 0) { 1247133Swnj usage: 1257133Swnj fprintf(stderr, "usage: routed [ -s ]\n"); 1267133Swnj exit(1); 1277133Swnj } 1287133Swnj rtinit(); 1297133Swnj ifinit(); 1307133Swnj if (supplier < 0) 1317133Swnj supplier = 0; 1327133Swnj gwkludge(); 1337133Swnj msg->rip_cmd = RIPCMD_REQUEST; 1347133Swnj msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 1357133Swnj msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 1367133Swnj toall(sendmsg); 1376920Ssam sigset(SIGALRM, timer); 1386929Ssam timer(); 1396920Ssam 1406920Ssam for (;;) { 1416920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1426920Ssam if (cc <= 0) { 1436920Ssam if (cc < 0 && errno != EINTR) 1446920Ssam perror("receive"); 1456920Ssam continue; 1466920Ssam } 1476920Ssam sighold(SIGALRM); 1486920Ssam rip_input(&from, cc); 1496920Ssam sigrelse(SIGALRM); 1506920Ssam } 1516920Ssam } 1526920Ssam 1537133Swnj rtinit() 1546920Ssam { 1556934Ssam register struct rthash *rh; 1566920Ssam 1577133Swnj for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 1587133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1597133Swnj for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 1607133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1616920Ssam } 1626920Ssam 1636934Ssam struct ifnet *ifnet; 1647133Swnj 1657133Swnj ifinit() 1666920Ssam { 1677133Swnj struct ifnet *ifp, *next; 1687133Swnj int uniquemultihostinterfaces = 0; 1696920Ssam 1707133Swnj nlist("/vmunix", nl); 1717133Swnj if (nl[N_IFNET].n_value == 0) { 1727133Swnj printf("ifnet: not in namelist\n"); 1737133Swnj goto bad; 1746920Ssam } 1757133Swnj kmem = open("/dev/kmem", 0); 1766920Ssam if (kmem < 0) { 1777133Swnj perror("/dev/kmem"); 1787133Swnj goto bad; 1796920Ssam } 1806929Ssam if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 1817133Swnj read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { 1827133Swnj printf("ifnet: error reading kmem\n"); 1837133Swnj goto bad; 1846929Ssam } 1857133Swnj while (next) { 1867133Swnj ifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 1877133Swnj if (ifp == 0) { 1887133Swnj printf("routed: out of memory\n"); 1896920Ssam break; 1906920Ssam } 1917133Swnj if (lseek(kmem, (long)next, 0) == -1 || 1927133Swnj read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) { 1937133Swnj perror("read"); 1947133Swnj goto bad; 1956929Ssam } 1967133Swnj next = ifp->if_next; 1976929Ssam if (ifp->if_addr.sa_family != AF_INET) 1987133Swnj continue; 1996920Ssam if (ifp->if_net == LOOPBACKNET) 2007133Swnj continue; 2016929Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0 || 2026929Ssam if_ifwithaddr(&ifp->if_dstaddr) == 0) 2037133Swnj uniquemultihostinterfaces++; 2046929Ssam ifp->if_next = ifnet; 2056929Ssam ifnet = ifp; 2067133Swnj addrouteforif(ifp); 2077133Swnj } 2087133Swnj if (uniquemultihostinterfaces > 1 && supplier < 0) 2097133Swnj supplier = 1; 2107133Swnj return; 2117133Swnj bad: 2127133Swnj sleep(60); 2137133Swnj execv("/etc/routed", argv0); 2147133Swnj _exit(0177); 2157133Swnj } 2167130Swnj 2177133Swnj addrouteforif(ifp) 2187133Swnj struct ifnet *ifp; 2197133Swnj { 2207133Swnj struct sockaddr_in net; 2217133Swnj struct sockaddr *dst; 2227133Swnj 2237133Swnj if (ifp->if_flags & IFF_POINTOPOINT) 2247133Swnj dst = &ifp->if_dstaddr; 2257133Swnj else { 2267133Swnj bzero((char *)&net, sizeof (net)); 2277133Swnj net.sin_family = AF_INET; 2287133Swnj net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 2297133Swnj dst = (struct sockaddr *)&net; 2306920Ssam } 231*7139Ssam rtadd(dst, &ifp->if_addr, 0, RTS_DONTDELETE|RTS_DONTROUTE); 2326920Ssam } 2336920Ssam 2347133Swnj gwkludge() 2357130Swnj { 2367130Swnj struct sockaddr_in dst, gate; 2377130Swnj FILE *fp; 238*7139Ssam char buf[BUFSIZ]; 2397130Swnj 2407130Swnj fp = fopen("/etc/gateways", "r"); 2417130Swnj if (fp == NULL) 2427130Swnj return; 2437130Swnj bzero((char *)&dst, sizeof (dst)); 2447130Swnj bzero((char *)&gate, sizeof (gate)); 2457130Swnj dst.sin_family = AF_INET; 2467130Swnj gate.sin_family = AF_INET; 2477133Swnj for (;;) { 248*7139Ssam buf[0] = '\0'; 249*7139Ssam /* format is: dst XX gateway XX [passive]\n */ 250*7139Ssam if (fscanf(fp, "dst %x gateway %x %s\n", &dst.sin_addr.s_addr, 251*7139Ssam &gate.sin_addr.s_addr, buf) == EOF) 2527133Swnj break; 2537133Swnj rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1, 254*7139Ssam strcmp(buf, "passive") == 0 ? RTS_PASSIVE : RTS_DONTDELETE); 2557130Swnj } 2567130Swnj fclose(fp); 2577130Swnj } 2587130Swnj 2597133Swnj timer() 2606920Ssam { 2616934Ssam register struct rthash *rh; 2626920Ssam register struct rt_entry *rt; 2636934Ssam struct rthash *base = hosthash; 2647133Swnj int doinghost = 1, state; 2656920Ssam 2667133Swnj timeval += TIMER_RATE; 2677133Swnj tprintf(">>> time %d >>>\n", timeval); 2686920Ssam again: 2697133Swnj for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 2707133Swnj rt = rh->rt_forw; 2717133Swnj for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 272*7139Ssam if (!(rt->rt_state & RTS_PASSIVE)) { 2737133Swnj rt->rt_timer += TIMER_RATE; 274*7139Ssam if (rt->rt_timer > 9999) 275*7139Ssam rt->rt_timer = 9999; 276*7139Ssam } 2777133Swnj log("", rt); 278*7139Ssam if (rt->rt_state & RTS_HIDDEN) 279*7139Ssam continue; 2807133Swnj if (rt->rt_timer >= EXPIRE_TIME) 2817133Swnj rt->rt_metric = HOPCNT_INFINITY; 2827133Swnj if ((rt->rt_state & RTS_DELRT) || 2837133Swnj rt->rt_timer >= GARBAGE_TIME) { 2847133Swnj rt = rt->rt_back; 2857133Swnj rtdelete(rt->rt_forw); 2867133Swnj continue; 2877133Swnj } 2887133Swnj state = rt->rt_state; 2897133Swnj if (rt->rt_state & RTS_ADDRT) { 2907133Swnj if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) 2917133Swnj perror("SIOCADDRT"); 2927133Swnj rt->rt_state &= ~RTS_ADDRT; 2937133Swnj } 2947133Swnj if (rt->rt_state & RTS_CHGRT) { 2957133Swnj struct rtentry oldroute; 2967133Swnj 2977133Swnj oldroute = rt->rt_rt; 298*7139Ssam oldroute.rt_gateway = rt->rt_oldrouter; 299*7139Ssam if (install && 300*7139Ssam ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) 3017133Swnj perror("SIOCADDRT"); 302*7139Ssam if (install && 303*7139Ssam ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 3047133Swnj perror("SIOCDELRT"); 3057133Swnj rt->rt_state &= ~RTS_CHGRT; 3067133Swnj } 3077133Swnj if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) { 3087133Swnj log("broadcast", rt); 3097133Swnj msg->rip_cmd = RIPCMD_RESPONSE; 3107133Swnj msg->rip_nets[0].rip_dst = rt->rt_dst; 3117133Swnj msg->rip_nets[0].rip_metric = 3127133Swnj min(rt->rt_metric+1, HOPCNT_INFINITY); 313*7139Ssam toall(sendmsg); 3147133Swnj } 3157133Swnj } 3166920Ssam } 3176920Ssam if (doinghost) { 3187133Swnj doinghost = 0; 3196929Ssam base = nethash; 3206920Ssam goto again; 3216920Ssam } 3227133Swnj if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 3237133Swnj toall(supply); 3247133Swnj tprintf("<<< time %d <<<\n", timeval); 3257133Swnj alarm(TIMER_RATE); 3266920Ssam } 3276920Ssam 3287133Swnj toall(f) 3297133Swnj int (*f)(); 3306920Ssam { 3317133Swnj register struct rthash *rh; 3326920Ssam register struct rt_entry *rt; 3336920Ssam register struct sockaddr *dst; 3346934Ssam struct rthash *base = hosthash; 3356920Ssam int doinghost = 1; 3366920Ssam 3376920Ssam again: 3386920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3396920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 340*7139Ssam if ((rt->rt_state & RTS_PASSIVE) || rt->rt_metric > 0) 3416920Ssam continue; 3426920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3436920Ssam dst = &rt->rt_ifp->if_broadaddr; 3446920Ssam else 3457130Swnj dst = &rt->rt_router; 346*7139Ssam (*f)(dst, rt->rt_state & RTS_DONTROUTE); 3476920Ssam } 3486920Ssam if (doinghost) { 3496920Ssam base = nethash; 3506920Ssam doinghost = 0; 3516920Ssam goto again; 3526920Ssam } 3536920Ssam } 3546920Ssam 355*7139Ssam /*ARGSUSED*/ 356*7139Ssam sendmsg(dst, dontroute) 3577133Swnj struct sockaddr *dst; 358*7139Ssam int dontroute; 3597133Swnj { 3607133Swnj (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip)); 3617133Swnj } 3627133Swnj 363*7139Ssam supply(dst, dontroute) 364*7139Ssam struct sockaddr *dst; 365*7139Ssam int dontroute; 366*7139Ssam { 3677133Swnj register struct rt_entry *rt; 3686920Ssam struct netinfo *n = msg->rip_nets; 3696934Ssam register struct rthash *rh; 3706934Ssam struct rthash *base = hosthash; 3716929Ssam int doinghost = 1, size; 372*7139Ssam int (*output)() = afswitch[dst->sa_family].af_output; 373*7139Ssam int sto = dontroute ? snoroute : s; 3746920Ssam 3756920Ssam again: 3766920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3776920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 378*7139Ssam if (rt->rt_state & RTS_HIDDEN) 379*7139Ssam continue; 3806929Ssam size = (char *)n - packet; 3816929Ssam if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 382*7139Ssam (*output)(sto, dst, size); 3836920Ssam n = msg->rip_nets; 3846920Ssam } 3856920Ssam n->rip_dst = rt->rt_dst; 3866929Ssam n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 3876929Ssam n++; 3886920Ssam } 3896920Ssam if (doinghost) { 3906920Ssam doinghost = 0; 3916920Ssam base = nethash; 3926920Ssam goto again; 3936920Ssam } 3946929Ssam if (n != msg->rip_nets) 395*7139Ssam (*output)(sto, dst, (char *)n - packet); 3966920Ssam } 3976920Ssam 3986920Ssam /* 3996920Ssam * Handle an incoming routing packet. 4006920Ssam */ 4016920Ssam rip_input(from, size) 4026920Ssam struct sockaddr *from; 4036920Ssam int size; 4046920Ssam { 4056920Ssam struct rt_entry *rt; 4066920Ssam struct netinfo *n; 4077133Swnj struct ifnet *ifp; 4087133Swnj time_t t; 409*7139Ssam int newsize; 410*7139Ssam struct afswitch *afp; 4116920Ssam 412*7139Ssam if (trace) { 413*7139Ssam if (msg->rip_cmd < RIPCMD_MAX) 414*7139Ssam printf("%s from %x\n", ripcmds[msg->rip_cmd], 415*7139Ssam ((struct sockaddr_in *)from)->sin_addr); 416*7139Ssam else 417*7139Ssam printf("%x from %x\n", msg->rip_cmd, 418*7139Ssam ((struct sockaddr_in *)from)->sin_addr); 419*7139Ssam } 420*7139Ssam if (from->sa_family >= AF_MAX) 421*7139Ssam return; 422*7139Ssam afp = &afswitch[from->sa_family]; 4236937Ssam switch (msg->rip_cmd) { 4246937Ssam 425*7139Ssam case RIPCMD_REQUEST: 426*7139Ssam newsize = 0; 427*7139Ssam size -= 4 * sizeof (char); 428*7139Ssam n = msg->rip_nets; 429*7139Ssam while (size > 0) { 430*7139Ssam if (size < sizeof (struct netinfo)) 431*7139Ssam break; 432*7139Ssam size -= sizeof (struct netinfo); 4336920Ssam 434*7139Ssam /* 435*7139Ssam * A single entry with sa_family == AF_UNSPEC and 436*7139Ssam * metric ``infinity'' means ``all routes''. 437*7139Ssam */ 438*7139Ssam if (n->rip_dst.sa_family == AF_UNSPEC && 439*7139Ssam n->rip_metric == HOPCNT_INFINITY && size == 0) { 440*7139Ssam supply(from, 0); /* don't route */ 441*7139Ssam return; 442*7139Ssam } 443*7139Ssam rt = rtlookup(&n->rip_dst); 444*7139Ssam n->rip_metric = rt == 0 ? HOPCNT_INFINITY : 445*7139Ssam min(rt->rt_metric+1, HOPCNT_INFINITY); 446*7139Ssam n++, newsize += sizeof (struct netinfo); 447*7139Ssam } 448*7139Ssam if (newsize > 0) { 449*7139Ssam msg->rip_cmd = RIPCMD_RESPONSE; 450*7139Ssam newsize += sizeof (int); 451*7139Ssam (*afp->af_output)(s, from, newsize); 452*7139Ssam } 4536920Ssam return; 4546937Ssam 4557029Ssam case RIPCMD_TRACEON: 456*7139Ssam if ((*afp->af_portcheck)(from) == 0) 4577029Ssam return; 4587133Swnj if (trace) 4597133Swnj return; 4607133Swnj packet[size] = '\0'; 4617133Swnj ftrace = fopen(msg->rip_tracefile, "a"); 4627133Swnj if (ftrace == NULL) 4637133Swnj return; 4647133Swnj (void) dup2(fileno(ftrace), 1); 4657133Swnj (void) dup2(fileno(ftrace), 2); 4667133Swnj trace = 1; 4677133Swnj t = time(0); 4687133Swnj printf("*** Tracing turned on at %.24s ***\n", ctime(&t)); 4697029Ssam return; 4707029Ssam 4717133Swnj case RIPCMD_TRACEOFF: 4727133Swnj /* verify message came from a priviledged port */ 473*7139Ssam if ((*afp->af_portcheck)(from) == 0) 4746937Ssam return; 4757029Ssam if (!trace) 4767029Ssam return; 4777029Ssam t = time(0); 4787029Ssam printf("*** Tracing turned off at %.24s ***\n", ctime(&t)); 4797029Ssam fflush(stdout), fflush(stderr); 4807029Ssam if (ftrace) 4817029Ssam fclose(ftrace); 4827029Ssam (void) close(1), (void) close(2); 4837029Ssam trace = 0; 4847029Ssam return; 4857133Swnj 4867133Swnj case RIPCMD_RESPONSE: 4877133Swnj /* verify message came from a router */ 488*7139Ssam if ((*afp->af_portmatch)(from) == 0) 4897133Swnj return; 490*7139Ssam (*afp->af_canon)(from); 4917133Swnj /* are we talking to ourselves? */ 4927133Swnj ifp = if_ifwithaddr(from); 4937133Swnj if (ifp) { 494*7139Ssam rt = rtfind(from, 0); 495*7139Ssam if (rt == 0) { 4967133Swnj addrouteforif(ifp); 497*7139Ssam return; 498*7139Ssam } 499*7139Ssam /* interface previously thought down? */ 500*7139Ssam if (rt->rt_metric > 0) { 501*7139Ssam struct rt_entry *downrt = rtfind(from, 1); 502*7139Ssam if (downrt) { 503*7139Ssam /* unhide old route and delete other */ 504*7139Ssam downrt->rt_state &= ~RTS_HIDDEN; 505*7139Ssam downrt->rt_state |= RTS_ADDRT; 506*7139Ssam rt->rt_state |= RTS_DELRT; 507*7139Ssam log("unhide", downrt); 508*7139Ssam } 509*7139Ssam } 510*7139Ssam rt->rt_timer = 0; 5117133Swnj return; 5127133Swnj } 5137133Swnj size -= 4 * sizeof (char); 5147133Swnj n = msg->rip_nets; 5157133Swnj for (; size > 0; size -= sizeof (struct netinfo), n++) { 5167133Swnj if (size < sizeof (struct netinfo)) 5177133Swnj break; 5187133Swnj if (n->rip_metric >= HOPCNT_INFINITY) 5197133Swnj continue; 5207133Swnj tprintf("dst %x hc %d...", 5217133Swnj ((struct sockaddr_in *)&n->rip_dst)->sin_addr, 5227133Swnj n->rip_metric); 5237133Swnj rt = rtlookup(&n->rip_dst); 5247133Swnj if (rt == 0) { 5257133Swnj rtadd(&n->rip_dst, from, n->rip_metric, 0); 5267133Swnj continue; 5277133Swnj } 5287133Swnj tprintf("ours: gate %x hc %d timer %d\n", 5297133Swnj ((struct sockaddr_in *)&rt->rt_router)->sin_addr, 5307133Swnj rt->rt_metric, rt->rt_timer); 531*7139Ssam 5327133Swnj /* 533*7139Ssam * update if from gateway, shorter, or getting 534*7139Ssam * stale and equivalent. 5357133Swnj */ 5367133Swnj if (equal(from, &rt->rt_router) || 5377133Swnj n->rip_metric < rt->rt_metric || 5387133Swnj (rt->rt_timer > (EXPIRE_TIME/2) && 5397133Swnj rt->rt_metric == n->rip_metric)) { 5407133Swnj rtchange(rt, from, n->rip_metric); 5417133Swnj rt->rt_timer = 0; 5427133Swnj } 5437133Swnj } 5447133Swnj return; 5457029Ssam } 546*7139Ssam printf("bad packet, cmd=%x\n", msg->rip_cmd); 5477029Ssam } 5487029Ssam 5496920Ssam struct rt_entry * 5506920Ssam rtlookup(dst) 5516920Ssam struct sockaddr *dst; 5526920Ssam { 5536920Ssam register struct rt_entry *rt; 5546934Ssam register struct rthash *rh; 5557011Ssam register int hash; 5566920Ssam struct afhash h; 5577011Ssam int doinghost = 1; 5586920Ssam 5597011Ssam if (dst->sa_family >= AF_MAX) 5607011Ssam return (0); 5617011Ssam (*afswitch[dst->sa_family].af_hash)(dst, &h); 5627011Ssam hash = h.afh_hosthash; 5637011Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 5647011Ssam again: 5657011Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 566*7139Ssam if (rt->rt_hash != hash || (rt->rt_state & RTS_HIDDEN)) 5677011Ssam continue; 5687011Ssam if (equal(&rt->rt_dst, dst)) 5697011Ssam return (rt); 5707011Ssam } 5717011Ssam if (doinghost) { 5727011Ssam doinghost = 0; 5737011Ssam hash = h.afh_nethash; 5747011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 5757011Ssam goto again; 5767011Ssam } 5777011Ssam return (0); 5787011Ssam } 5797011Ssam 5807011Ssam struct rt_entry * 581*7139Ssam rtfind(dst, lookfordownif) 5827011Ssam struct sockaddr *dst; 583*7139Ssam int lookfordownif; 5847011Ssam { 5857011Ssam register struct rt_entry *rt; 5867011Ssam register struct rthash *rh; 5877011Ssam register int hash; 5887011Ssam struct afhash h; 5897011Ssam int af = dst->sa_family; 5907011Ssam int doinghost = 1, (*match)(); 5917011Ssam 5926920Ssam if (af >= AF_MAX) 5936920Ssam return (0); 5946920Ssam (*afswitch[af].af_hash)(dst, &h); 5956920Ssam hash = h.afh_hosthash; 5966920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 5976920Ssam 5986920Ssam again: 5996920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 6006920Ssam if (rt->rt_hash != hash) 6016920Ssam continue; 602*7139Ssam if (lookfordownif ^ (rt->rt_state & RTS_HIDDEN)) 603*7139Ssam continue; 6046920Ssam if (doinghost) { 6056920Ssam if (equal(&rt->rt_dst, dst)) 6066920Ssam return (rt); 6076920Ssam } else { 6086920Ssam if (rt->rt_dst.sa_family == af && 6096920Ssam (*match)(&rt->rt_dst, dst)) 6106920Ssam return (rt); 6116920Ssam } 6126920Ssam } 6136920Ssam if (doinghost) { 6146920Ssam doinghost = 0; 6156920Ssam hash = h.afh_nethash; 6167011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6176920Ssam match = afswitch[af].af_netmatch; 6186920Ssam goto again; 6196920Ssam } 6206920Ssam return (0); 6216920Ssam } 6226920Ssam 623*7139Ssam rtadd(dst, gate, metric, state) 6246920Ssam struct sockaddr *dst, *gate; 625*7139Ssam int metric, state; 6266920Ssam { 6276920Ssam struct afhash h; 6286920Ssam register struct rt_entry *rt; 6296934Ssam struct rthash *rh; 6306920Ssam int af = dst->sa_family, flags, hash; 6316920Ssam 6326920Ssam if (af >= AF_MAX) 6336920Ssam return; 6346920Ssam (*afswitch[af].af_hash)(dst, &h); 6356920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6366920Ssam if (flags & RTF_HOST) { 6376920Ssam hash = h.afh_hosthash; 6386920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6396920Ssam } else { 6406920Ssam hash = h.afh_nethash; 6416920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6426920Ssam } 6436920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6446920Ssam if (rt == 0) 6456920Ssam return; 6466920Ssam rt->rt_hash = hash; 6476920Ssam rt->rt_dst = *dst; 6487130Swnj rt->rt_router = *gate; 6496920Ssam rt->rt_metric = metric; 6506920Ssam rt->rt_timer = 0; 651*7139Ssam rt->rt_flags = RTF_UP | flags; 652*7139Ssam rt->rt_state = state; 6537130Swnj rt->rt_ifp = if_ifwithnet(&rt->rt_router); 6547130Swnj if (metric) 6557130Swnj rt->rt_flags |= RTF_GATEWAY; 6566920Ssam insque(rt, rh); 6576929Ssam log("add", rt); 6587130Swnj if (install) 6596937Ssam rt->rt_state |= RTS_ADDRT; 6606920Ssam } 6616920Ssam 6626920Ssam rtchange(rt, gate, metric) 6636920Ssam struct rt_entry *rt; 6646920Ssam struct sockaddr *gate; 6656920Ssam short metric; 6666920Ssam { 667*7139Ssam int doioctl = 0, metricchanged = 0; 6686920Ssam 6697130Swnj if (!equal(&rt->rt_router, gate)) { 670*7139Ssam if (rt->rt_state & RTS_DONTDELETE) { 671*7139Ssam rtadd(&rt->rt_dst, gate, metric, 672*7139Ssam rt->rt_state &~ (RTS_DONTDELETE|RTS_DONTROUTE)); 673*7139Ssam rt->rt_state |= RTS_DELRT; 674*7139Ssam return; 675*7139Ssam } 676*7139Ssam doioctl++; 6776920Ssam } 6786920Ssam if (metric != rt->rt_metric) { 679*7139Ssam metricchanged++; 6806920Ssam rt->rt_metric = metric; 6816920Ssam } 682*7139Ssam if (doioctl) { 683*7139Ssam if ((rt->rt_state & RTS_CHGRT) == 0) 684*7139Ssam rt->rt_oldrouter = rt->rt_router; 685*7139Ssam rt->rt_router = *gate; 6866937Ssam rt->rt_state |= RTS_CHGRT; 687*7139Ssam } 688*7139Ssam if (doioctl || metricchanged) 689*7139Ssam log("change", rt); 6906920Ssam } 6916920Ssam 6926920Ssam rtdelete(rt) 6936920Ssam struct rt_entry *rt; 6946920Ssam { 6957133Swnj 6966929Ssam log("delete", rt); 6977130Swnj if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 6987130Swnj perror("SIOCDELRT"); 699*7139Ssam if (rt->rt_state & RTS_DONTDELETE) { 700*7139Ssam rt->rt_state |= RTS_HIDDEN; 7017130Swnj return; 702*7139Ssam } 7036920Ssam remque(rt); 7046920Ssam free((char *)rt); 7056920Ssam } 7066920Ssam 7076920Ssam log(operation, rt) 7086920Ssam char *operation; 7096920Ssam struct rt_entry *rt; 7106920Ssam { 7116920Ssam struct sockaddr_in *dst, *gate; 7126937Ssam static struct bits { 7136920Ssam int t_bits; 7146920Ssam char *t_name; 7156937Ssam } flagbits[] = { 7166920Ssam { RTF_UP, "UP" }, 7177130Swnj { RTF_GATEWAY, "GATEWAY" }, 7186920Ssam { RTF_HOST, "HOST" }, 7196920Ssam { 0 } 7206937Ssam }, statebits[] = { 721*7139Ssam { RTS_ADDRT, "ADD" }, 7226937Ssam { RTS_DELRT, "DELETE" }, 7236937Ssam { RTS_CHGRT, "CHANGE" }, 7247130Swnj { RTS_PASSIVE, "PASSIVE" }, 725*7139Ssam { RTS_DONTDELETE,"DONTDELETE" }, 726*7139Ssam { RTS_DONTROUTE,"DONTROUTE" }, 727*7139Ssam { RTS_HIDDEN, "HIDDEN" }, 7286937Ssam { 0 } 7296920Ssam }; 7306937Ssam register struct bits *p; 7316920Ssam register int first; 7326920Ssam char *cp; 7336920Ssam 7346929Ssam if (trace == 0) 7356929Ssam return; 7366920Ssam printf("%s ", operation); 7376920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 7387130Swnj gate = (struct sockaddr_in *)&rt->rt_router; 739*7139Ssam printf("dst %x, router %x", dst->sin_addr, gate->sin_addr); 740*7139Ssam if (rt->rt_state & RTS_CHGRT) 741*7139Ssam printf(" (old %x)", 742*7139Ssam ((struct sockaddr_in *)&rt->rt_oldrouter)->sin_addr); 743*7139Ssam printf(", metric %d, flags", rt->rt_metric); 7446937Ssam cp = " %s"; 7456937Ssam for (first = 1, p = flagbits; p->t_bits > 0; p++) { 7466920Ssam if ((rt->rt_flags & p->t_bits) == 0) 7476920Ssam continue; 7486920Ssam printf(cp, p->t_name); 7496920Ssam if (first) { 7506920Ssam cp = "|%s"; 7516920Ssam first = 0; 7526920Ssam } 7536920Ssam } 7546937Ssam printf(" state"); 7556937Ssam cp = " %s"; 7566937Ssam for (first = 1, p = statebits; p->t_bits > 0; p++) { 7576937Ssam if ((rt->rt_state & p->t_bits) == 0) 7586937Ssam continue; 7596937Ssam printf(cp, p->t_name); 7606937Ssam if (first) { 7616937Ssam cp = "|%s"; 7626937Ssam first = 0; 7636937Ssam } 7646937Ssam } 7656920Ssam putchar('\n'); 7666920Ssam } 7676929Ssam 7686929Ssam struct ifnet * 7696929Ssam if_ifwithaddr(addr) 7706929Ssam struct sockaddr *addr; 7716929Ssam { 7726929Ssam register struct ifnet *ifp; 7736929Ssam 7746929Ssam #define same(a1, a2) \ 7756929Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 7766929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 7776929Ssam if (ifp->if_addr.sa_family != addr->sa_family) 7786929Ssam continue; 7796929Ssam if (same(&ifp->if_addr, addr)) 7806929Ssam break; 7816929Ssam if ((ifp->if_flags & IFF_BROADCAST) && 7826929Ssam same(&ifp->if_broadaddr, addr)) 7836929Ssam break; 7846929Ssam } 7856929Ssam return (ifp); 7866929Ssam #undef same 7876929Ssam } 7886929Ssam 7896929Ssam struct ifnet * 7906929Ssam if_ifwithnet(addr) 7916929Ssam register struct sockaddr *addr; 7926929Ssam { 7936929Ssam register struct ifnet *ifp; 7946929Ssam register int af = addr->sa_family; 7956929Ssam register int (*netmatch)(); 7966929Ssam 7976929Ssam if (af >= AF_MAX) 7986929Ssam return (0); 7996929Ssam netmatch = afswitch[af].af_netmatch; 8006929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 8016929Ssam if (af != ifp->if_addr.sa_family) 8026929Ssam continue; 8036929Ssam if ((*netmatch)(addr, &ifp->if_addr)) 8046929Ssam break; 8056929Ssam } 8066929Ssam return (ifp); 8076929Ssam } 8086929Ssam 8096929Ssam struct in_addr 8106929Ssam if_makeaddr(net, host) 8116929Ssam int net, host; 8126929Ssam { 8136929Ssam u_long addr; 8146929Ssam 8156929Ssam if (net < 128) 8166929Ssam addr = (net << 24) | host; 8176929Ssam else if (net < 65536) 8186929Ssam addr = (net << 16) | host; 8196929Ssam else 8206929Ssam addr = (net << 8) | host; 8216929Ssam #ifdef vax 8226929Ssam addr = htonl(addr); 8236929Ssam #endif 8246929Ssam return (*(struct in_addr *)&addr); 8256929Ssam } 826