From owner-svn-src-stable-10@FreeBSD.ORG Tue Dec 23 16:33:46 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 69093BDF; Tue, 23 Dec 2014 16:33:46 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 526D11125; Tue, 23 Dec 2014 16:33:46 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sBNGXk5N019172; Tue, 23 Dec 2014 16:33:46 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sBNGXjER019167; Tue, 23 Dec 2014 16:33:45 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201412231633.sBNGXjER019167@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Tue, 23 Dec 2014 16:33:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r276149 - in stable/10: share/man/man4 sys/conf sys/net sys/netinet sys/netinet6 X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Dec 2014 16:33:46 -0000 Author: ae Date: Tue Dec 23 16:33:44 2014 New Revision: 276149 URL: https://svnweb.freebsd.org/changeset/base/276149 Log: 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. Modified: stable/10/share/man/man4/gif.4 stable/10/sys/conf/files stable/10/sys/net/if_gif.c stable/10/sys/net/if_gif.h stable/10/sys/netinet/in_gif.c stable/10/sys/netinet/in_gif.h stable/10/sys/netinet6/in6_gif.c stable/10/sys/netinet6/in6_gif.h Directory Properties: stable/10/ (props changed) stable/10/sys/gnu/dts/ (props changed) Modified: stable/10/share/man/man4/gif.4 ============================================================================== --- stable/10/share/man/man4/gif.4 Tue Dec 23 16:17:37 2014 (r276148) +++ stable/10/share/man/man4/gif.4 Tue Dec 23 16:33:44 2014 (r276149) @@ -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 Modified: stable/10/sys/conf/files ============================================================================== --- stable/10/sys/conf/files Tue Dec 23 16:17:37 2014 (r276148) +++ stable/10/sys/conf/files Tue Dec 23 16:33:44 2014 (r276149) @@ -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_e 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 Modified: stable/10/sys/net/if_gif.c ============================================================================== --- stable/10/sys/net/if_gif.c Tue Dec 23 16:17:37 2014 (r276148) +++ stable/10/sys/net/if_gif.c Tue Dec 23 16:33:44 2014 (r276149) @@ -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 ifn 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, i 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, i 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, i 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 mbu 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 mbu 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 + if (ifp->if_bridge) + af = AF_LINK; /* - * Make altq aware of the bytes we will add - * when we actually send it. + * 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. */ -#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 - /* - * Queue message on interface, update output statistics if - * successful, and start output if interface not yet active. - */ - 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 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 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 #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 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 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, &(((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: *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***