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