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