Blame view

net/netlink/genetlink.c 21.5 KB
482a8524f   Thomas Graf   [NETLINK]: Generi...
1
2
3
4
5
  /*
   * NETLINK      Generic Netlink Family
   *
   * 		Authors:	Jamal Hadi Salim
   * 				Thomas Graf <tgraf@suug.ch>
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
6
   *				Johannes Berg <johannes@sipsolutions.net>
482a8524f   Thomas Graf   [NETLINK]: Generi...
7
   */
482a8524f   Thomas Graf   [NETLINK]: Generi...
8
9
  #include <linux/module.h>
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
482a8524f   Thomas Graf   [NETLINK]: Generi...
11
12
13
14
15
  #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...
16
  #include <linux/mutex.h>
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
17
  #include <linux/bitmap.h>
482a8524f   Thomas Graf   [NETLINK]: Generi...
18
19
  #include <net/sock.h>
  #include <net/genetlink.h>
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
20
  static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
482a8524f   Thomas Graf   [NETLINK]: Generi...
21

f408e0ce4   James Chapman   netlink: Export g...
22
  void genl_lock(void)
482a8524f   Thomas Graf   [NETLINK]: Generi...
23
  {
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
24
  	mutex_lock(&genl_mutex);
482a8524f   Thomas Graf   [NETLINK]: Generi...
25
  }
