]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Change the readrawsocket API a little so that we know when EOF is reached.
authorRoy Marples <roy@marples.name>
Fri, 2 May 2014 23:54:29 +0000 (23:54 +0000)
committerRoy Marples <roy@marples.name>
Fri, 2 May 2014 23:54:29 +0000 (23:54 +0000)
This allows us to remove the non blocking option from our sockets due to the way BPF works.

arp.c
dhcp.c
dhcp6.c
dhcpcd.c
eloop.c
if-bsd.c
if-linux.c
if.h
ipv6nd.c

diff --git a/arp.c b/arp.c
index 22ff194fc4771c9921fe918e0290651440994285..93e2bd9c710651c975a808a8e3044e00e5252878 100644 (file)
--- 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 636acc5ae7520add3247a9fad318ed3a5895e083..0ddc7b649037835b7d0f6c380212653db8f84a1d 100644 (file)
--- 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 b9970e7bf245a11af9b478163261aa216b710abf..8a25dd93d1ce8acde6c9849270149878deddb049 100644 (file)
--- 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;
index f9cb85dae99204645671d98dda88ed5a99701ef0..b318cc3666aa07ccba9c61d67fdab9ca4a6d5119 100644 (file)
--- 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 ce632d7ad655d520fb438ed3431cdfe07205d9ee..141eb29c57a22e69bccaab289b3da48704e30613 100644 (file)
--- 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
index b36ccfd94f06228b734a3fed051045e539fa239b..474ec038babd1227239a2b57e23f0e0e8b59392b 100644 (file)
--- 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 */
index 0a27256197d7a8d2d2a976c74924d84565cc1776..47a19964663dfc309df4631945368fb11ce5c06d 100644 (file)
@@ -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 32c05ccda11224414afba61c7450f0a930c3a7be..cf7ea051061fbc3afc6863bd3e333157fab202d9 100644 (file)
--- 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 *);
index 233b3ac491701f4a2e821002b29988c08abbf524..9db94de0b686c40c9b5c4b86775847697cd7a98e 100644 (file)
--- 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,