return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
 }
 
+/* this can be increased when necessary - don't expose to userland */
+#define NETLINK_MAX_COOKIE_LEN 20
+
 /**
  * struct netlink_ext_ack - netlink extended ACK report struct
  * @_msg: message string to report - don't access directly, use
  *     %NL_SET_ERR_MSG
  * @bad_attr: attribute with error
+ * @cookie: cookie data to return to userspace (for success)
+ * @cookie_len: actual cookie data length
  */
 struct netlink_ext_ack {
        const char *_msg;
        const struct nlattr *bad_attr;
+       u8 cookie[NETLINK_MAX_COOKIE_LEN];
+       u8 cookie_len;
 };
 
 /* Always use this macro, this allows later putting the
 
  * @NLMSGERR_ATTR_MSG: error message string (string)
  * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
  *      message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ *     be used - in the success case - to identify a created
+ *     object or operation or similar (binary)
  * @__NLMSGERR_ATTR_MAX: number of attributes
  * @NLMSGERR_ATTR_MAX: highest attribute number
  */
        NLMSGERR_ATTR_UNUSED,
        NLMSGERR_ATTR_MSG,
        NLMSGERR_ATTR_OFFS,
+       NLMSGERR_ATTR_COOKIE,
 
        __NLMSGERR_ATTR_MAX,
        NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
 
                }
        } else {
                flags |= NLM_F_CAPPED;
+
+               if (nlk->flags & NETLINK_F_EXT_ACK &&
+                   extack && extack->cookie_len)
+                       tlvlen += nla_total_size(extack->cookie_len);
        }
 
        if (tlvlen)
        errmsg->error = err;
        memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
 
-       if (err && nlk->flags & NETLINK_F_EXT_ACK && extack) {
-               if (extack->_msg)
-                       WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
-                                              extack->_msg));
-               if (extack->bad_attr &&
-                   !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
-                            (u8 *)extack->bad_attr >= in_skb->data +
-                                                      in_skb->len))
-                       WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
-                                           (u8 *)extack->bad_attr -
-                                           in_skb->data));
+       if (nlk->flags & NETLINK_F_EXT_ACK && extack) {
+               if (err) {
+                       if (extack->_msg)
+                               WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
+                                                      extack->_msg));
+                       if (extack->bad_attr &&
+                           !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
+                                    (u8 *)extack->bad_attr >= in_skb->data +
+                                                              in_skb->len))
+                               WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
+                                                   (u8 *)extack->bad_attr -
+                                                   in_skb->data));
+               } else {
+                       if (extack->cookie_len)
+                               WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
+                                               extack->cookie_len,
+                                               extack->cookie));
+               }
        }
 
        nlmsg_end(skb, rep);