« Return to Thread: [PATCH] Simple implementation of network interface properties for Mac OS X

Re: [Mono-dev] [PATCH] Simple implementation of network interface properties for Mac OS X

by Alexander Shulgin :: Rate this Message:

Reply to Author | View in Thread

Alex Shulgin wrote:
> Hi,
>
> In the current version System.Net.NetworkInformation.NetworkInterface
> provides limited information about network interfaces on the system
> (their names only).
>
> The attached patch adds support for NetworkInterfaceType and
> GetPhysicalAddress() on Mac OS.

Oops, I've almost forgot about IPv6... and missed the added file
MacOsNetworkInterfaceMarshal.

Please see the fixed patch instead.

--
Alex


Index: System.dll.sources
===================================================================
--- System.dll.sources (revision 133967)
+++ System.dll.sources (working copy)
@@ -761,6 +761,7 @@
 System.Net.NetworkInformation/IPv4InterfaceStatistics.cs
 System.Net.NetworkInformation/IPv6InterfaceProperties.cs
 System.Net.NetworkInformation/LinuxNetworkInterfaceMarshal.cs
+System.Net.NetworkInformation/MacOsNetworkInterfaceMarshal.cs
 System.Net.NetworkInformation/MulticastIPAddressInformationCollection.cs
 System.Net.NetworkInformation/MulticastIPAddressInformation.cs
 System.Net.NetworkInformation/NetBiosNodeType.cs
Index: System.Net.NetworkInformation/IPv4InterfaceStatistics.cs
===================================================================
--- System.Net.NetworkInformation/IPv4InterfaceStatistics.cs (revision 133967)
+++ System.Net.NetworkInformation/IPv4InterfaceStatistics.cs (working copy)
@@ -201,8 +201,65 @@
  return Read ("statistics/tx_packets");
  }
  }
+ }
 
+ // dummy class
+ class MacOsIPv4InterfaceStatistics : IPv4InterfaceStatistics
+ {
+ MacOsNetworkInterface macos;
 
+ public MacOsIPv4InterfaceStatistics (MacOsNetworkInterface parent)
+ {
+ macos = parent;
+ }
+
+ public override long BytesReceived {
+ get { return 0; }
+ }
+
+ public override long BytesSent {
+ get { return 0; }
+ }
+
+ public override long IncomingPacketsDiscarded {
+ get { return 0; }
+ }
+
+ public override long IncomingPacketsWithErrors {
+ get { return 0; }
+ }
+
+ public override long IncomingUnknownProtocolPackets {
+ get { return 0; }
+ }
+
+ public override long NonUnicastPacketsReceived {
+ get { return 0; }
+ }
+
+ public override long NonUnicastPacketsSent {
+ get { return 0; }
+ }
+
+ public override long OutgoingPacketsDiscarded {
+ get { return 0; }
+ }
+
+ public override long OutgoingPacketsWithErrors {
+ get { return 0; }
+ }
+
+ public override long OutputQueueLength {
+ get { return 0; }
+ }
+
+ public override long UnicastPacketsReceived {
+ get { return 0; }
+ }
+
+ public override long UnicastPacketsSent {
+ get { return 0; }
+ }
  }
 
 }
