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 ff699bb..1ffb70c 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -702,6 +702,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 @@ -713,6 +720,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..26a0a99 100644 --- a/include/netlink/genl/ctrl.h +++ b/include/netlink/genl/ctrl.h @@ -29,6 +29,9 @@ 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); #ifdef __cplusplus } 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..364a471 100644 --- a/include/netlink/genl/genl.h +++ b/include/netlink/genl/genl.h @@ -21,7 +21,6 @@ extern "C" { #endif extern int genl_connect(struct nl_sock *); - extern int genl_send_simple(struct nl_sock *, int, int, int, int); diff --git a/include/netlink/socket.h b/include/netlink/socket.h index 7e71aed..31a36d3 100644 --- a/include/netlink/socket.h +++ b/include/netlink/socket.h @@ -37,7 +37,8 @@ extern void nl_join_groups(struct nl_sock *, int); extern uint32_t nl_socket_get_peer_port(struct nl_sock *); extern void nl_socket_set_peer_port(struct nl_sock *, uint32_t); - +extern uint32_t nl_socket_get_peer_groups(struct nl_sock *sk); +extern void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups); extern struct nl_cb * nl_socket_get_cb(struct nl_sock *); extern void nl_socket_set_cb(struct nl_sock *, struct nl_cb *); diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c index 1301642..3871795 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,44 @@ 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 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/nl.c b/lib/nl.c index c453b60..13c0514 100644 --- a/lib/nl.c +++ b/lib/nl.c @@ -387,7 +387,7 @@ errout: * Receives a netlink message, allocates a buffer in \c *buf and * stores the message content. The peer's netlink address is stored * in \c *nla. The caller is responsible for freeing the buffer allocated - * in \c *buf if a positive value is returned. Interruped system calls + * in \c *buf if a positive value is returned. Interrupted system calls * are handled by repeating the read. The input buffer size is determined * by peeking before the actual read is done. * diff --git a/lib/socket.c b/lib/socket.c index 8083bbb..bed53c1 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -398,6 +398,18 @@ void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port) sk->s_peer.nl_pid = port; } +uint32_t nl_socket_get_peer_groups(struct nl_sock *sk) +{ + return sk->s_peer.nl_groups; +} + +void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups) +{ + sk->s_peer.nl_groups = groups; +} + + + /** @} */ /**