1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 #if PLATFORM_LINUX 9 using System; 10 using System.Runtime.InteropServices; 11 using System.Text; 12 using Mono.Unix.Native; 13 using Mono.Unix; 14 using Antmicro.Renode.Utilities; 15 using System.Net.NetworkInformation; 16 using Antmicro.Renode.Logging; 17 18 namespace Antmicro.Renode.TAPHelper 19 { 20 public class TAPTools 21 { 22 private const int O_RDWR = 2; 23 private const int IFNAMSIZ = 0x10; 24 private const int TUNSETIFF = 1074025674; 25 private const int TUNSETPERSIST = 0x400454cb; 26 private const UInt16 IFF_TUN = 0x1; 27 private const UInt16 IFF_TAP_IFF_NO_PI = 0x0002 | 0x1000; 28 private const int IFR_SIZE = 80; 29 30 private const int SIOCSIFFLAGS = 0x8914; 31 private const int SIOCGIFFLAGS = 0x8913; 32 private const UInt16 IFF_UP = 1; 33 DoesInterfaceExist(string name)34 private static bool DoesInterfaceExist(string name) 35 { 36 var ifaces = NetworkInterface.GetAllNetworkInterfaces(); 37 foreach(var iface in ifaces) 38 { 39 if(iface.Name == name) 40 { 41 return true; 42 } 43 } 44 return false; 45 } 46 Up_TUNTAP(IntPtr ifrIn)47 private static int Up_TUNTAP(IntPtr ifrIn) 48 { 49 int err = 0; 50 51 // Bring TAP up - we need to create a regular socket for this 52 int sock = LibCWrapper.Socket(2, 2, 0); //AF_INET, SOCK_DGRAM 53 if(sock == -1) 54 { 55 Logger.Log(LogLevel.Debug, "Could not create ioctl socket, error {0}", Marshal.GetLastWin32Error()); 56 return sock; 57 } 58 59 // make copy of ifrIn, so our ioctls don't clobber the donor 60 var ifr = Marshal.AllocHGlobal(IFR_SIZE); 61 LibCWrapper.Strcpy(ifr, ifrIn); 62 try 63 { 64 if((err = LibCWrapper.Ioctl(sock, SIOCGIFFLAGS, ifr)) < 0) 65 { 66 Logger.Log(LogLevel.Debug, "Could not get flags on TUN/TAP interface, error {0}", Marshal.GetLastWin32Error()); 67 return err; 68 } 69 70 var currentFlags = BitConverter.ToUInt16(Marshal.ReadInt16(ifr, IFNAMSIZ).AsRawBytes(), 0); 71 72 // Only try this if TAP is down 73 if((currentFlags & IFF_UP) == 0) 74 { 75 currentFlags |= IFF_UP; 76 Marshal.WriteInt16(ifr, IFNAMSIZ, BitConverter.ToInt16(currentFlags.AsRawBytes(), 0)); 77 78 if((err = LibCWrapper.Ioctl(sock, SIOCSIFFLAGS, ifr)) < 0) 79 { 80 Logger.Log(LogLevel.Debug, "Could not activate TUN/TAP interface, error {0}", Marshal.GetLastWin32Error()); 81 return err; 82 } 83 } 84 } 85 finally 86 { 87 LibCWrapper.Close(sock); 88 Marshal.FreeHGlobal(ifr); 89 } 90 91 return err; 92 } 93 Open_TUNTAP(IntPtr dev, UInt16 flags, bool persistent)94 private static int Open_TUNTAP(IntPtr dev, UInt16 flags, bool persistent) 95 { 96 var fd = LibCWrapper.Open("/dev/net/tun", O_RDWR); 97 if(fd < 0) 98 { 99 Logger.Log(LogLevel.Debug, "Could not open /dev/net/tun, error: {0}", Marshal.GetLastWin32Error()); 100 return fd; 101 } 102 103 var ifr = Marshal.AllocHGlobal(IFR_SIZE); // we need 40 bytes, but we allocate a bit more 104 try 105 { 106 var memory = new byte[IFR_SIZE]; 107 Array.Clear(memory, 0, IFR_SIZE); 108 109 var bytes = BitConverter.GetBytes(flags); 110 Array.Copy(bytes, 0, memory, IFNAMSIZ, 2); 111 112 bool exists = false; 113 if(dev != IntPtr.Zero) 114 { 115 string devname = Marshal.PtrToStringAnsi(dev); 116 exists = DoesInterfaceExist(devname); 117 118 var devBytes = Encoding.ASCII.GetBytes(devname); 119 Array.Copy(devBytes, memory, Math.Min(devBytes.Length, IFNAMSIZ)); 120 } 121 122 Marshal.Copy(memory, 0, ifr, IFR_SIZE); 123 124 int err = 0; 125 if((err = LibCWrapper.Ioctl(fd, TUNSETIFF, ifr)) < 0) 126 { 127 Logger.Log(LogLevel.Debug, "Could not set TUNSETIFF, error: {0}", Marshal.GetLastWin32Error()); 128 LibCWrapper.Close(fd); 129 return err; 130 } 131 132 if(persistent) 133 { 134 if((err = LibCWrapper.Ioctl(fd, TUNSETPERSIST, 1)) < 0) 135 { 136 Logger.Log(LogLevel.Debug, "Could not set TUNSETPERSIST, error: {0}", Marshal.GetLastWin32Error()); 137 LibCWrapper.Close(fd); 138 return err; 139 } 140 } 141 142 // If TAP was created by us, we try to bring it up 143 if(!exists) 144 { 145 if((err = Up_TUNTAP(ifr)) < 0) 146 { 147 Logger.Log(LogLevel.Debug, "Could not bring device up, do it manually."); 148 LibCWrapper.Close(fd); 149 return err; 150 } 151 } 152 153 LibCWrapper.Strcpy(dev, ifr); 154 } 155 finally 156 { 157 Marshal.FreeHGlobal(ifr); 158 } 159 160 return fd; 161 } 162 OpenTUN(IntPtr dev, bool persistent = false)163 public static int OpenTUN(IntPtr dev, bool persistent = false) 164 { 165 return Open_TUNTAP(dev, IFF_TUN, persistent); 166 } 167 OpenTAP(IntPtr dev, bool persistent = false)168 public static int OpenTAP(IntPtr dev, bool persistent = false) 169 { 170 return Open_TUNTAP(dev, IFF_TAP_IFF_NO_PI, persistent); 171 } 172 } 173 } 174 #endif 175