diff options
-rw-r--r-- | include/net/genetlink.h | 5 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 59 |
2 files changed, 64 insertions, 0 deletions
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 38620da4aa7a..3ed31e5a445b 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h | |||
@@ -31,6 +31,9 @@ struct genl_info; | |||
31 | * do additional, common, filtering and return an error | 31 | * do additional, common, filtering and return an error |
32 | * @post_doit: called after an operation's doit callback, it may | 32 | * @post_doit: called after an operation's doit callback, it may |
33 | * undo operations done by pre_doit, for example release locks | 33 | * undo operations done by pre_doit, for example release locks |
34 | * @mcast_bind: a socket bound to the given multicast group (which | ||
35 | * is given as the offset into the groups array) | ||
36 | * @mcast_unbind: a socket was unbound from the given multicast group | ||
34 | * @attrbuf: buffer to store parsed attributes | 37 | * @attrbuf: buffer to store parsed attributes |
35 | * @family_list: family list | 38 | * @family_list: family list |
36 | * @mcgrps: multicast groups used by this family (private) | 39 | * @mcgrps: multicast groups used by this family (private) |
@@ -53,6 +56,8 @@ struct genl_family { | |||
53 | void (*post_doit)(const struct genl_ops *ops, | 56 | void (*post_doit)(const struct genl_ops *ops, |
54 | struct sk_buff *skb, | 57 | struct sk_buff *skb, |
55 | struct genl_info *info); | 58 | struct genl_info *info); |
59 | int (*mcast_bind)(int group); | ||
60 | void (*mcast_unbind)(int group); | ||
56 | struct nlattr ** attrbuf; /* private */ | 61 | struct nlattr ** attrbuf; /* private */ |
57 | const struct genl_ops * ops; /* private */ | 62 | const struct genl_ops * ops; /* private */ |
58 | const struct genl_multicast_group *mcgrps; /* private */ | 63 | const struct genl_multicast_group *mcgrps; /* private */ |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 76393f2f4b22..05bf40bbd189 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -983,11 +983,70 @@ static struct genl_multicast_group genl_ctrl_groups[] = { | |||
983 | { .name = "notify", }, | 983 | { .name = "notify", }, |
984 | }; | 984 | }; |
985 | 985 | ||
986 | static int genl_bind(int group) | ||
987 | { | ||
988 | int i, err; | ||
989 | bool found = false; | ||
990 | |||
991 | down_read(&cb_lock); | ||
992 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | ||
993 | struct genl_family *f; | ||
994 | |||
995 | list_for_each_entry(f, genl_family_chain(i), family_list) { | ||
996 | if (group >= f->mcgrp_offset && | ||
997 | group < f->mcgrp_offset + f->n_mcgrps) { | ||
998 | int fam_grp = group - f->mcgrp_offset; | ||
999 | |||
1000 | if (f->mcast_bind) | ||
1001 | err = f->mcast_bind(fam_grp); | ||
1002 | else | ||
1003 | err = 0; | ||
1004 | found = true; | ||
1005 | break; | ||
1006 | } | ||
1007 | } | ||
1008 | } | ||
1009 | up_read(&cb_lock); | ||
1010 | |||
1011 | if (WARN_ON(!found)) | ||
1012 | err = 0; | ||
1013 | |||
1014 | return err; | ||
1015 | } | ||
1016 | |||
1017 | static void genl_unbind(int group) | ||
1018 | { | ||
1019 | int i; | ||
1020 | bool found = false; | ||
1021 | |||
1022 | down_read(&cb_lock); | ||
1023 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | ||
1024 | struct genl_family *f; | ||
1025 | |||
1026 | list_for_each_entry(f, genl_family_chain(i), family_list) { | ||
1027 | if (group >= f->mcgrp_offset && | ||
1028 | group < f->mcgrp_offset + f->n_mcgrps) { | ||
1029 | int fam_grp = group - f->mcgrp_offset; | ||
1030 | |||
1031 | if (f->mcast_unbind) | ||
1032 | f->mcast_unbind(fam_grp); | ||
1033 | found = true; | ||
1034 | break; | ||
1035 | } | ||
1036 | } | ||
1037 | } | ||
1038 | up_read(&cb_lock); | ||
1039 | |||
1040 | WARN_ON(!found); | ||
1041 | } | ||
1042 | |||
986 | static int __net_init genl_pernet_init(struct net *net) | 1043 | static int __net_init genl_pernet_init(struct net *net) |
987 | { | 1044 | { |
988 | struct netlink_kernel_cfg cfg = { | 1045 | struct netlink_kernel_cfg cfg = { |
989 | .input = genl_rcv, | 1046 | .input = genl_rcv, |
990 | .flags = NL_CFG_F_NONROOT_RECV, | 1047 | .flags = NL_CFG_F_NONROOT_RECV, |
1048 | .bind = genl_bind, | ||
1049 | .unbind = genl_unbind, | ||
991 | }; | 1050 | }; |
992 | 1051 | ||
993 | /* we'll bump the group number right afterwards */ | 1052 | /* we'll bump the group number right afterwards */ |