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