diff options
Diffstat (limited to 'freebsd/sys/net/if_stf.c')
-rw-r--r-- | freebsd/sys/net/if_stf.c | 279 |
1 files changed, 84 insertions, 195 deletions
diff --git a/freebsd/sys/net/if_stf.c b/freebsd/sys/net/if_stf.c index e88fd34d..7c1b7075 100644 --- a/freebsd/sys/net/if_stf.c +++ b/freebsd/sys/net/if_stf.c @@ -76,9 +76,6 @@ * Note that there is no way to be 100% secure. */ -#include <rtems/bsd/local/opt_inet.h> -#include <rtems/bsd/local/opt_inet6.h> - #include <rtems/bsd/sys/param.h> #include <sys/systm.h> #include <sys/socket.h> @@ -86,24 +83,27 @@ #include <sys/mbuf.h> #include <rtems/bsd/sys/errno.h> #include <sys/kernel.h> +#include <rtems/bsd/sys/lock.h> #include <sys/module.h> #include <sys/protosw.h> #include <sys/proc.h> #include <sys/queue.h> +#include <sys/rmlock.h> #include <sys/sysctl.h> #include <machine/cpu.h> #include <sys/malloc.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_clone.h> #include <net/route.h> #include <net/netisr.h> #include <net/if_types.h> -#include <net/if_stf.h> #include <net/vnet.h> #include <netinet/in.h> +#include <netinet/in_fib.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> @@ -125,16 +125,10 @@ SYSCTL_DECL(_net_link); static SYSCTL_NODE(_net_link, IFT_STF, stf, CTLFLAG_RW, 0, "6to4 Interface"); -static int stf_route_cache = 1; -SYSCTL_INT(_net_link_stf, OID_AUTO, route_cache, CTLFLAG_RW, - &stf_route_cache, 0, "Caching of IPv4 routes for 6to4 Output"); - static int stf_permit_rfc1918 = 0; -TUNABLE_INT("net.link.stf.permit_rfc1918", &stf_permit_rfc1918); -SYSCTL_INT(_net_link_stf, OID_AUTO, permit_rfc1918, CTLFLAG_RW | CTLFLAG_TUN, +SYSCTL_INT(_net_link_stf, OID_AUTO, permit_rfc1918, CTLFLAG_RWTUN, &stf_permit_rfc1918, 0, "Permit the use of private IPv4 addresses"); -#define STFNAME "stf" #define STFUNIT 0 #define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002) @@ -143,36 +137,34 @@ SYSCTL_INT(_net_link_stf, OID_AUTO, permit_rfc1918, CTLFLAG_RW | CTLFLAG_TUN, * XXX: Return a pointer with 16-bit aligned. Don't cast it to * struct in_addr *; use bcopy() instead. */ -#define GET_V4(x) ((caddr_t)(&(x)->s6_addr16[1])) +#define GET_V4(x) (&(x)->s6_addr16[1]) struct stf_softc { struct ifnet *sc_ifp; - union { - struct route __sc_ro4; - struct route_in6 __sc_ro6; /* just for safety */ - } __sc_ro46; -#define sc_ro __sc_ro46.__sc_ro4 struct mtx sc_ro_mtx; u_int sc_fibnum; const struct encaptab *encap_cookie; }; #define STF2IFP(sc) ((sc)->sc_ifp) +static const char stfname[] = "stf"; + /* * Note that mutable fields in the softc are not currently locked. * We do lock sc_ro in stf_output though. */ -static MALLOC_DEFINE(M_STF, STFNAME, "6to4 Tunnel Interface"); +static MALLOC_DEFINE(M_STF, stfname, "6to4 Tunnel Interface"); static const int ip_stf_ttl = 40; extern struct domain inetdomain; -struct protosw in_stf_protosw = { +static int in_stf_input(struct mbuf **, int *, int); +static struct protosw in_stf_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = IPPROTO_IPV6, .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = in_stf_input, - .pr_output = (pr_output_t *)rip_output, + .pr_output = rip_output, .pr_ctloutput = rip_ctloutput, .pr_usrreqs = &rip_usrreqs }; @@ -181,22 +173,20 @@ static char *stfnames[] = {"stf0", "stf", "6to4", NULL}; static int stfmodevent(module_t, int, void *); static int stf_encapcheck(const struct mbuf *, int, int, void *); -static struct in6_ifaddr *stf_getsrcifa6(struct ifnet *); -static int stf_output(struct ifnet *, struct mbuf *, struct sockaddr *, +static int stf_getsrcifa6(struct ifnet *, struct in6_addr *, struct in6_addr *); +static int stf_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); static int isrfc1918addr(struct in_addr *); static int stf_checkaddr4(struct stf_softc *, struct in_addr *, struct ifnet *); static int stf_checkaddr6(struct stf_softc *, struct in6_addr *, struct ifnet *); -static void stf_rtrequest(int, struct rtentry *, struct rt_addrinfo *); static int stf_ioctl(struct ifnet *, u_long, caddr_t); static int stf_clone_match(struct if_clone *, const char *); static int stf_clone_create(struct if_clone *, char *, size_t, caddr_t); static int stf_clone_destroy(struct if_clone *, struct ifnet *); -struct if_clone stf_cloner = IFC_CLONE_INITIALIZER(STFNAME, NULL, 0, - NULL, stf_clone_match, stf_clone_create, stf_clone_destroy); +static struct if_clone *stf_cloner; static int stf_clone_match(struct if_clone *ifc, const char *name) @@ -247,7 +237,7 @@ stf_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) * we don't conform to the default naming convention for interfaces. */ strlcpy(ifp->if_xname, name, IFNAMSIZ); - ifp->if_dname = ifc->ifc_name; + ifp->if_dname = stfname; ifp->if_dunit = IF_DUNIT_NONE; mtx_init(&(sc)->sc_ro_mtx, "stf ro", NULL, MTX_DEF); @@ -289,18 +279,16 @@ stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) } static int -stfmodevent(mod, type, data) - module_t mod; - int type; - void *data; +stfmodevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: - if_clone_attach(&stf_cloner); + stf_cloner = if_clone_advanced(stfname, 0, stf_clone_match, + stf_clone_create, stf_clone_destroy); break; case MOD_UNLOAD: - if_clone_detach(&stf_cloner); + if_clone_detach(stf_cloner); break; default: return (EOPNOTSUPP); @@ -318,16 +306,12 @@ static moduledata_t stf_mod = { DECLARE_MODULE(if_stf, stf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); static int -stf_encapcheck(m, off, proto, arg) - const struct mbuf *m; - int off; - int proto; - void *arg; +stf_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip ip; - struct in6_ifaddr *ia6; struct stf_softc *sc; struct in_addr a, b, mask; + struct in6_addr addr6, mask6; sc = (struct stf_softc *)arg; if (sc == NULL) @@ -349,20 +333,16 @@ stf_encapcheck(m, off, proto, arg) if (ip.ip_v != 4) return 0; - ia6 = stf_getsrcifa6(STF2IFP(sc)); - if (ia6 == NULL) - return 0; + if (stf_getsrcifa6(STF2IFP(sc), &addr6, &mask6) != 0) + return (0); /* * check if IPv4 dst matches the IPv4 address derived from the * local 6to4 address. * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:... */ - if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst, - sizeof(ip.ip_dst)) != 0) { - ifa_free(&ia6->ia_ifa); + if (bcmp(GET_V4(&addr6), &ip.ip_dst, sizeof(ip.ip_dst)) != 0) return 0; - } /* * check if IPv4 src matches the IPv4 address derived from the @@ -371,9 +351,8 @@ stf_encapcheck(m, off, proto, arg) * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24 */ bzero(&a, sizeof(a)); - bcopy(GET_V4(&ia6->ia_addr.sin6_addr), &a, sizeof(a)); - bcopy(GET_V4(&ia6->ia_prefixmask.sin6_addr), &mask, sizeof(mask)); - ifa_free(&ia6->ia_ifa); + bcopy(GET_V4(&addr6), &a, sizeof(a)); + bcopy(GET_V4(&mask6), &mask, sizeof(mask)); a.s_addr &= mask.s_addr; b = ip.ip_src; b.s_addr &= mask.s_addr; @@ -384,12 +363,12 @@ stf_encapcheck(m, off, proto, arg) return 32; } -static struct in6_ifaddr * -stf_getsrcifa6(ifp) - struct ifnet *ifp; +static int +stf_getsrcifa6(struct ifnet *ifp, struct in6_addr *addr, struct in6_addr *mask) { struct ifaddr *ia; struct in_ifaddr *ia4; + struct in6_ifaddr *ia6; struct sockaddr_in6 *sin6; struct in_addr in; @@ -408,33 +387,30 @@ stf_getsrcifa6(ifp) if (ia4 == NULL) continue; - ifa_ref(ia); + ia6 = (struct in6_ifaddr *)ia; + + *addr = sin6->sin6_addr; + *mask = ia6->ia_prefixmask.sin6_addr; if_addr_runlock(ifp); - return (struct in6_ifaddr *)ia; + return (0); } if_addr_runlock(ifp); - return NULL; + return (ENOENT); } static int -stf_output(ifp, m, dst, ro) - struct ifnet *ifp; - struct mbuf *m; - struct sockaddr *dst; - struct route *ro; +stf_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, + struct route *ro) { struct stf_softc *sc; - struct sockaddr_in6 *dst6; - struct route *cached_route; + const struct sockaddr_in6 *dst6; struct in_addr in4; - caddr_t ptr; - struct sockaddr_in *dst4; + const void *ptr; u_int8_t tos; struct ip *ip; struct ip6_hdr *ip6; - struct in6_ifaddr *ia6; - u_int32_t af; + struct in6_addr addr6, mask6; int error; #ifdef MAC @@ -446,12 +422,12 @@ stf_output(ifp, m, dst, ro) #endif sc = ifp->if_softc; - dst6 = (struct sockaddr_in6 *)dst; + dst6 = (const struct sockaddr_in6 *)dst; /* just in case */ if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); - ifp->if_oerrors++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return ENETDOWN; } @@ -460,18 +436,16 @@ stf_output(ifp, m, dst, ro) * we shouldn't generate output. Without this check, we'll end up * using wrong IPv4 source. */ - ia6 = stf_getsrcifa6(ifp); - if (ia6 == NULL) { + if (stf_getsrcifa6(ifp, &addr6, &mask6) != 0) { m_freem(m); - ifp->if_oerrors++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return ENETDOWN; } if (m->m_len < sizeof(*ip6)) { m = m_pullup(m, sizeof(*ip6)); if (!m) { - ifa_free(&ia6->ia_ifa); - ifp->if_oerrors++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return ENOBUFS; } } @@ -479,15 +453,6 @@ stf_output(ifp, m, dst, ro) tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; /* - * BPF writes need to be handled specially. - * This is a null operation, nothing here checks dst->sa_family. - */ - if (dst->sa_family == AF_UNSPEC) { - bcopy(dst->sa_data, &af, sizeof(af)); - dst->sa_family = af; - } - - /* * Pickup the right outer dst addr from the list of candidates. * ip6_dst has priority as it may be able to give us shorter IPv4 hops. */ @@ -497,9 +462,8 @@ stf_output(ifp, m, dst, ro) else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr)) ptr = GET_V4(&dst6->sin6_addr); else { - ifa_free(&ia6->ia_ifa); m_freem(m); - ifp->if_oerrors++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return ENETUNREACH; } bcopy(ptr, &in4, sizeof(in4)); @@ -512,78 +476,38 @@ stf_output(ifp, m, dst, ro) * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer a to it). */ - af = AF_INET6; + u_int af = AF_INET6; bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); } - M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); + M_PREPEND(m, sizeof(struct ip), M_NOWAIT); if (m == NULL) { - ifa_free(&ia6->ia_ifa); - ifp->if_oerrors++; + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return ENOBUFS; } ip = mtod(m, struct ip *); bzero(ip, sizeof(*ip)); - bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), - &ip->ip_src, sizeof(ip->ip_src)); - ifa_free(&ia6->ia_ifa); + bcopy(GET_V4(&addr6), &ip->ip_src, sizeof(ip->ip_src)); bcopy(&in4, &ip->ip_dst, sizeof(ip->ip_dst)); ip->ip_p = IPPROTO_IPV6; ip->ip_ttl = ip_stf_ttl; - ip->ip_len = m->m_pkthdr.len; /*host order*/ + ip->ip_len = htons(m->m_pkthdr.len); if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos); else ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos); - if (!stf_route_cache) { - cached_route = NULL; - goto sendit; - } - - /* - * Do we have a cached route? - */ - mtx_lock(&(sc)->sc_ro_mtx); - dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; - if (dst4->sin_family != AF_INET || - bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) { - /* cache route doesn't match */ - dst4->sin_family = AF_INET; - dst4->sin_len = sizeof(struct sockaddr_in); - bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr)); - if (sc->sc_ro.ro_rt) { - RTFREE(sc->sc_ro.ro_rt); - sc->sc_ro.ro_rt = NULL; - } - } - - if (sc->sc_ro.ro_rt == NULL) { - rtalloc_fib(&sc->sc_ro, sc->sc_fibnum); - if (sc->sc_ro.ro_rt == NULL) { - m_freem(m); - mtx_unlock(&(sc)->sc_ro_mtx); - ifp->if_oerrors++; - return ENETUNREACH; - } - } - cached_route = &sc->sc_ro; - -sendit: M_SETFIB(m, sc->sc_fibnum); - ifp->if_opackets++; - error = ip_output(m, NULL, cached_route, 0, NULL, NULL); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + error = ip_output(m, NULL, NULL, 0, NULL, NULL); - if (cached_route != NULL) - mtx_unlock(&(sc)->sc_ro_mtx); return error; } static int -isrfc1918addr(in) - struct in_addr *in; +isrfc1918addr(struct in_addr *in) { /* * returns 1 if private address range: @@ -599,11 +523,9 @@ isrfc1918addr(in) } static int -stf_checkaddr4(sc, in, inifp) - struct stf_softc *sc; - struct in_addr *in; - struct ifnet *inifp; /* incoming interface */ +stf_checkaddr4(struct stf_softc *sc, struct in_addr *in, struct ifnet *inifp) { + struct rm_priotracker in_ifa_tracker; struct in_ifaddr *ia4; /* @@ -627,54 +549,35 @@ stf_checkaddr4(sc, in, inifp) /* * reject packets with broadcast */ - IN_IFADDR_RLOCK(); - for (ia4 = TAILQ_FIRST(&V_in_ifaddrhead); - ia4; - ia4 = TAILQ_NEXT(ia4, ia_link)) - { + IN_IFADDR_RLOCK(&in_ifa_tracker); + TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { - IN_IFADDR_RUNLOCK(); + IN_IFADDR_RUNLOCK(&in_ifa_tracker); return -1; } } - IN_IFADDR_RUNLOCK(); + IN_IFADDR_RUNLOCK(&in_ifa_tracker); /* * perform ingress filter */ if (sc && (STF2IFP(sc)->if_flags & IFF_LINK2) == 0 && inifp) { - struct sockaddr_in sin; - struct rtentry *rt; - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = *in; - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, - 0UL, sc->sc_fibnum); - if (!rt || rt->rt_ifp != inifp) { -#if 0 - log(LOG_WARNING, "%s: packet from 0x%x dropped " - "due to ingress filter\n", if_name(STF2IFP(sc)), - (u_int32_t)ntohl(sin.sin_addr.s_addr)); -#endif - if (rt) - RTFREE_LOCKED(rt); - return -1; - } - RTFREE_LOCKED(rt); + struct nhop4_basic nh4; + + if (fib4_lookup_nh_basic(sc->sc_fibnum, *in, 0, 0, &nh4) != 0) + return (-1); + + if (nh4.nh_ifp != inifp) + return (-1); } return 0; } static int -stf_checkaddr6(sc, in6, inifp) - struct stf_softc *sc; - struct in6_addr *in6; - struct ifnet *inifp; /* incoming interface */ +stf_checkaddr6(struct stf_softc *sc, struct in6_addr *in6, struct ifnet *inifp) { /* * check 6to4 addresses @@ -697,23 +600,23 @@ stf_checkaddr6(sc, in6, inifp) return 0; } -void -in_stf_input(m, off) - struct mbuf *m; - int off; +static int +in_stf_input(struct mbuf **mp, int *offp, int proto) { - int proto; struct stf_softc *sc; struct ip *ip; struct ip6_hdr *ip6; + struct mbuf *m; u_int8_t otos, itos; struct ifnet *ifp; + int off; - proto = mtod(m, struct ip *)->ip_p; + m = *mp; + off = *offp; if (proto != IPPROTO_IPV6) { m_freem(m); - return; + return (IPPROTO_DONE); } ip = mtod(m, struct ip *); @@ -722,7 +625,7 @@ in_stf_input(m, off) if (sc == NULL || (STF2IFP(sc)->if_flags & IFF_UP) == 0) { m_freem(m); - return; + return (IPPROTO_DONE); } ifp = STF2IFP(sc); @@ -738,7 +641,7 @@ in_stf_input(m, off) if (stf_checkaddr4(sc, &ip->ip_dst, NULL) < 0 || stf_checkaddr4(sc, &ip->ip_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); - return; + return (IPPROTO_DONE); } otos = ip->ip_tos; @@ -747,7 +650,7 @@ in_stf_input(m, off) if (m->m_len < sizeof(*ip6)) { m = m_pullup(m, sizeof(*ip6)); if (!m) - return; + return (IPPROTO_DONE); } ip6 = mtod(m, struct ip6_hdr *); @@ -758,7 +661,7 @@ in_stf_input(m, off) if (stf_checkaddr6(sc, &ip6->ip6_dst, NULL) < 0 || stf_checkaddr6(sc, &ip6->ip6_src, m->m_pkthdr.rcvif) < 0) { m_freem(m); - return; + return (IPPROTO_DONE); } itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; @@ -789,28 +692,15 @@ in_stf_input(m, off) * See net/if_gif.c for possible issues with packet processing * reorder due to extra queueing. */ - ifp->if_ipackets++; - ifp->if_ibytes += m->m_pkthdr.len; + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); M_SETFIB(m, ifp->if_fib); netisr_dispatch(NETISR_IPV6, m); -} - -/* ARGSUSED */ -static void -stf_rtrequest(cmd, rt, info) - int cmd; - struct rtentry *rt; - struct rt_addrinfo *info; -{ - RT_LOCK_ASSERT(rt); - rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; + return (IPPROTO_DONE); } static int -stf_ioctl(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; +stf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifaddr *ifa; struct ifreq *ifr; @@ -837,7 +727,6 @@ stf_ioctl(ifp, cmd, data) break; } - ifa->ifa_rtrequest = stf_rtrequest; ifp->if_flags |= IFF_UP; break; |