svn commit: r276149 - in stable/10: share/man/man4 sys/conf sys/net sys/netinet sys/netinet6
Andrey V. Elsukov
ae at FreeBSD.org
Tue Dec 23 16:33:46 UTC 2014
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 <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>
@@ -53,6 +58,7 @@
#include <machine/cpu.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
@@ -63,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>
@@ -75,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>
@@ -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 ***
More information about the svn-src-all
mailing list