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