1 /* route.c 4.20 83/05/30 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/protosw.h" 7 #include "../h/socket.h" 8 #include "../h/ioctl.h" 9 #include "../h/errno.h" 10 11 #include "../net/if.h" 12 #include "../net/af.h" 13 #include "../net/route.h" 14 15 int rttrash; /* routes not in table but not freed */ 16 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 17 18 /* 19 * Packet routing routines. 20 */ 21 rtalloc(ro) 22 register struct route *ro; 23 { 24 register struct rtentry *rt; 25 register struct mbuf *m; 26 register unsigned hash; 27 struct sockaddr *dst = &ro->ro_dst; 28 int (*match)(), doinghost; 29 struct afhash h; 30 u_int af = dst->sa_family; 31 struct rtentry *rtmin; 32 struct mbuf **table; 33 34 if (ro->ro_rt && ro->ro_rt->rt_ifp) /* XXX */ 35 return; 36 if (af >= AF_MAX) 37 return; 38 (*afswitch[af].af_hash)(dst, &h); 39 rtmin = 0; 40 match = afswitch[af].af_netmatch; 41 hash = h.afh_hosthash, table = rthost, doinghost = 1; 42 again: 43 for (m = table[hash % RTHASHSIZ]; m; m = m->m_next) { 44 rt = mtod(m, struct rtentry *); 45 if (rt->rt_hash != hash) 46 continue; 47 if ((rt->rt_flags & RTF_UP) == 0 || 48 (rt->rt_ifp->if_flags & IFF_UP) == 0) 49 continue; 50 if (doinghost) { 51 if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst, 52 sizeof (*dst))) 53 continue; 54 } else { 55 if (rt->rt_dst.sa_family != af || 56 !(*match)(&rt->rt_dst, dst)) 57 continue; 58 } 59 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 60 rtmin = rt; 61 } 62 if (rtmin == 0 && doinghost) { 63 doinghost = 0; 64 hash = h.afh_nethash, table = rtnet; 65 goto again; 66 } 67 /* 68 * Check for wildcard gateway, by convention network 0. 69 */ 70 if (rtmin == 0 && dst != &wildcard) { 71 dst = &wildcard, hash = 0; 72 goto again; 73 } 74 ro->ro_rt = rtmin; 75 if (rtmin == 0) { 76 rtstat.rts_unreach++; 77 return; 78 } 79 rtmin->rt_refcnt++; 80 if (dst == &wildcard) 81 rtstat.rts_wildcard++; 82 } 83 84 rtfree(rt) 85 register struct rtentry *rt; 86 { 87 88 if (rt == 0) 89 panic("rtfree"); 90 rt->rt_refcnt--; 91 if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) { 92 rttrash--; 93 (void) m_free(dtom(rt)); 94 } 95 } 96 97 /* 98 * Force a routing table entry to the specified 99 * destination to go through the given gateway. 100 * Normally called as a result of a routing redirect 101 * message from the network layer. 102 * 103 * N.B.: must be called at splnet or higher 104 * 105 * Should notify all parties with a reference to 106 * the route that it's changed (so, for instance, 107 * current round trip time estimates could be flushed), 108 * but we have no back pointers at the moment. 109 */ 110 rtredirect(dst, gateway) 111 struct sockaddr *dst, *gateway; 112 { 113 struct route ro; 114 register struct rtentry *rt; 115 116 /* verify the gateway is directly reachable */ 117 if (if_ifwithnet(gateway) == 0) { 118 rtstat.rts_badredirect++; 119 return; 120 } 121 ro.ro_dst = *dst; 122 ro.ro_rt = 0; 123 rtalloc(&ro); 124 rt = ro.ro_rt; 125 /* 126 * Create a new entry if the lookup failed. 127 * This is necessary for hosts which use routing 128 * redirects generated by smart gateways to dynamically 129 * build the routing tables. 130 */ 131 if (rt == 0) { 132 rtinit(dst, gateway, RTF_GATEWAY); 133 rtstat.rts_dynamic++; 134 return; 135 } 136 /* 137 * Don't listen to the redirect if it's 138 * for a route to an interface. 139 */ 140 if (rt->rt_flags & RTF_GATEWAY) { 141 /* 142 * Smash the current notion of the gateway to 143 * this destination. This is probably not right, 144 * as it's conceivable a flurry of redirects could 145 * cause the gateway value to fluctuate wildly during 146 * dynamic routing reconfiguration. 147 */ 148 rt->rt_gateway = *gateway; 149 rtfree(rt); 150 rtstat.rts_newgateway++; 151 return; 152 } 153 } 154 155 /* 156 * Carry out a request to change the routing table. Called by 157 * interfaces at boot time to make their ``local routes'' known, 158 * for ioctl's, and as the result of routing redirects. 159 */ 160 rtrequest(req, entry) 161 int req; 162 register struct rtentry *entry; 163 { 164 register struct mbuf *m, **mprev; 165 register struct rtentry *rt; 166 struct afhash h; 167 int s, error = 0, hash, (*match)(); 168 u_int af; 169 struct ifnet *ifp; 170 171 af = entry->rt_dst.sa_family; 172 if (af >= AF_MAX) 173 return (EAFNOSUPPORT); 174 (*afswitch[af].af_hash)(&entry->rt_dst, &h); 175 if (entry->rt_flags & RTF_HOST) { 176 hash = h.afh_hosthash; 177 mprev = &rthost[hash % RTHASHSIZ]; 178 } else { 179 hash = h.afh_nethash; 180 mprev = &rtnet[hash % RTHASHSIZ]; 181 } 182 match = afswitch[af].af_netmatch; 183 s = splimp(); 184 for (; m = *mprev; mprev = &m->m_next) { 185 rt = mtod(m, struct rtentry *); 186 if (rt->rt_hash != hash) 187 continue; 188 if (entry->rt_flags & RTF_HOST) { 189 #define equal(a1, a2) \ 190 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) 191 if (!equal(&rt->rt_dst, &entry->rt_dst)) 192 continue; 193 } else { 194 if (rt->rt_dst.sa_family != entry->rt_dst.sa_family || 195 (*match)(&rt->rt_dst, &entry->rt_dst) == 0) 196 continue; 197 } 198 if (equal(&rt->rt_gateway, &entry->rt_gateway)) 199 break; 200 } 201 switch (req) { 202 203 case SIOCDELRT: 204 if (m == 0) { 205 error = ESRCH; 206 goto bad; 207 } 208 *mprev = m->m_next; 209 if (rt->rt_refcnt > 0) { 210 rt->rt_flags &= ~RTF_UP; 211 rttrash++; 212 m->m_next = 0; 213 } else 214 (void) m_free(m); 215 break; 216 217 case SIOCADDRT: 218 if (m) { 219 error = EEXIST; 220 goto bad; 221 } 222 ifp = if_ifwithaddr(&entry->rt_gateway); 223 if (ifp == 0) { 224 ifp = if_ifwithnet(&entry->rt_gateway); 225 if (ifp == 0) { 226 error = ENETUNREACH; 227 goto bad; 228 } 229 } 230 m = m_get(M_DONTWAIT, MT_RTABLE); 231 if (m == 0) { 232 error = ENOBUFS; 233 goto bad; 234 } 235 *mprev = m; 236 m->m_off = MMINOFF; 237 m->m_len = sizeof (struct rtentry); 238 rt = mtod(m, struct rtentry *); 239 rt->rt_hash = hash; 240 rt->rt_dst = entry->rt_dst; 241 rt->rt_gateway = entry->rt_gateway; 242 rt->rt_flags = 243 RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY)); 244 rt->rt_refcnt = 0; 245 rt->rt_use = 0; 246 rt->rt_ifp = ifp; 247 break; 248 } 249 bad: 250 splx(s); 251 return (error); 252 } 253 254 /* 255 * Set up a routing table entry, normally 256 * for an interface. 257 */ 258 rtinit(dst, gateway, flags) 259 struct sockaddr *dst, *gateway; 260 int flags; 261 { 262 struct rtentry route; 263 int cmd; 264 265 if (flags == -1) { 266 cmd = (int)SIOCDELRT; 267 flags = 0; 268 } else { 269 cmd = (int)SIOCADDRT; 270 } 271 bzero((caddr_t)&route, sizeof (route)); 272 route.rt_dst = *dst; 273 route.rt_gateway = *gateway; 274 route.rt_flags = flags; 275 (void) rtrequest(cmd, &route); 276 } 277