aboutsummaryrefslogtreecommitdiff
path: root/sys/net/iflib.c
diff options
context:
space:
mode:
authorStephen Hurd <shurd@FreeBSD.org>2017-12-08 18:43:31 +0000
committerStephen Hurd <shurd@FreeBSD.org>2017-12-08 18:43:31 +0000
commita15fbbb8fe60575a874612b0fde59d6c69bb73ed (patch)
tree019428f860db9c44dbb1e288c3d0bef678a02316 /sys/net/iflib.c
parent824ce2def5220c9ec654b1075961bb5d733b9a69 (diff)
downloadsrc-a15fbbb8fe60575a874612b0fde59d6c69bb73ed.tar.gz
src-a15fbbb8fe60575a874612b0fde59d6c69bb73ed.zip
Handle read-only mbufs in iflib ether pad function
If ethernet padding is enabled, and a read-only mbuf is passed, it would modify the mbuf using m_append(). Instead, call m_dup() and append to the new packet. Reported by: Pyun YongHyeon Sponsored by: Limelight Networks Differential Revision: https://reviews.freebsd.org/D13414
Notes
Notes: svn path=/head/; revision=326702
Diffstat (limited to 'sys/net/iflib.c')
-rw-r--r--sys/net/iflib.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index d09ccdccbf39..6035ce49a018 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -3112,7 +3112,7 @@ calc_next_txd(iflib_txq_t txq, int cidx, uint8_t qid)
* min_frame_size is the frame size (less CRC) to pad the mbuf to
*/
static __noinline int
-iflib_ether_pad(device_t dev, struct mbuf *m_head, uint16_t min_frame_size)
+iflib_ether_pad(device_t dev, struct mbuf **m_head, uint16_t min_frame_size)
{
/*
* 18 is enough bytes to pad an ARP packet to 46 bytes, and
@@ -3120,14 +3120,25 @@ iflib_ether_pad(device_t dev, struct mbuf *m_head, uint16_t min_frame_size)
*/
static char pad[18]; /* just zeros */
int n;
+ struct mbuf *new_head;
- for (n = min_frame_size - m_head->m_pkthdr.len;
+ if (!M_WRITABLE(*m_head)) {
+ new_head = m_dup(*m_head, M_NOWAIT);
+ if (new_head == NULL) {
+ device_printf(dev, "cannot pad short frame, m_dup() failed");
+ return ENOMEM;
+ }
+ m_freem(*m_head);
+ *m_head = new_head;
+ }
+
+ for (n = min_frame_size - (*m_head)->m_pkthdr.len;
n > 0; n -= sizeof(pad))
- if (!m_append(m_head, min(n, sizeof(pad)), pad))
+ if (!m_append(*m_head, min(n, sizeof(pad)), pad))
break;
if (n > 0) {
- m_freem(m_head);
+ m_freem(*m_head);
device_printf(dev, "cannot pad short frame\n");
DBG_COUNTER_INC(encap_pad_mbuf_fail);
return (ENOBUFS);
@@ -3189,13 +3200,13 @@ iflib_encap(iflib_txq_t txq, struct mbuf **m_headp)
desc_tag = txq->ift_desc_tag;
max_segs = scctx->isc_tx_nsegments;
}
- m_head = *m_headp;
if ((sctx->isc_flags & IFLIB_NEED_ETHER_PAD) &&
__predict_false(m_head->m_pkthdr.len < scctx->isc_min_frame_size)) {
- err = iflib_ether_pad(ctx->ifc_dev, m_head, scctx->isc_min_frame_size);
+ err = iflib_ether_pad(ctx->ifc_dev, m_headp, scctx->isc_min_frame_size);
if (err)
return err;
}
+ m_head = *m_headp;
pkt_info_zero(&pi);
pi.ipi_mflags = (m_head->m_flags & (M_VLANTAG|M_BCAST|M_MCAST));