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.
This commit is contained in:
Augustin Cavalier 2022-05-27 16:42:07 -04:00
parent 3ed5041315
commit ca6a44c133

View File

@ -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);
}