From a1772de5f163ff8f66c1211798244a0509220168 Mon Sep 17 00:00:00 2001 From: ae Date: Tue, 23 Dec 2014 16:33:44 +0000 Subject: [PATCH] MFC r273087 (with modifications): Overhaul if_gif(4): o convert to if_transmit; o use rmlock to protect access to gif_softc; o use sx lock to protect from concurrent ioctls; o remove a lot of unneeded and duplicated code; o remove cached route support (it won't work with concurrent io); o style fixes. MFC r273090: Move memset under ifdef INET6. MFC r273091: Add more ifdefs. SIOC*_IN6 are defined only with INET6. MFC r273121: Add inet/inet6 to the dependency list. Without them if_gif is useless. MFC r273209 by bz: After r273087,r273090,r273091,r273121 changes to gif(4) try to fix NOIP builds for real. MFC r273587: Remove redundant check and m_pullup() call. git-svn-id: svn://svn.freebsd.org/base/stable/10@276149 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- share/man/man4/gif.4 | 12 +- sys/conf/files | 5 +- sys/net/if_gif.c | 943 +++++++++++++++++++++-------------------- sys/net/if_gif.h | 62 ++- sys/netinet/in_gif.c | 361 ++++------------ sys/netinet/in_gif.h | 7 +- sys/netinet6/in6_gif.c | 313 ++------------ sys/netinet6/in6_gif.h | 5 +- 8 files changed, 635 insertions(+), 1073 deletions(-) diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4 index 453b4bdb1..27ee61b4f 100644 --- a/share/man/man4/gif.4 +++ b/share/man/man4/gif.4 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 1, 2011 +.Dd October 14, 2014 .Dt GIF 4 .Os .Sh NAME @@ -160,16 +160,6 @@ routed network. It can be turned off by .Dv IFF_LINK2 bit. -.Ss Route caching -Processing each packet requires two route lookups: first on the -packet itself, and second on the tunnel destination. -This second route can be cached, increasing tunnel performance. -However, in a dynamically routed network, the tunnel will stick -to the cached route, ignoring routing table updates. -Route caching can be enabled with the -.Dv IFF_LINK0 -flag. -.\" .Ss Miscellaneous By default, .Nm diff --git a/sys/conf/files b/sys/conf/files index 2b97f6899..88d32c047 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3175,7 +3175,8 @@ net/if_ethersubr.c optional ether net/if_faith.c optional faith net/if_fddisubr.c optional fddi net/if_fwsubr.c optional fwip -net/if_gif.c optional gif | netgraph_gif +net/if_gif.c optional gif inet | gif inet6 | \ + netgraph_gif inet | netgraph_gif inet6 net/if_gre.c optional gre inet net/if_iso88025subr.c optional token net/if_lagg.c optional lagg @@ -3310,7 +3311,7 @@ netgraph/ng_ether.c optional netgraph_ether netgraph/ng_ether_echo.c optional netgraph_ether_echo netgraph/ng_fec.c optional netgraph_fec netgraph/ng_frame_relay.c optional netgraph_frame_relay -netgraph/ng_gif.c optional netgraph_gif +netgraph/ng_gif.c optional netgraph_gif inet6 | netgraph_gif inet netgraph/ng_gif_demux.c optional netgraph_gif_demux netgraph/ng_hole.c optional netgraph_hole netgraph/ng_iface.c optional netgraph_iface diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 4bec9b67d..a98fb19c8 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,6 +1,3 @@ -/* $FreeBSD$ */ -/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ - /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -28,8 +25,13 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */ +#include +__FBSDID("$FreeBSD$"); + #include "opt_inet.h" #include "opt_inet6.h" @@ -37,11 +39,14 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include @@ -53,6 +58,7 @@ #include #include +#include #include #include #include @@ -63,6 +69,7 @@ #include #include #include +#include #ifdef INET #include #include @@ -75,6 +82,7 @@ #endif #include #include +#include #include #include #include @@ -98,6 +106,8 @@ static VNET_DEFINE(struct mtx, gif_mtx); static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); static VNET_DEFINE(LIST_HEAD(, gif_softc), gif_softc_list); #define V_gif_softc_list VNET(gif_softc_list) +static struct sx gif_ioctl_sx; +SX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl"); #define GIF_LIST_LOCK_INIT(x) mtx_init(&V_gif_mtx, "gif_mtx", \ NULL, MTX_DEF) @@ -110,7 +120,12 @@ void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); void (*ng_gif_attach_p)(struct ifnet *ifp); void (*ng_gif_detach_p)(struct ifnet *ifp); -static void gif_start(struct ifnet *); +static int gif_set_tunnel(struct ifnet *, struct sockaddr *, + struct sockaddr *); +static void gif_delete_tunnel(struct ifnet *); +static int gif_ioctl(struct ifnet *, u_long, caddr_t); +static int gif_transmit(struct ifnet *, struct mbuf *); +static void gif_qflush(struct ifnet *); static int gif_clone_create(struct if_clone *, int, caddr_t); static void gif_clone_destroy(struct ifnet *); static VNET_DEFINE(struct if_clone *, gif_cloner); @@ -167,19 +182,10 @@ gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); sc->gif_fibnum = curthread->td_proc->p_fibnum; GIF2IFP(sc) = if_alloc(IFT_GIF); - if (GIF2IFP(sc) == NULL) { - free(sc, M_GIF); - return (ENOSPC); - } - GIF_LOCK_INIT(sc); - GIF2IFP(sc)->if_softc = sc; if_initname(GIF2IFP(sc), gifname, unit); - sc->encap_cookie4 = sc->encap_cookie6 = NULL; - sc->gif_options = 0; - GIF2IFP(sc)->if_addrlen = 0; GIF2IFP(sc)->if_mtu = GIF_MTU; GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; @@ -188,9 +194,9 @@ gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) GIF2IFP(sc)->if_flags |= IFF_LINK2; #endif GIF2IFP(sc)->if_ioctl = gif_ioctl; - GIF2IFP(sc)->if_start = gif_start; + GIF2IFP(sc)->if_transmit = gif_transmit; + GIF2IFP(sc)->if_qflush = gif_qflush; GIF2IFP(sc)->if_output = gif_output; - GIF2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen; if_attach(GIF2IFP(sc)); bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); if (ng_gif_attach_p != NULL) @@ -199,44 +205,29 @@ gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) GIF_LIST_LOCK(); LIST_INSERT_HEAD(&V_gif_softc_list, sc, gif_list); GIF_LIST_UNLOCK(); - return (0); } static void gif_clone_destroy(struct ifnet *ifp) { -#if defined(INET) || defined(INET6) - int err; -#endif - struct gif_softc *sc = ifp->if_softc; + struct gif_softc *sc; + sx_xlock(&gif_ioctl_sx); + sc = ifp->if_softc; + gif_delete_tunnel(ifp); GIF_LIST_LOCK(); LIST_REMOVE(sc, gif_list); GIF_LIST_UNLOCK(); - - gif_delete_tunnel(ifp); -#ifdef INET6 - if (sc->encap_cookie6 != NULL) { - err = encap_detach(sc->encap_cookie6); - KASSERT(err == 0, ("Unexpected error detaching encap_cookie6")); - } -#endif -#ifdef INET - if (sc->encap_cookie4 != NULL) { - err = encap_detach(sc->encap_cookie4); - KASSERT(err == 0, ("Unexpected error detaching encap_cookie4")); - } -#endif - if (ng_gif_detach_p != NULL) (*ng_gif_detach_p)(ifp); bpfdetach(ifp); if_detach(ifp); - if_free(ifp); + ifp->if_softc = NULL; + sx_xunlock(&gif_ioctl_sx); + if_free(ifp); GIF_LOCK_DESTROY(sc); - free(sc, M_GIF); } @@ -288,162 +279,191 @@ MODULE_VERSION(if_gif, 1); int gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { - struct ip ip; + GIF_RLOCK_TRACKER; struct gif_softc *sc; + int ret; + uint8_t ver; sc = (struct gif_softc *)arg; - if (sc == NULL) - return 0; + if (sc == NULL || (GIF2IFP(sc)->if_flags & IFF_UP) == 0) + return (0); - if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) - return 0; + ret = 0; + GIF_RLOCK(sc); /* no physical address */ - if (!sc->gif_psrc || !sc->gif_pdst) - return 0; + if (sc->gif_family == 0) + goto done; switch (proto) { #ifdef INET case IPPROTO_IPV4: - break; #endif #ifdef INET6 case IPPROTO_IPV6: - break; #endif case IPPROTO_ETHERIP: break; - default: - return 0; + goto done; } /* Bail on short packets */ - if (m->m_pkthdr.len < sizeof(ip)) - return 0; - - m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); + if (m->m_pkthdr.len < sizeof(struct ip)) + goto done; - switch (ip.ip_v) { + m_copydata(m, 0, 1, &ver); + switch (ver >> 4) { #ifdef INET case 4: - if (sc->gif_psrc->sa_family != AF_INET || - sc->gif_pdst->sa_family != AF_INET) - return 0; - return gif_encapcheck4(m, off, proto, arg); + if (sc->gif_family != AF_INET) + goto done; + ret = in_gif_encapcheck(m, off, proto, arg); + break; #endif #ifdef INET6 case 6: if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) - return 0; - if (sc->gif_psrc->sa_family != AF_INET6 || - sc->gif_pdst->sa_family != AF_INET6) - return 0; - return gif_encapcheck6(m, off, proto, arg); + goto done; + if (sc->gif_family != AF_INET6) + goto done; + ret = in6_gif_encapcheck(m, off, proto, arg); + break; #endif - default: - return 0; } +done: + GIF_RUNLOCK(sc); + return (ret); } + +static int +gif_transmit(struct ifnet *ifp, struct mbuf *m) +{ + struct gif_softc *sc; + struct etherip_header *eth; #ifdef INET -#define GIF_HDR_LEN (ETHER_HDR_LEN + sizeof (struct ip)) + struct ip *ip; #endif #ifdef INET6 -#define GIF_HDR_LEN6 (ETHER_HDR_LEN + sizeof (struct ip6_hdr)) + struct ip6_hdr *ip6; + uint32_t t; #endif - -static void -gif_start(struct ifnet *ifp) -{ - struct gif_softc *sc; - struct mbuf *m; uint32_t af; - int error = 0; + uint8_t proto, ecn; + int error; + error = ENETDOWN; sc = ifp->if_softc; - GIF_LOCK(sc); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { - - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == 0) - break; - -#ifdef ALTQ - /* Take out those altq bytes we add in gif_output */ + if (sc->gif_family == 0) { + m_freem(m); + goto err; + } + /* Now pull back the af that we stashed in the csum_data. */ + af = m->m_pkthdr.csum_data; + BPF_MTAP2(ifp, &af, sizeof(af), m); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); + M_SETFIB(m, sc->gif_fibnum); + /* inner AF-specific encapsulation */ + ecn = 0; + switch (af) { #ifdef INET - if (sc->gif_psrc->sa_family == AF_INET) - m->m_pkthdr.len -= GIF_HDR_LEN; + case AF_INET: + proto = IPPROTO_IPV4; + if (m->m_len < sizeof(struct ip)) + m = m_pullup(m, sizeof(struct ip)); + if (m == NULL) { + error = ENOBUFS; + goto err; + } + ip = mtod(m, struct ip *); + ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: + ECN_NOCARE, &ecn, &ip->ip_tos); + break; #endif #ifdef INET6 - if (sc->gif_psrc->sa_family == AF_INET6) - m->m_pkthdr.len -= GIF_HDR_LEN6; -#endif + case AF_INET6: + proto = IPPROTO_IPV6; + if (m->m_len < sizeof(struct ip6_hdr)) + m = m_pullup(m, sizeof(struct ip6_hdr)); + if (m == NULL) { + error = ENOBUFS; + goto err; + } + t = 0; + ip6 = mtod(m, struct ip6_hdr *); + ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: + ECN_NOCARE, &t, &ip6->ip6_flow); + ecn = (ntohl(t) >> 20) & 0xff; + break; #endif - /* - * Now pull back the af that we - * stashed in the csum_data. - */ - af = m->m_pkthdr.csum_data; - - /* override to IPPROTO_ETHERIP for bridged traffic */ - if (ifp->if_bridge) - af = AF_LINK; - - BPF_MTAP2(ifp, &af, sizeof(af), m); - ifp->if_opackets++; - -/* Done by IFQ_HANDOFF */ -/* ifp->if_obytes += m->m_pkthdr.len;*/ - - M_SETFIB(m, sc->gif_fibnum); - /* inner AF-specific encapsulation */ - /* XXX should we check if our outer source is legal? */ - /* dispatch to output logic based on outer AF */ - switch (sc->gif_psrc->sa_family) { + case AF_LINK: + proto = IPPROTO_ETHERIP; + M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); + if (m == NULL) { + error = ENOBUFS; + goto err; + } + eth = mtod(m, struct etherip_header *); + eth->eip_resvh = 0; + if ((sc->gif_options & GIF_SEND_REVETHIP) != 0) { + eth->eip_ver = 0; + eth->eip_resvl = ETHERIP_VERSION; + } else { + eth->eip_ver = ETHERIP_VERSION; + eth->eip_resvl = 0; + } + break; + default: + error = EAFNOSUPPORT; + m_freem(m); + goto err; + } + /* XXX should we check if our outer source is legal? */ + /* dispatch to output logic based on outer AF */ + switch (sc->gif_family) { #ifdef INET - case AF_INET: - error = in_gif_output(ifp, af, m); - break; + case AF_INET: + error = in_gif_output(ifp, m, proto, ecn); + break; #endif #ifdef INET6 - case AF_INET6: - error = in6_gif_output(ifp, af, m); - break; + case AF_INET6: + error = in6_gif_output(ifp, m, proto, ecn); + break; #endif - default: - m_freem(m); - error = ENETDOWN; - } - if (error) - ifp->if_oerrors++; - + default: + m_freem(m); } - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - GIF_UNLOCK(sc); - return; +err: + if (error) + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + return (error); +} + +static void +gif_qflush(struct ifnet *ifp __unused) +{ + } int gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) { - struct gif_softc *sc = ifp->if_softc; struct m_tag *mtag; - int error = 0; - int gif_called; uint32_t af; + int gif_called; + int error = 0; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); - if (error) { - m_freem(m); - goto end; - } + if (error) + goto err; #endif - if ((ifp->if_flags & IFF_MONITOR) != 0) { + if ((ifp->if_flags & IFF_MONITOR) != 0 || + (ifp->if_flags & IFF_UP) == 0) { error = ENETDOWN; - m_freem(m); - goto end; + goto err; } /* @@ -460,9 +480,8 @@ gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, log(LOG_NOTICE, "gif_output: loop detected on %s\n", (*(struct ifnet **)(mtag + 1))->if_xname); - m_freem(m); error = EIO; /* is there better errno? */ - goto end; + goto err; } mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag); gif_called++; @@ -471,73 +490,54 @@ gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, log(LOG_NOTICE, "gif_output: recursively called too many times(%d)\n", gif_called); - m_freem(m); error = EIO; /* is there better errno? */ - goto end; + goto err; } mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *), M_NOWAIT); if (mtag == NULL) { - m_freem(m); error = ENOMEM; - goto end; + goto err; } *(struct ifnet **)(mtag + 1) = ifp; m_tag_prepend(m, mtag); m->m_flags &= ~(M_BCAST|M_MCAST); - /* BPF writes need to be handled specially. */ if (dst->sa_family == AF_UNSPEC) bcopy(dst->sa_data, &af, sizeof(af)); else af = dst->sa_family; - /* - * Now save the af in the inbound pkt csum - * data, this is a cheat since we are using - * the inbound csum_data field to carry the - * af over to the gif_start() routine, avoiding - * using yet another mtag. - */ - m->m_pkthdr.csum_data = af; - if (!(ifp->if_flags & IFF_UP) || - sc->gif_psrc == NULL || sc->gif_pdst == NULL) { - m_freem(m); - error = ENETDOWN; - goto end; - } -#ifdef ALTQ - /* - * Make altq aware of the bytes we will add - * when we actually send it. - */ -#ifdef INET - if (sc->gif_psrc->sa_family == AF_INET) - m->m_pkthdr.len += GIF_HDR_LEN; -#endif -#ifdef INET6 - if (sc->gif_psrc->sa_family == AF_INET6) - m->m_pkthdr.len += GIF_HDR_LEN6; -#endif -#endif + if (ifp->if_bridge) + af = AF_LINK; /* - * Queue message on interface, update output statistics if - * successful, and start output if interface not yet active. + * Now save the af in the inbound pkt csum data, this is a cheat since + * we are using the inbound csum_data field to carry the af over to + * the gif_transmit() routine, avoiding using yet another mtag. */ - IFQ_HANDOFF(ifp, m, error); - end: - if (error) - ifp->if_oerrors++; + m->m_pkthdr.csum_data = af; + return (ifp->if_transmit(ifp, m)); +err: + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + m_freem(m); return (error); } void -gif_input(struct mbuf *m, int af, struct ifnet *ifp) +gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn) { - int isr, n; - struct gif_softc *sc; struct etherip_header *eip; +#ifdef INET + struct ip *ip; +#endif +#ifdef INET6 + struct ip6_hdr *ip6; + uint32_t t; +#endif + struct gif_softc *sc; struct ether_header *eh; struct ifnet *oldifp; + uint32_t gif_options; + int isr, n, af; if (ifp == NULL) { /* just in case */ @@ -545,21 +545,61 @@ gif_input(struct mbuf *m, int af, struct ifnet *ifp) return; } sc = ifp->if_softc; + gif_options = sc->gif_options; m->m_pkthdr.rcvif = ifp; m_clrprotoflags(m); + switch (proto) { +#ifdef INET + case IPPROTO_IPV4: + af = AF_INET; + if (m->m_len < sizeof(struct ip)) + m = m_pullup(m, sizeof(struct ip)); + if (m == NULL) + goto drop; + ip = mtod(m, struct ip *); + if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: + ECN_NOCARE, &ecn, &ip->ip_tos) == 0) { + m_freem(m); + goto drop; + } + break; +#endif +#ifdef INET6 + case IPPROTO_IPV6: + af = AF_INET6; + if (m->m_len < sizeof(struct ip6_hdr)) + m = m_pullup(m, sizeof(struct ip6_hdr)); + if (m == NULL) + goto drop; + t = htonl((uint32_t)ecn << 20); + ip6 = mtod(m, struct ip6_hdr *); + if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: + ECN_NOCARE, &t, &ip6->ip6_flow) == 0) { + m_freem(m); + goto drop; + } + break; +#endif + case IPPROTO_ETHERIP: + af = AF_LINK; + break; + default: + m_freem(m); + goto drop; + } #ifdef MAC mac_ifnet_create_mbuf(ifp, m); #endif if (bpf_peers_present(ifp->if_bpf)) { - u_int32_t af1 = af; + uint32_t af1 = af; bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); } if ((ifp->if_flags & IFF_MONITOR) != 0) { - 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_freem(m); return; } @@ -567,7 +607,7 @@ gif_input(struct mbuf *m, int af, struct ifnet *ifp) if (ng_gif_input_p != NULL) { (*ng_gif_input_p)(ifp, &m, af); if (m == NULL) - return; + goto drop; } /* @@ -594,33 +634,23 @@ gif_input(struct mbuf *m, int af, struct ifnet *ifp) #endif case AF_LINK: n = sizeof(struct etherip_header) + sizeof(struct ether_header); - if (n > m->m_len) { + if (n > m->m_len) m = m_pullup(m, n); - if (m == NULL) { - ifp->if_ierrors++; - return; - } - } - + if (m == NULL) + goto drop; eip = mtod(m, struct etherip_header *); - /* + /* * GIF_ACCEPT_REVETHIP (enabled by default) intentionally * accepts an EtherIP packet with revered version field in * the header. This is a knob for backward compatibility * with FreeBSD 7.2R or prior. */ - if (sc->gif_options & GIF_ACCEPT_REVETHIP) { - if (eip->eip_resvl != ETHERIP_VERSION - && eip->eip_ver != ETHERIP_VERSION) { + if (eip->eip_ver != ETHERIP_VERSION) { + if ((gif_options & GIF_ACCEPT_REVETHIP) == 0 || + eip->eip_resvl != ETHERIP_VERSION) { /* discard unknown versions */ m_freem(m); - return; - } - } else { - if (eip->eip_ver != ETHERIP_VERSION) { - /* discard unknown versions */ - m_freem(m); - return; + goto drop; } } m_adj(m, sizeof(struct etherip_header)); @@ -636,7 +666,7 @@ gif_input(struct mbuf *m, int af, struct ifnet *ifp) m->m_flags |= M_BCAST; else m->m_flags |= M_MCAST; - ifp->if_imcasts++; + if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); } BRIDGE_INPUT(ifp, m); @@ -661,53 +691,61 @@ gif_input(struct mbuf *m, int af, struct ifnet *ifp) return; } - 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(isr, m); + return; +drop: + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); } /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */ int gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - struct gif_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq*)data; - int error = 0, size; - u_int options; + GIF_RLOCK_TRACKER; + struct ifreq *ifr = (struct ifreq*)data; struct sockaddr *dst, *src; -#ifdef SIOCSIFMTU /* xxx */ - u_long mtu; + struct gif_softc *sc; +#ifdef INET + struct sockaddr_in *sin = NULL; +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6 = NULL; #endif + u_int options; + int error; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; - break; - case SIOCADDMULTI: case SIOCDELMULTI: - break; - -#ifdef SIOCSIFMTU /* xxx */ case SIOCGIFMTU: - break; - + case SIOCSIFFLAGS: + return (0); case SIOCSIFMTU: - mtu = ifr->ifr_mtu; - if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) + if (ifr->ifr_mtu < GIF_MTU_MIN || + ifr->ifr_mtu > GIF_MTU_MAX) return (EINVAL); - ifp->if_mtu = mtu; - break; -#endif /* SIOCSIFMTU */ - -#ifdef INET + else + ifp->if_mtu = ifr->ifr_mtu; + return (0); + } + sx_xlock(&gif_ioctl_sx); + sc = ifp->if_softc; + if (sc == NULL) { + error = ENXIO; + goto bad; + } + error = 0; + switch (cmd) { case SIOCSIFPHYADDR: -#endif #ifdef INET6 case SIOCSIFPHYADDR_IN6: -#endif /* INET6 */ - case SIOCSLIFPHYADDR: +#endif + error = EINVAL; switch (cmd) { #ifdef INET case SIOCSIFPHYADDR: @@ -725,199 +763,172 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) &(((struct in6_aliasreq *)data)->ifra_dstaddr); break; #endif - case SIOCSLIFPHYADDR: - src = (struct sockaddr *) - &(((struct if_laddrreq *)data)->addr); - dst = (struct sockaddr *) - &(((struct if_laddrreq *)data)->dstaddr); - break; default: - return EINVAL; + goto bad; } - /* sa_family must be equal */ - if (src->sa_family != dst->sa_family) - return EINVAL; + if (src->sa_family != dst->sa_family || + src->sa_len != dst->sa_len) + goto bad; /* validate sa_len */ switch (src->sa_family) { #ifdef INET case AF_INET: if (src->sa_len != sizeof(struct sockaddr_in)) - return EINVAL; + goto bad; break; #endif #ifdef INET6 case AF_INET6: if (src->sa_len != sizeof(struct sockaddr_in6)) - return EINVAL; - break; -#endif - default: - return EAFNOSUPPORT; - } - switch (dst->sa_family) { -#ifdef INET - case AF_INET: - if (dst->sa_len != sizeof(struct sockaddr_in)) - return EINVAL; - break; -#endif -#ifdef INET6 - case AF_INET6: - if (dst->sa_len != sizeof(struct sockaddr_in6)) - return EINVAL; + goto bad; break; #endif default: - return EAFNOSUPPORT; + error = EAFNOSUPPORT; + goto bad; } - /* check sa_family looks sane for the cmd */ + error = EAFNOSUPPORT; switch (cmd) { +#ifdef INET case SIOCSIFPHYADDR: if (src->sa_family == AF_INET) break; - return EAFNOSUPPORT; + goto bad; +#endif #ifdef INET6 case SIOCSIFPHYADDR_IN6: if (src->sa_family == AF_INET6) break; - return EAFNOSUPPORT; -#endif /* INET6 */ - case SIOCSLIFPHYADDR: - /* checks done in the above */ - break; + goto bad; +#endif } - - error = gif_set_tunnel(GIF2IFP(sc), src, dst); + error = EADDRNOTAVAIL; + switch (src->sa_family) { +#ifdef INET + case AF_INET: + if (satosin(src)->sin_addr.s_addr == INADDR_ANY || + satosin(dst)->sin_addr.s_addr == INADDR_ANY) + goto bad; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr) + || + IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr)) + goto bad; + /* + * Check validity of the scope zone ID of the + * addresses, and convert it into the kernel + * internal form if necessary. + */ + error = sa6_embedscope(satosin6(src), 0); + if (error != 0) + goto bad; + error = sa6_embedscope(satosin6(dst), 0); + if (error != 0) + goto bad; +#endif + }; + error = gif_set_tunnel(ifp, src, dst); break; - -#ifdef SIOCDIFPHYADDR case SIOCDIFPHYADDR: - gif_delete_tunnel(GIF2IFP(sc)); + gif_delete_tunnel(ifp); break; -#endif - case SIOCGIFPSRCADDR: + case SIOCGIFPDSTADDR: #ifdef INET6 case SIOCGIFPSRCADDR_IN6: -#endif /* INET6 */ - if (sc->gif_psrc == NULL) { + case SIOCGIFPDSTADDR_IN6: +#endif + if (sc->gif_family == 0) { error = EADDRNOTAVAIL; - goto bad; + break; } - src = sc->gif_psrc; + GIF_RLOCK(sc); switch (cmd) { #ifdef INET case SIOCGIFPSRCADDR: - dst = &ifr->ifr_addr; - size = sizeof(ifr->ifr_addr); + case SIOCGIFPDSTADDR: + if (sc->gif_family != AF_INET) { + error = EADDRNOTAVAIL; + break; + } + sin = (struct sockaddr_in *)&ifr->ifr_addr; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); break; -#endif /* INET */ +#endif #ifdef INET6 case SIOCGIFPSRCADDR_IN6: - dst = (struct sockaddr *) + case SIOCGIFPDSTADDR_IN6: + if (sc->gif_family != AF_INET6) { + error = EADDRNOTAVAIL; + break; + } + sin6 = (struct sockaddr_in6 *) &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(((struct in6_ifreq *)data)->ifr_addr); + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); break; -#endif /* INET6 */ +#endif default: - error = EADDRNOTAVAIL; - goto bad; - } - if (src->sa_len > size) - return EINVAL; - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); -#ifdef INET6 - if (dst->sa_family == AF_INET6) { - error = sa6_recoverscope((struct sockaddr_in6 *)dst); - if (error != 0) - return (error); + error = EAFNOSUPPORT; } + if (error == 0) { + switch (cmd) { +#ifdef INET + case SIOCGIFPSRCADDR: + sin->sin_addr = sc->gif_iphdr->ip_src; + break; + case SIOCGIFPDSTADDR: + sin->sin_addr = sc->gif_iphdr->ip_dst; + break; #endif - break; - - case SIOCGIFPDSTADDR: #ifdef INET6 - case SIOCGIFPDSTADDR_IN6: -#endif /* INET6 */ - if (sc->gif_pdst == NULL) { - error = EADDRNOTAVAIL; - goto bad; + case SIOCGIFPSRCADDR_IN6: + sin6->sin6_addr = sc->gif_ip6hdr->ip6_src; + break; + case SIOCGIFPDSTADDR_IN6: + sin6->sin6_addr = sc->gif_ip6hdr->ip6_dst; + break; +#endif + } } - src = sc->gif_pdst; + GIF_RUNLOCK(sc); + if (error != 0) + break; switch (cmd) { #ifdef INET + case SIOCGIFPSRCADDR: case SIOCGIFPDSTADDR: - dst = &ifr->ifr_addr; - size = sizeof(ifr->ifr_addr); + error = prison_if(curthread->td_ucred, + (struct sockaddr *)sin); + if (error != 0) + memset(sin, 0, sizeof(*sin)); break; -#endif /* INET */ +#endif #ifdef INET6 + case SIOCGIFPSRCADDR_IN6: case SIOCGIFPDSTADDR_IN6: - dst = (struct sockaddr *) - &(((struct in6_ifreq *)data)->ifr_addr); - size = sizeof(((struct in6_ifreq *)data)->ifr_addr); - break; -#endif /* INET6 */ - default: - error = EADDRNOTAVAIL; - goto bad; - } - if (src->sa_len > size) - return EINVAL; - error = prison_if(curthread->td_ucred, src); - if (error != 0) - return (error); - error = prison_if(curthread->td_ucred, dst); - if (error != 0) - return (error); - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); -#ifdef INET6 - if (dst->sa_family == AF_INET6) { - error = sa6_recoverscope((struct sockaddr_in6 *)dst); + error = prison_if(curthread->td_ucred, + (struct sockaddr *)sin6); + if (error == 0) + error = sa6_recoverscope(sin6); if (error != 0) - return (error); - } + memset(sin6, 0, sizeof(*sin6)); #endif - break; - - case SIOCGLIFPHYADDR: - if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) { - error = EADDRNOTAVAIL; - goto bad; } - - /* copy src */ - src = sc->gif_psrc; - dst = (struct sockaddr *) - &(((struct if_laddrreq *)data)->addr); - size = sizeof(((struct if_laddrreq *)data)->addr); - if (src->sa_len > size) - return EINVAL; - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); - - /* copy dst */ - src = sc->gif_pdst; - dst = (struct sockaddr *) - &(((struct if_laddrreq *)data)->dstaddr); - size = sizeof(((struct if_laddrreq *)data)->dstaddr); - if (src->sa_len > size) - return EINVAL; - bcopy((caddr_t)src, (caddr_t)dst, src->sa_len); - break; - - case SIOCSIFFLAGS: - /* if_ioctl() takes care of it */ break; - case GIFGOPTS: options = sc->gif_options; - error = copyout(&options, ifr->ifr_data, - sizeof(options)); + error = copyout(&options, ifr->ifr_data, sizeof(options)); break; - case GIFSOPTS: if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) break; @@ -934,142 +945,146 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = EINVAL; break; } - bad: - return error; +bad: + sx_xunlock(&gif_ioctl_sx); + return (error); } -/* - * XXXRW: There's a general event-ordering issue here: the code to check - * if a given tunnel is already present happens before we perform a - * potentially blocking setup of the tunnel. This code needs to be - * re-ordered so that the check and replacement can be atomic using - * a mutex. - */ -int -gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) +static void +gif_detach(struct gif_softc *sc) { - struct gif_softc *sc = ifp->if_softc; - struct gif_softc *sc2; - struct sockaddr *osrc, *odst, *sa; - int error = 0; - GIF_LIST_LOCK(); - LIST_FOREACH(sc2, &V_gif_softc_list, gif_list) { - if (sc2 == sc) - continue; - if (!sc2->gif_pdst || !sc2->gif_psrc) - continue; - if (sc2->gif_pdst->sa_family != dst->sa_family || - sc2->gif_pdst->sa_len != dst->sa_len || - sc2->gif_psrc->sa_family != src->sa_family || - sc2->gif_psrc->sa_len != src->sa_len) - continue; + sx_assert(&gif_ioctl_sx, SA_XLOCKED); + if (sc->gif_ecookie != NULL) + encap_detach(sc->gif_ecookie); + sc->gif_ecookie = NULL; +} - /* - * Disallow parallel tunnels unless instructed - * otherwise. - */ - if (!V_parallel_tunnels && - bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && - bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { - error = EADDRNOTAVAIL; - GIF_LIST_UNLOCK(); - goto bad; - } +static int +gif_attach(struct gif_softc *sc, int af) +{ - /* XXX both end must be valid? (I mean, not 0.0.0.0) */ + sx_assert(&gif_ioctl_sx, SA_XLOCKED); + switch (af) { +#ifdef INET + case AF_INET: + return (in_gif_attach(sc)); +#endif +#ifdef INET6 + case AF_INET6: + return (in6_gif_attach(sc)); +#endif } - GIF_LIST_UNLOCK(); + return (EAFNOSUPPORT); +} - /* XXX we can detach from both, but be polite just in case */ - if (sc->gif_psrc) - switch (sc->gif_psrc->sa_family) { +static int +gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) +{ + struct gif_softc *sc = ifp->if_softc; + struct gif_softc *tsc; #ifdef INET - case AF_INET: - (void)in_gif_detach(sc); - break; + struct ip *ip; #endif #ifdef INET6 - case AF_INET6: - (void)in6_gif_detach(sc); - break; + struct ip6_hdr *ip6; #endif - } - - osrc = sc->gif_psrc; - sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK); - bcopy((caddr_t)src, (caddr_t)sa, src->sa_len); - sc->gif_psrc = sa; - - odst = sc->gif_pdst; - sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK); - bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len); - sc->gif_pdst = sa; + void *hdr; + int error = 0; - switch (sc->gif_psrc->sa_family) { + if (sc == NULL) + return (ENXIO); + /* Disallow parallel tunnels unless instructed otherwise. */ + if (V_parallel_tunnels == 0) { + GIF_LIST_LOCK(); + LIST_FOREACH(tsc, &V_gif_softc_list, gif_list) { + if (tsc == sc || tsc->gif_family != src->sa_family) + continue; +#ifdef INET + if (tsc->gif_family == AF_INET && + tsc->gif_iphdr->ip_src.s_addr == + satosin(src)->sin_addr.s_addr && + tsc->gif_iphdr->ip_dst.s_addr == + satosin(dst)->sin_addr.s_addr) { + error = EADDRNOTAVAIL; + GIF_LIST_UNLOCK(); + goto bad; + } +#endif +#ifdef INET6 + if (tsc->gif_family == AF_INET6 && + IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_src, + &satosin6(src)->sin6_addr) && + IN6_ARE_ADDR_EQUAL(&tsc->gif_ip6hdr->ip6_dst, + &satosin6(dst)->sin6_addr)) { + error = EADDRNOTAVAIL; + GIF_LIST_UNLOCK(); + goto bad; + } +#endif + } + GIF_LIST_UNLOCK(); + } + switch (src->sa_family) { #ifdef INET case AF_INET: - error = in_gif_attach(sc); + hdr = ip = malloc(sizeof(struct ip), M_GIF, + M_WAITOK | M_ZERO); + ip->ip_src.s_addr = satosin(src)->sin_addr.s_addr; + ip->ip_dst.s_addr = satosin(dst)->sin_addr.s_addr; break; #endif #ifdef INET6 case AF_INET6: - /* - * Check validity of the scope zone ID of the addresses, and - * convert it into the kernel internal form if necessary. - */ - error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0); - if (error != 0) - break; - error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0); - if (error != 0) - break; - error = in6_gif_attach(sc); + hdr = ip6 = malloc(sizeof(struct ip6_hdr), M_GIF, + M_WAITOK | M_ZERO); + ip6->ip6_src = satosin6(src)->sin6_addr; + ip6->ip6_dst = satosin6(dst)->sin6_addr; + ip6->ip6_vfc = IPV6_VERSION; break; #endif - } - if (error) { - /* rollback */ - free((caddr_t)sc->gif_psrc, M_IFADDR); - free((caddr_t)sc->gif_pdst, M_IFADDR); - sc->gif_psrc = osrc; - sc->gif_pdst = odst; - goto bad; - } - - if (osrc) - free((caddr_t)osrc, M_IFADDR); - if (odst) - free((caddr_t)odst, M_IFADDR); - - bad: - if (sc->gif_psrc && sc->gif_pdst) + default: + return (EAFNOSUPPORT); + }; + + if (sc->gif_family != src->sa_family) + gif_detach(sc); + if (sc->gif_family == 0 || + sc->gif_family != src->sa_family) + error = gif_attach(sc, src->sa_family); + + GIF_WLOCK(sc); + if (sc->gif_family != 0) + free(sc->gif_hdr, M_GIF); + sc->gif_family = src->sa_family; + sc->gif_hdr = hdr; + GIF_WUNLOCK(sc); +#if defined(INET) || defined(INET6) +bad: +#endif + if (error == 0 && sc->gif_family != 0) ifp->if_drv_flags |= IFF_DRV_RUNNING; else ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - - return error; + return (error); } -void +static void gif_delete_tunnel(struct ifnet *ifp) { struct gif_softc *sc = ifp->if_softc; + int family; - if (sc->gif_psrc) { - free((caddr_t)sc->gif_psrc, M_IFADDR); - sc->gif_psrc = NULL; - } - if (sc->gif_pdst) { - free((caddr_t)sc->gif_pdst, M_IFADDR); - sc->gif_pdst = NULL; + if (sc == NULL) + return; + + GIF_WLOCK(sc); + family = sc->gif_family; + sc->gif_family = 0; + GIF_WUNLOCK(sc); + if (family != 0) { + gif_detach(sc); + free(sc->gif_hdr, M_GIF); } - /* it is safe to detach from both */ -#ifdef INET - (void)in_gif_detach(sc); -#endif -#ifdef INET6 - (void)in6_gif_detach(sc); -#endif ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index d6e58f5c1..b5ebf15d3 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -30,21 +30,17 @@ * SUCH DAMAGE. */ -/* - * if_gif.h - */ - #ifndef _NET_IF_GIF_H_ #define _NET_IF_GIF_H_ - #ifdef _KERNEL #include "opt_inet.h" #include "opt_inet6.h" #include -/* xxx sigh, why route have struct route instead of pointer? */ +struct ip; +struct ip6_hdr; struct encaptab; extern void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, @@ -56,35 +52,38 @@ extern void (*ng_gif_attach_p)(struct ifnet *ifp); extern void (*ng_gif_detach_p)(struct ifnet *ifp); struct gif_softc { - struct ifnet *gif_ifp; - struct mtx gif_mtx; - struct sockaddr *gif_psrc; /* Physical src addr */ - struct sockaddr *gif_pdst; /* Physical dst addr */ + struct ifnet *gif_ifp; + struct rmlock gif_lock; + const struct encaptab *gif_ecookie; + int gif_family; + int gif_flags; + u_int gif_fibnum; + u_int gif_options; + void *gif_netgraph; /* netgraph node info */ union { - struct route gifscr_ro; /* xxx */ + void *hdr; + struct ip *iphdr; #ifdef INET6 - struct route_in6 gifscr_ro6; /* xxx */ + struct ip6_hdr *ip6hdr; #endif - } gifsc_gifscr; - int gif_flags; - u_int gif_fibnum; - const struct encaptab *encap_cookie4; - const struct encaptab *encap_cookie6; - void *gif_netgraph; /* ng_gif(4) netgraph node info */ - u_int gif_options; - LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */ + } gif_uhdr; + LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */ }; #define GIF2IFP(sc) ((sc)->gif_ifp) -#define GIF_LOCK_INIT(sc) mtx_init(&(sc)->gif_mtx, "gif softc", \ - NULL, MTX_DEF) -#define GIF_LOCK_DESTROY(sc) mtx_destroy(&(sc)->gif_mtx) -#define GIF_LOCK(sc) mtx_lock(&(sc)->gif_mtx) -#define GIF_UNLOCK(sc) mtx_unlock(&(sc)->gif_mtx) -#define GIF_LOCK_ASSERT(sc) mtx_assert(&(sc)->gif_mtx, MA_OWNED) - -#define gif_ro gifsc_gifscr.gifscr_ro +#define GIF_LOCK_INIT(sc) rm_init(&(sc)->gif_lock, "gif softc") +#define GIF_LOCK_DESTROY(sc) rm_destroy(&(sc)->gif_lock) +#define GIF_RLOCK_TRACKER struct rm_priotracker gif_tracker +#define GIF_RLOCK(sc) rm_rlock(&(sc)->gif_lock, &gif_tracker) +#define GIF_RUNLOCK(sc) rm_runlock(&(sc)->gif_lock, &gif_tracker) +#define GIF_RLOCK_ASSERT(sc) rm_assert(&(sc)->gif_lock, RA_RLOCKED) +#define GIF_WLOCK(sc) rm_wlock(&(sc)->gif_lock) +#define GIF_WUNLOCK(sc) rm_wunlock(&(sc)->gif_lock) +#define GIF_WLOCK_ASSERT(sc) rm_assert(&(sc)->gif_lock, RA_WLOCKED) + +#define gif_iphdr gif_uhdr.iphdr +#define gif_hdr gif_uhdr.hdr #ifdef INET6 -#define gif_ro6 gifsc_gifscr.gifscr_ro6 +#define gif_ip6hdr gif_uhdr.ip6hdr #endif #define GIF_MTU (1280) /* Default MTU */ @@ -111,12 +110,9 @@ struct etherip_header { #define ETHERIP_ALIGN 2 /* Prototypes */ -void gif_input(struct mbuf *, int, struct ifnet *); +void gif_input(struct mbuf *, struct ifnet *, int, uint8_t); int gif_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); -int gif_ioctl(struct ifnet *, u_long, caddr_t); -int gif_set_tunnel(struct ifnet *, struct sockaddr *, struct sockaddr *); -void gif_delete_tunnel(struct ifnet *); int gif_encapcheck(const struct mbuf *, int, int, void *); #endif /* _KERNEL */ diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index abaf9b171..c4df3b348 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,5 +1,3 @@ -/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ - /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -27,16 +25,19 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); -#include "opt_mrouting.h" #include "opt_inet.h" #include "opt_inet6.h" #include +#include +#include #include #include #include @@ -48,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -64,22 +66,19 @@ __FBSDID("$FreeBSD$"); #include #endif -#ifdef MROUTING -#include -#endif /* MROUTING */ - -#include +#include static int gif_validate4(const struct ip *, struct gif_softc *, struct ifnet *); +static void in_gif_input10(struct mbuf *, int); extern struct domain inetdomain; struct protosw in_gif_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = 0/* IPPROTO_IPV[46] */, .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = in_gif_input, + .pr_input = in_gif_input10, .pr_output = (pr_output_t*)rip_output, .pr_ctloutput = rip_ctloutput, .pr_usrreqs = &rip_usrreqs @@ -91,127 +90,24 @@ SYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, &VNET_NAME(ip_gif_ttl), 0, ""); int -in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) +in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) { + GIF_RLOCK_TRACKER; struct gif_softc *sc = ifp->if_softc; - struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; - struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; - struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; - struct ip iphdr; /* capsule IP header, host byte ordered */ - struct etherip_header eiphdr; - int error, len, proto; - u_int8_t tos; - - GIF_LOCK_ASSERT(sc); - - if (sin_src == NULL || sin_dst == NULL || - sin_src->sin_family != AF_INET || - sin_dst->sin_family != AF_INET) { - m_freem(m); - return EAFNOSUPPORT; - } - - switch (family) { -#ifdef INET - case AF_INET: - { - struct ip *ip; - - proto = IPPROTO_IPV4; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return ENOBUFS; - } - ip = mtod(m, struct ip *); - tos = ip->ip_tos; - break; - } -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - { - struct ip6_hdr *ip6; - proto = IPPROTO_IPV6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return ENOBUFS; - } - ip6 = mtod(m, struct ip6_hdr *); - tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - break; - } -#endif /* INET6 */ - case AF_LINK: - proto = IPPROTO_ETHERIP; - - /* - * GIF_SEND_REVETHIP (disabled by default) intentionally - * sends an EtherIP packet with revered version field in - * the header. This is a knob for backward compatibility - * with FreeBSD 7.2R or prior. - */ - if ((sc->gif_options & GIF_SEND_REVETHIP)) { - eiphdr.eip_ver = 0; - eiphdr.eip_resvl = ETHERIP_VERSION; - eiphdr.eip_resvh = 0; - } else { - eiphdr.eip_ver = ETHERIP_VERSION; - eiphdr.eip_resvl = 0; - eiphdr.eip_resvh = 0; - } - /* prepend Ethernet-in-IP header */ - M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); - if (m && m->m_len < sizeof(struct etherip_header)) - m = m_pullup(m, sizeof(struct etherip_header)); - if (m == NULL) - return ENOBUFS; - bcopy(&eiphdr, mtod(m, struct etherip_header *), - sizeof(struct etherip_header)); - tos = 0; - break; - - default: -#ifdef DEBUG - printf("in_gif_output: warning: unknown family %d passed\n", - family); -#endif - m_freem(m); - return EAFNOSUPPORT; - } - - bzero(&iphdr, sizeof(iphdr)); - iphdr.ip_src = sin_src->sin_addr; - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - return ENETUNREACH; - } - iphdr.ip_p = proto; - /* version will be set in ip_output() */ - iphdr.ip_ttl = V_ip_gif_ttl; - iphdr.ip_len = htons(m->m_pkthdr.len + sizeof(struct ip)); - ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, - &iphdr.ip_tos, &tos); + struct ip *ip; + int len; /* prepend new IP header */ len = sizeof(struct ip); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) + if (proto == IPPROTO_ETHERIP) len += ETHERIP_ALIGN; #endif M_PREPEND(m, len, M_NOWAIT); - if (m != NULL && m->m_len < len) - m = m_pullup(m, len); - if (m == NULL) { - printf("ENOBUFS in in_gif_output %d\n", __LINE__); - return ENOBUFS; - } + if (m == NULL) + return (ENOBUFS); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) { + if (proto == IPPROTO_ETHERIP) { len = mtod(m, vm_offset_t) & 3; KASSERT(len == 0 || len == ETHERIP_ALIGN, ("in_gif_output: unexpected misalignment")); @@ -219,145 +115,60 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) m->m_len -= ETHERIP_ALIGN; } #endif - bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); - - M_SETFIB(m, sc->gif_fibnum); - - if (dst->sin_family != sin_dst->sin_family || - dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { - /* cache route doesn't match */ - bzero(dst, sizeof(*dst)); - dst->sin_family = sin_dst->sin_family; - dst->sin_len = sizeof(struct sockaddr_in); - dst->sin_addr = sin_dst->sin_addr; - if (sc->gif_ro.ro_rt) { - RTFREE(sc->gif_ro.ro_rt); - sc->gif_ro.ro_rt = NULL; - } -#if 0 - GIF2IFP(sc)->if_mtu = GIF_MTU; -#endif + ip = mtod(m, struct ip *); + GIF_RLOCK(sc); + if (sc->gif_family != AF_INET) { + m_freem(m); + GIF_RUNLOCK(sc); + return (ENETDOWN); } + bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); + GIF_RUNLOCK(sc); - if (sc->gif_ro.ro_rt == NULL) { - in_rtalloc_ign(&sc->gif_ro, 0, sc->gif_fibnum); - if (sc->gif_ro.ro_rt == NULL) { - m_freem(m); - return ENETUNREACH; - } - - /* if it constitutes infinite encapsulation, punt. */ - if (sc->gif_ro.ro_rt->rt_ifp == ifp) { - m_freem(m); - return ENETUNREACH; /* XXX */ - } -#if 0 - ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip); -#endif - } + ip->ip_p = proto; + /* version will be set in ip_output() */ + ip->ip_ttl = V_ip_gif_ttl; + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_tos = ecn; - m->m_flags &= ~(M_BCAST|M_MCAST); - error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); + return (ip_output(m, NULL, NULL, 0, NULL, NULL)); +} - if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && - sc->gif_ro.ro_rt != NULL) { - RTFREE(sc->gif_ro.ro_rt); - sc->gif_ro.ro_rt = NULL; - } +static void +in_gif_input10(struct mbuf *m, int off) +{ + int proto; - return (error); + proto = (mtod(m, struct ip *))->ip_p; + in_gif_input(&m, &off, proto); } -void -in_gif_input(struct mbuf *m, int off) +int +in_gif_input(struct mbuf **mp, int *offp, int proto) { - struct ifnet *gifp = NULL; + struct mbuf *m = *mp; struct gif_softc *sc; + struct ifnet *gifp; struct ip *ip; - int af; - u_int8_t otos; - int proto; - - ip = mtod(m, struct ip *); - proto = ip->ip_p; + uint8_t ecn; - sc = (struct gif_softc *)encap_getarg(m); + sc = encap_getarg(m); if (sc == NULL) { m_freem(m); KMOD_IPSTAT_INC(ips_nogif); - return; + return (IPPROTO_DONE); } - gifp = GIF2IFP(sc); - if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { - m_freem(m); - KMOD_IPSTAT_INC(ips_nogif); - return; - } - - otos = ip->ip_tos; - m_adj(m, off); - - switch (proto) { -#ifdef INET - case IPPROTO_IPV4: - { - struct ip *ip; - af = AF_INET; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return; - } + if ((gifp->if_flags & IFF_UP) != 0) { ip = mtod(m, struct ip *); - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &ip->ip_tos) == 0) { - m_freem(m); - return; - } - break; - } -#endif -#ifdef INET6 - case IPPROTO_IPV6: - { - struct ip6_hdr *ip6; - u_int8_t itos, oitos; - - af = AF_INET6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return; - } - ip6 = mtod(m, struct ip6_hdr *); - itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &itos) == 0) { - m_freem(m); - return; - } - if (itos != oitos) { - ip6->ip6_flow &= ~htonl(0xff << 20); - ip6->ip6_flow |= htonl((u_int32_t)itos << 20); - } - break; - } -#endif /* INET6 */ - case IPPROTO_ETHERIP: - af = AF_LINK; - break; - - default: - KMOD_IPSTAT_INC(ips_nogif); + ecn = ip->ip_tos; + m_adj(m, *offp); + gif_input(m, gifp, proto, ecn); + } else { m_freem(m); - return; + KMOD_IPSTAT_INC(ips_nogif); } - gif_input(m, af, gifp); - return; + return (IPPROTO_DONE); } /* @@ -366,37 +177,23 @@ in_gif_input(struct mbuf *m, int off) static int gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) { - struct sockaddr_in *src, *dst; - struct in_ifaddr *ia4; - src = (struct sockaddr_in *)sc->gif_psrc; - dst = (struct sockaddr_in *)sc->gif_pdst; + GIF_RLOCK_ASSERT(sc); /* check for address match */ - if (src->sin_addr.s_addr != ip->ip_dst.s_addr || - dst->sin_addr.s_addr != ip->ip_src.s_addr) - return 0; + if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr || + sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) + return (0); /* martian filters on outer source - NOT done in ip_input! */ if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) - return 0; + 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 */ - /* XXXRW: should use hash lists? */ - IN_IFADDR_RLOCK(); - TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { - 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) { - IN_IFADDR_RUNLOCK(); - return 0; - } + case 0: + case 127: + case 255: + return (0); } - IN_IFADDR_RUNLOCK(); /* ingress filters on outer source */ if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { @@ -411,19 +208,13 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, sc->gif_fibnum); if (!rt || rt->rt_ifp != ifp) { -#if 0 - log(LOG_WARNING, "%s: packet from 0x%x dropped " - "due to ingress filter\n", if_name(GIF2IFP(sc)), - (u_int32_t)ntohl(sin.sin_addr.s_addr)); -#endif if (rt) RTFREE_LOCKED(rt); - return 0; + return (0); } RTFREE_LOCKED(rt); } - - return 32 * 2; + return (32 * 2); } /* @@ -431,7 +222,7 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) * matched the physical addr family. see gif_encapcheck(). */ int -gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg) +in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip ip; struct gif_softc *sc; @@ -439,31 +230,21 @@ gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg) /* sanity check done in caller */ sc = (struct gif_softc *)arg; + GIF_RLOCK_ASSERT(sc); - /* LINTED const cast */ m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; - - return gif_validate4(&ip, sc, ifp); + return (gif_validate4(&ip, sc, ifp)); } int in_gif_attach(struct gif_softc *sc) { - sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, - &in_gif_protosw, sc); - if (sc->encap_cookie4 == NULL) - return EEXIST; - return 0; -} -int -in_gif_detach(struct gif_softc *sc) -{ - int error; - - error = encap_detach(sc->encap_cookie4); - if (error == 0) - sc->encap_cookie4 = NULL; - return error; + KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); + sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, + &in_gif_protosw, sc); + if (sc->gif_ecookie == NULL) + return (EEXIST); + return (0); } diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h index e1f4ae48d..d48d88109 100644 --- a/sys/netinet/in_gif.h +++ b/sys/netinet/in_gif.h @@ -36,10 +36,9 @@ #define GIF_TTL 30 struct gif_softc; -void in_gif_input(struct mbuf *, int); -int in_gif_output(struct ifnet *, int, struct mbuf *); -int gif_encapcheck4(const struct mbuf *, int, int, void *); +int in_gif_input(struct mbuf **, int *, int); +int in_gif_output(struct ifnet *, struct mbuf *, int, uint8_t); +int in_gif_encapcheck(const struct mbuf *, int, int, void *); int in_gif_attach(struct gif_softc *); -int in_gif_detach(struct gif_softc *); #endif /*_NETINET_IN_GIF_H_*/ diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index 97bc4a5c9..1872f5c83 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include "opt_inet6.h" #include +#include +#include #include #include #include @@ -49,7 +51,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include @@ -94,113 +98,24 @@ struct ip6protosw in6_gif_protosw = { }; int -in6_gif_output(struct ifnet *ifp, - int family, /* family of the packet to be encapsulate */ - struct mbuf *m) +in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) { + GIF_RLOCK_TRACKER; struct gif_softc *sc = ifp->if_softc; - struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; - struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; - struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; struct ip6_hdr *ip6; - struct etherip_header eiphdr; - int error, len, proto; - u_int8_t itos, otos; - - GIF_LOCK_ASSERT(sc); - - if (sin6_src == NULL || sin6_dst == NULL || - sin6_src->sin6_family != AF_INET6 || - sin6_dst->sin6_family != AF_INET6) { - m_freem(m); - return EAFNOSUPPORT; - } - - switch (family) { -#ifdef INET - case AF_INET: - { - struct ip *ip; - - proto = IPPROTO_IPV4; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return ENOBUFS; - } - ip = mtod(m, struct ip *); - itos = ip->ip_tos; - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct ip6_hdr *ip6; - proto = IPPROTO_IPV6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return ENOBUFS; - } - ip6 = mtod(m, struct ip6_hdr *); - itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; - break; - } -#endif - case AF_LINK: - proto = IPPROTO_ETHERIP; - - /* - * GIF_SEND_REVETHIP (disabled by default) intentionally - * sends an EtherIP packet with revered version field in - * the header. This is a knob for backward compatibility - * with FreeBSD 7.2R or prior. - */ - if ((sc->gif_options & GIF_SEND_REVETHIP)) { - eiphdr.eip_ver = 0; - eiphdr.eip_resvl = ETHERIP_VERSION; - eiphdr.eip_resvh = 0; - } else { - eiphdr.eip_ver = ETHERIP_VERSION; - eiphdr.eip_resvl = 0; - eiphdr.eip_resvh = 0; - } - /* prepend Ethernet-in-IP header */ - M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); - if (m && m->m_len < sizeof(struct etherip_header)) - m = m_pullup(m, sizeof(struct etherip_header)); - if (m == NULL) - return ENOBUFS; - bcopy(&eiphdr, mtod(m, struct etherip_header *), - sizeof(struct etherip_header)); - itos = 0; - break; - - default: -#ifdef DEBUG - printf("in6_gif_output: warning: unknown family %d passed\n", - family); -#endif - m_freem(m); - return EAFNOSUPPORT; - } + int len; /* prepend new IP header */ len = sizeof(struct ip6_hdr); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) + if (proto == IPPROTO_ETHERIP) len += ETHERIP_ALIGN; #endif M_PREPEND(m, len, M_NOWAIT); - if (m != NULL && m->m_len < len) - m = m_pullup(m, len); - if (m == NULL) { - printf("ENOBUFS in in6_gif_output %d\n", __LINE__); - return ENOBUFS; - } + if (m == NULL) + return (ENOBUFS); #ifndef __NO_STRICT_ALIGNMENT - if (family == AF_LINK) { + if (proto == IPPROTO_ETHERIP) { len = mtod(m, vm_offset_t) & 3; KASSERT(len == 0 || len == ETHERIP_ALIGN, ("in6_gif_output: unexpected misalignment")); @@ -210,166 +125,52 @@ in6_gif_output(struct ifnet *ifp, #endif ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); - ip6->ip6_nxt = proto; - ip6->ip6_hlim = V_ip6_gif_hlim; - ip6->ip6_src = sin6_src->sin6_addr; - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6->ip6_dst = sin6_dst->sin6_addr; - else { + GIF_RLOCK(sc); + if (sc->gif_family != AF_INET6) { m_freem(m); - return ENETUNREACH; + GIF_RUNLOCK(sc); + return (ENETDOWN); } - ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, - &otos, &itos); - ip6->ip6_flow &= ~htonl(0xff << 20); - ip6->ip6_flow |= htonl((u_int32_t)otos << 20); + bcopy(sc->gif_ip6hdr, ip6, sizeof(struct ip6_hdr)); + GIF_RUNLOCK(sc); - M_SETFIB(m, sc->gif_fibnum); - - if (dst->sin6_family != sin6_dst->sin6_family || - !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { - /* cache route doesn't match */ - bzero(dst, sizeof(*dst)); - dst->sin6_family = sin6_dst->sin6_family; - dst->sin6_len = sizeof(struct sockaddr_in6); - dst->sin6_addr = sin6_dst->sin6_addr; - if (sc->gif_ro6.ro_rt) { - RTFREE(sc->gif_ro6.ro_rt); - sc->gif_ro6.ro_rt = NULL; - } -#if 0 - GIF2IFP(sc)->if_mtu = GIF_MTU; -#endif - } - - if (sc->gif_ro6.ro_rt == NULL) { - in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum); - if (sc->gif_ro6.ro_rt == NULL) { - m_freem(m); - return ENETUNREACH; - } - - /* if it constitutes infinite encapsulation, punt. */ - if (sc->gif_ro.ro_rt->rt_ifp == ifp) { - m_freem(m); - return ENETUNREACH; /*XXX*/ - } -#if 0 - ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu - - sizeof(struct ip6_hdr); -#endif - } - - m->m_flags &= ~(M_BCAST|M_MCAST); -#ifdef IPV6_MINMTU + ip6->ip6_flow |= htonl((uint32_t)ecn << 20); + ip6->ip6_nxt = proto; + ip6->ip6_hlim = V_ip6_gif_hlim; /* * force fragmentation to minimum MTU, to avoid path MTU discovery. * it is too painful to ask for resend of inner packet, to achieve * path MTU discovery for encapsulated packets. */ - error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL); -#else - error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL); -#endif - - if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && - sc->gif_ro6.ro_rt != NULL) { - RTFREE(sc->gif_ro6.ro_rt); - sc->gif_ro6.ro_rt = NULL; - } - - return (error); + return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL)); } int in6_gif_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; - struct ifnet *gifp = NULL; + struct ifnet *gifp; struct gif_softc *sc; struct ip6_hdr *ip6; - int af = 0; - u_int32_t otos; + uint8_t ecn; - ip6 = mtod(m, struct ip6_hdr *); - - sc = (struct gif_softc *)encap_getarg(m); + sc = encap_getarg(m); if (sc == NULL) { m_freem(m); IP6STAT_INC(ip6s_nogif); - return IPPROTO_DONE; + return (IPPROTO_DONE); } - gifp = GIF2IFP(sc); - if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { - m_freem(m); - IP6STAT_INC(ip6s_nogif); - return IPPROTO_DONE; - } - - otos = ip6->ip6_flow; - m_adj(m, *offp); - - switch (proto) { -#ifdef INET - case IPPROTO_IPV4: - { - struct ip *ip; - u_int8_t otos8; - af = AF_INET; - otos8 = (ntohl(otos) >> 20) & 0xff; - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) - return IPPROTO_DONE; - } - ip = mtod(m, struct ip *); - if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos8, &ip->ip_tos) == 0) { - m_freem(m); - return IPPROTO_DONE; - } - break; - } -#endif /* INET */ -#ifdef INET6 - case IPPROTO_IPV6: - { - struct ip6_hdr *ip6; - af = AF_INET6; - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) - return IPPROTO_DONE; - } + if ((gifp->if_flags & IFF_UP) != 0) { ip6 = mtod(m, struct ip6_hdr *); - if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ? - ECN_ALLOWED : ECN_NOCARE, - &otos, &ip6->ip6_flow) == 0) { - m_freem(m); - return IPPROTO_DONE; - } - break; - } -#endif - case IPPROTO_ETHERIP: - af = AF_LINK; - break; - - default: - IP6STAT_INC(ip6s_nogif); + ecn = (ntohl(ip6->ip6_flow) >> 20) & 0xff; + m_adj(m, *offp); + gif_input(m, gifp, proto, ecn); + } else { m_freem(m); - return IPPROTO_DONE; + IP6STAT_INC(ip6s_nogif); } - - gif_input(m, af, gifp); - return IPPROTO_DONE; + return (IPPROTO_DONE); } /* @@ -379,19 +180,16 @@ static int gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, struct ifnet *ifp) { - struct sockaddr_in6 *src, *dst; - - src = (struct sockaddr_in6 *)sc->gif_psrc; - dst = (struct sockaddr_in6 *)sc->gif_pdst; + GIF_RLOCK_ASSERT(sc); /* * Check for address match. Note that the check is for an incoming * packet. We should compare the *source* address in our configuration * and the *destination* address of the packet, and vice versa. */ - if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || - !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) - return 0; + if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, &ip6->ip6_dst) || + !IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, &ip6->ip6_src)) + return (0); /* martian filters on outer source - done in ip6_input */ @@ -409,29 +207,22 @@ gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, sc->gif_fibnum); if (!rt || rt->rt_ifp != ifp) { -#if 0 - char ip6buf[INET6_ADDRSTRLEN]; - log(LOG_WARNING, "%s: packet from %s dropped " - "due to ingress filter\n", if_name(GIF2IFP(sc)), - ip6_sprintf(ip6buf, &sin6.sin6_addr)); -#endif if (rt) RTFREE_LOCKED(rt); - return 0; + return (0); } RTFREE_LOCKED(rt); } - return 128 * 2; + return (128 * 2); } /* * we know that we are in IFF_UP, outer address available, and outer family * matched the physical addr family. see gif_encapcheck(). - * sanity check for arg should have been done in the caller. */ int -gif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg) +in6_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip6_hdr ip6; struct gif_softc *sc; @@ -439,31 +230,21 @@ gif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg) /* sanity check done in caller */ sc = (struct gif_softc *)arg; + GIF_RLOCK_ASSERT(sc); - /* LINTED const cast */ m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6); ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; - - return gif_validate6(&ip6, sc, ifp); + return (gif_validate6(&ip6, sc, ifp)); } int in6_gif_attach(struct gif_softc *sc) { - sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, - (void *)&in6_gif_protosw, sc); - if (sc->encap_cookie6 == NULL) - return EEXIST; - return 0; -} - -int -in6_gif_detach(struct gif_softc *sc) -{ - int error; - error = encap_detach(sc->encap_cookie6); - if (error == 0) - sc->encap_cookie6 = NULL; - return error; + KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); + sc->gif_ecookie = encap_attach_func(AF_INET6, -1, gif_encapcheck, + (void *)&in6_gif_protosw, sc); + if (sc->gif_ecookie == NULL) + return (EEXIST); + return (0); } diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h index e11841759..124617120 100644 --- a/sys/netinet6/in6_gif.h +++ b/sys/netinet6/in6_gif.h @@ -37,9 +37,8 @@ struct gif_softc; int in6_gif_input(struct mbuf **, int *, int); -int in6_gif_output(struct ifnet *, int, struct mbuf *); -int gif_encapcheck6(const struct mbuf *, int, int, void *); +int in6_gif_output(struct ifnet *, struct mbuf *, int, uint8_t); +int in6_gif_encapcheck(const struct mbuf *, int, int, void *); int in6_gif_attach(struct gif_softc *); -int in6_gif_detach(struct gif_softc *); #endif /* _NETINET6_IN6_GIF_H_ */ -- 2.45.0