summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Network/lwip-new/vbox
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Network/lwip-new/vbox')
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/Makefile.kup0
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp230
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.h41
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/arch/bpstruct.h1
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/arch/cc.h62
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/arch/epstruct.h1
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/arch/perf.h7
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/arch/sys_arch.h39
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/lwip-log.h104
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/include/lwip-namespace.h227
-rw-r--r--src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c583
11 files changed, 1295 insertions, 0 deletions
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/Makefile.kup b/src/VBox/Devices/Network/lwip-new/vbox/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/Makefile.kup
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp
new file mode 100644
index 00000000..7ba57892
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp
@@ -0,0 +1,230 @@
+/* $Id: VBoxLwipCore.cpp $ */
+/** @file
+ * VBox Lwip Core Initiatetor/Finilizer.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+/**
+ * @todo: this should be somehow shared with with DevINIP, because
+ * we want that every NAT and DevINIP instance uses a initialized LWIP
+ * initialization of LWIP should happen on iLWIPInitiatorCounter 0 -> 1.
+ * see pfnConstruct/Destruct.
+ *
+ * @note: see comment to DevINIP.cpp:DevINIPConfigured
+ * @note: perhaps initilization stuff would be better move out of NAT driver,
+ * because we have to deal with attaching detaching NAT driver at runtime.
+ */
+#include <iprt/types.h>
+#include "VBoxLwipCore.h"
+/** @todo lwip or nat ? */
+#define LOG_GROUP LOG_GROUP_DRV_NAT
+#include <iprt/cpp/lock.h>
+#include <iprt/timer.h>
+#include <iprt/errcore.h>
+#include <VBox/log.h>
+
+extern "C" {
+#include "lwip/opt.h"
+#include "lwip/sys.h"
+#include "netif/etharp.h"
+#include "lwip/stats.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/tcpip.h"
+}
+
+typedef struct LWIPCOREUSERCALLBACK
+{
+ PFNRT1 pfn;
+ void *pvUser;
+} LWIPCOREUSERCALLBACK, *PLWIPCOREUSERCALLBACK;
+
+
+RTCLockMtx g_mtxLwip;
+
+typedef struct LWIPCORE
+{
+ int iLWIPInitiatorCounter;
+ sys_sem_t LwipTcpIpSem;
+} LWIPCORE;
+
+static LWIPCORE g_LwipCore;
+
+
+/**
+ * @note this function executes on TCPIP thread.
+ */
+static void lwipCoreUserCallback(void *pvArg) RT_NOTHROW_DEF
+{
+ LogFlowFunc(("ENTER: pvArg:%p\n", pvArg));
+
+ PLWIPCOREUSERCALLBACK pUserClbk = (PLWIPCOREUSERCALLBACK)pvArg;
+ if (pUserClbk != NULL && pUserClbk->pfn != NULL)
+ pUserClbk->pfn(pUserClbk->pvUser);
+
+ /* wake up caller on EMT/main */
+ sys_sem_signal(&g_LwipCore.LwipTcpIpSem);
+ LogFlowFuncLeave();
+}
+
+
+/**
+ * @note this function executes on TCPIP thread.
+ */
+static void lwipCoreInitDone(void *pvArg) RT_NOTHROW_DEF
+{
+ LogFlowFunc(("ENTER: pvArg:%p\n", pvArg));
+
+ /* ... init code goes here if need be ... */
+
+ lwipCoreUserCallback(pvArg);
+ LogFlowFuncLeave();
+}
+
+
+/**
+ * @note this function executes on TCPIP thread.
+ */
+static void lwipCoreFiniDone(void *pvArg) RT_NOTHROW_DEF
+{
+ LogFlowFunc(("ENTER: pvArg:%p\n", pvArg));
+
+ /* ... fini code goes here if need be ... */
+
+ lwipCoreUserCallback(pvArg);
+ LogFlowFuncLeave();
+}
+
+
+/**
+ * This function initializes lwip core once. Further NAT instancies
+ * should just add netifs configured according their needs.
+ *
+ * We're on EMT-n or on the main thread of a network service, and we
+ * want to execute something on the lwip tcpip thread.
+ */
+int vboxLwipCoreInitialize(PFNRT1 pfnCallback, void *pvCallbackArg)
+{
+ int rc = VINF_SUCCESS;
+ int lwipRc = ERR_OK;
+ LogFlowFuncEnter();
+
+ LWIPCOREUSERCALLBACK callback;
+ callback.pfn = pfnCallback;
+ callback.pvUser = pvCallbackArg;
+
+ {
+ RTCLock lock(g_mtxLwip);
+
+ if (g_LwipCore.iLWIPInitiatorCounter == 0)
+ {
+ lwipRc = sys_sem_new(&g_LwipCore.LwipTcpIpSem, 0);
+ if (lwipRc != ERR_OK)
+ {
+ LogFlowFunc(("sys_sem_new error %d\n", lwipRc));
+ goto done;
+ }
+
+ tcpip_init(lwipCoreInitDone, &callback);
+ }
+ else
+ {
+ lwipRc = tcpip_callback(lwipCoreUserCallback, &callback);
+ if (lwipRc != ERR_OK)
+ {
+ LogFlowFunc(("tcpip_callback error %d\n", lwipRc));
+ goto done;
+ }
+ }
+
+ sys_sem_wait(&g_LwipCore.LwipTcpIpSem);
+ ++g_LwipCore.iLWIPInitiatorCounter;
+ }
+ done:
+ if (lwipRc != ERR_OK)
+ {
+ /** @todo map lwip error code? */
+ rc = VERR_INTERNAL_ERROR;
+ }
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * This function decrement lwip reference counter
+ * and calls tcpip thread termination function.
+ */
+void vboxLwipCoreFinalize(PFNRT1 pfnCallback, void *pvCallbackArg)
+{
+ int lwipRc = ERR_OK;
+ LogFlowFuncEnter();
+
+ LWIPCOREUSERCALLBACK callback;
+ callback.pfn = pfnCallback;
+ callback.pvUser = pvCallbackArg;
+
+ {
+ RTCLock lock(g_mtxLwip);
+
+ if (g_LwipCore.iLWIPInitiatorCounter == 1)
+ {
+ /*
+ * TCPIP_MSG_CALLBACK_TERMINATE is like a static callback,
+ * but causes tcpip_thread() to return afterward.
+ *
+ * This should probably be hidden in a function inside
+ * lwip, but for it to be static callback the semaphore
+ * dance should also be done inside that function. There
+ * is tcpip_msg::sem, but it seems to be unused and may be
+ * gone in future versions of lwip.
+ */
+ struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+ if (msg)
+ {
+ msg->type = TCPIP_MSG_CALLBACK_TERMINATE;
+ msg->msg.cb.function = lwipCoreFiniDone;
+ msg->msg.cb.ctx = &callback;
+
+ lwipRc = tcpip_callbackmsg((struct tcpip_callback_msg *)msg);
+ if (lwipRc != ERR_OK)
+ LogFlowFunc(("tcpip_callback_msg error %d\n", lwipRc));
+ }
+ else
+ LogFlowFunc(("memp_malloc no memory\n"));
+ }
+ else
+ {
+ lwipRc = tcpip_callback(lwipCoreUserCallback, &callback);
+ if (lwipRc != ERR_OK)
+ LogFlowFunc(("tcpip_callback error %d\n", lwipRc));
+ }
+
+ if (lwipRc == ERR_OK)
+ sys_sem_wait(&g_LwipCore.LwipTcpIpSem);
+ }
+
+ LogFlowFuncLeave();
+}
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.h b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.h
new file mode 100644
index 00000000..9c917d3b
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.h
@@ -0,0 +1,41 @@
+/* $Id: VBoxLwipCore.h $ */
+
+/** @file
+ * VBox Lwip Core Initiatetor/Finilizer.
+ */
+
+/*
+ * Copyright (C) 2012-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef VBOX_INCLUDED_SRC_Network_lwip_new_vbox_VBoxLwipCore_h
+#define VBOX_INCLUDED_SRC_Network_lwip_new_vbox_VBoxLwipCore_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/**
+ * Initializes LWIP core, and do callback on tcp/ip thread.
+ */
+int vboxLwipCoreInitialize(PFNRT1 pfnCallback, void * pfnCallbackArg);
+void vboxLwipCoreFinalize(PFNRT1 pfnCallback, void * pfnCallbackArg);
+
+#endif /* !VBOX_INCLUDED_SRC_Network_lwip_new_vbox_VBoxLwipCore_h */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/arch/bpstruct.h b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/bpstruct.h
new file mode 100644
index 00000000..1d81e3f7
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/bpstruct.h
@@ -0,0 +1 @@
+#pragma pack(push,1)
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/arch/cc.h b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/cc.h
new file mode 100644
index 00000000..90ed1b53
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/cc.h
@@ -0,0 +1,62 @@
+#ifndef VBOX_ARCH_CC_H_
+#define VBOX_ARCH_CC_H_
+
+#ifndef LOG_GROUP
+#define LOG_GROUP LOG_GROUP_DRV_LWIP
+#endif
+#include <VBox/log.h>
+#include <iprt/stdint.h>
+#include <iprt/cdefs.h>
+#include <iprt/assert.h>
+#include <iprt/time.h>
+
+#ifndef RT_OS_WINDOWS
+# define LWIP_TIMEVAL_PRIVATE 0
+#endif
+
+typedef uint8_t u8_t;
+#ifndef RT_OS_SOLARIS
+typedef int8_t s8_t;
+#else
+/* Solaris /usr/include/sys/int_types.h incorrectly defines int8_t as "char" */
+typedef signed char s8_t;
+#endif
+typedef uint16_t u16_t;
+typedef int16_t s16_t;
+typedef uint32_t u32_t;
+typedef int32_t s32_t;
+
+typedef uintptr_t mem_ptr_t;
+
+#ifdef _MSC_VER
+# define PACK_STRUCT_FIELD(x) x
+# define PACK_STRUCT_STRUCT
+# define PACK_STRUCT_USE_INCLUDES
+# if _MSC_VER < 1600
+# define LWIP_PROVIDE_ERRNO
+# else
+# include <errno.h>
+# endif
+# pragma warning (disable: 4103)
+#elif defined(__GNUC__)
+# define PACK_STRUCT_FIELD(x) x
+# define PACK_STRUCT_STRUCT __attribute__((__packed__))
+# define PACK_STRUCT_BEGIN
+# define PACK_STRUCT_END
+# include <errno.h>
+#else
+# error This header file has not been ported yet for this compiler.
+#endif
+
+/* Provide byte order hint. */
+#undef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+
+#ifdef DEBUG
+#define LWIP_PLATFORM_DIAG(x) Log(x)
+#else /* !DEBUG */
+#define LWIP_PLATFORM_DIAG(x) LogRel(x)
+#endif /* !DEBUG */
+#define LWIP_PLATFORM_ASSERT(x) AssertReleaseMsgFailed((x))
+
+#endif /* !VBOX_ARCH_CC_H_ */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/arch/epstruct.h b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/epstruct.h
new file mode 100644
index 00000000..65898b54
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/epstruct.h
@@ -0,0 +1 @@
+#pragma pack(pop)
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/arch/perf.h b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/perf.h
new file mode 100644
index 00000000..5b364db0
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/perf.h
@@ -0,0 +1,7 @@
+#ifndef VBOX_ARCH_PERF_H_
+#define VBOX_ARCH_PERF_H_
+
+#define PERF_START
+#define PERF_STOP(x)
+
+#endif /* !VBOX_ARCH_PERF_H_ */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/arch/sys_arch.h b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/sys_arch.h
new file mode 100644
index 00000000..6a83cea3
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/arch/sys_arch.h
@@ -0,0 +1,39 @@
+#ifndef VBOX_ARCH_SYS_ARCH_H_
+#define VBOX_ARCH_SYS_ARCH_H_
+
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#ifdef RT_OS_DARWIN
+#include <sys/time.h>
+#endif
+
+/** NULL value for a mbox. */
+#define SYS_MBOX_NULL NULL
+
+/** NULL value for a mutex semaphore. */
+#define SYS_SEM_NULL NIL_RTSEMEVENT
+
+/** The IPRT event semaphore ID just works fine for this type. */
+typedef RTSEMEVENT sys_sem_t;
+
+
+/** The opaque type of a mbox. */
+typedef void *sys_mbox_t;
+
+/** The IPRT thread ID just works fine for this type. */
+typedef RTTHREAD sys_thread_t;
+
+#if SYS_LIGHTWEIGHT_PROT
+/** This is just a dummy. The implementation doesn't need anything. */
+typedef void *sys_prot_t;
+#endif
+
+/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mbox_valid(sys_mbox_t *mbox);
+/** Set an mbox invalid so that sys_mbox_valid returns 0 */
+void sys_mbox_set_invalid(sys_mbox_t *mbox);
+
+#define sys_sem_valid(sem) ((sem) && (*(sem)))
+#define sys_sem_set_invalid(sem) do {} while(0)
+
+#endif /* !VBOX_ARCH_SYS_ARCH_H_ */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-log.h b/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-log.h
new file mode 100644
index 00000000..10c47f21
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-log.h
@@ -0,0 +1,104 @@
+/* -*- indent-tabs-mode: nil; -*- */
+#ifndef __VBOX_LWIP_LOG_H__
+#define __VBOX_LWIP_LOG_H__
+
+#include <VBox/log.h>
+
+#ifdef LWIP_DEBUG
+/*
+ * All LWIP_DBG_* constants fit into a byte, so we use upper bits to
+ * encode the VBox log group.
+ *
+ * Mapping between FOO_DEBUG and LOG_GROUP_LWIP_FOO is straightforward
+ * except for IP4 where extra '4' was added to the group names to make
+ * it possible to specify lwip_ip4* instead of lwip_ip*, where the
+ * latter would enable both IP4 and IP6 logging.
+ *
+ * We ignore LWIP_DBG_STATE &c since in our scheme they would traslate
+ * into additional log groups and require combinatorial explosion. We
+ * probably can use LWIP_DBG_TYPES_ON for finer selection if need be
+ * (for internal debugging only, as it requires recompilation).
+ *
+ * Debug levels are mapped to RT debug levels so lwip's default level
+ * ends up as RT's level4. Non-default levels are currently not used
+ * much in lwip sources, so enable l4 to get the logs.
+ *
+ * Caveat: Slight snag. The LOG_GROUP_LWIP_XXXX are enum values and
+ * the lwIP XXXX_DEBUG macros are used in \#if XXXX_DEBUG
+ * tests around the place. This make MSC raise complaint
+ * C4668, that e.g. 'LOG_GROUP_LWIP_IP4' is not defined as a
+ * preprocessor macro and therefore replaced with '0'.
+ * However, that works just fine because we or LWIP_DBG_ON so
+ * the test is true despite the warning. Thus the pragma
+ * below.
+ */
+# ifdef _MSC_VER
+# pragma warning(disable:4668)
+# endif
+
+# define LWIP_DEBUGF_LOG_GROUP_SHIFT 8
+# define LWIP_DEBUGF_LOG_GROUP(_g) \
+ (((_g) << LWIP_DEBUGF_LOG_GROUP_SHIFT) | LWIP_DBG_ON)
+
+# define API_LIB_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_API_LIB)
+# define API_MSG_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_API_MSG)
+# define ETHARP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_ETHARP)
+# define ICMP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_ICMP)
+# define IGMP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_IGMP)
+# define INET_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_INET)
+# define IP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_IP4)
+# define IP_REASS_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_IP4_REASS)
+# define IP6_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_IP6)
+# define MEM_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_MEM)
+# define MEMP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_MEMP)
+# define NETIF_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_NETIF)
+# define PBUF_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_PBUF)
+# define RAW_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_RAW)
+# define SOCKETS_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_SOCKETS)
+# define SYS_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_SYS)
+# define TCP_CWND_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_CWND)
+# define TCP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP)
+# define TCP_FR_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_FR)
+# define TCP_INPUT_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_INPUT)
+# define TCP_OUTPUT_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_OUTPUT)
+# define TCP_QLEN_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_QLEN)
+# define TCP_RST_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_RST)
+# define TCP_RTO_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_RTO)
+# define TCP_WND_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCP_WND)
+# define TCPIP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TCPIP)
+# define TIMERS_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_TIMERS)
+# define UDP_DEBUG LWIP_DEBUGF_LOG_GROUP(LOG_GROUP_LWIP_UDP)
+
+/*
+ * The following symbols are for debugging of modules that are not
+ * compiled in. They are listed here for reference but there're no
+ * log groups defined for them currently.
+ */
+# undef AUTOIP_DEBUG
+# undef DHCP_DEBUG
+# undef DNS_DEBUG
+# undef PPP_DEBUG
+# undef SLIP_DEBUG
+# undef SNMP_MIB_DEBUG
+# undef SNMP_MSG_DEBUG
+
+# ifdef LOG_ENABLED
+
+# define LWIP_DEBUGF(_when, _args) \
+ do { \
+ const VBOXLOGGROUP _group = (_when) >> LWIP_DEBUGF_LOG_GROUP_SHIFT; \
+ if (_group >= LOG_GROUP_DEFAULT) { \
+ /* severe => l1; serious => l2; warning => l3; default => l4 */ \
+ const unsigned int _level = 1U << (LWIP_DBG_MASK_LEVEL + 1 - ((_when) & LWIP_DBG_MASK_LEVEL)); \
+ LogIt(_level, _group, _args); \
+ } \
+ } while (0)
+
+# else /* !LOG_ENABLED */
+
+# define LWIP_DEBUGF(_when, _args) do { } while (0)
+
+# endif /* !LOG_ENABLED */
+
+#endif /* LWIP_DEBUG */
+#endif /* !__VBOX_LWIP_LOG_H__ */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-namespace.h b/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-namespace.h
new file mode 100644
index 00000000..3aa59bc3
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/include/lwip-namespace.h
@@ -0,0 +1,227 @@
+/*
+ * Hack to avoid function name collisions with slirp or any other code.
+ * Include at the end of your lwipopts.h
+ */
+#ifndef _VBOX_LWIP_NAMESPACE_H_
+#define _VBOX_LWIP_NAMESPACE_H_
+
+#define api_msg_input lwip_api_msg_input
+#define api_msg_post lwip_api_msg_post
+#define etharp_arp_input lwip_etharp_arp_input
+#define etharp_find_addr lwip_etharp_find_addr
+#define etharp_ip_input lwip_etharp_ip_input
+#define etharp_output lwip_etharp_output
+#define etharp_query lwip_etharp_query
+#define etharp_request lwip_etharp_request
+#define etharp_tmr lwip_etharp_tmr
+#define icmp_dest_unreach lwip_icmp_dest_unreach
+#define icmp_input lwip_icmp_input
+#define inet_chksum lwip_inet_chksum
+#define inet_chksum_pbuf lwip_inet_chksum_pbuf
+#define inet_chksum_pseudo lwip_inet_chksum_pseudo
+#define lwip_inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)(addr))
+#define ip_addr_any lwip_ip_addr_any
+#define ip_addr_broadcast lwip_ip_addr_broadcast
+#ifdef ip_addr_isbroadcast
+# undef ip_addr_isbroadcast
+# if defined(ip4_addr_isbroadcast)
+# define lwip_ip_addr_isbroadcast(ipaddr. netif) lwip_ip4_addr_isbroadcast((ipaddr)->addr, (netif))
+# define ip4_addr_isbroadcast lwip_ip4_addr_isbroadcast
+# endif
+#endif
+#define ip_frag lwip_ip_frag
+#define ip_frag_init lwip_ip_frag_init
+#if 0
+#define ip_init lwip_ip_init
+#endif
+#define ip_input lwip_ip_input
+#define ip_output lwip_ip_output
+#define ip_output_if lwip_ip_output_if
+#define ip_reass lwip_ip_reass
+#define ip_reass_tmr lwip_ip_reass_tmr
+#define ip_route lwip_ip_route
+#define netbuf_alloc lwip_netbuf_alloc
+#define netbuf_chain lwip_netbuf_chain
+#define netbuf_data lwip_netbuf_data
+#define netbuf_delete lwip_netbuf_delete
+#define netbuf_first lwip_netbuf_first
+#define netbuf_free lwip_netbuf_free
+#define netbuf_new lwip_netbuf_new
+#define netbuf_next lwip_netbuf_next
+#define netbuf_ref lwip_netbuf_ref
+#define netconn_accept lwip_netconn_accept
+#if 0
+#define netconn_addr lwip_netconn_addr
+#endif
+#define netconn_bind lwip_netconn_bind
+#define netconn_close lwip_netconn_close
+#define netconn_connect lwip_netconn_connect
+#define netconn_delete lwip_netconn_delete
+#define netconn_disconnect lwip_netconn_disconnect
+#if 0
+#define netconn_err lwip_netconn_err
+#define netconn_listen lwip_netconn_listen
+#define netconn_new lwip_netconn_new
+#define netconn_new_with_callback lwip_netconn_new_with_callback
+#endif
+#define netconn_new_with_proto_and_callback lwip_netconn_new_with_proto_and_callback
+#if 0
+#define netconn_peer lwip_netconn_peer
+#endif
+#define netconn_recv lwip_netconn_recv
+#define netconn_send lwip_netconn_send
+#if 0
+#define netconn_type lwip_netconn_type
+#define netconn_write lwip_netconn_write
+#endif
+#define netif_add lwip_netif_add
+#define netif_default lwip_netif_default
+#define netif_find lwip_netif_find
+#define netif_init lwip_netif_init
+#define netif_list lwip_netif_list
+#define netif_remove lwip_netif_remove
+#define netif_set_addr lwip_netif_set_addr
+#define netif_set_default lwip_netif_set_default
+#define netif_set_down lwip_netif_set_down
+#define netif_set_gw lwip_netif_set_gw
+#define netif_set_ipaddr lwip_netif_set_ipaddr
+#define netif_set_netmask lwip_netif_set_netmask
+#define netif_set_up lwip_netif_set_up
+#if MEM_LIBC_MALLOC == 0
+#if MEM_USE_POOLS == 0
+#define mem_init lwip_mem_init
+#define mem_trim lwip_mem_trim
+#endif /* !MEM_USE_POOLS */
+#define mem_malloc lwip_mem_malloc
+#define mem_calloc lwip_mem_calloc
+#define mem_free lwip_mem_free
+#endif /* !MEM_LIBC_MALLOC */
+#define memp_free lwip_memp_free
+#define memp_init lwip_memp_init
+#define memp_malloc lwip_memp_malloc
+#define pbuf_alloc lwip_pbuf_alloc
+#define pbuf_cat lwip_pbuf_cat
+#define pbuf_chain lwip_pbuf_chain
+#define pbuf_clen lwip_pbuf_clen
+#define pbuf_dechain lwip_pbuf_dechain
+#define pbuf_dequeue lwip_pbuf_dequeue
+#define pbuf_free lwip_pbuf_free
+#define pbuf_header lwip_pbuf_header
+#if 0
+#define pbuf_init lwip_pbuf_init
+#endif
+#define pbuf_queue lwip_pbuf_queue
+#define pbuf_realloc lwip_pbuf_realloc
+#define pbuf_ref lwip_pbuf_ref
+#define pbuf_take lwip_pbuf_take
+#define raw_bind lwip_raw_bind
+#define raw_connect lwip_raw_connect
+#if 0
+#define raw_init lwip_raw_init
+#endif
+#define raw_input lwip_raw_input
+#define raw_new lwip_raw_new
+#define raw_recv lwip_raw_recv
+#define raw_remove lwip_raw_remove
+#define raw_send lwip_raw_send
+#define raw_sendto lwip_raw_sendto
+#define stats_init lwip_stats_init
+#define sys_arch_mbox_fetch lwip_sys_arch_mbox_fetch
+#if 0 /* XXX: cf. lwip/sys.h which misinterprets this */
+#define sys_arch_mbox_tryfetch lwip_sys_arch_mbox_tryfetch
+#endif
+#define sys_arch_protect lwip_sys_arch_protect
+#define sys_arch_sem_wait lwip_sys_arch_sem_wait
+#define sys_arch_timeouts lwip_sys_arch_timeouts
+#define sys_arch_unprotect lwip_sys_arch_unprotect
+#define sys_init lwip_sys_init
+#if 0
+#define sys_mbox_fetch lwip_sys_mbox_fetch
+#endif
+#define sys_mbox_free lwip_sys_mbox_free
+#define sys_mbox_new lwip_sys_mbox_new
+#define sys_mbox_post lwip_sys_mbox_post
+#define sys_thread_new lwip_sys_thread_new
+#define sys_msleep lwip_sys_msleep
+#define sys_mbox_set_invalid lwip_sys_mbox_set_invalid
+#define sys_mbox_valid lwip_sys_mbox_valid
+#if 1
+#define sys_sem_wait_timeout lwip_sys_sem_wait_timeout
+#define sys_sem_free lwip_sys_sem_free
+#define sys_sem_new lwip_sys_sem_new
+#define sys_sem_signal lwip_sys_sem_signal
+#define lwip_sys_sem_wait sys_sem_wait
+#define sys_arch_sem_wait lwip_sys_arch_sem_wait
+#endif
+#define sys_timeout_debug lwip_sys_timeout_debug
+#define sys_untimeout lwip_sys_untimeout
+#define tcp_abort lwip_tcp_abort
+#define tcp_accept lwip_tcp_accept
+#define tcp_active_pcbs lwip_tcp_active_pcbs
+#define tcp_alloc lwip_tcp_alloc
+#define tcp_arg lwip_tcp_arg
+#define tcp_backoff lwip_tcp_backoff
+#define tcp_bind lwip_tcp_bind
+#define tcp_close lwip_tcp_close
+#define tcp_connect lwip_tcp_connect
+#define tcp_enqueue lwip_tcp_enqueue
+#define tcp_err lwip_tcp_err
+#define tcp_fasttmr lwip_tcp_fasttmr
+#define tcp_init lwip_tcp_init
+#define tcp_input lwip_tcp_input
+#define tcp_input_pcb lwip_tcp_input_pcb
+#define tcp_keepalive lwip_tcp_keepalive
+#if defined(tcp_listen)
+# undef tcp_listen
+# define tcp_listen(pcb) lwip_tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
+#endif
+#define tcp_listen_with_backlog lwip_tcp_listen_with_backlog
+#define tcp_listen_pcbs lwip_tcp_listen_pcbs
+#define tcp_new lwip_tcp_new
+#define tcp_next_iss lwip_tcp_next_iss
+#define tcp_output lwip_tcp_output
+#define tcp_pcb_purge lwip_tcp_pcb_purge
+#define tcp_pcb_remove lwip_tcp_pcb_remove
+#define tcp_poll lwip_tcp_poll
+#define tcp_recv lwip_tcp_recv
+#define tcp_recved lwip_tcp_recved
+#define tcp_rexmit lwip_tcp_rexmit
+#define tcp_rexmit_rto lwip_tcp_rexmit_rto
+/* tcp_rst is renaming to tcp_rst_impl,
+ * so for cleaner ABI, _impl was added. */
+#define tcp_rst_impl lwip_tcp_rst_impl
+#define tcp_seg_copy lwip_tcp_seg_copy
+#define tcp_seg_free lwip_tcp_seg_free
+#define tcp_segs_free lwip_tcp_segs_free
+#define tcp_send_ctrl lwip_tcp_send_ctrl
+#define tcp_sent lwip_tcp_sent
+#define tcp_setprio lwip_tcp_setprio
+#define tcp_slowtmr lwip_tcp_slowtmr
+#define tcp_ticks lwip_tcp_ticks
+#define tcp_timer_needed lwip_tcp_timer_needed
+#define tcp_tmp_pcb lwip_tcp_tmp_pcb
+#define tcp_tmr lwip_tcp_tmr
+#define tcp_tw_pcbs lwip_tcp_tw_pcbs
+#define tcp_write lwip_tcp_write
+#define tcpip_apimsg lwip_tcpip_apimsg
+#if 0
+#define tcpip_callback lwip_tcpip_callback
+#endif
+#define tcpip_init lwip_tcpip_init
+#define tcpip_input lwip_tcpip_input
+#define udp_bind lwip_udp_bind
+#define udp_connect lwip_udp_connect
+#define udp_disconnect lwip_udp_disconnect
+#define udp_init lwip_udp_init
+#define udp_input lwip_udp_input
+#define udp_new lwip_udp_new
+#define udp_pcbs lwip_udp_pcbs
+#define udp_recv lwip_udp_recv
+#define udp_remove lwip_udp_remove
+#define udp_send lwip_udp_send
+#define udp_sendto lwip_udp_sendto
+
+#define lwip_pbuf_init()
+#define lwip_etharp_init()
+
+#endif /* _VBOX_LWIP_NAMESPACE_H_ */
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c b/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c
new file mode 100644
index 00000000..d04c03ab
--- /dev/null
+++ b/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c
@@ -0,0 +1,583 @@
+/** $Id: sys_arch.c $ */
+/** @file
+ * System dependent parts of lwIP, implemented with IPRT.
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+#include <lwip/sys.h>
+
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/critsect.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+/** @todo during my tests on Debian Lenny 64 bit I ran into trouble using
+ * mutex semaphores (crash deep down in the pthreads lib). Using the write
+ * case of rw semaphores also gives mutual exclusion, and didn't show those
+ * crashes. Should be investigated, because this "fix" might be just covering
+ * the symptoms of a bug elsewhere. */
+#if HC_ARCH_BITS == 64 && defined RT_ARCH_LINUX
+#define LWIPMUTEXTYPE RTSEMRW
+#define LWIPMutexCreate RTSemRWCreate
+#define LWIPMutexDestroy RTSemRWDestroy
+#define LWIPMutexRequest(m) RTSemRWRequestWrite((m), RT_INDEFINITE_WAIT)
+#define LWIPMutexRelease RTSemRWReleaseWrite
+#else
+#define LWIPMUTEXTYPE RTSEMMUTEX
+#define LWIPMutexCreate RTSemMutexCreate
+#define LWIPMutexDestroy RTSemMutexDestroy
+#define LWIPMutexRequest(m) RTSemMutexRequest((m), RT_INDEFINITE_WAIT)
+#define LWIPMutexRelease RTSemMutexRelease
+#endif
+
+/** Maximum number of threads lwIP is allowed to create. */
+#define THREADS_MAX 5
+
+/** Maximum number of mbox entries needed for reasonable performance. */
+#define MBOX_ENTRIES_MAX 128
+
+/** Data type for slots in TLS. */
+typedef struct
+{
+ RTTHREAD tid;
+ void (* thread)(void *arg);
+ void *arg;
+#if 0
+ struct sys_timeouts timeouts;
+#endif
+} THREADLOCALSTORAGE;
+
+/** Actual declaration of the mbox type. */
+/** @todo magic - ??? */
+struct sys_mbox
+{
+ LWIPMUTEXTYPE mutex;
+ RTSEMEVENTMULTI nonempty, nonfull;
+ void *apvEntries[MBOX_ENTRIES_MAX];
+ u32_t head, tail;
+ int valid;
+};
+
+#if SYS_LIGHTWEIGHT_PROT
+/** Critical section variable for short term synchronization. */
+static RTCRITSECT g_ProtCritSect;
+#else
+/** Synchronization for thread creation handling. */
+static RTSEMEVENT g_ThreadSem;
+#endif
+
+/** Number of threads currently created by lwIP. */
+static u32_t g_cThreads = 2;
+
+/** The simulated thread local storage for lwIP things. */
+static THREADLOCALSTORAGE g_aTLS[THREADS_MAX];
+
+/**
+ * Initialize the port to IPRT.
+ */
+void sys_init(void)
+{
+ int rc;
+ unsigned i;
+#if SYS_LIGHTWEIGHT_PROT
+ rc = RTCritSectInit(&g_ProtCritSect);
+ AssertRC(rc);
+#else
+ rc = RTSemEventCreate(&g_ThreadSem);
+ AssertRC(rc);
+ rc = RTSemEventSignal(g_ThreadSem);
+ AssertRC(rc);
+#endif
+ for (i = 0; i < THREADS_MAX; i++)
+ g_aTLS[i].tid = NIL_RTTHREAD;
+}
+
+/**
+ * Create a new (binary) semaphore.
+ */
+err_t sys_sem_new(sys_sem_t *pSem, u8_t count)
+{
+ int rc;
+ err_t rcLwip = ERR_ARG;
+
+ if (!pSem)
+ return ERR_ARG;
+ Assert(count <= 1);
+ rc = RTSemEventCreate(pSem);
+ AssertRCReturn(rc, ERR_ARG);
+ rcLwip = ERR_OK;
+ if (count == 1)
+ {
+ rc = RTSemEventSignal(*pSem);
+ AssertRCReturn(rc, ERR_VAL);
+ }
+ return rcLwip;
+}
+
+/**
+ * Destroy a (binary) semaphore.
+ */
+void sys_sem_free(sys_sem_t *sem)
+{
+ int rc;
+ rc = RTSemEventDestroy(*sem);
+ AssertRC(rc);
+}
+
+/**
+ * Signal a (binary) semaphore.
+ */
+void sys_sem_signal(sys_sem_t *sem)
+{
+ int rc;
+ rc = RTSemEventSignal(*sem);
+ AssertRC(rc);
+}
+
+/**
+ * Wait for a (binary) semaphore.
+ */
+u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
+{
+ int rc;
+ RTMSINTERVAL cMillies;
+ uint64_t tsStart, tsEnd;
+
+ tsStart = RTTimeMilliTS();
+ if (timeout == 0)
+ cMillies = RT_INDEFINITE_WAIT;
+ else
+ cMillies = timeout;
+ rc = RTSemEventWait(*sem, cMillies);
+ if (rc == VERR_TIMEOUT)
+ return SYS_ARCH_TIMEOUT;
+ AssertRC(rc);
+ tsEnd = RTTimeMilliTS();
+ return tsEnd - tsStart;
+}
+
+/**
+ * Create new mbox.
+ */
+err_t sys_mbox_new(sys_mbox_t *pvMbox, int size)
+{
+ int rc;
+ struct sys_mbox *mbox = NULL;
+ RT_NOREF(size); /** @todo safe to ignore this? */
+
+ if (pvMbox == NULL)
+ return ERR_ARG;
+ mbox = RTMemAllocZ(sizeof(struct sys_mbox));
+ Assert(mbox != NULL);
+ if (!mbox)
+ return ERR_MEM;
+ rc = LWIPMutexCreate(&mbox->mutex);
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(mbox);
+ return ERR_VAL;
+ }
+ rc = RTSemEventMultiCreate(&mbox->nonempty);
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ {
+ rc = LWIPMutexDestroy(mbox->mutex);
+ AssertRC(rc);
+ RTMemFree(mbox);
+ return ERR_VAL;
+ }
+ rc = RTSemEventMultiCreate(&mbox->nonfull);
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ {
+ rc = RTSemEventMultiDestroy(mbox->nonempty);
+ AssertRC(rc);
+ rc = LWIPMutexDestroy(mbox->mutex);
+ AssertRC(rc);
+ RTMemFree(mbox);
+ return ERR_VAL;
+ }
+ mbox->valid = 1;
+ *pvMbox = mbox;
+ return ERR_OK;
+}
+
+/**
+ * Free an mbox.
+ */
+void sys_mbox_free(sys_mbox_t *pvMbox)
+{
+ struct sys_mbox *mbox = NULL;
+ Assert(pvMbox && *pvMbox);
+ mbox = (struct sys_mbox*)*pvMbox;
+ LWIPMutexDestroy((mbox)->mutex);
+ RTSemEventMultiDestroy((mbox)->nonempty);
+ RTSemEventMultiDestroy((mbox)->nonfull);
+ RTMemFree(mbox);
+ *pvMbox = NULL;
+}
+
+/**
+ * Place an entry in an mbox, waiting for a free slot if necessary.
+ */
+void sys_mbox_post(sys_mbox_t *pvMbox, void *msg)
+{
+ int rc;
+ struct sys_mbox *mbox = NULL;
+ Assert(pvMbox && *pvMbox);
+ mbox = (struct sys_mbox*)*pvMbox;
+
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+
+ while (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ /* (mbox) is full, have to wait until a slot becomes available. */
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+
+ rc = RTSemEventMultiWait((mbox)->nonfull, RT_INDEFINITE_WAIT);
+ AssertRC(rc);
+
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+ }
+
+ if ((mbox)->head == (mbox)->tail)
+ {
+ rc = RTSemEventMultiSignal((mbox)->nonempty);
+ AssertRC(rc);
+ }
+ (mbox)->apvEntries[(mbox)->head] = msg;
+ (mbox)->head++;
+ (mbox)->head %= MBOX_ENTRIES_MAX;
+ if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ rc = RTSemEventMultiReset((mbox)->nonfull);
+ AssertRC(rc);
+ }
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+}
+
+
+/**
+ * Try to place an entry in an mbox if there is a free slot.
+ */
+err_t sys_mbox_trypost(sys_mbox_t *pvMbox, void *msg)
+{
+ int rc;
+ struct sys_mbox *mbox = NULL;
+ AssertReturn(pvMbox && *pvMbox, ERR_ARG);
+ mbox = (struct sys_mbox*)*pvMbox;
+
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+
+ if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ /* (mbox) is full */
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ return ERR_MEM;
+ }
+
+ if ((mbox)->head == (mbox)->tail)
+ {
+ rc = RTSemEventMultiSignal((mbox)->nonempty);
+ AssertRC(rc);
+ }
+ (mbox)->apvEntries[(mbox)->head] = msg;
+ (mbox)->head++;
+ (mbox)->head %= MBOX_ENTRIES_MAX;
+ if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ rc = RTSemEventMultiReset((mbox)->nonfull);
+ AssertRC(rc);
+ }
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ return ERR_OK;
+}
+
+
+/**
+ * Get an entry from an mbox.
+ */
+u32_t sys_arch_mbox_fetch(sys_mbox_t *pvMbox, void **msg, u32_t timeout)
+{
+ int rc;
+ RTMSINTERVAL cMillies;
+ uint64_t tsStart, tsEnd;
+ struct sys_mbox *mbox = NULL;
+
+ if (!pvMbox || !*pvMbox) return 0;
+ mbox = (struct sys_mbox*)*pvMbox;
+
+ tsStart = RTTimeMilliTS();
+ if (timeout == 0)
+ cMillies = RT_INDEFINITE_WAIT;
+ else
+ cMillies = timeout;
+
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+ while ((mbox)->head == (mbox)->tail)
+ {
+ /* (mbox) is empty, have to wait until a slot is filled. */
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ if (timeout != 0)
+ {
+ tsEnd = RTTimeMilliTS();
+ if (tsEnd - tsStart >= cMillies)
+ return SYS_ARCH_TIMEOUT;
+ cMillies -= tsEnd - tsStart;
+ }
+ rc = RTSemEventMultiWait((mbox)->nonempty, cMillies);
+ if (rc == VERR_TIMEOUT)
+ return SYS_ARCH_TIMEOUT;
+ AssertRC(rc);
+ if (timeout != 0)
+ {
+ tsEnd = RTTimeMilliTS();
+ if (tsEnd - tsStart >= cMillies)
+ return SYS_ARCH_TIMEOUT;
+ cMillies -= tsEnd - tsStart;
+ }
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+ }
+ if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ rc = RTSemEventMultiSignal((mbox)->nonfull);
+ AssertRC(rc);
+ }
+ if (msg != NULL)
+ *msg = (mbox)->apvEntries[(mbox)->tail];
+ (mbox)->tail++;
+ (mbox)->tail %= MBOX_ENTRIES_MAX;
+ rc = RTSemEventMultiSignal((mbox)->nonfull);
+ if ((mbox)->head == (mbox)->tail)
+ {
+ rc = RTSemEventMultiReset((mbox)->nonempty);
+ AssertRC(rc);
+ }
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ tsEnd = RTTimeMilliTS();
+ return tsEnd - tsStart;
+}
+
+/**
+ * Try to get an entry from an mbox.
+ */
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pvMbox, void **msg)
+{
+ int rc;
+ struct sys_mbox *mbox = NULL;
+ if (!pvMbox || !*pvMbox) return SYS_MBOX_EMPTY;
+ mbox = (struct sys_mbox*)*pvMbox;
+
+ rc = LWIPMutexRequest((mbox)->mutex);
+ AssertRC(rc);
+ if ((mbox)->head == (mbox)->tail)
+ {
+ /* (mbox) is empty, don't wait */
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ return SYS_MBOX_EMPTY;
+ }
+ if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
+ {
+ rc = RTSemEventMultiSignal((mbox)->nonfull);
+ AssertRC(rc);
+ }
+ if (msg != NULL)
+ *msg = (mbox)->apvEntries[(mbox)->tail];
+ (mbox)->tail++;
+ (mbox)->tail %= MBOX_ENTRIES_MAX;
+ rc = RTSemEventMultiSignal((mbox)->nonfull);
+ if ((mbox)->head == (mbox)->tail)
+ {
+ rc = RTSemEventMultiReset((mbox)->nonempty);
+ AssertRC(rc);
+ }
+ rc = LWIPMutexRelease((mbox)->mutex);
+ AssertRC(rc);
+ return 0;
+}
+
+/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mbox_valid(sys_mbox_t *pvMbox)
+{
+ struct sys_mbox *mbox = NULL;
+ if (!pvMbox || !*pvMbox) return 0;
+ mbox = (struct sys_mbox*)*pvMbox;
+ return (mbox)->valid;
+}
+
+/** Set an mbox invalid so that sys_mbox_valid returns 0 */
+void sys_mbox_set_invalid(sys_mbox_t *pvMbox)
+{
+ struct sys_mbox *mbox = NULL;
+ if (!pvMbox || !*pvMbox)
+ return;
+ mbox = (struct sys_mbox *)*pvMbox;
+ mbox->valid = 0;
+}
+
+#if 0
+/**
+ * Grab the pointer to this thread's timeouts from TLS.
+ */
+struct sys_timeouts *sys_arch_timeouts(void)
+{
+ unsigned i;
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_DECL_PROTECT(old_level);
+#endif
+ RTTHREAD myself;
+ struct sys_timeouts *to = NULL;
+
+ myself = RTThreadSelf();
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_PROTECT(old_level);
+#else
+ RTSemEventWait(g_ThreadSem, RT_INDEFINITE_WAIT);
+#endif
+ for (i = 0; i < g_cThreads; i++)
+ {
+ if (g_aTLS[i].tid == myself)
+ {
+ to = &g_aTLS[i].timeouts;
+ break;
+ }
+ }
+ /* Auto-adopt new threads which use lwIP as they pop up. */
+ if (!to)
+ {
+ unsigned id;
+ id = g_cThreads;
+ g_cThreads++;
+ Assert(g_cThreads <= THREADS_MAX);
+ g_aTLS[id].tid = myself;
+ to = &g_aTLS[id].timeouts;
+ }
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_UNPROTECT(old_level);
+#else
+ RTSemEventSignal(g_ThreadSem);
+#endif
+ return to;
+}
+#endif
+
+/**
+ * Internal: thread main function adapter, dropping the first parameter. Needed
+ * to make lwip thread main function compatible with IPRT thread main function.
+ */
+static DECLCALLBACK(int) sys_thread_adapter(RTTHREAD hThreadSelf, void *pvUser)
+{
+ THREADLOCALSTORAGE *tls = (THREADLOCALSTORAGE *)pvUser;
+ RT_NOREF(hThreadSelf);
+
+ tls->thread(tls->arg);
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Create new thread.
+ */
+sys_thread_t sys_thread_new(const char*name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
+{
+ int rc;
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_DECL_PROTECT(old_level);
+#endif
+ unsigned id;
+ RTTHREAD tid;
+
+ RT_NOREF(prio, stacksize, name);
+
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_PROTECT(old_level);
+#else
+ RTSemEventWait(g_ThreadSem, RT_INDEFINITE_WAIT);
+#endif
+ id = g_cThreads;
+ g_cThreads++;
+ Assert(g_cThreads <= THREADS_MAX);
+ g_aTLS[id].thread = thread;
+ g_aTLS[id].arg = arg;
+ rc = RTThreadCreateF(&tid, sys_thread_adapter, &g_aTLS[id], 0,
+ RTTHREADTYPE_IO, 0, "lwIP%u", id);
+ if (RT_FAILURE(rc))
+ {
+ g_cThreads--;
+ tid = NIL_RTTHREAD;
+ }
+ else
+ g_aTLS[id].tid = tid;
+#if SYS_LIGHTWEIGHT_PROT
+ SYS_ARCH_UNPROTECT(old_level);
+#else
+ RTSemEventSignal(g_ThreadSem);
+#endif
+ AssertRC(rc);
+ return tid;
+}
+
+#if SYS_LIGHTWEIGHT_PROT
+/**
+ * Start a short critical section.
+ */
+sys_prot_t sys_arch_protect(void)
+{
+ int rc;
+ rc = RTCritSectEnter(&g_ProtCritSect);
+ AssertRC(rc);
+ return NULL;
+}
+#endif
+
+#if SYS_LIGHTWEIGHT_PROT
+/**
+ * End a short critical section.
+ */
+void sys_arch_unprotect(sys_prot_t pval)
+{
+ int rc;
+ (void)pval;
+ rc = RTCritSectLeave(&g_ProtCritSect);
+ AssertRC(rc);
+}
+#endif
+