From bdbe76fd48617c781cb3e6154a76de96b64b4f54 Mon Sep 17 00:00:00 2001 From: lucannez64 <58551020+lucannez64@users.noreply.github.com> Date: Mon, 19 Oct 2026 20:24:19 +0200 Subject: [PATCH] Handle SIOCGIFMEDIA in the ioctl shim Vivox's network reachability provider calls SIOCGIFMEDIA for each interface and drops every interface whose ioctl fails. Darling passed the Darwin request through to Linux, which returns ENOTTY, so the SDK saw no usable interface and vx_req_connector_create failed with 1004. Return a synthetic active Ethernet/IEEE802.11 media record built from the host SIOCGIFFLAGS result, and add a standalone probe that fails on the old behavior. --- patches/xnu.patch | 80 ++++++++++++++++++++++++++++++++++++++ tools/riot-ifmedia-check.c | 58 +++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tools/riot-ifmedia-check.c diff --git a/patches/xnu.patch b/patches/xnu.patch index a02f9cd..5498085 100644 --- a/patches/xnu.patch +++ b/patches/xnu.patch @@ -6200,3 +6200,83 @@ diff --git a/darling/src/libsystem_kernel/emulation/src/linux_premigration/vchro ctxt->current_root = prefix_path; ctxt->current_root_len = prefix_path_len; } + +diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c +index f890ab2..8969577 100644 +--- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c ++++ b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/ioctl/socket.c +@@ -2,12 +2,29 @@ + + #include + #include +-#include + #include ++#include + #include + #include + #include + ++#include ++ ++extern int strcmp(const char* a, const char* b); ++extern int strncmp(const char* a, const char* b, size_t n); ++extern char* strncpy(char* destination, const char* source, size_t length); ++ ++#define LINUX_SIOCGIFFLAGS 0x8913 ++#define LINUX_IFNAMSIZ 16 ++ ++struct linux_ifreq { ++ char lifr_name[LINUX_IFNAMSIZ]; ++ union { ++ short lifr_flags; ++ char lifr_pad[24]; ++ }; ++}; ++ + int handle_socket(int fd, unsigned int cmd, void* arg, int* retval) + { + switch (cmd) +@@ -19,6 +36,43 @@ int handle_socket(int fd, unsigned int cmd, void* arg, int* retval) + case SIOCAIFADDR_IN6: // set IPv6 address + *retval = -ENOTSUP; + return IOCTL_HANDLED; ++ case SIOCGIFMEDIA: ++#ifdef SIOCGIFXMEDIA ++ case SIOCGIFXMEDIA: ++#endif ++ { ++ struct ifmediareq* ifmr = (struct ifmediareq*) arg; ++ struct linux_ifreq ifr; ++ int status; ++ ++ if (ifmr == NULL) ++ { ++ *retval = -EINVAL; ++ return IOCTL_HANDLED; ++ } ++ ++ ifr.lifr_name[LINUX_IFNAMSIZ - 1] = '\0'; ++ strncpy(ifr.lifr_name, ifmr->ifm_name, LINUX_IFNAMSIZ - 1); ++ status = __real_ioctl(fd, LINUX_SIOCGIFFLAGS, &ifr); ++ if (status < 0) ++ { ++ *retval = status; ++ return IOCTL_HANDLED; ++ } ++ ++ if (strncmp(ifmr->ifm_name, "wl", 2) == 0) ++ ifmr->ifm_current = IFM_IEEE80211 | IFM_AUTO; ++ else ++ ifmr->ifm_current = IFM_ETHER | IFM_AUTO; ++ ifmr->ifm_mask = 0; ++ ifmr->ifm_status = ((ifr.lifr_flags & IFF_UP) && (ifr.lifr_flags & IFF_RUNNING)) ++ ? (IFM_AVALID | IFM_ACTIVE) : IFM_AVALID; ++ ifmr->ifm_active = ifmr->ifm_current; ++ ifmr->ifm_count = 0; ++ ifmr->ifm_ulist = NULL; ++ *retval = 0; ++ return IOCTL_HANDLED; ++ } + } + return IOCTL_PASS; + } diff --git a/tools/riot-ifmedia-check.c b/tools/riot-ifmedia-check.c new file mode 100644 index 0000000..7e3167e --- /dev/null +++ b/tools/riot-ifmedia-check.c @@ -0,0 +1,58 @@ +// Vivox's network reachability provider calls SIOCGIFMEDIA on each interface +// and drops every interface whose ioctl fails. Darling used to pass the Darwin +// request through to Linux, which returns ENOTTY. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int check(const char *name, int required) { + int sock = socket(AF_INET, SOCK_DGRAM, 0); + struct ifmediareq ifmr; + memset(&ifmr, 0, sizeof(ifmr)); + strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name) - 1); + errno = 0; + int rc = ioctl(sock, SIOCGIFMEDIA, &ifmr); + close(sock); + int active = (ifmr.ifm_status & (IFM_AVALID | IFM_ACTIVE)) == (IFM_AVALID | IFM_ACTIVE); + int known_type = IFM_TYPE(ifmr.ifm_current) == IFM_ETHER || + IFM_TYPE(ifmr.ifm_current) == IFM_IEEE80211; + printf("IFMEDIA interface=%s rc=%d errno=%d current=0x%x status=0x%x active=%d type=%d\n", + name, rc, errno, ifmr.ifm_current, ifmr.ifm_status, active, known_type); + if (rc != 0) return required; + return required && (!active || !known_type); +} + +int main(int argc, char **argv) { + int failures = 0; + if (argc > 1) { + for (int i = 1; i < argc; i++) failures += check(argv[i], 1); + } else { + struct ifaddrs *interfaces = NULL; + char name[IFNAMSIZ] = {0}; + if (getifaddrs(&interfaces) != 0) { + printf("IFMEDIA getifaddrs failed errno=%d\n", errno); + return 1; + } + for (struct ifaddrs *entry = interfaces; entry; entry = entry->ifa_next) { + if (!entry->ifa_addr || entry->ifa_addr->sa_family != AF_INET) continue; + if (entry->ifa_flags & IFF_LOOPBACK) continue; + strncpy(name, entry->ifa_name, sizeof(name) - 1); + break; + } + freeifaddrs(interfaces); + if (!name[0]) { + printf("IFMEDIA no non-loopback IPv4 interface\n"); + return 1; + } + failures += check(name, 1); + } + printf("IFMEDIA_CHECK failures=%d\n", failures); + return failures ? 1 : 0; +}