Blame view

net/netlink/genetlink.c 33.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
482a8524f   Thomas Graf   [NETLINK]: Generi...
2
3
4
5
6
  /*
   * NETLINK      Generic Netlink Family
   *
   * 		Authors:	Jamal Hadi Salim
   * 				Thomas Graf <tgraf@suug.ch>
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
7
   *				Johannes Berg <johannes@sipsolutions.net>
482a8524f   Thomas Graf   [NETLINK]: Generi...
8
   */
482a8524f   Thomas Graf   [NETLINK]: Generi...
9
10
  #include <linux/module.h>
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
482a8524f   Thomas Graf   [NETLINK]: Generi...
12
13
14
15
16
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/string.h>
  #include <linux/skbuff.h>
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
17
  #include <linux/mutex.h>
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
18
  #include <linux/bitmap.h>
def311749   Pravin B Shelar   genl: Allow concu...
19
  #include <linux/rwsem.h>
2ae0f17df   Johannes Berg   genetlink: use id...
20
  #include <linux/idr.h>
482a8524f   Thomas Graf   [NETLINK]: Generi...
21
22
  #include <net/sock.h>
  #include <net/genetlink.h>
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
23
  static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
def311749   Pravin B Shelar   genl: Allow concu...
24
  static DECLARE_RWSEM(cb_lock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
25

ee1c24421   Johannes Berg   genetlink: synchr...
26
27
  atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0);
  DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq);
f408e0ce4   James Chapman   netlink: Export g...
28
  void genl_lock(void)
482a8524f   Thomas Graf   [NETLINK]: Generi...
29
  {
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
30
  	mutex_lock(&genl_mutex);
482a8524f   Thomas Graf   [NETLINK]: Generi...
31
  }
