124313Ssklower #ifndef lint 224313Ssklower static char rcsid[] = "$Header$"; 324313Ssklower #endif 424313Ssklower 524313Ssklower /* 624313Ssklower * Routing Table Management Daemon 724313Ssklower */ 824313Ssklower #include "defs.h" 924313Ssklower #include <sys/ioctl.h> 1024313Ssklower #include <errno.h> 1124313Ssklower 1224313Ssklower #ifndef DEBUG 1324313Ssklower #define DEBUG 0 1424313Ssklower #endif 1524313Ssklower 1624313Ssklower int install = !DEBUG; /* if 1 call kernel */ 17*24318Ssklower int delete = 1; 1824313Ssklower /* 1924313Ssklower * Lookup dst in the tables for an exact match. 2024313Ssklower */ 2124313Ssklower struct rt_entry * 2224313Ssklower rtlookup(dst) 2324313Ssklower struct sockaddr *dst; 2424313Ssklower { 2524313Ssklower register struct rt_entry *rt; 2624313Ssklower register struct rthash *rh; 2724313Ssklower register u_int hash; 2824313Ssklower struct afhash h; 2924313Ssklower int doinghost = 1; 3024313Ssklower 3124313Ssklower if (dst->sa_family >= AF_MAX) 3224313Ssklower return (0); 3324313Ssklower (*afswitch[dst->sa_family].af_hash)(dst, &h); 3424313Ssklower hash = h.afh_hosthash; 3524313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 3624313Ssklower again: 3724313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 3824313Ssklower if (rt->rt_hash != hash) 3924313Ssklower continue; 4024313Ssklower if (equal(&rt->rt_dst, dst)) 4124313Ssklower return (rt); 4224313Ssklower } 4324313Ssklower if (doinghost) { 4424313Ssklower doinghost = 0; 4524313Ssklower hash = h.afh_nethash; 4624313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 4724313Ssklower goto again; 4824313Ssklower } 4924313Ssklower return (0); 5024313Ssklower } 5124313Ssklower 5224313Ssklower /* 5324313Ssklower * Find a route to dst as the kernel would. 5424313Ssklower */ 5524313Ssklower struct rt_entry * 5624313Ssklower rtfind(dst) 5724313Ssklower struct sockaddr *dst; 5824313Ssklower { 5924313Ssklower register struct rt_entry *rt; 6024313Ssklower register struct rthash *rh; 6124313Ssklower register u_int hash; 6224313Ssklower struct afhash h; 6324313Ssklower int af = dst->sa_family; 6424313Ssklower int doinghost = 1, (*match)(); 6524313Ssklower 6624313Ssklower if (af >= AF_MAX) 6724313Ssklower return (0); 6824313Ssklower (*afswitch[af].af_hash)(dst, &h); 6924313Ssklower hash = h.afh_hosthash; 7024313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 7124313Ssklower 7224313Ssklower again: 7324313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 7424313Ssklower if (rt->rt_hash != hash) 7524313Ssklower continue; 7624313Ssklower if (doinghost) { 7724313Ssklower if (equal(&rt->rt_dst, dst)) 7824313Ssklower return (rt); 7924313Ssklower } 80*24318Ssklower if (rt->rt_dst.sa_family == af && 81*24318Ssklower (*match)(&rt->rt_dst, dst)) 82*24318Ssklower return (rt); 8324313Ssklower } 8424313Ssklower if (doinghost) { 8524313Ssklower doinghost = 0; 8624313Ssklower hash = h.afh_nethash; 8724313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 8824313Ssklower match = afswitch[af].af_netmatch; 8924313Ssklower goto again; 9024313Ssklower } 9124313Ssklower return (0); 9224313Ssklower } 9324313Ssklower 9424313Ssklower rtadd(dst, gate, metric, state) 9524313Ssklower struct sockaddr *dst, *gate; 9624313Ssklower int metric, state; 9724313Ssklower { 9824313Ssklower struct afhash h; 9924313Ssklower register struct rt_entry *rt; 10024313Ssklower struct rthash *rh; 10124313Ssklower int af = dst->sa_family, flags; 10224313Ssklower u_int hash; 10324313Ssklower 10424313Ssklower if (af >= AF_MAX) 10524313Ssklower return; 10624313Ssklower (*afswitch[af].af_hash)(dst, &h); 10724313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 10824313Ssklower if (flags & RTF_HOST) { 10924313Ssklower hash = h.afh_hosthash; 11024313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 11124313Ssklower } else { 11224313Ssklower hash = h.afh_nethash; 11324313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 11424313Ssklower } 11524313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 11624313Ssklower if (rt == 0) 11724313Ssklower return; 11824313Ssklower rt->rt_hash = hash; 11924313Ssklower rt->rt_dst = *dst; 12024313Ssklower rt->rt_router = *gate; 12124313Ssklower rt->rt_metric = metric; 12224313Ssklower rt->rt_timer = 0; 12324313Ssklower rt->rt_flags = RTF_UP | flags; 12424313Ssklower rt->rt_state = state | RTS_CHANGED; 12524313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 12624313Ssklower if (metric) 12724313Ssklower rt->rt_flags |= RTF_GATEWAY; 12824313Ssklower insque(rt, rh); 12924313Ssklower TRACE_ACTION(ADD, rt); 13024313Ssklower /* 13124313Ssklower * If the ioctl fails because the gateway is unreachable 13224313Ssklower * from this host, discard the entry. This should only 13324313Ssklower * occur because of an incorrect entry in /etc/gateways. 13424313Ssklower */ 13524313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 13624313Ssklower perror("SIOCADDRT"); 13724313Ssklower if (errno == ENETUNREACH) { 13824313Ssklower TRACE_ACTION(DELETE, rt); 13924313Ssklower remque(rt); 14024313Ssklower free((char *)rt); 14124313Ssklower } 14224313Ssklower } 14324313Ssklower } 14424313Ssklower 14524313Ssklower rtchange(rt, gate, metric) 14624313Ssklower struct rt_entry *rt; 14724313Ssklower struct sockaddr *gate; 14824313Ssklower short metric; 14924313Ssklower { 15024313Ssklower int doioctl = 0, metricchanged = 0; 15124313Ssklower struct rtentry oldroute; 15224313Ssklower 15324313Ssklower if (!equal(&rt->rt_router, gate)) 15424313Ssklower doioctl++; 15524313Ssklower if (metric != rt->rt_metric) 15624313Ssklower metricchanged++; 15724313Ssklower if (doioctl || metricchanged) { 15824313Ssklower TRACE_ACTION(CHANGE FROM, rt); 15924313Ssklower if (doioctl) { 16024313Ssklower oldroute = rt->rt_rt; 16124313Ssklower rt->rt_router = *gate; 16224313Ssklower } 16324313Ssklower rt->rt_metric = metric; 16424313Ssklower rt->rt_state &= ~RTS_INTERFACE; 16524313Ssklower if (metric) 16624313Ssklower rt->rt_state |= RTF_GATEWAY; 16724313Ssklower rt->rt_state |= RTS_CHANGED; 16824313Ssklower TRACE_ACTION(CHANGE TO, rt); 16924313Ssklower } 17024313Ssklower if (doioctl && install) { 17124313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 17224313Ssklower perror("SIOCADDRT"); 173*24318Ssklower if (delete) 17424313Ssklower if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 17524313Ssklower perror("SIOCDELRT"); 17624313Ssklower } 17724313Ssklower } 17824313Ssklower 17924313Ssklower rtdelete(rt) 18024313Ssklower struct rt_entry *rt; 18124313Ssklower { 18224313Ssklower 18324313Ssklower TRACE_ACTION(DELETE, rt); 184*24318Ssklower if (install && delete && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 18524313Ssklower perror("SIOCDELRT"); 18624313Ssklower remque(rt); 18724313Ssklower free((char *)rt); 18824313Ssklower } 18924313Ssklower 19024313Ssklower rtinit() 19124313Ssklower { 19224313Ssklower register struct rthash *rh; 19324313Ssklower 19424313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 19524313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 19624313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 19724313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 19824313Ssklower } 199