From c9f56c04dcb55ee71514b963e416d29c2e08983e Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 31 Jan 2005 23:49:36 +0000 Subject: [PATCH] Add RFC 3378 EtherIP support, ported from OpenBSD to NetBSD by Hans Rosenfeld (rosenfeld at grumpf.hope-2000.org) 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. --- sys/net/if_bridge.c | 40 ++++++++++++++++++++++--- sys/net/if_ethersubr.c | 30 +++++++++++-------- sys/net/if_gif.c | 68 ++++++++++++++++++++++++++++++++++++++++-- sys/netinet/in.h | 3 +- sys/netinet/in_gif.c | 26 ++++++++++++++-- sys/netinet/in_gif.h | 10 ++++++- sys/netinet/in_proto.c | 13 ++++++-- sys/sys/mbuf.h | 3 +- 8 files changed, 167 insertions(+), 26 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index d55bfc525912..21642cffb934 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridge.c,v 1.27 2004/12/04 18:31:43 peter Exp $ */ +/* $NetBSD: if_bridge.c,v 1.28 2005/01/31 23:49:36 kim Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -80,12 +80,13 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.27 2004/12/04 18:31:43 peter Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.28 2005/01/31 23:49:36 kim Exp $"); #include "opt_bridge_ipf.h" #include "opt_inet.h" #include "opt_pfil_hooks.h" #include "bpfilter.h" +#include "gif.h" #include #include @@ -580,7 +581,10 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif) */ (void) ifpromisc(ifs, 0); break; - +#if NGIF > 0 + case IFT_GIF: + break; +#endif default: #ifdef DIAGNOSTIC panic("bridge_delete_member: impossible"); @@ -633,7 +637,10 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) if (error) goto out; break; - +#if NGIF > 0 + case IFT_GIF: + break; +#endif default: error = EINVAL; goto out; @@ -1157,6 +1164,7 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, #endif /* ALTQ */ len = m->m_pkthdr.len; + m->m_flags |= M_PROTO1; mflags = m->m_flags; IFQ_ENQUEUE(&dst_ifp->if_snd, m, &pktattr, error); if (error) { @@ -1480,6 +1488,20 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) return (m); /* Perform the bridge forwarding function with the copy. */ +#if NGIF > 0 + if (ifp->if_type == IFT_GIF) { + LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { + if (bif->bif_ifp->if_type == IFT_ETHER) + break; + } + if (bif != NULL) { + m->m_flags |= M_PROTO1; + m->m_pkthdr.rcvif = bif->bif_ifp; + (*bif->bif_ifp->if_input)(bif->bif_ifp, m); + m = NULL; + } + } +#endif bridge_forward(sc, mc); /* Return the original packet for local processing. */ @@ -1499,6 +1521,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_ETHER) + continue; /* It is destined for us. */ if (memcmp(LLADDR(bif->bif_ifp->if_sadl), eh->ether_dhost, ETHER_ADDR_LEN) == 0) { @@ -1506,6 +1530,14 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) (void) bridge_rtupdate(sc, eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); m->m_pkthdr.rcvif = bif->bif_ifp; +#if NGIF > 0 + if (ifp->if_type == IFT_GIF) { + m->m_flags |= M_PROTO1; + m->m_pkthdr.rcvif = bif->bif_ifp; + (*bif->bif_ifp->if_input)(bif->bif_ifp, m); + m = NULL; + } +#endif return (m); } diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 4d41d97fc84c..34539e858527 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ethersubr.c,v 1.118 2005/01/08 03:18:18 yamt Exp $ */ +/* $NetBSD: if_ethersubr.c,v 1.119 2005/01/31 23:49:36 kim Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.118 2005/01/08 03:18:18 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.119 2005/01/31 23:49:36 kim Exp $"); #include "opt_inet.h" #include "opt_atalk.h" @@ -726,18 +726,22 @@ ether_input(struct ifnet *ifp, struct mbuf *m) * process it locally. */ if (ifp->if_bridge) { - /* clear M_PROMISC, in case the packets comes from a vlan */ - m->m_flags &= ~M_PROMISC; - m = bridge_input(ifp, m); - if (m == NULL) - return; + if(m->m_flags & M_PROTO1) { + m->m_flags &= ~M_PROTO1; + } else { + /* clear M_PROMISC, in case the packets comes from a vlan */ + m->m_flags &= ~M_PROMISC; + m = bridge_input(ifp, m); + if (m == NULL) + return; - /* - * Bridge has determined that the packet is for us. - * Update our interface pointer -- we may have had - * to "bridge" the packet locally. - */ - ifp = m->m_pkthdr.rcvif; + /* + * Bridge has determined that the packet is for us. + * Update our interface pointer -- we may have had + * to "bridge" the packet locally. + */ + ifp = m->m_pkthdr.rcvif; + } } else #endif /* NBRIDGE > 0 */ { diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index eb09e39a5b98..a2bf0a9bd302 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_gif.c,v 1.47 2004/12/04 18:31:43 peter Exp $ */ +/* $NetBSD: if_gif.c,v 1.48 2005/01/31 23:49:36 kim Exp $ */ /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */ /* @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.47 2004/12/04 18:31:43 peter Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.48 2005/01/31 23:49:36 kim Exp $"); #include "opt_inet.h" #include "opt_iso.h" @@ -82,9 +82,12 @@ __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.47 2004/12/04 18:31:43 peter Exp $"); #endif #include +#include +#include #include #include "bpfilter.h" +#include "bridge.h" #include @@ -93,6 +96,7 @@ void gifattach __P((int)); void gifnetisr __P((void)); #endif void gifintr __P((void *)); +void gif_start __P((struct ifnet *)); #ifdef ISO static struct mbuf *gif_eon_encap __P((struct mbuf *)); static struct mbuf *gif_eon_decap __P((struct ifnet *, struct mbuf *)); @@ -163,6 +167,7 @@ gifattach0(sc) sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; sc->gif_if.if_ioctl = gif_ioctl; sc->gif_if.if_output = gif_output; + sc->gif_if.if_start = gif_start; sc->gif_if.if_type = IFT_GIF; sc->gif_if.if_dlt = DLT_NULL; IFQ_SET_READY(&sc->gif_if.if_snd); @@ -198,6 +203,18 @@ gif_clone_destroy(ifp) return (0); } +void +gif_start(ifp) + struct ifnet *ifp; +{ +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + softintr_schedule(((struct gif_softc*)ifp)->gif_si); +#else + /* XXX bad spl level? */ + gifnetisr(); +#endif +} + #ifdef GIF_ENCAPCHECK int gif_encapcheck(m, off, proto, arg) @@ -232,6 +249,10 @@ gif_encapcheck(m, off, proto, arg) #ifdef ISO case IPPROTO_EON: break; +#endif +#if NBRIDGE > 0 + case IPPROTO_ETHERIP: + break; #endif default: return 0; @@ -391,6 +412,17 @@ gifintr(arg) if (m == NULL) break; +#if NBRIDGE > 0 + if(m->m_flags & M_PROTO1) { + M_PREPEND(m, sizeof(int), M_DONTWAIT); + if (!m) { + ifp->if_oerrors++; + continue; + } + *mtod(m, int *) = AF_LINK; + } + +#endif /* grab and chop off inner af type */ if (sizeof(int) > m->m_len) { m = m_pullup(m, sizeof(int)); @@ -443,6 +475,7 @@ gif_input(m, af, ifp) { int s, isr; struct ifqueue *ifq = NULL; + struct ether_header *eh; if (ifp == NULL) { /* just in case */ @@ -489,6 +522,37 @@ gif_input(m, af, ifp) ifq = &clnlintrq; isr = NETISR_ISO; break; +#endif +#if NBRIDGE > 0 + case AF_LINK: + m_adj(m, sizeof(struct etherip_header)); + if (sizeof(struct ether_header) > m->m_len) { + m = m_pullup(m, sizeof(struct ether_header)); + if (!m) { + ifp->if_ierrors++; + return; + } + } + eh = mtod(m, struct ether_header *); + m->m_flags &= ~(M_BCAST|M_MCAST); + if (eh->ether_dhost[0] & 1) { + if (bcmp((caddr_t) etherbroadcastaddr, + (caddr_t)eh->ether_dhost, sizeof(etherbroadcastaddr)) == 0) + m->m_flags |= M_BCAST; + else + m->m_flags |= M_MCAST; + } + m->m_pkthdr.rcvif = ifp; + if(ifp->if_bridge) { + if (m->m_flags & (M_BCAST|M_MCAST)) + ifp->if_imcasts++; + + s = splnet(); + m = bridge_input(ifp, m); + splx(s); + if (m == NULL) + return; + } #endif default: m_freem(m); diff --git a/sys/netinet/in.h b/sys/netinet/in.h index bedfeb6a7aa8..a7ce8305cf40 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.69 2004/12/15 04:25:19 thorpej Exp $ */ +/* $NetBSD: in.h,v 1.70 2005/01/31 23:49:36 kim Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -97,6 +97,7 @@ typedef __sa_family_t sa_family_t; #define IPPROTO_NONE 59 /* IP6 no next header */ #define IPPROTO_DSTOPTS 60 /* IP6 destination option */ #define IPPROTO_EON 80 /* ISO cnlp */ +#define IPPROTO_ETHERIP 97 /* Ethernet-in-IP */ #define IPPROTO_ENCAP 98 /* encapsulation header */ #define IPPROTO_PIM 103 /* Protocol indep. multicast */ #define IPPROTO_IPCOMP 108 /* IP Payload Comp. Protocol */ diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 1b0e4204a31d..e1d3228da072 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_gif.c,v 1.36 2004/04/26 01:31:56 matt Exp $ */ +/* $NetBSD: in_gif.c,v 1.37 2005/01/31 23:49:36 kim Exp $ */ /* $KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.36 2004/04/26 01:31:56 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.37 2005/01/31 23:49:36 kim Exp $"); #include "opt_inet.h" #include "opt_iso.h" @@ -65,6 +65,8 @@ __KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.36 2004/04/26 01:31:56 matt Exp $"); #include #include "gif.h" +#include "bridge.h" +#include #include @@ -97,6 +99,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; @@ -144,6 +147,20 @@ in_gif_output(ifp, family, m) proto = IPPROTO_EON; tos = 0; break; +#endif +#if NBRIDGE > 0 + 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; #endif default: #ifdef DEBUG @@ -291,6 +308,11 @@ in_gif_input(struct mbuf *m, ...) case IPPROTO_EON: af = AF_ISO; break; +#endif +#if NBRIDGE > 0 + case IPPROTO_ETHERIP: + af = AF_LINK; + break; #endif default: ipstat.ips_nogif++; diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h index be5ed0712aae..84a95ee4046c 100644 --- a/sys/netinet/in_gif.h +++ b/sys/netinet/in_gif.h @@ -1,4 +1,4 @@ -/* $NetBSD: in_gif.h,v 1.10 2004/04/21 17:49:46 itojun Exp $ */ +/* $NetBSD: in_gif.h,v 1.11 2005/01/31 23:49:36 kim Exp $ */ /* $KAME: in_gif.h,v 1.6 2001/07/25 00:55:48 itojun Exp $ */ /* @@ -46,4 +46,12 @@ int gif_encapcheck4(const struct mbuf *, int, int, void *); int in_gif_attach(struct gif_softc *); int in_gif_detach(struct gif_softc *); +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 + #endif /*_NETINET_IN_GIF_H_*/ diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 350479b9a40e..0fc7bafa05b8 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_proto.c,v 1.66 2005/01/23 18:41:57 matt Exp $ */ +/* $NetBSD: in_proto.c,v 1.67 2005/01/31 23:49:36 kim Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.66 2005/01/23 18:41:57 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.67 2005/01/31 23:49:36 kim Exp $"); #include "opt_mrouting.h" #include "opt_eon.h" /* ISO CLNL over IP */ @@ -146,6 +146,8 @@ __KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.66 2005/01/23 18:41:57 matt Exp $"); #include #endif +#include "bridge.h" + DOMAIN_DEFINE(inetdomain); /* forward declare and add to link set */ const struct protosw inetsw[] = { @@ -224,6 +226,13 @@ const struct protosw inetsw[] = { encap_init, 0, 0, 0, }, #endif /* INET6 */ +#if NBRIDGE > 0 +{ SOCK_RAW, &inetdomain, IPPROTO_ETHERIP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, + encap4_input, rip_output, rip_ctlinput, rip_ctloutput, + rip_usrreq, + encap_init, 0, 0, 0, +}, +#endif #if NGRE > 0 { SOCK_RAW, &inetdomain, IPPROTO_GRE, PR_ATOMIC|PR_ADDR|PR_LASTHDR, gre_input, rip_output, rip_ctlinput, rip_ctloutput, diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index b7b5666b5a29..cfe2fe75bb03 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $NetBSD: mbuf.h,v 1.99 2004/09/21 21:57:30 yamt Exp $ */ +/* $NetBSD: mbuf.h,v 1.100 2005/01/31 23:49:36 kim Exp $ */ /*- * Copyright (c) 1996, 1997, 1999, 2001 The NetBSD Foundation, Inc. @@ -272,6 +272,7 @@ MBUF_DEFINE(mbuf, MHLEN, MLEN); #define M_EXT 0x0001 /* has associated external storage */ #define M_PKTHDR 0x0002 /* start of record */ #define M_EOR 0x0004 /* end of record */ +#define M_PROTO1 0x0008 /* protocol-specific */ /* mbuf pkthdr flags, also in m_flags */ #define M_AUTHIPHDR 0x0010 /* data origin authentication for IP header */