16920Ssam #ifndef lint 2*6929Ssam static char sccsid[] = "@(#)routed.c 4.3 05/24/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) 26*6929Ssam #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; 37*6929Ssam 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 */ 41*6929Ssam int lookforinterfaces = 1; 42*6929Ssam 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 60*6929Ssam #ifdef notdef 616920Ssam { int t = open("/dev/tty", 2); 626920Ssam if (t >= 0) { 636920Ssam ioctl(t, TIOCNOTTY, 0); 646920Ssam close(t); 656920Ssam } 666920Ssam } 67*6929Ssam #endif 686920Ssam if (trace) { 69*6929Ssam (void) freopen("/etc/routerlog", "a", stdout); 70*6929Ssam (void) dup2(fileno(stdout), 2); 716920Ssam setbuf(stdout, NULL); 726920Ssam } 736920Ssam #ifdef vax 746920Ssam myaddr.sin_port = htons(myaddr.sin_port); 756920Ssam #endif 766920Ssam again: 776920Ssam s = socket(SOCK_DGRAM, 0, &myaddr, 0); 786920Ssam if (s < 0) { 796920Ssam perror("socket"); 806920Ssam sleep(30); 816920Ssam goto again; 826920Ssam } 836920Ssam rtinit(); 846920Ssam getothers(); 85*6929Ssam initializing = 1; 866920Ssam getinterfaces(); 87*6929Ssam initializing = 0; 886920Ssam request(); 896920Ssam 906920Ssam argv++, argc--; 916920Ssam while (argc > 0) { 926920Ssam if (strcmp(*argv, "-s") == 0) 93*6929Ssam supplier = 1; 946920Ssam else if (strcmp(*argv, "-q") == 0) 956920Ssam supplier = 0; 966920Ssam argv++, argc--; 976920Ssam } 986920Ssam sigset(SIGALRM, timer); 99*6929Ssam timer(); 1006920Ssam 1016920Ssam /* 1026920Ssam * Listen for routing packets 1036920Ssam */ 1046920Ssam for (;;) { 1056920Ssam cc = receive(s, &from, packet, sizeof (packet)); 1066920Ssam if (cc <= 0) { 1076920Ssam if (cc < 0 && errno != EINTR) 1086920Ssam perror("receive"); 1096920Ssam continue; 1106920Ssam } 1116920Ssam sighold(SIGALRM); 1126920Ssam rip_input(&from, cc); 1136920Ssam sigrelse(SIGALRM); 1146920Ssam } 1156920Ssam } 1166920Ssam 1176920Ssam /* 1186920Ssam * Look in a file for any gateways we should configure 1196920Ssam * outside the directly connected ones. This is a kludge, 1206920Ssam * but until we can find out about gateways on the "other side" 1216920Ssam * of the ARPANET using GGP, it's a must. 1226920Ssam * 1236920Ssam * We don't really know the distance to the gateway, so we 1246920Ssam * assume it's a neighbor. 1256920Ssam */ 1266920Ssam getothers() 1276920Ssam { 1286920Ssam struct sockaddr_in dst, gate; 1296920Ssam FILE *fp = fopen("/etc/gateways", "r"); 1306920Ssam struct rt_entry *rt; 1316920Ssam 1326920Ssam if (fp == NULL) 1336920Ssam return; 1346920Ssam bzero((char *)&dst, sizeof (dst)); 1356920Ssam bzero((char *)&gate, sizeof (gate)); 1366920Ssam dst.sin_family = AF_INET; 1376920Ssam gate.sin_family = AF_INET; 1386920Ssam while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, 1396920Ssam &gate.sin_addr.s_addr) != EOF) { 1406920Ssam rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1); 1416920Ssam rt = rtlookup((struct sockaddr *)&dst); 1426920Ssam if (rt) 1436920Ssam rt->rt_flags |= RTF_SILENT; 1446920Ssam } 1456920Ssam fclose(fp); 1466920Ssam } 1476920Ssam 148*6929Ssam /* 149*6929Ssam * Timer routine: 150*6929Ssam * 151*6929Ssam * o handle timers on table entries, 152*6929Ssam * o invalidate entries which haven't been updated in a while, 153*6929Ssam * o delete entries which are too old, 154*6929Ssam * o retry ioctl's which weren't successful the first 155*6929Ssam * time due to the kernel entry being busy 156*6929Ssam * o if we're an internetwork router, supply routing updates 157*6929Ssam * periodically 158*6929Ssam */ 159*6929Ssam timer() 1606920Ssam { 161*6929Ssam register struct rt_hash *rh; 162*6929Ssam register struct rt_entry *rt; 163*6929Ssam struct rt_hash *base = hosthash; 164*6929Ssam int doinghost = 1; 1656920Ssam 166*6929Ssam if (trace) 167*6929Ssam printf(">>> time %d >>>\n", timeval); 168*6929Ssam again: 169*6929Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 170*6929Ssam rt = rh->rt_forw; 171*6929Ssam for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 1726920Ssam 173*6929Ssam /* 174*6929Ssam * If the host is indicated to be 175*6929Ssam * "silent" (i.e. it's one we got 176*6929Ssam * from the initialization file), 177*6929Ssam * don't time out it's entry. 178*6929Ssam */ 179*6929Ssam if (rt->rt_flags & RTF_SILENT) 180*6929Ssam continue; 181*6929Ssam log("", rt); 182*6929Ssam rt->rt_timer += TIMER_RATE; 1836920Ssam 184*6929Ssam /* 185*6929Ssam * If the entry should be deleted 186*6929Ssam * attempt to do so and reclaim space. 187*6929Ssam */ 188*6929Ssam if (rt->rt_timer >= GARBAGE_TIME || 189*6929Ssam (rt->rt_flags & RTF_DELRT)) { 190*6929Ssam rt = rt->rt_forw; 191*6929Ssam rtdelete(rt->rt_back); 192*6929Ssam rt = rt->rt_back; 193*6929Ssam continue; 194*6929Ssam } 1956920Ssam 196*6929Ssam /* 197*6929Ssam * If we haven't heard from the router 198*6929Ssam * in a long time indicate the route is 199*6929Ssam * hard to reach. 200*6929Ssam */ 201*6929Ssam if (rt->rt_timer >= EXPIRE_TIME) 202*6929Ssam rt->rt_metric = HOPCNT_INFINITY; 203*6929Ssam if (rt->rt_flags & RTF_CHGRT) 204*6929Ssam if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) || 205*6929Ssam --rt->rt_retry == 0) 206*6929Ssam rt->rt_flags &= ~RTF_CHGRT; 2076920Ssam 208*6929Ssam /* 209*6929Ssam * Try to add the route to the kernel tables. 210*6929Ssam * If this fails because the entry already exists 211*6929Ssam * (perhaps because someone manually added it) 212*6929Ssam * change the add to a change. If the operation 213*6929Ssam * fails otherwise (likely because the entry is 214*6929Ssam * in use), retry the operation a few more times. 215*6929Ssam */ 216*6929Ssam if (rt->rt_flags & RTF_ADDRT) { 217*6929Ssam if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash)) { 218*6929Ssam if (errno == EEXIST) { 219*6929Ssam rt->rt_flags &= ~RTF_ADDRT; 220*6929Ssam rt->rt_flags |= RTF_CHGRT; 221*6929Ssam rt->rt_retry = 222*6929Ssam (EXPIRE_TIME/TIMER_RATE); 223*6929Ssam continue; 224*6929Ssam } 225*6929Ssam if (--rt->rt_retry) 226*6929Ssam continue; 227*6929Ssam } 228*6929Ssam rt->rt_flags &= ~RTF_ADDRT; 229*6929Ssam } 230*6929Ssam } 231*6929Ssam } 232*6929Ssam if (doinghost) { 233*6929Ssam doinghost = 0; 234*6929Ssam base = nethash; 235*6929Ssam goto again; 236*6929Ssam } 237*6929Ssam timeval += TIMER_RATE; 238*6929Ssam if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0) 239*6929Ssam getinterfaces(); 240*6929Ssam if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 241*6929Ssam supplyall(); 242*6929Ssam if (trace) 243*6929Ssam printf("<<< time %d <<<\n", timeval); 244*6929Ssam alarm(TIMER_RATE); 2456920Ssam } 2466920Ssam 2476920Ssam /* 2486920Ssam * Find the network interfaces attached to this machine. 249*6929Ssam * The info is used to: 2506920Ssam * 2516920Ssam * (1) initialize the routing tables, as done by the kernel. 2526920Ssam * (2) ignore incoming packets we send. 2536920Ssam * (3) figure out broadcast capability and addresses. 2546920Ssam * (4) figure out if we're an internetwork gateway. 2556920Ssam * 2566920Ssam * We don't handle anything but Internet addresses. 2576920Ssam */ 2586920Ssam getinterfaces() 2596920Ssam { 260*6929Ssam struct ifnet *ifp; 261*6929Ssam struct ifnet ifstruct, *next; 2626920Ssam struct sockaddr_in net; 263*6929Ssam register struct sockaddr *dst; 2646920Ssam int nets; 2656920Ssam 266*6929Ssam if (performnlist) { 267*6929Ssam nlist("/vmunix", nl); 268*6929Ssam if (nl[N_IFNET].n_value == 0) { 269*6929Ssam performnlist++; 270*6929Ssam printf("ifnet: not in namelist\n"); 271*6929Ssam return; 272*6929Ssam } 273*6929Ssam performnlist = 0; 2746920Ssam } 2756920Ssam if (kmem < 0) { 276*6929Ssam kmem = open("/dev/kmem", 0); 277*6929Ssam if (kmem < 0) { 278*6929Ssam perror("/dev/kmem"); 279*6929Ssam return; 280*6929Ssam } 2816920Ssam } 282*6929Ssam if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 || 283*6929Ssam read(kmem, (char *)&ifp, sizeof (ifp)) != sizeof (ifp)) { 284*6929Ssam performnlist = 1; 285*6929Ssam return; 286*6929Ssam } 2876920Ssam bzero((char *)&net, sizeof (net)); 2886920Ssam net.sin_family = AF_INET; 2896920Ssam nets = 0; 290*6929Ssam while (ifp) { 291*6929Ssam if (lseek(kmem, (long)ifp, 0) == -1 || 292*6929Ssam read(kmem, (char *)&ifstruct, sizeof (ifstruct)) != 293*6929Ssam sizeof (ifstruct)) { 2946920Ssam perror("read"); 295*6929Ssam performnlist = 1; 2966920Ssam break; 2976920Ssam } 298*6929Ssam ifp = &ifstruct; 299*6929Ssam if ((ifp->if_flags & IFF_UP) == 0) { 300*6929Ssam lookforinterfaces++; 301*6929Ssam skip: 302*6929Ssam ifp = ifp->if_next; 303*6929Ssam continue; 304*6929Ssam } 305*6929Ssam if (ifp->if_addr.sa_family != AF_INET) 306*6929Ssam goto skip; 307*6929Ssam /* ignore software loopback networks. */ 3086920Ssam if (ifp->if_net == LOOPBACKNET) 3096920Ssam goto skip; 310*6929Ssam /* check if we already know about this one */ 311*6929Ssam if (if_ifwithaddr(&ifstruct.if_addr)) { 312*6929Ssam nets++; 3136920Ssam goto skip; 3146920Ssam } 315*6929Ssam ifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 316*6929Ssam if (ifp == 0) { 317*6929Ssam printf("routed: out of memory\n"); 318*6929Ssam break; 319*6929Ssam } 320*6929Ssam bcopy((char *)&ifstruct, (char *)ifp, sizeof (struct ifnet)); 3216920Ssam 3226920Ssam /* 323*6929Ssam * Count the # of directly connected networks 324*6929Ssam * and point to point links which aren't looped 325*6929Ssam * back to ourself. This is used below to 326*6929Ssam * decide if we should be a routing "supplier". 3276920Ssam */ 328*6929Ssam if ((ifp->if_flags & IFF_POINTOPOINT) == 0 || 329*6929Ssam if_ifwithaddr(&ifp->if_dstaddr) == 0) 330*6929Ssam nets++; 3316920Ssam 332*6929Ssam if (ifp->if_flags & IFF_POINTOPOINT) 333*6929Ssam dst = &ifp->if_dstaddr; 334*6929Ssam else { 335*6929Ssam net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 336*6929Ssam dst = (struct sockaddr *)&net; 337*6929Ssam } 338*6929Ssam next = ifp->if_next; 339*6929Ssam ifp->if_next = ifnet; 340*6929Ssam ifnet = ifp; 341*6929Ssam if (rtlookup(dst) == 0) 342*6929Ssam rtadd(dst, &ifp->if_addr, 0); 343*6929Ssam ifp = next; 3446920Ssam } 3456920Ssam supplier = nets > 1; 3466920Ssam } 3476920Ssam 3486920Ssam /* 3496920Ssam * Send a request message to all directly 3506920Ssam * connected hosts and networks. 3516920Ssam */ 3526920Ssam request() 3536920Ssam { 354*6929Ssam register struct rip *msg = (struct rip *)packet; 3556920Ssam 356*6929Ssam msg->rip_cmd = RIPCMD_REQUEST; 357*6929Ssam msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 358*6929Ssam msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 359*6929Ssam sendall(); 3606920Ssam } 3616920Ssam 3626920Ssam /* 3636920Ssam * Broadcast a new, or modified, routing table entry 3646920Ssam * to all directly connected hosts and networks. 3656920Ssam */ 3666920Ssam broadcast(entry) 3676920Ssam struct rt_entry *entry; 3686920Ssam { 369*6929Ssam struct rip *msg = (struct rip *)packet; 370*6929Ssam 371*6929Ssam log("broadcast", entry); 372*6929Ssam msg->rip_cmd = RIPCMD_RESPONSE; 373*6929Ssam msg->rip_nets[0].rip_dst = entry->rt_dst; 374*6929Ssam msg->rip_nets[0].rip_metric = min(entry->rt_metric+1, HOPCNT_INFINITY); 375*6929Ssam sendall(); 376*6929Ssam } 377*6929Ssam 378*6929Ssam sendall() 379*6929Ssam { 3806920Ssam register struct rt_hash *rh; 3816920Ssam register struct rt_entry *rt; 3826920Ssam register struct sockaddr *dst; 3836920Ssam struct rt_hash *base = hosthash; 3846920Ssam int doinghost = 1; 3856920Ssam 3866920Ssam again: 3876920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 3886920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3896920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 3906920Ssam continue; 3916920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 3926920Ssam dst = &rt->rt_ifp->if_broadaddr; 3936920Ssam else 3946920Ssam dst = &rt->rt_gateway; 3956920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 3966920Ssam } 3976920Ssam if (doinghost) { 398*6929Ssam base = nethash; 3996920Ssam doinghost = 0; 4006920Ssam goto again; 4016920Ssam } 4026920Ssam } 4036920Ssam 4046920Ssam /* 4056920Ssam * Supply all directly connected neighbors with the 4066920Ssam * current state of the routing tables. 4076920Ssam */ 4086920Ssam supplyall() 4096920Ssam { 4106920Ssam register struct rt_entry *rt; 4116920Ssam register struct rt_hash *rh; 4126920Ssam register struct sockaddr *dst; 4136920Ssam struct rt_hash *base = hosthash; 4146920Ssam int doinghost = 1; 4156920Ssam 4166920Ssam again: 4176920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 4186920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4196920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 4206920Ssam continue; 4216920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 4226920Ssam dst = &rt->rt_ifp->if_broadaddr; 4236920Ssam else 4246920Ssam dst = &rt->rt_gateway; 425*6929Ssam log("supply", rt); 4266920Ssam supply(dst); 4276920Ssam } 4286920Ssam if (doinghost) { 4296920Ssam base = nethash; 4306920Ssam doinghost = 0; 4316920Ssam goto again; 4326920Ssam } 4336920Ssam } 4346920Ssam 4356920Ssam /* 4366920Ssam * Supply routing information to target "sa". 4376920Ssam */ 4386920Ssam supply(sa) 4396920Ssam struct sockaddr *sa; 4406920Ssam { 4416920Ssam struct rip *msg = (struct rip *)packet; 4426920Ssam struct netinfo *n = msg->rip_nets; 4436920Ssam register struct rt_hash *rh; 4446920Ssam register struct rt_entry *rt; 4456920Ssam struct rt_hash *base = hosthash; 446*6929Ssam int doinghost = 1, size; 4476920Ssam int (*output)() = afswitch[sa->sa_family].af_output; 4486920Ssam 4496920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 4506920Ssam again: 4516920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 4526920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 4536920Ssam 4546920Ssam /* 4556920Ssam * Flush packet out if not enough room for 4566920Ssam * another routing table entry. 4576920Ssam */ 458*6929Ssam size = (char *)n - packet; 459*6929Ssam if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { 460*6929Ssam (*output)(sa, size); 4616920Ssam n = msg->rip_nets; 4626920Ssam } 4636920Ssam n->rip_dst = rt->rt_dst; 464*6929Ssam n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY); 465*6929Ssam n++; 4666920Ssam } 4676920Ssam if (doinghost) { 4686920Ssam doinghost = 0; 4696920Ssam base = nethash; 4706920Ssam goto again; 4716920Ssam } 472*6929Ssam if (n != msg->rip_nets) 473*6929Ssam (*output)(sa, (char *)n - packet); 4746920Ssam } 4756920Ssam 4766920Ssam /* 4776920Ssam * Respond to a routing info request. 4786920Ssam */ 4796920Ssam rip_respond(from, size) 4806920Ssam struct sockaddr *from; 4816920Ssam int size; 4826920Ssam { 4836920Ssam register struct rip *msg = (struct rip *)packet; 4846920Ssam struct netinfo *np = msg->rip_nets; 4856920Ssam struct rt_entry *rt; 4866920Ssam int newsize = 0; 4876920Ssam 488*6929Ssam size -= 4 * sizeof (char); 4896920Ssam while (size > 0) { 4906920Ssam if (size < sizeof (struct netinfo)) 4916920Ssam break; 4926920Ssam size -= sizeof (struct netinfo); 4936920Ssam if (np->rip_dst.sa_family == AF_UNSPEC && 4946920Ssam np->rip_metric == HOPCNT_INFINITY && size == 0) { 4956920Ssam supply(from); 4966920Ssam return; 4976920Ssam } 4986920Ssam rt = rtlookup(&np->rip_dst); 499*6929Ssam np->rip_metric = rt == 0 ? 500*6929Ssam HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY); 5016920Ssam np++, newsize += sizeof (struct netinfo); 5026920Ssam } 5036920Ssam if (newsize > 0) { 5046920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 5056920Ssam newsize += sizeof (int); 5066920Ssam (*afswitch[from->sa_family].af_output)(from, newsize); 5076920Ssam } 5086920Ssam } 5096920Ssam 5106920Ssam /* 5116920Ssam * Handle an incoming routing packet. 5126920Ssam */ 5136920Ssam rip_input(from, size) 5146920Ssam struct sockaddr *from; 5156920Ssam int size; 5166920Ssam { 5176920Ssam register struct rip *msg = (struct rip *)packet; 5186920Ssam struct rt_entry *rt; 5196920Ssam struct netinfo *n; 5206920Ssam 5216920Ssam if (msg->rip_cmd != RIPCMD_RESPONSE && 5226920Ssam msg->rip_cmd != RIPCMD_REQUEST) 5236920Ssam return; 5246920Ssam 5256920Ssam if (msg->rip_cmd == RIPCMD_RESPONSE && 5266920Ssam (*afswitch[from->sa_family].af_portmatch)(from) == 0) 5276920Ssam return; 5286920Ssam if (msg->rip_cmd == RIPCMD_REQUEST) { 5296920Ssam rip_respond(from, size); 5306920Ssam return; 5316920Ssam } 5326920Ssam 5336920Ssam /* 5346920Ssam * Process updates. 5356920Ssam * Extraneous information like Internet ports 5366920Ssam * must first be purged from the sender's address for 5376920Ssam * pattern matching below. 5386920Ssam */ 5396920Ssam (*afswitch[from->sa_family].af_canon)(from); 5406920Ssam if (trace) 5416920Ssam printf("input from %x\n", from->sin_addr); 5426920Ssam /* 5436920Ssam * If response packet is from ourselves, use it only 5446920Ssam * to reset timer on entry. Otherwise, we'd believe 5456920Ssam * it as gospel (since it comes from the router) and 5466920Ssam * unknowingly update the metric to show the outgoing 5476920Ssam * cost (higher than our real cost). I guess the protocol 5486920Ssam * spec doesn't address this because Xerox Ethernets 5496920Ssam * don't hear their own broadcasts? 5506920Ssam */ 5516920Ssam if (if_ifwithaddr(from)) { 5526920Ssam rt = rtlookup(from); 5536920Ssam if (rt) 5546920Ssam rt->rt_timer = 0; 5556920Ssam return; 5566920Ssam } 557*6929Ssam size -= 4 * sizeof (char); 5586920Ssam n = msg->rip_nets; 5596920Ssam for (; size > 0; size -= sizeof (struct netinfo), n++) { 5606920Ssam if (size < sizeof (struct netinfo)) 5616920Ssam break; 5626920Ssam if (trace) 5636920Ssam printf("dst %x hc %d...", n->rip_dst.sin_addr, 5646920Ssam n->rip_metric); 5656920Ssam rt = rtlookup(&n->rip_dst); 5666920Ssam 5676920Ssam /* 5686920Ssam * Unknown entry, add it to the tables only if 5696920Ssam * its interesting. 5706920Ssam */ 5716920Ssam if (rt == 0) { 5726920Ssam if (n->rip_metric < HOPCNT_INFINITY) 5736920Ssam rtadd(&n->rip_dst, from, n->rip_metric); 5746920Ssam if (trace) 5756920Ssam printf("new\n"); 5766920Ssam continue; 5776920Ssam } 5786920Ssam 5796920Ssam if (trace) 5806920Ssam printf("ours: gate %x hc %d timer %d\n", 5816920Ssam rt->rt_gateway.sin_addr, 5826920Ssam rt->rt_metric, rt->rt_timer); 5836920Ssam /* 5846920Ssam * Update the entry if one of the following is true: 5856920Ssam * 5866920Ssam * (1) The update came directly from the gateway. 5876920Ssam * (2) A shorter path is provided. 5886920Ssam * (3) The entry hasn't been updated in a while 589*6929Ssam * and a path of equivalent cost is offered 590*6929Ssam * (with the cost finite). 5916920Ssam */ 5926920Ssam if (equal(from, &rt->rt_gateway) || 5936920Ssam rt->rt_metric > n->rip_metric || 5946920Ssam (rt->rt_timer > (EXPIRE_TIME/2) && 595*6929Ssam rt->rt_metric == n->rip_metric && 596*6929Ssam rt->rt_metric < HOPCNT_INFINITY)) { 5976920Ssam rtchange(rt, from, n->rip_metric); 5986920Ssam rt->rt_timer = 0; 5996920Ssam } 6006920Ssam } 6016920Ssam } 6026920Ssam 6036920Ssam /* 6046920Ssam * Lookup an entry to the appropriate dstination. 6056920Ssam */ 6066920Ssam struct rt_entry * 6076920Ssam rtlookup(dst) 6086920Ssam struct sockaddr *dst; 6096920Ssam { 6106920Ssam register struct rt_entry *rt; 6116920Ssam register struct rt_hash *rh; 6126920Ssam register int hash, (*match)(); 6136920Ssam struct afhash h; 6146920Ssam int af = dst->sa_family, doinghost = 1; 6156920Ssam 6166920Ssam if (af >= AF_MAX) 6176920Ssam return (0); 6186920Ssam (*afswitch[af].af_hash)(dst, &h); 6196920Ssam hash = h.afh_hosthash; 6206920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6216920Ssam 6226920Ssam again: 6236920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 6246920Ssam if (rt->rt_hash != hash) 6256920Ssam continue; 6266920Ssam if (doinghost) { 6276920Ssam if (equal(&rt->rt_dst, dst)) 6286920Ssam return (rt); 6296920Ssam } else { 6306920Ssam if (rt->rt_dst.sa_family == af && 6316920Ssam (*match)(&rt->rt_dst, dst)) 6326920Ssam return (rt); 6336920Ssam } 6346920Ssam } 6356920Ssam if (doinghost) { 6366920Ssam doinghost = 0; 6376920Ssam hash = h.afh_nethash; 6386920Ssam match = afswitch[af].af_netmatch; 6396920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6406920Ssam goto again; 6416920Ssam } 6426920Ssam return (0); 6436920Ssam } 6446920Ssam 6456920Ssam rtinit() 6466920Ssam { 6476920Ssam register struct rt_hash *rh; 6486920Ssam 6496920Ssam for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 6506920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6516920Ssam for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 6526920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 6536920Ssam } 6546920Ssam 6556920Ssam /* 6566920Ssam * Add a new entry. 6576920Ssam */ 6586920Ssam rtadd(dst, gate, metric) 6596920Ssam struct sockaddr *dst, *gate; 6606920Ssam short metric; 6616920Ssam { 6626920Ssam struct afhash h; 6636920Ssam register struct rt_entry *rt; 6646920Ssam struct rt_hash *rh; 6656920Ssam int af = dst->sa_family, flags, hash; 6666920Ssam 6676920Ssam if (af >= AF_MAX) 6686920Ssam return; 6696920Ssam (*afswitch[af].af_hash)(dst, &h); 6706920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 6716920Ssam if (flags & RTF_HOST) { 6726920Ssam hash = h.afh_hosthash; 6736920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 6746920Ssam } else { 6756920Ssam hash = h.afh_nethash; 6766920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 6776920Ssam } 6786920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 6796920Ssam if (rt == 0) 6806920Ssam return; 6816920Ssam rt->rt_hash = hash; 6826920Ssam rt->rt_dst = *dst; 6836920Ssam rt->rt_gateway = *gate; 6846920Ssam rt->rt_metric = metric; 6856920Ssam rt->rt_timer = 0; 6866920Ssam rt->rt_flags = RTF_UP | flags; 6876920Ssam rt->rt_ifp = if_ifwithnet(&rt->rt_gateway); 6886920Ssam if (metric == 0) 6896920Ssam rt->rt_flags |= RTF_DIRECT; 6906920Ssam insque(rt, rh); 691*6929Ssam log("add", rt); 6926920Ssam if (initializing) 6936920Ssam return; 6946920Ssam if (supplier) 6956920Ssam broadcast(rt); 6966920Ssam if (install) { 6976920Ssam rt->rt_flags |= RTF_ADDRT; 6986920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 6996920Ssam } 7006920Ssam } 7016920Ssam 7026920Ssam /* 7036920Ssam * Look to see if a change to an existing entry 7046920Ssam * is warranted; if so, make it. 7056920Ssam */ 7066920Ssam rtchange(rt, gate, metric) 7076920Ssam struct rt_entry *rt; 7086920Ssam struct sockaddr *gate; 7096920Ssam short metric; 7106920Ssam { 7116920Ssam int change = 0; 7126920Ssam 7136920Ssam if (!equal(&rt->rt_gateway, gate)) { 7146920Ssam rt->rt_gateway = *gate; 7156920Ssam change++; 7166920Ssam } 7176920Ssam 7186920Ssam /* 7196920Ssam * If the hop count has changed, adjust 7206920Ssam * the flags in the routing table entry accordingly. 7216920Ssam */ 7226920Ssam if (metric != rt->rt_metric) { 7236920Ssam if (rt->rt_metric == 0) 7246920Ssam rt->rt_flags &= ~RTF_DIRECT; 7256920Ssam rt->rt_metric = metric; 7266920Ssam if (metric >= HOPCNT_INFINITY) 7276920Ssam rt->rt_flags &= ~RTF_UP; 7286920Ssam else 7296920Ssam rt->rt_flags |= RTF_UP; 7306920Ssam change++; 7316920Ssam } 7326920Ssam 7336920Ssam if (!change) 7346920Ssam return; 7356920Ssam if (supplier) 7366920Ssam broadcast(rt); 737*6929Ssam log("change", rt); 7386920Ssam if (install) { 7396920Ssam rt->rt_flags |= RTF_CHGRT; 7406920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 7416920Ssam } 7426920Ssam } 7436920Ssam 7446920Ssam /* 7456920Ssam * Delete a routing table entry. 7466920Ssam */ 7476920Ssam rtdelete(rt) 7486920Ssam struct rt_entry *rt; 7496920Ssam { 750*6929Ssam log("delete", rt); 7516920Ssam if (install) 7526920Ssam if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) && 7536920Ssam errno == EBUSY) 7546920Ssam rt->rt_flags |= RTF_DELRT; 7556920Ssam remque(rt); 7566920Ssam free((char *)rt); 7576920Ssam } 7586920Ssam 7596920Ssam log(operation, rt) 7606920Ssam char *operation; 7616920Ssam struct rt_entry *rt; 7626920Ssam { 7636920Ssam time_t t = time(0); 7646920Ssam struct sockaddr_in *dst, *gate; 7656920Ssam static struct flagbits { 7666920Ssam int t_bits; 7676920Ssam char *t_name; 7686920Ssam } bits[] = { 7696920Ssam { RTF_UP, "UP" }, 7706920Ssam { RTF_DIRECT, "DIRECT" }, 7716920Ssam { RTF_HOST, "HOST" }, 7726920Ssam { RTF_DELRT, "DELETE" }, 7736920Ssam { RTF_CHGRT, "CHANGE" }, 7746920Ssam { RTF_SILENT, "SILENT" }, 7756920Ssam { 0 } 7766920Ssam }; 7776920Ssam register struct flagbits *p; 7786920Ssam register int first; 7796920Ssam char *cp; 7806920Ssam 781*6929Ssam if (trace == 0) 782*6929Ssam return; 7836920Ssam printf("%s ", operation); 7846920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 7856920Ssam gate = (struct sockaddr_in *)&rt->rt_gateway; 7866920Ssam printf("dst %x, router %x, metric %d, flags ", 7876920Ssam dst->sin_addr, gate->sin_addr, rt->rt_metric); 7886920Ssam cp = "%s"; 7896920Ssam for (first = 1, p = bits; p->t_bits > 0; p++) { 7906920Ssam if ((rt->rt_flags & p->t_bits) == 0) 7916920Ssam continue; 7926920Ssam printf(cp, p->t_name); 7936920Ssam if (first) { 7946920Ssam cp = "|%s"; 7956920Ssam first = 0; 7966920Ssam } 7976920Ssam } 7986920Ssam putchar('\n'); 7996920Ssam } 800*6929Ssam 801*6929Ssam struct ifnet * 802*6929Ssam if_ifwithaddr(addr) 803*6929Ssam struct sockaddr *addr; 804*6929Ssam { 805*6929Ssam register struct ifnet *ifp; 806*6929Ssam 807*6929Ssam #define same(a1, a2) \ 808*6929Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 809*6929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 810*6929Ssam if (ifp->if_addr.sa_family != addr->sa_family) 811*6929Ssam continue; 812*6929Ssam if (same(&ifp->if_addr, addr)) 813*6929Ssam break; 814*6929Ssam if ((ifp->if_flags & IFF_BROADCAST) && 815*6929Ssam same(&ifp->if_broadaddr, addr)) 816*6929Ssam break; 817*6929Ssam } 818*6929Ssam return (ifp); 819*6929Ssam #undef same 820*6929Ssam } 821*6929Ssam 822*6929Ssam struct ifnet * 823*6929Ssam if_ifwithnet(addr) 824*6929Ssam register struct sockaddr *addr; 825*6929Ssam { 826*6929Ssam register struct ifnet *ifp; 827*6929Ssam register int af = addr->sa_family; 828*6929Ssam register int (*netmatch)(); 829*6929Ssam 830*6929Ssam if (af >= AF_MAX) 831*6929Ssam return (0); 832*6929Ssam netmatch = afswitch[af].af_netmatch; 833*6929Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 834*6929Ssam if (af != ifp->if_addr.sa_family) 835*6929Ssam continue; 836*6929Ssam if ((*netmatch)(addr, &ifp->if_addr)) 837*6929Ssam break; 838*6929Ssam } 839*6929Ssam return (ifp); 840*6929Ssam } 841*6929Ssam 842*6929Ssam struct in_addr 843*6929Ssam if_makeaddr(net, host) 844*6929Ssam int net, host; 845*6929Ssam { 846*6929Ssam u_long addr; 847*6929Ssam 848*6929Ssam if (net < 128) 849*6929Ssam addr = (net << 24) | host; 850*6929Ssam else if (net < 65536) 851*6929Ssam addr = (net << 16) | host; 852*6929Ssam else 853*6929Ssam addr = (net << 8) | host; 854*6929Ssam #ifdef vax 855*6929Ssam addr = htonl(addr); 856*6929Ssam #endif 857*6929Ssam return (*(struct in_addr *)&addr); 858*6929Ssam } 859