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 static int s; /* for routing table ioctl's */ 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 } else { 80 if (rt->rt_dst.sa_family == af && 81 (*match)(&rt->rt_dst, dst)) 82 return (rt); 83 } 84 } 85 if (doinghost) { 86 doinghost = 0; 87 hash = h.afh_nethash; 88 rh = &nethash[hash & ROUTEHASHMASK]; 89 match = afswitch[af].af_netmatch; 90 goto again; 91 } 92 return (0); 93 } 94 95 rtadd(dst, gate, metric, state) 96 struct sockaddr *dst, *gate; 97 int metric, state; 98 { 99 struct afhash h; 100 register struct rt_entry *rt; 101 struct rthash *rh; 102 int af = dst->sa_family, flags; 103 u_int hash; 104 105 if (af >= AF_MAX) 106 return; 107 (*afswitch[af].af_hash)(dst, &h); 108 flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0; 109 if (flags & RTF_HOST) { 110 hash = h.afh_hosthash; 111 rh = &hosthash[hash & ROUTEHASHMASK]; 112 } else { 113 hash = h.afh_nethash; 114 rh = &nethash[hash & ROUTEHASHMASK]; 115 } 116 rt = (struct rt_entry *)malloc(sizeof (*rt)); 117 if (rt == 0) 118 return; 119 rt->rt_hash = hash; 120 rt->rt_dst = *dst; 121 rt->rt_router = *gate; 122 rt->rt_metric = metric; 123 rt->rt_timer = 0; 124 rt->rt_flags = RTF_UP | flags; 125 rt->rt_state = state | RTS_CHANGED; 126 rt->rt_ifp = if_ifwithnet(&rt->rt_router); 127 if (metric) 128 rt->rt_flags |= RTF_GATEWAY; 129 insque(rt, rh); 130 TRACE_ACTION(ADD, rt); 131 /* 132 * If the ioctl fails because the gateway is unreachable 133 * from this host, discard the entry. This should only 134 * occur because of an incorrect entry in /etc/gateways. 135 */ 136 if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) { 137 perror("SIOCADDRT"); 138 if (errno == ENETUNREACH) { 139 TRACE_ACTION(DELETE, rt); 140 remque(rt); 141 free((char *)rt); 142 } 143 } 144 } 145 146 rtchange(rt, gate, metric) 147 struct rt_entry *rt; 148 struct sockaddr *gate; 149 short metric; 150 { 151 int doioctl = 0, metricchanged = 0; 152 struct rtentry oldroute; 153 154 if (!equal(&rt->rt_router, gate)) 155 doioctl++; 156 if (metric != rt->rt_metric) 157 metricchanged++; 158 if (doioctl || metricchanged) { 159 TRACE_ACTION(CHANGE FROM, rt); 160 if (doioctl) { 161 oldroute = rt->rt_rt; 162 rt->rt_router = *gate; 163 } 164 rt->rt_metric = metric; 165 rt->rt_state &= ~RTS_INTERFACE; 166 if (metric) 167 rt->rt_state |= RTF_GATEWAY; 168 rt->rt_state |= RTS_CHANGED; 169 TRACE_ACTION(CHANGE TO, rt); 170 } 171 if (doioctl && install) { 172 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) 173 perror("SIOCADDRT"); 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 && 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 if ((s = socket(AF_XNS, SOCK_RAW, IDPPROTO_RAW)) < 0) { 200 perror("socket"); 201 exit(1); 202 } 203 } 204