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:
parent
3ed5041315
commit
ca6a44c133
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user