16920Ssam #ifndef lint 2*6922Ssam static char sccsid[] = "@(#)routed.c 4.2 05/23/82"; 36920Ssam #endif 46920Ssam 56920Ssam #include <sys/param.h> 66920Ssam #include <sys/protosw.h> 76920Ssam #include <sys/ioctl.h> 86920Ssam #include <sys/socket.h> 96920Ssam #include <net/in.h> 106920Ssam #define KERNEL 116920Ssam #include <net/route.h> 126920Ssam #include <net/if.h> 136920Ssam #include <errno.h> 146920Ssam #include <stdio.h> 156920Ssam #include <nlist.h> 166920Ssam #include <signal.h> 176920Ssam #include "rip.h" 186920Ssam #include "router.h" 196920Ssam 206920Ssam #define LOOPBACKNET 0177 216920Ssam /* casts to keep lint happy */ 226920Ssam #define insque(q,p) _insque((caddr_t)q,(caddr_t)p) 236920Ssam #define remque(q) _remque((caddr_t)q) 246920Ssam #define equal(a1, a2) \ 256920Ssam (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 266920Ssam 276920Ssam struct nlist nl[] = { 286920Ssam #define N_IFNET 0 296920Ssam { "_ifnet" }, 306920Ssam 0, 316920Ssam }; 326920Ssam 336920Ssam struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; 346920Ssam 356920Ssam int s; 366920Ssam int kmem; 376920Ssam int supplier; /* process should supply updates */ 386920Ssam int initializing; /* stem off broadcast() calls */ 396920Ssam int install = 0; /* if 1 call kernel */ 406920Ssam int timeval; 416920Ssam int timer(); 426920Ssam int cleanup(); 436920Ssam int trace = 0; 446920Ssam 456920Ssam char packet[MAXPACKETSIZE]; 466920Ssam 476920Ssam extern char *malloc(); 48*6922Ssam extern int errno, exit(); 496920Ssam 506920Ssam main(argc, argv) 516920Ssam int argc; 526920Ssam char *argv[]; 536920Ssam { 546920Ssam int cc; 556920Ssam struct sockaddr from; 566920Ssam 576920Ssam { int t = open("/dev/tty", 2); 586920Ssam if (t >= 0) { 596920Ssam ioctl(t, TIOCNOTTY, 0); 606920Ssam close(t); 616920Ssam } 626920Ssam } 636920Ssam if (trace) { 646920Ssam (void) fclose(stdout); 656920Ssam (void) fclose(stderr); 666920Ssam (void) fopen("trace", "a"); 676920Ssam (void) dup(fileno(stdout)); 686920Ssam setbuf(stdout, NULL); 696920Ssam 706920Ssam } 716920Ssam #ifdef vax 726920Ssam myaddr.sin_port = htons(myaddr.sin_port); 736920Ssam #endif 746920Ssam again: 756920Ssam s = socket(SOCK_DGRAM, 0, &myaddr, 0); 766920Ssam if (s < 0) { 776920Ssam perror("socket"); 786920Ssam sleep(30); 796920Ssam goto again; 806920Ssam } 816920Ssam rtinit(); 826920Ssam getothers(); 836920Ssam getinterfaces(); 846920Ssam request(); 856920Ssam 866920Ssam argv++, argc--; 876920Ssam while (argc > 0) { 886920Ssam if (strcmp(*argv, "-s") == 0) 896920Ssam supplier++; 906920Ssam else if (strcmp(*argv, "-q") == 0) 916920Ssam supplier = 0; 926920Ssam argv++, argc--; 936920Ssam } 94*6922Ssam sigset(SIGTERM, exit); 956920Ssam sigset(SIGALRM, timer); 966920Ssam alarm(TIMER_RATE); 976920Ssam 986920Ssam /* 996920Ssam * Listen for routing packets 1006920Ssam */ 1016920Ssam for (;;) { 1026920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1036920Ssam if (cc <= 0) { 1046920Ssam if (cc < 0 && errno != EINTR) 1056920Ssam perror("receive"); 1066920Ssam continue; 1076920Ssam } 1086920Ssam sighold(SIGALRM); 1096920Ssam rip_input(&from, cc); 1106920Ssam sigrelse(SIGALRM); 1116920Ssam } 1126920Ssam } 1136920Ssam 1146920Ssam /* 1156920Ssam * Look in a file for any gateways we should configure 1166920Ssam * outside the directly connected ones. This is a kludge, 1176920Ssam * but until we can find out about gateways on the "other side" 1186920Ssam * of the ARPANET using GGP, it's a must. 1196920Ssam * 1206920Ssam * We don't really know the distance to the gateway, so we 1216920Ssam * assume it's a neighbor. 1226920Ssam */ 1236920Ssam getothers() 1246920Ssam { 1256920Ssam struct sockaddr_in dst, gate; 1266920Ssam FILE *fp = fopen("/etc/gateways", "r"); 1276920Ssam struct rt_entry *rt; 1286920Ssam 1296920Ssam if (fp == NULL) 1306920Ssam return; 1316920Ssam bzero((char *)&dst, sizeof (dst)); 1326920Ssam bzero((char *)&gate, sizeof (gate)); 1336920Ssam dst.sin_family = AF_INET; 1346920Ssam gate.sin_family = AF_INET; 1356920Ssam while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, 1366920Ssam &gate.sin_addr.s_addr) != EOF) { 1376920Ssam rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1); 1386920Ssam rt = rtlookup((struct sockaddr *)&dst); 1396920Ssam if (rt) 1406920Ssam rt->rt_flags |= RTF_SILENT; 1416920Ssam } 1426920Ssam fclose(fp); 1436920Ssam } 1446920Ssam 1456920Ssam struct ifnet * 1466920Ssam if_ifwithaddr(addr) 1476920Ssam struct sockaddr *addr; 1486920Ssam { 1496920Ssam register struct ifnet *ifp; 1506920Ssam 1516920Ssam #define same(a1, a2) \ 1526920Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 1536920Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1546920Ssam if (ifp->if_addr.sa_family != addr->sa_family) 1556920Ssam continue; 1566920Ssam if (same(&ifp->if_addr, addr)) 1576920Ssam break; 1586920Ssam if ((ifp->if_flags & IFF_BROADCAST) && 1596920Ssam same(&ifp->if_broadaddr, addr)) 1606920Ssam break; 1616920Ssam } 1626920Ssam return (ifp); 1636920Ssam #undef same 1646920Ssam } 1656920Ssam 1666920Ssam struct ifnet * 1676920Ssam if_ifwithnet(addr) 1686920Ssam register struct sockaddr *addr; 1696920Ssam { 1706920Ssam register struct ifnet *ifp; 1716920Ssam register int af = addr->sa_family; 1726920Ssam register int (*netmatch)(); 1736920Ssam 1746920Ssam if (af >= AF_MAX) 1756920Ssam return (0); 1766920Ssam netmatch = afswitch[af].af_netmatch; 1776920Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 1786920Ssam if (af != ifp->if_addr.sa_family) 1796920Ssam continue; 1806920Ssam if ((*netmatch)(addr, &ifp->if_addr)) 1816920Ssam break; 1826920Ssam } 1836920Ssam return (ifp); 1846920Ssam } 1856920Ssam 1866920Ssam struct in_addr 1876920Ssam if_makeaddr(net, host) 1886920Ssam int net, host; 1896920Ssam { 1906920Ssam u_long addr; 1916920Ssam 1926920Ssam if (net < 128) 1936920Ssam addr = (net << 24) | host; 1946920Ssam else if (net < 65536) 1956920Ssam addr = (net << 16) | host; 1966920Ssam else 1976920Ssam addr = (net << 8) | host; 1986920Ssam #ifdef vax 1996920Ssam addr = htonl(addr); 2006920Ssam #endif 2016920Ssam return (*(struct in_addr *)&addr); 2026920Ssam } 2036920Ssam 2046920Ssam /* 2056920Ssam * Find the network interfaces attached to this machine. 2066920Ssam * The info is used to:: 2076920Ssam * 2086920Ssam * (1) initialize the routing tables, as done by the kernel. 2096920Ssam * (2) ignore incoming packets we send. 2106920Ssam * (3) figure out broadcast capability and addresses. 2116920Ssam * (4) figure out if we're an internetwork gateway. 2126920Ssam * 2136920Ssam * We don't handle anything but Internet addresses. 2146920Ssam */ 2156920Ssam getinterfaces() 2166920Ssam { 2176920Ssam register struct ifnet **pifp, *ifp; 2186920Ssam struct sockaddr_in net; 2196920Ssam struct in_addr logicaladdr; 2206920Ssam int nets; 2216920Ssam 2226920Ssam nlist("/vmunix", nl); 2236920Ssam if (nl[N_IFNET].n_value == 0) { 2246920Ssam printf("ifnet: symbol not in namelist\n"); 2256920Ssam exit(1); 2266920Ssam } 2276920Ssam kmem = open("/dev/kmem", 0); 2286920Ssam if (kmem < 0) { 2296920Ssam perror("/dev/kmem"); 2306920Ssam exit(1); 2316920Ssam } 2326920Ssam (void) lseek(kmem, (long)nl[N_IFNET].n_value, 0); 2336920Ssam (void) read(kmem, (char *)&ifnet, sizeof (ifnet)); 2346920Ssam bzero((char *)&net, sizeof (net)); 2356920Ssam net.sin_family = AF_INET; 2366920Ssam logicaladdr.s_addr = 0; 2376920Ssam nets = 0; 2386920Ssam pifp = &ifnet; 2396920Ssam initializing = 1; 2406920Ssam while (*pifp) { 2416920Ssam struct sockaddr_in *sin; 2426920Ssam 2436920Ssam (void) lseek(kmem, (long)*pifp, 0); 2446920Ssam ifp = *pifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 2456920Ssam if (ifp == 0) { 2466920Ssam printf("routed: out of memory\n"); 2476920Ssam break; 2486920Ssam } 2496920Ssam if (read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) { 2506920Ssam perror("read"); 2516920Ssam break; 2526920Ssam } 2536920Ssam if (ifp->if_net == LOOPBACKNET) 2546920Ssam goto skip; 2556920Ssam nets++; 2566920Ssam if ((ifp->if_flags & IFF_UP) == 0) 2576920Ssam goto skip; 2586920Ssam 2596920Ssam /* 2606920Ssam * Kludge: don't treat logical host pseudo-interface 2616920Ssam * as a net route, instead fabricate route 2626920Ssam * to get packets back from the gateway. 2636920Ssam */ 2646920Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 2656920Ssam if (sin->sin_family == AF_INET && ifp->if_net == 10 && 2666920Ssam sin->sin_addr.s_lh) { 2676920Ssam logicaladdr = sin->sin_addr; 2686920Ssam goto skip; 2696920Ssam } 2706920Ssam 2716920Ssam /* 2726920Ssam * Before we can handle point-point links, the interface 2736920Ssam * structure will have to include an indicator to allow 2746920Ssam * us to distinguish entries from "network" entries. 2756920Ssam */ 2766920Ssam net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 2776920Ssam rtadd((struct sockaddr *)&net, (struct sockaddr *)sin, 0); 2786920Ssam skip: 2796920Ssam pifp = &ifp->if_next; 2806920Ssam } 2816920Ssam if (logicaladdr.s_addr) { 2826920Ssam struct rt_entry *rt; 2836920Ssam 2846920Ssam net.sin_addr = logicaladdr; 2856920Ssam if (ifnet) 2866920Ssam rtadd((struct sockaddr *)&net, &ifnet->if_addr, 0); 2876920Ssam /* yech...yet another logical host kludge */ 2886920Ssam rt = rtlookup((struct sockaddr *)&net); 2896920Ssam if (rt) 2906920Ssam rt->rt_flags |= RTF_SILENT; 2916920Ssam } 2926920Ssam (void) close(kmem); 2936920Ssam initializing = 0; 2946920Ssam supplier = nets > 1; 2956920Ssam } 2966920Ssam 2976920Ssam /* 2986920Ssam * Send a request message to all directly 2996920Ssam * connected hosts and networks. 3006920Ssam */ 3016920Ssam request() 3026920Ssam { 3036920Ssam register struct rt_entry *rt; 3046920Ssam register struct rt_hash *rh; 3056920Ssam struct rt_hash *base = hosthash; 3066920Ssam int doinghost = 1; 3076920Ssam 3086920Ssam again: 3096920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3106920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3116920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 3126920Ssam continue; 3136920Ssam getall(rt); 3146920Ssam } 3156920Ssam if (doinghost) { 3166920Ssam base = nethash; 3176920Ssam doinghost = 0; 3186920Ssam goto again; 3196920Ssam } 3206920Ssam } 3216920Ssam 3226920Ssam /* 3236920Ssam * Broadcast a new, or modified, routing table entry 3246920Ssam * to all directly connected hosts and networks. 3256920Ssam */ 3266920Ssam broadcast(entry) 3276920Ssam struct rt_entry *entry; 3286920Ssam { 3296920Ssam register struct rt_hash *rh; 3306920Ssam register struct rt_entry *rt; 3316920Ssam register struct sockaddr *dst; 3326920Ssam struct rt_hash *base = hosthash; 3336920Ssam int doinghost = 1; 3346920Ssam struct rip *msg = (struct rip *)packet; 3356920Ssam 3366920Ssam if (trace) 3376920Ssam log("broadcast", entry); 3386920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 3396920Ssam msg->rip_nets[0].rip_dst = entry->rt_dst; 3406920Ssam msg->rip_nets[0].rip_metric = entry->rt_metric + 1; 3416920Ssam 3426920Ssam again: 3436920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3446920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3456920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 3466920Ssam continue; 3476920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3486920Ssam dst = &rt->rt_ifp->if_broadaddr; 3496920Ssam else 3506920Ssam dst = &rt->rt_gateway; 3516920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 3526920Ssam } 3536920Ssam if (doinghost) { 3546920Ssam doinghost = 0; 3556920Ssam base = nethash; 3566920Ssam goto again; 3576920Ssam } 3586920Ssam } 3596920Ssam 3606920Ssam /* 3616920Ssam * Supply all directly connected neighbors with the 3626920Ssam * current state of the routing tables. 3636920Ssam */ 3646920Ssam supplyall() 3656920Ssam { 3666920Ssam register struct rt_entry *rt; 3676920Ssam register struct rt_hash *rh; 3686920Ssam register struct sockaddr *dst; 3696920Ssam struct rt_hash *base = hosthash; 3706920Ssam int doinghost = 1; 3716920Ssam 3726920Ssam again: 3736920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3746920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3756920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 3766920Ssam continue; 3776920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3786920Ssam dst = &rt->rt_ifp->if_broadaddr; 3796920Ssam else 3806920Ssam dst = &rt->rt_gateway; 3816920Ssam if (trace) 3826920Ssam log("supply", rt); 3836920Ssam supply(dst); 3846920Ssam } 3856920Ssam if (doinghost) { 3866920Ssam base = nethash; 3876920Ssam doinghost = 0; 3886920Ssam goto again; 3896920Ssam } 3906920Ssam } 3916920Ssam 3926920Ssam /* 3936920Ssam * Supply routing information to target "sa". 3946920Ssam */ 3956920Ssam supply(sa) 3966920Ssam struct sockaddr *sa; 3976920Ssam { 3986920Ssam struct rip *msg = (struct rip *)packet; 3996920Ssam struct netinfo *n = msg->rip_nets; 4006920Ssam register struct rt_hash *rh; 4016920Ssam register struct rt_entry *rt; 4026920Ssam struct rt_hash *base = hosthash; 4036920Ssam int space = MAXPACKETSIZE - sizeof (int), doinghost = 1; 4046920Ssam int (*output)() = afswitch[sa->sa_family].af_output; 4056920Ssam 4066920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4076920Ssam again: 4086920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 4096920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4106920Ssam 4116920Ssam /* 4126920Ssam * Flush packet out if not enough room for 4136920Ssam * another routing table entry. 4146920Ssam */ 4156920Ssam if (space < sizeof (struct netinfo)) { 4166920Ssam (*output)(sa, MAXPACKETSIZE - space); 4176920Ssam space = MAXPACKETSIZE - sizeof (int); 4186920Ssam n = msg->rip_nets; 4196920Ssam } 4206920Ssam n->rip_dst = rt->rt_dst; 4216920Ssam n->rip_metric = rt->rt_metric + 1; 4226920Ssam n++, space -= sizeof (struct netinfo); 4236920Ssam } 4246920Ssam if (doinghost) { 4256920Ssam doinghost = 0; 4266920Ssam base = nethash; 4276920Ssam goto again; 4286920Ssam } 4296920Ssam 4306920Ssam if (space < MAXPACKETSIZE - sizeof (int)) 4316920Ssam (*output)(sa, MAXPACKETSIZE - space); 4326920Ssam } 4336920Ssam 4346920Ssam getall(rt) 4356920Ssam struct rt_entry *rt; 4366920Ssam { 4376920Ssam register struct rip *msg = (struct rip *)packet; 4386920Ssam struct sockaddr *dst; 4396920Ssam 4406920Ssam msg->rip_cmd = RIPCMD_REQUEST; 4416920Ssam msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 4426920Ssam msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 4436920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 4446920Ssam dst = &rt->rt_ifp->if_broadaddr; 4456920Ssam else 4466920Ssam dst = &rt->rt_gateway; 4476920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 4486920Ssam } 4496920Ssam 4506920Ssam /* 4516920Ssam * Respond to a routing info request. 4526920Ssam */ 4536920Ssam rip_respond(from, size) 4546920Ssam struct sockaddr *from; 4556920Ssam int size; 4566920Ssam { 4576920Ssam register struct rip *msg = (struct rip *)packet; 4586920Ssam struct netinfo *np = msg->rip_nets; 4596920Ssam struct rt_entry *rt; 4606920Ssam int newsize = 0; 4616920Ssam 4626920Ssam size -= sizeof (int); 4636920Ssam while (size > 0) { 4646920Ssam if (size < sizeof (struct netinfo)) 4656920Ssam break; 4666920Ssam size -= sizeof (struct netinfo); 4676920Ssam if (np->rip_dst.sa_family == AF_UNSPEC && 4686920Ssam np->rip_metric == HOPCNT_INFINITY && size == 0) { 4696920Ssam supply(from); 4706920Ssam return; 4716920Ssam } 4726920Ssam rt = rtlookup(&np->rip_dst); 4736920Ssam np->rip_metric = rt == 0 ? HOPCNT_INFINITY : rt->rt_metric + 1; 4746920Ssam np++, newsize += sizeof (struct netinfo); 4756920Ssam } 4766920Ssam if (newsize > 0) { 4776920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4786920Ssam newsize += sizeof (int); 4796920Ssam (*afswitch[from->sa_family].af_output)(from, newsize); 4806920Ssam } 4816920Ssam } 4826920Ssam 4836920Ssam /* 4846920Ssam * Handle an incoming routing packet. 4856920Ssam */ 4866920Ssam rip_input(from, size) 4876920Ssam struct sockaddr *from; 4886920Ssam int size; 4896920Ssam { 4906920Ssam register struct rip *msg = (struct rip *)packet; 4916920Ssam struct rt_entry *rt; 4926920Ssam struct netinfo *n; 4936920Ssam 4946920Ssam if (msg->rip_cmd != RIPCMD_RESPONSE && 4956920Ssam msg->rip_cmd != RIPCMD_REQUEST) 4966920Ssam return; 4976920Ssam 4986920Ssam /* 4996920Ssam * The router port is in the lower 1K of the UDP port space, 5006920Ssam * and so is priviledged. Hence we can "authenticate" incoming 5016920Ssam * updates simply by checking the source port. 5026920Ssam */ 5036920Ssam if (msg->rip_cmd == RIPCMD_RESPONSE && 5046920Ssam (*afswitch[from->sa_family].af_portmatch)(from) == 0) 5056920Ssam return; 5066920Ssam if (msg->rip_cmd == RIPCMD_REQUEST) { 5076920Ssam rip_respond(from, size); 5086920Ssam return; 5096920Ssam } 5106920Ssam 5116920Ssam /* 5126920Ssam * Process updates. 5136920Ssam * Extraneous information like Internet ports 5146920Ssam * must first be purged from the sender's address for 5156920Ssam * pattern matching below. 5166920Ssam */ 5176920Ssam (*afswitch[from->sa_family].af_canon)(from); 5186920Ssam if (trace) 5196920Ssam printf("input from %x\n", from->sin_addr); 5206920Ssam /* 5216920Ssam * If response packet is from ourselves, use it only 5226920Ssam * to reset timer on entry. Otherwise, we'd believe 5236920Ssam * it as gospel (since it comes from the router) and 5246920Ssam * unknowingly update the metric to show the outgoing 5256920Ssam * cost (higher than our real cost). I guess the protocol 5266920Ssam * spec doesn't address this because Xerox Ethernets 5276920Ssam * don't hear their own broadcasts? 5286920Ssam */ 5296920Ssam if (if_ifwithaddr(from)) { 5306920Ssam rt = rtlookup(from); 5316920Ssam if (rt) 5326920Ssam rt->rt_timer = 0; 5336920Ssam return; 5346920Ssam } 5356920Ssam size -= sizeof (int); 5366920Ssam n = msg->rip_nets; 5376920Ssam for (; size > 0; size -= sizeof (struct netinfo), n++) { 5386920Ssam if (size < sizeof (struct netinfo)) 5396920Ssam break; 5406920Ssam if (trace) 5416920Ssam printf("dst %x hc %d...", n->rip_dst.sin_addr, 5426920Ssam n->rip_metric); 5436920Ssam rt = rtlookup(&n->rip_dst); 5446920Ssam 5456920Ssam /* 5466920Ssam * Unknown entry, add it to the tables only if 5476920Ssam * its interesting. 5486920Ssam */ 5496920Ssam if (rt == 0) { 5506920Ssam if (n->rip_metric < HOPCNT_INFINITY) 5516920Ssam rtadd(&n->rip_dst, from, n->rip_metric); 5526920Ssam if (trace) 5536920Ssam printf("new\n"); 5546920Ssam continue; 5556920Ssam } 5566920Ssam 5576920Ssam if (trace) 5586920Ssam printf("ours: gate %x hc %d timer %d\n", 5596920Ssam rt->rt_gateway.sin_addr, 5606920Ssam rt->rt_metric, rt->rt_timer); 5616920Ssam /* 5626920Ssam * Update the entry if one of the following is true: 5636920Ssam * 5646920Ssam * (1) The update came directly from the gateway. 5656920Ssam * (2) A shorter path is provided. 5666920Ssam * (3) The entry hasn't been updated in a while 5676920Ssam * and a path of equivalent cost is offered. 5686920Ssam */ 5696920Ssam if (equal(from, &rt->rt_gateway) || 5706920Ssam rt->rt_metric > n->rip_metric || 5716920Ssam (rt->rt_timer > (EXPIRE_TIME/2) && 5726920Ssam rt->rt_metric == n->rip_metric)) { 5736920Ssam rtchange(rt, from, n->rip_metric); 5746920Ssam rt->rt_timer = 0; 5756920Ssam } 5766920Ssam } 5776920Ssam } 5786920Ssam 5796920Ssam /* 5806920Ssam * Lookup an entry to the appropriate dstination. 5816920Ssam */ 5826920Ssam struct rt_entry * 5836920Ssam rtlookup(dst) 5846920Ssam struct sockaddr *dst; 5856920Ssam { 5866920Ssam register struct rt_entry *rt; 5876920Ssam register struct rt_hash *rh; 5886920Ssam register int hash, (*match)(); 5896920Ssam struct afhash h; 5906920Ssam int af = dst->sa_family, doinghost = 1; 5916920Ssam 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; 6026920Ssam if (doinghost) { 6036920Ssam if (equal(&rt->rt_dst, dst)) 6046920Ssam return (rt); 6056920Ssam } else { 6066920Ssam if (rt->rt_dst.sa_family == af && 6076920Ssam (*match)(&rt->rt_dst, dst)) 6086920Ssam return (rt); 6096920Ssam } 6106920Ssam } 6116920Ssam if (doinghost) { 6126920Ssam doinghost = 0; 6136920Ssam hash = h.afh_nethash; 6146920Ssam match = afswitch[af].af_netmatch; 6156920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6166920Ssam goto again; 6176920Ssam } 6186920Ssam return (0); 6196920Ssam } 6206920Ssam 6216920Ssam rtinit() 6226920Ssam { 6236920Ssam register struct rt_hash *rh; 6246920Ssam 6256920Ssam for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 6266920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6276920Ssam for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 6286920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6296920Ssam } 6306920Ssam 6316920Ssam /* 6326920Ssam * Add a new entry. 6336920Ssam */ 6346920Ssam rtadd(dst, gate, metric) 6356920Ssam struct sockaddr *dst, *gate; 6366920Ssam short metric; 6376920Ssam { 6386920Ssam struct afhash h; 6396920Ssam register struct rt_entry *rt; 6406920Ssam struct rt_hash *rh; 6416920Ssam int af = dst->sa_family, flags, hash; 6426920Ssam 6436920Ssam if (af >= AF_MAX) 6446920Ssam return; 6456920Ssam (*afswitch[af].af_hash)(dst, &h); 6466920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6476920Ssam if (flags & RTF_HOST) { 6486920Ssam hash = h.afh_hosthash; 6496920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6506920Ssam } else { 6516920Ssam hash = h.afh_nethash; 6526920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6536920Ssam } 6546920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6556920Ssam if (rt == 0) 6566920Ssam return; 6576920Ssam rt->rt_hash = hash; 6586920Ssam rt->rt_dst = *dst; 6596920Ssam rt->rt_gateway = *gate; 6606920Ssam rt->rt_metric = metric; 6616920Ssam rt->rt_timer = 0; 6626920Ssam rt->rt_flags = RTF_UP | flags; 6636920Ssam rt->rt_ifp = if_ifwithnet(&rt->rt_gateway); 6646920Ssam if (metric == 0) 6656920Ssam rt->rt_flags |= RTF_DIRECT; 6666920Ssam insque(rt, rh); 6676920Ssam if (trace) 6686920Ssam log("add", rt); 6696920Ssam if (initializing) 6706920Ssam return; 6716920Ssam if (supplier) 6726920Ssam broadcast(rt); 6736920Ssam if (install) { 6746920Ssam rt->rt_flags |= RTF_ADDRT; 6756920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 6766920Ssam } 6776920Ssam } 6786920Ssam 6796920Ssam /* 6806920Ssam * Look to see if a change to an existing entry 6816920Ssam * is warranted; if so, make it. 6826920Ssam */ 6836920Ssam rtchange(rt, gate, metric) 6846920Ssam struct rt_entry *rt; 6856920Ssam struct sockaddr *gate; 6866920Ssam short metric; 6876920Ssam { 6886920Ssam int change = 0; 6896920Ssam 6906920Ssam if (!equal(&rt->rt_gateway, gate)) { 6916920Ssam rt->rt_gateway = *gate; 6926920Ssam change++; 6936920Ssam } 6946920Ssam 6956920Ssam /* 6966920Ssam * If the hop count has changed, adjust 6976920Ssam * the flags in the routing table entry accordingly. 6986920Ssam */ 6996920Ssam if (metric != rt->rt_metric) { 7006920Ssam if (rt->rt_metric == 0) 7016920Ssam rt->rt_flags &= ~RTF_DIRECT; 7026920Ssam rt->rt_metric = metric; 7036920Ssam if (metric >= HOPCNT_INFINITY) 7046920Ssam rt->rt_flags &= ~RTF_UP; 7056920Ssam else 7066920Ssam rt->rt_flags |= RTF_UP; 7076920Ssam change++; 7086920Ssam } 7096920Ssam 7106920Ssam if (!change) 7116920Ssam return; 7126920Ssam if (supplier) 7136920Ssam broadcast(rt); 7146920Ssam if (trace) 7156920Ssam log("change", rt); 7166920Ssam if (install) { 7176920Ssam rt->rt_flags |= RTF_CHGRT; 7186920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 7196920Ssam } 7206920Ssam } 7216920Ssam 7226920Ssam /* 7236920Ssam * Delete a routing table entry. 7246920Ssam */ 7256920Ssam rtdelete(rt) 7266920Ssam struct rt_entry *rt; 7276920Ssam { 7286920Ssam if (trace) 7296920Ssam log("delete", rt); 7306920Ssam if (install) 7316920Ssam if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) && 7326920Ssam errno == EBUSY) 7336920Ssam rt->rt_flags |= RTF_DELRT; 7346920Ssam remque(rt); 7356920Ssam free((char *)rt); 7366920Ssam } 7376920Ssam 7386920Ssam /* 7396920Ssam * Timer routine: 7406920Ssam * 7416920Ssam * o handle timers on table entries, 7426920Ssam * o invalidate entries which haven't been updated in a while, 7436920Ssam * o delete entries which are too old, 7446920Ssam * o retry ioctl's which weren't successful the first 7456920Ssam * time due to the kernel entry being busy 7466920Ssam * o if we're an internetwork router, supply routing updates 7476920Ssam * periodically 7486920Ssam */ 7496920Ssam timer() 7506920Ssam { 7516920Ssam register struct rt_hash *rh; 7526920Ssam register struct rt_entry *rt; 7536920Ssam struct rt_hash *base = hosthash; 7546920Ssam int doinghost = 1; 7556920Ssam 7566920Ssam if (trace) 7576920Ssam printf(">>> time %d >>>\n", timeval); 7586920Ssam again: 7596920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 7606920Ssam rt = rh->rt_forw; 7616920Ssam for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 7626920Ssam 7636920Ssam /* 7646920Ssam * If the host is indicated to be 7656920Ssam * "silent" (i.e. it's a logical host, 7666920Ssam * or one we got from the initialization 7676920Ssam * file), don't time out it's entry. 7686920Ssam */ 7696920Ssam if (rt->rt_flags & RTF_SILENT) 7706920Ssam continue; 7716920Ssam if (trace) 7726920Ssam log("", rt); 7736920Ssam rt->rt_timer += TIMER_RATE; 7746920Ssam if (rt->rt_timer >= GARBAGE_TIME || 7756920Ssam (rt->rt_flags & RTF_DELRT)) { 7766920Ssam rt = rt->rt_forw; 7776920Ssam rtdelete(rt->rt_back); 7786920Ssam rt = rt->rt_back; 7796920Ssam continue; 7806920Ssam } 7816920Ssam if (rt->rt_timer >= EXPIRE_TIME) 7826920Ssam rt->rt_metric = HOPCNT_INFINITY; 7836920Ssam if (rt->rt_flags & RTF_CHGRT) 7846920Ssam if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) || 7856920Ssam --rt->rt_retry == 0) 7866920Ssam rt->rt_flags &= ~RTF_CHGRT; 7876920Ssam if (rt->rt_flags & RTF_ADDRT) 7886920Ssam if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash) || 7896920Ssam --rt->rt_retry == 0) 7906920Ssam rt->rt_flags &= ~RTF_ADDRT; 7916920Ssam } 7926920Ssam } 7936920Ssam if (doinghost) { 7946920Ssam doinghost = 0; 7956920Ssam base = nethash; 7966920Ssam goto again; 7976920Ssam } 7986920Ssam timeval += TIMER_RATE; 7996920Ssam if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 8006920Ssam supplyall(); 8016920Ssam if (trace) 8026920Ssam printf("<<< time %d <<<\n", timeval); 8036920Ssam alarm(TIMER_RATE); 8046920Ssam } 8056920Ssam 8066920Ssam log(operation, rt) 8076920Ssam char *operation; 8086920Ssam struct rt_entry *rt; 8096920Ssam { 8106920Ssam time_t t = time(0); 8116920Ssam struct sockaddr_in *dst, *gate; 8126920Ssam static struct flagbits { 8136920Ssam int t_bits; 8146920Ssam char *t_name; 8156920Ssam } bits[] = { 8166920Ssam { RTF_UP, "UP" }, 8176920Ssam { RTF_DIRECT, "DIRECT" }, 8186920Ssam { RTF_HOST, "HOST" }, 8196920Ssam { RTF_DELRT, "DELETE" }, 8206920Ssam { RTF_CHGRT, "CHANGE" }, 8216920Ssam { RTF_SILENT, "SILENT" }, 8226920Ssam { 0 } 8236920Ssam }; 8246920Ssam register struct flagbits *p; 8256920Ssam register int first; 8266920Ssam char *cp; 8276920Ssam 8286920Ssam printf("%s ", operation); 8296920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 8306920Ssam gate = (struct sockaddr_in *)&rt->rt_gateway; 8316920Ssam printf("dst %x, router %x, metric %d, flags ", 8326920Ssam dst->sin_addr, gate->sin_addr, rt->rt_metric); 8336920Ssam cp = "%s"; 8346920Ssam for (first = 1, p = bits; p->t_bits > 0; p++) { 8356920Ssam if ((rt->rt_flags & p->t_bits) == 0) 8366920Ssam continue; 8376920Ssam printf(cp, p->t_name); 8386920Ssam if (first) { 8396920Ssam cp = "|%s"; 8406920Ssam first = 0; 8416920Ssam } 8426920Ssam } 8436920Ssam putchar('\n'); 8446920Ssam } 845