sd-netlink: support NLMSGERR_ATTR_MSG
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.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) },
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user