]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
When receiving multipart messages, receive them again until we get NLMSG_DONE.
authorRoy Marples <roy@marples.name>
Tue, 6 Sep 2016 13:46:12 +0000 (13:46 +0000)
committerRoy Marples <roy@marples.name>
Tue, 6 Sep 2016 13:46:12 +0000 (13:46 +0000)
if-linux.c

index 75b3f434ac47a3a3ad5b939fc78da4d58afff1b3..f46509d46edfbbb93141d6b044c23fcfa5a8bcc0 100644 (file)
@@ -49,6 +49,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <ctype.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -322,9 +323,10 @@ get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov,
 {
        struct msghdr msg;
        struct sockaddr_nl nladdr;
-       ssize_t bytes;
+       ssize_t len;
        struct nlmsghdr *nlm;
        int r;
+       unsigned int again;
 
        memset(&msg, 0, sizeof(msg));
        msg.msg_name = &nladdr;
@@ -332,8 +334,11 @@ get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov,
        memset(&nladdr, 0, sizeof(nladdr));
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;
-       if ((bytes = recvmsg_realloc(fd, &msg, flags)) == -1)
+recv_again:
+       if ((len = recvmsg_realloc(fd, &msg, flags)) == -1)
                return -1;
+       if (len == 0)
+               return 0;
 
        /* Check sender */
        if (msg.msg_namelen != sizeof(nladdr)) {
@@ -345,10 +350,12 @@ get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov,
                return 0;
 
        r = 0;
+       again = 0;      /* Appease static analysis */
        for (nlm = iov->iov_base;
-            nlm && NLMSG_OK(nlm, (size_t)bytes);
-            nlm = NLMSG_NEXT(nlm, bytes))
+            nlm && NLMSG_OK(nlm, (size_t)len);
+            nlm = NLMSG_NEXT(nlm, len))
        {
+               again = (nlm->nlmsg_flags & NLM_F_MULTI);
                if (nlm->nlmsg_type == NLMSG_NOOP)
                        continue;
                if (nlm->nlmsg_type == NLMSG_ERROR) {
@@ -363,13 +370,19 @@ get_netlink(struct dhcpcd_ctx *ctx, struct iovec *iov,
                                errno = -err->error;
                                return -1;
                        }
+                       break;
                }
-               if (nlm->nlmsg_type == NLMSG_DONE)
+               if (nlm->nlmsg_type == NLMSG_DONE) {
+                       again = 0;
                        break;
+               }
                if (callback && (r = callback(ctx, ifp, nlm)) != 0)
                        break;
        }
 
+       if (r == 0 && again)
+               goto recv_again;
+
        return r;
 }
 
@@ -1456,7 +1469,6 @@ if_initrt(struct dhcpcd_ctx *ctx)
        nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        nlm.hdr.nlmsg_type = RTM_GETROUTE;
        nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
-       nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
        nlm.rt.rtm_family = AF_INET;
        nlm.rt.rtm_table = RT_TABLE_MAIN;