f408e0ce4   James Chapman   netlink: Export g...
26
  EXPORT_SYMBOL(genl_lock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
27

f408e0ce4   James Chapman   netlink: Export g...
28
  void genl_unlock(void)
482a8524f   Thomas Graf   [NETLINK]: Generi...
29
  {
14cc3e2b6   Ingo Molnar   [PATCH] sem2mutex...
30
  	mutex_unlock(&genl_mutex);
482a8524f   Thomas Graf   [NETLINK]: Generi...
31
  }
f408e0ce4   James Chapman   netlink: Export g...
32
  EXPORT_SYMBOL(genl_unlock);
482a8524f   Thomas Graf   [NETLINK]: Generi...
33
34
35
36
37
  
  #define GENL_FAM_TAB_SIZE	16
  #define GENL_FAM_TAB_MASK	(GENL_FAM_TAB_SIZE - 1)
  
  static struct list_head family_ht[GENL_FAM_TAB_SIZE];
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
38
39
40
41
42
43
44
45
46
47
  /*
   * 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.
   */
  static unsigned long mc_group_start = 0x1;
  static unsigned long *mc_groups = &mc_group_start;
  static unsigned long mc_groups_longs = 1;
482a8524f   Thomas Graf   [NETLINK]: Generi...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  static int genl_ctrl_event(int event, void *data);
  
  static inline unsigned int genl_family_hash(unsigned int id)
  {
  	return id & GENL_FAM_TAB_MASK;
  }
  
  static inline struct list_head *genl_family_chain(unsigned int id)
  {
  	return &family_ht[genl_family_hash(id)];
  }
  
  static struct genl_family *genl_family_find_byid(unsigned int id)
  {
  	struct genl_family *f;
  
  	list_for_each_entry(f, genl_family_chain(id), family_list)
  		if (f->id == id)
  			return f;
  
  	return NULL;
  }
  
  static struct genl_family *genl_family_find_byname(char *name)
  {
  	struct genl_family *f;
  	int i;
  
  	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
  		list_for_each_entry(f, genl_family_chain(i), family_list)
  			if (strcmp(f->name, name) == 0)
  				return f;
  
  	return NULL;
  }
  
  static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
  {
  	struct genl_ops *ops;
  
  	list_for_each_entry(ops, &family->ops_list, ops_list)
  		if (ops->cmd == cmd)
  			return ops;
  
  	return NULL;
  }
  
  /* Of course we are going to have problems once we hit
   * 2^16 alive types, but that can only happen by year 2K
  */
  static inline u16 genl_generate_id(void)
  {
988ade6b8   Krishna Kumar   genetlink: Optimi...
101
102
  	static u16 id_gen_idx = GENL_MIN_ID;
  	int i;
482a8524f   Thomas Graf   [NETLINK]: Generi...
103

988ade6b8   Krishna Kumar   genetlink: Optimi...
104
105
106
107
  	for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) {
  		if (!genl_family_find_byid(id_gen_idx))
  			return id_gen_idx;
  		if (++id_gen_idx > GENL_MAX_ID)
482a8524f   Thomas Graf   [NETLINK]: Generi...
108
  			id_gen_idx = GENL_MIN_ID;
988ade6b8   Krishna Kumar   genetlink: Optimi...
109
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
110

988ade6b8   Krishna Kumar   genetlink: Optimi...
111
  	return 0;
482a8524f   Thomas Graf   [NETLINK]: Generi...
112
  }
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  static struct genl_multicast_group notify_grp;
  
  /**
   * genl_register_mc_group - register a multicast group
   *
   * Registers the specified multicast group and notifies userspace
   * about the new group.
   *
   * Returns 0 on success or a negative error code.
   *
   * @family: The generic netlink family the group shall be registered for.
   * @grp: The group to register, must have a name.
   */
  int genl_register_mc_group(struct genl_family *family,
  			   struct genl_multicast_group *grp)
  {
  	int id;
  	unsigned long *new_groups;
b1f571955   Brian Haley   netlink: silence ...
131
  	int err = 0;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  
  	BUG_ON(grp->name[0] == '\0');
  
  	genl_lock();
  
  	/* special-case our own group */
  	if (grp == &notify_grp)
  		id = GENL_ID_CTRL;
  	else
  		id = find_first_zero_bit(mc_groups,
  					 mc_groups_longs * BITS_PER_LONG);
  
  
  	if (id >= mc_groups_longs * BITS_PER_LONG) {
  		size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
  
  		if (mc_groups == &mc_group_start) {
  			new_groups = kzalloc(nlen, GFP_KERNEL);
  			if (!new_groups) {
  				err = -ENOMEM;
  				goto out;
  			}
  			mc_groups = new_groups;
  			*mc_groups = mc_group_start;
  		} else {
  			new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
  			if (!new_groups) {
  				err = -ENOMEM;
  				goto out;
  			}
  			mc_groups = new_groups;
  			mc_groups[mc_groups_longs] = 0;
  		}
  		mc_groups_longs++;
  	}
134e63756   Johannes Berg   genetlink: make n...
167
168
  	if (family->netnsok) {
  		struct net *net;
d136f1bd3   Johannes Berg   genetlink: fix ne...
169
  		netlink_table_grab();
134e63756   Johannes Berg   genetlink: make n...
170
171
  		rcu_read_lock();
  		for_each_net_rcu(net) {
d136f1bd3   Johannes Berg   genetlink: fix ne...
172
  			err = __netlink_change_ngroups(net->genl_sock,
134e63756   Johannes Berg   genetlink: make n...
173
174
175
176
177
178
179
180
181
  					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.
  				 */
  				rcu_read_unlock();
d136f1bd3   Johannes Berg   genetlink: fix ne...
182
  				netlink_table_ungrab();
134e63756   Johannes Berg   genetlink: make n...
183
184
185
186
  				goto out;
  			}
  		}
  		rcu_read_unlock();
d136f1bd3   Johannes Berg   genetlink: fix ne...
187
  		netlink_table_ungrab();
134e63756   Johannes Berg   genetlink: make n...
188
189
190
191
192
193
  	} else {
  		err = netlink_change_ngroups(init_net.genl_sock,
  					     mc_groups_longs * BITS_PER_LONG);
  		if (err)
  			goto out;
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
194
195
196
197
198
199
200
201
202
  
  	grp->id = id;
  	set_bit(id, mc_groups);
  	list_add_tail(&grp->list, &family->mcast_groups);
  	grp->family = family;
  
  	genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
   out:
  	genl_unlock();
79d310d01   Thomas Graf   [GENETLINK]: Corr...
203
  	return err;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
204
205
  }
  EXPORT_SYMBOL(genl_register_mc_group);
79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
206
207
208
  static void __genl_unregister_mc_group(struct genl_family *family,
  				       struct genl_multicast_group *grp)
  {
134e63756   Johannes Berg   genetlink: make n...
209
  	struct net *net;
79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
210
  	BUG_ON(grp->family != family);
134e63756   Johannes Berg   genetlink: make n...
211

b8273570f   Johannes Berg   genetlink: fix ne...
212
  	netlink_table_grab();
134e63756   Johannes Berg   genetlink: make n...
213
214
  	rcu_read_lock();
  	for_each_net_rcu(net)
b8273570f   Johannes Berg   genetlink: fix ne...
215
  		__netlink_clear_multicast_users(net->genl_sock, grp->id);
134e63756   Johannes Berg   genetlink: make n...
216
  	rcu_read_unlock();
b8273570f   Johannes Berg   genetlink: fix ne...
217
  	netlink_table_ungrab();
134e63756   Johannes Berg   genetlink: make n...
218

79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
219
220
221
222
223
224
  	clear_bit(grp->id, mc_groups);
  	list_del(&grp->list);
  	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
  	grp->id = 0;
  	grp->family = NULL;
  }
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  /**
   * genl_unregister_mc_group - unregister a multicast group
   *
   * Unregisters the specified multicast group and notifies userspace
   * about it. All current listeners on the group are removed.
   *
   * Note: It is not necessary to unregister all multicast groups before
   *       unregistering the family, unregistering the family will cause
   *       all assigned multicast groups to be unregistered automatically.
   *
   * @family: Generic netlink family the group belongs to.
   * @grp: The group to unregister, must have been registered successfully
   *	 previously.
   */
  void genl_unregister_mc_group(struct genl_family *family,
  			      struct genl_multicast_group *grp)
  {
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
242
  	genl_lock();
79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
243
  	__genl_unregister_mc_group(family, grp);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
244
245
  	genl_unlock();
  }
3efb40c2c   Inaky Perez-Gonzalez   genetlink: export...
246
  EXPORT_SYMBOL(genl_unregister_mc_group);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
247
248
249
250
251
252
  
  static void genl_unregister_mc_groups(struct genl_family *family)
  {
  	struct genl_multicast_group *grp, *tmp;
  
  	list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
79dc4386a   Thomas Graf   [GENETLINK]: Fix ...
253
  		__genl_unregister_mc_group(family, grp);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
254
  }
482a8524f   Thomas Graf   [NETLINK]: Generi...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  /**
   * genl_register_ops - register generic netlink operations
   * @family: generic netlink family
   * @ops: operations to be registered
   *
   * Registers the specified operations and assigns them to the specified
   * family. Either a doit or dumpit callback must be specified or the
   * operation will fail. Only one operation structure per command
   * identifier may be registered.
   *
   * See include/net/genetlink.h for more documenation on the operations
   * structure.
   *
   * Returns 0 on success or a negative error code.
   */
  int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
  {
  	int err = -EINVAL;
  
  	if (ops->dumpit == NULL && ops->doit == NULL)
  		goto errout;
  
  	if (genl_get_cmd(ops->cmd, family)) {
  		err = -EEXIST;
  		goto errout;
  	}
334c29a64   Jamal Hadi Salim   [GENETLINK]: Move...
281
  	if (ops->dumpit)
334c29a64   Jamal Hadi Salim   [GENETLINK]: Move...
282
  		ops->flags |= GENL_CMD_CAP_DUMP;
48d4ed7a8   Jamal Hadi Salim   [GENETLINK]: Fix ...
283
284
  	if (ops->doit)
  		ops->flags |= GENL_CMD_CAP_DO;
334c29a64   Jamal Hadi Salim   [GENETLINK]: Move...
285
286
  	if (ops->policy)
  		ops->flags |= GENL_CMD_CAP_HASPOL;
482a8524f   Thomas Graf   [NETLINK]: Generi...
287
288
289
290
291
292
293
294
295
  	genl_lock();
  	list_add_tail(&ops->ops_list, &family->ops_list);
  	genl_unlock();
  
  	genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
  	err = 0;
  errout:
  	return err;
  }
416c2f9cf   Changli Gao   genetlink: cleanu...
296
  EXPORT_SYMBOL(genl_register_ops);
482a8524f   Thomas Graf   [NETLINK]: Generi...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  
  /**
   * genl_unregister_ops - unregister generic netlink operations
   * @family: generic netlink family
   * @ops: operations to be unregistered
   *
   * Unregisters the specified operations and unassigns them from the
   * specified family. The operation blocks until the current message
   * processing has finished and doesn't start again until the
   * unregister process has finished.
   *
   * Note: It is not necessary to unregister all operations before
   *       unregistering the family, unregistering the family will cause
   *       all assigned operations to be unregistered automatically.
   *
   * Returns 0 on success or a negative error code.
   */
  int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
  {
  	struct genl_ops *rc;
  
  	genl_lock();
  	list_for_each_entry(rc, &family->ops_list, ops_list) {
  		if (rc == ops) {
  			list_del(&ops->ops_list);
  			genl_unlock();
  			genl_ctrl_event(CTRL_CMD_DELOPS, ops);
  			return 0;
  		}
  	}
  	genl_unlock();
  
  	return -ENOENT;
  }
416c2f9cf   Changli Gao   genetlink: cleanu...
331
  EXPORT_SYMBOL(genl_unregister_ops);
482a8524f   Thomas Graf   [NETLINK]: Generi...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  
  /**
   * genl_register_family - register a generic netlink family
   * @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.
   * The family id may equal GENL_ID_GENERATE causing an unique id to
   * be automatically generated and assigned.
   *
   * Return 0 on success or a negative error code.
   */
  int genl_register_family(struct genl_family *family)
  {
  	int err = -EINVAL;
  
  	if (family->id && family->id < GENL_MIN_ID)
  		goto errout;
  
  	if (family->id > GENL_MAX_ID)
  		goto errout;
  
  	INIT_LIST_HEAD(&family->ops_list);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
355
  	INIT_LIST_HEAD(&family->mcast_groups);
482a8524f   Thomas Graf   [NETLINK]: Generi...
356
357
358
359
360
361
362
  
  	genl_lock();
  
  	if (genl_family_find_byname(family->name)) {
  		err = -EEXIST;
  		goto errout_locked;
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
363
364
365
366
367
368
369
370
371
  	if (family->id == GENL_ID_GENERATE) {
  		u16 newid = genl_generate_id();
  
  		if (!newid) {
  			err = -ENOMEM;
  			goto errout_locked;
  		}
  
  		family->id = newid;
93860b08e   Krishna Kumar   genetlink: Optimi...
372
373
374
  	} else if (genl_family_find_byid(family->id)) {
  		err = -EEXIST;
  		goto errout_locked;
482a8524f   Thomas Graf   [NETLINK]: Generi...
375
376
377
378
379
380
381
  	}
  
  	if (family->maxattr) {
  		family->attrbuf = kmalloc((family->maxattr+1) *
  					sizeof(struct nlattr *), GFP_KERNEL);
  		if (family->attrbuf == NULL) {
  			err = -ENOMEM;
e200bd806   Jamal Hadi Salim   [NETLINK] genetli...
382
  			goto errout_locked;
482a8524f   Thomas Graf   [NETLINK]: Generi...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  		}
  	} else
  		family->attrbuf = NULL;
  
  	list_add_tail(&family->family_list, genl_family_chain(family->id));
  	genl_unlock();
  
  	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
  
  	return 0;
  
  errout_locked:
  	genl_unlock();
  errout:
  	return err;
  }
416c2f9cf   Changli Gao   genetlink: cleanu...
399
  EXPORT_SYMBOL(genl_register_family);
482a8524f   Thomas Graf   [NETLINK]: Generi...
400
401
  
  /**
a7b11d738   MichaÅ‚ MirosÅ‚aw   genetlink: Introd...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
   * genl_register_family_with_ops - register a generic netlink family
   * @family: generic netlink family
   * @ops: operations to be registered
   * @n_ops: number of elements to register
   *
   * Registers the specified family and operations from the specified table.
   * Only one family may be registered with the same family name or identifier.
   *
   * The family id may equal GENL_ID_GENERATE causing an unique id to
   * be automatically generated and assigned.
   *
   * Either a doit or dumpit callback must be specified for every registered
   * operation or the function will fail. Only one operation structure per
   * command identifier may be registered.
   *
   * See include/net/genetlink.h for more documenation on the operations
   * structure.
   *
   * This is equivalent to calling genl_register_family() followed by
   * genl_register_ops() for every operation entry in the table taking
   * care to unregister the family on error path.
   *
   * Return 0 on success or a negative error code.
   */
  int genl_register_family_with_ops(struct genl_family *family,
  	struct genl_ops *ops, size_t n_ops)
  {
  	int err, i;
  
  	err = genl_register_family(family);
  	if (err)
  		return err;
  
  	for (i = 0; i < n_ops; ++i, ++ops) {
  		err = genl_register_ops(family, ops);
  		if (err)
  			goto err_out;
  	}
  	return 0;
  err_out:
  	genl_unregister_family(family);
  	return err;
  }
  EXPORT_SYMBOL(genl_register_family_with_ops);
  
  /**
482a8524f   Thomas Graf   [NETLINK]: Generi...
448
449
450
451
452
453
454
455
456
457
458
459
   * genl_unregister_family - unregister generic netlink family
   * @family: generic netlink family
   *
   * Unregisters the specified family.
   *
   * Returns 0 on success or a negative error code.
   */
  int genl_unregister_family(struct genl_family *family)
  {
  	struct genl_family *rc;
  
  	genl_lock();
910d6c320   Pavel Emelyanov   [GENETLINK]: Rela...
460
  	genl_unregister_mc_groups(family);
482a8524f   Thomas Graf   [NETLINK]: Generi...
461
462
463
464
465
466
467
  	list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
  		if (family->id != rc->id || strcmp(rc->name, family->name))
  			continue;
  
  		list_del(&rc->family_list);
  		INIT_LIST_HEAD(&family->ops_list);
  		genl_unlock();
482a8524f   Thomas Graf   [NETLINK]: Generi...
468
469
470
471
472
473
474
475
476
  		kfree(family->attrbuf);
  		genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
  		return 0;
  	}
  
  	genl_unlock();
  
  	return -ENOENT;
  }
416c2f9cf   Changli Gao   genetlink: cleanu...
477
  EXPORT_SYMBOL(genl_unregister_family);
482a8524f   Thomas Graf   [NETLINK]: Generi...
478

1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
479
  static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
482a8524f   Thomas Graf   [NETLINK]: Generi...
480
481
482
  {
  	struct genl_ops *ops;
  	struct genl_family *family;
134e63756   Johannes Berg   genetlink: make n...
483
  	struct net *net = sock_net(skb->sk);
482a8524f   Thomas Graf   [NETLINK]: Generi...
484
485
  	struct genl_info info;
  	struct genlmsghdr *hdr = nlmsg_data(nlh);
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
486
  	int hdrlen, err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
487

746fac4dc   YOSHIFUJI Hideaki   [NET] NETLINK: Fi...
488
  	family = genl_family_find_byid(nlh->nlmsg_type);
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
489
490
  	if (family == NULL)
  		return -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
491

134e63756   Johannes Berg   genetlink: make n...
492
493
494
  	/* this family doesn't exist in this netns */
  	if (!family->netnsok && !net_eq(net, &init_net))
  		return -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
495
496
  	hdrlen = GENL_HDRLEN + family->hdrsize;
  	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
497
  		return -EINVAL;
482a8524f   Thomas Graf   [NETLINK]: Generi...
498
499
  
  	ops = genl_get_cmd(hdr->cmd, family);
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
500
501
  	if (ops == NULL)
  		return -EOPNOTSUPP;
482a8524f   Thomas Graf   [NETLINK]: Generi...
502

1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
503
504
505
  	if ((ops->flags & GENL_ADMIN_PERM) &&
  	    security_netlink_recv(skb, CAP_NET_ADMIN))
  		return -EPERM;
482a8524f   Thomas Graf   [NETLINK]: Generi...
506

b8f3ab429   David S. Miller   Revert "netlink: ...
507
  	if (nlh->nlmsg_flags & NLM_F_DUMP) {
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
508
509
  		if (ops->dumpit == NULL)
  			return -EOPNOTSUPP;
482a8524f   Thomas Graf   [NETLINK]: Generi...
510

6d1a3fb56   Patrick McHardy   netlink: genl: fi...
511
  		genl_unlock();
134e63756   Johannes Berg   genetlink: make n...
512
  		err = netlink_dump_start(net->genl_sock, skb, nlh,
c7ac8679b   Greg Rose   rtnetlink: Comput...
513
  					 ops->dumpit, ops->done, 0);
6d1a3fb56   Patrick McHardy   netlink: genl: fi...
514
515
  		genl_lock();
  		return err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
516
  	}
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
517
518
  	if (ops->doit == NULL)
  		return -EOPNOTSUPP;
482a8524f   Thomas Graf   [NETLINK]: Generi...
519
520
521
522
523
  
  	if (family->attrbuf) {
  		err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
  				  ops->policy);
  		if (err < 0)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
524
  			return err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
525
526
527
528
529
530
531
532
  	}
  
  	info.snd_seq = nlh->nlmsg_seq;
  	info.snd_pid = NETLINK_CB(skb).pid;
  	info.nlhdr = nlh;
  	info.genlhdr = nlmsg_data(nlh);
  	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
  	info.attrs = family->attrbuf;
134e63756   Johannes Berg   genetlink: make n...
533
  	genl_info_net_set(&info, net);
ff4c92d85   Johannes Berg   genetlink: introd...
534
  	memset(&info.user_ptr, 0, sizeof(info.user_ptr));
482a8524f   Thomas Graf   [NETLINK]: Generi...
535

ff4c92d85   Johannes Berg   genetlink: introd...
536
537
538
539
540
541
542
543
544
545
546
547
  	if (family->pre_doit) {
  		err = family->pre_doit(ops, skb, &info);
  		if (err)
  			return err;
  	}
  
  	err = ops->doit(skb, &info);
  
  	if (family->post_doit)
  		family->post_doit(ops, skb, &info);
  
  	return err;
482a8524f   Thomas Graf   [NETLINK]: Generi...
548
  }
cd40b7d39   Denis V. Lunev   [NET]: make netli...
549
  static void genl_rcv(struct sk_buff *skb)
482a8524f   Thomas Graf   [NETLINK]: Generi...
550
  {
cd40b7d39   Denis V. Lunev   [NET]: make netli...
551
552
553
  	genl_lock();
  	netlink_rcv_skb(skb, &genl_rcv_msg);
  	genl_unlock();
482a8524f   Thomas Graf   [NETLINK]: Generi...
554
555
556
557
558
  }
  
  /**************************************************************************
   * Controller
   **************************************************************************/
17c157c88   Thomas Graf   [GENL]: Add genlm...
559
560
561
  static struct genl_family genl_ctrl = {
  	.id = GENL_ID_CTRL,
  	.name = "nlctrl",
334c29a64   Jamal Hadi Salim   [GENETLINK]: Move...
562
  	.version = 0x2,
17c157c88   Thomas Graf   [GENL]: Add genlm...
563
  	.maxattr = CTRL_ATTR_MAX,
134e63756   Johannes Berg   genetlink: make n...
564
  	.netnsok = true,
17c157c88   Thomas Graf   [GENL]: Add genlm...
565
  };
482a8524f   Thomas Graf   [NETLINK]: Generi...
566
567
568
569
  static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
  			  u32 flags, struct sk_buff *skb, u8 cmd)
  {
  	void *hdr;
17c157c88   Thomas Graf   [GENL]: Add genlm...
570
  	hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
482a8524f   Thomas Graf   [NETLINK]: Generi...
571
572
573
574
575
  	if (hdr == NULL)
  		return -1;
  
  	NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
  	NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
eb328111e   Thomas Graf   [GENL]: Provide m...
576
577
578
  	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);
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
579
580
581
582
  	if (!list_empty(&family->ops_list)) {
  		struct nlattr *nla_ops;
  		struct genl_ops *ops;
  		int idx = 1;
eb328111e   Thomas Graf   [GENL]: Provide m...
583

e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
584
585
  		nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
  		if (nla_ops == NULL)
eb328111e   Thomas Graf   [GENL]: Provide m...
586
  			goto nla_put_failure;
e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
587
588
  		list_for_each_entry(ops, &family->ops_list, ops_list) {
  			struct nlattr *nest;
eb328111e   Thomas Graf   [GENL]: Provide m...
589

e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
590
591
592
  			nest = nla_nest_start(skb, idx++);
  			if (nest == NULL)
  				goto nla_put_failure;
eb328111e   Thomas Graf   [GENL]: Provide m...
593

e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
594
595
  			NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
  			NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
eb328111e   Thomas Graf   [GENL]: Provide m...
596

e94ef6820   Thomas Graf   [GENETLINK] ctrl:...
597
598
599
600
601
  			nla_nest_end(skb, nest);
  		}
  
  		nla_nest_end(skb, nla_ops);
  	}
