freebsd_network: Implement the new send/receive ioctls.

It would be nice to reuse the data_nodes as ext_bufs directly
and save another copy. However, we can't do that at the moment,
because while data_nodes and MCLBYTES are the same size (2048),
the data_nodes contain a header structure at the beginning of
that data.

(Perhaps we should consider reworking net_buffer to store data
differently to make that possible. It would also have the advantage
that data_nodes would start on a page boundary or a half-page boundary,
which would make doing direct DMA with them much easier in this
and other drivers as well.)

Change-Id: I8cd3b82a90f328c7a5d2437e3e95413bd74537ae
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7913
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-07-30 17:03:36 +00:00
committed by waddlesplash
parent 1485e71d8c
commit b07cf30aee
4 changed files with 57 additions and 42 deletions
+1 -1
View File
@@ -25,7 +25,7 @@
spinlock __haiku_intr_spinlock;
struct net_stack_module_info *gStack;
struct net_buffer_module_info *gBufferModule;
static struct list sRootDevices;
static int sNextUnit;
+1 -4
View File
@@ -17,8 +17,6 @@
#include <util/list.h>
#include <net_stack.h>
#include <compat/sys/kernel.h>
#include <compat/net/if.h>
@@ -52,9 +50,8 @@ enum {
};
extern struct net_stack_module_info *gStack;
extern struct net_buffer_module_info *gBufferModule;
extern pci_module_info *gPci;
extern struct pci_x86_module_info *gPCIx86;
static inline void
+48 -37
View File
@@ -13,6 +13,7 @@
#include <Drivers.h>
#include <ether_driver.h>
#include <net_buffer.h>
#include <compat/sys/haiku-module.h>
@@ -38,16 +39,11 @@ compat_open(const char *name, uint32 flags, void **cookie)
if (i == MAX_DEVICES)
return B_ERROR;
if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK)
return B_ERROR;
ifp = gDevices[i];
if_printf(ifp, "compat_open(0x%" B_PRIx32 ")\n", flags);
if (atomic_or(&ifp->open_count, 1)) {
put_module(NET_STACK_MODULE_NAME);
if (atomic_or(&ifp->open_count, 1))
return B_BUSY;
}
IFF_LOCKGIANT(ifp);
@@ -107,24 +103,21 @@ compat_free(void *cookie)
// TODO: empty out the send queue
atomic_and(&ifp->open_count, 0);
put_module(NET_STACK_MODULE_NAME);
return B_OK;
}
static status_t
compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
compat_receive(void *cookie, net_buffer **_buffer)
{
struct ifnet *ifp = cookie;
uint32 semFlags = B_CAN_INTERRUPT;
status_t status;
struct mbuf *mb;
size_t length = *numBytes;
//if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position,
// buffer, *numBytes);
//if_printf(ifp, "compat_receive(%p)\n", _buffer);
if (ifp->flags & DEVICE_CLOSED)
if ((ifp->flags & DEVICE_CLOSED) != 0)
return B_INTERRUPTED;
if (ifp->flags & DEVICE_NON_BLOCK)
@@ -132,46 +125,46 @@ compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
do {
status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
if (ifp->flags & DEVICE_CLOSED)
if ((ifp->flags & DEVICE_CLOSED) != 0)
return B_INTERRUPTED;
if (status == B_WOULD_BLOCK) {
*numBytes = 0;
return B_OK;
} else if (status < B_OK)
if (status != B_OK)
return status;
IF_DEQUEUE(&ifp->receive_queue, mb);
} while (mb == NULL);
if (mb->m_pkthdr.len > length) {
if_printf(ifp, "error reading packet: too large! (%d > %" B_PRIuSIZE ")\n",
mb->m_pkthdr.len, length);
net_buffer *buffer = gBufferModule->create(0);
if (buffer == NULL) {
m_freem(mb);
*numBytes = 0;
return E2BIG;
return B_NO_MEMORY;
}
length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), length);
m_copydata(mb, 0, length, buffer);
*numBytes = length;
for (struct mbuf *m = mb; m != NULL; m = m->m_next) {
status = gBufferModule->append(buffer, mtod(m, void *), mb->m_len);
if (status != B_OK)
break;
}
if (status != B_OK) {
gBufferModule->free(buffer);
m_freem(mb);
return status;
}
*_buffer = buffer;
m_freem(mb);
return B_OK;
}
static status_t
compat_write(void *cookie, off_t position, const void *buffer,
size_t *numBytes)
compat_send(void *cookie, net_buffer *buffer)
{
struct ifnet *ifp = cookie;
struct mbuf *mb;
int length = *numBytes;
int length = buffer->size;
//if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position,
// buffer, *numBytes);
//if_printf(ifp, "compat_send(%p, [%lu])\n", buffer, length);
if (length <= MHLEN) {
mb = m_gethdr(0, MT_DATA);
@@ -185,16 +178,20 @@ compat_write(void *cookie, off_t position, const void *buffer,
length = min_c(length, mb->m_ext.ext_size);
}
// if we waited, check after if the ifp is still valid
status_t status = gBufferModule->read(buffer, 0, mtod(mb, void *), length);
if (status != B_OK)
return status;
mb->m_pkthdr.len = mb->m_len = length;
memcpy(mtod(mb, void *), buffer, mb->m_len);
*numBytes = length;
if ((ifp->flags & DEVICE_CLOSED) != 0)
return B_INTERRUPTED;
IFF_LOCKGIANT(ifp);
int result = ifp->if_output(ifp, mb, NULL, NULL);
IFF_UNLOCKGIANT(ifp);
if (result == 0)
gBufferModule->free(buffer);
return result;
}
@@ -329,6 +326,20 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
}
return B_OK;
case ETHER_SEND_NET_BUFFER:
if (arg == NULL || length == 0)
return B_BAD_DATA;
if (!IS_KERNEL_ADDRESS(arg))
return B_BAD_ADDRESS;
return compat_send(cookie, (net_buffer*)arg);
case ETHER_RECEIVE_NET_BUFFER:
if (arg == NULL || length == 0)
return B_BAD_DATA;
if (!IS_KERNEL_ADDRESS(arg))
return B_BAD_ADDRESS;
return compat_receive(cookie, (net_buffer**)arg);
case SIOCSIFFLAGS:
case SIOCSIFMEDIA:
case SIOCSIFMTU:
@@ -349,6 +360,6 @@ device_hooks gDeviceHooks = {
compat_close,
compat_free,
compat_control,
compat_read,
compat_write,
NULL,
NULL,
};
+7
View File
@@ -11,6 +11,8 @@
#include <string.h>
#include <slab/Slab.h>
#include <net_buffer.h>
#include <compat/sys/malloc.h>
#include <compat/sys/mbuf.h>
#include <compat/sys/kernel.h>
@@ -311,6 +313,10 @@ m_free(struct mbuf* memoryBuffer)
status_t
init_mbufs()
{
status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
if (status != B_OK)
goto clean;
sMBufCache = create_object_cache("mbufs", MSIZE, 8, NULL, NULL, NULL);
if (sMBufCache == NULL)
goto clean;
@@ -335,6 +341,7 @@ clean:
delete_object_cache(sChunkCache);
if (sMBufCache != NULL)
delete_object_cache(sMBufCache);
put_module(NET_BUFFER_MODULE_NAME);
return B_NO_MEMORY;
}