1*24313Ssklower #ifndef lint 2*24313Ssklower static char rcsid[] = "$Header$"; 3*24313Ssklower #endif 4*24313Ssklower 5*24313Ssklower /* 6*24313Ssklower * Routing Table Management Daemon 7*24313Ssklower */ 8*24313Ssklower #include "defs.h" 9*24313Ssklower #include <sys/ioctl.h> 10*24313Ssklower #include <errno.h> 11*24313Ssklower 12*24313Ssklower #ifndef DEBUG 13*24313Ssklower #define DEBUG 0 14*24313Ssklower #endif 15*24313Ssklower 16*24313Ssklower int install = !DEBUG; /* if 1 call kernel */ 17*24313Ssklower static int s; /* for routing table ioctl's */ 18*24313Ssklower /* 19*24313Ssklower * Lookup dst in the tables for an exact match. 20*24313Ssklower */ 21*24313Ssklower struct rt_entry * 22*24313Ssklower rtlookup(dst) 23*24313Ssklower struct sockaddr *dst; 24*24313Ssklower { 25*24313Ssklower register struct rt_entry *rt; 26*24313Ssklower register struct rthash *rh; 27*24313Ssklower register u_int hash; 28*24313Ssklower struct afhash h; 29*24313Ssklower int doinghost = 1; 30*24313Ssklower 31*24313Ssklower if (dst->sa_family >= AF_MAX) 32*24313Ssklower return (0); 33*24313Ssklower (*afswitch[dst->sa_family].af_hash)(dst, &h); 34*24313Ssklower hash = h.afh_hosthash; 35*24313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 36*24313Ssklower again: 37*24313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 38*24313Ssklower if (rt->rt_hash != hash) 39*24313Ssklower continue; 40*24313Ssklower if (equal(&rt->rt_dst, dst)) 41*24313Ssklower return (rt); 42*24313Ssklower } 43*24313Ssklower if (doinghost) { 44*24313Ssklower doinghost = 0; 45*24313Ssklower hash = h.afh_nethash; 46*24313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 47*24313Ssklower goto again; 48*24313Ssklower } 49*24313Ssklower return (0); 50*24313Ssklower } 51*24313Ssklower 52*24313Ssklower /* 53*24313Ssklower * Find a route to dst as the kernel would. 54*24313Ssklower */ 55*24313Ssklower struct rt_entry * 56*24313Ssklower rtfind(dst) 57*24313Ssklower struct sockaddr *dst; 58*24313Ssklower { 59*24313Ssklower register struct rt_entry *rt; 60*24313Ssklower register struct rthash *rh; 61*24313Ssklower register u_int hash; 62*24313Ssklower struct afhash h; 63*24313Ssklower int af = dst->sa_family; 64*24313Ssklower int doinghost = 1, (*match)(); 65*24313Ssklower 66*24313Ssklower if (af >= AF_MAX) 67*24313Ssklower return (0); 68*24313Ssklower (*afswitch[af].af_hash)(dst, &h); 69*24313Ssklower hash = h.afh_hosthash; 70*24313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 71*24313Ssklower 72*24313Ssklower again: 73*24313Ssklower for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 74*24313Ssklower if (rt->rt_hash != hash) 75*24313Ssklower continue; 76*24313Ssklower if (doinghost) { 77*24313Ssklower if (equal(&rt->rt_dst, dst)) 78*24313Ssklower return (rt); 79*24313Ssklower } else { 80*24313Ssklower if (rt->rt_dst.sa_family == af && 81*24313Ssklower (*match)(&rt->rt_dst, dst)) 82*24313Ssklower return (rt); 83*24313Ssklower } 84*24313Ssklower } 85*24313Ssklower if (doinghost) { 86*24313Ssklower doinghost = 0; 87*24313Ssklower hash = h.afh_nethash; 88*24313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 89*24313Ssklower match = afswitch[af].af_netmatch; 90*24313Ssklower goto again; 91*24313Ssklower } 92*24313Ssklower return (0); 93*24313Ssklower } 94*24313Ssklower 95*24313Ssklower rtadd(dst, gate, metric, state) 96*24313Ssklower struct sockaddr *dst, *gate; 97*24313Ssklower int metric, state; 98*24313Ssklower { 99*24313Ssklower struct afhash h; 100*24313Ssklower register struct rt_entry *rt; 101*24313Ssklower struct rthash *rh; 102*24313Ssklower int af = dst->sa_family, flags; 103*24313Ssklower u_int hash; 104*24313Ssklower 105*24313Ssklower if (af >= AF_MAX) 106*24313Ssklower return; 107*24313Ssklower (*afswitch[af].af_hash)(dst, &h); 108*24313Ssklower flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 109*24313Ssklower if (flags & RTF_HOST) { 110*24313Ssklower hash = h.afh_hosthash; 111*24313Ssklower rh = &hosthash[hash & ROUTEHASHMASK]; 112*24313Ssklower } else { 113*24313Ssklower hash = h.afh_nethash; 114*24313Ssklower rh = &nethash[hash & ROUTEHASHMASK]; 115*24313Ssklower } 116*24313Ssklower rt = (struct rt_entry *)malloc(sizeof (*rt)); 117*24313Ssklower if (rt == 0) 118*24313Ssklower return; 119*24313Ssklower rt->rt_hash = hash; 120*24313Ssklower rt->rt_dst = *dst; 121*24313Ssklower rt->rt_router = *gate; 122*24313Ssklower rt->rt_metric = metric; 123*24313Ssklower rt->rt_timer = 0; 124*24313Ssklower rt->rt_flags = RTF_UP | flags; 125*24313Ssklower rt->rt_state = state | RTS_CHANGED; 126*24313Ssklower rt->rt_ifp = if_ifwithnet(&rt->rt_router); 127*24313Ssklower if (metric) 128*24313Ssklower rt->rt_flags |= RTF_GATEWAY; 129*24313Ssklower insque(rt, rh); 130*24313Ssklower TRACE_ACTION(ADD, rt); 131*24313Ssklower /* 132*24313Ssklower * If the ioctl fails because the gateway is unreachable 133*24313Ssklower * from this host, discard the entry. This should only 134*24313Ssklower * occur because of an incorrect entry in /etc/gateways. 135*24313Ssklower */ 136*24313Ssklower if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 137*24313Ssklower perror("SIOCADDRT"); 138*24313Ssklower if (errno == ENETUNREACH) { 139*24313Ssklower TRACE_ACTION(DELETE, rt); 140*24313Ssklower remque(rt); 141*24313Ssklower free((char *)rt); 142*24313Ssklower } 143*24313Ssklower } 144*24313Ssklower } 145*24313Ssklower 146*24313Ssklower rtchange(rt, gate, metric) 147*24313Ssklower struct rt_entry *rt; 148*24313Ssklower struct sockaddr *gate; 149*24313Ssklower short metric; 150*24313Ssklower { 151*24313Ssklower int doioctl = 0, metricchanged = 0; 152*24313Ssklower struct rtentry oldroute; 153*24313Ssklower 154*24313Ssklower if (!equal(&rt->rt_router, gate)) 155*24313Ssklower doioctl++; 156*24313Ssklower if (metric != rt->rt_metric) 157*24313Ssklower metricchanged++; 158*24313Ssklower if (doioctl || metricchanged) { 159*24313Ssklower TRACE_ACTION(CHANGE FROM, rt); 160*24313Ssklower if (doioctl) { 161*24313Ssklower oldroute = rt->rt_rt; 162*24313Ssklower rt->rt_router = *gate; 163*24313Ssklower } 164*24313Ssklower rt->rt_metric = metric; 165*24313Ssklower rt->rt_state &= ~RTS_INTERFACE; 166*24313Ssklower if (metric) 167*24313Ssklower rt->rt_state |= RTF_GATEWAY; 168*24313Ssklower rt->rt_state |= RTS_CHANGED; 169*24313Ssklower TRACE_ACTION(CHANGE TO, rt); 170*24313Ssklower } 171*24313Ssklower if (doioctl && install) { 172*24313Ssklower if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 173*24313Ssklower perror("SIOCADDRT"); 174*24313Ssklower if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) 175*24313Ssklower perror("SIOCDELRT"); 176*24313Ssklower } 177*24313Ssklower } 178*24313Ssklower 179*24313Ssklower rtdelete(rt) 180*24313Ssklower struct rt_entry *rt; 181*24313Ssklower { 182*24313Ssklower 183*24313Ssklower TRACE_ACTION(DELETE, rt); 184*24313Ssklower if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) 185*24313Ssklower perror("SIOCDELRT"); 186*24313Ssklower remque(rt); 187*24313Ssklower free((char *)rt); 188*24313Ssklower } 189*24313Ssklower 190*24313Ssklower rtinit() 191*24313Ssklower { 192*24313Ssklower register struct rthash *rh; 193*24313Ssklower 194*24313Ssklower for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 195*24313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 196*24313Ssklower for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++) 197*24313Ssklower rh->rt_forw = rh->rt_back = (struct rt_entry *)rh; 198*24313Ssklower 199*24313Ssklower if ((s = socket(AF_XNS, SOCK_RAW, IDPPROTO_RAW)) < 0) { 200*24313Ssklower perror("socket"); 201*24313Ssklower exit(1); 202*24313Ssklower } 203*24313Ssklower } 204