diff options
Diffstat (limited to '')
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 + |