aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/genetlink.h5
-rw-r--r--net/netlink/genetlink.c59
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
986static 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
1017static 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
986static int __net_init genl_pernet_init(struct net *net) 1043static 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 */