Incorrect warning message on thread pool startup in full AOT:ed Windows build.
[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                         const int AF_INET = 2;
254                         const int AF_INET6 = 10;
255                         const int AF_PACKET = 17;
256
257                         static void FreeInterfaceAddresses (IntPtr ifap)
258                         {
259 #if MONODROID
260                                 AndroidPlatform.FreeInterfaceAddresses (ifap);
261 #else
262                                 freeifaddrs (ifap);
263 #endif
264                         }
265
266                         static int GetInterfaceAddresses (out IntPtr ifap)
267                         {
268 #if MONODROID
269                                 return AndroidPlatform.GetInterfaceAddresses (out ifap);
270 #else
271                                 return getifaddrs (out ifap);
272 #endif
273                         }
274
275                         public override NetworkInterface [] GetAllNetworkInterfaces ()
276                         {
277
278                                 var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
279                                 IntPtr ifap;
280                                 if (GetInterfaceAddresses (out ifap) != 0)
281                                         throw new SystemException ("getifaddrs() failed");
282
283                                 try {
284                                         IntPtr next = ifap;
285                                         while (next != IntPtr.Zero) {
286                                                 ifaddrs   addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
287                                                 IPAddress address = IPAddress.None;
288                                                 string    name = addr.ifa_name;
289                                                 int       index = -1;
290                                                 byte[]    macAddress = null;
291                                                 NetworkInterfaceType type = NetworkInterfaceType.Unknown;
292                                                 int       nullNameCount = 0;
293
294                                                 if (addr.ifa_addr != IntPtr.Zero) {
295                                                         sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
296
297                                                         if (sockaddr.sin_family == AF_INET6) {
298                                                                 sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
299                                                                 address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
300                                                         } else if (sockaddr.sin_family == AF_INET) {
301                                                                 address = new IPAddress (sockaddr.sin_addr);
302                                                         } else if (sockaddr.sin_family == AF_PACKET) {
303                                                                 sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
304                                                                 if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
305                                                                         Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
306                                                                                                  sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
307                                                                         next = addr.ifa_next;
308                                                                         continue;
309                                                                 }
310                                                                 
311                                                                 macAddress = new byte [(int) sockaddrll.sll_halen];
312                                                                 Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
313                                                                 index = sockaddrll.sll_ifindex;
314
315                                                                 int hwtype = (int)sockaddrll.sll_hatype;
316                                                                 if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
317                                                                         switch ((LinuxArpHardware)hwtype) {
318                                                                                 case LinuxArpHardware.EETHER:
319                                                                                         goto case LinuxArpHardware.ETHER;
320                                                                                         
321                                                                                 case LinuxArpHardware.ETHER:
322                                                                                         type = NetworkInterfaceType.Ethernet;
323                                                                                         break;
324
325                                                                                 case LinuxArpHardware.PRONET:
326                                                                                         type = NetworkInterfaceType.TokenRing;
327                                                                                         break;
328
329                                                                                 case LinuxArpHardware.ATM:
330                                                                                         type = NetworkInterfaceType.Atm;
331                                                                                         break;
332                                                                                 
333                                                                                 case LinuxArpHardware.SLIP:
334                                                                                 case LinuxArpHardware.CSLIP:
335                                                                                 case LinuxArpHardware.SLIP6:
336                                                                                 case LinuxArpHardware.CSLIP6:
337                                                                                         type = NetworkInterfaceType.Slip;
338                                                                                         break;
339                                                                                 
340                                                                                 case LinuxArpHardware.PPP:
341                                                                                         type = NetworkInterfaceType.Ppp;
342                                                                                         break;
343                                                                                 
344                                                                                 case LinuxArpHardware.LOOPBACK:
345                                                                                         type = NetworkInterfaceType.Loopback;
346                                                                                         macAddress = null;
347                                                                                         break;
348
349                                                                                 case LinuxArpHardware.FDDI:
350                                                                                         type = NetworkInterfaceType.Fddi;
351                                                                                         break;
352
353                                                                                 case LinuxArpHardware.SIT:
354                                                                                 case LinuxArpHardware.IPDDP:
355                                                                                 case LinuxArpHardware.IPGRE:
356                                                                                 case LinuxArpHardware.IP6GRE:
357                                                                                 case LinuxArpHardware.TUNNEL6:
358                                                                                 case LinuxArpHardware.TUNNEL:
359                                                                                         type = NetworkInterfaceType.Tunnel;
360                                                                                         break;
361                                                                         }
362                                                                 }
363                                                         }
364                                                 }
365
366                                                 LinuxNetworkInterface iface = null;
367
368                                                 if (String.IsNullOrEmpty (name))
369                                                         name = "\0" + (++nullNameCount).ToString ();
370                                                 
371                                                 if (!interfaces.TryGetValue (name, out iface)) {
372                                                         iface = new LinuxNetworkInterface (name);
373                                                         interfaces.Add (name, iface);
374                                                 }
375
376                                                 if (!address.Equals (IPAddress.None))
377                                                         iface.AddAddress (address);
378
379                                                 if (macAddress != null || type == NetworkInterfaceType.Loopback) {
380                                                         if (type == NetworkInterfaceType.Ethernet) {
381                                                                 if (Directory.Exists(iface.IfacePath + "wireless")) {
382                                                                         type = NetworkInterfaceType.Wireless80211;
383                                                                 }
384                                                         }
385                                                         iface.SetLinkLayerInfo (index, macAddress, type);
386                                                 }
387
388                                                 next = addr.ifa_next;
389                                         }
390                                 } finally {
391                                         FreeInterfaceAddresses (ifap);
392                                 }
393
394                                 NetworkInterface [] result = new NetworkInterface [interfaces.Count];
395                                 int x = 0;
396                                 foreach (NetworkInterface thisInterface in interfaces.Values) {
397                                         result [x] = thisInterface;
398                                         x++;
399                                 }
400                                 return result;
401                         }
402
403                         public override int GetLoopbackInterfaceIndex ()
404                         {
405                                 return if_nametoindex ("lo");
406                         }
407
408                         public override IPAddress GetNetMask (IPAddress address)
409                         {
410                                 foreach (ifaddrs networkInteface in GetNetworkInterfaces()) {
411                                         if (networkInteface.ifa_addr == IntPtr.Zero)
412                                                 continue;
413
414                                         var sockaddr = (sockaddr_in)Marshal.PtrToStructure(networkInteface.ifa_addr, typeof(sockaddr_in));
415
416                                         if (sockaddr.sin_family != AF_INET)
417                                                 continue;
418
419                                         if (!address.Equals(new IPAddress(sockaddr.sin_addr)))
420                                                 continue;
421
422                                         var netmask = (sockaddr_in)Marshal.PtrToStructure(networkInteface.ifa_netmask, typeof(sockaddr_in));
423                                         return new IPAddress(netmask.sin_addr);
424                                 }
425
426                                 return null;
427                         }
428
429                         private static IEnumerable<ifaddrs> GetNetworkInterfaces()
430                         {
431                                 IntPtr ifap = IntPtr.Zero;
432
433                                 try {
434                                         if (GetInterfaceAddresses(out ifap) != 0)
435                                                 yield break;
436
437                                         var next = ifap;
438                                         while (next != IntPtr.Zero) {
439                                                 var addr = (ifaddrs)Marshal.PtrToStructure(next, typeof(ifaddrs));
440                                                 yield return addr;
441                                                 next = addr.ifa_next;
442                                         }
443                                 } finally {
444                                         if (ifap != IntPtr.Zero)
445                                                 FreeInterfaceAddresses(ifap);
446                                 }
447                         }
448                 }
449
450 #if !MOBILE
451                 class Win32NetworkInterfaceAPI : NetworkInterfaceFactory
452                 {
453                         [DllImport ("iphlpapi.dll", SetLastError = true)]
454                         static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
455
456                         unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
457                         {
458                                 byte [] bytes = null;
459                                 int len = 0;
460                                 GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
461                                 bytes = new byte [len];
462                                 int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
463                                 if (ret != 0)
464                                         throw new NetworkInformationException (ret);
465
466                                 List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
467                                 fixed (byte* ptr = bytes) {
468                                         Win32_IP_ADAPTER_ADDRESSES info;
469                                         for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
470                                                 info = new Win32_IP_ADAPTER_ADDRESSES ();
471                                                 Marshal.PtrToStructure (p, info);
472                                                 l.Add (info);
473                                         }
474                                 }
475                                 return l.ToArray ();
476                         }
477
478                         public override NetworkInterface [] GetAllNetworkInterfaces ()
479                         {
480         //                      Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
481                                 Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
482                                 NetworkInterface [] ret = new NetworkInterface [aa.Length];
483                                 for (int i = 0; i < ret.Length; i++)
484                                         ret [i] = new Win32NetworkInterface2 (aa [i]);
485                                 return ret;
486                         }
487
488                         public override int GetLoopbackInterfaceIndex ()
489                         {
490                                 throw new NotImplementedException ();
491                         }
492
493                         public override IPAddress GetNetMask (IPAddress address)
494                         {
495                                 throw new NotImplementedException ();
496                         }
497                 }
498 #endif
499
500                 public abstract NetworkInterface [] GetAllNetworkInterfaces ();
501                 public abstract int GetLoopbackInterfaceIndex ();
502                 public abstract IPAddress GetNetMask (IPAddress address);
503
504                 public static NetworkInterfaceFactory Create ()
505                 {
506 #if MONOTOUCH || XAMMAC
507                         return new MacOsNetworkInterfaceAPI ();
508 #else
509                         Version windowsVer51 = new Version (5, 1);
510                         bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
511
512                         if (runningOnUnix) {
513                                 if (Platform.IsMacOS || Platform.IsFreeBSD)
514                                         return new MacOsNetworkInterfaceAPI ();
515                                         
516                                 return new LinuxNetworkInterfaceAPI ();
517                         }
518
519 #if !MOBILE
520                         if (Environment.OSVersion.Version >= windowsVer51)
521                                 return new Win32NetworkInterfaceAPI ();
522 #endif
523
524                         throw new NotImplementedException ();
525 #endif
526                 }
527         }
528
529         abstract class UnixNetworkInterface : NetworkInterface
530         {
531
532                 protected IPv4InterfaceStatistics ipv4stats;
533                 protected IPInterfaceProperties ipproperties;
534                 
535                 string               name;
536                 //int                  index;
537                 protected List <IPAddress> addresses;
538                 byte[]               macAddress;
539                 NetworkInterfaceType type;
540                 
541                 internal UnixNetworkInterface (string name)
542                 {
543                         this.name = name;
544                         addresses = new List<IPAddress> ();
545                 }
546
547                 internal void AddAddress (IPAddress address)
548                 {
549                         addresses.Add (address);
550                 }
551
552                 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
553                 {
554                         //this.index = index;
555                         this.macAddress = macAddress;
556                         this.type = type;
557                 }
558
559                 public override PhysicalAddress GetPhysicalAddress ()
560                 {
561                         if (macAddress != null)
562                                 return new PhysicalAddress (macAddress);
563                         else
564                                 return PhysicalAddress.None;
565                 }
566
567                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
568                 {
569                         bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
570                         bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
571                                 
572                         foreach (IPAddress address in addresses) {
573                                 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
574                                         return true;
575                                 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
576                                         return true;
577                         }
578                         
579                         return false;
580                 }
581
582                 public override string Description {
583                         get { return name; }
584                 }
585
586                 public override string Id {
587                         get { return name; }
588                 }
589
590                 public override bool IsReceiveOnly {
591                         get { return false; }
592                 }
593
594                 public override string Name {
595                         get { return name; }
596                 }
597                 
598                 public override NetworkInterfaceType NetworkInterfaceType {
599                         get { return type; }
600                 }
601                 
602                 [MonoTODO ("Parse dmesg?")]
603                 public override long Speed {
604                         get {
605                                 // Bits/s
606                                 return 1000000;
607                         }
608                 }
609
610                 internal int NameIndex {
611                         get {
612                                 return NetworkInterfaceFactory.UnixNetworkInterfaceAPI.if_nametoindex (Name);
613                         }
614                 }
615         }
616
617         //
618         // This class needs support from the libsupport.so library to fetch the
619         // data using arch-specific ioctls.
620         //
621         // For this to work, we have to create this on the factory above.
622         //
623         sealed class LinuxNetworkInterface : UnixNetworkInterface
624         {
625                 //NetworkInterfaceType type;
626                 string               iface_path;
627                 string               iface_operstate_path;
628                 string               iface_flags_path;          
629
630                 internal string IfacePath {
631                         get { return iface_path; }
632                 }
633                 
634                 internal LinuxNetworkInterface (string name)
635                         : base (name)
636                 {
637                         iface_path = "/sys/class/net/" + name + "/";
638                         iface_operstate_path = iface_path + "operstate";
639                         iface_flags_path = iface_path + "flags";
640                 }
641
642                 public override IPInterfaceProperties GetIPProperties ()
643                 {
644                         if (ipproperties == null)
645                                 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
646                         return ipproperties;
647                 }
648
649                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
650                 {
651                         if (ipv4stats == null)
652                                 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
653                         return ipv4stats;
654                 }
655
656                 public override OperationalStatus OperationalStatus {
657                         get {
658                                 if (!Directory.Exists (iface_path))
659                                         return OperationalStatus.Unknown;
660                                 
661                                 try {
662                                         string s = ReadLine (iface_operstate_path);
663
664                                         switch (s){
665                                                 case "unknown":
666                                                         return OperationalStatus.Unknown;
667                                                 
668                                                 case "notpresent":
669                                                         return OperationalStatus.NotPresent;
670
671                                                 case "down":
672                                                         return OperationalStatus.Down;
673
674                                                 case "lowerlayerdown":
675                                                         return OperationalStatus.LowerLayerDown;
676
677                                                 case "testing":
678                                                         return OperationalStatus.Testing;
679
680                                                 case "dormant":
681                                                         return OperationalStatus.Dormant;
682
683                                                 case "up":
684                                                         return OperationalStatus.Up;
685                                         }
686                                 } catch {
687                                 }
688                                 return OperationalStatus.Unknown;
689                         }
690                 }
691
692                 public override bool SupportsMulticast {
693                         get {
694                                 if (!Directory.Exists (iface_path))
695                                         return false;
696                                 
697                                 try {
698                                         string s = ReadLine (iface_flags_path);
699                                         if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
700                                                 s = s.Substring (2);
701                                         
702                                         ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
703
704                                         // Hardcoded, only useful for Linux.
705                                         return ((f & 0x1000) == 0x1000);
706                                 } catch {
707                                         return false;
708                                 }
709                         }
710                 }
711
712                 internal static string ReadLine (string path)
713                 {
714                         using (FileStream fs = File.OpenRead (path)){
715                                 using (StreamReader sr = new StreamReader (fs)){
716                                         return sr.ReadLine ();
717                                 }
718                         }
719                 }               
720         }
721
722         sealed class MacOsNetworkInterface : UnixNetworkInterface
723         {
724                 private uint _ifa_flags;
725
726                 internal MacOsNetworkInterface (string name, uint ifa_flags)
727                         : base (name)
728                 {
729                         _ifa_flags = ifa_flags;
730                 }
731
732                 public override IPInterfaceProperties GetIPProperties ()
733                 {
734                         if (ipproperties == null)
735                                 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
736                         return ipproperties;
737                 }
738
739                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
740                 {
741                         if (ipv4stats == null)
742                                 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
743                         return ipv4stats;
744                 }
745
746                 public override OperationalStatus OperationalStatus {
747                         get {
748                                 if(((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_UP) == MacOsInterfaceFlags.IFF_UP){
749                                         return OperationalStatus.Up;
750                                 }
751                                 return OperationalStatus.Unknown;
752                         }
753                 }
754
755                 public override bool SupportsMulticast {
756                         get {
757                                 return ((MacOsInterfaceFlags)_ifa_flags & MacOsInterfaceFlags.IFF_MULTICAST) == MacOsInterfaceFlags.IFF_MULTICAST;
758                         }
759                 }
760         }
761
762 #if !MOBILE
763         class Win32NetworkInterface2 : NetworkInterface
764         {
765                 [DllImport ("iphlpapi.dll", SetLastError = true)]
766                 static extern int GetAdaptersInfo (byte [] info, ref int size);
767
768                 [DllImport ("iphlpapi.dll", SetLastError = true)]
769                 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
770
771                 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
772                 {
773                         foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
774                                 if (info.Index == index)
775                                         return info;
776                         return null;
777                 }
778
779                 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
780                 {
781                         byte [] bytes = null;
782                         int len = 0;
783                         GetAdaptersInfo (bytes, ref len);
784                         bytes = new byte [len];
785                         int ret = GetAdaptersInfo (bytes, ref len);
786
787                         if (ret != 0)
788                                 throw new NetworkInformationException (ret);
789
790                         List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
791                         fixed (byte* ptr = bytes) {
792                                 Win32_IP_ADAPTER_INFO info;
793                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
794                                         info = new Win32_IP_ADAPTER_INFO ();
795                                         Marshal.PtrToStructure (p, info);
796                                         l.Add (info);
797                                 }
798                         }
799                         return l.ToArray ();
800                 }
801
802                 Win32_IP_ADAPTER_ADDRESSES addr;
803                 Win32_MIB_IFROW mib4, mib6;
804                 Win32IPv4InterfaceStatistics ip4stats;
805                 IPInterfaceProperties ip_if_props;
806
807                 internal Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
808                 {
809                         this.addr = addr;
810                         mib4 = default (Win32_MIB_IFROW);
811                         mib4.Index = addr.Alignment.IfIndex;
812                         if (GetIfEntry (ref mib4) != 0)
813                                 mib4.Index = -1; // unavailable;
814                         mib6 = default (Win32_MIB_IFROW);
815                         mib6.Index = addr.Ipv6IfIndex;
816                         if (GetIfEntry (ref mib6) != 0)
817                                 mib6.Index = -1; // unavailable;
818                         ip4stats = new Win32IPv4InterfaceStatistics (mib4);
819                         ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
820                 }
821
822                 public override IPInterfaceProperties GetIPProperties ()
823                 {
824                         return ip_if_props;
825                 }
826
827                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
828                 {
829                         return ip4stats;
830                 }
831
832                 public override PhysicalAddress GetPhysicalAddress ()
833                 {
834                         byte [] bytes = new byte [addr.PhysicalAddressLength];
835                         Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
836                         return new PhysicalAddress (bytes);
837                 }
838
839                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
840                 {
841                         switch (networkInterfaceComponent) {
842                         case NetworkInterfaceComponent.IPv4:
843                                 return mib4.Index >= 0;
844                         case NetworkInterfaceComponent.IPv6:
845                                 return mib6.Index >= 0;
846                         }
847                         return false;
848                 }
849
850                 public override string Description {
851                         get { return addr.Description; }
852                 }
853                 public override string Id {
854                         get { return addr.AdapterName; }
855                 }
856                 public override bool IsReceiveOnly {
857                         get { return addr.IsReceiveOnly; }
858                 }
859                 public override string Name {
860                         get { return addr.FriendlyName; }
861                 }
862                 public override NetworkInterfaceType NetworkInterfaceType {
863                         get { return addr.IfType; }
864                 }
865                 public override OperationalStatus OperationalStatus {
866                         get { return addr.OperStatus; }
867                 }
868                 public override long Speed {
869                         get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
870                 }
871                 public override bool SupportsMulticast {
872                         get { return !addr.NoMulticast; }
873                 }
874         }
875 #endif
876 }
877