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