From 1d957df5cc0b9583af98d469f9aa1738a7e9c536 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sun, 14 Aug 2016 08:51:19 +0000 Subject: [PATCH] Bind to the local-link address rather than directly to the interface to allow many DHCPv6 clients on many interfaces. This works on all platforms. --- dhcp6.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/dhcp6.c b/dhcp6.c index 45fd5e3f..27aac291 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -3174,28 +3174,21 @@ dhcp6_open(struct dhcpcd_ctx *dctx) logger(dctx, LOG_WARNING, "setsockopt: SO_REUSEPORT: %m"); #endif -#ifdef SO_BINDTODEVICE - /* If we're not running in master mode, we can bind directly to the - * interface. This allows separate daemons to work on separate - * interfaces. */ if (!(dctx->options & DHCPCD_MASTER)) { - const struct interface *ifp; - struct ifreq ifr; + /* Bind to the link-local address to allow more than one + * DHCPv6 client to work. */ + struct interface *ifp; + struct ipv6_addr *ia; TAILQ_FOREACH(ifp, dctx->ifaces, next) { if (ifp->active) break; } - if (ifp != NULL) { - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); - if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, - sizeof(ifr)) == -1) - logger(dctx, LOG_WARNING, - "setsockopt: SO_BINDTODEVICE: %m"); + if ((ia = ipv6_linklocal(ifp)) != NULL) { + memcpy(&sa.sin6_addr, &ia->addr, sizeof(sa.sin6_addr)); + sa.sin6_scope_id = ifp->index; } } -#endif if (bind(ctx->dhcp_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) goto errexit; @@ -3253,6 +3246,9 @@ dhcp6_start1(void *arg) size_t i; const struct dhcp_compat *dhc; + if (ifp->ctx->ipv6->dhcp_fd == -1 && dhcp6_open(ifp->ctx) == -1) + return; + state = D6_STATE(ifp); /* If no DHCPv6 options are configured, match configured DHCPv4 options to DHCPv6 equivalents. */ @@ -3317,9 +3313,6 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state) if (!(ifp->options->options & DHCPCD_DHCP6)) return 0; - if (ifp->ctx->ipv6->dhcp_fd == -1 && dhcp6_open(ifp->ctx) == -1) - return -1; - ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state)); state = D6_STATE(ifp); if (state == NULL) -- 2.47.3