diff options
Diffstat (limited to 'net/netlink/genetlink.c')
-rw-r--r-- | net/netlink/genetlink.c | 186 |
1 files changed, 146 insertions, 40 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index eed4c6a8afc0..575c64341508 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -18,8 +18,6 @@ | |||
18 | #include <net/sock.h> | 18 | #include <net/sock.h> |
19 | #include <net/genetlink.h> | 19 | #include <net/genetlink.h> |
20 | 20 | ||
21 | struct sock *genl_sock = NULL; | ||
22 | |||
23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ | 21 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ |
24 | 22 | ||
25 | static inline void genl_lock(void) | 23 | static inline void genl_lock(void) |
@@ -175,10 +173,31 @@ int genl_register_mc_group(struct genl_family *family, | |||
175 | mc_groups_longs++; | 173 | mc_groups_longs++; |
176 | } | 174 | } |
177 | 175 | ||
178 | err = netlink_change_ngroups(genl_sock, | 176 | if (family->netnsok) { |
179 | mc_groups_longs * BITS_PER_LONG); | 177 | struct net *net; |
180 | if (err) | 178 | |
181 | goto out; | 179 | rcu_read_lock(); |
180 | for_each_net_rcu(net) { | ||
181 | err = netlink_change_ngroups(net->genl_sock, | ||
182 | mc_groups_longs * BITS_PER_LONG); | ||
183 | if (err) { | ||
184 | /* | ||
185 | * No need to roll back, can only fail if | ||
186 | * memory allocation fails and then the | ||
187 | * number of _possible_ groups has been | ||
188 | * increased on some sockets which is ok. | ||
189 | */ | ||
190 | rcu_read_unlock(); | ||
191 | goto out; | ||
192 | } | ||
193 | } | ||
194 | rcu_read_unlock(); | ||
195 | } else { | ||
196 | err = netlink_change_ngroups(init_net.genl_sock, | ||
197 | mc_groups_longs * BITS_PER_LONG); | ||
198 | if (err) | ||
199 | goto out; | ||
200 | } | ||
182 | 201 | ||
183 | grp->id = id; | 202 | grp->id = id; |
184 | set_bit(id, mc_groups); | 203 | set_bit(id, mc_groups); |
@@ -195,8 +214,14 @@ EXPORT_SYMBOL(genl_register_mc_group); | |||
195 | static void __genl_unregister_mc_group(struct genl_family *family, | 214 | static void __genl_unregister_mc_group(struct genl_family *family, |
196 | struct genl_multicast_group *grp) | 215 | struct genl_multicast_group *grp) |
197 | { | 216 | { |
217 | struct net *net; | ||
198 | BUG_ON(grp->family != family); | 218 | BUG_ON(grp->family != family); |
199 | netlink_clear_multicast_users(genl_sock, grp->id); | 219 | |
220 | rcu_read_lock(); | ||
221 | for_each_net_rcu(net) | ||
222 | netlink_clear_multicast_users(net->genl_sock, grp->id); | ||
223 | rcu_read_unlock(); | ||
224 | |||
200 | clear_bit(grp->id, mc_groups); | 225 | clear_bit(grp->id, mc_groups); |
201 | list_del(&grp->list); | 226 | list_del(&grp->list); |
202 | genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); | 227 | genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); |
@@ -467,6 +492,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
467 | { | 492 | { |
468 | struct genl_ops *ops; | 493 | struct genl_ops *ops; |
469 | struct genl_family *family; | 494 | struct genl_family *family; |
495 | struct net *net = sock_net(skb->sk); | ||
470 | struct genl_info info; | 496 | struct genl_info info; |
471 | struct genlmsghdr *hdr = nlmsg_data(nlh); | 497 | struct genlmsghdr *hdr = nlmsg_data(nlh); |
472 | int hdrlen, err; | 498 | int hdrlen, err; |
@@ -475,6 +501,10 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
475 | if (family == NULL) | 501 | if (family == NULL) |
476 | return -ENOENT; | 502 | return -ENOENT; |
477 | 503 | ||
504 | /* this family doesn't exist in this netns */ | ||
505 | if (!family->netnsok && !net_eq(net, &init_net)) | ||
506 | return -ENOENT; | ||
507 | |||
478 | hdrlen = GENL_HDRLEN + family->hdrsize; | 508 | hdrlen = GENL_HDRLEN + family->hdrsize; |
479 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) | 509 | if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) |
480 | return -EINVAL; | 510 | return -EINVAL; |
@@ -492,7 +522,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
492 | return -EOPNOTSUPP; | 522 | return -EOPNOTSUPP; |
493 | 523 | ||
494 | genl_unlock(); | 524 | genl_unlock(); |
495 | err = netlink_dump_start(genl_sock, skb, nlh, | 525 | err = netlink_dump_start(net->genl_sock, skb, nlh, |
496 | ops->dumpit, ops->done); | 526 | ops->dumpit, ops->done); |
497 | genl_lock(); | 527 | genl_lock(); |
498 | return err; | 528 | return err; |
@@ -514,6 +544,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
514 | info.genlhdr = nlmsg_data(nlh); | 544 | info.genlhdr = nlmsg_data(nlh); |
515 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 545 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
516 | info.attrs = family->attrbuf; | 546 | info.attrs = family->attrbuf; |
547 | genl_info_net_set(&info, net); | ||
517 | 548 | ||
518 | return ops->doit(skb, &info); | 549 | return ops->doit(skb, &info); |
519 | } | 550 | } |
@@ -534,6 +565,7 @@ static struct genl_family genl_ctrl = { | |||
534 | .name = "nlctrl", | 565 | .name = "nlctrl", |
535 | .version = 0x2, | 566 | .version = 0x2, |
536 | .maxattr = CTRL_ATTR_MAX, | 567 | .maxattr = CTRL_ATTR_MAX, |
568 | .netnsok = true, | ||
537 | }; | 569 | }; |
538 | 570 | ||
539 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | 571 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, |
@@ -650,6 +682,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
650 | 682 | ||
651 | int i, n = 0; | 683 | int i, n = 0; |
652 | struct genl_family *rt; | 684 | struct genl_family *rt; |
685 | struct net *net = sock_net(skb->sk); | ||
653 | int chains_to_skip = cb->args[0]; | 686 | int chains_to_skip = cb->args[0]; |
654 | int fams_to_skip = cb->args[1]; | 687 | int fams_to_skip = cb->args[1]; |
655 | 688 | ||
@@ -658,6 +691,8 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
658 | continue; | 691 | continue; |
659 | n = 0; | 692 | n = 0; |
660 | list_for_each_entry(rt, genl_family_chain(i), family_list) { | 693 | list_for_each_entry(rt, genl_family_chain(i), family_list) { |
694 | if (!rt->netnsok && !net_eq(net, &init_net)) | ||
695 | continue; | ||
661 | if (++n < fams_to_skip) | 696 | if (++n < fams_to_skip) |
662 | continue; | 697 | continue; |
663 | if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid, | 698 | if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid, |
@@ -729,6 +764,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | |||
729 | if (info->attrs[CTRL_ATTR_FAMILY_ID]) { | 764 | if (info->attrs[CTRL_ATTR_FAMILY_ID]) { |
730 | u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]); | 765 | u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]); |
731 | res = genl_family_find_byid(id); | 766 | res = genl_family_find_byid(id); |
767 | err = -ENOENT; | ||
732 | } | 768 | } |
733 | 769 | ||
734 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { | 770 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { |
@@ -736,49 +772,61 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | |||
736 | 772 | ||
737 | name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); | 773 | name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); |
738 | res = genl_family_find_byname(name); | 774 | res = genl_family_find_byname(name); |
775 | err = -ENOENT; | ||
739 | } | 776 | } |
740 | 777 | ||
741 | if (res == NULL) { | 778 | if (res == NULL) |
742 | err = -ENOENT; | 779 | return err; |
743 | goto errout; | 780 | |
781 | if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) { | ||
782 | /* family doesn't exist here */ | ||
783 | return -ENOENT; | ||
744 | } | 784 | } |
745 | 785 | ||
746 | msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq, | 786 | msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq, |
747 | CTRL_CMD_NEWFAMILY); | 787 | CTRL_CMD_NEWFAMILY); |
748 | if (IS_ERR(msg)) { | 788 | if (IS_ERR(msg)) |
749 | err = PTR_ERR(msg); | 789 | return PTR_ERR(msg); |
750 | goto errout; | ||
751 | } | ||
752 | 790 | ||
753 | err = genlmsg_reply(msg, info); | 791 | return genlmsg_reply(msg, info); |
754 | errout: | ||
755 | return err; | ||
756 | } | 792 | } |
757 | 793 | ||
758 | static int genl_ctrl_event(int event, void *data) | 794 | static int genl_ctrl_event(int event, void *data) |
759 | { | 795 | { |
760 | struct sk_buff *msg; | 796 | struct sk_buff *msg; |
797 | struct genl_family *family; | ||
798 | struct genl_multicast_group *grp; | ||
761 | 799 | ||
762 | if (genl_sock == NULL) | 800 | /* genl is still initialising */ |
801 | if (!init_net.genl_sock) | ||
763 | return 0; | 802 | return 0; |
764 | 803 | ||
765 | switch (event) { | 804 | switch (event) { |
766 | case CTRL_CMD_NEWFAMILY: | 805 | case CTRL_CMD_NEWFAMILY: |
767 | case CTRL_CMD_DELFAMILY: | 806 | case CTRL_CMD_DELFAMILY: |
768 | msg = ctrl_build_family_msg(data, 0, 0, event); | 807 | family = data; |
769 | if (IS_ERR(msg)) | 808 | msg = ctrl_build_family_msg(family, 0, 0, event); |
770 | return PTR_ERR(msg); | ||
771 | |||
772 | genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); | ||
773 | break; | 809 | break; |
774 | case CTRL_CMD_NEWMCAST_GRP: | 810 | case CTRL_CMD_NEWMCAST_GRP: |
775 | case CTRL_CMD_DELMCAST_GRP: | 811 | case CTRL_CMD_DELMCAST_GRP: |
812 | grp = data; | ||
813 | family = grp->family; | ||
776 | msg = ctrl_build_mcgrp_msg(data, 0, 0, event); | 814 | msg = ctrl_build_mcgrp_msg(data, 0, 0, event); |
777 | if (IS_ERR(msg)) | ||
778 | return PTR_ERR(msg); | ||
779 | |||
780 | genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); | ||
781 | break; | 815 | break; |
816 | default: | ||
817 | return -EINVAL; | ||
818 | } | ||
819 | |||
820 | if (IS_ERR(msg)) | ||
821 | return PTR_ERR(msg); | ||
822 | |||
823 | if (!family->netnsok) { | ||
824 | genlmsg_multicast_netns(&init_net, msg, 0, | ||
825 | GENL_ID_CTRL, GFP_KERNEL); | ||
826 | } else { | ||
827 | rcu_read_lock(); | ||
828 | genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC); | ||
829 | rcu_read_unlock(); | ||
782 | } | 830 | } |
783 | 831 | ||
784 | return 0; | 832 | return 0; |
@@ -795,6 +843,33 @@ static struct genl_multicast_group notify_grp = { | |||
795 | .name = "notify", | 843 | .name = "notify", |
796 | }; | 844 | }; |
797 | 845 | ||
846 | static int __net_init genl_pernet_init(struct net *net) | ||
847 | { | ||
848 | /* we'll bump the group number right afterwards */ | ||
849 | net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0, | ||
850 | genl_rcv, &genl_mutex, | ||
851 | THIS_MODULE); | ||
852 | |||
853 | if (!net->genl_sock && net_eq(net, &init_net)) | ||
854 | panic("GENL: Cannot initialize generic netlink\n"); | ||
855 | |||
856 | if (!net->genl_sock) | ||
857 | return -ENOMEM; | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | static void __net_exit genl_pernet_exit(struct net *net) | ||
863 | { | ||
864 | netlink_kernel_release(net->genl_sock); | ||
865 | net->genl_sock = NULL; | ||
866 | } | ||
867 | |||
868 | static struct pernet_operations genl_pernet_ops = { | ||
869 | .init = genl_pernet_init, | ||
870 | .exit = genl_pernet_exit, | ||
871 | }; | ||
872 | |||
798 | static int __init genl_init(void) | 873 | static int __init genl_init(void) |
799 | { | 874 | { |
800 | int i, err; | 875 | int i, err; |
@@ -804,36 +879,67 @@ static int __init genl_init(void) | |||
804 | 879 | ||
805 | err = genl_register_family(&genl_ctrl); | 880 | err = genl_register_family(&genl_ctrl); |
806 | if (err < 0) | 881 | if (err < 0) |
807 | goto errout; | 882 | goto problem; |
808 | 883 | ||
809 | err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops); | 884 | err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops); |
810 | if (err < 0) | 885 | if (err < 0) |
811 | goto errout_register; | 886 | goto problem; |
812 | 887 | ||
813 | netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); | 888 | netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); |
814 | 889 | ||
815 | /* we'll bump the group number right afterwards */ | 890 | err = register_pernet_subsys(&genl_pernet_ops); |
816 | genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0, | 891 | if (err) |
817 | genl_rcv, &genl_mutex, THIS_MODULE); | 892 | goto problem; |
818 | if (genl_sock == NULL) | ||
819 | panic("GENL: Cannot initialize generic netlink\n"); | ||
820 | 893 | ||
821 | err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); | 894 | err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); |
822 | if (err < 0) | 895 | if (err < 0) |
823 | goto errout_register; | 896 | goto problem; |
824 | 897 | ||
825 | return 0; | 898 | return 0; |
826 | 899 | ||
827 | errout_register: | 900 | problem: |
828 | genl_unregister_family(&genl_ctrl); | ||
829 | errout: | ||
830 | panic("GENL: Cannot register controller: %d\n", err); | 901 | panic("GENL: Cannot register controller: %d\n", err); |
831 | } | 902 | } |
832 | 903 | ||
833 | subsys_initcall(genl_init); | 904 | subsys_initcall(genl_init); |
834 | 905 | ||
835 | EXPORT_SYMBOL(genl_sock); | ||
836 | EXPORT_SYMBOL(genl_register_ops); | 906 | EXPORT_SYMBOL(genl_register_ops); |
837 | EXPORT_SYMBOL(genl_unregister_ops); | 907 | EXPORT_SYMBOL(genl_unregister_ops); |
838 | EXPORT_SYMBOL(genl_register_family); | 908 | EXPORT_SYMBOL(genl_register_family); |
839 | EXPORT_SYMBOL(genl_unregister_family); | 909 | EXPORT_SYMBOL(genl_unregister_family); |
910 | |||
911 | static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group, | ||
912 | gfp_t flags) | ||
913 | { | ||
914 | struct sk_buff *tmp; | ||
915 | struct net *net, *prev = NULL; | ||
916 | int err; | ||
917 | |||
918 | for_each_net_rcu(net) { | ||
919 | if (prev) { | ||
920 | tmp = skb_clone(skb, flags); | ||
921 | if (!tmp) { | ||
922 | err = -ENOMEM; | ||
923 | goto error; | ||
924 | } | ||
925 | err = nlmsg_multicast(prev->genl_sock, tmp, | ||
926 | pid, group, flags); | ||
927 | if (err) | ||
928 | goto error; | ||
929 | } | ||
930 | |||
931 | prev = net; | ||
932 | } | ||
933 | |||
934 | return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags); | ||
935 | error: | ||
936 | kfree_skb(skb); | ||
937 | return err; | ||
938 | } | ||
939 | |||
940 | int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, unsigned int group, | ||
941 | gfp_t flags) | ||
942 | { | ||
943 | return genlmsg_mcast(skb, pid, group, flags); | ||
944 | } | ||
945 | EXPORT_SYMBOL(genlmsg_multicast_allns); | ||