You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
710 lines
18 KiB
710 lines
18 KiB
/* |
|
* Copyright (c)2013-2020 ZeroTier, Inc. |
|
* |
|
* Use of this software is governed by the Business Source License included |
|
* in the LICENSE.TXT file in the project's root directory. |
|
* |
|
* Change Date: 2024-01-01 |
|
* |
|
* On the date above, in accordance with the Business Source License, use |
|
* of this software will be governed by version 2.0 of the Apache License. |
|
*/ |
|
/****/ |
|
|
|
/** |
|
* @file |
|
* |
|
* Virtual ethernet tap device and combined network stack driver |
|
*/ |
|
|
|
#include "Constants.hpp" |
|
#include "MAC.hpp" |
|
#include "Mutex.hpp" |
|
#include "InetAddress.hpp" |
|
#include "MulticastGroup.hpp" |
|
|
|
#include "lwip/netif.h" |
|
#include "lwip/etharp.h" |
|
#include "lwip/sys.h" |
|
#include "lwip/ethip6.h" |
|
#include "lwip/tcpip.h" |
|
#include "netif/ethernet.h" |
|
|
|
#ifdef LWIP_STATS |
|
#include "lwip/stats.h" |
|
#endif |
|
|
|
#include "VirtualTap.hpp" |
|
#include "ZeroTierSockets.h" |
|
#include "Events.hpp" |
|
#include "Debug.hpp" |
|
|
|
#if defined(__WINDOWS__) |
|
#include <time.h> |
|
#include "Synchapi.h" |
|
#endif |
|
|
|
#define ZTS_TAP_THREAD_POLLING_INTERVAL 50 |
|
#define LWIP_DRIVER_LOOP_INTERVAL 250 |
|
|
|
namespace ZeroTier { |
|
|
|
extern void _enqueueEvent(int16_t eventCode, void *arg = NULL); |
|
|
|
/** |
|
* A virtual tap device. The ZeroTier core service creates one of these for each |
|
* virtual network joined. It will be destroyed upon leave(). |
|
*/ |
|
VirtualTap::VirtualTap( |
|
const char *homePath, |
|
const MAC &mac, |
|
unsigned int mtu, |
|
unsigned int metric, |
|
uint64_t nwid, |
|
const char *friendlyName, |
|
void (*handler)(void *,void*,uint64_t,const MAC &,const MAC &, |
|
unsigned int,unsigned int,const void *,unsigned int), |
|
void *arg) : |
|
_handler(handler), |
|
_homePath(homePath), |
|
_arg(arg), |
|
_initialized(false), |
|
_enabled(true), |
|
_run(true), |
|
_mac(mac), |
|
_mtu(mtu), |
|
_nwid(nwid), |
|
_unixListenSocket((PhySocket *)0), |
|
_phy(this,false,true) |
|
{ |
|
memset(vtap_full_name, 0, sizeof(vtap_full_name)); |
|
snprintf(vtap_full_name, sizeof(vtap_full_name), "libzt%llx", (unsigned long long)_nwid); |
|
_dev = vtap_full_name; |
|
#ifndef __WINDOWS__ |
|
::pipe(_shutdownSignalPipe); |
|
#endif |
|
// Start virtual tap thread and stack I/O loops |
|
_thread = Thread::start(this); |
|
} |
|
|
|
VirtualTap::~VirtualTap() |
|
{ |
|
struct zts_network_details *nd = new zts_network_details; |
|
nd->nwid = _nwid; |
|
_run = false; |
|
#ifndef __WINDOWS__ |
|
::write(_shutdownSignalPipe[1],"\0",1); |
|
#endif |
|
_phy.whack(); |
|
_lwip_remove_netif(netif4); |
|
netif4 = NULL; |
|
_lwip_remove_netif(netif6); |
|
netif6 = NULL; |
|
_enqueueEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd); |
|
Thread::join(_thread); |
|
#ifndef __WINDOWS__ |
|
::close(_shutdownSignalPipe[0]); |
|
::close(_shutdownSignalPipe[1]); |
|
#endif |
|
} |
|
|
|
void VirtualTap::lastConfigUpdate(uint64_t lastConfigUpdateTime) |
|
{ |
|
_lastConfigUpdateTime = lastConfigUpdateTime; |
|
} |
|
|
|
void VirtualTap::setEnabled(bool en) |
|
{ |
|
_enabled = en; |
|
} |
|
|
|
bool VirtualTap::enabled() const |
|
{ |
|
return _enabled; |
|
} |
|
|
|
bool VirtualTap::hasIpv4Addr() |
|
{ |
|
Mutex::Lock _l(_ips_m); |
|
std::vector<InetAddress>::iterator it(_ips.begin()); |
|
while (it != _ips.end()) { |
|
if ((*it).isV4()) { return true; } |
|
it++; |
|
} |
|
return false; |
|
} |
|
|
|
bool VirtualTap::hasIpv6Addr() |
|
{ |
|
Mutex::Lock _l(_ips_m); |
|
std::vector<InetAddress>::iterator it(_ips.begin()); |
|
while (it != _ips.end()) { |
|
if ((*it).isV6()) { return true; } |
|
it++; |
|
} |
|
return false; |
|
} |
|
|
|
bool VirtualTap::addIp(const InetAddress &ip) |
|
{ |
|
char ipbuf[128]; |
|
//ip.toString(ipbuf); |
|
//DEBUG_INFO("addr=%s", ipbuf); |
|
|
|
/* Limit address assignments to one per type. |
|
This limitation can be removed if some changes |
|
are made in the netif driver. */ |
|
if (ip.isV4() && hasIpv4Addr()) { |
|
ip.toString(ipbuf); |
|
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf); |
|
return false; |
|
} |
|
if (ip.isV6() && hasIpv6Addr()) { |
|
ip.toString(ipbuf); |
|
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf); |
|
return false; |
|
} |
|
|
|
Mutex::Lock _l(_ips_m); |
|
if (_ips.size() >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { |
|
return false; |
|
} |
|
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) { |
|
_lwip_init_interface((void*)this, ip); |
|
_ips.push_back(ip); |
|
std::sort(_ips.begin(),_ips.end()); |
|
} |
|
return true; |
|
} |
|
|
|
bool VirtualTap::removeIp(const InetAddress &ip) |
|
{ |
|
Mutex::Lock _l(_ips_m); |
|
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip)); |
|
if (std::find(_ips.begin(),_ips.end(),ip) != _ips.end()) { |
|
_lwip_remove_address_from_netif((void*)this, ip); |
|
_ips.erase(i); |
|
} |
|
return true; |
|
} |
|
|
|
std::vector<InetAddress> VirtualTap::ips() const |
|
{ |
|
Mutex::Lock _l(_ips_m); |
|
return _ips; |
|
} |
|
|
|
void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType, |
|
const void *data,unsigned int len) |
|
{ |
|
if (len && _enabled) { |
|
_lwip_eth_rx(this, from, to, etherType, data, len); |
|
} |
|
} |
|
|
|
std::string VirtualTap::deviceName() const |
|
{ |
|
return _dev; |
|
} |
|
|
|
void VirtualTap::setFriendlyName(const char *friendlyName) |
|
{ |
|
DEBUG_INFO("%s", friendlyName); |
|
} |
|
|
|
void VirtualTap::scanMulticastGroups(std::vector<MulticastGroup> &added, |
|
std::vector<MulticastGroup> &removed) |
|
{ |
|
std::vector<MulticastGroup> newGroups; |
|
Mutex::Lock _l(_multicastGroups_m); |
|
// TODO: get multicast subscriptions |
|
std::vector<InetAddress> allIps(ips()); |
|
for (std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) |
|
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); |
|
|
|
std::sort(newGroups.begin(),newGroups.end()); |
|
std::unique(newGroups.begin(),newGroups.end()); |
|
|
|
for (std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { |
|
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) |
|
added.push_back(*m); |
|
} |
|
for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { |
|
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) |
|
removed.push_back(*m); |
|
} |
|
_multicastGroups.swap(newGroups); |
|
} |
|
|
|
void VirtualTap::setMtu(unsigned int mtu) |
|
{ |
|
_mtu = mtu; |
|
} |
|
|
|
void VirtualTap::threadMain() |
|
throw() |
|
{ |
|
fd_set readfds,nullfds; |
|
struct timeval tv; |
|
tv.tv_sec = 0; |
|
tv.tv_usec = 0; |
|
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); |
|
// writes to shutdown pipe terminate thread |
|
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) { |
|
break; |
|
} |
|
#if defined(__WINDOWS__) |
|
Sleep(ZTS_TAP_THREAD_POLLING_INTERVAL); |
|
#else |
|
struct timespec sleepValue = {0}; |
|
sleepValue.tv_nsec = ZTS_TAP_THREAD_POLLING_INTERVAL * 500000; |
|
nanosleep(&sleepValue, NULL); |
|
#endif |
|
} |
|
} |
|
|
|
void VirtualTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, |
|
const struct sockaddr *from,void *data,unsigned long len) {} |
|
void VirtualTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {} |
|
void VirtualTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN, |
|
const struct sockaddr *from) {} |
|
void VirtualTap::phyOnTcpClose(PhySocket *sock,void **uptr) {} |
|
void VirtualTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} |
|
void VirtualTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {} |
|
void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr) {} |
|
|
|
////////////////////////////////////////////////////////////////////////////// |
|
// Netif driver code for lwIP network stack // |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
bool _has_exited = false; |
|
|
|
// Used to generate enumerated lwIP interface names |
|
int netifCount = 0; |
|
|
|
// Lock to guard access to network stack state changes |
|
Mutex stackLock; |
|
|
|
// Callback for when the TCPIP thread has been successfully started |
|
static void _tcpip_init_done(void *arg) |
|
{ |
|
sys_sem_t *sem; |
|
sem = (sys_sem_t *)arg; |
|
_setState(ZTS_STATE_STACK_RUNNING); |
|
_enqueueEvent(ZTS_EVENT_STACK_UP); |
|
sys_sem_signal(sem); |
|
} |
|
|
|
static void _main_lwip_driver_loop(void *arg) |
|
{ |
|
#if defined(__linux__) |
|
pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME); |
|
#endif |
|
#if defined(__APPLE__) |
|
pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME); |
|
#endif |
|
sys_sem_t sem; |
|
LWIP_UNUSED_ARG(arg); |
|
if (sys_sem_new(&sem, 0) != ERR_OK) { |
|
DEBUG_ERROR("failed to create semaphore"); |
|
} |
|
tcpip_init(_tcpip_init_done, &sem); |
|
sys_sem_wait(&sem); |
|
// Main loop |
|
while(_getState(ZTS_STATE_STACK_RUNNING)) { |
|
zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL); |
|
} |
|
_has_exited = true; |
|
_enqueueEvent(ZTS_EVENT_STACK_DOWN); |
|
} |
|
|
|
bool _lwip_is_up() |
|
{ |
|
Mutex::Lock _l(stackLock); |
|
return _getState(ZTS_STATE_STACK_RUNNING); |
|
} |
|
|
|
void _lwip_driver_init() |
|
{ |
|
if (_lwip_is_up()) { |
|
return; |
|
} |
|
if (_has_exited) { |
|
return; |
|
} |
|
Mutex::Lock _l(stackLock); |
|
#if defined(__WINDOWS__) |
|
sys_init(); // Required for win32 init of critical sections |
|
#endif |
|
sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, _main_lwip_driver_loop, |
|
NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); |
|
} |
|
|
|
void _lwip_driver_shutdown() |
|
{ |
|
if (_has_exited) { |
|
return; |
|
} |
|
Mutex::Lock _l(stackLock); |
|
// Set flag to stop sending frames into the core |
|
_clrState(ZTS_STATE_STACK_RUNNING); |
|
// Wait until the main lwIP thread has exited |
|
while (!_has_exited) { zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL); } |
|
} |
|
|
|
void _lwip_remove_netif(void *netif) |
|
{ |
|
if (!netif) { |
|
return; |
|
} |
|
struct netif *n = (struct netif*)netif; |
|
LOCK_TCPIP_CORE(); |
|
netif_remove(n); |
|
netif_set_down(n); |
|
netif_set_link_down(n); |
|
UNLOCK_TCPIP_CORE(); |
|
} |
|
|
|
err_t _lwip_eth_tx(struct netif *n, struct pbuf *p) |
|
{ |
|
if (!n) { |
|
return ERR_IF; |
|
} |
|
struct pbuf *q; |
|
char buf[ZT_MAX_MTU+32]; |
|
char *bufptr; |
|
int totalLength = 0; |
|
|
|
VirtualTap *tap = (VirtualTap*)n->state; |
|
bufptr = buf; |
|
for (q = p; q != NULL; q = q->next) { |
|
memcpy(bufptr, q->payload, q->len); |
|
bufptr += q->len; |
|
totalLength += q->len; |
|
} |
|
struct eth_hdr *ethhdr; |
|
ethhdr = (struct eth_hdr *)buf; |
|
|
|
MAC src_mac; |
|
MAC dest_mac; |
|
src_mac.setTo(ethhdr->src.addr, 6); |
|
dest_mac.setTo(ethhdr->dest.addr, 6); |
|
|
|
char *data = buf + sizeof(struct eth_hdr); |
|
int len = totalLength - sizeof(struct eth_hdr); |
|
int proto = Utils::ntoh((uint16_t)ethhdr->type); |
|
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len); |
|
if (ZT_MSG_TRANSFER == true) { |
|
char flagbuf[32]; |
|
memset(&flagbuf, 0, 32); |
|
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; |
|
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2], |
|
ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]); |
|
MAC mac; |
|
mac.setTo(ethhdr->dest.addr, 6); |
|
mac.toAddress(tap->_nwid).toString(nodeBuf); |
|
/* |
|
DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] ethertype=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(), |
|
Utils::ntoh(ethhdr->type), flagbuf); |
|
*/ |
|
} |
|
return ERR_OK; |
|
} |
|
|
|
void _lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType, |
|
const void *data, unsigned int len) |
|
{ |
|
#ifdef LWIP_STATS |
|
stats_display(); |
|
#endif |
|
if (!_getState(ZTS_STATE_STACK_RUNNING)) { |
|
return; |
|
} |
|
struct pbuf *p,*q; |
|
struct eth_hdr ethhdr; |
|
from.copyTo(ethhdr.src.addr, 6); |
|
to.copyTo(ethhdr.dest.addr, 6); |
|
ethhdr.type = Utils::hton((uint16_t)etherType); |
|
|
|
if (ZT_MSG_TRANSFER == true) { |
|
char flagbuf[32]; |
|
memset(&flagbuf, 0, 32); |
|
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; |
|
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2], |
|
ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]); |
|
MAC mac; |
|
mac.setTo(ethhdr.src.addr, 6); |
|
mac.toAddress(tap->_nwid).toString(nodeBuf); |
|
/* |
|
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] ethertype=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), |
|
Utils::ntoh(ethhdr.type), flagbuf); |
|
*/ |
|
} |
|
|
|
p = pbuf_alloc(PBUF_RAW, (uint16_t)len+sizeof(struct eth_hdr), PBUF_RAM); |
|
if (!p) { |
|
DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf"); |
|
return; |
|
} |
|
// First pbuf gets ethernet header at start |
|
q = p; |
|
if (q->len < sizeof(ethhdr)) { |
|
pbuf_free(p); |
|
p = NULL; |
|
DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); |
|
return; |
|
} |
|
// Copy frame data into pbuf |
|
const char *dataptr = reinterpret_cast<const char *>(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; |
|
} |
|
// Feed packet into stack |
|
int err; |
|
|
|
if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) { |
|
if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) { |
|
DEBUG_ERROR("packet input error (%d)", err); |
|
pbuf_free(p); |
|
} |
|
} |
|
if (Utils::ntoh(ethhdr.type) == 0x86DD) { |
|
if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) { |
|
DEBUG_ERROR("packet input error (%d)", err); |
|
pbuf_free(p); |
|
} |
|
} |
|
} |
|
|
|
bool _lwip_is_netif_up(void *n) |
|
{ |
|
if (!n) { |
|
return false; |
|
} |
|
LOCK_TCPIP_CORE(); |
|
bool result = netif_is_up((struct netif*)n); |
|
UNLOCK_TCPIP_CORE(); |
|
return result; |
|
} |
|
|
|
static struct zts_netif_details *_lwip_prepare_netif_status_msg(struct netif *n) |
|
{ |
|
if (!n || !n->state) { |
|
return NULL; |
|
} |
|
VirtualTap *tap = (VirtualTap *)n->state; |
|
struct zts_netif_details *details = new zts_netif_details(); |
|
details->nwid = tap->_nwid; |
|
memcpy(&(details->mac), n->hwaddr, n->hwaddr_len); |
|
details->mtu = n->mtu; |
|
return details; |
|
} |
|
|
|
static void _netif_remove_callback(struct netif *n) |
|
{ |
|
// Called from core, no need to lock |
|
if (!n || !n->state) { |
|
return; |
|
} |
|
VirtualTap *tap = (VirtualTap *)n->state; |
|
struct zts_netif_details *details = new zts_netif_details(); |
|
details->nwid = tap->_nwid; |
|
details->mac = 0; |
|
details->mtu = 0; |
|
_enqueueEvent(ZTS_EVENT_NETIF_REMOVED, (void*)details); |
|
} |
|
|
|
static void _netif_status_callback(struct netif *n) |
|
{ |
|
// Called from core, no need to lock |
|
if (!n) { |
|
return; |
|
} if (netif_is_up(n)) { |
|
_enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n)); |
|
} else { |
|
_enqueueEvent(ZTS_EVENT_NETIF_DOWN, (void*)_lwip_prepare_netif_status_msg(n)); |
|
} |
|
} |
|
|
|
static void _netif_link_callback(struct netif *n) |
|
{ |
|
// Called from core, no need to lock |
|
if (!n) { |
|
return; |
|
} if (netif_is_link_up(n)) { |
|
_enqueueEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)_lwip_prepare_netif_status_msg(n)); |
|
} else { |
|
_enqueueEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)_lwip_prepare_netif_status_msg(n)); |
|
} |
|
} |
|
|
|
static err_t _netif_init4(struct netif *n) |
|
{ |
|
if (!n || !n->state) { |
|
return ERR_IF; |
|
} |
|
// Called from core, no need to lock |
|
VirtualTap *tap = (VirtualTap*)(n->state); |
|
n->hwaddr_len = 6; |
|
n->name[0] = '4'; |
|
n->name[1] = 'a'+netifCount; |
|
n->linkoutput = _lwip_eth_tx; |
|
n->output = etharp_output; |
|
n->mtu = std::min(LWIP_MTU,(int)tap->_mtu); |
|
n->flags = NETIF_FLAG_BROADCAST |
|
| NETIF_FLAG_ETHARP |
|
| NETIF_FLAG_ETHERNET |
|
| NETIF_FLAG_IGMP |
|
| NETIF_FLAG_MLD6 |
|
| NETIF_FLAG_LINK_UP |
|
| NETIF_FLAG_UP; |
|
n->hwaddr_len = sizeof(n->hwaddr); |
|
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); |
|
return ERR_OK; |
|
} |
|
|
|
static err_t _netif_init6(struct netif *n) |
|
{ |
|
if (!n || !n->state) { |
|
return ERR_IF; |
|
} |
|
n->hwaddr_len = sizeof(n->hwaddr); |
|
VirtualTap *tap = (VirtualTap*)(n->state); |
|
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); |
|
// Called from core, no need to lock |
|
n->hwaddr_len = 6; |
|
n->name[0] = '6'; |
|
n->name[1] = 'a'+netifCount; |
|
n->linkoutput = _lwip_eth_tx; |
|
n->output_ip6 = ethip6_output; |
|
n->mtu = std::min(LWIP_MTU,(int)tap->_mtu); |
|
n->flags = NETIF_FLAG_BROADCAST |
|
| NETIF_FLAG_ETHARP |
|
| NETIF_FLAG_ETHERNET |
|
| NETIF_FLAG_IGMP |
|
| NETIF_FLAG_MLD6 |
|
| NETIF_FLAG_LINK_UP |
|
| NETIF_FLAG_UP; |
|
return ERR_OK; |
|
} |
|
|
|
void _lwip_init_interface(void *tapref, const InetAddress &ip) |
|
{ |
|
char ipbuf[INET6_ADDRSTRLEN]; |
|
char macbuf[ZTS_MAC_ADDRSTRLEN]; |
|
|
|
VirtualTap *vtap = (VirtualTap*)tapref; |
|
struct netif *n = NULL; |
|
bool isNewNetif = false; |
|
|
|
if (ip.isV4()) { |
|
if (vtap->netif4) { |
|
n = (struct netif*)vtap->netif4; |
|
} |
|
else { |
|
n = new struct netif; |
|
isNewNetif = true; |
|
netifCount++; |
|
} |
|
/* |
|
netif_set_status_callback(n, _netif_status_callback); |
|
netif_set_remove_callback(n, _netif_remove_callback); |
|
netif_set_link_callback(n, _netif_link_callback); |
|
*/ |
|
char nmbuf[INET6_ADDRSTRLEN]; |
|
static ip4_addr_t ip4, netmask, gw; |
|
IP4_ADDR(&gw,127,0,0,1); |
|
ip4.addr = *((u32_t *)ip.rawIpData()); |
|
netmask.addr = *((u32_t *)ip.netmask().rawIpData()); |
|
LOCK_TCPIP_CORE(); |
|
netif_add(n, &ip4, &netmask, &gw, (void*)vtap, _netif_init4, tcpip_input); |
|
vtap->netif4 = (void*)n; |
|
UNLOCK_TCPIP_CORE(); |
|
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], |
|
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); |
|
//DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n, |
|
// macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap); |
|
} |
|
if (ip.isV6()) { |
|
if (vtap->netif6) { |
|
n = (struct netif*)vtap->netif6; |
|
} |
|
else { |
|
n = new struct netif; |
|
isNewNetif = true; |
|
netifCount++; |
|
}/* |
|
netif_set_status_callback(n, _netif_status_callback); |
|
netif_set_remove_callback(n, _netif_remove_callback); |
|
netif_set_link_callback(n, _netif_link_callback); |
|
*/ |
|
static ip6_addr_t ip6; |
|
memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr)); |
|
LOCK_TCPIP_CORE(); |
|
if (isNewNetif) { |
|
vtap->netif6 = (void*)n; |
|
netif_add(n, NULL, NULL, NULL, (void*)vtap, _netif_init6, ethernet_input); |
|
n->ip6_autoconfig_enabled = 1; |
|
vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len); |
|
netif_create_ip6_linklocal_address(n, 1); |
|
netif_set_link_up(n); |
|
netif_set_up(n); |
|
netif_set_default(n); |
|
} |
|
netif_add_ip6_address(n,&ip6,NULL); |
|
n->output_ip6 = ethip6_output; |
|
UNLOCK_TCPIP_CORE(); |
|
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", |
|
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], |
|
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); |
|
//DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n, |
|
// macbuf, ip.toString(ipbuf), vtap); |
|
} |
|
} |
|
|
|
void _lwip_remove_address_from_netif(void *tapref, const InetAddress &ip) |
|
{ |
|
if (!tapref) { |
|
return; |
|
} |
|
VirtualTap *vtap = (VirtualTap*)tapref; |
|
struct netif *n = NULL; |
|
/* When true multi-homing is implemented this will need to |
|
be a bit more sophisticated */ |
|
if (ip.isV4()) { |
|
if (vtap->netif4) { |
|
n = (struct netif*)vtap->netif4; |
|
} |
|
} |
|
if (ip.isV6()) { |
|
if (vtap->netif6) { |
|
n = (struct netif*)vtap->netif6; |
|
} |
|
} |
|
if (!n) { |
|
return; |
|
} |
|
_lwip_remove_netif(n); |
|
} |
|
|
|
} // namespace ZeroTier
|
|
|