blob: 1afca2a6c2ac15f5107ae48509e4b282ff1297c3 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Thomas Graf482a8522005-11-10 02:25:56 +01002/*
3 * NETLINK Generic Netlink Family
4 *
5 * Authors: Jamal Hadi Salim
6 * Thomas Graf <tgraf@suug.ch>
Johannes Berg2dbba6f2007-07-18 15:47:52 -07007 * Johannes Berg <johannes@sipsolutions.net>
Thomas Graf482a8522005-11-10 02:25:56 +01008 */
9
Thomas Graf482a8522005-11-10 02:25:56 +010010#include <linux/module.h>
11#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Thomas Graf482a8522005-11-10 02:25:56 +010013#include <linux/errno.h>
14#include <linux/types.h>
15#include <linux/socket.h>
16#include <linux/string.h>
17#include <linux/skbuff.h>
Ingo Molnar14cc3e22006-03-26 01:37:14 -080018#include <linux/mutex.h>
Johannes Berg2dbba6f2007-07-18 15:47:52 -070019#include <linux/bitmap.h>
Pravin B Shelardef31172013-04-23 07:48:30 +000020#include <linux/rwsem.h>
Johannes Berg2ae0f172016-10-24 14:40:04 +020021#include <linux/idr.h>
Thomas Graf482a8522005-11-10 02:25:56 +010022#include <net/sock.h>
23#include <net/genetlink.h>
24
Ingo Molnar14cc3e22006-03-26 01:37:14 -080025static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
Pravin B Shelardef31172013-04-23 07:48:30 +000026static DECLARE_RWSEM(cb_lock);
Thomas Graf482a8522005-11-10 02:25:56 +010027
Johannes Bergee1c24422015-01-16 11:37:14 +010028atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0);
29DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq);
30
James Chapmanf408e0c2010-04-02 06:19:05 +000031void genl_lock(void)
Thomas Graf482a8522005-11-10 02:25:56 +010032{
Ingo Molnar14cc3e22006-03-26 01:37:14 -080033 mutex_lock(&genl_mutex);
Thomas Graf482a8522005-11-10 02:25:56 +010034}
James Chapmanf408e0c2010-04-02 06:19:05 +000035EXPORT_SYMBOL(genl_lock);
Thomas Graf482a8522005-11-10 02:25:56 +010036
James Chapmanf408e0c2010-04-02 06:19:05 +000037void genl_unlock(void)
Thomas Graf482a8522005-11-10 02:25:56 +010038{
Ingo Molnar14cc3e22006-03-26 01:37:14 -080039 mutex_unlock(&genl_mutex);
Thomas Graf482a8522005-11-10 02:25:56 +010040}
James Chapmanf408e0c2010-04-02 06:19:05 +000041EXPORT_SYMBOL(genl_unlock);
Thomas Graf482a8522005-11-10 02:25:56 +010042
Pravin B Shelardef31172013-04-23 07:48:30 +000043static void genl_lock_all(void)
44{
45 down_write(&cb_lock);
46 genl_lock();
47}
48
49static void genl_unlock_all(void)
50{
51 genl_unlock();
52 up_write(&cb_lock);
53}
54
Johannes Berg2ae0f172016-10-24 14:40:04 +020055static DEFINE_IDR(genl_fam_idr);
Thomas Graf482a8522005-11-10 02:25:56 +010056
Johannes Berg2dbba6f2007-07-18 15:47:52 -070057/*
58 * Bitmap of multicast groups that are currently in use.
59 *
60 * To avoid an allocation at boot of just one unsigned long,
61 * declare it global instead.
62 * Bit 0 is marked as already used since group 0 is invalid.
Johannes Berge5dcecb2013-11-19 15:19:32 +010063 * Bit 1 is marked as already used since the drop-monitor code
64 * abuses the API and thinks it can statically use group 1.
65 * That group will typically conflict with other groups that
66 * any proper users use.
Johannes Berg2a94fe42013-11-19 15:19:39 +010067 * Bit 16 is marked as used since it's used for generic netlink
68 * and the code no longer marks pre-reserved IDs as used.
Johannes Berg2ecf7532013-11-19 15:19:33 +010069 * Bit 17 is marked as already used since the VFS quota code
70 * also abused this API and relied on family == group ID, we
71 * cater to that by giving it a static family and group ID.
Johannes Berg5e53e682013-11-24 21:09:26 +010072 * Bit 18 is marked as already used since the PMCRAID driver
73 * did the same thing as the VFS quota code (maybe copied?)
Johannes Berg2dbba6f2007-07-18 15:47:52 -070074 */
Johannes Berg2a94fe42013-11-19 15:19:39 +010075static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
Johannes Berg5e53e682013-11-24 21:09:26 +010076 BIT(GENL_ID_VFS_DQUOT) |
77 BIT(GENL_ID_PMCRAID);
Johannes Berg2dbba6f2007-07-18 15:47:52 -070078static unsigned long *mc_groups = &mc_group_start;
79static unsigned long mc_groups_longs = 1;
Thomas Graf482a8522005-11-10 02:25:56 +010080
Johannes Berg2ae0f172016-10-24 14:40:04 +020081static int genl_ctrl_event(int event, const struct genl_family *family,
Johannes Berg2a94fe42013-11-19 15:19:39 +010082 const struct genl_multicast_group *grp,
83 int grp_id);
Thomas Graf482a8522005-11-10 02:25:56 +010084
Johannes Berg2ae0f172016-10-24 14:40:04 +020085static const struct genl_family *genl_family_find_byid(unsigned int id)
Thomas Graf482a8522005-11-10 02:25:56 +010086{
Johannes Berg2ae0f172016-10-24 14:40:04 +020087 return idr_find(&genl_fam_idr, id);
Thomas Graf482a8522005-11-10 02:25:56 +010088}
89
Johannes Berg2ae0f172016-10-24 14:40:04 +020090static const struct genl_family *genl_family_find_byname(char *name)
Thomas Graf482a8522005-11-10 02:25:56 +010091{
Johannes Berg2ae0f172016-10-24 14:40:04 +020092 const struct genl_family *family;
93 unsigned int id;
Thomas Graf482a8522005-11-10 02:25:56 +010094
Johannes Berg2ae0f172016-10-24 14:40:04 +020095 idr_for_each_entry(&genl_fam_idr, family, id)
96 if (strcmp(family->name, name) == 0)
97 return family;
Thomas Graf482a8522005-11-10 02:25:56 +010098
99 return NULL;
100}
101
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700102static int genl_get_cmd_cnt(const struct genl_family *family)
103{
104 return family->n_ops + family->n_small_ops;
105}
106
107static void genl_op_from_full(const struct genl_family *family,
108 unsigned int i, struct genl_ops *op)
109{
110 *op = family->ops[i];
Jakub Kicinski48526a02020-10-02 14:49:57 -0700111
112 if (!op->maxattr)
113 op->maxattr = family->maxattr;
114 if (!op->policy)
115 op->policy = family->policy;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700116}
117
Jakub Kicinskie992a6e2020-10-03 10:44:46 +0200118static int genl_get_cmd_full(u32 cmd, const struct genl_family *family,
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700119 struct genl_ops *op)
Thomas Graf482a8522005-11-10 02:25:56 +0100120{
Johannes Bergd91824c2013-11-14 17:14:44 +0100121 int i;
Thomas Graf482a8522005-11-10 02:25:56 +0100122
Johannes Bergd91824c2013-11-14 17:14:44 +0100123 for (i = 0; i < family->n_ops; i++)
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700124 if (family->ops[i].cmd == cmd) {
125 genl_op_from_full(family, i, op);
126 return 0;
127 }
Thomas Graf482a8522005-11-10 02:25:56 +0100128
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700129 return -ENOENT;
130}
131
132static void genl_op_from_small(const struct genl_family *family,
133 unsigned int i, struct genl_ops *op)
134{
135 memset(op, 0, sizeof(*op));
136 op->doit = family->small_ops[i].doit;
137 op->dumpit = family->small_ops[i].dumpit;
138 op->cmd = family->small_ops[i].cmd;
139 op->internal_flags = family->small_ops[i].internal_flags;
140 op->flags = family->small_ops[i].flags;
141 op->validate = family->small_ops[i].validate;
Jakub Kicinski48526a02020-10-02 14:49:57 -0700142
143 op->maxattr = family->maxattr;
144 op->policy = family->policy;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700145}
146
Jakub Kicinskie992a6e2020-10-03 10:44:46 +0200147static int genl_get_cmd_small(u32 cmd, const struct genl_family *family,
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700148 struct genl_ops *op)
149{
150 int i;
151
152 for (i = 0; i < family->n_small_ops; i++)
153 if (family->small_ops[i].cmd == cmd) {
154 genl_op_from_small(family, i, op);
155 return 0;
156 }
157
158 return -ENOENT;
159}
160
Jakub Kicinskie992a6e2020-10-03 10:44:46 +0200161static int genl_get_cmd(u32 cmd, const struct genl_family *family,
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700162 struct genl_ops *op)
163{
164 if (!genl_get_cmd_full(cmd, family, op))
165 return 0;
166 return genl_get_cmd_small(cmd, family, op);
167}
168
169static void genl_get_cmd_by_index(unsigned int i,
170 const struct genl_family *family,
171 struct genl_ops *op)
172{
173 if (i < family->n_ops)
174 genl_op_from_full(family, i, op);
175 else if (i < family->n_ops + family->n_small_ops)
176 genl_op_from_small(family, i - family->n_ops, op);
177 else
178 WARN_ON_ONCE(1);
Thomas Graf482a8522005-11-10 02:25:56 +0100179}
180
Johannes Berg2a94fe42013-11-19 15:19:39 +0100181static int genl_allocate_reserve_groups(int n_groups, int *first_id)
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700182{
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700183 unsigned long *new_groups;
Johannes Berg2a94fe42013-11-19 15:19:39 +0100184 int start = 0;
185 int i;
186 int id;
187 bool fits;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700188
Johannes Berg2a94fe42013-11-19 15:19:39 +0100189 do {
190 if (start == 0)
191 id = find_first_zero_bit(mc_groups,
192 mc_groups_longs *
193 BITS_PER_LONG);
194 else
195 id = find_next_zero_bit(mc_groups,
196 mc_groups_longs * BITS_PER_LONG,
197 start);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700198
Johannes Berg2a94fe42013-11-19 15:19:39 +0100199 fits = true;
200 for (i = id;
201 i < min_t(int, id + n_groups,
202 mc_groups_longs * BITS_PER_LONG);
203 i++) {
204 if (test_bit(i, mc_groups)) {
205 start = i;
206 fits = false;
207 break;
208 }
209 }
210
David S. Millerb8e429a2016-01-13 10:28:06 -0500211 if (id + n_groups > mc_groups_longs * BITS_PER_LONG) {
Johannes Berg2a94fe42013-11-19 15:19:39 +0100212 unsigned long new_longs = mc_groups_longs +
213 BITS_TO_LONGS(n_groups);
214 size_t nlen = new_longs * sizeof(unsigned long);
215
216 if (mc_groups == &mc_group_start) {
217 new_groups = kzalloc(nlen, GFP_KERNEL);
218 if (!new_groups)
219 return -ENOMEM;
220 mc_groups = new_groups;
221 *mc_groups = mc_group_start;
222 } else {
223 new_groups = krealloc(mc_groups, nlen,
224 GFP_KERNEL);
225 if (!new_groups)
226 return -ENOMEM;
227 mc_groups = new_groups;
228 for (i = 0; i < BITS_TO_LONGS(n_groups); i++)
229 mc_groups[mc_groups_longs + i] = 0;
230 }
231 mc_groups_longs = new_longs;
232 }
233 } while (!fits);
234
235 for (i = id; i < id + n_groups; i++)
236 set_bit(i, mc_groups);
237 *first_id = id;
238 return 0;
239}
240
241static struct genl_family genl_ctrl;
242
243static int genl_validate_assign_mc_groups(struct genl_family *family)
244{
245 int first_id;
246 int n_groups = family->n_mcgrps;
Geert Uytterhoeven0f0e2152013-11-23 13:01:50 +0100247 int err = 0, i;
Johannes Berg2a94fe42013-11-19 15:19:39 +0100248 bool groups_allocated = false;
249
250 if (!n_groups)
251 return 0;
252
253 for (i = 0; i < n_groups; i++) {
254 const struct genl_multicast_group *grp = &family->mcgrps[i];
255
256 if (WARN_ON(grp->name[0] == '\0'))
257 return -EINVAL;
258 if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL))
259 return -EINVAL;
260 }
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700261
Johannes Berge5dcecb2013-11-19 15:19:32 +0100262 /* special-case our own group and hacks */
Johannes Berg2a94fe42013-11-19 15:19:39 +0100263 if (family == &genl_ctrl) {
264 first_id = GENL_ID_CTRL;
265 BUG_ON(n_groups != 1);
266 } else if (strcmp(family->name, "NET_DM") == 0) {
267 first_id = 1;
268 BUG_ON(n_groups != 1);
Johannes Berg5e53e682013-11-24 21:09:26 +0100269 } else if (family->id == GENL_ID_VFS_DQUOT) {
Johannes Berg2a94fe42013-11-19 15:19:39 +0100270 first_id = GENL_ID_VFS_DQUOT;
271 BUG_ON(n_groups != 1);
Johannes Berg5e53e682013-11-24 21:09:26 +0100272 } else if (family->id == GENL_ID_PMCRAID) {
273 first_id = GENL_ID_PMCRAID;
274 BUG_ON(n_groups != 1);
Johannes Berg2a94fe42013-11-19 15:19:39 +0100275 } else {
276 groups_allocated = true;
277 err = genl_allocate_reserve_groups(n_groups, &first_id);
278 if (err)
279 return err;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700280 }
281
Johannes Berg2a94fe42013-11-19 15:19:39 +0100282 family->mcgrp_offset = first_id;
283
Randy Dunlap85405912020-08-22 16:40:15 -0700284 /* if still initializing, can't and don't need to realloc bitmaps */
Johannes Berg2a94fe42013-11-19 15:19:39 +0100285 if (!init_net.genl_sock)
286 return 0;
287
Johannes Berg134e6372009-07-10 09:51:34 +0000288 if (family->netnsok) {
289 struct net *net;
290
Johannes Bergd136f1b2009-09-12 03:03:15 +0000291 netlink_table_grab();
Johannes Berg134e6372009-07-10 09:51:34 +0000292 rcu_read_lock();
293 for_each_net_rcu(net) {
Johannes Bergd136f1b2009-09-12 03:03:15 +0000294 err = __netlink_change_ngroups(net->genl_sock,
Johannes Berg134e6372009-07-10 09:51:34 +0000295 mc_groups_longs * BITS_PER_LONG);
296 if (err) {
297 /*
298 * No need to roll back, can only fail if
299 * memory allocation fails and then the
300 * number of _possible_ groups has been
301 * increased on some sockets which is ok.
302 */
Johannes Berg2a94fe42013-11-19 15:19:39 +0100303 break;
Johannes Berg134e6372009-07-10 09:51:34 +0000304 }
305 }
306 rcu_read_unlock();
Johannes Bergd136f1b2009-09-12 03:03:15 +0000307 netlink_table_ungrab();
Johannes Berg134e6372009-07-10 09:51:34 +0000308 } else {
309 err = netlink_change_ngroups(init_net.genl_sock,
310 mc_groups_longs * BITS_PER_LONG);
Johannes Berg134e6372009-07-10 09:51:34 +0000311 }
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700312
Johannes Berg2a94fe42013-11-19 15:19:39 +0100313 if (groups_allocated && err) {
314 for (i = 0; i < family->n_mcgrps; i++)
315 clear_bit(family->mcgrp_offset + i, mc_groups);
316 }
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700317
Thomas Graf79d310d2007-07-24 15:34:53 -0700318 return err;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700319}
Thomas Graf79dc43862007-07-24 15:32:46 -0700320
Johannes Berg2ae0f172016-10-24 14:40:04 +0200321static void genl_unregister_mc_groups(const struct genl_family *family)
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700322{
Johannes Berg2a94fe42013-11-19 15:19:39 +0100323 struct net *net;
324 int i;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700325
Johannes Berg2a94fe42013-11-19 15:19:39 +0100326 netlink_table_grab();
327 rcu_read_lock();
328 for_each_net_rcu(net) {
329 for (i = 0; i < family->n_mcgrps; i++)
330 __netlink_clear_multicast_users(
331 net->genl_sock, family->mcgrp_offset + i);
332 }
333 rcu_read_unlock();
334 netlink_table_ungrab();
335
336 for (i = 0; i < family->n_mcgrps; i++) {
337 int grp_id = family->mcgrp_offset + i;
338
339 if (grp_id != 1)
340 clear_bit(grp_id, mc_groups);
341 genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family,
342 &family->mcgrps[i], grp_id);
343 }
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700344}
345
Denis ChengRq2f91abd2014-06-02 01:18:01 -0700346static int genl_validate_ops(const struct genl_family *family)
Thomas Graf482a8522005-11-10 02:25:56 +0100347{
Johannes Bergd91824c2013-11-14 17:14:44 +0100348 int i, j;
Thomas Graf482a8522005-11-10 02:25:56 +0100349
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700350 if (WARN_ON(family->n_ops && !family->ops) ||
351 WARN_ON(family->n_small_ops && !family->small_ops))
Johannes Berg568508a2013-11-15 14:19:08 +0100352 return -EINVAL;
353
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700354 for (i = 0; i < genl_get_cmd_cnt(family); i++) {
355 struct genl_ops op;
Johannes Berg568508a2013-11-15 14:19:08 +0100356
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700357 genl_get_cmd_by_index(i, family, &op);
358 if (op.dumpit == NULL && op.doit == NULL)
Johannes Bergd91824c2013-11-14 17:14:44 +0100359 return -EINVAL;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700360 for (j = i + 1; j < genl_get_cmd_cnt(family); j++) {
361 struct genl_ops op2;
362
363 genl_get_cmd_by_index(j, family, &op2);
364 if (op.cmd == op2.cmd)
Johannes Bergd91824c2013-11-14 17:14:44 +0100365 return -EINVAL;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700366 }
Thomas Graf482a8522005-11-10 02:25:56 +0100367 }
368
Johannes Bergd91824c2013-11-14 17:14:44 +0100369 return 0;
Thomas Graf482a8522005-11-10 02:25:56 +0100370}
Thomas Graf482a8522005-11-10 02:25:56 +0100371
372/**
Johannes Berg489111e2016-10-24 14:40:03 +0200373 * genl_register_family - register a generic netlink family
Thomas Graf482a8522005-11-10 02:25:56 +0100374 * @family: generic netlink family
375 *
376 * Registers the specified family after validating it first. Only one
377 * family may be registered with the same family name or identifier.
Thomas Graf482a8522005-11-10 02:25:56 +0100378 *
Johannes Berg489111e2016-10-24 14:40:03 +0200379 * The family's ops, multicast groups and module pointer must already
380 * be assigned.
Johannes Berg568508a2013-11-15 14:19:08 +0100381 *
Thomas Graf482a8522005-11-10 02:25:56 +0100382 * Return 0 on success or a negative error code.
383 */
Johannes Berg489111e2016-10-24 14:40:03 +0200384int genl_register_family(struct genl_family *family)
Thomas Graf482a8522005-11-10 02:25:56 +0100385{
Johannes Berga07ea4d2016-10-24 14:40:02 +0200386 int err, i;
Johannes Berg2ae0f172016-10-24 14:40:04 +0200387 int start = GENL_START_ALLOC, end = GENL_MAX_ID;
Thomas Graf482a8522005-11-10 02:25:56 +0100388
Johannes Berg568508a2013-11-15 14:19:08 +0100389 err = genl_validate_ops(family);
390 if (err)
391 return err;
392
Pravin B Shelardef31172013-04-23 07:48:30 +0000393 genl_lock_all();
Thomas Graf482a8522005-11-10 02:25:56 +0100394
395 if (genl_family_find_byname(family->name)) {
396 err = -EEXIST;
397 goto errout_locked;
398 }
399
Johannes Berg2ae0f172016-10-24 14:40:04 +0200400 /*
401 * Sadly, a few cases need to be special-cased
402 * due to them having previously abused the API
403 * and having used their family ID also as their
404 * multicast group ID, so we use reserved IDs
405 * for both to be sure we can do that mapping.
406 */
Johannes Berga07ea4d2016-10-24 14:40:02 +0200407 if (family == &genl_ctrl) {
Johannes Berg2ae0f172016-10-24 14:40:04 +0200408 /* and this needs to be special for initial family lookups */
409 start = end = GENL_ID_CTRL;
410 } else if (strcmp(family->name, "pmcraid") == 0) {
411 start = end = GENL_ID_PMCRAID;
412 } else if (strcmp(family->name, "VFS_DQUOT") == 0) {
413 start = end = GENL_ID_VFS_DQUOT;
Thomas Graf482a8522005-11-10 02:25:56 +0100414 }
415
Marcel Holtmann4e43df32019-04-24 22:18:53 +0200416 family->id = idr_alloc_cyclic(&genl_fam_idr, family,
417 start, end + 1, GFP_KERNEL);
Wei Yongjun22ca9042016-11-01 14:45:52 +0000418 if (family->id < 0) {
419 err = family->id;
Cong Wangbf64ff42020-06-27 00:12:24 -0700420 goto errout_locked;
Wei Yongjun22ca9042016-11-01 14:45:52 +0000421 }
Johannes Berg2a94fe42013-11-19 15:19:39 +0100422
Johannes Berg2ae0f172016-10-24 14:40:04 +0200423 err = genl_validate_assign_mc_groups(family);
424 if (err)
425 goto errout_remove;
426
Pravin B Shelardef31172013-04-23 07:48:30 +0000427 genl_unlock_all();
Thomas Graf482a8522005-11-10 02:25:56 +0100428
Johannes Berg2a94fe42013-11-19 15:19:39 +0100429 /* send all events */
430 genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0);
431 for (i = 0; i < family->n_mcgrps; i++)
432 genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family,
433 &family->mcgrps[i], family->mcgrp_offset + i);
Thomas Graf482a8522005-11-10 02:25:56 +0100434
435 return 0;
436
Johannes Berg2ae0f172016-10-24 14:40:04 +0200437errout_remove:
438 idr_remove(&genl_fam_idr, family->id);
Thomas Graf482a8522005-11-10 02:25:56 +0100439errout_locked:
Pravin B Shelardef31172013-04-23 07:48:30 +0000440 genl_unlock_all();
Thomas Graf482a8522005-11-10 02:25:56 +0100441 return err;
442}
Johannes Berg489111e2016-10-24 14:40:03 +0200443EXPORT_SYMBOL(genl_register_family);
Thomas Graf482a8522005-11-10 02:25:56 +0100444
445/**
446 * genl_unregister_family - unregister generic netlink family
447 * @family: generic netlink family
448 *
449 * Unregisters the specified family.
450 *
451 * Returns 0 on success or a negative error code.
452 */
Johannes Berg2ae0f172016-10-24 14:40:04 +0200453int genl_unregister_family(const struct genl_family *family)
Thomas Graf482a8522005-11-10 02:25:56 +0100454{
Pravin B Shelardef31172013-04-23 07:48:30 +0000455 genl_lock_all();
Thomas Graf482a8522005-11-10 02:25:56 +0100456
pravin shelar0e82c762016-10-28 16:01:41 -0700457 if (!genl_family_find_byid(family->id)) {
Johannes Berg2ae0f172016-10-24 14:40:04 +0200458 genl_unlock_all();
459 return -ENOENT;
Thomas Graf482a8522005-11-10 02:25:56 +0100460 }
461
Johannes Berg2ae0f172016-10-24 14:40:04 +0200462 genl_unregister_mc_groups(family);
Thomas Graf482a8522005-11-10 02:25:56 +0100463
Johannes Berg2ae0f172016-10-24 14:40:04 +0200464 idr_remove(&genl_fam_idr, family->id);
465
466 up_write(&cb_lock);
467 wait_event(genl_sk_destructing_waitq,
468 atomic_read(&genl_sk_destructing_cnt) == 0);
469 genl_unlock();
470
Johannes Berg2ae0f172016-10-24 14:40:04 +0200471 genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
472
473 return 0;
Thomas Graf482a8522005-11-10 02:25:56 +0100474}
Changli Gao416c2f92010-07-25 20:46:01 +0000475EXPORT_SYMBOL(genl_unregister_family);
Thomas Graf482a8522005-11-10 02:25:56 +0100476
Denys Vlasenkoa46621a2012-01-30 15:22:06 -0500477/**
478 * genlmsg_put - Add generic netlink header to netlink message
479 * @skb: socket buffer holding the message
Eric W. Biederman15e47302012-09-07 20:12:54 +0000480 * @portid: netlink portid the message is addressed to
Denys Vlasenkoa46621a2012-01-30 15:22:06 -0500481 * @seq: sequence number (usually the one of the sender)
482 * @family: generic netlink family
Ben Hutchings2c530402012-07-10 10:55:09 +0000483 * @flags: netlink message flags
Denys Vlasenkoa46621a2012-01-30 15:22:06 -0500484 * @cmd: generic netlink command
485 *
486 * Returns pointer to user specific header
487 */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000488void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
Johannes Berg2ae0f172016-10-24 14:40:04 +0200489 const struct genl_family *family, int flags, u8 cmd)
Denys Vlasenkoa46621a2012-01-30 15:22:06 -0500490{
491 struct nlmsghdr *nlh;
492 struct genlmsghdr *hdr;
493
Eric W. Biederman15e47302012-09-07 20:12:54 +0000494 nlh = nlmsg_put(skb, portid, seq, family->id, GENL_HDRLEN +
Denys Vlasenkoa46621a2012-01-30 15:22:06 -0500495 family->hdrsize, flags);
496 if (nlh == NULL)
497 return NULL;
498
499 hdr = nlmsg_data(nlh);
500 hdr->cmd = cmd;
501 hdr->version = family->version;
502 hdr->reserved = 0;
503
504 return (char *) hdr + GENL_HDRLEN;
505}
506EXPORT_SYMBOL(genlmsg_put);
507
Jiri Pirko1927f412019-10-05 20:04:34 +0200508static struct genl_dumpit_info *genl_dumpit_info_alloc(void)
509{
510 return kmalloc(sizeof(struct genl_dumpit_info), GFP_KERNEL);
511}
512
513static void genl_dumpit_info_free(const struct genl_dumpit_info *info)
514{
515 kfree(info);
516}
517
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200518static struct nlattr **
519genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
520 struct nlmsghdr *nlh,
521 struct netlink_ext_ack *extack,
522 const struct genl_ops *ops,
523 int hdrlen,
Cong Wangb65ce382020-06-12 00:16:55 -0700524 enum genl_validate_flags no_strict_flag)
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200525{
526 enum netlink_validation validate = ops->validate & no_strict_flag ?
527 NL_VALIDATE_LIBERAL :
528 NL_VALIDATE_STRICT;
529 struct nlattr **attrbuf;
530 int err;
531
Jakub Kicinski48526a02020-10-02 14:49:57 -0700532 if (!ops->maxattr)
Michal Kubecekcb0ce182019-10-11 09:40:09 +0200533 return NULL;
534
Jakub Kicinski48526a02020-10-02 14:49:57 -0700535 attrbuf = kmalloc_array(ops->maxattr + 1,
Cong Wangbf64ff42020-06-27 00:12:24 -0700536 sizeof(struct nlattr *), GFP_KERNEL);
537 if (!attrbuf)
538 return ERR_PTR(-ENOMEM);
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200539
Jakub Kicinski48526a02020-10-02 14:49:57 -0700540 err = __nlmsg_parse(nlh, hdrlen, attrbuf, ops->maxattr, ops->policy,
541 validate, extack);
Paolo Abeni39f3b412020-02-21 19:42:13 +0100542 if (err) {
Cong Wangbf64ff42020-06-27 00:12:24 -0700543 kfree(attrbuf);
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200544 return ERR_PTR(err);
545 }
546 return attrbuf;
547}
548
Cong Wangbf64ff42020-06-27 00:12:24 -0700549static void genl_family_rcv_msg_attrs_free(struct nlattr **attrbuf)
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200550{
Cong Wangbf64ff42020-06-27 00:12:24 -0700551 kfree(attrbuf);
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200552}
553
Cong Wangc36f0552020-06-02 21:49:10 -0700554struct genl_start_context {
555 const struct genl_family *family;
556 struct nlmsghdr *nlh;
557 struct netlink_ext_ack *extack;
558 const struct genl_ops *ops;
559 int hdrlen;
560};
561
562static int genl_start(struct netlink_callback *cb)
Tom Herbertfc9e50f2015-12-15 15:41:37 -0800563{
Cong Wangc36f0552020-06-02 21:49:10 -0700564 struct genl_start_context *ctx = cb->data;
565 const struct genl_ops *ops = ctx->ops;
566 struct genl_dumpit_info *info;
567 struct nlattr **attrs = NULL;
Tom Herbertfc9e50f2015-12-15 15:41:37 -0800568 int rc = 0;
569
Cong Wangc36f0552020-06-02 21:49:10 -0700570 if (ops->validate & GENL_DONT_VALIDATE_DUMP)
571 goto no_attrs;
572
573 if (ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen))
574 return -EINVAL;
575
576 attrs = genl_family_rcv_msg_attrs_parse(ctx->family, ctx->nlh, ctx->extack,
577 ops, ctx->hdrlen,
Cong Wangb65ce382020-06-12 00:16:55 -0700578 GENL_DONT_VALIDATE_DUMP_STRICT);
Cong Wangc36f0552020-06-02 21:49:10 -0700579 if (IS_ERR(attrs))
580 return PTR_ERR(attrs);
581
582no_attrs:
583 info = genl_dumpit_info_alloc();
584 if (!info) {
Cong Wangbf64ff42020-06-27 00:12:24 -0700585 genl_family_rcv_msg_attrs_free(attrs);
Cong Wangc36f0552020-06-02 21:49:10 -0700586 return -ENOMEM;
587 }
588 info->family = ctx->family;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700589 info->op = *ops;
Cong Wangc36f0552020-06-02 21:49:10 -0700590 info->attrs = attrs;
591
592 cb->data = info;
Tom Herbertfc9e50f2015-12-15 15:41:37 -0800593 if (ops->start) {
Cong Wangc36f0552020-06-02 21:49:10 -0700594 if (!ctx->family->parallel_ops)
595 genl_lock();
Tom Herbertfc9e50f2015-12-15 15:41:37 -0800596 rc = ops->start(cb);
Cong Wangc36f0552020-06-02 21:49:10 -0700597 if (!ctx->family->parallel_ops)
598 genl_unlock();
599 }
600
601 if (rc) {
Cong Wangbf64ff42020-06-27 00:12:24 -0700602 genl_family_rcv_msg_attrs_free(info->attrs);
Cong Wangc36f0552020-06-02 21:49:10 -0700603 genl_dumpit_info_free(info);
604 cb->data = NULL;
Tom Herbertfc9e50f2015-12-15 15:41:37 -0800605 }
606 return rc;
607}
608
Pravin B Shelar9b963092013-08-23 12:44:55 -0700609static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
610{
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700611 const struct genl_ops *ops = &genl_dumpit_info(cb)->op;
Pravin B Shelar9b963092013-08-23 12:44:55 -0700612 int rc;
613
614 genl_lock();
615 rc = ops->dumpit(skb, cb);
616 genl_unlock();
617 return rc;
618}
619
620static int genl_lock_done(struct netlink_callback *cb)
621{
Jiri Pirko1927f412019-10-05 20:04:34 +0200622 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700623 const struct genl_ops *ops = &info->op;
Pravin B Shelar9b963092013-08-23 12:44:55 -0700624 int rc = 0;
625
626 if (ops->done) {
627 genl_lock();
628 rc = ops->done(cb);
629 genl_unlock();
630 }
Cong Wangbf64ff42020-06-27 00:12:24 -0700631 genl_family_rcv_msg_attrs_free(info->attrs);
Jiri Pirko1927f412019-10-05 20:04:34 +0200632 genl_dumpit_info_free(info);
633 return rc;
634}
635
636static int genl_parallel_done(struct netlink_callback *cb)
637{
638 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700639 const struct genl_ops *ops = &info->op;
Jiri Pirko1927f412019-10-05 20:04:34 +0200640 int rc = 0;
641
642 if (ops->done)
643 rc = ops->done(cb);
Cong Wangbf64ff42020-06-27 00:12:24 -0700644 genl_family_rcv_msg_attrs_free(info->attrs);
Jiri Pirko1927f412019-10-05 20:04:34 +0200645 genl_dumpit_info_free(info);
Pravin B Shelar9b963092013-08-23 12:44:55 -0700646 return rc;
647}
648
Jiri Pirkobe064de2019-10-05 20:04:33 +0200649static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
650 struct sk_buff *skb,
651 struct nlmsghdr *nlh,
652 struct netlink_ext_ack *extack,
653 const struct genl_ops *ops,
654 int hdrlen, struct net *net)
Thomas Graf482a8522005-11-10 02:25:56 +0100655{
Cong Wangc36f0552020-06-02 21:49:10 -0700656 struct genl_start_context ctx;
Jiri Pirkobe064de2019-10-05 20:04:33 +0200657 int err;
Thomas Graf482a8522005-11-10 02:25:56 +0100658
Jiri Pirkobe064de2019-10-05 20:04:33 +0200659 if (!ops->dumpit)
Thomas Graf1d00a4e2007-03-22 23:30:12 -0700660 return -EOPNOTSUPP;
Thomas Graf482a8522005-11-10 02:25:56 +0100661
Cong Wangc36f0552020-06-02 21:49:10 -0700662 ctx.family = family;
663 ctx.nlh = nlh;
664 ctx.extack = extack;
665 ctx.ops = ops;
666 ctx.hdrlen = hdrlen;
Jiri Pirko1927f412019-10-05 20:04:34 +0200667
Jiri Pirkobe064de2019-10-05 20:04:33 +0200668 if (!family->parallel_ops) {
669 struct netlink_dump_control c = {
670 .module = family->module,
Cong Wangc36f0552020-06-02 21:49:10 -0700671 .data = &ctx,
672 .start = genl_start,
Jiri Pirkobe064de2019-10-05 20:04:33 +0200673 .dump = genl_lock_dumpit,
674 .done = genl_lock_done,
675 };
676
677 genl_unlock();
678 err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
679 genl_lock();
Jiri Pirkobe064de2019-10-05 20:04:33 +0200680 } else {
681 struct netlink_dump_control c = {
682 .module = family->module,
Cong Wangc36f0552020-06-02 21:49:10 -0700683 .data = &ctx,
684 .start = genl_start,
Jiri Pirkobe064de2019-10-05 20:04:33 +0200685 .dump = ops->dumpit,
Jiri Pirko1927f412019-10-05 20:04:34 +0200686 .done = genl_parallel_done,
Jiri Pirkobe064de2019-10-05 20:04:33 +0200687 };
688
689 err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
690 }
691
692 return err;
693}
694
695static int genl_family_rcv_msg_doit(const struct genl_family *family,
696 struct sk_buff *skb,
697 struct nlmsghdr *nlh,
698 struct netlink_ext_ack *extack,
699 const struct genl_ops *ops,
700 int hdrlen, struct net *net)
701{
702 struct nlattr **attrbuf;
703 struct genl_info info;
704 int err;
705
706 if (!ops->doit)
Thomas Graf1d00a4e2007-03-22 23:30:12 -0700707 return -EOPNOTSUPP;
Thomas Graf482a8522005-11-10 02:25:56 +0100708
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200709 attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
710 ops, hdrlen,
Cong Wangb65ce382020-06-12 00:16:55 -0700711 GENL_DONT_VALIDATE_STRICT);
Jiri Pirkoc10e6cf2019-10-05 20:04:35 +0200712 if (IS_ERR(attrbuf))
713 return PTR_ERR(attrbuf);
Thomas Graf482a8522005-11-10 02:25:56 +0100714
715 info.snd_seq = nlh->nlmsg_seq;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000716 info.snd_portid = NETLINK_CB(skb).portid;
Thomas Graf482a8522005-11-10 02:25:56 +0100717 info.nlhdr = nlh;
718 info.genlhdr = nlmsg_data(nlh);
719 info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
Pravin B Shelardef31172013-04-23 07:48:30 +0000720 info.attrs = attrbuf;
Johannes Berg7ab606d2017-04-12 14:34:05 +0200721 info.extack = extack;
Johannes Berg134e6372009-07-10 09:51:34 +0000722 genl_info_net_set(&info, net);
Johannes Bergff4c92d2010-10-04 21:14:03 +0200723 memset(&info.user_ptr, 0, sizeof(info.user_ptr));
Thomas Graf482a8522005-11-10 02:25:56 +0100724
Johannes Bergff4c92d2010-10-04 21:14:03 +0200725 if (family->pre_doit) {
726 err = family->pre_doit(ops, skb, &info);
727 if (err)
Wei Yongjun50754d212013-04-26 15:34:16 +0000728 goto out;
Johannes Bergff4c92d2010-10-04 21:14:03 +0200729 }
730
731 err = ops->doit(skb, &info);
732
733 if (family->post_doit)
734 family->post_doit(ops, skb, &info);
735
Wei Yongjun50754d212013-04-26 15:34:16 +0000736out:
Cong Wangbf64ff42020-06-27 00:12:24 -0700737 genl_family_rcv_msg_attrs_free(attrbuf);
Pravin B Shelardef31172013-04-23 07:48:30 +0000738
739 return err;
740}
741
Jiri Pirkobe064de2019-10-05 20:04:33 +0200742static int genl_family_rcv_msg(const struct genl_family *family,
743 struct sk_buff *skb,
744 struct nlmsghdr *nlh,
745 struct netlink_ext_ack *extack)
746{
Jiri Pirkobe064de2019-10-05 20:04:33 +0200747 struct net *net = sock_net(skb->sk);
748 struct genlmsghdr *hdr = nlmsg_data(nlh);
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700749 struct genl_ops op;
Jiri Pirkobe064de2019-10-05 20:04:33 +0200750 int hdrlen;
751
752 /* this family doesn't exist in this netns */
753 if (!family->netnsok && !net_eq(net, &init_net))
754 return -ENOENT;
755
756 hdrlen = GENL_HDRLEN + family->hdrsize;
757 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
758 return -EINVAL;
759
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700760 if (genl_get_cmd(hdr->cmd, family, &op))
Jiri Pirkobe064de2019-10-05 20:04:33 +0200761 return -EOPNOTSUPP;
762
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700763 if ((op.flags & GENL_ADMIN_PERM) &&
Jiri Pirkobe064de2019-10-05 20:04:33 +0200764 !netlink_capable(skb, CAP_NET_ADMIN))
765 return -EPERM;
766
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700767 if ((op.flags & GENL_UNS_ADMIN_PERM) &&
Jiri Pirkobe064de2019-10-05 20:04:33 +0200768 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
769 return -EPERM;
770
771 if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
772 return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700773 &op, hdrlen, net);
Jiri Pirkobe064de2019-10-05 20:04:33 +0200774 else
775 return genl_family_rcv_msg_doit(family, skb, nlh, extack,
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700776 &op, hdrlen, net);
Jiri Pirkobe064de2019-10-05 20:04:33 +0200777}
778
Johannes Berg2d4bc932017-04-12 14:34:04 +0200779static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
780 struct netlink_ext_ack *extack)
Pravin B Shelardef31172013-04-23 07:48:30 +0000781{
Johannes Berg2ae0f172016-10-24 14:40:04 +0200782 const struct genl_family *family;
Pravin B Shelardef31172013-04-23 07:48:30 +0000783 int err;
784
785 family = genl_family_find_byid(nlh->nlmsg_type);
786 if (family == NULL)
787 return -ENOENT;
788
789 if (!family->parallel_ops)
790 genl_lock();
791
Johannes Berg7ab606d2017-04-12 14:34:05 +0200792 err = genl_family_rcv_msg(family, skb, nlh, extack);
Pravin B Shelardef31172013-04-23 07:48:30 +0000793
794 if (!family->parallel_ops)
795 genl_unlock();
796
Johannes Bergff4c92d2010-10-04 21:14:03 +0200797 return err;
Thomas Graf482a8522005-11-10 02:25:56 +0100798}
799
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -0700800static void genl_rcv(struct sk_buff *skb)
Thomas Graf482a8522005-11-10 02:25:56 +0100801{
Pravin B Shelardef31172013-04-23 07:48:30 +0000802 down_read(&cb_lock);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -0700803 netlink_rcv_skb(skb, &genl_rcv_msg);
Pravin B Shelardef31172013-04-23 07:48:30 +0000804 up_read(&cb_lock);
Thomas Graf482a8522005-11-10 02:25:56 +0100805}
806
807/**************************************************************************
808 * Controller
809 **************************************************************************/
810
Johannes Berg489111e2016-10-24 14:40:03 +0200811static struct genl_family genl_ctrl;
Thomas Graf17c157c2006-11-14 19:46:02 -0800812
Johannes Berg2ae0f172016-10-24 14:40:04 +0200813static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
Thomas Graf482a8522005-11-10 02:25:56 +0100814 u32 flags, struct sk_buff *skb, u8 cmd)
815{
816 void *hdr;
817
Eric W. Biederman15e47302012-09-07 20:12:54 +0000818 hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
Thomas Graf482a8522005-11-10 02:25:56 +0100819 if (hdr == NULL)
820 return -1;
821
David S. Miller444653f2012-03-29 23:25:11 -0400822 if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
823 nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) ||
824 nla_put_u32(skb, CTRL_ATTR_VERSION, family->version) ||
825 nla_put_u32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize) ||
826 nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
827 goto nla_put_failure;
Thomas Grafeb328112006-09-18 00:01:59 -0700828
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700829 if (genl_get_cmd_cnt(family)) {
Thomas Grafe94ef682006-11-23 11:44:37 -0800830 struct nlattr *nla_ops;
Johannes Bergd91824c2013-11-14 17:14:44 +0100831 int i;
Thomas Grafeb328112006-09-18 00:01:59 -0700832
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200833 nla_ops = nla_nest_start_noflag(skb, CTRL_ATTR_OPS);
Thomas Grafe94ef682006-11-23 11:44:37 -0800834 if (nla_ops == NULL)
Thomas Grafeb328112006-09-18 00:01:59 -0700835 goto nla_put_failure;
836
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700837 for (i = 0; i < genl_get_cmd_cnt(family); i++) {
Thomas Grafe94ef682006-11-23 11:44:37 -0800838 struct nlattr *nest;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700839 struct genl_ops op;
840 u32 op_flags;
Johannes Bergf84f7712013-11-14 17:14:45 +0100841
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700842 genl_get_cmd_by_index(i, family, &op);
843 op_flags = op.flags;
844 if (op.dumpit)
Johannes Berg029b2342013-11-18 20:54:58 +0100845 op_flags |= GENL_CMD_CAP_DUMP;
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700846 if (op.doit)
Johannes Berg029b2342013-11-18 20:54:58 +0100847 op_flags |= GENL_CMD_CAP_DO;
Jakub Kicinski48526a02020-10-02 14:49:57 -0700848 if (op.policy)
Johannes Berg029b2342013-11-18 20:54:58 +0100849 op_flags |= GENL_CMD_CAP_HASPOL;
Thomas Grafeb328112006-09-18 00:01:59 -0700850
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200851 nest = nla_nest_start_noflag(skb, i + 1);
Thomas Grafe94ef682006-11-23 11:44:37 -0800852 if (nest == NULL)
853 goto nla_put_failure;
Thomas Grafeb328112006-09-18 00:01:59 -0700854
Jakub Kicinski0b588afd2020-10-02 14:49:53 -0700855 if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) ||
Johannes Berg029b2342013-11-18 20:54:58 +0100856 nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
David S. Miller444653f2012-03-29 23:25:11 -0400857 goto nla_put_failure;
Thomas Grafeb328112006-09-18 00:01:59 -0700858
Thomas Grafe94ef682006-11-23 11:44:37 -0800859 nla_nest_end(skb, nest);
860 }
861
862 nla_nest_end(skb, nla_ops);
Thomas Grafeb328112006-09-18 00:01:59 -0700863 }
864
Johannes Berg2a94fe42013-11-19 15:19:39 +0100865 if (family->n_mcgrps) {
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700866 struct nlattr *nla_grps;
Johannes Berg2a94fe42013-11-19 15:19:39 +0100867 int i;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700868
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200869 nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700870 if (nla_grps == NULL)
871 goto nla_put_failure;
872
Johannes Berg2a94fe42013-11-19 15:19:39 +0100873 for (i = 0; i < family->n_mcgrps; i++) {
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700874 struct nlattr *nest;
Johannes Berg2a94fe42013-11-19 15:19:39 +0100875 const struct genl_multicast_group *grp;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700876
Johannes Berg2a94fe42013-11-19 15:19:39 +0100877 grp = &family->mcgrps[i];
878
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200879 nest = nla_nest_start_noflag(skb, i + 1);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700880 if (nest == NULL)
881 goto nla_put_failure;
882
Johannes Berg2a94fe42013-11-19 15:19:39 +0100883 if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID,
884 family->mcgrp_offset + i) ||
David S. Miller444653f2012-03-29 23:25:11 -0400885 nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
886 grp->name))
887 goto nla_put_failure;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700888
889 nla_nest_end(skb, nest);
890 }
891 nla_nest_end(skb, nla_grps);
892 }
893
Johannes Berg053c0952015-01-16 22:09:00 +0100894 genlmsg_end(skb, hdr);
895 return 0;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700896
897nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -0700898 genlmsg_cancel(skb, hdr);
899 return -EMSGSIZE;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700900}
901
Johannes Berg2ae0f172016-10-24 14:40:04 +0200902static int ctrl_fill_mcgrp_info(const struct genl_family *family,
Johannes Berg2a94fe42013-11-19 15:19:39 +0100903 const struct genl_multicast_group *grp,
904 int grp_id, u32 portid, u32 seq, u32 flags,
905 struct sk_buff *skb, u8 cmd)
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700906{
907 void *hdr;
908 struct nlattr *nla_grps;
909 struct nlattr *nest;
910
Eric W. Biederman15e47302012-09-07 20:12:54 +0000911 hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700912 if (hdr == NULL)
913 return -1;
914
Johannes Bergc2ebb902013-11-19 15:19:36 +0100915 if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
916 nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id))
David S. Miller444653f2012-03-29 23:25:11 -0400917 goto nla_put_failure;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700918
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200919 nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700920 if (nla_grps == NULL)
921 goto nla_put_failure;
922
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200923 nest = nla_nest_start_noflag(skb, 1);
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700924 if (nest == NULL)
925 goto nla_put_failure;
926
Johannes Berg2a94fe42013-11-19 15:19:39 +0100927 if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) ||
David S. Miller444653f2012-03-29 23:25:11 -0400928 nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
929 grp->name))
930 goto nla_put_failure;
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700931
932 nla_nest_end(skb, nest);
933 nla_nest_end(skb, nla_grps);
934
Johannes Berg053c0952015-01-16 22:09:00 +0100935 genlmsg_end(skb, hdr);
936 return 0;
Thomas Graf482a8522005-11-10 02:25:56 +0100937
938nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -0700939 genlmsg_cancel(skb, hdr);
940 return -EMSGSIZE;
Thomas Graf482a8522005-11-10 02:25:56 +0100941}
942
943static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
944{
Johannes Berg2ae0f172016-10-24 14:40:04 +0200945 int n = 0;
Thomas Graf482a8522005-11-10 02:25:56 +0100946 struct genl_family *rt;
Johannes Berg134e6372009-07-10 09:51:34 +0000947 struct net *net = sock_net(skb->sk);
Johannes Berg2ae0f172016-10-24 14:40:04 +0200948 int fams_to_skip = cb->args[0];
949 unsigned int id;
Thomas Graf482a8522005-11-10 02:25:56 +0100950
Johannes Berg2ae0f172016-10-24 14:40:04 +0200951 idr_for_each_entry(&genl_fam_idr, rt, id) {
952 if (!rt->netnsok && !net_eq(net, &init_net))
953 continue;
Thomas Graf482a8522005-11-10 02:25:56 +0100954
Johannes Berg2ae0f172016-10-24 14:40:04 +0200955 if (n++ < fams_to_skip)
956 continue;
957
958 if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
959 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Stanislaw Gruszka1d2a6a52017-03-22 16:08:33 +0100960 skb, CTRL_CMD_NEWFAMILY) < 0) {
961 n--;
Johannes Berg2ae0f172016-10-24 14:40:04 +0200962 break;
Stanislaw Gruszka1d2a6a52017-03-22 16:08:33 +0100963 }
Thomas Graf482a8522005-11-10 02:25:56 +0100964 }
965
Johannes Berg2ae0f172016-10-24 14:40:04 +0200966 cb->args[0] = n;
Thomas Graf482a8522005-11-10 02:25:56 +0100967 return skb->len;
968}
969
Johannes Berg2ae0f172016-10-24 14:40:04 +0200970static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000971 u32 portid, int seq, u8 cmd)
Thomas Graf482a8522005-11-10 02:25:56 +0100972{
973 struct sk_buff *skb;
974 int err;
975
Thomas Graf339bf982006-11-10 14:10:15 -0800976 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Thomas Graf482a8522005-11-10 02:25:56 +0100977 if (skb == NULL)
978 return ERR_PTR(-ENOBUFS);
979
Eric W. Biederman15e47302012-09-07 20:12:54 +0000980 err = ctrl_fill_info(family, portid, seq, 0, skb, cmd);
Thomas Graf482a8522005-11-10 02:25:56 +0100981 if (err < 0) {
982 nlmsg_free(skb);
983 return ERR_PTR(err);
984 }
985
986 return skb;
987}
988
Johannes Berg2a94fe42013-11-19 15:19:39 +0100989static struct sk_buff *
Johannes Berg2ae0f172016-10-24 14:40:04 +0200990ctrl_build_mcgrp_msg(const struct genl_family *family,
Johannes Berg2a94fe42013-11-19 15:19:39 +0100991 const struct genl_multicast_group *grp,
992 int grp_id, u32 portid, int seq, u8 cmd)
Johannes Berg2dbba6f2007-07-18 15:47:52 -0700993{
994 struct sk_buff *skb;
995 int err;
996
997 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
998 if (skb == NULL)
999 return ERR_PTR(-ENOBUFS);
1000
Johannes Berg2a94fe42013-11-19 15:19:39 +01001001 err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid,
1002 seq, 0, skb, cmd);
Johannes Berg2dbba6f2007-07-18 15:47:52 -07001003 if (err < 0) {
1004 nlmsg_free(skb);
1005 return ERR_PTR(err);
1006 }
1007
1008 return skb;
1009}
1010
Jakub Kicinskia4bb4f52020-10-02 14:50:00 -07001011static const struct nla_policy ctrl_policy_family[] = {
Thomas Graf482a8522005-11-10 02:25:56 +01001012 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
Thomas Graf5176f912006-08-26 20:13:18 -07001013 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
1014 .len = GENL_NAMSIZ - 1 },
Thomas Graf482a8522005-11-10 02:25:56 +01001015};
1016
1017static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
1018{
1019 struct sk_buff *msg;
Johannes Berg2ae0f172016-10-24 14:40:04 +02001020 const struct genl_family *res = NULL;
Thomas Graf482a8522005-11-10 02:25:56 +01001021 int err = -EINVAL;
1022
1023 if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
1024 u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
1025 res = genl_family_find_byid(id);
Johannes Berg134e6372009-07-10 09:51:34 +00001026 err = -ENOENT;
Thomas Graf482a8522005-11-10 02:25:56 +01001027 }
1028
1029 if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
Thomas Graf5176f912006-08-26 20:13:18 -07001030 char *name;
Thomas Graf482a8522005-11-10 02:25:56 +01001031
Thomas Graf5176f912006-08-26 20:13:18 -07001032 name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
Thomas Graf482a8522005-11-10 02:25:56 +01001033 res = genl_family_find_byname(name);
Stephen Hemmingerfa843092011-12-28 13:48:55 -05001034#ifdef CONFIG_MODULES
1035 if (res == NULL) {
1036 genl_unlock();
Stanislaw Gruszkac74f2b22013-07-26 11:00:10 +02001037 up_read(&cb_lock);
Neil Hormane9412c32012-05-29 09:30:41 +00001038 request_module("net-pf-%d-proto-%d-family-%s",
Stephen Hemmingerfa843092011-12-28 13:48:55 -05001039 PF_NETLINK, NETLINK_GENERIC, name);
Stanislaw Gruszkac74f2b22013-07-26 11:00:10 +02001040 down_read(&cb_lock);
Stephen Hemmingerfa843092011-12-28 13:48:55 -05001041 genl_lock();
1042 res = genl_family_find_byname(name);
1043 }
1044#endif
Johannes Berg134e6372009-07-10 09:51:34 +00001045 err = -ENOENT;
Thomas Graf482a8522005-11-10 02:25:56 +01001046 }
1047
Johannes Berg134e6372009-07-10 09:51:34 +00001048 if (res == NULL)
1049 return err;
1050
1051 if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) {
1052 /* family doesn't exist here */
1053 return -ENOENT;
Thomas Graf482a8522005-11-10 02:25:56 +01001054 }
1055
Eric W. Biederman15e47302012-09-07 20:12:54 +00001056 msg = ctrl_build_family_msg(res, info->snd_portid, info->snd_seq,
Johannes Berg2dbba6f2007-07-18 15:47:52 -07001057 CTRL_CMD_NEWFAMILY);
Johannes Berg134e6372009-07-10 09:51:34 +00001058 if (IS_ERR(msg))
1059 return PTR_ERR(msg);
Thomas Graf482a8522005-11-10 02:25:56 +01001060
Johannes Berg134e6372009-07-10 09:51:34 +00001061 return genlmsg_reply(msg, info);
Thomas Graf482a8522005-11-10 02:25:56 +01001062}
1063
Johannes Berg2ae0f172016-10-24 14:40:04 +02001064static int genl_ctrl_event(int event, const struct genl_family *family,
Johannes Berg2a94fe42013-11-19 15:19:39 +01001065 const struct genl_multicast_group *grp,
1066 int grp_id)
Thomas Graf482a8522005-11-10 02:25:56 +01001067{
1068 struct sk_buff *msg;
1069
Johannes Berg134e6372009-07-10 09:51:34 +00001070 /* genl is still initialising */
1071 if (!init_net.genl_sock)
Thomas Graf482a8522005-11-10 02:25:56 +01001072 return 0;
1073
1074 switch (event) {
1075 case CTRL_CMD_NEWFAMILY:
1076 case CTRL_CMD_DELFAMILY:
Johannes Bergc2ebb902013-11-19 15:19:36 +01001077 WARN_ON(grp);
Johannes Berg134e6372009-07-10 09:51:34 +00001078 msg = ctrl_build_family_msg(family, 0, 0, event);
Johannes Berg2dbba6f2007-07-18 15:47:52 -07001079 break;
1080 case CTRL_CMD_NEWMCAST_GRP:
1081 case CTRL_CMD_DELMCAST_GRP:
Johannes Bergc2ebb902013-11-19 15:19:36 +01001082 BUG_ON(!grp);
Johannes Berg2a94fe42013-11-19 15:19:39 +01001083 msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event);
Thomas Graf482a8522005-11-10 02:25:56 +01001084 break;
Johannes Berg134e6372009-07-10 09:51:34 +00001085 default:
1086 return -EINVAL;
1087 }
1088
1089 if (IS_ERR(msg))
1090 return PTR_ERR(msg);
1091
1092 if (!family->netnsok) {
Johannes Berg68eb5502013-11-19 15:19:38 +01001093 genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +01001094 0, GFP_KERNEL);
Johannes Berg134e6372009-07-10 09:51:34 +00001095 } else {
1096 rcu_read_lock();
Johannes Berg68eb5502013-11-19 15:19:38 +01001097 genlmsg_multicast_allns(&genl_ctrl, msg, 0,
Johannes Berg2a94fe42013-11-19 15:19:39 +01001098 0, GFP_ATOMIC);
Johannes Berg134e6372009-07-10 09:51:34 +00001099 rcu_read_unlock();
Thomas Graf482a8522005-11-10 02:25:56 +01001100 }
1101
1102 return 0;
1103}
1104
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001105struct ctrl_dump_policy_ctx {
1106 struct netlink_policy_dump_state *state;
Johannes Berg50a896cf2020-10-03 10:44:45 +02001107 const struct genl_family *rt;
1108 unsigned int opidx;
Jakub Kicinskie992a6e2020-10-03 10:44:46 +02001109 u32 op;
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001110 u16 fam_id;
Jakub Kicinskie992a6e2020-10-03 10:44:46 +02001111 u8 policies:1,
1112 single_op:1;
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001113};
1114
Jakub Kicinskia4bb4f52020-10-02 14:50:00 -07001115static const struct nla_policy ctrl_policy_policy[] = {
1116 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
1117 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
1118 .len = GENL_NAMSIZ - 1 },
Jakub Kicinskie992a6e2020-10-03 10:44:46 +02001119 [CTRL_ATTR_OP] = { .type = NLA_U32 },
Jakub Kicinskia4bb4f52020-10-02 14:50:00 -07001120};
1121
Jakub Kicinski78ade612020-10-02 14:49:56 -07001122static int ctrl_dumppolicy_start(struct netlink_callback *cb)
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001123{
Jakub Kicinski8e1ed282020-10-02 14:49:59 -07001124 const struct genl_dumpit_info *info = genl_dumpit_info(cb);
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001125 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
Jakub Kicinski8e1ed282020-10-02 14:49:59 -07001126 struct nlattr **tb = info->attrs;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001127 const struct genl_family *rt;
Johannes Berg50a896cf2020-10-03 10:44:45 +02001128 struct genl_ops op;
1129 int err, i;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001130
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001131 BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
1132
Jakub Kicinski78ade612020-10-02 14:49:56 -07001133 if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
1134 return -EINVAL;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001135
Jakub Kicinski78ade612020-10-02 14:49:56 -07001136 if (tb[CTRL_ATTR_FAMILY_ID]) {
1137 ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
1138 } else {
1139 rt = genl_family_find_byname(
1140 nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
1141 if (!rt)
1142 return -ENOENT;
1143 ctx->fam_id = rt->id;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001144 }
1145
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001146 rt = genl_family_find_byid(ctx->fam_id);
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001147 if (!rt)
1148 return -ENOENT;
1149
Johannes Berg50a896cf2020-10-03 10:44:45 +02001150 ctx->rt = rt;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001151
Jakub Kicinskie992a6e2020-10-03 10:44:46 +02001152 if (tb[CTRL_ATTR_OP]) {
1153 ctx->single_op = true;
1154 ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]);
1155
1156 err = genl_get_cmd(ctx->op, rt, &op);
1157 if (err) {
1158 NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
1159 return err;
1160 }
1161
1162 if (!op.policy)
1163 return -ENODATA;
1164
1165 return netlink_policy_dump_add_policy(&ctx->state, op.policy,
1166 op.maxattr);
1167 }
1168
Johannes Berg50a896cf2020-10-03 10:44:45 +02001169 for (i = 0; i < genl_get_cmd_cnt(rt); i++) {
1170 genl_get_cmd_by_index(i, rt, &op);
1171
1172 if (op.policy) {
1173 err = netlink_policy_dump_add_policy(&ctx->state,
1174 op.policy,
1175 op.maxattr);
1176 if (err)
1177 return err;
1178 }
1179 }
1180
1181 if (!ctx->state)
1182 return -ENODATA;
1183 return 0;
Jakub Kicinski78ade612020-10-02 14:49:56 -07001184}
1185
Johannes Bergaa85ee52020-10-03 10:44:44 +02001186static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
1187 struct netlink_callback *cb)
1188{
1189 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1190 void *hdr;
1191
1192 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1193 cb->nlh->nlmsg_seq, &genl_ctrl,
1194 NLM_F_MULTI, CTRL_CMD_GETPOLICY);
1195 if (!hdr)
1196 return NULL;
1197
1198 if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
1199 return NULL;
1200
1201 return hdr;
1202}
1203
Johannes Berg50a896cf2020-10-03 10:44:45 +02001204static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
1205 struct netlink_callback *cb,
1206 struct genl_ops *op)
1207{
1208 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1209 struct nlattr *nest_pol, *nest_op;
1210 void *hdr;
1211 int idx;
1212
1213 /* skip if we have nothing to show */
1214 if (!op->policy)
1215 return 0;
1216 if (!op->doit &&
1217 (!op->dumpit || op->validate & GENL_DONT_VALIDATE_DUMP))
1218 return 0;
1219
1220 hdr = ctrl_dumppolicy_prep(skb, cb);
1221 if (!hdr)
1222 return -ENOBUFS;
1223
1224 nest_pol = nla_nest_start(skb, CTRL_ATTR_OP_POLICY);
1225 if (!nest_pol)
1226 goto err;
1227
1228 nest_op = nla_nest_start(skb, op->cmd);
1229 if (!nest_op)
1230 goto err;
1231
1232 /* for now both do/dump are always the same */
1233 idx = netlink_policy_dump_get_policy_idx(ctx->state,
1234 op->policy,
1235 op->maxattr);
1236
1237 if (op->doit && nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx))
1238 goto err;
1239
1240 if (op->dumpit && !(op->validate & GENL_DONT_VALIDATE_DUMP) &&
1241 nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx))
1242 goto err;
1243
1244 nla_nest_end(skb, nest_op);
1245 nla_nest_end(skb, nest_pol);
1246 genlmsg_end(skb, hdr);
1247
1248 return 0;
1249err:
1250 genlmsg_cancel(skb, hdr);
1251 return -ENOBUFS;
1252}
1253
Jakub Kicinski78ade612020-10-02 14:49:56 -07001254static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
1255{
1256 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
Johannes Berg50a896cf2020-10-03 10:44:45 +02001257 void *hdr;
1258
1259 if (!ctx->policies) {
1260 while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) {
1261 struct genl_ops op;
1262
Jakub Kicinskie992a6e2020-10-03 10:44:46 +02001263 if (ctx->single_op) {
1264 int err;
1265
1266 err = genl_get_cmd(ctx->op, ctx->rt, &op);
1267 if (WARN_ON(err))
1268 return skb->len;
1269
1270 /* break out of the loop after this one */
1271 ctx->opidx = genl_get_cmd_cnt(ctx->rt);
1272 } else {
1273 genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op);
1274 }
Johannes Berg50a896cf2020-10-03 10:44:45 +02001275
1276 if (ctrl_dumppolicy_put_op(skb, cb, &op))
1277 return skb->len;
1278
1279 ctx->opidx++;
1280 }
1281
1282 /* completed with the per-op policy index list */
1283 ctx->policies = true;
1284 }
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001285
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001286 while (netlink_policy_dump_loop(ctx->state)) {
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001287 struct nlattr *nest;
1288
Johannes Bergaa85ee52020-10-03 10:44:44 +02001289 hdr = ctrl_dumppolicy_prep(skb, cb);
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001290 if (!hdr)
1291 goto nla_put_failure;
1292
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001293 nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
1294 if (!nest)
1295 goto nla_put_failure;
1296
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001297 if (netlink_policy_dump_write(skb, ctx->state))
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001298 goto nla_put_failure;
1299
1300 nla_nest_end(skb, nest);
1301
1302 genlmsg_end(skb, hdr);
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001303 }
1304
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001305 return skb->len;
Johannes Berg50a896cf2020-10-03 10:44:45 +02001306
1307nla_put_failure:
1308 genlmsg_cancel(skb, hdr);
1309 return skb->len;
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001310}
1311
Johannes Berg949ca6b2020-10-02 09:46:04 +02001312static int ctrl_dumppolicy_done(struct netlink_callback *cb)
1313{
Jakub Kicinskiadc84842020-10-02 14:49:55 -07001314 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1315
1316 netlink_policy_dump_free(ctx->state);
Johannes Berg949ca6b2020-10-02 09:46:04 +02001317 return 0;
1318}
1319
stephen hemminger12d8de62016-08-31 15:22:00 -07001320static const struct genl_ops genl_ctrl_ops[] = {
Johannes Bergc53ed742013-11-19 15:19:31 +01001321 {
1322 .cmd = CTRL_CMD_GETFAMILY,
Johannes Bergef6243a2019-04-26 14:07:31 +02001323 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Jakub Kicinskia4bb4f52020-10-02 14:50:00 -07001324 .policy = ctrl_policy_family,
1325 .maxattr = ARRAY_SIZE(ctrl_policy_family) - 1,
Johannes Bergc53ed742013-11-19 15:19:31 +01001326 .doit = ctrl_getfamily,
1327 .dumpit = ctrl_dumpfamily,
Johannes Bergc53ed742013-11-19 15:19:31 +01001328 },
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001329 {
1330 .cmd = CTRL_CMD_GETPOLICY,
Jakub Kicinskia4bb4f52020-10-02 14:50:00 -07001331 .policy = ctrl_policy_policy,
1332 .maxattr = ARRAY_SIZE(ctrl_policy_policy) - 1,
Jakub Kicinski78ade612020-10-02 14:49:56 -07001333 .start = ctrl_dumppolicy_start,
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001334 .dumpit = ctrl_dumppolicy,
Johannes Berg949ca6b2020-10-02 09:46:04 +02001335 .done = ctrl_dumppolicy_done,
Johannes Bergd07dcf9a2020-04-30 22:13:12 +02001336 },
Thomas Graf482a8522005-11-10 02:25:56 +01001337};
1338
stephen hemminger12d8de62016-08-31 15:22:00 -07001339static const struct genl_multicast_group genl_ctrl_groups[] = {
Johannes Berg2a94fe42013-11-19 15:19:39 +01001340 { .name = "notify", },
Johannes Berg2dbba6f2007-07-18 15:47:52 -07001341};
1342
Johannes Berg56989f62016-10-24 14:40:05 +02001343static struct genl_family genl_ctrl __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +02001344 .module = THIS_MODULE,
1345 .ops = genl_ctrl_ops,
1346 .n_ops = ARRAY_SIZE(genl_ctrl_ops),
1347 .mcgrps = genl_ctrl_groups,
1348 .n_mcgrps = ARRAY_SIZE(genl_ctrl_groups),
1349 .id = GENL_ID_CTRL,
1350 .name = "nlctrl",
1351 .version = 0x2,
Johannes Berg489111e2016-10-24 14:40:03 +02001352 .netnsok = true,
1353};
1354
Florian Westphal4d54cc32021-02-12 15:59:59 -08001355static int genl_bind(struct net *net, int group)
1356{
1357 const struct genl_family *family;
1358 unsigned int id;
1359 int ret = 0;
1360
1361 genl_lock_all();
1362
1363 idr_for_each_entry(&genl_fam_idr, family, id) {
1364 const struct genl_multicast_group *grp;
1365 int i;
1366
1367 if (family->n_mcgrps == 0)
1368 continue;
1369
1370 i = group - family->mcgrp_offset;
1371 if (i < 0 || i >= family->n_mcgrps)
1372 continue;
1373
1374 grp = &family->mcgrps[i];
1375 if ((grp->flags & GENL_UNS_ADMIN_PERM) &&
1376 !ns_capable(net->user_ns, CAP_NET_ADMIN))
1377 ret = -EPERM;
1378
1379 break;
1380 }
1381
1382 genl_unlock_all();
1383 return ret;
1384}
1385
Johannes Berg134e6372009-07-10 09:51:34 +00001386static int __net_init genl_pernet_init(struct net *net)
1387{
Pablo Neira Ayusoa31f2d12012-06-29 06:15:21 +00001388 struct netlink_kernel_cfg cfg = {
1389 .input = genl_rcv,
Pablo Neira Ayuso9785e102012-09-08 02:53:53 +00001390 .flags = NL_CFG_F_NONROOT_RECV,
Florian Westphal4d54cc32021-02-12 15:59:59 -08001391 .bind = genl_bind,
Pablo Neira Ayusoa31f2d12012-06-29 06:15:21 +00001392 };
1393
Johannes Berg134e6372009-07-10 09:51:34 +00001394 /* we'll bump the group number right afterwards */
Pablo Neira Ayuso9f00d972012-09-08 02:53:54 +00001395 net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg);
Johannes Berg134e6372009-07-10 09:51:34 +00001396
1397 if (!net->genl_sock && net_eq(net, &init_net))
1398 panic("GENL: Cannot initialize generic netlink\n");
1399
1400 if (!net->genl_sock)
1401 return -ENOMEM;
1402
1403 return 0;
1404}
1405
1406static void __net_exit genl_pernet_exit(struct net *net)
1407{
1408 netlink_kernel_release(net->genl_sock);
1409 net->genl_sock = NULL;
1410}
1411
1412static struct pernet_operations genl_pernet_ops = {
1413 .init = genl_pernet_init,
1414 .exit = genl_pernet_exit,
1415};
1416
Thomas Graf482a8522005-11-10 02:25:56 +01001417static int __init genl_init(void)
1418{
Johannes Berg2ae0f172016-10-24 14:40:04 +02001419 int err;
Thomas Graf482a8522005-11-10 02:25:56 +01001420
Johannes Berg489111e2016-10-24 14:40:03 +02001421 err = genl_register_family(&genl_ctrl);
Thomas Graf482a8522005-11-10 02:25:56 +01001422 if (err < 0)
Johannes Berg134e6372009-07-10 09:51:34 +00001423 goto problem;
Thomas Graf482a8522005-11-10 02:25:56 +01001424
Johannes Berg134e6372009-07-10 09:51:34 +00001425 err = register_pernet_subsys(&genl_pernet_ops);
1426 if (err)
1427 goto problem;
Thomas Graf482a8522005-11-10 02:25:56 +01001428
1429 return 0;
1430
Johannes Berg134e6372009-07-10 09:51:34 +00001431problem:
Thomas Graf482a8522005-11-10 02:25:56 +01001432 panic("GENL: Cannot register controller: %d\n", err);
Thomas Graf482a8522005-11-10 02:25:56 +01001433}
1434
Daniel Lezcanoc62e7ac2020-07-15 09:41:18 +02001435core_initcall(genl_init);
Thomas Graf482a8522005-11-10 02:25:56 +01001436
Eric W. Biederman15e47302012-09-07 20:12:54 +00001437static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
Johannes Berg134e6372009-07-10 09:51:34 +00001438 gfp_t flags)
1439{
1440 struct sk_buff *tmp;
1441 struct net *net, *prev = NULL;
Nicolas Dichtelcb9f7a92018-02-06 14:48:32 +01001442 bool delivered = false;
Johannes Berg134e6372009-07-10 09:51:34 +00001443 int err;
1444
1445 for_each_net_rcu(net) {
1446 if (prev) {
1447 tmp = skb_clone(skb, flags);
1448 if (!tmp) {
1449 err = -ENOMEM;
1450 goto error;
1451 }
1452 err = nlmsg_multicast(prev->genl_sock, tmp,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001453 portid, group, flags);
Nicolas Dichtelcb9f7a92018-02-06 14:48:32 +01001454 if (!err)
1455 delivered = true;
1456 else if (err != -ESRCH)
Johannes Berg134e6372009-07-10 09:51:34 +00001457 goto error;
1458 }
1459
1460 prev = net;
1461 }
1462
Nicolas Dichtelcb9f7a92018-02-06 14:48:32 +01001463 err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
1464 if (!err)
1465 delivered = true;
1466 else if (err != -ESRCH)
Nicolas Dichtel02a23852018-03-14 21:10:23 +01001467 return err;
Nicolas Dichtelcb9f7a92018-02-06 14:48:32 +01001468 return delivered ? 0 : -ESRCH;
Johannes Berg134e6372009-07-10 09:51:34 +00001469 error:
1470 kfree_skb(skb);
1471 return err;
1472}
1473
Johannes Berg2ae0f172016-10-24 14:40:04 +02001474int genlmsg_multicast_allns(const struct genl_family *family,
1475 struct sk_buff *skb, u32 portid,
1476 unsigned int group, gfp_t flags)
Johannes Berg134e6372009-07-10 09:51:34 +00001477{
Johannes Berg220815a2013-11-21 18:17:04 +01001478 if (WARN_ON_ONCE(group >= family->n_mcgrps))
Johannes Berg2a94fe42013-11-19 15:19:39 +01001479 return -EINVAL;
Yajun Dengf9b282b2021-07-27 11:41:41 +08001480
Johannes Berg2a94fe42013-11-19 15:19:39 +01001481 group = family->mcgrp_offset + group;
Eric W. Biederman15e47302012-09-07 20:12:54 +00001482 return genlmsg_mcast(skb, portid, group, flags);
Johannes Berg134e6372009-07-10 09:51:34 +00001483}
1484EXPORT_SYMBOL(genlmsg_multicast_allns);
Pravin B Shelar263ba612011-11-10 19:14:37 -08001485
Johannes Berg2ae0f172016-10-24 14:40:04 +02001486void genl_notify(const struct genl_family *family, struct sk_buff *skb,
Jiri Benc92c14d92015-09-22 18:56:43 +02001487 struct genl_info *info, u32 group, gfp_t flags)
Pravin B Shelar263ba612011-11-10 19:14:37 -08001488{
Jiri Benc92c14d92015-09-22 18:56:43 +02001489 struct net *net = genl_info_net(info);
Pravin B Shelar263ba612011-11-10 19:14:37 -08001490 struct sock *sk = net->genl_sock;
Pravin B Shelar263ba612011-11-10 19:14:37 -08001491
Johannes Berg220815a2013-11-21 18:17:04 +01001492 if (WARN_ON_ONCE(group >= family->n_mcgrps))
Johannes Berg2a94fe42013-11-19 15:19:39 +01001493 return;
Yajun Dengf9b282b2021-07-27 11:41:41 +08001494
Johannes Berg2a94fe42013-11-19 15:19:39 +01001495 group = family->mcgrp_offset + group;
Yajun Dengf9b282b2021-07-27 11:41:41 +08001496 nlmsg_notify(sk, skb, info->snd_portid, group,
1497 nlmsg_report(info->nlhdr), flags);
Pravin B Shelar263ba612011-11-10 19:14:37 -08001498}
1499EXPORT_SYMBOL(genl_notify);