i have a plan to allow virtual interfaces (eg, vlan, etherip, etc) to
provide their own output functions so they can bypass the ifq machinery
and push the packet onto the underlying layer directly.

they'll still need to get an ethernet header though. vlan needs to get
the ethernet header and put the vlan shim into it, therefore
ether_resolve is exposed. etherip doesnt need a shim, it just wants
ethernet encapsulating the payload before adding its own headers to the
packet, therefore there is ether_encap.

does this make sense?

ok?

Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.253
diff -u -p -r1.253 if_ethersubr.c
--- net/if_ethersubr.c  13 Mar 2018 01:31:48 -0000      1.253
+++ net/if_ethersubr.c  30 Nov 2018 02:02:58 -0000
@@ -178,24 +178,18 @@ ether_rtrequest(struct ifnet *ifp, int r
                break;
        }
 }
-/*
- * Ethernet output routine.
- * Encapsulate a packet of type family for the local net.
- * Assumes that ifp is actually pointer to arpcom structure.
- */
+
 int
-ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
-    struct rtentry *rt)
+ether_resolve(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct rtentry *rt, struct ether_header *eh)
 {
-       u_int16_t etype;
-       u_char edst[ETHER_ADDR_LEN];
-       u_char *esrc;
-       struct mbuf *mcopy = NULL;
-       struct ether_header *eh;
        struct arpcom *ac = (struct arpcom *)ifp;
        sa_family_t af = dst->sa_family;
        int error = 0;
 
+       if (!ISSET(ifp->if_flags, IFF_RUNNING))
+               senderr(ENETDOWN);
+
        KASSERT(rt != NULL || ISSET(m->m_flags, M_MCAST|M_BCAST) ||
                af == AF_UNSPEC || af == pseudo_AF_HDRCMPLT);
 
@@ -207,28 +201,31 @@ ether_output(struct ifnet *ifp, struct m
        }
 #endif
 
-       esrc = ac->ac_enaddr;
-
-       if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
-               senderr(ENETDOWN);
-
        switch (af) {
        case AF_INET:
-               error = arpresolve(ifp, rt, m, dst, edst);
+               error = arpresolve(ifp, rt, m, dst, eh->ether_dhost);
                if (error)
-                       return (error == EAGAIN ? 0 : error);
+                       return (error);
+               eh->ether_type = htons(ETHERTYPE_IP);
+
                /* If broadcasting on a simplex interface, loopback a copy */
-               if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
-                   !m->m_pkthdr.pf.routed)
+               if (ISSET(m->m_flags, M_BCAST) &&
+                   ISSET(ifp->if_flags, IFF_SIMPLEX) &&
+                   !m->m_pkthdr.pf.routed) {
+                       struct mbuf *mcopy;
+
+                       /* XXX Should we input an unencrypted IPsec packet? */
                        mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-               etype = htons(ETHERTYPE_IP);
+                       if (mcopy != NULL)
+                               if_input_local(ifp, mcopy, af);
+               }
                break;
 #ifdef INET6
        case AF_INET6:
-               error = nd6_resolve(ifp, rt, m, dst, edst);
+               error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost);
                if (error)
-                       return (error == EAGAIN ? 0 : error);
-               etype = htons(ETHERTYPE_IPV6);
+                       return (error);
+               eh->ether_type = htons(ETHERTYPE_IPV6);
                break;
 #endif
 #ifdef MPLS
