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