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