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