2 * Copyright 2017 Intel Deutschland GmbH
4 #include <net/genetlink.h>
13 NLMSGERR_ATTR_MAX
= __NLMSGERR_ATTR_MAX
- 1
16 #define NLM_F_CAPPED 0x100 /* request was capped */
17 #define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
19 struct bp_extack_genl_family
{
20 struct genl_family family
;
21 struct genl_family
*real_family
;
23 struct genl_ops ops
[];
26 static const struct nla_policy extack_dummy_policy
[1] = {};
28 static struct bp_extack_genl_family
*get_copy(const struct genl_ops
*op
)
32 } while (op
->policy
!= extack_dummy_policy
);
34 return container_of(op
, struct bp_extack_genl_family
, ops
[0]);
37 static int extack_pre_doit(const struct genl_ops
*ops
,
39 struct genl_info
*info
)
41 struct netlink_ext_ack
*extack
= kzalloc(sizeof(*extack
), GFP_KERNEL
);
42 struct bp_extack_genl_family
*copy
= get_copy(ops
);
43 const struct genl_ops
*real_ops
;
46 info
->userhdr
= extack
;
49 info
->userhdr
= ERR_PTR(-ENOMEM
);
53 real_ops
= ©
->real_family
->ops
[ops
- ©
->ops
[1]];
54 extack
->__bp_genl_real_ops
= real_ops
;
56 if (copy
->real_family
->pre_doit
)
57 err
= copy
->real_family
->pre_doit(real_ops
, skb
, info
);
62 info
->userhdr
= ERR_PTR(err
);
69 static void extack_netlink_ack(struct sk_buff
*in_skb
, struct nlmsghdr
*nlh
,
70 int err
, const struct netlink_ext_ack
*extack
)
74 struct nlmsgerr
*errmsg
;
75 size_t payload
= sizeof(*errmsg
);
77 unsigned int flags
= 0;
78 /* backports assumes everyone supports this - libnl does so it's true */
79 bool nlk_has_extack
= true;
81 /* Error messages get the original request appened, unless the user
82 * requests to cap the error message, and get extra error data if
84 * (ignored in backports)
88 payload
+= nlmsg_len(nlh
);
90 flags
|= NLM_F_CAPPED
;
91 if (nlk_has_extack
&& extack
) {
93 tlvlen
+= nla_total_size(strlen(extack
->_msg
) + 1);
95 tlvlen
+= nla_total_size(sizeof(u32
));
98 flags
|= NLM_F_CAPPED
;
100 if (nlk_has_extack
&& extack
&& extack
->cookie_len
)
101 tlvlen
+= nla_total_size(extack
->cookie_len
);
105 flags
|= NLM_F_ACK_TLVS
;
107 skb
= nlmsg_new(payload
+ tlvlen
, GFP_KERNEL
);
109 NETLINK_CB(in_skb
).sk
->sk_err
= ENOBUFS
;
110 NETLINK_CB(in_skb
).sk
->sk_error_report(NETLINK_CB(in_skb
).sk
);
114 rep
= __nlmsg_put(skb
, NETLINK_CB(in_skb
).portid
, nlh
->nlmsg_seq
,
115 NLMSG_ERROR
, payload
, flags
);
116 errmsg
= nlmsg_data(rep
);
118 memcpy(&errmsg
->msg
, nlh
, payload
> sizeof(*errmsg
) ? nlh
->nlmsg_len
: sizeof(*nlh
));
120 if (nlk_has_extack
&& extack
) {
123 WARN_ON(nla_put_string(skb
, NLMSGERR_ATTR_MSG
,
125 if (extack
->bad_attr
&&
126 !WARN_ON((u8
*)extack
->bad_attr
< in_skb
->data
||
127 (u8
*)extack
->bad_attr
>= in_skb
->data
+
129 WARN_ON(nla_put_u32(skb
, NLMSGERR_ATTR_OFFS
,
130 (u8
*)extack
->bad_attr
-
133 if (extack
->cookie_len
)
134 WARN_ON(nla_put(skb
, NLMSGERR_ATTR_COOKIE
,
142 netlink_unicast(in_skb
->sk
, skb
, NETLINK_CB(in_skb
).portid
, MSG_DONTWAIT
);
145 static int extack_doit(struct sk_buff
*skb
, struct genl_info
*info
)
147 const struct genl_ops
*real_ops
;
150 /* older kernels have a bug here */
151 if (IS_ERR(info
->userhdr
)) {
152 extack_netlink_ack(skb
, info
->nlhdr
,
153 PTR_ERR(info
->userhdr
),
154 genl_info_extack(info
));
158 real_ops
= genl_info_extack(info
)->__bp_genl_real_ops
;
159 err
= real_ops
->doit(skb
, info
);
164 if (info
->nlhdr
->nlmsg_flags
& NLM_F_ACK
|| err
)
165 extack_netlink_ack(skb
, info
->nlhdr
, err
,
166 genl_info_extack(info
));
169 /* suppress sending ACK from normal netlink code */
170 info
->nlhdr
->nlmsg_flags
&= ~NLM_F_ACK
;
174 static void extack_post_doit(const struct genl_ops
*ops
,
176 struct genl_info
*info
)
178 void (*post_doit
)(const struct genl_ops
*ops
,
180 struct genl_info
*info
);
182 post_doit
= get_copy(ops
)->real_family
->post_doit
;
185 post_doit(ops
, skb
, info
);
186 kfree(info
->userhdr
);
189 int bp_extack_genl_register_family(struct genl_family
*family
)
191 unsigned int size
= sizeof(struct bp_extack_genl_family
) +
192 sizeof(family
->ops
[0]) * (family
->n_ops
+ 1);
193 struct bp_extack_genl_family
*copy
;
196 copy
= kzalloc(size
, GFP_KERNEL
);
200 copy
->family
= *family
;
201 copy
->real_family
= family
;
202 copy
->family
.ops
= ©
->ops
[1];
204 for (i
= 0; i
< family
->n_ops
; i
++) {
205 copy
->ops
[i
+ 1] = family
->ops
[i
];
206 if (family
->ops
[i
].doit
)
207 copy
->ops
[i
+ 1].doit
= extack_doit
;
210 copy
->ops
[0].policy
= extack_dummy_policy
;
212 copy
->family
.pre_doit
= extack_pre_doit
;
213 copy
->family
.post_doit
= extack_post_doit
;
216 * store in attrbuf, so that even if we re-register the family
217 * the data will be overwritten and we don't overwrite data
218 * that's used again later...
220 family
->attrbuf
= (void *)copy
;
222 err
= __real_bp_extack_genl_register_family(©
->family
);
227 EXPORT_SYMBOL_GPL(bp_extack_genl_register_family
);
229 int bp_extack_genl_unregister_family(struct genl_family
*family
)
231 struct bp_extack_genl_family
*copy
= (void *)family
->attrbuf
;
237 err
= __real_bp_extack_genl_unregister_family(©
->family
);
243 EXPORT_SYMBOL_GPL(bp_extack_genl_unregister_family
);