X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/c124e99765d0f6dcbd313a3f51049048be62e9b6..5e3649c60f3939c8e845ca6d6734f440d2f2642f:/usr/src/sys/net/route.c diff --git a/usr/src/sys/net/route.c b/usr/src/sys/net/route.c index cf923703b7..b46049b984 100644 --- a/usr/src/sys/net/route.c +++ b/usr/src/sys/net/route.c @@ -1,4 +1,4 @@ -/* route.c 4.3 82/03/29 */ +/* route.c 4.12 82/10/09 */ #include "../h/param.h" #include "../h/systm.h" @@ -6,204 +6,192 @@ #include "../h/protosw.h" #include "../h/socket.h" #include "../h/ioctl.h" -#include "../net/in.h" -#include "../net/in_systm.h" #include "../net/if.h" #include "../net/af.h" #include "../net/route.h" #include +int rttrash; /* routes not in table but not freed */ /* * Packet routing routines. */ - -/* - * With much ado about nothing... - * route the cars that climb halfway to the stars... - */ -allocroute(ro) +rtalloc(ro) register struct route *ro; { register struct rtentry *rt, *rtmin; register struct mbuf *m; - register int key; + register int hash, (*match)(); struct afhash h; struct sockaddr *dst = &ro->ro_dst; - int af = dst->sa_family, doinghost; + int af = dst->sa_family; -COUNT(ALLOCROUTE); - if (ro->ro_rt && ro->ro_rt->rt_ifp) /* can't happen */ + if (ro->ro_rt && ro->ro_rt->rt_ifp) /* XXX */ + return; + if (af >= AF_MAX) return; (*afswitch[af].af_hash)(dst, &h); - m = routehash[h.afh_hosthash % RTHASHSIZ]; - key = h.afh_hostkey; - rtmin = 0, doinghost = 1; -again: - for (; m; m = m->m_next) { + rtmin = 0, hash = h.afh_hosthash; + for (m = rthost[hash % RTHASHSIZ]; m; m = m->m_next) { rt = mtod(m, struct rtentry *); - if (rt->rt_key != key) + if (rt->rt_hash != hash) + continue; + if ((rt->rt_flags & RTF_UP) == 0 || + (rt->rt_ifp->if_flags & IFF_UP) == 0) + continue; + if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst, sizeof (*dst))) continue; - if (doinghost) { -#define equal(a1, a2) \ - (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0) - if (!equal(&rt->rt_dst, dst)) - continue; - } else { - if (rt->rt_dst.sa_family != af) - continue; - if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0) - continue; - } if (rtmin == 0 || rt->rt_use < rtmin->rt_use) rtmin = rt; } - if (rtmin) { - ro->ro_dst = rt->rt_dst; - ro->ro_rt = rt; - rt->rt_refcnt++; - return (rt->rt_flags & RTF_DIRECT); - } - if (doinghost) { - doinghost = 0; - m = routehash[h.afh_nethash % RTHASHSIZ]; - key = h.afh_netkey; - goto again; + if (rtmin) + goto found; + + hash = h.afh_nethash; + match = afswitch[af].af_netmatch; + for (m = rtnet[hash % RTHASHSIZ]; m; m = m->m_next) { + rt = mtod(m, struct rtentry *); + if (rt->rt_hash != hash) + continue; + if ((rt->rt_flags & RTF_UP) == 0 || + (rt->rt_ifp->if_flags & IFF_UP) == 0) + continue; + if (rt->rt_dst.sa_family != af || !(*match)(&rt->rt_dst, dst)) + continue; + if (rtmin == 0 || rt->rt_use < rtmin->rt_use) + rtmin = rt; } - ro->ro_rt = 0; - return (0); +found: + ro->ro_rt = rtmin; + if (rtmin) + rtmin->rt_refcnt++; } -freeroute(rt) +rtfree(rt) register struct rtentry *rt; { -COUNT(FREEROUTE); + register struct mbuf **mp; + if (rt == 0) panic("freeroute"); rt->rt_refcnt--; - /* on refcnt == 0 reclaim? notify someone? */ -} - -#ifdef notdef -struct rtentry * -reroute(sa) - register struct sockaddr *sa; -{ - register struct rtentry *rt; - register struct mbuf *m; - register int key; - struct afhash h; - -COUNT(REROUTE); - (*afswitch[sa->sa_family].af_hash)(sa, &h); - m = routehash[h.afh_hosthash]; - key = h.afh_hostkey; - for (; m; m = m->m_next) { - rt = mtod(m, struct rtentry *); - if (rt->rt_key != key) - continue; - if (equal(&rt->rt_gateway, sa)) - return (rt); + if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) { + rttrash--; + (void) m_free(dtom(rt)); } - return (0); } -#endif /* * Carry out a request to change the routing table. Called by * interfaces at boot time to make their ``local routes'' known * and for ioctl's. */ -rtrequest(req, new) +rtrequest(req, entry) int req; - register struct rtentry *new; + register struct rtentry *entry; { - register struct rtentry *rt; register struct mbuf *m, **mprev; - register int key; - struct sockaddr *sa = &new->rt_dst; + register struct rtentry *rt; struct afhash h; - int af = sa->sa_family, doinghost, s, error = 0; + int af, s, error = 0, hash, (*match)(); + struct ifnet *ifp; -COUNT(RTREQUEST); - (*afswitch[af].af_hash)(sa, &h); - mprev = &routehash[h.afh_hosthash % RTHASHSIZ]; - key = h.afh_hostkey; - doinghost = 1; + af = entry->rt_dst.sa_family; + if (af >= AF_MAX) + return (EAFNOSUPPORT); + (*afswitch[af].af_hash)(&entry->rt_dst, &h); + if (entry->rt_flags & RTF_HOST) { + hash = h.afh_hosthash; + mprev = &rthost[hash % RTHASHSIZ]; + } else { + hash = h.afh_nethash; + mprev = &rtnet[hash % RTHASHSIZ]; + } + match = afswitch[af].af_netmatch; s = splimp(); -again: for (; m = *mprev; mprev = &m->m_next) { rt = mtod(m, struct rtentry *); - if (rt->rt_key != key) + if (rt->rt_hash != hash) continue; - if (doinghost) { - if (!equal(&rt->rt_dst, &new->rt_dst)) + if (entry->rt_flags & RTF_HOST) { +#define equal(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0) + if (!equal(&rt->rt_dst, &entry->rt_dst)) continue; } else { - if (rt->rt_dst.sa_family != af) - continue; - if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0) + if (rt->rt_dst.sa_family != entry->rt_dst.sa_family || + (*match)(&rt->rt_dst, &entry->rt_dst) == 0) continue; } - /* require full match on deletions */ - if (req == SIOCDELRT && - !equal(&rt->rt_gateway, &new->rt_gateway)) - continue; - /* don't keep multiple identical entries */ - if (req == SIOCADDRT && - equal(&rt->rt_gateway, &new->rt_gateway)) { - error = EEXIST; - goto bad; - } - break; - } - if (m == 0 && doinghost) { - doinghost = 0; - mprev = &routehash[h.afh_nethash % RTHASHSIZ]; - key = h.afh_netkey; - goto again; - } - - if (m == 0 && req != SIOCADDRT) { - error = ESRCH; - goto bad; + if (equal(&rt->rt_gateway, &entry->rt_gateway)) + break; } switch (req) { case SIOCDELRT: - rt->rt_flags &= ~RTF_UP; - if (rt->rt_refcnt > 0) /* should we notify protocols? */ - error = EBUSY; - else - *mprev = m_free(m); - break; - - case SIOCCHGRT: - rt->rt_flags = new->rt_flags; - if (rt->rt_refcnt > 0) - error = EBUSY; - else if (!equal(&rt->rt_gateway, &new->rt_gateway)) - goto newneighbor; + if (m == 0) { + error = ESRCH; + goto bad; + } + *mprev = m->m_next; + if (rt->rt_refcnt > 0) { + rt->rt_flags &= ~RTF_UP; + rttrash++; + m->m_next = 0; + } else + (void) m_free(m); break; case SIOCADDRT: - m = m_getclr(M_DONTWAIT); + if (m) { + error = EEXIST; + goto bad; + } + ifp = if_ifwithaddr(&entry->rt_gateway); + if (ifp == 0) { + ifp = if_ifwithnet(&entry->rt_gateway); + if (ifp == 0) { + error = ENETUNREACH; + goto bad; + } + } + m = m_get(M_DONTWAIT); if (m == 0) { error = ENOBUFS; - break; + goto bad; } - m->m_off = MMINOFF; *mprev = m; + m->m_off = MMINOFF; + m->m_len = sizeof (struct rtentry); rt = mtod(m, struct rtentry *); - *rt = *new; - rt->rt_key = h.afh_nethash | h.afh_hosthash; -newneighbor: - rt->rt_ifp = if_ifonnetof(&new->rt_gateway); - if (rt->rt_ifp == 0) - rt->rt_flags &= ~RTF_UP; + rt->rt_hash = hash; + rt->rt_dst = entry->rt_dst; + rt->rt_gateway = entry->rt_gateway; + rt->rt_flags = + RTF_UP | (entry->rt_flags & (RTF_HOST|RTF_GATEWAY)); rt->rt_refcnt = 0; + rt->rt_use = 0; + rt->rt_ifp = ifp; break; } bad: splx(s); return (error); } + +/* + * Set up a routing table entry, normally + * for an interface. + */ +rtinit(dst, gateway, flags) + struct sockaddr *dst, *gateway; + int flags; +{ + struct rtentry route; + struct route ro; + + bzero((caddr_t)&route, sizeof (route)); + route.rt_dst = *dst; + route.rt_gateway = *gateway; + route.rt_flags = flags; + (void) rtrequest(SIOCADDRT, &route); +}