virtio_net: Align transfer buffers, check get_memory_map result.
The buffers were allocated with B_ANY_KERNEL_ADDRESS and the buffer plus header block would produce uneven sizes. This lead to some buffers crossing page boundaries. The call to get_memory_map() is only supplied with a single entry, which in such a situation may not be enough if the physical pages are not contiguous. Due to missing result checks this was not noticed. Use B_ANY_KERNEL_BLOCK_ADDRESS and align the size of the total buffer to avoid such page boundary crossing. Fixes randomly truncated frames in the receive path.
This commit is contained in:
@@ -23,7 +23,6 @@
|
|||||||
#define VIRTIO_NET_DEVICE_ID_GENERATOR "virtio_net/device_id"
|
#define VIRTIO_NET_DEVICE_ID_GENERATOR "virtio_net/device_id"
|
||||||
|
|
||||||
#define BUFFER_SIZE 2048
|
#define BUFFER_SIZE 2048
|
||||||
// #define MAX_FRAME_SIZE (BUFFER_SIZE - sizeof(virtio_net_hdr))
|
|
||||||
#define MAX_FRAME_SIZE 1536
|
#define MAX_FRAME_SIZE 1536
|
||||||
|
|
||||||
|
|
||||||
@@ -269,8 +268,6 @@ virtio_net_init_device(void* _info, void** _cookie)
|
|||||||
|
|
||||||
char* rxBuffer;
|
char* rxBuffer;
|
||||||
char* txBuffer;
|
char* txBuffer;
|
||||||
const size_t rxBufferSize = BUFFER_SIZE + sizeof(virtio_net_rx_hdr);
|
|
||||||
const size_t txBufferSize = BUFFER_SIZE + sizeof(virtio_net_tx_hdr);
|
|
||||||
|
|
||||||
info->rxQueues = new(std::nothrow) virtio_queue[info->pairsCount];
|
info->rxQueues = new(std::nothrow) virtio_queue[info->pairsCount];
|
||||||
info->txQueues = new(std::nothrow) virtio_queue[info->pairsCount];
|
info->txQueues = new(std::nothrow) virtio_queue[info->pairsCount];
|
||||||
@@ -301,8 +298,8 @@ virtio_net_init_device(void* _info, void** _cookie)
|
|||||||
|
|
||||||
// create receive buffer area
|
// create receive buffer area
|
||||||
info->rxArea = create_area("virtionet rx buffer", (void**)&rxBuffer,
|
info->rxArea = create_area("virtionet rx buffer", (void**)&rxBuffer,
|
||||||
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(
|
B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
|
||||||
rxBufferSize * info->rxSizes[0]),
|
BUFFER_SIZE * info->rxSizes[0]),
|
||||||
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
if (info->rxArea < B_OK) {
|
if (info->rxArea < B_OK) {
|
||||||
status = info->rxArea;
|
status = info->rxArea;
|
||||||
@@ -316,19 +313,27 @@ virtio_net_init_device(void* _info, void** _cookie)
|
|||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
goto err4;
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->rxBufInfos[i] = buf;
|
info->rxBufInfos[i] = buf;
|
||||||
buf->hdr = (struct virtio_net_hdr*)((addr_t)rxBuffer
|
buf->hdr = (struct virtio_net_hdr*)((addr_t)rxBuffer
|
||||||
+ i * rxBufferSize);
|
+ i * BUFFER_SIZE);
|
||||||
buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_rx_hdr));
|
buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_rx_hdr));
|
||||||
get_memory_map(buf->buffer, BUFFER_SIZE, &buf->entry, 1);
|
|
||||||
get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
|
status = get_memory_map(buf->buffer,
|
||||||
|
BUFFER_SIZE - sizeof(virtio_net_rx_hdr), &buf->entry, 1);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err4;
|
||||||
|
|
||||||
|
status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
|
||||||
&buf->hdrEntry, 1);
|
&buf->hdrEntry, 1);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create transmit buffer area
|
// create transmit buffer area
|
||||||
info->txArea = create_area("virtionet tx buffer", (void**)&txBuffer,
|
info->txArea = create_area("virtionet tx buffer", (void**)&txBuffer,
|
||||||
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(
|
B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
|
||||||
txBufferSize * info->txSizes[0]),
|
BUFFER_SIZE * info->txSizes[0]),
|
||||||
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
if (info->txArea < B_OK) {
|
if (info->txArea < B_OK) {
|
||||||
status = info->txArea;
|
status = info->txArea;
|
||||||
@@ -342,13 +347,22 @@ virtio_net_init_device(void* _info, void** _cookie)
|
|||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
goto err6;
|
goto err6;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->txBufInfos[i] = buf;
|
info->txBufInfos[i] = buf;
|
||||||
buf->hdr = (struct virtio_net_hdr*)((addr_t)txBuffer
|
buf->hdr = (struct virtio_net_hdr*)((addr_t)txBuffer
|
||||||
+ i * txBufferSize);
|
+ i * BUFFER_SIZE);
|
||||||
buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_tx_hdr));
|
buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_tx_hdr));
|
||||||
get_memory_map(buf->buffer, BUFFER_SIZE, &buf->entry, 1);
|
|
||||||
get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
|
status = get_memory_map(buf->buffer,
|
||||||
|
BUFFER_SIZE - sizeof(virtio_net_tx_hdr), &buf->entry, 1);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err6;
|
||||||
|
|
||||||
|
status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
|
||||||
&buf->hdrEntry, 1);
|
&buf->hdrEntry, 1);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err6;
|
||||||
|
|
||||||
info->txFreeList.Add(buf);
|
info->txFreeList.Add(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user