482a8524f   Thomas Graf   [NETLINK]: Generi...
602

2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  	if (!list_empty(&family->mcast_groups)) {
  		struct genl_multicast_group *grp;
  		struct nlattr *nla_grps;
  		int idx = 1;
  
  		nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
  		if (nla_grps == NULL)
  			goto nla_put_failure;
  
  		list_for_each_entry(grp, &family->mcast_groups, list) {
  			struct nlattr *nest;
  
  			nest = nla_nest_start(skb, idx++);
  			if (nest == NULL)
  				goto nla_put_failure;
  
  			NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
  			NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
  				       grp->name);
  
  			nla_nest_end(skb, nest);
  		}
  		nla_nest_end(skb, nla_grps);
  	}
  
  	return genlmsg_end(skb, hdr);
  
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
631
632
  	genlmsg_cancel(skb, hdr);
  	return -EMSGSIZE;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  }
  
  static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
  				u32 seq, u32 flags, struct sk_buff *skb,
  				u8 cmd)
  {
  	void *hdr;
  	struct nlattr *nla_grps;
  	struct nlattr *nest;
  
  	hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
  	if (hdr == NULL)
  		return -1;
  
  	NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
  	NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
  
  	nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
  	if (nla_grps == NULL)
  		goto nla_put_failure;
  
  	nest = nla_nest_start(skb, 1);
  	if (nest == NULL)
  		goto nla_put_failure;
  
  	NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
  	NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
  		       grp->name);
  
  	nla_nest_end(skb, nest);
  	nla_nest_end(skb, nla_grps);
