]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #12949 from yuwata/sd-netlink-sd-netlink-message-enter-array
authorLennart Poettering <lennart@poettering.net>
Thu, 4 Jul 2019 13:46:02 +0000 (15:46 +0200)
committerGitHub <noreply@github.com>
Thu, 4 Jul 2019 13:46:02 +0000 (15:46 +0200)
sd-netlink: introduce sd_netlink_message_enter_array()

src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/test-netlink.c
src/systemd/sd-netlink.h

index 68b232b7d42242929285ad631bfa8d0aae42fca4..78504063234a631caf91bb26a208d66f0129ce2d 100644 (file)
@@ -802,24 +802,18 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type,
 
 static int netlink_container_parse(sd_netlink_message *m,
                                    struct netlink_container *container,
-                                   int count,
                                    struct rtattr *rta,
                                    unsigned rt_len) {
         _cleanup_free_ struct netlink_attribute *attributes = NULL;
-
-        attributes = new0(struct netlink_attribute, count);
-        if (!attributes)
-                return -ENOMEM;
+        size_t n_allocated = 0;
 
         for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
                 unsigned short type;
 
                 type = RTA_TYPE(rta);
 
-                /* if the kernel is newer than the headers we used
-                   when building, we ignore out-of-range attributes */
-                if (type >= count)
-                        continue;
+                if (!GREEDY_REALLOC0(attributes, n_allocated, type + 1))
+                        return -ENOMEM;
 
                 if (attributes[type].offset != 0)
                         log_debug("rtnl: message parse - overwriting repeated attribute");
@@ -830,7 +824,7 @@ static int netlink_container_parse(sd_netlink_message *m,
         }
 
         container->attributes = TAKE_PTR(attributes);
-        container->n_attributes = count;
+        container->n_attributes = n_allocated;
 
         return 0;
 }
@@ -911,14 +905,13 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
         r = netlink_message_read_internal(m, type_id, &container, NULL);
         if (r < 0)
                 return r;
-        else
-                size = (size_t)r;
+
+        size = (size_t)r;
 
         m->n_containers++;
 
         r = netlink_container_parse(m,
                                     &m->containers[m->n_containers],
-                                    type_system_get_count(type_system),
                                     container,
                                     size);
         if (r < 0) {
@@ -931,6 +924,36 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
         return 0;
 }
 
