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