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