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