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
;
22 struct list_head list
;
24 struct genl_ops ops
[];
27 static LIST_HEAD(copies_list
);
28 static DEFINE_MUTEX(copies_mutex
);
30 static const struct nla_policy extack_dummy_policy
[1] = {};
32 static struct bp_extack_genl_family
*get_copy(__genl_const
struct genl_ops
*op
)
36 } while (op
->policy
!= extack_dummy_policy
);
38 return container_of(op
, struct bp_extack_genl_family
, ops
[0]);
41 static int extack_pre_doit(__genl_const
struct genl_ops
*ops
,
43 struct genl_info
*info
)
45 struct netlink_ext_ack
*extack
= kzalloc(sizeof(*extack
), GFP_KERNEL
);
46 struct bp_extack_genl_family
*copy
= get_copy(ops
);
47 struct genl_ops
*real_ops
;
50 __bp_genl_info_userhdr_set(info
, extack
);
53 __bp_genl_info_userhdr_set(info
, ERR_PTR(-ENOMEM
));
57 real_ops
= (void *)©
->real_family
->ops
[ops
- ©
->ops
[1]];
58 extack
->__bp_genl_real_ops
= real_ops
;
60 if (copy
->real_family
->pre_doit
)
61 err
= copy
->real_family
->pre_doit(real_ops
, skb
, info
);
66 __bp_genl_info_userhdr_set(info
, ERR_PTR(err
));
73 static void extack_netlink_ack(struct sk_buff
*in_skb
, struct nlmsghdr
*nlh
,
74 int err
, const struct netlink_ext_ack
*extack
)
78 struct nlmsgerr
*errmsg
;
79 size_t payload
= sizeof(*errmsg
);
81 unsigned int flags
= 0;
82 /* backports assumes everyone supports this - libnl does so it's true */
83 bool nlk_has_extack
= true;
85 /* Error messages get the original request appened, unless the user
86 * requests to cap the error message, and get extra error data if
88 * (ignored in backports)
90 if (nlk_has_extack
&& extack
&& extack
->_msg
)
91 tlvlen
+= nla_total_size(strlen(extack
->_msg
) + 1);
95 payload
+= nlmsg_len(nlh
);
97 flags
|= NLM_F_CAPPED
;
98 if (nlk_has_extack
&& extack
&& extack
->bad_attr
)
99 tlvlen
+= nla_total_size(sizeof(u32
));
101 flags
|= NLM_F_CAPPED
;
103 if (nlk_has_extack
&& extack
&& extack
->cookie_len
)
104 tlvlen
+= nla_total_size(extack
->cookie_len
);
108 flags
|= NLM_F_ACK_TLVS
;
110 skb
= nlmsg_new(payload
+ tlvlen
, GFP_KERNEL
);
112 NETLINK_CB(in_skb
).sk
->sk_err
= ENOBUFS
;
113 NETLINK_CB(in_skb
).sk
->sk_error_report(NETLINK_CB(in_skb
).sk
);
117 rep
= __nlmsg_put(skb
, NETLINK_CB(in_skb
).portid
, nlh
->nlmsg_seq
,
118 NLMSG_ERROR
, payload
, flags
);
119 errmsg
= nlmsg_data(rep
);
121 memcpy(&errmsg
->msg
, nlh
, payload
> sizeof(*errmsg
) ? nlh
->nlmsg_len
: sizeof(*nlh
));
123 if (nlk_has_extack
&& extack
) {
125 WARN_ON(nla_put_string(skb
, NLMSGERR_ATTR_MSG
,
129 if (extack
->bad_attr
&&
130 !WARN_ON((u8
*)extack
->bad_attr
< in_skb
->data
||
131 (u8
*)extack
->bad_attr
>= in_skb
->data
+
133 WARN_ON(nla_put_u32(skb
, NLMSGERR_ATTR_OFFS
,
134 (u8
*)extack
->bad_attr
-
137 if (extack
->cookie_len
)
138 WARN_ON(nla_put(skb
, NLMSGERR_ATTR_COOKIE
,
146 netlink_unicast(in_skb
->sk
, skb
, NETLINK_CB(in_skb
).portid
, MSG_DONTWAIT
);
149 static int extack_doit(struct sk_buff
*skb
, struct genl_info
*info
)
151 struct genl_ops
*real_ops
;
154 /* older kernels have a bug here */
155 if (IS_ERR(__bp_genl_info_userhdr(info
))) {
156 extack_netlink_ack(skb
, info
->nlhdr
,
157 PTR_ERR(__bp_genl_info_userhdr(info
)),
158 genl_info_extack(info
));
162 real_ops
= genl_info_extack(info
)->__bp_genl_real_ops
;
163 err
= real_ops
->doit(skb
, info
);
168 if (info
->nlhdr
->nlmsg_flags
& NLM_F_ACK
|| err
)
169 extack_netlink_ack(skb
, info
->nlhdr
, err
,
170 genl_info_extack(info
));
173 /* suppress sending ACK from normal netlink code */
174 info
->nlhdr
->nlmsg_flags
&= ~NLM_F_ACK
;
178 static void extack_post_doit(__genl_const
struct genl_ops
*ops
,
180 struct genl_info
*info
)
182 void (*post_doit
)(__genl_const
struct genl_ops
*ops
,
184 struct genl_info
*info
);
186 post_doit
= get_copy(ops
)->real_family
->post_doit
;
189 post_doit(ops
, skb
, info
);
190 kfree(__bp_genl_info_userhdr(info
));
193 int bp_extack_genl_register_family(struct genl_family
*family
)
195 unsigned int size
= sizeof(struct bp_extack_genl_family
) +
196 sizeof(family
->ops
[0]) * (family
->n_ops
+ 1);
197 struct bp_extack_genl_family
*copy
;
200 copy
= kzalloc(size
, GFP_KERNEL
);
204 copy
->family
= *family
;
205 copy
->real_family
= family
;
206 copy
->family
.ops
= ©
->ops
[1];
208 for (i
= 0; i
< family
->n_ops
; i
++) {
209 copy
->ops
[i
+ 1] = family
->ops
[i
];
210 if (family
->ops
[i
].doit
)
211 copy
->ops
[i
+ 1].doit
= extack_doit
;
214 copy
->ops
[0].policy
= extack_dummy_policy
;
216 copy
->family
.pre_doit
= extack_pre_doit
;
217 copy
->family
.post_doit
= extack_post_doit
;
219 err
= __real_bp_extack_genl_register_family(©
->family
);
225 /* copy this since the family might access it directly */
226 family
->id
= copy
->family
.id
;
227 family
->attrbuf
= copy
->family
.attrbuf
;
228 #if LINUX_VERSION_IS_GEQ(3,13,0)
229 family
->mcgrp_offset
= copy
->family
.mcgrp_offset
;
232 mutex_lock(&copies_mutex
);
233 list_add_tail(©
->list
, &copies_list
);
234 mutex_unlock(&copies_mutex
);
238 EXPORT_SYMBOL_GPL(bp_extack_genl_register_family
);
240 int bp_extack_genl_unregister_family(struct genl_family
*family
)
242 struct bp_extack_genl_family
*tmp
, *copy
= NULL
;
245 mutex_lock(&copies_mutex
);
246 list_for_each_entry(tmp
, &copies_list
, list
) {
247 if (tmp
->real_family
== family
) {
253 list_del(©
->list
);
254 mutex_unlock(&copies_mutex
);
259 err
= __real_bp_extack_genl_unregister_family(©
->family
);
265 EXPORT_SYMBOL_GPL(bp_extack_genl_unregister_family
);