gre (the protocol) can easily encapsulate ethernet. this addes an
egre interface that allows configuration of such a thing.

the only caveat with it is that the protocol doesnt pad ethernet
frames, so theyre misaligned. egre copes with this on input by
copying the payload to new, aligned memory if needed. on tx it
unconditionally prepends an mbuf for the gre and encapsulating ip
headers to go into.

it looks a lot like vxlan when set up:

$ ifconfig -C
bridge carp egre enc etherip gif gre lo mobileip mpe mpw pair pflog pflow 
pfsync ppp pppoe svlan switch tap trunk tun vether vlan vxlan
$ ifconfig egre0                                                     
egre0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr fe:e1:ba:d0:43:48
        index 8 priority 0 llprio 3
        encap: vnetid 100
        groups: egre
        tunnel: inet 192.168.96.40 -> 192.168.96.54 ttl 64
        inet 100.64.9.1 netmask 0xffffff00 broadcast 100.64.9.255

and cos it's ethernet it can be bridged to other ethernet interfaces.

ok?

Index: if_gre.c
===================================================================
RCS file: /cvs/src/sys/net/if_gre.c,v
retrieving revision 1.93
diff -u -p -r1.93 if_gre.c
--- if_gre.c    8 Feb 2018 05:00:37 -0000       1.93
+++ if_gre.c    8 Feb 2018 08:40:57 -0000
@@ -165,6 +165,10 @@ static struct mbuf *
 static int
                gre_ip_output(const struct gre_tunnel *, struct mbuf *,
                    uint8_t);
+
+static int     gre_tunnel_ioctl(struct ifnet *, struct gre_tunnel *,
+                   u_long, void *);
+
 /*
  * layer 3 GRE tunnels
  */
@@ -215,12 +219,39 @@ static int        gre_input_key(struct mbuf **,
                    struct gre_tunnel *);
 
 static struct mbuf *
-               gre_encap(struct gre_softc *, struct mbuf *, uint8_t *);
+               gre_encap(struct gre_tunnel *, struct mbuf *, uint16_t);
 
 static void    gre_keepalive_send(void *);
 static void    gre_keepalive_recv(struct ifnet *ifp, struct mbuf *);
 static void    gre_keepalive_hold(void *);
 
