summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_ethersubr.c163
-rw-r--r--sys/netinet/if_ether.h11
2 files changed, 103 insertions, 71 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 76f6c3147e0..68a2b265b26 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.253 2018/03/13 01:31:48 dlg Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.254 2018/12/11 01:27:08 dlg Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -178,24 +178,18 @@ ether_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
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 mbuf *m, struct sockaddr *dst,
}
#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 mbuf *m, struct sockaddr *dst,
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);
+ 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);
+ 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
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index fdff5c8c1cf..441d2696176 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ether.h,v 1.73 2016/11/29 10:09:57 reyk Exp $ */
+/* $OpenBSD: if_ether.h,v 1.74 2018/12/11 01:27:08 dlg Exp $ */
/* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */
/*
@@ -240,8 +240,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 *);