f408e0ce4   James Chapman   netlink: Export g...
32
  EXPORT_SYMBOL(genl_lock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
33

f408e0ce4   James Chapman   netlink: Export g...
34
  void genl_unlock(void)
482a8524f   Thomas Graf   [NETLINK]: Generi...
35
  {
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
36
  	mutex_unlock(&genl_mutex);
482a8524f   Thomas Graf   [NETLINK]: Generi...
37
  }
f408e0ce4   James Chapman   netlink: Export g...
38
  EXPORT_SYMBOL(genl_unlock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
39

def311749   Pravin B Shelar   genl: Allow concu...
40
41
42
43
44
45
46
47
48
49
50
  static void genl_lock_all(void)
  {
  	down_write(&cb_lock);
  	genl_lock();
  }
  
  static void genl_unlock_all(void)
  {
  	genl_unlock();
  	up_write(&cb_lock);
  }
2ae0f17df   Johannes Berg   genetlink: use id...
51
  static DEFINE_IDR(genl_fam_idr);
482a8524f   Thomas Graf   [NETLINK]: Generi...
52

2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
53
54
55
56
57
58
  /*
   * Bitmap of multicast groups that are currently in use.
   *
   * To avoid an allocation at boot of just one unsigned long,
   * declare it global instead.
   * Bit 0 is marked as already used since group 0 is invalid.
e5dcecba0   Johannes Berg   drop_monitor/gene...
59
60
61
62
   * Bit 1 is marked as already used since the drop-monitor code
   * abuses the API and thinks it can statically use group 1.
   * That group will typically conflict with other groups that
   * any proper users use.
2a94fe48f   Johannes Berg   genetlink: make m...
63
64
   * Bit 16 is marked as used since it's used for generic netlink
   * and the code no longer marks pre-reserved IDs as used.
2ecf7536b   Johannes Berg   quota/genetlink: ...
65
66
67
   * Bit 17 is marked as already used since the VFS quota code
   * also abused this API and relied on family == group ID, we
   * cater to that by giving it a static family and group ID.
5e53e689b   Johannes Berg   genetlink/pmcraid...
68
69
   * Bit 18 is marked as already used since the PMCRAID driver
   * did the same thing as the VFS quota code (maybe copied?)
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
70
   */
2a94fe48f   Johannes Berg   genetlink: make m...
71
  static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
5e53e689b   Johannes Berg   genetlink/pmcraid...
72
73
  				      BIT(GENL_ID_VFS_DQUOT) |
  				      BIT(GENL_ID_PMCRAID);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
74
75
  static unsigned long *mc_groups = &mc_group_start;
  static unsigned long mc_groups_longs = 1;
482a8524f   Thomas Graf   [NETLINK]: Generi...
76

2ae0f17df   Johannes Berg   genetlink: use id...
77
  static int genl_ctrl_event(int event, const struct genl_family *family,
2a94fe48f   Johannes Berg   genetlink: make m...
78
79
  			   const struct genl_multicast_group *grp,
  			   int grp_id);
482a8524f   Thomas Graf   [NETLINK]: Generi...
80

2ae0f17df   Johannes Berg   genetlink: use id...
81
  static const struct genl_family *genl_family_find_byid(unsigned int id)
482a8524f   Thomas Graf   [NETLINK]: Generi...
82
  {
2ae0f17df   Johannes Berg   genetlink: use id...
83
  	return idr_find(&genl_fam_idr, id);
482a8524f   Thomas Graf   [NETLINK]: Generi...
84
  }
2ae0f17df   Johannes Berg   genetlink: use id...
85
  static const struct genl_family *genl_family_find_byname(char *name)
482a8524f   Thomas Graf   [NETLINK]: Generi...
86
  {
2ae0f17df   Johannes Berg   genetlink: use id...
87
88
  	const struct genl_family *family;
  	unsigned int id;
482a8524f   Thomas Graf   [NETLINK]: Generi...
89

2ae0f17df   Johannes Berg   genetlink: use id...
90
91
92
  	idr_for_each_entry(&genl_fam_idr, family, id)
  		if (strcmp(family->name, name) == 0)
  			return family;
482a8524f   Thomas Graf   [NETLINK]: Generi...
93
94
95
  
  	return NULL;
  }
0b588afdd   Jakub Kicinski   genetlink: add sm...
96
97
98
99
100
101
102
103
104
  static int genl_get_cmd_cnt(const struct genl_family *family)
  {
  	return family->n_ops + family->n_small_ops;
  }
  
  static void genl_op_from_full(const struct genl_family *family,
  			      unsigned int i, struct genl_ops *op)
  {
  	*op = family->ops[i];
48526a0f4   Jakub Kicinski   genetlink: bring ...
105
106
107
108
109
  
  	if (!op->maxattr)
  		op->maxattr = family->maxattr;
  	if (!op->policy)
  		op->policy = family->policy;
0b588afdd   Jakub Kicinski   genetlink: add sm...
110
  }
e992a6eda   Jakub Kicinski   genetlink: allow ...
111
  static int genl_get_cmd_full(u32 cmd, const struct genl_family *family,
0b588afdd   Jakub Kicinski   genetlink: add sm...
112
  			     struct genl_ops *op)
482a8524f   Thomas Graf   [NETLINK]: Generi...
113
  {
d91824c08   Johannes Berg   genetlink: regist...
114
  	int i;
482a8524f   Thomas Graf   [NETLINK]: Generi...
115

d91824c08   Johannes Berg   genetlink: regist...
116
  	for (i = 0; i < family->n_ops; i++)
0b588afdd   Jakub Kicinski   genetlink: add sm...
117
118
119
120
  		if (family->ops[i].cmd == cmd) {
  			genl_op_from_full(family, i, op);
  			return 0;
  		}
482a8524f   Thomas Graf   [NETLINK]: Generi...
121

0b588afdd   Jakub Kicinski   genetlink: add sm...
122
123
124
125
126
127
128
129
130
131
132
133
134
  	return -ENOENT;
  }
  
  static void genl_op_from_small(const struct genl_family *family,
  			       unsigned int i, struct genl_ops *op)
  {
  	memset(op, 0, sizeof(*op));
  	op->doit	= family->small_ops[i].doit;
  	op->dumpit	= family->small_ops[i].dumpit;
  	op->cmd		= family->small_ops[i].cmd;
  	op->internal_flags = family->small_ops[i].internal_flags;
  	op->flags	= family->small_ops[i].flags;
  	op->validate	= family->small_ops[i].validate;
48526a0f4   Jakub Kicinski   genetlink: bring ...
135
136
137
  
  	op->maxattr = family->maxattr;
  	op->policy = family->policy;
0b588afdd   Jakub Kicinski   genetlink: add sm...
138
  }
e992a6eda   Jakub Kicinski   genetlink: allow ...
139
  static int genl_get_cmd_small(u32 cmd, const struct genl_family *family,
0b588afdd   Jakub Kicinski   genetlink: add sm...
140
141
142
143
144
145
146
147
148
149
150
151
  			      struct genl_ops *op)
  {
  	int i;
  
  	for (i = 0; i < family->n_small_ops; i++)
  		if (family->small_ops[i].cmd == cmd) {
  			genl_op_from_small(family, i, op);
  			return 0;
  		}
  
  	return -ENOENT;
  }
e992a6eda   Jakub Kicinski   genetlink: allow ...
152
  static int genl_get_cmd(u32 cmd, const struct genl_family *family,
0b588afdd   Jakub Kicinski   genetlink: add sm...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  			struct genl_ops *op)
  {
  	if (!genl_get_cmd_full(cmd, family, op))
  		return 0;
  	return genl_get_cmd_small(cmd, family, op);
  }
  
  static void genl_get_cmd_by_index(unsigned int i,
  				  const struct genl_family *family,
  				  struct genl_ops *op)
  {
  	if (i < family->n_ops)
  		genl_op_from_full(family, i, op);
  	else if (i < family->n_ops + family->n_small_ops)
  		genl_op_from_small(family, i - family->n_ops, op);
  	else
  		WARN_ON_ONCE(1);
482a8524f   Thomas Graf   [NETLINK]: Generi...
170
  }
2a94fe48f   Johannes Berg   genetlink: make m...
171
  static int genl_allocate_reserve_groups(int n_groups, int *first_id)
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
172
  {
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
173
  	unsigned long *new_groups;
2a94fe48f   Johannes Berg   genetlink: make m...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	int start = 0;
  	int i;
  	int id;
  	bool fits;
  
  	do {
  		if (start == 0)
  			id = find_first_zero_bit(mc_groups,
  						 mc_groups_longs *
  						 BITS_PER_LONG);
  		else
  			id = find_next_zero_bit(mc_groups,
  						mc_groups_longs * BITS_PER_LONG,
  						start);
  
  		fits = true;
  		for (i = id;
  		     i < min_t(int, id + n_groups,
  			       mc_groups_longs * BITS_PER_LONG);
  		     i++) {
  			if (test_bit(i, mc_groups)) {
  				start = i;
  				fits = false;
  				break;
  			}
  		}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
200

b8e429a2f   David S. Miller   genetlink: Fix of...
201
  		if (id + n_groups > mc_groups_longs * BITS_PER_LONG) {
2a94fe48f   Johannes Berg   genetlink: make m...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  			unsigned long new_longs = mc_groups_longs +
  						  BITS_TO_LONGS(n_groups);
  			size_t nlen = new_longs * sizeof(unsigned long);
  
  			if (mc_groups == &mc_group_start) {
  				new_groups = kzalloc(nlen, GFP_KERNEL);
  				if (!new_groups)
  					return -ENOMEM;
  				mc_groups = new_groups;
  				*mc_groups = mc_group_start;
  			} else {
  				new_groups = krealloc(mc_groups, nlen,
  						      GFP_KERNEL);
  				if (!new_groups)
  					return -ENOMEM;
  				mc_groups = new_groups;
  				for (i = 0; i < BITS_TO_LONGS(n_groups); i++)
  					mc_groups[mc_groups_longs + i] = 0;
  			}
  			mc_groups_longs = new_longs;
  		}
  	} while (!fits);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
224

2a94fe48f   Johannes Berg   genetlink: make m...
225
226
227
228
229
230
231
232
233
234
235
236
  	for (i = id; i < id + n_groups; i++)
  		set_bit(i, mc_groups);
  	*first_id = id;
  	return 0;
  }
  
  static struct genl_family genl_ctrl;
  
  static int genl_validate_assign_mc_groups(struct genl_family *family)
  {
  	int first_id;
  	int n_groups = family->n_mcgrps;
0f0e2159c   Geert Uytterhoeven   genetlink: Fix un...
237
  	int err = 0, i;
2a94fe48f   Johannes Berg   genetlink: make m...
238
239
240
241
242
243
244
245
246
247
248
249
250
  	bool groups_allocated = false;
  
  	if (!n_groups)
  		return 0;
  
  	for (i = 0; i < n_groups; i++) {
  		const struct genl_multicast_group *grp = &family->mcgrps[i];
  
  		if (WARN_ON(grp->name[0] == '\0'))
  			return -EINVAL;
  		if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL))
  			return -EINVAL;
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
251

e5dcecba0   Johannes Berg   drop_monitor/gene...
252
  	/* special-case our own group and hacks */
2a94fe48f   Johannes Berg   genetlink: make m...
253
254
255
256
257
258
  	if (family == &genl_ctrl) {
  		first_id = GENL_ID_CTRL;
  		BUG_ON(n_groups != 1);
  	} else if (strcmp(family->name, "NET_DM") == 0) {
  		first_id = 1;
  		BUG_ON(n_groups != 1);
5e53e689b   Johannes Berg   genetlink/pmcraid...
259
  	} else if (family->id == GENL_ID_VFS_DQUOT) {
2a94fe48f   Johannes Berg   genetlink: make m...
260
261
  		first_id = GENL_ID_VFS_DQUOT;
  		BUG_ON(n_groups != 1);
5e53e689b   Johannes Berg   genetlink/pmcraid...
262
263
264
  	} else if (family->id == GENL_ID_PMCRAID) {
  		first_id = GENL_ID_PMCRAID;
  		BUG_ON(n_groups != 1);
2a94fe48f   Johannes Berg   genetlink: make m...
265
266
267
268
269
  	} else {
  		groups_allocated = true;
  		err = genl_allocate_reserve_groups(n_groups, &first_id);
  		if (err)
  			return err;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
270
  	}
2a94fe48f   Johannes Berg   genetlink: make m...
271
  	family->mcgrp_offset = first_id;
854059188   Randy Dunlap   net: netlink: del...
272
  	/* if still initializing, can't and don't need to realloc bitmaps */
2a94fe48f   Johannes Berg   genetlink: make m...
273
274
  	if (!init_net.genl_sock)
  		return 0;
134e63756   Johannes Berg   genetlink: make n...
275
276
  	if (family->netnsok) {
  		struct net *net;
d136f1bd3   Johannes Berg   genetlink: fix ne...
277
  		netlink_table_grab();
134e63756   Johannes Berg   genetlink: make n...
278
279
  		rcu_read_lock();
  		for_each_net_rcu(net) {
d136f1bd3   Johannes Berg   genetlink: fix ne...
280
  			err = __netlink_change_ngroups(net->genl_sock,
134e63756   Johannes Berg   genetlink: make n...
281
282
283
284
285
286
287
288
  					mc_groups_longs * BITS_PER_LONG);
  			if (err) {
  				/*
  				 * No need to roll back, can only fail if
  				 * memory allocation fails and then the
  				 * number of _possible_ groups has been
  				 * increased on some sockets which is ok.
  				 */
2a94fe48f   Johannes Berg   genetlink: make m...
289
  				break;
134e63756   Johannes Berg   genetlink: make n...
290
291
292
  			}
  		}
  		rcu_read_unlock();
d136f1bd3   Johannes Berg   genetlink: fix ne...
293
  		netlink_table_ungrab();
134e63756   Johannes Berg   genetlink: make n...
294
295
296
  	} else {
  		err = netlink_change_ngroups(init_net.genl_sock,
  					     mc_groups_longs * BITS_PER_LONG);
134e63756   Johannes Berg   genetlink: make n...
297
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
298

2a94fe48f   Johannes Berg   genetlink: make m...
299
300
301
302
  	if (groups_allocated && err) {
  		for (i = 0; i < family->n_mcgrps; i++)
  			clear_bit(family->mcgrp_offset + i, mc_groups);
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
303

79d310d01   Thomas Graf   [GENETLINK]: Corr...
304
  	return err;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
305
  }
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
306

2ae0f17df   Johannes Berg   genetlink: use id...
307
  static void genl_unregister_mc_groups(const struct genl_family *family)
79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
308
  {
134e63756   Johannes Berg   genetlink: make n...
309
  	struct net *net;
2a94fe48f   Johannes Berg   genetlink: make m...
310
  	int i;
134e63756   Johannes Berg   genetlink: make n...
311

b8273570f   Johannes Berg   genetlink: fix ne...
312
  	netlink_table_grab();
134e63756   Johannes Berg   genetlink: make n...
313
  	rcu_read_lock();
2a94fe48f   Johannes Berg   genetlink: make m...
314
315
316
317
318
  	for_each_net_rcu(net) {
  		for (i = 0; i < family->n_mcgrps; i++)
  			__netlink_clear_multicast_users(
  				net->genl_sock, family->mcgrp_offset + i);
  	}
134e63756   Johannes Berg   genetlink: make n...
319
  	rcu_read_unlock();
b8273570f   Johannes Berg   genetlink: fix ne...
320
  	netlink_table_ungrab();
134e63756   Johannes Berg   genetlink: make n...
321

2a94fe48f   Johannes Berg   genetlink: make m...
322
323
  	for (i = 0; i < family->n_mcgrps; i++) {
  		int grp_id = family->mcgrp_offset + i;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
324

2a94fe48f   Johannes Berg   genetlink: make m...
325
326
327
328
329
  		if (grp_id != 1)
  			clear_bit(grp_id, mc_groups);
  		genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family,
  				&family->mcgrps[i], grp_id);
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
330
  }
2f91abd45   Denis ChengRq   genetlink: remove...
331
  static int genl_validate_ops(const struct genl_family *family)
482a8524f   Thomas Graf   [NETLINK]: Generi...
332
  {
d91824c08   Johannes Berg   genetlink: regist...
333
  	int i, j;
0b588afdd   Jakub Kicinski   genetlink: add sm...
334
335
  	if (WARN_ON(family->n_ops && !family->ops) ||
  	    WARN_ON(family->n_small_ops && !family->small_ops))
568508aa0   Johannes Berg   genetlink: unify ...
336
  		return -EINVAL;
0b588afdd   Jakub Kicinski   genetlink: add sm...
337
338
  	for (i = 0; i < genl_get_cmd_cnt(family); i++) {
  		struct genl_ops op;
568508aa0   Johannes Berg   genetlink: unify ...
339

0b588afdd   Jakub Kicinski   genetlink: add sm...
340
341
  		genl_get_cmd_by_index(i, family, &op);
  		if (op.dumpit == NULL && op.doit == NULL)
d91824c08   Johannes Berg   genetlink: regist...
342
  			return -EINVAL;
0b588afdd   Jakub Kicinski   genetlink: add sm...
343
344
345
346
347
  		for (j = i + 1; j < genl_get_cmd_cnt(family); j++) {
  			struct genl_ops op2;
  
  			genl_get_cmd_by_index(j, family, &op2);
  			if (op.cmd == op2.cmd)
d91824c08   Johannes Berg   genetlink: regist...
348
  				return -EINVAL;
0b588afdd   Jakub Kicinski   genetlink: add sm...
349
  		}
482a8524f   Thomas Graf   [NETLINK]: Generi...
350
  	}
d91824c08   Johannes Berg   genetlink: regist...
351
  	return 0;
482a8524f   Thomas Graf   [NETLINK]: Generi...
352
  }
482a8524f   Thomas Graf   [NETLINK]: Generi...
353
354
  
  /**
489111e5c   Johannes Berg   genetlink: static...
355
   * genl_register_family - register a generic netlink family
482a8524f   Thomas Graf   [NETLINK]: Generi...
356
357
358
359
   * @family: generic netlink family
   *
   * Registers the specified family after validating it first. Only one
   * family may be registered with the same family name or identifier.
482a8524f   Thomas Graf   [NETLINK]: Generi...
360
   *
489111e5c   Johannes Berg   genetlink: static...
361
362
   * The family's ops, multicast groups and module pointer must already
   * be assigned.
568508aa0   Johannes Berg   genetlink: unify ...
363
   *
482a8524f   Thomas Graf   [NETLINK]: Generi...
364
365
   * Return 0 on success or a negative error code.
   */
489111e5c   Johannes Berg   genetlink: static...
366
  int genl_register_family(struct genl_family *family)
482a8524f   Thomas Graf   [NETLINK]: Generi...
367
  {
a07ea4d99   Johannes Berg   genetlink: no lon...
368
  	int err, i;
2ae0f17df   Johannes Berg   genetlink: use id...
369
  	int start = GENL_START_ALLOC, end = GENL_MAX_ID;
482a8524f   Thomas Graf   [NETLINK]: Generi...
370

568508aa0   Johannes Berg   genetlink: unify ...
371
372
373
  	err = genl_validate_ops(family);
  	if (err)
  		return err;
def311749   Pravin B Shelar   genl: Allow concu...
374
  	genl_lock_all();
482a8524f   Thomas Graf   [NETLINK]: Generi...
375
376
377
378
379
  
  	if (genl_family_find_byname(family->name)) {
  		err = -EEXIST;
  		goto errout_locked;
  	}
2ae0f17df   Johannes Berg   genetlink: use id...
380
381
382
383
384
385
386
  	/*
  	 * Sadly, a few cases need to be special-cased
  	 * due to them having previously abused the API
  	 * and having used their family ID also as their
  	 * multicast group ID, so we use reserved IDs
  	 * for both to be sure we can do that mapping.
  	 */
a07ea4d99   Johannes Berg   genetlink: no lon...
387
  	if (family == &genl_ctrl) {
2ae0f17df   Johannes Berg   genetlink: use id...
388
389
390
391
392
393
  		/* and this needs to be special for initial family lookups */
  		start = end = GENL_ID_CTRL;
  	} else if (strcmp(family->name, "pmcraid") == 0) {
  		start = end = GENL_ID_PMCRAID;
  	} else if (strcmp(family->name, "VFS_DQUOT") == 0) {
  		start = end = GENL_ID_VFS_DQUOT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
394
  	}
4e43df38a   Marcel Holtmann   genetlink: use id...
395
396
  	family->id = idr_alloc_cyclic(&genl_fam_idr, family,
  				      start, end + 1, GFP_KERNEL);
22ca904ad   Wei Yongjun   genetlink: fix er...
397
398
  	if (family->id < 0) {
  		err = family->id;
bf64ff4c2   Cong Wang   genetlink: get ri...
399
  		goto errout_locked;
22ca904ad   Wei Yongjun   genetlink: fix er...
400
  	}
2ae0f17df   Johannes Berg   genetlink: use id...
401

2a94fe48f   Johannes Berg   genetlink: make m...
402
403
  	err = genl_validate_assign_mc_groups(family);
  	if (err)
2ae0f17df   Johannes Berg   genetlink: use id...
404
  		goto errout_remove;
2a94fe48f   Johannes Berg   genetlink: make m...
405

def311749   Pravin B Shelar   genl: Allow concu...
406
  	genl_unlock_all();
482a8524f   Thomas Graf   [NETLINK]: Generi...
407

2a94fe48f   Johannes Berg   genetlink: make m...
408
409
410
411
412
  	/* send all events */
  	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0);
  	for (i = 0; i < family->n_mcgrps; i++)
  		genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family,
  				&family->mcgrps[i], family->mcgrp_offset + i);
482a8524f   Thomas Graf   [NETLINK]: Generi...
413
414
  
  	return 0;
2ae0f17df   Johannes Berg   genetlink: use id...
415
416
  errout_remove:
  	idr_remove(&genl_fam_idr, family->id);
482a8524f   Thomas Graf   [NETLINK]: Generi...
417
  errout_locked:
def311749   Pravin B Shelar   genl: Allow concu...
418
  	genl_unlock_all();
482a8524f   Thomas Graf   [NETLINK]: Generi...
419
420
  	return err;
  }
489111e5c   Johannes Berg   genetlink: static...
421
  EXPORT_SYMBOL(genl_register_family);
482a8524f   Thomas Graf   [NETLINK]: Generi...
422
423
424
425
426
427
428
429
430
  
  /**
   * genl_unregister_family - unregister generic netlink family
   * @family: generic netlink family
   *
   * Unregisters the specified family.
   *
   * Returns 0 on success or a negative error code.
   */
2ae0f17df   Johannes Berg   genetlink: use id...
431
  int genl_unregister_family(const struct genl_family *family)
482a8524f   Thomas Graf   [NETLINK]: Generi...
432
  {
def311749   Pravin B Shelar   genl: Allow concu...
433
  	genl_lock_all();
482a8524f   Thomas Graf   [NETLINK]: Generi...
434

0e82c7635   pravin shelar   genetlink: Fix ge...
435
  	if (!genl_family_find_byid(family->id)) {
2ae0f17df   Johannes Berg   genetlink: use id...
436
437
438
  		genl_unlock_all();
  		return -ENOENT;
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
439

2ae0f17df   Johannes Berg   genetlink: use id...
440
  	genl_unregister_mc_groups(family);
ee1c24421   Johannes Berg   genetlink: synchr...
441

2ae0f17df   Johannes Berg   genetlink: use id...
442
  	idr_remove(&genl_fam_idr, family->id);
482a8524f   Thomas Graf   [NETLINK]: Generi...
443

2ae0f17df   Johannes Berg   genetlink: use id...
444
445
446
447
  	up_write(&cb_lock);
  	wait_event(genl_sk_destructing_waitq,
  		   atomic_read(&genl_sk_destructing_cnt) == 0);
  	genl_unlock();
482a8524f   Thomas Graf   [NETLINK]: Generi...
448

2ae0f17df   Johannes Berg   genetlink: use id...
449
450
451
  	genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
  
  	return 0;
482a8524f   Thomas Graf   [NETLINK]: Generi...
452
  }
416c2f9cf   Changli Gao   genetlink: cleanu...
453
  EXPORT_SYMBOL(genl_unregister_family);
482a8524f   Thomas Graf   [NETLINK]: Generi...
454

a46621a3a   Denys Vlasenko   net: Deinline __n...
455
456
457
  /**
   * genlmsg_put - Add generic netlink header to netlink message
   * @skb: socket buffer holding the message
15e473046   Eric W. Biederman   netlink: Rename p...
458
   * @portid: netlink portid the message is addressed to
a46621a3a   Denys Vlasenko   net: Deinline __n...
459
460
   * @seq: sequence number (usually the one of the sender)
   * @family: generic netlink family
2c53040f0   Ben Hutchings   net: Fix (nearly-...
461
   * @flags: netlink message flags
a46621a3a   Denys Vlasenko   net: Deinline __n...
462
463
464
465
   * @cmd: generic netlink command
   *
   * Returns pointer to user specific header
   */
15e473046   Eric W. Biederman   netlink: Rename p...
466
  void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
2ae0f17df   Johannes Berg   genetlink: use id...
467
  		  const struct genl_family *family, int flags, u8 cmd)
a46621a3a   Denys Vlasenko   net: Deinline __n...
468
469
470
  {
  	struct nlmsghdr *nlh;
  	struct genlmsghdr *hdr;
15e473046   Eric W. Biederman   netlink: Rename p...
471
  	nlh = nlmsg_put(skb, portid, seq, family->id, GENL_HDRLEN +
a46621a3a   Denys Vlasenko   net: Deinline __n...
472
473
474
475
476
477
478
479
480
481
482
483
  			family->hdrsize, flags);
  	if (nlh == NULL)
  		return NULL;
  
  	hdr = nlmsg_data(nlh);
  	hdr->cmd = cmd;
  	hdr->version = family->version;
  	hdr->reserved = 0;
  
  	return (char *) hdr + GENL_HDRLEN;
  }
  EXPORT_SYMBOL(genlmsg_put);
1927f41a2   Jiri Pirko   net: genetlink: i...
484
485
486
487
488
489
490
491
492
  static struct genl_dumpit_info *genl_dumpit_info_alloc(void)
  {
  	return kmalloc(sizeof(struct genl_dumpit_info), GFP_KERNEL);
  }
  
  static void genl_dumpit_info_free(const struct genl_dumpit_info *info)
  {
  	kfree(info);
  }
c10e6cf85   Jiri Pirko   net: genetlink: p...
493
494
495
496
497
498
  static struct nlattr **
  genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
  				struct nlmsghdr *nlh,
  				struct netlink_ext_ack *extack,
  				const struct genl_ops *ops,
  				int hdrlen,
b65ce380b   Cong Wang   genetlink: clean ...
499
  				enum genl_validate_flags no_strict_flag)
