Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

namespace System.Net.NetworkInformation
Expand Down Expand Up @@ -67,9 +68,38 @@ public GatewayIPAddressInformationCollection GetGatewayAddresses(LinuxNetworkInt
StringParsingHelpers.ParseIPv6GatewayAddressesFromRouteFile(collection, systemProperties.IPv6Routes, _linuxNetworkInterface.Name, _linuxNetworkInterface.Index);
}

// Meadow.OS (NuttX) has no /proc/net/route; its native layer reports the gateway.
if ((systemProperties.IPv4Routes == null) && (systemProperties.IPv6Routes == null))
{
AddNativeGatewayAddresses(collection, _linuxNetworkInterface.Index);
}

return new GatewayIPAddressInformationCollection(collection);
}

private struct GatewayContext
{
internal List<GatewayIPAddressInformation> _collection;
}

private static unsafe void AddNativeGatewayAddresses(List<GatewayIPAddressInformation> collection, int interfaceIndex)
{
GatewayContext context;
context._collection = collection;

// A failure leaves the collection as it is: no gateway is known.
Interop.Sys.EnumerateGatewayAddressesForInterface(&context, (uint)interfaceIndex, &OnGatewayFound);
}

[UnmanagedCallersOnly]
private static unsafe void OnGatewayFound(void* pContext, Interop.Sys.IpAddressInfo* gatewayAddressInfo)
{
GatewayContext* context = (GatewayContext*)pContext;

IPAddress ipAddress = new IPAddress(((ReadOnlySpan<byte>)gatewayAddressInfo->AddressBytes)[..gatewayAddressInfo->NumAddressBytes]);
context->_collection.Add(new SimpleGatewayIPAddressInformation(ipAddress));
}