482a8524f   Thomas Graf   [NETLINK]: Generi...
664
665
666
  	return genlmsg_end(skb, hdr);
  
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
667
668
  	genlmsg_cancel(skb, hdr);
  	return -EMSGSIZE;
482a8524f   Thomas Graf   [NETLINK]: Generi...
669
670
671
672
673
674
675
  }
  
  static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
  {
  
  	int i, n = 0;
  	struct genl_family *rt;
134e63756   Johannes Berg   genetlink: make n...
676
  	struct net *net = sock_net(skb->sk);
482a8524f   Thomas Graf   [NETLINK]: Generi...
677
678
  	int chains_to_skip = cb->args[0];
  	int fams_to_skip = cb->args[1];
e1d5a0107   Samir Bellabes   genetlink: optimi...
679
  	for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
482a8524f   Thomas Graf   [NETLINK]: Generi...
680
681
  		n = 0;
  		list_for_each_entry(rt, genl_family_chain(i), family_list) {
134e63756   Johannes Berg   genetlink: make n...
682
683
  			if (!rt->netnsok && !net_eq(net, &init_net))
  				continue;
482a8524f   Thomas Graf   [NETLINK]: Generi...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
  			if (++n < fams_to_skip)
  				continue;
  			if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
  					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
  					   skb, CTRL_CMD_NEWFAMILY) < 0)
  				goto errout;
  		}
  
  		fams_to_skip = 0;
  	}
  
  errout:
  	cb->args[0] = i;
  	cb->args[1] = n;
  
  	return skb->len;
  }
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
701
702
  static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
  					     u32 pid, int seq, u8 cmd)
