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