+int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id) {
+        void *container;
+        size_t size;
+        int r;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+
+        r = netlink_message_read_internal(m, type_id, &container, NULL);
+        if (r < 0)
+                return r;
+
+        size = (size_t) r;
+
+        m->n_containers++;
+
+        r = netlink_container_parse(m,
+                                    &m->containers[m->n_containers],
+                                    container,
+                                    size);
+        if (r < 0) {
+                m->n_containers--;
+                return r;
+        }
+
+        m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
+
+        return 0;
+}
+
 int sd_netlink_message_exit_container(sd_netlink_message *m) {
         assert_return(m, -EINVAL);
         assert_return(m->sealed, -EINVAL);
@@ -1015,7 +1038,6 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
 
                 r = netlink_container_parse(m,
                                             &m->containers[m->n_containers],
-                                            type_system_get_count(type_system),
                                             (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
                                             NLMSG_PAYLOAD(m->hdr, size));
                 if (r < 0)
index d1c95b260f8f91b275b623a93668f65203a28857..98edb7e2bae2be11660a3005c69607c72deb7b87 100644 (file)
@@ -392,7 +392,7 @@ int socket_read_message(sd_netlink *rtnl) {
 
                 /* check that the size matches the message type */
                 if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) {
-                        log_debug("sd-netlink: message larger than expected, dropping");
+                        log_debug("sd-netlink: message is shorter than expected, dropping");
                         continue;
                 }
 
index 0ac3d1664b2ded813aaa758f31e95214d6667b70..68507739776df0a350f4f951912973fd52db4cdf 100644 (file)
@@ -785,9 +785,20 @@ static const NLTypeSystem genl_wireguard_type_system = {
         .types = genl_wireguard_cmds,
 };
 
+static const NLType genl_mcast_group_types[] = {
+        [CTRL_ATTR_MCAST_GRP_NAME]  = { .type = NETLINK_TYPE_STRING },
+        [CTRL_ATTR_MCAST_GRP_ID]    = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem genl_mcast_group_type_system = {
+        .count = ELEMENTSOF(genl_mcast_group_types),
+        .types = genl_mcast_group_types,
+};
+
 static const NLType genl_get_family_types[] = {
-        [CTRL_ATTR_FAMILY_NAME] = { .type = NETLINK_TYPE_STRING },
-        [CTRL_ATTR_FAMILY_ID] = { .type = NETLINK_TYPE_U16 },
+        [CTRL_ATTR_FAMILY_NAME]  = { .type = NETLINK_TYPE_STRING },
+        [CTRL_ATTR_FAMILY_ID]    = { .type = NETLINK_TYPE_U16 },
+        [CTRL_ATTR_MCAST_GROUPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_mcast_group_type_system },
 };
 
 static const NLTypeSystem genl_get_family_type_system = {
index b13fa224cc4c06a94f772d4ea185e35dedcbd942..868fcd01241892a24d6f61357e098544d5a9b10a 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <net/if.h>
 #include <netinet/ether.h>
+#include <linux/genetlink.h>
 
 #include "sd-netlink.h"
 
@@ -11,6 +12,7 @@
 #include "missing.h"
 #include "netlink-util.h"
 #include "socket-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "util.h"
 
@@ -507,6 +509,48 @@ static void test_message(sd_netlink *rtnl) {
         assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT);
 }
 
+static void test_array(void) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+
+        assert_se(sd_genl_socket_open(&genl) >= 0);
+        assert_se(sd_genl_message_new(genl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &m) >= 0);
+
+        assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
+        for (unsigned i = 0; i < 10; i++) {
+                char name[STRLEN("hoge") + DECIMAL_STR_MAX(uint32_t)];
+                uint32_t id = i + 1000;
+
+                xsprintf(name, "hoge%" PRIu32, id);
+                assert_se(sd_netlink_message_open_array(m, i + 1) >= 0);
+                assert_se(sd_netlink_message_append_u32(m, CTRL_ATTR_MCAST_GRP_ID, id) >= 0);
+                assert_se(sd_netlink_message_append_string(m, CTRL_ATTR_MCAST_GRP_NAME, name) >= 0);
+                assert_se(sd_netlink_message_close_container(m) >= 0);
+        }
+        assert_se(sd_netlink_message_close_container(m) >= 0);
+
+        rtnl_message_seal(m);
+        assert_se(sd_netlink_message_rewind(m) >= 0);
+
+        assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
+        for (unsigned i = 0; i < 10; i++) {
+                char expected[STRLEN("hoge") + DECIMAL_STR_MAX(uint32_t)];
+                const char *name;
+                uint32_t id;
+
+                assert_se(sd_netlink_message_enter_array(m, i + 1) >= 0);
+                assert_se(sd_netlink_message_read_u32(m, CTRL_ATTR_MCAST_GRP_ID, &id) >= 0);
+                assert_se(sd_netlink_message_read_string(m, CTRL_ATTR_MCAST_GRP_NAME, &name) >= 0);
+                assert_se(sd_netlink_message_exit_container(m) >= 0);
+
+                assert_se(id == i + 1000);
+                xsprintf(expected, "hoge%" PRIu32, id);
+                assert_se(streq(name, expected));
+        }
+        assert_se(sd_netlink_message_exit_container(m) >= 0);
+
+}
+
 int main(void) {
         sd_netlink *rtnl;
         sd_netlink_message *m;
@@ -524,6 +568,7 @@ int main(void) {
         test_route(rtnl);
         test_message(rtnl);
         test_container(rtnl);
+        test_array();
 
         if_loopback = (int) if_nametoindex("lo");
         assert_se(if_loopback > 0);
index d27e0ad2019cb9b5016404ab1e24d3c360777e3b..b0a51185e9c19fc8dfe9f8a7119fc2044e96b40f 100644 (file)
@@ -105,6 +105,7 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ
 int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data);
 int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data);
 int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type);
+int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type);
 int sd_netlink_message_exit_container(sd_netlink_message *m);
 
 int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);