Index: System.Net.NetworkInformation/MacOsNetworkInterfaceMarshal.cs
===================================================================
--- System.Net.NetworkInformation/MacOsNetworkInterfaceMarshal.cs (revision 0)
+++ System.Net.NetworkInformation/MacOsNetworkInterfaceMarshal.cs (revision 0)
@@ -0,0 +1,73 @@
+#if NET_2_0
+using System;
+using System.Runtime.InteropServices;
+
+namespace System.Net.NetworkInformation {
+ namespace MacOsStructs {
+ internal struct ifaddrs
+ {
+ public IntPtr  ifa_next;
+ public string  ifa_name;
+ public uint    ifa_flags;
+ public IntPtr  ifa_addr;
+ public IntPtr  ifa_netmask;
+ public IntPtr  ifa_dstaddr;
+ public IntPtr  ifa_data;
+ }
+
+ internal struct sockaddr
+ {
+ public byte  sa_len;
+ public byte  sa_family;
+ }
+
+ internal struct sockaddr_in
+ {
+ public byte   sin_len;
+ public byte   sin_family;
+ public ushort sin_port;
+ public uint   sin_addr;
+ }
+
+ internal struct in6_addr
+ {
+ [MarshalAs (UnmanagedType.ByValArray, SizeConst=16)]
+ public byte[] u6_addr8;
+ }
+
+ internal struct sockaddr_in6
+ {
+ public byte     sin6_len;
+ public byte     sin6_family;
+ public ushort   sin6_port;
+ public uint     sin6_flowinfo;
+ public in6_addr sin6_addr;
+ public uint     sin6_scope_id;
+ }
+
+ internal struct sockaddr_dl
+ {
+ public byte   sdl_len;
+ public byte   sdl_family;
+ public ushort sdl_index;
+ public byte   sdl_type;
+ public byte   sdl_nlen;
+ public byte   sdl_alen;
+ public byte   sdl_slen;
+
+ [MarshalAs (UnmanagedType.ByValArray, SizeConst=12)]
+ public byte[] sdl_data;
+ }
+
+ }
+
+ internal enum MacOsArpHardware {
+ ETHER = 0x6,
+ ATM = 0x25,
+ SLIP = 0x1c,
+ PPP = 0x17,
+ LOOPBACK = 0x18,
+ FDDI = 0xf
+ }
+}
+#endif
Index: System.Net.NetworkInformation/IPv4InterfaceProperties.cs
===================================================================
--- System.Net.NetworkInformation/IPv4InterfaceProperties.cs (revision 133967)
+++ System.Net.NetworkInformation/IPv4InterfaceProperties.cs (working copy)
@@ -46,17 +46,17 @@
  public abstract bool UsesWins { get; }
  }
 
- sealed class LinuxIPv4InterfaceProperties : IPv4InterfaceProperties
+ abstract class UnixIPv4InterfaceProperties : IPv4InterfaceProperties
  {
- LinuxNetworkInterface iface;
+ protected UnixNetworkInterface iface;
 
- public LinuxIPv4InterfaceProperties (LinuxNetworkInterface iface)
+ public UnixIPv4InterfaceProperties (UnixNetworkInterface iface)
  {
  this.iface = iface;
  }
 
  public override int Index {
- get { return LinuxNetworkInterface.IfNameToIndex (iface.Name); }
+ get { return UnixNetworkInterface.IfNameToIndex (iface.Name); }
  }
 
  // TODO: how to discover that?
@@ -74,6 +74,18 @@
  get { return false; }
  }
 
