return -1;
}
+ /* In non master mode we listen and send from fixed addresses.
+ * We should try and match an address we have to unicast to,
+ * but for now this is the safest policy. */
+ if (unicast != NULL && !(ifp->ctx->options & DHCPCD_MASTER)) {
+ logdebugx("%s: ignoring unicast option as not master",
+ ifp->name);
+ unicast = NULL;
+ }
+
#ifdef AUTH
auth_len = 0;
if (ifo->auth.options & DHCPCD_AUTH_SEND) {
uint8_t neg;
const char *broad_uni;
const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
+ struct ipv6_addr *lla;
+ int s;
if (!callback && ifp->carrier == LINK_DOWN)
return 0;
#endif
state = D6_STATE(ifp);
+ lla = ipv6_linklocal(ifp);
/* We need to ensure we have sufficient scope to unicast the address */
/* XXX FIXME: We should check any added addresses we have like from
* a Router Advertisement */
if (IN6_IS_ADDR_UNSPECIFIED(&state->unicast) ||
(state->state == DH6S_REQUEST &&
- (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp))))
+ (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || lla == NULL)))
{
dst.sin6_addr = alldhcp;
broad_uni = "broadcasting";
ctx->sndhdr.msg_controllen = 0;
}
- if (sendmsg(ctx->dhcp6_fd, &ctx->sndhdr, 0) == -1) {
+ if (ctx->dhcp6_fd != -1)
+ s = ctx->dhcp6_fd;
+ else if (lla != NULL && lla->dhcp6_fd != -1)
+ s = lla->dhcp6_fd;
+ else {
+ logerrx("%s: no socket to send from", ifp->name);
+ return -1;
+ }
+
+ if (sendmsg(s, &ctx->sndhdr, 0) == -1) {
logerr("%s: %s: sendmsg", __func__, ifp->name);
/* Allow DHCPv6 to continue .... the errors
* would be rate limited by the protocol.
if (ia != NULL) {
memcpy(&sa.sin6_addr, &ia->addr, sizeof(sa.sin6_addr));
sa.sin6_scope_id = ia->iface->index;
- } else if (!(ctx->options & DHCPCD_MASTER))
- /* This socket is only used for sending. */
- return s;
+ }
if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1)
goto errexit;
- if (ia == NULL) {
- n = 1;
- if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- &n, sizeof(n)) == -1)
- goto errexit;
- } else {
+ n = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &n, sizeof(n)) == -1)
+ goto errexit;
+
+ if (ia != NULL) {
ia->dhcp6_fd = s;
eloop_event_add(ctx->eloop, s, dhcp6_recvaddr, ia);
}
return -1;
}
-static int
-dhcp6_open(struct dhcpcd_ctx *ctx)
-{
-
- /* Open an unbound socket to send from. */
- ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
- if (ctx->dhcp6_fd != -1 && (ctx->options & DHCPCD_MASTER))
- eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
-
- return ctx->dhcp6_fd;
-}
-
#ifndef SMALL
static void
dhcp6_activateinterfaces(struct interface *ifp)
dhcp6_start1(void *arg)
{
struct interface *ifp = arg;
+ struct dhcpcd_ctx *ctx = ifp->ctx;
struct if_options *ifo = ifp->options;
struct dhcp6_state *state;
size_t i;
const struct dhcp_compat *dhc;
- if (ifp->ctx->dhcp6_fd == -1 && dhcp6_open(ifp->ctx) == -1)
- return;
+ if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) {
+ ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
+ if (ctx->dhcp6_fd == -1)
+ return;
+ eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
+ }
state = D6_STATE(ifp);
/* If no DHCPv6 options are configured,