@@ -67,6 +67,8 @@ struct netlink_ext_err {
u32 ext_code;
u32 msg_offset;
u16 attr;
+ const u8 *cookie;
+ u8 cookie_len;
};
extern void netlink_kernel_release(struct sock *sk);
@@ -119,6 +119,9 @@ struct nlmsgerr {
* @NLMSGERR_ATTR_CODE: extended per-subsystem error code (u32)
* @NLMSGERR_ATTR_ATTR: top-level attribute that caused the error
* (or is missing, u16)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
*/
enum nlmsgerr_attrs {
NLMSGERR_ATTR_UNUSED,
@@ -126,6 +129,7 @@ enum nlmsgerr_attrs {
NLMSGERR_ATTR_OFFS,
NLMSGERR_ATTR_CODE,
NLMSGERR_ATTR_ATTR,
+ NLMSGERR_ATTR_COOKIE,
};
#define NETLINK_ADD_MEMBERSHIP 1
@@ -2277,6 +2277,9 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
if (exterr && exterr->attr)
payload += nla_total_size(sizeof(u16));
}
+ } else if (nlk->flags & NETLINK_F_EXT_ACK) {
+ if (exterr && exterr->cookie_len)
+ payload += nla_total_size(exterr->cookie_len);
}
skb = nlmsg_new(payload, GFP_KERNEL);
@@ -2301,15 +2304,22 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
if (nlk->flags & NETLINK_F_EXT_ACK) {
- if (exterr && exterr->msg)
- WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
- exterr->msg));
- if (exterr && exterr->msg_offset)
- WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
- exterr->msg_offset));
- if (exterr && exterr->attr)
- WARN_ON(nla_put_u16(skb, NLMSGERR_ATTR_ATTR,
- exterr->attr));
+ if (err) {
+ if (exterr && exterr->msg)
+ WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
+ exterr->msg));
+ if (exterr && exterr->msg_offset)
+ WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
+ exterr->msg_offset));
+ if (exterr && exterr->attr)
+ WARN_ON(nla_put_u16(skb, NLMSGERR_ATTR_ATTR,
+ exterr->attr));
+ } else {
+ if (exterr && exterr->attr)
+ WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
+ exterr->cookie_len,
+ exterr->cookie));
+ }
}
netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);