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