From c0aac699e77b4b802069c2c389c8f526d6c801de Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Fri, 29 Sep 2017 15:37:50 -0700 Subject: [PATCH] Stubbed out experimental raw drivers --- include/lwIP.hpp | 7 ++ src/VirtualTap.cpp | 61 +++++++--- src/VirtualTap.hpp | 4 +- src/libzt.cpp | 296 ++++++++++++++++++++++++++++++++++++++++----- src/lwIP.cpp | 87 ++++++++++--- 5 files changed, 392 insertions(+), 63 deletions(-) diff --git a/include/lwIP.hpp b/include/lwIP.hpp index 23733ad..9cc1f68 100644 --- a/include/lwIP.hpp +++ b/include/lwIP.hpp @@ -36,14 +36,21 @@ #include "MAC.hpp" #include "InetAddress.hpp" #include "Defs.h" +#include "Mutex.hpp" /** * @brief Initialize network stack semaphores, threads, and timers. * + * @usage This is called during the initial setup of each VirtualTap but is only allowed to execute once * @return */ void lwip_driver_init(); +void general_lwip_init_interface(void *tapref, struct netif *interface, const char *name, const ZeroTier::MAC &mac, + const ZeroTier::InetAddress &addr, const ZeroTier::InetAddress &nm, const ZeroTier::InetAddress &gw); + +void general_turn_on_interface(struct netif *interface); + /** * @brief Set up an interface in the network stack for the VirtualTap. * diff --git a/src/VirtualTap.cpp b/src/VirtualTap.cpp index ae99eda..85cb9b0 100644 --- a/src/VirtualTap.cpp +++ b/src/VirtualTap.cpp @@ -100,11 +100,13 @@ namespace ZeroTier { snprintf(vtap_full_name, sizeof(vtap_full_name), "libzt%d-%lx", devno++, _nwid); _dev = vtap_full_name; DEBUG_INFO("set VirtualTap interface name to: %s", _dev.c_str()); - // set virtual tap interface name (abbreviated) memset(vtap_abbr_name, 0, sizeof(vtap_abbr_name)); snprintf(vtap_abbr_name, sizeof(vtap_abbr_name), "libzt%d", devno); - +#if defined(STACK_LWIP) + // initialize network stacks + lwip_driver_init(); +#endif // start vtap thread and stack I/O loops _thread = Thread::start(this); } @@ -129,18 +131,16 @@ namespace ZeroTier { bool VirtualTap::registerIpWithStack(const InetAddress &ip) { - DEBUG_EXTRA(); - lwip_driver_init(); +#if defined(STACK_LWIP) lwip_init_interface((void*)this, this->_mac, ip); +#endif return true; } bool VirtualTap::addIp(const InetAddress &ip) { - int err = false; char ipbuf[INET6_ADDRSTRLEN]; - DEBUG_EXTRA("addIp (%s)", ip.toString(ipbuf)); - + DEBUG_EXTRA("addr=%s", ip.toString(ipbuf)); Mutex::Lock _l(_ips_m); if (registerIpWithStack(ip)) { if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) { @@ -149,7 +149,7 @@ namespace ZeroTier { } return true; } - return err; + return false; } bool VirtualTap::removeIp(const InetAddress &ip) @@ -179,7 +179,9 @@ namespace ZeroTier { void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType, const void *data,unsigned int len) { +#if defined(STACK_LWIP) lwip_eth_rx(this, from, to, etherType, data, len); +#endif } std::string VirtualTap::deviceName() const @@ -237,7 +239,6 @@ namespace ZeroTier { void VirtualTap::threadMain() throw() { - DEBUG_EXTRA(); while (true) { _phy.poll(ZT_PHY_POLL_INTERVAL); Housekeeping(); @@ -259,16 +260,48 @@ namespace ZeroTier { DEBUG_EXTRA(); } - bool VirtualTap::routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw) + bool VirtualTap::routeAdd(const InetAddress &ip, const InetAddress &nm, const InetAddress &gw) { + bool err = false; DEBUG_EXTRA(); - return false; +#if defined(STACK_LWIP) + //general_lwip_init_interface(this, NULL, "n1", _mac, ip, nm, gw); + //general_turn_on_interface(NULL); +#endif +#if defined(STACK_PICO) + if (picostack) { + return picostack->pico_route_add(this, ip, nm, gw, 0); + } else { + handle_general_failure(); + return false; + } +#endif +#if defined(NO_STACK) + // nothing to do +#endif + return err; } - bool VirtualTap::routeDelete(const InetAddress &addr, const InetAddress &nm) + bool VirtualTap::routeDelete(const InetAddress &ip, const InetAddress &nm) { + bool err = false; DEBUG_EXTRA(); - return false; +#if defined(STACK_LWIP) + //general_lwip_init_interface(this, NULL, "n1", _mac, ip, nm, gw); + //general_turn_on_interface(NULL); +#endif +#if defined(STACK_PICO) + if (picostack) { + return picostack->pico_route_del(this, ip, nm, 0); + } else { + handle_general_failure(); + return false; + } +#endif +#if defined(NO_STACK) + // nothing to do +#endif + return err; } void VirtualTap::addVirtualSocket() @@ -369,7 +402,7 @@ namespace ZeroTier { Mutex::Lock _l(_tcpconns_m); std::time_t current_ts = std::time(nullptr); if (current_ts > last_housekeeping_ts + ZT_HOUSEKEEPING_INTERVAL) { - DEBUG_EXTRA(); + // DEBUG_EXTRA(); // update managed routes (add/del from network stacks) ZeroTier::OneService *service = ((ZeroTier::OneService *)zt1ServiceRef); if (service) { diff --git a/src/VirtualTap.hpp b/src/VirtualTap.hpp index bdde820..9fc3457 100644 --- a/src/VirtualTap.hpp +++ b/src/VirtualTap.hpp @@ -143,12 +143,12 @@ namespace ZeroTier { /** * Adds a route to the virtual tap */ - bool routeAdd(const InetAddress &addr, const InetAddress &nm, const InetAddress &gw); + bool routeAdd(const InetAddress &ip, const InetAddress &nm, const InetAddress &gw); /** * Deletes a route from the virtual tap */ - bool routeDelete(const InetAddress &addr, const InetAddress &nm); + bool routeDelete(const InetAddress &ip, const InetAddress &nm); /** * Assign a VirtualSocket to the VirtualTap diff --git a/src/libzt.cpp b/src/libzt.cpp index f61b826..2ecb981 100644 --- a/src/libzt.cpp +++ b/src/libzt.cpp @@ -32,9 +32,14 @@ #include +#if defined(STACK_LWIP) #include "lwip/sockets.h" #include "lwip/sys.h" #include "lwip/ip_addr.h" +#endif +#if defined(NO_STACK) +#include +#endif #include "libzt.h" @@ -42,6 +47,7 @@ extern "C" { #endif +#if defined(STACK_LWIP) void sys2lwip(int fd, const struct sockaddr *orig, struct sockaddr *modified) { /* Inelegant fix for lwIP 'sequential' API address error check (in sockets.c). For some reason @@ -76,183 +82,409 @@ void sys2lwip(int fd, const struct sockaddr *orig, struct sockaddr *modified) { #endif } } +#endif // STACK_LWIP int zts_socket(int socket_family, int socket_type, int protocol) { + int err = -1; DEBUG_EXTRA("family=%d, type=%d, proto=%d", socket_family, socket_type, protocol); - return lwip_socket(socket_family, socket_type, protocol); +#if defined(STACK_LWIP) + err = lwip_socket(socket_family, socket_type, protocol); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) { + int err = -1; DEBUG_EXTRA("fd=%d",fd); +#if defined(STACK_LWIP) struct sockaddr_storage ss; sys2lwip(fd, addr, (struct sockaddr*)&ss); - return lwip_connect(fd, (struct sockaddr*)&ss, addrlen); + err = lwip_connect(fd, (struct sockaddr*)&ss, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); +#if defined(STACK_LWIP) struct sockaddr_storage ss; sys2lwip(fd, addr, (struct sockaddr*)&ss); - return lwip_bind(fd, (struct sockaddr*)&ss, addrlen); + err = lwip_bind(fd, (struct sockaddr*)&ss, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_listen(int fd, int backlog) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); - return lwip_listen(fd, backlog); +#if defined(STACK_LWIP) + err = lwip_listen(fd, backlog); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); - return lwip_accept(fd, addr, addrlen); +#if defined(STACK_LWIP) + err = lwip_accept(fd, addr, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } #if defined(__linux__) int zts_accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); - return zts_accept(fd, addr, addrlen); +#if defined(STACK_LWIP) + err = zts_accept(fd, addr, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } #endif int zts_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { + int err = -1; DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname); - return lwip_setsockopt(fd, level, optname, optval, optlen); +#if defined(STACK_LWIP) + err = lwip_setsockopt(fd, level, optname, optval, optlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { + int err = -1; DEBUG_EXTRA("fd=%d, level=%d, optname=%d", fd, level, optname); - return lwip_getsockopt(fd, level, optname, optval, optlen); +#if defined(STACK_LWIP) + err = lwip_getsockopt(fd, level, optname, optval, optlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) { + int err = -1; DEBUG_EXTRA("fd=%p", fd); - return lwip_getsockname(fd, addr, addrlen); +#if defined(STACK_LWIP) + err = lwip_getsockname(fd, addr, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); - return lwip_getpeername(fd, addr, addrlen); +#if defined(STACK_LWIP) + err = lwip_getpeername(fd, addr, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_gethostname(char *name, size_t len) { DEBUG_EXTRA(); - return -1; + int err = -1; +#if defined(STACK_LWIP) +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_sethostname(const char *name, size_t len) { DEBUG_EXTRA(); - return -1; + int err = -1; +#if defined(STACK_LWIP) +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_close(int fd) { + int err = -1; DEBUG_EXTRA("fd=%d", fd); - return lwip_close(fd); +#if defined(STACK_LWIP) + err = lwip_close(fd); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_poll(struct pollfd *fds, nfds_t nfds, int timeout) { + int err = -1; +#if defined(STACK_LWIP) DEBUG_ERROR("warning, this is not implemented"); return poll(fds, nfds, timeout); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } -int zts_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +int zts_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) { + int err = -1; //DEBUG_EXTRA(); - return lwip_select(nfds, readfds, writefds, exceptfds, timeout); +#if defined(STACK_LWIP) + err = lwip_select(nfds, readfds, writefds, exceptfds, timeout); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_fcntl(int fd, int cmd, int flags) { + int err = -1; DEBUG_EXTRA("fd=%p, cmd=%d, flags=%d", cmd, flags); +#if defined(STACK_LWIP) + // translation required since lwIP uses different flag values int translated_flags = 0; if (flags == 2048) { translated_flags = 1; } - return lwip_fcntl(fd, cmd, translated_flags); + err = lwip_fcntl(fd, cmd, translated_flags); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_ioctl(int fd, unsigned long request, void *argp) { + int err = -1; DEBUG_EXTRA("fd=%d, req=%d", fd, request); - return lwip_ioctl(fd, request, argp); +#if defined(STACK_LWIP) + err = lwip_ioctl(fd, request, argp); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } -ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) +ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags, + const struct sockaddr *addr, socklen_t addrlen) { + int err = -1; DEBUG_TRANS("fd=%d, len=%d", fd, len); +#if defined(STACK_LWIP) struct sockaddr_storage ss; sys2lwip(fd, addr, (struct sockaddr*)&ss); - return lwip_sendto(fd, buf, len, flags, (struct sockaddr*)&ss, addrlen); + err = lwip_sendto(fd, buf, len, flags, (struct sockaddr*)&ss, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } ssize_t zts_send(int fd, const void *buf, size_t len, int flags) { + int err = -1; DEBUG_TRANS("fd=%d, len=%d", fd, len); - return lwip_send(fd, buf, len, flags); +#if defined(STACK_LWIP) + err = lwip_send(fd, buf, len, flags); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } ssize_t zts_sendmsg(int fd, const struct msghdr *msg, int flags) { + int err = -1; DEBUG_TRANS("fd=%d", fd); - return lwip_sendmsg(fd, msg, flags); +#if defined(STACK_LWIP) + err = lwip_sendmsg(fd, msg, flags); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } ssize_t zts_recv(int fd, void *buf, size_t len, int flags) { + int err = -1; DEBUG_TRANS("fd=%d", fd); - return lwip_recv(fd, buf, len, flags); +#if defined(STACK_LWIP) + err = lwip_recv(fd, buf, len, flags); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } -ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) +ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags, + struct sockaddr *addr, socklen_t *addrlen) { + int err = -1; DEBUG_TRANS("fd=%d", fd); - return lwip_recvfrom(fd, buf, len, flags, addr, addrlen); +#if defined(STACK_LWIP) + err = lwip_recvfrom(fd, buf, len, flags, addr, addrlen); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } ssize_t zts_recvmsg(int fd, struct msghdr *msg,int flags) { DEBUG_TRANS("fd=%d", fd); - return -1; + int err = -1; +#if defined(STACK_LWIP) +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } -int zts_read(int fd, void *buf, size_t len) { +int zts_read(int fd, void *buf, size_t len) +{ + int err = -1; //DEBUG_TRANS("fd=%d, len=%d", fd, len); - return lwip_read(fd, buf, len); +#if defined(STACK_LWIP) + err = lwip_read(fd, buf, len); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } -int zts_write(int fd, const void *buf, size_t len) { +int zts_write(int fd, const void *buf, size_t len) +{ //DEBUG_TRANS("fd=%d, len=%d", fd, len); - return lwip_write(fd, buf, len); + int err = -1; +#if defined(STACK_LWIP) + err = lwip_write(fd, buf, len); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_shutdown(int fd, int how) { + int err = -1; DEBUG_EXTRA("fd=%d, how=%d", fd, how); - return lwip_shutdown(fd, how); +#if defined(STACK_LWIP) + err = lwip_shutdown(fd, how); +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_add_dns_nameserver(struct sockaddr *addr) { DEBUG_EXTRA(); - return -1; + int err = -1; +#if defined(STACK_LWIP) +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } int zts_del_dns_nameserver(struct sockaddr *addr) { DEBUG_EXTRA(); - return -1; + int err = -1; +#if defined(STACK_LWIP) +#endif +#if defined(STCK_PICO) +#endif +#if defined(NO_STACK) +#endif + return err; } #ifdef __cplusplus diff --git a/src/lwIP.cpp b/src/lwIP.cpp index ea72a8e..f55f9e5 100644 --- a/src/lwIP.cpp +++ b/src/lwIP.cpp @@ -53,9 +53,12 @@ #include "lwIP.hpp" -netif lwipdev, lwipdev6; +netif lwipdev, lwipdev6, n1; -static bool started = false; +struct netif netifs[10]; + +bool lwip_driver_initialized = false; +ZeroTier::Mutex driver_m; err_t tapif_init(struct netif *netif) { @@ -78,11 +81,13 @@ static void tcp_timeout(void *data) // callback for when the TCPIP thread has been successfully started static void tcpip_init_done(void *arg) { - DEBUG_EXTRA(); sys_sem_t *sem; sem = (sys_sem_t *)arg; netif_set_up(&lwipdev); - DEBUG_INFO("Applications started."); + DEBUG_EXTRA("lwIP stack driver initialized"); + lwip_driver_initialized = true; + driver_m.unlock(); + DEBUG_EXTRA("released lock"); // sys_timeout(5000, tcp_timeout, NULL); sys_sem_signal(sem); } @@ -90,27 +95,24 @@ static void tcpip_init_done(void *arg) // main thread which starts the initialization process static void main_network_stack_thread(void *arg) { - DEBUG_EXTRA(); sys_sem_t sem; LWIP_UNUSED_ARG(arg); if (sys_sem_new(&sem, 0) != ERR_OK) { - DEBUG_ERROR("Failed to create semaphore", 0); + DEBUG_ERROR("failed to create semaphore", 0); } tcpip_init(tcpip_init_done, &sem); sys_sem_wait(&sem); - DEBUG_INFO("TCP/IP initialized."); + DEBUG_EXTRA("tcpip thread started"); sys_sem_wait(&sem); } // initialize the lwIP stack void lwip_driver_init() { - DEBUG_EXTRA(); - // TODO: this should be replaced with something thread-safe - if (started == false) { - started=true; - } - else { + DEBUG_EXTRA("getting lock.."); + driver_m.lock(); // unlocked from callback indicating completion of init + DEBUG_EXTRA("got lock"); + if (lwip_driver_initialized == true) { return; } sys_thread_new("main_network_stack_thread", main_network_stack_thread, @@ -158,6 +160,44 @@ err_t lwip_eth_tx(struct netif *netif, struct pbuf *p) return ERR_OK; } +void general_lwip_init_interface(void *tapref, struct netif *interface, const char *name, const ZeroTier::MAC &mac, const ZeroTier::InetAddress &addr, const ZeroTier::InetAddress &nm, const ZeroTier::InetAddress &gw) +{ + char ipbuf[INET6_ADDRSTRLEN], nmbuf[INET6_ADDRSTRLEN], gwbuf[INET6_ADDRSTRLEN]; + static ip_addr_t _addr, _nm, _gw; + IP4_ADDR(&_gw,127,0,0,1); + IP4_ADDR(&_addr,10,6,6,86); + //_addr.addr = *((u32_t *)addr.rawIpData()); + _nm.addr = *((u32_t *)addr.netmask().rawIpData()); + netif_add(&(n1),&_addr, &_nm, &_gw, NULL, tapif_init, tcpip_input); + n1.state = tapref; + n1.output = etharp_output; + n1.mtu = ZT_MAX_MTU; + n1.name[0] = name[0]; + n1.name[1] = name[1]; + n1.linkoutput = lwip_eth_tx; + n1.hwaddr_len = 6; + mac.copyTo(n1.hwaddr, n1.hwaddr_len); + n1.flags = NETIF_FLAG_BROADCAST + | NETIF_FLAG_ETHARP + | NETIF_FLAG_IGMP + | NETIF_FLAG_LINK_UP + | NETIF_FLAG_UP; + netif_set_link_up(&n1); + char macbuf[ZT_MAC_ADDRSTRLEN]; + mac2str(macbuf, ZT_MAC_ADDRSTRLEN, n1.hwaddr); + DEBUG_INFO("initialized netif as [mac=%s, addr=%s, nm=%s, gw=%s]", macbuf, addr.toString(ipbuf), addr.netmask().toString(nmbuf), gw.toString(gwbuf)); +} + +void general_turn_on_interface(struct netif *interface) +{ + //netif_set_up(&n1); + //netif_set_default(&n1); + //lwipdev.linkoutput = NULL; + //sleep(2); + //netif_set_down(&lwipdev); + //netif_set_link_down(&lwipdev); +} + void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier::InetAddress &ip) { /* NOTE: It is a known issue that when assigned more than one IP address via @@ -184,10 +224,10 @@ void lwip_init_interface(void *tapref, const ZeroTier::MAC &mac, const ZeroTier: | NETIF_FLAG_UP; netif_set_default(&(lwipdev)); netif_set_link_up(&(lwipdev)); - //netif_set_up(&(lwipdev)); + netif_set_up(&(lwipdev)); char macbuf[ZT_MAC_ADDRSTRLEN]; mac2str(macbuf, ZT_MAC_ADDRSTRLEN, lwipdev.hwaddr); - DEBUG_INFO("mac=%s, addr=%s, nm=%s", macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf)); + DEBUG_INFO("initialized netif as [mac=%s, addr=%s, nm=%s]", macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf)); } } @@ -234,7 +274,24 @@ void lwip_eth_rx(ZeroTier::VirtualTap *tap, const ZeroTier::MAC &from, const Zer ZeroTier::Utils::ntoh(ethhdr.type), beautify_eth_proto_nums(ZeroTier::Utils::ntoh(ethhdr.type)), flagbuf); } { + + // Here we select which interface shall receive the Ethernet frames coming in off the ZeroTier virtual wire + + // ROUTING CODE SHALL GO HERE +/* + for (int i=0; ihwaddr; + + } + } +*/ #if defined(LIBZT_IPV4) + if (lwipdev.input == NULL) + { + return; + } if (lwipdev.input(p, &(lwipdev)) != ERR_OK) { DEBUG_ERROR("error while feeding frame into stack interface (ipv4)"); }