aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/crypto_user.c3
-rw-r--r--drivers/infiniband/core/netlink.c5
-rw-r--r--drivers/scsi/scsi_netlink.c2
-rw-r--r--include/linux/netlink.h26
-rw-r--r--include/net/netlink.h3
-rw-r--r--include/uapi/linux/netlink.h32
-rw-r--r--kernel/audit.c2
-rw-r--r--net/core/rtnetlink.c3
-rw-r--r--net/core/sock_diag.c3
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c2
-rw-r--r--net/hsr/hsr_netlink.c4
-rw-r--r--net/netfilter/ipset/ip_set_core.c2
-rw-r--r--net/netfilter/nfnetlink.c22
-rw-r--r--net/netlink/af_netlink.c71
-rw-r--r--net/netlink/af_netlink.h1
-rw-r--r--net/netlink/genetlink.c3
-rw-r--r--net/xfrm/xfrm_user.c3
17 files changed, 153 insertions, 34 deletions
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index a90404a0c5ff..4a44830741c1 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -483,7 +483,8 @@ static const struct crypto_link {
483 [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng }, 483 [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
484}; 484};
485 485
486static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 486static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
487 struct netlink_ext_ack *extack)
487{ 488{
488 struct nlattr *attrs[CRYPTOCFGA_MAX+1]; 489 struct nlattr *attrs[CRYPTOCFGA_MAX+1];
489 const struct crypto_link *link; 490 const struct crypto_link *link;
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index 10469b0088b5..b784055423c8 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -146,7 +146,8 @@ nla_put_failure:
146} 146}
147EXPORT_SYMBOL(ibnl_put_attr); 147EXPORT_SYMBOL(ibnl_put_attr);
148 148
149static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 149static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
150 struct netlink_ext_ack *extack)
150{ 151{
151 struct ibnl_client *client; 152 struct ibnl_client *client;
152 int type = nlh->nlmsg_type; 153 int type = nlh->nlmsg_type;
@@ -209,7 +210,7 @@ static void ibnl_rcv_reply_skb(struct sk_buff *skb)
209 if (nlh->nlmsg_flags & NLM_F_REQUEST) 210 if (nlh->nlmsg_flags & NLM_F_REQUEST)
210 return; 211 return;
211 212
212 ibnl_rcv_msg(skb, nlh); 213 ibnl_rcv_msg(skb, nlh, NULL);
213 214
214 msglen = NLMSG_ALIGN(nlh->nlmsg_len); 215 msglen = NLMSG_ALIGN(nlh->nlmsg_len);
215 if (msglen > skb->len) 216 if (msglen > skb->len)
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 109802f776ed..50e624fb8307 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -111,7 +111,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
111 111
112next_msg: 112next_msg:
113 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 113 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
114 netlink_ack(skb, nlh, err); 114 netlink_ack(skb, nlh, err, NULL);
115 115
116 skb_pull(skb, rlen); 116 skb_pull(skb, rlen);
117 } 117 }
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index da14ab61f363..60e7137f840d 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -62,11 +62,35 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
62 return __netlink_kernel_create(net, unit, THIS_MODULE, cfg); 62 return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
63} 63}
64 64
65/**
66 * struct netlink_ext_ack - netlink extended ACK report struct
67 * @_msg: message string to report - don't access directly, use
68 * %NL_SET_ERR_MSG
69 * @bad_attr: attribute with error
70 */
71struct netlink_ext_ack {
72 const char *_msg;
73 const struct nlattr *bad_attr;
74};
75
76/* Always use this macro, this allows later putting the
77 * message into a separate section or such for things
78 * like translation or listing all possible messages.
79 * Currently string formatting is not supported (due
80 * to the lack of an output buffer.)
81 */
82#define NL_SET_ERR_MSG(extack, msg) do { \
83 static const char _msg[] = (msg); \
84 \
85 (extack)->_msg = _msg; \
86} while (0)
87
65extern void netlink_kernel_release(struct sock *sk); 88extern void netlink_kernel_release(struct sock *sk);
66extern int __netlink_change_ngroups(struct sock *sk, unsigned int groups); 89extern int __netlink_change_ngroups(struct sock *sk, unsigned int groups);
67extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); 90extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
68extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group); 91extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group);
69extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); 92extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
93 const struct netlink_ext_ack *extack);
70extern int netlink_has_listeners(struct sock *sk, unsigned int group); 94extern int netlink_has_listeners(struct sock *sk, unsigned int group);
71 95
72extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock); 96extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
diff --git a/include/net/netlink.h b/include/net/netlink.h
index b239fcd33d80..a064ec3e2ee1 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -233,7 +233,8 @@ struct nl_info {
233}; 233};
234 234
235int netlink_rcv_skb(struct sk_buff *skb, 235int netlink_rcv_skb(struct sk_buff *skb,
236 int (*cb)(struct sk_buff *, struct nlmsghdr *)); 236 int (*cb)(struct sk_buff *, struct nlmsghdr *,
237 struct netlink_ext_ack *));
237int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid, 238int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
238 unsigned int group, int report, gfp_t flags); 239 unsigned int group, int report, gfp_t flags);
239 240
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index b2c9c26ea30f..7df88770e029 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -69,6 +69,10 @@ struct nlmsghdr {
69#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ 69#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
70#define NLM_F_APPEND 0x800 /* Add to end of list */ 70#define NLM_F_APPEND 0x800 /* Add to end of list */
71 71
72/* Flags for ACK message */
73#define NLM_F_CAPPED 0x100 /* request was capped */
74#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
75
72/* 76/*
73 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL 77 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
74 4.4BSD CHANGE NLM_F_REPLACE 78 4.4BSD CHANGE NLM_F_REPLACE
@@ -101,6 +105,33 @@ struct nlmsghdr {
101struct nlmsgerr { 105struct nlmsgerr {
102 int error; 106 int error;
103 struct nlmsghdr msg; 107 struct nlmsghdr msg;
108 /*
109 * followed by the message contents unless NETLINK_CAP_ACK was set
110 * or the ACK indicates success (error == 0)
111 * message length is aligned with NLMSG_ALIGN()
112 */
113 /*
114 * followed by TLVs defined in enum nlmsgerr_attrs
115 * if NETLINK_EXT_ACK was set
116 */
117};
118
119/**
120 * enum nlmsgerr_attrs - nlmsgerr attributes
121 * @NLMSGERR_ATTR_UNUSED: unused
122 * @NLMSGERR_ATTR_MSG: error message string (string)
123 * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
124 * message, counting from the beginning of the header (u32)
125 * @__NLMSGERR_ATTR_MAX: number of attributes
126 * @NLMSGERR_ATTR_MAX: highest attribute number
127 */
128enum nlmsgerr_attrs {
129 NLMSGERR_ATTR_UNUSED,
130 NLMSGERR_ATTR_MSG,
131 NLMSGERR_ATTR_OFFS,
132
133 __NLMSGERR_ATTR_MAX,
134 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
104}; 135};
105 136
106#define NETLINK_ADD_MEMBERSHIP 1 137#define NETLINK_ADD_MEMBERSHIP 1
@@ -115,6 +146,7 @@ struct nlmsgerr {
115#define NETLINK_LISTEN_ALL_NSID 8 146#define NETLINK_LISTEN_ALL_NSID 8
116#define NETLINK_LIST_MEMBERSHIPS 9 147#define NETLINK_LIST_MEMBERSHIPS 9
117#define NETLINK_CAP_ACK 10 148#define NETLINK_CAP_ACK 10
149#define NETLINK_EXT_ACK 11
118 150
119struct nl_pktinfo { 151struct nl_pktinfo {
120 __u32 group; 152 __u32 group;
diff --git a/kernel/audit.c b/kernel/audit.c
index 2f4964cfde0b..d54bf5932374 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1402,7 +1402,7 @@ static void audit_receive_skb(struct sk_buff *skb)
1402 err = audit_receive_msg(skb, nlh); 1402 err = audit_receive_msg(skb, nlh);
1403 /* if err or if this message says it wants a response */ 1403 /* if err or if this message says it wants a response */
1404 if (err || (nlh->nlmsg_flags & NLM_F_ACK)) 1404 if (err || (nlh->nlmsg_flags & NLM_F_ACK))
1405 netlink_ack(skb, nlh, err); 1405 netlink_ack(skb, nlh, err, NULL);
1406 1406
1407 nlh = nlmsg_next(nlh, &len); 1407 nlh = nlmsg_next(nlh, &len);
1408 } 1408 }
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index c138b6b75e59..3cc4a627a537 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -4046,7 +4046,8 @@ out:
4046 4046
4047/* Process one rtnetlink message. */ 4047/* Process one rtnetlink message. */
4048 4048
4049static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 4049static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4050 struct netlink_ext_ack *extack)
4050{ 4051{
4051 struct net *net = sock_net(skb->sk); 4052 struct net *net = sock_net(skb->sk);
4052 rtnl_doit_func doit; 4053 rtnl_doit_func doit;
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index fb9d0e2fd148..217f4e3b82f6 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -238,7 +238,8 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
238 return err; 238 return err;
239} 239}
240 240
241static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 241static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
242 struct netlink_ext_ack *extack)
242{ 243{
243 int ret; 244 int ret;
244 245
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 85f2fdc360c2..c8bf5136a72b 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -96,7 +96,7 @@ static unsigned int dnrmg_hook(void *priv,
96} 96}
97 97
98 98
99#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) 99#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err), NULL); return; } while (0)
100 100
101static inline void dnrmg_receive_user_skb(struct sk_buff *skb) 101static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
102{ 102{
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 1ab30e7d3f99..81dac16933fc 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -350,7 +350,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
350 return 0; 350 return 0;
351 351
352invalid: 352invalid:
353 netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL); 353 netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
354 return 0; 354 return 0;
355 355
356nla_put_failure: 356nla_put_failure:
@@ -432,7 +432,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
432 return 0; 432 return 0;
433 433
434invalid: 434invalid:
435 netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL); 435 netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
436 return 0; 436 return 0;
437 437
438nla_put_failure: 438nla_put_failure:
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index c296f9b606d4..26356bf8cebf 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1305,7 +1305,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
1305 * manually :-( 1305 * manually :-(
1306 */ 1306 */
1307 if (nlh->nlmsg_flags & NLM_F_ACK) 1307 if (nlh->nlmsg_flags & NLM_F_ACK)
1308 netlink_ack(cb->skb, nlh, ret); 1308 netlink_ack(cb->skb, nlh, ret, NULL);
1309 return ret; 1309 return ret;
1310 } 1310 }
1311 } 1311 }
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 68eda920160e..181d3bb800e6 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -148,7 +148,8 @@ int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
148EXPORT_SYMBOL_GPL(nfnetlink_unicast); 148EXPORT_SYMBOL_GPL(nfnetlink_unicast);
149 149
150/* Process one complete nfnetlink message. */ 150/* Process one complete nfnetlink message. */
151static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 151static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
152 struct netlink_ext_ack *extack)
152{ 153{
153 struct net *net = sock_net(skb->sk); 154 struct net *net = sock_net(skb->sk);
154 const struct nfnl_callback *nc; 155 const struct nfnl_callback *nc;
@@ -261,7 +262,7 @@ static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
261 struct nfnl_err *nfnl_err, *next; 262 struct nfnl_err *nfnl_err, *next;
262 263
263 list_for_each_entry_safe(nfnl_err, next, err_list, head) { 264 list_for_each_entry_safe(nfnl_err, next, err_list, head) {
264 netlink_ack(skb, nfnl_err->nlh, nfnl_err->err); 265 netlink_ack(skb, nfnl_err->nlh, nfnl_err->err, NULL);
265 nfnl_err_del(nfnl_err); 266 nfnl_err_del(nfnl_err);
266 } 267 }
267} 268}
@@ -284,13 +285,13 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
284 int err; 285 int err;
285 286
286 if (subsys_id >= NFNL_SUBSYS_COUNT) 287 if (subsys_id >= NFNL_SUBSYS_COUNT)
287 return netlink_ack(skb, nlh, -EINVAL); 288 return netlink_ack(skb, nlh, -EINVAL, NULL);
288replay: 289replay:
289 status = 0; 290 status = 0;
290 291
291 skb = netlink_skb_clone(oskb, GFP_KERNEL); 292 skb = netlink_skb_clone(oskb, GFP_KERNEL);
292 if (!skb) 293 if (!skb)
293 return netlink_ack(oskb, nlh, -ENOMEM); 294 return netlink_ack(oskb, nlh, -ENOMEM, NULL);
294 295
295 nfnl_lock(subsys_id); 296 nfnl_lock(subsys_id);
296 ss = nfnl_dereference_protected(subsys_id); 297 ss = nfnl_dereference_protected(subsys_id);
@@ -304,20 +305,20 @@ replay:
304#endif 305#endif
305 { 306 {
306 nfnl_unlock(subsys_id); 307 nfnl_unlock(subsys_id);
307 netlink_ack(oskb, nlh, -EOPNOTSUPP); 308 netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
308 return kfree_skb(skb); 309 return kfree_skb(skb);
309 } 310 }
310 } 311 }
311 312
312 if (!ss->commit || !ss->abort) { 313 if (!ss->commit || !ss->abort) {
313 nfnl_unlock(subsys_id); 314 nfnl_unlock(subsys_id);
314 netlink_ack(oskb, nlh, -EOPNOTSUPP); 315 netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
315 return kfree_skb(skb); 316 return kfree_skb(skb);
316 } 317 }
317 318
318 if (genid && ss->valid_genid && !ss->valid_genid(net, genid)) { 319 if (genid && ss->valid_genid && !ss->valid_genid(net, genid)) {
319 nfnl_unlock(subsys_id); 320 nfnl_unlock(subsys_id);
320 netlink_ack(oskb, nlh, -ERESTART); 321 netlink_ack(oskb, nlh, -ERESTART, NULL);
321 return kfree_skb(skb); 322 return kfree_skb(skb);
322 } 323 }
323 324
@@ -407,7 +408,8 @@ ack:
407 * pointing to the batch header. 408 * pointing to the batch header.
408 */ 409 */
409 nfnl_err_reset(&err_list); 410 nfnl_err_reset(&err_list);
410 netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM); 411 netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM,
412 NULL);
411 status |= NFNL_BATCH_FAILURE; 413 status |= NFNL_BATCH_FAILURE;
412 goto done; 414 goto done;
413 } 415 }
@@ -467,7 +469,7 @@ static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
467 469
468 err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy); 470 err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy);
469 if (err < 0) { 471 if (err < 0) {
470 netlink_ack(skb, nlh, err); 472 netlink_ack(skb, nlh, err, NULL);
471 return; 473 return;
472 } 474 }
473 if (cda[NFNL_BATCH_GENID]) 475 if (cda[NFNL_BATCH_GENID])
@@ -493,7 +495,7 @@ static void nfnetlink_rcv(struct sk_buff *skb)
493 return; 495 return;
494 496
495 if (!netlink_net_capable(skb, CAP_NET_ADMIN)) { 497 if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
496 netlink_ack(skb, nlh, -EPERM); 498 netlink_ack(skb, nlh, -EPERM, NULL);
497 return; 499 return;
498 } 500 }
499 501
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index fc232441cf23..c1564768000e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1652,6 +1652,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1652 nlk->flags &= ~NETLINK_F_CAP_ACK; 1652 nlk->flags &= ~NETLINK_F_CAP_ACK;
1653 err = 0; 1653 err = 0;
1654 break; 1654 break;
1655 case NETLINK_EXT_ACK:
1656 if (val)
1657 nlk->flags |= NETLINK_F_EXT_ACK;
1658 else
1659 nlk->flags &= ~NETLINK_F_EXT_ACK;
1660 err = 0;
1661 break;
1655 default: 1662 default:
1656 err = -ENOPROTOOPT; 1663 err = -ENOPROTOOPT;
1657 } 1664 }
@@ -1736,6 +1743,15 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
1736 return -EFAULT; 1743 return -EFAULT;
1737 err = 0; 1744 err = 0;
1738 break; 1745 break;
1746 case NETLINK_EXT_ACK:
1747 if (len < sizeof(int))
1748 return -EINVAL;
1749 len = sizeof(int);
1750 val = nlk->flags & NETLINK_F_EXT_ACK ? 1 : 0;
1751 if (put_user(len, optlen) || put_user(val, optval))
1752 return -EFAULT;
1753 err = 0;
1754 break;
1739 default: 1755 default:
1740 err = -ENOPROTOOPT; 1756 err = -ENOPROTOOPT;
1741 } 1757 }
@@ -2267,21 +2283,40 @@ error_free:
2267} 2283}
2268EXPORT_SYMBOL(__netlink_dump_start); 2284EXPORT_SYMBOL(__netlink_dump_start);
2269 2285
2270void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) 2286void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
2287 const struct netlink_ext_ack *extack)
2271{ 2288{
2272 struct sk_buff *skb; 2289 struct sk_buff *skb;
2273 struct nlmsghdr *rep; 2290 struct nlmsghdr *rep;
2274 struct nlmsgerr *errmsg; 2291 struct nlmsgerr *errmsg;
2275 size_t payload = sizeof(*errmsg); 2292 size_t payload = sizeof(*errmsg);
2293 size_t tlvlen = 0;
2276 struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk); 2294 struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
2295 unsigned int flags = 0;
2277 2296
2278 /* Error messages get the original request appened, unless the user 2297 /* Error messages get the original request appened, unless the user
2279 * requests to cap the error message. 2298 * requests to cap the error message, and get extra error data if
2299 * requested.
2280 */ 2300 */
2281 if (!(nlk->flags & NETLINK_F_CAP_ACK) && err) 2301 if (err) {
2282 payload += nlmsg_len(nlh); 2302 if (!(nlk->flags & NETLINK_F_CAP_ACK))
2303 payload += nlmsg_len(nlh);
2304 else
2305 flags |= NLM_F_CAPPED;
2306 if (nlk->flags & NETLINK_F_EXT_ACK && extack) {
2307 if (extack->_msg)
2308 tlvlen += nla_total_size(strlen(extack->_msg) + 1);
2309 if (extack->bad_attr)
2310 tlvlen += nla_total_size(sizeof(u32));
2311 }
2312 } else {
2313 flags |= NLM_F_CAPPED;
2314 }
2283 2315
2284 skb = nlmsg_new(payload, GFP_KERNEL); 2316 if (tlvlen)
2317 flags |= NLM_F_ACK_TLVS;
2318
2319 skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
2285 if (!skb) { 2320 if (!skb) {
2286 struct sock *sk; 2321 struct sock *sk;
2287 2322
@@ -2297,17 +2332,35 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
2297 } 2332 }
2298 2333
2299 rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 2334 rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
2300 NLMSG_ERROR, payload, 0); 2335 NLMSG_ERROR, payload, flags);
2301 errmsg = nlmsg_data(rep); 2336 errmsg = nlmsg_data(rep);
2302 errmsg->error = err; 2337 errmsg->error = err;
2303 memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh)); 2338 memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
2339
2340 if (err && nlk->flags & NETLINK_F_EXT_ACK && extack) {
2341 if (extack->_msg)
2342 WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
2343 extack->_msg));
2344 if (extack->bad_attr &&
2345 !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
2346 (u8 *)extack->bad_attr >= in_skb->data +
2347 in_skb->len))
2348 WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
2349 (u8 *)extack->bad_attr -
2350 in_skb->data));
2351 }
2352
2353 nlmsg_end(skb, rep);
2354
2304 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); 2355 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);
2305} 2356}
2306EXPORT_SYMBOL(netlink_ack); 2357EXPORT_SYMBOL(netlink_ack);
2307 2358
2308int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, 2359int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
2309 struct nlmsghdr *)) 2360 struct nlmsghdr *,
2361 struct netlink_ext_ack *))
2310{ 2362{
2363 struct netlink_ext_ack extack = {};
2311 struct nlmsghdr *nlh; 2364 struct nlmsghdr *nlh;
2312 int err; 2365 int err;
2313 2366
@@ -2328,13 +2381,13 @@ int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
2328 if (nlh->nlmsg_type < NLMSG_MIN_TYPE) 2381 if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
2329 goto ack; 2382 goto ack;
2330 2383
2331 err = cb(skb, nlh); 2384 err = cb(skb, nlh, &extack);
2332 if (err == -EINTR) 2385 if (err == -EINTR)
2333 goto skip; 2386 goto skip;
2334 2387
2335ack: 2388ack:
2336 if (nlh->nlmsg_flags & NLM_F_ACK || err) 2389 if (nlh->nlmsg_flags & NLM_F_ACK || err)
2337 netlink_ack(skb, nlh, err); 2390 netlink_ack(skb, nlh, err, &extack);
2338 2391
2339skip: 2392skip:
2340 msglen = NLMSG_ALIGN(nlh->nlmsg_len); 2393 msglen = NLMSG_ALIGN(nlh->nlmsg_len);
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index f792f8d7f982..3490f2430532 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -13,6 +13,7 @@
13#define NETLINK_F_RECV_NO_ENOBUFS 0x8 13#define NETLINK_F_RECV_NO_ENOBUFS 0x8
14#define NETLINK_F_LISTEN_ALL_NSID 0x10 14#define NETLINK_F_LISTEN_ALL_NSID 0x10
15#define NETLINK_F_CAP_ACK 0x20 15#define NETLINK_F_CAP_ACK 0x20
16#define NETLINK_F_EXT_ACK 0x40
16 17
17#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) 18#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
18#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long)) 19#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 92e0981f7404..57b2e3648bc0 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -605,7 +605,8 @@ out:
605 return err; 605 return err;
606} 606}
607 607
608static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 608static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
609 struct netlink_ext_ack *extack)
609{ 610{
610 const struct genl_family *family; 611 const struct genl_family *family;
611 int err; 612 int err;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4f7e62ddc17e..e93d5c0471b2 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2448,7 +2448,8 @@ static const struct xfrm_link {
2448 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo }, 2448 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
2449}; 2449};
2450 2450
2451static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 2451static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
2452 struct netlink_ext_ack *extack)
2452{ 2453{
2453 struct net *net = sock_net(skb->sk); 2454 struct net *net = sock_net(skb->sk);
2454 struct nlattr *attrs[XFRMA_MAX+1]; 2455 struct nlattr *attrs[XFRMA_MAX+1];