From a9d2e140046908f62a52311d2eff4065635e4191 Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Sun, 25 Oct 2026 15:38:06 +0100 Subject: [PATCH] net: an interface that appears after boot starts the stack With the native r8169 out of the registry, the TUF A15 boots with no network device; netinit() saw none and left the stack off, and net_attach_late() then refused every interface that came later -- its comment assumed netinit() was still to run. Linux's r8169 under LDLS got as far as registering ldls0 and was turned away. A late interface now starts the stack, whose first act is to attach every device there is; net_eth_attach() refuses a device it already has, for the window in which both could offer it. LDLS says which refusal it got: EBUSY is another process, anything else is the kernel. Tested in QEMU with -nic none and netecho: no interface at boot, then ldls0 with a DHCP lease and ping answered. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4 --- kernel/net/lwip/netif_eth.c | 5 +++++ kernel/net/net.c | 12 ++++++++++-- ldls/kpi/net.c | 8 ++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/kernel/net/lwip/netif_eth.c b/kernel/net/lwip/netif_eth.c index a16b5dd..764a178 100644 --- a/kernel/net/lwip/netif_eth.c +++ b/kernel/net/lwip/netif_eth.c @@ -110,6 +110,11 @@ net_eth_attach(struct device *dev) if (nifs >= NETIF_MAX || dev == 0) return -1; + // Once only: a device that appears while netd is starting can be offered + // both by netd's boot-time walk and by net_attach_late. + for (int i = 0; i < nifs; i++) + if (ifs[i].used && ifs[i].dev == dev) + return -1; struct eth_if *e = &ifs[nifs]; e->dev = dev; diff --git a/kernel/net/net.c b/kernel/net/net.c index 5fbc2b7..b526350 100644 --- a/kernel/net/net.c +++ b/kernel/net/net.c @@ -194,8 +194,16 @@ net_attach_late(struct device *d) { int idx; - if (!net_ready) - return -1; // netinit() has not run; it will pick this up + // No stack yet. Either netinit() is still to run, or it ran on a machine + // with no network device and left the stack off -- which is every boot + // now that the laptop's RTL8168 is driven by a process (LDLS) that only + // appears later. Start it: net_thread's first act is to attach every + // network device there is, and that now includes this one. + if (!net_ready) { + if (!net_started) + netinit(); + return net_started ? 0 : -1; + } lwip_sys_lock(); idx = net_eth_attach(d); diff --git a/ldls/kpi/net.c b/ldls/kpi/net.c index e702a0d..ae8b14c 100644 --- a/ldls/kpi/net.c +++ b/ldls/kpi/net.c @@ -220,8 +220,12 @@ kpi_register_netdev(void *dev) c.pad[0] = c.pad[1] = 0; c.name[0] = 'l'; c.name[1] = 'd'; c.name[2] = 'l'; c.name[3] = 's'; - if (ioctl(kpi.netfd, NETUSERIOC_CREATE, &c) < 0) { - kpi_log("kpi: /dev/netdev is already somebody else's\n"); + int r = ioctl(kpi.netfd, NETUSERIOC_CREATE, &c); + if (r < 0) { + // -16 EBUSY is another process; anything else is the kernel refusing. + kpi_log(r == -16 ? "kpi: /dev/netdev is already somebody else's\n" + : "kpi: the kernel would not take the interface, error "); + if (r != -16) { kpi_lognum(r); kpi_log("\n"); } close(kpi.netfd); kpi.netfd = -1; return -1;