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

Reply via email to