1*6920Ssam #ifndef lint 2*6920Ssam static char sccsid[] = "@(#)routed.c 4.1 05/22/82"; 3*6920Ssam #endif 4*6920Ssam 5*6920Ssam #include <sys/param.h> 6*6920Ssam #include <sys/protosw.h> 7*6920Ssam #include <sys/ioctl.h> 8*6920Ssam #include <sys/socket.h> 9*6920Ssam #include <net/in.h> 10*6920Ssam #define KERNEL 11*6920Ssam #include <net/route.h> 12*6920Ssam #include <net/if.h> 13*6920Ssam #include <errno.h> 14*6920Ssam #include <stdio.h> 15*6920Ssam #include <nlist.h> 16*6920Ssam #include <signal.h> 17*6920Ssam #include "rip.h" 18*6920Ssam #include "router.h" 19*6920Ssam 20*6920Ssam #define LOOPBACKNET 0177 21*6920Ssam /* casts to keep lint happy */ 22*6920Ssam #define insque(q,p) _insque((caddr_t)q,(caddr_t)p) 23*6920Ssam #define remque(q) _remque((caddr_t)q) 24*6920Ssam #define equal(a1, a2) \ 25*6920Ssam (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 26*6920Ssam 27*6920Ssam struct nlist nl[] = { 28*6920Ssam #define N_IFNET 0 29*6920Ssam { "_ifnet" }, 30*6920Ssam 0, 31*6920Ssam }; 32*6920Ssam 33*6920Ssam struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; 34*6920Ssam 35*6920Ssam int s; 36*6920Ssam int kmem; 37*6920Ssam int supplier; /* process should supply updates */ 38*6920Ssam int initializing; /* stem off broadcast() calls */ 39*6920Ssam int install = 0; /* if 1 call kernel */ 40*6920Ssam int timeval; 41*6920Ssam int timer(); 42*6920Ssam int cleanup(); 43*6920Ssam int trace = 0; 44*6920Ssam 45*6920Ssam char packet[MAXPACKETSIZE]; 46*6920Ssam 47*6920Ssam extern char *malloc(); 48*6920Ssam extern int errno; 49*6920Ssam 50*6920Ssam main(argc, argv) 51*6920Ssam int argc; 52*6920Ssam char *argv[]; 53*6920Ssam { 54*6920Ssam int cc; 55*6920Ssam struct sockaddr from; 56*6920Ssam 57*6920Ssam { int t = open("/dev/tty", 2); 58*6920Ssam if (t >= 0) { 59*6920Ssam ioctl(t, TIOCNOTTY, 0); 60*6920Ssam close(t); 61*6920Ssam } 62*6920Ssam } 63*6920Ssam if (trace) { 64*6920Ssam (void) fclose(stdout); 65*6920Ssam (void) fclose(stderr); 66*6920Ssam (void) fopen("trace", "a"); 67*6920Ssam (void) dup(fileno(stdout)); 68*6920Ssam setbuf(stdout, NULL); 69*6920Ssam 70*6920Ssam } 71*6920Ssam #ifdef vax 72*6920Ssam myaddr.sin_port = htons(myaddr.sin_port); 73*6920Ssam #endif 74*6920Ssam again: 75*6920Ssam s = socket(SOCK_DGRAM, 0, &myaddr, 0); 76*6920Ssam if (s < 0) { 77*6920Ssam perror("socket"); 78*6920Ssam sleep(30); 79*6920Ssam goto again; 80*6920Ssam } 81*6920Ssam rtinit(); 82*6920Ssam getothers(); 83*6920Ssam getinterfaces(); 84*6920Ssam request(); 85*6920Ssam 86*6920Ssam argv++, argc--; 87*6920Ssam while (argc > 0) { 88*6920Ssam if (strcmp(*argv, "-s") == 0) 89*6920Ssam supplier++; 90*6920Ssam else if (strcmp(*argv, "-q") == 0) 91*6920Ssam supplier = 0; 92*6920Ssam argv++, argc--; 93*6920Ssam } 94*6920Ssam sigset(SIGALRM, timer); 95*6920Ssam alarm(TIMER_RATE); 96*6920Ssam 97*6920Ssam /* 98*6920Ssam * Listen for routing packets 99*6920Ssam */ 100*6920Ssam for (;;) { 101*6920Ssam cc = receive(s, &from, packet, sizeof (packet)); 102*6920Ssam if (cc <= 0) { 103*6920Ssam if (cc < 0 && errno != EINTR) 104*6920Ssam perror("receive"); 105*6920Ssam continue; 106*6920Ssam } 107*6920Ssam sighold(SIGALRM); 108*6920Ssam rip_input(&from, cc); 109*6920Ssam sigrelse(SIGALRM); 110*6920Ssam } 111*6920Ssam } 112*6920Ssam 113*6920Ssam /* 114*6920Ssam * Look in a file for any gateways we should configure 115*6920Ssam * outside the directly connected ones. This is a kludge, 116*6920Ssam * but until we can find out about gateways on the "other side" 117*6920Ssam * of the ARPANET using GGP, it's a must. 118*6920Ssam * 119*6920Ssam * We don't really know the distance to the gateway, so we 120*6920Ssam * assume it's a neighbor. 121*6920Ssam */ 122*6920Ssam getothers() 123*6920Ssam { 124*6920Ssam struct sockaddr_in dst, gate; 125*6920Ssam FILE *fp = fopen("/etc/gateways", "r"); 126*6920Ssam struct rt_entry *rt; 127*6920Ssam 128*6920Ssam if (fp == NULL) 129*6920Ssam return; 130*6920Ssam bzero((char *)&dst, sizeof (dst)); 131*6920Ssam bzero((char *)&gate, sizeof (gate)); 132*6920Ssam dst.sin_family = AF_INET; 133*6920Ssam gate.sin_family = AF_INET; 134*6920Ssam while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, 135*6920Ssam &gate.sin_addr.s_addr) != EOF) { 136*6920Ssam rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1); 137*6920Ssam rt = rtlookup((struct sockaddr *)&dst); 138*6920Ssam if (rt) 139*6920Ssam rt->rt_flags |= RTF_SILENT; 140*6920Ssam } 141*6920Ssam fclose(fp); 142*6920Ssam } 143*6920Ssam 144*6920Ssam struct ifnet * 145*6920Ssam if_ifwithaddr(addr) 146*6920Ssam struct sockaddr *addr; 147*6920Ssam { 148*6920Ssam register struct ifnet *ifp; 149*6920Ssam 150*6920Ssam #define same(a1, a2) \ 151*6920Ssam (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0) 152*6920Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 153*6920Ssam if (ifp->if_addr.sa_family != addr->sa_family) 154*6920Ssam continue; 155*6920Ssam if (same(&ifp->if_addr, addr)) 156*6920Ssam break; 157*6920Ssam if ((ifp->if_flags & IFF_BROADCAST) && 158*6920Ssam same(&ifp->if_broadaddr, addr)) 159*6920Ssam break; 160*6920Ssam } 161*6920Ssam return (ifp); 162*6920Ssam #undef same 163*6920Ssam } 164*6920Ssam 165*6920Ssam struct ifnet * 166*6920Ssam if_ifwithnet(addr) 167*6920Ssam register struct sockaddr *addr; 168*6920Ssam { 169*6920Ssam register struct ifnet *ifp; 170*6920Ssam register int af = addr->sa_family; 171*6920Ssam register int (*netmatch)(); 172*6920Ssam 173*6920Ssam if (af >= AF_MAX) 174*6920Ssam return (0); 175*6920Ssam netmatch = afswitch[af].af_netmatch; 176*6920Ssam for (ifp = ifnet; ifp; ifp = ifp->if_next) { 177*6920Ssam if (af != ifp->if_addr.sa_family) 178*6920Ssam continue; 179*6920Ssam if ((*netmatch)(addr, &ifp->if_addr)) 180*6920Ssam break; 181*6920Ssam } 182*6920Ssam return (ifp); 183*6920Ssam } 184*6920Ssam 185*6920Ssam struct in_addr 186*6920Ssam if_makeaddr(net, host) 187*6920Ssam int net, host; 188*6920Ssam { 189*6920Ssam u_long addr; 190*6920Ssam 191*6920Ssam if (net < 128) 192*6920Ssam addr = (net << 24) | host; 193*6920Ssam else if (net < 65536) 194*6920Ssam addr = (net << 16) | host; 195*6920Ssam else 196*6920Ssam addr = (net << 8) | host; 197*6920Ssam #ifdef vax 198*6920Ssam addr = htonl(addr); 199*6920Ssam #endif 200*6920Ssam return (*(struct in_addr *)&addr); 201*6920Ssam } 202*6920Ssam 203*6920Ssam /* 204*6920Ssam * Find the network interfaces attached to this machine. 205*6920Ssam * The info is used to:: 206*6920Ssam * 207*6920Ssam * (1) initialize the routing tables, as done by the kernel. 208*6920Ssam * (2) ignore incoming packets we send. 209*6920Ssam * (3) figure out broadcast capability and addresses. 210*6920Ssam * (4) figure out if we're an internetwork gateway. 211*6920Ssam * 212*6920Ssam * We don't handle anything but Internet addresses. 213*6920Ssam */ 214*6920Ssam getinterfaces() 215*6920Ssam { 216*6920Ssam register struct ifnet **pifp, *ifp; 217*6920Ssam struct sockaddr_in net; 218*6920Ssam struct in_addr logicaladdr; 219*6920Ssam int nets; 220*6920Ssam 221*6920Ssam nlist("/vmunix", nl); 222*6920Ssam if (nl[N_IFNET].n_value == 0) { 223*6920Ssam printf("ifnet: symbol not in namelist\n"); 224*6920Ssam exit(1); 225*6920Ssam } 226*6920Ssam kmem = open("/dev/kmem", 0); 227*6920Ssam if (kmem < 0) { 228*6920Ssam perror("/dev/kmem"); 229*6920Ssam exit(1); 230*6920Ssam } 231*6920Ssam (void) lseek(kmem, (long)nl[N_IFNET].n_value, 0); 232*6920Ssam (void) read(kmem, (char *)&ifnet, sizeof (ifnet)); 233*6920Ssam bzero((char *)&net, sizeof (net)); 234*6920Ssam net.sin_family = AF_INET; 235*6920Ssam logicaladdr.s_addr = 0; 236*6920Ssam nets = 0; 237*6920Ssam pifp = &ifnet; 238*6920Ssam initializing = 1; 239*6920Ssam while (*pifp) { 240*6920Ssam struct sockaddr_in *sin; 241*6920Ssam 242*6920Ssam (void) lseek(kmem, (long)*pifp, 0); 243*6920Ssam ifp = *pifp = (struct ifnet *)malloc(sizeof (struct ifnet)); 244*6920Ssam if (ifp == 0) { 245*6920Ssam printf("routed: out of memory\n"); 246*6920Ssam break; 247*6920Ssam } 248*6920Ssam if (read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) { 249*6920Ssam perror("read"); 250*6920Ssam break; 251*6920Ssam } 252*6920Ssam if (ifp->if_net == LOOPBACKNET) 253*6920Ssam goto skip; 254*6920Ssam nets++; 255*6920Ssam if ((ifp->if_flags & IFF_UP) == 0) 256*6920Ssam goto skip; 257*6920Ssam 258*6920Ssam /* 259*6920Ssam * Kludge: don't treat logical host pseudo-interface 260*6920Ssam * as a net route, instead fabricate route 261*6920Ssam * to get packets back from the gateway. 262*6920Ssam */ 263*6920Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 264*6920Ssam if (sin->sin_family == AF_INET && ifp->if_net == 10 && 265*6920Ssam sin->sin_addr.s_lh) { 266*6920Ssam logicaladdr = sin->sin_addr; 267*6920Ssam goto skip; 268*6920Ssam } 269*6920Ssam 270*6920Ssam /* 271*6920Ssam * Before we can handle point-point links, the interface 272*6920Ssam * structure will have to include an indicator to allow 273*6920Ssam * us to distinguish entries from "network" entries. 274*6920Ssam */ 275*6920Ssam net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 276*6920Ssam rtadd((struct sockaddr *)&net, (struct sockaddr *)sin, 0); 277*6920Ssam skip: 278*6920Ssam pifp = &ifp->if_next; 279*6920Ssam } 280*6920Ssam if (logicaladdr.s_addr) { 281*6920Ssam struct rt_entry *rt; 282*6920Ssam 283*6920Ssam net.sin_addr = logicaladdr; 284*6920Ssam if (ifnet) 285*6920Ssam rtadd((struct sockaddr *)&net, &ifnet->if_addr, 0); 286*6920Ssam /* yech...yet another logical host kludge */ 287*6920Ssam rt = rtlookup((struct sockaddr *)&net); 288*6920Ssam if (rt) 289*6920Ssam rt->rt_flags |= RTF_SILENT; 290*6920Ssam } 291*6920Ssam (void) close(kmem); 292*6920Ssam initializing = 0; 293*6920Ssam supplier = nets > 1; 294*6920Ssam } 295*6920Ssam 296*6920Ssam /* 297*6920Ssam * Send a request message to all directly 298*6920Ssam * connected hosts and networks. 299*6920Ssam */ 300*6920Ssam request() 301*6920Ssam { 302*6920Ssam register struct rt_entry *rt; 303*6920Ssam register struct rt_hash *rh; 304*6920Ssam struct rt_hash *base = hosthash; 305*6920Ssam int doinghost = 1; 306*6920Ssam 307*6920Ssam again: 308*6920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 309*6920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 310*6920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 311*6920Ssam continue; 312*6920Ssam getall(rt); 313*6920Ssam } 314*6920Ssam if (doinghost) { 315*6920Ssam base = nethash; 316*6920Ssam doinghost = 0; 317*6920Ssam goto again; 318*6920Ssam } 319*6920Ssam } 320*6920Ssam 321*6920Ssam /* 322*6920Ssam * Broadcast a new, or modified, routing table entry 323*6920Ssam * to all directly connected hosts and networks. 324*6920Ssam */ 325*6920Ssam broadcast(entry) 326*6920Ssam struct rt_entry *entry; 327*6920Ssam { 328*6920Ssam register struct rt_hash *rh; 329*6920Ssam register struct rt_entry *rt; 330*6920Ssam register struct sockaddr *dst; 331*6920Ssam struct rt_hash *base = hosthash; 332*6920Ssam int doinghost = 1; 333*6920Ssam struct rip *msg = (struct rip *)packet; 334*6920Ssam 335*6920Ssam if (trace) 336*6920Ssam log("broadcast", entry); 337*6920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 338*6920Ssam msg->rip_nets[0].rip_dst = entry->rt_dst; 339*6920Ssam msg->rip_nets[0].rip_metric = entry->rt_metric + 1; 340*6920Ssam 341*6920Ssam again: 342*6920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 343*6920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 344*6920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 345*6920Ssam continue; 346*6920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 347*6920Ssam dst = &rt->rt_ifp->if_broadaddr; 348*6920Ssam else 349*6920Ssam dst = &rt->rt_gateway; 350*6920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 351*6920Ssam } 352*6920Ssam if (doinghost) { 353*6920Ssam doinghost = 0; 354*6920Ssam base = nethash; 355*6920Ssam goto again; 356*6920Ssam } 357*6920Ssam } 358*6920Ssam 359*6920Ssam /* 360*6920Ssam * Supply all directly connected neighbors with the 361*6920Ssam * current state of the routing tables. 362*6920Ssam */ 363*6920Ssam supplyall() 364*6920Ssam { 365*6920Ssam register struct rt_entry *rt; 366*6920Ssam register struct rt_hash *rh; 367*6920Ssam register struct sockaddr *dst; 368*6920Ssam struct rt_hash *base = hosthash; 369*6920Ssam int doinghost = 1; 370*6920Ssam 371*6920Ssam again: 372*6920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 373*6920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 374*6920Ssam if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) 375*6920Ssam continue; 376*6920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 377*6920Ssam dst = &rt->rt_ifp->if_broadaddr; 378*6920Ssam else 379*6920Ssam dst = &rt->rt_gateway; 380*6920Ssam if (trace) 381*6920Ssam log("supply", rt); 382*6920Ssam supply(dst); 383*6920Ssam } 384*6920Ssam if (doinghost) { 385*6920Ssam base = nethash; 386*6920Ssam doinghost = 0; 387*6920Ssam goto again; 388*6920Ssam } 389*6920Ssam } 390*6920Ssam 391*6920Ssam /* 392*6920Ssam * Supply routing information to target "sa". 393*6920Ssam */ 394*6920Ssam supply(sa) 395*6920Ssam struct sockaddr *sa; 396*6920Ssam { 397*6920Ssam struct rip *msg = (struct rip *)packet; 398*6920Ssam struct netinfo *n = msg->rip_nets; 399*6920Ssam register struct rt_hash *rh; 400*6920Ssam register struct rt_entry *rt; 401*6920Ssam struct rt_hash *base = hosthash; 402*6920Ssam int space = MAXPACKETSIZE - sizeof (int), doinghost = 1; 403*6920Ssam int (*output)() = afswitch[sa->sa_family].af_output; 404*6920Ssam 405*6920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 406*6920Ssam again: 407*6920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) 408*6920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 409*6920Ssam 410*6920Ssam /* 411*6920Ssam * Flush packet out if not enough room for 412*6920Ssam * another routing table entry. 413*6920Ssam */ 414*6920Ssam if (space < sizeof (struct netinfo)) { 415*6920Ssam (*output)(sa, MAXPACKETSIZE - space); 416*6920Ssam space = MAXPACKETSIZE - sizeof (int); 417*6920Ssam n = msg->rip_nets; 418*6920Ssam } 419*6920Ssam n->rip_dst = rt->rt_dst; 420*6920Ssam n->rip_metric = rt->rt_metric + 1; 421*6920Ssam n++, space -= sizeof (struct netinfo); 422*6920Ssam } 423*6920Ssam if (doinghost) { 424*6920Ssam doinghost = 0; 425*6920Ssam base = nethash; 426*6920Ssam goto again; 427*6920Ssam } 428*6920Ssam 429*6920Ssam if (space < MAXPACKETSIZE - sizeof (int)) 430*6920Ssam (*output)(sa, MAXPACKETSIZE - space); 431*6920Ssam } 432*6920Ssam 433*6920Ssam getall(rt) 434*6920Ssam struct rt_entry *rt; 435*6920Ssam { 436*6920Ssam register struct rip *msg = (struct rip *)packet; 437*6920Ssam struct sockaddr *dst; 438*6920Ssam 439*6920Ssam msg->rip_cmd = RIPCMD_REQUEST; 440*6920Ssam msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 441*6920Ssam msg->rip_nets[0].rip_metric = HOPCNT_INFINITY; 442*6920Ssam if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) 443*6920Ssam dst = &rt->rt_ifp->if_broadaddr; 444*6920Ssam else 445*6920Ssam dst = &rt->rt_gateway; 446*6920Ssam (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); 447*6920Ssam } 448*6920Ssam 449*6920Ssam /* 450*6920Ssam * Respond to a routing info request. 451*6920Ssam */ 452*6920Ssam rip_respond(from, size) 453*6920Ssam struct sockaddr *from; 454*6920Ssam int size; 455*6920Ssam { 456*6920Ssam register struct rip *msg = (struct rip *)packet; 457*6920Ssam struct netinfo *np = msg->rip_nets; 458*6920Ssam struct rt_entry *rt; 459*6920Ssam int newsize = 0; 460*6920Ssam 461*6920Ssam size -= sizeof (int); 462*6920Ssam while (size > 0) { 463*6920Ssam if (size < sizeof (struct netinfo)) 464*6920Ssam break; 465*6920Ssam size -= sizeof (struct netinfo); 466*6920Ssam if (np->rip_dst.sa_family == AF_UNSPEC && 467*6920Ssam np->rip_metric == HOPCNT_INFINITY && size == 0) { 468*6920Ssam supply(from); 469*6920Ssam return; 470*6920Ssam } 471*6920Ssam rt = rtlookup(&np->rip_dst); 472*6920Ssam np->rip_metric = rt == 0 ? HOPCNT_INFINITY : rt->rt_metric + 1; 473*6920Ssam np++, newsize += sizeof (struct netinfo); 474*6920Ssam } 475*6920Ssam if (newsize > 0) { 476*6920Ssam msg->rip_cmd = RIPCMD_RESPONSE; 477*6920Ssam newsize += sizeof (int); 478*6920Ssam (*afswitch[from->sa_family].af_output)(from, newsize); 479*6920Ssam } 480*6920Ssam } 481*6920Ssam 482*6920Ssam /* 483*6920Ssam * Handle an incoming routing packet. 484*6920Ssam */ 485*6920Ssam rip_input(from, size) 486*6920Ssam struct sockaddr *from; 487*6920Ssam int size; 488*6920Ssam { 489*6920Ssam register struct rip *msg = (struct rip *)packet; 490*6920Ssam struct rt_entry *rt; 491*6920Ssam struct netinfo *n; 492*6920Ssam 493*6920Ssam if (msg->rip_cmd != RIPCMD_RESPONSE && 494*6920Ssam msg->rip_cmd != RIPCMD_REQUEST) 495*6920Ssam return; 496*6920Ssam 497*6920Ssam /* 498*6920Ssam * The router port is in the lower 1K of the UDP port space, 499*6920Ssam * and so is priviledged. Hence we can "authenticate" incoming 500*6920Ssam * updates simply by checking the source port. 501*6920Ssam */ 502*6920Ssam if (msg->rip_cmd == RIPCMD_RESPONSE && 503*6920Ssam (*afswitch[from->sa_family].af_portmatch)(from) == 0) 504*6920Ssam return; 505*6920Ssam if (msg->rip_cmd == RIPCMD_REQUEST) { 506*6920Ssam rip_respond(from, size); 507*6920Ssam return; 508*6920Ssam } 509*6920Ssam 510*6920Ssam /* 511*6920Ssam * Process updates. 512*6920Ssam * Extraneous information like Internet ports 513*6920Ssam * must first be purged from the sender's address for 514*6920Ssam * pattern matching below. 515*6920Ssam */ 516*6920Ssam (*afswitch[from->sa_family].af_canon)(from); 517*6920Ssam if (trace) 518*6920Ssam printf("input from %x\n", from->sin_addr); 519*6920Ssam /* 520*6920Ssam * If response packet is from ourselves, use it only 521*6920Ssam * to reset timer on entry. Otherwise, we'd believe 522*6920Ssam * it as gospel (since it comes from the router) and 523*6920Ssam * unknowingly update the metric to show the outgoing 524*6920Ssam * cost (higher than our real cost). I guess the protocol 525*6920Ssam * spec doesn't address this because Xerox Ethernets 526*6920Ssam * don't hear their own broadcasts? 527*6920Ssam */ 528*6920Ssam if (if_ifwithaddr(from)) { 529*6920Ssam rt = rtlookup(from); 530*6920Ssam if (rt) 531*6920Ssam rt->rt_timer = 0; 532*6920Ssam return; 533*6920Ssam } 534*6920Ssam size -= sizeof (int); 535*6920Ssam n = msg->rip_nets; 536*6920Ssam for (; size > 0; size -= sizeof (struct netinfo), n++) { 537*6920Ssam if (size < sizeof (struct netinfo)) 538*6920Ssam break; 539*6920Ssam if (trace) 540*6920Ssam printf("dst %x hc %d...", n->rip_dst.sin_addr, 541*6920Ssam n->rip_metric); 542*6920Ssam rt = rtlookup(&n->rip_dst); 543*6920Ssam 544*6920Ssam /* 545*6920Ssam * Unknown entry, add it to the tables only if 546*6920Ssam * its interesting. 547*6920Ssam */ 548*6920Ssam if (rt == 0) { 549*6920Ssam if (n->rip_metric < HOPCNT_INFINITY) 550*6920Ssam rtadd(&n->rip_dst, from, n->rip_metric); 551*6920Ssam if (trace) 552*6920Ssam printf("new\n"); 553*6920Ssam continue; 554*6920Ssam } 555*6920Ssam 556*6920Ssam if (trace) 557*6920Ssam printf("ours: gate %x hc %d timer %d\n", 558*6920Ssam rt->rt_gateway.sin_addr, 559*6920Ssam rt->rt_metric, rt->rt_timer); 560*6920Ssam /* 561*6920Ssam * Update the entry if one of the following is true: 562*6920Ssam * 563*6920Ssam * (1) The update came directly from the gateway. 564*6920Ssam * (2) A shorter path is provided. 565*6920Ssam * (3) The entry hasn't been updated in a while 566*6920Ssam * and a path of equivalent cost is offered. 567*6920Ssam */ 568*6920Ssam if (equal(from, &rt->rt_gateway) || 569*6920Ssam rt->rt_metric > n->rip_metric || 570*6920Ssam (rt->rt_timer > (EXPIRE_TIME/2) && 571*6920Ssam rt->rt_metric == n->rip_metric)) { 572*6920Ssam rtchange(rt, from, n->rip_metric); 573*6920Ssam rt->rt_timer = 0; 574*6920Ssam } 575*6920Ssam } 576*6920Ssam } 577*6920Ssam 578*6920Ssam /* 579*6920Ssam * Lookup an entry to the appropriate dstination. 580*6920Ssam */ 581*6920Ssam struct rt_entry * 582*6920Ssam rtlookup(dst) 583*6920Ssam struct sockaddr *dst; 584*6920Ssam { 585*6920Ssam register struct rt_entry *rt; 586*6920Ssam register struct rt_hash *rh; 587*6920Ssam register int hash, (*match)(); 588*6920Ssam struct afhash h; 589*6920Ssam int af = dst->sa_family, doinghost = 1; 590*6920Ssam 591*6920Ssam if (af >= AF_MAX) 592*6920Ssam return (0); 593*6920Ssam (*afswitch[af].af_hash)(dst, &h); 594*6920Ssam hash = h.afh_hosthash; 595*6920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 596*6920Ssam 597*6920Ssam again: 598*6920Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 599*6920Ssam if (rt->rt_hash != hash) 600*6920Ssam continue; 601*6920Ssam if (doinghost) { 602*6920Ssam if (equal(&rt->rt_dst, dst)) 603*6920Ssam return (rt); 604*6920Ssam } else { 605*6920Ssam if (rt->rt_dst.sa_family == af && 606*6920Ssam (*match)(&rt->rt_dst, dst)) 607*6920Ssam return (rt); 608*6920Ssam } 609*6920Ssam } 610*6920Ssam if (doinghost) { 611*6920Ssam doinghost = 0; 612*6920Ssam hash = h.afh_nethash; 613*6920Ssam match = afswitch[af].af_netmatch; 614*6920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 615*6920Ssam goto again; 616*6920Ssam } 617*6920Ssam return (0); 618*6920Ssam } 619*6920Ssam 620*6920Ssam rtinit() 621*6920Ssam { 622*6920Ssam register struct rt_hash *rh; 623*6920Ssam 624*6920Ssam for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 625*6920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 626*6920Ssam for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 627*6920Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 628*6920Ssam } 629*6920Ssam 630*6920Ssam /* 631*6920Ssam * Add a new entry. 632*6920Ssam */ 633*6920Ssam rtadd(dst, gate, metric) 634*6920Ssam struct sockaddr *dst, *gate; 635*6920Ssam short metric; 636*6920Ssam { 637*6920Ssam struct afhash h; 638*6920Ssam register struct rt_entry *rt; 639*6920Ssam struct rt_hash *rh; 640*6920Ssam int af = dst->sa_family, flags, hash; 641*6920Ssam 642*6920Ssam if (af >= AF_MAX) 643*6920Ssam return; 644*6920Ssam (*afswitch[af].af_hash)(dst, &h); 645*6920Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 646*6920Ssam if (flags & RTF_HOST) { 647*6920Ssam hash = h.afh_hosthash; 648*6920Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 649*6920Ssam } else { 650*6920Ssam hash = h.afh_nethash; 651*6920Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 652*6920Ssam } 653*6920Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 654*6920Ssam if (rt == 0) 655*6920Ssam return; 656*6920Ssam rt->rt_hash = hash; 657*6920Ssam rt->rt_dst = *dst; 658*6920Ssam rt->rt_gateway = *gate; 659*6920Ssam rt->rt_metric = metric; 660*6920Ssam rt->rt_timer = 0; 661*6920Ssam rt->rt_flags = RTF_UP | flags; 662*6920Ssam rt->rt_ifp = if_ifwithnet(&rt->rt_gateway); 663*6920Ssam if (metric == 0) 664*6920Ssam rt->rt_flags |= RTF_DIRECT; 665*6920Ssam insque(rt, rh); 666*6920Ssam if (trace) 667*6920Ssam log("add", rt); 668*6920Ssam if (initializing) 669*6920Ssam return; 670*6920Ssam if (supplier) 671*6920Ssam broadcast(rt); 672*6920Ssam if (install) { 673*6920Ssam rt->rt_flags |= RTF_ADDRT; 674*6920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 675*6920Ssam } 676*6920Ssam } 677*6920Ssam 678*6920Ssam /* 679*6920Ssam * Look to see if a change to an existing entry 680*6920Ssam * is warranted; if so, make it. 681*6920Ssam */ 682*6920Ssam rtchange(rt, gate, metric) 683*6920Ssam struct rt_entry *rt; 684*6920Ssam struct sockaddr *gate; 685*6920Ssam short metric; 686*6920Ssam { 687*6920Ssam int change = 0; 688*6920Ssam 689*6920Ssam if (!equal(&rt->rt_gateway, gate)) { 690*6920Ssam rt->rt_gateway = *gate; 691*6920Ssam change++; 692*6920Ssam } 693*6920Ssam 694*6920Ssam /* 695*6920Ssam * If the hop count has changed, adjust 696*6920Ssam * the flags in the routing table entry accordingly. 697*6920Ssam */ 698*6920Ssam if (metric != rt->rt_metric) { 699*6920Ssam if (rt->rt_metric == 0) 700*6920Ssam rt->rt_flags &= ~RTF_DIRECT; 701*6920Ssam rt->rt_metric = metric; 702*6920Ssam if (metric >= HOPCNT_INFINITY) 703*6920Ssam rt->rt_flags &= ~RTF_UP; 704*6920Ssam else 705*6920Ssam rt->rt_flags |= RTF_UP; 706*6920Ssam change++; 707*6920Ssam } 708*6920Ssam 709*6920Ssam if (!change) 710*6920Ssam return; 711*6920Ssam if (supplier) 712*6920Ssam broadcast(rt); 713*6920Ssam if (trace) 714*6920Ssam log("change", rt); 715*6920Ssam if (install) { 716*6920Ssam rt->rt_flags |= RTF_CHGRT; 717*6920Ssam rt->rt_retry = EXPIRE_TIME/TIMER_RATE; 718*6920Ssam } 719*6920Ssam } 720*6920Ssam 721*6920Ssam /* 722*6920Ssam * Delete a routing table entry. 723*6920Ssam */ 724*6920Ssam rtdelete(rt) 725*6920Ssam struct rt_entry *rt; 726*6920Ssam { 727*6920Ssam if (trace) 728*6920Ssam log("delete", rt); 729*6920Ssam if (install) 730*6920Ssam if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) && 731*6920Ssam errno == EBUSY) 732*6920Ssam rt->rt_flags |= RTF_DELRT; 733*6920Ssam remque(rt); 734*6920Ssam free((char *)rt); 735*6920Ssam } 736*6920Ssam 737*6920Ssam /* 738*6920Ssam * Timer routine: 739*6920Ssam * 740*6920Ssam * o handle timers on table entries, 741*6920Ssam * o invalidate entries which haven't been updated in a while, 742*6920Ssam * o delete entries which are too old, 743*6920Ssam * o retry ioctl's which weren't successful the first 744*6920Ssam * time due to the kernel entry being busy 745*6920Ssam * o if we're an internetwork router, supply routing updates 746*6920Ssam * periodically 747*6920Ssam */ 748*6920Ssam timer() 749*6920Ssam { 750*6920Ssam register struct rt_hash *rh; 751*6920Ssam register struct rt_entry *rt; 752*6920Ssam struct rt_hash *base = hosthash; 753*6920Ssam int doinghost = 1; 754*6920Ssam 755*6920Ssam if (trace) 756*6920Ssam printf(">>> time %d >>>\n", timeval); 757*6920Ssam again: 758*6920Ssam for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) { 759*6920Ssam rt = rh->rt_forw; 760*6920Ssam for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 761*6920Ssam 762*6920Ssam /* 763*6920Ssam * If the host is indicated to be 764*6920Ssam * "silent" (i.e. it's a logical host, 765*6920Ssam * or one we got from the initialization 766*6920Ssam * file), don't time out it's entry. 767*6920Ssam */ 768*6920Ssam if (rt->rt_flags & RTF_SILENT) 769*6920Ssam continue; 770*6920Ssam if (trace) 771*6920Ssam log("", rt); 772*6920Ssam rt->rt_timer += TIMER_RATE; 773*6920Ssam if (rt->rt_timer >= GARBAGE_TIME || 774*6920Ssam (rt->rt_flags & RTF_DELRT)) { 775*6920Ssam rt = rt->rt_forw; 776*6920Ssam rtdelete(rt->rt_back); 777*6920Ssam rt = rt->rt_back; 778*6920Ssam continue; 779*6920Ssam } 780*6920Ssam if (rt->rt_timer >= EXPIRE_TIME) 781*6920Ssam rt->rt_metric = HOPCNT_INFINITY; 782*6920Ssam if (rt->rt_flags & RTF_CHGRT) 783*6920Ssam if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) || 784*6920Ssam --rt->rt_retry == 0) 785*6920Ssam rt->rt_flags &= ~RTF_CHGRT; 786*6920Ssam if (rt->rt_flags & RTF_ADDRT) 787*6920Ssam if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash) || 788*6920Ssam --rt->rt_retry == 0) 789*6920Ssam rt->rt_flags &= ~RTF_ADDRT; 790*6920Ssam } 791*6920Ssam } 792*6920Ssam if (doinghost) { 793*6920Ssam doinghost = 0; 794*6920Ssam base = nethash; 795*6920Ssam goto again; 796*6920Ssam } 797*6920Ssam timeval += TIMER_RATE; 798*6920Ssam if (supplier && (timeval % SUPPLY_INTERVAL) == 0) 799*6920Ssam supplyall(); 800*6920Ssam if (trace) 801*6920Ssam printf("<<< time %d <<<\n", timeval); 802*6920Ssam alarm(TIMER_RATE); 803*6920Ssam } 804*6920Ssam 805*6920Ssam log(operation, rt) 806*6920Ssam char *operation; 807*6920Ssam struct rt_entry *rt; 808*6920Ssam { 809*6920Ssam time_t t = time(0); 810*6920Ssam struct sockaddr_in *dst, *gate; 811*6920Ssam static struct flagbits { 812*6920Ssam int t_bits; 813*6920Ssam char *t_name; 814*6920Ssam } bits[] = { 815*6920Ssam { RTF_UP, "UP" }, 816*6920Ssam { RTF_DIRECT, "DIRECT" }, 817*6920Ssam { RTF_HOST, "HOST" }, 818*6920Ssam { RTF_DELRT, "DELETE" }, 819*6920Ssam { RTF_CHGRT, "CHANGE" }, 820*6920Ssam { RTF_SILENT, "SILENT" }, 821*6920Ssam { 0 } 822*6920Ssam }; 823*6920Ssam register struct flagbits *p; 824*6920Ssam register int first; 825*6920Ssam char *cp; 826*6920Ssam 827*6920Ssam printf("%s ", operation); 828*6920Ssam dst = (struct sockaddr_in *)&rt->rt_dst; 829*6920Ssam gate = (struct sockaddr_in *)&rt->rt_gateway; 830*6920Ssam printf("dst %x, router %x, metric %d, flags ", 831*6920Ssam dst->sin_addr, gate->sin_addr, rt->rt_metric); 832*6920Ssam cp = "%s"; 833*6920Ssam for (first = 1, p = bits; p->t_bits > 0; p++) { 834*6920Ssam if ((rt->rt_flags & p->t_bits) == 0) 835*6920Ssam continue; 836*6920Ssam printf(cp, p->t_name); 837*6920Ssam if (first) { 838*6920Ssam cp = "|%s"; 839*6920Ssam first = 0; 840*6920Ssam } 841*6920Ssam } 842*6920Ssam putchar('\n'); 843*6920Ssam } 844