diff options
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-message.c | 36 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-types.c | 14 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/sd-netlink.c | 4 |
3 files changed, 47 insertions, 7 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 295a73fb59..34b66e6fa6 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -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; } diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index a55460f034..26bd0dd620 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -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) }, diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 87350e8591..5b7081089e 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -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 */ |