16920Ssam #ifndef lint 2*7145Ssam static char sccsid[] = "@(#)routed.c 4.16 82/06/10"; 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> 187139Ssam #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 367139Ssam struct sockaddr_in routingaddr = { AF_INET, IPPORT_ROUTESERVER }; 377139Ssam 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 */ 44*7145Ssam int lookforinterfaces = 1; 45*7145Ssam int performnlist = 1; 467133Swnj int timeval = -TIMER_RATE; 476920Ssam int timer(); 486920Ssam int cleanup(); 497133Swnj 507133Swnj #define tprintf if (trace) printf 516920Ssam int trace = 0; 527029Ssam FILE *ftrace; 536920Ssam 547133Swnj char packet[MAXPACKETSIZE+1]; 557133Swnj struct rip *msg = (struct rip *)packet; 566920Ssam 576934Ssam struct in_addr if_makeaddr(); 58*7145Ssam struct interface *if_ifwithaddr(), *if_ifwithnet(); 59*7145Ssam extern char *malloc(), *sys_errlist[]; 606922Ssam extern int errno, exit(); 617133Swnj char **argv0; 626920Ssam 637139Ssam int sendmsg(), supply(); 647133Swnj 656920Ssam main(argc, argv) 666920Ssam int argc; 676920Ssam char *argv[]; 686920Ssam { 696920Ssam int cc; 706920Ssam struct sockaddr from; 716920Ssam 727133Swnj argv0 = argv; 737029Ssam #ifndef DEBUG 747029Ssam if (fork()) 757029Ssam exit(0); 767029Ssam for (cc = 0; cc < 10; cc++) 777029Ssam (void) close(cc); 787029Ssam (void) open("/", 0); 797029Ssam (void) dup2(0, 1); 807029Ssam (void) dup2(0, 2); 817029Ssam { int t = open("/dev/tty", 2); 827029Ssam if (t >= 0) { 837029Ssam ioctl(t, TIOCNOTTY, (char *)0); 847029Ssam (void) close(t); 857029Ssam } 866920Ssam } 877029Ssam #endif 886920Ssam if (trace) { 897029Ssam ftrace = fopen("/etc/routerlog", "w"); 907029Ssam dup2(fileno(ftrace), 1); 917029Ssam dup2(fileno(ftrace), 2); 926920Ssam } 936937Ssam #ifdef vax || pdp11 947139Ssam routingaddr.sin_port = htons(routingaddr.sin_port); 957139Ssam noroutingaddr.sin_port = htons(noroutingaddr.sin_port); 966920Ssam #endif 976920Ssam again: 987139Ssam s = socket(SOCK_DGRAM, 0, &routingaddr, 0); 996920Ssam if (s < 0) { 1006920Ssam perror("socket"); 1016920Ssam sleep(30); 1026920Ssam goto again; 1036920Ssam } 1047130Swnj again2: 1057139Ssam snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE); 1067130Swnj if (snoroute < 0) { 1077130Swnj perror("socket"); 1087130Swnj sleep(30); 1097130Swnj goto again2; 1107130Swnj } 1116920Ssam argv++, argc--; 1127133Swnj while (argc > 0 && **argv == '-') { 1137133Swnj if (!strcmp(*argv, "-s") == 0) { 1146929Ssam supplier = 1; 1157133Swnj argv++, argc--; 1167133Swnj continue; 1177133Swnj } 1187133Swnj if (!strcmp(*argv, "-q") == 0) { 1196920Ssam supplier = 0; 1207133Swnj argv++, argc--; 1217133Swnj continue; 1227133Swnj } 1237133Swnj goto usage; 1246920Ssam } 1257133Swnj if (argc > 0) { 1267133Swnj usage: 127*7145Ssam fprintf(stderr, "usage: routed [ -sq ]\n"); 1287133Swnj exit(1); 1297133Swnj } 1307133Swnj rtinit(); 1317133Swnj ifinit(); 1327133Swnj if (supplier < 0) 1337133Swnj supplier = 0; 1347133Swnj gwkludge(); 1357133Swnj msg->rip_cmd = RIPCMD_REQUEST; 1367133Swnj msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 1377133Swnj msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 1387133Swnj toall(sendmsg); 1396920Ssam sigset(SIGALRM, timer); 1406929Ssam timer(); 1416920Ssam 1426920Ssam for (;;) { 1436920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1446920Ssam if (cc <= 0) { 1456920Ssam if (cc < 0 && errno != EINTR) 1466920Ssam perror("receive"); 1476920Ssam continue; 1486920Ssam } 1496920Ssam sighold(SIGALRM); 1506920Ssam rip_input(&from, cc); 1516920Ssam sigrelse(SIGALRM); 1526920Ssam } 1536920Ssam } 1546920Ssam 1557133Swnj rtinit() 1566920Ssam { 1576934Ssam register struct rthash *rh; 1586920Ssam 1597133Swnj for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 1607133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1617133Swnj for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 1627133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1636920Ssam } 1646920Ssam 165*7145Ssam struct interface *ifnet; 1667133Swnj 1677133Swnj ifinit() 1686920Ssam { 169*7145Ssam struct interface *ifp; 170*7145Ssam struct ifnet ifs, *next; 171*7145Ssam int externalinterfaces = 0; 1726920Ssam 173*7145Ssam if (performnlist) { 174*7145Ssam nlist("/vmunix", nl); 175*7145Ssam if (nl[N_IFNET].n_value == 0) { 176*7145Ssam printf("ifnet: not in namelist\n"); 177*7145Ssam goto bad; 178*7145Ssam } 179*7145Ssam performnlist = 0; 1806920Ssam } 1816920Ssam if (kmem < 0) { 182*7145Ssam kmem = open("/dev/kmem", 0); 183*7145Ssam if (kmem < 0) { 184*7145Ssam perror("/dev/kmem"); 185*7145Ssam goto bad; 186*7145Ssam } 1876920Ssam } 1886929Ssam if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 1897133Swnj read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { 1907133Swnj printf("ifnet: error reading kmem\n"); 1917133Swnj goto bad; 1926929Ssam } 193*7145Ssam lookforinterfaces = 0; 1947133Swnj while (next) { 1957133Swnj if (lseek(kmem, (long)next, 0) == -1 || 196*7145Ssam read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) { 1977133Swnj perror("read"); 1987133Swnj goto bad; 1996929Ssam } 200*7145Ssam next = ifs.if_next; 201*7145Ssam if ((ifs.if_flags & IFF_UP) == 0) { 202*7145Ssam lookforinterfaces = 1; 2037133Swnj continue; 204*7145Ssam } 205*7145Ssam if (if_ifwithaddr(&ifs.if_addr)) 2067133Swnj continue; 207*7145Ssam if (ifs.if_addr.sa_family != AF_INET) 208*7145Ssam continue; 209*7145Ssam if (ifs.if_net == LOOPBACKNET) 210*7145Ssam continue; 211*7145Ssam ifp = (struct interface *)malloc(sizeof (struct interface)); 212*7145Ssam if (ifp == 0) { 213*7145Ssam printf("routed: out of memory\n"); 214*7145Ssam break; 215*7145Ssam } 216*7145Ssam /* 217*7145Ssam * Count the # of directly connected networks 218*7145Ssam * and point to point links which aren't looped 219*7145Ssam * back to ourself. This is used below to 220*7145Ssam * decide if we should be a routing "supplier". 221*7145Ssam */ 222*7145Ssam if ((ifs.if_flags & IFF_POINTOPOINT) == 0 || 223*7145Ssam if_ifwithaddr(&ifs.if_dstaddr) == 0) 224*7145Ssam externalinterfaces++; 225*7145Ssam ifp->int_addr = ifs.if_addr; 226*7145Ssam ifp->int_flags = ifs.if_flags | IFF_INTERFACE; 227*7145Ssam /* this works because broadaddr overlaps dstaddr */ 228*7145Ssam ifp->int_broadaddr = ifs.if_broadaddr; 229*7145Ssam ifp->int_net = ifs.if_net; 230*7145Ssam ifp->int_metric = 0; 231*7145Ssam ifp->int_next = ifnet; 2326929Ssam ifnet = ifp; 2337133Swnj addrouteforif(ifp); 2347133Swnj } 235*7145Ssam if (externalinterfaces > 1 && supplier < 0) 2367133Swnj supplier = 1; 2377133Swnj return; 2387133Swnj bad: 2397133Swnj sleep(60); 240*7145Ssam close(kmem), close(s), close(snoroute); 2417133Swnj execv("/etc/routed", argv0); 2427133Swnj _exit(0177); 2437133Swnj } 2447130Swnj 2457133Swnj addrouteforif(ifp) 246*7145Ssam struct interface *ifp; 2477133Swnj { 2487133Swnj struct sockaddr_in net; 2497133Swnj struct sockaddr *dst; 250*7145Ssam int state, metric; 2517133Swnj 252*7145Ssam if (ifp->int_flags & IFF_POINTOPOINT) 253*7145Ssam dst = &ifp->int_dstaddr; 2547133Swnj else { 2557133Swnj bzero((char *)&net, sizeof (net)); 2567133Swnj net.sin_family = AF_INET; 257*7145Ssam net.sin_addr = if_makeaddr(ifp->int_net, INADDR_ANY); 2587133Swnj dst = (struct sockaddr *)&net; 2596920Ssam } 260*7145Ssam rtadd(dst, &ifp->int_addr, ifp->int_metric, 261*7145Ssam ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE)); 2626920Ssam } 2636920Ssam 2647133Swnj gwkludge() 2657130Swnj { 2667130Swnj struct sockaddr_in dst, gate; 2677130Swnj FILE *fp; 2687139Ssam char buf[BUFSIZ]; 269*7145Ssam struct interface *ifp; 270*7145Ssam int metric; 2717130Swnj 2727130Swnj fp = fopen("/etc/gateways", "r"); 2737130Swnj if (fp == NULL) 2747130Swnj return; 2757130Swnj bzero((char *)&dst, sizeof (dst)); 2767130Swnj bzero((char *)&gate, sizeof (gate)); 277*7145Ssam dst.sin_family = gate.sin_family = AF_INET; 278*7145Ssam /* format: dst XX gateway XX metric DD [passive]\n */ 279*7145Ssam #define readentry(fp) \ 280*7145Ssam fscanf((fp), "dst %x gateway %x metric %d %s\n", \ 281*7145Ssam &dst.sin_addr.s_addr, &gate.sin_addr.s_addr, &metric, buf) 2827133Swnj for (;;) { 283*7145Ssam if (readentry(fp) == EOF) 2847133Swnj break; 285*7145Ssam ifp = (struct interface *)malloc(sizeof (*ifp)); 286*7145Ssam bzero((char *)ifp, sizeof (*ifp)); 287*7145Ssam ifp->int_flags = IFF_REMOTE; 288*7145Ssam /* can't identify broadcast capability */ 289*7145Ssam if ((*afswitch[dst.sin_family].af_checkhost)(&dst)) { 290*7145Ssam ifp->int_flags |= IFF_POINTOPOINT; 291*7145Ssam ifp->int_net = dst.sin_addr.s_net; /* XXX */ 292*7145Ssam ifp->int_dstaddr = *((struct sockaddr *)&dst); 293*7145Ssam } else 294*7145Ssam ifp->int_net = dst.sin_addr.s_addr; /* XXX */ 295*7145Ssam if (strcmp(buf, "passive") == 0) 296*7145Ssam ifp->int_flags |= IFF_PASSIVE; 297*7145Ssam ifp->int_addr = *((struct sockaddr *)&gate); 298*7145Ssam ifp->int_metric = metric; 299*7145Ssam ifp->int_next = ifnet; 300*7145Ssam ifnet = ifp; 301*7145Ssam addrouteforif(ifp); 3027130Swnj } 3037130Swnj fclose(fp); 3047130Swnj } 3057130Swnj 3067133Swnj timer() 3076920Ssam { 3086934Ssam register struct rthash *rh; 3096920Ssam register struct rt_entry *rt; 3106934Ssam struct rthash *base = hosthash; 311*7145Ssam int doinghost = 1, supplyeverything; 3126920Ssam 3137133Swnj timeval += TIMER_RATE; 314*7145Ssam if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0) 315*7145Ssam ifinit(); 316*7145Ssam supplyeverything = supplier && (timeval % SUPPLY_INTERVAL) == 0; 3177133Swnj tprintf(">>> time %d >>>\n", timeval); 3186920Ssam again: 3197133Swnj for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 3207133Swnj rt = rh->rt_forw; 3217133Swnj for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 322*7145Ssam if (!(rt->rt_state & RTS_PASSIVE)) 3237133Swnj rt->rt_timer += TIMER_RATE; 3247133Swnj if (rt->rt_timer >= EXPIRE_TIME) 3257133Swnj rt->rt_metric = HOPCNT_INFINITY; 326*7145Ssam log("", rt); 327*7145Ssam if (rt->rt_timer >= GARBAGE_TIME) { 3287133Swnj rt = rt->rt_back; 3297133Swnj rtdelete(rt->rt_forw); 3307133Swnj continue; 3317133Swnj } 332*7145Ssam if (rt->rt_state & RTS_CHANGED) { 333*7145Ssam rt->rt_state &= ~RTS_CHANGED; 334*7145Ssam /* don't send extraneous packets */ 335*7145Ssam if (supplyeverything) 336*7145Ssam continue; 3377133Swnj log("broadcast", rt); 3387133Swnj msg->rip_cmd = RIPCMD_RESPONSE; 3397133Swnj msg->rip_nets[0].rip_dst = rt->rt_dst; 3407133Swnj msg->rip_nets[0].rip_metric = 3417133Swnj min(rt->rt_metric+1, HOPCNT_INFINITY); 3427139Ssam toall(sendmsg); 3437133Swnj } 3447133Swnj } 3456920Ssam } 3466920Ssam if (doinghost) { 3477133Swnj doinghost = 0; 3486929Ssam base = nethash; 3496920Ssam goto again; 3506920Ssam } 351*7145Ssam if (supplyeverything) 3527133Swnj toall(supply); 3537133Swnj tprintf("<<< time %d <<<\n", timeval); 3547133Swnj alarm(TIMER_RATE); 3556920Ssam } 3566920Ssam 3577133Swnj toall(f) 3587133Swnj int (*f)(); 3596920Ssam { 360*7145Ssam register struct interface *ifp; 3616920Ssam register struct sockaddr *dst; 3626920Ssam 363*7145Ssam for (ifp = ifnet; ifp; ifp = ifp->int_next) { 364*7145Ssam if (ifp->int_flags & IFF_PASSIVE) 3656920Ssam continue; 366*7145Ssam dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr : 367*7145Ssam ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr : 368*7145Ssam &ifp->int_addr; 369*7145Ssam (*f)(dst, ifp->int_flags & IFF_INTERFACE); 3706920Ssam } 3716920Ssam } 3726920Ssam 3737139Ssam /*ARGSUSED*/ 3747139Ssam sendmsg(dst, dontroute) 3757133Swnj struct sockaddr *dst; 3767139Ssam int dontroute; 3777133Swnj { 3787133Swnj (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip)); 3797133Swnj } 3807133Swnj 3817139Ssam supply(dst, dontroute) 3827139Ssam struct sockaddr *dst; 3837139Ssam int dontroute; 3847139Ssam { 3857133Swnj register struct rt_entry *rt; 3866920Ssam struct netinfo *n = msg->rip_nets; 3876934Ssam register struct rthash *rh; 3886934Ssam struct rthash *base = hosthash; 3896929Ssam int doinghost = 1, size; 3907139Ssam int (*output)() = afswitch[dst->sa_family].af_output; 3917139Ssam int sto = dontroute ? snoroute : s; 3926920Ssam 3936920Ssam again: 3946920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3956920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3966929Ssam size = (char *)n - packet; 3976929Ssam if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 3987139Ssam (*output)(sto, dst, size); 3996920Ssam n = msg->rip_nets; 4006920Ssam } 4016920Ssam n->rip_dst = rt->rt_dst; 4026929Ssam n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 4036929Ssam n++; 4046920Ssam } 4056920Ssam if (doinghost) { 4066920Ssam doinghost = 0; 4076920Ssam base = nethash; 4086920Ssam goto again; 4096920Ssam } 4106929Ssam if (n != msg->rip_nets) 4117139Ssam (*output)(sto, dst, (char *)n - packet); 4126920Ssam } 4136920Ssam 4146920Ssam /* 4156920Ssam * Handle an incoming routing packet. 4166920Ssam */ 4176920Ssam rip_input(from, size) 4186920Ssam struct sockaddr *from; 4196920Ssam int size; 4206920Ssam { 4216920Ssam struct rt_entry *rt; 4226920Ssam struct netinfo *n; 423*7145Ssam struct interface *ifp; 4247133Swnj time_t t; 4257139Ssam int newsize; 4267139Ssam struct afswitch *afp; 4276920Ssam 4287139Ssam if (trace) { 4297139Ssam if (msg->rip_cmd < RIPCMD_MAX) 4307139Ssam printf("%s from %x\n", ripcmds[msg->rip_cmd], 4317139Ssam ((struct sockaddr_in *)from)->sin_addr); 4327139Ssam else 4337139Ssam printf("%x from %x\n", msg->rip_cmd, 4347139Ssam ((struct sockaddr_in *)from)->sin_addr); 4357139Ssam } 4367139Ssam if (from->sa_family >= AF_MAX) 4377139Ssam return; 4387139Ssam afp = &afswitch[from->sa_family]; 4396937Ssam switch (msg->rip_cmd) { 4406937Ssam 4417139Ssam case RIPCMD_REQUEST: 4427139Ssam newsize = 0; 4437139Ssam size -= 4 * sizeof (char); 4447139Ssam n = msg->rip_nets; 4457139Ssam while (size > 0) { 4467139Ssam if (size < sizeof (struct netinfo)) 4477139Ssam break; 4487139Ssam size -= sizeof (struct netinfo); 4496920Ssam 4507139Ssam /* 4517139Ssam * A single entry with sa_family == AF_UNSPEC and 4527139Ssam * metric ``infinity'' means ``all routes''. 4537139Ssam */ 4547139Ssam if (n->rip_dst.sa_family == AF_UNSPEC && 4557139Ssam n->rip_metric == HOPCNT_INFINITY && size == 0) { 4567139Ssam supply(from, 0); /* don't route */ 4577139Ssam return; 4587139Ssam } 4597139Ssam rt = rtlookup(&n->rip_dst); 4607139Ssam n->rip_metric = rt == 0 ? HOPCNT_INFINITY : 4617139Ssam min(rt->rt_metric+1, HOPCNT_INFINITY); 4627139Ssam n++, newsize += sizeof (struct netinfo); 4637139Ssam } 4647139Ssam if (newsize > 0) { 4657139Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4667139Ssam newsize += sizeof (int); 4677139Ssam (*afp->af_output)(s, from, newsize); 4687139Ssam } 4696920Ssam return; 4706937Ssam 4717029Ssam case RIPCMD_TRACEON: 4727139Ssam if ((*afp->af_portcheck)(from) == 0) 4737029Ssam return; 4747133Swnj if (trace) 4757133Swnj return; 4767133Swnj packet[size] = '\0'; 4777133Swnj ftrace = fopen(msg->rip_tracefile, "a"); 4787133Swnj if (ftrace == NULL) 4797133Swnj return; 4807133Swnj (void) dup2(fileno(ftrace), 1); 4817133Swnj (void) dup2(fileno(ftrace), 2); 4827133Swnj trace = 1; 4837133Swnj t = time(0); 4847133Swnj printf("*** Tracing turned on at %.24s ***\n", ctime(&t)); 4857029Ssam return; 4867029Ssam 4877133Swnj case RIPCMD_TRACEOFF: 4887133Swnj /* verify message came from a priviledged port */ 4897139Ssam if ((*afp->af_portcheck)(from) == 0) 4906937Ssam return; 4917029Ssam if (!trace) 4927029Ssam return; 4937029Ssam t = time(0); 4947029Ssam printf("*** Tracing turned off at %.24s ***\n", ctime(&t)); 4957029Ssam fflush(stdout), fflush(stderr); 4967029Ssam if (ftrace) 4977029Ssam fclose(ftrace); 4987029Ssam (void) close(1), (void) close(2); 4997029Ssam trace = 0; 5007029Ssam return; 5017133Swnj 5027133Swnj case RIPCMD_RESPONSE: 5037133Swnj /* verify message came from a router */ 5047139Ssam if ((*afp->af_portmatch)(from) == 0) 5057133Swnj return; 5067139Ssam (*afp->af_canon)(from); 5077133Swnj /* are we talking to ourselves? */ 5087133Swnj ifp = if_ifwithaddr(from); 5097133Swnj if (ifp) { 510*7145Ssam rt = rtfind(from); 511*7145Ssam if (rt == 0) 5127133Swnj addrouteforif(ifp); 513*7145Ssam else 514*7145Ssam rt->rt_timer = 0; 5157133Swnj return; 5167133Swnj } 5177133Swnj size -= 4 * sizeof (char); 5187133Swnj n = msg->rip_nets; 5197133Swnj for (; size > 0; size -= sizeof (struct netinfo), n++) { 5207133Swnj if (size < sizeof (struct netinfo)) 5217133Swnj break; 5227133Swnj if (n->rip_metric >= HOPCNT_INFINITY) 5237133Swnj continue; 5247133Swnj tprintf("dst %x hc %d...", 5257133Swnj ((struct sockaddr_in *)&n->rip_dst)->sin_addr, 5267133Swnj n->rip_metric); 5277133Swnj rt = rtlookup(&n->rip_dst); 5287133Swnj if (rt == 0) { 5297133Swnj rtadd(&n->rip_dst, from, n->rip_metric, 0); 5307133Swnj continue; 5317133Swnj } 5327133Swnj tprintf("ours: gate %x hc %d timer %d\n", 5337133Swnj ((struct sockaddr_in *)&rt->rt_router)->sin_addr, 5347133Swnj rt->rt_metric, rt->rt_timer); 5357139Ssam 5367133Swnj /* 5377139Ssam * update if from gateway, shorter, or getting 5387139Ssam * stale and equivalent. 5397133Swnj */ 5407133Swnj if (equal(from, &rt->rt_router) || 5417133Swnj n->rip_metric < rt->rt_metric || 5427133Swnj (rt->rt_timer > (EXPIRE_TIME/2) && 5437133Swnj rt->rt_metric == n->rip_metric)) { 5447133Swnj rtchange(rt, from, n->rip_metric); 5457133Swnj rt->rt_timer = 0; 5467133Swnj } 5477133Swnj } 5487133Swnj return; 5497029Ssam } 550*7145Ssam tprintf("bad packet, cmd=%x\n", msg->rip_cmd); 5517029Ssam } 5527029Ssam 5536920Ssam struct rt_entry * 5546920Ssam rtlookup(dst) 5556920Ssam struct sockaddr *dst; 5566920Ssam { 5576920Ssam register struct rt_entry *rt; 5586934Ssam register struct rthash *rh; 5597011Ssam register int hash; 5606920Ssam struct afhash h; 5617011Ssam int doinghost = 1; 5626920Ssam 5637011Ssam if (dst->sa_family >= AF_MAX) 5647011Ssam return (0); 5657011Ssam (*afswitch[dst->sa_family].af_hash)(dst, &h); 5667011Ssam hash = h.afh_hosthash; 5677011Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 5687011Ssam again: 5697011Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 570*7145Ssam if (rt->rt_hash != hash) 5717011Ssam continue; 5727011Ssam if (equal(&rt->rt_dst, dst)) 5737011Ssam return (rt); 5747011Ssam } 5757011Ssam if (doinghost) { 5767011Ssam doinghost = 0; 5777011Ssam hash = h.afh_nethash; 5787011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 5797011Ssam goto again; 5807011Ssam } 5817011Ssam return (0); 5827011Ssam } 5837011Ssam 5847011Ssam struct rt_entry * 585*7145Ssam rtfind(dst) 5867011Ssam struct sockaddr *dst; 5877011Ssam { 5887011Ssam register struct rt_entry *rt; 5897011Ssam register struct rthash *rh; 5907011Ssam register int hash; 5917011Ssam struct afhash h; 5927011Ssam int af = dst->sa_family; 5937011Ssam int doinghost = 1, (*match)(); 5947011Ssam 5956920Ssam if (af >= AF_MAX) 5966920Ssam return (0); 5976920Ssam (*afswitch[af].af_hash)(dst, &h); 5986920Ssam hash = h.afh_hosthash; 5996920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6006920Ssam 6016920Ssam again: 6026920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 6036920Ssam if (rt->rt_hash != hash) 6046920Ssam continue; 6056920Ssam if (doinghost) { 6066920Ssam if (equal(&rt->rt_dst, dst)) 6076920Ssam return (rt); 6086920Ssam } else { 6096920Ssam if (rt->rt_dst.sa_family == af && 6106920Ssam (*match)(&rt->rt_dst, dst)) 6116920Ssam return (rt); 6126920Ssam } 6136920Ssam } 6146920Ssam if (doinghost) { 6156920Ssam doinghost = 0; 6166920Ssam hash = h.afh_nethash; 6177011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6186920Ssam match = afswitch[af].af_netmatch; 6196920Ssam goto again; 6206920Ssam } 6216920Ssam return (0); 6226920Ssam } 6236920Ssam 6247139Ssam rtadd(dst, gate, metric, state) 6256920Ssam struct sockaddr *dst, *gate; 6267139Ssam int metric, state; 6276920Ssam { 6286920Ssam struct afhash h; 6296920Ssam register struct rt_entry *rt; 6306934Ssam struct rthash *rh; 6316920Ssam int af = dst->sa_family, flags, hash; 6326920Ssam 6336920Ssam if (af >= AF_MAX) 6346920Ssam return; 6356920Ssam (*afswitch[af].af_hash)(dst, &h); 6366920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6376920Ssam if (flags & RTF_HOST) { 6386920Ssam hash = h.afh_hosthash; 6396920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6406920Ssam } else { 6416920Ssam hash = h.afh_nethash; 6426920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6436920Ssam } 6446920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6456920Ssam if (rt == 0) 6466920Ssam return; 6476920Ssam rt->rt_hash = hash; 6486920Ssam rt->rt_dst = *dst; 6497130Swnj rt->rt_router = *gate; 6506920Ssam rt->rt_metric = metric; 6516920Ssam rt->rt_timer = 0; 6527139Ssam rt->rt_flags = RTF_UP | flags; 653*7145Ssam rt->rt_state = state | RTS_CHANGED; 6547130Swnj rt->rt_ifp = if_ifwithnet(&rt->rt_router); 6557130Swnj if (metric) 6567130Swnj rt->rt_flags |= RTF_GATEWAY; 6576920Ssam insque(rt, rh); 6586929Ssam log("add", rt); 659*7145Ssam if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 660*7145Ssam tprintf("SIOCADDRT: %s\n", sys_errlist[errno]); 6616920Ssam } 6626920Ssam 6636920Ssam rtchange(rt, gate, metric) 6646920Ssam struct rt_entry *rt; 6656920Ssam struct sockaddr *gate; 6666920Ssam short metric; 6676920Ssam { 6687139Ssam int doioctl = 0, metricchanged = 0; 669*7145Ssam struct rtentry oldroute; 6706920Ssam 671*7145Ssam if (!equal(&rt->rt_router, gate)) 6727139Ssam doioctl++; 6736920Ssam if (metric != rt->rt_metric) { 6747139Ssam metricchanged++; 6756920Ssam rt->rt_metric = metric; 6766920Ssam } 677*7145Ssam if (doioctl || metricchanged) { 678*7145Ssam log("change", rt); 679*7145Ssam rt->rt_state |= RTS_CHANGED; 680*7145Ssam } 6817139Ssam if (doioctl) { 682*7145Ssam oldroute = rt->rt_rt; 6837139Ssam rt->rt_router = *gate; 684*7145Ssam if (install) { 685*7145Ssam if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 686*7145Ssam tprintf("SIOCADDRT: %s\n", sys_errlist[errno]); 687*7145Ssam if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 688*7145Ssam tprintf("SIOCDELRT: %s\n", sys_errlist[errno]); 689*7145Ssam } 6907139Ssam } 6916920Ssam } 6926920Ssam 6936920Ssam rtdelete(rt) 6946920Ssam struct rt_entry *rt; 6956920Ssam { 6966929Ssam log("delete", rt); 6977130Swnj if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 698*7145Ssam tprintf("SIOCDELRT: %s\n", sys_errlist[errno]); 6996920Ssam remque(rt); 7006920Ssam free((char *)rt); 7016920Ssam } 7026920Ssam 7036920Ssam log(operation, rt) 7046920Ssam char *operation; 7056920Ssam struct rt_entry *rt; 7066920Ssam { 7076920Ssam struct sockaddr_in *dst, *gate; 7086937Ssam static struct bits { 7096920Ssam int t_bits; 7106920Ssam char *t_name; 7116937Ssam } flagbits[] = { 7126920Ssam { RTF_UP, "UP" }, 7137130Swnj { RTF_GATEWAY, "GATEWAY" }, 7146920Ssam { RTF_HOST, "HOST" }, 7156920Ssam { 0 } 7166937Ssam }, statebits[] = { 7177130Swnj { RTS_PASSIVE, "PASSIVE" }, 718*7145Ssam { RTS_REMOTE, "REMOTE" }, 719*7145Ssam { RTS_INTERFACE,"INTERFACE" }, 720*7145Ssam { RTS_CHANGED, "CHANGED" }, 7216937Ssam { 0 } 7226920Ssam }; 7236937Ssam register struct bits *p; 7246920Ssam register int first; 7256920Ssam char *cp; 7266920Ssam 7276929Ssam if (trace == 0) 7286929Ssam return; 7296920Ssam printf("%s ", operation); 7306920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 7317130Swnj gate = (struct sockaddr_in *)&rt->rt_router; 732*7145Ssam printf("dst %x, router %x, metric %d, flags", dst->sin_addr, 733*7145Ssam gate->sin_addr, rt->rt_metric); 7346937Ssam cp = " %s"; 7356937Ssam for (first = 1, p = flagbits; p->t_bits > 0; p++) { 7366920Ssam if ((rt->rt_flags & p->t_bits) == 0) 7376920Ssam continue; 7386920Ssam printf(cp, p->t_name); 7396920Ssam if (first) { 7406920Ssam cp = "|%s"; 7416920Ssam first = 0; 7426920Ssam } 7436920Ssam } 7446937Ssam printf(" state"); 7456937Ssam cp = " %s"; 7466937Ssam for (first = 1, p = statebits; p->t_bits > 0; p++) { 7476937Ssam if ((rt->rt_state & p->t_bits) == 0) 7486937Ssam continue; 7496937Ssam printf(cp, p->t_name); 7506937Ssam if (first) { 7516937Ssam cp = "|%s"; 7526937Ssam first = 0; 7536937Ssam } 7546937Ssam } 7556920Ssam putchar('\n'); 7566920Ssam } 7576929Ssam 758*7145Ssam struct interface * 7596929Ssam if_ifwithaddr(addr) 7606929Ssam struct sockaddr *addr; 7616929Ssam { 762*7145Ssam register struct interface *ifp; 7636929Ssam 7646929Ssam #define same(a1, a2) \ 7656929Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 766*7145Ssam for (ifp = ifnet; ifp; ifp = ifp->int_next) { 767*7145Ssam if (ifp->int_flags & IFF_REMOTE) 7686929Ssam continue; 769*7145Ssam if (ifp->int_addr.sa_family != addr->sa_family) 770*7145Ssam continue; 771*7145Ssam if (same(&ifp->int_addr, addr)) 7726929Ssam break; 773*7145Ssam if ((ifp->int_flags & IFF_BROADCAST) && 774*7145Ssam same(&ifp->int_broadaddr, addr)) 7756929Ssam break; 7766929Ssam } 7776929Ssam return (ifp); 7786929Ssam #undef same 7796929Ssam } 7806929Ssam 781*7145Ssam struct interface * 7826929Ssam if_ifwithnet(addr) 7836929Ssam register struct sockaddr *addr; 7846929Ssam { 785*7145Ssam register struct interface *ifp; 7866929Ssam register int af = addr->sa_family; 7876929Ssam register int (*netmatch)(); 7886929Ssam 7896929Ssam if (af >= AF_MAX) 7906929Ssam return (0); 7916929Ssam netmatch = afswitch[af].af_netmatch; 792*7145Ssam for (ifp = ifnet; ifp; ifp = ifp->int_next) { 793*7145Ssam if (ifp->int_flags & IFF_REMOTE) 7946929Ssam continue; 795*7145Ssam if (af != ifp->int_addr.sa_family) 796*7145Ssam continue; 797*7145Ssam if ((*netmatch)(addr, &ifp->int_addr)) 7986929Ssam break; 7996929Ssam } 8006929Ssam return (ifp); 8016929Ssam } 8026929Ssam 8036929Ssam struct in_addr 8046929Ssam if_makeaddr(net, host) 8056929Ssam int net, host; 8066929Ssam { 8076929Ssam u_long addr; 8086929Ssam 8096929Ssam if (net < 128) 8106929Ssam addr = (net << 24) | host; 8116929Ssam else if (net < 65536) 8126929Ssam addr = (net << 16) | host; 8136929Ssam else 8146929Ssam addr = (net << 8) | host; 8156929Ssam #ifdef vax 8166929Ssam addr = htonl(addr); 8176929Ssam #endif 8186929Ssam return (*(struct in_addr *)&addr); 8196929Ssam } 820