|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * @(#)route.c 7.1 (Berkeley) 6/4/86 ! 7: */ ! 8: ! 9: #include "param.h" ! 10: #include "systm.h" ! 11: #include "mbuf.h" ! 12: #include "protosw.h" ! 13: #include "socket.h" ! 14: #include "dir.h" ! 15: #include "user.h" ! 16: #include "ioctl.h" ! 17: #include "errno.h" ! 18: ! 19: #include "if.h" ! 20: #include "af.h" ! 21: #include "route.h" ! 22: ! 23: int rttrash; /* routes not in table but not freed */ ! 24: struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ ! 25: int rthashsize = RTHASHSIZ; /* for netstat, etc. */ ! 26: ! 27: /* ! 28: * Packet routing routines. ! 29: */ ! 30: rtalloc(ro) ! 31: register struct route *ro; ! 32: { ! 33: register struct rtentry *rt; ! 34: register struct mbuf *m; ! 35: register u_long hash; ! 36: struct sockaddr *dst = &ro->ro_dst; ! 37: int (*match)(), doinghost, s; ! 38: struct afhash h; ! 39: u_int af = dst->sa_family; ! 40: struct mbuf **table; ! 41: ! 42: if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) ! 43: return; /* XXX */ ! 44: if (af >= AF_MAX) ! 45: return; ! 46: (*afswitch[af].af_hash)(dst, &h); ! 47: match = afswitch[af].af_netmatch; ! 48: hash = h.afh_hosthash, table = rthost, doinghost = 1; ! 49: s = splnet(); ! 50: again: ! 51: for (m = table[RTHASHMOD(hash)]; m; m = m->m_next) { ! 52: rt = mtod(m, struct rtentry *); ! 53: if (rt->rt_hash != hash) ! 54: continue; ! 55: if ((rt->rt_flags & RTF_UP) == 0 || ! 56: (rt->rt_ifp->if_flags & IFF_UP) == 0) ! 57: continue; ! 58: if (doinghost) { ! 59: if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst, ! 60: sizeof (*dst))) ! 61: continue; ! 62: } else { ! 63: if (rt->rt_dst.sa_family != af || ! 64: !(*match)(&rt->rt_dst, dst)) ! 65: continue; ! 66: } ! 67: rt->rt_refcnt++; ! 68: splx(s); ! 69: if (dst == &wildcard) ! 70: rtstat.rts_wildcard++; ! 71: ro->ro_rt = rt; ! 72: return; ! 73: } ! 74: if (doinghost) { ! 75: doinghost = 0; ! 76: hash = h.afh_nethash, table = rtnet; ! 77: goto again; ! 78: } ! 79: /* ! 80: * Check for wildcard gateway, by convention network 0. ! 81: */ ! 82: if (dst != &wildcard) { ! 83: dst = &wildcard, hash = 0; ! 84: goto again; ! 85: } ! 86: splx(s); ! 87: rtstat.rts_unreach++; ! 88: } ! 89: ! 90: rtfree(rt) ! 91: register struct rtentry *rt; ! 92: { ! 93: ! 94: if (rt == 0) ! 95: panic("rtfree"); ! 96: rt->rt_refcnt--; ! 97: if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) { ! 98: rttrash--; ! 99: (void) m_free(dtom(rt)); ! 100: } ! 101: } ! 102: ! 103: /* ! 104: * Force a routing table entry to the specified ! 105: * destination to go through the given gateway. ! 106: * Normally called as a result of a routing redirect ! 107: * message from the network layer. ! 108: * ! 109: * N.B.: must be called at splnet or higher ! 110: * ! 111: */ ! 112: rtredirect(dst, gateway, flags, src) ! 113: struct sockaddr *dst, *gateway, *src; ! 114: int flags; ! 115: { ! 116: struct route ro; ! 117: register struct rtentry *rt; ! 118: ! 119: /* verify the gateway is directly reachable */ ! 120: if (ifa_ifwithnet(gateway) == 0) { ! 121: rtstat.rts_badredirect++; ! 122: return; ! 123: } ! 124: ro.ro_dst = *dst; ! 125: ro.ro_rt = 0; ! 126: rtalloc(&ro); ! 127: rt = ro.ro_rt; ! 128: #define equal(a1, a2) \ ! 129: (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0) ! 130: /* ! 131: * If the redirect isn't from our current router for this dst, ! 132: * it's either old or wrong. If it redirects us to ourselves, ! 133: * we have a routing loop, perhaps as a result of an interface ! 134: * going down recently. ! 135: */ ! 136: if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) { ! 137: rtstat.rts_badredirect++; ! 138: if (rt) ! 139: rtfree(rt); ! 140: return; ! 141: } ! 142: /* ! 143: * Create a new entry if we just got back a wildcard entry ! 144: * or the the lookup failed. This is necessary for hosts ! 145: * which use routing redirects generated by smart gateways ! 146: * to dynamically build the routing tables. ! 147: */ ! 148: if (rt && ! 149: (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) { ! 150: rtfree(rt); ! 151: rt = 0; ! 152: } ! 153: if (rt == 0) { ! 154: rtinit(dst, gateway, (int)SIOCADDRT, ! 155: (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC); ! 156: rtstat.rts_dynamic++; ! 157: return; ! 158: } ! 159: /* ! 160: * Don't listen to the redirect if it's ! 161: * for a route to an interface. ! 162: */ ! 163: if (rt->rt_flags & RTF_GATEWAY) { ! 164: if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { ! 165: /* ! 166: * Changing from route to net => route to host. ! 167: * Create new route, rather than smashing route to net. ! 168: */ ! 169: rtinit(dst, gateway, (int)SIOCADDRT, ! 170: flags | RTF_DYNAMIC); ! 171: rtstat.rts_dynamic++; ! 172: } else { ! 173: /* ! 174: * Smash the current notion of the gateway to ! 175: * this destination. ! 176: */ ! 177: rt->rt_gateway = *gateway; ! 178: } ! 179: rtstat.rts_newgateway++; ! 180: } else ! 181: rtstat.rts_badredirect++; ! 182: rtfree(rt); ! 183: } ! 184: ! 185: /* ! 186: * Routing table ioctl interface. ! 187: */ ! 188: rtioctl(cmd, data) ! 189: int cmd; ! 190: caddr_t data; ! 191: { ! 192: ! 193: if (cmd != SIOCADDRT && cmd != SIOCDELRT) ! 194: return (EINVAL); ! 195: if (!suser()) ! 196: return (u.u_error); ! 197: return (rtrequest(cmd, (struct rtentry *)data)); ! 198: } ! 199: ! 200: /* ! 201: * Carry out a request to change the routing table. Called by ! 202: * interfaces at boot time to make their ``local routes'' known, ! 203: * for ioctl's, and as the result of routing redirects. ! 204: */ ! 205: rtrequest(req, entry) ! 206: int req; ! 207: register struct rtentry *entry; ! 208: { ! 209: register struct mbuf *m, **mprev; ! 210: struct mbuf **mfirst; ! 211: register struct rtentry *rt; ! 212: struct afhash h; ! 213: int s, error = 0, (*match)(); ! 214: u_int af; ! 215: u_long hash; ! 216: struct ifaddr *ifa; ! 217: struct ifaddr *ifa_ifwithdstaddr(); ! 218: ! 219: af = entry->rt_dst.sa_family; ! 220: if (af >= AF_MAX) ! 221: return (EAFNOSUPPORT); ! 222: (*afswitch[af].af_hash)(&entry->rt_dst, &h); ! 223: if (entry->rt_flags & RTF_HOST) { ! 224: hash = h.afh_hosthash; ! 225: mprev = &rthost[RTHASHMOD(hash)]; ! 226: } else { ! 227: hash = h.afh_nethash; ! 228: mprev = &rtnet[RTHASHMOD(hash)]; ! 229: } ! 230: match = afswitch[af].af_netmatch; ! 231: s = splimp(); ! 232: for (mfirst = mprev; m = *mprev; mprev = &m->m_next) { ! 233: rt = mtod(m, struct rtentry *); ! 234: if (rt->rt_hash != hash) ! 235: continue; ! 236: if (entry->rt_flags & RTF_HOST) { ! 237: if (!equal(&rt->rt_dst, &entry->rt_dst)) ! 238: continue; ! 239: } else { ! 240: if (rt->rt_dst.sa_family != entry->rt_dst.sa_family || ! 241: (*match)(&rt->rt_dst, &entry->rt_dst) == 0) ! 242: continue; ! 243: } ! 244: if (equal(&rt->rt_gateway, &entry->rt_gateway)) ! 245: break; ! 246: } ! 247: switch (req) { ! 248: ! 249: case SIOCDELRT: ! 250: if (m == 0) { ! 251: error = ESRCH; ! 252: goto bad; ! 253: } ! 254: *mprev = m->m_next; ! 255: if (rt->rt_refcnt > 0) { ! 256: rt->rt_flags &= ~RTF_UP; ! 257: rttrash++; ! 258: m->m_next = 0; ! 259: } else ! 260: (void) m_free(m); ! 261: break; ! 262: ! 263: case SIOCADDRT: ! 264: if (m) { ! 265: error = EEXIST; ! 266: goto bad; ! 267: } ! 268: if ((entry->rt_flags & RTF_GATEWAY) == 0) { ! 269: /* ! 270: * If we are adding a route to an interface, ! 271: * and the interface is a pt to pt link ! 272: * we should search for the destination ! 273: * as our clue to the interface. Otherwise ! 274: * we can use the local address. ! 275: */ ! 276: ifa = 0; ! 277: if (entry->rt_flags & RTF_HOST) ! 278: ifa = ifa_ifwithdstaddr(&entry->rt_dst); ! 279: if (ifa == 0) ! 280: ifa = ifa_ifwithaddr(&entry->rt_gateway); ! 281: } else { ! 282: /* ! 283: * If we are adding a route to a remote net ! 284: * or host, the gateway may still be on the ! 285: * other end of a pt to pt link. ! 286: */ ! 287: ifa = ifa_ifwithdstaddr(&entry->rt_gateway); ! 288: } ! 289: if (ifa == 0) { ! 290: ifa = ifa_ifwithnet(&entry->rt_gateway); ! 291: if (ifa == 0) { ! 292: error = ENETUNREACH; ! 293: goto bad; ! 294: } ! 295: } ! 296: m = m_get(M_DONTWAIT, MT_RTABLE); ! 297: if (m == 0) { ! 298: error = ENOBUFS; ! 299: goto bad; ! 300: } ! 301: m->m_next = *mfirst; ! 302: *mfirst = m; ! 303: m->m_off = MMINOFF; ! 304: m->m_len = sizeof (struct rtentry); ! 305: rt = mtod(m, struct rtentry *); ! 306: rt->rt_hash = hash; ! 307: rt->rt_dst = entry->rt_dst; ! 308: rt->rt_gateway = entry->rt_gateway; ! 309: rt->rt_flags = RTF_UP | ! 310: (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC)); ! 311: rt->rt_refcnt = 0; ! 312: rt->rt_use = 0; ! 313: rt->rt_ifp = ifa->ifa_ifp; ! 314: break; ! 315: } ! 316: bad: ! 317: splx(s); ! 318: return (error); ! 319: } ! 320: ! 321: /* ! 322: * Set up a routing table entry, normally ! 323: * for an interface. ! 324: */ ! 325: rtinit(dst, gateway, cmd, flags) ! 326: struct sockaddr *dst, *gateway; ! 327: int cmd, flags; ! 328: { ! 329: struct rtentry route; ! 330: ! 331: bzero((caddr_t)&route, sizeof (route)); ! 332: route.rt_dst = *dst; ! 333: route.rt_gateway = *gateway; ! 334: route.rt_flags = flags; ! 335: (void) rtrequest(cmd, &route); ! 336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.