+/* This is the libnl callback for when an error has happened
+ * kernel side. An error message is sent back to the user.
+ */
+static int yaml_netlink_msg_error(struct sockaddr_nl *who,
+ struct nlmsgerr *errmsg, void *arg)
+{
+ struct nlmsghdr *nlh = (void *)errmsg - NLMSG_HDRLEN;
+ struct yaml_netlink_input *data = arg;
+
+ if ((nlh->nlmsg_type == NLMSG_ERROR ||
+ nlh->nlmsg_flags & NLM_F_ACK_TLVS) && errmsg->error) {
+ /* libyaml stomps on the reader error so we need to
+ * cache the source of the error.
+ */
+ const char *errstr = nl_geterror(nl_syserr2nlerr(errmsg->error));
+
+#ifdef HAVE_USRSPC_NLMSGERR
+ /* Newer kernels support NLM_F_ACK_TLVS in nlmsg_flags
+ * which gives greater detail why we failed.
+ */
+ if ((nlh->nlmsg_flags & NLM_F_ACK_TLVS) &&
+ !(nlh->nlmsg_flags & NLM_F_CAPPED)) {
+ struct nlattr *head = ((void *)&errmsg->msg);
+ struct nlattr *tb[NLMSGERR_ATTR_MAX];
+
+ if (nla_parse(tb, NLMSGERR_ATTR_MAX, head,
+ nlmsg_attrlen(nlh, 0), NULL) == 0) {
+ if (tb[NLMSGERR_ATTR_MSG])
+ errstr = nla_strdup(tb[NLMSGERR_ATTR_MSG]);
+ }
+ }
+#endif /* HAVE_USRSPC_NLMSGERR */
+ data->errmsg = errstr;
+ data->parser->error = YAML_READER_ERROR;
+ data->complete = true;
+ }
+ return NL_STOP;
+}
+