16920Ssam #ifndef lint 2*6933Ssam static char sccsid[] = "@(#)routed.c 4.5 05/25/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) 266929Ssam #define min(a,b) ((a)>(b)?(b):(a)) 276920Ssam 286920Ssam struct nlist nl[] = { 296920Ssam #define N_IFNET 0 306920Ssam { "_ifnet" }, 316920Ssam 0, 326920Ssam }; 336920Ssam 346920Ssam struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; 356920Ssam 366920Ssam int s; 376929Ssam int kmem = -1; 386920Ssam int supplier; /* process should supply updates */ 396920Ssam int initializing; /* stem off broadcast() calls */ 406920Ssam int install = 0; /* if 1 call kernel */ 416929Ssam int lookforinterfaces = 1; 426929Ssam int performnlist = 1; 436920Ssam int timeval; 446920Ssam int timer(); 456920Ssam int cleanup(); 466920Ssam int trace = 0; 476920Ssam 486920Ssam char packet[MAXPACKETSIZE]; 496920Ssam 506920Ssam extern char *malloc(); 516922Ssam extern int errno, exit(); 526920Ssam 536920Ssam main(argc, argv) 546920Ssam int argc; 556920Ssam char *argv[]; 566920Ssam { 576920Ssam int cc; 586920Ssam struct sockaddr from; 596920Ssam 606920Ssam { int t = open("/dev/tty", 2); 616920Ssam if (t >= 0) { 626920Ssam ioctl(t, TIOCNOTTY, 0); 636920Ssam close(t); 646920Ssam } 656920Ssam } 666920Ssam if (trace) { 676929Ssam (void) freopen("/etc/routerlog", "a", stdout); 686929Ssam (void) dup2(fileno(stdout), 2); 696920Ssam setbuf(stdout, NULL); 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(); 836929Ssam initializing = 1; 846920Ssam getinterfaces(); 856929Ssam initializing = 0; 866920Ssam request(); 876920Ssam 886920Ssam argv++, argc--; 896920Ssam while (argc > 0) { 906920Ssam if (strcmp(*argv, "-s") == 0) 916929Ssam supplier = 1; 926920Ssam else if (strcmp(*argv, "-q") == 0) 936920Ssam supplier = 0; 946920Ssam argv++, argc--; 956920Ssam } 966920Ssam sigset(SIGALRM, timer); 976929Ssam timer(); 986920Ssam 996920Ssam /* 1006920Ssam * Listen for routing packets 1016920Ssam */ 1026920Ssam for (;;) { 1036920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1046920Ssam if (cc <= 0) { 1056920Ssam if (cc < 0 && errno != EINTR) 1066920Ssam perror("receive"); 1076920Ssam continue; 1086920Ssam } 1096920Ssam sighold(SIGALRM); 1106920Ssam rip_input(&from, cc); 1116920Ssam sigrelse(SIGALRM); 1126920Ssam } 1136920Ssam } 1146920Ssam 1156920Ssam /* 1166920Ssam * Look in a file for any gateways we should configure 1176920Ssam * outside the directly connected ones. This is a kludge, 1186920Ssam * but until we can find out about gateways on the "other side" 1196920Ssam * of the ARPANET using GGP, it's a must. 1206920Ssam * 1216920Ssam * We don't really know the distance to the gateway, so we 1226920Ssam * assume it's a neighbor. 1236920Ssam */ 1246920Ssam getothers() 1256920Ssam { 1266920Ssam struct sockaddr_in dst, gate; 1276920Ssam FILE *fp = fopen("/etc/gateways", "r"); 1286920Ssam struct rt_entry *rt; 1296920Ssam 1306920Ssam if (fp == NULL) 1316920Ssam return; 1326920Ssam bzero((char *)&dst, sizeof (dst)); 1336920Ssam bzero((char *)&gate, sizeof (gate)); 1346920Ssam dst.sin_family = AF_INET; 1356920Ssam gate.sin_family = AF_INET; 1366920Ssam while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, 1376920Ssam &gate.sin_addr.s_addr) != EOF) { 1386920Ssam rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1); 1396920Ssam rt = rtlookup((struct sockaddr *)&dst); 1406920Ssam if (rt) 1416920Ssam rt->rt_flags |= RTF_SILENT; 1426920Ssam } 1436920Ssam fclose(fp); 1446920Ssam } 1456920Ssam 1466929Ssam /* 1476929Ssam * Timer routine: 1486929Ssam * 1496929Ssam * o handle timers on table entries, 1506929Ssam * o invalidate entries which haven't been updated in a while, 1516929Ssam * o delete entries which are too old, 1526929Ssam * o retry ioctl's which weren't successful the first 1536929Ssam * time due to the kernel entry being busy 1546929Ssam * o if we're an internetwork router, supply routing updates 1556929Ssam * periodically 1566929Ssam */ 1576929Ssam timer() 1586920Ssam { 1596929Ssam register struct rt_hash *rh; 1606929Ssam register struct rt_entry *rt; 1616929Ssam struct rt_hash *base = hosthash; 1626929Ssam int doinghost = 1; 1636920Ssam 1646929Ssam if (trace) 1656929Ssam printf(">>> time %d >>>\n", timeval); 1666929Ssam again: 1676929Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 1686929Ssam rt = rh->rt_forw; 1696929Ssam for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 1706920Ssam 1716929Ssam /* 1726929Ssam * If the host is indicated to be 1736929Ssam * "silent" (i.e. it's one we got 1746929Ssam * from the initialization file), 1756929Ssam * don't time out it's entry. 1766929Ssam */ 177*6933Ssam if ((rt->rt_flags & RTF_SILENT) == 0) 178*6933Ssam rt->rt_timer += TIMER_RATE; 1796929Ssam log("", rt); 1806920Ssam 1816929Ssam /* 1826929Ssam * If the entry should be deleted 1836929Ssam * attempt to do so and reclaim space. 1846929Ssam */ 1856929Ssam if (rt->rt_timer >= GARBAGE_TIME || 1866929Ssam (rt->rt_flags & RTF_DELRT)) { 1876929Ssam rt = rt->rt_forw; 1886929Ssam rtdelete(rt->rt_back); 1896929Ssam rt = rt->rt_back; 1906929Ssam continue; 1916929Ssam } 1926920Ssam 1936929Ssam /* 1946929Ssam * If we haven't heard from the router 1956929Ssam * in a long time indicate the route is 1966929Ssam * hard to reach. 1976929Ssam */ 1986929Ssam if (rt->rt_timer >= EXPIRE_TIME) 1996929Ssam rt->rt_metric = HOPCNT_INFINITY; 2006929Ssam if (rt->rt_flags & RTF_CHGRT) 2016929Ssam if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) || 2026929Ssam --rt->rt_retry == 0) 2036929Ssam rt->rt_flags &= ~RTF_CHGRT; 2046920Ssam 2056929Ssam /* 2066929Ssam * Try to add the route to the kernel tables. 2076929Ssam * If this fails because the entry already exists 2086929Ssam * (perhaps because someone manually added it) 2096929Ssam * change the add to a change. If the operation 2106929Ssam * fails otherwise (likely because the entry is 2116929Ssam * in use), retry the operation a few more times. 2126929Ssam */ 2136929Ssam if (rt->rt_flags & RTF_ADDRT) { 2146929Ssam if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash)) { 2156929Ssam if (errno == EEXIST) { 2166929Ssam rt->rt_flags &= ~RTF_ADDRT; 2176929Ssam rt->rt_flags |= RTF_CHGRT; 2186929Ssam rt->rt_retry = 2196929Ssam (EXPIRE_TIME/TIMER_RATE); 2206929Ssam continue; 2216929Ssam } 2226929Ssam if (--rt->rt_retry) 2236929Ssam continue; 2246929Ssam } 2256929Ssam rt->rt_flags &= ~RTF_ADDRT; 2266929Ssam } 2276929Ssam } 2286929Ssam } 2296929Ssam if (doinghost) { 2306929Ssam doinghost = 0; 2316929Ssam base = nethash; 2326929Ssam goto again; 2336929Ssam } 2346929Ssam timeval += TIMER_RATE; 2356929Ssam if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0) 2366929Ssam getinterfaces(); 2376929Ssam if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 2386929Ssam supplyall(); 2396929Ssam if (trace) 2406929Ssam printf("<<< time %d <<<\n", timeval); 2416929Ssam alarm(TIMER_RATE); 2426920Ssam } 2436920Ssam 2446920Ssam /* 2456920Ssam * Find the network interfaces attached to this machine. 2466929Ssam * The info is used to: 2476920Ssam * 2486920Ssam * (1) initialize the routing tables, as done by the kernel. 2496920Ssam * (2) ignore incoming packets we send. 2506920Ssam * (3) figure out broadcast capability and addresses. 2516920Ssam * (4) figure out if we're an internetwork gateway. 2526920Ssam * 2536920Ssam * We don't handle anything but Internet addresses. 2546920Ssam */ 2556920Ssam getinterfaces() 2566920Ssam { 2576929Ssam struct ifnet *ifp; 2586929Ssam struct ifnet ifstruct, *next; 2596920Ssam struct sockaddr_in net; 2606929Ssam register struct sockaddr *dst; 2616920Ssam int nets; 2626920Ssam 2636929Ssam if (performnlist) { 2646929Ssam nlist("/vmunix", nl); 2656929Ssam if (nl[N_IFNET].n_value == 0) { 2666929Ssam performnlist++; 2676929Ssam printf("ifnet: not in namelist\n"); 2686929Ssam return; 2696929Ssam } 2706929Ssam performnlist = 0; 2716920Ssam } 2726920Ssam if (kmem < 0) { 2736929Ssam kmem = open("/dev/kmem", 0); 2746929Ssam if (kmem < 0) { 2756929Ssam perror("/dev/kmem"); 2766929Ssam return; 2776929Ssam } 2786920Ssam } 2796929Ssam if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 2806929Ssam read(kmem, (char *)&ifp, sizeof (ifp)) != sizeof (ifp)) { 2816929Ssam performnlist = 1; 2826929Ssam return; 2836929Ssam } 2846920Ssam bzero((char *)&net, sizeof (net)); 2856920Ssam net.sin_family = AF_INET; 2866920Ssam nets = 0; 2876929Ssam while (ifp) { 2886929Ssam if (lseek(kmem, (long)ifp, 0) == -1 || 2896929Ssam read(kmem, (char *)&ifstruct, sizeof (ifstruct)) != 2906929Ssam sizeof (ifstruct)) { 2916920Ssam perror("read"); 2926929Ssam performnlist = 1; 2936920Ssam break; 2946920Ssam } 2956929Ssam ifp = &ifstruct; 2966929Ssam if ((ifp->if_flags & IFF_UP) == 0) { 2976929Ssam lookforinterfaces++; 2986929Ssam skip: 2996929Ssam ifp = ifp->if_next; 3006929Ssam continue; 3016929Ssam } 3026929Ssam if (ifp->if_addr.sa_family != AF_INET) 3036929Ssam goto skip; 3046929Ssam /* ignore software loopback networks. */ 3056920Ssam if (ifp->if_net == LOOPBACKNET) 3066920Ssam goto skip; 3076929Ssam /* check if we already know about this one */ 3086929Ssam if (if_ifwithaddr(&ifstruct.if_addr)) { 3096929Ssam nets++; 3106920Ssam goto skip; 3116920Ssam } 3126929Ssam ifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 3136929Ssam if (ifp == 0) { 3146929Ssam printf("routed: out of memory\n"); 3156929Ssam break; 3166929Ssam } 3176929Ssam bcopy((char *)&ifstruct, (char *)ifp, sizeof (struct ifnet)); 3186920Ssam 3196920Ssam /* 3206929Ssam * Count the # of directly connected networks 3216929Ssam * and point to point links which aren't looped 3226929Ssam * back to ourself. This is used below to 3236929Ssam * decide if we should be a routing "supplier". 3246920Ssam */ 3256929Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0 || 3266929Ssam if_ifwithaddr(&ifp->if_dstaddr) == 0) 3276929Ssam nets++; 3286920Ssam 3296929Ssam if (ifp->if_flags & IFF_POINTOPOINT) 3306929Ssam dst = &ifp->if_dstaddr; 3316929Ssam else { 3326929Ssam net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 3336929Ssam dst = (struct sockaddr *)&net; 3346929Ssam } 3356929Ssam next = ifp->if_next; 3366929Ssam ifp->if_next = ifnet; 3376929Ssam ifnet = ifp; 3386929Ssam if (rtlookup(dst) == 0) 3396929Ssam rtadd(dst, &ifp->if_addr, 0); 3406929Ssam ifp = next; 3416920Ssam } 3426920Ssam supplier = nets > 1; 3436920Ssam } 3446920Ssam 3456920Ssam /* 3466920Ssam * Send a request message to all directly 3476920Ssam * connected hosts and networks. 3486920Ssam */ 3496920Ssam request() 3506920Ssam { 3516929Ssam register struct rip *msg = (struct rip *)packet; 3526920Ssam 3536929Ssam msg->rip_cmd = RIPCMD_REQUEST; 3546929Ssam msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 3556929Ssam msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 3566929Ssam sendall(); 3576920Ssam } 3586920Ssam 3596920Ssam /* 3606920Ssam * Broadcast a new, or modified, routing table entry 3616920Ssam * to all directly connected hosts and networks. 3626920Ssam */ 3636920Ssam broadcast(entry) 3646920Ssam struct rt_entry *entry; 3656920Ssam { 3666929Ssam struct rip *msg = (struct rip *)packet; 3676929Ssam 3686929Ssam log("broadcast", entry); 3696929Ssam msg->rip_cmd = RIPCMD_RESPONSE; 3706929Ssam msg->rip_nets[0].rip_dst = entry->rt_dst; 3716929Ssam msg->rip_nets[0].rip_metric = min(entry->rt_metric+1, HOPCNT_INFINITY); 3726929Ssam sendall(); 3736929Ssam } 3746929Ssam 3756929Ssam sendall() 3766929Ssam { 3776920Ssam register struct rt_hash *rh; 3786920Ssam register struct rt_entry *rt; 3796920Ssam register struct sockaddr *dst; 3806920Ssam struct rt_hash *base = hosthash; 3816920Ssam int doinghost = 1; 3826920Ssam 3836920Ssam again: 3846920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3856920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3866920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 3876920Ssam continue; 3886920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3896920Ssam dst = &rt->rt_ifp->if_broadaddr; 3906920Ssam else 3916920Ssam dst = &rt->rt_gateway; 3926920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 3936920Ssam } 3946920Ssam if (doinghost) { 3956929Ssam base = nethash; 3966920Ssam doinghost = 0; 3976920Ssam goto again; 3986920Ssam } 3996920Ssam } 4006920Ssam 4016920Ssam /* 4026920Ssam * Supply all directly connected neighbors with the 4036920Ssam * current state of the routing tables. 4046920Ssam */ 4056920Ssam supplyall() 4066920Ssam { 4076920Ssam register struct rt_entry *rt; 4086920Ssam register struct rt_hash *rh; 4096920Ssam register struct sockaddr *dst; 4106920Ssam struct rt_hash *base = hosthash; 4116920Ssam int doinghost = 1; 4126920Ssam 4136920Ssam again: 4146920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 4156920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4166920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 4176920Ssam continue; 4186920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 4196920Ssam dst = &rt->rt_ifp->if_broadaddr; 4206920Ssam else 4216920Ssam dst = &rt->rt_gateway; 4226929Ssam log("supply", rt); 4236920Ssam supply(dst); 4246920Ssam } 4256920Ssam if (doinghost) { 4266920Ssam base = nethash; 4276920Ssam doinghost = 0; 4286920Ssam goto again; 4296920Ssam } 4306920Ssam } 4316920Ssam 4326920Ssam /* 4336920Ssam * Supply routing information to target "sa". 4346920Ssam */ 4356920Ssam supply(sa) 4366920Ssam struct sockaddr *sa; 4376920Ssam { 4386920Ssam struct rip *msg = (struct rip *)packet; 4396920Ssam struct netinfo *n = msg->rip_nets; 4406920Ssam register struct rt_hash *rh; 4416920Ssam register struct rt_entry *rt; 4426920Ssam struct rt_hash *base = hosthash; 4436929Ssam int doinghost = 1, size; 4446920Ssam int (*output)() = afswitch[sa->sa_family].af_output; 4456920Ssam 4466920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4476920Ssam again: 4486920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 4496920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4506920Ssam 4516920Ssam /* 4526920Ssam * Flush packet out if not enough room for 4536920Ssam * another routing table entry. 4546920Ssam */ 4556929Ssam size = (char *)n - packet; 4566929Ssam if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 4576929Ssam (*output)(sa, size); 4586920Ssam n = msg->rip_nets; 4596920Ssam } 4606920Ssam n->rip_dst = rt->rt_dst; 4616929Ssam n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 4626929Ssam n++; 4636920Ssam } 4646920Ssam if (doinghost) { 4656920Ssam doinghost = 0; 4666920Ssam base = nethash; 4676920Ssam goto again; 4686920Ssam } 4696929Ssam if (n != msg->rip_nets) 4706929Ssam (*output)(sa, (char *)n - packet); 4716920Ssam } 4726920Ssam 4736920Ssam /* 4746920Ssam * Respond to a routing info request. 4756920Ssam */ 4766920Ssam rip_respond(from, size) 4776920Ssam struct sockaddr *from; 4786920Ssam int size; 4796920Ssam { 4806920Ssam register struct rip *msg = (struct rip *)packet; 4816920Ssam struct netinfo *np = msg->rip_nets; 4826920Ssam struct rt_entry *rt; 4836920Ssam int newsize = 0; 4846920Ssam 4856929Ssam size -= 4 * sizeof (char); 4866920Ssam while (size > 0) { 4876920Ssam if (size < sizeof (struct netinfo)) 4886920Ssam break; 4896920Ssam size -= sizeof (struct netinfo); 4906920Ssam if (np->rip_dst.sa_family == AF_UNSPEC && 4916920Ssam np->rip_metric == HOPCNT_INFINITY && size == 0) { 4926920Ssam supply(from); 4936920Ssam return; 4946920Ssam } 4956920Ssam rt = rtlookup(&np->rip_dst); 4966929Ssam np->rip_metric = rt == 0 ? 4976929Ssam HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY); 4986920Ssam np++, newsize += sizeof (struct netinfo); 4996920Ssam } 5006920Ssam if (newsize > 0) { 5016920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 5026920Ssam newsize += sizeof (int); 5036920Ssam (*afswitch[from->sa_family].af_output)(from, newsize); 5046920Ssam } 5056920Ssam } 5066920Ssam 5076920Ssam /* 5086920Ssam * Handle an incoming routing packet. 5096920Ssam */ 5106920Ssam rip_input(from, size) 5116920Ssam struct sockaddr *from; 5126920Ssam int size; 5136920Ssam { 5146920Ssam register struct rip *msg = (struct rip *)packet; 5156920Ssam struct rt_entry *rt; 5166920Ssam struct netinfo *n; 5176920Ssam 5186920Ssam if (msg->rip_cmd != RIPCMD_RESPONSE && 5196920Ssam msg->rip_cmd != RIPCMD_REQUEST) 5206920Ssam return; 5216920Ssam 5226920Ssam if (msg->rip_cmd == RIPCMD_RESPONSE && 5236920Ssam (*afswitch[from->sa_family].af_portmatch)(from) == 0) 5246920Ssam return; 5256920Ssam if (msg->rip_cmd == RIPCMD_REQUEST) { 5266920Ssam rip_respond(from, size); 5276920Ssam return; 5286920Ssam } 5296920Ssam 5306920Ssam /* 5316920Ssam * Process updates. 5326920Ssam * Extraneous information like Internet ports 5336920Ssam * must first be purged from the sender's address for 5346920Ssam * pattern matching below. 5356920Ssam */ 5366920Ssam (*afswitch[from->sa_family].af_canon)(from); 5376920Ssam if (trace) 5386920Ssam printf("input from %x\n", from->sin_addr); 5396920Ssam /* 5406920Ssam * If response packet is from ourselves, use it only 5416920Ssam * to reset timer on entry. Otherwise, we'd believe 5426920Ssam * it as gospel (since it comes from the router) and 5436920Ssam * unknowingly update the metric to show the outgoing 5446920Ssam * cost (higher than our real cost). I guess the protocol 5456920Ssam * spec doesn't address this because Xerox Ethernets 5466920Ssam * don't hear their own broadcasts? 5476920Ssam */ 5486920Ssam if (if_ifwithaddr(from)) { 5496920Ssam rt = rtlookup(from); 5506920Ssam if (rt) 5516920Ssam rt->rt_timer = 0; 5526920Ssam return; 5536920Ssam } 5546929Ssam size -= 4 * sizeof (char); 5556920Ssam n = msg->rip_nets; 5566920Ssam for (; size > 0; size -= sizeof (struct netinfo), n++) { 5576920Ssam if (size < sizeof (struct netinfo)) 5586920Ssam break; 5596920Ssam if (trace) 5606920Ssam printf("dst %x hc %d...", n->rip_dst.sin_addr, 5616920Ssam n->rip_metric); 5626920Ssam rt = rtlookup(&n->rip_dst); 5636920Ssam 5646920Ssam /* 5656920Ssam * Unknown entry, add it to the tables only if 5666920Ssam * its interesting. 5676920Ssam */ 5686920Ssam if (rt == 0) { 5696920Ssam if (n->rip_metric < HOPCNT_INFINITY) 5706920Ssam rtadd(&n->rip_dst, from, n->rip_metric); 5716920Ssam if (trace) 5726920Ssam printf("new\n"); 5736920Ssam continue; 5746920Ssam } 5756920Ssam 5766920Ssam if (trace) 5776920Ssam printf("ours: gate %x hc %d timer %d\n", 5786920Ssam rt->rt_gateway.sin_addr, 5796920Ssam rt->rt_metric, rt->rt_timer); 5806920Ssam /* 5816920Ssam * Update the entry if one of the following is true: 5826920Ssam * 5836920Ssam * (1) The update came directly from the gateway. 5846920Ssam * (2) A shorter path is provided. 5856920Ssam * (3) The entry hasn't been updated in a while 5866929Ssam * and a path of equivalent cost is offered 5876929Ssam * (with the cost finite). 5886920Ssam */ 5896920Ssam if (equal(from, &rt->rt_gateway) || 5906920Ssam rt->rt_metric > n->rip_metric || 5916920Ssam (rt->rt_timer > (EXPIRE_TIME/2) && 5926929Ssam rt->rt_metric == n->rip_metric && 5936929Ssam rt->rt_metric < HOPCNT_INFINITY)) { 5946920Ssam rtchange(rt, from, n->rip_metric); 5956920Ssam rt->rt_timer = 0; 5966920Ssam } 5976920Ssam } 5986920Ssam } 5996920Ssam 6006920Ssam /* 6016920Ssam * Lookup an entry to the appropriate dstination. 6026920Ssam */ 6036920Ssam struct rt_entry * 6046920Ssam rtlookup(dst) 6056920Ssam struct sockaddr *dst; 6066920Ssam { 6076920Ssam register struct rt_entry *rt; 6086920Ssam register struct rt_hash *rh; 6096920Ssam register int hash, (*match)(); 6106920Ssam struct afhash h; 6116920Ssam int af = dst->sa_family, doinghost = 1; 6126920Ssam 6136920Ssam if (af >= AF_MAX) 6146920Ssam return (0); 6156920Ssam (*afswitch[af].af_hash)(dst, &h); 6166920Ssam hash = h.afh_hosthash; 6176920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6186920Ssam 6196920Ssam again: 6206920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 6216920Ssam if (rt->rt_hash != hash) 6226920Ssam continue; 6236920Ssam if (doinghost) { 6246920Ssam if (equal(&rt->rt_dst, dst)) 6256920Ssam return (rt); 6266920Ssam } else { 6276920Ssam if (rt->rt_dst.sa_family == af && 6286920Ssam (*match)(&rt->rt_dst, dst)) 6296920Ssam return (rt); 6306920Ssam } 6316920Ssam } 6326920Ssam if (doinghost) { 6336920Ssam doinghost = 0; 6346920Ssam hash = h.afh_nethash; 6356920Ssam match = afswitch[af].af_netmatch; 6366920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6376920Ssam goto again; 6386920Ssam } 6396920Ssam return (0); 6406920Ssam } 6416920Ssam 6426920Ssam rtinit() 6436920Ssam { 6446920Ssam register struct rt_hash *rh; 6456920Ssam 6466920Ssam for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 6476920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6486920Ssam for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 6496920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6506920Ssam } 6516920Ssam 6526920Ssam /* 6536920Ssam * Add a new entry. 6546920Ssam */ 6556920Ssam rtadd(dst, gate, metric) 6566920Ssam struct sockaddr *dst, *gate; 6576920Ssam short metric; 6586920Ssam { 6596920Ssam struct afhash h; 6606920Ssam register struct rt_entry *rt; 6616920Ssam struct rt_hash *rh; 6626920Ssam int af = dst->sa_family, flags, hash; 6636920Ssam 6646920Ssam if (af >= AF_MAX) 6656920Ssam return; 6666920Ssam (*afswitch[af].af_hash)(dst, &h); 6676920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6686920Ssam if (flags & RTF_HOST) { 6696920Ssam hash = h.afh_hosthash; 6706920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6716920Ssam } else { 6726920Ssam hash = h.afh_nethash; 6736920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6746920Ssam } 6756920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6766920Ssam if (rt == 0) 6776920Ssam return; 6786920Ssam rt->rt_hash = hash; 6796920Ssam rt->rt_dst = *dst; 6806920Ssam rt->rt_gateway = *gate; 6816920Ssam rt->rt_metric = metric; 6826920Ssam rt->rt_timer = 0; 6836920Ssam rt->rt_flags = RTF_UP | flags; 6846920Ssam rt->rt_ifp = if_ifwithnet(&rt->rt_gateway); 6856920Ssam if (metric == 0) 6866920Ssam rt->rt_flags |= RTF_DIRECT; 6876920Ssam insque(rt, rh); 6886929Ssam log("add", rt); 6896920Ssam if (initializing) 6906920Ssam return; 6916920Ssam if (supplier) 6926920Ssam broadcast(rt); 6936920Ssam if (install) { 6946920Ssam rt->rt_flags |= RTF_ADDRT; 6956920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 6966920Ssam } 6976920Ssam } 6986920Ssam 6996920Ssam /* 7006920Ssam * Look to see if a change to an existing entry 7016920Ssam * is warranted; if so, make it. 7026920Ssam */ 7036920Ssam rtchange(rt, gate, metric) 7046920Ssam struct rt_entry *rt; 7056920Ssam struct sockaddr *gate; 7066920Ssam short metric; 7076920Ssam { 7086920Ssam int change = 0; 7096920Ssam 7106920Ssam if (!equal(&rt->rt_gateway, gate)) { 7116920Ssam rt->rt_gateway = *gate; 7126920Ssam change++; 7136920Ssam } 7146920Ssam 7156920Ssam /* 7166920Ssam * If the hop count has changed, adjust 7176920Ssam * the flags in the routing table entry accordingly. 7186920Ssam */ 7196920Ssam if (metric != rt->rt_metric) { 7206920Ssam if (rt->rt_metric == 0) 7216920Ssam rt->rt_flags &= ~RTF_DIRECT; 7226920Ssam rt->rt_metric = metric; 7236920Ssam if (metric >= HOPCNT_INFINITY) 7246920Ssam rt->rt_flags &= ~RTF_UP; 7256920Ssam else 7266920Ssam rt->rt_flags |= RTF_UP; 7276920Ssam change++; 7286920Ssam } 7296920Ssam 7306920Ssam if (!change) 7316920Ssam return; 7326920Ssam if (supplier) 7336920Ssam broadcast(rt); 7346929Ssam log("change", rt); 7356920Ssam if (install) { 7366920Ssam rt->rt_flags |= RTF_CHGRT; 7376920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 7386920Ssam } 7396920Ssam } 7406920Ssam 7416920Ssam /* 7426920Ssam * Delete a routing table entry. 7436920Ssam */ 7446920Ssam rtdelete(rt) 7456920Ssam struct rt_entry *rt; 7466920Ssam { 7476929Ssam log("delete", rt); 7486920Ssam if (install) 7496920Ssam if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) && 7506920Ssam errno == EBUSY) 7516920Ssam rt->rt_flags |= RTF_DELRT; 7526920Ssam remque(rt); 7536920Ssam free((char *)rt); 7546920Ssam } 7556920Ssam 7566920Ssam log(operation, rt) 7576920Ssam char *operation; 7586920Ssam struct rt_entry *rt; 7596920Ssam { 7606920Ssam time_t t = time(0); 7616920Ssam struct sockaddr_in *dst, *gate; 7626920Ssam static struct flagbits { 7636920Ssam int t_bits; 7646920Ssam char *t_name; 7656920Ssam } bits[] = { 7666920Ssam { RTF_UP, "UP" }, 7676920Ssam { RTF_DIRECT, "DIRECT" }, 7686920Ssam { RTF_HOST, "HOST" }, 7696920Ssam { RTF_DELRT, "DELETE" }, 7706920Ssam { RTF_CHGRT, "CHANGE" }, 7716920Ssam { RTF_SILENT, "SILENT" }, 7726920Ssam { 0 } 7736920Ssam }; 7746920Ssam register struct flagbits *p; 7756920Ssam register int first; 7766920Ssam char *cp; 7776920Ssam 7786929Ssam if (trace == 0) 7796929Ssam return; 7806920Ssam printf("%s ", operation); 7816920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 7826920Ssam gate = (struct sockaddr_in *)&rt->rt_gateway; 7836920Ssam printf("dst %x, router %x, metric %d, flags ", 7846920Ssam dst->sin_addr, gate->sin_addr, rt->rt_metric); 7856920Ssam cp = "%s"; 7866920Ssam for (first = 1, p = bits; p->t_bits > 0; p++) { 7876920Ssam if ((rt->rt_flags & p->t_bits) == 0) 7886920Ssam continue; 7896920Ssam printf(cp, p->t_name); 7906920Ssam if (first) { 7916920Ssam cp = "|%s"; 7926920Ssam first = 0; 7936920Ssam } 7946920Ssam } 7956920Ssam putchar('\n'); 7966920Ssam } 7976929Ssam 7986929Ssam struct ifnet * 7996929Ssam if_ifwithaddr(addr) 8006929Ssam struct sockaddr *addr; 8016929Ssam { 8026929Ssam register struct ifnet *ifp; 8036929Ssam 8046929Ssam #define same(a1, a2) \ 8056929Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 8066929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 8076929Ssam if (ifp->if_addr.sa_family != addr->sa_family) 8086929Ssam continue; 8096929Ssam if (same(&ifp->if_addr, addr)) 8106929Ssam break; 8116929Ssam if ((ifp->if_flags & IFF_BROADCAST) && 8126929Ssam same(&ifp->if_broadaddr, addr)) 8136929Ssam break; 8146929Ssam } 8156929Ssam return (ifp); 8166929Ssam #undef same 8176929Ssam } 8186929Ssam 8196929Ssam struct ifnet * 8206929Ssam if_ifwithnet(addr) 8216929Ssam register struct sockaddr *addr; 8226929Ssam { 8236929Ssam register struct ifnet *ifp; 8246929Ssam register int af = addr->sa_family; 8256929Ssam register int (*netmatch)(); 8266929Ssam 8276929Ssam if (af >= AF_MAX) 8286929Ssam return (0); 8296929Ssam netmatch = afswitch[af].af_netmatch; 8306929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 8316929Ssam if (af != ifp->if_addr.sa_family) 8326929Ssam continue; 8336929Ssam if ((*netmatch)(addr, &ifp->if_addr)) 8346929Ssam break; 8356929Ssam } 8366929Ssam return (ifp); 8376929Ssam } 8386929Ssam 8396929Ssam struct in_addr 8406929Ssam if_makeaddr(net, host) 8416929Ssam int net, host; 8426929Ssam { 8436929Ssam u_long addr; 8446929Ssam 8456929Ssam if (net < 128) 8466929Ssam addr = (net << 24) | host; 8476929Ssam else if (net < 65536) 8486929Ssam addr = (net << 16) | host; 8496929Ssam else 8506929Ssam addr = (net << 8) | host; 8516929Ssam #ifdef vax 8526929Ssam addr = htonl(addr); 8536929Ssam #endif 8546929Ssam return (*(struct in_addr *)&addr); 8556929Ssam } 856