diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h index f7a9377..b834ef6 100644 --- a/include/linux/genetlink.h +++ b/include/linux/genetlink.h @@ -1,6 +1,7 @@ #ifndef __LINUX_GENERIC_NETLINK_H #define __LINUX_GENERIC_NETLINK_H +#include #include #define GENL_NAMSIZ 16 /* length of family name */ @@ -39,6 +40,9 @@ enum { CTRL_CMD_NEWOPS, CTRL_CMD_DELOPS, CTRL_CMD_GETOPS, + CTRL_CMD_NEWMCAST_GRP, + CTRL_CMD_DELMCAST_GRP, + CTRL_CMD_GETMCAST_GRP, /* unused */ __CTRL_CMD_MAX, }; @@ -52,6 +56,7 @@ enum { CTRL_ATTR_HDRSIZE, CTRL_ATTR_MAXATTR, CTRL_ATTR_OPS, + CTRL_ATTR_MCAST_GROUPS, __CTRL_ATTR_MAX, }; @@ -66,4 +71,13 @@ enum { #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) +enum { + CTRL_ATTR_MCAST_GRP_UNSPEC, + CTRL_ATTR_MCAST_GRP_NAME, + CTRL_ATTR_MCAST_GRP_ID, + __CTRL_ATTR_MCAST_GRP_MAX, +}; + +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) + #endif /* __LINUX_GENERIC_NETLINK_H */ diff --git a/include/netlink-types.h b/include/netlink-types.h index ace5dde..c30aa17 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -701,6 +701,13 @@ struct genl_family_op struct nl_list_head o_list; }; +struct genl_family_grp { + struct genl_family *family; /* private */ + struct nl_list_head list; /* private */ + char name[GENL_NAMSIZ]; + u_int32_t id; +}; + struct genl_family { NLHDR_COMMON @@ -712,6 +719,7 @@ struct genl_family uint32_t gf_maxattr; struct nl_list_head gf_ops; + struct nl_list_head gf_mc_grps; }; union nfnl_ct_proto diff --git a/include/netlink/genl/ctrl.h b/include/netlink/genl/ctrl.h index 1ae62f4..ac188f4 100644 --- a/include/netlink/genl/ctrl.h +++ b/include/netlink/genl/ctrl.h @@ -29,7 +29,11 @@ extern struct genl_family * genl_ctrl_search_by_name(struct nl_cache *, const char *); extern int genl_ctrl_resolve(struct nl_sock *, const char *); +extern int genl_ctrl_resolve_grp(struct nl_sock *sk, + const char *family, + const char *grp); +extern int genl_dump(struct nl_sock *sk, const char *name); #ifdef __cplusplus } #endif diff --git a/include/netlink/genl/family.h b/include/netlink/genl/family.h index 74319e5..721dc13 100644 --- a/include/netlink/genl/family.h +++ b/include/netlink/genl/family.h @@ -42,6 +42,9 @@ extern void genl_family_set_maxattr(struct genl_family *, extern int genl_family_add_op(struct genl_family *, int, int); +extern int genl_family_add_grp(struct genl_family *, + uint32_t , const char *); + #ifdef __cplusplus } diff --git a/include/netlink/genl/genl.h b/include/netlink/genl/genl.h index 3f3340c..cd8f8b1 100644 --- a/include/netlink/genl/genl.h +++ b/include/netlink/genl/genl.h @@ -21,7 +21,7 @@ extern "C" { #endif extern int genl_connect(struct nl_sock *); - +extern int genl_connect_mc(struct nl_sock *sk, uint32_t group); extern int genl_send_simple(struct nl_sock *, int, int, int, int); diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c index 1301642..69dc201 100644 --- a/lib/genl/ctrl.c +++ b/lib/genl/ctrl.c @@ -45,6 +45,7 @@ static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, + [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, }; static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = { @@ -52,6 +53,11 @@ static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = { [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 }, }; +static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = { + [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING }, + [CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 }, +}; + static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, struct genl_info *info, void *arg) { @@ -126,6 +132,40 @@ static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, } } + + if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) { + struct nlattr *nla, *nla_grps; + int remaining; + + nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS]; + nla_for_each_nested(nla, nla_grps, remaining) { + struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1]; + int id; + const char * name; + + err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla, + family_grp_policy); + if (err < 0) + goto errout; + + if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]); + + if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) { + err = -NLE_MISSING_ATTR; + goto errout; + } + name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]); + + err = genl_family_add_grp(family, id, name); + if (err < 0) + goto errout; + } + + } err = pp->pp_cb((struct nl_object *) family, pp); errout: @@ -242,6 +282,74 @@ errout: return err; } +static int genl_ctrl_grp_by_name(const struct genl_family *family, + const char *grp_name) +{ + struct genl_family_grp *grp; + + nl_list_for_each_entry(grp, &family->gf_mc_grps, list) { + if (!strcmp(grp->name, grp_name)) { + return grp->id; + } + } + + return 0; +} + +int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name, + const char *grp_name) +{ + struct nl_cache *cache; + struct genl_family *family; + int err; + + if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0) + return err; + + family = genl_ctrl_search_by_name(cache, family_name); + if (family == NULL) { + err = -NLE_OBJ_NOTFOUND; + goto errout; + } + + err = genl_ctrl_grp_by_name(family, grp_name); + genl_family_put(family); +errout: + nl_cache_free(cache); + + return err; +} + + +static struct nl_dump_params nl_stdout_dp = { + .dp_type = NL_DUMP_DETAILS, +}; + +int genl_dump(struct nl_sock *sk, const char *name) +{ + struct nl_cache *cache; + struct genl_family *family; + int err; + + if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0) + return err; + + family = genl_ctrl_search_by_name(cache, name); + if (family == NULL) { + err = -NLE_OBJ_NOTFOUND; + goto errout; + } + + nl_stdout_dp.dp_fd = stdout; + nl_object_dump((struct nl_object *)family, &nl_stdout_dp); + genl_family_put(family); +errout: + nl_cache_free(cache); + + return err; +} + + /** @} */ static struct genl_cmd genl_cmds[] = { diff --git a/lib/genl/family.c b/lib/genl/family.c index 4c6c18d..687f4b1 100644 --- a/lib/genl/family.c +++ b/lib/genl/family.c @@ -39,12 +39,14 @@ static void family_constructor(struct nl_object *c) struct genl_family *family = (struct genl_family *) c; nl_init_list_head(&family->gf_ops); + nl_init_list_head(&family->gf_mc_grps); } static void family_free_data(struct nl_object *c) { struct genl_family *family = (struct genl_family *) c; struct genl_family_op *ops, *tmp; + struct genl_family_grp *grp, *t_grp; if (family == NULL) return; @@ -53,6 +55,12 @@ static void family_free_data(struct nl_object *c) nl_list_del(&ops->o_list); free(ops); } + + nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) { + nl_list_del(&grp->list); + free(grp); + } + } static int family_clone(struct nl_object *_dst, struct nl_object *_src) @@ -60,6 +68,7 @@ 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; + struct genl_family_grp *grp; int err; nl_list_for_each_entry(ops, &src->gf_ops, o_list) { @@ -67,6 +76,13 @@ static int family_clone(struct nl_object *_dst, struct nl_object *_src) if (err < 0) return err; } + + nl_list_for_each_entry(grp, &src->gf_mc_grps, list) { + err = genl_family_add_grp(dst, grp->id, grp->name); + if (err < 0) + return err; + } + return 0; } @@ -93,6 +109,7 @@ static char *ops_flags2str(int flags, char *buf, size_t len) static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p) { + struct genl_family_grp *grp; struct genl_family *family = (struct genl_family *) obj; family_dump_line(obj, p); @@ -118,6 +135,11 @@ static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p) nl_dump(p, "\n"); } } + + nl_list_for_each_entry(grp, &family->gf_mc_grps, list) { + nl_dump_line(p, " grp %s (0x%02x)\n", grp->name, grp->id); + } + } static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) @@ -255,6 +277,23 @@ int genl_family_add_op(struct genl_family *family, int id, int flags) return 0; } +int genl_family_add_grp(struct genl_family *family, uint32_t id, + const char *name) +{ + struct genl_family_grp *grp; + + grp = calloc(1, sizeof(*grp)); + if (grp == NULL) + return -NLE_NOMEM; + + grp->id = id; + strncpy(grp->name, name, GENL_NAMSIZ - 1); + + nl_list_add_tail(&grp->list, &family->gf_mc_grps); + + return 0; +} + /** @} */ /** @cond SKIP */ diff --git a/lib/genl/genl.c b/lib/genl/genl.c index 055be91..6c99433 100644 --- a/lib/genl/genl.c +++ b/lib/genl/genl.c @@ -104,6 +104,12 @@ int genl_connect(struct nl_sock *sk) return nl_connect(sk, NETLINK_GENERIC); } +int genl_connect_mc(struct nl_sock *sk, uint32_t group) +{ + sk->s_local.nl_groups = group; + return genl_connect(sk); +} + /** @} */ /**