c10e6cf85   Jiri Pirko   net: genetlink: p...
500
501
502
503
504
505
  {
  	enum netlink_validation validate = ops->validate & no_strict_flag ?
  					   NL_VALIDATE_LIBERAL :
  					   NL_VALIDATE_STRICT;
  	struct nlattr **attrbuf;
  	int err;
48526a0f4   Jakub Kicinski   genetlink: bring ...
506
  	if (!ops->maxattr)
cb0ce18aa   Michal Kubecek   genetlink: do not...
507
  		return NULL;
48526a0f4   Jakub Kicinski   genetlink: bring ...
508
  	attrbuf = kmalloc_array(ops->maxattr + 1,
bf64ff4c2   Cong Wang   genetlink: get ri...
509
510
511
  				sizeof(struct nlattr *), GFP_KERNEL);
  	if (!attrbuf)
  		return ERR_PTR(-ENOMEM);
c10e6cf85   Jiri Pirko   net: genetlink: p...
512

48526a0f4   Jakub Kicinski   genetlink: bring ...
513
514
  	err = __nlmsg_parse(nlh, hdrlen, attrbuf, ops->maxattr, ops->policy,
  			    validate, extack);
39f3b41aa   Paolo Abeni   net: genetlink: r...
515
  	if (err) {
bf64ff4c2   Cong Wang   genetlink: get ri...
516
  		kfree(attrbuf);
c10e6cf85   Jiri Pirko   net: genetlink: p...
517
518
519
520
  		return ERR_PTR(err);
  	}
  	return attrbuf;
  }
bf64ff4c2   Cong Wang   genetlink: get ri...
521
  static void genl_family_rcv_msg_attrs_free(struct nlattr **attrbuf)
