diff --git a/external/bsd/dhcpcd/dist/src/arp.c b/external/bsd/dhcpcd/dist/src/arp.c index ba3755e6923d..0fdcdd9aa3ba 100644 --- a/external/bsd/dhcpcd/dist/src/arp.c +++ b/external/bsd/dhcpcd/dist/src/arp.c @@ -206,7 +206,6 @@ arp_validate(const struct interface *ifp, struct arphdr *arp) return true; } - static void arp_packet(struct interface *ifp, uint8_t *data, size_t len) { @@ -280,9 +279,9 @@ arp_close(struct interface *ifp) } static void -arp_tryfree(struct interface *ifp) +arp_tryfree(struct iarp_state *state) { - struct iarp_state *state = ARP_STATE(ifp); + struct interface *ifp = state->ifp; /* If there are no more ARP states, close the socket. */ if (TAILQ_FIRST(&state->arp_states) == NULL) { @@ -302,15 +301,14 @@ arp_tryfree(struct interface *ifp) static void arp_read(void *arg) { - struct interface *ifp = arg; - struct iarp_state *state; + struct iarp_state *state = arg; + struct interface *ifp = state->ifp; uint8_t buf[ARP_LEN]; ssize_t bytes; /* Some RAW mechanisms are generic file descriptors, not sockets. * This means we have no kernel call to just get one packet, * so we have to process the entire buffer. */ - state = ARP_STATE(ifp); state->bpf_flags &= ~BPF_EOF; state->bpf_flags |= BPF_READING; while (!(state->bpf_flags & BPF_EOF)) { @@ -329,7 +327,7 @@ arp_read(void *arg) if (state != NULL) { state->bpf_flags &= ~BPF_READING; /* Try and free the state if nothing left to do. */ - arp_tryfree(ifp); + arp_tryfree(state); } } @@ -343,7 +341,7 @@ arp_open(struct interface *ifp) state->bpf_fd = bpf_open(ifp, bpf_arp); if (state->bpf_fd == -1) return -1; - eloop_event_add(ifp->ctx->eloop, state->bpf_fd, arp_read, ifp); + eloop_event_add(ifp->ctx->eloop, state->bpf_fd, arp_read, state); } return state->bpf_fd; } @@ -571,6 +569,7 @@ arp_new(struct interface *ifp, const struct in_addr *addr) logerr(__func__); return NULL; } + state->ifp = ifp; state->bpf_fd = -1; state->bpf_flags = 0; TAILQ_INIT(&state->arp_states); @@ -618,7 +617,7 @@ arp_free(struct arp_state *astate) if (astate->free_cb) astate->free_cb(astate); free(astate); - arp_tryfree(ifp); + arp_tryfree(state); } void diff --git a/external/bsd/dhcpcd/dist/src/arp.h b/external/bsd/dhcpcd/dist/src/arp.h index 0065e0c91786..4842c3579ae0 100644 --- a/external/bsd/dhcpcd/dist/src/arp.h +++ b/external/bsd/dhcpcd/dist/src/arp.h @@ -78,6 +78,7 @@ struct arp_state { TAILQ_HEAD(arp_statehead, arp_state); struct iarp_state { + struct interface *ifp; int bpf_fd; unsigned int bpf_flags; struct arp_statehead arp_states; diff --git a/external/bsd/dhcpcd/dist/src/control.c b/external/bsd/dhcpcd/dist/src/control.c index 4ae227931636..8825a3620dbb 100644 --- a/external/bsd/dhcpcd/dist/src/control.c +++ b/external/bsd/dhcpcd/dist/src/control.c @@ -274,9 +274,8 @@ control_stop(struct dhcpcd_ctx *ctx) if (ctx->control_fd == -1) return 0; - eloop_event_delete(ctx->eloop, ctx->control_fd); - close(ctx->control_fd); - ctx->control_fd = -1; + + control_close(ctx); if (unlink(ctx->control_sock) == -1) retval = -1; @@ -455,6 +454,7 @@ control_close(struct dhcpcd_ctx *ctx) { if (ctx->control_fd != -1) { + eloop_event_delete(ctx->eloop, ctx->control_fd); close(ctx->control_fd); ctx->control_fd = -1; } diff --git a/external/bsd/dhcpcd/dist/src/defs.h b/external/bsd/dhcpcd/dist/src/defs.h index eaa105a00f04..a87ed4bb7568 100644 --- a/external/bsd/dhcpcd/dist/src/defs.h +++ b/external/bsd/dhcpcd/dist/src/defs.h @@ -29,7 +29,7 @@ #define CONFIG_H #define PACKAGE "dhcpcd" -#define VERSION "8.1.1" +#define VERSION "8.1.2" #ifndef CONFIG # define CONFIG SYSCONFDIR "/" PACKAGE ".conf" diff --git a/external/bsd/dhcpcd/dist/src/dhcp.c b/external/bsd/dhcpcd/dist/src/dhcp.c index 356b7708a7c9..e3f7aecdbc59 100644 --- a/external/bsd/dhcpcd/dist/src/dhcp.c +++ b/external/bsd/dhcpcd/dist/src/dhcp.c @@ -41,6 +41,10 @@ #include #undef __FAVOR_BSD +#ifdef AF_LINK +# include +#endif + #include #include #include @@ -132,9 +136,7 @@ static void dhcp_arp_found(struct arp_state *, const struct arp_msg *); #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 @@ -1550,7 +1552,10 @@ dhcp_openudp(struct interface *ifp) n = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) goto eexit; -#ifdef IP_RECVPKTINFO +#ifdef IP_RECVIF + if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &n, sizeof(n)) == -1) + goto eexit; +#else if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1) goto eexit; #endif @@ -1647,39 +1652,36 @@ dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length, static ssize_t dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len) { - int s; - struct msghdr msg; - struct sockaddr_in sin; - struct iovec iov[1]; + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr = *to, + .sin_port = htons(BOOTPS), +#ifdef HAVE_SA_LEN + .sin_len = sizeof(sin), +#endif + }; + struct iovec iov[] = { + { .iov_base = data, .iov_len = len } + }; + struct msghdr msg = { + .msg_name = (void *)&sin, + .msg_namelen = sizeof(sin), + .msg_iov = iov, + .msg_iovlen = 1, + }; struct dhcp_state *state = D_STATE(ifp); ssize_t r; + int fd; - iov[0].iov_base = data; - iov[0].iov_len = len; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr = *to; - sin.sin_port = htons(BOOTPS); -#ifdef HAVE_SA_LEN - sin.sin_len = sizeof(sin); -#endif - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = (void *)&sin; - msg.msg_namelen = sizeof(sin); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - s = state->udp_fd; - if (s == -1) { - s = dhcp_openudp(ifp); - if (s == -1) + fd = state->udp_fd; + if (fd == -1) { + fd = dhcp_openudp(ifp); + if (fd == -1) return -1; } - r = sendmsg(s, &msg, 0); + r = sendmsg(fd, &msg, 0); if (state->udp_fd == -1) - close(s); + close(fd); return r; } @@ -1780,7 +1782,7 @@ send_message(struct interface *ifp, uint8_t type, * As such we remove it from consideration without actually * stopping the interface. */ if (r == -1) { - logerr("%s: if_sendraw", ifp->name); + logerr("%s: bpf_send", ifp->name); switch(errno) { case ENETDOWN: case ENETRESET: @@ -2257,30 +2259,27 @@ dhcp_bind(struct interface *ifp) ipv4_applyaddr(ifp); -#ifdef IP_PKTINFO /* Close the BPF filter as we can now receive DHCP 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__); - /* Address sharing without master mode is - * not supported. It's also possible another - * DHCP client could be running which is - * even worse. - * We still need to work, so re-open BPF. */ - dhcp_openbpf(ifp); - } else - eloop_event_add(ctx->eloop, - state->udp_fd, dhcp_handleifudp, ifp); - } + if (!(state->udp_fd == -1 || + (state->old != NULL && state->old->yiaddr != state->new->yiaddr))) + return; + dhcp_close(ifp); + + /* If not in master mode, open an address specific socket. */ + if (ctx->udp_fd != -1) + return; + state->udp_fd = dhcp_openudp(ifp); + if (state->udp_fd == -1) { + logerr(__func__); + /* Address sharing without master mode is not supported. + * It's also possible another DHCP client could be running, + * which is even worse. + * We still need to work, so re-open BPF. */ + dhcp_openbpf(ifp); + return; } -#endif + eloop_event_add(ctx->eloop, state->udp_fd, dhcp_handleifudp, ifp); } static void @@ -2609,6 +2608,11 @@ dhcp_reboot(struct interface *ifp) ifp->name, inet_ntoa(state->lease.addr)); #ifdef ARP +#ifndef KERNEL_RFC5227 + /* Create the DHCP ARP state so we can defend it. */ + (void)dhcp_arp_new(ifp, &state->lease.addr); +#endif + /* If the address exists on the interface and no other interface * is currently using it then announce it to ensure this * interface gets the reply. */ @@ -3315,7 +3319,7 @@ checksums_valid(void *packet, struct ip *ip = packet; union pip { struct ip ip; - uint16_t w[sizeof(struct ip)]; + uint16_t w[sizeof(struct ip) / 2]; } pip = { .ip.ip_p = IPPROTO_UDP, .ip.ip_src = ip->ip_src, @@ -3350,7 +3354,7 @@ checksums_valid(void *packet, uh_sump = udpp + offsetof(struct udphdr, uh_sum); memset(uh_sump, 0, sizeof(udp.uh_sum)); - /* Checksum psuedo header and then UDP + payload. */ + /* Checksum pseudo header and then UDP + payload. */ in_cksum(pip.w, sizeof(pip.w), &csum); csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum); @@ -3450,6 +3454,35 @@ dhcp_readbpf(void *arg) state->bpf_flags &= ~BPF_READING; } +static void +dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) +{ + struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name; + struct iovec *iov = &msg->msg_iov[0]; + struct interface *ifp; + const struct dhcp_state *state; + + ifp = if_findifpfromcmsg(ctx, msg, NULL); + if (ifp == NULL) { + logerr(__func__); + return; + } + state = D_CSTATE(ifp); + if (state == NULL) { + logdebugx("%s: received BOOTP for inactive interface", + ifp->name); + return; + } + + if (state->bpf_fd != -1) { + /* Avoid a duplicate read if BPF is open for the interface. */ + return; + } + + dhcp_handlebootp(ifp, (struct bootp *)iov->iov_base, iov->iov_len, + &from->sin_addr); +} + static void dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) { @@ -3460,16 +3493,15 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) .iov_base = buf, .iov_len = sizeof(buf), }; -#ifdef IP_PKTINFO +#ifdef IP_RECVIF + unsigned char ctl[CMSG_SPACE(sizeof(struct sockaddr_dl))] = { 0 }; +#else 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; @@ -3486,31 +3518,8 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) 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; - } - state = D_CSTATE(ifp); - if (state == NULL) { - logdebugx("%s: received BOOTP for inactive interface", - ifp->name); - return; - } - } - - if (state->bpf_fd != -1) { - /* Avoid a duplicate read if BPF is open for the interface. */ - return; - } - - dhcp_handlebootp(ifp, (struct bootp *)(void *)buf, (size_t)bytes, - &from.sin_addr); -#endif + iov.iov_len = (size_t)bytes; + dhcp_recvmsg(ctx, &msg); } static void @@ -3521,16 +3530,24 @@ dhcp_handleudp(void *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_open(struct dhcpcd_ctx *ctx) +{ + + if (ctx->udp_fd != -1 || (ctx->udp_fd = dhcp_openudp(NULL)) == -1) + return ctx->udp_fd; + + eloop_event_add(ctx->eloop, ctx->udp_fd, dhcp_handleudp, ctx); + return ctx->udp_fd; +} static int dhcp_openbpf(struct interface *ifp) @@ -3740,16 +3757,13 @@ dhcp_start1(void *arg) * ICMP port unreachable message back to the DHCP server. * Only do this in master mode so we don't swallow messages * for dhcpcd running on another interface. */ - if (ctx->udp_fd == -1 && ctx->options & DHCPCD_MASTER) { - ctx->udp_fd = dhcp_openudp(NULL); - if (ctx->udp_fd == -1) { + if (ctx->options & DHCPCD_MASTER) { + if (dhcp_open(ctx) == -1) { /* Don't log an error if some other process * is handling this. */ if (errno != EADDRINUSE) - logerr("%s: dhcp_openudp", __func__); - } else - eloop_event_add(ctx->eloop, - ctx->udp_fd, dhcp_handleudp, ctx); + logerr("%s: dhcp_open", __func__); + } } if (dhcp_init(ifp) == -1) { @@ -4008,7 +4022,7 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) * to drop the lease. */ dhcp_drop(ifp, "EXPIRE"); dhcp_start1(ifp); - return NULL; + return ia; } } diff --git a/external/bsd/dhcpcd/dist/src/dhcp6.c b/external/bsd/dhcpcd/dist/src/dhcp6.c index 4ef2e565e969..c2d15bbfe824 100644 --- a/external/bsd/dhcpcd/dist/src/dhcp6.c +++ b/external/bsd/dhcpcd/dist/src/dhcp6.c @@ -3465,23 +3465,10 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, } static void -dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) +dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, 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; + struct sockaddr_in6 *from = msg->msg_name; + size_t len = msg->msg_iov[0].iov_len; char sfrom[INET6_ADDRSTRLEN]; struct interface *ifp; struct dhcp6_message *r; @@ -3489,14 +3476,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) uint8_t *o; uint16_t ol; - s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd; - bytes = recvmsg(s, &msg, 0); - if (bytes == -1) { - logerr(__func__); - return; - } - len = (size_t)bytes; - inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom)); + inet_ntop(AF_INET6, &from->sin6_addr, sfrom, sizeof(sfrom)); if (len < sizeof(struct dhcp6_message)) { logerrx("DHCPv6 packet too short from %s", sfrom); return; @@ -3505,14 +3485,14 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) if (ia != NULL) ifp = ia->iface; else { - ifp = if_findifpfromcmsg(ctx, &msg, NULL); + ifp = if_findifpfromcmsg(ctx, msg, NULL); if (ifp == NULL) { logerr(__func__); return; } } - r = (struct dhcp6_message *)buf; + r = (struct dhcp6_message *)msg->msg_iov[0].iov_base; o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol); if (o == NULL || ol != ctx->duid_len || memcmp(o, ctx->duid, ol) != 0) @@ -3580,6 +3560,35 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) dhcp6_recvif(ifp, sfrom, r, len); } +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; + ssize_t bytes; + + s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd; + bytes = recvmsg(s, &msg, 0); + if (bytes == -1) { + logerr(__func__); + return; + } + + iov.iov_len = (size_t)bytes; + dhcp6_recvmsg(ctx, &msg, ia); +} + static void dhcp6_recvaddr(void *arg) { @@ -3677,6 +3686,18 @@ dhcp6_activateinterfaces(struct interface *ifp) } #endif +static int +dhcp6_open(struct dhcpcd_ctx *ctx) +{ + + if (ctx->dhcp6_fd != -1 || + (ctx->dhcp6_fd = dhcp6_listen(ctx, NULL)) == -1) + return ctx->dhcp6_fd; + + eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx); + return ctx->dhcp6_fd; +} + static void dhcp6_start1(void *arg) { @@ -3687,11 +3708,9 @@ dhcp6_start1(void *arg) size_t i; const struct dhcp_compat *dhc; - if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) { - ctx->dhcp6_fd = dhcp6_listen(ctx, NULL); - if (ctx->dhcp6_fd == -1) + if (ctx->options & DHCPCD_MASTER) { + if (dhcp6_open(ctx) == -1) return; - eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx); } state = D6_STATE(ifp); diff --git a/external/bsd/dhcpcd/dist/src/dhcpcd.c b/external/bsd/dhcpcd/dist/src/dhcpcd.c index 6ab4f8e21c2a..11e8198014c3 100644 --- a/external/bsd/dhcpcd/dist/src/dhcpcd.c +++ b/external/bsd/dhcpcd/dist/src/dhcpcd.c @@ -186,6 +186,12 @@ handle_exit_timeout(void *arg) ctx = arg; logerrx("timed out"); if (!(ctx->options & DHCPCD_MASTER)) { + struct interface *ifp; + + TAILQ_FOREACH(ifp, ctx->ifaces, next) { + if (ifp->active == IF_ACTIVE_USER) + script_runreason(ifp, "STOPPED"); + } eloop_exit(ctx->eloop, EXIT_FAILURE); return; } @@ -702,6 +708,21 @@ dhcpcd_initstate(struct interface *ifp, unsigned long long options) dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options); } +static void +dhcpcd_reportssid(struct interface *ifp) +{ + char pssid[IF_SSIDLEN * 4]; + + if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, + ifp->ssid, ifp->ssid_len) == -1) + { + logerr(__func__); + return; + } + + loginfox("%s: connected to Access Point `%s'", ifp->name, pssid); +} + void dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, const char *ifname) @@ -773,6 +794,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, if (ifp->ssid_len != olen || memcmp(ifp->ssid, ossid, ifp->ssid_len)) { + dhcpcd_reportssid(ifp); #ifdef NOCARRIER_PRESERVE_IP dhcpcd_drop(ifp, 0); #endif @@ -970,7 +992,8 @@ run_preinit(struct interface *ifp) return; script_runreason(ifp, "PREINIT"); - + if (ifp->wireless) + dhcpcd_reportssid(ifp); if (ifp->options->options & DHCPCD_LINK && ifp->carrier != LINK_UNKNOWN) script_runreason(ifp, ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER"); @@ -1989,6 +2012,12 @@ printpidfile: ctx.options & DHCPCD_IPV4 ? " [ip4]" : "", ctx.options & DHCPCD_IPV6 ? " [ip6]" : ""); +#ifdef BSD + /* Disable the kernel RTADV sysctl as early as possible. */ + if (ctx.options & DHCPCD_IPV6 && ctx.options & DHCPCD_IPV6RS) + if_disable_rtadv(); +#endif + if (if_opensockets(&ctx) == -1) { logerr("%s: if_opensockets", __func__); goto exit_failure; @@ -2127,6 +2156,7 @@ exit1: if_free(ifp); } free(ctx.ifaces); + ctx.ifaces = NULL; } free_options(&ctx, ifo); #ifdef HAVE_OPEN_MEMSTREAM diff --git a/external/bsd/dhcpcd/dist/src/eloop.c b/external/bsd/dhcpcd/dist/src/eloop.c index e8be9a34ac87..0ab742a6fd10 100644 --- a/external/bsd/dhcpcd/dist/src/eloop.c +++ b/external/bsd/dhcpcd/dist/src/eloop.c @@ -830,7 +830,8 @@ eloop_new(void) return eloop; } -void eloop_free(struct eloop *eloop) +void +eloop_clear(struct eloop *eloop) { struct eloop_event *e; struct eloop_timeout *t; @@ -839,6 +840,12 @@ void eloop_free(struct eloop *eloop) return; free(eloop->event_fds); + eloop->event_fds = NULL; + eloop->events_len = 0; + eloop->events_maxfd = -1; + eloop->signals = NULL; + eloop->signals_len = 0; + while ((e = TAILQ_FIRST(&eloop->events))) { TAILQ_REMOVE(&eloop->events, e, next); free(e); @@ -855,11 +862,23 @@ void eloop_free(struct eloop *eloop) TAILQ_REMOVE(&eloop->free_timeouts, t, next); free(t); } -#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) - close(eloop->poll_fd); -#elif defined(HAVE_POLL) + +#if defined(HAVE_POLL) free(eloop->fds); + eloop->fds = NULL; + eloop->fds_len = 0; #endif +} + +void +eloop_free(struct eloop *eloop) +{ + +#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) + if (eloop != NULL) + close(eloop->poll_fd); +#endif + eloop_clear(eloop); free(eloop); } diff --git a/external/bsd/dhcpcd/dist/src/eloop.h b/external/bsd/dhcpcd/dist/src/eloop.h index a98d57ed7ec1..18cd06d7d60b 100644 --- a/external/bsd/dhcpcd/dist/src/eloop.h +++ b/external/bsd/dhcpcd/dist/src/eloop.h @@ -105,6 +105,7 @@ int eloop_signal_mask(struct eloop *, sigset_t *oldset); struct eloop * eloop_new(void); int eloop_requeue(struct eloop *); +void eloop_clear(struct eloop *); void eloop_free(struct eloop *); void eloop_exit(struct eloop *, int); int eloop_start(struct eloop *, sigset_t *); diff --git a/external/bsd/dhcpcd/dist/src/if-bsd.c b/external/bsd/dhcpcd/dist/src/if-bsd.c index a2c613edcb30..9f93f66fc093 100644 --- a/external/bsd/dhcpcd/dist/src/if-bsd.c +++ b/external/bsd/dhcpcd/dist/src/if-bsd.c @@ -1130,6 +1130,10 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) case LINK_STATE_UNKNOWN: link_state = LINK_UNKNOWN; break; +#ifdef LINK_STATE_FULL_DUPLEX + case LINK_STATE_HALF_DUPLEX: /* FALLTHROUGH */ + case LINK_STATE_FULL_DUPLEX: /* FALLTHROUGH */ +#endif case LINK_STATE_UP: link_state = LINK_UP; break; @@ -1484,6 +1488,42 @@ inet6_sysctl(int code, int val, int action) } #endif +int +if_applyra(const struct ra *rap) +{ +#ifdef SIOCSIFINFO_IN6 + struct in6_ndireq ndi = { .ndi.chlim = 0 }; + struct priv *priv = rap->iface->ctx->priv; + int error; + + strlcpy(ndi.ifname, rap->iface->name, sizeof(ndi.ifname)); + if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &ndi) == -1) + return -1; + + ndi.ndi.linkmtu = rap->mtu; + ndi.ndi.chlim = rap->hoplimit; + ndi.ndi.retrans = rap->retrans; + ndi.ndi.basereachable = rap->reachable; + error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi); + if (error == -1 && errno == EINVAL) { + /* + * Very likely that this is caused by a dodgy MTU + * setting specific to the interface. + * Let's set it to "unspecified" and try again. + * Doesn't really matter as we fix the MTU against the + * routes we add as not all OS support SIOCSIFINFO_IN6. + */ + ndi.ndi.linkmtu = 0; + error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi); + } + return error; +#else +#warning OS does not allow setting of RA bits hoplimit, retrans or reachable + UNUSED(rap); + return 0; +#endif +} + #ifdef IPV6_MANAGETEMPADDR #ifndef IPV6CTL_TEMPVLTIME #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0) @@ -1619,6 +1659,22 @@ set_ifxflags(int s, const struct interface *ifp) #define ND6_NDI_FLAGS #endif +void +if_disable_rtadv(void) +{ +#if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV) + int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); + + if (ra == -1) { + if (errno != ENOENT) + logerr("IPV6CTL_ACCEPT_RTADV"); + else if (ra != 0) + if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) + logerr("IPV6CTL_ACCEPT_RTADV"); + } +#endif +} + void if_setup_inet6(const struct interface *ifp) { @@ -1690,21 +1746,6 @@ if_setup_inet6(const struct interface *ifp) logerr("%s: set_ifxflags", ifp->name); #endif -#if defined(IPV6CTL_ACCEPT_RTADV) && !defined(ND6_IFF_ACCEPT_RTADV) - /* If we cannot control ra per interface, disable it globally. */ - if (ifp->options->options & DHCPCD_IPV6RS) { - int ra = get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV); - - if (ra == -1) { - if (errno != ENOENT) - logerr("IPV6CTL_ACCEPT_RTADV"); - else if (ra != 0) - if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 0) == -1) - logerr("IPV6CTL_ACCEPT_RTADV"); - } - } -#endif - #if defined(IPV6CTL_ACCEPT_RTADV) || defined(ND6_IFF_ACCEPT_RTADV) /* Flush the kernel knowledge of advertised routers * and prefixes so the kernel does not expire prefixes diff --git a/external/bsd/dhcpcd/dist/src/if.c b/external/bsd/dhcpcd/dist/src/if.c index 459af3afd5ae..c0b67ec99144 100644 --- a/external/bsd/dhcpcd/dist/src/if.c +++ b/external/bsd/dhcpcd/dist/src/if.c @@ -740,9 +740,13 @@ if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit) struct cmsghdr *cm; unsigned int ifindex = 0; struct interface *ifp; -#if defined(INET) && defined(IP_PKTINFO) +#ifdef INET +#ifdef IP_RECVIF + struct sockaddr_dl sdl; +#else struct in_pktinfo ipi; #endif +#endif #ifdef INET6 struct in6_pktinfo ipi6; #else @@ -753,15 +757,27 @@ if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit) cm; cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm)) { -#if defined(INET) && defined(IP_PKTINFO) +#ifdef INET if (cm->cmsg_level == IPPROTO_IP) { switch(cm->cmsg_type) { +#ifdef IP_RECVIF + case IP_RECVIF: + if (cm->cmsg_len < + offsetof(struct sockaddr_dl, sdl_index) + + sizeof(sdl.sdl_index)) + continue; + memcpy(&sdl, CMSG_DATA(cm), + MIN(sizeof(sdl), cm->cmsg_len)); + ifindex = sdl.sdl_index; + break; +#else case IP_PKTINFO: if (cm->cmsg_len != CMSG_LEN(sizeof(ipi))) continue; memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi)); ifindex = (unsigned int)ipi.ipi_ifindex; break; +#endif } } #endif diff --git a/external/bsd/dhcpcd/dist/src/if.h b/external/bsd/dhcpcd/dist/src/if.h index 19b6b2fe1b97..cc62cc948fa5 100644 --- a/external/bsd/dhcpcd/dist/src/if.h +++ b/external/bsd/dhcpcd/dist/src/if.h @@ -65,6 +65,7 @@ #include "dhcpcd.h" #include "ipv4.h" #include "ipv6.h" +#include "ipv6nd.h" #include "route.h" #define EUI64_ADDR_LEN 8 @@ -195,6 +196,7 @@ int if_addrflags(const struct interface *, const struct in_addr *, #endif #ifdef INET6 +void if_disable_rtadv(void); void if_setup_inet6(const struct interface *); #ifdef IPV6_MANAGETEMPADDR int ip6_use_tempaddr(const char *ifname); @@ -205,6 +207,7 @@ int ip6_temp_valid_lifetime(const char *ifname); #endif int ip6_forwarding(const char *ifname); +int if_applyra(const struct ra *); int if_address6(unsigned char, const struct ipv6_addr *); int if_addrflags6(const struct interface *, const struct in6_addr *, const char *); diff --git a/external/bsd/dhcpcd/dist/src/ipv4.c b/external/bsd/dhcpcd/dist/src/ipv4.c index c55a7da6cb1d..53550696048b 100644 --- a/external/bsd/dhcpcd/dist/src/ipv4.c +++ b/external/bsd/dhcpcd/dist/src/ipv4.c @@ -654,7 +654,7 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, #endif ia->flags = IPV4_AF_NEW; } else - ia->flags |= ~IPV4_AF_NEW; + ia->flags &= ~IPV4_AF_NEW; ia->mask = *mask; ia->brd = *bcast; @@ -687,7 +687,8 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, if (errno != EEXIST) logerr("%s: if_addaddress", __func__); - free(ia); + if (ia->flags & IPV4_AF_NEW) + free(ia); return NULL; } @@ -941,7 +942,7 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx, #endif } - if (cmd == RTM_DELADDR && ia != NULL) + if (cmd == RTM_DELADDR) free(ia); } @@ -951,15 +952,13 @@ ipv4_free(struct interface *ifp) struct ipv4_state *state; struct ipv4_addr *ia; - if (ifp) { - state = IPV4_STATE(ifp); - if (state) { - while ((ia = TAILQ_FIRST(&state->addrs))) { - TAILQ_REMOVE(&state->addrs, ia, next); - free(ia); - } - free(state->buffer); - free(state); - } + if (ifp == NULL || (state = IPV4_STATE(ifp)) == NULL) + return; + + while ((ia = TAILQ_FIRST(&state->addrs))) { + TAILQ_REMOVE(&state->addrs, ia, next); + free(ia); } + free(state->buffer); + free(state); } diff --git a/external/bsd/dhcpcd/dist/src/ipv6nd.c b/external/bsd/dhcpcd/dist/src/ipv6nd.c index 929b071d090b..06e158b994da 100644 --- a/external/bsd/dhcpcd/dist/src/ipv6nd.c +++ b/external/bsd/dhcpcd/dist/src/ipv6nd.c @@ -196,36 +196,41 @@ ipv6nd_printoptions(const struct dhcpcd_ctx *ctx, static int ipv6nd_open0(void) { - int s, on; + int fd, on; struct icmp6_filter filt; #define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK - s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); + fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); #undef SOCK_FLAGS - if (s == -1) + if (fd == -1) return -1; /* RFC4861 4.1 */ on = 255; - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) == -1) goto eexit; on = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof(on)) == -1) + goto eexit; + + on = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, + if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) goto eexit; - return s; + return fd; eexit: - close(s); + close(fd); return -1; } @@ -233,7 +238,7 @@ eexit: static int ipv6nd_open(struct interface *ifp) { - int s; + int fd; struct ipv6_mreq mreq = { .ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, .ipv6mr_interface = ifp->index @@ -244,52 +249,44 @@ ipv6nd_open(struct interface *ifp) if (state->nd_fd != -1) return state->nd_fd; - s = ipv6nd_open0(); - if (s == -1) + fd = ipv6nd_open0(); + if (fd == -1) return -1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, + if (setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &ifindex, sizeof(ifindex)) == -1) { - close(s); + close(fd); return -1; } - if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, + if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) { - close(s); + close(fd); return -1; } - state->nd_fd = s; - eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp); - return s; + state->nd_fd = fd; + eloop_event_add(ifp->ctx->eloop, fd, ipv6nd_handledata, ifp); + return fd; } #else static int ipv6nd_open(struct dhcpcd_ctx *ctx) { - int s, on; + int fd; if (ctx->nd_fd != -1) return ctx->nd_fd; - s = ipv6nd_open0(); - if (s == -1) + fd = ipv6nd_open0(); + if (fd == -1) return -1; - on = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &on, sizeof(on)) == -1) - { - close(s); - return -1; - } - - ctx->nd_fd = s; - eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx); - return s; + ctx->nd_fd = fd; + eloop_event_add(ctx->eloop, fd, ipv6nd_handledata, ctx); + return fd; } #endif @@ -559,6 +556,76 @@ ipv6nd_startexpire(struct interface *ifp) ipv6nd_expire, ifp); } +static int +ipv6nd_rtpref(struct ra *rap) +{ + + switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) { + case ND_RA_FLAG_RTPREF_HIGH: + return RTPREF_HIGH; + case ND_RA_FLAG_RTPREF_MEDIUM: + case ND_RA_FLAG_RTPREF_RSV: + return RTPREF_MEDIUM; + case ND_RA_FLAG_RTPREF_LOW: + return RTPREF_LOW; + default: + logerrx("%s: impossible RA flag %x", __func__, rap->flags); + return RTPREF_INVALID; + } + /* NOTREACHED */ +} + +static void +ipv6nd_sortrouters(struct dhcpcd_ctx *ctx) +{ + struct ra_head sorted_routers = TAILQ_HEAD_INITIALIZER(sorted_routers); + struct ra *ra1, *ra2; + + while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) { + TAILQ_REMOVE(ctx->ra_routers, ra1, next); + TAILQ_FOREACH(ra2, &sorted_routers, next) { + if (ra1->iface->metric < ra2->iface->metric) + continue; + if (ra1->expired && !ra2->expired) + continue; + if (ra1->lifetime == 0 && ra2->lifetime != 0) + continue; + if (!ra1->isreachable && ra2->reachable) + continue; + if (ipv6nd_rtpref(ra1) < ipv6nd_rtpref(ra2)) + continue; + /* All things being equal, prefer older routers. */ + if (timespeccmp(&ra1->acquired, &ra2->acquired, >=)) + continue; + TAILQ_INSERT_BEFORE(ra2, ra1, next); + break; + } + if (ra2 == NULL) + TAILQ_INSERT_TAIL(&sorted_routers, ra1, next); + } + + TAILQ_CONCAT(ctx->ra_routers, &sorted_routers, next); +} + +static void +ipv6nd_applyra(struct dhcpcd_ctx *ctx, struct interface *ifp) +{ + struct ra *rap; + struct rs_state *state = RS_STATE(ifp); + + TAILQ_FOREACH(rap, ctx->ra_routers, next) { + if (rap->iface == ifp) + break; + } + + if (rap == NULL) + return; + + state->retrans = rap->retrans; + if (if_applyra(rap) == -1) + logerr(__func__); +} + /* * Neighbour reachability. * @@ -585,23 +652,20 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, bool reachable) break; } - if (rap == NULL || rap->expired) + if (rap == NULL || rap->expired || rap->reachable == reachable) return; - if (reachable) { - if (rap->isreachable) - return; - loginfox("%s: %s is reachable again", - rap->iface->name, rap->sfrom); - rap->isreachable = true; + rap->isreachable = reachable; + loginfox("%s: %s is %s", rap->iface->name, rap->sfrom, + reachable ? "reachable again" : "unreachable"); + + /* See if we can install a reachable default router. */ + ipv6nd_sortrouters(ctx); + ipv6nd_applyra(ctx, rap->iface); + rt_build(ctx, AF_INET6); + + if (reachable) return; - } else { - if (!rap->isreachable) - return; - logwarnx("%s: %s is unreachable", - rap->iface->name, rap->sfrom); - rap->isreachable = false; - } /* If we have no reachable default routers, try and solicit one. */ TAILQ_FOREACH(rapr, ctx->ra_routers, next) { @@ -722,42 +786,6 @@ ipv6nd_free(struct interface *ifp) return n; } -static int -rtpref(struct ra *rap) -{ - - switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) { - case ND_RA_FLAG_RTPREF_HIGH: - return (RTPREF_HIGH); - case ND_RA_FLAG_RTPREF_MEDIUM: - case ND_RA_FLAG_RTPREF_RSV: - return (RTPREF_MEDIUM); - case ND_RA_FLAG_RTPREF_LOW: - return (RTPREF_LOW); - default: - logerrx("rtpref: impossible RA flag %x", rap->flags); - return (RTPREF_INVALID); - } - /* NOTREACHED */ -} - -static void -add_router(struct dhcpcd_ctx *ctx, struct ra *router) -{ - struct ra *rap; - - TAILQ_FOREACH(rap, ctx->ra_routers, next) { - if (router->iface->metric < rap->iface->metric || - (router->iface->metric == rap->iface->metric && - rtpref(router) > rtpref(rap))) - { - TAILQ_INSERT_BEFORE(rap, router, next); - return; - } - } - TAILQ_INSERT_TAIL(ctx->ra_routers, router, next); -} - static int ipv6nd_scriptrun(struct ra *rap) { @@ -965,6 +993,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct dhcp_opt *dho; bool new_rap, new_data, has_address; uint32_t old_lifetime; + int ifmtu; __printflike(1, 2) void (*logfunc)(const char *, ...); #ifdef IPV6_MANAGETEMPADDR uint8_t new_ap; @@ -1074,20 +1103,25 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, if (!new_rap && rap->lifetime == 0 && old_lifetime != 0) logwarnx("%s: %s: no longer a default router", ifp->name, rap->sfrom); - if (nd_ra->nd_ra_reachable) { + if (nd_ra->nd_ra_curhoplimit != 0) + rap->hoplimit = nd_ra->nd_ra_curhoplimit; + else + rap->hoplimit = IPV6_DEFHLIM; + if (nd_ra->nd_ra_reachable != 0) { rap->reachable = ntohl(nd_ra->nd_ra_reachable); if (rap->reachable > MAX_REACHABLE_TIME) rap->reachable = 0; - } - if (nd_ra->nd_ra_retransmit) { - struct rs_state *state = RS_STATE(ifp); - - state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit); - } + } else + rap->reachable = REACHABLE_TIME; + if (nd_ra->nd_ra_retransmit != 0) + rap->retrans = ntohl(nd_ra->nd_ra_retransmit); + else + rap->retrans = RETRANS_TIMER; rap->expired = false; rap->hasdns = false; rap->isreachable = true; has_address = false; + rap->mtu = 0; #ifdef IPV6_AF_TEMPORARY ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY); @@ -1245,22 +1279,30 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, case ND_OPT_MTU: if (len < sizeof(mtu)) { - logerrx("%s: short MTU option", ifp->name); + logfunc("%s: short MTU option", ifp->name); break; } memcpy(&mtu, p, sizeof(mtu)); mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu); if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) { - logerrx("%s: invalid MTU %d", + logfunc("%s: invalid MTU %d", ifp->name, mtu.nd_opt_mtu_mtu); break; } - rap->mtu = mtu.nd_opt_mtu_mtu; + ifmtu = if_getmtu(ifp); + if (ifmtu == -1) + logerr("if_getmtu"); + else if (mtu.nd_opt_mtu_mtu > (uint32_t)ifmtu) { + logfunc("%s: advertised MTU %d" + " is greater than link MTU %d", + ifp->name, mtu.nd_opt_mtu_mtu, ifmtu); + rap->mtu = (uint32_t)ifmtu; + } else + rap->mtu = mtu.nd_opt_mtu_mtu; break; - case ND_OPT_RDNSS: if (len < sizeof(rdnss)) { - logerrx("%s: short RDNSS option", ifp->name); + logfunc("%s: short RDNSS option", ifp->name); break; } memcpy(&rdnss, p, sizeof(rdnss)); @@ -1295,12 +1337,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, ifp->name); if (new_rap) - add_router(ifp->ctx, rap); + TAILQ_INSERT_TAIL(ctx->ra_routers, rap, next); + if (new_data) + ipv6nd_sortrouters(ifp->ctx); if (ifp->ctx->options & DHCPCD_TEST) { script_runreason(ifp, "TEST"); goto handle_flag; } + ipv6nd_applyra(ifp->ctx, ifp); ipv6_addaddrs(&rap->addrs); #ifdef IPV6_MANAGETEMPADDR ipv6_addtempaddrs(ifp, &rap->acquired); @@ -1718,11 +1763,52 @@ ipv6nd_drop(struct interface *ifp) } } +static void +ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) +{ + struct sockaddr_in6 *from = (struct sockaddr_in6 *)msg->msg_name; + char sfrom[INET6_ADDRSTRLEN]; + int hoplimit = 0; + struct icmp6_hdr *icp; + struct interface *ifp; + size_t len = msg->msg_iov[0].iov_len; + + 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", sfrom); + return; + } + + ifp = if_findifpfromcmsg(ctx, msg, &hoplimit); + if (ifp == NULL) { + logerr(__func__); + return; + } + + /* Don't do anything if the user hasn't configured it. */ + if (ifp->active != IF_ACTIVE_USER || + !(ifp->options->options & DHCPCD_IPV6)) + return; + + icp = (struct icmp6_hdr *)msg->msg_iov[0].iov_base; + if (icp->icmp6_code == 0) { + switch(icp->icmp6_type) { + case ND_ROUTER_ADVERT: + 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, sfrom); +} + static void ipv6nd_handledata(void *arg) { struct dhcpcd_ctx *ctx; - int s; + int fd; struct sockaddr_in6 from; unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */ struct iovec iov = { @@ -1736,60 +1822,27 @@ ipv6nd_handledata(void *arg) .msg_control = ctl, .msg_controllen = sizeof(ctl), }; ssize_t len; - char sfrom[INET6_ADDRSTRLEN]; - int hoplimit = 0; - struct icmp6_hdr *icp; - struct interface *ifp; #ifdef __sun + struct interface *ifp; struct rs_state *state; ifp = arg; state = RS_STATE(ifp); ctx = ifp->ctx; - s = state->nd_fd; + fd = state->nd_fd; #else ctx = arg; - s = ctx->nd_fd; + fd = ctx->nd_fd; #endif - len = recvmsg(s, &msg, 0); + len = recvmsg(fd, &msg, 0); if (len == -1) { logerr(__func__); return; } - 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", sfrom); - return; - } -#ifdef __sun - if_findifpfromcmsg(ctx, &msg, &hoplimit); -#else - ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit); - if (ifp == NULL) { - logerr(__func__); - return; - } -#endif - - /* Don't do anything if the user hasn't configured it. */ - if (ifp->active != IF_ACTIVE_USER || - !(ifp->options->options & DHCPCD_IPV6)) - return; - - icp = (struct icmp6_hdr *)buf; - if (icp->icmp6_code == 0) { - switch(icp->icmp6_type) { - case ND_ROUTER_ADVERT: - 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, sfrom); + iov.iov_len = (size_t)len; + ipv6nd_recvmsg(ctx, &msg); } static void diff --git a/external/bsd/dhcpcd/dist/src/ipv6nd.h b/external/bsd/dhcpcd/dist/src/ipv6nd.h index 16c4dc795041..82e024e5e767 100644 --- a/external/bsd/dhcpcd/dist/src/ipv6nd.h +++ b/external/bsd/dhcpcd/dist/src/ipv6nd.h @@ -50,6 +50,7 @@ struct ra { uint32_t reachable; uint32_t retrans; uint32_t mtu; + uint8_t hoplimit; struct ipv6_addrhead addrs; bool hasdns; bool expired; @@ -78,6 +79,10 @@ struct rs_state { #define RTR_SOLICITATION_INTERVAL 4 /* seconds */ #define MAX_RTR_SOLICITATIONS 3 /* times */ #define MAX_NEIGHBOR_ADVERTISEMENT 3 /* 3 transmissions */ + +#ifndef IPV6_DEFHLIM +#define IPV6_DEFHLIM 64 +#endif #endif /* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */ diff --git a/external/bsd/dhcpcd/dist/src/script.c b/external/bsd/dhcpcd/dist/src/script.c index 3cb33b6e709b..4d0ba447cfdc 100644 --- a/external/bsd/dhcpcd/dist/src/script.c +++ b/external/bsd/dhcpcd/dist/src/script.c @@ -86,9 +86,9 @@ if_printoptions(void) } static int -exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env) +script_exec(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env) { - pid_t pid; + pid_t pid = 0; posix_spawnattr_t attr; int r; #ifdef USE_SIGNALS @@ -173,14 +173,55 @@ efprintf(FILE *fp, const char *fmt, ...) return r; } +static char ** +script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len) +{ + char **env, **envp, *bufp, *endp; + size_t nenv; + + /* Count the terminated env strings. + * Assert that the terminations are correct. */ + nenv = 0; + endp = buf + len; + for (bufp = buf; bufp < endp; bufp++) { + if (*bufp == '\0') { +#ifndef NDEBUG + if (bufp + 1 < endp) + assert(*(bufp + 1) != '\0'); +#endif + nenv++; + } + } + assert(*(bufp - 1) == '\0'); + + if (ctx->script_envlen < nenv) { + env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env)); + if (env == NULL) + return NULL; + ctx->script_env = env; + ctx->script_envlen = nenv; + } + + bufp = buf; + envp = ctx->script_env; + *envp++ = bufp++; + endp--; /* Avoid setting the last \0 to an invalid pointer */ + for (; bufp < endp; bufp++) { + if (*bufp == '\0') + *envp++ = bufp + 1; + } + *envp = NULL; + + return ctx->script_env; +} + static long make_env(const struct interface *ifp, const char *reason) { struct dhcpcd_ctx *ctx = ifp->ctx; FILE *fp; - char **env, **envp, *bufp, *endp, *path; - size_t nenv; long buf_pos, i; + char *path; int protocol = PROTO_LINK; const struct if_options *ifo = ifp->options; const struct interface *ifp2; @@ -377,7 +418,7 @@ make_env(const struct interface *ifp, const char *reason) if (efprintf(fp, "syslog_debug=true") == -1) goto eexit; } - if (*ifp->profile) { + if (*ifp->profile != '\0') { if (efprintf(fp, "profile=%s", ifp->profile) == -1) goto eexit; } @@ -476,38 +517,8 @@ dumplease: fp = NULL; #endif - /* Count the terminated env strings. - * Assert that the terminations are correct. */ - nenv = 0; - endp = ctx->script_buf + buf_pos; - for (bufp = ctx->script_buf; bufp < endp; bufp++) { - if (*bufp == '\0') { -#ifndef NDEBUG - if (bufp + 1 < endp) - assert(*(bufp + 1) != '\0'); -#endif - nenv++; - } - } - assert(*(bufp - 1) == '\0'); - - if (ctx->script_envlen < nenv) { - env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env)); - if (env == NULL) - goto eexit; - ctx->script_env = env; - ctx->script_envlen = nenv; - } - - bufp = ctx->script_buf; - envp = ctx->script_env; - *envp++ = bufp++; - endp--; /* Avoid setting the last \0 to an invalid pointer */ - for (; bufp < endp; bufp++) { - if (*bufp == '\0') - *envp++ = bufp + 1; - } - *envp = NULL; + if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL) + goto eexit; return buf_pos - 1; @@ -620,7 +631,7 @@ script_runreason(const struct interface *ifp, const char *reason) argv[1] = NULL; logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); - pid = exec_script(ctx, argv, ctx->script_env); + pid = script_exec(ctx, argv, ctx->script_env); if (pid == -1) logerr("%s: %s", __func__, argv[0]); else if (pid != 0) {