]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: support NLMSGERR_ATTR_MSG
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 30 Nov 2019 06:01:06 +0000 (15:01 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 30 Nov 2019 07:13:51 +0000 (16:13 +0900)
From v4.12 the kernel appends some attributes to netlink acks
containing a textual description of the error and other fields.
This makes sd-netlink parse the attributes.

src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/sd-netlink.c

index 295a73fb59aa644293cdfc3cb016beb69b3e0c0d..34b66e6fa605defff13d192ca5ad7e43fe26a523 100644 (file)
@@ -575,7 +575,9 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
         assert_return(data, -EINVAL);
 
         assert(m->n_containers < RTNL_CONTAINER_DEPTH);
-        assert(m->containers[m->n_containers].attributes);
+
+        if (!m->containers[m->n_containers].attributes)
+                return -ENODATA;
 
         if (type >= m->containers[m->n_containers].n_attributes)
                 return -ENODATA;
@@ -1021,6 +1023,27 @@ int sd_netlink_message_get_errno(const sd_netlink_message *m) {
         return err->error;
 }
 
+static int netlink_message_parse_error(sd_netlink_message *m) {
+        struct nlmsgerr *err = NLMSG_DATA(m->hdr);
+        size_t hlen = sizeof(struct nlmsgerr);
+
+        /* no TLVs, nothing to do here */
+        if (!(m->hdr->nlmsg_flags & NLM_F_ACK_TLVS))
+                return 0;
+
+        /* if NLM_F_CAPPED is set then the inner err msg was capped */
+        if (!(m->hdr->nlmsg_flags & NLM_F_CAPPED))
+                hlen += err->msg.nlmsg_len - sizeof(struct nlmsghdr);
+
+        if (m->hdr->nlmsg_len <= NLMSG_SPACE(hlen))
+                return 0;
+
+        return netlink_container_parse(m,
+                                       &m->containers[m->n_containers],
+                                       (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + hlen),
+                                       NLMSG_PAYLOAD(m->hdr, hlen));
+}
+
 int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
         const NLType *nl_type;
         uint16_t type;
@@ -1060,10 +1083,13 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
 
                 m->containers[0].type_system = type_system;
 
-                r = netlink_container_parse(m,
-                                            &m->containers[m->n_containers],
-                                            (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
-                                            NLMSG_PAYLOAD(m->hdr, size));
+                if (sd_netlink_message_is_error(m))
+                        r = netlink_message_parse_error(m);
+                else
+                        r = netlink_container_parse(m,
+                                                    &m->containers[m->n_containers],
+                                                    (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
+                                                    NLMSG_PAYLOAD(m->hdr, size));
                 if (r < 0)
                         return r;
         }
index a55460f03407b3f3600422463ff3d371e2bf42b6..26bd0dd620d66f7e29e834655dcf734563612fa8 100644 (file)
@@ -745,9 +745,19 @@ static const NLTypeSystem rtnl_qdisc_type_system = {
         .types = rtnl_qdisc_types,
 };
 
+static const NLType error_types[] = {
+        [NLMSGERR_ATTR_MSG]  = { .type = NETLINK_TYPE_STRING },
+        [NLMSGERR_ATTR_OFFS] = { .type = NETLINK_TYPE_U32 },
+};
+
+static const NLTypeSystem error_type_system = {
+        .count = ELEMENTSOF(error_types),
+        .types = error_types,
+};
+
 static const NLType rtnl_types[] = {
         [NLMSG_DONE]       = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
-        [NLMSG_ERROR]      = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
+        [NLMSG_ERROR]      = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
         [RTM_NEWLINK]      = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
         [RTM_DELLINK]      = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
         [RTM_GETLINK]      = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
@@ -1052,7 +1062,7 @@ const NLTypeSystem genl_family_type_system_root = {
 };
 
 static const NLType genl_types[] = {
-        [SD_GENL_ERROR]   = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
+        [SD_GENL_ERROR]   = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
         [SD_GENL_DONE]    = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system },
         [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
         [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) },
index 87350e8591dc7ecca902615673328aa396b6881a..5b7081089e4a92dbb6c753bdf55cfdea30899402 100644 (file)
@@ -107,6 +107,10 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
         rtnl->fd = fd;
         rtnl->protocol = protocol;
 
+        r = setsockopt_int(fd, SOL_NETLINK, NETLINK_EXT_ACK, 1);
+        if (r < 0)
+                log_debug_errno(r, "sd-netlink: Failed to enable NETLINK_EXT_ACK option, ignoring: %m");
+
         r = socket_bind(rtnl);
         if (r < 0) {
                 rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */