From c6d03ef17f34f7380d95e91a6091a06bce332979 Mon Sep 17 00:00:00 2001
From: Mathias Hall-Andersen <mathias@hall-andersen.dk>
Date: Tue, 22 Aug 2017 14:57:32 +0200
Subject: [PATCH] Update MTU based on netlink messages (linux)

---
 src/device.go    | 37 -------------------------------------
 src/tun.go       | 44 +++++++++++++++++++++++++++++++++++++++++---
 src/tun_linux.go |  3 ++-
 3 files changed, 43 insertions(+), 41 deletions(-)

diff --git a/src/device.go b/src/device.go
index 9bcd2f5..2a0d0ca 100644
--- a/src/device.go
+++ b/src/device.go
@@ -176,43 +176,6 @@ func NewDevice(tun TUNDevice, logLevel int) *Device {
 	return device
 }
 
-func (device *Device) RoutineTUNEventReader() {
-	logInfo := device.log.Info
-	logError := device.log.Error
-
-	events := device.tun.device.Events()
-
-	for event := range events {
-		if event&TUNEventMTUUpdate != 0 {
-			mtu, err := device.tun.device.MTU()
-			if err != nil {
-				logError.Println("Failed to load updated MTU of device:", err)
-			} else {
-				if mtu+MessageTransportSize > MaxMessageSize {
-					mtu = MaxMessageSize - MessageTransportSize
-				}
-				atomic.StoreInt32(&device.tun.mtu, int32(mtu))
-			}
-		}
-
-		if event&TUNEventUp != 0 {
-			if !device.tun.isUp.Get() {
-				device.tun.isUp.Set(true)
-				updateUDPConn(device)
-				logInfo.Println("Interface set up")
-			}
-		}
-
-		if event&TUNEventDown != 0 {
-			if device.tun.isUp.Get() {
-				device.tun.isUp.Set(false)
-				closeUDPConn(device)
-				logInfo.Println("Interface set down")
-			}
-		}
-	}
-}
-
 func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
 	device.mutex.RLock()
 	defer device.mutex.RUnlock()
diff --git a/src/tun.go b/src/tun.go
index 1c4c281..b4fbc62 100644
--- a/src/tun.go
+++ b/src/tun.go
@@ -1,8 +1,8 @@
 package main
 
-/*
- * The default MTU of the new device must be 1420
- */
+import (
+	"sync/atomic"
+)
 
 const DefaultMTU = 1420
 
@@ -22,3 +22,41 @@ type TUNDevice interface {
 	Events() chan TUNEvent     // returns a constant channel of events related to the device
 	Close() error              // stops the device and closes the event channel
 }
+
+func (device *Device) RoutineTUNEventReader() {
+	logInfo := device.log.Info
+	logError := device.log.Error
+
+	for event := range device.tun.device.Events() {
+		if event&TUNEventMTUUpdate != 0 {
+			mtu, err := device.tun.device.MTU()
+			old := atomic.LoadInt32(&device.tun.mtu)
+			if err != nil {
+				logError.Println("Failed to load updated MTU of device:", err)
+			} else if int(old) != mtu {
+				atomic.StoreInt32(&device.tun.mtu, int32(mtu))
+				if mtu+MessageTransportSize > MaxMessageSize {
+					logInfo.Println("MTU updated:", mtu, "(too large)")
+				} else {
+					logInfo.Println("MTU updated:", mtu)
+				}
+			}
+		}
+
+		if event&TUNEventUp != 0 {
+			if !device.tun.isUp.Get() {
+				device.tun.isUp.Set(true)
+				updateUDPConn(device)
+				logInfo.Println("Interface set up")
+			}
+		}
+
+		if event&TUNEventDown != 0 {
+			if device.tun.isUp.Get() {
+				device.tun.isUp.Set(false)
+				closeUDPConn(device)
+				logInfo.Println("Interface set down")
+			}
+		}
+	}
+}
diff --git a/src/tun_linux.go b/src/tun_linux.go
index e752733..b9541c9 100644
--- a/src/tun_linux.go
+++ b/src/tun_linux.go
@@ -85,6 +85,7 @@ func (tun *NativeTun) RoutineNetlinkListener() {
 
 			case unix.RTM_NEWLINK:
 				info := *(*unix.IfInfomsg)(unsafe.Pointer(&remain[unix.SizeofNlMsghdr]))
+				remain = remain[hdr.Len:]
 
 				if info.Index != tun.index {
 					// not our interface
@@ -99,7 +100,7 @@ func (tun *NativeTun) RoutineNetlinkListener() {
 					tun.events <- TUNEventDown
 				}
 
-				remain = remain[hdr.Len:]
+				tun.events <- TUNEventMTUUpdate
 
 			default:
 				remain = remain[hdr.Len:]