Module Name: src Committed By: roy Date: Wed Apr 17 23:35:35 UTC 2019
Modified Files: src/external/bsd/dhcpcd/dist/src: dhcp.c dhcp6.c dhcpcd.c if-bsd.c if-options.c ipv6nd.c Log Message: Sync To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/external/bsd/dhcpcd/dist/src/dhcp.c cvs rdiff -u -r1.4 -r1.5 src/external/bsd/dhcpcd/dist/src/dhcp6.c \ src/external/bsd/dhcpcd/dist/src/if-bsd.c \ src/external/bsd/dhcpcd/dist/src/ipv6nd.c cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/dhcpcd.c cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/src/if-options.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/dhcpcd/dist/src/dhcp.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.16 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.17 --- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.16 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp.c Wed Apr 17 23:35:34 2019 @@ -86,9 +86,9 @@ #define IPDEFTTL 64 /* RFC1340 */ #endif -/* NetBSD-7 has an incomplete IP_PKTINFO implementation. */ -#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000 -#undef IP_PKTINFO +/* Support older systems with different defines */ +#if !defined(IP_RECVPKTINFO) && defined(IP_PKTINFO) +#define IP_RECVPKTINFO IP_PKTINFO #endif /* Assert the correct structure size for on wire */ @@ -129,6 +129,9 @@ static void dhcp_arp_conflicted(struct a #endif static void dhcp_handledhcp(struct interface *, struct bootp *, size_t, const struct in_addr *); +#ifdef IP_PKTINFO +static void dhcp_handleifudp(void *); +#endif static int dhcp_initstate(struct interface *); void @@ -447,7 +450,7 @@ decode_rfc3442_rt(struct rt_head *routes memcpy(&gateway.s_addr, p, 4); p += 4; - /* A host route is normally set by having the + /* An on-link host route is normally set by having the * gateway match the destination or assigned address */ if (gateway.s_addr == dest.s_addr || (gateway.s_addr == bootp->yiaddr || @@ -455,17 +458,14 @@ decode_rfc3442_rt(struct rt_head *routes { gateway.s_addr = INADDR_ANY; netmask.s_addr = INADDR_BROADCAST; - rt->rt_flags = RTF_HOST; } + if (netmask.s_addr == INADDR_BROADCAST) + rt->rt_flags = RTF_HOST; sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); - /* If CIDR is 32 then it's a host route. */ - if (cidr == 32) - rt->rt_flags = RTF_HOST; - TAILQ_INSERT_TAIL(routes, rt, rt_next); n++; } @@ -638,7 +638,7 @@ get_option_routes(struct rt_head *routes if ((rt = rt_new(ifp)) == NULL) return -1; - /* A host route is normally set by having the + /* A on-link host route is normally set by having the * gateway match the destination or assigned address */ if (gateway.s_addr == dest.s_addr || (gateway.s_addr == bootp->yiaddr || @@ -646,12 +646,15 @@ get_option_routes(struct rt_head *routes { gateway.s_addr = INADDR_ANY; netmask.s_addr = INADDR_BROADCAST; - rt->rt_flags = RTF_HOST; } else netmask.s_addr = route_netmask(dest.s_addr); + if (netmask.s_addr == INADDR_BROADCAST) + rt->rt_flags = RTF_HOST; + sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); + TAILQ_INSERT_TAIL(routes, rt, rt_next); n++; } @@ -1587,6 +1590,11 @@ dhcp_close(struct interface *ifp) state->bpf_fd = -1; state->bpf_flags |= BPF_EOF; } + if (state->udp_fd != -1) { + eloop_event_delete(ifp->ctx->eloop, state->udp_fd); + close(state->udp_fd); + state->udp_fd = -1; + } state->interval = 0; } @@ -1604,11 +1612,15 @@ dhcp_openudp(struct interface *ifp) n = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) goto eexit; +#ifdef IP_RECVPKTINFO + if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1) + goto eexit; +#endif memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(BOOTPC); if (ifp) { - struct dhcp_state *state = D_STATE(ifp); + const struct dhcp_state *state = D_CSTATE(ifp); if (state->addr) sin.sin_addr.s_addr = state->addr->addr.s_addr; @@ -1699,12 +1711,8 @@ dhcp_sendudp(struct interface *ifp, stru struct msghdr msg; struct sockaddr_in sin; struct iovec iov[1]; + struct dhcp_state *state = D_STATE(ifp); ssize_t r; -#ifdef IP_PKTINFO - uint8_t cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct cmsghdr *cm; - struct in_pktinfo ipi; -#endif iov[0].iov_base = data; iov[0].iov_len = len; @@ -1723,29 +1731,15 @@ dhcp_sendudp(struct interface *ifp, stru msg.msg_iov = iov; msg.msg_iovlen = 1; -#ifdef IP_PKTINFO - /* Set the outbound interface */ - msg.msg_control = cmsg; - msg.msg_controllen = sizeof(cmsg); - - memset(&ipi, 0, sizeof(ipi)); - ipi.ipi_ifindex = ifp->index; - cm = CMSG_FIRSTHDR(&msg); - if (cm == NULL) { - errno = ESRCH; - return -1; + s = state->udp_fd; + if (s == -1) { + s = dhcp_openudp(ifp); + if (s == -1) + return -1; } - cm->cmsg_level = IPPROTO_IP; - cm->cmsg_type = IP_PKTINFO; - cm->cmsg_len = CMSG_LEN(sizeof(ipi)); - memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi)); -#endif - - s = dhcp_openudp(ifp); - if (s == -1) - return -1; r = sendmsg(s, &msg, 0); - close(s); + if (state->udp_fd == -1) + close(s); return r; } @@ -1803,7 +1797,7 @@ send_message(struct interface *ifp, uint else to.s_addr = INADDR_ANY; - /* If unicasting, try and void sending by BPF so we don't + /* If unicasting, try and avoid sending by BPF so we don't * use a L2 broadcast. */ if (to.s_addr != INADDR_ANY && to.s_addr != INADDR_BROADCAST) { if (dhcp_sendudp(ifp, &to, bootp, len) != -1) @@ -2068,11 +2062,6 @@ dhcp_arp_probed(struct arp_state *astate return; } arp_free(astate); -#ifdef KERNEL_RFC5227 - /* As arping is finished, close the ARP socket. - * The kernel will handle ACD from here. */ - arp_close(ifp); -#endif dhcpcd_startinterface(ifp); return; } @@ -2150,11 +2139,6 @@ dhcp_arp_conflicted(struct arp_state *as return; } arp_free(astate); -#ifdef KERNEL_RFC5227 - /* As arping is finished, close the ARP socket. - * The kernel will handle ACD from here. */ - arp_close(ifp); -#endif eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); dhcpcd_startinterface(ifp); return; @@ -2209,11 +2193,22 @@ dhcp_arp_conflicted(struct arp_state *as return; } } + +static void +dhcp_arp_announced(struct arp_state *state) +{ + +// TODO: DHCP addresses handle ACD? +//#ifdef KERNEL_RFC5227 + arp_free(state); +//#endif +} #endif void dhcp_bind(struct interface *ifp) { + struct dhcpcd_ctx *ctx = ifp->ctx; struct dhcp_state *state = D_STATE(ifp); struct if_options *ifo = ifp->options; struct dhcp_lease *lease = &state->lease; @@ -2289,10 +2284,10 @@ dhcp_bind(struct interface *ifp) lease->leasetime); } } - if (ifp->ctx->options & DHCPCD_TEST) { + if (ctx->options & DHCPCD_TEST) { state->reason = "TEST"; script_runreason(ifp, state->reason); - eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); + eloop_exit(ctx->eloop, EXIT_SUCCESS); return; } if (state->reason == NULL) { @@ -2311,26 +2306,42 @@ dhcp_bind(struct interface *ifp) if (lease->leasetime == ~0U) lease->renewaltime = lease->rebindtime = lease->leasetime; else { - eloop_timeout_add_sec(ifp->ctx->eloop, + eloop_timeout_add_sec(ctx->eloop, (time_t)lease->renewaltime, dhcp_startrenew, ifp); - eloop_timeout_add_sec(ifp->ctx->eloop, + eloop_timeout_add_sec(ctx->eloop, (time_t)lease->rebindtime, dhcp_rebind, ifp); - eloop_timeout_add_sec(ifp->ctx->eloop, + eloop_timeout_add_sec(ctx->eloop, (time_t)lease->leasetime, dhcp_expire, ifp); logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 " seconds", ifp->name, lease->renewaltime, lease->rebindtime); } state->state = DHS_BOUND; - /* Re-apply the filter because we need to accept any XID anymore. */ - if (bpf_bootp(ifp, state->bpf_fd) == -1) - logerr(__func__); /* try to continue */ if (!state->lease.frominfo && !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) if (write_lease(ifp, state->new, state->new_len) == -1) logerr(__func__); ipv4_applyaddr(ifp); + +#ifdef IP_PKTINFO + /* Close the BPF filter as we can now receive the DHCP renew messages + * on a UDP socket. */ + if (state->udp_fd == -1 || + (state->old != NULL && state->old->yiaddr != state->new->yiaddr)) + { + dhcp_close(ifp); + /* If not in master mode, open an address specific socket. */ + if (ctx->udp_fd == -1) { + state->udp_fd = dhcp_openudp(ifp); + if (state->udp_fd == -1) + logerr(__func__); + else + eloop_event_add(ctx->eloop, + state->udp_fd, dhcp_handleifudp, ifp); + } + } +#endif } static void @@ -2384,6 +2395,20 @@ dhcp_message_new(struct bootp **bootp, } #ifdef ARP +static struct arp_state * +dhcp_arp_new(struct interface *ifp, struct in_addr *addr) +{ + struct arp_state *astate; + astate = arp_new(ifp, addr); + if (astate == NULL) + return NULL; + + astate->probed_cb = dhcp_arp_probed; + astate->conflicted_cb = dhcp_arp_conflicted; + astate->announced_cb = dhcp_arp_announced; + return astate; +} + static int dhcp_arp_address(struct interface *ifp) { @@ -2400,10 +2425,9 @@ dhcp_arp_address(struct interface *ifp) /* If the interface already has the address configured * then we can't ARP for duplicate detection. */ ia = ipv4_iffindaddr(ifp, &addr, NULL); - if ((astate = arp_new(ifp, &addr)) == NULL) + astate = dhcp_arp_new(ifp, &addr); + if (astate == NULL) return -1; - astate->probed_cb = dhcp_arp_probed; - astate->conflicted_cb = dhcp_arp_conflicted; #ifdef IN_IFF_TENTATIVE if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { @@ -2440,7 +2464,8 @@ static void dhcp_arp_bind(struct interface *ifp) { - if (dhcp_arp_address(ifp) == 1) + if (ifp->ctx->options & DHCPCD_TEST || + dhcp_arp_address(ifp) == 1) dhcp_bind(ifp); } #endif @@ -2879,14 +2904,11 @@ dhcp_handledhcp(struct interface *ifp, s #define LOGDHCP(l, m) \ log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1) - /* Handled in our BPF filter. */ -#if 0 if (bootp->op != BOOTREPLY) { logdebugx("%s: op (%d) is not BOOTREPLY", ifp->name, bootp->op); return; } -#endif if (state->xid != ntohl(bootp->xid)) { if (state->state != DHS_BOUND && state->state != DHS_NONE) @@ -3190,6 +3212,7 @@ dhcp_handledhcp(struct interface *ifp, s state->reason = "TEST"; script_runreason(ifp, state->reason); eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); + state->bpf_flags |= BPF_EOF; return; } eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); @@ -3337,6 +3360,30 @@ valid_udp_packet(void *data, size_t data } static void +dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len, + struct in_addr *from) +{ + size_t v; + + /* udp_len must be correct because the values are checked in + * valid_udp_packet(). */ + if (len < offsetof(struct bootp, vend)) { + logerrx("%s: truncated packet (%zu) from %s", + ifp->name, len, inet_ntoa(*from)); + return; + } + /* To make our IS_DHCP macro easy, ensure the vendor + * area has at least 4 octets. */ + v = len - offsetof(struct bootp, vend); + while (v < 4) { + bootp->vend[v++] = '\0'; + len++; + } + + dhcp_handledhcp(ifp, bootp, len, from); +} + +static void dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len) { struct bootp *bootp; @@ -3370,22 +3417,7 @@ dhcp_handlepacket(struct interface *ifp, * dhcpcd can work fine without the vendor area being sent. */ bootp = get_udp_data(data, &udp_len); - /* udp_len must be correct because the values are checked in - * valid_udp_packet(). */ - if (udp_len < offsetof(struct bootp, vend)) { - logerrx("%s: truncated packet (%zu) from %s", - ifp->name, udp_len, inet_ntoa(from)); - return; - } - /* To make our IS_DHCP macro easy, ensure the vendor - * area has at least 4 octets. */ - len = udp_len - offsetof(struct bootp, vend); - while (len < 4) { - bootp->vend[len++] = '\0'; - udp_len++; - } - - dhcp_handledhcp(ifp, bootp, udp_len, &from); + dhcp_handlebootp(ifp, bootp, udp_len, &from); } static void @@ -3421,23 +3453,76 @@ dhcp_readpacket(void *arg) } static void -dhcp_handleudp(void *arg) +dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) { - struct dhcpcd_ctx *ctx; - uint8_t buffer[MTU_MAX]; + struct sockaddr_in from; + unsigned char buf[10 * 1024]; /* Maximum MTU */ + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; +#ifdef IP_PKTINFO + unsigned char ctl[CMSG_SPACE(sizeof(struct in_pktinfo))] = { 0 }; + char sfrom[INET_ADDRSTRLEN]; +#endif + struct msghdr msg = { + .msg_name = &from, .msg_namelen = sizeof(from), + .msg_iov = &iov, .msg_iovlen = 1, +#ifdef IP_PKTINFO + .msg_control = ctl, .msg_controllen = sizeof(ctl), +#endif + }; + int s; + ssize_t bytes; - ctx = arg; + if (ifp != NULL) { + const struct dhcp_state *state = D_CSTATE(ifp); - /* Just read what's in the UDP fd and discard it as we always read - * from the raw fd */ - if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) { + s = state->udp_fd; + } else + s = ctx->udp_fd; + + bytes = recvmsg(s, &msg, 0); + if (bytes == -1) { logerr(__func__); - eloop_event_delete(ctx->eloop, ctx->udp_fd); - close(ctx->udp_fd); - ctx->udp_fd = -1; + return; } + +#ifdef IP_PKTINFO + inet_ntop(AF_INET, &from.sin_addr, sfrom, sizeof(sfrom)); + + if (ifp == NULL) { + ifp = if_findifpfromcmsg(ctx, &msg, NULL); + if (ifp == NULL) { + logerr(__func__); + return; + } + } + + dhcp_handlebootp(ifp, (struct bootp *)buf, (size_t)bytes, + &from.sin_addr); +#endif } +static void +dhcp_handleudp(void *arg) +{ + struct dhcpcd_ctx *ctx = arg; + + dhcp_readudp(ctx, NULL); +} + +#ifdef IP_PKTINFO +static void +dhcp_handleifudp(void *arg) +{ + struct interface *ifp = arg; + + dhcp_readudp(ifp->ctx, ifp); + +} +#endif + static int dhcp_openbpf(struct interface *ifp) { @@ -3547,6 +3632,7 @@ dhcp_initstate(struct interface *ifp) state->state = DHS_NONE; /* 0 is a valid fd, so init to -1 */ state->bpf_fd = -1; + state->udp_fd = -1; #ifdef ARPING state->arping_index = -1; #endif @@ -3676,12 +3762,9 @@ dhcp_start1(void *arg) if (ifo->arping_len && state->arping_index < ifo->arping_len) { struct arp_state *astate; - astate = arp_new(ifp, NULL); - if (astate) { - astate->probed_cb = dhcp_arp_probed; - astate->conflicted_cb = dhcp_arp_conflicted; + astate = dhcp_arp_new(ifp, NULL); + if (astate) dhcp_arp_probed(astate); - } return; } #endif @@ -3691,13 +3774,11 @@ dhcp_start1(void *arg) return; } - if (ifo->options & DHCPCD_DHCP && dhcp_openbpf(ifp) == -1) - return; - if (ifo->options & DHCPCD_INFORM) { dhcp_inform(ifp); return; } + if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') { logwarnx("%s: needs a clientid to configure", ifp->name); dhcp_drop(ifp, "FAIL"); Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.4 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.5 --- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.4 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Wed Apr 17 23:35:34 2019 @@ -168,7 +168,7 @@ static const char * const dhcp6_statuses "No Prefix Available" }; -static void dhcp6_bind(struct interface *, const char *); +static void dhcp6_bind(struct interface *, const char *, const char *); static void dhcp6_failinform(void *); static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *); static void dhcp6_recvaddr(void *); @@ -797,8 +797,7 @@ dhcp6_makemessage(struct interface *ifp) m = state->new; ml = state->new_len; } - unicast = NULL; - /* Depending on state, get the unicast address */ + switch(state->state) { case DH6S_INIT: /* FALLTHROUGH */ case DH6S_DISCOVER: @@ -806,7 +805,6 @@ dhcp6_makemessage(struct interface *ifp) break; case DH6S_REQUEST: type = DHCP6_REQUEST; - unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len); break; case DH6S_CONFIRM: type = DHCP6_CONFIRM; @@ -816,20 +814,33 @@ dhcp6_makemessage(struct interface *ifp) break; case DH6S_RENEW: type = DHCP6_RENEW; - unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len); break; case DH6S_INFORM: type = DHCP6_INFORMATION_REQ; break; case DH6S_RELEASE: type = DHCP6_RELEASE; - unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len); break; default: errno = EINVAL; return -1; } + switch(state->state) { + case DH6S_REQUEST: /* FALLTHROUGH */ + case DH6S_RENEW: /* FALLTHROUGH */ + case DH6S_RELEASE: + if (has_option_mask(ifo->nomask6, D6_OPTION_UNICAST)) { + unicast = NULL; + break; + } + unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len); + break; + default: + unicast = NULL; + break; + } + /* 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. */ @@ -1157,9 +1168,12 @@ dhcp6_update_auth(struct interface *ifp, static int dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) { - struct dhcp6_state *state; - struct dhcpcd_ctx *ctx; - struct sockaddr_in6 dst; + struct dhcp6_state *state = D6_STATE(ifp); + struct dhcpcd_ctx *ctx = ifp->ctx; + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_port = htons(DHCP6_SERVER_PORT), + }; struct timespec RTprev; double rnd; time_t ms; @@ -1168,18 +1182,22 @@ dhcp6_sendmessage(struct interface *ifp, const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT; struct ipv6_addr *lla; int s; + struct iovec iov = { + .iov_base = state->send, .iov_len = state->send_len, + }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + struct msghdr msg = { + .msg_name = &dst, .msg_namelen = sizeof(dst), + .msg_iov = &iov, .msg_iovlen = 1, + }; if (!callback && ifp->carrier <= LINK_DOWN) return 0; - memset(&dst, 0, sizeof(dst)); - dst.sin6_family = AF_INET6; - dst.sin6_port = htons(DHCP6_SERVER_PORT); #ifdef HAVE_SA_LEN dst.sin6_len = sizeof(dst); #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 @@ -1280,7 +1298,7 @@ logsend: /* Wait the initial delay */ if (state->IMD != 0) { state->IMD = 0; - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, callback, ifp); return 0; } @@ -1301,31 +1319,21 @@ logsend: } #endif - ctx = ifp->ctx; - ctx->sndhdr.msg_name = (void *)&dst; - ctx->sndhdr.msg_iov[0].iov_base = state->send; - ctx->sndhdr.msg_iov[0].iov_len = state->send_len; - /* Set the outbound interface */ if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) { struct cmsghdr *cm; - struct in6_pktinfo pi; + struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; dst.sin6_scope_id = ifp->index; - cm = CMSG_FIRSTHDR(&ctx->sndhdr); + msg.msg_control = ctl; + msg.msg_controllen = sizeof(ctl); + cm = CMSG_FIRSTHDR(&msg); if (cm == NULL) /* unlikely */ return -1; cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); - memset(&pi, 0, sizeof(pi)); - pi.ipi6_ifindex = ifp->index; memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); - } else { - /* Remove the control buffer as we're not dictating - * which interface to use for outgoing messages. */ - ctx->sndhdr.msg_control = NULL; - ctx->sndhdr.msg_controllen = 0; } if (ctx->dhcp6_fd != -1) @@ -1337,7 +1345,7 @@ logsend: return -1; } - if (sendmsg(s, &ctx->sndhdr, 0) == -1) { + if (sendmsg(s, &msg, 0) == -1) { logerr("%s: %s: sendmsg", __func__, ifp->name); /* Allow DHCPv6 to continue .... the errors * would be rate limited by the protocol. @@ -1345,19 +1353,13 @@ logsend: * associate with an access point. */ } - /* Restore the control buffer assignment. */ - if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) { - ctx->sndhdr.msg_control = ctx->sndbuf; - ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf); - } - state->RTC++; if (callback) { if (state->MRC == 0 || state->RTC < state->MRC) - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, callback, ifp); else if (state->MRC != 0 && state->MRCcallback) - eloop_timeout_add_tv(ifp->ctx->eloop, + eloop_timeout_add_tv(ctx->eloop, &state->RT, state->MRCcallback, ifp); else logwarnx("%s: sent %d times with no reply", @@ -1650,7 +1652,7 @@ dhcp6_fail(struct interface *ifp) break; } - dhcp6_bind(ifp, NULL); + dhcp6_bind(ifp, NULL, NULL); switch (state->state) { case DH6S_BOUND: @@ -1911,13 +1913,16 @@ static int dhcp6_checkstatusok(const struct interface *ifp, struct dhcp6_message *m, uint8_t *p, size_t len) { + struct dhcp6_state *state; uint8_t *opt; uint16_t opt_len, code; size_t mlen; void * (*f)(void *, size_t, uint16_t, uint16_t *), *farg; char buf[32], *sbuf; const char *status; + logfunc_t *logfunc; + state = D6_STATE(ifp); f = p ? dhcp6_findoption : dhcp6_findmoption; if (p) farg = p; @@ -1925,6 +1930,7 @@ dhcp6_checkstatusok(const struct interfa farg = m; if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) { //logdebugx("%s: no status", ifp->name); + state->lerror = 0; return 0; } @@ -1934,8 +1940,10 @@ dhcp6_checkstatusok(const struct interfa } memcpy(&code, opt, sizeof(code)); code = ntohs(code); - if (code == D6_STATUS_OK) + if (code == D6_STATUS_OK) { + state->lerror = 0; return 1; + } /* Anything after the code is a message. */ opt += sizeof(code); @@ -1958,8 +1966,13 @@ dhcp6_checkstatusok(const struct interfa status = sbuf; } - logerrx("%s: DHCPv6 REPLY: %s", ifp->name, status); + if (state->lerror == code || state->state == DH6S_INIT) + logfunc = logdebugx; + else + logfunc = logerrx; + logfunc("%s: DHCPv6 REPLY: %s", ifp->name, status); free(sbuf); + state->lerror = code; return -1; } @@ -2927,7 +2940,7 @@ dhcp6_find_delegates(struct interface *i #endif static void -dhcp6_bind(struct interface *ifp, const char *op) +dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) { struct dhcp6_state *state = D6_STATE(ifp); bool has_new = false; @@ -2943,8 +2956,7 @@ dhcp6_bind(struct interface *ifp, const } lognewinfo = has_new ? loginfox : logdebugx; if (op != NULL) - lognewinfo("%s: %s received from %s", - ifp->name, op, ifp->ctx->sfrom); + lognewinfo("%s: %s received from %s", ifp->name, op, sfrom); state->reason = NULL; if (state->state != DH6S_ITIMEDOUT) @@ -3176,7 +3188,8 @@ dhcp6_bind(struct interface *ifp, const } static void -dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) +dhcp6_recvif(struct interface *ifp, const char *sfrom, + struct dhcp6_message *r, size_t len) { struct dhcpcd_ctx *ctx; size_t i; @@ -3211,8 +3224,7 @@ dhcp6_recvif(struct interface *ifp, stru } if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { - logdebugx("%s: no DHCPv6 server ID from %s", - ifp->name, ctx->sfrom); + logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom); return; } @@ -3225,14 +3237,14 @@ dhcp6_recvif(struct interface *ifp, stru !dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) { logwarnx("%s: reject DHCPv6 (no option %s) from %s", - ifp->name, opt->var, ctx->sfrom); + ifp->name, opt->var, sfrom); return; } if (has_option_mask(ifo->rejectmask6, opt->option) && dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) { logwarnx("%s: reject DHCPv6 (option %s) from %s", - ifp->name, opt->var, ctx->sfrom); + ifp->name, opt->var, sfrom); return; } } @@ -3245,7 +3257,7 @@ dhcp6_recvif(struct interface *ifp, stru (uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL) { logerr("%s: authentication failed from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (state->auth.token) @@ -3256,11 +3268,10 @@ dhcp6_recvif(struct interface *ifp, stru } else if (ifo->auth.options & DHCPCD_AUTH_SEND) { if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { logerr("%s: no authentication from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } - logwarnx("%s: no authentication from %s", - ifp->name, ctx->sfrom); + logwarnx("%s: no authentication from %s", ifp->name, sfrom); } #endif @@ -3274,8 +3285,7 @@ dhcp6_recvif(struct interface *ifp, stru return; break; case DH6S_CONFIRM: - if (dhcp6_validatelease(ifp, r, len, - ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) { dhcp6_startdiscover(ifp); return; @@ -3297,8 +3307,7 @@ dhcp6_recvif(struct interface *ifp, stru case DH6S_REQUEST: /* FALLTHROUGH */ case DH6S_RENEW: /* FALLTHROUGH */ case DH6S_REBIND: - if (dhcp6_validatelease(ifp, r, len, - ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) { /* * If we can't use the lease, fallback to @@ -3366,7 +3375,7 @@ dhcp6_recvif(struct interface *ifp, stru logerrx("%s: invalid INF_MAX_RT %u", ifp->name, max_rt); } - if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1) + if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) return; break; case DHCP6_RECONFIGURE: @@ -3374,12 +3383,12 @@ dhcp6_recvif(struct interface *ifp, stru if (auth == NULL) { #endif logerrx("%s: unauthenticated %s from %s", - ifp->name, op, ctx->sfrom); + ifp->name, op, sfrom); if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) return; #ifdef AUTH } - loginfox("%s: %s from %s", ifp->name, op, ctx->sfrom); + loginfox("%s: %s from %s", ifp->name, op, sfrom); o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol); if (o == NULL) { logerrx("%s: missing Reconfigure Message option", @@ -3456,10 +3465,10 @@ dhcp6_recvif(struct interface *ifp, stru ia = TAILQ_FIRST(&state->addrs); if (ia == NULL) loginfox("%s: ADV (no address) from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); else loginfox("%s: ADV %s from %s", - ifp->name, ia->saddr, ctx->sfrom); + ifp->name, ia->saddr, sfrom); if (ifp->ctx->options & DHCPCD_TEST) break; dhcp6_startrequest(ifp); @@ -3467,97 +3476,81 @@ dhcp6_recvif(struct interface *ifp, stru } } - dhcp6_bind(ifp, op); + dhcp6_bind(ifp, op, sfrom); } static void dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) { + struct sockaddr_in6 from; + unsigned char buf[64 * 1024]; /* Maximum UDP message size */ + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + struct msghdr msg = { + .msg_name = &from, .msg_namelen = sizeof(from), + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = ctl, .msg_controllen = sizeof(ctl), + }; int s; size_t len; ssize_t bytes; + char sfrom[INET6_ADDRSTRLEN]; struct interface *ifp; struct dhcp6_message *r; const struct dhcp6_state *state; uint8_t *o; uint16_t ol; - ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd; - bytes = recvmsg_realloc(s, &ctx->rcvhdr, 0); + bytes = recvmsg(s, &msg, 0); if (bytes == -1) { - logerr("%s: recvmsg_realloc", __func__); + logerr(__func__); return; } len = (size_t)bytes; - ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, - ctx->ntopbuf, sizeof(ctx->ntopbuf)); + inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom)); if (len < sizeof(struct dhcp6_message)) { - logerrx("DHCPv6 packet too short from %s", ctx->sfrom); + logerrx("DHCPv6 packet too short from %s", sfrom); return; } if (ia != NULL) ifp = ia->iface; else { - struct cmsghdr *cm; - struct in6_pktinfo pi; - - pi.ipi6_ifindex = 0; - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr); - cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm)) - { - if (cm->cmsg_level != IPPROTO_IPV6) - continue; - switch(cm->cmsg_type) { - case IPV6_PKTINFO: - if (cm->cmsg_len == CMSG_LEN(sizeof(pi))) - memcpy(&pi, CMSG_DATA(cm), sizeof(pi)); - break; - } - } - if (pi.ipi6_ifindex == 0) { - logerrx("DHCPv6 reply did not contain index from %s", - ctx->sfrom); - return; - } - - TAILQ_FOREACH(ifp, ctx->ifaces, next) { - if (ifp->index == (unsigned int)pi.ipi6_ifindex) - break; - } + ifp = if_findifpfromcmsg(ctx, &msg, NULL); if (ifp == NULL) { - logerrx("DHCPv6 reply for unexpected interface from %s", - ctx->sfrom); + logerr(__func__); return; } } - r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base; + r = (struct dhcp6_message *)buf; o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol); if (o == NULL || ol != ctx->duid_len || memcmp(o, ctx->duid, ol) != 0) { logdebugx("%s: incorrect client ID from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { logdebugx("%s: no DHCPv6 server ID from %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } if (r->type == DHCP6_RECONFIGURE) { logdebugx("%s: RECONFIGURE6 recv from %s," " sending to all interfaces", - ifp->name, ctx->sfrom); + ifp->name, sfrom); TAILQ_FOREACH(ifp, ctx->ifaces, next) { state = D6_CSTATE(ifp); if (state != NULL && state->send != NULL) - dhcp6_recvif(ifp, r, len); + dhcp6_recvif(ifp, sfrom, r, len); } return; } @@ -3591,7 +3584,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc state->send->xid[0], state->send->xid[1], state->send->xid[2], - ctx->sfrom); + sfrom); return; } logdebugx("%s: redirecting DHCP6 message to %s", @@ -3599,7 +3592,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struc ifp = ifp1; } - dhcp6_recvif(ifp, r, len); + dhcp6_recvif(ifp, sfrom, r, len); } static void @@ -3812,6 +3805,7 @@ dhcp6_start(struct interface *ifp, enum gogogo: state->state = init_state; + state->lerror = 0; dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), AF_INET6, ifp); if (ipv6_linklocal(ifp) == NULL) { @@ -3831,18 +3825,20 @@ dhcp6_reboot(struct interface *ifp) struct dhcp6_state *state; state = D6_STATE(ifp); - if (state) { - switch (state->state) { - case DH6S_BOUND: - dhcp6_startrebind(ifp); - break; - case DH6S_INFORMED: - dhcp6_startinform(ifp); - break; - default: - dhcp6_startdiscover(ifp); - break; - } + if (state == NULL) + return; + + state->lerror = 0; + switch (state->state) { + case DH6S_BOUND: + dhcp6_startrebind(ifp); + break; + case DH6S_INFORMED: + dhcp6_startinform(ifp); + break; + default: + dhcp6_startdiscover(ifp); + break; } } Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.4 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.5 --- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.4 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Wed Apr 17 23:35:34 2019 @@ -99,14 +99,20 @@ #endif #ifdef INET6 -static void -ifa_scope(struct sockaddr_in6 *, unsigned int); +static void ifa_setscope(struct sockaddr_in6 *, unsigned int); +static unsigned int ifa_getscope(const struct sockaddr_in6 *); #endif struct priv { int pf_inet6_fd; }; +struct rtm +{ + struct rt_msghdr hdr; + char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX]; +}; + int if_init(__unused struct interface *iface) { @@ -418,9 +424,13 @@ if_findsa(struct dhcpcd_ctx *ctx, const case AF_INET6: { const struct sockaddr_in6 *sin; + unsigned int scope; struct ipv6_addr *ia; sin = (const void *)sa; + scope = ifa_getscope(sin); + if (scope != 0) + return if_findindex(ctx->ifaces, scope); if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) return ia->iface; break; @@ -458,11 +468,7 @@ int if_route(unsigned char cmd, const struct rt *rt) { struct dhcpcd_ctx *ctx; - struct rtm - { - struct rt_msghdr hdr; - char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX]; - } rtmsg; + struct rtm rtmsg; struct rt_msghdr *rtm = &rtmsg.hdr; char *bp = rtmsg.buffer; struct sockaddr_dl sdl; @@ -577,7 +583,7 @@ if_route(unsigned char cmd, const struct if_copysa(&gateway.sa, &rt->rt_gateway); #ifdef INET6 if (gateway.sa.sa_family == AF_INET6) - ifa_scope(&gateway.sin6, rt->rt_ifp->index); + ifa_setscope(&gateway.sin6, rt->rt_ifp->index); #endif ADDSA(&gateway.sa); } @@ -605,19 +611,27 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct { const struct sockaddr *rti_info[RTAX_MAX]; - if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) + if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) { + errno = EINVAL; return -1; + } #ifdef RTF_CLONED - if (rtm->rtm_flags & RTF_CLONED) + if (rtm->rtm_flags & RTF_CLONED) { + errno = ENOTSUP; return -1; + } #endif #ifdef RTF_LOCAL - if (rtm->rtm_flags & RTF_LOCAL) + if (rtm->rtm_flags & RTF_LOCAL) { + errno = ENOTSUP; return -1; + } #endif #ifdef RTF_BROADCAST - if (rtm->rtm_flags & RTF_BROADCAST) + if (rtm->rtm_flags & RTF_BROADCAST) { + errno = ENOTSUP; return -1; + } #endif get_addrs(rtm->rtm_addrs, rtm + 1, rti_info); @@ -688,7 +702,7 @@ if_initrt(struct dhcpcd_ctx *ctx, int af rtm = (void *)p; if (if_copyrt(ctx, &rt, rtm) == 0) { rt.rt_dflags |= RTDF_INIT; - rt_recvrt(RTM_ADD, &rt); + rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid); } } free(buf); @@ -751,7 +765,7 @@ if_addrflags(const struct interface *ifp #ifdef INET6 static void -ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex) +ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex) { #ifdef __KAME__ @@ -771,6 +785,23 @@ ifa_scope(struct sockaddr_in6 *sin, unsi #endif } +static unsigned int +ifa_getscope(const struct sockaddr_in6 *sin) +{ +#ifdef __KAME__ + uint16_t scope; +#endif + + if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) + return 0; +#ifdef __KAME__ + memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope)); + return (unsigned int)ntohs(scope); +#else + return (unsigned int)sin->sin6_scope_id; +#endif +} + int if_address6(unsigned char cmd, const struct ipv6_addr *ia) { @@ -810,7 +841,7 @@ if_address6(unsigned char cmd, const str } ADDADDR(&ifa.ifra_addr, &ia->addr); - ifa_scope(&ifa.ifra_addr, ia->iface->index); + ifa_setscope(&ifa.ifra_addr, ia->iface->index); ipv6_mask(&mask, ia->prefix_len); ADDADDR(&ifa.ifra_prefixmask, &mask); @@ -887,7 +918,7 @@ if_addrflags6(const struct interface *if strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name)); ifr6.ifr_addr.sin6_family = AF_INET6; ifr6.ifr_addr.sin6_addr = *addr; - ifa_scope(&ifr6.ifr_addr, ifp->index); + ifa_setscope(&ifr6.ifr_addr, ifp->index); priv = (struct priv *)ifp->ctx->priv; if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) flags = ifr6.ifr_ifru.ifru_flags6; @@ -908,7 +939,7 @@ if_getlifetime6(struct ipv6_addr *ia) strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name)); ifr6.ifr_addr.sin6_family = AF_INET6; ifr6.ifr_addr.sin6_addr = ia->addr; - ifa_scope(&ifr6.ifr_addr, ia->iface->index); + ifa_setscope(&ifr6.ifr_addr, ia->iface->index); priv = (struct priv *)ia->iface->ctx->priv; if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1) return -1; @@ -1010,7 +1041,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const str } #endif - rt_recvrt(rtm->rtm_type, &rt); + rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid); } static void @@ -1095,7 +1126,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const str ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr); ifra.ifra_addr.sin_addr = addr; if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) { - if (errno != EADDRNOTAVAIL) + if (errno != ENXIO && errno != EADDRNOTAVAIL) logerr("%s: SIOCGIFALIAS", __func__); if (ifam->ifam_type != RTM_DELADDR) break; @@ -1229,18 +1260,16 @@ if_dispatch(struct dhcpcd_ctx *ctx, cons int if_handlelink(struct dhcpcd_ctx *ctx) { - struct msghdr msg; + struct rtm rtm; + struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t len; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = ctx->iov; - msg.msg_iovlen = 1; - - len = recvmsg_realloc(ctx->link_fd, &msg, 0); + len = recvmsg(ctx->link_fd, &msg, 0); if (len == -1) return -1; if (len != 0) - if_dispatch(ctx, ctx->iov[0].iov_base); + if_dispatch(ctx, &rtm.hdr); return 0; } Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.4 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.5 --- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.4 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c Wed Apr 17 23:35:35 2019 @@ -274,10 +274,17 @@ ipv6nd_sendrsprobe(void *arg) { struct interface *ifp = arg; struct dhcpcd_ctx *ctx; - struct rs_state *state; - struct sockaddr_in6 dst; + struct rs_state *state = RS_STATE(ifp); + struct sockaddr_in6 dst = { .sin6_family = AF_INET6 }; + struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + struct msghdr msg = { + .msg_name = &dst, .msg_namelen = sizeof(dst), + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = ctl, .msg_controllen = sizeof(ctl), + }; struct cmsghdr *cm; - struct in6_pktinfo pi; + struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; if (ipv6_linklocal(ifp) == NULL) { logdebugx("%s: delaying Router Solicitation for LL address", @@ -286,8 +293,6 @@ ipv6nd_sendrsprobe(void *arg) return; } - memset(&dst, 0, sizeof(dst)); - dst.sin6_family = AF_INET6; #ifdef HAVE_SA_LEN dst.sin6_len = sizeof(dst); #endif @@ -297,25 +302,19 @@ ipv6nd_sendrsprobe(void *arg) return; } - state = RS_STATE(ifp); ctx = ifp->ctx; - ctx->sndhdr.msg_name = (void *)&dst; - ctx->sndhdr.msg_iov[0].iov_base = state->rs; - ctx->sndhdr.msg_iov[0].iov_len = state->rslen; /* Set the outbound interface */ - cm = CMSG_FIRSTHDR(&ctx->sndhdr); + cm = CMSG_FIRSTHDR(&msg); if (cm == NULL) /* unlikely */ return; cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); - memset(&pi, 0, sizeof(pi)); - pi.ipi6_ifindex = ifp->index; memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); logdebugx("%s: sending Router Solicitation", ifp->name); - if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { + if (sendmsg(ctx->nd_fd, &msg, 0) == -1) { logerr(__func__); /* Allow IPv6ND to continue .... at most a few errors * would be logged. @@ -341,41 +340,42 @@ ipv6nd_sendadvertisement(void *arg) struct ipv6_addr *ia = arg; struct interface *ifp = ia->iface; struct dhcpcd_ctx *ctx = ifp->ctx; - struct sockaddr_in6 dst; + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_scope_id = ifp->index, + }; + struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; + struct msghdr msg = { + .msg_name = &dst, .msg_namelen = sizeof(dst), + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = ctl, .msg_controllen = sizeof(ctl), + }; struct cmsghdr *cm; - struct in6_pktinfo pi; + struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; const struct rs_state *state = RS_CSTATE(ifp); if (state == NULL || ifp->carrier <= LINK_DOWN) goto freeit; - memset(&dst, 0, sizeof(dst)); - dst.sin6_family = AF_INET6; #ifdef SIN6_LEN dst.sin6_len = sizeof(dst); #endif - dst.sin6_scope_id = ifp->index; if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) { logerr(__func__); return; } - ctx->sndhdr.msg_name = (void *)&dst; - ctx->sndhdr.msg_iov[0].iov_base = ia->na; - ctx->sndhdr.msg_iov[0].iov_len = ia->na_len; - /* Set the outbound interface. */ - cm = CMSG_FIRSTHDR(&ctx->sndhdr); + cm = CMSG_FIRSTHDR(&msg); assert(cm != NULL); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); - memset(&pi, 0, sizeof(pi)); - pi.ipi6_ifindex = ifp->index; memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); logdebugx("%s: sending NA for %s", ifp->name, ia->saddr); - if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) + if (sendmsg(ctx->nd_fd, &msg, 0) == -1) logerr(__func__); if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) { @@ -872,8 +872,9 @@ dhcp6_start(__unused struct interface *i #endif static void -ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp, - struct icmp6_hdr *icp, size_t len, int hoplimit) +ipv6nd_handlera(struct dhcpcd_ctx *ctx, + const struct sockaddr_in6 *from, const char *sfrom, + struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit) { size_t i, olen; struct nd_router_advert *nd_ra; @@ -895,33 +896,29 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, if (ifp == NULL) { #ifdef DEBUG_RS - logdebugx("RA for unexpected interface from %s", - ctx->sfrom); + logdebugx("RA for unexpected interface from %s", sfrom); #endif return; } if (len < sizeof(struct nd_router_advert)) { - logerrx("IPv6 RA packet too short from %s", ctx->sfrom); + logerrx("IPv6 RA packet too short from %s", sfrom); return; } /* RFC 4861 7.1.2 */ if (hoplimit != 255) { - logerrx("invalid hoplimit(%d) in RA from %s", - hoplimit, ctx->sfrom); + logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom); return; } - - if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) { - logerrx("RA from non local address %s", ctx->sfrom); + if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) { + logerrx("RA from non local address %s", sfrom); return; } if (!(ifp->options->options & DHCPCD_IPV6RS)) { #ifdef DEBUG_RS - logerrx("%s: unexpected RA from %s", - ifp->name, ctx->sfrom); + logerrx("%s: unexpected RA from %s", ifp->name, sfrom); #endif return; } @@ -930,20 +927,20 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, if (ipv6_linklocal(ifp) == NULL) { #ifdef DEBUG_RS logdebugx("%s: received RA from %s (no link-local)", - ifp->name, ctx->sfrom); + ifp->name, sfrom); #endif return; } - if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) { + if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) { logdebugx("%s: ignoring RA from ourself %s", - ifp->name, ctx->sfrom); + ifp->name, sfrom); return; } TAILQ_FOREACH(rap, ctx->ra_routers, next) { if (ifp == rap->iface && - IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr)) + IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr)) break; } @@ -968,8 +965,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, return; } rap->iface = ifp; - rap->from = ctx->from.sin6_addr; - strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom)); + rap->from = from->sin6_addr; + strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom)); TAILQ_INIT(&rap->addrs); new_rap = true; } else @@ -991,8 +988,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, * in accordance with the own prefix times which would result in too * much needless log spam. */ logfunc = new_rap ? loginfox : logdebugx, - logfunc("%s: Router Advertisement from %s", - ifp->name, ctx->sfrom); + logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom); clock_gettime(CLOCK_MONOTONIC, &rap->acquired); rap->flags = nd_ra->nd_ra_flags_reserved; @@ -1053,10 +1049,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, } if (dho != NULL) logwarnx("%s: reject RA (option %s) from %s", - ifp->name, dho->var, ctx->sfrom); + ifp->name, dho->var, rap->sfrom); else logwarnx("%s: reject RA (option %d) from %s", - ifp->name, ndo.nd_opt_type, ctx->sfrom); + ifp->name, ndo.nd_opt_type, rap->sfrom); if (new_rap) ipv6nd_removefreedrop_ra(rap, 0, 0); else @@ -1196,7 +1192,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, dho->option)) { logwarnx("%s: reject RA (no option %s) from %s", - ifp->name, dho->var, ctx->sfrom); + ifp->name, dho->var, rap->sfrom); if (new_rap) ipv6nd_removefreedrop_ra(rap, 0, 0); else @@ -1584,8 +1580,8 @@ ipv6nd_drop(struct interface *ifp) } static void -ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp, - struct icmp6_hdr *icp, size_t len, int hoplimit) +ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom, + struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit) { struct nd_neighbor_advert *nd_na; struct in6_addr nd_na_target; @@ -1596,22 +1592,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, if (ifp == NULL) { #ifdef DEBUG_NS - logdebugx("NA for unexpected interface from %s", - ctx->sfrom); + logdebugx("NA for unexpected interface from %s", sfrom); #endif return; } if ((size_t)len < sizeof(struct nd_neighbor_advert)) { - logerrx("%s: IPv6 NA too short from %s", - ifp->name, ctx->sfrom); + logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom); return; } /* RFC 4861 7.1.2 */ if (hoplimit != 255) { logerrx("invalid hoplimit(%d) in NA from %s", - hoplimit, ctx->sfrom); + hoplimit, sfrom); return; } @@ -1625,7 +1619,7 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target)); if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) { logerrx("%s: NA multicast address %s (%s)", - ifp->name, taddr, ctx->sfrom); + ifp->name, taddr, sfrom); return; } @@ -1637,20 +1631,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, if (rap == NULL) { #ifdef DEBUG_NS logdebugx("%s: unexpected NA from %s for %s", - ifp->name, ctx->sfrom, taddr); + ifp->name, sfrom, taddr); #endif return; } #ifdef DEBUG_NS logdebugx("%s: %sNA for %s from %s", - ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom); + ifp->name, is_solicited ? "solicited " : "", taddr, sfrom); #endif /* Node is no longer a router, so remove it from consideration */ if (!is_router && !rap->expired) { loginfox("%s: %s not a router (%s)", - ifp->name, taddr, ctx->sfrom); + ifp->name, taddr, sfrom); rap->expired = 1; rt_build(ifp->ctx, AF_INET6); script_runreason(ifp, "ROUTERADVERT"); @@ -1665,81 +1659,63 @@ static void ipv6nd_handledata(void *arg) { struct dhcpcd_ctx *ctx; + struct sockaddr_in6 from; + unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */ + struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf), + }; + unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 }; + struct msghdr msg = { + .msg_name = &from, .msg_namelen = sizeof(from), + .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = ctl, .msg_controllen = sizeof(ctl), + }; ssize_t len; - struct cmsghdr *cm; - int hoplimit; - struct in6_pktinfo pkt; + char sfrom[INET6_ADDRSTRLEN]; + int hoplimit = 0; struct icmp6_hdr *icp; struct interface *ifp; ctx = arg; - ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); - len = recvmsg_realloc(ctx->nd_fd, &ctx->rcvhdr, 0); + len = recvmsg(ctx->nd_fd, &msg, 0); if (len == -1) { logerr(__func__); return; } - ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, - ctx->ntopbuf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom)); if ((size_t)len < sizeof(struct icmp6_hdr)) { - logerrx("IPv6 ICMP packet too short from %s", ctx->sfrom); + logerrx("IPv6 ICMP packet too short from %s", sfrom); return; } - pkt.ipi6_ifindex = 0; - hoplimit = 0; - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr); - cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm)) - { - if (cm->cmsg_level != IPPROTO_IPV6) - continue; - switch(cm->cmsg_type) { - case IPV6_PKTINFO: - if (cm->cmsg_len == CMSG_LEN(sizeof(pkt))) - memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt)); - break; - case IPV6_HOPLIMIT: - if (cm->cmsg_len == CMSG_LEN(sizeof(int))) - memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int)); - break; - } - } - - if (pkt.ipi6_ifindex == 0) { - logerrx("IPv6 RA/NA did not contain index from %s", ctx->sfrom); + ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit); + if (ifp == NULL) { + logerr(__func__); return; } - /* Find the receiving interface */ - TAILQ_FOREACH(ifp, ctx->ifaces, next) { - if (ifp->index == (unsigned int)pkt.ipi6_ifindex) - break; - } - /* Don't do anything if the user hasn't configured it. */ - if (ifp != NULL && - (ifp->active != IF_ACTIVE_USER || - !(ifp->options->options & DHCPCD_IPV6))) + if (ifp->active != IF_ACTIVE_USER || + !(ifp->options->options & DHCPCD_IPV6)) return; - icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base; + icp = (struct icmp6_hdr *)buf; if (icp->icmp6_code == 0) { switch(icp->icmp6_type) { case ND_NEIGHBOR_ADVERT: - ipv6nd_handlena(ctx, ifp, icp, (size_t)len, - hoplimit); + ipv6nd_handlena(ctx, sfrom, + ifp, icp, (size_t)len, hoplimit); return; case ND_ROUTER_ADVERT: - ipv6nd_handlera(ctx, ifp, icp, (size_t)len, - hoplimit); + ipv6nd_handlera(ctx, &from, sfrom, + ifp, icp, (size_t)len, hoplimit); return; } } logerrx("invalid IPv6 type %d or code %d from %s", - icp->icmp6_type, icp->icmp6_code, ctx->sfrom); + icp->icmp6_type, icp->icmp6_code, sfrom); } static void Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.17 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.18 --- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.17 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Wed Apr 17 23:35:34 2019 @@ -54,6 +54,7 @@ const char dhcpcd_copyright[] = "Copyrig #include "dev.h" #include "dhcp-common.h" #include "dhcpcd.h" +#include "dhcp.h" #include "dhcp6.h" #include "duid.h" #include "eloop.h" @@ -978,7 +979,12 @@ dhcpcd_prestartinterface(void *arg) if ((!(ifp->ctx->options & DHCPCD_MASTER) || ifp->options->options & DHCPCD_IF_UP) && - if_up(ifp) == -1) + if_up(ifp) == -1 +#ifdef __sun + /* Interface could not yet be plumbed. */ + && errno != ENXIO +#endif + ) logerr("%s: %s", __func__, ifp->name); if (ifp->options->options & DHCPCD_LINK && @@ -1606,9 +1612,6 @@ main(int argc, char **argv) ctx.cffile = CONFIG; ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1; ctx.pf_inet_fd = -1; -#ifdef IFLR_ACTIVE - ctx.pf_link_fd = -1; -#endif TAILQ_INIT(&ctx.control_fds); #ifdef PLUGIN_DEV @@ -2142,7 +2145,6 @@ exit1: #endif dev_stop(&ctx); eloop_free(ctx.eloop); - free(ctx.iov[0].iov_base); if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) loginfox(PACKAGE " exited"); Index: src/external/bsd/dhcpcd/dist/src/if-options.c diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.12 src/external/bsd/dhcpcd/dist/src/if-options.c:1.13 --- src/external/bsd/dhcpcd/dist/src/if-options.c:1.12 Thu Feb 7 21:37:36 2019 +++ src/external/bsd/dhcpcd/dist/src/if-options.c Wed Apr 17 23:35:34 2019 @@ -207,11 +207,12 @@ const struct option cf_options[] = { {NULL, 0, NULL, '\0'} }; +static const char *default_script = SCRIPT; + static char * -add_environ(struct if_options *ifo, const char *value, int uniq) +add_environ(char ***array, const char *value, int uniq) { - char **newlist; - char **lst = ifo->environ; + char **newlist, **list = *array; size_t i = 0, l, lv; char *match = NULL, *p, *n; @@ -229,8 +230,8 @@ add_environ(struct if_options *ifo, cons *p++ = '\0'; l = strlen(match); - while (lst && lst[i]) { - if (match && strncmp(lst[i], match, l) == 0) { + while (list && list[i]) { + if (match && strncmp(list[i], match, l) == 0) { if (uniq) { n = strdup(value); if (n == NULL) { @@ -238,25 +239,25 @@ add_environ(struct if_options *ifo, cons free(match); return NULL; } - free(lst[i]); - lst[i] = n; + free(list[i]); + list[i] = n; } else { /* Append a space and the value to it */ - l = strlen(lst[i]); + l = strlen(list[i]); lv = strlen(p); - n = realloc(lst[i], l + lv + 2); + n = realloc(list[i], l + lv + 2); if (n == NULL) { logerr(__func__); free(match); return NULL; } - lst[i] = n; - lst[i][l] = ' '; - memcpy(lst[i] + l + 1, p, lv); - lst[i][l + lv + 1] = '\0'; + list[i] = n; + list[i][l] = ' '; + memcpy(list[i] + l + 1, p, lv); + list[i][l + lv + 1] = '\0'; } free(match); - return lst[i]; + return list[i]; } i++; } @@ -267,7 +268,7 @@ add_environ(struct if_options *ifo, cons logerr(__func__); return NULL; } - newlist = reallocarray(lst, i + 2, sizeof(char *)); + newlist = reallocarray(list, i + 2, sizeof(char *)); if (newlist == NULL) { logerr(__func__); free(n); @@ -275,26 +276,31 @@ add_environ(struct if_options *ifo, cons } newlist[i] = n; newlist[i + 1] = NULL; - ifo->environ = newlist; + *array = newlist; return newlist[i]; } -#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0) +#define PARSE_STRING 0 +#define PARSE_STRING_NULL 1 +#define PARSE_HWADDR 2 +#define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING) +#define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR) static ssize_t -parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid) +parse_str(char *sbuf, size_t slen, const char *str, int flags) { size_t l; - const char *p; - int i, punt_last = 0; + const char *p, *end; + int i; char c[4], cmd; + end = str + strlen(str); /* If surrounded by quotes then it's a string */ if (*str == '"') { - str++; - l = strlen(str); - p = str + l - 1; - if (*p == '"') - punt_last = 1; + p = end - 1; + if (*p == '"') { + str++; + end = p; + } } else { l = (size_t)hwaddr_aton(NULL, str); if ((ssize_t) l != -1 && l > 1) { @@ -311,13 +317,13 @@ parse_string_hwaddr(char *sbuf, size_t s l = 0; /* If processing a string on the clientid, first byte should be * 0 to indicate a non hardware type */ - if (clid && *str) { + if (flags == PARSE_HWADDR && *str) { if (sbuf) *sbuf++ = 0; l++; } c[3] = '\0'; - while (*str) { + while (str < end) { if (++l > slen && sbuf) { errno = ENOBUFS; return -1; @@ -385,11 +391,8 @@ parse_string_hwaddr(char *sbuf, size_t s str++; } } - if (punt_last) { - if (sbuf) - *--sbuf = '\0'; - l--; - } + if (flags == PARSE_STRING_NULL && sbuf) + *sbuf = '\0'; return (ssize_t)l; } @@ -654,7 +657,7 @@ parse_option(struct dhcpcd_ctx *ctx, con int e, i, t; long l; unsigned long u; - char *p = NULL, *bp, *fp, *np, **nconf; + char *p = NULL, *bp, *fp, *np; ssize_t s; struct in_addr addr, addr2; in_addr_t *naddr; @@ -708,17 +711,33 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case 'c': ARG_REQUIRED; - free(ifo->script); - ifo->script = strdup(arg); - if (ifo->script == NULL) + if (ifo->script != default_script) + free(ifo->script); + s = parse_str(NULL, 0, arg, PARSE_STRING_NULL); + if (s == 0) { + ifo->script = NULL; + break; + } + dl = (size_t)s; + if (s == -1 || (ifo->script = malloc(dl)) == NULL) { + ifo->script = NULL; logerr(__func__); + return -1; + } + parse_str(ifo->script, dl, arg, PARSE_STRING_NULL); + if (ifo->script[0] == '\0' || + strcmp(ifo->script, "/dev/null") == 0) + { + free(ifo->script); + ifo->script = NULL; + } break; case 'd': ifo->options |= DHCPCD_DEBUG; break; case 'e': ARG_REQUIRED; - add_environ(ifo, arg, 1); + add_environ(&ifo->environ, arg, 1); break; case 'h': if (!arg) { @@ -969,7 +988,7 @@ parse_option(struct dhcpcd_ctx *ctx, con return -1; } snprintf(p, dl, "skip_hooks=%s", arg); - add_environ(ifo, p, 0); + add_environ(&ifo->environ, p, 0); free(p); break; case 'D': @@ -1006,8 +1025,8 @@ parse_option(struct dhcpcd_ctx *ctx, con /* Strings have a type of 0 */; ifo->clientid[1] = 0; if (arg) - s = parse_string_hwaddr((char *)ifo->clientid + 1, - CLIENTID_MAX_LEN, arg, 1); + s = parse_hwaddr((char *)ifo->clientid + 1, + CLIENTID_MAX_LEN, arg); else s = 0; if (s == -1) { @@ -1112,6 +1131,7 @@ parse_option(struct dhcpcd_ctx *ctx, con sa_in_init(&rt->rt_gateway, &addr3); TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); *fp = ' '; + add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { if (parse_addr(&addr, NULL, p) == -1) return -1; @@ -1122,6 +1142,7 @@ parse_option(struct dhcpcd_ctx *ctx, con sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_gateway, &addr); TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); + add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "interface_mtu=", strlen("interface_mtu=")) == 0 || strncmp(arg, "mtu=", strlen("mtu=")) == 0) @@ -1149,40 +1170,8 @@ parse_option(struct dhcpcd_ctx *ctx, con } else ifo->req_prefix_len = 128; } - } else { - dl = 0; - if (ifo->config != NULL) { - while (ifo->config[dl] != NULL) { - if (strncmp(ifo->config[dl], arg, - (size_t)(p - arg)) == 0) - { - p = strdup(arg); - if (p == NULL) { - logerr(__func__); - return -1; - } - free(ifo->config[dl]); - ifo->config[dl] = p; - return 1; - } - dl++; - } - } - p = strdup(arg); - if (p == NULL) { - logerr(__func__); - return -1; - } - nconf = reallocarray(ifo->config, dl+2, sizeof(char *)); - if (nconf == NULL) { - logerr(__func__); - free(p); - return -1; - } - ifo->config = nconf; - ifo->config[dl] = p; - ifo->config[dl + 1] = NULL; - } + } else + add_environ(&ifo->config, arg, 1); break; case 'W': if (parse_addr(&addr, &addr2, arg) != 0) @@ -2277,6 +2266,7 @@ default_config(struct dhcpcd_ctx *ctx) ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY; ifo->timeout = DEFAULT_TIMEOUT; ifo->reboot = DEFAULT_REBOOT; + ifo->script = UNCONST(default_script); ifo->metric = -1; ifo->auth.options |= DHCPCD_AUTH_REQUIRE; TAILQ_INIT(&ifo->routes); @@ -2626,7 +2616,8 @@ free_options(struct dhcpcd_ctx *ctx, str free(ifo->config); } rt_headclear0(ctx, &ifo->routes, AF_UNSPEC); - free(ifo->script); + if (ifo->script != default_script) + free(ifo->script); free(ifo->arping); free(ifo->blacklist); free(ifo->fallback);