diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c6196c..9ba2824 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ set (ZTO_SRC_DIR "${PROJ_DIR}/ext/ZeroTierOne") set (LIBZT_SRC_DIR "${PROJ_DIR}/src") include_directories ("${LIBZT_SRC_DIR}") -#include_directories ("${ZTO_SRC_DIR}/include") +include_directories ("${ZTO_SRC_DIR}/include") include_directories ("${PROJ_DIR}") include_directories ("${ZTO_SRC_DIR}/osdep") include_directories ("${ZTO_SRC_DIR}/node") diff --git a/Makefile b/Makefile index 5a893a2..914e439 100644 --- a/Makefile +++ b/Makefile @@ -46,4 +46,5 @@ update: # Patch submodules patch: -git -C ext/lwip apply ../lwip.patch - -git -C ext/lwip-contrib apply ../lwip-contrib.patch \ No newline at end of file + -git -C ext/lwip-contrib apply ../lwip-contrib.patch + -git -C ext/ZeroTierOne apply ../ZeroTierOne.patch diff --git a/ext/ZeroTierOne.patch b/ext/ZeroTierOne.patch new file mode 100644 index 0000000..7ffc17b --- /dev/null +++ b/ext/ZeroTierOne.patch @@ -0,0 +1,17 @@ +diff --git a/service/OneService.cpp b/service/OneService.cpp +index a1c53764..757863a8 100644 +--- a/service/OneService.cpp ++++ b/service/OneService.cpp +@@ -2244,6 +2244,12 @@ public: + #endif + syncManagedStuff(n,true,true); + n.tap->setMtu(nwc->mtu); ++#if defined(ZT_SDK) ++ // Inform the virtual tap of the update ++ if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE) { ++ n.tap->lastConfigUpdate(OSUtils::now()); ++ } ++#endif + } else { + _nets.erase(nwid); + return -999; // tap init failed diff --git a/ext/lwip-contrib.patch b/ext/lwip-contrib.patch index 284a50f..6f5d026 100644 --- a/ext/lwip-contrib.patch +++ b/ext/lwip-contrib.patch @@ -1,16 +1,33 @@ diff --git a/ports/unix/port/include/arch/cc.h b/ports/unix/port/include/arch/cc.h -index a3dac04..39fede7 100644 +index a3dac04..424285e 100644 --- a/ports/unix/port/include/arch/cc.h +++ b/ports/unix/port/include/arch/cc.h -@@ -34,7 +34,7 @@ +@@ -32,6 +32,8 @@ + #ifndef LWIP_ARCH_CC_H + #define LWIP_ARCH_CC_H ++#include "include/Debug.hpp" ++ /* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ #if defined __ANDROID__ --#define LWIP_UNIX_ANDROID -+//#define LWIP_UNIX_ANDROID - #elif defined __linux__ - #define LWIP_UNIX_LINUX - #elif defined __APPLE__ + #define LWIP_UNIX_ANDROID +@@ -55,7 +57,7 @@ + #endif + + #if defined(LWIP_UNIX_ANDROID) && defined(FD_SET) +-typedef __kernel_fd_set fd_set; ++//typedef __kernel_fd_set fd_set; + #endif + + struct sio_status_s; +@@ -63,4 +65,7 @@ typedef struct sio_status_s sio_status_t; + #define sio_fd_t sio_status_t* + #define __sio_fd_t_defined + ++// Comment out the following line to use lwIP's default diagnostic printing routine ++#define LWIP_PLATFORM_DIAG(x) do {DEBUG_INFO x;} while(0) ++ + #endif /* LWIP_ARCH_CC_H */ diff --git a/ports/win32/include/arch/cc.h b/ports/win32/include/arch/cc.h index 334be07..9384b70 100644 --- a/ports/win32/include/arch/cc.h diff --git a/include/Constants.hpp b/include/Constants.hpp index 8b0149a..b25aa43 100644 --- a/include/Constants.hpp +++ b/include/Constants.hpp @@ -34,15 +34,31 @@ #define LIBZT_CONSTANTS_HPP ////////////////////////////////////////////////////////////////////////////// -// Error codes returned by libzt API // +// Error codes returned by ZeroTier and the libzt API // +// See ext/ZeroTierOne/include/ZeroTierOne.h // ////////////////////////////////////////////////////////////////////////////// typedef int zts_err_t; -#define ZTS_ERR_OK 0 -#define ZTS_ERR_INVALID_ARG -1 // A parameter provided by the user application is invalid (e.g. our of range, NULL, etc) -#define ZTS_ERR_SERVICE -2 // The service isn't initialized or is for some other reason currently unavailable -#define ZTS_ERR_INVALID_OP -3 // For some reason this API operation is not permitted (perhaps the service is still starting?) +#define ZTS_ERR_OK 0 // Everything is ok +#define ZTS_ERR_INVALID_ARG -1 // A parameter provided by the user application is invalid (e.g. our of range, NULL, etc) +#define ZTS_ERR_SERVICE -2 // The service isn't initialized or is for some other reason currently unavailable +#define ZTS_ERR_INVALID_OP -3 // For some reason this API operation is not permitted (perhaps the service is still starting?) + +#define ZTS_EVENT_NODE_ONLINE 0x01 // Node is online +#define ZTS_EVENT_NODE_OFFLINE 0x02 // Node is offline +#define ZTS_EVENT_NODE_DOWN 0x03 // Node is shutting down +#define ZTS_EVENT_NODE_IDENTITY_COLLISION 0x04 // Identity collision - check for duplicate instances +#define ZTS_EVENT_NODE_UNRECOVERABLE_ERROR 0x05 // Something is seriously wrong +#define ZTS_EVENT_NODE_NORMAL_TERMINATION 0x06 // Service thread has stopped + +#define ZTS_EVENT_NETWORK_NOT_FOUND 0x07 +#define ZTS_EVENT_NETWORK_CLIENT_TOO_OLD 0x08 +#define ZTS_EVENT_NETWORK_REQUESTING_CONFIG 0x09 +#define ZTS_EVENT_NETWORK_OK 0x0a +#define ZTS_EVENT_NETWORK_ACCESS_DENIED 0x0b +#define ZTS_EVENT_NETWORK_READY 0x0c +#define ZTS_EVENT_NETWORK_DOWN 0x0d ////////////////////////////////////////////////////////////////////////////// // libzt config // @@ -113,6 +129,16 @@ typedef int zts_err_t; */ #define ZTS_HOUSEKEEPING_INTERVAL 1000 +/** + * Name of the service thread (for debug purposes only) + */ +#define ZTS_SERVICE_THREAD_NAME "ZeroTierServiceThread" + +/** + * Name of the callback monitor thread (for debug purposes only) + */ +#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZeroTierEventCallbackThread" + ////////////////////////////////////////////////////////////////////////////// // lwIP driver config // // For more LWIP configuration options see: include/lwipopts.h // diff --git a/include/ServiceControls.hpp b/include/ServiceControls.hpp index 8d8e7ce..1501afa 100644 --- a/include/ServiceControls.hpp +++ b/include/ServiceControls.hpp @@ -89,6 +89,22 @@ ZT_SOCKET_API int ZTCALL zts_get_service_port(); */ ZT_SOCKET_API int ZTCALL zts_start(const char *path, int blocking); +/** + * @brief Starts the ZeroTier service and notifies user application of events via callback + * + * @usage Should be called at the beginning of your application. Will blocks until all of the following conditions are met: + * - ZeroTier core service has been initialized + * - Cryptographic identity has been generated or loaded from directory specified by `path` + * - Virtual network is successfully joined + * - IP address is assigned by network controller service + * @param path path directory where cryptographic identities and network configuration files are stored and retrieved + * (`identity.public`, `identity.secret`) + * @param userCallbackFunc User-specified callback for ZeroTier events + * @param blocking whether or not this call will block until the entire service is up and running + * @return 0 if successful; or 1 if failed + */ +ZT_SOCKET_API int ZTCALL zts_start_with_callback(const char *path, void (*userCallbackFunc)(uint64_t, int), int blocking); + /** * @brief Starts the ZeroTier service * diff --git a/include/VirtualTap.hpp b/include/VirtualTap.hpp index a2d0a96..eb57915 100644 --- a/include/VirtualTap.hpp +++ b/include/VirtualTap.hpp @@ -77,6 +77,25 @@ public: ~VirtualTap(); + /** + * A state will only be reported via callback if it differs from this value. Subsequently this + * value will be updated. + */ + int _lastReportedStatus; + + /** + * The last time that this virtual tap received a network config update from the core + */ + uint64_t _lastConfigUpdateTime = 0; + + /** + * The last time that a callback notification was sent to the user application signalling + * that this interface is ready to process traffic. + */ + uint64_t _lastReadyReportTime = 0; + + void lastConfigUpdate(uint64_t lastConfigUpdateTime); + void setEnabled(bool en); bool enabled() const; @@ -163,7 +182,6 @@ public: ////////////////////////////////////////////////////////////////////////////// std::vector > routes; - void *zt1ServiceRef = NULL; char vtap_full_name[64]; char vtap_abbr_name[16]; diff --git a/include/VirtualTapManager.hpp b/include/VirtualTapManager.hpp index c75a59d..ab2958b 100644 --- a/include/VirtualTapManager.hpp +++ b/include/VirtualTapManager.hpp @@ -30,14 +30,14 @@ * Management of virtual tap interfaces */ +#ifndef LIBZT_VIRTUAL_TAP_MANAGER_H +#define LIBZT_VIRTUAL_TAP_MANAGER_H + #include "VirtualTap.hpp" #include "OneService.hpp" namespace ZeroTier { -extern std::vector vtaps; -extern Mutex _vtaps_lock; - class VirtualTap; /** @@ -47,94 +47,16 @@ class VirtualTapManager { public: - static void add_tap(VirtualTap *tap) { - _vtaps_lock.lock(); - vtaps.push_back((void*)tap); - _vtaps_lock.unlock(); - } - - static VirtualTap *getTapByNWID(uint64_t nwid) - { - _vtaps_lock.lock(); - VirtualTap *s, *tap = nullptr; - for (size_t i=0; i_nwid == nwid) { tap = s; } - } - _vtaps_lock.unlock(); - return tap; - } - - static size_t get_vtaps_size() { - size_t sz; - _vtaps_lock.lock(); - sz = vtaps.size(); - _vtaps_lock.unlock(); - return sz; - } - - // TODO: We shouldn't re-apply the reference to everything all the time - static void update_service_references(void *serviceRef) { - _vtaps_lock.lock(); - for (size_t i=0;izt1ServiceRef=serviceRef; - } - _vtaps_lock.unlock(); - } - - static void remove_by_nwid(uint64_t nwid) { - _vtaps_lock.lock(); - for (size_t i=0;i_nwid == nwid) { - vtaps.erase(vtaps.begin() + i); - } - } - _vtaps_lock.unlock(); - } - - static void clear() { - _vtaps_lock.lock(); - vtaps.clear(); - _vtaps_lock.unlock(); - } - - static void get_network_details(uint64_t nwid, struct zts_network_details *nd) - { - VirtualTap *tap; - socklen_t addrlen; - _vtaps_lock.lock(); - for (size_t i=0; i_nwid == nwid) { - nd->nwid = tap->_nwid; - nd->mtu = tap->_mtu; - // assigned addresses - nd->num_addresses = tap->_ips.size() < ZTS_MAX_ASSIGNED_ADDRESSES ? tap->_ips.size() : ZTS_MAX_ASSIGNED_ADDRESSES; - for (int j=0; jnum_addresses; j++) { - addrlen = tap->_ips[j].isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - memcpy(&(nd->addr[j]), &(tap->_ips[j]), addrlen); - } - // routes - nd->num_routes = ZTS_MAX_NETWORK_ROUTES; - OneService *zt1Service = (OneService*)tap->zt1ServiceRef; - zt1Service->getRoutes(nwid, (ZT_VirtualNetworkRoute*)&(nd->routes)[0], &(nd->num_routes)); - break; - } - } - _vtaps_lock.unlock(); - } - - static void get_all_network_details(struct zts_network_details *nds, int *num) - { - VirtualTap *tap; - *num = get_vtaps_size(); - for (size_t i=0; i_nwid, &nds[i]); - } - } + static void add_tap(VirtualTap *tap); + static VirtualTap *getTapByNWID(uint64_t nwid); + static size_t get_vtaps_size(); + static void remove_by_nwid(uint64_t nwid); + static void clear(); + static void get_network_details_helper(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd); + static void get_network_details(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd); + static void get_all_network_details(void *zt1ServiceRef, struct zts_network_details *nds, int *num); }; -} // namespace ZeroTier \ No newline at end of file +} // namespace ZeroTier + +#endif // _H \ No newline at end of file diff --git a/include/libzt.h b/include/libzt.h index e5b49ff..2f75735 100644 --- a/include/libzt.h +++ b/include/libzt.h @@ -100,7 +100,7 @@ typedef SSIZE_T ssize_t; #define ZTS_PF_INET ZTS_AF_INET #define ZTS_PF_INET6 ZTS_AF_INET6 #define ZTS_PF_UNSPEC ZTS_AF_UNSPEC -// +// Protocol command types #define ZTS_IPPROTO_IP 0x0000 #define ZTS_IPPROTO_ICMP 0x0001 #define ZTS_IPPROTO_TCP 0x0006 @@ -121,7 +121,7 @@ typedef SSIZE_T ssize_t; // fnctl() flags #define ZTS_O_NONBLOCK 0x0001 #define ZTS_O_NDELAY 0x0001 -// +// Shutdown commands #define ZTS_SHUT_RD 0x0000 #define ZTS_SHUT_WR 0x0001 #define ZTS_SHUT_RDWR 0x0002 @@ -161,7 +161,7 @@ typedef SSIZE_T ssize_t; // IPPROTO_IPV6 options #define ZTS_IPV6_CHECKSUM 0x0007 // RFC3542 #define ZTS_IPV6_V6ONLY 0x001b // RFC3493 -// +// Macro's for defining ioctl() command values #define ZTS_IOCPARM_MASK 0x7fU #define ZTS_IOC_VOID 0x20000000UL #define ZTS_IOC_OUT 0x40000000UL @@ -170,11 +170,10 @@ typedef SSIZE_T ssize_t; #define ZTS_IO(x,y) (ZTS_IOC_VOID | ((x)<<8)|(y)) #define ZTS_IOR(x,y,t) (ZTS_IOC_OUT | (((long)sizeof(t) & ZTS_IOCPARM_MASK)<<16) | ((x)<<8) | (y)) #define ZTS_IOW(x,y,t) (ZTS_IOC_IN | (((long)sizeof(t) & ZTS_IOCPARM_MASK)<<16) | ((x)<<8) | (y)) -// +// ioctl() commands #define ZTS_FIONREAD ZTS_IOR('f', 127, unsigned long) #define ZTS_FIONBIO ZTS_IOW('f', 126, unsigned long) - /* FD_SET used for lwip_select */ #ifndef ZTS_FD_SET @@ -330,6 +329,9 @@ struct sockaddr_ll { extern "C" { #endif +// Custom errno to prevent conflicts with platform's own errno +extern int zts_errno; + /** * @brief Create a socket * diff --git a/include/lwipopts.h b/include/lwipopts.h index b2e5164..7f96921 100644 --- a/include/lwipopts.h +++ b/include/lwipopts.h @@ -38,106 +38,47 @@ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ +/*------------------------------------------------------------------------------ +------------------- Custom additions to lwipopts.h for libzt ------------------- +------------------------------------------------------------------------------*/ -/* - * Provides short-named socket macros. Keep disabled - */ -#define LWIP_COMPAT_SOCKETS 0 - -/** - * Respond to broadcast pings (default is unicast only) - */ -#define LWIP_BROADCAST_PING 0 - -/** - * Respond to multicast pings (default is unicast only) - */ -#define LWIP_MULTICAST_PING 0 - -/** - * Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#define IP_FORWARD 0 - -/** - * Number of active MAC-IP address pairs cached. - */ -#define ARP_TABLE_SIZE 10 - -/** - * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of - * pending data in the network buffer. This is the way windows does it. It's - * the default for lwIP since it is smaller. - * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next - * pending datagram in bytes. This is the way linux does it. This code is only - * here for compatibility. - */ -#define LWIP_FIONREAD_LINUXMODE 1 -/** - * Enable SO_RCVBUF processing. - */ -#define LWIP_SO_RCVBUF 1 -/** - * Enable SO_LINGER processing. - */ -#define LWIP_SO_LINGER 0 /* * Provides its own errno */ #if __ANDROID__ -#define LWIP_PROVIDE_ERRNO 0 +#define LWIP_PROVIDE_ERRNO 1 //#define SOCKLEN_T_DEFINED #elif !defined(_MSC_VER) #define LWIP_PROVIDE_ERRNO 1 #endif -/* - * Provides core locking machinery +/** + * Disable assertions */ -#define LWIP_TCPIP_CORE_LOCKING 1 +#define LWIP_NOASSERT 1 -/* - * Provides a macro to spoof the names of the lwip socket functions +/** + * Don't redefine byte-order functions if they're already available */ -#define LWIP_POSIX_SOCKETS_IO_NAMES 0 - -/* - * - */ -#define LWIP_NOASSERT 0 -/* - * - */ -#define LWIP_TIMERS 1 - -/* - * Provides network/host byte transformation macros - */ - #if __ANDROID__ #define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 1 #endif +/** + * Checksum for payloads + */ +#define LWIP_CHKSUM_ALGORITHM 2 -#define LWIP_IPV6_AUTOCONFIG 1 +/** + * Used to compute TCP_MSS + */ +#define MTU 1500 -// #define LWIP_IPV6_MLD 1 -// #define LWIP_ICMP6 1 -// #define LWIP_IPV6_NUM_ADDRESSES 3 -// #define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 -// #define LWIP_IPV6_SEND_ROUTER_SOLICIT 0 - -// IP Protocol version -#define LWIP_NETIF_STATUS_CALLBACK 1 -#define LWIP_IPV4 1 -#define LWIP_IPV6 1 - -// --- DEBUG --- - - -#define LWIP_DEBUG 1 +/** + * Enable or disable debug, see debug ection near end of file + * for more options. + */ +#define LWIP_DEBUG 0 /* flag for LWIP_DEBUGF indicating a tracing message * (to follow program flow) @@ -156,327 +97,655 @@ */ #define LWIP_DBG_HALT 0x08U -//#define LWIP_DBG_TYPES_ON LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_FRESH - -#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL -#define LWIP_DBG_TYPES_ON LWIP_DBG_ON - -#define ETHARP_DEBUG LWIP_DBG_OFF - -// interfaces -#define SLIP_DEBUG LWIP_DBG_OFF -#define NETIF_DEBUG LWIP_DBG_OFF -// API -#define API_LIB_DEBUG LWIP_DBG_OFF -#define API_MSG_DEBUG LWIP_DBG_OFF -#define SOCKETS_DEBUG LWIP_DBG_ON -// other -#define ICMP_DEBUG LWIP_DBG_OFF -#define IGMP_DEBUG LWIP_DBG_OFF -#define INET_DEBUG LWIP_DBG_OFF -#define RAW_DEBUG LWIP_DBG_OFF -// memory -#define PBUF_DEBUG LWIP_DBG_OFF -#define MEM_DEBUG LWIP_DBG_OFF -#define MEMP_DEBUG LWIP_DBG_OFF -// system -#define SYS_DEBUG LWIP_DBG_OFF -#define TIMERS_DEBUG LWIP_DBG_OFF -// TCP -#define TCP_DEBUG_TMR LWIP_DBG_OFF // not standard in lwIP, added for debugging convenience -#define TCP_DEBUG LWIP_DBG_OFF -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#define TCP_FR_DEBUG LWIP_DBG_OFF -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#define TCP_WND_DEBUG LWIP_DBG_OFF -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#define TCP_RST_DEBUG LWIP_DBG_OFF -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -// IP -#define AUTOIP_DEBUG LWIP_DBG_OFF -#define IP_DEBUG LWIP_DBG_OFF -#define IP_REASS_DEBUG LWIP_DBG_OFF -#define IP6_DEBUG LWIP_DBG_OFF -// TCP/IP -#define TCPIP_DEBUG LWIP_DBG_OFF -// UDP -#define UDP_DEBUG LWIP_DBG_OFF -// services -#define DHCP_DEBUG LWIP_DBG_OFF -#define DNS_DEBUG LWIP_DBG_OFF - - -#define LWIP_ETHERNET 1 - -#define LWIP_CHKSUM_ALGORITHM 2 - -#undef TCP_MSS - -#define MTU 1500 -#define TCP_MSS MTU - 40 - -#define LWIP_NETIF_API 1 -#define LWIP_DEBUG_TIMERNAMES 1 -/* -The TCP window size can be adjusted by changing the define TCP_WND. However, -do keep in mind that this should be at least twice the size of TCP_MSS (thus -on ethernet, where TCP_MSS is 1460, it should be set to at least 2920). If -memory allows it, set this as high as possible (16-bit, so 0xFFFF is the highest -value), but keep in mind that for every active connection, the full window may -have to be buffered until it is acknowledged by the remote side (although this -buffer size can still be controlled by TCP_SND_BUF and TCP_SND_QUEUELEN). The -reason for "twice" are both the nagle algorithm and delayed ACK from the -remote peer. -*/ - -#define TCP_WND 0xffff // max = 0xffff, min = TCP_MSS*2 - -#define TCP_LISTEN_BACKLOG 0 - /*------------------------------------------------------------------------------ ----------------------------------- Timers -------------------------------------- -------------------------------------------------------------------------------*/ -/* -Be careful about setting this too small. lwIP just counts the number -of times its timer is called and uses this to control time sensitive -operations (such as TCP retransmissions), rather than actually -measuring time using something more accurate. If you call the timer -functions very frequently you may see things (such as retransmissions) -happening sooner than they should. -*/ -/* these are originally defined in tcp_impl.h */ -#ifndef TCP_TMR_INTERVAL -/* The TCP timer interval in milliseconds. */ -#define TCP_TMR_INTERVAL 250 -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -/* the fine grained timeout in milliseconds */ -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVALs -/* the coarse grained timeout in milliseconds */ -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) -#endif /* TCP_SLOW_INTERVAL */ - - -/*------------------------------------------------------------------------------ ---------------------------- Platform specific locking ------------------------- +----------------------- Below: Modified contents of opt.h ---------------------- ------------------------------------------------------------------------------*/ -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#define SYS_LIGHTWEIGHT_PROT 1 /** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. + * @defgroup lwip_opts Options (lwipopts.h) + * @ingroup lwip + * + * @defgroup lwip_opts_debug Debugging + * @ingroup lwip_opts + * + * @defgroup lwip_opts_infrastructure Infrastructure + * @ingroup lwip_opts + * + * @defgroup lwip_opts_callback Callback-style APIs + * @ingroup lwip_opts + * + * @defgroup lwip_opts_threadsafe_apis Thread-safe APIs + * @ingroup lwip_opts */ -/* set to 1 so we have no thread behaviour */ + /* + ------------------------------------ + -------------- NO SYS -------------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_nosys NO_SYS + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * NO_SYS==1: Use lwIP without OS-awareness (no thread, semaphores, mutexes or + * mboxes). This means threaded APIs cannot be used (socket, netconn, + * i.e. everything in the 'api' folder), only the callback-style raw API is + * available (and you have to watch out for yourself that you don't access + * lwIP functions/structures from more than one context at a time!) + */ +#if !defined NO_SYS || defined __DOXYGEN__ #define NO_SYS 0 +#endif +/** + * @} + */ -/* set to 1 so we can use our own timers */ -#define NO_SYS_NO_TIMERS 0 +/** + * @defgroup lwip_opts_timers Timers + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers. + * (the array of lwip-internal cyclic timers is still provided) + * (check NO_SYS_NO_TIMERS for compatibility to old versions) + */ +#if !defined LWIP_TIMERS || defined __DOXYGEN__ +#ifdef NO_SYS_NO_TIMERS +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) +#else +#define LWIP_TIMERS 1 +#endif +#endif +/** + * LWIP_TIMERS_CUSTOM==1: Provide your own timer implementation. + * Function prototypes in timeouts.h and the array of lwip-internal cyclic timers + * are still included, but the implementation is not. The following functions + * will be required: sys_timeouts_init(), sys_timeout(), sys_untimeout(), + * sys_timeouts_mbox_fetch() + */ +#if !defined LWIP_TIMERS_CUSTOM || defined __DOXYGEN__ +#define LWIP_TIMERS_CUSTOM 0 +#endif +/** + * @} + */ -/*------------------------------------------------------------------------------ --------------------------------- Memory options -------------------------------- -------------------------------------------------------------------------------*/ +/** + * @defgroup lwip_opts_memcpy memcpy + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#if !defined MEMCPY || defined __DOXYGEN__ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) +#endif -//#define MEM_USE_POOLS 0 -//#define MEMP_USE_CUSTOM_POOLS 1 +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#if !defined SMEMCPY || defined __DOXYGEN__ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) +#endif +/** + * @} + */ -/* Misc */ -#define MEM_LIBC_MALLOC 0 -#define MEMP_MEM_MALLOC 1 /* if set to 1, all dynamically allocated memory will come from MEM_SIZE */ +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_lock Core locking and MPU + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MPU_COMPATIBLE: enables special memory management mechanism + * which makes lwip able to work on MPU (Memory Protection Unit) system + * by not passing stack-pointers to other threads + * (this decreases performance as memory is allocated from pools instead + * of keeping it on the stack) + */ +#if !defined LWIP_MPU_COMPATIBLE || defined __DOXYGEN__ +#define LWIP_MPU_COMPATIBLE 0 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#if !defined LWIP_TCPIP_CORE_LOCKING || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING 1 +#endif + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#if !defined LWIP_TCPIP_CORE_LOCKING_INPUT || defined __DOXYGEN__ +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** + * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt + * protection) for certain critical regions during buffer allocation, deallocation + * and memory allocation and deallocation. + * ATTENTION: This is required when using lwIP from more than one context! If + * you disable this, you must be sure what you are doing! + */ +#if !defined SYS_LIGHTWEIGHT_PROT || defined __DOXYGEN__ +#define SYS_LIGHTWEIGHT_PROT 1 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_mem Heap and memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__ +#define MEM_LIBC_MALLOC 1 +#endif + +/** + * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. + * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution + * speed (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ +#if !defined MEMP_MEM_MALLOC || defined __DOXYGEN__ +#define MEMP_MEM_MALLOC 1 +#endif /** * MEM_ALIGNMENT: should be set to the alignment of the CPU - * 4 byte alignment -> #define MEM_ALIGNMENT 4 - * 2 byte alignment -> #define MEM_ALIGNMENT 2 + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 */ +#if !defined MEM_ALIGNMENT || defined __DOXYGEN__ #define MEM_ALIGNMENT 4 +#endif /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ -#define MEM_SIZE 1024 * 1024 -#define TCP_SND_BUF 1024 * 63 -//#define TCP_OVERSIZE TCP_MSS -#define TCP_SND_QUEUELEN 1024 - -/*------------------------------------------------------------------------------ --------------------------------- Pbuf Options ---------------------------------- -------------------------------------------------------------------------------*/ +#if !defined MEM_SIZE || defined __DOXYGEN__ +#define MEM_SIZE 1024*1024 +#endif /** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) */ -#define PBUF_LINK_HLEN 16 +#if !defined MEMP_OVERFLOW_CHECK || defined __DOXYGEN__ +#define MEMP_OVERFLOW_CHECK 0 +#endif /** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. -* + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. */ -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#if !defined MEMP_SANITY_CHECK || defined __DOXYGEN__ +#define MEMP_SANITY_CHECK 0 +#endif +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#if !defined MEM_USE_POOLS || defined __DOXYGEN__ +#define MEM_USE_POOLS 0 +#endif -/*------------------------------------------------------------------------------ --------------------------- Internal Memory Pool Sizes -------------------------- -------------------------------------------------------------------------------*/ +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#if !defined MEM_USE_POOLS_TRY_BIGGER_POOL || defined __DOXYGEN__ +#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 +#endif +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your + * include path somewhere. + */ +#if !defined MEMP_USE_CUSTOM_POOLS || defined __DOXYGEN__ +#define MEMP_USE_CUSTOM_POOLS 0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#if !defined LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT || defined __DOXYGEN__ +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_memp Internal memory pools + * @ingroup lwip_opts_infrastructure + * @{ + */ /** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */ +#if !defined MEMP_NUM_PBUF || defined __DOXYGEN__ #define MEMP_NUM_PBUF 256 +#endif /** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */ +#if !defined MEMP_NUM_RAW_PCB || defined __DOXYGEN__ #define MEMP_NUM_RAW_PCB 128 +#endif /** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */ +#if !defined MEMP_NUM_UDP_PCB || defined __DOXYGEN__ #define MEMP_NUM_UDP_PCB 128 +#endif /** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. * (requires the LWIP_TCP option) */ +#if !defined MEMP_NUM_TCP_PCB || defined __DOXYGEN__ #define MEMP_NUM_TCP_PCB 128 +#endif /** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */ +#if !defined MEMP_NUM_TCP_PCB_LISTEN || defined __DOXYGEN__ #define MEMP_NUM_TCP_PCB_LISTEN 128 +#endif /** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */ -#define MEMP_NUM_TCP_SEG 1024 +#if !defined MEMP_NUM_TCP_SEG || defined __DOXYGEN__ +#define MEMP_NUM_TCP_SEG 512 +#endif /** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for * reassembly (whole packets, not fragments!) */ -#define MEMP_NUM_REASSDATA 1 +#if !defined MEMP_NUM_REASSDATA || defined __DOXYGEN__ +#define MEMP_NUM_REASSDATA 32 +#endif /** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 + * with DMA-enabled MACs where the packet is not yet sent when netif->output + * returns. + */ +#if !defined MEMP_NUM_FRAG_PBUF || defined __DOXYGEN__ +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simultaneously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */ -#define MEMP_NUM_ARP_QUEUE 2 +#if !defined MEMP_NUM_ARP_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ARP_QUEUE 30 +#endif /** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members at the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) */ -#define MEMP_NUM_SYS_TIMEOUT 3 +#if !defined MEMP_NUM_IGMP_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_IGMP_GROUP 8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts. + * The default number of timeouts is calculated here for all enabled modules. + * The formula expects settings to be either '0' or '1'. + */ +#if !defined MEMP_NUM_SYS_TIMEOUT || defined __DOXYGEN__ +#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) +#endif /** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */ +#if !defined MEMP_NUM_NETBUF || defined __DOXYGEN__ #define MEMP_NUM_NETBUF 2 +#endif /** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */ -#define MEMP_NUM_NETCONN 256 +#if !defined MEMP_NUM_NETCONN || defined __DOXYGEN__ +#define MEMP_NUM_NETCONN 128 +#endif /** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */ -#define MEMP_NUM_TCPIP_MSG_API 64 +#if !defined MEMP_NUM_TCPIP_MSG_API || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_API 128 +#endif /** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */ -#define MEMP_NUM_TCPIP_MSG_INPKT 32 +#if !defined MEMP_NUM_TCPIP_MSG_INPKT || defined __DOXYGEN__ +#define MEMP_NUM_TCPIP_MSG_INPKT 128 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#if !defined MEMP_NUM_NETDB || defined __DOXYGEN__ +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#if !defined MEMP_NUM_LOCALHOSTLIST || defined __DOXYGEN__ +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif /** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ -#define PBUF_POOL_SIZE 128 /* was 32 */ +#if !defined PBUF_POOL_SIZE || defined __DOXYGEN__ +#define PBUF_POOL_SIZE 512 +#endif +/** MEMP_NUM_API_MSG: the number of concurrently active calls to various + * socket, netconn, and tcpip functions + */ +#if !defined MEMP_NUM_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif -/*------------------------------------------------------------------------------ ------------------------------------ ARP options -------------------------------- -------------------------------------------------------------------------------*/ +/** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname + */ +#if !defined MEMP_NUM_DNS_API_MSG || defined __DOXYGEN__ +#define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls + * to getsockopt/setsockopt + */ +#if !defined MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA || defined __DOXYGEN__ +#define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API +#endif + +/** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the + * netifapi functions + */ +#if !defined MEMP_NUM_NETIFAPI_MSG || defined __DOXYGEN__ +#define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_arp ARP + * @ingroup lwip_opts_ipv4 + * @{ + */ /** * LWIP_ARP==1: Enable ARP functionality. */ +#if !defined LWIP_ARP || defined __DOXYGEN__ #define LWIP_ARP 1 -#define ARP_TABLE_SIZE 64 -//#define ETHARP_FLAG_TRY_HARD 0 +#endif -/*------------------------------------------------------------------------------ ------------------------------------- IP options--------------------------------- -------------------------------------------------------------------------------*/ +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#if !defined ARP_TABLE_SIZE || defined __DOXYGEN__ +#define ARP_TABLE_SIZE 64 +#endif + +/** the time an ARP entry stays valid after its last update, + * for ARP_TMR_INTERVAL = 1000, this is + * (60 * 5) seconds = 5 minutes. + */ +#if !defined ARP_MAXAGE || defined __DOXYGEN__ +#define ARP_MAXAGE 300 +#endif + +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#if !defined ARP_QUEUEING || defined __DOXYGEN__ +#define ARP_QUEUEING 1 +#endif + +/** The maximum number of packets which may be queued for each + * unresolved address by other network layers. Defaults to 3, 0 means disabled. + * Old packets are dropped, new packets are queued. + */ +#if !defined ARP_QUEUE_LEN || defined __DOXYGEN__ +#define ARP_QUEUE_LEN 8 +#endif + +/** + * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with + * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and + * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. + * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. + * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. + * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. + */ +#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__ +#define ETHARP_SUPPORT_VLAN 0 +#endif + +/** LWIP_ETHERNET==1: enable ethernet support even though ARP might be disabled + */ +#if !defined LWIP_ETHERNET || defined __DOXYGEN__ +#define LWIP_ETHERNET LWIP_ARP +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#if !defined ETH_PAD_SIZE || defined __DOXYGEN__ +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#if !defined ETHARP_SUPPORT_STATIC_ENTRIES || defined __DOXYGEN__ +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/** ETHARP_TABLE_MATCH_NETIF==1: Match netif for ARP table entries. + * If disabled, duplicate IP address on multiple netifs are not supported + * (but this should only occur for AutoIP). + */ +#if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ +#define ETHARP_TABLE_MATCH_NETIF 0 +#endif +/** + * @} + */ + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv4 IPv4 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#if !defined LWIP_IPV4 || defined __DOXYGEN__ +#define LWIP_IPV4 1 +#endif /** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */ +#if !defined IP_FORWARD || defined __DOXYGEN__ #define IP_FORWARD 0 - -/** - * IP_OPTIONS: Defines the behavior for IP options. - * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. - * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). - */ -#define IP_OPTIONS_ALLOWED 1 +#endif /** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ +#if !defined IP_REASSEMBLY || defined __DOXYGEN__ #define IP_REASSEMBLY 1 +#endif /** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */ +#if !defined IP_FRAG || defined __DOXYGEN__ #define IP_FRAG 1 -#define IPV6_FRAG_COPYHEADER 1 // Was 0 +#endif + +#if !LWIP_IPV4 +/* disable IPv4 extensions when IPv4 is disabled */ +#undef IP_FORWARD +#define IP_FORWARD 0 +#undef IP_REASSEMBLY +#define IP_REASSEMBLY 0 +#undef IP_FRAG +#define IP_FRAG 0 +#endif /* !LWIP_IPV4 */ + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#if !defined IP_OPTIONS_ALLOWED || defined __DOXYGEN__ +#define IP_OPTIONS_ALLOWED 1 +#endif /** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */ +#if !defined IP_REASS_MAXAGE || defined __DOXYGEN__ #define IP_REASS_MAXAGE 3 +#endif /** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. @@ -484,191 +753,2176 @@ happening sooner than they should. * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */ +#if !defined IP_REASS_MAX_PBUFS || defined __DOXYGEN__ #define IP_REASS_MAX_PBUFS 32 - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented. -*/ -#define IP_FRAG_USES_STATIC_BUF 0 +#endif /** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */ +#if !defined IP_DEFAULT_TTL || defined __DOXYGEN__ #define IP_DEFAULT_TTL 255 +#endif +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#if !defined IP_SOF_BROADCAST || defined __DOXYGEN__ +#define IP_SOF_BROADCAST 0 +#endif -/*------------------------------------------------------------------------------ -------------------------------- ICMP Options ----------------------------------- -------------------------------------------------------------------------------*/ +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#if !defined IP_SOF_BROADCAST_RECV || defined __DOXYGEN__ +#define IP_SOF_BROADCAST_RECV 0 +#endif +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#if !defined IP_FORWARD_ALLOW_TX_ON_RX_NETIF || defined __DOXYGEN__ +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#if !defined LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS || defined __DOXYGEN__ +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_icmp ICMP + * @ingroup lwip_opts_ipv4 + * @{ + */ /** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */ +#if !defined LWIP_ICMP || defined __DOXYGEN__ #define LWIP_ICMP 1 -#define LWIP_ICMP6 LWIP_IPV6 && 1 // Was 0 +#endif -/*------------------------------------------------------------------------------ -------------------------------- RAW Options ------------------------------------ -------------------------------------------------------------------------------*/ +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#if !defined ICMP_TTL || defined __DOXYGEN__ +#define ICMP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#if !defined LWIP_BROADCAST_PING || defined __DOXYGEN__ +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#if !defined LWIP_MULTICAST_PING || defined __DOXYGEN__ +#define LWIP_MULTICAST_PING 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_raw RAW + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#if !defined LWIP_RAW || defined __DOXYGEN__ +#define LWIP_RAW 0 +#endif /** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ -#define LWIP_RAW 1 - - -/*------------------------------------------------------------------------------ -------------------------------- DHCP Options ----------------------------------- -------------------------------------------------------------------------------*/ +#if !defined RAW_TTL || defined __DOXYGEN__ +#define RAW_TTL (IP_DEFAULT_TTL) +#endif +/** + * @} + */ +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dhcp DHCP + * @ingroup lwip_opts_ipv4 + * @{ + */ /** * LWIP_DHCP==1: Enable DHCP module. */ +#if !defined LWIP_DHCP || defined __DOXYGEN__ #define LWIP_DHCP 0 +#endif +#if !LWIP_IPV4 +/* disable DHCP when IPv4 is disabled */ +#undef LWIP_DHCP +#define LWIP_DHCP 0 +#endif /* !LWIP_IPV4 */ +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#if !defined DHCP_DOES_ARP_CHECK || defined __DOXYGEN__ +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif -/*------------------------------------------------------------------------------ ------------------------------- AUTOIP Options ---------------------------------- -------------------------------------------------------------------------------*/ +/** + * LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has + * NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and + * netif drivers might not set this flag, the default is off. If enabled, + * netif_set_link_up() must be called to continue dhcp starting. + */ +#if !defined LWIP_DHCP_CHECK_LINK_UP +#define LWIP_DHCP_CHECK_LINK_UP 0 +#endif +/** + * LWIP_DHCP_BOOTP_FILE==1: Store offered_si_addr and boot_file_name. + */ +#if !defined LWIP_DHCP_BOOTP_FILE || defined __DOXYGEN__ +#define LWIP_DHCP_BOOTP_FILE 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#if !defined LWIP_DHCP_GET_NTP_SRV || defined __DOXYGEN__ +#define LWIP_DHCP_GET_NTP_SRV 0 +#endif + +/** + * The maximum of NTP servers requested + */ +#if !defined LWIP_DHCP_MAX_NTP_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_NTP_SERVERS 1 +#endif + +/** + * LWIP_DHCP_MAX_DNS_SERVERS > 0: Request DNS servers with discover/select. + * DHCP servers received in the response are passed to DNS via @ref dns_setserver() + * (up to the maximum limit defined here). + */ +#if !defined LWIP_DHCP_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_DHCP_MAX_DNS_SERVERS DNS_MAX_SERVERS +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_autoip AUTOIP + * @ingroup lwip_opts_ipv4 + * @{ + */ /** * LWIP_AUTOIP==1: Enable AUTOIP module. */ +#if !defined LWIP_AUTOIP || defined __DOXYGEN__ #define LWIP_AUTOIP 0 - - -/*------------------------------------------------------------------------------ -------------------------------- SNMP Options ----------------------------------- -------------------------------------------------------------------------------*/ +#endif +#if !LWIP_IPV4 +/* disable AUTOIP when IPv4 is disabled */ +#undef LWIP_AUTOIP +#define LWIP_AUTOIP 0 +#endif /* !LWIP_IPV4 */ /** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. */ -#define LWIP_SNMP 0 +#if !defined LWIP_DHCP_AUTOIP_COOP || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP 0 +#endif +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP (the DHCP client keeps + * running in this case). This can be set as low as 1 to get an AutoIP address + * very quickly, but you should be prepared to handle a changing IP address + * when DHCP overrides AutoIP. + */ +#if !defined LWIP_DHCP_AUTOIP_COOP_TRIES || defined __DOXYGEN__ +#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 +#endif +/** + * @} + */ -/*------------------------------------------------------------------------------ -------------------------------- IGMP Options ----------------------------------- -------------------------------------------------------------------------------*/ +/* + ---------------------------------- + ----- SNMP MIB2 support ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_mib2 SNMP MIB2 callbacks + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * LWIP_MIB2_CALLBACKS==1: Turn on SNMP MIB2 callbacks. + * Turn this on to get callbacks needed to implement MIB2. + * Usually MIB2_STATS should be enabled, too. + */ +#if !defined LWIP_MIB2_CALLBACKS || defined __DOXYGEN__ +#define LWIP_MIB2_CALLBACKS 0 +#endif +/** + * @} + */ +/* + ---------------------------------- + ----- Multicast/IGMP options ----- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_igmp IGMP + * @ingroup lwip_opts_ipv4 + * @{ + */ /** * LWIP_IGMP==1: Turn on IGMP module. */ +#if !defined LWIP_IGMP || defined __DOXYGEN__ #define LWIP_IGMP 0 +#endif +#if !LWIP_IPV4 +#undef LWIP_IGMP +#define LWIP_IGMP 0 +#endif +/** + * LWIP_MULTICAST_TX_OPTIONS==1: Enable multicast TX support like the socket options + * IP_MULTICAST_TTL/IP_MULTICAST_IF/IP_MULTICAST_LOOP + */ +#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ +#define LWIP_MULTICAST_TX_OPTIONS (LWIP_IGMP && LWIP_UDP) +#endif +/** + * @} + */ -/*------------------------------------------------------------------------------ --------------------------------- DNS Options ----------------------------------- -------------------------------------------------------------------------------*/ - +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_dns DNS + * @ingroup lwip_opts_callback + * @{ + */ /** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */ +#if !defined LWIP_DNS || defined __DOXYGEN__ #define LWIP_DNS 0 -#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif -/*------------------------------------------------------------------------------ --------------------------------- UDP Options ----------------------------------- -------------------------------------------------------------------------------*/ +/** DNS maximum number of entries to maintain locally. */ +#if !defined DNS_TABLE_SIZE || defined __DOXYGEN__ +#define DNS_TABLE_SIZE 4 +#endif +/** DNS maximum host name length supported in the name table. */ +#if !defined DNS_MAX_NAME_LENGTH || defined __DOXYGEN__ +#define DNS_MAX_NAME_LENGTH 256 +#endif + +/** The maximum of DNS servers + * The first server can be initialized automatically by defining + * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#if !defined DNS_MAX_SERVERS || defined __DOXYGEN__ +#define DNS_MAX_SERVERS 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#if !defined DNS_DOES_NAME_CHECK || defined __DOXYGEN__ +#define DNS_DOES_NAME_CHECK 1 +#endif + +/** LWIP_DNS_SECURE: controls the security level of the DNS implementation + * Use all DNS security features by default. + * This is overridable but should only be needed by very small targets + * or when using against non standard DNS servers. */ +#if !defined LWIP_DNS_SECURE || defined __DOXYGEN__ +#define LWIP_DNS_SECURE (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) +#endif + +/* A list of DNS security features follows */ +#define LWIP_DNS_SECURE_RAND_XID 1 +#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING 2 +#define LWIP_DNS_SECURE_RAND_SRC_PORT 4 + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, you have to define an initializer: + * \#define DNS_LOCAL_HOSTLIST_INIT {DNS_LOCAL_HOSTLIST_ELEM("host_ip4", IPADDR4_INIT_BYTES(1,2,3,4)), \ + * DNS_LOCAL_HOSTLIST_ELEM("host_ip6", IPADDR6_INIT_HOST(123, 234, 345, 456)} + * + * Instead, you can also use an external function: + * \#define DNS_LOOKUP_LOCAL_EXTERN(x) extern err_t my_lookup_function(const char *name, ip_addr_t *addr, u8_t dns_addrtype) + * that looks up the IP address and returns ERR_OK if found (LWIP_DNS_ADDRTYPE_xxx is passed in dns_addrtype). + */ +#if !defined DNS_LOCAL_HOSTLIST || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST 0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + * at runtime. */ +#if !defined DNS_LOCAL_HOSTLIST_IS_DYNAMIC || defined __DOXYGEN__ +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#if !defined LWIP_DNS_SUPPORT_MDNS_QUERIES || defined __DOXYGEN__ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_udp UDP + * @ingroup lwip_opts_callback + * @{ + */ /** * LWIP_UDP==1: Turn on UDP. */ +#if !defined LWIP_UDP || defined __DOXYGEN__ #define LWIP_UDP 1 +#endif +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#if !defined LWIP_UDPLITE || defined __DOXYGEN__ +#define LWIP_UDPLITE 0 +#endif -/*------------------------------------------------------------------------------ --------------------------------- TCP Options ----------------------------------- -------------------------------------------------------------------------------*/ +/** + * UDP_TTL: Default Time-To-Live value. + */ +#if !defined UDP_TTL || defined __DOXYGEN__ +#define UDP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. + */ +#if !defined LWIP_NETBUF_RECVINFO || defined __DOXYGEN__ +#define LWIP_NETBUF_RECVINFO 0 +#endif +/** + * @} + */ + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * @defgroup lwip_opts_tcp TCP + * @ingroup lwip_opts_callback + * @{ + */ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#if !defined LWIP_TCP || defined __DOXYGEN__ +#define LWIP_TCP 1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#if !defined TCP_TTL || defined __DOXYGEN__ +#define TCP_TTL (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#if !defined TCP_WND || defined __DOXYGEN__ +#define TCP_WND 0xffff // was (4 * TCP_MSS) +#endif + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#if !defined TCP_MAXRTX || defined __DOXYGEN__ +#define TCP_MAXRTX 12 +#endif /** * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. */ -#define TCP_SYNMAXRTX 12 +#if !defined TCP_SYNMAXRTX || defined __DOXYGEN__ +#define TCP_SYNMAXRTX 6 +#endif /** - * LWIP_TCP==1: Turn on TCP. + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. */ -#define LWIP_TCP 1 - -#define LWIP_LISTEN_BACKLOG 0 - - -/*------------------------------------------------------------------------------ ---------------------------------- LOOPIF Options ------------------------------- -------------------------------------------------------------------------------*/ +#if !defined TCP_QUEUE_OOSEQ || defined __DOXYGEN__ +#define TCP_QUEUE_OOSEQ (LWIP_TCP) +#endif /** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. */ -#define LWIP_HAVE_LOOPIF 0 +#if !defined TCP_MSS || defined __DOXYGEN__ +#define TCP_MSS MTU - 40 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#if !defined TCP_CALCULATE_EFF_SEND_MSS || defined __DOXYGEN__ +#define TCP_CALCULATE_EFF_SEND_MSS 1 +#endif -/*------------------------------------------------------------------------------ ----------------------------- Sequential Layer Options -------------------------- -------------------------------------------------------------------------------*/ +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#if !defined TCP_SND_BUF || defined __DOXYGEN__ +#define TCP_SND_BUF TCP_WND // was (2 * TCP_MSS) +#endif +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#if !defined TCP_SND_QUEUELEN || defined __DOXYGEN__ +#define TCP_SND_QUEUELEN ((8 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). + */ +#if !defined TCP_SNDLOWAT || defined __DOXYGEN__ +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) +#endif + +/** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#if !defined TCP_SNDQUEUELOWAT || defined __DOXYGEN__ +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__ +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_LISTEN_BACKLOG 1 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#if !defined TCP_DEFAULT_LISTEN_BACKLOG || defined __DOXYGEN__ +#define TCP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#if !defined TCP_OVERSIZE || defined __DOXYGEN__ +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#if !defined LWIP_TCP_TIMESTAMPS || defined __DOXYGEN__ +#define LWIP_TCP_TIMESTAMPS 0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#if !defined TCP_WND_UPDATE_THRESHOLD || defined __DOXYGEN__ +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) || defined __DOXYGEN__ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 +#else +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API 0 +#endif +#ifndef LWIP_CALLBACK_API +#define LWIP_CALLBACK_API 0 +#endif +#endif + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#if !defined LWIP_WND_SCALE || defined __DOXYGEN__ +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * @defgroup lwip_opts_pbuf PBUF + * @ingroup lwip_opts + * @{ + */ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#if !defined PBUF_LINK_HLEN || defined __DOXYGEN__ +#if defined LWIP_HOOK_VLAN_SET && !defined __DOXYGEN__ +#define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) +#else /* LWIP_HOOK_VLAN_SET */ +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) +#endif /* LWIP_HOOK_VLAN_SET */ +#endif + +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + */ +#if !defined PBUF_LINK_ENCAPSULATION_HLEN || defined __DOXYGEN__ +#define PBUF_LINK_ENCAPSULATION_HLEN 0u +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accommodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN) +#endif +/** + * @} + */ + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#if !defined LWIP_NETIF_HOSTNAME || defined __DOXYGEN__ +#define LWIP_NETIF_HOSTNAME 0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#if !defined LWIP_NETIF_API || defined __DOXYGEN__ +#define LWIP_NETIF_API 1 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#if !defined LWIP_NETIF_STATUS_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#if !defined LWIP_NETIF_LINK_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LINK_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#if !defined LWIP_NETIF_REMOVE_CALLBACK || defined __DOXYGEN__ +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#if !defined LWIP_NETIF_HWADDRHINT || defined __DOXYGEN__ +#define LWIP_NETIF_HWADDRHINT 1 +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#if !defined LWIP_NETIF_TX_SINGLE_PBUF || defined __DOXYGEN__ +#define LWIP_NETIF_TX_SINGLE_PBUF 0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif. + */ +#if !defined LWIP_NUM_NETIF_CLIENT_DATA || defined __DOXYGEN__ +#define LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_loop Loopback interface + * @ingroup lwip_opts_netif + * @{ + */ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other + * netif is available, loopback traffic uses this netif. + */ +#if !defined LWIP_HAVE_LOOPIF || defined __DOXYGEN__ +#define LWIP_HAVE_LOOPIF LWIP_NETIF_LOOPBACK +#endif + +/** + * LWIP_LOOPIF_MULTICAST==1: Support multicast/IGMP on loop interface (127.0.0.1). + */ +#if !defined LWIP_LOOPIF_MULTICAST || defined __DOXYGEN__ +#define LWIP_LOOPIF_MULTICAST 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#if !defined LWIP_NETIF_LOOPBACK || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#if !defined LWIP_LOOPBACK_MAX_PBUFS || defined __DOXYGEN__ +#define LWIP_LOOPBACK_MAX_PBUFS 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#if !defined LWIP_NETIF_LOOPBACK_MULTITHREADING || defined __DOXYGEN__ +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_thread Threading + * @ingroup lwip_opts_infrastructure + * @{ + */ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#if !defined TCPIP_THREAD_NAME || defined __DOXYGEN__ +#define TCPIP_THREAD_NAME "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_STACKSIZE || defined __DOXYGEN__ +#define TCPIP_THREAD_STACKSIZE 0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined TCPIP_THREAD_PRIO || defined __DOXYGEN__ +#define TCPIP_THREAD_PRIO 1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#if !defined TCPIP_MBOX_SIZE || defined __DOXYGEN__ +#define TCPIP_MBOX_SIZE 0 +#endif + +/** + * Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. + */ +#if !defined LWIP_TCPIP_THREAD_ALIVE || defined __DOXYGEN__ +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#if !defined SLIPIF_THREAD_NAME || defined __DOXYGEN__ +#define SLIPIF_THREAD_NAME "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_STACKSIZE || defined __DOXYGEN__ +#define SLIPIF_THREAD_STACKSIZE 0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined SLIPIF_THREAD_PRIO || defined __DOXYGEN__ +#define SLIPIF_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#if !defined DEFAULT_THREAD_NAME || defined __DOXYGEN__ +#define DEFAULT_THREAD_NAME "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_STACKSIZE || defined __DOXYGEN__ +#define DEFAULT_THREAD_STACKSIZE 0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#if !defined DEFAULT_THREAD_PRIO || defined __DOXYGEN__ +#define DEFAULT_THREAD_PRIO 1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_RAW_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_RAW_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_UDP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_UDP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#if !defined DEFAULT_TCP_RECVMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_TCP_RECVMBOX_SIZE 0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#if !defined DEFAULT_ACCEPTMBOX_SIZE || defined __DOXYGEN__ +#define DEFAULT_ACCEPTMBOX_SIZE 0 +#endif +/** + * @} + */ + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * @defgroup lwip_opts_netconn Netconn + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ /** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */ -#define LWIP_NETCONN 1//(NO_SYS==0) +#if !defined LWIP_NETCONN || defined __DOXYGEN__ +#define LWIP_NETCONN 1 +#endif +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout to create + * timers running in tcpip_thread from another thread. + */ +#if !defined LWIP_TCPIP_TIMEOUT || defined __DOXYGEN__ +#define LWIP_TCPIP_TIMEOUT 0 +#endif -/*------------------------------------------------------------------------------ ---------------------------------- Socket Options ------------------------------- -------------------------------------------------------------------------------*/ +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#if !defined LWIP_NETCONN_SEM_PER_THREAD || defined __DOXYGEN__ +#define LWIP_NETCONN_SEM_PER_THREAD 0 +#endif + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#if !defined LWIP_NETCONN_FULLDUPLEX || defined __DOXYGEN__ +#define LWIP_NETCONN_FULLDUPLEX 0 +#endif +/** + * @} + */ + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * @defgroup lwip_opts_socket Sockets + * @ingroup lwip_opts_threadsafe_apis + * @{ + */ /** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */ +#if !defined LWIP_SOCKET || defined __DOXYGEN__ +#define LWIP_SOCKET 1 +#endif -#define LWIP_SOCKET 1//(NO_SYS==0) +/* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete + * successfully, as required by POSIX. Default is POSIX-compliant. + */ +#if !defined LWIP_SOCKET_SET_ERRNO || defined __DOXYGEN__ +#define LWIP_SOCKET_SET_ERRNO 1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#if !defined LWIP_COMPAT_SOCKETS || defined __DOXYGEN__ +#define LWIP_COMPAT_SOCKETS 0 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#if !defined LWIP_POSIX_SOCKETS_IO_NAMES || defined __DOXYGEN__ +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 +#endif + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * This can be useful when there are multiple APIs which create file descriptors. + * When they all start with a different offset and you won't make them overlap you can + * re implement read/write/close/ioctl/fnctl to send the requested action to the right + * library (sharing select will need more work though). + */ +#if !defined LWIP_SOCKET_OFFSET || defined __DOXYGEN__ +#define LWIP_SOCKET_OFFSET 0 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#if !defined LWIP_TCP_KEEPALIVE || defined __DOXYGEN__ +#define LWIP_TCP_KEEPALIVE 1 +#endif /** * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and * SO_SNDTIMEO processing. */ +#if !defined LWIP_SO_SNDTIMEO || defined __DOXYGEN__ #define LWIP_SO_SNDTIMEO 1 +#endif /** * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and * SO_RCVTIMEO processing. */ +#if !defined LWIP_SO_RCVTIMEO || defined __DOXYGEN__ #define LWIP_SO_RCVTIMEO 1 +#endif + +/** + * LWIP_SO_SNDRCVTIMEO_NONSTANDARD==1: SO_RCVTIMEO/SO_SNDTIMEO take an int + * (milliseconds, much like winsock does) instead of a struct timeval (default). + */ +#if !defined LWIP_SO_SNDRCVTIMEO_NONSTANDARD || defined __DOXYGEN__ +#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 0 +#endif /** * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. */ +#if !defined LWIP_SO_RCVBUF || defined __DOXYGEN__ #define LWIP_SO_RCVBUF 1 +#endif -/*------------------------------------------------------------------------------ ------------------------------- Statistics Options ------------------------------ -------------------------------------------------------------------------------*/ +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#if !defined LWIP_SO_LINGER || defined __DOXYGEN__ +#define LWIP_SO_LINGER 1 +#endif +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#if !defined RECV_BUFSIZE_DEFAULT || defined __DOXYGEN__ +#define RECV_BUFSIZE_DEFAULT INT_MAX +#endif + +/** + * By default, TCP socket/netconn close waits 20 seconds max to send the FIN + */ +#if !defined LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT || defined __DOXYGEN__ +#define LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT 20000 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + */ +#if !defined SO_REUSE || defined __DOXYGEN__ +#define SO_REUSE 1 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#if !defined SO_REUSE_RXTOALL || defined __DOXYGEN__ +#define SO_REUSE_RXTOALL 0 +#endif + +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#if !defined LWIP_FIONREAD_LINUXMODE || defined __DOXYGEN__ +#define LWIP_FIONREAD_LINUXMODE 1 +#endif +/** + * @} + */ + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * @defgroup lwip_opts_stats Statistics + * @ingroup lwip_opts_debug + * @{ + */ /** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */ -#define LWIP_STATS 1 -//#define LWIP_STATS_DISPLAY 1 +#if !defined LWIP_STATS || defined __DOXYGEN__ +#define LWIP_STATS 0 +#endif -/*------------------------------------------------------------------------------ ---------------------------------- PPP Options ---------------------------------- -------------------------------------------------------------------------------*/ +#if LWIP_STATS /** - * PPP_SUPPORT==1: Enable PPP. + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#if !defined LWIP_STATS_DISPLAY || defined __DOXYGEN__ +#define LWIP_STATS_DISPLAY 0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#if !defined LINK_STATS || defined __DOXYGEN__ +#define LINK_STATS 0 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#if !defined ETHARP_STATS || defined __DOXYGEN__ +#define ETHARP_STATS (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#if !defined IP_STATS || defined __DOXYGEN__ +#define IP_STATS 1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#if !defined IPFRAG_STATS || defined __DOXYGEN__ +#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#if !defined ICMP_STATS || defined __DOXYGEN__ +#define ICMP_STATS 0 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#if !defined IGMP_STATS || defined __DOXYGEN__ +#define IGMP_STATS (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#if !defined UDP_STATS || defined __DOXYGEN__ +#define UDP_STATS (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#if !defined TCP_STATS || defined __DOXYGEN__ +#define TCP_STATS (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#if !defined MEM_STATS || defined __DOXYGEN__ +#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#if !defined MEMP_STATS || defined __DOXYGEN__ +#define MEMP_STATS (MEMP_MEM_MALLOC == 0) +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#if !defined SYS_STATS || defined __DOXYGEN__ +#define SYS_STATS (NO_SYS == 0) +#endif + +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#if !defined IP6_STATS || defined __DOXYGEN__ +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#if !defined ICMP6_STATS || defined __DOXYGEN__ +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#if !defined IP6_FRAG_STATS || defined __DOXYGEN__ +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#if !defined MLD6_STATS || defined __DOXYGEN__ +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#if !defined ND6_STATS || defined __DOXYGEN__ +#define ND6_STATS (LWIP_IPV6) +#endif + +/** + * MIB2_STATS==1: Stats for SNMP MIB2. + */ +#if !defined MIB2_STATS || defined __DOXYGEN__ +#define MIB2_STATS 0 +#endif + +#else + +#define LINK_STATS 0 +#define ETHARP_STATS 0 +#define IP_STATS 0 +#define IPFRAG_STATS 0 +#define ICMP_STATS 0 +#define IGMP_STATS 0 +#define UDP_STATS 0 +#define TCP_STATS 0 +#define MEM_STATS 0 +#define MEMP_STATS 0 +#define SYS_STATS 0 +#define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 +#define MIB2_STATS 0 + +#endif /* LWIP_STATS */ +/** + * @} */ -#define PPP_SUPPORT 0 /* - * Include user defined options first. Anything not defined in these files - * will be set to standard values. Override anything you dont like! + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ +/** + * @defgroup lwip_opts_checksum Checksum + * @ingroup lwip_opts_infrastructure + * @{ */ -#include "lwip/debug.h" +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#if !defined LWIP_CHECKSUM_CTRL_PER_NETIF || defined __DOXYGEN__ +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#endif -#endif /* __LWIPOPTS_H__ */ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#if !defined CHECKSUM_GEN_IP || defined __DOXYGEN__ +#define CHECKSUM_GEN_IP 1 +#endif +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#if !defined CHECKSUM_GEN_UDP || defined __DOXYGEN__ +#define CHECKSUM_GEN_UDP 1 +#endif + +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#if !defined CHECKSUM_GEN_TCP || defined __DOXYGEN__ +#define CHECKSUM_GEN_TCP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. + */ +#if !defined CHECKSUM_GEN_ICMP || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP 1 +#endif + +/** + * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. + */ +#if !defined CHECKSUM_GEN_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_GEN_ICMP6 1 +#endif + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#if !defined CHECKSUM_CHECK_IP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_IP 0 // turned off since ZeroTier CRC's entire payload +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#if !defined CHECKSUM_CHECK_UDP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_UDP 0 // turned off since ZeroTier CRC's entire payload +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#if !defined CHECKSUM_CHECK_TCP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_TCP 0 // turned off since ZeroTier CRC's entire payload +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#if !defined CHECKSUM_CHECK_ICMP || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP 0 // turned off since ZeroTier CRC's entire payload +#endif + +/** + * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets + */ +#if !defined CHECKSUM_CHECK_ICMP6 || defined __DOXYGEN__ +#define CHECKSUM_CHECK_ICMP6 0 // turned off since ZeroTier CRC's entire payload +#endif + +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#if !defined LWIP_CHECKSUM_ON_COPY || defined __DOXYGEN__ +#define LWIP_CHECKSUM_ON_COPY 0 // turned off since ZeroTier CRC's entire payload +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_ipv6 IPv6 + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#if !defined LWIP_IPV6 || defined __DOXYGEN__ +#define LWIP_IPV6 1 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#if !defined LWIP_IPV6_NUM_ADDRESSES || defined __DOXYGEN__ +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#if !defined LWIP_IPV6_FORWARD || defined __DOXYGEN__ +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#if !defined LWIP_IPV6_FRAG || defined __DOXYGEN__ +#define LWIP_IPV6_FRAG 1 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#if !defined LWIP_IPV6_REASS || defined __DOXYGEN__ +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__ +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#if !defined LWIP_IPV6_AUTOCONFIG || defined __DOXYGEN__ +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts. + */ +#if !defined LWIP_IPV6_DUP_DETECT_ATTEMPTS || defined __DOXYGEN__ +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_icmp6 ICMP6 + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#if !defined LWIP_ICMP6 || defined __DOXYGEN__ +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__ +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#if !defined LWIP_ICMP6_HL || defined __DOXYGEN__ +#define LWIP_ICMP6_HL 255 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_mld6 Multicast listener discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + * If LWIP_IPV6 is enabled but this setting is disabled, the MAC layer must + * indiscriminately pass all inbound IPv6 multicast traffic to lwIP. + */ +#if !defined LWIP_IPV6_MLD || defined __DOXYGEN__ +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast groups that can be joined. + * There must be enough groups so that each netif can join the solicited-node + * multicast group for each of its local addresses, plus one for MDNS if + * applicable, plus any number of groups to be joined on UDP sockets. + */ +#if !defined MEMP_NUM_MLD6_GROUP || defined __DOXYGEN__ +#define MEMP_NUM_MLD6_GROUP 4 +#endif +/** + * @} + */ + +/** + * @defgroup lwip_opts_nd6 Neighbor discovery + * @ingroup lwip_opts_ipv6 + * @{ + */ +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#if !defined LWIP_ND6_QUEUEING || defined __DOXYGEN__ +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#if !defined MEMP_NUM_ND6_QUEUE || defined __DOXYGEN__ +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#if !defined LWIP_ND6_NUM_NEIGHBORS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_NEIGHBORS 32 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#if !defined LWIP_ND6_NUM_DESTINATIONS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_DESTINATIONS 32 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#if !defined LWIP_ND6_NUM_PREFIXES || defined __DOXYGEN__ +#define LWIP_ND6_NUM_PREFIXES 16 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#if !defined LWIP_ND6_NUM_ROUTERS || defined __DOXYGEN__ +#define LWIP_ND6_NUM_ROUTERS 8 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#if !defined LWIP_ND6_MAX_MULTICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#if !defined LWIP_ND6_MAX_UNICAST_SOLICIT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#if !defined LWIP_ND6_MAX_ANYCAST_DELAY_TIME || defined __DOXYGEN__ +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#if !defined LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT || defined __DOXYGEN__ +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#if !defined LWIP_ND6_REACHABLE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#if !defined LWIP_ND6_RETRANS_TIMER || defined __DOXYGEN__ +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#if !defined LWIP_ND6_DELAY_FIRST_PROBE_TIME || defined __DOXYGEN__ +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#if !defined LWIP_ND6_ALLOW_RA_UPDATES || defined __DOXYGEN__ +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#if !defined LWIP_ND6_TCP_REACHABILITY_HINTS || defined __DOXYGEN__ +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#if !defined LWIP_ND6_RDNSS_MAX_DNS_SERVERS || defined __DOXYGEN__ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS 0 +#endif +/** + * @} + */ + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#if !defined LWIP_IPV6_DHCP6 || defined __DOXYGEN__ +#define LWIP_IPV6_DHCP6 0 +#endif + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/** + * @defgroup lwip_opts_hooks Hooks + * @ingroup lwip_opts_infrastructure + * Hooks are undefined by default, define them to a function if you need them. + * @{ + */ + +/** + * LWIP_HOOK_FILENAME: Custom filename to #include in files that provide hooks. + * Declare your hook function prototypes in there, you may also #include all headers + * providing data types that are need in this file. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_FILENAME "path/to/my/lwip_hooks.h" +#endif + +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528 (see contrib/adons/tcp_isn), + * or any other desired algorithm as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE() +#endif + +/** + * LWIP_HOOK_IP4_ROUTE_SRC(dest, src): + * - source-based routing for IPv4 (see LWIP_HOOK_IP4_ROUTE(), src may be NULL) + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP4_ROUTE_SRC(dest, src) +#endif + +/** + * LWIP_HOOK_ETHARP_GET_GW(netif, dest): + * - called from etharp_output() (IPv4) + * - netif: the netif used for sending + * - dest: the destination IPv4 address + * Returns the IPv4 address of the gateway to handle the specified destination + * IPv4 address. If NULL is returned, the netif's default gateway is used. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv4 routing together with + * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ETHARP_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_IP6_INPUT(pbuf, input_netif): + * - called from ip6_input() (IPv6) + * - pbuf: received struct pbuf passed to ip6_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_INPUT(pbuf, input_netif) +#endif + +/** + * LWIP_HOOK_IP6_ROUTE(src, dest): + * - called from ip6_route() (IPv6) + * - src: sourc IPv6 address + * - dest: destination IPv6 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip6_route() continues as normal. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_IP6_ROUTE(src, dest) +#endif + +/** + * LWIP_HOOK_ND6_GET_GW(netif, dest): + * - called from nd6_get_next_hop_entry() (IPv6) + * - netif: the netif used for sending + * - dest: the destination IPv6 address + * Returns the IPv6 address of the next hop to handle the specified destination + * IPv6 address. If NULL is returned, a NDP-discovered router is used instead. + * The returned address MUST be directly reachable on the specified netif! + * This function is meant to implement advanced IPv6 routing together with + * LWIP_HOOK_IP6_ROUTE(). The actual routing/gateway table implementation is + * not part of lwIP but can e.g. be hidden in the netif's state argument. +*/ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_ND6_GET_GW(netif, dest) +#endif + +/** + * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): + * - called from ethernet_input() if VLAN support is enabled + * - netif: struct netif on which the packet has been received + * - eth_hdr: struct eth_hdr of the packet + * - vlan_hdr: struct eth_vlan_hdr of the packet + * Return values: + * - 0: Packet must be dropped. + * - != 0: Packet must be accepted. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr) +#endif + +/** + * LWIP_HOOK_VLAN_SET: + * Hook can be used to set prio_vid field of vlan_hdr. If you need to store data + * on per-netif basis to implement this callback, see @ref netif_cd. + * Called from ethernet_output() if VLAN support (@ref ETHARP_SUPPORT_VLAN) is enabled.\n + * Signature: s32_t my_hook_vlan_set(struct netif* netif, struct pbuf* pbuf, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type);\n + * Arguments: + * - netif: struct netif that the packet will be sent through + * - p: struct pbuf packet to be sent + * - src: source eth address + * - dst: destination eth address + * - eth_type: ethernet type to packet to be sent\n + * + * + * Return values: + * - <0: Packet shall not contain VLAN header. + * - 0 <= return value <= 0xFFFF: Packet shall contain VLAN header. Return value is prio_vid in host byte order. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type) +#endif + +/** + * LWIP_HOOK_MEMP_AVAILABLE(memp_t_type): + * - called from memp_free() when a memp pool was empty and an item is now available + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_MEMP_AVAILABLE(memp_t_type) +#endif + +/** + * LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif): + * Called from ethernet_input() when an unknown eth type is encountered. + * Return ERR_OK if packet is accepted, any error code otherwise. + * Payload points to ethernet header! + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(pbuf, netif) +#endif +/** + * @} + */ + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * @defgroup lwip_opts_debugmsg Debug messages + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + * @see debugging_levels + */ +#if !defined LWIP_DBG_MIN_LEVEL || defined __DOXYGEN__ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + * @see debugging_levels + */ +#if !defined LWIP_DBG_TYPES_ON || defined __DOXYGEN__ +#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#if !defined ETHARP_DEBUG || defined __DOXYGEN__ +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#if !defined NETIF_DEBUG || defined __DOXYGEN__ +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#if !defined PBUF_DEBUG || defined __DOXYGEN__ +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#if !defined API_LIB_DEBUG || defined __DOXYGEN__ +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#if !defined API_MSG_DEBUG || defined __DOXYGEN__ +#define API_MSG_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#if !defined SOCKETS_DEBUG || defined __DOXYGEN__ +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#if !defined ICMP_DEBUG || defined __DOXYGEN__ +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#if !defined IGMP_DEBUG || defined __DOXYGEN__ +#define IGMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#if !defined INET_DEBUG || defined __DOXYGEN__ +#define INET_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#if !defined IP_DEBUG || defined __DOXYGEN__ +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#if !defined IP_REASS_DEBUG || defined __DOXYGEN__ +#define IP_REASS_DEBUG LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#if !defined RAW_DEBUG || defined __DOXYGEN__ +#define RAW_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#if !defined MEM_DEBUG || defined __DOXYGEN__ +#define MEM_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#if !defined MEMP_DEBUG || defined __DOXYGEN__ +#define MEMP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#if !defined SYS_DEBUG || defined __DOXYGEN__ +#define SYS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#if !defined TIMERS_DEBUG || defined __DOXYGEN__ +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#if !defined TCP_DEBUG || defined __DOXYGEN__ +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#if !defined TCP_INPUT_DEBUG || defined __DOXYGEN__ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#if !defined TCP_FR_DEBUG || defined __DOXYGEN__ +#define TCP_FR_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#if !defined TCP_RTO_DEBUG || defined __DOXYGEN__ +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#if !defined TCP_CWND_DEBUG || defined __DOXYGEN__ +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#if !defined TCP_WND_DEBUG || defined __DOXYGEN__ +#define TCP_WND_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#if !defined TCP_OUTPUT_DEBUG || defined __DOXYGEN__ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#if !defined TCP_RST_DEBUG || defined __DOXYGEN__ +#define TCP_RST_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#if !defined TCP_QLEN_DEBUG || defined __DOXYGEN__ +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#if !defined UDP_DEBUG || defined __DOXYGEN__ +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#if !defined TCPIP_DEBUG || defined __DOXYGEN__ +#define TCPIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#if !defined SLIP_DEBUG || defined __DOXYGEN__ +#define SLIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#if !defined DHCP_DEBUG || defined __DOXYGEN__ +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#if !defined AUTOIP_DEBUG || defined __DOXYGEN__ +#define AUTOIP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#if !defined DNS_DEBUG || defined __DOXYGEN__ +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#if !defined IP6_DEBUG || defined __DOXYGEN__ +#define IP6_DEBUG LWIP_DBG_OFF +#endif +/** + * @} + */ + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ +/** + * @defgroup lwip_opts_perf Performance + * @ingroup lwip_opts_debug + * @{ + */ +/** + * LWIP_PERF: Enable performance testing for lwIP + * (if enabled, arch/perf.h is included) + */ +#if !defined LWIP_PERF || defined __DOXYGEN__ +#define LWIP_PERF 0 +#endif +/** + * @} + */ + +#endif /* LWIP_HDR_OPT_H */ diff --git a/src/ServiceControls.cpp b/src/ServiceControls.cpp index e7d34aa..0467187 100644 --- a/src/ServiceControls.cpp +++ b/src/ServiceControls.cpp @@ -30,16 +30,11 @@ * ZeroTier service controls */ - +#include #include "OneService.hpp" #include "Node.hpp" - -namespace ZeroTier -{ - std::vector vtaps; - Mutex _vtaps_lock; -} +#include "ZeroTierOne.h" #include "Constants.hpp" #include "VirtualTapManager.hpp" @@ -47,27 +42,64 @@ namespace ZeroTier #include "OSUtils.hpp" #include "ServiceControls.hpp" -//#define SDK_JNI 1 -#ifdef SDK_JNI -#include -#endif - -ZeroTier::Mutex _service_lock; -ZeroTier::Mutex _startup_lock; - -static ZeroTier::OneService *zt1Service; -std::string homeDir; -int servicePort = ZTS_DEFAULT_PORT; -bool _freeHasBeenCalled = false; -bool _serviceIsShuttingDown = false; -bool _startupError = false; +#include "lwip/stats.h" #if defined(_WIN32) WSADATA wsaData; #include #endif +#ifdef SDK_JNI +#include +#endif + +namespace ZeroTier { + +/* + * A lock used to protect any call which relies on the presence of a valid pointer + * to the ZeroTier service. + */ +Mutex _service_lock; + +/* + * A lock which protects flags and state variables used during the startup and + * shutdown phase. + */ +Mutex _startup_lock; + +/* + * A lock used to protect callback method pointers. With a coarser-grained lock it + * would be possible for one thread to alter the callback method pointer causing + * undefined behaviour. + */ +Mutex _callback_lock; + +std::string homeDir; +int servicePort = ZTS_DEFAULT_PORT; +bool _freeHasBeenCalled = false; +bool _serviceIsShuttingDown = false; +bool _startupError = false; +bool _nodeIsOnlineToggle = false; + pthread_t service_thread; +pthread_t callback_thread; + +// Collection of virtual tap interfaces +std::map vtapMap; +Mutex _vtaps_lock; + +// Global reference to ZeroTier service +OneService *zt1Service; + +// User-provided callback for ZeroTier events +void (*_userCallbackFunc)(uint64_t, int); +#ifdef SDK_JNI +// Global references to JNI objects and VM kept for future callbacks +static JavaVM *jvm = NULL; +jobject objRef = NULL; +jmethodID _userCallbackMethodRef = NULL; +#endif +} using namespace ZeroTier; @@ -75,7 +107,69 @@ using namespace ZeroTier; // Internal ZeroTier Service Controls (user application shall not use these)// ////////////////////////////////////////////////////////////////////////////// -void api_sleep(int interval_ms) +std::queue*> _callbackMsgQueue; + +void _push_callback_event(uint64_t nwid, int eventCode) +{ + _callback_lock.lock(); + if (_callbackMsgQueue.size() >= 128) { + DEBUG_ERROR("too many callback messages in queue"); + _callback_lock.unlock(); + return; + } + _callbackMsgQueue.push(new std::pair(nwid,eventCode)); + _callback_lock.unlock(); +} + +void _process_callback_event_helper(uint64_t nwid, int eventCode) +{ +#ifdef SDK_JNI + if(_userCallbackMethodRef) { + JNIEnv *env; + jint rs = jvm->AttachCurrentThread(&env, NULL); + assert (rs == JNI_OK); + env->CallVoidMethod(objRef, _userCallbackMethodRef, nwid, eventCode); + } +#else + if (_userCallbackFunc) { + _userCallbackFunc((uint64_t)0, ZTS_EVENT_NODE_OFFLINE); + } +#endif +} + +void _process_callback_event(uint64_t nwid, int eventCode) +{ + _callback_lock.lock(); + _process_callback_event_helper(nwid, eventCode); + _callback_lock.unlock(); +} + +bool _is_callback_registered() +{ + _callback_lock.lock(); + bool retval = false; +#ifdef SDK_JNI + retval = (jvm && objRef && _userCallbackMethodRef); +#else + retval = _userCallbackFunc; +#endif + _callback_lock.unlock(); + return retval; +} + +void _clear_registered_callback() +{ + _callback_lock.lock(); +#ifdef SDK_JNI + objRef = NULL; + _userCallbackMethodRef = NULL; +#else + _userCallbackFunc = NULL; +#endif + _callback_lock.unlock(); +} + +void _api_sleep(int interval_ms) { #if defined(_WIN32) Sleep(interval_ms); @@ -107,6 +201,90 @@ void _hibernate_if_needed() #ifdef SDK_JNI #endif +/* + * Monitors the conditions required for triggering callbacks into user code. This was made + * into its own thread to prevent user application abuse of callbacks from affecting + * the timing of more sensitive aspects of the library such as polling and RX/TX of packets + */ +#if defined(_WIN32) +DWORD WINAPI _zts_monitor_callback_conditions(LPVOID thread_id) +#else +void *_zts_monitor_callback_conditions(void *thread_id) +#endif +{ +#if defined(__APPLE__) + pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME); +#endif + while (!_serviceIsShuttingDown) + { + if (!_zts_node_online()) { + if (_nodeIsOnlineToggle) { + _nodeIsOnlineToggle = false; + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_OFFLINE); + } + } if (_zts_node_online()) { // Only process pending network callbacks if the node is online + if (!_nodeIsOnlineToggle) { + _nodeIsOnlineToggle = true; + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_ONLINE); + } + + // First, handle queued messages from other threads + _callback_lock.lock(); + while (_callbackMsgQueue.size()) { + std::pair *msg = _callbackMsgQueue.front(); + _callbackMsgQueue.pop(); + _process_callback_event_helper(msg->first, msg->second); + delete msg; + } + _callback_lock.unlock(); + + // Second, inspect network states for changes we should report + _vtaps_lock.lock(); + ZT_VirtualNetworkList *nl = zt1Service->getNode()->networks(); + for(unsigned long i=0;inetworkCount;++i) { + OneService::NetworkSettings localSettings; + zt1Service->getNetworkSettings(nl->networks[i].nwid,localSettings); + if (vtapMap[nl->networks[i].nwid]->_lastReportedStatus != nl->networks[i].status) { + switch (nl->networks[i].status) { + case ZT_NETWORK_STATUS_NOT_FOUND: + _process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_NOT_FOUND); + break; + case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: + _process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_CLIENT_TOO_OLD); + break; + case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: + _process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_REQUESTING_CONFIG); + break; + case ZT_NETWORK_STATUS_OK: + _process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_OK); + break; + case ZT_NETWORK_STATUS_ACCESS_DENIED: + _process_callback_event(nl->networks[i].nwid, ZTS_EVENT_NETWORK_ACCESS_DENIED); + break; + default: + break; + } + vtapMap[nl->networks[i].nwid]->_lastReportedStatus = nl->networks[i].status; + } + } + zt1Service->getNode()->freeQueryResult((void *)nl); + // Finally, check for a more useful definition of "readiness" + std::map::iterator it; + for (it = vtapMap.begin(); it != vtapMap.end(); it++) { + VirtualTap *tap = it->second; + if (tap->_lastConfigUpdateTime > 0 && !tap->_lastReadyReportTime && tap->_ips.size() > 0) { + tap->_lastReadyReportTime = tap->_lastConfigUpdateTime; + _process_callback_event(tap->_nwid, ZTS_EVENT_NETWORK_READY); + } + } + _vtaps_lock.unlock(); + } + // Doesn't need to happen as often as other API operations + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + } + DEBUG_ERROR("exiting from monitor loop"); +} + // Starts a ZeroTier service in the background #if defined(_WIN32) DWORD WINAPI _zts_start_service(LPVOID thread_id) @@ -114,8 +292,10 @@ DWORD WINAPI _zts_start_service(LPVOID thread_id) void *_zts_start_service(void *thread_id) #endif { +#if defined(__APPLE__) + pthread_setname_np(ZTS_SERVICE_THREAD_NAME); +#endif void *retval; - //DEBUG_INFO("identities are stored in path (%s)", homeDir.c_str()); zt1Service = (OneService *)0; if (!homeDir.length()) { @@ -155,10 +335,12 @@ void *_zts_start_service(void *thread_id) switch(zt1Service->run()) { case OneService::ONE_STILL_RUNNING: case OneService::ONE_NORMAL_TERMINATION: + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_NORMAL_TERMINATION); break; case OneService::ONE_UNRECOVERABLE_ERROR: DEBUG_ERROR("fatal error: %s", zt1Service->fatalErrorMessage().c_str()); _startupError = true; + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_UNRECOVERABLE_ERROR); break; case OneService::ONE_IDENTITY_COLLISION: { _startupError = true; @@ -171,6 +353,7 @@ void *_zts_start_service(void *thread_id) OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); } + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_IDENTITY_COLLISION); } continue; // restart! } break; // terminate loop -- normally we don't keep restarting @@ -183,6 +366,7 @@ void *_zts_start_service(void *thread_id) zt1Service = (OneService *)0; _service_lock.unlock(); _serviceIsShuttingDown = false; + _process_callback_event((uint64_t)0, ZTS_EVENT_NODE_DOWN); } catch ( ... ) { DEBUG_ERROR("unexpected exception starting ZeroTier instance"); } @@ -197,6 +381,18 @@ extern "C" { // ZeroTier Service Controls // ////////////////////////////////////////////////////////////////////////////// +#ifdef SDK_JNI +/* + * Called from Java, saves a reference to the VM so it can be used later to call + * a user-specified callback method from C. + */ +JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_init(JNIEnv *env, jobject thisObj) +{ + jint rs = env->GetJavaVM(&jvm); + assert (rs == JNI_OK); +} +#endif + zts_err_t zts_set_service_port(int portno) { zts_err_t retval = ZTS_ERR_OK; @@ -234,107 +430,6 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1service_1port( return zts_get_service_port(); } #endif -/* -int zts_get_address(const uint64_t nwid, struct sockaddr_storage *addr, - const int address_family) -{ - int err = -1; - if (!zt1Service) { - return ZTS_ERR_SERVICE; - } - VirtualTap *tap = getTapByNWID(nwid); - if (!tap) { - return -1; - } - _vtaps_lock.lock(); - socklen_t addrlen = address_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - for (size_t i=0; i_ips.size(); i++) { - if (address_family == AF_INET) { - if (tap->_ips[i].isV4()) { - memcpy(addr, &(tap->_ips[i]), addrlen); - addr->ss_family = AF_INET; - err = 0; - break; - } - } - if (address_family == AF_INET6) { - if (tap->_ips[i].isV6()) { - memcpy(addr, &(tap->_ips[i]), addrlen); - addr->ss_family = AF_INET6; - err = 0; - break; - } - } - } - _vtaps_lock.unlock(); - return err; // nothing found -} -#ifdef SDK_JNI -JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_get_1address( - JNIEnv *env, jobject thisObj, jlong nwid, jint address_family, jobject addr) -{ - struct sockaddr_storage ss; - int err = zts_get_address((uint64_t)nwid, &ss, address_family); - ss2zta(env, &ss, addr); - return err; -} -#endif - -int zts_has_address(const uint64_t nwid) -{ - struct sockaddr_storage ss; - memset(&ss, 0, sizeof(ss)); - zts_get_address(nwid, &ss, AF_INET); - if (ss.ss_family == AF_INET) { - return true; - } - zts_get_address(nwid, &ss, AF_INET6); - if (ss.ss_family == AF_INET6) { - return true; - } - return false; -} -#ifdef SDK_JNI -JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_has_1address( - JNIEnv *env, jobject thisObj, jlong nwid) -{ - return zts_has_address(nwid); -} -#endif -*/ - -/* -void zts_get_6plane_addr(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId) -{ - ZeroTier::InetAddress _6planeAddr = ZeroTier::InetAddress::makeIpv66plane(nwid,nodeId); - memcpy(addr, _6planeAddr.rawIpData(), sizeof(struct sockaddr_storage)); -} -#ifdef SDK_JNI -JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_get_16plane_1addr( - JNIEnv *env, jobject thisObj, jlong nwid, jlong nodeId, jobject addr) -{ - struct sockaddr_storage ss; - zts_get_6plane_addr(&ss, nwid, nodeId); - ss2zta(env, &ss, addr); -} -#endif - -void zts_get_rfc4193_addr(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId) -{ - ZeroTier::InetAddress _rfc4193Addr = ZeroTier::InetAddress::makeIpv6rfc4193(nwid,nodeId); - memcpy(addr, _rfc4193Addr.rawIpData(), sizeof(struct sockaddr_storage)); -} -#ifdef SDK_JNI -JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_get_1rfc4193_1addr( - JNIEnv *env, jobject thisObj, jlong nwid, jlong nodeId, jobject addr) -{ - struct sockaddr_storage ss; - zts_get_rfc4193_addr(&ss, nwid, nodeId); - ss2zta(env, &ss, addr); -} -#endif -*/ - zts_err_t zts_join(const uint64_t nwid, int blocking) { @@ -351,7 +446,7 @@ zts_err_t zts_join(const uint64_t nwid, int blocking) retval = ZTS_ERR_SERVICE; break; } - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); } } } else { @@ -366,7 +461,6 @@ zts_err_t zts_join(const uint64_t nwid, int blocking) if (zt1Service) { zt1Service->getNode()->join(nwid, NULL, NULL); } - VirtualTapManager::update_service_references((void*)zt1Service); } _service_lock.unlock(); _hibernate_if_needed(); @@ -394,7 +488,7 @@ zts_err_t zts_leave(const uint64_t nwid, int blocking) retval = ZTS_ERR_SERVICE; break; } - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); } } } else { @@ -506,7 +600,7 @@ JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_ready( } #endif -zts_err_t zts_start(const char *path, int blocking = false) +zts_err_t zts_start_with_callback(const char *path, void (*callback)(uint64_t, int), int blocking) { _startup_lock.lock(); zts_err_t retval = ZTS_ERR_OK; @@ -521,15 +615,31 @@ zts_err_t zts_start(const char *path, int blocking = false) if (!path) { retval = ZTS_ERR_INVALID_ARG; } + + _userCallbackFunc = callback; + if (retval == ZTS_ERR_OK) { homeDir = path; #if defined(_WIN32) // initialize WinSock. Used in Phy for loopback pipe WSAStartup(MAKEWORD(2, 2), &wsaData); - HANDLE thr = CreateThread(NULL, 0, _zts_start_service, NULL, 0, NULL); + HANDLE serviceThread = CreateThread(NULL, 0, _zts_start_service, NULL, 0, NULL); + if (_is_callback_registered()) { + HANDLE callbackThread = CreateThread(NULL, 0, _zts_monitor_callback_conditions, NULL, 0, NULL); + } + // TODO: Add thread names on Windows (optional) #else _startupError = false; retval = pthread_create(&service_thread, NULL, _zts_start_service, NULL); +#if defined(__linux__) + pthread_setname_np(service_thread, ZTS_SERVICE_THREAD_NAME); +#endif + if (_is_callback_registered()) { + retval = pthread_create(&callback_thread, NULL, _zts_monitor_callback_conditions, NULL); +#if defined(__linux__) + pthread_setname_np(callback_thread, ZTS_EVENT_CALLBACK_THREAD_NAME); +#endif + } // Wait for confirmation that the ZT service has been initialized, // this wait condition is so brief and so rarely used that it should be // acceptable even in a non-blocking context. @@ -539,7 +649,7 @@ zts_err_t zts_start(const char *path, int blocking = false) retval = ZTS_ERR_SERVICE; break; } - api_sleep(10); + _api_sleep(10); } #endif if (blocking && retval == ZTS_ERR_OK) { @@ -551,7 +661,7 @@ zts_err_t zts_start(const char *path, int blocking = false) retval = ZTS_ERR_SERVICE; break; } - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); } if (retval == ZTS_ERR_OK) { // waiting for node address assignment @@ -560,7 +670,7 @@ zts_err_t zts_start(const char *path, int blocking = false) retval = ZTS_ERR_SERVICE; break; } - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); } } if (retval == ZTS_ERR_OK) { @@ -575,7 +685,7 @@ zts_err_t zts_start(const char *path, int blocking = false) // Node is fully online break; } - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); _service_lock.unlock(); } _service_lock.unlock(); @@ -587,6 +697,35 @@ zts_err_t zts_start(const char *path, int blocking = false) _hibernate_if_needed(); return retval; } + +#ifdef SDK_JNI +JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_start_1with_1callback( + JNIEnv *env, jobject thisObj, jstring path, jobject userCallbackClass) +{ + jclass eventListenerClass = env->GetObjectClass(userCallbackClass); + if(eventListenerClass == NULL) { + DEBUG_ERROR("Couldn't find class for ZeroTierEventListener instance"); + return; + } + jmethodID eventListenerCallbackMethod = env->GetMethodID(eventListenerClass, "onZeroTierEvent", "(JI)V"); + if(eventListenerCallbackMethod == NULL) { + DEBUG_ERROR("Couldn't find onZeroTierEvent method"); + return; + } + objRef = env->NewGlobalRef(userCallbackClass); // Reference used for later calls + _userCallbackMethodRef = eventListenerCallbackMethod; + if (path) { + const char* utf_string = env->GetStringUTFChars(path, NULL); + zts_start_with_callback(utf_string, NULL, false); + env->ReleaseStringUTFChars(path, utf_string); + } +} +#endif + +zts_err_t zts_start(const char *path, int blocking = false) +{ + return zts_start_with_callback(path, NULL, blocking); +} #ifdef SDK_JNI JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_start( JNIEnv *env, jobject thisObj, jstring path, jboolean blocking) @@ -611,7 +750,7 @@ zts_err_t zts_startjoin(const char *path, const uint64_t nwid) break; } catch( ... ) { - api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); + _api_sleep(ZTS_WRAPPER_CHECK_INTERVAL); retval = ZTS_ERR_SERVICE; } } @@ -653,6 +792,7 @@ zts_err_t zts_stop(int blocking) pthread_join(service_thread, NULL); } _hibernate_if_needed(); + _clear_registered_callback(); return retval; } #ifdef SDK_JNI @@ -780,7 +920,7 @@ zts_err_t zts_get_network_details(uint64_t nwid, struct zts_network_details *nd) retval = ZTS_ERR_SERVICE; } if (retval == ZTS_ERR_OK) { - VirtualTapManager::get_network_details(nwid, nd); + VirtualTapManager::get_network_details(zt1Service, nwid, nd); } return retval; } @@ -797,7 +937,7 @@ zts_err_t zts_get_all_network_details(struct zts_network_details *nds, int *num) retval = ZTS_ERR_SERVICE; } if (retval == ZTS_ERR_OK) { - VirtualTapManager::get_all_network_details(nds, num); + VirtualTapManager::get_all_network_details(zt1Service, nds, num); } return retval; } diff --git a/src/VirtualTap.cpp b/src/VirtualTap.cpp index ac1adbc..a691d3e 100644 --- a/src/VirtualTap.cpp +++ b/src/VirtualTap.cpp @@ -35,6 +35,9 @@ #include "Node.hpp" #include "OSUtils.hpp" +#include "Constants.hpp" // libzt +extern void _push_callback_event(uint64_t nwid, int eventCode); + #include "Mutex.hpp" #include "VirtualTapManager.hpp" #include "lwIP.h" @@ -45,6 +48,9 @@ namespace ZeroTier { +extern OneService *zt1Service; +extern void (*_userCallbackFunc)(uint64_t, int); + VirtualTap::VirtualTap( const char *homePath, const MAC &mac, @@ -79,6 +85,7 @@ VirtualTap::VirtualTap( VirtualTap::~VirtualTap() { + _push_callback_event(_nwid, ZTS_EVENT_NETWORK_DOWN); lwip_driver_set_tap_interfaces_down(this); _run = false; ::write(_shutdownSignalPipe[1],"\0",1); @@ -88,6 +95,11 @@ VirtualTap::~VirtualTap() ::close(_shutdownSignalPipe[1]); } +void VirtualTap::lastConfigUpdate(uint64_t lastConfigUpdateTime) +{ + _lastConfigUpdateTime = lastConfigUpdateTime; +} + void VirtualTap::setEnabled(bool en) { _enabled = en; @@ -106,7 +118,6 @@ void VirtualTap::registerIpWithStack(const InetAddress &ip) bool VirtualTap::addIp(const InetAddress &ip) { char ipbuf[INET6_ADDRSTRLEN]; - // DEBUG_INFO("addr=%s, nwid=%llx", ip.toString(ipbuf), (unsigned long long)_nwid); Mutex::Lock _l(_ips_m); registerIpWithStack(ip); if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) { @@ -152,10 +163,10 @@ std::string VirtualTap::deviceName() const std::string VirtualTap::nodeId() const { - if (zt1ServiceRef) { + if (zt1Service) { char id[ZTS_ID_LEN]; memset(id, 0, sizeof(id)); - sprintf(id, "%llx", (unsigned long long)((OneService *)zt1ServiceRef)->getNode()->address()); + sprintf(id, "%llx", (unsigned long long)((OneService *)zt1Service)->getNode()->address()); return std::string(id); } else { @@ -207,6 +218,12 @@ void VirtualTap::threadMain() FD_ZERO(&readfds); FD_ZERO(&nullfds); int nfds = (int)std::max(_shutdownSignalPipe[0],0) + 1; +#if defined(__linux__) + pthread_setname_np(pthread_self(), vtap_full_name); +#endif +#if defined(__APPLE__) + pthread_setname_np(vtap_full_name); +#endif while (true) { FD_SET(_shutdownSignalPipe[0],&readfds); select(nfds,&readfds,&nullfds,&nullfds,&tv); @@ -231,7 +248,7 @@ void VirtualTap::threadMain() void VirtualTap::Housekeeping() { Mutex::Lock _l(_tcpconns_m); - OneService *service = ((OneService *)zt1ServiceRef); + OneService *service = ((OneService *)zt1Service); if (!service) { return; } diff --git a/src/VirtualTapManager.cpp b/src/VirtualTapManager.cpp new file mode 100644 index 0000000..fedb38c --- /dev/null +++ b/src/VirtualTapManager.cpp @@ -0,0 +1,116 @@ +/* + * ZeroTier SDK - Network Virtualization Everywhere + * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +/** + * @file + * + * Management of virtual tap interfaces + */ + +#include "VirtualTap.hpp" +#include "VirtualTapManager.hpp" +#include "ServiceControls.hpp" +#include "OneService.hpp" + +namespace ZeroTier { + +extern std::map vtapMap; +extern Mutex _vtaps_lock; +extern void (*_userCallbackFunc)(uint64_t, int); + +class VirtualTap; + +void VirtualTapManager::add_tap(VirtualTap *tap) { + _vtaps_lock.lock(); + vtapMap[tap->_nwid] = tap; + _vtaps_lock.unlock(); +} + +VirtualTap *VirtualTapManager::getTapByNWID(uint64_t nwid) { + _vtaps_lock.lock(); + VirtualTap *s, *tap = vtapMap[nwid]; + _vtaps_lock.unlock(); + return tap; +} + +size_t VirtualTapManager::get_vtaps_size() { + size_t sz; + _vtaps_lock.lock(); + sz = vtapMap.size(); + _vtaps_lock.unlock(); + return sz; +} + +void VirtualTapManager::remove_by_nwid(uint64_t nwid) { + _vtaps_lock.lock(); + vtapMap.erase(nwid); + _vtaps_lock.unlock(); +} + +void VirtualTapManager::clear() { + _vtaps_lock.lock(); + vtapMap.clear(); + _vtaps_lock.unlock(); +} + +void VirtualTapManager::get_network_details_helper(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd) +{ + socklen_t addrlen; + VirtualTap *tap = vtapMap[nwid]; + nd->nwid = tap->_nwid; + nd->mtu = tap->_mtu; + // assigned addresses + nd->num_addresses = tap->_ips.size() < ZTS_MAX_ASSIGNED_ADDRESSES ? tap->_ips.size() : ZTS_MAX_ASSIGNED_ADDRESSES; + for (int j=0; jnum_addresses; j++) { + addrlen = tap->_ips[j].isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + memcpy(&(nd->addr[j]), &(tap->_ips[j]), addrlen); + } + // routes + nd->num_routes = ZTS_MAX_NETWORK_ROUTES; + OneService *zt1Service = (OneService*)zt1ServiceRef; + zt1Service->getRoutes(nwid, (ZT_VirtualNetworkRoute*)&(nd->routes)[0], &(nd->num_routes)); +} + +void VirtualTapManager::get_network_details(void *zt1ServiceRef, uint64_t nwid, struct zts_network_details *nd) { + _vtaps_lock.lock(); + get_network_details_helper(zt1ServiceRef, nwid, nd); + _vtaps_lock.unlock(); +} + +void VirtualTapManager::get_all_network_details(void *zt1ServiceRef, struct zts_network_details *nds, int *num) { + + _vtaps_lock.lock(); + *num = vtapMap.size(); + int idx = 0; + std::map::iterator it; + for (it = vtapMap.begin(); it != vtapMap.end(); it++) { + get_network_details(zt1ServiceRef, it->first, &nds[idx]); + idx++; + } + _vtaps_lock.unlock(); +} + +} // namespace ZeroTier \ No newline at end of file diff --git a/src/libzt.cpp b/src/libzt.cpp index 01cf70b..f0245d9 100644 --- a/src/libzt.cpp +++ b/src/libzt.cpp @@ -48,6 +48,7 @@ #ifdef __cplusplus extern "C" { + #endif void ss2zta(JNIEnv *env, struct sockaddr_storage *ss, jobject addr); void zta2ss(JNIEnv *env, struct sockaddr_storage *ss, jobject addr); @@ -66,6 +67,9 @@ extern "C" { extern "C" { #endif +// Custom errno to prevent conflicts with platform's own errno +int zts_errno; + // lwIP prototypes copied from lwip/src/include/sockets.h // Don't call these directly, call zts_* functions instead int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); @@ -116,7 +120,8 @@ int zts_socket(int socket_family, int socket_type, int protocol) JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_socket( JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol) { - return zts_socket(family, type, protocol); + zts_err_t retval = zts_socket(family, type, protocol); + return retval > -1 ? retval : -(zts_errno); // Encode lwip errno in return value for JNI functions only } #endif @@ -137,7 +142,8 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_connect( struct sockaddr_storage ss; zta2ss(env, &ss, addr); socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - return zts_connect(fd, (struct sockaddr *)&ss, addrlen); + zts_err_t retval = zts_connect(fd, (struct sockaddr *)&ss, addrlen); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -158,7 +164,8 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_bind( struct sockaddr_storage ss; zta2ss(env, &ss, addr); socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - return zts_bind(fd, (struct sockaddr*)&ss, addrlen); + zts_err_t retval = zts_bind(fd, (struct sockaddr*)&ss, addrlen); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -170,7 +177,8 @@ int zts_listen(int fd, int backlog) JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_listen( JNIEnv *env, jobject thisObj, jint fd, int backlog) { - return zts_listen(fd, backlog); + zts_err_t retval = zts_listen(fd, backlog); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -184,9 +192,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept( { struct sockaddr_storage ss; socklen_t addrlen = sizeof(struct sockaddr_storage); - int err = zts_accept(fd, (struct sockaddr *)&ss, &addrlen); + zts_err_t retval =zts_accept(fd, (struct sockaddr *)&ss, &addrlen); ss2zta(env, &ss, addr); - return err; + return retval > -1 ? retval : -(zts_errno); } #endif @@ -203,9 +211,9 @@ int zts_accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) { struct sockaddr_storage ss; socklen_t addrlen = sizeof(struct sockaddr_storage); - int err = zts_accept4(fd, (struct sockaddr *)&ss, &addrlen, flags); + zts_err_t retval = zts_accept4(fd, (struct sockaddr *)&ss, &addrlen, flags); ss2zta(env, &ss, addr); - return err; + return retval > -1 ? retval : -(zts_errno); } #endif #endif @@ -230,10 +238,11 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt( || optname == ZTS_SO_REUSEPORT || optname == ZTS_TCP_NODELAY) { - jfieldID fid = (*env).GetFieldID(c, "booleanValue", "B"); + jfieldID fid = (*env).GetFieldID(c, "booleanValue", "Z"); optval_int = (int)(*env).GetBooleanField(optval, fid); } - if (optname == ZTS_IP_TTL + if (optname == ZTS_IP_TTL + || optname == ZTS_SO_RCVTIMEO || optname == ZTS_IP_TOS || optname == ZTS_SO_LINGER || optname == ZTS_SO_RCVBUF @@ -242,8 +251,20 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt( jfieldID fid = (*env).GetFieldID(c, "integerValue", "I"); optval_int = (*env).GetIntField(optval, fid); } - int optlen = sizeof(optval_int); - return zts_setsockopt(fd, level, optname, &optval_int, optlen); + + zts_err_t retval = ZTS_ERR_OK; + + if (optname == ZTS_SO_RCVTIMEO) { + struct timeval tv; + // Convert milliseconds from setSoTimeout() call to seconds and microseconds + tv.tv_usec = optval_int * 1000; + tv.tv_sec = optval_int / 1000000; + retval = zts_setsockopt(fd, level, optname, &tv, sizeof(tv)); + } + else { + retval = zts_setsockopt(fd, level, optname, &optval_int, sizeof(optval_int)); + } + return retval > -1 ? retval : -(zts_errno); } #endif @@ -259,33 +280,46 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt( if (!c) { return ZTS_ERR_INVALID_OP; } - int optval_int; + int optval_int = 0; int optlen; // Intentionally not used - int err = ZTS_ERR_OK; - err = zts_getsockopt(fd, level, optname, &optval_int, &optlen); + + zts_err_t retval; + + if (optname == ZTS_SO_RCVTIMEO) { + struct timeval tv; + optlen = sizeof(tv); + retval = zts_getsockopt(fd, level, optname, &tv, &optlen); + // Convert seconds and microseconds back to milliseconds + optval_int = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } + else { + retval = zts_getsockopt(fd, level, optname, &optval_int, &optlen); + } + if (optname == ZTS_SO_BROADCAST || optname == ZTS_SO_KEEPALIVE || optname == ZTS_SO_REUSEADDR || optname == ZTS_SO_REUSEPORT || optname == ZTS_TCP_NODELAY) { - jfieldID fid = (*env).GetFieldID(c, "isBoolean", "B"); + jfieldID fid = (*env).GetFieldID(c, "isBoolean", "Z"); (*env).SetBooleanField(optval, fid, true); - fid = (*env).GetFieldID(c, "booleanValue", "B"); + fid = (*env).GetFieldID(c, "booleanValue", "Z"); (*env).SetBooleanField(optval, fid, (bool)optval_int); } - if (optname == ZTS_IP_TTL + if (optname == ZTS_IP_TTL + || optname == ZTS_SO_RCVTIMEO || optname == ZTS_IP_TOS || optname == ZTS_SO_LINGER || optname == ZTS_SO_RCVBUF || optname == ZTS_SO_SNDBUF) { - jfieldID fid = (*env).GetFieldID(c, "isInteger", "B"); + jfieldID fid = (*env).GetFieldID(c, "isInteger", "Z"); (*env).SetBooleanField(optval, fid, true); fid = (*env).GetFieldID(c, "integerValue", "I"); (*env).SetIntField(optval, fid, optval_int); } - return err; + return retval > -1 ? retval : -(zts_errno); } #endif @@ -305,9 +339,9 @@ JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_getsockname(JNIEnv * { struct sockaddr_storage ss; socklen_t addrlen = sizeof(struct sockaddr_storage); - int err = zts_getsockname(fd, (struct sockaddr *)&ss, &addrlen); - ss2zta(env, &ss, addr); - return err; + zts_err_t retval =zts_getsockname(fd, (struct sockaddr *)&ss, &addrlen); + ss2zta(env, &ss, addr); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -326,9 +360,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getpeername(JNIEnv *env, jint fd, jobject addr) { struct sockaddr_storage ss; - int err = zts_getpeername(fd, (struct sockaddr *)&ss, (socklen_t *)sizeof(struct sockaddr_storage)); - ss2zta(env, &ss, addr); - return err; + zts_err_t retval = zts_getpeername(fd, (struct sockaddr *)&ss, (socklen_t *)sizeof(struct sockaddr_storage)); + ss2zta(env, &ss, addr); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -394,34 +428,34 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_select(JNIEnv *env, jobj { struct timeval _timeout; _timeout.tv_sec = timeout_sec; - _timeout.tv_usec = timeout_usec; - fd_set _readfds, _writefds, _exceptfds; - fd_set *r = NULL; - fd_set *w = NULL; - fd_set *e = NULL; - if (readfds) { - r = &_readfds; - ztfdset2fdset(env, nfds, readfds, &_readfds); - } - if (writefds) { - w = &_writefds; - ztfdset2fdset(env, nfds, writefds, &_writefds); - } - if (exceptfds) { - e = &_exceptfds; - ztfdset2fdset(env, nfds, exceptfds, &_exceptfds); - } - int err = zts_select(nfds, r, w, e, &_timeout); + _timeout.tv_usec = timeout_usec; + fd_set _readfds, _writefds, _exceptfds; + fd_set *r = NULL; + fd_set *w = NULL; + fd_set *e = NULL; + if (readfds) { + r = &_readfds; + ztfdset2fdset(env, nfds, readfds, &_readfds); + } + if (writefds) { + w = &_writefds; + ztfdset2fdset(env, nfds, writefds, &_writefds); + } + if (exceptfds) { + e = &_exceptfds; + ztfdset2fdset(env, nfds, exceptfds, &_exceptfds); + } + zts_err_t retval = zts_select(nfds, r, w, e, &_timeout); if (readfds) { fdset2ztfdset(env, nfds, &_readfds, readfds); } if (writefds) { - fdset2ztfdset(env, nfds, &_writefds, writefds); - } - if (exceptfds) { - fdset2ztfdset(env, nfds, &_exceptfds, exceptfds); - } - return err; + fdset2ztfdset(env, nfds, &_writefds, writefds); + } + if (exceptfds) { + fdset2ztfdset(env, nfds, &_exceptfds, exceptfds); + } + return retval > -1 ? retval : -(zts_errno); } #endif @@ -445,7 +479,8 @@ int zts_fcntl(int fd, int cmd, int flags) JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_fcntl( JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags) { - return zts_fcntl(fd, cmd, flags); + zts_err_t retval = zts_fcntl(fd, cmd, flags); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -479,7 +514,7 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl( DEBUG_ERROR("FIONBIO"); retval = zts_ioctl(fd, request, &meaninglessVariable); } - return retval; + return retval > -1 ? retval : -(zts_errno); } #endif @@ -495,9 +530,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_send( JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, int flags) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int w = zts_send(fd, data, env->GetArrayLength(buf), flags); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return w; + zts_err_t retval = zts_send(fd, data, env->GetArrayLength(buf), flags); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -520,9 +555,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto( struct sockaddr_storage ss; zta2ss(env, &ss, addr); socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - int w = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, addrlen); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return w; + zts_err_t retval = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, addrlen); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -545,9 +580,9 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobjec jint fd, jbyteArray buf, jint flags) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int r = zts_recv(fd, data, env->GetArrayLength(buf), flags); + zts_err_t retval = zts_recv(fd, data, env->GetArrayLength(buf), flags); env->ReleasePrimitiveArrayCritical(buf, data, 0); - return r; + return retval > -1 ? retval : -(zts_errno); } #endif @@ -566,10 +601,10 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recvfrom( socklen_t addrlen = sizeof(struct sockaddr_storage); struct sockaddr_storage ss; void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int r = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, &addrlen); + zts_err_t retval = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, &addrlen); env->ReleasePrimitiveArrayCritical(buf, data, 0); - ss2zta(env, &ss, addr); - return r; + ss2zta(env, &ss, addr); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -600,25 +635,25 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read(JNIEnv *env, jobjec jint fd, jbyteArray buf) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int r = zts_read(fd, data, env->GetArrayLength(buf)); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return r; + zts_err_t retval = zts_read(fd, data, env->GetArrayLength(buf)); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1offset(JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint offset, jint len) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int r = zts_read_offset(fd, data, offset, len); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return r; + zts_err_t retval = zts_read_offset(fd, data, offset, len); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1length(JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint len) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int r = zts_read(fd, data, len); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return r; + zts_err_t retval = zts_read(fd, data, len); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } #endif @@ -634,22 +669,23 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write__IB(JNIEnv *env, j jint fd, jbyteArray buf) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int w = zts_write(fd, data, env->GetArrayLength(buf)); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return w; + zts_err_t retval = zts_write(fd, data, env->GetArrayLength(buf)); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1offset(JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint offset, jint len) { void *data = env->GetPrimitiveArrayCritical(&(buf[offset]), NULL); // PENDING: check? - int w = zts_write(fd, data, len); - env->ReleasePrimitiveArrayCritical(buf, data, 0); - return w; + zts_err_t retval = zts_write(fd, data, len); + env->ReleasePrimitiveArrayCritical(buf, data, 0); + return retval > -1 ? retval : -(zts_errno); } JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1byte(JNIEnv *env, jobject thisObj, jint fd, jbyte buf) { - return zts_write(fd, &buf, 1); + zts_err_t retval = zts_write(fd, &buf, 1); + return retval > -1 ? retval : -(zts_errno); } #endif diff --git a/src/lwIP.cpp b/src/lwIP.cpp index 004986e..a303fe4 100644 --- a/src/lwIP.cpp +++ b/src/lwIP.cpp @@ -31,6 +31,7 @@ */ #include +#include #include "MAC.hpp" @@ -46,7 +47,6 @@ #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/tcp.h" -#include "lwip/priv/tcp_priv.h" /* for tcp_debug_print_pcbs() */ #include "lwip/timeouts.h" #include "lwip/stats.h" #include "lwip/ethip6.h" @@ -65,9 +65,9 @@ void ms_sleep(unsigned long ms) } #endif +std::queue rx_queue; + ZeroTier::Mutex _rx_input_lock_m; -struct pbuf* lwip_frame_rxbuf[LWIP_MAX_GUARDED_RX_BUF_SZ]; -int lwip_frame_rxbuf_tot = 0; bool main_loop_exited = false; bool lwip_driver_initialized = false; @@ -103,14 +103,19 @@ void my_tcpip_callback(void *arg) if (main_loop_exited) { return; } - ZeroTier::Mutex::Lock _l(_rx_input_lock_m); + err_t err = ERR_OK; int loop_score = LWIP_FRAMES_HANDLED_PER_CORE_CALL; // max num of packets to read per polling call // TODO: Optimize (use Ringbuffer) - int pkt_num = 0; - int count_initial = lwip_frame_rxbuf_tot; - while (lwip_frame_rxbuf_tot > 0 && loop_score > 0) { - struct pbuf *p = lwip_frame_rxbuf[pkt_num]; - pkt_num++; + while (loop_score > 0) { + // TODO: Swap this block out for a thread-safe container + _rx_input_lock_m.lock(); + if (rx_queue.size() == 0) { + _rx_input_lock_m.unlock(); + return; + } + struct pbuf *p = rx_queue.front(); + rx_queue.pop(); + _rx_input_lock_m.unlock(); // Packet routing logic. Inputs packet into correct lwip netif interface depending on protocol type struct ip_hdr *iphdr; switch (((struct eth_hdr *)p->payload)->type) @@ -120,8 +125,8 @@ void my_tcpip_callback(void *arg) for (size_t i=0; ioutput_ip6 && lwip_netifs[i]->output_ip6 == ethip6_output) { - if (lwip_netifs[i]->input(p, lwip_netifs[i]) != ERR_OK) { - DEBUG_ERROR("packet input error (ipv6, p=%p, netif=%p)", p, &lwip_netifs[i]); + if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) { + DEBUG_ERROR("packet input error (ipv6, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err); break; } } @@ -134,8 +139,8 @@ void my_tcpip_callback(void *arg) lwip_netifs[i]->output == etharp_output) { if (lwip_netifs[i]->ip_addr.u_addr.ip4.addr == iphdr->dest.addr || ip4_addr_isbroadcast_u32(iphdr->dest.addr, lwip_netifs[i])) { - if (lwip_netifs[i]->input(p, lwip_netifs[i]) != ERR_OK) { - DEBUG_ERROR("packet input error (ipv4, p=%p, netif=%p)", p, &lwip_netifs[i]); + if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) { + DEBUG_ERROR("packet input error (ipv4, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err); break; } } @@ -146,8 +151,8 @@ void my_tcpip_callback(void *arg) for (size_t i=0; istate) { pbuf_ref(p); - if (lwip_netifs[i]->input(p, lwip_netifs[i]) != ERR_OK) { - DEBUG_ERROR("packet input error (arp, p=%p, netif=%p)", p, &lwip_netifs[i]); + if ((err = lwip_netifs[i]->input(p, lwip_netifs[i])) != ERR_OK) { + DEBUG_ERROR("packet input error (arp, p=%p, netif=%p)=%d", p, &lwip_netifs[i], err); } break; } @@ -157,19 +162,19 @@ void my_tcpip_callback(void *arg) default: break; } - lwip_frame_rxbuf_tot--; loop_score--; } - int count_final = lwip_frame_rxbuf_tot; - // Move pbuf frame pointer address buffer by the number of frames successfully fed into the stack core - if (count_initial - count_final > 0) { - memmove(lwip_frame_rxbuf, lwip_frame_rxbuf + count_final, count_initial - count_final); - } } // main thread which starts the initialization process static void main_lwip_driver_loop(void *arg) { +#if defined(__linux__) + pthread_setname_np(pthread_self(), "lwip_driver_loop"); +#endif +#if defined(__APPLE__) + pthread_setname_np("lwip_driver_loop"); +#endif sys_sem_t sem; LWIP_UNUSED_ARG(arg); if (sys_sem_new(&sem, 0) != ERR_OK) { @@ -178,8 +183,6 @@ static void main_lwip_driver_loop(void *arg) tcpip_init(tcpip_init_done, &sem); has_already_been_initialized = true; sys_sem_wait(&sem); - //DEBUG_INFO("stack thread init complete"); - while(lwip_driver_initialized) { #if defined(_WIN32) ms_sleep(LWIP_GUARDED_BUF_CHECK_INTERVAL*hibernationDelayMultiplier); @@ -301,12 +304,19 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p) DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] proto=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(), ZeroTier::Utils::ntoh(ethhdr->type), flagbuf); } + + return ERR_OK; } void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const ZeroTier::MAC &to, unsigned int etherType, const void *data, unsigned int len) { + if (!lwip_netifs.size()) { + DEBUG_ERROR("there are no netifs set up to handle this packet. ignoring."); + return; + } + struct pbuf *p,*q; struct eth_hdr ethhdr; from.copyTo(ethhdr.src.addr, 6); @@ -326,41 +336,35 @@ void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const Zer DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), ZeroTier::Utils::ntoh(ethhdr.type), flagbuf); } - - p = pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_POOL); - if (p != NULL) { - const char *dataptr = reinterpret_cast(data); - // First pbuf gets ethernet header at start - q = p; - if (q->len < sizeof(ethhdr)) { - DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); - return; - } - memcpy(q->payload,ðhdr,sizeof(ethhdr)); - memcpy((char*)q->payload + sizeof(ethhdr),dataptr,q->len - sizeof(ethhdr)); - dataptr += q->len - sizeof(ethhdr); - // Remaining pbufs (if any) get rest of data - while ((q = q->next)) { - memcpy(q->payload,dataptr,q->len); - dataptr += q->len; - } - } - else { - DEBUG_ERROR("dropped packet: no pbufs available"); + + p = pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_RAM); + if (!p) { + DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf"); return; } - if (!lwip_netifs.size()) { - DEBUG_ERROR("there are no netifs set up to handle this packet. ignoring."); + // First pbuf gets ethernet header at start + q = p; + if (q->len < sizeof(ethhdr)) { + DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); return; } - ZeroTier::Mutex::Lock _l(_rx_input_lock_m); - if (lwip_frame_rxbuf_tot == LWIP_MAX_GUARDED_RX_BUF_SZ) { - DEBUG_ERROR("dropped packet -- guarded receive buffer full, adjust MAX_GUARDED_RX_BUF_SZ or LWIP_GUARDED_BUF_CHECK_INTERVAL"); + const char *dataptr = reinterpret_cast(data); + memcpy(q->payload,ðhdr,sizeof(ethhdr)); + int remainingPayloadSpace = q->len - sizeof(ethhdr); + memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace); + dataptr += remainingPayloadSpace; + // Remaining pbufs (if any) get rest of data + while ((q = q->next)) { + memcpy(q->payload,dataptr,q->len); + dataptr += q->len; + } + _rx_input_lock_m.lock(); + if (rx_queue.size() >= LWIP_MAX_GUARDED_RX_BUF_SZ) { + DEBUG_INFO("dropped packet: rx_queue is full (>= %d)", LWIP_MAX_GUARDED_RX_BUF_SZ); return; } - //pbuf_ref(p); // Increment reference to allow user application to copy data from buffer -- Will be automatically deallocated by socket API - lwip_frame_rxbuf[lwip_frame_rxbuf_tot] = p; - lwip_frame_rxbuf_tot += 1; + rx_queue.push(p); + _rx_input_lock_m.unlock(); } /* @@ -377,9 +381,9 @@ void lwip_start_dhcp(void *netif) #endif } +/* static void netif_status_callback(struct netif *netif) { - /* DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n", netif, netif->name[0], @@ -397,8 +401,8 @@ static void netif_status_callback(struct netif *netif) netif->state, netif->flags ); - */ } +*/ ZeroTier::MAC _mac; @@ -455,7 +459,7 @@ void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier: IP4_ADDR(&gw,127,0,0,1); ipaddr.addr = *((u32_t *)ip.rawIpData()); netmask.addr = *((u32_t *)ip.netmask().rawIpData()); - netif_set_status_callback(lwipdev, netif_status_callback); + //netif_set_status_callback(lwipdev, netif_status_callback); netif_add(lwipdev, &ipaddr, &netmask, &gw, NULL, netif_init_4, tcpip_input); lwipdev->state = tapref; snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", @@ -475,7 +479,7 @@ void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier: netif_create_ip6_linklocal_address(lwipdev, 1); netif_ip6_addr_set_state(lwipdev, 0, IP6_ADDR_TENTATIVE); netif_ip6_addr_set_state(lwipdev, 1, IP6_ADDR_TENTATIVE); - netif_set_status_callback(lwipdev, netif_status_callback); + //netif_set_status_callback(lwipdev, netif_status_callback); netif_set_default(lwipdev); netif_set_up(lwipdev); netif_set_link_up(lwipdev);