diff options
Diffstat (limited to 'net/netlink/genetlink.c')
-rw-r--r-- | net/netlink/genetlink.c | 64 |
1 files changed, 61 insertions, 3 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 76393f2f4b22..ee57459fc258 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -23,6 +23,9 @@ | |||
23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ | 23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ |
24 | static DECLARE_RWSEM(cb_lock); | 24 | static DECLARE_RWSEM(cb_lock); |
25 | 25 | ||
26 | atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0); | ||
27 | DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq); | ||
28 | |||
26 | void genl_lock(void) | 29 | void genl_lock(void) |
27 | { | 30 | { |
28 | mutex_lock(&genl_mutex); | 31 | mutex_lock(&genl_mutex); |
@@ -435,15 +438,18 @@ int genl_unregister_family(struct genl_family *family) | |||
435 | 438 | ||
436 | genl_lock_all(); | 439 | genl_lock_all(); |
437 | 440 | ||
438 | genl_unregister_mc_groups(family); | ||
439 | |||
440 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { | 441 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { |
441 | if (family->id != rc->id || strcmp(rc->name, family->name)) | 442 | if (family->id != rc->id || strcmp(rc->name, family->name)) |
442 | continue; | 443 | continue; |
443 | 444 | ||
445 | genl_unregister_mc_groups(family); | ||
446 | |||
444 | list_del(&rc->family_list); | 447 | list_del(&rc->family_list); |
445 | family->n_ops = 0; | 448 | family->n_ops = 0; |
446 | genl_unlock_all(); | 449 | up_write(&cb_lock); |
450 | wait_event(genl_sk_destructing_waitq, | ||
451 | atomic_read(&genl_sk_destructing_cnt) == 0); | ||
452 | genl_unlock(); | ||
447 | 453 | ||
448 | kfree(family->attrbuf); | 454 | kfree(family->attrbuf); |
449 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); | 455 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); |
@@ -983,11 +989,63 @@ static struct genl_multicast_group genl_ctrl_groups[] = { | |||
983 | { .name = "notify", }, | 989 | { .name = "notify", }, |
984 | }; | 990 | }; |
985 | 991 | ||
992 | static int genl_bind(struct net *net, int group) | ||
993 | { | ||
994 | int i, err = -ENOENT; | ||
995 | |||
996 | down_read(&cb_lock); | ||
997 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | ||
998 | struct genl_family *f; | ||
999 | |||
1000 | list_for_each_entry(f, genl_family_chain(i), family_list) { | ||
1001 | if (group >= f->mcgrp_offset && | ||
1002 | group < f->mcgrp_offset + f->n_mcgrps) { | ||
1003 | int fam_grp = group - f->mcgrp_offset; | ||
1004 | |||
1005 | if (!f->netnsok && net != &init_net) | ||
1006 | err = -ENOENT; | ||
1007 | else if (f->mcast_bind) | ||
1008 | err = f->mcast_bind(net, fam_grp); | ||
1009 | else | ||
1010 | err = 0; | ||
1011 | break; | ||
1012 | } | ||
1013 | } | ||
1014 | } | ||
1015 | up_read(&cb_lock); | ||
1016 | |||
1017 | return err; | ||
1018 | } | ||
1019 | |||
1020 | static void genl_unbind(struct net *net, int group) | ||
1021 | { | ||
1022 | int i; | ||
1023 | |||
1024 | down_read(&cb_lock); | ||
1025 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | ||
1026 | struct genl_family *f; | ||
1027 | |||
1028 | list_for_each_entry(f, genl_family_chain(i), family_list) { | ||
1029 | if (group >= f->mcgrp_offset && | ||
1030 | group < f->mcgrp_offset + f->n_mcgrps) { | ||
1031 | int fam_grp = group - f->mcgrp_offset; | ||
1032 | |||
1033 | if (f->mcast_unbind) | ||
1034 | f->mcast_unbind(net, fam_grp); | ||
1035 | break; | ||
1036 | } | ||
1037 | } | ||
1038 | } | ||
1039 | up_read(&cb_lock); | ||
1040 | } | ||
1041 | |||
986 | static int __net_init genl_pernet_init(struct net *net) | 1042 | static int __net_init genl_pernet_init(struct net *net) |
987 | { | 1043 | { |
988 | struct netlink_kernel_cfg cfg = { | 1044 | struct netlink_kernel_cfg cfg = { |
989 | .input = genl_rcv, | 1045 | .input = genl_rcv, |
990 | .flags = NL_CFG_F_NONROOT_RECV, | 1046 | .flags = NL_CFG_F_NONROOT_RECV, |
1047 | .bind = genl_bind, | ||
1048 | .unbind = genl_unbind, | ||
991 | }; | 1049 | }; |
992 | 1050 | ||
993 | /* we'll bump the group number right afterwards */ | 1051 | /* we'll bump the group number right afterwards */ |