2 // System.Net.NetworkInformation.NetworkInterface
5 // Gonzalo Paniagua Javier (gonzalo@novell.com)
6 // Atsushi Enomoto (atsushi@ximian.com)
7 // Miguel de Icaza (miguel@novell.com)
8 // Eric Butler (eric@extremeboredom.net)
9 // Marek Habersack (mhabersack@novell.com)
11 // Copyright (c) 2006-2008 Novell, Inc. (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections.Generic;
34 using System.Collections;
36 using System.Net.Sockets;
37 using System.Runtime.InteropServices;
40 using System.Globalization;
42 namespace System.Net.NetworkInformation {
43 public abstract class NetworkInterface {
45 internal const bool runningOnUnix = true;
47 static Version windowsVer51 = new Version (5, 1);
48 static internal readonly bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
50 protected NetworkInterface ()
54 public static NetworkInterface [] GetAllNetworkInterfaces ()
57 return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
62 return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
64 return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
65 } catch (SystemException ex) {
68 return new NetworkInterface [0];
71 if (Environment.OSVersion.Version >= windowsVer51)
72 return Win32NetworkInterface2.ImplGetAllNetworkInterfaces ();
73 return new NetworkInterface [0];
78 [MonoTODO("Always returns true")]
79 public static bool GetIsNetworkAvailable ()
84 internal static string ReadLine (string path)
86 using (FileStream fs = File.OpenRead (path)){
87 using (StreamReader sr = new StreamReader (fs)){
88 return sr.ReadLine ();
93 [MonoTODO("Only works on Linux. Returns 0 on other systems.")]
94 public static int LoopbackInterfaceIndex {
96 // Disable warning for code not reachable, due to runningOnUnix being always true on Monotouch
97 #pragma warning disable 162
100 return UnixNetworkInterface.IfNameToIndex ("lo");
106 #pragma warning restore 162
110 public abstract IPInterfaceProperties GetIPProperties ();
111 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
112 public abstract PhysicalAddress GetPhysicalAddress ();
113 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
115 public abstract string Description { get; }
116 public abstract string Id { get; }
117 public abstract bool IsReceiveOnly { get; }
118 public abstract string Name { get; }
119 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
120 public abstract OperationalStatus OperationalStatus { get; }
121 public abstract long Speed { get; }
122 public abstract bool SupportsMulticast { get; }
125 abstract class UnixNetworkInterface : NetworkInterface
128 static extern int if_nametoindex(string ifname);
130 protected IPv4InterfaceStatistics ipv4stats;
131 protected IPInterfaceProperties ipproperties;
135 protected List <IPAddress> addresses;
137 NetworkInterfaceType type;
139 internal UnixNetworkInterface (string name)
142 addresses = new List<IPAddress> ();
145 public static int IfNameToIndex (string ifname)
147 return if_nametoindex(ifname);
150 internal void AddAddress (IPAddress address)
152 addresses.Add (address);
155 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
157 //this.index = index;
158 this.macAddress = macAddress;
162 public override PhysicalAddress GetPhysicalAddress ()
164 if (macAddress != null)
165 return new PhysicalAddress (macAddress);
167 return PhysicalAddress.None;
170 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
172 bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
173 bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
175 foreach (IPAddress address in addresses) {
176 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
178 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
185 public override string Description {
189 public override string Id {
193 public override bool IsReceiveOnly {
194 get { return false; }
197 public override string Name {
201 public override NetworkInterfaceType NetworkInterfaceType {
205 [MonoTODO ("Parse dmesg?")]
206 public override long Speed {
215 // This class needs support from the libsupport.so library to fetch the
216 // data using arch-specific ioctls.
218 // For this to work, we have to create this on the factory above.
220 class LinuxNetworkInterface : UnixNetworkInterface
223 static extern int getifaddrs (out IntPtr ifap);
226 static extern void freeifaddrs (IntPtr ifap);
228 const int AF_INET = 2;
229 const int AF_INET6 = 10;
230 const int AF_PACKET = 17;
232 //NetworkInterfaceType type;
234 string iface_operstate_path;
235 string iface_flags_path;
237 internal string IfacePath {
238 get { return iface_path; }
241 static int GetInterfaceAddresses (out IntPtr ifap)
244 return AndroidPlatform.GetInterfaceAddresses (out ifap);
246 return getifaddrs (out ifap);
250 static void FreeInterfaceAddresses (IntPtr ifap)
253 AndroidPlatform.FreeInterfaceAddresses (ifap);
259 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
261 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
263 if (GetInterfaceAddresses (out ifap) != 0)
264 throw new SystemException ("getifaddrs() failed");
268 while (next != IntPtr.Zero) {
269 ifaddrs addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
270 IPAddress address = IPAddress.None;
271 string name = addr.ifa_name;
273 byte[] macAddress = null;
274 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
275 int nullNameCount = 0;
277 if (addr.ifa_addr != IntPtr.Zero) {
278 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
280 if (sockaddr.sin_family == AF_INET6) {
281 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
282 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
283 } else if (sockaddr.sin_family == AF_INET) {
284 address = new IPAddress (sockaddr.sin_addr);
285 } else if (sockaddr.sin_family == AF_PACKET) {
286 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
287 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
288 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
289 sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
290 next = addr.ifa_next;
294 macAddress = new byte [(int) sockaddrll.sll_halen];
295 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
296 index = sockaddrll.sll_ifindex;
298 int hwtype = (int)sockaddrll.sll_hatype;
299 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
300 switch ((LinuxArpHardware)hwtype) {
301 case LinuxArpHardware.EETHER:
302 goto case LinuxArpHardware.ETHER;
304 case LinuxArpHardware.ETHER:
305 type = NetworkInterfaceType.Ethernet;
308 case LinuxArpHardware.PRONET:
309 type = NetworkInterfaceType.TokenRing;
312 case LinuxArpHardware.ATM:
313 type = NetworkInterfaceType.Atm;
316 case LinuxArpHardware.SLIP:
317 case LinuxArpHardware.CSLIP:
318 case LinuxArpHardware.SLIP6:
319 case LinuxArpHardware.CSLIP6:
320 type = NetworkInterfaceType.Slip;
323 case LinuxArpHardware.PPP:
324 type = NetworkInterfaceType.Ppp;
327 case LinuxArpHardware.LOOPBACK:
328 type = NetworkInterfaceType.Loopback;
332 case LinuxArpHardware.FDDI:
333 type = NetworkInterfaceType.Fddi;
336 case LinuxArpHardware.SIT:
337 case LinuxArpHardware.IPDDP:
338 case LinuxArpHardware.IPGRE:
339 case LinuxArpHardware.IP6GRE:
340 case LinuxArpHardware.TUNNEL6:
341 case LinuxArpHardware.TUNNEL:
342 type = NetworkInterfaceType.Tunnel;
349 LinuxNetworkInterface iface = null;
351 if (String.IsNullOrEmpty (name))
352 name = "\0" + (++nullNameCount).ToString ();
354 if (!interfaces.TryGetValue (name, out iface)) {
355 iface = new LinuxNetworkInterface (name);
356 interfaces.Add (name, iface);
359 if (!address.Equals (IPAddress.None))
360 iface.AddAddress (address);
362 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
363 if (type == NetworkInterfaceType.Ethernet) {
364 if (Directory.Exists(iface.IfacePath + "wireless")) {
365 type = NetworkInterfaceType.Wireless80211;
368 iface.SetLinkLayerInfo (index, macAddress, type);
371 next = addr.ifa_next;
374 FreeInterfaceAddresses (ifap);
377 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
379 foreach (NetworkInterface thisInterface in interfaces.Values) {
380 result [x] = thisInterface;
386 LinuxNetworkInterface (string name)
389 iface_path = "/sys/class/net/" + name + "/";
390 iface_operstate_path = iface_path + "operstate";
391 iface_flags_path = iface_path + "flags";
394 public override IPInterfaceProperties GetIPProperties ()
396 if (ipproperties == null)
397 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
401 public override IPv4InterfaceStatistics GetIPv4Statistics ()
403 if (ipv4stats == null)
404 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
408 public override OperationalStatus OperationalStatus {
410 if (!Directory.Exists (iface_path))
411 return OperationalStatus.Unknown;
414 string s = ReadLine (iface_operstate_path);
418 return OperationalStatus.Unknown;
421 return OperationalStatus.NotPresent;
424 return OperationalStatus.Down;
426 case "lowerlayerdown":
427 return OperationalStatus.LowerLayerDown;
430 return OperationalStatus.Testing;
433 return OperationalStatus.Dormant;
436 return OperationalStatus.Up;
440 return OperationalStatus.Unknown;
444 public override bool SupportsMulticast {
446 if (!Directory.Exists (iface_path))
450 string s = ReadLine (iface_flags_path);
451 if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
454 ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
456 // Hardcoded, only useful for Linux.
457 return ((f & 0x1000) == 0x1000);
465 class MacOsNetworkInterface : UnixNetworkInterface
468 static extern int getifaddrs (out IntPtr ifap);
471 static extern void freeifaddrs (IntPtr ifap);
473 const int AF_INET = 2;
474 const int AF_INET6 = 30;
475 const int AF_LINK = 18;
477 private uint _ifa_flags;
479 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
481 var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
483 if (getifaddrs (out ifap) != 0)
484 throw new SystemException ("getifaddrs() failed");
488 while (next != IntPtr.Zero) {
489 MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
490 IPAddress address = IPAddress.None;
491 string name = addr.ifa_name;
493 byte[] macAddress = null;
494 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
496 if (addr.ifa_addr != IntPtr.Zero) {
498 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
500 if (sockaddr.sa_family == AF_INET6) {
501 MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
502 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
503 } else if (sockaddr.sa_family == AF_INET) {
504 MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
505 address = new IPAddress (sockaddrin.sin_addr);
506 } else if (sockaddr.sa_family == AF_LINK) {
507 MacOsStructs.sockaddr_dl sockaddrdl = new MacOsStructs.sockaddr_dl ();
508 sockaddrdl.Read (addr.ifa_addr);
510 macAddress = new byte [(int) sockaddrdl.sdl_alen];
511 // copy mac address from sdl_data field starting at last index pos of interface name into array macaddress, starting
513 Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
515 index = sockaddrdl.sdl_index;
517 int hwtype = (int) sockaddrdl.sdl_type;
518 if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
519 switch ((MacOsArpHardware) hwtype) {
520 case MacOsArpHardware.ETHER:
521 type = NetworkInterfaceType.Ethernet;
524 case MacOsArpHardware.ATM:
525 type = NetworkInterfaceType.Atm;
528 case MacOsArpHardware.SLIP:
529 type = NetworkInterfaceType.Slip;
532 case MacOsArpHardware.PPP:
533 type = NetworkInterfaceType.Ppp;
536 case MacOsArpHardware.LOOPBACK:
537 type = NetworkInterfaceType.Loopback;
541 case MacOsArpHardware.FDDI:
542 type = NetworkInterfaceType.Fddi;
549 MacOsNetworkInterface iface = null;
551 // create interface if not already present
552 if (!interfaces.TryGetValue (name, out iface)) {
553 iface = new MacOsNetworkInterface (name, addr.ifa_flags);
554 interfaces.Add (name, iface);
557 // if a new address has been found, add it
558 if (!address.Equals (IPAddress.None))
559 iface.AddAddress (address);
561 // set link layer info, if iface has macaddress or is loopback device
562 if (macAddress != null || type == NetworkInterfaceType.Loopback)
563 iface.SetLinkLayerInfo (index, macAddress, type);
565 next = addr.ifa_next;
571 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
573 foreach (NetworkInterface thisInterface in interfaces.Values) {
574 result [x] = thisInterface;
580 MacOsNetworkInterface (string name, uint ifa_flags)
583 _ifa_flags = ifa_flags;
586 public override IPInterfaceProperties GetIPProperties ()
588 if (ipproperties == null)
589 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
593 public override IPv4InterfaceStatistics GetIPv4Statistics ()
595 if (ipv4stats == null)
596 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
600 public override OperationalStatus OperationalStatus {
602 if(((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_UP) == MacOsInterfaceFlags.IFF_UP){
603 return OperationalStatus.Up;
605 return OperationalStatus.Unknown;
609 public override bool SupportsMulticast {
611 return ((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_MULTICAST) == MacOsInterfaceFlags.IFF_MULTICAST;
616 class Win32NetworkInterface2 : NetworkInterface
618 [DllImport ("iphlpapi.dll", SetLastError = true)]
619 static extern int GetAdaptersInfo (byte [] info, ref int size);
621 [DllImport ("iphlpapi.dll", SetLastError = true)]
622 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
624 [DllImport ("iphlpapi.dll", SetLastError = true)]
625 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
627 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
629 // Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
630 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
631 NetworkInterface [] ret = new NetworkInterface [aa.Length];
632 for (int i = 0; i < ret.Length; i++)
633 ret [i] = new Win32NetworkInterface2 (aa [i]);
637 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
639 foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
640 if (info.Index == index)
645 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
647 byte [] bytes = null;
649 GetAdaptersInfo (bytes, ref len);
650 bytes = new byte [len];
651 int ret = GetAdaptersInfo (bytes, ref len);
654 throw new NetworkInformationException (ret);
656 List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
657 fixed (byte* ptr = bytes) {
658 Win32_IP_ADAPTER_INFO info;
659 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
660 info = new Win32_IP_ADAPTER_INFO ();
661 Marshal.PtrToStructure (p, info);
668 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
670 byte [] bytes = null;
672 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
673 bytes = new byte [len];
674 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
676 throw new NetworkInformationException (ret);
678 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
679 fixed (byte* ptr = bytes) {
680 Win32_IP_ADAPTER_ADDRESSES info;
681 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
682 info = new Win32_IP_ADAPTER_ADDRESSES ();
683 Marshal.PtrToStructure (p, info);
690 Win32_IP_ADAPTER_ADDRESSES addr;
691 Win32_MIB_IFROW mib4, mib6;
692 Win32IPv4InterfaceStatistics ip4stats;
693 IPInterfaceProperties ip_if_props;
695 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
698 mib4 = default (Win32_MIB_IFROW);
699 mib4.Index = addr.Alignment.IfIndex;
700 if (GetIfEntry (ref mib4) != 0)
701 mib4.Index = -1; // unavailable;
702 mib6 = default (Win32_MIB_IFROW);
703 mib6.Index = addr.Ipv6IfIndex;
704 if (GetIfEntry (ref mib6) != 0)
705 mib6.Index = -1; // unavailable;
706 ip4stats = new Win32IPv4InterfaceStatistics (mib4);
707 ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
710 public override IPInterfaceProperties GetIPProperties ()
715 public override IPv4InterfaceStatistics GetIPv4Statistics ()
720 public override PhysicalAddress GetPhysicalAddress ()
722 byte [] bytes = new byte [addr.PhysicalAddressLength];
723 Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
724 return new PhysicalAddress (bytes);
727 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
729 switch (networkInterfaceComponent) {
730 case NetworkInterfaceComponent.IPv4:
731 return mib4.Index >= 0;
732 case NetworkInterfaceComponent.IPv6:
733 return mib6.Index >= 0;
738 public override string Description {
739 get { return addr.Description; }
741 public override string Id {
742 get { return addr.AdapterName; }
744 public override bool IsReceiveOnly {
745 get { return addr.IsReceiveOnly; }
747 public override string Name {
748 get { return addr.FriendlyName; }
750 public override NetworkInterfaceType NetworkInterfaceType {
751 get { return addr.IfType; }
753 public override OperationalStatus OperationalStatus {
754 get { return addr.OperStatus; }
756 public override long Speed {
757 get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
759 public override bool SupportsMulticast {
760 get { return !addr.NoMulticast; }