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