Roy Marples, le mar. 02 juin 2026 09:14:42 +0100, a ecrit: > Knowing that Hurd uses NetBSD drivers
It doesn't yet, netdde is based on Linux. rumpnet (on its way) will be based on BSD. Samuel > and knowing I'm very intimate with the > NetBSD network stack, how true is it that IFF_RUNNING reflects carrier state? > > On BSD, carrier state is part of if_data - if_link_state. > Every driver in every BSD supports this even if LINK_STATE_UNKNOWN. > > Some drivers (but not all) also report link state via MEDIA. > MacOS deviates from BSD here and does not have if_link_state and soely relies > on MEDIA. > > On every BSD IFF_RUNNING means that kernel resources have been allocated (ie > tx > /rx rings setup etc etc). > On Linux IFF_RUNNING means yes we have a carrier. > > Roy > > > > From: Martin-Éric Racine <[email protected]> > To: "Roy Marples"<[email protected]> > Date: Sun, 03 May 2026 09:31:19 +0100 > Subject: Fwd: [PATCH 4/6] New GNU/Hurd backend > > > ---------- Forwarded message --------- > Lähettäjä: Joan Lledó <[1][email protected]> > Date: ma 6.4.2026 klo 16.00 > Subject: [PATCH 4/6] New GNU/Hurd backend > To: <[2][email protected]> > Cc: <[3][email protected]>, Joan Lledó <[4][email protected]> > > > From: Joan Lledó <[5][email protected]> > > This adds a new main module to port dhcpdp to the Hurd. > > * The Hurd module relies on libpcap to work with BPF filters. > * Addresses and routes are configured via ioctls to the stack. > * Only IPv4 over Ethernet is supported so far. > * Privilege separation and detection of network configuration changes > is not implemented yet. > * libpcap and liblwip are required dependencies. > * Only 32-bit Hurd has been tested so far. > --- > src/if-hurd.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 448 insertions(+) > create mode 100644 src/if-hurd.c > > diff --git a/src/if-hurd.c b/src/if-hurd.c > new file mode 100644 > index 00000000..00482af8 > --- /dev/null > +++ b/src/if-hurd.c > @@ -0,0 +1,448 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > +/* > + * libpcap interface driver for dhcpcd > + * Copyright (c) 2025 Joan Lledó <[6][email protected]> > + * All rights reserved > + > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE > GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY > WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include <string.h> > +#include <sys/ioctl.h> > +#include <net/if_arp.h> > +#include <hurd.h> > +#include <hurd/paths.h> > +#include <hurd/pfinet.h> > +#include <device/device.h> > + > +#include "logerr.h" > +#include "if.h" > +#include "dhcpcd.h" > + > +#define ETH_HWADDR_LEN 6 > + > +/* Get the MAC address from an array of int */ > +#define GET_HWADDR_BYTE(x,n) (((unsigned char*)x)[n]) > + > +/* > + * We should just use `struct ifrtreq` from net/route.h instead of > defining this. > + * Regrettably, dhcpcd defines some macros inside `struct rt` that > conflict with > + * `struct ifrtreq` fields, so we need to mimic `struct ifrtreq` here, > but > + * renaming the fields. > + */ > +struct kroute { > + char ifname[IF_NAMESIZE]; > + in_addr_t dest; > + in_addr_t mask; > + in_addr_t gateway; > + int flags; > + int mtu; > + int metric; > + char padding[sizeof(int) * 4]; > +}; > + > +int > +if_getssid(__unused struct interface *ifp) { > + /* Not supported. Returning -1 means interface is not wireless */ > + errno = EOPNOTSUPP; > + return -1; > +} > + > +bool > +if_roaming(__unused struct interface *ifp) { > + /* Not supported */ > + errno = EOPNOTSUPP; > + return false; > +} > + > +static int > +if_copyrt(struct dhcpcd_ctx *ctx, struct rt *dest, struct kroute *src) { > + struct interface *ifp; > + > + ifp = if_find(ctx->ifaces, src->ifname); > + if (ifp == NULL) { > + logerr("%s: interface not found: %s", __func__, src->ifname); > + return -1; > + } > + > + memset(dest, 0, sizeof(struct rt)); > + > + dest->rt_ifp = ifp; > + dest->rt_ss_dest.sin.sin_family = AF_INET; > + dest->rt_ss_dest.sin.sin_len = sizeof(struct sockaddr_in); > + dest->rt_ss_dest.sin.sin_addr.s_addr = src->dest; > + dest->rt_ss_netmask.sin.sin_family = AF_INET; > + dest->rt_ss_netmask.sin.sin_len = sizeof(struct sockaddr_in); > + dest->rt_ss_netmask.sin.sin_addr.s_addr = src->mask; > + dest->rt_ss_gateway.sin.sin_family = AF_INET; > + dest->rt_ss_gateway.sin.sin_len = sizeof(struct sockaddr_in); > + dest->rt_ss_gateway.sin.sin_addr.s_addr = src->gateway; > + dest->rt_flags = (unsigned int)src->flags; > + dest->rt_mtu = (unsigned int)src->mtu; > +#ifdef HAVE_ROUTE_METRIC > + dest->rt_metric = (unsigned int)src->metric; > +#endif > + > + return 0; > +} > + > +static int > +if_copykrt(struct kroute *dst, const struct rt *src) { > + memset(dst, 0, sizeof(struct kroute)); > + > + strncpy(dst->ifname, src->rt_ifp->name, IF_NAMESIZE); > + dst->dest = src->rt_ss_dest.sin.sin_addr.s_addr;; > + dst->mask = src->rt_ss_netmask.sin.sin_addr.s_addr; > + dst->gateway = src->rt_ss_gateway.sin.sin_addr.s_addr; > + dst->flags = (int)src->rt_flags; > + dst->mtu = (int)src->rt_mtu; > +#ifdef HAVE_ROUTE_METRIC > + dst->metric = (int)src->rt_metric; > +#endif > + > + /* Set flags. Required by pfinet, ignored by lwip */ > + > + /* All dhcp routes must be marked as static */ > + dst->flags |= RTF_STATIC; > + > + /* Flag route type */ > + if (dst->mask == INADDR_NONE) > + /* All ones netmask means host route */ > + dst->flags |= RTF_HOST; > + else if (dst->mask != INADDR_ANY) > + /* Subnet route */ > + dst->flags &= ~RTF_HOST; > + else if (dst->gateway != INADDR_ANY) > + /* Netmask is any, and we got a gateway so default route */ > + dst->flags |= RTF_GATEWAY; > + > + return 0; > +} > + > +/* Get all routes for existing interfaces and add them to th RB tree */ > +int > +if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *routes, int af) { > + mach_port_t pfinet; > + char socket_inet[32]; > + char *raw_data; > + struct kroute *kroutes; > + unsigned int i, len = 0, kroutes_count; > + struct rt rt, *rtn = NULL; > + error_t err; > + > + snprintf(socket_inet, sizeof(socket_inet), _SERVERS_SOCKET "/%d", af); > + pfinet = file_name_lookup (socket_inet, O_RDONLY, 0); > + if (pfinet == MACH_PORT_NULL) { > + logerr("%s: cannot open file: %s", __func__, socket_inet); > + return -1; > + } > + > + err = pfinet_getroutes (pfinet, (vm_size_t)-1, &raw_data, &len); > + if (err) { > + errno = err; > + logerr("%s: cannot get routes from stack", __func__); > + goto errout; > + } > + > + kroutes = (struct kroute *)raw_data; > + kroutes_count = len / sizeof(struct kroute); > + > + for (i = 0; i < kroutes_count; i++) { > + if (if_copyrt(ctx, &rt, &kroutes[i]) != 0) > + goto errout; > + > + if ((rtn = rt_new(rt.rt_ifp)) == NULL) { > + goto errout; > + } > + > + memcpy(rtn, &rt, sizeof(*rtn)); > + > + if (rb_tree_insert_node(routes, rtn) != rtn) > + rt_free(rtn); > + } > + > + mach_port_deallocate (mach_task_self (), pfinet); > + vm_deallocate (mach_task_self(), (vm_address_t)raw_data, len); > + > + return 0; > + > +errout: > + mach_port_deallocate (mach_task_self (), pfinet); > + > + if (raw_data) > + vm_deallocate (mach_task_self(), (vm_address_t)raw_data, len); > + > + return -1; > +} > + > +int > +if_vimaster(__unused struct dhcpcd_ctx *ctx, __unused const char *ifname) > { > + /* Used mostly for wlan. Not supported */ > + errno = EOPNOTSUPP; > + return -1; > +} > + > +#ifdef INET > +int > +if_route(unsigned char cmd, const struct rt *rt) { > + struct dhcpcd_ctx *ctx; > + struct kroute krt; > + > + if (cmd == RTM_CHANGE) { > + /* > + * Asked to change route, the hurd doesn't provide a way to do this, > + * available ioctls only allow adding and deleting. > + * ESRCH is the expected error in this scenario. > + */ > + errno = ESRCH; > + return -1; > + } > + > + ctx = rt->rt_ifp->ctx; > + > + if_copykrt(&krt, rt); > + return if_ioctl(ctx, cmd == RTM_DELETE ? SIOCDELRT : SIOCADDRT, > &krt, sizeof(krt)); > +} > + > +static int > +if_ioctl_addr(struct dhcpcd_ctx *ctx, const char *ifname, > + const struct in_addr *addr, ioctl_request_t cmd) { > + struct ifreq ifr; > + struct sockaddr_in *sin; > + > + memset(&ifr, 0, sizeof(ifr)); > + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); > + sin = (struct sockaddr_in *)&ifr.ifr_addr; > + sin->sin_family = AF_INET; > + sin->sin_addr = *addr; > + sin->sin_len = sizeof(struct sockaddr_in); > + > + return if_ioctl(ctx, cmd, &ifr, sizeof(ifr)); > +} > + > +int > +if_address(unsigned char cmd, const struct ipv4_addr *ia) { > + int err; > + struct in_addr addr; > + > + if (cmd == RTM_DELADDR) { > + addr.s_addr = ia->addr.s_addr; > + err = if_ioctl_addr(ia->iface->ctx, ia->iface->name, &addr, > SIOCDIFADDR); > + if (err) { > + logerr("%s: cannot delete address", __func__); > + return -1; > + } > + > + return 0; > + } > + > + addr.s_addr = ia->addr.s_addr; > + err = if_ioctl_addr(ia->iface->ctx, ia->iface->name, &addr, > SIOCSIFADDR); > + if (err) { > + logerr("%s: cannot set address", __func__); > + return -1; > + } > + > + addr.s_addr = ia->mask.s_addr; > + err = if_ioctl_addr(ia->iface->ctx, ia->iface->name, &addr, > SIOCSIFNETMASK); > + if (err) { > + logerr("%s: cannot set network mask", __func__); > + return -1; > + } > + > + addr.s_addr = ia->brd.s_addr; > + err = if_ioctl_addr(ia->iface->ctx, ia->iface->name, &addr, > SIOCSIFBRDADDR); > + if (err && errno != ENOTTY) { > + /* We have to accept ENOTTY as a success state here because lwip doesn't > + * accept setting a broadcast address, it's a computed value. > + * About pfinet, we expect to get a ENOTTY only when it doesn't get an > + * authorized user. Not possible here because in that case previous calls > + * would fail and the code wouldn't reach here. > + */ > + logerr("%s: cannot set broadcast address", __func__); > + return -1; > + } > + > + return 0; > +} > + > +int > +if_addrflags(__unused const struct interface *ifp, __unused const > struct in_addr *addr, > + __unused const char *alias) { > + /* Not supported. Set flags to 0 */ > + return 0; > +} > +#endif > + > +#ifdef INET6 > +int > +if_address6(__unused unsigned char cmd, __unused const struct ipv6_addr > *ia) { > + /* TODO */ > + return -1; > +} > + > +int > +if_getlifetime6(__unused struct ipv6_addr *addr) { > + /* TODO */ > + return -1; > +} > + > +int > +if_addrflags6(__unused const struct interface *ifp, __unused const > struct in6_addr *addr, > + __unused const char *alias) { > + /* TODO */ > + return -1; > +} > + > +void > +if_setup_inet6(__unused const struct interface *ifp) { > + /* TODO */ > +} > + > +int > +if_applyra(__unused const struct ra *rap) { > + /* TODO */ > + return -1; > +} > +#endif > + > +#ifdef PRIVSEP > +ssize_t > +ps_root_os(__unused struct dhcpcd_ctx *ctx, __unused struct ps_msghdr > *psm, __unused struct msghdr *msg, > + __unused void **rdata, __unused size_t *rlen, __unused bool *free_data) > { > + /* TODO */ > + return -1; > +} > +#endif > + > +int > +os_init(void) { > + /* Not needed for now */ > + return 0; > +} > + > +/* > + * Initialize the given interface. > + * Try to get its MAC address and index > + */ > +int > +if_init(struct interface *ifp) { > + struct ifreq ifr; > + > + memset(&ifr, 0, sizeof(ifr)); > + strlcpy(ifr.ifr_name, ifp->name, IFNAMSIZ); > + > + /* Don't try to get HW address for loopback interfaces */ > + if ((ifp->flags & IFF_LOOPBACK) == 0) { > + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1) { > + logerr("%s: SIOCGIFHWADDR", ifp->name); > + return -1; > + } > + memcpy(ifp->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_HWADDR_LEN); > + ifp->hwtype = ifr.ifr_hwaddr.sa_family; > + ifp->hwlen = ifr.ifr_hwaddr.sa_len; > + } > + > + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1) { > + logerr("%s: SIOCGIFINDEX", ifp->name); > + return -1; > + } > + ifp->index = (unsigned int)ifr.ifr_ifindex; > + > + return 0; > +} > + > +int > +if_opensockets_os(__unused struct dhcpcd_ctx *ctx) { > + ctx->link_fd = -1; > + > + return 0; > +} > + > +void > +if_closesockets_os(__unused struct dhcpcd_ctx *ctx) { > + /* Nothing to do, as link_fd is not initialized */ > +} > + > +int > +if_conf(__unused struct interface *ifp) { > + /* Not needed for now */ > + return 0; > +} > + > +int > +if_handlelink(__unused struct dhcpcd_ctx *ctx) { > + /* No needed if link_fd is not initialized */ > + return 0; > +} > + > +int > +if_setmac(__unused struct interface *ifp, __unused void *mac, > __unused uint8_t maclen) { > + errno = EOPNOTSUPP; > + return -1; > +} > + > +unsigned short > +if_vlanid(__unused const struct interface *ifp) { > + /* We don't support vlans for now */ > + return 0; > +} > + > +int > +if_carrier(struct interface *ifp, __unused const void *ifadata) { > + struct ifreq ifr; > + > + memset(&ifr, 0, sizeof(ifr)); > + strlcpy(ifr.ifr_name, ifp->name, IFNAMSIZ); > + > + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1) { > + logerr("%s: SIOCGIFFLAGS", ifp->name); > + return LINK_UNKNOWN; > + } > + > + if (ifr.ifr_flags & IFF_RUNNING) > + return LINK_UP; > + > + return LINK_DOWN; > +} > + > +bool > +if_ignore(__unused struct dhcpcd_ctx *ctx, __unused const char *ifname) { > + /* > + * Return `true` for interfaces we want dhcpcd to ignore. > + * > + * Other OSs use this to ignore taps, bridges, and other kinds of > + * virtual interfaces. > + * > + * We don't use this for now. > + */ > + return false; > +} > + > +int > +if_machinearch(__unused char *str, __unused size_t len) { > + /* > + * dhcpcd already has uname info. > + * We don't need to add extra architecture info for now. > + */ > + return 0; > +} > -- > 2.50.1
