Add RFC 3378 EtherIP support. This change makes it possible to add gif
interfaces to bridges, which will then send and receive IP protocol 97 packets. Packets are Ethernet frames with an EtherIP header prepended. Obtained from: NetBSD MFC after: 2 weeks
This commit is contained in:
parent
373d1a3f8c
commit
73ff045c57
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=153621
@ -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 ,
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -257,6 +257,16 @@ struct protosw inetsw[] = {
|
||||
.pr_init = encap_init,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
},
|
||||
{
|
||||
.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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user