version 1.87, 2017/01/06 03:25:13 |
version 1.87.8.6, 2019/09/24 18:27:10 |
Line 67 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 67 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <net/net_osdep.h> |
#include <net/net_osdep.h> |
|
|
static int gif_validate4(const struct ip *, struct gif_softc *, |
static int gif_validate4(const struct ip *, struct gif_variant *, |
struct ifnet *); |
struct ifnet *); |
|
|
int ip_gif_ttl = GIF_TTL; |
int ip_gif_ttl = GIF_TTL; |
Line 79 static const struct encapsw in_gif_encap |
|
Line 79 static const struct encapsw in_gif_encap |
|
} |
} |
}; |
}; |
|
|
int |
static int |
in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) |
in_gif_output(struct gif_variant *var, int family, struct mbuf *m) |
{ |
{ |
struct rtentry *rt; |
struct rtentry *rt; |
struct route *ro; |
struct gif_softc *sc; |
struct gif_softc *sc = ifp->if_softc; |
struct sockaddr_in *sin_src; |
struct sockaddr_in *sin_src = satosin(sc->gif_psrc); |
struct sockaddr_in *sin_dst; |
struct sockaddr_in *sin_dst = satosin(sc->gif_pdst); |
struct ifnet *ifp; |
|
struct route *ro_pc; |
|
kmutex_t *lock_pc; |
struct ip iphdr; /* capsule IP header, host byte ordered */ |
struct ip iphdr; /* capsule IP header, host byte ordered */ |
int proto, error; |
int proto, error; |
u_int8_t tos; |
u_int8_t tos; |
|
|
|
KASSERT(gif_heldref_variant(var)); |
|
|
|
sin_src = satosin(var->gv_psrc); |
|
sin_dst = satosin(var->gv_pdst); |
|
ifp = &var->gv_softc->gif_if; |
|
|
if (sin_src == NULL || sin_dst == NULL || |
if (sin_src == NULL || sin_dst == NULL || |
sin_src->sin_family != AF_INET || |
sin_src->sin_family != AF_INET || |
sin_dst->sin_family != AF_INET) { |
sin_dst->sin_family != AF_INET) { |
Line 166 in_gif_output(struct ifnet *ifp, int fam |
|
Line 174 in_gif_output(struct ifnet *ifp, int fam |
|
return ENOBUFS; |
return ENOBUFS; |
bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); |
bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); |
|
|
ro = percpu_getref(sc->gif_ro_percpu); |
sc = var->gv_softc; |
if ((rt = rtcache_lookup(ro, sc->gif_pdst)) == NULL) { |
if_tunnel_get_ro(sc->gif_ro_percpu, &ro_pc, &lock_pc); |
percpu_putref(sc->gif_ro_percpu); |
if ((rt = rtcache_lookup(ro_pc, var->gv_pdst)) == NULL) { |
|
if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); |
m_freem(m); |
m_freem(m); |
return ENETUNREACH; |
return ENETUNREACH; |
} |
} |
|
|
/* If the route constitutes infinite encapsulation, punt. */ |
/* If the route constitutes infinite encapsulation, punt. */ |
if (rt->rt_ifp == ifp) { |
if (rt->rt_ifp == ifp) { |
rtcache_unref(rt, ro); |
rtcache_unref(rt, ro_pc); |
rtcache_free(ro); |
rtcache_free(ro_pc); |
percpu_putref(sc->gif_ro_percpu); |
if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); |
m_freem(m); |
m_freem(m); |
return ENETUNREACH; /*XXX*/ |
return ENETUNREACH; /*XXX*/ |
} |
} |
rtcache_unref(rt, ro); |
rtcache_unref(rt, ro_pc); |
|
|
error = ip_output(m, NULL, ro, 0, NULL, NULL); |
error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); |
percpu_putref(sc->gif_ro_percpu); |
if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); |
return (error); |
return (error); |
} |
} |
|
|
void |
void |
in_gif_input(struct mbuf *m, int off, int proto) |
in_gif_input(struct mbuf *m, int off, int proto, void *eparg) |
{ |
{ |
struct ifnet *gifp = NULL; |
struct gif_softc *sc = eparg; |
|
struct ifnet *gifp = &sc->gif_if; |
const struct ip *ip; |
const struct ip *ip; |
int af; |
int af; |
u_int8_t otos; |
u_int8_t otos; |
|
|
ip = mtod(m, const struct ip *); |
KASSERT(sc != NULL); |
|
|
gifp = (struct ifnet *)encap_getarg(m); |
ip = mtod(m, const struct ip *); |
|
|
if (gifp == NULL || (gifp->if_flags & (IFF_UP|IFF_RUNNING)) |
gifp = &sc->gif_if; |
!= (IFF_UP|IFF_RUNNING)) { |
if ((gifp->if_flags & IFF_UP) == 0) { |
m_freem(m); |
m_freem(m); |
ip_statinc(IP_STAT_NOGIF); |
ip_statinc(IP_STAT_NOGIF); |
return; |
return; |
} |
} |
#ifndef GIF_ENCAPCHECK |
#ifndef GIF_ENCAPCHECK |
struct gif_softc *sc = (struct gif_softc *)gifp->if_softc; |
struct psref psref_var; |
|
struct gif_variant *var = gif_getref_variant(sc, &psref_var); |
/* other CPU do delete_tunnel */ |
/* other CPU do delete_tunnel */ |
if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { |
if (var->gv_psrc == NULL || var->gv_pdst == NULL) { |
|
gif_putref_variant(var, &psref_var); |
m_freem(m); |
m_freem(m); |
ip_statinc(IP_STAT_NOGIF); |
ip_statinc(IP_STAT_NOGIF); |
return; |
return; |
} |
} |
|
|
struct ifnet *rcvif; |
struct ifnet *rcvif; |
struct psref psref; |
struct psref psref_rcvif; |
rcvif = m_get_rcvif_psref(m, &psref); |
rcvif = m_get_rcvif_psref(m, &psref_rcvif); |
if (!gif_validate4(ip, sc, rcvif)) { |
if (!gif_validate4(ip, var, rcvif)) { |
m_put_rcvif_psref(rcvif, &psref); |
m_put_rcvif_psref(rcvif, &psref_rcvif); |
|
gif_putref_variant(var, &psref_var); |
m_freem(m); |
m_freem(m); |
ip_statinc(IP_STAT_NOGIF); |
ip_statinc(IP_STAT_NOGIF); |
return; |
return; |
} |
} |
m_put_rcvif_psref(rcvif, &psref); |
m_put_rcvif_psref(rcvif, &psref_rcvif); |
|
gif_putref_variant(var, &psref_var); |
#endif |
#endif |
otos = ip->ip_tos; |
otos = ip->ip_tos; |
m_adj(m, off); |
m_adj(m, off); |
Line 281 in_gif_input(struct mbuf *m, int off, in |
|
Line 295 in_gif_input(struct mbuf *m, int off, in |
|
* validate outer address. |
* validate outer address. |
*/ |
*/ |
static int |
static int |
gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) |
gif_validate4(const struct ip *ip, struct gif_variant *var, struct ifnet *ifp) |
{ |
{ |
struct sockaddr_in *src, *dst; |
struct sockaddr_in *src, *dst; |
struct in_ifaddr *ia4; |
int ret; |
int s; |
|
|
|
src = satosin(sc->gif_psrc); |
src = satosin(var->gv_psrc); |
dst = satosin(sc->gif_pdst); |
dst = satosin(var->gv_pdst); |
|
|
/* check for address match */ |
ret = in_tunnel_validate(ip, src->sin_addr, dst->sin_addr); |
if (src->sin_addr.s_addr != ip->ip_dst.s_addr || |
if (ret == 0) |
dst->sin_addr.s_addr != ip->ip_src.s_addr) |
|
return 0; |
return 0; |
|
|
/* martian filters on outer source - NOT done in ip_input! */ |
|
if (IN_MULTICAST(ip->ip_src.s_addr)) |
|
return 0; |
|
switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { |
|
case 0: case 127: case 255: |
|
return 0; |
|
} |
|
/* reject packets with broadcast on source */ |
|
s = pserialize_read_enter(); |
|
IN_ADDRLIST_READER_FOREACH(ia4) { |
|
if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) |
|
continue; |
|
if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { |
|
pserialize_read_exit(s); |
|
return 0; |
|
} |
|
} |
|
pserialize_read_exit(s); |
|
|
|
/* ingress filters on outer source */ |
/* ingress filters on outer source */ |
if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { |
if ((var->gv_softc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { |
union { |
union { |
struct sockaddr sa; |
struct sockaddr sa; |
struct sockaddr_in sin; |
struct sockaddr_in sin; |
Line 327 gif_validate4(const struct ip *ip, struc |
|
Line 320 gif_validate4(const struct ip *ip, struc |
|
if (rt == NULL || rt->rt_ifp != ifp) { |
if (rt == NULL || rt->rt_ifp != ifp) { |
#if 0 |
#if 0 |
log(LOG_WARNING, "%s: packet from 0x%x dropped " |
log(LOG_WARNING, "%s: packet from 0x%x dropped " |
"due to ingress filter\n", if_name(&sc->gif_if), |
"due to ingress filter\n", |
|
if_name(&var->gv_softc->gif_if), |
(u_int32_t)ntohl(u.sin.sin_addr.s_addr)); |
(u_int32_t)ntohl(u.sin.sin_addr.s_addr)); |
#endif |
#endif |
if (rt != NULL) |
if (rt != NULL) |
Line 337 gif_validate4(const struct ip *ip, struc |
|
Line 331 gif_validate4(const struct ip *ip, struc |
|
rt_unref(rt); |
rt_unref(rt); |
} |
} |
|
|
return 32 * 2; |
return ret; |
} |
} |
|
|
#ifdef GIF_ENCAPCHECK |
#ifdef GIF_ENCAPCHECK |
Line 346 gif_validate4(const struct ip *ip, struc |
|
Line 340 gif_validate4(const struct ip *ip, struc |
|
* matched the physical addr family. see gif_encapcheck(). |
* matched the physical addr family. see gif_encapcheck(). |
*/ |
*/ |
int |
int |
gif_encapcheck4(struct mbuf *m, int off, int proto, void *arg) |
gif_encapcheck4(struct mbuf *m, int off, int proto, struct gif_variant *var) |
{ |
{ |
struct ip ip; |
struct ip ip; |
struct gif_softc *sc; |
|
struct ifnet *ifp = NULL; |
struct ifnet *ifp = NULL; |
int r; |
int r; |
struct psref psref; |
struct psref psref; |
|
|
/* sanity check done in caller */ |
|
sc = arg; |
|
|
|
m_copydata(m, 0, sizeof(ip), &ip); |
m_copydata(m, 0, sizeof(ip), &ip); |
if ((m->m_flags & M_PKTHDR) != 0) |
if ((m->m_flags & M_PKTHDR) != 0) |
ifp = m_get_rcvif_psref(m, &psref); |
ifp = m_get_rcvif_psref(m, &psref); |
|
|
r = gif_validate4(&ip, sc, ifp); |
r = gif_validate4(&ip, var, ifp); |
|
|
m_put_rcvif_psref(ifp, &psref); |
m_put_rcvif_psref(ifp, &psref); |
return r; |
return r; |
Line 369 gif_encapcheck4(struct mbuf *m, int off, |
|
Line 360 gif_encapcheck4(struct mbuf *m, int off, |
|
#endif |
#endif |
|
|
int |
int |
in_gif_attach(struct gif_softc *sc) |
in_gif_attach(struct gif_variant *var) |
{ |
{ |
#ifndef GIF_ENCAPCHECK |
#ifndef GIF_ENCAPCHECK |
struct sockaddr_in mask4; |
struct sockaddr_in mask4; |
Line 378 in_gif_attach(struct gif_softc *sc) |
|
Line 369 in_gif_attach(struct gif_softc *sc) |
|
mask4.sin_len = sizeof(struct sockaddr_in); |
mask4.sin_len = sizeof(struct sockaddr_in); |
mask4.sin_addr.s_addr = ~0; |
mask4.sin_addr.s_addr = ~0; |
|
|
if (!sc->gif_psrc || !sc->gif_pdst) |
if (!var->gv_psrc || !var->gv_pdst) |
return EINVAL; |
return EINVAL; |
sc->encap_cookie4 = encap_attach(AF_INET, -1, sc->gif_psrc, |
var->gv_encap_cookie4 = encap_attach(AF_INET, -1, var->gv_psrc, |
(struct sockaddr *)&mask4, sc->gif_pdst, (struct sockaddr *)&mask4, |
(struct sockaddr *)&mask4, var->gv_pdst, (struct sockaddr *)&mask4, |
&in_gif_encapsw, sc); |
&in_gif_encapsw, var->gv_softc); |
#else |
#else |
sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, |
var->gv_encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, |
&in_gif_encapsw, sc); |
&in_gif_encapsw, var->gv_softc); |
#endif |
#endif |
if (sc->encap_cookie4 == NULL) |
if (var->gv_encap_cookie4 == NULL) |
return EEXIST; |
return EEXIST; |
return 0; |
|
} |
|
|
|
int |
|
in_gif_detach(struct gif_softc *sc) |
|
{ |
|
int error; |
|
|
|
error = in_gif_pause(sc); |
|
|
|
percpu_foreach(sc->gif_ro_percpu, gif_rtcache_free_pc, NULL); |
|
|
|
return error; |
var->gv_output = in_gif_output; |
|
return 0; |
} |
} |
|
|
int |
int |
in_gif_pause(struct gif_softc *sc) |
in_gif_detach(struct gif_variant *var) |
{ |
{ |
int error; |
int error; |
|
struct gif_softc *sc = var->gv_softc; |
|
|
error = encap_detach(sc->encap_cookie4); |
error = encap_detach(var->gv_encap_cookie4); |
if (error == 0) |
if (error == 0) |
sc->encap_cookie4 = NULL; |
var->gv_encap_cookie4 = NULL; |
|
|
|
if_tunnel_ro_percpu_rtcache_free(sc->gif_ro_percpu); |
|
|
return error; |
return error; |
} |
} |