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