xref: /aosp_15_r20/external/libnl/lib/genl/family.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_ctrl
8  * @defgroup genl_family Generic Netlink Family Object
9  *
10  * Object representing a kernel side registered Generic Netlink family
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/family.h>
20 #include <netlink/utils.h>
21 
22 #include "nl-genl.h"
23 #include "nl-priv-dynamic-core/object-api.h"
24 #include "nl-priv-dynamic-core/nl-core.h"
25 
26 /** @cond SKIP */
27 struct genl_family_op
28 {
29 	uint32_t		o_id;
30 	uint32_t		o_flags;
31 
32 	struct nl_list_head	o_list;
33 };
34 
35 #define FAMILY_ATTR_ID		0x01
36 #define FAMILY_ATTR_NAME	0x02
37 #define FAMILY_ATTR_VERSION	0x04
38 #define FAMILY_ATTR_HDRSIZE	0x08
39 #define FAMILY_ATTR_MAXATTR	0x10
40 #define FAMILY_ATTR_OPS		0x20
41 
42 struct nl_object_ops genl_family_ops;
43 
family_constructor(struct nl_object * c)44 static void family_constructor(struct nl_object *c)
45 {
46 	struct genl_family *family = (struct genl_family *) c;
47 
48 	nl_init_list_head(&family->gf_ops);
49 	nl_init_list_head(&family->gf_mc_grps);
50 }
51 
family_free_data(struct nl_object * c)52 static void family_free_data(struct nl_object *c)
53 {
54 	struct genl_family *family = (struct genl_family *) c;
55 	struct genl_family_op *ops, *tmp;
56 	struct genl_family_grp *grp, *t_grp;
57 
58 	if (family == NULL)
59 		return;
60 
61 	nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
62 		nl_list_del(&ops->o_list);
63 		free(ops);
64 	}
65 
66 	nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) {
67 		nl_list_del(&grp->list);
68 		free(grp);
69 	}
70 
71 }
72 
family_clone(struct nl_object * _dst,struct nl_object * _src)73 static int family_clone(struct nl_object *_dst, struct nl_object *_src)
74 {
75 	struct genl_family *dst = nl_object_priv(_dst);
76 	struct genl_family *src = nl_object_priv(_src);
77 	struct genl_family_op *ops;
78 	struct genl_family_grp *grp;
79 	int err;
80 
81 	nl_init_list_head(&dst->gf_ops);
82 	nl_init_list_head(&dst->gf_mc_grps);
83 
84 	nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
85 		err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
86 		if (err < 0)
87 			return err;
88 	}
89 
90 	nl_list_for_each_entry(grp, &src->gf_mc_grps, list) {
91 		err = genl_family_add_grp(dst, grp->id, grp->name);
92 		if (err < 0)
93 			return err;
94 	}
95 
96 
97 	return 0;
98 }
99 
family_dump_line(struct nl_object * obj,struct nl_dump_params * p)100 static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p)
101 {
102 	struct genl_family *family = (struct genl_family *) obj;
103 
104 	nl_dump(p, "0x%04x %s version %u\n",
105 		family->gf_id, family->gf_name, family->gf_version);
106 }
107 
108 static const struct trans_tbl ops_flags[] = {
109 	__ADD(GENL_ADMIN_PERM, admin_perm),
110 	__ADD(GENL_CMD_CAP_DO, has_doit),
111 	__ADD(GENL_CMD_CAP_DUMP, has_dump),
112 	__ADD(GENL_CMD_CAP_HASPOL, has_policy),
113 };
114 
ops_flags2str(int flags,char * buf,size_t len)115 static char *ops_flags2str(int flags, char *buf, size_t len)
116 {
117 	return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags));
118 }
119 
family_dump_details(struct nl_object * obj,struct nl_dump_params * p)120 static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p)
121 {
122 	struct genl_family_grp *grp;
123 	struct genl_family *family = (struct genl_family *) obj;
124 
125 	family_dump_line(obj, p);
126 	nl_dump_line(p, "    hdrsize %u maxattr %u\n",
127 		     family->gf_hdrsize, family->gf_maxattr);
128 
129 	if (family->ce_mask & FAMILY_ATTR_OPS) {
130 		struct genl_family_op *op;
131 		char buf[64];
132 
133 		nl_list_for_each_entry(op, &family->gf_ops, o_list) {
134 			ops_flags2str(op->o_flags, buf, sizeof(buf));
135 
136 			genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf));
137 
138 			nl_dump_line(p, "      op %s (0x%02x)", buf, op->o_id);
139 
140 			if (op->o_flags)
141 				nl_dump(p, " <%s>",
142 					ops_flags2str(op->o_flags, buf,
143 						      sizeof(buf)));
144 
145 			nl_dump(p, "\n");
146 		}
147 	}
148 
149 	nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
150 		nl_dump_line(p, "      grp %s (0x%02x)\n", grp->name, grp->id);
151 	}
152 
153 }
154 
family_dump_stats(struct nl_object * obj,struct nl_dump_params * p)155 static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
156 {
157 	family_dump_details(obj, p);
158 }
159 
family_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)160 static uint64_t family_compare(struct nl_object *_a, struct nl_object *_b,
161 			  uint64_t attrs, int flags)
162 {
163 	struct genl_family *a = (struct genl_family *) _a;
164 	struct genl_family *b = (struct genl_family *) _b;
165 	uint64_t diff = 0;
166 
167 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
168 	diff |= _DIFF(FAMILY_ATTR_ID, a->gf_id != b->gf_id);
169 	diff |= _DIFF(FAMILY_ATTR_VERSION, a->gf_version != b->gf_version);
170 	diff |= _DIFF(FAMILY_ATTR_HDRSIZE, a->gf_hdrsize != b->gf_hdrsize);
171 	diff |= _DIFF(FAMILY_ATTR_MAXATTR, a->gf_maxattr != b->gf_maxattr);
172 	diff |= _DIFF(FAMILY_ATTR_NAME, strcmp(a->gf_name, b->gf_name));
173 #undef _DIFF
174 
175 	return diff;
176 }
177 /** @endcond */
178 
179 /**
180  * @name Object Allocation
181  * @{
182  */
183 
184 /**
185  * Allocate new Generic Netlink family object
186  *
187  * @return Newly allocated Generic Netlink family object or NULL.
188  */
genl_family_alloc(void)189 struct genl_family *genl_family_alloc(void)
190 {
191 	return (struct genl_family *) nl_object_alloc(&genl_family_ops);
192 }
193 
194 /**
195  * Release reference on Generic Netlink family object
196  * @arg family		Generic Netlink family object
197  *
198  * Reduces the reference counter of a Generic Netlink family object by one.
199  * The object is freed after the last user has returned its reference.
200  *
201  * @see nl_object_put()
202  */
genl_family_put(struct genl_family * family)203 void genl_family_put(struct genl_family *family)
204 {
205 	nl_object_put((struct nl_object *) family);
206 }
207 
208 /** @} */
209 
210 /**
211  * @name Numeric Identifier
212  * @{
213  */
214 
215 /**
216  * Return numeric identifier
217  * @arg family		Generic Netlink family object
218  *
219  * @return Numeric identifier or 0 if not available.
220  */
genl_family_get_id(struct genl_family * family)221 unsigned int genl_family_get_id(struct genl_family *family)
222 {
223 	if (family->ce_mask & FAMILY_ATTR_ID)
224 		return family->gf_id;
225 	else
226 		return 0;
227 }
228 
229 /**
230  * Set the numeric identifier
231  * @arg family		Generic Netlink family object
232  * @arg id		New numeric identifier
233  */
genl_family_set_id(struct genl_family * family,unsigned int id)234 void genl_family_set_id(struct genl_family *family, unsigned int id)
235 {
236 	family->gf_id = id;
237 	family->ce_mask |= FAMILY_ATTR_ID;
238 }
239 
240 /** @} */
241 
242 /**
243  * @name Human Readable Name
244  * @{
245  */
246 
247 /**
248  * Return human readable name
249  * @arg family		Generic Netlink family object
250  *
251  * @return Name of family or NULL if not available
252  */
genl_family_get_name(struct genl_family * family)253 char *genl_family_get_name(struct genl_family *family)
254 {
255 	if (family->ce_mask & FAMILY_ATTR_NAME)
256 		return family->gf_name;
257 	else
258 		return NULL;
259 }
260 
261 /**
262  * Set human readable name
263  * @arg family		Generic Netlink family object
264  * @arg name		New human readable name
265  */
genl_family_set_name(struct genl_family * family,const char * name)266 void genl_family_set_name(struct genl_family *family, const char *name)
267 {
268 	_nl_strncpy_trunc(family->gf_name, name, GENL_NAMSIZ);
269 	family->ce_mask |= FAMILY_ATTR_NAME;
270 }
271 
272 /**
273  * @name Interface Version
274  * @{
275  */
276 
277 /**
278  * Return interface version
279  * @arg family		Generic Netlink family object
280  *
281  * @return Interface version or 0 if not available.
282  */
genl_family_get_version(struct genl_family * family)283 uint8_t genl_family_get_version(struct genl_family *family)
284 {
285 	if (family->ce_mask & FAMILY_ATTR_VERSION)
286 		return family->gf_version;
287 	else
288 		return 0;
289 }
290 
291 /**
292  * Set interface version
293  * @arg family		Generic Netlink family object
294  * @arg version		New interface version
295  */
genl_family_set_version(struct genl_family * family,uint8_t version)296 void genl_family_set_version(struct genl_family *family, uint8_t version)
297 {
298 	family->gf_version = version;
299 	family->ce_mask |= FAMILY_ATTR_VERSION;
300 }
301 
302 /** @} */
303 
304 /**
305  * @name Header Size
306  * @{
307  */
308 
309 /**
310  * Return user header size expected by kernel component
311  * @arg family		Generic Netlink family object
312  *
313  * @return Expected header length or 0 if not available.
314  */
genl_family_get_hdrsize(struct genl_family * family)315 uint32_t genl_family_get_hdrsize(struct genl_family *family)
316 {
317 	if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
318 		return family->gf_hdrsize;
319 	else
320 		return 0;
321 }
322 
genl_family_set_hdrsize(struct genl_family * family,uint32_t hdrsize)323 void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
324 {
325 	family->gf_hdrsize = hdrsize;
326 	family->ce_mask |= FAMILY_ATTR_HDRSIZE;
327 }
328 
329 /** @} */
330 
331 /**
332  * @name Maximum Expected Attribute
333  * @{
334  */
335 
genl_family_get_maxattr(struct genl_family * family)336 uint32_t genl_family_get_maxattr(struct genl_family *family)
337 {
338 	if (family->ce_mask & FAMILY_ATTR_MAXATTR)
339 		return family->gf_maxattr;
340 	else
341 		return 0;
342 }
343 
genl_family_set_maxattr(struct genl_family * family,uint32_t maxattr)344 void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
345 {
346 	family->gf_maxattr = maxattr;
347 	family->ce_mask |= FAMILY_ATTR_MAXATTR;
348 }
349 
350 /** @} */
351 
352 /**
353  * @name Operations
354  * @{
355  */
356 
genl_family_add_op(struct genl_family * family,int id,int flags)357 int genl_family_add_op(struct genl_family *family, int id, int flags)
358 {
359 	struct genl_family_op *op;
360 
361 	op = calloc(1, sizeof(*op));
362 	if (op == NULL)
363 		return -NLE_NOMEM;
364 
365 	op->o_id = id;
366 	op->o_flags = flags;
367 
368 	nl_list_add_tail(&op->o_list, &family->gf_ops);
369 	family->ce_mask |= FAMILY_ATTR_OPS;
370 
371 	return 0;
372 }
373 
genl_family_add_grp(struct genl_family * family,uint32_t id,const char * name)374 int genl_family_add_grp(struct genl_family *family, uint32_t id,
375                         const char *name)
376 {
377 	struct genl_family_grp *grp;
378 
379 	if (   !name
380 	    || strlen (name) >= GENL_NAMSIZ)
381 		return -NLE_INVAL;
382 
383 	grp = calloc(1, sizeof(*grp));
384 	if (grp == NULL)
385 		return -NLE_NOMEM;
386 
387 	grp->id = id;
388 	_nl_strncpy_assert(grp->name, name, GENL_NAMSIZ);
389 
390 	nl_list_add_tail(&grp->list, &family->gf_mc_grps);
391 
392 	return 0;
393 }
394 
395 /** @} */
396 
397 /** @cond SKIP */
398 struct nl_object_ops genl_family_ops = {
399 	.oo_name		= "genl/family",
400 	.oo_size		= sizeof(struct genl_family),
401 	.oo_constructor		= family_constructor,
402 	.oo_free_data		= family_free_data,
403 	.oo_clone		= family_clone,
404 	.oo_dump = {
405 	    [NL_DUMP_LINE]	= family_dump_line,
406 	    [NL_DUMP_DETAILS]	= family_dump_details,
407 	    [NL_DUMP_STATS]	= family_dump_stats,
408 	},
409 	.oo_compare		= family_compare,
410 	.oo_id_attrs		= FAMILY_ATTR_ID,
411 };
412 /** @endcond */
413 
414 /** @} */
415