• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/genl/ctrl.c		Generic Netlink Controller
4  *
5  *	This library is free software; you can redistribute it and/or
6  *	modify it under the terms of the GNU Lesser General Public
7  *	License as published by the Free Software Foundation version 2.1
8  *	of the License.
9  *
10  * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
11  */
12 
13 /**
14  * @ingroup genl
15  * @defgroup genl_ctrl Controller (Resolver)
16  *
17  * Resolves Generic Netlink family names to numeric identifiers.
18  *
19  * The controller is a component in the kernel that resolves Generic Netlink
20  * family names to their numeric identifiers. This module provides functions
21  * to query the controller to access the resolving functionality.
22  * @{
23  */
24 
25 #include <netlink-private/genl.h>
26 #include <netlink/netlink.h>
27 #include <netlink/genl/genl.h>
28 #include <netlink/genl/family.h>
29 #include <netlink/genl/mngt.h>
30 #include <netlink/genl/ctrl.h>
31 #include <netlink/utils.h>
32 
33 /** @cond SKIP */
34 #define CTRL_VERSION		0x0001
35 
36 static struct nl_cache_ops genl_ctrl_ops;
37 
ctrl_request_update(struct nl_cache * c,struct nl_sock * h)38 static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
39 {
40 	return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
41 				CTRL_VERSION, NLM_F_DUMP);
42 }
43 
44 static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
45 	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
46 	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_STRING,
47 				    .maxlen = GENL_NAMSIZ },
48 	[CTRL_ATTR_VERSION]	= { .type = NLA_U32 },
49 	[CTRL_ATTR_HDRSIZE]	= { .type = NLA_U32 },
50 	[CTRL_ATTR_MAXATTR]	= { .type = NLA_U32 },
51 	[CTRL_ATTR_OPS]		= { .type = NLA_NESTED },
52 	[CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
53 };
54 
55 static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
56 	[CTRL_ATTR_OP_ID]	= { .type = NLA_U32 },
57 	[CTRL_ATTR_OP_FLAGS]	= { .type = NLA_U32 },
58 };
59 
60 static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
61 	[CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
62 	[CTRL_ATTR_MCAST_GRP_ID]   = { .type = NLA_U32 },
63 };
64 
parse_mcast_grps(struct genl_family * family,struct nlattr * grp_attr)65 static int parse_mcast_grps(struct genl_family *family, struct nlattr *grp_attr)
66 {
67 	struct nlattr *nla;
68 	int remaining, err;
69 
70 	if (!grp_attr)
71 		BUG();
72 
73 	nla_for_each_nested(nla, grp_attr, remaining) {
74 		struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
75 		int id;
76 		const char * name;
77 
78 		err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
79 				       family_grp_policy);
80 		if (err < 0)
81 			goto errout;
82 
83 		if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
84 			err = -NLE_MISSING_ATTR;
85 			goto errout;
86 		}
87 		id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
88 
89 		if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
90 			err = -NLE_MISSING_ATTR;
91 			goto errout;
92 		}
93 		name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
94 
95 		err = genl_family_add_grp(family, id, name);
96 		if (err < 0)
97 			goto errout;
98 	}
99 
100 	err = 0;
101 
102 errout:
103 	return err;
104 }
105 
ctrl_msg_parser(struct nl_cache_ops * ops,struct genl_cmd * cmd,struct genl_info * info,void * arg)106 static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
107 			   struct genl_info *info, void *arg)
108 {
109 	struct genl_family *family;
110 	struct nl_parser_param *pp = arg;
111 	int err;
112 
113 	family = genl_family_alloc();
114 	if (family == NULL) {
115 		err = -NLE_NOMEM;
116 		goto errout;
117 	}
118 
119 	if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
120 		err = -NLE_MISSING_ATTR;
121 		goto errout;
122 	}
123 
124 	if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
125 		err = -NLE_MISSING_ATTR;
126 		goto errout;
127 	}
128 
129 	family->ce_msgtype = info->nlh->nlmsg_type;
130 	genl_family_set_id(family,
131 			   nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
132 	genl_family_set_name(family,
133 		     nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
134 
135 	if (info->attrs[CTRL_ATTR_VERSION]) {
136 		uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
137 		genl_family_set_version(family, version);
138 	}
139 
140 	if (info->attrs[CTRL_ATTR_HDRSIZE]) {
141 		uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
142 		genl_family_set_hdrsize(family, hdrsize);
143 	}
144 
145 	if (info->attrs[CTRL_ATTR_MAXATTR]) {
146 		uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
147 		genl_family_set_maxattr(family, maxattr);
148 	}
149 
150 	if (info->attrs[CTRL_ATTR_OPS]) {
151 		struct nlattr *nla, *nla_ops;
152 		int remaining;
153 
154 		nla_ops = info->attrs[CTRL_ATTR_OPS];
155 		nla_for_each_nested(nla, nla_ops, remaining) {
156 			struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
157 			int flags = 0, id;
158 
159 			err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
160 					       family_op_policy);
161 			if (err < 0)
162 				goto errout;
163 
164 			if (tb[CTRL_ATTR_OP_ID] == NULL) {
165 				err = -NLE_MISSING_ATTR;
166 				goto errout;
167 			}
168 
169 			id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
170 
171 			if (tb[CTRL_ATTR_OP_FLAGS])
172 				flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
173 
174 			err = genl_family_add_op(family, id, flags);
175 			if (err < 0)
176 				goto errout;
177 
178 		}
179 	}
180 
181 	if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
182 		err = parse_mcast_grps(family, info->attrs[CTRL_ATTR_MCAST_GROUPS]);
183 		if (err < 0)
184 			goto errout;
185 	}
186 
187 	err = pp->pp_cb((struct nl_object *) family, pp);
188 errout:
189 	genl_family_put(family);
190 	return err;
191 }
192 
193 /**
194  * process responses from from the query sent by genl_ctrl_probe_by_name
195  * @arg nl_msg		Returned message.
196  * @arg name		genl_family structure to fill out.
197  *
198  * Process returned messages, filling out the missing informatino in the
199  * genl_family structure
200  *
201  * @return Indicator to keep processing frames or not
202  *
203  */
probe_response(struct nl_msg * msg,void * arg)204 static int probe_response(struct nl_msg *msg, void *arg)
205 {
206 	struct nlattr *tb[CTRL_ATTR_MAX+1];
207 	struct nlmsghdr *nlh = nlmsg_hdr(msg);
208 	struct genl_family *ret = (struct genl_family *)arg;
209 
210 	if (genlmsg_parse(nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy))
211 		return NL_SKIP;
212 
213 	if (tb[CTRL_ATTR_FAMILY_ID])
214 		genl_family_set_id(ret, nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
215 
216 	if (tb[CTRL_ATTR_MCAST_GROUPS])
217 		if (parse_mcast_grps(ret, tb[CTRL_ATTR_MCAST_GROUPS]) < 0)
218 			return NL_SKIP;
219 
220 	return NL_STOP;
221 }
222 
223 /**
224  * Look up generic netlink family by family name querying the kernel directly
225  * @arg sk		Socket.
226  * @arg name		Family name.
227  *
228  * Directly query's the kernel for a given family name.  The caller will own a
229  * reference on the returned object which needsd to be given back after usage
230  * using genl_family_put.
231  *
232  * Note: This API call differs from genl_ctrl_search_by_name in that it querys
233  * the kernel directly, alowing for module autoload to take place to resolve the
234  * family request. Using an nl_cache prevents that operation
235  *
236  * @return Generic netlink family object or NULL if no match was found.
237  */
genl_ctrl_probe_by_name(struct nl_sock * sk,const char * name)238 static struct genl_family *genl_ctrl_probe_by_name(struct nl_sock *sk,
239 						   const char *name)
240 {
241 	struct nl_msg *msg;
242 	struct genl_family *ret;
243 	struct nl_cb *cb, *orig;
244 	int rc;
245 
246 	ret = genl_family_alloc();
247 	if (!ret)
248 		goto out;
249 
250 	genl_family_set_name(ret, name);
251 
252 	msg = nlmsg_alloc();
253 	if (!msg)
254 		goto out_fam_free;
255 
256 	if (!(orig = nl_socket_get_cb(sk)))
257 		goto out_msg_free;
258 
259 	cb = nl_cb_clone(orig);
260 	nl_cb_put(orig);
261 	if (!cb)
262 		goto out_msg_free;
263 
264 	if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
265 			0, 0, CTRL_CMD_GETFAMILY, 1)) {
266 		BUG();
267 		goto out_cb_free;
268 	}
269 
270 	if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
271 		goto out_cb_free;
272 
273 	rc = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response,
274 		       (void *) ret);
275 	if (rc < 0)
276 		goto out_cb_free;
277 
278 	rc = nl_send_auto_complete(sk, msg);
279 	if (rc < 0)
280 		goto out_cb_free;
281 
282 	rc = nl_recvmsgs(sk, cb);
283 	if (rc < 0)
284 		goto out_cb_free;
285 
286 	/* If search was successful, request may be ACKed after data */
287 	rc = wait_for_ack(sk);
288 	if (rc < 0)
289 		goto out_cb_free;
290 
291 	if (genl_family_get_id(ret) != 0) {
292 		nlmsg_free(msg);
293 		nl_cb_put(cb);
294 		return ret;
295 	}
296 
297 out_cb_free:
298 	nl_cb_put(cb);
299 out_msg_free:
300 	nlmsg_free(msg);
301 out_fam_free:
302 	genl_family_put(ret);
303 	ret = NULL;
304 out:
305 	return ret;
306 }
307 
308 
309 /** @endcond */
310 
311 /**
312  * @name Controller Cache
313  *
314  * The controller cache allows to keep a local copy of the list of all
315  * kernel side registered Generic Netlink families to quickly resolve
316  * multiple Generic Netlink family names without requiring to communicate
317  * with the kernel for each resolving iteration.
318  *
319  * @{
320  */
321 
322 /**
323  * Allocate a new controller cache
324  * @arg sk		Generic Netlink socket
325  * @arg result		Pointer to store resulting cache
326  *
327  * Allocates a new cache mirroring the state of the controller and stores it
328  * in \c *result. The allocated cache will contain a list of all currently
329  * registered kernel side Generic Netlink families. The cache is meant to be
330  * used to resolve family names locally.
331  *
332  * @return 0 on success or a negative error code.
333  */
genl_ctrl_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)334 int genl_ctrl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
335 {
336 	return nl_cache_alloc_and_fill(&genl_ctrl_ops, sk, result);
337 }
338 
339 /**
340  * Search controller cache for a numeric address match
341  * @arg cache		Controller cache
342  * @arg id		Numeric family identifier.
343  *
344  * Searches a previously allocated controller cache and looks for an entry
345  * that matches the specified numeric family identifier \c id.  If a match
346  * is found successfully, the reference count of the matching object is
347  * increased by one before the objet is returned.
348  *
349  * @see genl_ctrl_alloc_cache()
350  * @see genl_ctrl_search_by_name()
351  * @see genl_family_put()
352  *
353  * @return Generic Netlink family object or NULL if no match was found.
354  */
genl_ctrl_search(struct nl_cache * cache,int id)355 struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
356 {
357 	struct genl_family *fam;
358 
359 	if (cache->c_ops != &genl_ctrl_ops)
360 		BUG();
361 
362 	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
363 		if (fam->gf_id == id) {
364 			nl_object_get((struct nl_object *) fam);
365 			return fam;
366 		}
367 	}
368 
369 	return NULL;
370 }
371 
372 /**
373  * Search controller cache for a family name match
374  * @arg cache		Controller cache
375  * @arg name		Name of Generic Netlink family
376  *
377  * Searches a previously allocated controller cache and looks for an entry
378  * that matches the specified family \c name. If a match is found successfully,
379  * the reference count of the matching object is increased by one before the
380  * objet is returned.
381  *
382  * @see genl_ctrl_alloc_cache()
383  * @see genl_ctrl_search()
384  * @see genl_family_put()
385  *
386  * @return Generic Netlink family object or NULL if no match was found.
387  */
genl_ctrl_search_by_name(struct nl_cache * cache,const char * name)388 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
389 					     const char *name)
390 {
391 	struct genl_family *fam;
392 
393 	if (cache->c_ops != &genl_ctrl_ops)
394 		BUG();
395 
396 	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
397 		if (!strcmp(name, fam->gf_name)) {
398 			nl_object_get((struct nl_object *) fam);
399 			return fam;
400 		}
401 	}
402 
403 	return NULL;
404 }
405 
406 /** @} */
407 
408 /**
409  * @name Direct Resolvers
410  *
411  * These functions communicate directly with the kernel and do not require
412  * a cache to be kept up to date.
413  *
414  * @{
415  */
416 
417 /**
418  * Resolve Generic Netlink family name to numeric identifier
419  * @arg sk		Generic Netlink socket.
420  * @arg name		Name of Generic Netlink family
421  *
422  * Resolves the Generic Netlink family name to the corresponding numeric
423  * family identifier. This function queries the kernel directly, use
424  * genl_ctrl_search_by_name() if you need to resolve multiple names.
425  *
426  * @see genl_ctrl_search_by_name()
427  *
428  * @return The numeric family identifier or a negative error code.
429  */
genl_ctrl_resolve(struct nl_sock * sk,const char * name)430 int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
431 {
432 	struct genl_family *family;
433 	int err;
434 
435 	family = genl_ctrl_probe_by_name(sk, name);
436 	if (family == NULL) {
437 		err = -NLE_OBJ_NOTFOUND;
438 		goto errout;
439 	}
440 
441 	err = genl_family_get_id(family);
442 	genl_family_put(family);
443 errout:
444 	return err;
445 }
446 
genl_ctrl_grp_by_name(const struct genl_family * family,const char * grp_name)447 static int genl_ctrl_grp_by_name(const struct genl_family *family,
448 				 const char *grp_name)
449 {
450 	struct genl_family_grp *grp;
451 
452 	nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
453 		if (!strcmp(grp->name, grp_name)) {
454 			return grp->id;
455 		}
456 	}
457 
458 	return -NLE_OBJ_NOTFOUND;
459 }
460 
461 /**
462  * Resolve Generic Netlink family group name
463  * @arg sk		Generic Netlink socket
464  * @arg family_name	Name of Generic Netlink family
465  * @arg grp_name	Name of group to resolve
466  *
467  * Looks up the family object and resolves the group name to the numeric
468  * group identifier.
469  *
470  * @return Numeric group identifier or a negative error code.
471  */
genl_ctrl_resolve_grp(struct nl_sock * sk,const char * family_name,const char * grp_name)472 int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
473 			  const char *grp_name)
474 {
475 
476 	struct genl_family *family;
477 	int err;
478 
479 	family = genl_ctrl_probe_by_name(sk, family_name);
480 	if (family == NULL) {
481 		err = -NLE_OBJ_NOTFOUND;
482 		goto errout;
483 	}
484 
485 	err = genl_ctrl_grp_by_name(family, grp_name);
486 	genl_family_put(family);
487 errout:
488 	return err;
489 }
490 
491 /** @} */
492 
493 /** @cond SKIP */
494 static struct genl_cmd genl_cmds[] = {
495 	{
496 		.c_id		= CTRL_CMD_NEWFAMILY,
497 		.c_name		= "NEWFAMILY" ,
498 		.c_maxattr	= CTRL_ATTR_MAX,
499 		.c_attr_policy	= ctrl_policy,
500 		.c_msg_parser	= ctrl_msg_parser,
501 	},
502 	{
503 		.c_id		= CTRL_CMD_DELFAMILY,
504 		.c_name		= "DELFAMILY" ,
505 	},
506 	{
507 		.c_id		= CTRL_CMD_GETFAMILY,
508 		.c_name		= "GETFAMILY" ,
509 	},
510 	{
511 		.c_id		= CTRL_CMD_NEWOPS,
512 		.c_name		= "NEWOPS" ,
513 	},
514 	{
515 		.c_id		= CTRL_CMD_DELOPS,
516 		.c_name		= "DELOPS" ,
517 	},
518 };
519 
520 static struct genl_ops genl_ops = {
521 	.o_cmds			= genl_cmds,
522 	.o_ncmds		= ARRAY_SIZE(genl_cmds),
523 };
524 
525 extern struct nl_object_ops genl_family_ops;
526 
527 static struct nl_cache_ops genl_ctrl_ops = {
528 	.co_name		= "genl/family",
529 	.co_hdrsize		= GENL_HDRSIZE(0),
530 	.co_msgtypes		= GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
531 	.co_genl		= &genl_ops,
532 	.co_protocol		= NETLINK_GENERIC,
533 	.co_request_update      = ctrl_request_update,
534 	.co_obj_ops		= &genl_family_ops,
535 };
536 
ctrl_init(void)537 static void __init ctrl_init(void)
538 {
539 	genl_register(&genl_ctrl_ops);
540 }
541 
ctrl_exit(void)542 static void __exit ctrl_exit(void)
543 {
544 	genl_unregister(&genl_ctrl_ops);
545 }
546 /** @endcond */
547 
548 /** @} */
549