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 35struct nl_object_ops genl_family_ops; 36 37static 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 45static 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 66static 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 90static 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 98static 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 105static 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 110static 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 145static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 146{ 147 family_dump_details(obj, p); 148} 149 150static 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 */ 181struct 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 */ 195void 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 */ 213unsigned 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 */ 226void 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 */ 245char *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 */ 258void 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 */ 275uint8_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 */ 288void 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 */ 307uint32_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 315void 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 328uint32_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 336void 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 349int 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 366int 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 */ 386struct 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