Home | History | Annotate | Download | only in genl
      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 (at) 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 /** @} */
    403