19020Ssam #ifndef lint 2*15098Ssam static char sccsid[] = "@(#)tables.c 4.4 (Berkeley) 09/25/83"; 39020Ssam #endif 49020Ssam 59020Ssam /* 69020Ssam * Routing Table Management Daemon 79020Ssam */ 810245Ssam #include "defs.h" 99020Ssam #include <sys/ioctl.h> 109020Ssam #include <errno.h> 119020Ssam 129020Ssam #ifndef DEBUG 139020Ssam #define DEBUG 0 149020Ssam #endif 159020Ssam 169020Ssam int install = !DEBUG; /* if 1 call kernel */ 179020Ssam 189020Ssam /* 199020Ssam * Lookup dst in the tables for an exact match. 209020Ssam */ 219020Ssam struct rt_entry * 229020Ssam rtlookup(dst) 239020Ssam struct sockaddr *dst; 249020Ssam { 259020Ssam register struct rt_entry *rt; 269020Ssam register struct rthash *rh; 279020Ssam register int hash; 289020Ssam struct afhash h; 299020Ssam int doinghost = 1; 309020Ssam 319020Ssam if (dst->sa_family >= AF_MAX) 329020Ssam return (0); 339020Ssam (*afswitch[dst->sa_family].af_hash)(dst, &h); 349020Ssam hash = h.afh_hosthash; 359020Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 369020Ssam again: 379020Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 389020Ssam if (rt->rt_hash != hash) 399020Ssam continue; 409020Ssam if (equal(&rt->rt_dst, dst)) 419020Ssam return (rt); 429020Ssam } 439020Ssam if (doinghost) { 449020Ssam doinghost = 0; 459020Ssam hash = h.afh_nethash; 469020Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 479020Ssam goto again; 489020Ssam } 499020Ssam return (0); 509020Ssam } 519020Ssam 529020Ssam /* 539020Ssam * Find a route to dst as the kernel would. 549020Ssam */ 559020Ssam struct rt_entry * 569020Ssam rtfind(dst) 579020Ssam struct sockaddr *dst; 589020Ssam { 599020Ssam register struct rt_entry *rt; 609020Ssam register struct rthash *rh; 619020Ssam register int hash; 629020Ssam struct afhash h; 639020Ssam int af = dst->sa_family; 649020Ssam int doinghost = 1, (*match)(); 659020Ssam 669020Ssam if (af >= AF_MAX) 679020Ssam return (0); 689020Ssam (*afswitch[af].af_hash)(dst, &h); 699020Ssam hash = h.afh_hosthash; 709020Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 719020Ssam 729020Ssam again: 739020Ssam for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 749020Ssam if (rt->rt_hash != hash) 759020Ssam continue; 769020Ssam if (doinghost) { 779020Ssam if (equal(&rt->rt_dst, dst)) 789020Ssam return (rt); 799020Ssam } else { 809020Ssam if (rt->rt_dst.sa_family == af && 819020Ssam (*match)(&rt->rt_dst, dst)) 829020Ssam return (rt); 839020Ssam } 849020Ssam } 859020Ssam if (doinghost) { 869020Ssam doinghost = 0; 879020Ssam hash = h.afh_nethash; 889020Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 899020Ssam match = afswitch[af].af_netmatch; 909020Ssam goto again; 919020Ssam } 929020Ssam return (0); 939020Ssam } 949020Ssam 959020Ssam rtadd(dst, gate, metric, state) 969020Ssam struct sockaddr *dst, *gate; 979020Ssam int metric, state; 989020Ssam { 999020Ssam struct afhash h; 1009020Ssam register struct rt_entry *rt; 1019020Ssam struct rthash *rh; 1029020Ssam int af = dst->sa_family, flags, hash; 1039020Ssam 1049020Ssam if (af >= AF_MAX) 1059020Ssam return; 1069020Ssam (*afswitch[af].af_hash)(dst, &h); 1079020Ssam flags = (*afswitch[af].af_checkhost)(dst) ? RTF_HOST : 0; 1089020Ssam if (flags & RTF_HOST) { 1099020Ssam hash = h.afh_hosthash; 1109020Ssam rh = &hosthash[hash % ROUTEHASHSIZ]; 1119020Ssam } else { 1129020Ssam hash = h.afh_nethash; 1139020Ssam rh = &nethash[hash % ROUTEHASHSIZ]; 1149020Ssam } 1159020Ssam rt = (struct rt_entry *)malloc(sizeof (*rt)); 1169020Ssam if (rt == 0) 1179020Ssam return; 1189020Ssam rt->rt_hash = hash; 1199020Ssam rt->rt_dst = *dst; 1209020Ssam rt->rt_router = *gate; 1219020Ssam rt->rt_metric = metric; 1229020Ssam rt->rt_timer = 0; 1239020Ssam rt->rt_flags = RTF_UP | flags; 1249020Ssam rt->rt_state = state | RTS_CHANGED; 1259020Ssam rt->rt_ifp = if_ifwithnet(&rt->rt_router); 1269020Ssam if (metric) 1279020Ssam rt->rt_flags |= RTF_GATEWAY; 1289020Ssam insque(rt, rh); 1299020Ssam TRACE_ACTION(ADD, rt); 130*15098Ssam /* 131*15098Ssam * If the ioctl fails because the gateway is unreachable 132*15098Ssam * from this host, discard the entry. This should only 133*15098Ssam * occur because of an incorrect entry in /etc/gateways. 134*15098Ssam */ 135*15098Ssam if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 1369020Ssam perror("SIOCADDRT"); 137*15098Ssam if (errno == ENETUNREACH) { 138*15098Ssam TRACE_ACTION(DELETE, rt); 139*15098Ssam remque(rt); 140*15098Ssam free((char *)rt); 141*15098Ssam } 142*15098Ssam } 1439020Ssam } 1449020Ssam 1459020Ssam rtchange(rt, gate, metric) 1469020Ssam struct rt_entry *rt; 1479020Ssam struct sockaddr *gate; 1489020Ssam short metric; 1499020Ssam { 1509020Ssam int doioctl = 0, metricchanged = 0; 1519020Ssam struct rtentry oldroute; 1529020Ssam 1539020Ssam if (!equal(&rt->rt_router, gate)) 1549020Ssam doioctl++; 1559020Ssam if (metric != rt->rt_metric) { 1569020Ssam metricchanged++; 1579020Ssam rt->rt_metric = metric; 1589020Ssam } 1599020Ssam if (doioctl || metricchanged) { 1609020Ssam TRACE_ACTION(CHANGE, rt); 1619020Ssam rt->rt_state |= RTS_CHANGED; 1629020Ssam } 1639020Ssam if (doioctl) { 1649020Ssam oldroute = rt->rt_rt; 1659020Ssam rt->rt_router = *gate; 1669020Ssam if (install) { 1679020Ssam if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 1689020Ssam perror("SIOCADDRT"); 1699020Ssam if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 1709020Ssam perror("SIOCDELRT"); 1719020Ssam } 1729020Ssam } 1739020Ssam } 1749020Ssam 1759020Ssam rtdelete(rt) 1769020Ssam struct rt_entry *rt; 1779020Ssam { 178*15098Ssam 1799020Ssam TRACE_ACTION(DELETE, rt); 1809020Ssam if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 1819020Ssam perror("SIOCDELRT"); 1829020Ssam remque(rt); 1839020Ssam free((char *)rt); 1849020Ssam } 1859020Ssam 1869020Ssam rtinit() 1879020Ssam { 1889020Ssam register struct rthash *rh; 1899020Ssam 1909020Ssam for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 1919020Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1929020Ssam for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 1939020Ssam rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 1949020Ssam } 195