summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2014-12-23 16:33:44 +0000
committerae <ae@FreeBSD.org>2014-12-23 16:33:44 +0000
commit7a82e24551b11b26164c99f1cf257be33793fdb0 (patch)
tree8fc4bf8849b5d3379bc90002e8e1e43fc1250d65
parent9cec8144119c5694ae6d69790232cbcb9ef1e0b5 (diff)
downloadFreeBSD-src-7a82e24551b11b26164c99f1cf257be33793fdb0.zip
FreeBSD-src-7a82e24551b11b26164c99f1cf257be33793fdb0.tar.gz
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.
-rw-r--r--share/man/man4/gif.412
-rw-r--r--sys/conf/files5
-rw-r--r--sys/net/if_gif.c943
-rw-r--r--sys/net/if_gif.h62
-rw-r--r--sys/netinet/in_gif.c361
-rw-r--r--sys/netinet/in_gif.h7
-rw-r--r--sys/netinet6/in6_gif.c313
-rw-r--r--sys/netinet6/in6_gif.h5
8 files changed, 635 insertions, 1073 deletions
diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4
index 453b4bd..27ee61b 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 2b97f68..88d32c0 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 4bec9b6..a98fb19 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 <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 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 d6e58f5..b5ebf15 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 <netinet/in.h>
-/* 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 abaf9b1..c4df3b3 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_mrouting.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/rmlock.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -48,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/route.h>
#include <net/vnet.h>
@@ -64,22 +66,19 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip6.h>
#endif
-#ifdef MROUTING
-#include <netinet/ip_mroute.h>
-#endif /* MROUTING */
-
-#include <net/if_gif.h>
+#include <net/if_gif.h>
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 e1f4ae4..d48d881 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 97bc4a5..1872f5c 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/rmlock.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -49,7 +51,9 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/route.h>
+#include <net/vnet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -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 e118417..1246171 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_ */
OpenPOWER on IntegriCloud