private InternalIPAddressCollection GetDhcpServerAddresses()
{
List<IPAddress> internalCollection = new List<IPAddress>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ internal static class NetworkFiles
public const string SockstatFile = "/proc/net/sockstat";
public const string Sockstat6File = "/proc/net/sockstat6";
public const string SysClassNetFolder = "/sys/class/net";
public const string EtcResolvConfFile = "/etc/resolv.conf";
// Meadow.OS (NuttX) has no /etc; its DNS client reads the name servers from
// /meadow0/dns.conf (CONFIG_NETDB_RESOLVCONF_PATH), which uses the resolv.conf
// format and is written by the OS at boot.
public const string EtcResolvConfFile = "/meadow0/dns.conf";
public const string Tcp4ConnectionsFile = "/proc/net/tcp";
public const string Tcp6ConnectionsFile = "/proc/net/tcp6";
public const string Udp4ConnectionsFile = "/proc/net/udp";
Expand Down
6 changes: 6 additions & 0 deletions src/mono/cmake/nuttx-compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,10 @@
#define IFF_ALLMULTI 0
#endif

/* Meadow.OS interface flag: espcp (the ESP32 WiFi coprocessor driver) sets it
* on the interface it reports, so that the interface can be identified as
* WiFi. It must match IFF_WIFI in Meadow.OS F7MeadowOS/espcp/espcp_usrsock.h
* and uses a bit that NuttX <net/if.h> leaves free. */
#define MEADOW_IFF_WIFI (1 << 14)

#endif /* _NUTTX_COMPAT_H */
38 changes: 20 additions & 18 deletions src/mono/mono/arch/arm/thumb-codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -3040,18 +3040,20 @@ arm_asr_imm(void **code, int rd, int rm, int imm)

#define ARM_SAR_IMM(p, rd, rm, imm) arm_asr_imm((void **)&p, rd, rm, imm)

/*
* rd = rn >> rm (arithmetic). The 16-bit ASRS shifts its destination, so it
* can only be used when rd == rn; a shift is not commutative, so rd == rm must
* not swap the operands. Every other case is the 32-bit register-controlled
* shift (type ASR). The data processing (constant shift) encoding used before
* computed rn EOR rm.
*/
static __THUMB_INLINE__ void
arm_asr_register(void **code, int rd, int rn, int rm)
{
if ((rd < 8) && (rn < 8) && (rm < 8)) {
if (rd == rm)
arm_dpri16(code, rd, rn, 4);
else if (rd == rn)
arm_dpri16(code, rd, rm, 4);
else
arm_dpc32(code, rd, rn, rm, 0, 0, 4, 0);
} else
arm_dpc32(code, rd, rn, rm, 0, 0, 4, 0);
if ((rd < 8) && (rn < 8) && (rm < 8) && (rd == rn))
arm_dpri16(code, rd, rm, 4);
else
arm_rcs32(code, rd, rn, rm, 4, 0);
}

#define ARM_SAR_REG(p, rd, rn, rs) arm_asr_register((void **)&p, rd, rn, rs)
Expand Down Expand Up @@ -3931,18 +3933,18 @@ arm_ror_imm_rot(void **code, int rd, int rn, int imm, int rot, int cond)

#define ARM_ROR_REG_IMM(p, rd, rn, imm, rot) arm_ror_imm_rot((void **) &p, rd, rm, imm, rot, 0)

/*
* rd = rn ROR rm. As for arm_asr_register: the 16-bit RORS only when
* rd == rn, otherwise the 32-bit register-controlled shift (type ROR). The
* data processing (constant shift) encoding used before computed rn ORN rm.
*/
static __THUMB_INLINE__ void
arm_ror_register(void **code, int rd, int rn, int rm)
{
if ((rd < 8) && (rn < 8) && (rm < 8)) {
if (rd == rm)
arm_dpri16(code, rd, rn, 7);
else if (rd == rn)
arm_dpri16(code, rd, rm, 7);
else
arm_dpc32(code, rd, rn, rm, 0, 0, 6, 0);
} else
arm_dpc32(code, rd, rn, rm, 0, 0, 6, 0);
if ((rd < 8) && (rn < 8) && (rm < 8) && (rd == rn))
arm_dpri16(code, rd, rm, 7);
else
arm_rcs32(code, rd, rn, rm, 6, 0);
}

#define ARM_ROR_REG_REG(p, rd, rn, rm) arm_ror_register((void **) &p, rd, rn, rm)
Expand Down
54 changes: 54 additions & 0 deletions src/native/libs/System.Native/pal_interfaceaddresses.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <net/if.h>
#elif defined(__NuttX__)
#include <net/if.h>
#include <arpa/inet.h>
#endif
#include <netinet/in.h>
#include <string.h>
Expand Down Expand Up @@ -440,6 +441,28 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter
// OperationalState returns whether the interface can transmit data packets.
// The administrator must have enabled the interface (IFF_UP), and the cable must be plugged in (IFF_RUNNING).
nii->OperationalState = ((ifaddrsEntry->ifa_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) ? OperationalStatus_Up : OperationalStatus_Down;

#if defined(__NuttX__)
// NuttX getifaddrs() returns no link-layer (AF_PACKET/AF_LINK) entries. The
// hardware address is in ifa_data (a struct sockaddr from SIOCGIFHWADDR, the
// address in sa_data), and Meadow.OS marks its WiFi interface with
// MEADOW_IFF_WIFI, so take the type and the address from those. The NuttX
// loopback device does not set IFF_LOOPBACK, so it is recognised by name.
if ((strcmp(ifa_name, "lo") == 0) || ((ifaddrsEntry->ifa_flags & IFF_LOOPBACK) != 0))
{
nii->HardwareType = NetworkInterfaceType_Loopback;
}
else
{
nii->HardwareType = ((ifaddrsEntry->ifa_flags & MEADOW_IFF_WIFI) != 0) ? NetworkInterfaceType_Wireless80211 : NetworkInterfaceType_Ethernet;
}
if (ifaddrsEntry->ifa_data != NULL)
{
struct sockaddr* hwaddr = (struct sockaddr*)ifaddrsEntry->ifa_data;
nii->NumAddressBytes = IFHWADDRLEN;
memcpy_s(&nii->AddressBytes, sizeof_member(NetworkInterfaceInfo, AddressBytes), (uint8_t*)hwaddr->sa_data, IFHWADDRLEN);
}
#endif
}

if (ifaddrsEntry->ifa_addr == NULL)
Expand Down Expand Up @@ -696,6 +719,37 @@ int32_t SystemNative_EnumerateGatewayAddressesForInterface(void* context, uint32
free(buffer);
return 0;
}
#elif defined(__NuttX__)
// Meadow.OS keeps the gateway of the active network interface in its configuration,
// set when the network connects (WiFi through the ESP32 coprocessor has no NuttX
// routing table), and returns it as a dotted string. The OS answer is passed on as
// it is, 0.0.0.0 included: over WiFi the OS does not yet learn the DHCP gateway
// (Meadow.OS issue #703).
extern int meadow_os_get_gateway_address(char* buffer);

int32_t SystemNative_EnumerateGatewayAddressesForInterface(void* context, uint32_t interfaceIndex, GatewayAddressFound onGatewayFound)
{
char address[INET_ADDRSTRLEN];
struct in_addr gateway;

if (meadow_os_get_gateway_address(address) < 0)
{
errno = ENOTSUP;
return -1;
}

if (inet_pton(AF_INET, address, &gateway) == 1)
{
IpAddressInfo iai;
memset(&iai, 0, sizeof(IpAddressInfo));
iai.InterfaceIndex = interfaceIndex;
iai.NumAddressBytes = NUM_BYTES_IN_IPV4_ADDRESS;
memcpy_s(iai.AddressBytes, sizeof_member(IpAddressInfo, AddressBytes), &gateway.s_addr, sizeof(gateway.s_addr));
onGatewayFound(context, &iai);
}

return 0;
}
#else
int32_t SystemNative_EnumerateGatewayAddressesForInterface(void* context, uint32_t interfaceIndex, GatewayAddressFound onGatewayFound)
{
Expand Down