Date: Tue, 14 Oct 2014 13:31:47 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r273087 - in head: share/man/man4 sys/net sys/netinet sys/netinet6 Message-ID: <201410141331.s9EDVlXw037463@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Tue Oct 14 13:31:47 2014 New Revision: 273087 URL: https://svnweb.freebsd.org/changeset/base/273087 Log: 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. Reviewed by: melifaro Obtained from: Yandex LLC MFC after: 1 month Sponsored by: Yandex LLC Modified: head/share/man/man4/gif.4 head/sys/net/if_gif.c head/sys/net/if_gif.h head/sys/netinet/in_gif.c head/sys/netinet/in_gif.h head/sys/netinet6/in6_gif.c head/sys/netinet6/in6_gif.h Modified: head/share/man/man4/gif.4 ============================================================================== --- head/share/man/man4/gif.4 Tue Oct 14 13:24:25 2014 (r273086) +++ head/share/man/man4/gif.4 Tue Oct 14 13:31:47 2014 (r273087) @@ -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: head/sys/net/if_gif.c ============================================================================== --- head/sys/net/if_gif.c Tue Oct 14 13:24:25 2014 (r273086) +++ head/sys/net/if_gif.c Tue Oct 14 13:31:47 2014 (r273087) @@ -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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include "opt_inet.h" #include "opt_inet6.h" @@ -37,11 +39,14 @@ #include <sys/systm.h> #include <sys/jail.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/module.h> +#include <sys/rmlock.h> #include <sys/socket.h> #include <sys/sockio.h> +#include <sys/sx.h> #include <sys/errno.h> #include <sys/time.h> #include <sys/sysctl.h> @@ -64,6 +69,7 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/ip_ecn.h> #ifdef INET #include <netinet/in_var.h> #include <netinet/in_gif.h> @@ -76,6 +82,7 @@ #endif #include <netinet6/in6_var.h> #include <netinet/ip6.h> +#include <netinet6/ip6_ecn.h> #include <netinet6/ip6_var.h> #include <netinet6/scope6_var.h> #include <netinet6/in6_gif.h> @@ -99,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) @@ -111,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); @@ -168,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; @@ -189,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) @@ -200,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); } @@ -289,162 +279,193 @@ 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); - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - -/* Done by IFQ_HANDOFF */ -/* if_inc_counter(ifp, IFCOUNTER_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 && m->m_len < sizeof(struct etherip_header)) + m = m_pullup(m, sizeof(struct etherip_header)); + 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) - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - + 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; } /* @@ -461,9 +482,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++; @@ -472,73 +492,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) - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + 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 */ @@ -546,15 +547,55 @@ 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); } @@ -568,7 +609,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; } /* @@ -595,33 +636,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) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - 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)); @@ -666,48 +697,55 @@ gif_input(struct mbuf *m, int af, struct 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 */ + error = EINVAL; switch (cmd) { #ifdef INET case SIOCSIFPHYADDR: @@ -726,164 +764,169 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, break; #endif 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 */ + 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: -#ifdef INET6 + case SIOCGIFPDSTADDR: case SIOCGIFPSRCADDR_IN6: -#endif /* INET6 */ - if (sc->gif_psrc == NULL) { + case SIOCGIFPDSTADDR_IN6: + 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); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201410141331.s9EDVlXw037463>