c10e6cf85   Jiri Pirko   net: genetlink: p...
522
  {
bf64ff4c2   Cong Wang   genetlink: get ri...
523
  	kfree(attrbuf);
c10e6cf85   Jiri Pirko   net: genetlink: p...
524
  }
c36f05559   Cong Wang   genetlink: fix me...
525
526
527
528
529
530
531
532
533
  struct genl_start_context {
  	const struct genl_family *family;
  	struct nlmsghdr *nlh;
  	struct netlink_ext_ack *extack;
  	const struct genl_ops *ops;
  	int hdrlen;
  };
  
  static int genl_start(struct netlink_callback *cb)
fc9e50f5a   Tom Herbert   netlink: add a st...
534
  {
c36f05559   Cong Wang   genetlink: fix me...
535
536
537
538
  	struct genl_start_context *ctx = cb->data;
  	const struct genl_ops *ops = ctx->ops;
  	struct genl_dumpit_info *info;
  	struct nlattr **attrs = NULL;
fc9e50f5a   Tom Herbert   netlink: add a st...
539
  	int rc = 0;
c36f05559   Cong Wang   genetlink: fix me...
540
541
542
543
544
545
546
547
  	if (ops->validate & GENL_DONT_VALIDATE_DUMP)
  		goto no_attrs;
  
  	if (ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen))
  		return -EINVAL;
  
  	attrs = genl_family_rcv_msg_attrs_parse(ctx->family, ctx->nlh, ctx->extack,
  						ops, ctx->hdrlen,
b65ce380b   Cong Wang   genetlink: clean ...
548
  						GENL_DONT_VALIDATE_DUMP_STRICT);
c36f05559   Cong Wang   genetlink: fix me...
549
550
551
552
553
554
  	if (IS_ERR(attrs))
  		return PTR_ERR(attrs);
  
  no_attrs:
  	info = genl_dumpit_info_alloc();
  	if (!info) {
bf64ff4c2   Cong Wang   genetlink: get ri...
555
  		genl_family_rcv_msg_attrs_free(attrs);
c36f05559   Cong Wang   genetlink: fix me...
556
557
558
  		return -ENOMEM;
  	}
  	info->family = ctx->family;
0b588afdd   Jakub Kicinski   genetlink: add sm...
559
  	info->op = *ops;
c36f05559   Cong Wang   genetlink: fix me...
560
561
562
  	info->attrs = attrs;
  
  	cb->data = info;
fc9e50f5a   Tom Herbert   netlink: add a st...
563
  	if (ops->start) {
c36f05559   Cong Wang   genetlink: fix me...
564
565
  		if (!ctx->family->parallel_ops)
  			genl_lock();
fc9e50f5a   Tom Herbert   netlink: add a st...
566
  		rc = ops->start(cb);
c36f05559   Cong Wang   genetlink: fix me...
567
568
569
570
571
  		if (!ctx->family->parallel_ops)
  			genl_unlock();
  	}
  
  	if (rc) {
bf64ff4c2   Cong Wang   genetlink: get ri...
572
  		genl_family_rcv_msg_attrs_free(info->attrs);
c36f05559   Cong Wang   genetlink: fix me...
573
574
  		genl_dumpit_info_free(info);
  		cb->data = NULL;
fc9e50f5a   Tom Herbert   netlink: add a st...
575
576
577
  	}
  	return rc;
  }
9b96309c5   Pravin B Shelar   genl: Fix genl du...
578
579
  static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
  {
0b588afdd   Jakub Kicinski   genetlink: add sm...
580
  	const struct genl_ops *ops = &genl_dumpit_info(cb)->op;
9b96309c5   Pravin B Shelar   genl: Fix genl du...
581
582
583
584
585
586
587
588
589
590
  	int rc;
  
  	genl_lock();
  	rc = ops->dumpit(skb, cb);
  	genl_unlock();
  	return rc;
  }
  
  static int genl_lock_done(struct netlink_callback *cb)
  {
1927f41a2   Jiri Pirko   net: genetlink: i...
591
  	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
0b588afdd   Jakub Kicinski   genetlink: add sm...
592
  	const struct genl_ops *ops = &info->op;
9b96309c5   Pravin B Shelar   genl: Fix genl du...
593
594
595
596
597
598
599
  	int rc = 0;
  
  	if (ops->done) {
  		genl_lock();
  		rc = ops->done(cb);
  		genl_unlock();
  	}
bf64ff4c2   Cong Wang   genetlink: get ri...
600
  	genl_family_rcv_msg_attrs_free(info->attrs);
1927f41a2   Jiri Pirko   net: genetlink: i...
601
602
603
604
605
606
607
  	genl_dumpit_info_free(info);
  	return rc;
  }
  
  static int genl_parallel_done(struct netlink_callback *cb)
  {
  	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
0b588afdd   Jakub Kicinski   genetlink: add sm...
608
  	const struct genl_ops *ops = &info->op;
1927f41a2   Jiri Pirko   net: genetlink: i...
609
610
611
612
  	int rc = 0;
  
  	if (ops->done)
  		rc = ops->done(cb);
bf64ff4c2   Cong Wang   genetlink: get ri...
613
  	genl_family_rcv_msg_attrs_free(info->attrs);
1927f41a2   Jiri Pirko   net: genetlink: i...
614
  	genl_dumpit_info_free(info);
9b96309c5   Pravin B Shelar   genl: Fix genl du...
615
616
  	return rc;
  }
be064defa   Jiri Pirko   net: genetlink: p...
617
618
619
620
621
622
  static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
  				      struct sk_buff *skb,
  				      struct nlmsghdr *nlh,
  				      struct netlink_ext_ack *extack,
  				      const struct genl_ops *ops,
  				      int hdrlen, struct net *net)
482a8524f   Thomas Graf   [NETLINK]: Generi...
623
  {
c36f05559   Cong Wang   genetlink: fix me...
624
  	struct genl_start_context ctx;
be064defa   Jiri Pirko   net: genetlink: p...
625
  	int err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
626

be064defa   Jiri Pirko   net: genetlink: p...
627
  	if (!ops->dumpit)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
628
  		return -EOPNOTSUPP;
482a8524f   Thomas Graf   [NETLINK]: Generi...
629

c36f05559   Cong Wang   genetlink: fix me...
630
631
632
633
634
  	ctx.family = family;
  	ctx.nlh = nlh;
  	ctx.extack = extack;
  	ctx.ops = ops;
  	ctx.hdrlen = hdrlen;
1927f41a2   Jiri Pirko   net: genetlink: i...
635

be064defa   Jiri Pirko   net: genetlink: p...
636
637
638
  	if (!family->parallel_ops) {
  		struct netlink_dump_control c = {
  			.module = family->module,
c36f05559   Cong Wang   genetlink: fix me...
639
640
  			.data = &ctx,
  			.start = genl_start,
be064defa   Jiri Pirko   net: genetlink: p...
641
642
643
  			.dump = genl_lock_dumpit,
  			.done = genl_lock_done,
  		};
ef6243acb   Johannes Berg   genetlink: option...
644

be064defa   Jiri Pirko   net: genetlink: p...
645
646
647
  		genl_unlock();
  		err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
  		genl_lock();
be064defa   Jiri Pirko   net: genetlink: p...
648
649
650
  	} else {
  		struct netlink_dump_control c = {
  			.module = family->module,
c36f05559   Cong Wang   genetlink: fix me...
651
652
  			.data = &ctx,
  			.start = genl_start,
be064defa   Jiri Pirko   net: genetlink: p...
653
  			.dump = ops->dumpit,
1927f41a2   Jiri Pirko   net: genetlink: i...
654
  			.done = genl_parallel_done,
be064defa   Jiri Pirko   net: genetlink: p...
655
656
657
658
  		};
  
  		err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
  	}
ef6243acb   Johannes Berg   genetlink: option...
659

be064defa   Jiri Pirko   net: genetlink: p...
660
661
  	return err;
  }
9b96309c5   Pravin B Shelar   genl: Fix genl du...
662

be064defa   Jiri Pirko   net: genetlink: p...
663
664
665
666
667
668
669
670
671
672
  static int genl_family_rcv_msg_doit(const struct genl_family *family,
  				    struct sk_buff *skb,
  				    struct nlmsghdr *nlh,
  				    struct netlink_ext_ack *extack,
  				    const struct genl_ops *ops,
  				    int hdrlen, struct net *net)
  {
  	struct nlattr **attrbuf;
  	struct genl_info info;
  	int err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
673

be064defa   Jiri Pirko   net: genetlink: p...
674
  	if (!ops->doit)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
675
  		return -EOPNOTSUPP;
482a8524f   Thomas Graf   [NETLINK]: Generi...
676

c10e6cf85   Jiri Pirko   net: genetlink: p...
677
678
  	attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
  						  ops, hdrlen,
b65ce380b   Cong Wang   genetlink: clean ...
679
  						  GENL_DONT_VALIDATE_STRICT);
c10e6cf85   Jiri Pirko   net: genetlink: p...
680
681
  	if (IS_ERR(attrbuf))
  		return PTR_ERR(attrbuf);
482a8524f   Thomas Graf   [NETLINK]: Generi...
682
683
  
  	info.snd_seq = nlh->nlmsg_seq;
15e473046   Eric W. Biederman   netlink: Rename p...
684
  	info.snd_portid = NETLINK_CB(skb).portid;
482a8524f   Thomas Graf   [NETLINK]: Generi...
685
686
687
  	info.nlhdr = nlh;
  	info.genlhdr = nlmsg_data(nlh);
  	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
def311749   Pravin B Shelar   genl: Allow concu...
688
  	info.attrs = attrbuf;
7ab606d16   Johannes Berg   genetlink: pass e...
689
  	info.extack = extack;
134e63756   Johannes Berg   genetlink: make n...
690
  	genl_info_net_set(&info, net);
ff4c92d85   Johannes Berg   genetlink: introd...
691
  	memset(&info.user_ptr, 0, sizeof(info.user_ptr));
482a8524f   Thomas Graf   [NETLINK]: Generi...
692

