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