@@ -62,6 +62,9 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
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 32
+
/**
* struct netlink_ext_ack - netlink extended ACK report struct
* @_msg: message string to report - don't access directly, use
@@ -118,12 +118,16 @@ struct nlmsgerr {
* @NLMSGERR_ATTR_OFFS: error offset in the original message (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,
NLMSGERR_ATTR_MSG,
NLMSGERR_ATTR_OFFS,
NLMSGERR_ATTR_ATTR,
+ NLMSGERR_ATTR_COOKIE,
};
#define NETLINK_ADD_MEMBERSHIP 1
@@ -2312,6 +2312,9 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
(extack->missing_attr || extack->bad_attr))
acksize += nla_total_size(sizeof(u16));
}
+ } else if (nlk->flags & NETLINK_F_EXT_ACK) {
+ if (extack && extack->cookie_len)
+ acksize += nla_total_size(extack->cookie_len);
}
skb = nlmsg_new(acksize, GFP_KERNEL);
@@ -2337,20 +2340,27 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
!(nlk->flags & NETLINK_F_CAP_ACK) ? nlh->nlmsg_len
: sizeof(*nlh));
- if (err && nlk->flags & NETLINK_F_EXT_ACK) {
- if (extack && extack->_msg)
- WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
- extack->_msg));
- if (extack && 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 (extack && extack->missing_attr)
- WARN_ON(nla_put_u16(skb, NLMSGERR_ATTR_ATTR,
- extack->missing_attr));
+ if (nlk->flags & NETLINK_F_EXT_ACK) {
+ if (err) {
+ if (extack && extack->_msg)
+ WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
+ extack->_msg));
+ if (extack && 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 (extack && extack->missing_attr)
+ WARN_ON(nla_put_u16(skb, NLMSGERR_ATTR_ATTR,
+ extack->missing_attr));
+ } else {
+ if (extack && extack->cookie_len)
+ WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
+ extack->cookie_len,
+ extack->cookie));
+ }
}
netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);