summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if_stf.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net/if_stf.c')
-rw-r--r--freebsd/sys/net/if_stf.c279
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;