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