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:
committed by
waddlesplash
parent
1485e71d8c
commit
b07cf30aee
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user