ff4c92d85   Johannes Berg   genetlink: introd...
693
694
695
  	if (family->pre_doit) {
  		err = family->pre_doit(ops, skb, &info);
  		if (err)
50754d218   Wei Yongjun   genetlink: fix po...
696
  			goto out;
ff4c92d85   Johannes Berg   genetlink: introd...
697
698
699
700
701
702
  	}
  
  	err = ops->doit(skb, &info);
  
  	if (family->post_doit)
  		family->post_doit(ops, skb, &info);
50754d218   Wei Yongjun   genetlink: fix po...
703
  out:
bf64ff4c2   Cong Wang   genetlink: get ri...
704
  	genl_family_rcv_msg_attrs_free(attrbuf);
def311749   Pravin B Shelar   genl: Allow concu...
705
706
707
  
  	return err;
  }
be064defa   Jiri Pirko   net: genetlink: p...
708
709
710
711
712
  static int genl_family_rcv_msg(const struct genl_family *family,
  			       struct sk_buff *skb,
  			       struct nlmsghdr *nlh,
  			       struct netlink_ext_ack *extack)
  {
be064defa   Jiri Pirko   net: genetlink: p...
713
714
  	struct net *net = sock_net(skb->sk);
  	struct genlmsghdr *hdr = nlmsg_data(nlh);
0b588afdd   Jakub Kicinski   genetlink: add sm...
715
  	struct genl_ops op;
be064defa   Jiri Pirko   net: genetlink: p...
716
717
718
719
720
721
722
723
724
  	int hdrlen;
  
  	/* this family doesn't exist in this netns */
  	if (!family->netnsok && !net_eq(net, &init_net))
  		return -ENOENT;
  
  	hdrlen = GENL_HDRLEN + family->hdrsize;
  	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
  		return -EINVAL;
0b588afdd   Jakub Kicinski   genetlink: add sm...
725
  	if (genl_get_cmd(hdr->cmd, family, &op))
be064defa   Jiri Pirko   net: genetlink: p...
726
  		return -EOPNOTSUPP;
0b588afdd   Jakub Kicinski   genetlink: add sm...
727
  	if ((op.flags & GENL_ADMIN_PERM) &&
be064defa   Jiri Pirko   net: genetlink: p...
728
729
  	    !netlink_capable(skb, CAP_NET_ADMIN))
  		return -EPERM;
0b588afdd   Jakub Kicinski   genetlink: add sm...
730
  	if ((op.flags & GENL_UNS_ADMIN_PERM) &&
be064defa   Jiri Pirko   net: genetlink: p...
731
732
733
734
735
  	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
  		return -EPERM;
  
  	if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
  		return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
0b588afdd   Jakub Kicinski   genetlink: add sm...
736
  						  &op, hdrlen, net);
be064defa   Jiri Pirko   net: genetlink: p...
737
738
  	else
  		return genl_family_rcv_msg_doit(family, skb, nlh, extack,
0b588afdd   Jakub Kicinski   genetlink: add sm...
739
  						&op, hdrlen, net);
be064defa   Jiri Pirko   net: genetlink: p...
740
  }
2d4bc9336   Johannes Berg   netlink: extended...
741
742
  static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
  			struct netlink_ext_ack *extack)
def311749   Pravin B Shelar   genl: Allow concu...
743
  {
2ae0f17df   Johannes Berg   genetlink: use id...
744
  	const struct genl_family *family;
def311749   Pravin B Shelar   genl: Allow concu...
745
746
747
748
749
750
751
752
  	int err;
  
  	family = genl_family_find_byid(nlh->nlmsg_type);
  	if (family == NULL)
  		return -ENOENT;
  
  	if (!family->parallel_ops)
  		genl_lock();
7ab606d16   Johannes Berg   genetlink: pass e...
753
  	err = genl_family_rcv_msg(family, skb, nlh, extack);
def311749   Pravin B Shelar   genl: Allow concu...
754
755
756
  
  	if (!family->parallel_ops)
  		genl_unlock();
ff4c92d85   Johannes Berg   genetlink: introd...
757
  	return err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
758
  }
cd40b7d39   Denis V. Lunev   [NET]: make netli...
759
  static void genl_rcv(struct sk_buff *skb)
482a8524f   Thomas Graf   [NETLINK]: Generi...
760
  {
def311749   Pravin B Shelar   genl: Allow concu...
761
  	down_read(&cb_lock);
cd40b7d39   Denis V. Lunev   [NET]: make netli...
762
  	netlink_rcv_skb(skb, &genl_rcv_msg);
def311749   Pravin B Shelar   genl: Allow concu...
763
  	up_read(&cb_lock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
764
765
766
767
768
  }
  
  /**************************************************************************
   * Controller
   **************************************************************************/
489111e5c   Johannes Berg   genetlink: static...
769
  static struct genl_family genl_ctrl;
17c157c88   Thomas Graf   [GENL]: Add genlm...
770

2ae0f17df   Johannes Berg   genetlink: use id...
771
  static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
482a8524f   Thomas Graf   [NETLINK]: Generi...
772
773
774
  			  u32 flags, struct sk_buff *skb, u8 cmd)
  {
  	void *hdr;
15e473046   Eric W. Biederman   netlink: Rename p...
775
  	hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
482a8524f   Thomas Graf   [NETLINK]: Generi...
776
777
  	if (hdr == NULL)
  		return -1;
444653f69   David S. Miller   genetlink: Stop u...
778
779
780
781
782
783
  	if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
  	    nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) ||
  	    nla_put_u32(skb, CTRL_ATTR_VERSION, family->version) ||
  	    nla_put_u32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize) ||
  	    nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
  		goto nla_put_failure;
eb328111e   Thomas Graf   [GENL]: Provide m...
784

0b588afdd   Jakub Kicinski   genetlink: add sm...
785
  	if (genl_get_cmd_cnt(family)) {
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
786
  		struct nlattr *nla_ops;
d91824c08   Johannes Berg   genetlink: regist...
787
  		int i;
eb328111e   Thomas Graf   [GENL]: Provide m...
788

ae0be8de9   Michal Kubecek   netlink: make nla...
789
  		nla_ops = nla_nest_start_noflag(skb, CTRL_ATTR_OPS);
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
790
  		if (nla_ops == NULL)
eb328111e   Thomas Graf   [GENL]: Provide m...
791
  			goto nla_put_failure;
0b588afdd   Jakub Kicinski   genetlink: add sm...
792
  		for (i = 0; i < genl_get_cmd_cnt(family); i++) {
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
793
  			struct nlattr *nest;
0b588afdd   Jakub Kicinski   genetlink: add sm...
794
795
  			struct genl_ops op;
  			u32 op_flags;
f84f771d9   Johannes Berg   genetlink: allow ...
796

0b588afdd   Jakub Kicinski   genetlink: add sm...
797
798
799
  			genl_get_cmd_by_index(i, family, &op);
  			op_flags = op.flags;
  			if (op.dumpit)
029b234fb   Johannes Berg   genetlink: rename...
800
  				op_flags |= GENL_CMD_CAP_DUMP;
0b588afdd   Jakub Kicinski   genetlink: add sm...
801
  			if (op.doit)
029b234fb   Johannes Berg   genetlink: rename...
802
  				op_flags |= GENL_CMD_CAP_DO;
48526a0f4   Jakub Kicinski   genetlink: bring ...
803
  			if (op.policy)
029b234fb   Johannes Berg   genetlink: rename...
804
  				op_flags |= GENL_CMD_CAP_HASPOL;
eb328111e   Thomas Graf   [GENL]: Provide m...
805

ae0be8de9   Michal Kubecek   netlink: make nla...
806
  			nest = nla_nest_start_noflag(skb, i + 1);
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
807
808
  			if (nest == NULL)
  				goto nla_put_failure;
eb328111e   Thomas Graf   [GENL]: Provide m...
809

0b588afdd   Jakub Kicinski   genetlink: add sm...
810
  			if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) ||
029b234fb   Johannes Berg   genetlink: rename...
811
  			    nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
444653f69   David S. Miller   genetlink: Stop u...
812
  				goto nla_put_failure;
eb328111e   Thomas Graf   [GENL]: Provide m...
813

e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
814
815
816
817
818
  			nla_nest_end(skb, nest);
  		}
  
  		nla_nest_end(skb, nla_ops);
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
819

2a94fe48f   Johannes Berg   genetlink: make m...
820
  	if (family->n_mcgrps) {
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
821
  		struct nlattr *nla_grps;
2a94fe48f   Johannes Berg   genetlink: make m...
822
  		int i;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
823

ae0be8de9   Michal Kubecek   netlink: make nla...
824
  		nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
825
826
  		if (nla_grps == NULL)
  			goto nla_put_failure;
2a94fe48f   Johannes Berg   genetlink: make m...
827
  		for (i = 0; i < family->n_mcgrps; i++) {
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
828
  			struct nlattr *nest;
2a94fe48f   Johannes Berg   genetlink: make m...
829
  			const struct genl_multicast_group *grp;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
830

2a94fe48f   Johannes Berg   genetlink: make m...
831
  			grp = &family->mcgrps[i];
ae0be8de9   Michal Kubecek   netlink: make nla...
832
  			nest = nla_nest_start_noflag(skb, i + 1);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
833
834
  			if (nest == NULL)
  				goto nla_put_failure;
2a94fe48f   Johannes Berg   genetlink: make m...
835
836
  			if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID,
  					family->mcgrp_offset + i) ||
444653f69   David S. Miller   genetlink: Stop u...
837
838
839
  			    nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
  					   grp->name))
  				goto nla_put_failure;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
840
841
842
843
844
  
  			nla_nest_end(skb, nest);
  		}
  		nla_nest_end(skb, nla_grps);
  	}
053c095a8   Johannes Berg   netlink: make nlm...
845
846
  	genlmsg_end(skb, hdr);
  	return 0;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
847
848
  
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
849
850
  	genlmsg_cancel(skb, hdr);
  	return -EMSGSIZE;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
851
  }