482a8524f   Thomas Graf   [NETLINK]: Generi...
703
704
705
  {
  	struct sk_buff *skb;
  	int err;
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
706
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
482a8524f   Thomas Graf   [NETLINK]: Generi...
707
708
709
710
711
712
713
714
715
716
717
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
  
  	err = ctrl_fill_info(family, pid, seq, 0, skb, cmd);
  	if (err < 0) {
  		nlmsg_free(skb);
  		return ERR_PTR(err);
  	}
  
  	return skb;
  }
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
  					    u32 pid, int seq, u8 cmd)
  {
  	struct sk_buff *skb;
  	int err;
  
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  	if (skb == NULL)
  		return ERR_PTR(-ENOBUFS);
  
  	err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
  	if (err < 0) {
  		nlmsg_free(skb);
  		return ERR_PTR(err);
  	}
  
  	return skb;
  }
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
736
  static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
482a8524f   Thomas Graf   [NETLINK]: Generi...
737
  	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
5176f91ea   Thomas Graf   [NETLINK]: Make u...
738
739
  	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
  				    .len = GENL_NAMSIZ - 1 },
482a8524f   Thomas Graf   [NETLINK]: Generi...
740
741
742
743
744
745
746
747
748
749
750
  };
  
  static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
  {
  	struct sk_buff *msg;
  	struct genl_family *res = NULL;
  	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...
751
  		err = -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
752
753
754
  	}
  
  	if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
