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