@@ -242,72 +239,102 @@ ether_output(struct ifnet *ifp, struct m
                        senderr(ENETUNREACH);
 
                switch (dst->sa_family) {
-                       case AF_LINK:
-                               if (satosdl(dst)->sdl_alen < sizeof(edst))
-                                       senderr(EHOSTUNREACH);
-                               memcpy(edst, LLADDR(satosdl(dst)),
-                                   sizeof(edst));
-                               break;
+               case AF_LINK:
+                       if (satosdl(dst)->sdl_alen < sizeof(eh->ether_dhost))
+                               senderr(EHOSTUNREACH);
+                       memcpy(eh->ether_dhost, LLADDR(satosdl(dst)),
+                           sizeof(eh->ether_dhost));
+                       break;
 #ifdef INET6
-                       case AF_INET6:
-                               error = nd6_resolve(ifp, rt, m, dst, edst);
-                               if (error)
-                                       return (error == EAGAIN ? 0 : error);
-                               break;
+               case AF_INET6:
+                       error = nd6_resolve(ifp, rt, m, dst, eh->ether_dhost);
+                       if (error)
+                               return (error == EAGAIN ? 0 : error);
+                       break;
 #endif
-                       case AF_INET:
-                       case AF_MPLS:
-                               error = arpresolve(ifp, rt, m, dst, edst);
-                               if (error)
-                                       return (error == EAGAIN ? 0 : error);
-                               break;
-                       default:
-                               senderr(EHOSTUNREACH);
+               case AF_INET:
+               case AF_MPLS:
+                       error = arpresolve(ifp, rt, m, dst, eh->ether_dhost);
+                       if (error)
+                               return (error == EAGAIN ? 0 : error);
+                       break;
+               default:
+                       senderr(EHOSTUNREACH);
                }
                /* XXX handling for simplex devices in case of M/BCAST ?? */
                if (m->m_flags & (M_BCAST | M_MCAST))
-                       etype = htons(ETHERTYPE_MPLS_MCAST);
+                       eh->ether_type = htons(ETHERTYPE_MPLS_MCAST);
                else
-                       etype = htons(ETHERTYPE_MPLS);
+                       eh->ether_type = htons(ETHERTYPE_MPLS);
                break;
 #endif /* MPLS */
        case pseudo_AF_HDRCMPLT:
-               eh = (struct ether_header *)dst->sa_data;
-               esrc = eh->ether_shost;
-               /* FALLTHROUGH */
+               /* take the whole header from the sa */
+               memcpy(eh, dst->sa_data, sizeof(*eh));
+               return (0);
 
        case AF_UNSPEC:
-               eh = (struct ether_header *)dst->sa_data;
-               memcpy(edst, eh->ether_dhost, sizeof(edst));
-               /* AF_UNSPEC doesn't swap the byte order of the ether_type. */
-               etype = eh->ether_type;
+               /* take the dst and type from the sa, but get src below */
+               memcpy(eh, dst->sa_data, sizeof(*eh));
                break;
 
        default:
-               printf("%s: can't handle af%d\n", ifp->if_xname,
-                       dst->sa_family);
+               printf("%s: can't handle af%d\n", ifp->if_xname, af);
                senderr(EAFNOSUPPORT);
        }
 
-       /* XXX Should we feed-back an unencrypted IPsec packet ? */
-       if (mcopy)
-               if_input_local(ifp, mcopy, dst->sa_family);
+       memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost));
 
-       M_PREPEND(m, sizeof(struct ether_header) + ETHER_ALIGN, M_DONTWAIT);
-       if (m == NULL)
-               return (ENOBUFS);
-       m_adj(m, ETHER_ALIGN);
-       eh = mtod(m, struct ether_header *);
-       eh->ether_type = etype;
-       memcpy(eh->ether_dhost, edst, sizeof(eh->ether_dhost));
-       memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost));
+       return (0);
 
-       return (if_enqueue(ifp, m));
 bad:
        m_freem(m);
        return (error);
 }
 
+struct mbuf*
+ether_encap(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct rtentry *rt, int *errorp)
+{
+       struct ether_header eh;
+       int error;
+
+       error = ether_resolve(ifp, m, dst, rt, &eh);
+       switch (error) {
+       case 0:
+               break;
+       case EAGAIN:
+               error = 0;
+       default:
+               *errorp = error;
+               return (NULL);
+       }
+
+       m = m_prepend(m, ETHER_ALIGN + sizeof(eh), M_DONTWAIT);
+       if (m == NULL) {
+               *errorp = ENOBUFS;
+               return (NULL);
+       }
+
+       m_adj(m, ETHER_ALIGN);
+       memcpy(mtod(m, struct ether_header *), &eh, sizeof(eh));
+
+       return (m);
+}
+
+int
+ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct rtentry *rt)
+{
+       int error;
+
+       m = ether_encap(ifp, m, dst, rt, &error);
+       if (m == NULL)
+               return (error);
+
+       return (if_enqueue(ifp, m));
+}
+
 /*
  * Process a received Ethernet packet;
  * the packet is in the mbuf chain m without
Index: netinet/if_ether.h
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.h,v
retrieving revision 1.73
diff -u -p -r1.73 if_ether.h
--- netinet/if_ether.h  29 Nov 2016 10:09:57 -0000      1.73
+++ netinet/if_ether.h  30 Nov 2018 02:02:58 -0000
@@ -240,8 +245,13 @@ void       ether_ifattach(struct ifnet *);
 void   ether_ifdetach(struct ifnet *);
 int    ether_ioctl(struct ifnet *, struct arpcom *, u_long, caddr_t);
 int    ether_input(struct ifnet *, struct mbuf *, void *);
-int    ether_output(struct ifnet *,
-           struct mbuf *, struct sockaddr *, struct rtentry *);
+int    ether_resolve(struct ifnet *, struct mbuf *, struct sockaddr *,
+           struct rtentry *, struct ether_header *);
+struct mbuf *
+       ether_encap(struct ifnet *, struct mbuf *, struct sockaddr *,
+           struct rtentry *, int *);
+int    ether_output(struct ifnet *, struct mbuf *, struct sockaddr *,
+           struct rtentry *);
 void   ether_rtrequest(struct ifnet *, int, struct rtentry *);
 char   *ether_sprintf(u_char *);
 

Reply via email to