xref: /aosp_15_r20/external/libnl/lib/genl/mngt.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2012 Thomas Graf <[email protected]>
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 
28 static NL_LIST_HEAD(genl_ops_list);
29 
lookup_cmd(struct genl_ops * ops,int cmd_id)30 static 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 
cmd_msg_parser(struct sockaddr_nl * who,struct nlmsghdr * nlh,struct genl_ops * ops,struct nl_cache_ops * cache_ops,void * arg)44 static 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 
genl_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)86 static 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 
lookup_family(int family)95 static 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 
lookup_family_by_name(const char * name)107 static 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 
genl_op2name(int family,int op,char * buf,size_t len)119 char *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  */
genl_register_family(struct genl_ops * ops)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  */
genl_unregister_family(struct genl_ops * ops)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  */
genl_handle_msg(struct nl_msg * msg,void * arg)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  */
genl_register(struct nl_cache_ops * ops)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);
271 errout:
272 	return err;
273 }
274 
275 /**
276  * Unregister cache based Generic Netlink family
277  * @arg ops		Cache operations definition
278  */
genl_unregister(struct nl_cache_ops * ops)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 */
__genl_ops_resolve(struct nl_cache * ctrl,struct genl_ops * ops)292 static 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. */
genl_resolve_id(struct genl_ops * ops)312 int 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 
332 errout_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  */
genl_ops_resolve(struct nl_sock * sk,struct genl_ops * ops)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);
364 errout:
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  */
genl_mngt_resolve(struct nl_sock * sk)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);
395 errout:
396 	return err;
397 }
398 
399 /** @} */
400 
401 /** @} */
402