16920Ssam #ifndef lint 2*7133Swnj static char sccsid[] = "@(#)routed.c 4.14 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> 186920Ssam #include "rip.h" 196920Ssam #include "router.h" 206920Ssam 216920Ssam #define LOOPBACKNET 0177 226920Ssam /* casts to keep lint happy */ 236920Ssam #define insque(q,p) _insque((caddr_t)q,(caddr_t)p) 246920Ssam #define remque(q) _remque((caddr_t)q) 256920Ssam #define equal(a1, a2) \ 266920Ssam (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 276929Ssam #define min(a,b) ((a)>(b)?(b):(a)) 286920Ssam 296920Ssam struct nlist nl[] = { 306920Ssam #define N_IFNET 0 316920Ssam { "_ifnet" }, 326920Ssam 0, 336920Ssam }; 346920Ssam 356920Ssam struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; 366920Ssam 376920Ssam int s; 387130Swnj int snoroute; /* socket with no routing */ 396929Ssam int kmem = -1; 40*7133Swnj int supplier = -1; /* process should supply updates */ 416962Ssam int install = 1; /* if 1 call kernel */ 42*7133Swnj int timeval = -TIMER_RATE; 436920Ssam int timer(); 446920Ssam int cleanup(); 45*7133Swnj 46*7133Swnj #define tprintf if (trace) printf 476920Ssam int trace = 0; 487029Ssam FILE *ftrace; 496920Ssam 50*7133Swnj char packet[MAXPACKETSIZE+1]; 51*7133Swnj struct rip *msg = (struct rip *)packet; 526920Ssam 536934Ssam struct in_addr if_makeaddr(); 546934Ssam struct ifnet *if_ifwithaddr(), *if_ifwithnet(); 556920Ssam extern char *malloc(); 566922Ssam extern int errno, exit(); 57*7133Swnj char **argv0; 586920Ssam 59*7133Swnj int sndmsg(), supply(); 60*7133Swnj 616920Ssam main(argc, argv) 626920Ssam int argc; 636920Ssam char *argv[]; 646920Ssam { 656920Ssam int cc; 666920Ssam struct sockaddr from; 676920Ssam 68*7133Swnj argv0 = argv; 697029Ssam #ifndef DEBUG 707029Ssam if (fork()) 717029Ssam exit(0); 727029Ssam for (cc = 0; cc < 10; cc++) 737029Ssam (void) close(cc); 747029Ssam (void) open("/", 0); 757029Ssam (void) dup2(0, 1); 767029Ssam (void) dup2(0, 2); 777029Ssam { int t = open("/dev/tty", 2); 787029Ssam if (t >= 0) { 797029Ssam ioctl(t, TIOCNOTTY, (char *)0); 807029Ssam (void) close(t); 817029Ssam } 826920Ssam } 837029Ssam #endif 846920Ssam if (trace) { 857029Ssam ftrace = fopen("/etc/routerlog", "w"); 867029Ssam dup2(fileno(ftrace), 1); 877029Ssam dup2(fileno(ftrace), 2); 886920Ssam } 896937Ssam #ifdef vax || pdp11 906920Ssam myaddr.sin_port = htons(myaddr.sin_port); 916920Ssam #endif 926920Ssam again: 936920Ssam s = socket(SOCK_DGRAM, 0, &myaddr, 0); 946920Ssam if (s < 0) { 956920Ssam perror("socket"); 966920Ssam sleep(30); 976920Ssam goto again; 986920Ssam } 997130Swnj again2: 1007130Swnj snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE); 1017130Swnj if (snoroute < 0) { 1027130Swnj perror("socket"); 1037130Swnj sleep(30); 1047130Swnj goto again2; 1057130Swnj } 1066920Ssam argv++, argc--; 107*7133Swnj while (argc > 0 && **argv == '-') { 108*7133Swnj if (!strcmp(*argv, "-s") == 0) { 1096929Ssam supplier = 1; 110*7133Swnj argv++, argc--; 111*7133Swnj continue; 112*7133Swnj } 113*7133Swnj if (!strcmp(*argv, "-q") == 0) { 1146920Ssam supplier = 0; 115*7133Swnj argv++, argc--; 116*7133Swnj continue; 117*7133Swnj } 118*7133Swnj goto usage; 1196920Ssam } 120*7133Swnj if (argc > 0) { 121*7133Swnj usage: 122*7133Swnj fprintf(stderr, "usage: routed [ -s ]\n"); 123*7133Swnj exit(1); 124*7133Swnj } 125*7133Swnj rtinit(); 126*7133Swnj ifinit(); 127*7133Swnj if (supplier < 0) 128*7133Swnj supplier = 0; 129*7133Swnj gwkludge(); 130*7133Swnj msg->rip_cmd = RIPCMD_REQUEST; 131*7133Swnj msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 132*7133Swnj msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 133*7133Swnj toall(sendmsg); 1346920Ssam sigset(SIGALRM, timer); 1356929Ssam timer(); 1366920Ssam 1376920Ssam for (;;) { 1386920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1396920Ssam if (cc <= 0) { 1406920Ssam if (cc < 0 && errno != EINTR) 1416920Ssam perror("receive"); 1426920Ssam continue; 1436920Ssam } 1446920Ssam sighold(SIGALRM); 1456920Ssam rip_input(&from, cc); 1466920Ssam sigrelse(SIGALRM); 1476920Ssam } 1486920Ssam } 1496920Ssam 150*7133Swnj rtinit() 1516920Ssam { 1526934Ssam register struct rthash *rh; 1536920Ssam 154*7133Swnj for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 155*7133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 156*7133Swnj for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 157*7133Swnj rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1586920Ssam } 1596920Ssam 1606934Ssam struct ifnet *ifnet; 161*7133Swnj 162*7133Swnj ifinit() 1636920Ssam { 164*7133Swnj struct ifnet *ifp, *next; 1656929Ssam register struct sockaddr *dst; 166*7133Swnj int uniquemultihostinterfaces = 0; 1676920Ssam 168*7133Swnj nlist("/vmunix", nl); 169*7133Swnj if (nl[N_IFNET].n_value == 0) { 170*7133Swnj printf("ifnet: not in namelist\n"); 171*7133Swnj goto bad; 1726920Ssam } 173*7133Swnj kmem = open("/dev/kmem", 0); 1746920Ssam if (kmem < 0) { 175*7133Swnj perror("/dev/kmem"); 176*7133Swnj goto bad; 1776920Ssam } 1786929Ssam if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 179*7133Swnj read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) { 180*7133Swnj printf("ifnet: error reading kmem\n"); 181*7133Swnj goto bad; 1826929Ssam } 183*7133Swnj while (next) { 184*7133Swnj ifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 185*7133Swnj if (ifp == 0) { 186*7133Swnj printf("routed: out of memory\n"); 1876920Ssam break; 1886920Ssam } 189*7133Swnj if (lseek(kmem, (long)next, 0) == -1 || 190*7133Swnj read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) { 191*7133Swnj perror("read"); 192*7133Swnj goto bad; 1936929Ssam } 194*7133Swnj next = ifp->if_next; 1956929Ssam if (ifp->if_addr.sa_family != AF_INET) 196*7133Swnj continue; 1976920Ssam if (ifp->if_net == LOOPBACKNET) 198*7133Swnj continue; 1996929Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0 || 2006929Ssam if_ifwithaddr(&ifp->if_dstaddr) == 0) 201*7133Swnj uniquemultihostinterfaces++; 2026929Ssam ifp->if_next = ifnet; 2036929Ssam ifnet = ifp; 204*7133Swnj addrouteforif(ifp); 205*7133Swnj } 206*7133Swnj if (uniquemultihostinterfaces > 1 && supplier < 0) 207*7133Swnj supplier = 1; 208*7133Swnj return; 209*7133Swnj bad: 210*7133Swnj sleep(60); 211*7133Swnj execv("/etc/routed", argv0); 212*7133Swnj _exit(0177); 213*7133Swnj } 2147130Swnj 215*7133Swnj addrouteforif(ifp) 216*7133Swnj struct ifnet *ifp; 217*7133Swnj { 218*7133Swnj struct sockaddr_in net; 219*7133Swnj struct sockaddr *dst; 220*7133Swnj 221*7133Swnj if (ifp->if_flags & IFF_POINTOPOINT) 222*7133Swnj dst = &ifp->if_dstaddr; 223*7133Swnj else { 224*7133Swnj bzero((char *)&net, sizeof (net)); 225*7133Swnj net.sin_family = AF_INET; 226*7133Swnj net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 227*7133Swnj dst = (struct sockaddr *)&net; 2286920Ssam } 229*7133Swnj rtadd(dst, &ifp->if_addr, 0, RTS_INTERFACE); 2306920Ssam } 2316920Ssam 232*7133Swnj gwkludge() 2337130Swnj { 2347130Swnj struct sockaddr_in dst, gate; 2357130Swnj FILE *fp; 2367130Swnj struct rt_entry *rt; 237*7133Swnj char flags[BUFSIZ]; 2387130Swnj 2397130Swnj fp = fopen("/etc/gateways", "r"); 2407130Swnj if (fp == NULL) 2417130Swnj return; 2427130Swnj bzero((char *)&dst, sizeof (dst)); 2437130Swnj bzero((char *)&gate, sizeof (gate)); 2447130Swnj dst.sin_family = AF_INET; 2457130Swnj gate.sin_family = AF_INET; 246*7133Swnj for (;;) { 247*7133Swnj if (fscanf(fp, "dst %x gateway %x\n", &dst.sin_addr.s_addr, 248*7133Swnj &gate.sin_addr.s_addr, flags) == EOF) 249*7133Swnj break; 250*7133Swnj rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1, 251*7133Swnj RTS_GLOBAL|(!strcmp(flags, "passive") ? RTS_PASSIVE : 0)); 2527130Swnj } 2537130Swnj fclose(fp); 2547130Swnj } 2557130Swnj 256*7133Swnj timer() 2576920Ssam { 2586934Ssam register struct rthash *rh; 2596920Ssam register struct rt_entry *rt; 2606934Ssam struct rthash *base = hosthash; 261*7133Swnj int doinghost = 1, state; 2626920Ssam 263*7133Swnj timeval += TIMER_RATE; 264*7133Swnj tprintf(">>> time %d >>>\n", timeval); 2656920Ssam again: 266*7133Swnj for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 267*7133Swnj rt = rh->rt_forw; 268*7133Swnj for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 269*7133Swnj if (!(rt->rt_state & RTS_GLOBAL)) 270*7133Swnj rt->rt_timer += TIMER_RATE; 271*7133Swnj log("", rt); 272*7133Swnj if (rt->rt_timer >= EXPIRE_TIME) 273*7133Swnj rt->rt_metric = HOPCNT_INFINITY; 274*7133Swnj if ((rt->rt_state & RTS_DELRT) || 275*7133Swnj rt->rt_timer >= GARBAGE_TIME) { 276*7133Swnj if (rt->rt_state&(RTS_INTERFACE|RTS_GLOBAL)) { 277*7133Swnj if (rt->rt_timer > 9999) 278*7133Swnj rt->rt_timer = 9999; 279*7133Swnj continue; 280*7133Swnj } 281*7133Swnj rt = rt->rt_back; 282*7133Swnj rtdelete(rt->rt_forw); 283*7133Swnj continue; 284*7133Swnj } 285*7133Swnj state = rt->rt_state; 286*7133Swnj if (rt->rt_state & RTS_ADDRT) { 287*7133Swnj if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) 288*7133Swnj perror("SIOCADDRT"); 289*7133Swnj rt->rt_state &= ~RTS_ADDRT; 290*7133Swnj } 291*7133Swnj if (rt->rt_state & RTS_CHGRT) { 292*7133Swnj struct rtentry oldroute; 293*7133Swnj 294*7133Swnj oldroute = rt->rt_rt; 295*7133Swnj rt->rt_router = rt->rt_newrouter; 296*7133Swnj if (ioctl(s, SIOCADDRT,(char *)&rt->rt_rt) < 0) 297*7133Swnj perror("SIOCADDRT"); 298*7133Swnj if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 299*7133Swnj perror("SIOCDELRT"); 300*7133Swnj rt->rt_state &= ~RTS_CHGRT; 301*7133Swnj } 302*7133Swnj if (supplier && (state & (RTS_CHGRT|RTS_ADDRT))) { 303*7133Swnj log("broadcast", rt); 304*7133Swnj msg->rip_cmd = RIPCMD_RESPONSE; 305*7133Swnj msg->rip_nets[0].rip_dst = rt->rt_dst; 306*7133Swnj msg->rip_nets[0].rip_metric = 307*7133Swnj min(rt->rt_metric+1, HOPCNT_INFINITY); 308*7133Swnj sendmsgtoall(); 309*7133Swnj } 310*7133Swnj } 3116920Ssam } 3126920Ssam if (doinghost) { 313*7133Swnj doinghost = 0; 3146929Ssam base = nethash; 3156920Ssam goto again; 3166920Ssam } 317*7133Swnj if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 318*7133Swnj toall(supply); 319*7133Swnj tprintf("<<< time %d <<<\n", timeval); 320*7133Swnj alarm(TIMER_RATE); 3216920Ssam } 3226920Ssam 323*7133Swnj toall(f) 324*7133Swnj int (*f)(); 3256920Ssam { 326*7133Swnj register struct rthash *rh; 3276920Ssam register struct rt_entry *rt; 3286920Ssam register struct sockaddr *dst; 3296934Ssam struct rthash *base = hosthash; 3306920Ssam int doinghost = 1; 3316920Ssam 3326920Ssam again: 3336920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3346920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 335*7133Swnj if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0) 3366920Ssam continue; 3376920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3386920Ssam dst = &rt->rt_ifp->if_broadaddr; 3396920Ssam else 3407130Swnj dst = &rt->rt_router; 341*7133Swnj (*f)(rt, dst); 3426920Ssam } 3436920Ssam if (doinghost) { 3446920Ssam base = nethash; 3456920Ssam doinghost = 0; 3466920Ssam goto again; 3476920Ssam } 3486920Ssam } 3496920Ssam 350*7133Swnj sendmsg(rt, dst) 351*7133Swnj register struct rt_entry *rt; 352*7133Swnj struct sockaddr *dst; 353*7133Swnj { 354*7133Swnj 355*7133Swnj (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip)); 356*7133Swnj } 357*7133Swnj 358*7133Swnj supply(rt, sa) 359*7133Swnj register struct rt_entry *rt; 3606920Ssam struct sockaddr *sa; 3616920Ssam { 3626920Ssam struct netinfo *n = msg->rip_nets; 3636934Ssam register struct rthash *rh; 3646934Ssam struct rthash *base = hosthash; 3656929Ssam int doinghost = 1, size; 3666920Ssam int (*output)() = afswitch[sa->sa_family].af_output; 367*7133Swnj int sto = (rt->rt_state&RTS_INTERFACE) ? snoroute : s; 3686920Ssam 369*7133Swnj log("supply", rt); 3706920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 3716920Ssam again: 3726920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3736920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3746929Ssam size = (char *)n - packet; 3756929Ssam if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 376*7133Swnj (*output)(sto, sa, size); 3776920Ssam n = msg->rip_nets; 3786920Ssam } 3796920Ssam n->rip_dst = rt->rt_dst; 3806929Ssam n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 3816929Ssam n++; 3826920Ssam } 3836920Ssam if (doinghost) { 3846920Ssam doinghost = 0; 3856920Ssam base = nethash; 3866920Ssam goto again; 3876920Ssam } 3886929Ssam if (n != msg->rip_nets) 389*7133Swnj (*output)(sto, sa, (char *)n - packet); 3906920Ssam } 3916920Ssam 3926920Ssam /* 3936920Ssam * Respond to a routing info request. 3946920Ssam */ 3956920Ssam rip_respond(from, size) 3966920Ssam struct sockaddr *from; 3976920Ssam int size; 3986920Ssam { 3996920Ssam struct netinfo *np = msg->rip_nets; 4006920Ssam struct rt_entry *rt; 4016920Ssam int newsize = 0; 4026920Ssam 4036929Ssam size -= 4 * sizeof (char); 4046920Ssam while (size > 0) { 4056920Ssam if (size < sizeof (struct netinfo)) 4066920Ssam break; 4076920Ssam size -= sizeof (struct netinfo); 4086920Ssam if (np->rip_dst.sa_family == AF_UNSPEC && 4096920Ssam np->rip_metric == HOPCNT_INFINITY && size == 0) { 4107130Swnj supply(s, from); 4116920Ssam return; 4126920Ssam } 4136920Ssam rt = rtlookup(&np->rip_dst); 4146929Ssam np->rip_metric = rt == 0 ? 4156929Ssam HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY); 4166920Ssam np++, newsize += sizeof (struct netinfo); 4176920Ssam } 4186920Ssam if (newsize > 0) { 4196920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4206920Ssam newsize += sizeof (int); 4217130Swnj (*afswitch[from->sa_family].af_output)(s, from, newsize); 4226920Ssam } 4236920Ssam } 4246920Ssam 4256920Ssam /* 4266920Ssam * Handle an incoming routing packet. 4276920Ssam */ 4286920Ssam rip_input(from, size) 4296920Ssam struct sockaddr *from; 4306920Ssam int size; 4316920Ssam { 4326920Ssam struct rt_entry *rt; 4336920Ssam struct netinfo *n; 434*7133Swnj struct ifnet *ifp; 435*7133Swnj time_t t; 4366920Ssam 4376937Ssam switch (msg->rip_cmd) { 4386937Ssam 4396937Ssam default: 4406920Ssam return; 4416920Ssam 4426937Ssam case RIPCMD_REQUEST: 4436920Ssam rip_respond(from, size); 4446920Ssam return; 4456937Ssam 4467029Ssam case RIPCMD_TRACEON: 4477029Ssam if ((*afswitch[from->sa_family].af_portcheck)(from) == 0) 4487029Ssam return; 449*7133Swnj if (trace) 450*7133Swnj return; 451*7133Swnj packet[size] = '\0'; 452*7133Swnj ftrace = fopen(msg->rip_tracefile, "a"); 453*7133Swnj if (ftrace == NULL) 454*7133Swnj return; 455*7133Swnj (void) dup2(fileno(ftrace), 1); 456*7133Swnj (void) dup2(fileno(ftrace), 2); 457*7133Swnj trace = 1; 458*7133Swnj t = time(0); 459*7133Swnj printf("*** Tracing turned on at %.24s ***\n", ctime(&t)); 4607029Ssam return; 4617029Ssam 462*7133Swnj case RIPCMD_TRACEOFF: 463*7133Swnj /* verify message came from a priviledged port */ 464*7133Swnj if ((*afswitch[from->sa_family].af_portcheck)(from) == 0) 4656937Ssam return; 4667029Ssam if (!trace) 4677029Ssam return; 4687029Ssam t = time(0); 4697029Ssam printf("*** Tracing turned off at %.24s ***\n", ctime(&t)); 4707029Ssam fflush(stdout), fflush(stderr); 4717029Ssam if (ftrace) 4727029Ssam fclose(ftrace); 4737029Ssam (void) close(1), (void) close(2); 4747029Ssam trace = 0; 4757029Ssam return; 476*7133Swnj 477*7133Swnj case RIPCMD_RESPONSE: 478*7133Swnj /* verify message came from a router */ 479*7133Swnj if ((*afswitch[from->sa_family].af_portmatch)(from) == 0) 480*7133Swnj return; 481*7133Swnj (*afswitch[from->sa_family].af_canon)(from); 482*7133Swnj tprintf("input from %x\n", 483*7133Swnj ((struct sockaddr_in *)from)->sin_addr); 484*7133Swnj /* are we talking to ourselves? */ 485*7133Swnj ifp = if_ifwithaddr(from); 486*7133Swnj if (ifp) { 487*7133Swnj rt = rtfind(from); 488*7133Swnj if (rt) 489*7133Swnj rt->rt_timer = 0; 490*7133Swnj else 491*7133Swnj addrouteforif(ifp); 492*7133Swnj return; 493*7133Swnj } 494*7133Swnj size -= 4 * sizeof (char); 495*7133Swnj n = msg->rip_nets; 496*7133Swnj for (; size > 0; size -= sizeof (struct netinfo), n++) { 497*7133Swnj if (size < sizeof (struct netinfo)) 498*7133Swnj break; 499*7133Swnj if (n->rip_metric >= HOPCNT_INFINITY) 500*7133Swnj continue; 501*7133Swnj tprintf("dst %x hc %d...", 502*7133Swnj ((struct sockaddr_in *)&n->rip_dst)->sin_addr, 503*7133Swnj n->rip_metric); 504*7133Swnj rt = rtlookup(&n->rip_dst); 505*7133Swnj if (rt == 0) { 506*7133Swnj rtadd(&n->rip_dst, from, n->rip_metric, 0); 507*7133Swnj tprintf("new\n"); 508*7133Swnj continue; 509*7133Swnj } 510*7133Swnj tprintf("ours: gate %x hc %d timer %d\n", 511*7133Swnj ((struct sockaddr_in *)&rt->rt_router)->sin_addr, 512*7133Swnj rt->rt_metric, rt->rt_timer); 513*7133Swnj /* 514*7133Swnj * update if from gateway, shorter, or getting stale 515*7133Swnj * and equivalent. 516*7133Swnj */ 517*7133Swnj if (equal(from, &rt->rt_router) || 518*7133Swnj n->rip_metric < rt->rt_metric || 519*7133Swnj (rt->rt_timer > (EXPIRE_TIME/2) && 520*7133Swnj rt->rt_metric == n->rip_metric)) { 521*7133Swnj rtchange(rt, from, n->rip_metric); 522*7133Swnj rt->rt_timer = 0; 523*7133Swnj } 524*7133Swnj } 525*7133Swnj return; 5267029Ssam } 5277029Ssam } 5287029Ssam 5296920Ssam struct rt_entry * 5306920Ssam rtlookup(dst) 5316920Ssam struct sockaddr *dst; 5326920Ssam { 5336920Ssam register struct rt_entry *rt; 5346934Ssam register struct rthash *rh; 5357011Ssam register int hash; 5366920Ssam struct afhash h; 5377011Ssam int doinghost = 1; 5386920Ssam 5397011Ssam if (dst->sa_family >= AF_MAX) 5407011Ssam return (0); 5417011Ssam (*afswitch[dst->sa_family].af_hash)(dst, &h); 5427011Ssam hash = h.afh_hosthash; 5437011Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 5447011Ssam again: 5457011Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 5467011Ssam if (rt->rt_hash != hash) 5477011Ssam continue; 5487011Ssam if (equal(&rt->rt_dst, dst)) 5497011Ssam return (rt); 5507011Ssam } 5517011Ssam if (doinghost) { 5527011Ssam doinghost = 0; 5537011Ssam hash = h.afh_nethash; 5547011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 5557011Ssam goto again; 5567011Ssam } 5577011Ssam return (0); 5587011Ssam } 5597011Ssam 5607011Ssam struct rt_entry * 5617011Ssam rtfind(dst) 5627011Ssam struct sockaddr *dst; 5637011Ssam { 5647011Ssam register struct rt_entry *rt; 5657011Ssam register struct rthash *rh; 5667011Ssam register int hash; 5677011Ssam struct afhash h; 5687011Ssam int af = dst->sa_family; 5697011Ssam int doinghost = 1, (*match)(); 5707011Ssam 5716920Ssam if (af >= AF_MAX) 5726920Ssam return (0); 5736920Ssam (*afswitch[af].af_hash)(dst, &h); 5746920Ssam hash = h.afh_hosthash; 5756920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 5766920Ssam 5776920Ssam again: 5786920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 5796920Ssam if (rt->rt_hash != hash) 5806920Ssam continue; 5816920Ssam if (doinghost) { 5826920Ssam if (equal(&rt->rt_dst, dst)) 5836920Ssam return (rt); 5846920Ssam } else { 5856920Ssam if (rt->rt_dst.sa_family == af && 5866920Ssam (*match)(&rt->rt_dst, dst)) 5876920Ssam return (rt); 5886920Ssam } 5896920Ssam } 5906920Ssam if (doinghost) { 5916920Ssam doinghost = 0; 5926920Ssam hash = h.afh_nethash; 5937011Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 5946920Ssam match = afswitch[af].af_netmatch; 5956920Ssam goto again; 5966920Ssam } 5976920Ssam return (0); 5986920Ssam } 5996920Ssam 600*7133Swnj rtadd(dst, gate, metric, iflags) 6016920Ssam struct sockaddr *dst, *gate; 602*7133Swnj int metric, iflags; 6036920Ssam { 6046920Ssam struct afhash h; 6056920Ssam register struct rt_entry *rt; 6066934Ssam struct rthash *rh; 6076920Ssam int af = dst->sa_family, flags, hash; 6086920Ssam 6096920Ssam if (af >= AF_MAX) 6106920Ssam return; 6116920Ssam (*afswitch[af].af_hash)(dst, &h); 6126920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6136920Ssam if (flags & RTF_HOST) { 6146920Ssam hash = h.afh_hosthash; 6156920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6166920Ssam } else { 6176920Ssam hash = h.afh_nethash; 6186920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6196920Ssam } 6206920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6216920Ssam if (rt == 0) 6226920Ssam return; 6236920Ssam rt->rt_hash = hash; 6246920Ssam rt->rt_dst = *dst; 6257130Swnj rt->rt_router = *gate; 6266920Ssam rt->rt_metric = metric; 6276920Ssam rt->rt_timer = 0; 628*7133Swnj rt->rt_flags = RTF_UP | flags | iflags; 6296937Ssam rt->rt_state = 0; 6307130Swnj rt->rt_ifp = if_ifwithnet(&rt->rt_router); 6317130Swnj if (metric) 6327130Swnj rt->rt_flags |= RTF_GATEWAY; 6336920Ssam insque(rt, rh); 6346929Ssam log("add", rt); 6357130Swnj if (install) 6366937Ssam rt->rt_state |= RTS_ADDRT; 6376920Ssam } 6386920Ssam 6396920Ssam rtchange(rt, gate, metric) 6406920Ssam struct rt_entry *rt; 6416920Ssam struct sockaddr *gate; 6426920Ssam short metric; 6436920Ssam { 6446920Ssam int change = 0; 6456920Ssam 6467130Swnj if (!equal(&rt->rt_router, gate)) { 6477130Swnj rt->rt_newrouter = *gate; 6486920Ssam change++; 6496920Ssam } 6506920Ssam if (metric != rt->rt_metric) { 6517130Swnj if (metric == 0) 6527130Swnj rt->rt_flags |= RTF_GATEWAY; 6536920Ssam rt->rt_metric = metric; 6546920Ssam change++; 6556920Ssam } 6566920Ssam if (!change) 6576920Ssam return; 6586929Ssam log("change", rt); 6597130Swnj if (install) 6606937Ssam rt->rt_state |= RTS_CHGRT; 6616920Ssam } 6626920Ssam 6636920Ssam rtdelete(rt) 6646920Ssam struct rt_entry *rt; 6656920Ssam { 666*7133Swnj 6676929Ssam log("delete", rt); 6687130Swnj if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 6697130Swnj perror("SIOCDELRT"); 6707130Swnj /* don't delete interface entries so we can poll them later */ 6717130Swnj if (rt->rt_state & RTS_INTERFACE) 6727130Swnj return; 6736920Ssam remque(rt); 6746920Ssam free((char *)rt); 6756920Ssam } 6766920Ssam 6776920Ssam log(operation, rt) 6786920Ssam char *operation; 6796920Ssam struct rt_entry *rt; 6806920Ssam { 6816920Ssam time_t t = time(0); 6826920Ssam struct sockaddr_in *dst, *gate; 6836937Ssam static struct bits { 6846920Ssam int t_bits; 6856920Ssam char *t_name; 6866937Ssam } flagbits[] = { 6876920Ssam { RTF_UP, "UP" }, 6887130Swnj { RTF_GATEWAY, "GATEWAY" }, 6896920Ssam { RTF_HOST, "HOST" }, 6906920Ssam { 0 } 6916937Ssam }, statebits[] = { 6926937Ssam { RTS_DELRT, "DELETE" }, 6936937Ssam { RTS_CHGRT, "CHANGE" }, 6947130Swnj { RTS_PASSIVE, "PASSIVE" }, 6957130Swnj { RTS_INTERFACE,"INTERFACE" }, 696*7133Swnj { RTS_GLOBAL, "GLOBAL" }, 6976937Ssam { 0 } 6986920Ssam }; 6996937Ssam register struct bits *p; 7006920Ssam register int first; 7016920Ssam char *cp; 7026920Ssam 7036929Ssam if (trace == 0) 7046929Ssam return; 7056920Ssam printf("%s ", operation); 7066920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 7077130Swnj gate = (struct sockaddr_in *)&rt->rt_router; 7086937Ssam printf("dst %x, router %x, metric %d, flags", 7096920Ssam dst->sin_addr, gate->sin_addr, rt->rt_metric); 7106937Ssam cp = " %s"; 7116937Ssam for (first = 1, p = flagbits; p->t_bits > 0; p++) { 7126920Ssam if ((rt->rt_flags & p->t_bits) == 0) 7136920Ssam continue; 7146920Ssam printf(cp, p->t_name); 7156920Ssam if (first) { 7166920Ssam cp = "|%s"; 7176920Ssam first = 0; 7186920Ssam } 7196920Ssam } 7206937Ssam printf(" state"); 7216937Ssam cp = " %s"; 7226937Ssam for (first = 1, p = statebits; p->t_bits > 0; p++) { 7236937Ssam if ((rt->rt_state & p->t_bits) == 0) 7246937Ssam continue; 7256937Ssam printf(cp, p->t_name); 7266937Ssam if (first) { 7276937Ssam cp = "|%s"; 7286937Ssam first = 0; 7296937Ssam } 7306937Ssam } 7316920Ssam putchar('\n'); 7326920Ssam } 7336929Ssam 7346929Ssam struct ifnet * 7356929Ssam if_ifwithaddr(addr) 7366929Ssam struct sockaddr *addr; 7376929Ssam { 7386929Ssam register struct ifnet *ifp; 7396929Ssam 7406929Ssam #define same(a1, a2) \ 7416929Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 7426929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 7436929Ssam if (ifp->if_addr.sa_family != addr->sa_family) 7446929Ssam continue; 7456929Ssam if (same(&ifp->if_addr, addr)) 7466929Ssam break; 7476929Ssam if ((ifp->if_flags & IFF_BROADCAST) && 7486929Ssam same(&ifp->if_broadaddr, addr)) 7496929Ssam break; 7506929Ssam } 7516929Ssam return (ifp); 7526929Ssam #undef same 7536929Ssam } 7546929Ssam 7556929Ssam struct ifnet * 7566929Ssam if_ifwithnet(addr) 7576929Ssam register struct sockaddr *addr; 7586929Ssam { 7596929Ssam register struct ifnet *ifp; 7606929Ssam register int af = addr->sa_family; 7616929Ssam register int (*netmatch)(); 7626929Ssam 7636929Ssam if (af >= AF_MAX) 7646929Ssam return (0); 7656929Ssam netmatch = afswitch[af].af_netmatch; 7666929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 7676929Ssam if (af != ifp->if_addr.sa_family) 7686929Ssam continue; 7696929Ssam if ((*netmatch)(addr, &ifp->if_addr)) 7706929Ssam break; 7716929Ssam } 7726929Ssam return (ifp); 7736929Ssam } 7746929Ssam 7756929Ssam struct in_addr 7766929Ssam if_makeaddr(net, host) 7776929Ssam int net, host; 7786929Ssam { 7796929Ssam u_long addr; 7806929Ssam 7816929Ssam if (net < 128) 7826929Ssam addr = (net << 24) | host; 7836929Ssam else if (net < 65536) 7846929Ssam addr = (net << 16) | host; 7856929Ssam else 7866929Ssam addr = (net << 8) | host; 7876929Ssam #ifdef vax 7886929Ssam addr = htonl(addr); 7896929Ssam #endif 7906929Ssam return (*(struct in_addr *)&addr); 7916929Ssam } 792