2ae0f17df   Johannes Berg   genetlink: use id...
852
  static int ctrl_fill_mcgrp_info(const struct genl_family *family,
2a94fe48f   Johannes Berg   genetlink: make m...
853
854
855
  				const struct genl_multicast_group *grp,
  				int grp_id, u32 portid, u32 seq, u32 flags,
  				struct sk_buff *skb, u8 cmd)
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
856
857
858
859
  {
  	void *hdr;
  	struct nlattr *nla_grps;
  	struct nlattr *nest;
15e473046   Eric W. Biederman   netlink: Rename p...
860
  	hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
861
862
  	if (hdr == NULL)
  		return -1;
c2ebb9084   Johannes Berg   genetlink: remove...
863
864
  	if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
  	    nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id))
444653f69   David S. Miller   genetlink: Stop u...
865
  		goto nla_put_failure;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
866

ae0be8de9   Michal Kubecek   netlink: make nla...
867
  	nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
868
869
  	if (nla_grps == NULL)
  		goto nla_put_failure;
ae0be8de9   Michal Kubecek   netlink: make nla...
870
  	nest = nla_nest_start_noflag(skb, 1);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
871
872
  	if (nest == NULL)
  		goto nla_put_failure;
2a94fe48f   Johannes Berg   genetlink: make m...
873
  	if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) ||
444653f69   David S. Miller   genetlink: Stop u...
874
875
876
  	    nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
  			   grp->name))
  		goto nla_put_failure;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
877
878
879
  
  	nla_nest_end(skb, nest);
  	nla_nest_end(skb, nla_grps);
053c095a8   Johannes Berg   netlink: make nlm...
880
881
  	genlmsg_end(skb, hdr);
  	return 0;
482a8524f   Thomas Graf   [NETLINK]: Generi...
882
883
  
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
884
885
  	genlmsg_cancel(skb, hdr);
  	return -EMSGSIZE;
482a8524f   Thomas Graf   [NETLINK]: Generi...
886
887
888
889
  }
  
  static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
  {
2ae0f17df   Johannes Berg   genetlink: use id...
890
  	int n = 0;
482a8524f   Thomas Graf   [NETLINK]: Generi...
891
  	struct genl_family *rt;
134e63756   Johannes Berg   genetlink: make n...
892
  	struct net *net = sock_net(skb->sk);
2ae0f17df   Johannes Berg   genetlink: use id...
893
894
  	int fams_to_skip = cb->args[0];
  	unsigned int id;
482a8524f   Thomas Graf   [NETLINK]: Generi...
895

2ae0f17df   Johannes Berg   genetlink: use id...
896
897
898
899
900
901
  	idr_for_each_entry(&genl_fam_idr, rt, id) {
  		if (!rt->netnsok && !net_eq(net, &init_net))
  			continue;
  
  		if (n++ < fams_to_skip)
  			continue;
482a8524f   Thomas Graf   [NETLINK]: Generi...
902

2ae0f17df   Johannes Berg   genetlink: use id...
903
904
  		if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
  				   cb->nlh->nlmsg_seq, NLM_F_MULTI,
1d2a6a5e4   Stanislaw Gruszka   genetlink: fix co...
905
906
  				   skb, CTRL_CMD_NEWFAMILY) < 0) {
  			n--;
2ae0f17df   Johannes Berg   genetlink: use id...
907
  			break;
1d2a6a5e4   Stanislaw Gruszka   genetlink: fix co...
908
  		}
2ae0f17df   Johannes Berg   genetlink: use id...
909
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
910

2ae0f17df   Johannes Berg   genetlink: use id...
911
  	cb->args[0] = n;
482a8524f   Thomas Graf   [NETLINK]: Generi...
912
913
  	return skb->len;
  }
2ae0f17df   Johannes Berg   genetlink: use id...
914
  static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family,
15e473046   Eric W. Biederman   netlink: Rename p...
915
  					     u32 portid, int seq, u8 cmd)
482a8524f   Thomas Graf   [NETLINK]: Generi...
916
917
918
  {
  	struct sk_buff *skb;
  	int err;
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
919
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
482a8524f   Thomas Graf   [NETLINK]: Generi...
920
921
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
15e473046   Eric W. Biederman   netlink: Rename p...
922
  	err = ctrl_fill_info(family, portid, seq, 0, skb, cmd);
482a8524f   Thomas Graf   [NETLINK]: Generi...
923
924
925
926
927
928
929
  	if (err < 0) {
  		nlmsg_free(skb);
  		return ERR_PTR(err);
  	}
  
  	return skb;
  }
2a94fe48f   Johannes Berg   genetlink: make m...
930
  static struct sk_buff *
2ae0f17df   Johannes Berg   genetlink: use id...
931
  ctrl_build_mcgrp_msg(const struct genl_family *family,
2a94fe48f   Johannes Berg   genetlink: make m...
932
933
  		     const struct genl_multicast_group *grp,
  		     int grp_id, u32 portid, int seq, u8 cmd)
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
934
935
936
937
938
939
940
  {
  	struct sk_buff *skb;
  	int err;
  
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
2a94fe48f   Johannes Berg   genetlink: make m...
941
942
  	err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid,
  				   seq, 0, skb, cmd);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
943
944
945
946
947
948
949
  	if (err < 0) {
  		nlmsg_free(skb);
  		return ERR_PTR(err);
  	}
  
  	return skb;
  }
a4bb4f5fc   Jakub Kicinski   genetlink: switch...
950
  static const struct nla_policy ctrl_policy_family[] = {
482a8524f   Thomas Graf   [NETLINK]: Generi...
951
  	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
5176f91ea   Thomas Graf   [NETLINK]: Make u...
952
953
  	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
  				    .len = GENL_NAMSIZ - 1 },
482a8524f   Thomas Graf   [NETLINK]: Generi...
954
955
956
957
958
  };
  
  static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
  {
  	struct sk_buff *msg;
2ae0f17df   Johannes Berg   genetlink: use id...
959
  	const struct genl_family *res = NULL;
482a8524f   Thomas Graf   [NETLINK]: Generi...
960
961
962
963
964
  	int err = -EINVAL;
  
  	if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
  		u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
  		res = genl_family_find_byid(id);
134e63756   Johannes Berg   genetlink: make n...
965
  		err = -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
966
967
968
  	}
  
  	if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
5176f91ea   Thomas Graf   [NETLINK]: Make u...
969
  		char *name;
482a8524f   Thomas Graf   [NETLINK]: Generi...
970

5176f91ea   Thomas Graf   [NETLINK]: Make u...
971
  		name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
482a8524f   Thomas Graf   [NETLINK]: Generi...
972
  		res = genl_family_find_byname(name);
fa8430953   Stephen Hemminger   genetlink: add au...
973
974
975
  #ifdef CONFIG_MODULES
  		if (res == NULL) {
  			genl_unlock();
c74f2b267   Stanislaw Gruszka   genetlink: releas...
976
  			up_read(&cb_lock);
e9412c370   Neil Horman   genetlink: Build ...
977
  			request_module("net-pf-%d-proto-%d-family-%s",
fa8430953   Stephen Hemminger   genetlink: add au...
978
  				       PF_NETLINK, NETLINK_GENERIC, name);
c74f2b267   Stanislaw Gruszka   genetlink: releas...
979
  			down_read(&cb_lock);
fa8430953   Stephen Hemminger   genetlink: add au...
980
981
982
983
  			genl_lock();
  			res = genl_family_find_byname(name);
  		}
  #endif
134e63756   Johannes Berg   genetlink: make n...
984
  		err = -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
985
  	}
134e63756   Johannes Berg   genetlink: make n...
986
987
988
989
990
991
  	if (res == NULL)
  		return err;
  
  	if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) {
  		/* family doesn't exist here */
  		return -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
992
  	}
15e473046   Eric W. Biederman   netlink: Rename p...
993
  	msg = ctrl_build_family_msg(res, info->snd_portid, info->snd_seq,
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
994
  				    CTRL_CMD_NEWFAMILY);
134e63756   Johannes Berg   genetlink: make n...
995
996
  	if (IS_ERR(msg))
  		return PTR_ERR(msg);
482a8524f   Thomas Graf   [NETLINK]: Generi...
997

134e63756   Johannes Berg   genetlink: make n...
998
  	return genlmsg_reply(msg, info);
482a8524f   Thomas Graf   [NETLINK]: Generi...
999
  }
2ae0f17df   Johannes Berg   genetlink: use id...
1000
  static int genl_ctrl_event(int event, const struct genl_family *family,
2a94fe48f   Johannes Berg   genetlink: make m...
1001
1002
  			   const struct genl_multicast_group *grp,
  			   int grp_id)
482a8524f   Thomas Graf   [NETLINK]: Generi...
1003
1004
  {
  	struct sk_buff *msg;
134e63756   Johannes Berg   genetlink: make n...
1005
1006
  	/* genl is still initialising */
  	if (!init_net.genl_sock)
482a8524f   Thomas Graf   [NETLINK]: Generi...
1007
1008
1009
1010
1011
  		return 0;
  
  	switch (event) {
  	case CTRL_CMD_NEWFAMILY:
  	case CTRL_CMD_DELFAMILY:
c2ebb9084   Johannes Berg   genetlink: remove...
1012
  		WARN_ON(grp);
134e63756   Johannes Berg   genetlink: make n...
1013
  		msg = ctrl_build_family_msg(family, 0, 0, event);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
1014
1015
1016
  		break;
  	case CTRL_CMD_NEWMCAST_GRP:
  	case CTRL_CMD_DELMCAST_GRP:
c2ebb9084   Johannes Berg   genetlink: remove...
1017
  		BUG_ON(!grp);
2a94fe48f   Johannes Berg   genetlink: make m...
1018
  		msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event);
482a8524f   Thomas Graf   [NETLINK]: Generi...
1019
  		break;
134e63756   Johannes Berg   genetlink: make n...
1020
1021
1022
1023
1024
1025
1026
1027
  	default:
  		return -EINVAL;
  	}
  
  	if (IS_ERR(msg))
  		return PTR_ERR(msg);
  
  	if (!family->netnsok) {
68eb55031   Johannes Berg   genetlink: pass f...
1028
  		genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0,
2a94fe48f   Johannes Berg   genetlink: make m...
1029
  					0, GFP_KERNEL);
