2 // System.Net.NetworkInformation.NetworkInterface
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)
11 // Copyright (c) 2006-2008 Novell, Inc. (http://www.novell.com)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System
.Collections
.Generic
;
35 using System
.Collections
;
37 using System
.Net
.Sockets
;
38 using System
.Runtime
.InteropServices
;
41 using System
.Globalization
;
43 namespace System
.Net
.NetworkInformation
{
44 public abstract class NetworkInterface
{
46 static extern int uname (IntPtr buf
);
48 static Version windowsVer51
= new Version (5, 1);
49 static internal readonly bool runningOnUnix
= (Environment
.OSVersion
.Platform
== PlatformID
.Unix
);
51 protected NetworkInterface ()
55 [MonoTODO("Only works on Linux and Windows")]
56 public static NetworkInterface
[] GetAllNetworkInterfaces ()
60 IntPtr buf
= Marshal
.AllocHGlobal (8192);
61 if (uname (buf
) == 0) {
62 string os
= Marshal
.PtrToStringAnsi (buf
);
66 Marshal
.FreeHGlobal (buf
);
70 return MacOsNetworkInterface
.ImplGetAllNetworkInterfaces ();
72 return LinuxNetworkInterface
.ImplGetAllNetworkInterfaces ();
73 } catch (SystemException ex
) {
76 return new NetworkInterface
[0];
79 if (Environment
.OSVersion
.Version
>= windowsVer51
)
80 return Win32NetworkInterface2
.ImplGetAllNetworkInterfaces ();
81 return new NetworkInterface
[0];
85 [MonoTODO("Always returns true")]
86 public static bool GetIsNetworkAvailable ()
91 internal static string ReadLine (string path
)
93 using (FileStream fs
= File
.OpenRead (path
)){
94 using (StreamReader sr
= new StreamReader (fs
)){
95 return sr
.ReadLine ();
100 [MonoTODO("Only works on Linux. Returns 0 on other systems.")]
101 public static int LoopbackInterfaceIndex
{
105 return UnixNetworkInterface
.IfNameToIndex ("lo");
114 public abstract IPInterfaceProperties
GetIPProperties ();
115 public abstract IPv4InterfaceStatistics
GetIPv4Statistics ();
116 public abstract PhysicalAddress
GetPhysicalAddress ();
117 public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent
);
119 public abstract string Description { get; }
120 public abstract string Id { get; }
121 public abstract bool IsReceiveOnly { get; }
122 public abstract string Name { get; }
123 public abstract NetworkInterfaceType NetworkInterfaceType { get; }
124 public abstract OperationalStatus OperationalStatus { get; }
125 public abstract long Speed { get; }
126 public abstract bool SupportsMulticast { get; }
129 abstract class UnixNetworkInterface
: NetworkInterface
132 static extern int if_nametoindex(string ifname
);
134 protected IPv4InterfaceStatistics ipv4stats
;
135 protected IPInterfaceProperties ipproperties
;
139 protected List
<IPAddress
> addresses
;
141 NetworkInterfaceType type
;
143 internal UnixNetworkInterface (string name
)
146 addresses
= new List
<IPAddress
> ();
149 public static int IfNameToIndex (string ifname
)
151 return if_nametoindex(ifname
);
154 internal void AddAddress (IPAddress address
)
156 addresses
.Add (address
);
159 internal void SetLinkLayerInfo (int index
, byte[] macAddress
, NetworkInterfaceType type
)
161 //this.index = index;
162 this.macAddress
= macAddress
;
166 public override PhysicalAddress
GetPhysicalAddress ()
168 if (macAddress
!= null)
169 return new PhysicalAddress (macAddress
);
171 return PhysicalAddress
.None
;
174 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent
)
176 bool wantIPv4
= networkInterfaceComponent
== NetworkInterfaceComponent
.IPv4
;
177 bool wantIPv6
= wantIPv4
? false : networkInterfaceComponent
== NetworkInterfaceComponent
.IPv6
;
179 foreach (IPAddress address
in addresses
) {
180 if (wantIPv4
&& address
.AddressFamily
== AddressFamily
.InterNetwork
)
182 else if (wantIPv6
&& address
.AddressFamily
== AddressFamily
.InterNetworkV6
)
189 public override string Description
{
193 public override string Id
{
197 public override bool IsReceiveOnly
{
198 get { return false; }
201 public override string Name
{
205 public override NetworkInterfaceType NetworkInterfaceType
{
209 [MonoTODO ("Parse dmesg?")]
210 public override long Speed
{
219 // This class needs support from the libsupport.so library to fetch the
220 // data using arch-specific ioctls.
222 // For this to work, we have to create this on the factory above.
224 class LinuxNetworkInterface
: UnixNetworkInterface
227 static extern int getifaddrs (out IntPtr ifap
);
230 static extern void freeifaddrs (IntPtr ifap
);
232 const int AF_INET
= 2;
233 const int AF_INET6
= 10;
234 const int AF_PACKET
= 17;
236 //NetworkInterfaceType type;
238 string iface_operstate_path
;
239 string iface_flags_path
;
241 internal string IfacePath
{
242 get { return iface_path; }
245 public static NetworkInterface
[] ImplGetAllNetworkInterfaces ()
247 var interfaces
= new Dictionary
<string, LinuxNetworkInterface
> ();
249 if (getifaddrs (out ifap
) != 0)
250 throw new SystemException ("getifaddrs() failed");
254 while (next
!= IntPtr
.Zero
) {
255 ifaddrs addr
= (ifaddrs
) Marshal
.PtrToStructure (next
, typeof (ifaddrs
));
256 IPAddress address
= IPAddress
.None
;
257 string name
= addr
.ifa_name
;
259 byte[] macAddress
= null;
260 NetworkInterfaceType type
= NetworkInterfaceType
.Unknown
;
262 if (addr
.ifa_addr
!= IntPtr
.Zero
) {
263 sockaddr_in sockaddr
= (sockaddr_in
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (sockaddr_in
));
265 if (sockaddr
.sin_family
== AF_INET6
) {
266 sockaddr_in6 sockaddr6
= (sockaddr_in6
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (sockaddr_in6
));
267 address
= new IPAddress (sockaddr6
.sin6_addr
.u6_addr8
, sockaddr6
.sin6_scope_id
);
268 } else if (sockaddr
.sin_family
== AF_INET
) {
269 address
= new IPAddress (sockaddr
.sin_addr
);
270 } else if (sockaddr
.sin_family
== AF_PACKET
) {
271 sockaddr_ll sockaddrll
= (sockaddr_ll
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (sockaddr_ll
));
272 if (((int)sockaddrll
.sll_halen
) > sockaddrll
.sll_addr
.Length
){
273 Console
.Error
.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
274 sockaddrll
.sll_halen
, sockaddrll
.sll_addr
.Length
);
278 macAddress
= new byte [(int) sockaddrll
.sll_halen
];
279 Array
.Copy (sockaddrll
.sll_addr
, 0, macAddress
, 0, macAddress
.Length
);
280 index
= sockaddrll
.sll_ifindex
;
282 int hwtype
= (int)sockaddrll
.sll_hatype
;
283 if (Enum
.IsDefined (typeof (LinuxArpHardware
), hwtype
)) {
284 switch ((LinuxArpHardware
)hwtype
) {
285 case LinuxArpHardware
.EETHER
:
286 goto case LinuxArpHardware
.ETHER
;
288 case LinuxArpHardware
.ETHER
:
289 type
= NetworkInterfaceType
.Ethernet
;
292 case LinuxArpHardware
.PRONET
:
293 type
= NetworkInterfaceType
.TokenRing
;
296 case LinuxArpHardware
.ATM
:
297 type
= NetworkInterfaceType
.Atm
;
300 case LinuxArpHardware
.SLIP
:
301 type
= NetworkInterfaceType
.Slip
;
304 case LinuxArpHardware
.PPP
:
305 type
= NetworkInterfaceType
.Ppp
;
308 case LinuxArpHardware
.LOOPBACK
:
309 type
= NetworkInterfaceType
.Loopback
;
313 case LinuxArpHardware
.FDDI
:
314 type
= NetworkInterfaceType
.Fddi
;
317 case LinuxArpHardware
.TUNNEL6
:
318 goto case LinuxArpHardware
.TUNNEL
;
320 case LinuxArpHardware
.TUNNEL
:
321 type
= NetworkInterfaceType
.Tunnel
;
328 LinuxNetworkInterface iface
= null;
330 if (!interfaces
.TryGetValue (name
, out iface
)) {
331 iface
= new LinuxNetworkInterface (name
);
332 interfaces
.Add (name
, iface
);
335 if (!address
.Equals (IPAddress
.None
))
336 iface
.AddAddress (address
);
338 if (macAddress
!= null || type
== NetworkInterfaceType
.Loopback
) {
339 if (type
== NetworkInterfaceType
.Ethernet
) {
340 if (Directory
.Exists(iface
.IfacePath
+ "wireless")) {
341 type
= NetworkInterfaceType
.Wireless80211
;
344 iface
.SetLinkLayerInfo (index
, macAddress
, type
);
347 next
= addr
.ifa_next
;
353 NetworkInterface
[] result
= new NetworkInterface
[interfaces
.Count
];
355 foreach (NetworkInterface thisInterface
in interfaces
.Values
) {
356 result
[x
] = thisInterface
;
362 LinuxNetworkInterface (string name
)
365 iface_path
= "/sys/class/net/" + name
+ "/";
366 iface_operstate_path
= iface_path
+ "operstate";
367 iface_flags_path
= iface_path
+ "flags";
370 public override IPInterfaceProperties
GetIPProperties ()
372 if (ipproperties
== null)
373 ipproperties
= new LinuxIPInterfaceProperties (this, addresses
);
377 public override IPv4InterfaceStatistics
GetIPv4Statistics ()
379 if (ipv4stats
== null)
380 ipv4stats
= new LinuxIPv4InterfaceStatistics (this);
384 public override OperationalStatus OperationalStatus
{
386 if (!Directory
.Exists (iface_path
))
387 return OperationalStatus
.Unknown
;
390 string s
= ReadLine (iface_operstate_path
);
394 return OperationalStatus
.Unknown
;
397 return OperationalStatus
.NotPresent
;
400 return OperationalStatus
.Down
;
402 case "lowerlayerdown":
403 return OperationalStatus
.LowerLayerDown
;
406 return OperationalStatus
.Testing
;
409 return OperationalStatus
.Dormant
;
412 return OperationalStatus
.Up
;
416 return OperationalStatus
.Unknown
;
420 public override bool SupportsMulticast
{
422 if (!Directory
.Exists (iface_path
))
426 string s
= ReadLine (iface_flags_path
);
427 if (s
.Length
> 2 && s
[0] == '0' && s
[1] == 'x')
430 ulong f
= UInt64
.Parse (s
, NumberStyles
.HexNumber
);
432 // Hardcoded, only useful for Linux.
433 return ((f
& 0x1000) == 0x1000);
441 class MacOsNetworkInterface
: UnixNetworkInterface
444 static extern int getifaddrs (out IntPtr ifap
);
447 static extern void freeifaddrs (IntPtr ifap
);
449 const int AF_INET
= 2;
450 const int AF_INET6
= 30;
451 const int AF_LINK
= 18;
453 public static NetworkInterface
[] ImplGetAllNetworkInterfaces ()
455 var interfaces
= new Dictionary
<string, MacOsNetworkInterface
> ();
457 if (getifaddrs (out ifap
) != 0)
458 throw new SystemException ("getifaddrs() failed");
462 while (next
!= IntPtr
.Zero
) {
463 MacOsStructs
.ifaddrs addr
= (MacOsStructs
.ifaddrs
) Marshal
.PtrToStructure (next
, typeof (MacOsStructs
.ifaddrs
));
464 IPAddress address
= IPAddress
.None
;
465 string name
= addr
.ifa_name
;
467 byte[] macAddress
= null;
468 NetworkInterfaceType type
= NetworkInterfaceType
.Unknown
;
470 if (addr
.ifa_addr
!= IntPtr
.Zero
) {
471 MacOsStructs
.sockaddr sockaddr
= (MacOsStructs
.sockaddr
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (MacOsStructs
.sockaddr
));
473 if (sockaddr
.sa_family
== AF_INET6
) {
474 MacOsStructs
.sockaddr_in6 sockaddr6
= (MacOsStructs
.sockaddr_in6
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (MacOsStructs
.sockaddr_in6
));
475 address
= new IPAddress (sockaddr6
.sin6_addr
.u6_addr8
, sockaddr6
.sin6_scope_id
);
476 } else if (sockaddr
.sa_family
== AF_INET
) {
477 MacOsStructs
.sockaddr_in sockaddrin
= (MacOsStructs
.sockaddr_in
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (MacOsStructs
.sockaddr_in
));
478 address
= new IPAddress (sockaddrin
.sin_addr
);
479 } else if (sockaddr
.sa_family
== AF_LINK
) {
480 MacOsStructs
.sockaddr_dl sockaddrdl
= (MacOsStructs
.sockaddr_dl
) Marshal
.PtrToStructure (addr
.ifa_addr
, typeof (MacOsStructs
.sockaddr_dl
));
482 macAddress
= new byte [(int) sockaddrdl
.sdl_alen
];
483 Array
.Copy (sockaddrdl
.sdl_data
, sockaddrdl
.sdl_nlen
, macAddress
, 0, macAddress
.Length
);
484 index
= sockaddrdl
.sdl_index
;
486 int hwtype
= (int) sockaddrdl
.sdl_type
;
487 if (Enum
.IsDefined (typeof (MacOsArpHardware
), hwtype
)) {
488 switch ((MacOsArpHardware
) hwtype
) {
489 case MacOsArpHardware
.ETHER
:
490 type
= NetworkInterfaceType
.Ethernet
;
493 case MacOsArpHardware
.ATM
:
494 type
= NetworkInterfaceType
.Atm
;
497 case MacOsArpHardware
.SLIP
:
498 type
= NetworkInterfaceType
.Slip
;
501 case MacOsArpHardware
.PPP
:
502 type
= NetworkInterfaceType
.Ppp
;
505 case MacOsArpHardware
.LOOPBACK
:
506 type
= NetworkInterfaceType
.Loopback
;
510 case MacOsArpHardware
.FDDI
:
511 type
= NetworkInterfaceType
.Fddi
;
518 MacOsNetworkInterface iface
= null;
520 if (!interfaces
.TryGetValue (name
, out iface
)) {
521 iface
= new MacOsNetworkInterface (name
);
522 interfaces
.Add (name
, iface
);
525 if (!address
.Equals (IPAddress
.None
))
526 iface
.AddAddress (address
);
528 if (macAddress
!= null || type
== NetworkInterfaceType
.Loopback
)
529 iface
.SetLinkLayerInfo (index
, macAddress
, type
);
531 next
= addr
.ifa_next
;
537 NetworkInterface
[] result
= new NetworkInterface
[interfaces
.Count
];
539 foreach (NetworkInterface thisInterface
in interfaces
.Values
) {
540 result
[x
] = thisInterface
;
546 MacOsNetworkInterface (string name
)
551 public override IPInterfaceProperties
GetIPProperties ()
553 if (ipproperties
== null)
554 ipproperties
= new MacOsIPInterfaceProperties (this, addresses
);
558 public override IPv4InterfaceStatistics
GetIPv4Statistics ()
560 if (ipv4stats
== null)
561 ipv4stats
= new MacOsIPv4InterfaceStatistics (this);
565 public override OperationalStatus OperationalStatus
{
567 return OperationalStatus
.Unknown
;
571 public override bool SupportsMulticast
{
578 class Win32NetworkInterface2
: NetworkInterface
580 [DllImport ("iphlpapi.dll", SetLastError
= true)]
581 static extern int GetAdaptersInfo (byte [] info
, ref int size
);
583 [DllImport ("iphlpapi.dll", SetLastError
= true)]
584 static extern int GetAdaptersAddresses (uint family
, uint flags
, IntPtr reserved
, byte [] info
, ref int size
);
586 [DllImport ("iphlpapi.dll", SetLastError
= true)]
587 static extern int GetIfEntry (ref Win32_MIB_IFROW row
);
589 public static NetworkInterface
[] ImplGetAllNetworkInterfaces ()
591 // Win32_IP_ADAPTER_INFO [] ai = GetAdaptersInfo ();
592 Win32_IP_ADAPTER_ADDRESSES
[] aa
= GetAdaptersAddresses ();
593 NetworkInterface
[] ret
= new NetworkInterface
[aa
.Length
];
594 for (int i
= 0; i
< ret
.Length
; i
++)
595 ret
[i
] = new Win32NetworkInterface2 (aa
[i
]);
599 public static Win32_IP_ADAPTER_INFO
GetAdapterInfoByIndex (int index
)
601 foreach (Win32_IP_ADAPTER_INFO info
in GetAdaptersInfo ())
602 if (info
.Index
== index
)
607 unsafe static Win32_IP_ADAPTER_INFO
[] GetAdaptersInfo ()
609 byte [] bytes
= null;
611 GetAdaptersInfo (bytes
, ref len
);
612 bytes
= new byte [len
];
613 int ret
= GetAdaptersInfo (bytes
, ref len
);
616 throw new NetworkInformationException (ret
);
618 List
<Win32_IP_ADAPTER_INFO
> l
= new List
<Win32_IP_ADAPTER_INFO
> ();
619 fixed (byte* ptr
= bytes
) {
620 Win32_IP_ADAPTER_INFO info
;
621 for (IntPtr p
= (IntPtr
) ptr
; p
!= IntPtr
.Zero
; p
= info
.Next
) {
622 info
= new Win32_IP_ADAPTER_INFO ();
623 Marshal
.PtrToStructure (p
, info
);
630 unsafe static Win32_IP_ADAPTER_ADDRESSES
[] GetAdaptersAddresses ()
632 byte [] bytes
= null;
634 GetAdaptersAddresses (0, 0, IntPtr
.Zero
, bytes
, ref len
);
635 bytes
= new byte [len
];
636 int ret
= GetAdaptersAddresses (0, 0, IntPtr
.Zero
, bytes
, ref len
);
638 throw new NetworkInformationException (ret
);
640 List
<Win32_IP_ADAPTER_ADDRESSES
> l
= new List
<Win32_IP_ADAPTER_ADDRESSES
> ();
641 fixed (byte* ptr
= bytes
) {
642 Win32_IP_ADAPTER_ADDRESSES info
;
643 for (IntPtr p
= (IntPtr
) ptr
; p
!= IntPtr
.Zero
; p
= info
.Next
) {
644 info
= new Win32_IP_ADAPTER_ADDRESSES ();
645 Marshal
.PtrToStructure (p
, info
);
652 Win32_IP_ADAPTER_ADDRESSES addr
;
653 Win32_MIB_IFROW mib4
, mib6
;
654 Win32IPv4InterfaceStatistics ip4stats
;
655 IPInterfaceProperties ip_if_props
;
657 Win32NetworkInterface2 (Win32_IP_ADAPTER_ADDRESSES addr
)
660 mib4
= default (Win32_MIB_IFROW
);
661 mib4
.Index
= addr
.Alignment
.IfIndex
;
662 if (GetIfEntry (ref mib4
) != 0)
663 mib4
.Index
= -1; // unavailable;
664 mib6
= default (Win32_MIB_IFROW
);
665 mib6
.Index
= addr
.Ipv6IfIndex
;
666 if (GetIfEntry (ref mib6
) != 0)
667 mib6
.Index
= -1; // unavailable;
668 ip4stats
= new Win32IPv4InterfaceStatistics (mib4
);
669 ip_if_props
= new Win32IPInterfaceProperties2 (addr
, mib4
, mib6
);
672 public override IPInterfaceProperties
GetIPProperties ()
677 public override IPv4InterfaceStatistics
GetIPv4Statistics ()
682 public override PhysicalAddress
GetPhysicalAddress ()
684 byte [] bytes
= new byte [addr
.PhysicalAddressLength
];
685 Array
.Copy (addr
.PhysicalAddress
, 0, bytes
, 0, bytes
.Length
);
686 return new PhysicalAddress (bytes
);
689 public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent
)
691 switch (networkInterfaceComponent
) {
692 case NetworkInterfaceComponent
.IPv4
:
693 return mib4
.Index
>= 0;
694 case NetworkInterfaceComponent
.IPv6
:
695 return mib6
.Index
>= 0;
700 public override string Description
{
701 get { return addr.Description; }
703 public override string Id
{
704 get { return addr.AdapterName; }
706 public override bool IsReceiveOnly
{
707 get { return addr.IsReceiveOnly; }
709 public override string Name
{
710 get { return addr.FriendlyName; }
712 public override NetworkInterfaceType NetworkInterfaceType
{
713 get { return addr.IfType; }
715 public override OperationalStatus OperationalStatus
{
716 get { return addr.OperStatus; }
718 public override long Speed
{
719 get { return mib6.Index >= 0 ? mib6.Speed : mib4.Speed; }
721 public override bool SupportsMulticast
{
722 get { return !addr.NoMulticast; }