libnl: /data/src/libnl/lib/genl/mngt.c Source File

libnl 3.12.0

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