Преглед на файлове

potential fix for 2.6.x kernels

detect if the kernel is super old.  if so, do not execute the post IF_UP commands on the interface
Grant Limberg преди 3 години
родител
ревизия
fdf4ebd43c
променени са 1 файла, в които са добавени 54 реда и са изтрити 12 реда
  1. 54 12
      osdep/LinuxEthernetTap.cpp

+ 54 - 12
osdep/LinuxEthernetTap.cpp

@@ -52,6 +52,10 @@
 #include <utility>
 #include <string>
 
+#include <ctype.h>
+#include <sys/utsname.h>
+
+
 #ifndef IFNAMSIZ
 #define IFNAMSIZ 16
 #endif
@@ -63,6 +67,35 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
 
 namespace ZeroTier {
 
+// determine if we're running a really old linux kernel.
+// Kernels in the 2.6.x series don't behave the same when bringing up 
+// the tap devices.
+//
+// Returns true if the kernel major version is < 3
+bool isOldLinuxKernel() {
+	struct utsname buffer;
+	char *p;
+	long ver[16];
+	int i = 0;
+	if (uname(&buffer) != 0) {
+		perror("uname");
+		exit(EXIT_FAILURE);
+	}
+
+	p = buffer.release;
+
+    while (*p) {
+        if (isdigit(*p)) {
+            ver[i] = strtol(p, &p, 10);
+            i++;
+        } else {
+            p++;
+        }
+    }
+
+	return ver[0] < 3;
+}
+
 static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' };
 static void _base32_5_to_8(const uint8_t *in,char *out)
 {
@@ -213,6 +246,13 @@ LinuxEthernetTap::LinuxEthernetTap(
 			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;
+		}
+
 		usleep(100000);
 
 		ifr.ifr_flags |= IFF_MULTICAST;
@@ -225,19 +265,21 @@ LinuxEthernetTap::LinuxEthernetTap(
 
 		usleep(100000);
 
-		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;
-		}
+		if (!isLinuxV2OrLess()) {
+			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;
+			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;
+			}
 		}
 
 		fcntl(_fd,F_SETFL,O_NONBLOCK);