From: Roy Marples Date: Fri, 2 May 2014 23:54:29 +0000 (+0000) Subject: Change the readrawsocket API a little so that we know when EOF is reached. X-Git-Tag: v6.4.0~75 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68e672702b8683e64e6c93d2687bd8f47f74c760;p=thirdparty%2Fdhcpcd.git Change the readrawsocket API a little so that we know when EOF is reached. This allows us to remove the non blocking option from our sockets due to the way BPF works. --- diff --git a/arp.c b/arp.c index 22ff194f..93e2bd9c 100644 --- a/arp.c +++ b/arp.c @@ -134,14 +134,20 @@ arp_packet(void *arg) const char *hwaddr; struct in_addr ina; char hwbuf[HWADDR_LEN * 3]; + int flags; state = D_STATE(ifp); state->fail.s_addr = 0; - for(;;) { + flags = 0; + while (!(flags & RAW_EOF)) { bytes = if_readrawpacket(ifp, ETHERTYPE_ARP, - arp_buffer, sizeof(arp_buffer), NULL); - if (bytes == 0 || bytes == -1) + arp_buffer, sizeof(arp_buffer), &flags); + if (bytes == 0 || bytes == -1) { + syslog(LOG_ERR, "%s: arp if_readrawpacket: %m", + ifp->name); + dhcp_close(ifp); return; + } /* We must have a full ARP header */ if ((size_t)bytes < sizeof(ar)) continue; diff --git a/dhcp.c b/dhcp.c index 636acc5a..0ddc7b64 100644 --- a/dhcp.c +++ b/dhcp.c @@ -2557,55 +2557,58 @@ valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from, static void dhcp_handlepacket(void *arg) { - struct interface *iface = arg; + struct interface *ifp = arg; struct dhcp_message *dhcp = NULL; const uint8_t *pp; size_t bytes; struct in_addr from; - int i, partialcsum = 0; - const struct dhcp_state *state = D_CSTATE(iface); + int i, flags; + const struct dhcp_state *state = D_CSTATE(ifp); - /* We loop through until our buffer is empty. - * The benefit is that if we get >1 DHCP packet in our buffer and - * the first one fails for any reason, we can use the next. */ - for(;;) { - bytes = (size_t)if_readrawpacket(iface, ETHERTYPE_IP, - iface->ctx->packet, udp_dhcp_len, &partialcsum); - if (bytes == 0 || (ssize_t)bytes == -1) + /* Need this API due to BPF */ + flags = 0; + while (!(flags & RAW_EOF)) { + bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP, + ifp->ctx->packet, udp_dhcp_len, &flags); + if (bytes == 0 || (ssize_t)bytes == -1) { + syslog(LOG_ERR, "%s: dhcp if_readrawpacket: %m", + ifp->name); + dhcp_close(ifp); break; - if (valid_udp_packet(iface->ctx->packet, bytes, - &from, partialcsum) == -1) + } + if (valid_udp_packet(ifp->ctx->packet, bytes, + &from, flags & RAW_PARTIALCSUM) == -1) { syslog(LOG_ERR, "%s: invalid UDP packet from %s", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); continue; } - i = whitelisted_ip(iface->options, from.s_addr); + i = whitelisted_ip(ifp->options, from.s_addr); if (i == 0) { syslog(LOG_WARNING, "%s: non whitelisted DHCP packet from %s", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); continue; } else if (i != 1 && - blacklisted_ip(iface->options, from.s_addr) == 1) + blacklisted_ip(ifp->options, from.s_addr) == 1) { syslog(LOG_WARNING, "%s: blacklisted DHCP packet from %s", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); continue; } - if (iface->flags & IFF_POINTOPOINT && + if (ifp->flags & IFF_POINTOPOINT && state->dst.s_addr != from.s_addr) { syslog(LOG_WARNING, "%s: server %s is not destination", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); } - bytes = get_udp_data(&pp, iface->ctx->packet); + bytes = get_udp_data(&pp, ifp->ctx->packet); if (bytes > sizeof(*dhcp)) { syslog(LOG_ERR, "%s: packet greater than DHCP size from %s", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); continue; } if (dhcp == NULL) { @@ -2618,22 +2621,22 @@ dhcp_handlepacket(void *arg) memcpy(dhcp, pp, bytes); if (dhcp->cookie != htonl(MAGIC_COOKIE)) { syslog(LOG_DEBUG, "%s: bogus cookie from %s", - iface->name, inet_ntoa(from)); + ifp->name, inet_ntoa(from)); continue; } /* Ensure packet is for us */ - if (iface->hwlen <= sizeof(dhcp->chaddr) && - memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen)) + if (ifp->hwlen <= sizeof(dhcp->chaddr) && + memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen)) { char buf[sizeof(dhcp->chaddr) * 3]; syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s", - iface->name, ntohl(dhcp->xid), + ifp->name, ntohl(dhcp->xid), hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr), buf, sizeof(buf))); continue; } - dhcp_handledhcp(iface, &dhcp, &from); + dhcp_handledhcp(ifp, &dhcp, &from); if (state->raw_fd == -1) break; } diff --git a/dhcp6.c b/dhcp6.c index b9970e7b..8a25dd93 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -2036,8 +2036,11 @@ dhcp6_handledata(void *arg) ctx = dhcpcd_ctx->ipv6; ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); bytes = recvmsg(ctx->dhcp_fd, &ctx->rcvhdr, 0); - if (bytes == -1) { + if (bytes == -1 || bytes == 0) { syslog(LOG_ERR, "recvmsg: %m"); + close(ctx->dhcp_fd); + eloop_event_delete(dhcpcd_ctx->eloop, ctx->dhcp_fd); + ctx->dhcp_fd = -1; return; } len = (size_t)bytes; diff --git a/dhcpcd.c b/dhcpcd.c index f9cb85da..b318cc36 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -641,8 +641,12 @@ handle_link(void *arg) struct dhcpcd_ctx *ctx; ctx = arg; - if (if_managelink(ctx) == -1 && errno != ENXIO && errno != ENODEV) + if (if_managelink(ctx) == -1) { syslog(LOG_ERR, "if_managelink: %m"); + eloop_event_delete(ctx->eloop, ctx->link_fd); + close(ctx->link_fd); + ctx->link_fd = -1; + } } static void diff --git a/eloop.c b/eloop.c index ce632d7a..141eb29c 100644 --- a/eloop.c +++ b/eloop.c @@ -386,7 +386,7 @@ eloop_start(struct dhcpcd_ctx *dctx) n = poll(ctx->fds, ctx->events_len, timeout); #endif if (n == -1) { - if (errno == EAGAIN || errno == EINTR) + if (errno == EINTR) continue; syslog(LOG_ERR, "poll: %m"); break; @@ -395,7 +395,7 @@ eloop_start(struct dhcpcd_ctx *dctx) /* Process any triggered events. */ if (n > 0) { TAILQ_FOREACH(e, &ctx->events, next) { - if (e->pollfd->revents & (POLLIN | POLLHUP)) { + if (e->pollfd->revents & (POLLIN)) { e->callback(e->arg); /* We need to break here as the * callback could destroy the next diff --git a/if-bsd.c b/if-bsd.c index b36ccfd9..474ec038 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -114,7 +114,7 @@ if_openlinksocket(void) { #ifdef SOCK_CLOEXEC - return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0); #else int s, flags; @@ -126,12 +126,6 @@ if_openlinksocket(void) close(s); return -1; } - if ((flags = fcntl(s, F_GETFL, 0)) == -1 || - fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) - { - close(s); - return -1; - } return s; #endif } @@ -228,14 +222,14 @@ if_openrawsocket(struct interface *ifp, int protocol) int flags; #endif #ifdef _PATH_BPF - fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC | O_NONBLOCK); + fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC); #else char device[32]; int n = 0; do { snprintf(device, sizeof(device), "/dev/bpf%d", n++); - fd = open(device, O_RDWR | O_CLOEXEC | O_NONBLOCK); + fd = open(device, O_RDWR | O_CLOEXEC); } while (fd == -1 && errno == EBUSY); #endif @@ -289,13 +283,6 @@ if_openrawsocket(struct interface *ifp, int protocol) if (ioctl(fd, BIOCSETF, &pf) == -1) goto eexit; -#ifdef __OpenBSD__ - /* For some reason OpenBSD fails to open the fd as non blocking */ - if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || - fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) - goto eexit; -#endif - return fd; eexit: @@ -333,9 +320,9 @@ if_sendrawpacket(const struct interface *ifp, int protocol, * So we pass the buffer in the API so we can loop on >1 packet. */ ssize_t if_readrawpacket(struct interface *ifp, int protocol, - void *data, size_t len, int *partialcsum) + void *data, size_t len, int *flags) { - int fd = -1; + int fd; struct bpf_hdr packet; ssize_t bytes; const unsigned char *payload; @@ -347,16 +334,14 @@ if_readrawpacket(struct interface *ifp, int protocol, else fd = state->raw_fd; - if (partialcsum != NULL) - *partialcsum = 0; /* Not supported on BSD */ + if (flags != NULL) + *flags = 0; /* Not supported on BSD */ for (;;) { if (state->buffer_len == 0) { bytes = read(fd, state->buffer, state->buffer_size); - if (bytes == -1) - return errno == EAGAIN ? 0 : -1; - else if ((size_t)bytes < sizeof(packet)) - return -1; + if (bytes == -1 || bytes == 0) + return bytes; state->buffer_len = (size_t)bytes; state->buffer_pos = 0; } @@ -377,8 +362,10 @@ if_readrawpacket(struct interface *ifp, int protocol, next: state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen + packet.bh_caplen); - if (state->buffer_pos >= state->buffer_len) + if (state->buffer_pos >= state->buffer_len) { state->buffer_len = state->buffer_pos = 0; + *flags |= RAW_EOF; + } if (bytes != -1) return bytes; } @@ -774,143 +761,136 @@ if_managelink(struct dhcpcd_ctx *ctx) int ifa_flags; #endif - for (;;) { - bytes = read(ctx->link_fd, msg, sizeof(msg)); - if (bytes == -1) { - if (errno == EAGAIN) - return 0; - if (errno == EINTR) - continue; - return -1; - } - e = msg + bytes; - for (p = msg; p < e; p += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)p; - // Ignore messages generated by us - if (rtm->rtm_pid == getpid()) - break; - switch(rtm->rtm_type) { + bytes = read(ctx->link_fd, msg, sizeof(msg)); + if (bytes == -1 || bytes == 0) + return bytes; + e = msg + bytes; + for (p = msg; p < e; p += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)p; + // Ignore messages generated by us + if (rtm->rtm_pid == getpid()) + break; + switch(rtm->rtm_type) { #ifdef RTM_IFANNOUNCE - case RTM_IFANNOUNCE: - ifan = (struct if_announcemsghdr *)(void *)p; - switch(ifan->ifan_what) { - case IFAN_ARRIVAL: - dhcpcd_handleinterface(ctx, 1, - ifan->ifan_name); - break; - case IFAN_DEPARTURE: - dhcpcd_handleinterface(ctx, -1, - ifan->ifan_name); - break; - } + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)(void *)p; + switch(ifan->ifan_what) { + case IFAN_ARRIVAL: + dhcpcd_handleinterface(ctx, 1, + ifan->ifan_name); break; + case IFAN_DEPARTURE: + dhcpcd_handleinterface(ctx, -1, + ifan->ifan_name); + break; + } + break; #endif - case RTM_IFINFO: - ifm = (struct if_msghdr *)(void *)p; - memset(ifname, 0, sizeof(ifname)); - if (!(if_indextoname(ifm->ifm_index, ifname))) - break; - switch (ifm->ifm_data.ifi_link_state) { - case LINK_STATE_DOWN: - len = LINK_DOWN; - break; - case LINK_STATE_UP: - len = LINK_UP; - break; - default: - /* handle_carrier will re-load - * the interface flags and check for - * IFF_RUNNING as some drivers that - * don't handle link state also don't - * set IFF_RUNNING when this routing - * message is generated. - * As such, it is a race ...*/ - len = LINK_UNKNOWN; - break; - } - dhcpcd_handlecarrier(ctx, len, - (unsigned int)ifm->ifm_flags, ifname); + case RTM_IFINFO: + ifm = (struct if_msghdr *)(void *)p; + memset(ifname, 0, sizeof(ifname)); + if (!(if_indextoname(ifm->ifm_index, ifname))) + break; + switch (ifm->ifm_data.ifi_link_state) { + case LINK_STATE_DOWN: + len = LINK_DOWN; + break; + case LINK_STATE_UP: + len = LINK_UP; + break; + default: + /* handle_carrier will re-load + * the interface flags and check for + * IFF_RUNNING as some drivers that + * don't handle link state also don't + * set IFF_RUNNING when this routing + * message is generated. + * As such, it is a race ...*/ + len = LINK_UNKNOWN; + break; + } + dhcpcd_handlecarrier(ctx, len, + (unsigned int)ifm->ifm_flags, ifname); + break; + case RTM_DELETE: + if (~rtm->rtm_addrs & + (RTA_DST | RTA_GATEWAY | RTA_NETMASK)) + break; + cp = (char *)(void *)(rtm + 1); + sa = (struct sockaddr *)(void *)cp; + if (sa->sa_family != AF_INET) break; - case RTM_DELETE: - if (~rtm->rtm_addrs & - (RTA_DST | RTA_GATEWAY | RTA_NETMASK)) - break; - cp = (char *)(void *)(rtm + 1); - sa = (struct sockaddr *)(void *)cp; - if (sa->sa_family != AF_INET) - break; #ifdef INET - get_addrs(rtm->rtm_addrs, cp, rti_info); - memset(&rt, 0, sizeof(rt)); - rt.iface = NULL; - COPYOUT(rt.dest, rti_info[RTAX_DST]); - COPYOUT(rt.net, rti_info[RTAX_NETMASK]); - COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]); - ipv4_routedeleted(ctx, &rt); + get_addrs(rtm->rtm_addrs, cp, rti_info); + memset(&rt, 0, sizeof(rt)); + rt.iface = NULL; + COPYOUT(rt.dest, rti_info[RTAX_DST]); + COPYOUT(rt.net, rti_info[RTAX_NETMASK]); + COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]); + ipv4_routedeleted(ctx, &rt); #endif - break; + break; #ifdef RTM_CHGADDR - case RTM_CHGADDR: /* FALLTHROUGH */ + case RTM_CHGADDR: /* FALLTHROUGH */ #endif - case RTM_DELADDR: /* FALLTHROUGH */ - case RTM_NEWADDR: - ifam = (struct ifa_msghdr *)(void *)p; - if (!if_indextoname(ifam->ifam_index, ifname)) - break; - cp = (char *)(void *)(ifam + 1); - get_addrs(ifam->ifam_addrs, cp, rti_info); - if (rti_info[RTAX_IFA] == NULL) - break; - switch (rti_info[RTAX_IFA]->sa_family) { - case AF_LINK: + case RTM_DELADDR: /* FALLTHROUGH */ + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)(void *)p; + if (!if_indextoname(ifam->ifam_index, ifname)) + break; + cp = (char *)(void *)(ifam + 1); + get_addrs(ifam->ifam_addrs, cp, rti_info); + if (rti_info[RTAX_IFA] == NULL) + break; + switch (rti_info[RTAX_IFA]->sa_family) { + case AF_LINK: #ifdef RTM_CHGADDR - if (rtm->rtm_type != RTM_CHGADDR) - break; + if (rtm->rtm_type != RTM_CHGADDR) + break; #else - if (rtm->rtm_type != RTM_NEWADDR) - break; -#endif - memcpy(&sdl, rti_info[RTAX_IFA], - rti_info[RTAX_IFA]->sa_len); - dhcpcd_handlehwaddr(ctx, ifname, - (const unsigned char*)CLLADDR(&sdl), - sdl.sdl_alen); + if (rtm->rtm_type != RTM_NEWADDR) break; +#endif + memcpy(&sdl, rti_info[RTAX_IFA], + rti_info[RTAX_IFA]->sa_len); + dhcpcd_handlehwaddr(ctx, ifname, + (const unsigned char*)CLLADDR(&sdl), + sdl.sdl_alen); + break; #ifdef INET - case AF_INET: - case 255: /* FIXME: Why 255? */ - COPYOUT(rt.dest, rti_info[RTAX_IFA]); - COPYOUT(rt.net, rti_info[RTAX_NETMASK]); - COPYOUT(rt.gate, rti_info[RTAX_BRD]); - ipv4_handleifa(ctx, rtm->rtm_type, - NULL, ifname, - &rt.dest, &rt.net, &rt.gate); - break; + case AF_INET: + case 255: /* FIXME: Why 255? */ + COPYOUT(rt.dest, rti_info[RTAX_IFA]); + COPYOUT(rt.net, rti_info[RTAX_NETMASK]); + COPYOUT(rt.gate, rti_info[RTAX_BRD]); + ipv4_handleifa(ctx, rtm->rtm_type, + NULL, ifname, + &rt.dest, &rt.net, &rt.gate); + break; #endif #ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6*)(void *) - rti_info[RTAX_IFA]; - memcpy(ia6.s6_addr, - sin6->sin6_addr.s6_addr, - sizeof(ia6.s6_addr)); - if (rtm->rtm_type == RTM_NEWADDR) { - ifa_flags = if_addrflags6( - ifname, - &ia6); - if (ifa_flags == -1) - break; - } else - ifa_flags = 0; - ipv6_handleifa(ctx, rtm->rtm_type, NULL, - ifname, &ia6, ifa_flags); - break; -#endif - } + case AF_INET6: + sin6 = (struct sockaddr_in6*)(void *) + rti_info[RTAX_IFA]; + memcpy(ia6.s6_addr, + sin6->sin6_addr.s6_addr, + sizeof(ia6.s6_addr)); + if (rtm->rtm_type == RTM_NEWADDR) { + ifa_flags = if_addrflags6(ifname, &ia6); + if (ifa_flags == -1) + break; + } else + ifa_flags = 0; + ipv6_handleifa(ctx, rtm->rtm_type, NULL, + ifname, &ia6, ifa_flags); break; +#endif } + break; } } + + return 0; } #ifndef SYS_NMLN /* OSX */ diff --git a/if-linux.c b/if-linux.c index 0a272561..47a19964 100644 --- a/if-linux.c +++ b/if-linux.c @@ -272,15 +272,9 @@ get_netlink(struct dhcpcd_ctx *ctx, int fd, int flags, for (;;) { bytes = recv(fd, NULL, 0, flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC); - if (bytes == -1) { - if (errno == EAGAIN) { - r = 0; - goto eexit; - } - if (errno == EINTR) - continue; + if (bytes == -1 || bytes == 0) goto eexit; - } else if ((size_t)bytes == buflen) { + if ((size_t)bytes == buflen) { /* Support kernels older than 2.6.22 */ if (bytes == 0) bytes = 512; @@ -297,15 +291,8 @@ get_netlink(struct dhcpcd_ctx *ctx, int fd, int flags, } bytes = recvfrom(fd, buf, buflen, flags, (struct sockaddr *)&nladdr, &nladdr_len); - if (bytes == -1) { - if (errno == EAGAIN) { - r = 0; - goto eexit; - } - if (errno == EINTR) - continue; + if (bytes == -1 || bytes == 0) goto eexit; - } /* Check sender */ if (nladdr_len != sizeof(nladdr)) { @@ -752,7 +739,7 @@ if_openrawsocket(struct interface *ifp, int protocol) #endif #ifdef SOCK_CLOEXEC - if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(protocol))) == -1) return -1; #else @@ -766,12 +753,6 @@ if_openrawsocket(struct interface *ifp, int protocol) close(s); return -1; } - if ((flags = fcntl(s, F_GETFL, 0)) == -1 || - fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) - { - close(s); - return -1; - } #endif /* Install the DHCP filter */ memset(&pf, 0, sizeof(pf)); @@ -839,7 +820,7 @@ if_sendrawpacket(const struct interface *ifp, int protocol, ssize_t if_readrawpacket(struct interface *ifp, int protocol, - void *data, size_t len, int *partialcsum) + void *data, size_t len, int *flags) { struct iovec iov = { .iov_base = data, @@ -871,9 +852,9 @@ if_readrawpacket(struct interface *ifp, int protocol, fd = state->raw_fd; bytes = recvmsg(fd, &msg, 0); if (bytes == -1) - return errno == EAGAIN ? 0 : -1; - if (partialcsum != NULL) { - *partialcsum = 0; + return -1; + if (bytes) { + *flags &= ~RAW_PARTIALCSUM; #ifdef PACKET_AUXDATA for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; @@ -882,8 +863,8 @@ if_readrawpacket(struct interface *ifp, int protocol, if (cmsg->cmsg_level == SOL_PACKET && cmsg->cmsg_type == PACKET_AUXDATA) { aux = (void *)CMSG_DATA(cmsg); - *partialcsum = aux->tp_status & - TP_STATUS_CSUMNOTREADY; + if (aux->tp_status & TP_STATUS_CSUMNOTREADY) + *flags |= RAW_PARTIALCSUM; } } #endif diff --git a/if.h b/if.h index 32c05ccd..cf7ea051 100644 --- a/if.h +++ b/if.h @@ -80,6 +80,9 @@ # define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR) #endif +#define RAW_EOF 1 << 0 +#define RAW_PARTIALCSUM 2 << 0 + struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *); struct interface *if_find(struct dhcpcd_ctx *, const char *); void if_free(struct interface *); diff --git a/ipv6nd.c b/ipv6nd.c index 233b3ac4..9db94de0 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -1166,10 +1166,10 @@ ipv6nd_proberouter(void *arg) pi.ipi6_ifindex = rap->iface->index; memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); -#ifdef DEBUG_NS +//#ifdef DEBUG_NS syslog(LOG_INFO, "%s: sending IPv6 NS for %s", rap->iface->name, rap->sfrom); -#endif +//#endif if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { syslog(LOG_ERR, "%s: %s: sendmsg: %m", rap->iface->name, __func__); @@ -1432,8 +1432,11 @@ ipv6nd_handledata(void *arg) ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0); - if (len == -1) { + if (len == -1 || len == 0) { syslog(LOG_ERR, "recvmsg: %m"); + eloop_event_delete(dhcpcd_ctx->eloop, ctx->nd_fd); + close(ctx->nd_fd); + ctx->nd_fd = -1; return; } ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,