134e63756   Johannes Berg   genetlink: make n...
1030
1031
  	} else {
  		rcu_read_lock();
68eb55031   Johannes Berg   genetlink: pass f...
1032
  		genlmsg_multicast_allns(&genl_ctrl, msg, 0,
2a94fe48f   Johannes Berg   genetlink: make m...
1033
  					0, GFP_ATOMIC);
134e63756   Johannes Berg   genetlink: make n...
1034
  		rcu_read_unlock();
482a8524f   Thomas Graf   [NETLINK]: Generi...
1035
1036
1037
1038
  	}
  
  	return 0;
  }
adc848450   Jakub Kicinski   genetlink: add a ...
1039
1040
  struct ctrl_dump_policy_ctx {
  	struct netlink_policy_dump_state *state;
50a896cf2   Johannes Berg   genetlink: proper...
1041
1042
  	const struct genl_family *rt;
  	unsigned int opidx;
e992a6eda   Jakub Kicinski   genetlink: allow ...
1043
  	u32 op;
adc848450   Jakub Kicinski   genetlink: add a ...
1044
  	u16 fam_id;
e992a6eda   Jakub Kicinski   genetlink: allow ...
1045
1046
  	u8 policies:1,
  	   single_op:1;
adc848450   Jakub Kicinski   genetlink: add a ...
1047
  };
a4bb4f5fc   Jakub Kicinski   genetlink: switch...
1048
1049
1050
1051
  static const struct nla_policy ctrl_policy_policy[] = {
  	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
  	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
  				    .len = GENL_NAMSIZ - 1 },
e992a6eda   Jakub Kicinski   genetlink: allow ...
1052
  	[CTRL_ATTR_OP]		= { .type = NLA_U32 },
a4bb4f5fc   Jakub Kicinski   genetlink: switch...
1053
  };
78ade619c   Jakub Kicinski   genetlink: use .s...
1054
  static int ctrl_dumppolicy_start(struct netlink_callback *cb)
d07dcf9aa   Johannes Berg   netlink: add infr...
1055
  {
8e1ed28fd   Jakub Kicinski   genetlink: use pa...
1056
  	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
adc848450   Jakub Kicinski   genetlink: add a ...
1057
  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
8e1ed28fd   Jakub Kicinski   genetlink: use pa...
1058
  	struct nlattr **tb = info->attrs;
d07dcf9aa   Johannes Berg   netlink: add infr...
1059
  	const struct genl_family *rt;
50a896cf2   Johannes Berg   genetlink: proper...
1060
1061
  	struct genl_ops op;
  	int err, i;
d07dcf9aa   Johannes Berg   netlink: add infr...
1062

adc848450   Jakub Kicinski   genetlink: add a ...
1063
  	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
78ade619c   Jakub Kicinski   genetlink: use .s...
1064
1065
  	if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
  		return -EINVAL;
d07dcf9aa   Johannes Berg   netlink: add infr...
1066

78ade619c   Jakub Kicinski   genetlink: use .s...
1067
1068
1069
1070
1071
1072
1073
1074
  	if (tb[CTRL_ATTR_FAMILY_ID]) {
  		ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
  	} else {
  		rt = genl_family_find_byname(
  			nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
  		if (!rt)
  			return -ENOENT;
  		ctx->fam_id = rt->id;
d07dcf9aa   Johannes Berg   netlink: add infr...
1075
  	}
adc848450   Jakub Kicinski   genetlink: add a ...
1076
  	rt = genl_family_find_byid(ctx->fam_id);
d07dcf9aa   Johannes Berg   netlink: add infr...
1077
1078
  	if (!rt)
  		return -ENOENT;
50a896cf2   Johannes Berg   genetlink: proper...
1079
  	ctx->rt = rt;
e992a6eda   Jakub Kicinski   genetlink: allow ...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  	if (tb[CTRL_ATTR_OP]) {
  		ctx->single_op = true;
  		ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]);
  
  		err = genl_get_cmd(ctx->op, rt, &op);
  		if (err) {
  			NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
  			return err;
  		}
  
  		if (!op.policy)
  			return -ENODATA;
  
  		return netlink_policy_dump_add_policy(&ctx->state, op.policy,
  						      op.maxattr);
  	}
50a896cf2   Johannes Berg   genetlink: proper...
1096
1097
1098
1099
1100
1101
1102
1103
  	for (i = 0; i < genl_get_cmd_cnt(rt); i++) {
  		genl_get_cmd_by_index(i, rt, &op);
  
  		if (op.policy) {
  			err = netlink_policy_dump_add_policy(&ctx->state,
  							     op.policy,
  							     op.maxattr);
  			if (err)
b0672895d   Jakub Kicinski   net: genl: fix er...
1104
  				goto err_free_state;
50a896cf2   Johannes Berg   genetlink: proper...
1105
1106
  		}
  	}
d07dcf9aa   Johannes Berg   netlink: add infr...
1107

50a896cf2   Johannes Berg   genetlink: proper...
1108
1109
1110
  	if (!ctx->state)
  		return -ENODATA;
  	return 0;
b0672895d   Jakub Kicinski   net: genl: fix er...
1111
1112
1113
1114
  
  err_free_state:
  	netlink_policy_dump_free(ctx->state);
  	return err;
78ade619c   Jakub Kicinski   genetlink: use .s...
1115
  }
aa85ee5f9   Johannes Berg   genetlink: factor...
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
  static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
  				  struct netlink_callback *cb)
  {
  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
  	void *hdr;
  
  	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
  			  cb->nlh->nlmsg_seq, &genl_ctrl,
  			  NLM_F_MULTI, CTRL_CMD_GETPOLICY);
  	if (!hdr)
  		return NULL;
  
  	if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
  		return NULL;
  
  	return hdr;
  }
50a896cf2   Johannes Berg   genetlink: proper...
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
  				  struct netlink_callback *cb,
  			          struct genl_ops *op)
  {
  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
  	struct nlattr *nest_pol, *nest_op;
  	void *hdr;
  	int idx;
  
  	/* skip if we have nothing to show */
  	if (!op->policy)
  		return 0;
  	if (!op->doit &&
  	    (!op->dumpit || op->validate & GENL_DONT_VALIDATE_DUMP))
  		return 0;
  
  	hdr = ctrl_dumppolicy_prep(skb, cb);
  	if (!hdr)
  		return -ENOBUFS;
  
  	nest_pol = nla_nest_start(skb, CTRL_ATTR_OP_POLICY);
  	if (!nest_pol)
  		goto err;
  
  	nest_op = nla_nest_start(skb, op->cmd);
  	if (!nest_op)
  		goto err;
  
  	/* for now both do/dump are always the same */
  	idx = netlink_policy_dump_get_policy_idx(ctx->state,
  						 op->policy,
  						 op->maxattr);
  
  	if (op->doit && nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx))
  		goto err;
  
  	if (op->dumpit && !(op->validate & GENL_DONT_VALIDATE_DUMP) &&
  	    nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx))
  		goto err;
  
  	nla_nest_end(skb, nest_op);
  	nla_nest_end(skb, nest_pol);
  	genlmsg_end(skb, hdr);
  
  	return 0;
  err:
  	genlmsg_cancel(skb, hdr);
  	return -ENOBUFS;
  }
78ade619c   Jakub Kicinski   genetlink: use .s...
1182
1183
1184
  static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
50a896cf2   Johannes Berg   genetlink: proper...
1185
1186
1187
1188
1189
  	void *hdr;
  
  	if (!ctx->policies) {
  		while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) {
  			struct genl_ops op;
e992a6eda   Jakub Kicinski   genetlink: allow ...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
  			if (ctx->single_op) {
  				int err;
  
  				err = genl_get_cmd(ctx->op, ctx->rt, &op);
  				if (WARN_ON(err))
  					return skb->len;
  
  				/* break out of the loop after this one */
  				ctx->opidx = genl_get_cmd_cnt(ctx->rt);
  			} else {
  				genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op);
  			}
50a896cf2   Johannes Berg   genetlink: proper...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  
  			if (ctrl_dumppolicy_put_op(skb, cb, &op))
  				return skb->len;
  
  			ctx->opidx++;
  		}
  
  		/* completed with the per-op policy index list */
  		ctx->policies = true;
  	}
d07dcf9aa   Johannes Berg   netlink: add infr...
1212

adc848450   Jakub Kicinski   genetlink: add a ...
1213
  	while (netlink_policy_dump_loop(ctx->state)) {
d07dcf9aa   Johannes Berg   netlink: add infr...
1214
  		struct nlattr *nest;
aa85ee5f9   Johannes Berg   genetlink: factor...
1215
  		hdr = ctrl_dumppolicy_prep(skb, cb);
d07dcf9aa   Johannes Berg   netlink: add infr...
1216
1217
  		if (!hdr)
  			goto nla_put_failure;
d07dcf9aa   Johannes Berg   netlink: add infr...
1218
1219
1220
  		nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
  		if (!nest)
  			goto nla_put_failure;
adc848450   Jakub Kicinski   genetlink: add a ...
1221
  		if (netlink_policy_dump_write(skb, ctx->state))
d07dcf9aa   Johannes Berg   netlink: add infr...
1222
1223
1224
1225
1226
  			goto nla_put_failure;
  
  		nla_nest_end(skb, nest);
  
  		genlmsg_end(skb, hdr);
d07dcf9aa   Johannes Berg   netlink: add infr...
1227
  	}
d07dcf9aa   Johannes Berg   netlink: add infr...
1228
  	return skb->len;
50a896cf2   Johannes Berg   genetlink: proper...
1229
1230
1231
1232
  
  nla_put_failure:
  	genlmsg_cancel(skb, hdr);
  	return skb->len;
d07dcf9aa   Johannes Berg   netlink: add infr...
1233
  }
949ca6b82   Johannes Berg   netlink: fix poli...
1234
1235
  static int ctrl_dumppolicy_done(struct netlink_callback *cb)
  {
adc848450   Jakub Kicinski   genetlink: add a ...
1236
1237
1238
  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
  
  	netlink_policy_dump_free(ctx->state);
949ca6b82   Johannes Berg   netlink: fix poli...
1239
1240
  	return 0;
  }