+ public override bool UsesWins {
+ get { return false; }
+ }
+ }
+
+ sealed class LinuxIPv4InterfaceProperties : UnixIPv4InterfaceProperties
+ {
+ public LinuxIPv4InterfaceProperties (LinuxNetworkInterface iface)
+ : base (iface)
+ {
+ }
+
  public override bool IsForwardingEnabled {
  get {
  string iface_path = "/proc/sys/net/ipv4/conf/" + iface.Name + "/forwarding";
@@ -87,9 +99,10 @@
  return false;
  }
  }
+
  public override int Mtu {
  get {
- string iface_path = iface.IfacePath + "mtu";
+ string iface_path = (iface as LinuxNetworkInterface).IfacePath + "mtu";
  int ret = 0;
 
  if (File.Exists (iface_path)) {
@@ -105,10 +118,24 @@
 
  }
  }
-
- public override bool UsesWins {
+ }
+
+ sealed class MacOsIPv4InterfaceProperties : UnixIPv4InterfaceProperties
+ {
+ public MacOsIPv4InterfaceProperties (MacOsNetworkInterface iface)
+ : base (iface)
+ {
+ }
+
+ // dummy
+ public override bool IsForwardingEnabled {
  get { return false; }
  }
+
+ // dummy
+ public override int Mtu {
+ get { return 0; }
+ }
  }
 
  sealed class Win32IPv4InterfaceProperties : IPv4InterfaceProperties
Index: System.Net.NetworkInformation/IPInterfaceProperties.cs
===================================================================
--- System.Net.NetworkInformation/IPInterfaceProperties.cs (revision 133967)
+++ System.Net.NetworkInformation/IPInterfaceProperties.cs (working copy)
@@ -53,35 +53,26 @@
  public abstract IPAddressCollection WinsServersAddresses { get; }
  }
 
- class LinuxIPInterfaceProperties : IPInterfaceProperties
+ abstract class UnixIPInterfaceProperties : IPInterfaceProperties
  {
- IPv4InterfaceProperties ipv4iface_properties;
- LinuxNetworkInterface iface;
+ protected IPv4InterfaceProperties ipv4iface_properties;
+ protected UnixNetworkInterface iface;
  List <IPAddress> addresses;
  IPAddressCollection dns_servers;
  string dns_suffix;
  DateTime last_parse;
 
- public LinuxIPInterfaceProperties (LinuxNetworkInterface iface, List <IPAddress> addresses)
+ public UnixIPInterfaceProperties (UnixNetworkInterface iface, List <IPAddress> addresses)
  {
  this.iface = iface;
  this.addresses = addresses;
  }
 
- public override IPv4InterfaceProperties GetIPv4Properties ()
- {
- if (ipv4iface_properties == null)
- ipv4iface_properties = new LinuxIPv4InterfaceProperties (iface);
-
- return ipv4iface_properties;
- }
-
  public override IPv6InterfaceProperties GetIPv6Properties ()
  {
  throw new NotImplementedException ();
  }
 
-
  static Regex ns = new Regex (@"\s*nameserver\s+(?<address>.*)");
  static Regex search = new Regex (@"\s*search\s+(?<domain>.*)");
  void ParseResolvConf ()
@@ -234,6 +225,38 @@
  }
  }
 
