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