After some additional consideration I think I can improve
upon my previous diff. Pull-up of the Ethernet header can
and should be made conditional: since an Ethernet header
requires 2 byte alignment, any position within a real life
mbuf is a valid one so unless there's not enough data in
the first mbuf, we shouldn't do anything. This also puts
this m_pullup in line with the other ones in the tree in
terms of the preceeding length check.
Also, I believe I was wrong insisting on requiring explicit
ETHER_ALIGN alignment. It's not really necessary if we're
going to pull-up anyways.
And finally I'm using "sizeof(struct ether_header)" instead
of the define for consistency with the rest of the code.
OK?
diff --git sys/net/if_vxlan.c sys/net/if_vxlan.c
index 034e651..f010e3e 100644
--- sys/net/if_vxlan.c
+++ sys/net/if_vxlan.c
@@ -577,11 +577,12 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int
iphlen,
struct ifnet *ifp;
int skip;
#if NBRIDGE > 0
struct bridge_tunneltag *brtag;
#endif
- struct mbuf *m0;
+ struct mbuf *n;
+ int off;
/* XXX Should verify the UDP port first before copying the packet */
skip = iphlen + sizeof(*uh);
if (m->m_pkthdr.len - skip < sizeof(v))
return (0);
@@ -634,12 +635,14 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int
iphlen,
/* not found */
return (0);
found:
- if (m->m_pkthdr.len < skip + sizeof(struct ether_header))
+ if (m->m_pkthdr.len < skip + sizeof(struct ether_header)) {
+ m_freem(m);
return (EINVAL);
+ }
m_adj(m, skip);
ifp = &sc->sc_ac.ac_if;
#if NBRIDGE > 0
@@ -656,19 +659,26 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int
iphlen,
m->m_flags &= ~(M_MCAST|M_BCAST);
#if NPF > 0
pf_pkt_addr_changed(m);
#endif
- if ((m = m_pullup(m, sizeof(struct ether_header))) == NULL)
+ if ((m->m_len < sizeof(struct ether_header)) &&
+ (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
return (ENOBUFS);
- if (!ALIGNED_POINTER(mtod(m, caddr_t) + ETHER_HDR_LEN, uint32_t)) {
- m0 = m;
- m = m_dup_pkt(m0, ETHER_ALIGN, M_NOWAIT);
- m_freem(m0);
- if (m == NULL)
+ n = m_getptr(m, sizeof(struct ether_header), &off);
+ if (n == NULL) {
+ m_freem(m);
+ return (EINVAL);
+ }
+ if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) {
+ n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
+ /* Dispose of the original mbuf chain */
+ m_freem(m);
+ if (n == NULL)
return (ENOBUFS);
+ m = n;
}
ml_enqueue(&ml, m);
if_input(ifp, &ml);