Merge pull request #347 from JamesB7/master
[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                 static Version windowsVer51 = new Version (5, 1);
45                 static internal readonly bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
46                 
47                 protected NetworkInterface ()
48                 {
49                 }
50
51                 public static NetworkInterface [] GetAllNetworkInterfaces ()
52                 {
53                         if (runningOnUnix) {
54                                 try {
55                                         if (Platform.IsMacOS)
56                                                 return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
57                                         else
58                                                 return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
59                                 } catch (SystemException ex) {
60                                         throw ex;
61                                 } catch {
62                                         return new NetworkInterface [0];
63                                 }
64                         } else {
65                                 if (Environment.OSVersion.Version >= windowsVer51)
66                                         return Win32NetworkInterface2.ImplGetAllNetworkInterfaces ();
67                                 return new NetworkInterface [0];
68                         }
69                 }
70
71                 [MonoTODO("Always returns true")]
72                 public static bool GetIsNetworkAvailable ()
73                 {
74                         return true;
75                 }
76
77                 internal static string ReadLine (string path)
78                 {
79                         using (FileStream fs = File.OpenRead (path)){
80                                 using (StreamReader sr = new StreamReader (fs)){
81                                         return sr.ReadLine ();
82                                 }
83                         }
84                 }
85                 
86                 [MonoTODO("Only works on Linux. Returns 0 on other systems.")]
87                 public static int LoopbackInterfaceIndex {
88                         get {
89                                 if (runningOnUnix) {
90                                         try {
91                                                 return UnixNetworkInterface.IfNameToIndex ("lo");
92                                         } catch  {
93                                                 return 0;
94                                         }
95                                 } else
96                                         return 0;
97                         }
98                 }
99
100                 public abstract IPInterfaceProperties GetIPProperties ();
101                 public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
102                 public abstract PhysicalAddress GetPhysicalAddress ();
103                 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
104
105                 public abstract string Description { get; }
106                 public abstract string Id { get; }
107                 public abstract bool IsReceiveOnly { get; }
108                 public abstract string Name { get; }
109                 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
110                 public abstract OperationalStatus OperationalStatus { get; }
111                 public abstract long Speed { get; }
112                 public abstract bool SupportsMulticast { get; }
113         }
114
115         abstract class UnixNetworkInterface : NetworkInterface
116         {
117                 [DllImport("libc")]
118                 static extern int if_nametoindex(string ifname);
119
120                 protected IPv4InterfaceStatistics ipv4stats;
121                 protected IPInterfaceProperties ipproperties;
122                 
123                 string               name;
124                 //int                  index;
125                 protected List <IPAddress> addresses;
126                 byte[]               macAddress;
127                 NetworkInterfaceType type;
128                 
129                 internal UnixNetworkInterface (string name)
130                 {
131                         this.name = name;
132                         addresses = new List<IPAddress> ();
133                 }
134
135                 public static int IfNameToIndex (string ifname)
136                 {
137                         return if_nametoindex(ifname);
138                 }
139                 
140                 internal void AddAddress (IPAddress address)
141                 {
142                         addresses.Add (address);
143                 }
144
145                 internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
146                 {
147                         //this.index = index;
148                         this.macAddress = macAddress;
149                         this.type = type;
150                 }
151
152                 public override PhysicalAddress GetPhysicalAddress ()
153                 {
154                         if (macAddress != null)
155                                 return new PhysicalAddress (macAddress);
156                         else
157                                 return PhysicalAddress.None;
158                 }
159
160                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
161                 {
162                         bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
163                         bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
164                                 
165                         foreach (IPAddress address in addresses) {
166                                 if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
167                                         return true;
168                                 else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
169                                         return true;
170                         }
171                         
172                         return false;
173                 }
174
175                 public override string Description {
176                         get { return name; }
177                 }
178
179                 public override string Id {
180                         get { return name; }
181                 }
182
183                 public override bool IsReceiveOnly {
184                         get { return false; }
185                 }
186
187                 public override string Name {
188                         get { return name; }
189                 }
190                 
191                 public override NetworkInterfaceType NetworkInterfaceType {
192                         get { return type; }
193                 }
194                 
195                 [MonoTODO ("Parse dmesg?")]
196                 public override long Speed {
197                         get {
198                                 // Bits/s
199                                 return 1000000;
200                         }
201                 }
202         }
203
204         //
205         // This class needs support from the libsupport.so library to fetch the
206         // data using arch-specific ioctls.
207         //
208         // For this to work, we have to create this on the factory above.
209         //
210         class LinuxNetworkInterface : UnixNetworkInterface
211         {
212                 [DllImport ("libc")]
213                 static extern int getifaddrs (out IntPtr ifap);
214
215                 [DllImport ("libc")]
216                 static extern void freeifaddrs (IntPtr ifap);
217
218                 const int AF_INET   = 2;
219                 const int AF_INET6  = 10;
220                 const int AF_PACKET = 17;
221                 
222                 //NetworkInterfaceType type;
223                 string               iface_path;
224                 string               iface_operstate_path;
225                 string               iface_flags_path;          
226
227                 internal string IfacePath {
228                         get { return iface_path; }
229                 }
230                 
231                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
232                 {
233                         var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
234                         IntPtr ifap;
235                         if (getifaddrs (out ifap) != 0)
236                                 throw new SystemException ("getifaddrs() failed");
237
238                         try {
239                                 IntPtr next = ifap;
240                                 while (next != IntPtr.Zero) {
241                                         ifaddrs   addr = (ifaddrs) Marshal.PtrToStructure (next, typeof (ifaddrs));
242                                         IPAddress address = IPAddress.None;
243                                         string    name = addr.ifa_name;
244                                         int       index = -1;
245                                         byte[]    macAddress = null;
246                                         NetworkInterfaceType type = NetworkInterfaceType.Unknown;
247
248                                         if (addr.ifa_addr != IntPtr.Zero) {
249                                                 sockaddr_in sockaddr = (sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in));
250
251                                                 if (sockaddr.sin_family == AF_INET6) {
252                                                         sockaddr_in6 sockaddr6 = (sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_in6));
253                                                         address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
254                                                 } else if (sockaddr.sin_family == AF_INET) {
255                                                         address = new IPAddress (sockaddr.sin_addr);
256                                                 } else if (sockaddr.sin_family == AF_PACKET) {
257                                                         sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
258                                                         if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
259                                                                 Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
260                                                                                          sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
261                                                                 next = addr.ifa_next;
262                                                                 continue;
263                                                         }
264                                                         
265                                                         macAddress = new byte [(int) sockaddrll.sll_halen];
266                                                         Array.Copy (sockaddrll.sll_addr, 0, macAddress, 0, macAddress.Length);
267                                                         index = sockaddrll.sll_ifindex;
268
269                                                         int hwtype = (int)sockaddrll.sll_hatype;
270                                                         if (Enum.IsDefined (typeof (LinuxArpHardware), hwtype)) {
271                                                                 switch ((LinuxArpHardware)hwtype) {
272                                                                         case LinuxArpHardware.EETHER:
273                                                                                 goto case LinuxArpHardware.ETHER;
274                                                                                 
275                                                                         case LinuxArpHardware.ETHER:
276                                                                                 type = NetworkInterfaceType.Ethernet;
277                                                                                 break;
278
279                                                                         case LinuxArpHardware.PRONET:
280                                                                                 type = NetworkInterfaceType.TokenRing;
281                                                                                 break;
282
283                                                                         case LinuxArpHardware.ATM:
284                                                                                 type = NetworkInterfaceType.Atm;
285                                                                                 break;
286                                                                         
287                                                                         case LinuxArpHardware.SLIP:
288                                                                                 type = NetworkInterfaceType.Slip;
289                                                                                 break;
290                                                                         
291                                                                         case LinuxArpHardware.PPP:
292                                                                                 type = NetworkInterfaceType.Ppp;
293                                                                                 break;
294                                                                         
295                                                                         case LinuxArpHardware.LOOPBACK:
296                                                                                 type = NetworkInterfaceType.Loopback;
297                                                                                 macAddress = null;
298                                                                                 break;
299
300                                                                         case LinuxArpHardware.FDDI:
301                                                                                 type = NetworkInterfaceType.Fddi;
302                                                                                 break;
303
304                                                                         case LinuxArpHardware.TUNNEL6:
305                                                                                 goto case LinuxArpHardware.TUNNEL;
306                                                                                 
307                                                                         case LinuxArpHardware.TUNNEL:
308                                                                                 type = NetworkInterfaceType.Tunnel;
309                                                                                 break;
310                                                                 }
311                                                         }
312                                                 }
313                                         }
314
315                                         LinuxNetworkInterface iface = null;
316
317                                         if (!interfaces.TryGetValue (name, out iface)) {
318                                                 iface = new LinuxNetworkInterface (name);
319                                                 interfaces.Add (name, iface);
320                                         }
321
322                                         if (!address.Equals (IPAddress.None))
323                                                 iface.AddAddress (address);
324
325                                         if (macAddress != null || type == NetworkInterfaceType.Loopback) {
326                                                 if (type == NetworkInterfaceType.Ethernet) {
327                                                         if (Directory.Exists(iface.IfacePath + "wireless")) {
328                                                                 type = NetworkInterfaceType.Wireless80211;
329                                                         }
330                                                 }
331                                                 iface.SetLinkLayerInfo (index, macAddress, type);
332                                         }
333
334                                         next = addr.ifa_next;
335                                 }
336                         } finally {
337                                 freeifaddrs (ifap);
338                         }
339
340                         NetworkInterface [] result = new NetworkInterface [interfaces.Count];
341                         int x = 0;
342                         foreach (NetworkInterface thisInterface in interfaces.Values) {
343                                 result [x] = thisInterface;
344                                 x++;
345                         }
346                         return result;
347                 }
348                 
349                 LinuxNetworkInterface (string name)
350                         : base (name)
351                 {
352                         iface_path = "/sys/class/net/" + name + "/";
353                         iface_operstate_path = iface_path + "operstate";
354                         iface_flags_path = iface_path + "flags";
355                 }
356
357                 public override IPInterfaceProperties GetIPProperties ()
358                 {
359                         if (ipproperties == null)
360                                 ipproperties = new LinuxIPInterfaceProperties (this, addresses);
361                         return ipproperties;
362                 }
363
364                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
365                 {
366                         if (ipv4stats == null)
367                                 ipv4stats = new LinuxIPv4InterfaceStatistics (this);
368                         return ipv4stats;
369                 }
370
371                 public override OperationalStatus OperationalStatus {
372                         get {
373                                 if (!Directory.Exists (iface_path))
374                                         return OperationalStatus.Unknown;
375                                 
376                                 try {
377                                         string s = ReadLine (iface_operstate_path);
378
379                                         switch (s){
380                                                 case "unknown":
381                                                         return OperationalStatus.Unknown;
382                                                 
383                                                 case "notpresent":
384                                                         return OperationalStatus.NotPresent;
385
386                                                 case "down":
387                                                         return OperationalStatus.Down;
388
389                                                 case "lowerlayerdown":
390                                                         return OperationalStatus.LowerLayerDown;
391
392                                                 case "testing":
393                                                         return OperationalStatus.Testing;
394
395                                                 case "dormant":
396                                                         return OperationalStatus.Dormant;
397
398                                                 case "up":
399                                                         return OperationalStatus.Up;
400                                         }
401                                 } catch {
402                                 }
403                                 return OperationalStatus.Unknown;
404                         }
405                 }
406
407                 public override bool SupportsMulticast {
408                         get {
409                                 if (!Directory.Exists (iface_path))
410                                         return false;
411                                 
412                                 try {
413                                         string s = ReadLine (iface_flags_path);
414                                         if (s.Length > 2 && s [0] == '0' && s [1] == 'x')
415                                                 s = s.Substring (2);
416                                         
417                                         ulong f = UInt64.Parse (s, NumberStyles.HexNumber);
418
419                                         // Hardcoded, only useful for Linux.
420                                         return ((f & 0x1000) == 0x1000);
421                                 } catch {
422                                         return false;
423                                 }
424                         }
425                 }
426         }
427
428         class MacOsNetworkInterface : UnixNetworkInterface
429         {
430                 [DllImport ("libc")]
431                 static extern int getifaddrs (out IntPtr ifap);
432
433                 [DllImport ("libc")]
434                 static extern void freeifaddrs (IntPtr ifap);
435
436                 const int AF_INET  = 2;
437                 const int AF_INET6 = 30;
438                 const int AF_LINK  = 18;
439                 
440                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
441                 {
442                         var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
443                         IntPtr ifap;
444                         if (getifaddrs (out ifap) != 0)
445                                 throw new SystemException ("getifaddrs() failed");
446
447                         try {
448                                 IntPtr next = ifap;
449                                 while (next != IntPtr.Zero) {
450                                         MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
451                                         IPAddress address = IPAddress.None;
452                                         string    name = addr.ifa_name;
453                                         int       index = -1;
454                                         byte[]    macAddress = null;
455                                         NetworkInterfaceType type = NetworkInterfaceType.Unknown;
456
457                                         if (addr.ifa_addr != IntPtr.Zero) {
458                                                 MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
459
460                                                 if (sockaddr.sa_family == AF_INET6) {
461                                                         MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
462                                                         address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
463                                                 } else if (sockaddr.sa_family == AF_INET) {
464                                                         MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
465                                                         address = new IPAddress (sockaddrin.sin_addr);
466                                                 } else if (sockaddr.sa_family == AF_LINK) {
467                                                         MacOsStructs.sockaddr_dl sockaddrdl = (MacOsStructs.sockaddr_dl) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_dl));
468
469                                                         macAddress = new byte [(int) sockaddrdl.sdl_alen];
470                                                         Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, Math.Min (macAddress.Length, sockaddrdl.sdl_data.Length - sockaddrdl.sdl_nlen));
471                                                         index = sockaddrdl.sdl_index;
472
473                                                         int hwtype = (int) sockaddrdl.sdl_type;
474                                                         if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
475                                                                 switch ((MacOsArpHardware) hwtype) {
476                                                                         case MacOsArpHardware.ETHER:
477                                                                                 type = NetworkInterfaceType.Ethernet;
478                                                                                 break;
479
480                                                                         case MacOsArpHardware.ATM:
481                                                                                 type = NetworkInterfaceType.Atm;
482                                                                                 break;
483                                                                         
484                                                                         case MacOsArpHardware.SLIP:
485                                                                                 type = NetworkInterfaceType.Slip;
486                                                                                 break;
487                                                                         
488                                                                         case MacOsArpHardware.PPP:
489                                                                                 type = NetworkInterfaceType.Ppp;
490                                                                                 break;
491                                                                         
492                                                                         case MacOsArpHardware.LOOPBACK:
493                                                                                 type = NetworkInterfaceType.Loopback;
494                                                                                 macAddress = null;
495                                                                                 break;
496
497                                                                         case MacOsArpHardware.FDDI:
498                                                                                 type = NetworkInterfaceType.Fddi;
499                                                                                 break;
500                                                                 }
501                                                         }
502                                                 }
503                                         }
504
505                                         MacOsNetworkInterface iface = null;
506
507                                         if (!interfaces.TryGetValue (name, out iface)) {
508                                                 iface = new MacOsNetworkInterface (name);
509                                                 interfaces.Add (name, iface);
510                                         }
511
512                                         if (!address.Equals (IPAddress.None))
513                                                 iface.AddAddress (address);
514
515                                         if (macAddress != null || type == NetworkInterfaceType.Loopback)
516                                                 iface.SetLinkLayerInfo (index, macAddress, type);
517
518                                         next = addr.ifa_next;
519                                 }
520                         } finally {
521                                 freeifaddrs (ifap);
522                         }
523
524                         NetworkInterface [] result = new NetworkInterface [interfaces.Count];
525                         int x = 0;
526                         foreach (NetworkInterface thisInterface in interfaces.Values) {
527                                 result [x] = thisInterface;
528                                 x++;
529                         }
530                         return result;
531                 }
532                 
533                 MacOsNetworkInterface (string name)
534                         : base (name)
535                 {
536                 }
537
538                 public override IPInterfaceProperties GetIPProperties ()
539                 {
540                         if (ipproperties == null)
541                                 ipproperties = new MacOsIPInterfaceProperties (this, addresses);
542                         return ipproperties;
543                 }
544
545                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
546                 {
547                         if (ipv4stats == null)
548                                 ipv4stats = new MacOsIPv4InterfaceStatistics (this);
549                         return ipv4stats;
550                 }
551
552                 public override OperationalStatus OperationalStatus {
553                         get {
554                                 return OperationalStatus.Unknown;
555                         }
556                 }
557
558                 public override bool SupportsMulticast {
559                         get {
560                                 return false;
561                         }
562                 }
563         }
564
565         class Win32NetworkInterface2 : NetworkInterface
566         {
567                 [DllImport ("iphlpapi.dll", SetLastError = true)]
568                 static extern int GetAdaptersInfo (byte [] info, ref int size);
569
570                 [DllImport ("iphlpapi.dll", SetLastError = true)]
571                 static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
572
573                 [DllImport ("iphlpapi.dll", SetLastError = true)]
574                 static extern int GetIfEntry (ref Win32_MIB_IFROW row);
575
576                 public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
577                 {
578 //                      Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
579                         Win32_IP_ADAPTER_ADDRESSES [] aa = GetAdaptersAddresses ();
580                         NetworkInterface [] ret = new NetworkInterface [aa.Length];
581                         for (int i = 0; i < ret.Length; i++)
582                                 ret [i] = new Win32NetworkInterface2 (aa [i]);
583                         return ret;
584                 }
585
586                 public static Win32_IP_ADAPTER_INFO GetAdapterInfoByIndex (int index)
587                 {
588                         foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
589                                 if (info.Index == index)
590                                         return info;
591                         return null;
592                 }
593
594                 unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
595                 {
596                         byte [] bytes = null;
597                         int len = 0;
598                         GetAdaptersInfo (bytes, ref len);
599                         bytes = new byte [len];
600                         int ret = GetAdaptersInfo (bytes, ref len);
601
602                         if (ret != 0)
603                                 throw new NetworkInformationException (ret);
604
605                         List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
606                         fixed (byte* ptr = bytes) {
607                                 Win32_IP_ADAPTER_INFO info;
608                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
609                                         info = new Win32_IP_ADAPTER_INFO ();
610                                         Marshal.PtrToStructure (p, info);
611                                         l.Add (info);
612                                 }
613                         }
614                         return l.ToArray ();
615                 }
616
617                 unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
618                 {
619                         byte [] bytes = null;
620                         int len = 0;
621                         GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
622                         bytes = new byte [len];
623                         int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
624                         if (ret != 0)
625                                 throw new NetworkInformationException (ret);
626
627                         List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
628                         fixed (byte* ptr = bytes) {
629                                 Win32_IP_ADAPTER_ADDRESSES info;
630                                 for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
631                                         info = new Win32_IP_ADAPTER_ADDRESSES ();
632                                         Marshal.PtrToStructure (p, info);
633                                         l.Add (info);
634                                 }
635                         }
636                         return l.ToArray ();
637                 }
638
639                 Win32_IP_ADAPTER_ADDRESSES addr;
640                 Win32_MIB_IFROW mib4, mib6;
641                 Win32IPv4InterfaceStatistics ip4stats;
642                 IPInterfaceProperties ip_if_props;
643
644                 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr)
645                 {
646                         this.addr = addr;
647                         mib4 = default (Win32_MIB_IFROW);
648                         mib4.Index = addr.Alignment.IfIndex;
649                         if (GetIfEntry (ref mib4) != 0)
650                                 mib4.Index = -1; // unavailable;
651                         mib6 = default (Win32_MIB_IFROW);
652                         mib6.Index = addr.Ipv6IfIndex;
653                         if (GetIfEntry (ref mib6) != 0)
654                                 mib6.Index = -1; // unavailable;
655                         ip4stats = new Win32IPv4InterfaceStatistics (mib4);
656                         ip_if_props = new Win32IPInterfaceProperties2 (addr, mib4, mib6);
657                 }
658
659                 public override IPInterfaceProperties GetIPProperties ()
660                 {
661                         return ip_if_props;
662                 }
663
664                 public override IPv4InterfaceStatistics GetIPv4Statistics ()
665                 {
666                         return ip4stats;
667                 }
668
669                 public override PhysicalAddress GetPhysicalAddress ()
670                 {
671                         byte [] bytes = new byte [addr.PhysicalAddressLength];
672                         Array.Copy (addr.PhysicalAddress, 0, bytes, 0, bytes.Length);
673                         return new PhysicalAddress (bytes);
674                 }
675
676                 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
677                 {
678                         switch (networkInterfaceComponent) {
679                         case NetworkInterfaceComponent.IPv4:
680                                 return mib4.Index >= 0;
681                         case NetworkInterfaceComponent.IPv6:
682                                 return mib6.Index >= 0;
683                         }
684                         return false;
685                 }
686
687                 public override string Description {
688                         get { return addr.Description; }
689                 }
690                 public override string Id {
691                         get { return addr.AdapterName; }
692                 }
693                 public override bool IsReceiveOnly {
694                         get { return addr.IsReceiveOnly; }
695                 }
696                 public override string Name {
697                         get { return addr.FriendlyName; }
698                 }
699                 public override NetworkInterfaceType NetworkInterfaceType {
700                         get { return addr.IfType; }
701                 }
702                 public override OperationalStatus OperationalStatus {
703                         get { return addr.OperStatus; }
704                 }
705                 public override long Speed {
706                         get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
707                 }
708                 public override bool SupportsMulticast {
709                         get { return !addr.NoMulticast; }
710                 }
711         }
712 }
713