|
|
|
|
@ -167,63 +167,8 @@ LinuxEthernetTap::LinuxEthernetTap(
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
|
|
|
|
|
|
|
|
|
|
const int sock = socket(AF_INET,SOCK_DGRAM,0); |
|
|
|
|
if (sock <= 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
throw std::runtime_error("unable to open netlink socket"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_dev = ifr.ifr_name; |
|
|
|
|
|
|
|
|
|
// Set/check loop is a workaround for a weird likely kernel bug in which
|
|
|
|
|
// the interface doesn't come up right away when set to up. This causes
|
|
|
|
|
// settings like the MAC address to not "take."
|
|
|
|
|
for(;;) { |
|
|
|
|
if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
::close(sock); |
|
|
|
|
throw std::runtime_error("unable to get TAP interface flags"); |
|
|
|
|
} |
|
|
|
|
ifr.ifr_flags |= IFF_UP; |
|
|
|
|
if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
::close(sock); |
|
|
|
|
throw std::runtime_error("unable to bring up TAP interface"); |
|
|
|
|
} |
|
|
|
|
if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
::close(sock); |
|
|
|
|
throw std::runtime_error("unable to get TAP interface flags"); |
|
|
|
|
} |
|
|
|
|
usleep(1000); |
|
|
|
|
if ((ifr.ifr_flags & IFF_UP) != 0) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; |
|
|
|
|
mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6); |
|
|
|
|
if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
::close(sock); |
|
|
|
|
throw std::runtime_error("unable to configure TAP hardware (MAC) address"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ifr.ifr_ifru.ifru_mtu = (int)mtu; |
|
|
|
|
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { |
|
|
|
|
::close(_fd); |
|
|
|
|
::close(sock); |
|
|
|
|
throw std::runtime_error("unable to configure TAP MTU"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { |
|
|
|
|
::close(_fd); |
|
|
|
|
throw std::runtime_error("unable to set flags on file descriptor for TAP device"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
::close(sock); |
|
|
|
|
|
|
|
|
|
// Set close-on-exec so that devices cannot persist if we fork/exec for update
|
|
|
|
|
::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); |
|
|
|
|
|
|
|
|
|
@ -460,7 +405,55 @@ void LinuxEthernetTap::threadMain()
|
|
|
|
|
int n,nfds,r; |
|
|
|
|
char getBuf[ZT_MAX_MTU + 64]; |
|
|
|
|
|
|
|
|
|
Thread::sleep(500); |
|
|
|
|
Thread::sleep(100); |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
struct ifreq ifr; |
|
|
|
|
memset(&ifr,0,sizeof(ifr)); |
|
|
|
|
|
|
|
|
|
strcpy(ifr.ifr_name,_dev.c_str()); |
|
|
|
|
|
|
|
|
|
const int sock = socket(AF_INET,SOCK_DGRAM,0); |
|
|
|
|
if (sock <= 0) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) { |
|
|
|
|
::close(sock); |
|
|
|
|
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
ifr.ifr_flags |= IFF_UP; |
|
|
|
|
if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) { |
|
|
|
|
::close(sock); |
|
|
|
|
printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Thread::sleep(500); |
|
|
|
|
|
|
|
|
|
ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; |
|
|
|
|
mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6); |
|
|
|
|
if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) { |
|
|
|
|
::close(sock); |
|
|
|
|
printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ifr.ifr_ifru.ifru_mtu = (int)mtu; |
|
|
|
|
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { |
|
|
|
|
::close(sock); |
|
|
|
|
printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { |
|
|
|
|
::close(sock); |
|
|
|
|
printf("WARNING: ioctl() failed setting up Linux tap device (set non-blocking)\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
::close(sock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FD_ZERO(&readfds); |
|
|
|
|
FD_ZERO(&nullfds); |
|
|
|
|
|