On 2025/12/22 10:48, Courtney Hicks wrote:
> I recently updated my router to the latest -current as well as ports,
> which upgraded my previous version of dhcpcd 10.2.4v0 to 10.3.0v0. I
> eventually realized I was no longer getting IPv6 addresses on my
> clients. I checked my logs and got a bunch of "no buffer space
> available" messages on my LAN interfaces that I have PDs going to. 
> 
> dhcpcd[55787]: if_getmtu: No buffer space available
> 
> I also noticed that this was messing with arp info too for some reason.
> This is my config:
> 
> ipv6only
> noipv6rs
> duid
> persistent
> option rapid_commit
> require dhcp_server_identifier
> 
> script ""
> 
> allowinterfaces igc0 ixl0 vlan5
> interface igc0
>         ipv6rs
>         ia_na 1
>         ia_pd 2/::/60 ixl0/1/64 vlan5/2/64
> 
> I built dhcpcd 10.2.4v0 and replaced 10.3.0v0 and everything is working
> as expected. I imagine this is a dhcpcd bug, but I wanted to bring this
> up here on the ports list.
> 
> Courtney
> 
> PS: I hope Thunderbird formats my line width to 72 correctly. My
> apologies if it does not and breaks netiquette
> 

On 2025/12/27 14:43, Zack Newman wrote:
> Yeah, this is a known issue[^1]. If you compile the code yourself with
> the proposed patch, it should work[^2]. Note I don't run -current, so
> I'm merely speaking as a reader. I recommend staying in the loop with
> upstream seeing how disruptive issues with dhcpcd can be. I always look
> at the issues on GitHub before updating it.
> 
> [^1]: https://github.com/NetworkConfiguration/dhcpcd/issues/555
> [^2]: 
> https://github.com/NetworkConfiguration/dhcpcd/issues/555#issuecomment-3546211800
> 


Can you try this please? It is the result of the set of patches from
https://github.com/NetworkConfiguration/dhcpcd/pull/556

Would be good to comment on the upstream PR if it helps too.

Index: Makefile
===================================================================
RCS file: /cvs/ports/net/dhcpcd/Makefile,v
diff -u -p -r1.119 Makefile
--- Makefile    17 Nov 2025 18:36:41 -0000      1.119
+++ Makefile    28 Dec 2025 14:39:02 -0000
@@ -1,6 +1,7 @@
 COMMENT=       DHCPv4/IPv4LL/IPv6RS/DHCPv6 quad stack client
 
 V=             10.3.0
+REVISION=      0
 DISTNAME=      dhcpcd-$V
 EXTRACT_SUFX=  .tar.xz
 
