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