Merge pull request #1510 from BrzVlad/fix-file-map
[mono.git] / mcs / class / System / System.Net.NetworkInformation / NetworkInterface.cs
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)
10 //  Marek Safar (marek.safar@gmail.com)
11 //
12 // Copyright (c) 2006-2008 Novell, Inc. (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
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;
42
43 namespace System.Net.NetworkInformation {
44         public abstract class NetworkInterface {
45
46                 static readonly NetworkInterfaceFactory nif = NetworkInterfaceFactory.Create ();
47
48                 protected NetworkInterface ()
49                 {
50                 }
51
52                 public static NetworkInterface [] GetAllNetworkInterfaces ()
53                 {
54                         try {
55                                 return nif.GetAllNetworkInterfaces ();
56                         } catch {
57                                 return new NetworkInterface [0];
58                         }
59                 }
60
61                 [MonoTODO("Always returns true")]
62                 public static bool GetIsNetworkAvailable ()
63                 {
64                         return true;
65                 }
66                 
67                 public static int LoopbackInterfaceIndex {
68                         get {
69                                 return nif.GetLoopbackInterfaceIndex ();
70                         }
71                 }
72
73                 public abstract IPInterfaceProperties GetIPProperties ();
74                 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
75                 public abstract PhysicalAddress GetPhysicalAddress ();
76                 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
77
78                 public abstract string Description { get; }
79                 public abstract string Id { get; }
80                 public abstract bool IsReceiveOnly { get; }
81                 public abstract string Name { get; }
82                 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
83                 public abstract OperationalStatus OperationalStatus { get; }
84                 public abstract long Speed { get; }
85                 public abstract bool SupportsMulticast { get; }
86         }
87
88         abstract class NetworkInterfaceFactory
89         {
90                 internal abstract class UnixNetworkInterfaceAPI : NetworkInterfaceFactory
91                 {
92                         [DllImport("libc")]
93                         public static extern int if_nametoindex(string ifname);
94
95                         [DllImport ("libc")]
96                         protected static extern int getifaddrs (out IntPtr ifap);
97
98                         [DllImport ("libc")]
99                         protected static extern void freeifaddrs (IntPtr ifap);
100                 }
101
102                 class MacOsNetworkInterfaceAPI : UnixNetworkInterfaceAPI
103                 {
104                         public override NetworkInterface [] GetAllNetworkInterfaces ()
105                         {
106                                 const int AF_INET  = 2;
107                                 const int AF_INET6 = 30;
108                                 const int AF_LINK  = 18;
109
110                                 var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
111                                 IntPtr ifap;
112                                 if (getifaddrs (out ifap) != 0)
113                                         throw new SystemException ("getifaddrs() failed");
114
115                                 try {
116                                         IntPtr next = ifap;
117                                         while (next != IntPtr.Zero) {
118                                                 MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
119                                                 IPAddress address = IPAddress.None;
120                                                 string    name = addr.ifa_name;
121                                                 int       index = -1;
122                                                 byte[]    macAddress = null;
123                                                 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
124
125                                                 if (addr.ifa_addr != IntPtr.Zero) {
126                                                         // optain IPAddress
127                                                         MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
128
129                                                         if (sockaddr.sa_family == AF_INET6) {
130                                                                 MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
131                                                                 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
132                                                         } else if (sockaddr.sa_family == AF_INET) {
133                                                                 MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
134                                                                 address = new IPAddress (sockaddrin.sin_addr);
135                                                         } else if (sockaddr.sa_family == AF_LINK) {
136                                                                 MacOsStructs.sockaddr_dl sockaddrdl = new MacOsStructs.sockaddr_dl ();
137                                                                 sockaddrdl.Read (addr.ifa_addr);
138
139                                                                 macAddress = new byte [(int) sockaddrdl.sdl_alen];
140                                                                 // copy mac address from sdl_data field starting at last index pos of interface name into array macaddress, starting
141                                                                 // at index 0
142                                                                 Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
143
144                                                                 index = sockaddrdl.sdl_index;
145
146                                                                 int hwtype = (int) sockaddrdl.sdl_type;
147                                                                 if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
148                                                                         switch ((MacOsArpHardware) hwtype) {
149                                                                                 case MacOsArpHardware.ETHER:
150                                                                                         type = NetworkInterfaceType.Ethernet;
151                                                                                         break;
152
153                                                                                 case MacOsArpHardware.ATM:
154                                                                                         type = NetworkInterfaceType.Atm;
155                                                                                         break;
156                                                                                 
157                                                                                 case MacOsArpHardware.SLIP:
158                                                                                         type = NetworkInterfaceType.Slip;
159                                                                                         break;
160                                                                                 
161                                                                                 case MacOsArpHardware.PPP:
162                                                                                         type = NetworkInterfaceType.Ppp;
163                                                                                         break;
164                                                                                 
165                                                                                 case MacOsArpHardware.LOOPBACK:
166                                                                                         type = NetworkInterfaceType.Loopback;
167                                                                                         macAddress = null;
168                                                                                         break;
169
170                                                                                 case MacOsArpHardware.FDDI:
171                                                                                         type = NetworkInterfaceType.Fddi;
172                                                                                         break;
173                                                                         }
174                                                                 }
175                                                         }
176                                                 }
177
178                                                 MacOsNetworkInterface iface = null;
179
180                                                 // create interface if not already present
181                                                 if (!interfaces.TryGetValue (name, out iface)) {
182                                                         iface = new MacOsNetworkInterface (name, addr.ifa_flags);
183                                                         interfaces.Add (name, iface);
184                                                 }
185
186                                                 // if a new address has been found, add it
187                                                 if (!address.Equals (IPAddress.None))
188                                                         iface.AddAddress (address);
189
190                                                 // set link layer info, if iface has macaddress or is loopback device
191                                                 if (macAddress != null || type == NetworkInterfaceType.Loopback)
192                                                         iface.SetLinkLayerInfo (index, macAddress, type);
193
194                                                 next = addr.ifa_next;
195                                         }
196                                 } finally {
197                                         freeifaddrs (ifap);
198                                 }
199
200                                 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
201                                 int x = 0;
202                                 foreach (NetworkInterface thisInterface in interfaces.Values) {
203                                         result [x] = thisInterface;
204                                         x++;
205                                 }
206                                 return result;
207                         }
208
209                         public override int GetLoopbackInterfaceIndex ()
210                         {
211                                 return if_nametoindex ("lo0");
212                         }
213                 }
214
215                 class LinuxNetworkInterfaceAPI : UnixNetworkInterfaceAPI
216                 {
217                         static void FreeInterfaceAddresses (IntPtr ifap)
218                         {
219 #if MONODROID
220                                 AndroidPlatform.FreeInterfaceAddresses (ifap);
221 #else
222                                 freeifaddrs (ifap);
223 #endif
224                         }
225
226                         static int GetInterfaceAddresses (out IntPtr ifap)
227                         {
228 #if MONODROID
229                                 return AndroidPlatform.GetInterfaceAddresses (out ifap);
230 #else
231                                 return getifaddrs (out ifap);
232 #endif
233                         }
234
235                         public override NetworkInterface [] GetAllNetworkInterfaces ()
236                         {
237                                 const int AF_INET   = 2;
238                                 const int AF_INET6  = 10;
239                                 const int AF_PACKET = 17;
240
241                                 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
242                                 IntPtr ifap;
243                                 if (GetInterfaceAddresses (out ifap) != 0)
244                                         throw new SystemException ("getifaddrs() failed");
245
246                                 try {
247                                         IntPtr next = ifap;
248                                         while (next != IntPtr.Zero) {
249                                                 ifaddrs   addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
250                                                 IPAddress address = IPAddress.None;
251                                                 string    name = addr.ifa_name;
252                                                 int       index = -1;
253                                                 byte[]    macAddress = null;
254                                                 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
255                                                 int       nullNameCount = 0;
256
257                                                 if (addr.ifa_addr != IntPtr.Zero) {
258                                                         sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
259
260                                                         if (sockaddr.sin_family == AF_INET6) {
261                                                                 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
262                                                                 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
263                                                         } else if (sockaddr.sin_family == AF_INET) {
264                                                                 address = new IPAddress (sockaddr.sin_addr);
265                                                         } else if (sockaddr.sin_family == AF_PACKET) {
266                                                                 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
267                                                                 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
268                                                                         Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
269                                                                                                  sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
270                                                                         next = addr.ifa_next;
271                                                                         continue;
272                                                                 }
273                                                                 
274                                                                 macAddress = new byte [(int) sockaddrll.sll_halen];
275                                                                 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
276                                                                 index = sockaddrll.sll_ifindex;
277
278                                                                 int hwtype = (int)sockaddrll.sll_hatype;
279                                                                 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
280                                                                         switch ((LinuxArpHardware)hwtype) {
281                                                                                 case LinuxArpHardware.EETHER:
282                                                                                         goto case LinuxArpHardware.ETHER;
283                                                                                         
284                                                                                 case LinuxArpHardware.ETHER:
285                                                                                         type = NetworkInterfaceType.Ethernet;
286                                                                                         break;
287
288                                                                                 case LinuxArpHardware.PRONET:
289                                                                                         type = NetworkInterfaceType.TokenRing;
290                                                                                         break;
291
292                                                                                 case LinuxArpHardware.ATM:
293                                                                                         type = NetworkInterfaceType.Atm;
294                                                                                         break;
295                                                                                 
296                                                                                 case LinuxArpHardware.SLIP:
297                                                                                 case LinuxArpHardware.CSLIP:
298                                                                                 case LinuxArpHardware.SLIP6:
299                                                                                 case LinuxArpHardware.CSLIP6:
300                                                                                         type = NetworkInterfaceType.Slip;
301                                                                                         break;
302                                                                                 
303                                                                                 case LinuxArpHardware.PPP:
304                                                                                         type = NetworkInterfaceType.Ppp;
305                                                                                         break;
306                                                                                 
307                                                                                 case LinuxArpHardware.LOOPBACK:
308                                                                                         type = NetworkInterfaceType.Loopback;
309                                                                                         macAddress = null;
310                                                                                         break;
311
312                                                                                 case LinuxArpHardware.FDDI:
313                                                                                         type = NetworkInterfaceType.Fddi;
314                                                                                         break;
315
316                                                                                 case LinuxArpHardware.SIT:
317                                                                                 case LinuxArpHardware.IPDDP:
318                                                                                 case LinuxArpHardware.IPGRE:
319                                                                                 case LinuxArpHardware.IP6GRE:
320                                                                                 case LinuxArpHardware.TUNNEL6:
321                                                                                 case LinuxArpHardware.TUNNEL:
322                                                                                         type = NetworkInterfaceType.Tunnel;
323                                                                                         break;
324                                                                         }
325                                                                 }
326                                                         }
327                                                 }
328
329                                                 LinuxNetworkInterface iface = null;
330
331                                                 if (String.IsNullOrEmpty (name))
332                                                         name = "\0" + (++nullNameCount).ToString ();
333                                                 
334                                                 if (!interfaces.TryGetValue (name, out iface)) {
335                                                         iface = new LinuxNetworkInterface (name);
336                                                         interfaces.Add (name, iface);
337                                                 }
338
339                                                 if (!address.Equals (IPAddress.None))
340                                                         iface.AddAddress (address);
341
342                                                 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
343                                                         if (type == NetworkInterfaceType.Ethernet) {
344                                                                 if (Directory.Exists(iface.IfacePath + "wireless")) {
345                                                                         type = NetworkInterfaceType.Wireless80211;
346                                                                 }
347                                                         }
348                                                         iface.SetLinkLayerInfo (index, macAddress, type);
349                                                 }
350
351                                                 next = addr.ifa_next;
352                                         }
353                                 } finally {
354                                         FreeInterfaceAddresses (ifap);
355                                 }
356
357                                 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
358                                 int x = 0;
359                                 foreach (NetworkInterface thisInterface in interfaces.Values) {
360                                         result [x] = thisInterface;
361                                         x++;
362                                 }
363                                 return result;
364                         }
365
366                         public override int GetLoopbackInterfaceIndex ()
367                         {
368                                 return if_nametoindex ("lo");
369                         }
370                 }
371
372                 class Win32NetworkInterfaceAPI : NetworkInterfaceFactory
373                 {
374                         [DllImport ("iphlpapi.dll", SetLastError = true)]
375                         static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
376
377                         unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
378                         {
379                                 byte [] bytes = null;
380                                 int len = 0;
381                                 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
382                                 bytes = new byte [len];
383                                 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
384                                 if (ret != 0)
385                                         throw new NetworkInformationException (ret);
386
387                                 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
388                                 fixed (byte* ptr = bytes) {
389                                         Win32_IP_ADAPTER_ADDRESSES info;
390                                         for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
391                                                 info = new Win32_IP_ADAPTER_ADDRESSES ();
392                                                 Marshal.PtrToStructure (p, info);
393                                                 l.Add (info);
394                                         }
395                                 }
396                                 return l.ToArray ();
397                         }
398
399                         public override NetworkInterface [] GetAllNetworkInterfaces ()
400                         {
401         //                      Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
402                                 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
403                                 NetworkInterface [] ret = new NetworkInterface [aa.Length];
404                                 for (int i = 0; i < ret.Length; i++)
405                                         ret [i] = new Win32NetworkInterface2 (aa [i]);
406                                 return ret;
407                         }
408
409                         public override int GetLoopbackInterfaceIndex ()
410                         {
411                                 throw new NotImplementedException ();
412                         }
413                 }
414
415                 public abstract NetworkInterface [] GetAllNetworkInterfaces ();
416                 public abstract int GetLoopbackInterfaceIndex ();
417
418                 public static NetworkInterfaceFactory Create ()
419                 {
420 #if MONOTOUCH
421                         return new MacOsNetworkInterfaceAPI ();
422 #else
423                         Version windowsVer51 = new Version (5, 1);
424                         bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
425
426                         if (runningOnUnix) {
427                                 if (Platform.IsMacOS || Platform.IsFreeBSD)
428                                         return new MacOsNetworkInterfaceAPI ();
429                                         
430                                 return new LinuxNetworkInterfaceAPI ();
431                         }
432
433                         if (Environment.OSVersion.Version >= windowsVer51)
434                                 return new Win32NetworkInterfaceAPI ();
435
436                         throw new NotImplementedException ();
437 #endif
438                 }
439         }
440
441         abstract class UnixNetworkInterface : NetworkInterface
442         {
443
444                 protected IPv4InterfaceStatistics ipv4stats;
445                 protected IPInterfaceProperties ipproperties;
446                 
447                 string               name;
448                 //int                  index;
449                 protected List <IPAddress> addresses;
450                 byte[]               macAddress;
451                 NetworkInterfaceType type;
452                 
453                 internal UnixNetworkInterface (string name)
454                 {
455                         this.name = name;
456                         addresses = new List<IPAddress> ();
457                 }
458
459                 internal void AddAddress (IPAddress address)
460                 {
461                         addresses.Add (address);
462                 }
463
464                 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
465                 {
466                         //this.index = index;
467                         this.macAddress = macAddress;
468                         this.type = type;
469                 }
470
471                 public override PhysicalAddress GetPhysicalAddress ()
472                 {
473                         if (macAddress != null)
474                                 return new PhysicalAddress (macAddress);
475                         else
476                                 return PhysicalAddress.None;
477                 }
478
479                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
480                 {
481                         bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
482                         bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
483                                 
484                         foreach (IPAddress address in addresses) {
485                                 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
486                                         return true;
487                                 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
488                                         return true;
489                         }
490                         
491                         return false;
492                 }
493
494                 public override string Description {
495                         get { return name; }
496                 }
497
498                 public override string Id {
499                         get { return name; }
500                 }
501
502                 public override bool IsReceiveOnly {
503                         get { return false; }
504                 }
505
506                 public override string Name {
507                         get { return name; }
508                 }
509                 
510                 public override NetworkInterfaceType NetworkInterfaceType {
511                         get { return type; }
512                 }
513                 
514                 [MonoTODO ("Parse dmesg?")]
515                 public override long Speed {
516                         get {
517                                 // Bits/s
518                                 return 1000000;
519                         }
520                 }
521
522                 internal int NameIndex {
523                         get {
524                                 return NetworkInterfaceFactory.UnixNetworkInterfaceAPI.if_nametoindex (Name);
525                         }
526                 }
527         }
528
529         //
530         // This class needs support from the libsupport.so library to fetch the
531         // data using arch-specific ioctls.
532         //
533         // For this to work, we have to create this on the factory above.
534         //
535         sealed class LinuxNetworkInterface : UnixNetworkInterface
536         {
537                 //NetworkInterfaceType type;
538                 string               iface_path;
539                 string               iface_operstate_path;
540                 string               iface_flags_path;          
541
542                 internal string IfacePath {
543                         get { return iface_path; }
544                 }
545                 
546                 internal LinuxNetworkInterface (string name)
547                         : base (name)
548                 {
549                         iface_path = "/sys/class/net/" + name + "/";
550                         iface_operstate_path = iface_path + "operstate";
551                         iface_flags_path = iface_path + "flags";
552                 }
553
554                 public override IPInterfaceProperties GetIPProperties ()
555                 {
556                         if (ipproperties == null)
557                                 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
558                         return ipproperties;
559                 }
560
561                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
562                 {
563                         if (ipv4stats == null)
564                                 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
565                         return ipv4stats;
566                 }
567
568                 public override OperationalStatus OperationalStatus {
569                         get {
570                                 if (!Directory.Exists (iface_path))
571                                         return OperationalStatus.Unknown;
572                                 
573                                 try {
574                                         string s = ReadLine (iface_operstate_path);
575
576                                         switch (s){
577                                                 case "unknown":
578                                                         return OperationalStatus.Unknown;
579                                                 
580                                                 case "notpresent":
581                                                         return OperationalStatus.NotPresent;
582
583                                                 case "down":
584                                                         return OperationalStatus.Down;
585
586                                                 case "lowerlayerdown":
587                                                         return OperationalStatus.LowerLayerDown;
588
589                                                 case "testing":
590                                                         return OperationalStatus.Testing;
591
592                                                 case "dormant":
593                                                         return OperationalStatus.Dormant;
594
595                                                 case "up":
596                                                         return OperationalStatus.Up;
597                                         }
598                                 } catch {
599                                 }
600                                 return OperationalStatus.Unknown;
601                         }
602                 }
603
604                 public override bool SupportsMulticast {
605                         get {
606                                 if (!Directory.Exists (iface_path))
607                                         return false;
608                                 
609                                 try {
610                                         string s = ReadLine (iface_flags_path);
611                                         if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
612                                                 s = s.Substring (2);
613                                         
614                                         ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
615
616                                         // Hardcoded, only useful for Linux.
617                                         return ((f & 0x1000) == 0x1000);
618                                 } catch {
619                                         return false;
620                                 }
621                         }
622                 }
623
624                 internal static string ReadLine (string path)
625                 {
626                         using (FileStream fs = File.OpenRead (path)){
627                                 using (StreamReader sr = new StreamReader (fs)){
628                                         return sr.ReadLine ();
629                                 }
630                         }
631                 }               
632         }
633
634         sealed class MacOsNetworkInterface : UnixNetworkInterface
635         {
636                 private uint _ifa_flags;
637
638                 internal MacOsNetworkInterface (string name, uint ifa_flags)
639                         : base (name)
640                 {
641                         _ifa_flags = ifa_flags;
642                 }
643
644                 public override IPInterfaceProperties GetIPProperties ()
645                 {
646                         if (ipproperties == null)
647                                 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
648                         return ipproperties;
649                 }
650
651                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
652                 {
653                         if (ipv4stats == null)
654                                 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
655                         return ipv4stats;
656                 }
657
658                 public override OperationalStatus OperationalStatus {
659                         get {
660                                 if(((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_UP) == MacOsInterfaceFlags.IFF_UP){
661                                         return OperationalStatus.Up;
662                                 }
663                                 return OperationalStatus.Unknown;
664                         }
665                 }
666
667                 public override bool SupportsMulticast {
668                         get {
669                                 return ((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_MULTICAST) == MacOsInterfaceFlags.IFF_MULTICAST;
670                         }
671                 }
672         }
673
674         class Win32NetworkInterface2 : NetworkInterface
675         {
676                 [DllImport ("iphlpapi.dll", SetLastError = true)]
677                 static extern int GetAdaptersInfo (byte [] info, ref int size);
678
679                 [DllImport ("iphlpapi.dll", SetLastError = true)]
680                 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
681
682                 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
683                 {
684                         foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
685                                 if (info.Index == index)
686                                         return info;
687                         return null;
688                 }
689
690                 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
691                 {
692                         byte [] bytes = null;
693                         int len = 0;
694                         GetAdaptersInfo (bytes, ref len);
695                         bytes = new byte [len];
696                         int ret = GetAdaptersInfo (bytes, ref len);
697
698                         if (ret != 0)
699                                 throw new NetworkInformationException (ret);
700
701                         List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
702                         fixed (byte* ptr = bytes) {
703                                 Win32_IP_ADAPTER_INFO info;
704                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
705                                         info = new Win32_IP_ADAPTER_INFO ();
706                                         Marshal.PtrToStructure (p, info);
707                                         l.Add (info);
708                                 }
709                         }
710                         return l.ToArray ();
711                 }
712
713                 Win32_IP_ADAPTER_ADDRESSES addr;
714                 Win32_MIB_IFROW mib4, mib6;
715                 Win32IPv4InterfaceStatistics ip4stats;
716                 IPInterfaceProperties ip_if_props;
717
718                 internal Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
719                 {
720                         this.addr = addr;
721                         mib4 = default (Win32_MIB_IFROW);
722                         mib4.Index = addr.Alignment.IfIndex;
723                         if (GetIfEntry (ref mib4) != 0)
724                                 mib4.Index = -1; // unavailable;
725                         mib6 = default (Win32_MIB_IFROW);
726                         mib6.Index = addr.Ipv6IfIndex;
727                         if (GetIfEntry (ref mib6) != 0)
728                                 mib6.Index = -1; // unavailable;
729                         ip4stats = new Win32IPv4InterfaceStatistics (mib4);
730                         ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
731                 }
732
733                 public override IPInterfaceProperties GetIPProperties ()
734                 {
735                         return ip_if_props;
736                 }
737
738                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
739                 {
740                         return ip4stats;
741                 }
742
743                 public override PhysicalAddress GetPhysicalAddress ()
744                 {
745                         byte [] bytes = new byte [addr.PhysicalAddressLength];
746                         Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
747                         return new PhysicalAddress (bytes);
748                 }
749
750                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
751                 {
752                         switch (networkInterfaceComponent) {
753                         case NetworkInterfaceComponent.IPv4:
754                                 return mib4.Index >= 0;
755                         case NetworkInterfaceComponent.IPv6:
756                                 return mib6.Index >= 0;
757                         }
758                         return false;
759                 }
760
761                 public override string Description {
762                         get { return addr.Description; }
763                 }
764                 public override string Id {
765                         get { return addr.AdapterName; }
766                 }
767                 public override bool IsReceiveOnly {
768                         get { return addr.IsReceiveOnly; }
769                 }
770                 public override string Name {
771                         get { return addr.FriendlyName; }
772                 }
773                 public override NetworkInterfaceType NetworkInterfaceType {
774                         get { return addr.IfType; }
775                 }
776                 public override OperationalStatus OperationalStatus {
777                         get { return addr.OperStatus; }
778                 }
779                 public override long Speed {
780                         get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
781                 }
782                 public override bool SupportsMulticast {
783                         get { return !addr.NoMulticast; }
784                 }
785         }
786 }
787