1 /* 2 * Copyright (c) 1980, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)route.c 7.17 (Berkeley) 06/28/90 8 */ 9 #include "machine/reg.h" 10 11 #include "param.h" 12 #include "systm.h" 13 #include "user.h" 14 #include "proc.h" 15 #include "mbuf.h" 16 #include "socket.h" 17 #include "socketvar.h" 18 #include "domain.h" 19 #include "protosw.h" 20 #include "errno.h" 21 #include "ioctl.h" 22 23 #include "if.h" 24 #include "af.h" 25 #include "route.h" 26 #include "raw_cb.h" 27 #include "../netinet/in.h" 28 #include "../netinet/in_var.h" 29 30 #include "../netns/ns.h" 31 #include "machine/mtpr.h" 32 #include "netisr.h" 33 #define SA(p) ((struct sockaddr *)(p)) 34 35 int rttrash; /* routes not in table but not freed */ 36 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 37 int rthashsize = RTHASHSIZ; /* for netstat, etc. */ 38 39 static int rtinits_done = 0; 40 struct radix_node_head *ns_rnhead, *in_rnhead; 41 struct radix_node *rn_match(), *rn_delete(), *rn_addroute(); 42 rtinitheads() 43 { 44 if (rtinits_done == 0 && 45 rn_inithead(&ns_rnhead, 16, AF_NS) && 46 rn_inithead(&in_rnhead, 32, AF_INET)) 47 rtinits_done = 1; 48 } 49 50 /* 51 * Packet routing routines. 52 */ 53 rtalloc(ro) 54 register struct route *ro; 55 { 56 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 57 return; /* XXX */ 58 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 59 } 60 61 struct rtentry * 62 rtalloc1(dst, report) 63 register struct sockaddr *dst; 64 int report; 65 { 66 register struct radix_node_head *rnh; 67 register struct rtentry *rt; 68 register struct radix_node *rn; 69 struct rtentry *newrt = 0; 70 int s = splnet(), err = 0; 71 72 for (rnh = radix_node_head; rnh && (dst->sa_family != rnh->rnh_af); ) 73 rnh = rnh->rnh_next; 74 if (rnh && rnh->rnh_treetop && 75 (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) && 76 ((rn->rn_flags & RNF_ROOT) == 0)) { 77 newrt = rt = (struct rtentry *)rn; 78 if (report && (rt->rt_flags & RTF_CLONING)) { 79 if (err = rtrequest(RTM_RESOLVE, dst, SA(0), 80 SA(0), 0, &newrt)) 81 goto miss; 82 } else 83 rt->rt_refcnt++; 84 } else { 85 rtstat.rts_unreach++; 86 miss: if (report) 87 rt_missmsg(RTM_MISS, dst, SA(0), SA(0), SA(0), 0, err); 88 } 89 splx(s); 90 return (newrt); 91 } 92 93 rtfree(rt) 94 register struct rtentry *rt; 95 { 96 register struct ifaddr *ifa; 97 if (rt == 0) 98 panic("rtfree"); 99 rt->rt_refcnt--; 100 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 101 rttrash--; 102 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 103 panic ("rtfree 2"); 104 free((caddr_t)rt, M_RTABLE); 105 } 106 } 107 108 /* 109 * Force a routing table entry to the specified 110 * destination to go through the given gateway. 111 * Normally called as a result of a routing redirect 112 * message from the network layer. 113 * 114 * N.B.: must be called at splnet 115 * 116 */ 117 rtredirect(dst, gateway, netmask, flags, src, rtp) 118 struct sockaddr *dst, *gateway, *netmask, *src; 119 int flags; 120 struct rtentry **rtp; 121 { 122 register struct rtentry *rt; 123 int error = 0; 124 short *stat = 0; 125 126 /* verify the gateway is directly reachable */ 127 if (ifa_ifwithnet(gateway) == 0) { 128 error = ENETUNREACH; 129 goto done; 130 } 131 rt = rtalloc1(dst, 0); 132 /* 133 * If the redirect isn't from our current router for this dst, 134 * it's either old or wrong. If it redirects us to ourselves, 135 * we have a routing loop, perhaps as a result of an interface 136 * going down recently. 137 */ 138 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 139 if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway)) 140 error = EINVAL; 141 else if (ifa_ifwithaddr(gateway)) 142 error = EHOSTUNREACH; 143 if (error) 144 goto done; 145 /* 146 * Create a new entry if we just got back a wildcard entry 147 * or the the lookup failed. This is necessary for hosts 148 * which use routing redirects generated by smart gateways 149 * to dynamically build the routing tables. 150 */ 151 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 152 goto create; 153 /* 154 * Don't listen to the redirect if it's 155 * for a route to an interface. 156 */ 157 if (rt->rt_flags & RTF_GATEWAY) { 158 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 159 /* 160 * Changing from route to net => route to host. 161 * Create new route, rather than smashing route to net. 162 */ 163 create: 164 flags |= RTF_GATEWAY | RTF_DYNAMIC; 165 error = rtrequest((int)RTM_ADD, dst, gateway, 166 SA(0), flags, 167 (struct rtentry **)0); 168 stat = &rtstat.rts_dynamic; 169 } else { 170 /* 171 * Smash the current notion of the gateway to 172 * this destination. Should check about netmask!!! 173 */ 174 if (gateway->sa_len <= rt->rt_gateway->sa_len) { 175 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 176 rt->rt_flags |= RTF_MODIFIED; 177 flags |= RTF_MODIFIED; 178 stat = &rtstat.rts_newgateway; 179 } else 180 error = ENOSPC; 181 } 182 } else 183 error = EHOSTUNREACH; 184 done: 185 if (rt) { 186 if (rtp && !error) 187 *rtp = rt; 188 else 189 rtfree(rt); 190 } 191 if (error) 192 rtstat.rts_badredirect++; 193 else 194 (stat && (*stat)++); 195 rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error); 196 } 197 198 /* 199 * Routing table ioctl interface. 200 */ 201 rtioctl(req, data) 202 int req; 203 caddr_t data; 204 { 205 #ifndef COMPAT_43 206 return (EOPNOTSUPP); 207 #else 208 register struct ortentry *entry = (struct ortentry *)data; 209 int error; 210 struct sockaddr *netmask = 0; 211 212 if (req == SIOCADDRT) 213 req = RTM_ADD; 214 else if (req == SIOCDELRT) 215 req = RTM_DELETE; 216 else 217 return (EINVAL); 218 219 if (error = suser(u.u_cred, &u.u_acflag)) 220 return (error); 221 #if BYTE_ORDER != BIG_ENDIAN 222 if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) { 223 entry->rt_dst.sa_family = entry->rt_dst.sa_len; 224 entry->rt_dst.sa_len = 16; 225 } 226 if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) { 227 entry->rt_gateway.sa_family = entry->rt_gateway.sa_len; 228 entry->rt_gateway.sa_len = 16; 229 } 230 #else 231 if (entry->rt_dst.sa_len == 0) 232 entry->rt_dst.sa_len = 16; 233 if (entry->rt_gateway.sa_len == 0) 234 entry->rt_gateway.sa_len = 16; 235 #endif 236 if ((entry->rt_flags & RTF_HOST) == 0) 237 switch (entry->rt_dst.sa_family) { 238 #ifdef INET 239 case AF_INET: 240 { 241 extern struct sockaddr_in icmpmask; 242 struct sockaddr_in *dst_in = 243 (struct sockaddr_in *)&entry->rt_dst; 244 245 in_sockmaskof(dst_in->sin_addr, &icmpmask); 246 netmask = (struct sockaddr *)&icmpmask; 247 } 248 break; 249 #endif 250 #ifdef NS 251 case AF_NS: 252 { 253 extern struct sockaddr_ns ns_netmask; 254 netmask = (struct sockaddr *)&ns_netmask; 255 } 256 #endif 257 } 258 error = rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask, 259 entry->rt_flags, (struct rtentry **)0); 260 rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL), 261 &(entry->rt_dst), &(entry->rt_gateway), 262 netmask, SA(0), entry->rt_flags, error); 263 return (error); 264 #endif 265 } 266 267 struct ifaddr * 268 ifa_ifwithroute(flags, dst, gateway) 269 int flags; 270 struct sockaddr *dst, *gateway; 271 { 272 struct ifaddr *ifa; 273 if ((flags & RTF_GATEWAY) == 0) { 274 /* 275 * If we are adding a route to an interface, 276 * and the interface is a pt to pt link 277 * we should search for the destination 278 * as our clue to the interface. Otherwise 279 * we can use the local address. 280 */ 281 ifa = 0; 282 if (flags & RTF_HOST) 283 ifa = ifa_ifwithdstaddr(dst); 284 if (ifa == 0) 285 ifa = ifa_ifwithaddr(gateway); 286 } else { 287 /* 288 * If we are adding a route to a remote net 289 * or host, the gateway may still be on the 290 * other end of a pt to pt link. 291 */ 292 ifa = ifa_ifwithdstaddr(gateway); 293 } 294 if (ifa == 0) 295 ifa = ifa_ifwithnet(gateway); 296 return (ifa); 297 } 298 299 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 300 301 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 302 int req, flags; 303 struct sockaddr *dst, *gateway, *netmask; 304 struct rtentry **ret_nrt; 305 { 306 int s = splnet(), len, error = 0; 307 register struct rtentry *rt; 308 register struct radix_node *rn; 309 register struct radix_node_head *rnh; 310 struct ifaddr *ifa, *ifa_ifwithdstaddr(); 311 struct sockaddr *ndst; 312 u_char af = dst->sa_family; 313 #define senderr(x) { error = x ; goto bad; } 314 315 if (rtinits_done == 0) 316 rtinitheads(); 317 for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); ) 318 rnh = rnh->rnh_next; 319 if (rnh == 0) 320 senderr(ESRCH); 321 if (flags & RTF_HOST) 322 netmask = 0; 323 switch (req) { 324 case RTM_DELETE: 325 if (ret_nrt && (rt = *ret_nrt)) { 326 RTFREE(rt); 327 *ret_nrt = 0; 328 } 329 if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 330 rnh->rnh_treetop)) == 0) 331 senderr(ESRCH); 332 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 333 panic ("rtrequest delete"); 334 rt = (struct rtentry *)rn; 335 rt->rt_flags &= ~RTF_UP; 336 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 337 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 338 rttrash++; 339 if (rt->rt_refcnt <= 0) 340 rtfree(rt); 341 break; 342 343 case RTM_RESOLVE: 344 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 345 senderr(EINVAL); 346 ifa = rt->rt_ifa; 347 flags = rt->rt_flags & ~RTF_CLONING; 348 gateway = rt->rt_gateway; 349 if ((netmask = rt->rt_genmask) == 0) 350 flags |= RTF_HOST; 351 goto makeroute; 352 353 case RTM_ADD: 354 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 355 senderr(ENETUNREACH); 356 makeroute: 357 len = sizeof (*rt) + ROUNDUP(gateway->sa_len) 358 + ROUNDUP(dst->sa_len); 359 R_Malloc(rt, struct rtentry *, len); 360 if (rt == 0) 361 senderr(ENOBUFS); 362 Bzero(rt, len); 363 ndst = (struct sockaddr *)(rt + 1); 364 if (netmask) { 365 rt_maskedcopy(dst, ndst, netmask); 366 } else 367 Bcopy(dst, ndst, dst->sa_len); 368 rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask, 369 rnh->rnh_treetop, rt->rt_nodes); 370 if (rn == 0) { 371 free((caddr_t)rt, M_RTABLE); 372 senderr(EEXIST); 373 } 374 rt->rt_ifa = ifa; 375 rt->rt_ifp = ifa->ifa_ifp; 376 rt->rt_flags = RTF_UP | flags; 377 rn->rn_key = (caddr_t) ndst; /* == rt_dst */ 378 rt->rt_gateway = (struct sockaddr *) 379 (rn->rn_key + ROUNDUP(dst->sa_len)); 380 Bcopy(gateway, rt->rt_gateway, gateway->sa_len); 381 if (req == RTM_RESOLVE) 382 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 383 if (ifa->ifa_rtrequest) 384 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 385 if (ret_nrt) { 386 *ret_nrt = rt; 387 rt->rt_refcnt++; 388 } 389 break; 390 } 391 bad: 392 splx(s); 393 return (error); 394 } 395 396 rt_maskedcopy(src, dst, netmask) 397 struct sockaddr *src, *dst, *netmask; 398 { 399 register u_char *cp1 = (u_char *)src; 400 register u_char *cp2 = (u_char *)dst; 401 register u_char *cp3 = (u_char *)netmask; 402 u_char *cplim = cp2 + *cp3; 403 u_char *cplim2 = cp2 + *cp1; 404 405 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 406 cp3 += 2; 407 if (cplim > cplim2) 408 cplim = cplim2; 409 while (cp2 < cplim) 410 *cp2++ = *cp1++ & *cp3++; 411 if (cp2 < cplim2) 412 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 413 } 414 /* 415 * Set up a routing table entry, normally 416 * for an interface. 417 */ 418 rtinit(ifa, cmd, flags) 419 register struct ifaddr *ifa; 420 int cmd, flags; 421 { 422 return rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr, 423 ifa->ifa_netmask, flags | ifa->ifa_flags, &ifa->ifa_rt); 424 } 425