5176f91ea   Thomas Graf   [NETLINK]: Make u...
755
  		char *name;
482a8524f   Thomas Graf   [NETLINK]: Generi...
756

5176f91ea   Thomas Graf   [NETLINK]: Make u...
757
  		name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
482a8524f   Thomas Graf   [NETLINK]: Generi...
758
  		res = genl_family_find_byname(name);
134e63756   Johannes Berg   genetlink: make n...
759
  		err = -ENOENT;
482a8524f   Thomas Graf   [NETLINK]: Generi...
760
  	}
134e63756   Johannes Berg   genetlink: make n...
761
762
763
764
765
766
  	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...
767
  	}
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
768
769
  	msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
  				    CTRL_CMD_NEWFAMILY);
134e63756   Johannes Berg   genetlink: make n...
770
771
  	if (IS_ERR(msg))
  		return PTR_ERR(msg);
482a8524f   Thomas Graf   [NETLINK]: Generi...
772

134e63756   Johannes Berg   genetlink: make n...
773
  	return genlmsg_reply(msg, info);
482a8524f   Thomas Graf   [NETLINK]: Generi...
774
775
776
777
778
  }
  
  static int genl_ctrl_event(int event, void *data)
  {
  	struct sk_buff *msg;
134e63756   Johannes Berg   genetlink: make n...
779
780
  	struct genl_family *family;
  	struct genl_multicast_group *grp;
482a8524f   Thomas Graf   [NETLINK]: Generi...
781

134e63756   Johannes Berg   genetlink: make n...
782
783
  	/* genl is still initialising */
  	if (!init_net.genl_sock)
482a8524f   Thomas Graf   [NETLINK]: Generi...
784
785
786
787
788
  		return 0;
  
  	switch (event) {
  	case CTRL_CMD_NEWFAMILY:
  	case CTRL_CMD_DELFAMILY:
134e63756   Johannes Berg   genetlink: make n...
789
790
  		family = data;
  		msg = ctrl_build_family_msg(family, 0, 0, event);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
791
792
793
  		break;
  	case CTRL_CMD_NEWMCAST_GRP:
  	case CTRL_CMD_DELMCAST_GRP:
134e63756   Johannes Berg   genetlink: make n...
794
795
  		grp = data;
  		family = grp->family;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
796
  		msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
482a8524f   Thomas Graf   [NETLINK]: Generi...
797
  		break;
134e63756   Johannes Berg   genetlink: make n...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
  	default:
  		return -EINVAL;
  	}
  
  	if (IS_ERR(msg))
  		return PTR_ERR(msg);
  
  	if (!family->netnsok) {
  		genlmsg_multicast_netns(&init_net, msg, 0,
  					GENL_ID_CTRL, GFP_KERNEL);
  	} else {
  		rcu_read_lock();
  		genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC);
  		rcu_read_unlock();
482a8524f   Thomas Graf   [NETLINK]: Generi...
812
813
814
815
816
817
818
819
820
821
822
  	}
  
  	return 0;
  }
  
  static struct genl_ops genl_ctrl_ops = {
  	.cmd		= CTRL_CMD_GETFAMILY,
  	.doit		= ctrl_getfamily,
  	.dumpit		= ctrl_dumpfamily,
  	.policy		= ctrl_policy,
  };
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
823
824
825
  static struct genl_multicast_group notify_grp = {
  	.name		= "notify",
  };
