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