Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * NETLINK Generic Netlink Family
4 : : *
5 : : * Authors: Jamal Hadi Salim
6 : : * Thomas Graf <tgraf@suug.ch>
7 : : * Johannes Berg <johannes@sipsolutions.net>
8 : : */
9 : :
10 : : #include <linux/module.h>
11 : : #include <linux/kernel.h>
12 : : #include <linux/slab.h>
13 : : #include <linux/errno.h>
14 : : #include <linux/types.h>
15 : : #include <linux/socket.h>
16 : : #include <linux/string.h>
17 : : #include <linux/skbuff.h>
18 : : #include <linux/mutex.h>
19 : : #include <linux/bitmap.h>
20 : : #include <linux/rwsem.h>
21 : : #include <linux/idr.h>
22 : : #include <net/sock.h>
23 : : #include <net/genetlink.h>
24 : :
25 : : static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
26 : : static DECLARE_RWSEM(cb_lock);
27 : :
28 : : atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0);
29 : : DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq);
30 : :
31 : 360 : void genl_lock(void)
32 : : {
33 : 0 : mutex_lock(&genl_mutex);
34 : 0 : }
35 : : EXPORT_SYMBOL(genl_lock);
36 : :
37 : 360 : void genl_unlock(void)
38 : : {
39 : 0 : mutex_unlock(&genl_mutex);
40 : 0 : }
41 : : EXPORT_SYMBOL(genl_unlock);
42 : :
43 : : #ifdef CONFIG_LOCKDEP
44 : : bool lockdep_genl_is_held(void)
45 : : {
46 : : return lockdep_is_held(&genl_mutex);
47 : : }
48 : : EXPORT_SYMBOL(lockdep_genl_is_held);
49 : : #endif
50 : :
51 : 360 : static void genl_lock_all(void)
52 : : {
53 : 360 : down_write(&cb_lock);
54 : 360 : genl_lock();
55 : : }
56 : :
57 : 360 : static void genl_unlock_all(void)
58 : : {
59 : 360 : genl_unlock();
60 : 360 : up_write(&cb_lock);
61 : : }
62 : :
63 : : static DEFINE_IDR(genl_fam_idr);
64 : :
65 : : /*
66 : : * Bitmap of multicast groups that are currently in use.
67 : : *
68 : : * To avoid an allocation at boot of just one unsigned long,
69 : : * declare it global instead.
70 : : * Bit 0 is marked as already used since group 0 is invalid.
71 : : * Bit 1 is marked as already used since the drop-monitor code
72 : : * abuses the API and thinks it can statically use group 1.
73 : : * That group will typically conflict with other groups that
74 : : * any proper users use.
75 : : * Bit 16 is marked as used since it's used for generic netlink
76 : : * and the code no longer marks pre-reserved IDs as used.
77 : : * Bit 17 is marked as already used since the VFS quota code
78 : : * also abused this API and relied on family == group ID, we
79 : : * cater to that by giving it a static family and group ID.
80 : : * Bit 18 is marked as already used since the PMCRAID driver
81 : : * did the same thing as the VFS quota code (maybe copied?)
82 : : */
83 : : static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
84 : : BIT(GENL_ID_VFS_DQUOT) |
85 : : BIT(GENL_ID_PMCRAID);
86 : : static unsigned long *mc_groups = &mc_group_start;
87 : : static unsigned long mc_groups_longs = 1;
88 : :
89 : : static int genl_ctrl_event(int event, const struct genl_family *family,
90 : : const struct genl_multicast_group *grp,
91 : : int grp_id);
92 : :
93 : 0 : static const struct genl_family *genl_family_find_byid(unsigned int id)
94 : : {
95 : 0 : return idr_find(&genl_fam_idr, id);
96 : : }
97 : :
98 : 360 : static const struct genl_family *genl_family_find_byname(char *name)
99 : : {
100 : 360 : const struct genl_family *family;
101 : 360 : unsigned int id;
102 : :
103 [ + + ]: 2340 : idr_for_each_entry(&genl_fam_idr, family, id)
104 [ - + ]: 1980 : if (strcmp(family->name, name) == 0)
105 : 0 : return family;
106 : :
107 : : return NULL;
108 : : }
109 : :
110 : 0 : static const struct genl_ops *genl_get_cmd(u8 cmd,
111 : : const struct genl_family *family)
112 : : {
113 : 0 : int i;
114 : :
115 [ # # ]: 0 : for (i = 0; i < family->n_ops; i++)
116 [ # # ]: 0 : if (family->ops[i].cmd == cmd)
117 : : return &family->ops[i];
118 : :
119 : : return NULL;
120 : : }
121 : :
122 : 90 : static int genl_allocate_reserve_groups(int n_groups, int *first_id)
123 : : {
124 : 90 : unsigned long *new_groups;
125 : 90 : int start = 0;
126 : 90 : int i;
127 : 90 : int id;
128 : 90 : bool fits;
129 : :
130 : 90 : do {
131 [ + - ]: 90 : if (start == 0)
132 : 90 : id = find_first_zero_bit(mc_groups,
133 : : mc_groups_longs *
134 : : BITS_PER_LONG);
135 : : else
136 : 0 : id = find_next_zero_bit(mc_groups,
137 : : mc_groups_longs * BITS_PER_LONG,
138 : : start);
139 : :
140 : 90 : fits = true;
141 : 90 : for (i = id;
142 [ + + ]: 330 : i < min_t(int, id + n_groups,
143 : : mc_groups_longs * BITS_PER_LONG);
144 : 240 : i++) {
145 [ + - ]: 240 : if (test_bit(i, mc_groups)) {
146 : : start = i;
147 : : fits = false;
148 : : break;
149 : : }
150 : : }
151 : :
152 [ - + ]: 90 : if (id + n_groups > mc_groups_longs * BITS_PER_LONG) {
153 : 0 : unsigned long new_longs = mc_groups_longs +
154 : 0 : BITS_TO_LONGS(n_groups);
155 : 0 : size_t nlen = new_longs * sizeof(unsigned long);
156 : :
157 [ # # ]: 0 : if (mc_groups == &mc_group_start) {
158 : 0 : new_groups = kzalloc(nlen, GFP_KERNEL);
159 [ # # ]: 0 : if (!new_groups)
160 : : return -ENOMEM;
161 : 0 : mc_groups = new_groups;
162 : 0 : *mc_groups = mc_group_start;
163 : : } else {
164 : 0 : new_groups = krealloc(mc_groups, nlen,
165 : : GFP_KERNEL);
166 [ # # ]: 0 : if (!new_groups)
167 : : return -ENOMEM;
168 : 0 : mc_groups = new_groups;
169 [ # # ]: 0 : for (i = 0; i < BITS_TO_LONGS(n_groups); i++)
170 : 0 : mc_groups[mc_groups_longs + i] = 0;
171 : : }
172 : 0 : mc_groups_longs = new_longs;
173 : : }
174 [ - + ]: 90 : } while (!fits);
175 : :
176 [ + + ]: 330 : for (i = id; i < id + n_groups; i++)
177 : 240 : set_bit(i, mc_groups);
178 : 90 : *first_id = id;
179 : 90 : return 0;
180 : : }
181 : :
182 : : static struct genl_family genl_ctrl;
183 : :
184 : 360 : static int genl_validate_assign_mc_groups(struct genl_family *family)
185 : : {
186 : 360 : int first_id;
187 : 360 : int n_groups = family->n_mcgrps;
188 : 360 : int err = 0, i;
189 : 360 : bool groups_allocated = false;
190 : :
191 [ + + ]: 360 : if (!n_groups)
192 : : return 0;
193 : :
194 [ + + ]: 450 : for (i = 0; i < n_groups; i++) {
195 : 300 : const struct genl_multicast_group *grp = &family->mcgrps[i];
196 : :
197 [ - + + - ]: 300 : if (WARN_ON(grp->name[0] == '\0'))
198 : : return -EINVAL;
199 [ - + + - ]: 300 : if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL))
200 : : return -EINVAL;
201 : : }
202 : :
203 : : /* special-case our own group and hacks */
204 [ + + ]: 150 : if (family == &genl_ctrl) {
205 : 30 : first_id = GENL_ID_CTRL;
206 [ - + ]: 30 : BUG_ON(n_groups != 1);
207 [ - + ]: 120 : } else if (strcmp(family->name, "NET_DM") == 0) {
208 : 0 : first_id = 1;
209 [ # # ]: 0 : BUG_ON(n_groups != 1);
210 [ + + ]: 120 : } else if (family->id == GENL_ID_VFS_DQUOT) {
211 : 30 : first_id = GENL_ID_VFS_DQUOT;
212 [ - + ]: 30 : BUG_ON(n_groups != 1);
213 [ - + ]: 90 : } else if (family->id == GENL_ID_PMCRAID) {
214 : 0 : first_id = GENL_ID_PMCRAID;
215 [ # # ]: 0 : BUG_ON(n_groups != 1);
216 : : } else {
217 : 90 : groups_allocated = true;
218 : 90 : err = genl_allocate_reserve_groups(n_groups, &first_id);
219 [ + - ]: 90 : if (err)
220 : : return err;
221 : : }
222 : :
223 : 150 : family->mcgrp_offset = first_id;
224 : :
225 : : /* if still initializing, can't and don't need to to realloc bitmaps */
226 [ + + ]: 150 : if (!init_net.genl_sock)
227 : : return 0;
228 : :
229 [ + + ]: 120 : if (family->netnsok) {
230 : 60 : struct net *net;
231 : :
232 : 60 : netlink_table_grab();
233 : 60 : rcu_read_lock();
234 [ + + ]: 120 : for_each_net_rcu(net) {
235 : 60 : err = __netlink_change_ngroups(net->genl_sock,
236 : : mc_groups_longs * BITS_PER_LONG);
237 [ + - ]: 60 : if (err) {
238 : : /*
239 : : * No need to roll back, can only fail if
240 : : * memory allocation fails and then the
241 : : * number of _possible_ groups has been
242 : : * increased on some sockets which is ok.
243 : : */
244 : : break;
245 : : }
246 : : }
247 : 60 : rcu_read_unlock();
248 : 60 : netlink_table_ungrab();
249 : : } else {
250 : 60 : err = netlink_change_ngroups(init_net.genl_sock,
251 : : mc_groups_longs * BITS_PER_LONG);
252 : : }
253 : :
254 [ - + ]: 120 : if (groups_allocated && err) {
255 [ # # ]: 0 : for (i = 0; i < family->n_mcgrps; i++)
256 : 0 : clear_bit(family->mcgrp_offset + i, mc_groups);
257 : : }
258 : :
259 : : return err;
260 : : }
261 : :
262 : 0 : static void genl_unregister_mc_groups(const struct genl_family *family)
263 : : {
264 : 0 : struct net *net;
265 : 0 : int i;
266 : :
267 : 0 : netlink_table_grab();
268 : 0 : rcu_read_lock();
269 [ # # ]: 0 : for_each_net_rcu(net) {
270 [ # # ]: 0 : for (i = 0; i < family->n_mcgrps; i++)
271 : 0 : __netlink_clear_multicast_users(
272 : 0 : net->genl_sock, family->mcgrp_offset + i);
273 : : }
274 : 0 : rcu_read_unlock();
275 : 0 : netlink_table_ungrab();
276 : :
277 [ # # ]: 0 : for (i = 0; i < family->n_mcgrps; i++) {
278 : 0 : int grp_id = family->mcgrp_offset + i;
279 : :
280 [ # # ]: 0 : if (grp_id != 1)
281 : 0 : clear_bit(grp_id, mc_groups);
282 : 0 : genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family,
283 : 0 : &family->mcgrps[i], grp_id);
284 : : }
285 : 0 : }
286 : :
287 : : static int genl_validate_ops(const struct genl_family *family)
288 : : {
289 : : const struct genl_ops *ops = family->ops;
290 : : unsigned int n_ops = family->n_ops;
291 : : int i, j;
292 : :
293 : : if (WARN_ON(n_ops && !ops))
294 : : return -EINVAL;
295 : :
296 : : if (!n_ops)
297 : : return 0;
298 : :
299 : : for (i = 0; i < n_ops; i++) {
300 : : if (ops[i].dumpit == NULL && ops[i].doit == NULL)
301 : : return -EINVAL;
302 : : for (j = i + 1; j < n_ops; j++)
303 : : if (ops[i].cmd == ops[j].cmd)
304 : : return -EINVAL;
305 : : }
306 : :
307 : : return 0;
308 : : }
309 : :
310 : : /**
311 : : * genl_register_family - register a generic netlink family
312 : : * @family: generic netlink family
313 : : *
314 : : * Registers the specified family after validating it first. Only one
315 : : * family may be registered with the same family name or identifier.
316 : : *
317 : : * The family's ops, multicast groups and module pointer must already
318 : : * be assigned.
319 : : *
320 : : * Return 0 on success or a negative error code.
321 : : */
322 : 360 : int genl_register_family(struct genl_family *family)
323 : : {
324 : 360 : int err, i;
325 : 360 : int start = GENL_START_ALLOC, end = GENL_MAX_ID;
326 : :
327 : 360 : err = genl_validate_ops(family);
328 [ + - ]: 360 : if (err)
329 : : return err;
330 : :
331 : 360 : genl_lock_all();
332 : :
333 [ - + ]: 360 : if (genl_family_find_byname(family->name)) {
334 : 0 : err = -EEXIST;
335 : 0 : goto errout_locked;
336 : : }
337 : :
338 : : /*
339 : : * Sadly, a few cases need to be special-cased
340 : : * due to them having previously abused the API
341 : : * and having used their family ID also as their
342 : : * multicast group ID, so we use reserved IDs
343 : : * for both to be sure we can do that mapping.
344 : : */
345 [ + + ]: 360 : if (family == &genl_ctrl) {
346 : : /* and this needs to be special for initial family lookups */
347 : : start = end = GENL_ID_CTRL;
348 [ + - ]: 330 : } else if (strcmp(family->name, "pmcraid") == 0) {
349 : : start = end = GENL_ID_PMCRAID;
350 [ + + ]: 330 : } else if (strcmp(family->name, "VFS_DQUOT") == 0) {
351 : 30 : start = end = GENL_ID_VFS_DQUOT;
352 : : }
353 : :
354 [ + + + + ]: 360 : if (family->maxattr && !family->parallel_ops) {
355 : 270 : family->attrbuf = kmalloc_array(family->maxattr + 1,
356 : : sizeof(struct nlattr *),
357 : : GFP_KERNEL);
358 [ - + ]: 270 : if (family->attrbuf == NULL) {
359 : 0 : err = -ENOMEM;
360 : 0 : goto errout_locked;
361 : : }
362 : : } else
363 : 90 : family->attrbuf = NULL;
364 : :
365 : 360 : family->id = idr_alloc_cyclic(&genl_fam_idr, family,
366 : : start, end + 1, GFP_KERNEL);
367 [ - + ]: 360 : if (family->id < 0) {
368 : 0 : err = family->id;
369 : 0 : goto errout_free;
370 : : }
371 : :
372 : 360 : err = genl_validate_assign_mc_groups(family);
373 [ - + ]: 360 : if (err)
374 : 0 : goto errout_remove;
375 : :
376 : 360 : genl_unlock_all();
377 : :
378 : : /* send all events */
379 : 360 : genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0);
380 [ + + ]: 1020 : for (i = 0; i < family->n_mcgrps; i++)
381 : 300 : genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family,
382 : 300 : &family->mcgrps[i], family->mcgrp_offset + i);
383 : :
384 : : return 0;
385 : :
386 : : errout_remove:
387 : 0 : idr_remove(&genl_fam_idr, family->id);
388 : 0 : errout_free:
389 : 0 : kfree(family->attrbuf);
390 : 0 : errout_locked:
391 : 0 : genl_unlock_all();
392 : 0 : return err;
393 : : }
394 : : EXPORT_SYMBOL(genl_register_family);
395 : :
396 : : /**
397 : : * genl_unregister_family - unregister generic netlink family
398 : : * @family: generic netlink family
399 : : *
400 : : * Unregisters the specified family.
401 : : *
402 : : * Returns 0 on success or a negative error code.
403 : : */
404 : 0 : int genl_unregister_family(const struct genl_family *family)
405 : : {
406 : 0 : genl_lock_all();
407 : :
408 [ # # ]: 0 : if (!genl_family_find_byid(family->id)) {
409 : 0 : genl_unlock_all();
410 : 0 : return -ENOENT;
411 : : }
412 : :
413 : 0 : genl_unregister_mc_groups(family);
414 : :
415 : 0 : idr_remove(&genl_fam_idr, family->id);
416 : :
417 : 0 : up_write(&cb_lock);
418 [ # # # # ]: 0 : wait_event(genl_sk_destructing_waitq,
419 : : atomic_read(&genl_sk_destructing_cnt) == 0);
420 : 0 : genl_unlock();
421 : :
422 : 0 : kfree(family->attrbuf);
423 : :
424 : 0 : genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
425 : :
426 : 0 : return 0;
427 : : }
428 : : EXPORT_SYMBOL(genl_unregister_family);
429 : :
430 : : /**
431 : : * genlmsg_put - Add generic netlink header to netlink message
432 : : * @skb: socket buffer holding the message
433 : : * @portid: netlink portid the message is addressed to
434 : : * @seq: sequence number (usually the one of the sender)
435 : : * @family: generic netlink family
436 : : * @flags: netlink message flags
437 : : * @cmd: generic netlink command
438 : : *
439 : : * Returns pointer to user specific header
440 : : */
441 : 618 : void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
442 : : const struct genl_family *family, int flags, u8 cmd)
443 : : {
444 : 618 : struct nlmsghdr *nlh;
445 : 618 : struct genlmsghdr *hdr;
446 : :
447 : 618 : nlh = nlmsg_put(skb, portid, seq, family->id, GENL_HDRLEN +
448 : 618 : family->hdrsize, flags);
449 [ + - ]: 618 : if (nlh == NULL)
450 : : return NULL;
451 : :
452 : 618 : hdr = nlmsg_data(nlh);
453 : 618 : hdr->cmd = cmd;
454 : 618 : hdr->version = family->version;
455 : 618 : hdr->reserved = 0;
456 : :
457 : 618 : return (char *) hdr + GENL_HDRLEN;
458 : : }
459 : : EXPORT_SYMBOL(genlmsg_put);
460 : :
461 : : static struct genl_dumpit_info *genl_dumpit_info_alloc(void)
462 : : {
463 : : return kmalloc(sizeof(struct genl_dumpit_info), GFP_KERNEL);
464 : : }
465 : :
466 : 0 : static void genl_dumpit_info_free(const struct genl_dumpit_info *info)
467 : : {
468 : 0 : kfree(info);
469 : : }
470 : :
471 : : static struct nlattr **
472 : 0 : genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
473 : : struct nlmsghdr *nlh,
474 : : struct netlink_ext_ack *extack,
475 : : const struct genl_ops *ops,
476 : : int hdrlen,
477 : : enum genl_validate_flags no_strict_flag,
478 : : bool parallel)
479 : : {
480 : 0 : enum netlink_validation validate = ops->validate & no_strict_flag ?
481 [ # # ]: 0 : NL_VALIDATE_LIBERAL :
482 : : NL_VALIDATE_STRICT;
483 : 0 : struct nlattr **attrbuf;
484 : 0 : int err;
485 : :
486 [ # # ]: 0 : if (!family->maxattr)
487 : : return NULL;
488 : :
489 [ # # ]: 0 : if (parallel) {
490 : 0 : attrbuf = kmalloc_array(family->maxattr + 1,
491 : : sizeof(struct nlattr *), GFP_KERNEL);
492 [ # # ]: 0 : if (!attrbuf)
493 : : return ERR_PTR(-ENOMEM);
494 : : } else {
495 : 0 : attrbuf = family->attrbuf;
496 : : }
497 : :
498 : 0 : err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
499 : : family->policy, validate, extack);
500 [ # # ]: 0 : if (err) {
501 [ # # ]: 0 : if (parallel)
502 : 0 : kfree(attrbuf);
503 : 0 : return ERR_PTR(err);
504 : : }
505 : : return attrbuf;
506 : : }
507 : :
508 : 0 : static void genl_family_rcv_msg_attrs_free(const struct genl_family *family,
509 : : struct nlattr **attrbuf,
510 : : bool parallel)
511 : : {
512 : 0 : if (parallel)
513 : 0 : kfree(attrbuf);
514 : : }
515 : :
516 : 0 : static int genl_lock_start(struct netlink_callback *cb)
517 : : {
518 [ # # ]: 0 : const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
519 : 0 : int rc = 0;
520 : :
521 [ # # ]: 0 : if (ops->start) {
522 : 0 : genl_lock();
523 : 0 : rc = ops->start(cb);
524 : 0 : genl_unlock();
525 : : }
526 : 0 : return rc;
527 : : }
528 : :
529 : 0 : static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
530 : : {
531 : 0 : const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
532 : 0 : int rc;
533 : :
534 : 0 : genl_lock();
535 : 0 : rc = ops->dumpit(skb, cb);
536 : 0 : genl_unlock();
537 : 0 : return rc;
538 : : }
539 : :
540 : 0 : static int genl_lock_done(struct netlink_callback *cb)
541 : : {
542 [ # # ]: 0 : const struct genl_dumpit_info *info = genl_dumpit_info(cb);
543 : 0 : const struct genl_ops *ops = info->ops;
544 : 0 : int rc = 0;
545 : :
546 [ # # ]: 0 : if (ops->done) {
547 : 0 : genl_lock();
548 : 0 : rc = ops->done(cb);
549 : 0 : genl_unlock();
550 : : }
551 : 0 : genl_family_rcv_msg_attrs_free(info->family, info->attrs, true);
552 : 0 : genl_dumpit_info_free(info);
553 : 0 : return rc;
554 : : }
555 : :
556 : 0 : static int genl_parallel_done(struct netlink_callback *cb)
557 : : {
558 [ # # ]: 0 : const struct genl_dumpit_info *info = genl_dumpit_info(cb);
559 : 0 : const struct genl_ops *ops = info->ops;
560 : 0 : int rc = 0;
561 : :
562 [ # # ]: 0 : if (ops->done)
563 : 0 : rc = ops->done(cb);
564 : 0 : genl_family_rcv_msg_attrs_free(info->family, info->attrs, true);
565 : 0 : genl_dumpit_info_free(info);
566 : 0 : return rc;
567 : : }
568 : :
569 : : static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
570 : : struct sk_buff *skb,
571 : : struct nlmsghdr *nlh,
572 : : struct netlink_ext_ack *extack,
573 : : const struct genl_ops *ops,
574 : : int hdrlen, struct net *net)
575 : : {
576 : : struct genl_dumpit_info *info;
577 : : struct nlattr **attrs = NULL;
578 : : int err;
579 : :
580 : : if (!ops->dumpit)
581 : : return -EOPNOTSUPP;
582 : :
583 : : if (ops->validate & GENL_DONT_VALIDATE_DUMP)
584 : : goto no_attrs;
585 : :
586 : : if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
587 : : return -EINVAL;
588 : :
589 : : attrs = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
590 : : ops, hdrlen,
591 : : GENL_DONT_VALIDATE_DUMP_STRICT,
592 : : true);
593 : : if (IS_ERR(attrs))
594 : : return PTR_ERR(attrs);
595 : :
596 : : no_attrs:
597 : : /* Allocate dumpit info. It is going to be freed by done() callback. */
598 : : info = genl_dumpit_info_alloc();
599 : : if (!info) {
600 : : genl_family_rcv_msg_attrs_free(family, attrs, true);
601 : : return -ENOMEM;
602 : : }
603 : :
604 : : info->family = family;
605 : : info->ops = ops;
606 : : info->attrs = attrs;
607 : :
608 : : if (!family->parallel_ops) {
609 : : struct netlink_dump_control c = {
610 : : .module = family->module,
611 : : .data = info,
612 : : .start = genl_lock_start,
613 : : .dump = genl_lock_dumpit,
614 : : .done = genl_lock_done,
615 : : };
616 : :
617 : : genl_unlock();
618 : : err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
619 : : genl_lock();
620 : :
621 : : } else {
622 : : struct netlink_dump_control c = {
623 : : .module = family->module,
624 : : .data = info,
625 : : .start = ops->start,
626 : : .dump = ops->dumpit,
627 : : .done = genl_parallel_done,
628 : : };
629 : :
630 : : err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
631 : : }
632 : :
633 : : return err;
634 : : }
635 : :
636 : 0 : static int genl_family_rcv_msg_doit(const struct genl_family *family,
637 : : struct sk_buff *skb,
638 : : struct nlmsghdr *nlh,
639 : : struct netlink_ext_ack *extack,
640 : : const struct genl_ops *ops,
641 : : int hdrlen, struct net *net)
642 : : {
643 : 0 : struct nlattr **attrbuf;
644 : 0 : struct genl_info info;
645 : 0 : int err;
646 : :
647 [ # # ]: 0 : if (!ops->doit)
648 : : return -EOPNOTSUPP;
649 : :
650 : 0 : attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
651 : : ops, hdrlen,
652 : : GENL_DONT_VALIDATE_STRICT,
653 : 0 : family->parallel_ops);
654 [ # # ]: 0 : if (IS_ERR(attrbuf))
655 : 0 : return PTR_ERR(attrbuf);
656 : :
657 : 0 : info.snd_seq = nlh->nlmsg_seq;
658 : 0 : info.snd_portid = NETLINK_CB(skb).portid;
659 : 0 : info.nlhdr = nlh;
660 [ # # ]: 0 : info.genlhdr = nlmsg_data(nlh);
661 : 0 : info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
662 : 0 : info.attrs = attrbuf;
663 : 0 : info.extack = extack;
664 [ # # ]: 0 : genl_info_net_set(&info, net);
665 : 0 : memset(&info.user_ptr, 0, sizeof(info.user_ptr));
666 : :
667 [ # # ]: 0 : if (family->pre_doit) {
668 : 0 : err = family->pre_doit(ops, skb, &info);
669 [ # # ]: 0 : if (err)
670 : 0 : goto out;
671 : : }
672 : :
673 : 0 : err = ops->doit(skb, &info);
674 : :
675 [ # # ]: 0 : if (family->post_doit)
676 : 0 : family->post_doit(ops, skb, &info);
677 : :
678 : 0 : out:
679 [ # # ]: 0 : genl_family_rcv_msg_attrs_free(family, attrbuf, family->parallel_ops);
680 : :
681 : : return err;
682 : : }
683 : :
684 : 0 : static int genl_family_rcv_msg(const struct genl_family *family,
685 : : struct sk_buff *skb,
686 : : struct nlmsghdr *nlh,
687 : : struct netlink_ext_ack *extack)
688 : : {
689 : 0 : const struct genl_ops *ops;
690 [ # # ]: 0 : struct net *net = sock_net(skb->sk);
691 [ # # ]: 0 : struct genlmsghdr *hdr = nlmsg_data(nlh);
692 : 0 : int hdrlen;
693 : :
694 : : /* this family doesn't exist in this netns */
695 [ # # # # ]: 0 : if (!family->netnsok && !net_eq(net, &init_net))
696 : : return -ENOENT;
697 : :
698 : 0 : hdrlen = GENL_HDRLEN + family->hdrsize;
699 [ # # ]: 0 : if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
700 : : return -EINVAL;
701 : :
702 : 0 : ops = genl_get_cmd(hdr->cmd, family);
703 [ # # ]: 0 : if (ops == NULL)
704 : : return -EOPNOTSUPP;
705 : :
706 [ # # # # ]: 0 : if ((ops->flags & GENL_ADMIN_PERM) &&
707 : 0 : !netlink_capable(skb, CAP_NET_ADMIN))
708 : : return -EPERM;
709 : :
710 [ # # # # ]: 0 : if ((ops->flags & GENL_UNS_ADMIN_PERM) &&
711 : 0 : !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
712 : : return -EPERM;
713 : :
714 [ # # ]: 0 : if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
715 : 0 : return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
716 : : ops, hdrlen, net);
717 : : else
718 : 0 : return genl_family_rcv_msg_doit(family, skb, nlh, extack,
719 : : ops, hdrlen, net);
720 : : }
721 : :
722 : 0 : static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
723 : : struct netlink_ext_ack *extack)
724 : : {
725 : 0 : const struct genl_family *family;
726 : 0 : int err;
727 : :
728 : 0 : family = genl_family_find_byid(nlh->nlmsg_type);
729 [ # # ]: 0 : if (family == NULL)
730 : : return -ENOENT;
731 : :
732 [ # # ]: 0 : if (!family->parallel_ops)
733 : 0 : genl_lock();
734 : :
735 : 0 : err = genl_family_rcv_msg(family, skb, nlh, extack);
736 : :
737 [ # # ]: 0 : if (!family->parallel_ops)
738 : 0 : genl_unlock();
739 : :
740 : : return err;
741 : : }
742 : :
743 : 0 : static void genl_rcv(struct sk_buff *skb)
744 : : {
745 : 0 : down_read(&cb_lock);
746 : 0 : netlink_rcv_skb(skb, &genl_rcv_msg);
747 : 0 : up_read(&cb_lock);
748 : 0 : }
749 : :
750 : : /**************************************************************************
751 : : * Controller
752 : : **************************************************************************/
753 : :
754 : : static struct genl_family genl_ctrl;
755 : :
756 : 330 : static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
757 : : u32 flags, struct sk_buff *skb, u8 cmd)
758 : : {
759 : 330 : void *hdr;
760 : :
761 : 330 : hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
762 [ + - ]: 330 : if (hdr == NULL)
763 : : return -1;
764 : :
765 [ + - + - ]: 660 : if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
766 [ + - ]: 660 : nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) ||
767 [ + - ]: 660 : nla_put_u32(skb, CTRL_ATTR_VERSION, family->version) ||
768 [ - + ]: 660 : nla_put_u32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize) ||
769 : 330 : nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
770 : 0 : goto nla_put_failure;
771 : :
772 [ + + ]: 330 : if (family->n_ops) {
773 : 270 : struct nlattr *nla_ops;
774 : 270 : int i;
775 : :
776 : 270 : nla_ops = nla_nest_start_noflag(skb, CTRL_ATTR_OPS);
777 [ - + ]: 270 : if (nla_ops == NULL)
778 : 0 : goto nla_put_failure;
779 : :
780 [ + + ]: 4680 : for (i = 0; i < family->n_ops; i++) {
781 : 4410 : struct nlattr *nest;
782 : 4410 : const struct genl_ops *ops = &family->ops[i];
783 : 4410 : u32 op_flags = ops->flags;
784 : :
785 [ + + ]: 4410 : if (ops->dumpit)
786 : 690 : op_flags |= GENL_CMD_CAP_DUMP;
787 [ + + ]: 4410 : if (ops->doit)
788 : 4140 : op_flags |= GENL_CMD_CAP_DO;
789 [ + + ]: 4410 : if (family->policy)
790 : 4050 : op_flags |= GENL_CMD_CAP_HASPOL;
791 : :
792 : 4410 : nest = nla_nest_start_noflag(skb, i + 1);
793 [ - + ]: 4410 : if (nest == NULL)
794 : 0 : goto nla_put_failure;
795 : :
796 [ + - - + ]: 8820 : if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
797 : : nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
798 : 0 : goto nla_put_failure;
799 : :
800 : 4410 : nla_nest_end(skb, nest);
801 : : }
802 : :
803 : 270 : nla_nest_end(skb, nla_ops);
804 : : }
805 : :
806 [ + + ]: 330 : if (family->n_mcgrps) {
807 : 120 : struct nlattr *nla_grps;
808 : 120 : int i;
809 : :
810 : 120 : nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
811 [ - + ]: 120 : if (nla_grps == NULL)
812 : 0 : goto nla_put_failure;
813 : :
814 [ + + ]: 390 : for (i = 0; i < family->n_mcgrps; i++) {
815 : 270 : struct nlattr *nest;
816 : 270 : const struct genl_multicast_group *grp;
817 : :
818 : 270 : grp = &family->mcgrps[i];
819 : :
820 : 270 : nest = nla_nest_start_noflag(skb, i + 1);
821 [ - + ]: 270 : if (nest == NULL)
822 : 0 : goto nla_put_failure;
823 : :
824 [ + - ]: 270 : if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID,
825 [ - + ]: 540 : family->mcgrp_offset + i) ||
826 : 270 : nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
827 : 270 : grp->name))
828 : 0 : goto nla_put_failure;
829 : :
830 : 270 : nla_nest_end(skb, nest);
831 : : }
832 : 120 : nla_nest_end(skb, nla_grps);
833 : : }
834 : :
835 : 330 : genlmsg_end(skb, hdr);
836 : 330 : return 0;
837 : :
838 : 0 : nla_put_failure:
839 : 0 : genlmsg_cancel(skb, hdr);
840 : 0 : return -EMSGSIZE;
841 : : }
842 : :
843 : 270 : static int ctrl_fill_mcgrp_info(const struct genl_family *family,
844 : : const struct genl_multicast_group *grp,
845 : : int grp_id, u32 portid, u32 seq, u32 flags,
846 : : struct sk_buff *skb, u8 cmd)
847 : : {
848 : 270 : void *hdr;
849 : 270 : struct nlattr *nla_grps;
850 : 270 : struct nlattr *nest;
851 : :
852 : 270 : hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
853 [ + - ]: 270 : if (hdr == NULL)
854 : : return -1;
855 : :
856 [ + - - + ]: 540 : if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
857 : 270 : nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id))
858 : 0 : goto nla_put_failure;
859 : :
860 : 270 : nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
861 [ - + ]: 270 : if (nla_grps == NULL)
862 : 0 : goto nla_put_failure;
863 : :
864 : 270 : nest = nla_nest_start_noflag(skb, 1);
865 [ - + ]: 270 : if (nest == NULL)
866 : 0 : goto nla_put_failure;
867 : :
868 [ + - - + ]: 540 : if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) ||
869 : 270 : nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
870 : 270 : grp->name))
871 : 0 : goto nla_put_failure;
872 : :
873 : 270 : nla_nest_end(skb, nest);
874 : 270 : nla_nest_end(skb, nla_grps);
875 : :
876 : 270 : genlmsg_end(skb, hdr);
877 : 270 : return 0;
878 : :
879 : 0 : nla_put_failure:
880 : 0 : genlmsg_cancel(skb, hdr);
881 : 0 : return -EMSGSIZE;
882 : : }
883 : :
884 : 0 : static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
885 : : {
886 : 0 : int n = 0;
887 : 0 : struct genl_family *rt;
888 : 0 : struct net *net = sock_net(skb->sk);
889 : 0 : int fams_to_skip = cb->args[0];
890 : 0 : unsigned int id;
891 : :
892 [ # # ]: 0 : idr_for_each_entry(&genl_fam_idr, rt, id) {
893 [ # # # # ]: 0 : if (!rt->netnsok && !net_eq(net, &init_net))
894 : 0 : continue;
895 : :
896 [ # # ]: 0 : if (n++ < fams_to_skip)
897 : 0 : continue;
898 : :
899 [ # # ]: 0 : if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
900 : 0 : cb->nlh->nlmsg_seq, NLM_F_MULTI,
901 : : skb, CTRL_CMD_NEWFAMILY) < 0) {
902 : : n--;
903 : : break;
904 : : }
905 : : }
906 : :
907 : 0 : cb->args[0] = n;
908 : 0 : return skb->len;
909 : : }
910 : :
911 : 330 : static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family,
912 : : u32 portid, int seq, u8 cmd)
913 : : {
914 : 330 : struct sk_buff *skb;
915 : 330 : int err;
916 : :
917 : 330 : skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
918 [ + - ]: 330 : if (skb == NULL)
919 : : return ERR_PTR(-ENOBUFS);
920 : :
921 : 330 : err = ctrl_fill_info(family, portid, seq, 0, skb, cmd);
922 [ - + ]: 330 : if (err < 0) {
923 : 0 : nlmsg_free(skb);
924 : 0 : return ERR_PTR(err);
925 : : }
926 : :
927 : : return skb;
928 : : }
929 : :
930 : : static struct sk_buff *
931 : 270 : ctrl_build_mcgrp_msg(const struct genl_family *family,
932 : : const struct genl_multicast_group *grp,
933 : : int grp_id, u32 portid, int seq, u8 cmd)
934 : : {
935 : 270 : struct sk_buff *skb;
936 : 270 : int err;
937 : :
938 : 270 : skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
939 [ + - ]: 270 : if (skb == NULL)
940 : : return ERR_PTR(-ENOBUFS);
941 : :
942 : 270 : err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid,
943 : : seq, 0, skb, cmd);
944 [ - + ]: 270 : if (err < 0) {
945 : 0 : nlmsg_free(skb);
946 : 0 : return ERR_PTR(err);
947 : : }
948 : :
949 : : return skb;
950 : : }
951 : :
952 : : static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
953 : : [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
954 : : [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
955 : : .len = GENL_NAMSIZ - 1 },
956 : : };
957 : :
958 : 0 : static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
959 : : {
960 : 0 : struct sk_buff *msg;
961 : 0 : const struct genl_family *res = NULL;
962 : 0 : int err = -EINVAL;
963 : :
964 [ # # ]: 0 : if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
965 : 0 : u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
966 : 0 : res = genl_family_find_byid(id);
967 : 0 : err = -ENOENT;
968 : : }
969 : :
970 [ # # ]: 0 : if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
971 : 0 : char *name;
972 : :
973 : 0 : name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
974 : 0 : res = genl_family_find_byname(name);
975 : : #ifdef CONFIG_MODULES
976 [ # # ]: 0 : if (res == NULL) {
977 : 0 : genl_unlock();
978 : 0 : up_read(&cb_lock);
979 : 0 : request_module("net-pf-%d-proto-%d-family-%s",
980 : : PF_NETLINK, NETLINK_GENERIC, name);
981 : 0 : down_read(&cb_lock);
982 : 0 : genl_lock();
983 : 0 : res = genl_family_find_byname(name);
984 : : }
985 : : #endif
986 : : err = -ENOENT;
987 : : }
988 : :
989 [ # # ]: 0 : if (res == NULL)
990 : : return err;
991 : :
992 [ # # # # ]: 0 : if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) {
993 : : /* family doesn't exist here */
994 : : return -ENOENT;
995 : : }
996 : :
997 : 0 : msg = ctrl_build_family_msg(res, info->snd_portid, info->snd_seq,
998 : : CTRL_CMD_NEWFAMILY);
999 [ # # ]: 0 : if (IS_ERR(msg))
1000 : 0 : return PTR_ERR(msg);
1001 : :
1002 : 0 : return genlmsg_reply(msg, info);
1003 : : }
1004 : :
1005 : 660 : static int genl_ctrl_event(int event, const struct genl_family *family,
1006 : : const struct genl_multicast_group *grp,
1007 : : int grp_id)
1008 : : {
1009 : 660 : struct sk_buff *msg;
1010 : :
1011 : : /* genl is still initialising */
1012 [ + + ]: 660 : if (!init_net.genl_sock)
1013 : : return 0;
1014 : :
1015 [ + + - ]: 600 : switch (event) {
1016 : 330 : case CTRL_CMD_NEWFAMILY:
1017 : : case CTRL_CMD_DELFAMILY:
1018 [ - + ]: 330 : WARN_ON(grp);
1019 : 330 : msg = ctrl_build_family_msg(family, 0, 0, event);
1020 : 330 : break;
1021 : 270 : case CTRL_CMD_NEWMCAST_GRP:
1022 : : case CTRL_CMD_DELMCAST_GRP:
1023 [ - + ]: 270 : BUG_ON(!grp);
1024 : 270 : msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event);
1025 : 270 : break;
1026 : : default:
1027 : : return -EINVAL;
1028 : : }
1029 : :
1030 [ - + ]: 600 : if (IS_ERR(msg))
1031 : 0 : return PTR_ERR(msg);
1032 : :
1033 [ + + ]: 600 : if (!family->netnsok) {
1034 : 270 : genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0,
1035 : : 0, GFP_KERNEL);
1036 : : } else {
1037 : 330 : rcu_read_lock();
1038 : 330 : genlmsg_multicast_allns(&genl_ctrl, msg, 0,
1039 : : 0, GFP_ATOMIC);
1040 : 330 : rcu_read_unlock();
1041 : : }
1042 : :
1043 : : return 0;
1044 : : }
1045 : :
1046 : : static const struct genl_ops genl_ctrl_ops[] = {
1047 : : {
1048 : : .cmd = CTRL_CMD_GETFAMILY,
1049 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1050 : : .doit = ctrl_getfamily,
1051 : : .dumpit = ctrl_dumpfamily,
1052 : : },
1053 : : };
1054 : :
1055 : : static const struct genl_multicast_group genl_ctrl_groups[] = {
1056 : : { .name = "notify", },
1057 : : };
1058 : :
1059 : : static struct genl_family genl_ctrl __ro_after_init = {
1060 : : .module = THIS_MODULE,
1061 : : .ops = genl_ctrl_ops,
1062 : : .n_ops = ARRAY_SIZE(genl_ctrl_ops),
1063 : : .mcgrps = genl_ctrl_groups,
1064 : : .n_mcgrps = ARRAY_SIZE(genl_ctrl_groups),
1065 : : .id = GENL_ID_CTRL,
1066 : : .name = "nlctrl",
1067 : : .version = 0x2,
1068 : : .maxattr = CTRL_ATTR_MAX,
1069 : : .policy = ctrl_policy,
1070 : : .netnsok = true,
1071 : : };
1072 : :
1073 : 0 : static int genl_bind(struct net *net, int group)
1074 : : {
1075 : 0 : struct genl_family *f;
1076 : 0 : int err = -ENOENT;
1077 : 0 : unsigned int id;
1078 : :
1079 : 0 : down_read(&cb_lock);
1080 : :
1081 [ # # ]: 0 : idr_for_each_entry(&genl_fam_idr, f, id) {
1082 [ # # ]: 0 : if (group >= f->mcgrp_offset &&
1083 [ # # ]: 0 : group < f->mcgrp_offset + f->n_mcgrps) {
1084 : 0 : int fam_grp = group - f->mcgrp_offset;
1085 : :
1086 [ # # # # ]: 0 : if (!f->netnsok && net != &init_net)
1087 : : err = -ENOENT;
1088 [ # # ]: 0 : else if (f->mcast_bind)
1089 : 0 : err = f->mcast_bind(net, fam_grp);
1090 : : else
1091 : : err = 0;
1092 : : break;
1093 : : }
1094 : : }
1095 : 0 : up_read(&cb_lock);
1096 : :
1097 : 0 : return err;
1098 : : }
1099 : :
1100 : 0 : static void genl_unbind(struct net *net, int group)
1101 : : {
1102 : 0 : struct genl_family *f;
1103 : 0 : unsigned int id;
1104 : :
1105 : 0 : down_read(&cb_lock);
1106 : :
1107 [ # # ]: 0 : idr_for_each_entry(&genl_fam_idr, f, id) {
1108 [ # # ]: 0 : if (group >= f->mcgrp_offset &&
1109 [ # # ]: 0 : group < f->mcgrp_offset + f->n_mcgrps) {
1110 : 0 : int fam_grp = group - f->mcgrp_offset;
1111 : :
1112 [ # # ]: 0 : if (f->mcast_unbind)
1113 : 0 : f->mcast_unbind(net, fam_grp);
1114 : : break;
1115 : : }
1116 : : }
1117 : 0 : up_read(&cb_lock);
1118 : 0 : }
1119 : :
1120 : 30 : static int __net_init genl_pernet_init(struct net *net)
1121 : : {
1122 : 30 : struct netlink_kernel_cfg cfg = {
1123 : : .input = genl_rcv,
1124 : : .flags = NL_CFG_F_NONROOT_RECV,
1125 : : .bind = genl_bind,
1126 : : .unbind = genl_unbind,
1127 : : };
1128 : :
1129 : : /* we'll bump the group number right afterwards */
1130 : 30 : net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg);
1131 : :
1132 [ - + - - ]: 30 : if (!net->genl_sock && net_eq(net, &init_net))
1133 : 0 : panic("GENL: Cannot initialize generic netlink\n");
1134 : :
1135 [ - + ]: 30 : if (!net->genl_sock)
1136 : 0 : return -ENOMEM;
1137 : :
1138 : : return 0;
1139 : : }
1140 : :
1141 : 0 : static void __net_exit genl_pernet_exit(struct net *net)
1142 : : {
1143 : 0 : netlink_kernel_release(net->genl_sock);
1144 : 0 : net->genl_sock = NULL;
1145 : 0 : }
1146 : :
1147 : : static struct pernet_operations genl_pernet_ops = {
1148 : : .init = genl_pernet_init,
1149 : : .exit = genl_pernet_exit,
1150 : : };
1151 : :
1152 : 30 : static int __init genl_init(void)
1153 : : {
1154 : 30 : int err;
1155 : :
1156 : 30 : err = genl_register_family(&genl_ctrl);
1157 [ - + ]: 30 : if (err < 0)
1158 : 0 : goto problem;
1159 : :
1160 : 30 : err = register_pernet_subsys(&genl_pernet_ops);
1161 [ - + ]: 30 : if (err)
1162 : 0 : goto problem;
1163 : :
1164 : 30 : return 0;
1165 : :
1166 : 0 : problem:
1167 : 0 : panic("GENL: Cannot register controller: %d\n", err);
1168 : : }
1169 : :
1170 : : subsys_initcall(genl_init);
1171 : :
1172 : 336 : static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
1173 : : gfp_t flags)
1174 : : {
1175 : 336 : struct sk_buff *tmp;
1176 : 336 : struct net *net, *prev = NULL;
1177 : 336 : bool delivered = false;
1178 : 336 : int err;
1179 : :
1180 [ + + ]: 672 : for_each_net_rcu(net) {
1181 [ - + ]: 336 : if (prev) {
1182 : 0 : tmp = skb_clone(skb, flags);
1183 [ # # ]: 0 : if (!tmp) {
1184 : 0 : err = -ENOMEM;
1185 : 0 : goto error;
1186 : : }
1187 : 0 : err = nlmsg_multicast(prev->genl_sock, tmp,
1188 : : portid, group, flags);
1189 [ # # ]: 0 : if (!err)
1190 : : delivered = true;
1191 [ # # ]: 0 : else if (err != -ESRCH)
1192 : 0 : goto error;
1193 : : }
1194 : :
1195 : 336 : prev = net;
1196 : : }
1197 : :
1198 : 336 : err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
1199 [ + - ]: 336 : if (!err)
1200 : : delivered = true;
1201 [ + - ]: 336 : else if (err != -ESRCH)
1202 : : return err;
1203 [ + - ]: 336 : return delivered ? 0 : -ESRCH;
1204 : 0 : error:
1205 : 0 : kfree_skb(skb);
1206 : 0 : return err;
1207 : : }
1208 : :
1209 : 336 : int genlmsg_multicast_allns(const struct genl_family *family,
1210 : : struct sk_buff *skb, u32 portid,
1211 : : unsigned int group, gfp_t flags)
1212 : : {
1213 [ - + + - ]: 336 : if (WARN_ON_ONCE(group >= family->n_mcgrps))
1214 : : return -EINVAL;
1215 : 336 : group = family->mcgrp_offset + group;
1216 : 336 : return genlmsg_mcast(skb, portid, group, flags);
1217 : : }
1218 : : EXPORT_SYMBOL(genlmsg_multicast_allns);
1219 : :
1220 : 0 : void genl_notify(const struct genl_family *family, struct sk_buff *skb,
1221 : : struct genl_info *info, u32 group, gfp_t flags)
1222 : : {
1223 [ # # ]: 0 : struct net *net = genl_info_net(info);
1224 : 0 : struct sock *sk = net->genl_sock;
1225 : 0 : int report = 0;
1226 : :
1227 [ # # ]: 0 : if (info->nlhdr)
1228 : 0 : report = nlmsg_report(info->nlhdr);
1229 : :
1230 [ # # # # ]: 0 : if (WARN_ON_ONCE(group >= family->n_mcgrps))
1231 : : return;
1232 : 0 : group = family->mcgrp_offset + group;
1233 : 0 : nlmsg_notify(sk, skb, info->snd_portid, group, report, flags);
1234 : : }
1235 : : EXPORT_SYMBOL(genl_notify);
|