12d8de6d9   stephen hemminger   net: make genetli...
1241
  static const struct genl_ops genl_ctrl_ops[] = {
c53ed7423   Johannes Berg   genetlink: only p...
1242
1243
  	{
  		.cmd		= CTRL_CMD_GETFAMILY,
ef6243acb   Johannes Berg   genetlink: option...
1244
  		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
a4bb4f5fc   Jakub Kicinski   genetlink: switch...
1245
1246
  		.policy		= ctrl_policy_family,
  		.maxattr	= ARRAY_SIZE(ctrl_policy_family) - 1,
c53ed7423   Johannes Berg   genetlink: only p...
1247
1248
  		.doit		= ctrl_getfamily,
  		.dumpit		= ctrl_dumpfamily,
c53ed7423   Johannes Berg   genetlink: only p...
1249
  	},
d07dcf9aa   Johannes Berg   netlink: add infr...
1250
1251
  	{
  		.cmd		= CTRL_CMD_GETPOLICY,
a4bb4f5fc   Jakub Kicinski   genetlink: switch...
1252
1253
  		.policy		= ctrl_policy_policy,
  		.maxattr	= ARRAY_SIZE(ctrl_policy_policy) - 1,
78ade619c   Jakub Kicinski   genetlink: use .s...
1254
  		.start		= ctrl_dumppolicy_start,
d07dcf9aa   Johannes Berg   netlink: add infr...
1255
  		.dumpit		= ctrl_dumppolicy,
949ca6b82   Johannes Berg   netlink: fix poli...
1256
  		.done		= ctrl_dumppolicy_done,
d07dcf9aa   Johannes Berg   netlink: add infr...
1257
  	},
482a8524f   Thomas Graf   [NETLINK]: Generi...
1258
  };
12d8de6d9   stephen hemminger   net: make genetli...
1259
  static const struct genl_multicast_group genl_ctrl_groups[] = {
2a94fe48f   Johannes Berg   genetlink: make m...
1260
  	{ .name = "notify", },
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
1261
  };
56989f6d8   Johannes Berg   genetlink: mark f...
1262
  static struct genl_family genl_ctrl __ro_after_init = {
489111e5c   Johannes Berg   genetlink: static...
1263
1264
1265
1266
1267
1268
1269
1270
  	.module = THIS_MODULE,
  	.ops = genl_ctrl_ops,
  	.n_ops = ARRAY_SIZE(genl_ctrl_ops),
  	.mcgrps = genl_ctrl_groups,
  	.n_mcgrps = ARRAY_SIZE(genl_ctrl_groups),
  	.id = GENL_ID_CTRL,
  	.name = "nlctrl",
  	.version = 0x2,
489111e5c   Johannes Berg   genetlink: static...
1271
1272
  	.netnsok = true,
  };
4d54cc321   Florian Westphal   mptcp: avoid lock...
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  static int genl_bind(struct net *net, int group)
  {
  	const struct genl_family *family;
  	unsigned int id;
  	int ret = 0;
  
  	genl_lock_all();
  
  	idr_for_each_entry(&genl_fam_idr, family, id) {
  		const struct genl_multicast_group *grp;
  		int i;
  
  		if (family->n_mcgrps == 0)
  			continue;
  
  		i = group - family->mcgrp_offset;
  		if (i < 0 || i >= family->n_mcgrps)
  			continue;
  
  		grp = &family->mcgrps[i];
  		if ((grp->flags & GENL_UNS_ADMIN_PERM) &&
  		    !ns_capable(net->user_ns, CAP_NET_ADMIN))
  			ret = -EPERM;
  
  		break;
  	}
  
  	genl_unlock_all();
  	return ret;
  }
134e63756   Johannes Berg   genetlink: make n...
1303
1304
  static int __net_init genl_pernet_init(struct net *net)
  {
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
1305
1306
  	struct netlink_kernel_cfg cfg = {
  		.input		= genl_rcv,
9785e10ae   Pablo Neira Ayuso   netlink: kill net...
1307
  		.flags		= NL_CFG_F_NONROOT_RECV,
4d54cc321   Florian Westphal   mptcp: avoid lock...
1308
  		.bind		= genl_bind,
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
1309
  	};
134e63756   Johannes Berg   genetlink: make n...
1310
  	/* we'll bump the group number right afterwards */
9f00d9776   Pablo Neira Ayuso   netlink: hide str...
1311
  	net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg);
134e63756   Johannes Berg   genetlink: make n...
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  
  	if (!net->genl_sock && net_eq(net, &init_net))
  		panic("GENL: Cannot initialize generic netlink
  ");
  
  	if (!net->genl_sock)
  		return -ENOMEM;
  
  	return 0;
  }
  
  static void __net_exit genl_pernet_exit(struct net *net)
  {
  	netlink_kernel_release(net->genl_sock);
  	net->genl_sock = NULL;
  }
  
  static struct pernet_operations genl_pernet_ops = {
  	.init = genl_pernet_init,
  	.exit = genl_pernet_exit,
  };
482a8524f   Thomas Graf   [NETLINK]: Generi...
1333
1334
  static int __init genl_init(void)
  {
2ae0f17df   Johannes Berg   genetlink: use id...
1335
  	int err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
1336

489111e5c   Johannes Berg   genetlink: static...
1337
  	err = genl_register_family(&genl_ctrl);
482a8524f   Thomas Graf   [NETLINK]: Generi...
1338
  	if (err < 0)
134e63756   Johannes Berg   genetlink: make n...
1339
  		goto problem;
482a8524f   Thomas Graf   [NETLINK]: Generi...
1340

134e63756   Johannes Berg   genetlink: make n...
1341
1342
1343
  	err = register_pernet_subsys(&genl_pernet_ops);
  	if (err)
  		goto problem;
482a8524f   Thomas Graf   [NETLINK]: Generi...
1344
1345
  
  	return 0;
134e63756   Johannes Berg   genetlink: make n...
1346
  problem:
482a8524f   Thomas Graf   [NETLINK]: Generi...
1347
1348
  	panic("GENL: Cannot register controller: %d
  ", err);
482a8524f   Thomas Graf   [NETLINK]: Generi...
1349
  }
c62e7ac39   Daniel Lezcano   net: genetlink: M...
1350
  core_initcall(genl_init);
482a8524f   Thomas Graf   [NETLINK]: Generi...
1351

15e473046   Eric W. Biederman   netlink: Rename p...
1352
  static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
134e63756   Johannes Berg   genetlink: make n...
1353
1354
1355
1356
  			 gfp_t flags)
  {
  	struct sk_buff *tmp;
  	struct net *net, *prev = NULL;
cb9f7a9a5   Nicolas Dichtel   netlink: ensure t...
1357
  	bool delivered = false;
134e63756   Johannes Berg   genetlink: make n...
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  	int err;
  
  	for_each_net_rcu(net) {
  		if (prev) {
  			tmp = skb_clone(skb, flags);
  			if (!tmp) {
  				err = -ENOMEM;
  				goto error;
  			}
  			err = nlmsg_multicast(prev->genl_sock, tmp,
15e473046   Eric W. Biederman   netlink: Rename p...
1368
  					      portid, group, flags);
cb9f7a9a5   Nicolas Dichtel   netlink: ensure t...
1369
1370
1371
  			if (!err)
  				delivered = true;
  			else if (err != -ESRCH)
134e63756   Johannes Berg   genetlink: make n...
1372
1373
1374
1375
1376
  				goto error;
  		}
  
  		prev = net;
  	}
cb9f7a9a5   Nicolas Dichtel   netlink: ensure t...
1377
1378
1379
1380
  	err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
  	if (!err)
  		delivered = true;
  	else if (err != -ESRCH)
02a2385f3   Nicolas Dichtel   netlink: avoid a ...
1381
  		return err;
cb9f7a9a5   Nicolas Dichtel   netlink: ensure t...
1382
  	return delivered ? 0 : -ESRCH;
134e63756   Johannes Berg   genetlink: make n...
1383
1384
1385
1386
   error:
  	kfree_skb(skb);
  	return err;
  }
2ae0f17df   Johannes Berg   genetlink: use id...
1387
1388
1389
  int genlmsg_multicast_allns(const struct genl_family *family,
  			    struct sk_buff *skb, u32 portid,
  			    unsigned int group, gfp_t flags)
134e63756   Johannes Berg   genetlink: make n...
1390
  {
220815a96   Johannes Berg   genetlink: fix ge...
1391
  	if (WARN_ON_ONCE(group >= family->n_mcgrps))
2a94fe48f   Johannes Berg   genetlink: make m...
1392
  		return -EINVAL;
f9b282b36   Yajun Deng   net: netlink: add...
1393

2a94fe48f   Johannes Berg   genetlink: make m...
1394
  	group = family->mcgrp_offset + group;
15e473046   Eric W. Biederman   netlink: Rename p...
1395
  	return genlmsg_mcast(skb, portid, group, flags);
134e63756   Johannes Berg   genetlink: make n...
1396
1397
  }
  EXPORT_SYMBOL(genlmsg_multicast_allns);
263ba61d3   Pravin B Shelar   genetlink: Add ge...
1398

2ae0f17df   Johannes Berg   genetlink: use id...
1399
  void genl_notify(const struct genl_family *family, struct sk_buff *skb,
92c14d9b5   Jiri Benc   genetlink: simpli...
1400
  		 struct genl_info *info, u32 group, gfp_t flags)
263ba61d3   Pravin B Shelar   genetlink: Add ge...
1401
  {
92c14d9b5   Jiri Benc   genetlink: simpli...
1402
  	struct net *net = genl_info_net(info);
263ba61d3   Pravin B Shelar   genetlink: Add ge...
1403
  	struct sock *sk = net->genl_sock;
263ba61d3   Pravin B Shelar   genetlink: Add ge...
1404

220815a96   Johannes Berg   genetlink: fix ge...
1405
  	if (WARN_ON_ONCE(group >= family->n_mcgrps))
2a94fe48f   Johannes Berg   genetlink: make m...
1406
  		return;
f9b282b36   Yajun Deng   net: netlink: add...
1407

2a94fe48f   Johannes Berg   genetlink: make m...
1408
  	group = family->mcgrp_offset + group;
f9b282b36   Yajun Deng   net: netlink: add...
1409
1410
  	nlmsg_notify(sk, skb, info->snd_portid, group,
  		     nlmsg_report(info->nlhdr), flags);
263ba61d3   Pravin B Shelar   genetlink: Add ge...
1411
1412
  }
  EXPORT_SYMBOL(genl_notify);