Removed DeflateStream.UnmanagedRead Read loop. Fixes #19313.
[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)
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                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
242                 {
243                         var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
244                         IntPtr ifap;
245                         if (getifaddrs (out ifap) != 0)
246                                 throw new SystemException ("getifaddrs() failed");
247
248                         try {
249                                 IntPtr next = ifap;
250                                 while (next != IntPtr.Zero) {
251                                         ifaddrs   addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
252                                         IPAddress address = IPAddress.None;
253                                         string    name = addr.ifa_name;
254                                         int       index = -1;
255                                         byte[]    macAddress = null;
256                                         NetworkInterfaceType type = NetworkInterfaceType.Unknown;
257
258                                         if (addr.ifa_addr != IntPtr.Zero) {
259                                                 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
260
261                                                 if (sockaddr.sin_family == AF_INET6) {
262                                                         sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
263                                                         address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
264                                                 } else if (sockaddr.sin_family == AF_INET) {
265                                                         address = new IPAddress (sockaddr.sin_addr);
266                                                 } else if (sockaddr.sin_family == AF_PACKET) {
267                                                         sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
268                                                         if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
269                                                                 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
270                                                                                          sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
271                                                                 next = addr.ifa_next;
272                                                                 continue;
273                                                         }
274                                                         
275                                                         macAddress = new byte [(int) sockaddrll.sll_halen];
276                                                         Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
277                                                         index = sockaddrll.sll_ifindex;
278
279                                                         int hwtype = (int)sockaddrll.sll_hatype;
280                                                         if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
281                                                                 switch ((LinuxArpHardware)hwtype) {
282                                                                         case LinuxArpHardware.EETHER:
283                                                                                 goto case LinuxArpHardware.ETHER;
284                                                                                 
285                                                                         case LinuxArpHardware.ETHER:
286                                                                                 type = NetworkInterfaceType.Ethernet;
287                                                                                 break;
288
289                                                                         case LinuxArpHardware.PRONET:
290                                                                                 type = NetworkInterfaceType.TokenRing;
291                                                                                 break;
292
293                                                                         case LinuxArpHardware.ATM:
294                                                                                 type = NetworkInterfaceType.Atm;
295                                                                                 break;
296                                                                         
297                                                                         case LinuxArpHardware.SLIP:
298                                                                                 type = NetworkInterfaceType.Slip;
299                                                                                 break;
300                                                                         
301                                                                         case LinuxArpHardware.PPP:
302                                                                                 type = NetworkInterfaceType.Ppp;
303                                                                                 break;
304                                                                         
305                                                                         case LinuxArpHardware.LOOPBACK:
306                                                                                 type = NetworkInterfaceType.Loopback;
307                                                                                 macAddress = null;
308                                                                                 break;
309
310                                                                         case LinuxArpHardware.FDDI:
311                                                                                 type = NetworkInterfaceType.Fddi;
312                                                                                 break;
313
314                                                                         case LinuxArpHardware.TUNNEL6:
315                                                                                 goto case LinuxArpHardware.TUNNEL;
316                                                                                 
317                                                                         case LinuxArpHardware.TUNNEL:
318                                                                                 type = NetworkInterfaceType.Tunnel;
319                                                                                 break;
320                                                                 }
321                                                         }
322                                                 }
323                                         }
324
325                                         LinuxNetworkInterface iface = null;
326
327                                         if (!interfaces.TryGetValue (name, out iface)) {
328                                                 iface = new LinuxNetworkInterface (name);
329                                                 interfaces.Add (name, iface);
330                                         }
331
332                                         if (!address.Equals (IPAddress.None))
333                                                 iface.AddAddress (address);
334
335                                         if (macAddress != null || type == NetworkInterfaceType.Loopback) {
336                                                 if (type == NetworkInterfaceType.Ethernet) {
337                                                         if (Directory.Exists(iface.IfacePath + "wireless")) {
338                                                                 type = NetworkInterfaceType.Wireless80211;
339                                                         }
340                                                 }
341                                                 iface.SetLinkLayerInfo (index, macAddress, type);
342                                         }
343
344                                         next = addr.ifa_next;
345                                 }
346                         } finally {
347                                 freeifaddrs (ifap);
348                         }
349
350                         NetworkInterface [] result = new NetworkInterface [interfaces.Count];
351                         int x = 0;
352                         foreach (NetworkInterface thisInterface in interfaces.Values) {
353                                 result [x] = thisInterface;
354                                 x++;
355                         }
356                         return result;
357                 }
358                 
359                 LinuxNetworkInterface (string name)
360                         : base (name)
361                 {
362                         iface_path = "/sys/class/net/" + name + "/";
363                         iface_operstate_path = iface_path + "operstate";
364                         iface_flags_path = iface_path + "flags";
365                 }
366
367                 public override IPInterfaceProperties GetIPProperties ()
368                 {
369                         if (ipproperties == null)
370                                 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
371                         return ipproperties;
372                 }
373
374                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
375                 {
376                         if (ipv4stats == null)
377                                 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
378                         return ipv4stats;
379                 }
380
381                 public override OperationalStatus OperationalStatus {
382                         get {
383                                 if (!Directory.Exists (iface_path))
384                                         return OperationalStatus.Unknown;
385                                 
386                                 try {
387                                         string s = ReadLine (iface_operstate_path);
388
389                                         switch (s){
390                                                 case "unknown":
391                                                         return OperationalStatus.Unknown;
392                                                 
393                                                 case "notpresent":
394                                                         return OperationalStatus.NotPresent;
395
396                                                 case "down":
397                                                         return OperationalStatus.Down;
398
399                                                 case "lowerlayerdown":
400                                                         return OperationalStatus.LowerLayerDown;
401
402                                                 case "testing":
403                                                         return OperationalStatus.Testing;
404
405                                                 case "dormant":
406                                                         return OperationalStatus.Dormant;
407
408                                                 case "up":
409                                                         return OperationalStatus.Up;
410                                         }
411                                 } catch {
412                                 }
413                                 return OperationalStatus.Unknown;
414                         }
415                 }
416
417                 public override bool SupportsMulticast {
418                         get {
419                                 if (!Directory.Exists (iface_path))
420                                         return false;
421                                 
422                                 try {
423                                         string s = ReadLine (iface_flags_path);
424                                         if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
425                                                 s = s.Substring (2);
426                                         
427                                         ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
428
429                                         // Hardcoded, only useful for Linux.
430                                         return ((f & 0x1000) == 0x1000);
431                                 } catch {
432                                         return false;
433                                 }
434                         }
435                 }
436         }
437
438         class MacOsNetworkInterface : UnixNetworkInterface
439         {
440                 [DllImport ("libc")]
441                 static extern int getifaddrs (out IntPtr ifap);
442
443                 [DllImport ("libc")]
444                 static extern void freeifaddrs (IntPtr ifap);
445
446                 const int AF_INET  = 2;
447                 const int AF_INET6 = 30;
448                 const int AF_LINK  = 18;
449                 
450                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
451                 {
452                         var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
453                         IntPtr ifap;
454                         if (getifaddrs (out ifap) != 0)
455                                 throw new SystemException ("getifaddrs() failed");
456
457                         try {
458                                 IntPtr next = ifap;
459                                 while (next != IntPtr.Zero) {
460                                         MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
461                                         IPAddress address = IPAddress.None;
462                                         string    name = addr.ifa_name;
463                                         int       index = -1;
464                                         byte[]    macAddress = null;
465                                         NetworkInterfaceType type = NetworkInterfaceType.Unknown;
466
467                                         if (addr.ifa_addr != IntPtr.Zero) {
468                                                 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
469
470                                                 if (sockaddr.sa_family == AF_INET6) {
471                                                         MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
472                                                         address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
473                                                 } else if (sockaddr.sa_family == AF_INET) {
474                                                         MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
475                                                         address = new IPAddress (sockaddrin.sin_addr);
476                                                 } else if (sockaddr.sa_family == AF_LINK) {
477                                                         MacOsStructs.sockaddr_dl sockaddrdl = new MacOsStructs.sockaddr_dl ();
478                                                         sockaddrdl.Read (addr.ifa_addr);
479
480                                                         macAddress = new byte [(int) sockaddrdl.sdl_alen];
481                                                         Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
482                                                         index = sockaddrdl.sdl_index;
483
484                                                         int hwtype = (int) sockaddrdl.sdl_type;
485                                                         if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
486                                                                 switch ((MacOsArpHardware) hwtype) {
487                                                                         case MacOsArpHardware.ETHER:
488                                                                                 type = NetworkInterfaceType.Ethernet;
489                                                                                 break;
490
491                                                                         case MacOsArpHardware.ATM:
492                                                                                 type = NetworkInterfaceType.Atm;
493                                                                                 break;
494                                                                         
495                                                                         case MacOsArpHardware.SLIP:
496                                                                                 type = NetworkInterfaceType.Slip;
497                                                                                 break;
498                                                                         
499                                                                         case MacOsArpHardware.PPP:
500                                                                                 type = NetworkInterfaceType.Ppp;
501                                                                                 break;
502                                                                         
503                                                                         case MacOsArpHardware.LOOPBACK:
504                                                                                 type = NetworkInterfaceType.Loopback;
505                                                                                 macAddress = null;
506                                                                                 break;
507
508                                                                         case MacOsArpHardware.FDDI:
509                                                                                 type = NetworkInterfaceType.Fddi;
510                                                                                 break;
511                                                                 }
512                                                         }
513                                                 }
514                                         }
515
516                                         MacOsNetworkInterface iface = null;
517
518                                         if (!interfaces.TryGetValue (name, out iface)) {
519                                                 iface = new MacOsNetworkInterface (name);
520                                                 interfaces.Add (name, iface);
521                                         }
522
523                                         if (!address.Equals (IPAddress.None))
524                                                 iface.AddAddress (address);
525
526                                         if (macAddress != null || type == NetworkInterfaceType.Loopback)
527                                                 iface.SetLinkLayerInfo (index, macAddress, type);
528
529                                         next = addr.ifa_next;
530                                 }
531                         } finally {
532                                 freeifaddrs (ifap);
533                         }
534
535                         NetworkInterface [] result = new NetworkInterface [interfaces.Count];
536                         int x = 0;
537                         foreach (NetworkInterface thisInterface in interfaces.Values) {
538                                 result [x] = thisInterface;
539                                 x++;
540                         }
541                         return result;
542                 }
543                 
544                 MacOsNetworkInterface (string name)
545                         : base (name)
546                 {
547                 }
548
549                 public override IPInterfaceProperties GetIPProperties ()
550                 {
551                         if (ipproperties == null)
552                                 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
553                         return ipproperties;
554                 }
555
556                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
557                 {
558                         if (ipv4stats == null)
559                                 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
560                         return ipv4stats;
561                 }
562
563                 public override OperationalStatus OperationalStatus {
564                         get {
565                                 return OperationalStatus.Unknown;
566                         }
567                 }
568
569                 public override bool SupportsMulticast {
570                         get {
571                                 return false;
572                         }
573                 }
574         }
575
576         class Win32NetworkInterface2 : NetworkInterface
577         {
578                 [DllImport ("iphlpapi.dll", SetLastError = true)]
579                 static extern int GetAdaptersInfo (byte [] info, ref int size);
580
581                 [DllImport ("iphlpapi.dll", SetLastError = true)]
582                 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
583
584                 [DllImport ("iphlpapi.dll", SetLastError = true)]
585                 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
586
587                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
588                 {
589 //                      Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
590                         Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
591                         NetworkInterface [] ret = new NetworkInterface [aa.Length];
592                         for (int i = 0; i < ret.Length; i++)
593                                 ret [i] = new Win32NetworkInterface2 (aa [i]);
594                         return ret;
595                 }
596
597                 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
598                 {
599                         foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
600                                 if (info.Index == index)
601                                         return info;
602                         return null;
603                 }
604
605                 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
606                 {
607                         byte [] bytes = null;
608                         int len = 0;
609                         GetAdaptersInfo (bytes, ref len);
610                         bytes = new byte [len];
611                         int ret = GetAdaptersInfo (bytes, ref len);
612
613                         if (ret != 0)
614                                 throw new NetworkInformationException (ret);
615
616                         List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
617                         fixed (byte* ptr = bytes) {
618                                 Win32_IP_ADAPTER_INFO info;
619                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
620                                         info = new Win32_IP_ADAPTER_INFO ();
621                                         Marshal.PtrToStructure (p, info);
622                                         l.Add (info);
623                                 }
624                         }
625                         return l.ToArray ();
626                 }
627
628                 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
629                 {
630                         byte [] bytes = null;
631                         int len = 0;
632                         GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
633                         bytes = new byte [len];
634                         int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
635                         if (ret != 0)
636                                 throw new NetworkInformationException (ret);
637
638                         List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
639                         fixed (byte* ptr = bytes) {
640                                 Win32_IP_ADAPTER_ADDRESSES info;
641                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
642                                         info = new Win32_IP_ADAPTER_ADDRESSES ();
643                                         Marshal.PtrToStructure (p, info);
644                                         l.Add (info);
645                                 }
646                         }
647                         return l.ToArray ();
648                 }
649
650                 Win32_IP_ADAPTER_ADDRESSES addr;
651                 Win32_MIB_IFROW mib4, mib6;
652                 Win32IPv4InterfaceStatistics ip4stats;
653                 IPInterfaceProperties ip_if_props;
654
655                 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
656                 {
657                         this.addr = addr;
658                         mib4 = default (Win32_MIB_IFROW);
659                         mib4.Index = addr.Alignment.IfIndex;
660                         if (GetIfEntry (ref mib4) != 0)
661                                 mib4.Index = -1; // unavailable;
662                         mib6 = default (Win32_MIB_IFROW);
663                         mib6.Index = addr.Ipv6IfIndex;
664                         if (GetIfEntry (ref mib6) != 0)
665                                 mib6.Index = -1; // unavailable;
666                         ip4stats = new Win32IPv4InterfaceStatistics (mib4);
667                         ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
668                 }
669
670                 public override IPInterfaceProperties GetIPProperties ()
671                 {
672                         return ip_if_props;
673                 }
674
675                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
676                 {
677                         return ip4stats;
678                 }
679
680                 public override PhysicalAddress GetPhysicalAddress ()
681                 {
682                         byte [] bytes = new byte [addr.PhysicalAddressLength];
683                         Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
684                         return new PhysicalAddress (bytes);
685                 }
686
687                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
688                 {
689                         switch (networkInterfaceComponent) {
690                         case NetworkInterfaceComponent.IPv4:
691                                 return mib4.Index >= 0;
692                         case NetworkInterfaceComponent.IPv6:
693                                 return mib6.Index >= 0;
694                         }
695                         return false;
696                 }
697
698                 public override string Description {
699                         get { return addr.Description; }
700                 }
701                 public override string Id {
702                         get { return addr.AdapterName; }
703                 }
704                 public override bool IsReceiveOnly {
705                         get { return addr.IsReceiveOnly; }
706                 }
707                 public override string Name {
708                         get { return addr.FriendlyName; }
709                 }
710                 public override NetworkInterfaceType NetworkInterfaceType {
711                         get { return addr.IfType; }
712                 }
713                 public override OperationalStatus OperationalStatus {
714                         get { return addr.OperStatus; }
715                 }
716                 public override long Speed {
717                         get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
718                 }
719                 public override bool SupportsMulticast {
720                         get { return !addr.NoMulticast; }
721                 }
722         }
723 }
724