libnl  3.2.24-rc1
family.c
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 
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 
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 
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 
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 
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 
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 
145 static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
146 {
147  family_dump_details(obj, p);
148 }
149 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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 
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 
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 
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 /** @} */