summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-08-05 22:17:35 +0200
committerThomas Haller <thaller@redhat.com>2022-08-09 08:02:40 +0200
commit494b3d82c104903167395fa8fe61f7b263f0cc06 (patch)
tree7a8506603d05225343bd45d4eaba309a1cbed01a
parent6e7d8f0335e36c0cccb34d915a67532fd9df92ca (diff)
downloadNetworkManager-494b3d82c104903167395fa8fe61f7b263f0cc06.tar.gz
platform/netlink: add nlmsg_parse_error() helper
-rw-r--r--src/libnm-glib-aux/nm-errno.c1
-rw-r--r--src/libnm-glib-aux/nm-errno.h1
-rw-r--r--src/libnm-platform/nm-netlink.c46
-rw-r--r--src/libnm-platform/nm-netlink.h2
4 files changed, 50 insertions, 0 deletions
diff --git a/src/libnm-glib-aux/nm-errno.c b/src/libnm-glib-aux/nm-errno.c
index 14d93d64c9..b76386a6fe 100644
--- a/src/libnm-glib-aux/nm-errno.c
+++ b/src/libnm-glib-aux/nm-errno.c
@@ -28,6 +28,7 @@ static NM_UTILS_LOOKUP_STR_DEFINE(
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"),
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"),
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"),
+ NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_INVAL, "NME_NL_MSG_INVAL"),
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"),
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"),
NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"),
diff --git a/src/libnm-glib-aux/nm-errno.h b/src/libnm-glib-aux/nm-errno.h
index 62c8379f83..f893a528b2 100644
--- a/src/libnm-glib-aux/nm-errno.h
+++ b/src/libnm-glib-aux/nm-errno.h
@@ -39,6 +39,7 @@ enum _NMErrno {
/* netlink errors. */
NME_NL_SEQ_MISMATCH,
+ NME_NL_MSG_INVAL,
NME_NL_MSG_TRUNC,
NME_NL_MSG_TOOSHORT,
NME_NL_DUMP_INTR,
diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c
index 3d89a4c1d6..36841d5626 100644
--- a/src/libnm-platform/nm-netlink.c
+++ b/src/libnm-platform/nm-netlink.c
@@ -291,6 +291,52 @@ nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad)
/*****************************************************************************/
+int
+nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg)
+{
+ const struct nlmsgerr *e;
+
+ nm_assert(nlh);
+
+ NM_SET_OUT(out_extack_msg, NULL);
+
+ if (nlh->nlmsg_type != NLMSG_ERROR)
+ return -NME_NL_MSG_INVAL;
+
+ if (nlh->nlmsg_len < nlmsg_size(sizeof(struct nlmsgerr))) {
+ /* Truncated error message, the default action
+ * is to stop parsing. The user may overrule
+ * this action by returning NL_SKIP or
+ * NL_PROCEED (dangerous) */
+ return -NME_NL_MSG_TRUNC;
+ }
+
+ e = nlmsg_data(nlh);
+
+ if (!e->error)
+ return 0;
+
+ if (NM_FLAGS_HAS(nlh->nlmsg_flags, NLM_F_ACK_TLVS) && out_extack_msg
+ && nlh->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) {
+ static const struct nla_policy policy[] = {
+ [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING},
+ [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32},
+ };
+ struct nlattr *tb[G_N_ELEMENTS(policy)];
+ struct nlattr *tlvs;
+
+ tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len - NLMSG_HDRLEN);
+ if (nla_parse_arr(tb, tlvs, nlh->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, policy) >= 0) {
+ if (tb[NLMSGERR_ATTR_MSG])
+ *out_extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]);
+ }
+ }
+
+ return -nm_errno_from_native(e->error);
+}
+
+/*****************************************************************************/
+
struct nlattr *
nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
{
diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h
index 1b4267c517..fd1450cc12 100644
--- a/src/libnm-platform/nm-netlink.h
+++ b/src/libnm-platform/nm-netlink.h
@@ -497,6 +497,8 @@ nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
return nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), attrtype);
}
+int nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg);
+
int nlmsg_parse(const struct nlmsghdr *nlh,
int hdrlen,
struct nlattr *tb[],