1 /* 2 * Copyright (c) 1980, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)route.c 8.2 (Berkeley) 11/15/93 34 * $Id$ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/proc.h> 40 #include <sys/mbuf.h> 41 #include <sys/socket.h> 42 #include <sys/socketvar.h> 43 #include <sys/domain.h> 44 #include <sys/protosw.h> 45 #include <sys/ioctl.h> 46 47 #include <net/if.h> 48 #include <net/route.h> 49 #include <net/raw_cb.h> 50 51 #include <netinet/in.h> 52 #include <netinet/in_var.h> 53 54 #ifdef NS 55 #include <netns/ns.h> 56 #endif 57 58 #define SA(p) ((struct sockaddr *)(p)) 59 60 int rttrash; /* routes not in table but not freed */ 61 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ 62 63 void 64 rtable_init(table) 65 void **table; 66 { 67 struct domain *dom; 68 for (dom = domains; dom; dom = dom->dom_next) 69 if (dom->dom_rtattach) 70 dom->dom_rtattach(&table[dom->dom_family], 71 dom->dom_rtoffset); 72 } 73 74 void 75 route_init() 76 { 77 rn_init(); /* initialize all zeroes, all ones, mask table */ 78 rtable_init((void **)rt_tables); 79 } 80 81 /* 82 * Packet routing routines. 83 */ 84 void 85 rtalloc(ro) 86 register struct route *ro; 87 { 88 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) 89 return; /* XXX */ 90 ro->ro_rt = rtalloc1(&ro->ro_dst, 1); 91 } 92 93 struct rtentry * 94 rtalloc1(dst, report) 95 register struct sockaddr *dst; 96 int report; 97 { 98 register struct radix_node_head *rnh = rt_tables[dst->sa_family]; 99 register struct rtentry *rt; 100 register struct radix_node *rn; 101 struct rtentry *newrt = 0; 102 struct rt_addrinfo info; 103 int s = splnet(), err = 0, msgtype = RTM_MISS; 104 105 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && 106 ((rn->rn_flags & RNF_ROOT) == 0)) { 107 newrt = rt = (struct rtentry *)rn; 108 if (report && (rt->rt_flags & RTF_CLONING)) { 109 err = rtrequest(RTM_RESOLVE, dst, SA(0), 110 SA(0), 0, &newrt); 111 if (err) { 112 newrt = rt; 113 rt->rt_refcnt++; 114 goto miss; 115 } 116 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { 117 msgtype = RTM_RESOLVE; 118 goto miss; 119 } 120 } else 121 rt->rt_refcnt++; 122 } else { 123 rtstat.rts_unreach++; 124 miss: if (report) { 125 bzero((caddr_t)&info, sizeof(info)); 126 info.rti_info[RTAX_DST] = dst; 127 rt_missmsg(msgtype, &info, 0, err); 128 } 129 } 130 splx(s); 131 return (newrt); 132 } 133 134 void 135 rtfree(rt) 136 register struct rtentry *rt; 137 { 138 register struct ifaddr *ifa; 139 140 if (rt == 0) 141 panic("rtfree"); 142 rt->rt_refcnt--; 143 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { 144 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 145 panic ("rtfree 2"); 146 rttrash--; 147 if (rt->rt_refcnt < 0) { 148 printf("rtfree: %x not freed (neg refs)\n", rt); 149 return; 150 } 151 ifa = rt->rt_ifa; 152 IFAFREE(ifa); 153 Free(rt_key(rt)); 154 Free(rt); 155 } 156 } 157 158 void 159 ifafree(ifa) 160 register struct ifaddr *ifa; 161 { 162 if (ifa == NULL) 163 panic("ifafree"); 164 if (ifa->ifa_refcnt == 0) 165 free(ifa, M_IFADDR); 166 else 167 ifa->ifa_refcnt--; 168 } 169 170 /* 171 * Force a routing table entry to the specified 172 * destination to go through the given gateway. 173 * Normally called as a result of a routing redirect 174 * message from the network layer. 175 * 176 * N.B.: must be called at splnet 177 * 178 */ 179 void 180 rtredirect(dst, gateway, netmask, flags, src, rtp) 181 struct sockaddr *dst, *gateway, *netmask, *src; 182 int flags; 183 struct rtentry **rtp; 184 { 185 register struct rtentry *rt; 186 int error = 0; 187 short *stat = 0; 188 struct rt_addrinfo info; 189 struct ifaddr *ifa; 190 191 /* verify the gateway is directly reachable */ 192 if ((ifa = ifa_ifwithnet(gateway)) == 0) { 193 error = ENETUNREACH; 194 goto out; 195 } 196 rt = rtalloc1(dst, 0); 197 /* 198 * If the redirect isn't from our current router for this dst, 199 * it's either old or wrong. If it redirects us to ourselves, 200 * we have a routing loop, perhaps as a result of an interface 201 * going down recently. 202 */ 203 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0) 204 if (!(flags & RTF_DONE) && rt && 205 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 206 error = EINVAL; 207 else if (ifa_ifwithaddr(gateway)) 208 error = EHOSTUNREACH; 209 if (error) 210 goto done; 211 /* 212 * Create a new entry if we just got back a wildcard entry 213 * or the the lookup failed. This is necessary for hosts 214 * which use routing redirects generated by smart gateways 215 * to dynamically build the routing tables. 216 */ 217 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 218 goto create; 219 /* 220 * Don't listen to the redirect if it's 221 * for a route to an interface. 222 */ 223 if (rt->rt_flags & RTF_GATEWAY) { 224 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 225 /* 226 * Changing from route to net => route to host. 227 * Create new route, rather than smashing route to net. 228 */ 229 create: 230 flags |= RTF_GATEWAY | RTF_DYNAMIC; 231 error = rtrequest((int)RTM_ADD, dst, gateway, 232 netmask, flags, 233 (struct rtentry **)0); 234 stat = &rtstat.rts_dynamic; 235 } else { 236 /* 237 * Smash the current notion of the gateway to 238 * this destination. Should check about netmask!!! 239 */ 240 rt->rt_flags |= RTF_MODIFIED; 241 flags |= RTF_MODIFIED; 242 stat = &rtstat.rts_newgateway; 243 rt_setgate(rt, rt_key(rt), gateway); 244 } 245 } else 246 error = EHOSTUNREACH; 247 done: 248 if (rt) { 249 if (rtp && !error) 250 *rtp = rt; 251 else 252 rtfree(rt); 253 } 254 out: 255 if (error) 256 rtstat.rts_badredirect++; 257 else if (stat != NULL) 258 (*stat)++; 259 bzero((caddr_t)&info, sizeof(info)); 260 info.rti_info[RTAX_DST] = dst; 261 info.rti_info[RTAX_GATEWAY] = gateway; 262 info.rti_info[RTAX_NETMASK] = netmask; 263 info.rti_info[RTAX_AUTHOR] = src; 264 rt_missmsg(RTM_REDIRECT, &info, flags, error); 265 } 266 267 /* 268 * Routing table ioctl interface. 269 */ 270 int 271 rtioctl(req, data, p) 272 int req; 273 caddr_t data; 274 struct proc *p; 275 { 276 return (EOPNOTSUPP); 277 } 278 279 struct ifaddr * 280 ifa_ifwithroute(flags, dst, gateway) 281 int flags; 282 struct sockaddr *dst, *gateway; 283 { 284 register struct ifaddr *ifa; 285 if ((flags & RTF_GATEWAY) == 0) { 286 /* 287 * If we are adding a route to an interface, 288 * and the interface is a pt to pt link 289 * we should search for the destination 290 * as our clue to the interface. Otherwise 291 * we can use the local address. 292 */ 293 ifa = 0; 294 if (flags & RTF_HOST) 295 ifa = ifa_ifwithdstaddr(dst); 296 if (ifa == 0) 297 ifa = ifa_ifwithaddr(gateway); 298 } else { 299 /* 300 * If we are adding a route to a remote net 301 * or host, the gateway may still be on the 302 * other end of a pt to pt link. 303 */ 304 ifa = ifa_ifwithdstaddr(gateway); 305 } 306 if (ifa == 0) 307 ifa = ifa_ifwithnet(gateway); 308 if (ifa == 0) { 309 struct rtentry *rt = rtalloc1(dst, 0); 310 if (rt == 0) 311 return (0); 312 rt->rt_refcnt--; 313 if ((ifa = rt->rt_ifa) == 0) 314 return (0); 315 } 316 if (ifa->ifa_addr->sa_family != dst->sa_family) { 317 struct ifaddr *oifa = ifa; 318 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 319 if (ifa == 0) 320 ifa = oifa; 321 } 322 return (ifa); 323 } 324 325 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 326 327 int 328 rtrequest(req, dst, gateway, netmask, flags, ret_nrt) 329 int req, flags; 330 struct sockaddr *dst, *gateway, *netmask; 331 struct rtentry **ret_nrt; 332 { 333 int s = splnet(); int error = 0; 334 register struct rtentry *rt; 335 register struct radix_node *rn; 336 register struct radix_node_head *rnh; 337 struct ifaddr *ifa; 338 struct sockaddr *ndst; 339 #define senderr(x) { error = x ; goto bad; } 340 341 if ((rnh = rt_tables[dst->sa_family]) == 0) 342 senderr(ESRCH); 343 if (flags & RTF_HOST) 344 netmask = 0; 345 switch (req) { 346 case RTM_DELETE: 347 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) 348 senderr(ESRCH); 349 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 350 panic ("rtrequest delete"); 351 rt = (struct rtentry *)rn; 352 rt->rt_flags &= ~RTF_UP; 353 if (rt->rt_gwroute) { 354 rt = rt->rt_gwroute; RTFREE(rt); 355 (rt = (struct rtentry *)rn)->rt_gwroute = 0; 356 } 357 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 358 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 359 rttrash++; 360 if (ret_nrt) 361 *ret_nrt = rt; 362 else if (rt->rt_refcnt <= 0) { 363 rt->rt_refcnt++; 364 rtfree(rt); 365 } 366 break; 367 368 case RTM_RESOLVE: 369 if (ret_nrt == 0 || (rt = *ret_nrt) == 0) 370 senderr(EINVAL); 371 ifa = rt->rt_ifa; 372 flags = rt->rt_flags & ~RTF_CLONING; 373 gateway = rt->rt_gateway; 374 if ((netmask = rt->rt_genmask) == 0) 375 flags |= RTF_HOST; 376 goto makeroute; 377 378 case RTM_ADD: 379 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0) 380 senderr(ENETUNREACH); 381 makeroute: 382 R_Malloc(rt, struct rtentry *, sizeof(*rt)); 383 if (rt == 0) 384 senderr(ENOBUFS); 385 Bzero(rt, sizeof(*rt)); 386 rt->rt_flags = RTF_UP | flags; 387 if (rt_setgate(rt, dst, gateway)) { 388 Free(rt); 389 senderr(ENOBUFS); 390 } 391 ndst = rt_key(rt); 392 if (netmask) { 393 rt_maskedcopy(dst, ndst, netmask); 394 } else 395 Bcopy(dst, ndst, dst->sa_len); 396 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, 397 rnh, rt->rt_nodes); 398 if (rn == 0) { 399 if (rt->rt_gwroute) 400 rtfree(rt->rt_gwroute); 401 Free(rt_key(rt)); 402 Free(rt); 403 senderr(EEXIST); 404 } 405 ifa->ifa_refcnt++; 406 rt->rt_ifa = ifa; 407 rt->rt_ifp = ifa->ifa_ifp; 408 if (req == RTM_RESOLVE) 409 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ 410 if (ifa->ifa_rtrequest) 411 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); 412 if (ret_nrt) { 413 *ret_nrt = rt; 414 rt->rt_refcnt++; 415 } 416 break; 417 } 418 bad: 419 splx(s); 420 return (error); 421 } 422 423 int 424 rt_setgate(rt0, dst, gate) 425 struct rtentry *rt0; 426 struct sockaddr *dst, *gate; 427 { 428 caddr_t new, old; 429 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); 430 register struct rtentry *rt = rt0; 431 432 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { 433 old = (caddr_t)rt_key(rt); 434 R_Malloc(new, caddr_t, dlen + glen); 435 if (new == 0) 436 return 1; 437 rt->rt_nodes->rn_key = new; 438 } else { 439 new = rt->rt_nodes->rn_key; 440 old = 0; 441 } 442 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); 443 if (old) { 444 Bcopy(dst, new, dlen); 445 Free(old); 446 } 447 if (rt->rt_gwroute) { 448 rt = rt->rt_gwroute; RTFREE(rt); 449 rt = rt0; rt->rt_gwroute = 0; 450 } 451 if (rt->rt_flags & RTF_GATEWAY) { 452 rt->rt_gwroute = rtalloc1(gate, 1); 453 } 454 return 0; 455 } 456 457 void 458 rt_maskedcopy(src, dst, netmask) 459 struct sockaddr *src, *dst, *netmask; 460 { 461 register u_char *cp1 = (u_char *)src; 462 register u_char *cp2 = (u_char *)dst; 463 register u_char *cp3 = (u_char *)netmask; 464 u_char *cplim = cp2 + *cp3; 465 u_char *cplim2 = cp2 + *cp1; 466 467 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 468 cp3 += 2; 469 if (cplim > cplim2) 470 cplim = cplim2; 471 while (cp2 < cplim) 472 *cp2++ = *cp1++ & *cp3++; 473 if (cp2 < cplim2) 474 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 475 } 476 477 /* 478 * Set up a routing table entry, normally 479 * for an interface. 480 */ 481 int 482 rtinit(ifa, cmd, flags) 483 register struct ifaddr *ifa; 484 int cmd, flags; 485 { 486 register struct rtentry *rt; 487 register struct sockaddr *dst; 488 register struct sockaddr *deldst; 489 struct mbuf *m = 0; 490 struct rtentry *nrt = 0; 491 int error; 492 493 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; 494 if (cmd == RTM_DELETE) { 495 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { 496 m = m_get(M_WAIT, MT_SONAME); 497 deldst = mtod(m, struct sockaddr *); 498 rt_maskedcopy(dst, deldst, ifa->ifa_netmask); 499 dst = deldst; 500 } 501 if (rt = rtalloc1(dst, 0)) { 502 rt->rt_refcnt--; 503 if (rt->rt_ifa != ifa) { 504 if (m) 505 (void) m_free(m); 506 return (flags & RTF_HOST ? EHOSTUNREACH 507 : ENETUNREACH); 508 } 509 } 510 } 511 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, 512 flags | ifa->ifa_flags, &nrt); 513 if (m) 514 (void) m_free(m); 515 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { 516 rt_newaddrmsg(cmd, ifa, error, nrt); 517 if (rt->rt_refcnt <= 0) { 518 rt->rt_refcnt++; 519 rtfree(rt); 520 } 521 } 522 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { 523 rt->rt_refcnt--; 524 if (rt->rt_ifa != ifa) { 525 printf("rtinit: wrong ifa (%x) was (%x)\n", ifa, 526 rt->rt_ifa); 527 if (rt->rt_ifa->ifa_rtrequest) 528 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); 529 IFAFREE(rt->rt_ifa); 530 rt->rt_ifa = ifa; 531 rt->rt_ifp = ifa->ifa_ifp; 532 ifa->ifa_refcnt++; 533 if (ifa->ifa_rtrequest) 534 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); 535 } 536 rt_newaddrmsg(cmd, ifa, error, nrt); 537 } 538 return (error); 539 } 540