134e63756   Johannes Berg   genetlink: make n...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
  static int __net_init genl_pernet_init(struct net *net)
  {
  	/* we'll bump the group number right afterwards */
  	net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
  					       genl_rcv, &genl_mutex,
  					       THIS_MODULE);
  
  	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...
853
854
855
856
857
858
  static int __init genl_init(void)
  {
  	int i, err;
  
  	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
  		INIT_LIST_HEAD(&family_ht[i]);
652c67174   Changli Gao   genetlink: use ge...
859
  	err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1);
482a8524f   Thomas Graf   [NETLINK]: Generi...
860
  	if (err < 0)
134e63756   Johannes Berg   genetlink: make n...
861
  		goto problem;
482a8524f   Thomas Graf   [NETLINK]: Generi...
862
863
  
  	netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
864

134e63756   Johannes Berg   genetlink: make n...
865
866
867
  	err = register_pernet_subsys(&genl_pernet_ops);
  	if (err)
  		goto problem;
482a8524f   Thomas Graf   [NETLINK]: Generi...
868

2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
869
870
  	err = genl_register_mc_group(&genl_ctrl, &notify_grp);
  	if (err < 0)
134e63756   Johannes Berg   genetlink: make n...
871
  		goto problem;
2dbba6f77   Johannes Berg   [GENETLINK]: Dyna...
872

482a8524f   Thomas Graf   [NETLINK]: Generi...
873
  	return 0;
134e63756   Johannes Berg   genetlink: make n...
874
  problem:
482a8524f   Thomas Graf   [NETLINK]: Generi...
875
876
  	panic("GENL: Cannot register controller: %d
  ", err);
482a8524f   Thomas Graf   [NETLINK]: Generi...
877
878
879
  }
  
  subsys_initcall(genl_init);
134e63756   Johannes Berg   genetlink: make n...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
  			 gfp_t flags)
  {
  	struct sk_buff *tmp;
  	struct net *net, *prev = NULL;
  	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,
  					      pid, group, flags);
  			if (err)
  				goto error;
  		}
  
  		prev = net;
  	}
  
  	return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
   error:
  	kfree_skb(skb);
  	return err;
  }
  
  int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, unsigned int group,
  			    gfp_t flags)
  {
  	return genlmsg_mcast(skb, pid, group, flags);
  }
  EXPORT_SYMBOL(genlmsg_multicast_allns);