+/*
+ * Ethernet GRE tunnels
+ */
+
+struct egre_softc {
+       struct gre_tunnel       sc_tunnel; /* must be first */
+       struct arpcom           sc_ac;
+       struct ifmedia          sc_media;
+};
+
+static int     egre_clone_create(struct if_clone *, int);
+static int     egre_clone_destroy(struct ifnet *);
+
+static void    egre_start(struct ifnet *);
+static int     egre_ioctl(struct ifnet *, u_long, caddr_t);
+static int     egre_media_change(struct ifnet *);
+static void    egre_media_status(struct ifnet *, struct ifmediareq *);
+
+static int     egre_up(struct egre_softc *);
+static int     egre_down(struct egre_softc *);
+
+static int     egre_input(const struct gre_tunnel *, struct mbuf *, int);
+
+struct if_clone egre_cloner =
+    IF_CLONE_INITIALIZER("egre", egre_clone_create, egre_clone_destroy);
+
+struct gre_tree egre_softcs = RBT_INITIALIZER();
 
 /*
  * It is not easy to calculate the right value for a GRE MTU.
@@ -245,6 +276,7 @@ void
 greattach(int n)
 {
        if_clone_attach(&gre_cloner);
+       if_clone_attach(&egre_cloner);
 }
 
 static int
@@ -302,6 +334,58 @@ gre_clone_destroy(struct ifnet *ifp)
        return (0);
 }
 
+static int
+egre_clone_create(struct if_clone *ifc, int unit)
+{
+       struct egre_softc *sc;
+       struct ifnet *ifp;
+
+       sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
+       ifp = &sc->sc_ac.ac_if;
+
+       snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
+           ifc->ifc_name, unit);
+
+       ifp->if_softc = sc;
+       ifp->if_mtu = 1500; /* XXX */
+       ifp->if_ioctl = egre_ioctl;
+       ifp->if_start = egre_start;
+       ifp->if_xflags = IFXF_CLONED;
+       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ether_fakeaddr(ifp);
+
+       sc->sc_tunnel.t_ttl = ip_defttl;
+
+       ifmedia_init(&sc->sc_media, 0, egre_media_change, egre_media_status);
+       ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+       ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
+
+       if_attach(ifp);
+       ether_ifattach(ifp);
+
+       return (0);
+}
+
+static int
+egre_clone_destroy(struct ifnet *ifp)
+{
+       struct egre_softc *sc = ifp->if_softc;
+
+       NET_LOCK();
+       if (ISSET(ifp->if_flags, IFF_RUNNING))
+               egre_down(sc);
+       NET_UNLOCK();
+
+       ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
+       ether_ifdetach(ifp);
+       if_detach(ifp);
+
+       free(sc, M_DEVBUF, sizeof(*sc));
+
+       return (0);
+}
+
 int
 gre_input(struct mbuf **mp, int *offp, int type, int af)
 {
@@ -355,6 +439,7 @@ gre_input_key(struct mbuf **mp, int *off
        struct gre_h_key *gkh;
        void (*input)(struct ifnet *, struct mbuf *);
        int bpf_af = AF_UNSPEC; /* bpf */
+       int mcast = 0;
 
        if (!gre_allow)
                goto decline;
@@ -431,8 +516,10 @@ gre_input_key(struct mbuf **mp, int *off
                break;
 #endif
 #ifdef MPLS
-       case htons(ETHERTYPE_MPLS):
        case htons(ETHERTYPE_MPLS_MCAST):
+               mcast = M_MCAST|M_BCAST;
+               /* fallthrough */
+       case htons(ETHERTYPE_MPLS):
 #if NBPFILTER > 0
                bpf_af = AF_MPLS;
 #endif
@@ -446,7 +533,9 @@ gre_input_key(struct mbuf **mp, int *off
                input = gre_keepalive_recv;
                break;
 
-       case htons(ETHERTYPE_TRANSETHER): /* not yet */
+       case htons(ETHERTYPE_TRANSETHER):
+               if (egre_input(key, m, hlen) == -1)
+                       goto decline;
        default:
                goto decline;
        }
@@ -460,6 +549,7 @@ gre_input_key(struct mbuf **mp, int *off
        m_adj(m, hlen);
 
        m->m_flags &= ~(M_MCAST|M_BCAST);
+       m->m_flags |= mcast;
        m->m_pkthdr.ph_ifidx = ifp->if_index;
        m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
 
@@ -482,6 +572,57 @@ decline:
        return (-1);
 }
 
+static int
+egre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen)
+{
+       struct egre_softc *sc;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct mbuf *n;
+       int off;
+
+       sc = (struct egre_softc *)RBT_FIND(gre_tree, &egre_softcs, key);
+       if (sc == NULL)
+               return (-1);
+
+       /* it's ours now */
+
+       m_adj(m, hlen);
+
+       if (m->m_pkthdr.len < sizeof(struct ether_header)) {
+               m_freem(m);
+               return (0);
+       }
+
+       m = m_pullup(m, sizeof(struct ether_header));
+       if (m == NULL)
+               return (0);
+
+       n = m_getptr(m, sizeof(struct ether_header), &off);
+       if (n == NULL) {
+               m_freem(m);
+               return (0);
+       }
+
+       if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) {
+               n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
+               m_freem(m);
+               if (n == NULL)
+                       return (0);
+               m = n;
+       }
+
+       m->m_flags &= ~(M_MCAST|M_BCAST);
+
+#if NPF > 0
+       pf_pkt_addr_changed(m);
+#endif
+
+       ml_enqueue(&ml, m);
+       if_input(&sc->sc_ac.ac_if, &ml);
+
+       return (0);
+}
+
 static void
 gre_keepalive_recv(struct ifnet *ifp, struct mbuf *m)
 {
@@ -621,6 +762,7 @@ gre_start(struct ifnet *ifp)
        struct gre_softc *sc = ifp->if_softc;
        struct mbuf *m;
        uint8_t tos;
+       uint16_t proto;
 #if NBPFILTER > 0
        caddr_t if_bpf;
 #endif
@@ -642,7 +784,32 @@ gre_start(struct ifnet *ifp)
                pf_pkt_addr_changed(m);
 #endif
 
-               m = gre_encap(sc, m, &tos);
+               switch (m->m_pkthdr.ph_family) {
+               case AF_INET: {
+                       struct ip *ip = mtod(m, struct ip *);
+                       tos = ip->ip_tos;
+
+                       proto = htons(ETHERTYPE_IP);
+                       break;
+               }
+#ifdef INET6
+               case AF_INET6:
+                       proto = htons(ETHERTYPE_IPV6);
+                       break;
+#endif
+#ifdef MPLS
+               case AF_MPLS:
+                       if (m->m_flags & (M_BCAST | M_MCAST))
+                               proto = htons(ETHERTYPE_MPLS_MCAST);
+                       else
+                       proto = htons(ETHERTYPE_MPLS);
+                       break;
+#endif
+               default:
+                       unhandled_af(m->m_pkthdr.ph_family);
+               }
+
+               m = gre_encap(&sc->sc_tunnel, m, proto);
                if (m == NULL || gre_ip_output(&sc->sc_tunnel, m, tos) != 0) {
                        ifp->if_oerrors++;
                        continue;
@@ -650,6 +817,53 @@ gre_start(struct ifnet *ifp)
        }
 }
 
+static void
+egre_start(struct ifnet *ifp)
+{
+       struct egre_softc *sc = ifp->if_softc;
+       struct mbuf *m0, *m;
+#if NBPFILTER > 0
+       caddr_t if_bpf;
+#endif
+
+       if (!gre_allow)
+               ifq_purge(&ifp->if_snd);
+
+       while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) {
+#if NBPFILTER > 0
+               if_bpf = ifp->if_bpf;
+               if (if_bpf)
+                       bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT);
+#endif
+
+               m = m_gethdr(M_DONTWAIT, m0->m_type);
+               if (m == NULL) {
+                       m_freem(m0);
+                       continue;
+               }
+
+               M_MOVE_PKTHDR(m, m0);
+               m->m_next = m0;
+
+               MH_ALIGN(m, 0);
+               m->m_len = 0;
+
+               m->m_flags &= ~(M_MCAST|M_BCAST);
+               m->m_pkthdr.ph_ifidx = ifp->if_index;
+               m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
+
+#if NPF > 0
+               pf_pkt_addr_changed(m);
+#endif
+
+               m = gre_encap(&sc->sc_tunnel, m, htons(ETHERTYPE_TRANSETHER));
+               if (m == NULL || gre_ip_output(&sc->sc_tunnel, m, 0) != 0) {
+                       ifp->if_oerrors++;
+                       continue;
+               }
+       }
+}
+
 static int
 gre_ip_output(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t tos)
 {
@@ -675,44 +889,14 @@ gre_ip_output(const struct gre_tunnel *t
 }
 
 static struct mbuf *
-gre_encap(struct gre_softc *sc, struct mbuf *m, uint8_t *tos)
+gre_encap(struct gre_tunnel *tunnel, struct mbuf *m, uint16_t proto)
 {
        struct gre_header *gh;
        struct gre_h_key *gkh;
-       uint16_t proto;
        int hlen;
 
-       *tos = 0;
-       switch (m->m_pkthdr.ph_family) {
-       case AF_INET: {
-               proto = htons(ETHERTYPE_IP);
-
-               struct ip *ip = mtod(m, struct ip *);
-               *tos = ip->ip_tos;
-               break;
-       }
-#ifdef INET6
-       case AF_INET6:
-               proto = htons(ETHERTYPE_IPV6);
-               break;
-#endif
-#ifdef MPLS
-       case AF_MPLS:
-               if (m->m_flags & (M_BCAST | M_MCAST))
-                       proto = htons(ETHERTYPE_MPLS_MCAST);
-               else
-                       proto = htons(ETHERTYPE_MPLS);
-               break;
-#endif
-       case AF_UNSPEC:
-               proto = htons(0);
-               break;
-       default:
-               unhandled_af(m->m_pkthdr.ph_family);
-       }
-
        hlen = sizeof(*gh);
-       if (sc->sc_tunnel.t_key_mask != GRE_KEY_NONE)
+       if (tunnel->t_key_mask != GRE_KEY_NONE)
                hlen += sizeof(*gkh);
 
        m = m_prepend(m, hlen, M_DONTWAIT);
@@ -722,11 +906,11 @@ gre_encap(struct gre_softc *sc, struct m
        gh = mtod(m, struct gre_header *);
        gh->gre_flags = GRE_VERS_0;
        gh->gre_proto = proto;
-       if (sc->sc_tunnel.t_key_mask != GRE_KEY_NONE) {
+       if (tunnel->t_key_mask != GRE_KEY_NONE) {
                gh->gre_flags |= htons(GRE_KP);
 
                gkh = (struct gre_h_key *)(gh + 1);
-               gkh->gre_key = sc->sc_tunnel.t_key;
+               gkh->gre_key = tunnel->t_key;
        }
 
        return (m);
@@ -790,28 +974,13 @@ gre_ip_encap(const struct gre_tunnel *tu
 }
 
 static int
-gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+gre_tunnel_ioctl(struct ifnet *ifp, struct gre_tunnel *tunnel,
+    u_long cmd, void *data)
 {
-       struct gre_softc *sc = ifp->if_softc;
        struct ifreq *ifr = (struct ifreq *)data;
-       struct ifkalivereq *ikar = (struct ifkalivereq *)data;
        int error = 0;
 
        switch(cmd) {
-       case SIOCSIFADDR:
-               ifp->if_flags |= IFF_UP;
-               /* FALLTHROUGH */
-       case SIOCSIFFLAGS:
-               if (ISSET(ifp->if_flags, IFF_UP)) {
-                       if (!ISSET(ifp->if_flags, IFF_RUNNING))
-                               error = gre_up(sc);
-                       else
-                               error = 0;
-               } else {
-                       if (ISSET(ifp->if_flags, IFF_RUNNING))
-                               error = gre_down(sc);
-               }
-               break;
        case SIOCSIFMTU:
                if (ifr->ifr_mtu < 576) {
                        error = EINVAL;
@@ -830,49 +999,23 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
                }
                break;
 
-       case SIOCSETKALIVE:
-               if (ISSET(ifp->if_flags, IFF_RUNNING)) {
-                       error = EBUSY;
-                       break;
-               }
-
-               if (ikar->ikar_timeo < 0 || ikar->ikar_timeo > 86400 ||
-                   ikar->ikar_cnt < 0 || ikar->ikar_cnt > 256)
-                       return (EINVAL);
-
-               if (ikar->ikar_timeo == 0 || ikar->ikar_cnt == 0) {
-                       sc->sc_ka_count = 0;
-                       sc->sc_ka_timeo = 0;
-                       sc->sc_ka_state = GRE_KA_NONE;
-               } else {
-                       sc->sc_ka_count = ikar->ikar_cnt;
-                       sc->sc_ka_timeo = ikar->ikar_timeo;
-                       sc->sc_ka_state = GRE_KA_DOWN;
-               }
-               break;
-
-       case SIOCGETKALIVE:
-               ikar->ikar_cnt = sc->sc_ka_count;
-               ikar->ikar_timeo = sc->sc_ka_timeo;
-               break;
-
        case SIOCSVNETID:
                if (ISSET(ifp->if_flags, IFF_RUNNING)) {
                        error = EBUSY;
                        break;
                }
-               error = gre_set_vnetid(&sc->sc_tunnel, ifr);
+               error = gre_set_vnetid(tunnel, ifr);
                break;
 
        case SIOCGVNETID:
-               error = gre_get_vnetid(&sc->sc_tunnel, ifr);
+               error = gre_get_vnetid(tunnel, ifr);
                break;
        case SIOCDVNETID:
                if (ISSET(ifp->if_flags, IFF_RUNNING)) {
                        error = EBUSY;
                        break;
                }
-               error = gre_del_vnetid(&sc->sc_tunnel);
+               error = gre_del_vnetid(tunnel);
                break;
 
        case SIOCSLIFPHYADDR:
@@ -880,12 +1023,10 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
                        error = EBUSY;
                        break;
                }
-               error = gre_set_tunnel(&sc->sc_tunnel,
-                   (struct if_laddrreq *)data);
+               error = gre_set_tunnel(tunnel, (struct if_laddrreq *)data);
                break;
        case SIOCGLIFPHYADDR:
-               error = gre_get_tunnel(&sc->sc_tunnel,
-                   (struct if_laddrreq *)data);
+               error = gre_get_tunnel(tunnel, (struct if_laddrreq *)data);
                break;
        case SIOCDIFPHYADDR:
                if (ISSET(ifp->if_flags, IFF_RUNNING)) {
@@ -893,7 +1034,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
                        break;
                }
 
-               error = gre_del_tunnel(&sc->sc_tunnel);
+               error = gre_del_tunnel(tunnel);
                break;
 
        case SIOCSLIFPHYRTABLE:
@@ -908,10 +1049,10 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
                        error = EINVAL;
                        break;
                }
-               sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
+               tunnel->t_rtableid = ifr->ifr_rdomainid;
                break;
        case SIOCGLIFPHYRTABLE:
-               ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
+               ifr->ifr_rdomainid = tunnel->t_rtableid;
                break;
 
        case SIOCSLIFPHYTTL:
@@ -921,15 +1062,111 @@ gre_ioctl(struct ifnet *ifp, u_long cmd,
                }
 
                /* commit */
-               sc->sc_tunnel.t_ttl = (uint8_t)ifr->ifr_ttl;
+               tunnel->t_ttl = (uint8_t)ifr->ifr_ttl;
                break;
 
        case SIOCGLIFPHYTTL:
-               ifr->ifr_ttl = (int)sc->sc_tunnel.t_ttl;
+               ifr->ifr_ttl = (int)tunnel->t_ttl;
                break;
 
        default:
                error = ENOTTY;
+               break;
+       }
+
+       return (error);
+}
+
+static int
+gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct gre_softc *sc = ifp->if_softc;
+       struct ifkalivereq *ikar = (struct ifkalivereq *)data;
+       int error = 0;
+
+       switch(cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               /* FALLTHROUGH */
+       case SIOCSIFFLAGS:
+               if (ISSET(ifp->if_flags, IFF_UP)) {
+                       if (!ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = gre_up(sc);
+                       else
+                               error = 0;
+               } else {
+                       if (ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = gre_down(sc);
+               }
+               break;
+       case SIOCSIFRDOMAIN:
+               if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+                       error = EBUSY;
+                       break;
+               }
+               break;
+
+       case SIOCSETKALIVE:
+               if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+                       error = EBUSY;
+                       break;
+               }
+
+               if (ikar->ikar_timeo < 0 || ikar->ikar_timeo > 86400 ||
+                   ikar->ikar_cnt < 0 || ikar->ikar_cnt > 256)
+                       return (EINVAL);
+
+               if (ikar->ikar_timeo == 0 || ikar->ikar_cnt == 0) {
+                       sc->sc_ka_count = 0;
+                       sc->sc_ka_timeo = 0;
+                       sc->sc_ka_state = GRE_KA_NONE;
+               } else {
+                       sc->sc_ka_count = ikar->ikar_cnt;
+                       sc->sc_ka_timeo = ikar->ikar_timeo;
+                       sc->sc_ka_state = GRE_KA_DOWN;
+               }
+               break;
+
+       case SIOCGETKALIVE:
+               ikar->ikar_cnt = sc->sc_ka_count;
+               ikar->ikar_timeo = sc->sc_ka_timeo;
+               break;
+
+       default:
+               error = gre_tunnel_ioctl(ifp, &sc->sc_tunnel, cmd, data);
+               break;
+       }
+
+       return (error);
+}
+
+static int
+egre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct egre_softc *sc = ifp->if_softc;
+       int error = 0;
+
+       switch(cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               /* FALLTHROUGH */
+       case SIOCSIFFLAGS:
+               if (ISSET(ifp->if_flags, IFF_UP)) {
+                       if (!ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = egre_up(sc);
+                       else
+                               error = 0;
+               } else {
+                       if (ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = egre_down(sc);
+               }
+               break;
+
+       default:
+               error = gre_tunnel_ioctl(ifp, &sc->sc_tunnel, cmd, data);
+               if (error == ENOTTY)
+                       error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+               break;
        }
 
        return (error);
@@ -947,7 +1184,7 @@ gre_up(struct gre_softc *sc)
                return (EHOSTUNREACH);
 
        if (RBT_INSERT(gre_tree, &gre_softcs, &sc->sc_tunnel) != NULL)
-               return (EBUSY);
+               return (EADDRINUSE);
 
        /* we're up and running now */
 
@@ -1023,7 +1260,7 @@ gre_keepalive_send(void *arg)
        struct gre_keepalive *gk;
        SIPHASH_CTX ctx;
        int linkhdr, len;
-       uint8_t tos;
+       uint16_t proto;
 
        if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING) ||
            sc->sc_ka_state == GRE_KA_NONE)
@@ -1061,8 +1298,7 @@ gre_keepalive_send(void *arg)
        SipHash24_Update(&ctx, &gk->gk_random, sizeof(gk->gk_random));
        SipHash24_Final(gk->gk_digest, &ctx);
 
-       m->m_pkthdr.ph_family = AF_UNSPEC;
-       m = gre_encap(sc, m, &tos);
+       m = gre_encap(&sc->sc_tunnel, m, htons(0));
        if (m == NULL)
                return;
 
@@ -1070,11 +1306,12 @@ gre_keepalive_send(void *arg)
        t.t_ttl = sc->sc_tunnel.t_ttl;
        memcpy(t.t_src, sc->sc_tunnel.t_dst, sizeof(t.t_src));
        memcpy(t.t_dst, sc->sc_tunnel.t_src, sizeof(t.t_dst));
-       m = gre_ip_encap(&t, m, tos);
+       m = gre_ip_encap(&t, m, 0);
        if (m == NULL)
                return;
 
-       if (sc->sc_tunnel.t_af == AF_INET) {
+       switch (sc->sc_tunnel.t_af) {
+       case AF_INET: {
                struct ip *ip;
 
                ip = mtod(m, struct ip *);
@@ -1084,20 +1321,29 @@ gre_keepalive_send(void *arg)
                ip->ip_id = htons(ip_randomid());
                ip->ip_sum = 0;
                ip->ip_sum = in_cksum(m, sizeof(*ip));
+
+               proto = htons(ETHERTYPE_IP);
+               break;
+       }
+#ifdef INET6
+       case AF_INET6:
+               proto = htons(ETHERTYPE_IPV6);
+               break;
+#endif
        }
 
+
        /*
         * put it in the tunnel
         */
-       m->m_pkthdr.ph_family = sc->sc_tunnel.t_af;
-       m = gre_encap(sc, m, &tos);
+       m = gre_encap(&sc->sc_tunnel, m, proto);
        if (m == NULL)
                return;
 
        m->m_pkthdr.ph_ifidx = sc->sc_if.if_index;
        m->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
 
-       gre_ip_output(&sc->sc_tunnel, m, tos);
+       gre_ip_output(&sc->sc_tunnel, m, 0);
 
        timeout_add_sec(&sc->sc_ka_send, sc->sc_ka_timeo);
 }
@@ -1288,6 +1534,48 @@ gre_del_vnetid(struct gre_tunnel *tunnel
        return (0);
 }
 
+static int
+egre_up(struct egre_softc *sc)
+{
+       if (sc->sc_tunnel.t_af == AF_UNSPEC)
+               return (ENXIO);
+
+       NET_ASSERT_LOCKED(); 
+       if (RBT_INSERT(gre_tree, &egre_softcs, &sc->sc_tunnel) != NULL)
+               return (EADDRINUSE);
+
+       SET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING);
+
+       return (0);
+}
+
+static int
+egre_down(struct egre_softc *sc)
+{
+       NET_ASSERT_LOCKED();
+
+       RBT_REMOVE(gre_tree, &egre_softcs, &sc->sc_tunnel);
+
+       CLR(sc->sc_ac.ac_if.if_flags, IFF_RUNNING);
+
+       /* barrier? */
+
+       return (0);
+}
+
+static int
+egre_media_change(struct ifnet *ifp)
+{
+       return (ENOTTY);
+}
+
+static void
+egre_media_status(struct ifnet *ifp, struct ifmediareq *imr)
+{
+       imr->ifm_active = IFM_ETHER | IFM_AUTO;
+       imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+}
+
 int
 gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
     size_t newlen)
@@ -1311,7 +1599,7 @@ gre_sysctl(int *name, u_int namelen, voi
                return (error);
        default:
                return (ENOPROTOOPT);
-        }
+       }
        /* NOTREACHED */
 }
 

Reply via email to