add ISafeSerializationData
[mcs.git] / class / System / System.Net.NetworkInformation / NetworkInterface.cs
blob0dea7a9d19764f73c5f54ecaebfe8c64b3f585e7
1 //
2 // System.Net.NetworkInformation.NetworkInterface
3 //
4 // Authors:
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:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
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.
32 #if NET_2_0
33 using System;
34 using System.Collections.Generic;
35 using System.Collections;
36 using System.Net;
37 using System.Net.Sockets;
38 using System.Runtime.InteropServices;
39 using System.Text;
40 using System.IO;
41 using System.Globalization;
43 namespace System.Net.NetworkInformation {
44 public abstract class NetworkInterface {
45 [DllImport ("libc")]
46 static extern int uname (IntPtr buf);
48 static Version windowsVer51 = new Version (5, 1);
49 static internal readonly bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
51 protected NetworkInterface ()
55 [MonoTODO("Only works on Linux and Windows")]
56 public static NetworkInterface [] GetAllNetworkInterfaces ()
58 if (runningOnUnix) {
59 bool darwin = false;
60 IntPtr buf = Marshal.AllocHGlobal (8192);
61 if (uname (buf) == 0) {
62 string os = Marshal.PtrToStringAnsi (buf);
63 if (os == "Darwin")
64 darwin = true;
66 Marshal.FreeHGlobal (buf);
68 try {
69 if (darwin)
70 return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
71 else
72 return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
73 } catch (SystemException ex) {
74 throw ex;
75 } catch {
76 return new NetworkInterface [0];
78 } else {
79 if (Environment.OSVersion.Version >= windowsVer51)
80 return Win32NetworkInterface2.ImplGetAllNetworkInterfaces ();
81 return new NetworkInterface [0];
85 [MonoTODO("Always returns true")]
86 public static bool GetIsNetworkAvailable ()
88 return true;
91 internal static string ReadLine (string path)
93 using (FileStream fs = File.OpenRead (path)){
94 using (StreamReader sr = new StreamReader (fs)){
95 return sr.ReadLine ();
100 [MonoTODO("Only works on Linux. Returns 0 on other systems.")]
101 public static int LoopbackInterfaceIndex {
102 get {
103 if (runningOnUnix) {
104 try {
105 return UnixNetworkInterface.IfNameToIndex ("lo");
106 } catch {
107 return 0;
109 } else
110 return 0;
114 public abstract IPInterfaceProperties GetIPProperties ();
115 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
116 public abstract PhysicalAddress GetPhysicalAddress ();
117 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
119 public abstract string Description { get; }
120 public abstract string Id { get; }
121 public abstract bool IsReceiveOnly { get; }
122 public abstract string Name { get; }
123 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
124 public abstract OperationalStatus OperationalStatus { get; }
125 public abstract long Speed { get; }
126 public abstract bool SupportsMulticast { get; }
129 abstract class UnixNetworkInterface : NetworkInterface
131 [DllImport("libc")]
132 static extern int if_nametoindex(string ifname);
134 protected IPv4InterfaceStatistics ipv4stats;
135 protected IPInterfaceProperties ipproperties;
137 string name;
138 //int index;
139 protected List <IPAddress> addresses;
140 byte[] macAddress;
141 NetworkInterfaceType type;
143 internal UnixNetworkInterface (string name)
145 this.name = name;
146 addresses = new List<IPAddress> ();
149 public static int IfNameToIndex (string ifname)
151 return if_nametoindex(ifname);
154 internal void AddAddress (IPAddress address)
156 addresses.Add (address);
159 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
161 //this.index = index;
162 this.macAddress = macAddress;
163 this.type = type;
166 public override PhysicalAddress GetPhysicalAddress ()
168 if (macAddress != null)
169 return new PhysicalAddress (macAddress);
170 else
171 return PhysicalAddress.None;
174 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
176 bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
177 bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
179 foreach (IPAddress address in addresses) {
180 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
181 return true;
182 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
183 return true;
186 return false;
189 public override string Description {
190 get { return name; }
193 public override string Id {
194 get { return name; }
197 public override bool IsReceiveOnly {
198 get { return false; }
201 public override string Name {
202 get { return name; }
205 public override NetworkInterfaceType NetworkInterfaceType {
206 get { return type; }
209 [MonoTODO ("Parse dmesg?")]
210 public override long Speed {
211 get {
212 // Bits/s
213 return 1000000;
219 // This class needs support from the libsupport.so library to fetch the
220 // data using arch-specific ioctls.
222 // For this to work, we have to create this on the factory above.
224 class LinuxNetworkInterface : UnixNetworkInterface
226 [DllImport ("libc")]
227 static extern int getifaddrs (out IntPtr ifap);
229 [DllImport ("libc")]
230 static extern void freeifaddrs (IntPtr ifap);
232 const int AF_INET = 2;
233 const int AF_INET6 = 10;
234 const int AF_PACKET = 17;
236 //NetworkInterfaceType type;
237 string iface_path;
238 string iface_operstate_path;
239 string iface_flags_path;
241 internal string IfacePath {
242 get { return iface_path; }
245 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
247 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
248 IntPtr ifap;
249 if (getifaddrs (out ifap) != 0)
250 throw new SystemException ("getifaddrs() failed");
252 try {
253 IntPtr next = ifap;
254 while (next != IntPtr.Zero) {
255 ifaddrs addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
256 IPAddress address = IPAddress.None;
257 string name = addr.ifa_name;
258 int index = -1;
259 byte[] macAddress = null;
260 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
262 if (addr.ifa_addr != IntPtr.Zero) {
263 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
265 if (sockaddr.sin_family == AF_INET6) {
266 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
267 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
268 } else if (sockaddr.sin_family == AF_INET) {
269 address = new IPAddress (sockaddr.sin_addr);
270 } else if (sockaddr.sin_family == AF_PACKET) {
271 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
272 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
273 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
274 sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
275 continue;
278 macAddress = new byte [(int) sockaddrll.sll_halen];
279 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
280 index = sockaddrll.sll_ifindex;
282 int hwtype = (int)sockaddrll.sll_hatype;
283 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
284 switch ((LinuxArpHardware)hwtype) {
285 case LinuxArpHardware.EETHER:
286 goto case LinuxArpHardware.ETHER;
288 case LinuxArpHardware.ETHER:
289 type = NetworkInterfaceType.Ethernet;
290 break;
292 case LinuxArpHardware.PRONET:
293 type = NetworkInterfaceType.TokenRing;
294 break;
296 case LinuxArpHardware.ATM:
297 type = NetworkInterfaceType.Atm;
298 break;
300 case LinuxArpHardware.SLIP:
301 type = NetworkInterfaceType.Slip;
302 break;
304 case LinuxArpHardware.PPP:
305 type = NetworkInterfaceType.Ppp;
306 break;
308 case LinuxArpHardware.LOOPBACK:
309 type = NetworkInterfaceType.Loopback;
310 macAddress = null;
311 break;
313 case LinuxArpHardware.FDDI:
314 type = NetworkInterfaceType.Fddi;
315 break;
317 case LinuxArpHardware.TUNNEL6:
318 goto case LinuxArpHardware.TUNNEL;
320 case LinuxArpHardware.TUNNEL:
321 type = NetworkInterfaceType.Tunnel;
322 break;
328 LinuxNetworkInterface iface = null;
330 if (!interfaces.TryGetValue (name, out iface)) {
331 iface = new LinuxNetworkInterface (name);
332 interfaces.Add (name, iface);
335 if (!address.Equals (IPAddress.None))
336 iface.AddAddress (address);
338 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
339 if (type == NetworkInterfaceType.Ethernet) {
340 if (Directory.Exists(iface.IfacePath + "wireless")) {
341 type = NetworkInterfaceType.Wireless80211;
344 iface.SetLinkLayerInfo (index, macAddress, type);
347 next = addr.ifa_next;
349 } finally {
350 freeifaddrs (ifap);
353 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
354 int x = 0;
355 foreach (NetworkInterface thisInterface in interfaces.Values) {
356 result [x] = thisInterface;
357 x++;
359 return result;
362 LinuxNetworkInterface (string name)
363 : base (name)
365 iface_path = "/sys/class/net/" + name + "/";
366 iface_operstate_path = iface_path + "operstate";
367 iface_flags_path = iface_path + "flags";
370 public override IPInterfaceProperties GetIPProperties ()
372 if (ipproperties == null)
373 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
374 return ipproperties;
377 public override IPv4InterfaceStatistics GetIPv4Statistics ()
379 if (ipv4stats == null)
380 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
381 return ipv4stats;
384 public override OperationalStatus OperationalStatus {
385 get {
386 if (!Directory.Exists (iface_path))
387 return OperationalStatus.Unknown;
389 try {
390 string s = ReadLine (iface_operstate_path);
392 switch (s){
393 case "unknown":
394 return OperationalStatus.Unknown;
396 case "notpresent":
397 return OperationalStatus.NotPresent;
399 case "down":
400 return OperationalStatus.Down;
402 case "lowerlayerdown":
403 return OperationalStatus.LowerLayerDown;
405 case "testing":
406 return OperationalStatus.Testing;
408 case "dormant":
409 return OperationalStatus.Dormant;
411 case "up":
412 return OperationalStatus.Up;
414 } catch {
416 return OperationalStatus.Unknown;
420 public override bool SupportsMulticast {
421 get {
422 if (!Directory.Exists (iface_path))
423 return false;
425 try {
426 string s = ReadLine (iface_flags_path);
427 if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
428 s = s.Substring (2);
430 ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
432 // Hardcoded, only useful for Linux.
433 return ((f & 0x1000) == 0x1000);
434 } catch {
435 return false;
441 class MacOsNetworkInterface : UnixNetworkInterface
443 [DllImport ("libc")]
444 static extern int getifaddrs (out IntPtr ifap);
446 [DllImport ("libc")]
447 static extern void freeifaddrs (IntPtr ifap);
449 const int AF_INET = 2;
450 const int AF_INET6 = 30;
451 const int AF_LINK = 18;
453 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
455 var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
456 IntPtr ifap;
457 if (getifaddrs (out ifap) != 0)
458 throw new SystemException ("getifaddrs() failed");
460 try {
461 IntPtr next = ifap;
462 while (next != IntPtr.Zero) {
463 MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
464 IPAddress address = IPAddress.None;
465 string name = addr.ifa_name;
466 int index = -1;
467 byte[] macAddress = null;
468 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
470 if (addr.ifa_addr != IntPtr.Zero) {
471 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
473 if (sockaddr.sa_family == AF_INET6) {
474 MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
475 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
476 } else if (sockaddr.sa_family == AF_INET) {
477 MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
478 address = new IPAddress (sockaddrin.sin_addr);
479 } else if (sockaddr.sa_family == AF_LINK) {
480 MacOsStructs.sockaddr_dl sockaddrdl = (MacOsStructs.sockaddr_dl) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_dl));
482 macAddress = new byte [(int) sockaddrdl.sdl_alen];
483 Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, macAddress.Length);
484 index = sockaddrdl.sdl_index;
486 int hwtype = (int) sockaddrdl.sdl_type;
487 if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
488 switch ((MacOsArpHardware) hwtype) {
489 case MacOsArpHardware.ETHER:
490 type = NetworkInterfaceType.Ethernet;
491 break;
493 case MacOsArpHardware.ATM:
494 type = NetworkInterfaceType.Atm;
495 break;
497 case MacOsArpHardware.SLIP:
498 type = NetworkInterfaceType.Slip;
499 break;
501 case MacOsArpHardware.PPP:
502 type = NetworkInterfaceType.Ppp;
503 break;
505 case MacOsArpHardware.LOOPBACK:
506 type = NetworkInterfaceType.Loopback;
507 macAddress = null;
508 break;
510 case MacOsArpHardware.FDDI:
511 type = NetworkInterfaceType.Fddi;
512 break;
518 MacOsNetworkInterface iface = null;
520 if (!interfaces.TryGetValue (name, out iface)) {
521 iface = new MacOsNetworkInterface (name);
522 interfaces.Add (name, iface);
525 if (!address.Equals (IPAddress.None))
526 iface.AddAddress (address);
528 if (macAddress != null || type == NetworkInterfaceType.Loopback)
529 iface.SetLinkLayerInfo (index, macAddress, type);
531 next = addr.ifa_next;
533 } finally {
534 freeifaddrs (ifap);
537 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
538 int x = 0;
539 foreach (NetworkInterface thisInterface in interfaces.Values) {
540 result [x] = thisInterface;
541 x++;
543 return result;
546 MacOsNetworkInterface (string name)
547 : base (name)
551 public override IPInterfaceProperties GetIPProperties ()
553 if (ipproperties == null)
554 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
555 return ipproperties;
558 public override IPv4InterfaceStatistics GetIPv4Statistics ()
560 if (ipv4stats == null)
561 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
562 return ipv4stats;
565 public override OperationalStatus OperationalStatus {
566 get {
567 return OperationalStatus.Unknown;
571 public override bool SupportsMulticast {
572 get {
573 return false;
578 class Win32NetworkInterface2 : NetworkInterface
580 [DllImport ("iphlpapi.dll", SetLastError = true)]
581 static extern int GetAdaptersInfo (byte [] info, ref int size);
583 [DllImport ("iphlpapi.dll", SetLastError = true)]
584 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
586 [DllImport ("iphlpapi.dll", SetLastError = true)]
587 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
589 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
591 // Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
592 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
593 NetworkInterface [] ret = new NetworkInterface [aa.Length];
594 for (int i = 0; i < ret.Length; i++)
595 ret [i] = new Win32NetworkInterface2 (aa [i]);
596 return ret;
599 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
601 foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
602 if (info.Index == index)
603 return info;
604 return null;
607 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
609 byte [] bytes = null;
610 int len = 0;
611 GetAdaptersInfo (bytes, ref len);
612 bytes = new byte [len];
613 int ret = GetAdaptersInfo (bytes, ref len);
615 if (ret != 0)
616 throw new NetworkInformationException (ret);
618 List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
619 fixed (byte* ptr = bytes) {
620 Win32_IP_ADAPTER_INFO info;
621 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
622 info = new Win32_IP_ADAPTER_INFO ();
623 Marshal.PtrToStructure (p, info);
624 l.Add (info);
627 return l.ToArray ();
630 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
632 byte [] bytes = null;
633 int len = 0;
634 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
635 bytes = new byte [len];
636 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
637 if (ret != 0)
638 throw new NetworkInformationException (ret);
640 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
641 fixed (byte* ptr = bytes) {
642 Win32_IP_ADAPTER_ADDRESSES info;
643 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
644 info = new Win32_IP_ADAPTER_ADDRESSES ();
645 Marshal.PtrToStructure (p, info);
646 l.Add (info);
649 return l.ToArray ();
652 Win32_IP_ADAPTER_ADDRESSES addr;
653 Win32_MIB_IFROW mib4, mib6;
654 Win32IPv4InterfaceStatistics ip4stats;
655 IPInterfaceProperties ip_if_props;
657 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
659 this.addr = addr;
660 mib4 = default (Win32_MIB_IFROW);
661 mib4.Index = addr.Alignment.IfIndex;
662 if (GetIfEntry (ref mib4) != 0)
663 mib4.Index = -1; // unavailable;
664 mib6 = default (Win32_MIB_IFROW);
665 mib6.Index = addr.Ipv6IfIndex;
666 if (GetIfEntry (ref mib6) != 0)
667 mib6.Index = -1; // unavailable;
668 ip4stats = new Win32IPv4InterfaceStatistics (mib4);
669 ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
672 public override IPInterfaceProperties GetIPProperties ()
674 return ip_if_props;
677 public override IPv4InterfaceStatistics GetIPv4Statistics ()
679 return ip4stats;
682 public override PhysicalAddress GetPhysicalAddress ()
684 byte [] bytes = new byte [addr.PhysicalAddressLength];
685 Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
686 return new PhysicalAddress (bytes);
689 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
691 switch (networkInterfaceComponent) {
692 case NetworkInterfaceComponent.IPv4:
693 return mib4.Index >= 0;
694 case NetworkInterfaceComponent.IPv6:
695 return mib6.Index >= 0;
697 return false;
700 public override string Description {
701 get { return addr.Description; }
703 public override string Id {
704 get { return addr.AdapterName; }
706 public override bool IsReceiveOnly {
707 get { return addr.IsReceiveOnly; }
709 public override string Name {
710 get { return addr.FriendlyName; }
712 public override NetworkInterfaceType NetworkInterfaceType {
713 get { return addr.IfType; }
715 public override OperationalStatus OperationalStatus {
716 get { return addr.OperStatus; }
718 public override long Speed {
719 get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
721 public override bool SupportsMulticast {
722 get { return !addr.NoMulticast; }
726 #endif