+ class LinuxIPInterfaceProperties : UnixIPInterfaceProperties
+ {
+ public LinuxIPInterfaceProperties (LinuxNetworkInterface iface, List <IPAddress> addresses)
+ : base (iface, addresses)
+ {
+ }
+
+ public override IPv4InterfaceProperties GetIPv4Properties ()
+ {
+ if (ipv4iface_properties == null)
+ ipv4iface_properties = new LinuxIPv4InterfaceProperties (iface as LinuxNetworkInterface);
+
+ return ipv4iface_properties;
+ }
+ }
+
+ class MacOsIPInterfaceProperties : UnixIPInterfaceProperties
+ {
+ public MacOsIPInterfaceProperties (MacOsNetworkInterface iface, List <IPAddress> addresses)
+ : base (iface, addresses)
+ {
+ }
+
+ public override IPv4InterfaceProperties GetIPv4Properties ()
+ {
+ if (ipv4iface_properties == null)
+ ipv4iface_properties = new MacOsIPv4InterfaceProperties (iface as MacOsNetworkInterface);
+
+ return ipv4iface_properties;
+ }
+ }
+
  class Win32IPInterfaceProperties2 : IPInterfaceProperties
  {
  readonly Win32_IP_ADAPTER_ADDRESSES addr;
Index: System.Net.NetworkInformation/NetworkInterface.cs
===================================================================
--- System.Net.NetworkInformation/NetworkInterface.cs (revision 133967)
+++ System.Net.NetworkInformation/NetworkInterface.cs (working copy)
@@ -42,6 +42,9 @@
 
 namespace System.Net.NetworkInformation {
  public abstract class NetworkInterface {
+ [DllImport ("libc")]
+ static extern int uname (IntPtr buf);
+
  static Version windowsVer51 = new Version (5, 1);
  static internal readonly bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
 
@@ -53,8 +56,20 @@
  public static NetworkInterface [] GetAllNetworkInterfaces ()
  {
  if (runningOnUnix) {
+ bool darwin = false;
+ IntPtr buf = Marshal.AllocHGlobal (8192);
+ if (uname (buf) == 0) {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ darwin = true;
+ }
+ Marshal.FreeHGlobal (buf);
+
  try {
- return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
+ if (darwin)
+ return MacOsNetworkInterface.ImplGetAllNetworkInterfaces ();
+ else
+ return LinuxNetworkInterface.ImplGetAllNetworkInterfaces ();
  } catch (SystemException ex) {
  throw ex;
  } catch {
@@ -87,7 +102,7 @@
  get {
  if (runningOnUnix) {
  try {
- return LinuxNetworkInterface.IfNameToIndex ("lo");
+ return UnixNetworkInterface.IfNameToIndex ("lo");
  } catch  {
  return 0;
  }
@@ -111,17 +126,103 @@
  public abstract bool SupportsMulticast { get; }
  }
 
+ abstract class UnixNetworkInterface : NetworkInterface
+ {
+ [DllImport("libc")]
+ static extern int if_nametoindex(string ifname);
+
+ protected IPv4InterfaceStatistics ipv4stats;
+ protected IPInterfaceProperties ipproperties;
+
+ string               name;
+ int                  index;
+ protected List <IPAddress> addresses;
+ byte[]               macAddress;
+ NetworkInterfaceType type;
+
+ internal UnixNetworkInterface (string name)
+ {
+ this.name = name;
+ addresses = new List<IPAddress> ();
+ }
+
+ public static int IfNameToIndex (string ifname)
+ {
+ return if_nametoindex(ifname);
+ }
+
+ internal void AddAddress (IPAddress address)
+ {
+ addresses.Add (address);
+ }
+
+ internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
+ {
+ this.index = index;
+ this.macAddress = macAddress;
+ this.type = type;
+ }
+
+ public override PhysicalAddress GetPhysicalAddress ()
+ {
+ if (macAddress != null)
+ return new PhysicalAddress (macAddress);
+ else
+ return PhysicalAddress.None;
+ }
+
+ public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
+ {
+ bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
+ bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
+
+ foreach (IPAddress address in addresses) {
+ if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
+ return true;
+ else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
+ return true;
+ }
+
+ return false;
+ }
+
+ public override string Description {
+ get { return name; }
+ }
+
+ public override string Id {
+ get { return name; }
+ }
+
+ public override bool IsReceiveOnly {
+ get { return false; }
+ }
+
+ public override string Name {
+ get { return name; }
+ }
+
+ public override NetworkInterfaceType NetworkInterfaceType {
+ get { return type; }
+ }
+
+ [MonoTODO ("Parse dmesg?")]
+ public override long Speed {
+ get {
+ // Bits/s
+ return 1000000;
+ }
+ }
+ }
+
  //
  // This class needs support from the libsupport.so library to fetch the
  // data using arch-specific ioctls.
  //
  // For this to work, we have to create this on the factory above.
  //
- class LinuxNetworkInterface : NetworkInterface
+ class LinuxNetworkInterface : UnixNetworkInterface
  {
- [DllImport("libc")]
- static extern int if_nametoindex(string ifname);
-
  [DllImport ("libc")]
  static extern int getifaddrs (out IntPtr ifap);
 
@@ -132,13 +233,6 @@
  const int AF_INET6  = 10;
  const int AF_PACKET = 17;
 
- IPv4InterfaceStatistics ipv4stats;
- IPInterfaceProperties ipproperties;
-
- string               name;
- int                  index;
- List <IPAddress>     addresses;
- byte[]               macAddress;
  NetworkInterfaceType type;
  string               iface_path;
  string               iface_operstate_path;
@@ -148,11 +242,6 @@
  get { return iface_path; }
  }
 
- public static int IfNameToIndex (string ifname)
- {
- return if_nametoindex(ifname);
- }
-
  public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
  {
  var interfaces = new Dictionary <string, LinuxNetworkInterface> ();
@@ -246,8 +335,14 @@
  if (!address.Equals (IPAddress.None))
  iface.AddAddress (address);
 
- if (macAddress != null || type == NetworkInterfaceType.Loopback)
+ if (macAddress != null || type == NetworkInterfaceType.Loopback) {
+ if (type == NetworkInterfaceType.Ethernet) {
+ if (Directory.Exists(iface.IfacePath + "wireless")) {
+ type = NetworkInterfaceType.Wireless80211;
+ }
+ }
  iface.SetLinkLayerInfo (index, macAddress, type);
+ }
 
  next = addr.ifa_next;
  }
@@ -265,31 +360,13 @@
  }
 
  LinuxNetworkInterface (string name)
+ : base (name)
  {
- this.name = name;
- addresses = new List<IPAddress> ();
  iface_path = "/sys/class/net/" + name + "/";
  iface_operstate_path = iface_path + "operstate";
  iface_flags_path = iface_path + "flags";
  }
 
- internal void AddAddress (IPAddress address)
- {
- addresses.Add (address);
- }
-
- internal void SetLinkLayerInfo (int index, byte[] macAddress, NetworkInterfaceType type)
- {
- this.index = index;
- this.macAddress = macAddress;
- if (type == NetworkInterfaceType.Ethernet) {
- if (Directory.Exists(iface_path + "wireless")) {
- type = NetworkInterfaceType.Wireless80211;
- }
- }
- this.type = type;
- }
-
  public override IPInterfaceProperties GetIPProperties ()
  {
  if (ipproperties == null)
@@ -301,53 +378,9 @@
  {
  if (ipv4stats == null)
  ipv4stats = new LinuxIPv4InterfaceStatistics (this);
-
  return ipv4stats;
  }
 
- public override PhysicalAddress GetPhysicalAddress ()
- {
- if (macAddress != null)
- return new PhysicalAddress (macAddress);
- else
- return PhysicalAddress.None;
- }
-
- public override bool Supports (NetworkInterfaceComponent networkInterfaceComponent)
- {
- bool wantIPv4 = networkInterfaceComponent == NetworkInterfaceComponent.IPv4;
- bool wantIPv6 = wantIPv4 ? false : networkInterfaceComponent == NetworkInterfaceComponent.IPv6;
-
- foreach (IPAddress address in addresses) {
- if (wantIPv4 && address.AddressFamily == AddressFamily.InterNetwork)
- return true;
- else if (wantIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6)
- return true;
-                        }
-
-                        return false;
- }
-
- public override string Description {
- get { return name; }
- }
-
- public override string Id {
- get { return name; }
- }
-
- public override bool IsReceiveOnly {
- get { return false; }
- }
-
- public override string Name {
- get { return name; }
- }
-
- public override NetworkInterfaceType NetworkInterfaceType {
- get { return type; }
- }
-
  public override OperationalStatus OperationalStatus {
  get {
  if (!Directory.Exists (iface_path))
@@ -384,14 +417,6 @@
  }
  }
 
- [MonoTODO ("Parse dmesg?")]
- public override long Speed {
- get {
- // Bits/s
- return 1000000;
- }
- }
-
  public override bool SupportsMulticast {
  get {
  if (!Directory.Exists (iface_path))
@@ -413,6 +438,143 @@
  }
  }
 
+ class MacOsNetworkInterface : UnixNetworkInterface
+ {
+ [DllImport ("libc")]
+ static extern int getifaddrs (out IntPtr ifap);
+
+ [DllImport ("libc")]
+ static extern void freeifaddrs (IntPtr ifap);
+
+ const int AF_INET  = 2;
+ const int AF_INET6 = 30;
+ const int AF_LINK  = 18;
+
+ public static NetworkInterface [] ImplGetAllNetworkInterfaces ()
+ {
+ var interfaces = new Dictionary <string, MacOsNetworkInterface> ();
+ IntPtr ifap;
+ if (getifaddrs (out ifap) != 0)
+ throw new SystemException ("getifaddrs() failed");
+
+ try {
+ IntPtr next = ifap;
+ while (next != IntPtr.Zero) {
+ MacOsStructs.ifaddrs addr = (MacOsStructs.ifaddrs) Marshal.PtrToStructure (next, typeof (MacOsStructs.ifaddrs));
+ IPAddress address = IPAddress.None;
+ string    name = addr.ifa_name;
+ int       index = -1;
+ byte[]    macAddress = null;
+ NetworkInterfaceType type = NetworkInterfaceType.Unknown;
+
+ if (addr.ifa_addr != IntPtr.Zero) {
+ MacOsStructs.sockaddr sockaddr = (MacOsStructs.sockaddr) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr));
+
+ if (sockaddr.sa_family == AF_INET6) {
+ MacOsStructs.sockaddr_in6 sockaddr6 = (MacOsStructs.sockaddr_in6) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in6));
+ address = new IPAddress (sockaddr6.sin6_addr.u6_addr8, sockaddr6.sin6_scope_id);
+ } else if (sockaddr.sa_family == AF_INET) {
+ MacOsStructs.sockaddr_in sockaddrin = (MacOsStructs.sockaddr_in) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_in));
+ address = new IPAddress (sockaddrin.sin_addr);
+ } else if (sockaddr.sa_family == AF_LINK) {
+ MacOsStructs.sockaddr_dl sockaddrdl = (MacOsStructs.sockaddr_dl) Marshal.PtrToStructure (addr.ifa_addr, typeof (MacOsStructs.sockaddr_dl));
+
+ macAddress = new byte [(int) sockaddrdl.sdl_alen];
+ Array.Copy (sockaddrdl.sdl_data, sockaddrdl.sdl_nlen, macAddress, 0, macAddress.Length);
+ index = sockaddrdl.sdl_index;
+
+ int hwtype = (int) sockaddrdl.sdl_type;
+ if (Enum.IsDefined (typeof (MacOsArpHardware), hwtype)) {
+ switch ((MacOsArpHardware) hwtype) {
+ case MacOsArpHardware.ETHER:
+ type = NetworkInterfaceType.Ethernet;
+ break;
+
+ case MacOsArpHardware.ATM:
+ type = NetworkInterfaceType.Atm;
+ break;
+
+ case MacOsArpHardware.SLIP:
+ type = NetworkInterfaceType.Slip;
+ break;
+
+ case MacOsArpHardware.PPP:
+ type = NetworkInterfaceType.Ppp;
+ break;
+
+ case MacOsArpHardware.LOOPBACK:
+ type = NetworkInterfaceType.Loopback;
+ macAddress = null;
+ break;
+
+ case MacOsArpHardware.FDDI:
+ type = NetworkInterfaceType.Fddi;
+ break;
+ }
+ }
+ }
+ }
+
+ MacOsNetworkInterface iface = null;
+
+ if (!interfaces.TryGetValue (name, out iface)) {
+ iface = new MacOsNetworkInterface (name);
+ interfaces.Add (name, iface);
+ }
+
+ if (!address.Equals (IPAddress.None))
+ iface.AddAddress (address);
+
+ if (macAddress != null || type == NetworkInterfaceType.Loopback)
+ iface.SetLinkLayerInfo (index, macAddress, type);
+
+ next = addr.ifa_next;
+ }
+ } finally {
+ freeifaddrs (ifap);
+ }
+
+ NetworkInterface [] result = new NetworkInterface [interfaces.Count];
+ int x = 0;
+ foreach (NetworkInterface thisInterface in interfaces.Values) {
+ result [x] = thisInterface;
+ x++;
+ }
+ return result;
+ }
+
+ MacOsNetworkInterface (string name)
+ : base (name)
+ {
+ }
+
+ public override IPInterfaceProperties GetIPProperties ()
+ {
+ if (ipproperties == null)
+ ipproperties = new MacOsIPInterfaceProperties (this, addresses);
+ return ipproperties;
+ }
+
+ public override IPv4InterfaceStatistics GetIPv4Statistics ()
+ {
+ if (ipv4stats == null)
+ ipv4stats = new MacOsIPv4InterfaceStatistics (this);
+ return ipv4stats;
+ }
+
+ public override OperationalStatus OperationalStatus {
+ get {
+ return OperationalStatus.Unknown;
+ }
+ }
+
+ public override bool SupportsMulticast {
+ get {
+ return false;
+ }
+ }
+ }
+
  class Win32NetworkInterface2 : NetworkInterface
  {
  [DllImport ("iphlpapi.dll", SetLastError = true)]

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

 « Return to Thread: [PATCH] Simple implementation of network interface properties for Mac OS X