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.
34 using System.Collections.Generic;
35 using System.Collections;
37 using System.Net.Sockets;
38 using System.Runtime.InteropServices;
41 using System.Globalization;
43 namespace System.Net.NetworkInformation {
44 public abstract class NetworkInterface {
45 static Version windowsVer51 = new Version (5, 1);
46 static internal readonly bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
48 protected NetworkInterface ()
52 public static NetworkInterface [] GetAllNetworkInterfaces ()
57 return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
59 return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
60 } catch (SystemException ex) {
63 return new NetworkInterface [0];
66 if (Environment.OSVersion.Version >= windowsVer51)
67 return Win32NetworkInterface2.ImplGetAllNetworkInterfaces ();
68 return new NetworkInterface [0];
72 [MonoTODO("Always returns true")]
73 public static bool GetIsNetworkAvailable ()
78 internal static string ReadLine (string path)
80 using (FileStream fs = File.OpenRead (path)){
81 using (StreamReader sr = new StreamReader (fs)){
82 return sr.ReadLine ();
87 [MonoTODO("Only works on Linux. Returns 0 on other systems.")]
88 public static int LoopbackInterfaceIndex {
92 return UnixNetworkInterface.IfNameToIndex ("lo");
101 public abstract IPInterfaceProperties GetIPProperties ();
102 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
103 public abstract PhysicalAddress GetPhysicalAddress ();
104 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
106 public abstract string Description { get; }
107 public abstract string Id { get; }
108 public abstract bool IsReceiveOnly { get; }
109 public abstract string Name { get; }
110 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
111 public abstract OperationalStatus OperationalStatus { get; }
112 public abstract long Speed { get; }
113 public abstract bool SupportsMulticast { get; }
116 abstract class UnixNetworkInterface : NetworkInterface
119 static extern int if_nametoindex(string ifname);
121 protected IPv4InterfaceStatistics ipv4stats;
122 protected IPInterfaceProperties ipproperties;
126 protected List <IPAddress> addresses;
128 NetworkInterfaceType type;
130 internal UnixNetworkInterface (string name)
133 addresses = new List<IPAddress> ();
136 public static int IfNameToIndex (string ifname)
138 return if_nametoindex(ifname);
141 internal void AddAddress (IPAddress address)
143 addresses.Add (address);
146 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
148 //this.index = index;
149 this.macAddress = macAddress;
153 public override PhysicalAddress GetPhysicalAddress ()
155 if (macAddress != null)
156 return new PhysicalAddress (macAddress);
158 return PhysicalAddress.None;
161 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
163 bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
164 bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
166 foreach (IPAddress address in addresses) {
167 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
169 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
176 public override string Description {
180 public override string Id {
184 public override bool IsReceiveOnly {
185 get { return false; }
188 public override string Name {
192 public override NetworkInterfaceType NetworkInterfaceType {
196 [MonoTODO ("Parse dmesg?")]
197 public override long Speed {
206 // This class needs support from the libsupport.so library to fetch the
207 // data using arch-specific ioctls.
209 // For this to work, we have to create this on the factory above.
211 class LinuxNetworkInterface : UnixNetworkInterface
214 static extern int getifaddrs (out IntPtr ifap);
217 static extern void freeifaddrs (IntPtr ifap);
219 const int AF_INET = 2;
220 const int AF_INET6 = 10;
221 const int AF_PACKET = 17;
223 //NetworkInterfaceType type;
225 string iface_operstate_path;
226 string iface_flags_path;
228 internal string IfacePath {
229 get { return iface_path; }
232 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
234 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
236 if (getifaddrs (out ifap) != 0)
237 throw new SystemException ("getifaddrs() failed");
241 while (next != IntPtr.Zero) {
242 ifaddrs addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
243 IPAddress address = IPAddress.None;
244 string name = addr.ifa_name;
246 byte[] macAddress = null;
247 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
249 if (addr.ifa_addr != IntPtr.Zero) {
250 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
252 if (sockaddr.sin_family == AF_INET6) {
253 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
254 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
255 } else if (sockaddr.sin_family == AF_INET) {
256 address = new IPAddress (sockaddr.sin_addr);
257 } else if (sockaddr.sin_family == AF_PACKET) {
258 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
259 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
260 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
261 sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
262 next = addr.ifa_next;
266 macAddress = new byte [(int) sockaddrll.sll_halen];
267 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
268 index = sockaddrll.sll_ifindex;
270 int hwtype = (int)sockaddrll.sll_hatype;
271 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
272 switch ((LinuxArpHardware)hwtype) {
273 case LinuxArpHardware.EETHER:
274 goto case LinuxArpHardware.ETHER;
276 case LinuxArpHardware.ETHER:
277 type = NetworkInterfaceType.Ethernet;
280 case LinuxArpHardware.PRONET:
281 type = NetworkInterfaceType.TokenRing;
284 case LinuxArpHardware.ATM:
285 type = NetworkInterfaceType.Atm;
288 case LinuxArpHardware.SLIP:
289 type = NetworkInterfaceType.Slip;
292 case LinuxArpHardware.PPP:
293 type = NetworkInterfaceType.Ppp;
296 case LinuxArpHardware.LOOPBACK:
297 type = NetworkInterfaceType.Loopback;
301 case LinuxArpHardware.FDDI:
302 type = NetworkInterfaceType.Fddi;
305 case LinuxArpHardware.TUNNEL6:
306 goto case LinuxArpHardware.TUNNEL;
308 case LinuxArpHardware.TUNNEL:
309 type = NetworkInterfaceType.Tunnel;
316 LinuxNetworkInterface iface = null;
318 if (!interfaces.TryGetValue (name, out iface)) {
319 iface = new LinuxNetworkInterface (name);
320 interfaces.Add (name, iface);
323 if (!address.Equals (IPAddress.None))
324 iface.AddAddress (address);
326 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
327 if (type == NetworkInterfaceType.Ethernet) {
328 if (Directory.Exists(iface.IfacePath + "wireless")) {
329 type = NetworkInterfaceType.Wireless80211;
332 iface.SetLinkLayerInfo (index, macAddress, type);
335 next = addr.ifa_next;
341 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
343 foreach (NetworkInterface thisInterface in interfaces.Values) {
344 result [x] = thisInterface;
350 LinuxNetworkInterface (string name)
353 iface_path = "/sys/class/net/" + name + "/";
354 iface_operstate_path = iface_path + "operstate";
355 iface_flags_path = iface_path + "flags";
358 public override IPInterfaceProperties GetIPProperties ()
360 if (ipproperties == null)
361 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
365 public override IPv4InterfaceStatistics GetIPv4Statistics ()
367 if (ipv4stats == null)
368 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
372 public override OperationalStatus OperationalStatus {
374 if (!Directory.Exists (iface_path))
375 return OperationalStatus.Unknown;
378 string s = ReadLine (iface_operstate_path);
382 return OperationalStatus.Unknown;
385 return OperationalStatus.NotPresent;
388 return OperationalStatus.Down;
390 case "lowerlayerdown":
391 return OperationalStatus.LowerLayerDown;
394 return OperationalStatus.Testing;
397 return OperationalStatus.Dormant;
400 return OperationalStatus.Up;
404 return OperationalStatus.Unknown;
408 public override bool SupportsMulticast {
410 if (!Directory.Exists (iface_path))
414 string s = ReadLine (iface_flags_path);
415 if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
418 ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
420 // Hardcoded, only useful for Linux.
421 return ((f & 0x1000) == 0x1000);
429 class MacOsNetworkInterface : UnixNetworkInterface
432 static extern int getifaddrs (out IntPtr ifap);
435 static extern void freeifaddrs (IntPtr ifap);
437 const int AF_INET = 2;
438 const int AF_INET6 = 30;
439 const int AF_LINK = 18;
441 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
443 var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
445 if (getifaddrs (out ifap) != 0)
446 throw new SystemException ("getifaddrs() failed");
450 while (next != IntPtr.Zero) {
451 MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
452 IPAddress address = IPAddress.None;
453 string name = addr.ifa_name;
455 byte[] macAddress = null;
456 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
458 if (addr.ifa_addr != IntPtr.Zero) {
459 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
461 if (sockaddr.sa_family == AF_INET6) {
462 MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
463 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
464 } else if (sockaddr.sa_family == AF_INET) {
465 MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
466 address = new IPAddress (sockaddrin.sin_addr);
467 } else if (sockaddr.sa_family == AF_LINK) {
468 MacOsStructs.sockaddr_dl sockaddrdl = (MacOsStructs.sockaddr_dl) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_dl));
470 macAddress = new byte [(int) sockaddrdl.sdl_alen];
471 Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
472 index = sockaddrdl.sdl_index;
474 int hwtype = (int) sockaddrdl.sdl_type;
475 if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
476 switch ((MacOsArpHardware) hwtype) {
477 case MacOsArpHardware.ETHER:
478 type = NetworkInterfaceType.Ethernet;
481 case MacOsArpHardware.ATM:
482 type = NetworkInterfaceType.Atm;
485 case MacOsArpHardware.SLIP:
486 type = NetworkInterfaceType.Slip;
489 case MacOsArpHardware.PPP:
490 type = NetworkInterfaceType.Ppp;
493 case MacOsArpHardware.LOOPBACK:
494 type = NetworkInterfaceType.Loopback;
498 case MacOsArpHardware.FDDI:
499 type = NetworkInterfaceType.Fddi;
506 MacOsNetworkInterface iface = null;
508 if (!interfaces.TryGetValue (name, out iface)) {
509 iface = new MacOsNetworkInterface (name);
510 interfaces.Add (name, iface);
513 if (!address.Equals (IPAddress.None))
514 iface.AddAddress (address);
516 if (macAddress != null || type == NetworkInterfaceType.Loopback)
517 iface.SetLinkLayerInfo (index, macAddress, type);
519 next = addr.ifa_next;
525 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
527 foreach (NetworkInterface thisInterface in interfaces.Values) {
528 result [x] = thisInterface;
534 MacOsNetworkInterface (string name)
539 public override IPInterfaceProperties GetIPProperties ()
541 if (ipproperties == null)
542 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
546 public override IPv4InterfaceStatistics GetIPv4Statistics ()
548 if (ipv4stats == null)
549 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
553 public override OperationalStatus OperationalStatus {
555 return OperationalStatus.Unknown;
559 public override bool SupportsMulticast {
566 class Win32NetworkInterface2 : NetworkInterface
568 [DllImport ("iphlpapi.dll", SetLastError = true)]
569 static extern int GetAdaptersInfo (byte [] info, ref int size);
571 [DllImport ("iphlpapi.dll", SetLastError = true)]
572 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
574 [DllImport ("iphlpapi.dll", SetLastError = true)]
575 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
577 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
579 // Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
580 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
581 NetworkInterface [] ret = new NetworkInterface [aa.Length];
582 for (int i = 0; i < ret.Length; i++)
583 ret [i] = new Win32NetworkInterface2 (aa [i]);
587 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
589 foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
590 if (info.Index == index)
595 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
597 byte [] bytes = null;
599 GetAdaptersInfo (bytes, ref len);
600 bytes = new byte [len];
601 int ret = GetAdaptersInfo (bytes, ref len);
604 throw new NetworkInformationException (ret);
606 List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
607 fixed (byte* ptr = bytes) {
608 Win32_IP_ADAPTER_INFO info;
609 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
610 info = new Win32_IP_ADAPTER_INFO ();
611 Marshal.PtrToStructure (p, info);
618 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
620 byte [] bytes = null;
622 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
623 bytes = new byte [len];
624 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
626 throw new NetworkInformationException (ret);
628 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
629 fixed (byte* ptr = bytes) {
630 Win32_IP_ADAPTER_ADDRESSES info;
631 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
632 info = new Win32_IP_ADAPTER_ADDRESSES ();
633 Marshal.PtrToStructure (p, info);
640 Win32_IP_ADAPTER_ADDRESSES addr;
641 Win32_MIB_IFROW mib4, mib6;
642 Win32IPv4InterfaceStatistics ip4stats;
643 IPInterfaceProperties ip_if_props;
645 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
648 mib4 = default (Win32_MIB_IFROW);
649 mib4.Index = addr.Alignment.IfIndex;
650 if (GetIfEntry (ref mib4) != 0)
651 mib4.Index = -1; // unavailable;
652 mib6 = default (Win32_MIB_IFROW);
653 mib6.Index = addr.Ipv6IfIndex;
654 if (GetIfEntry (ref mib6) != 0)
655 mib6.Index = -1; // unavailable;
656 ip4stats = new Win32IPv4InterfaceStatistics (mib4);
657 ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
660 public override IPInterfaceProperties GetIPProperties ()
665 public override IPv4InterfaceStatistics GetIPv4Statistics ()
670 public override PhysicalAddress GetPhysicalAddress ()
672 byte [] bytes = new byte [addr.PhysicalAddressLength];
673 Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
674 return new PhysicalAddress (bytes);
677 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
679 switch (networkInterfaceComponent) {
680 case NetworkInterfaceComponent.IPv4:
681 return mib4.Index >= 0;
682 case NetworkInterfaceComponent.IPv6:
683 return mib6.Index >= 0;
688 public override string Description {
689 get { return addr.Description; }
691 public override string Id {
692 get { return addr.AdapterName; }
694 public override bool IsReceiveOnly {
695 get { return addr.IsReceiveOnly; }
697 public override string Name {
698 get { return addr.FriendlyName; }
700 public override NetworkInterfaceType NetworkInterfaceType {
701 get { return addr.IfType; }
703 public override OperationalStatus OperationalStatus {
704 get { return addr.OperStatus; }
706 public override long Speed {
707 get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
709 public override bool SupportsMulticast {
710 get { return !addr.NoMulticast; }