Index: patches/patch-src_privsep-root_c
===================================================================
RCS file: patches/patch-src_privsep-root_c
diff -N patches/patch-src_privsep-root_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_privsep-root_c    28 Dec 2025 14:39:02 -0000
@@ -0,0 +1,253 @@
+https://patch-diff.githubusercontent.com/raw/NetworkConfiguration/dhcpcd/pull/556.patch
+
+Index: src/privsep-root.c
+--- src/privsep-root.c.orig
++++ src/privsep-root.c
+@@ -71,21 +71,20 @@ struct psr_ctx {
+       struct psr_error psr_error;
+       size_t psr_datalen;
+       void *psr_data;
+-      size_t psr_mdatalen;
+-      void *psr_mdata;
+-      bool psr_usemdata;
++      bool psr_mallocdata;
+ };
+ 
+ static ssize_t
+-ps_root_readerrorcb(struct psr_ctx *psr_ctx)
++ps_root_readerrorcb(struct psr_ctx *pc)
+ {
+-      struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx;
++      struct dhcpcd_ctx *ctx = pc->psr_ctx;
+       int fd = PS_ROOT_FD(ctx);
+-      struct psr_error *psr_error = &psr_ctx->psr_error;
++      struct psr_error *psr_error = &pc->psr_error;
+       struct iovec iov[] = {
+               { .iov_base = psr_error, .iov_len = sizeof(*psr_error) },
+-              { .iov_base = NULL, .iov_len = 0 },
++              { .iov_base = pc->psr_data, .iov_len = pc->psr_datalen },
+       };
++      struct msghdr msg = { .msg_iov = iov, .msg_iovlen = __arraycount(iov) };
+       ssize_t len;
+ 
+ #define PSR_ERROR(e)                          \
+@@ -98,81 +97,84 @@ ps_root_readerrorcb(struct psr_ctx *psr_ctx)
+       if (eloop_waitfd(fd) == -1)
+               PSR_ERROR(errno);
+ 
+-      len = recv(fd, psr_error, sizeof(*psr_error), MSG_PEEK);
++      if (!pc->psr_mallocdata)
++              goto recv;
++
++      /* We peek at the psr_error structure to tell us how much of a buffer
++       * we need to read the whole packet. */
++      msg.msg_iovlen--;
++      len = recvmsg(fd, &msg, MSG_PEEK | MSG_WAITALL);
+       if (len == -1)
+               PSR_ERROR(errno);
+-      else if ((size_t)len < sizeof(*psr_error))
+-              PSR_ERROR(EINVAL);
+ 
+-      if (psr_error->psr_datalen > SSIZE_MAX)
+-              PSR_ERROR(ENOBUFS);
+-      if (psr_ctx->psr_usemdata &&
+-          psr_error->psr_datalen > psr_ctx->psr_mdatalen)
+-      {
+-              void *d = realloc(psr_ctx->psr_mdata, psr_error->psr_datalen);
+-              if (d == NULL)
+-                      PSR_ERROR(errno);
+-              psr_ctx->psr_mdata = d;
+-              psr_ctx->psr_mdatalen = psr_error->psr_datalen;
++      /* After this point, we MUST do another recvmsg even on a failure
++       * to remove the message after peeking. */
++      if ((size_t)len < sizeof(*psr_error)) {
++              /* We can't use the header to work out buffers, so
++               * remove the message and bail. */
++              (void)recvmsg(fd, &msg, MSG_WAITALL);
++              PSR_ERROR(EINVAL);
+       }
+-      if (psr_error->psr_datalen != 0) {
+-              if (psr_ctx->psr_usemdata)
+-                      iov[1].iov_base = psr_ctx->psr_mdata;
+-              else {
+-                      if (psr_error->psr_datalen > psr_ctx->psr_datalen)
+-                              PSR_ERROR(ENOBUFS);
+-                      iov[1].iov_base = psr_ctx->psr_data;
+-              }
++
++      /* No data to read? Unlikely but ... */
++      if (psr_error->psr_datalen == 0)
++              goto recv;
++
++      pc->psr_data = malloc(psr_error->psr_datalen);
++      if (pc->psr_data != NULL) {
++              iov[1].iov_base = pc->psr_data;
+               iov[1].iov_len = psr_error->psr_datalen;
++              msg.msg_iovlen++;
+       }
+ 
+-      len = readv(fd, iov, __arraycount(iov));
++recv:
++      len = recvmsg(fd, &msg, MSG_WAITALL);
+       if (len == -1)
+               PSR_ERROR(errno);
+-      else if ((size_t)len != sizeof(*psr_error) + psr_error->psr_datalen)
++      else if ((size_t)len < sizeof(*psr_error))
+               PSR_ERROR(EINVAL);
++      else if (msg.msg_flags & MSG_TRUNC)
++              PSR_ERROR(ENOBUFS);
++      else if ((size_t)len != sizeof(*psr_error) + psr_error->psr_datalen) {
++              logerrx("%s: recvmsg returned %zd, expecting %zu", __func__,
++                  len, sizeof(*psr_error) + psr_error->psr_datalen);
++              PSR_ERROR(EBADMSG);
++      }
+       return len;
+ }
+ 
+ ssize_t
+ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
+ {
+-      struct psr_ctx *pc = ctx->ps_root->psp_data;
++      struct psr_ctx pc = {
++              .psr_ctx = ctx,
++              .psr_data = data,
++              .psr_datalen = len,
++              .psr_mallocdata = false
++      };
+ 
+-      pc->psr_data = data;
+-      pc->psr_datalen = len;
+-      pc->psr_usemdata = false;
+-      ps_root_readerrorcb(pc);
++      ps_root_readerrorcb(&pc);
+ 
+-      errno = pc->psr_error.psr_errno;
+-      return pc->psr_error.psr_result;
++      errno = pc.psr_error.psr_errno;
++      return pc.psr_error.psr_result;
+ }
+ 
+ ssize_t
+ ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
+ {
+-      struct psr_ctx *pc = ctx->ps_root->psp_data;
+-      void *d;
++      struct psr_ctx pc = {
++              .psr_ctx = ctx,
++              .psr_data = NULL,
++              .psr_datalen = 0,
++              .psr_mallocdata = true
++      };
+ 
+-      pc->psr_usemdata = true;
+-      ps_root_readerrorcb(pc);
++      ps_root_readerrorcb(&pc);
+ 
+-      if (pc->psr_error.psr_datalen != 0) {
+-              if (pc->psr_error.psr_datalen > pc->psr_mdatalen) {
+-                      errno = EINVAL;
+-                      return -1;
+-              }
+-              d = malloc(pc->psr_error.psr_datalen);
+-              if (d == NULL)
+-                      return -1;
+-              memcpy(d, pc->psr_mdata, pc->psr_error.psr_datalen);
+-      } else
+-              d = NULL;
+-
+-      errno = pc->psr_error.psr_errno;
+-      *data = d;
+-      *len = pc->psr_error.psr_datalen;
+-      return pc->psr_error.psr_result;
++      errno = pc.psr_error.psr_errno;
++      *data = pc.psr_data;
++      *len = pc.psr_error.psr_datalen;
++      return pc.psr_error.psr_result;
+ }
+ 
+ static ssize_t
+@@ -196,6 +198,8 @@ ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t res
+       logdebugx("%s: result %zd errno %d", __func__, result, errno);
+ #endif
+ 
++      if (len == 0)
++              msg.msg_iovlen = 1;
+       err = sendmsg(fd, &msg, MSG_EOR);
+ 
+       /* Error sending the message? Try sending the error of sending. */
+@@ -204,8 +208,8 @@ ps_root_writeerror(struct dhcpcd_ctx *ctx, ssize_t res
+                   __func__, result, data, len);
+               psr.psr_result = err;
+               psr.psr_errno = errno;
+-              iov[1].iov_base = NULL;
+-              iov[1].iov_len = 0;
++              psr.psr_datalen = 0;
++              msg.msg_iovlen = 1;
+               err = sendmsg(fd, &msg, MSG_EOR);
+       }
+ 
+@@ -602,7 +606,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, st
+               break;
+       }
+ 
+-      err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen);
++      err = ps_root_writeerror(ctx, err, rdata, rlen);
+       if (free_rdata)
+               free(rdata);
+       return err;
+@@ -843,17 +847,6 @@ ps_root_log(void *arg, unsigned short events)
+               logerr(__func__);
+ }
+ 
+-static void
+-ps_root_freepsdata(void *arg)
+-{
+-      struct psr_ctx *pc = arg;
+-
+-      if (pc == NULL)
+-              return;
+-      free(pc->psr_mdata);
+-      free(pc);
+-}
+-
+ pid_t
+ ps_root_start(struct dhcpcd_ctx *ctx)
+ {
+@@ -864,7 +857,6 @@ ps_root_start(struct dhcpcd_ctx *ctx)
+       struct ps_process *psp;
+       int logfd[2] = { -1, -1}, datafd[2] = { -1, -1};
+       pid_t pid;
+-      struct psr_ctx *pc;
+ 
+       if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, logfd) == -1)
+               return -1;
+@@ -883,27 +875,15 @@ ps_root_start(struct dhcpcd_ctx *ctx)
+               return -1;
+ #endif
+ 
+-      pc = calloc(1, sizeof(*pc));
+-      if (pc == NULL)
+-              return -1;
+-      pc->psr_ctx = ctx;
+-
+       psp = ctx->ps_root = ps_newprocess(ctx, &id);
+       if (psp == NULL)
+-      {
+-              free(pc);
+               return -1;
+-      }
+-      psp->psp_freedata = ps_root_freepsdata;
++
+       strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name));
+       pid = ps_startprocess(psp, ps_root_recvmsg, NULL,
+           ps_root_startcb, PSF_ELOOP);
+-      if (pid == -1) {
+-              free(pc);
++      if (pid == -1)
+               return -1;
+-      }
+-
+-      psp->psp_data = pc;
+ 
+       if (pid == 0) {
+               ctx->ps_log_fd = logfd[0]; /* Keep open to pass to processes */
Index: patches/patch-src_privsep_c
===================================================================
RCS file: patches/patch-src_privsep_c
diff -N patches/patch-src_privsep_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_privsep_c 28 Dec 2025 14:39:02 -0000
@@ -0,0 +1,17 @@
+https://patch-diff.githubusercontent.com/raw/NetworkConfiguration/dhcpcd/pull/556.patch
+
+Index: src/privsep.c
+--- src/privsep.c.orig
++++ src/privsep.c
+@@ -761,11 +761,6 @@ ps_freeprocess(struct ps_process *psp)
+ 
+       TAILQ_REMOVE(&ctx->ps_processes, psp, next);
+ 
+-      if (psp->psp_freedata != NULL)
+-              psp->psp_freedata(psp->psp_data);
+-      else
+-              free(psp->psp_data);
+-
+       if (psp->psp_fd != -1) {
+               eloop_event_delete(ctx->eloop, psp->psp_fd);
+               close(psp->psp_fd);
Index: patches/patch-src_privsep_h
===================================================================
RCS file: patches/patch-src_privsep_h
diff -N patches/patch-src_privsep_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_privsep_h 28 Dec 2025 14:39:02 -0000
@@ -0,0 +1,14 @@
+https://patch-diff.githubusercontent.com/raw/NetworkConfiguration/dhcpcd/pull/556.patch
+
+Index: src/privsep.h
+--- src/privsep.h.orig
++++ src/privsep.h
+@@ -184,8 +184,6 @@ struct ps_process {
+       char psp_name[PSP_NAMESIZE];
+       uint16_t psp_proto;
+       const char *psp_protostr;
+-      void *psp_data;
+-      void (*psp_freedata)(void *);
+       bool psp_started;
+ 
+ #ifdef INET

Reply via email to