libnl  3.5.0
mngt.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/genl/mngt.c Generic Netlink Management
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_mngt Family and Command Registration
16  *
17  * Registering Generic Netlink Families and Commands
18  *
19  * @{
20  */
21 
22 #include <netlink-private/genl.h>
23 #include <netlink/netlink.h>
24 #include <netlink/genl/genl.h>
25 #include <netlink/genl/mngt.h>
26 #include <netlink/genl/family.h>
27 #include <netlink/genl/ctrl.h>
28 #include <netlink/utils.h>
29 
30 #include "netlink-private/utils.h"
31 
32 /** @cond SKIP */
33 
34 static NL_LIST_HEAD(genl_ops_list);
35 
36 static struct genl_cmd *lookup_cmd(struct genl_ops *ops, int cmd_id)
37 {
38  struct genl_cmd *cmd;
39  int i;
40 
41  for (i = 0; i < ops->o_ncmds; i++) {
42  cmd = &ops->o_cmds[i];
43  if (cmd->c_id == cmd_id)
44  return cmd;
45  }
46 
47  return NULL;
48 }
49 
50 static int cmd_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
51  struct genl_ops *ops, struct nl_cache_ops *cache_ops, void *arg)
52 {
53  _nl_auto_free struct nlattr **tb_free = NULL;
54  int err;
55  struct genlmsghdr *ghdr;
56  struct genl_cmd *cmd;
57  struct nlattr **tb;
58 
59  ghdr = genlmsg_hdr(nlh);
60 
61  if (!(cmd = lookup_cmd(ops, ghdr->cmd)))
62  return -NLE_MSGTYPE_NOSUPPORT;
63 
64  if (cmd->c_msg_parser == NULL)
65  return -NLE_OPNOTSUPP;
66 
67  tb = _nl_malloc_maybe_a (300, (((size_t) cmd->c_maxattr) + 1u) * sizeof (struct nlattr *), &tb_free);
68  if (!tb)
69  return -NLE_NOMEM;
70 
71  err = nlmsg_parse(nlh,
72  GENL_HDRSIZE(ops->o_hdrsize),
73  tb,
74  cmd->c_maxattr,
75  cmd->c_attr_policy);
76  if (err < 0)
77  return err;
78 
79  {
80  struct genl_info info = {
81  .who = who,
82  .nlh = nlh,
83  .genlhdr = ghdr,
84  .userhdr = genlmsg_user_hdr(ghdr),
85  .attrs = tb,
86  };
87 
88  return cmd->c_msg_parser(cache_ops, cmd, &info, arg);
89  }
90 }
91 
92 static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
93  struct nlmsghdr *nlh, struct nl_parser_param *pp)
94 {
95  if (ops->co_genl == NULL)
96  BUG();
97 
98  return cmd_msg_parser(who, nlh, ops->co_genl, ops, pp);
99 }
100 
101 static struct genl_ops *lookup_family(int family)
102 {
103  struct genl_ops *ops;
104 
105  nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
106  if (ops->o_id == family)
107  return ops;
108  }
109 
110  return NULL;
111 }
112 
113 static struct genl_ops *lookup_family_by_name(const char *name)
114 {
115  struct genl_ops *ops;
116 
117  nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
118  if (!strcmp(ops->o_name, name))
119  return ops;
120  }
121 
122  return NULL;
123 }
124 
125 char *genl_op2name(int family, int op, char *buf, size_t len)
126 {
127  struct genl_ops *ops;
128  int i;
129 
130  if ((ops = lookup_family(family))) {
131  for (i = 0; i < ops->o_ncmds; i++) {
132  struct genl_cmd *cmd;
133  cmd = &ops->o_cmds[i];
134 
135  if (cmd->c_id == op) {
136  strncpy(buf, cmd->c_name, len - 1);
137  return buf;
138  }
139  }
140  }
141 
142  strncpy(buf, "unknown", len - 1);
143  return NULL;
144 }
145 
146 /** @endcond */
147 
148 /**
149  * @name Registration
150  * @{
151  */
152 
153 /**
154  * Register Generic Netlink family and associated commands
155  * @arg ops Generic Netlink family definition
156  *
157  * Registers the specified Generic Netlink family definition together with
158  * all associated commands. After registration, received Generic Netlink
159  * messages can be passed to genl_handle_msg() which will validate the
160  * messages, look for a matching command and call the respective callback
161  * function automatically.
162  *
163  * @note Consider using genl_register() if the family is used to implement a
164  * cacheable type.
165  *
166  * @see genl_unregister_family();
167  * @see genl_register();
168  *
169  * @return 0 on success or a negative error code.
170  */
172 {
173  if (!ops->o_name)
174  return -NLE_INVAL;
175 
176  if (ops->o_cmds && ops->o_ncmds <= 0)
177  return -NLE_INVAL;
178 
179  if (ops->o_id && lookup_family(ops->o_id))
180  return -NLE_EXIST;
181 
182  if (lookup_family_by_name(ops->o_name))
183  return -NLE_EXIST;
184 
185  nl_list_add_tail(&ops->o_list, &genl_ops_list);
186 
187  return 0;
188 }
189 
190 /**
191  * Unregister Generic Netlink family
192  * @arg ops Generic Netlink family definition
193  *
194  * Unregisters a family and all associated commands that were previously
195  * registered using genl_register_family().
196  *
197  * @see genl_register_family()
198  *
199  * @return 0 on success or a negative error code.
200  */
202 {
203  nl_list_del(&ops->o_list);
204 
205  return 0;
206 }
207 
208 /**
209  * Run a received message through the demultiplexer
210  * @arg msg Generic Netlink message
211  * @arg arg Argument passed on to the message handler callback
212  *
213  * @return 0 on success or a negative error code.
214  */
215 int genl_handle_msg(struct nl_msg *msg, void *arg)
216 {
217  struct nlmsghdr *nlh = nlmsg_hdr(msg);
218  struct genl_ops *ops;
219 
220  if (!genlmsg_valid_hdr(nlh, 0))
221  return -NLE_INVAL;
222 
223  if (!(ops = lookup_family(nlh->nlmsg_type)))
224  return -NLE_MSGTYPE_NOSUPPORT;
225 
226  return cmd_msg_parser(nlmsg_get_src(msg), nlh, ops, NULL, arg);
227 }
228 
229 /** @} */
230 
231 /**
232  * @name Registration of Cache Operations
233  * @{
234  */
235 
236 /**
237  * Register Generic Netlink family backed cache
238  * @arg ops Cache operations definition
239  *
240  * Same as genl_register_family() but additionally registers the specified
241  * cache operations using nl_cache_mngt_register() and associates it with
242  * the Generic Netlink family.
243  *
244  * @see genl_register_family()
245  *
246  * @return 0 on success or a negative error code.
247  */
248 int genl_register(struct nl_cache_ops *ops)
249 {
250  int err;
251 
252  if (ops->co_protocol != NETLINK_GENERIC) {
253  err = -NLE_PROTO_MISMATCH;
254  goto errout;
255  }
256 
257  if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
258  err = -NLE_INVAL;
259  goto errout;
260  }
261 
262  if (ops->co_genl == NULL) {
263  err = -NLE_INVAL;
264  goto errout;
265  }
266 
267  ops->co_genl->o_cache_ops = ops;
268  ops->co_genl->o_hdrsize = ops->co_hdrsize - GENL_HDRLEN;
269  ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
270  ops->co_genl->o_id = ops->co_msgtypes[0].mt_id;
271  ops->co_msg_parser = genl_msg_parser;
272 
273  if ((err = genl_register_family(ops->co_genl)) < 0)
274  goto errout;
275 
276  err = nl_cache_mngt_register(ops);
277 errout:
278  return err;
279 }
280 
281 /**
282  * Unregister cache based Generic Netlink family
283  * @arg ops Cache operations definition
284  */
285 void genl_unregister(struct nl_cache_ops *ops)
286 {
287  if (!ops)
288  return;
289 
291 
292  genl_unregister_family(ops->co_genl);
293 }
294 
295 /** @} */
296 
297 /** @cond SKIP */
298 static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
299 {
300  struct genl_family *family;
301 
302  family = genl_ctrl_search_by_name(ctrl, ops->o_name);
303  if (family != NULL) {
304  ops->o_id = genl_family_get_id(family);
305 
306  if (ops->o_cache_ops)
307  ops->o_cache_ops->co_msgtypes[0].mt_id = ops->o_id;
308 
309  genl_family_put(family);
310 
311  return 0;
312  }
313 
314  return -NLE_OBJ_NOTFOUND;
315 }
316 
317 int genl_resolve_id(struct genl_ops *ops)
318 {
319  struct nl_sock *sk;
320  int err = 0;
321 
322  /* Check if resolved already */
323  if (ops->o_id != 0)
324  return 0;
325 
326  if (!ops->o_name)
327  return -NLE_INVAL;
328 
329  if (!(sk = nl_socket_alloc()))
330  return -NLE_NOMEM;
331 
332  if ((err = genl_connect(sk)) < 0)
333  goto errout_free;
334 
335  err = genl_ops_resolve(sk, ops);
336 
337 errout_free:
338  nl_socket_free(sk);
339 
340  return err;
341 }
342 /** @endcond */
343 
344 /**
345  * @name Resolving the name of registered families
346  * @{
347  */
348 
349 /**
350  * Resolve a single Generic Netlink family
351  * @arg sk Generic Netlink socket
352  * @arg ops Generic Netlink family definition
353  *
354  * Resolves the family name to its numeric identifier.
355  *
356  * @return 0 on success or a negative error code.
357  */
358 int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops)
359 {
360  struct nl_cache *ctrl;
361  int err;
362 
363  if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
364  goto errout;
365 
366  err = __genl_ops_resolve(ctrl, ops);
367 
368  nl_cache_free(ctrl);
369 errout:
370  return err;
371 }
372 
373 /**
374  * Resolve all registered Generic Netlink families
375  * @arg sk Generic Netlink socket
376  *
377  * Walks through all local Generic Netlink families that have been registered
378  * using genl_register() and resolves the name of each family to the
379  * corresponding numeric identifier.
380  *
381  * @see genl_register()
382  * @see genl_ops_resolve()
383  *
384  * @return 0 on success or a negative error code.
385  */
386 int genl_mngt_resolve(struct nl_sock *sk)
387 {
388  struct nl_cache *ctrl;
389  struct genl_ops *ops;
390  int err = 0;
391 
392  if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
393  goto errout;
394 
395  nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
396  err = __genl_ops_resolve(ctrl, ops);
397  }
398 
399  nl_cache_free(ctrl);
400 errout:
401  return err;
402 }
403 
404 /** @} */
405 
406 /** @} */
struct sockaddr_nl * who
Socket address of sender.
Definition: mngt.h:40
int genl_mngt_resolve(struct nl_sock *sk)
Resolve all registered Generic Netlink families.
Definition: mngt.c:386
struct nla_policy * c_attr_policy
Attribute validation policy, enforced before the callback is called.
Definition: mngt.h:104
int genl_handle_msg(struct nl_msg *msg, void *arg)
Run a received message through the demultiplexer.
Definition: mngt.c:215
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:215
void * genlmsg_user_hdr(const struct genlmsghdr *gnlh)
Return pointer to user header.
Definition: genl.c:244
int genl_register(struct nl_cache_ops *ops)
Register Generic Netlink family backed cache.
Definition: mngt.c:248
struct genl_cmd * o_cmds
Optional array defining the available Generic Netlink commands.
Definition: mngt.h:150
Definition of a Generic Netlink command.
Definition: mngt.h:87
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:288
int genl_connect(struct nl_sock *sk)
Connect a Generic Netlink socket.
Definition: genl.c:46
char * c_name
Human readable name (required)
Definition: mngt.h:93
int genl_ctrl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
Allocate a new controller cache.
Definition: ctrl.c:334
int o_ncmds
Number of elements in o_cmds array.
Definition: mngt.h:153
int genl_unregister_family(struct genl_ops *ops)
Unregister Generic Netlink family.
Definition: mngt.c:201
struct nl_sock * nl_socket_alloc(void)
Allocate new netlink socket.
Definition: socket.c:206
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition: cache.c:409
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
int c_id
Numeric command identifier (required)
Definition: mngt.h:90
struct genlmsghdr * genlmsg_hdr(struct nlmsghdr *nlh)
Return pointer to Generic Netlink header.
Definition: genl.c:212
void genl_unregister(struct nl_cache_ops *ops)
Unregister cache based Generic Netlink family.
Definition: mngt.c:285
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
Definition: msg.c:543
struct genl_family * genl_ctrl_search_by_name(struct nl_cache *cache, const char *name)
Search controller cache for a family name match.
Definition: ctrl.c:388
Definition of a Generic Netlink family.
Definition: mngt.h:132
void nl_socket_free(struct nl_sock *sk)
Free a netlink socket.
Definition: socket.c:244
int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops)
Resolve a single Generic Netlink family.
Definition: mngt.c:358
Informative structure passed on to message parser callbacks.
Definition: mngt.h:37
int genl_register_family(struct genl_ops *ops)
Register Generic Netlink family and associated commands.
Definition: mngt.c:171
struct nl_cache_ops * o_cache_ops
If registered via genl_register(), will point to the related cache operations.
Definition: mngt.h:147
void genl_family_put(struct genl_family *family)
Release reference on Generic Netlink family object.
Definition: family.c:198
struct nlmsghdr * nlh
Pointer to Netlink message header.
Definition: mngt.h:43
unsigned int o_hdrsize
Length of user header.
Definition: mngt.h:135
int o_id
Numeric identifier, automatically filled in by genl_ops_resolve()
Definition: mngt.h:138
unsigned int genl_family_get_id(struct genl_family *family)
Return numeric identifier.
Definition: family.c:216
char * o_name
Human readable name, used by genl_ops_resolve() to resolve numeric id.
Definition: mngt.h:141
int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
Validate Generic Netlink message headers.
Definition: genl.c:119
int(* c_msg_parser)(struct nl_cache_ops *, struct genl_cmd *, struct genl_info *, void *)
Called whenever a message for this command is received.
Definition: mngt.h:99
struct nl_list_head o_list
Used internally to link together all registered operations.
Definition: mngt.h:159
int c_maxattr
Maximum attribute identifier that the command is prepared to handle.
Definition: mngt.h:96