| /* |
| * lib/genl/family.c Generic Netlink Family |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation version 2.1 |
| * of the License. |
| * |
| * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> |
| */ |
| |
| /** |
| * @ingroup genl |
| * @defgroup genl_family Generic Netlink Family |
| * @brief |
| * |
| * @{ |
| */ |
| |
| #include <netlink-generic.h> |
| #include <netlink/netlink.h> |
| #include <netlink/genl/genl.h> |
| #include <netlink/genl/family.h> |
| #include <netlink/utils.h> |
| |
| /** @cond SKIP */ |
| #define FAMILY_ATTR_ID 0x01 |
| #define FAMILY_ATTR_NAME 0x02 |
| #define FAMILY_ATTR_VERSION 0x04 |
| #define FAMILY_ATTR_HDRSIZE 0x08 |
| #define FAMILY_ATTR_MAXATTR 0x10 |
| #define FAMILY_ATTR_OPS 0x20 |
| |
| struct nl_object_ops genl_family_ops; |
| /** @endcond */ |
| |
| static void family_constructor(struct nl_object *c) |
| { |
| struct genl_family *family = (struct genl_family *) c; |
| |
| nl_init_list_head(&family->gf_ops); |
| } |
| |
| static void family_free_data(struct nl_object *c) |
| { |
| struct genl_family *family = (struct genl_family *) c; |
| struct genl_family_op *ops, *tmp; |
| |
| if (family == NULL) |
| return; |
| |
| nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) { |
| nl_list_del(&ops->o_list); |
| free(ops); |
| } |
| } |
| |
| static int family_clone(struct nl_object *_dst, struct nl_object *_src) |
| { |
| struct genl_family *dst = nl_object_priv(_dst); |
| struct genl_family *src = nl_object_priv(_src); |
| struct genl_family_op *ops; |
| int err; |
| |
| nl_list_for_each_entry(ops, &src->gf_ops, o_list) { |
| err = genl_family_add_op(dst, ops->o_id, ops->o_flags); |
| if (err < 0) |
| return err; |
| } |
| |
| return 0; |
| } |
| |
| static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p) |
| { |
| struct genl_family *family = (struct genl_family *) obj; |
| |
| nl_dump(p, "0x%04x %s version %u\n", |
| family->gf_id, family->gf_name, family->gf_version); |
| } |
| |
| static struct trans_tbl ops_flags[] = { |
| __ADD(GENL_ADMIN_PERM, admin-perm) |
| __ADD(GENL_CMD_CAP_DO, has-doit) |
| __ADD(GENL_CMD_CAP_DUMP, has-dump) |
| __ADD(GENL_CMD_CAP_HASPOL, has-policy) |
| }; |
| |
| static char *ops_flags2str(int flags, char *buf, size_t len) |
| { |
| return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags)); |
| } |
| |
| static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p) |
| { |
| struct genl_family *family = (struct genl_family *) obj; |
| |
| family_dump_line(obj, p); |
| nl_dump_line(p, " hdrsize %u maxattr %u\n", |
| family->gf_hdrsize, family->gf_maxattr); |
| |
| if (family->ce_mask & FAMILY_ATTR_OPS) { |
| struct genl_family_op *op; |
| char buf[64]; |
| |
| nl_list_for_each_entry(op, &family->gf_ops, o_list) { |
| ops_flags2str(op->o_flags, buf, sizeof(buf)); |
| |
| genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf)); |
| |
| nl_dump_line(p, " op %s (0x%02x)", buf, op->o_id); |
| |
| if (op->o_flags) |
| nl_dump(p, " <%s>", |
| ops_flags2str(op->o_flags, buf, |
| sizeof(buf))); |
| |
| nl_dump(p, "\n"); |
| } |
| } |
| } |
| |
| static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) |
| { |
| family_dump_details(obj, p); |
| } |
| |
| static int family_compare(struct nl_object *_a, struct nl_object *_b, |
| uint32_t attrs, int flags) |
| { |
| struct genl_family *a = (struct genl_family *) _a; |
| struct genl_family *b = (struct genl_family *) _b; |
| int diff = 0; |
| |
| #define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR) |
| |
| diff |= FAM_DIFF(ID, a->gf_id != b->gf_id); |
| diff |= FAM_DIFF(VERSION, a->gf_version != b->gf_version); |
| diff |= FAM_DIFF(HDRSIZE, a->gf_hdrsize != b->gf_hdrsize); |
| diff |= FAM_DIFF(MAXATTR, a->gf_maxattr != b->gf_maxattr); |
| diff |= FAM_DIFF(NAME, strcmp(a->gf_name, b->gf_name)); |
| |
| #undef FAM_DIFF |
| |
| return diff; |
| } |
| |
| |
| /** |
| * @name Family Object |
| * @{ |
| */ |
| |
| struct genl_family *genl_family_alloc(void) |
| { |
| return (struct genl_family *) nl_object_alloc(&genl_family_ops); |
| } |
| |
| void genl_family_put(struct genl_family *family) |
| { |
| nl_object_put((struct nl_object *) family); |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name Attributes |
| * @{ |
| */ |
| |
| unsigned int genl_family_get_id(struct genl_family *family) |
| { |
| if (family->ce_mask & FAMILY_ATTR_ID) |
| return family->gf_id; |
| else |
| return GENL_ID_GENERATE; |
| } |
| |
| void genl_family_set_id(struct genl_family *family, unsigned int id) |
| { |
| family->gf_id = id; |
| family->ce_mask |= FAMILY_ATTR_ID; |
| } |
| |
| char *genl_family_get_name(struct genl_family *family) |
| { |
| if (family->ce_mask & FAMILY_ATTR_NAME) |
| return family->gf_name; |
| else |
| return NULL; |
| } |
| |
| void genl_family_set_name(struct genl_family *family, const char *name) |
| { |
| strncpy(family->gf_name, name, GENL_NAMSIZ-1); |
| family->ce_mask |= FAMILY_ATTR_NAME; |
| } |
| |
| uint8_t genl_family_get_version(struct genl_family *family) |
| { |
| if (family->ce_mask & FAMILY_ATTR_VERSION) |
| return family->gf_version; |
| else |
| return 0; |
| } |
| |
| void genl_family_set_version(struct genl_family *family, uint8_t version) |
| { |
| family->gf_version = version; |
| family->ce_mask |= FAMILY_ATTR_VERSION; |
| } |
| |
| uint32_t genl_family_get_hdrsize(struct genl_family *family) |
| { |
| if (family->ce_mask & FAMILY_ATTR_HDRSIZE) |
| return family->gf_hdrsize; |
| else |
| return 0; |
| } |
| |
| void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize) |
| { |
| family->gf_hdrsize = hdrsize; |
| family->ce_mask |= FAMILY_ATTR_HDRSIZE; |
| } |
| |
| uint32_t genl_family_get_maxattr(struct genl_family *family) |
| { |
| if (family->ce_mask & FAMILY_ATTR_MAXATTR) |
| return family->gf_maxattr; |
| else |
| return family->gf_maxattr; |
| } |
| |
| void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr) |
| { |
| family->gf_maxattr = maxattr; |
| family->ce_mask |= FAMILY_ATTR_MAXATTR; |
| } |
| |
| int genl_family_add_op(struct genl_family *family, int id, int flags) |
| { |
| struct genl_family_op *op; |
| |
| op = calloc(1, sizeof(*op)); |
| if (op == NULL) |
| return -NLE_NOMEM; |
| |
| op->o_id = id; |
| op->o_flags = flags; |
| |
| nl_list_add_tail(&op->o_list, &family->gf_ops); |
| family->ce_mask |= FAMILY_ATTR_OPS; |
| |
| return 0; |
| } |
| |
| /** @} */ |
| |
| /** @cond SKIP */ |
| struct nl_object_ops genl_family_ops = { |
| .oo_name = "genl/family", |
| .oo_size = sizeof(struct genl_family), |
| .oo_constructor = family_constructor, |
| .oo_free_data = family_free_data, |
| .oo_clone = family_clone, |
| .oo_dump = { |
| [NL_DUMP_LINE] = family_dump_line, |
| [NL_DUMP_DETAILS] = family_dump_details, |
| [NL_DUMP_STATS] = family_dump_stats, |
| }, |
| .oo_compare = family_compare, |
| .oo_id_attrs = FAMILY_ATTR_ID, |
| }; |
| /** @endcond */ |
| |
| /** @} */ |