diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/LinuxIPInterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/LinuxIPInterfaceProperties.cs index 6930f757dc6ef4..44b0e2d001f3cb 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/LinuxIPInterfaceProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/LinuxIPInterfaceProperties.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Runtime.Versioning; namespace System.Net.NetworkInformation @@ -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 _collection; + } + + private static unsafe void AddNativeGatewayAddresses(List 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)gatewayAddressInfo->AddressBytes)[..gatewayAddressInfo->NumAddressBytes]); + context->_collection.Add(new SimpleGatewayIPAddressInformation(ipAddress)); + } + private InternalIPAddressCollection GetDhcpServerAddresses() { List internalCollection = new List(); diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkFiles.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkFiles.cs index bc31a9fabf3072..dd318bb7443791 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkFiles.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkFiles.cs @@ -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"; diff --git a/src/mono/cmake/nuttx-compat.h b/src/mono/cmake/nuttx-compat.h index 7f56fc3c96fc9f..668acf4637a0c7 100644 --- a/src/mono/cmake/nuttx-compat.h +++ b/src/mono/cmake/nuttx-compat.h @@ -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 leaves free. */ +#define MEADOW_IFF_WIFI (1 << 14) + #endif /* _NUTTX_COMPAT_H */ diff --git a/src/mono/mono/arch/arm/thumb-codegen.h b/src/mono/mono/arch/arm/thumb-codegen.h index fc37c16e9d6bc5..efc0be67cfc6e7 100644 --- a/src/mono/mono/arch/arm/thumb-codegen.h +++ b/src/mono/mono/arch/arm/thumb-codegen.h @@ -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) @@ -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) diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c index dfaafe5c22c87e..26bc21e7a0fe6a 100644 --- a/src/native/libs/System.Native/pal_interfaceaddresses.c +++ b/src/native/libs/System.Native/pal_interfaceaddresses.c @@ -27,6 +27,7 @@ #include #elif defined(__NuttX__) #include +#include #endif #include #include @@ -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) @@ -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) {