summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/if_bridge.417
-rw-r--r--sys/net/if_bridge.c26
-rw-r--r--sys/net/if_gif.c71
-rw-r--r--sys/net/if_gif.h8
-rw-r--r--sys/netinet/in_gif.c19
-rw-r--r--sys/netinet/in_proto.c10
-rw-r--r--sys/netinet6/in6_gif.c19
7 files changed, 160 insertions, 10 deletions
diff --git a/share/man/man4/if_bridge.4 b/share/man/man4/if_bridge.4
index 0dc4b05..66ca881 100644
--- a/share/man/man4/if_bridge.4
+++ b/share/man/man4/if_bridge.4
@@ -173,7 +173,24 @@ ifconfig bridge0 \e
addm fxp7 stp fxp7 \e
up
.Ed
+.Pp
+The bridge can tunnel Ethernet across an IP internet using the EtherIP
+protocol.
+This can be combined with
+.Xr ipsec 4
+to provide an encrypted connection.
+Create a
+.Xr gif 4
+interface and set the local and remote IP addresses for the
+tunnel, these are reversed on the remote bridge.
+.Bd -literal -offset indent
+ifconfig gif0 create
+ifconfig gif0 tunnel 1.2.3.4 5.6.7.8 up
+ifconfig bridge0 create
+ifconfig bridge0 addm fxp0 addm gif0 up
+.Ed
.Sh SEE ALSO
+.Xr gif 4 ,
.Xr ipf 4 ,
.Xr ipfw 4 ,
.Xr pf 4 ,
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index a91adbd..d98052f 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -724,6 +724,9 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
(void) ifpromisc(ifs, 0);
break;
+ case IFT_GIF:
+ break;
+
default:
#ifdef DIAGNOSTIC
panic("bridge_delete_member: impossible");
@@ -781,12 +784,15 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
if (ifs == bif->bif_ifp)
return (EBUSY);
- /* Allow the first member to define the MTU */
- if (LIST_EMPTY(&sc->sc_iflist))
- sc->sc_ifp->if_mtu = ifs->if_mtu;
- else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
- if_printf(sc->sc_ifp, "invalid MTU for %s\n", ifs->if_xname);
- return (EINVAL);
+ /* Allow the first Ethernet member to define the MTU */
+ if (ifs->if_type != IFT_GIF) {
+ if (LIST_EMPTY(&sc->sc_iflist))
+ sc->sc_ifp->if_mtu = ifs->if_mtu;
+ else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
+ if_printf(sc->sc_ifp, "invalid MTU for %s\n",
+ ifs->if_xname);
+ return (EINVAL);
+ }
}
if (ifs->if_bridge == sc)
@@ -810,6 +816,9 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
goto out;
break;
+ case IFT_GIF:
+ break;
+
default:
error = EINVAL;
goto out;
@@ -1553,6 +1562,9 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
dst_if = bif->bif_ifp;
+
+ if (dst_if->if_type == IFT_GIF)
+ continue;
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
continue;
@@ -1944,6 +1956,8 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
* Unicast. Make sure it's not for us.
*/
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+ if(bif->bif_ifp->if_type == IFT_GIF)
+ continue;
/* It is destined for us. */
if (memcmp(IF_LLADDR(bif->bif_ifp), eh->ether_dhost,
ETHER_ADDR_LEN) == 0) {
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index c946a1c..940e00e 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -80,6 +80,8 @@
#endif /* INET6 */
#include <netinet/ip_encap.h>
+#include <net/ethernet.h>
+#include <net/if_bridgevar.h>
#include <net/if_gif.h>
#include <net/net_osdep.h>
@@ -99,6 +101,7 @@ 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_clone_create(struct if_clone *, int);
static void gif_clone_destroy(struct ifnet *);
@@ -177,6 +180,7 @@ gifattach0(sc)
GIF2IFP(sc)->if_flags |= IFF_LINK2;
#endif
GIF2IFP(sc)->if_ioctl = gif_ioctl;
+ GIF2IFP(sc)->if_start = gif_start;
GIF2IFP(sc)->if_output = gif_output;
GIF2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(GIF2IFP(sc));
@@ -289,6 +293,9 @@ gif_encapcheck(m, off, proto, arg)
case IPPROTO_IPV6:
break;
#endif
+ case IPPROTO_ETHERIP:
+ break;
+
default:
return 0;
}
@@ -321,6 +328,28 @@ gif_encapcheck(m, off, proto, arg)
}
}
+static void
+gif_start(struct ifnet *ifp)
+{
+ struct gif_softc *sc;
+ struct mbuf *m;
+
+ sc = ifp->if_softc;
+
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ for (;;) {
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ break;
+
+ gif_output(ifp, m, sc->gif_pdst, NULL);
+
+ }
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ return;
+}
+
int
gif_output(ifp, m, dst, rt)
struct ifnet *ifp;
@@ -395,13 +424,17 @@ gif_output(ifp, m, dst, rt)
dst->sa_family = af;
}
+ af = dst->sa_family;
if (ifp->if_bpf) {
- af = dst->sa_family;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
}
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
+ /* override to IPPROTO_ETHERIP for bridged traffic */
+ if (ifp->if_bridge)
+ af = AF_LINK;
+
/* inner AF-specific encapsulation */
/* XXX should we check if our outer source is legal? */
@@ -410,12 +443,12 @@ gif_output(ifp, m, dst, rt)
switch (sc->gif_psrc->sa_family) {
#ifdef INET
case AF_INET:
- error = in_gif_output(ifp, dst->sa_family, m);
+ error = in_gif_output(ifp, af, m);
break;
#endif
#ifdef INET6
case AF_INET6:
- error = in6_gif_output(ifp, dst->sa_family, m);
+ error = in6_gif_output(ifp, af, m);
break;
#endif
default:
@@ -436,7 +469,8 @@ gif_input(m, af, ifp)
int af;
struct ifnet *ifp;
{
- int isr;
+ int isr, n;
+ struct etherip_header *eip;
if (ifp == NULL) {
/* just in case */
@@ -483,6 +517,35 @@ gif_input(m, af, ifp)
isr = NETISR_IPV6;
break;
#endif
+ case AF_LINK:
+ n = sizeof(struct etherip_header) + sizeof(struct ether_header);
+ if (n > m->m_len) {
+ m = m_pullup(m, n);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ }
+
+ eip = mtod(m, struct etherip_header *);
+ if (eip->eip_ver !=
+ (ETHERIP_VERSION & ETHERIP_VER_VERS_MASK)) {
+ /* discard unknown versions */
+ m_freem(m);
+ return;
+ }
+ m_adj(m, sizeof(struct etherip_header));
+
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+ m->m_pkthdr.rcvif = ifp;
+
+ if (ifp->if_bridge)
+ BRIDGE_INPUT(ifp, m);
+
+ if (m != NULL)
+ m_freem(m);
+ return;
+
default:
if (ng_gif_input_orphan_p != NULL)
(*ng_gif_input_orphan_p)(ifp, m, af);
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 831c7f7..698c6703 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -85,6 +85,14 @@ struct gif_softc {
#define MTAG_GIF 1080679712
#define MTAG_GIF_CALLED 0
+struct etherip_header {
+ u_int8_t eip_ver; /* version/reserved */
+ u_int8_t eip_pad; /* required padding byte */
+};
+#define ETHERIP_VER_VERS_MASK 0x0f
+#define ETHERIP_VER_RSVD_MASK 0xf0
+#define ETHERIP_VERSION 0x03
+
/* Prototypes */
void gifattach0(struct gif_softc *);
void gif_input(struct mbuf *, int, struct ifnet *);
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index 0eae228..cc6b64d 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -100,6 +100,7 @@ in_gif_output(ifp, family, m)
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 proto, error;
u_int8_t tos;
@@ -142,6 +143,20 @@ in_gif_output(ifp, family, m)
break;
}
#endif /* INET6 */
+ case AF_LINK:
+ proto = IPPROTO_ETHERIP;
+ eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
+ eiphdr.eip_pad = 0;
+ /* prepend Ethernet-in-IP header */
+ M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
+ 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));
+ break;
+
default:
#ifdef DEBUG
printf("in_gif_output: warning: unknown family %d passed\n",
@@ -302,6 +317,10 @@ in_gif_input(m, off)
break;
}
#endif /* INET6 */
+ case IPPROTO_ETHERIP:
+ af = AF_LINK;
+ break;
+
default:
ipstat.ips_nogif++;
m_freem(m);
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index fefb4bc..d8caddd 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -260,6 +260,16 @@ struct protosw inetsw[] = {
{
.pr_type = SOCK_RAW,
.pr_domain = &inetdomain,
+ .pr_protocol = IPPROTO_ETHERIP,
+ .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+ .pr_input = encap4_input,
+ .pr_ctloutput = rip_ctloutput,
+ .pr_init = encap_init,
+ .pr_usrreqs = &rip_usrreqs
+},
+{
+ .pr_type = SOCK_RAW,
+ .pr_domain = &inetdomain,
.pr_protocol = IPPROTO_GRE,
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
.pr_input = encap4_input,
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 632ff8f..41c34f2 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -93,6 +93,7 @@ in6_gif_output(ifp, family, m)
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 proto, error;
u_int8_t itos, otos;
@@ -135,6 +136,20 @@ in6_gif_output(ifp, family, m)
break;
}
#endif
+ case AF_LINK:
+ proto = IPPROTO_ETHERIP;
+ eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
+ eiphdr.eip_pad = 0;
+ /* prepend Ethernet-in-IP header */
+ M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
+ 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));
+ break;
+
default:
#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
@@ -301,6 +316,10 @@ in6_gif_input(mp, offp, proto)
break;
}
#endif
+ case IPPROTO_ETHERIP:
+ af = AF_LINK;
+ break;
+
default:
ip6stat.ip6s_nogif++;
m_freem(m);
OpenPOWER on IntegriCloud