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