From ca6a44c1333c467706a7ceae2842d0de380139cb Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Fri, 27 May 2022 16:42:07 -0400 Subject: [PATCH] freebsd_network: Overhaul device read/write functions. * In read, check that we actually have enough buffer capacity to read the next buffer on the queue. Otherwise return E2BIG. (This fixes data being silently discarded if the mbuf was larger than the passed read buffer, but that should not usually happen anyway based on MTU buffer sizing.) * In write, use m_get2 to get an appropriately sized mbuf (which may be up to 16K) instead of clamping all writes to the cluster size. These changes are needed for jumbo-frames to be actually read and written as one unit. However, they are not yet enabled, as more changes are needed above this point both in ioctl() here and in the stack. --- .../compat/freebsd_network/device_hooks.c | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/libs/compat/freebsd_network/device_hooks.c b/src/libs/compat/freebsd_network/device_hooks.c index 4799d5e6b8..1d8cf98247 100644 --- a/src/libs/compat/freebsd_network/device_hooks.c +++ b/src/libs/compat/freebsd_network/device_hooks.c @@ -112,7 +112,7 @@ compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes) uint32 semFlags = B_CAN_INTERRUPT; status_t status; struct mbuf *mb; - size_t length; + size_t length = *numBytes; //if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position, // buffer, *numBytes); @@ -134,18 +134,17 @@ compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes) } else if (status < B_OK) return status; - IF_DEQUEUE(&ifp->receive_queue, mb); + IF_LOCK(&ifp->receive_queue); + if (ifp->receive_queue.ifq_head != NULL + && ifp->receive_queue.ifq_head->m_pkthdr.len >= length) { + IF_UNLOCK(&ifp->receive_queue); + return E2BIG; + } + _IF_DEQUEUE(&ifp->receive_queue, mb); + IF_UNLOCK(&ifp->receive_queue); } while (mb == NULL); - length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), *numBytes); - -#if 0 - mb = m_defrag(mb, 0); - if (mb == NULL) { - *numBytes = 0; - return B_NO_MEMORY; - } -#endif + length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), length); m_copydata(mb, 0, length, buffer); *numBytes = length; @@ -161,24 +160,28 @@ compat_write(void *cookie, off_t position, const void *buffer, { struct ifnet *ifp = cookie; struct mbuf *mb; + int length = *numBytes; //if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position, // buffer, *numBytes); - if (*numBytes > MHLEN) { - mb = m_getcl(0, MT_DATA, M_PKTHDR); - *numBytes = min_c(*numBytes, (size_t)MCLBYTES); - } else { + if (length <= MHLEN) { mb = m_gethdr(0, MT_DATA); - } + if (mb == NULL) + return ENOBUFS; + } else { + mb = m_get2(length, 0, MT_DATA, M_PKTHDR); + if (mb == NULL) + return E2BIG; - if (mb == NULL) - return ENOBUFS; + length = min_c(length, mb->m_ext.ext_size); + } // if we waited, check after if the ifp is still valid - mb->m_pkthdr.len = mb->m_len = *numBytes; + mb->m_pkthdr.len = mb->m_len = length; memcpy(mtod(mb, void *), buffer, mb->m_len); + *numBytes = length; return ifp->if_output(ifp, mb, NULL, NULL); }