diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 8d766d9100cb..f2b731df8d77 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -117,6 +117,18 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, | |||
117 | return opt; | 117 | return opt; |
118 | } | 118 | } |
119 | 119 | ||
120 | static bool setsockopt_needs_rtnl(int optname) | ||
121 | { | ||
122 | switch (optname) { | ||
123 | case IPV6_ADD_MEMBERSHIP: | ||
124 | case IPV6_DROP_MEMBERSHIP: | ||
125 | case MCAST_JOIN_GROUP: | ||
126 | case MCAST_LEAVE_GROUP: | ||
127 | return true; | ||
128 | } | ||
129 | return false; | ||
130 | } | ||
131 | |||
120 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | 132 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
121 | char __user *optval, unsigned int optlen) | 133 | char __user *optval, unsigned int optlen) |
122 | { | 134 | { |
@@ -124,6 +136,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
124 | struct net *net = sock_net(sk); | 136 | struct net *net = sock_net(sk); |
125 | int val, valbool; | 137 | int val, valbool; |
126 | int retv = -ENOPROTOOPT; | 138 | int retv = -ENOPROTOOPT; |
139 | bool needs_rtnl = setsockopt_needs_rtnl(optname); | ||
127 | 140 | ||
128 | if (optval == NULL) | 141 | if (optval == NULL) |
129 | val = 0; | 142 | val = 0; |
@@ -140,6 +153,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
140 | if (ip6_mroute_opt(optname)) | 153 | if (ip6_mroute_opt(optname)) |
141 | return ip6_mroute_setsockopt(sk, optname, optval, optlen); | 154 | return ip6_mroute_setsockopt(sk, optname, optval, optlen); |
142 | 155 | ||
156 | if (needs_rtnl) | ||
157 | rtnl_lock(); | ||
143 | lock_sock(sk); | 158 | lock_sock(sk); |
144 | 159 | ||
145 | switch (optname) { | 160 | switch (optname) { |
@@ -582,9 +597,9 @@ done: | |||
582 | break; | 597 | break; |
583 | 598 | ||
584 | if (optname == IPV6_ADD_MEMBERSHIP) | 599 | if (optname == IPV6_ADD_MEMBERSHIP) |
585 | retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); | 600 | retv = __ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); |
586 | else | 601 | else |
587 | retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); | 602 | retv = __ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); |
588 | break; | 603 | break; |
589 | } | 604 | } |
590 | case IPV6_JOIN_ANYCAST: | 605 | case IPV6_JOIN_ANYCAST: |
@@ -623,11 +638,11 @@ done: | |||
623 | } | 638 | } |
624 | psin6 = (struct sockaddr_in6 *)&greq.gr_group; | 639 | psin6 = (struct sockaddr_in6 *)&greq.gr_group; |
625 | if (optname == MCAST_JOIN_GROUP) | 640 | if (optname == MCAST_JOIN_GROUP) |
626 | retv = ipv6_sock_mc_join(sk, greq.gr_interface, | 641 | retv = __ipv6_sock_mc_join(sk, greq.gr_interface, |
627 | &psin6->sin6_addr); | 642 | &psin6->sin6_addr); |
628 | else | 643 | else |
629 | retv = ipv6_sock_mc_drop(sk, greq.gr_interface, | 644 | retv = __ipv6_sock_mc_drop(sk, greq.gr_interface, |
630 | &psin6->sin6_addr); | 645 | &psin6->sin6_addr); |
631 | break; | 646 | break; |
632 | } | 647 | } |
633 | case MCAST_JOIN_SOURCE_GROUP: | 648 | case MCAST_JOIN_SOURCE_GROUP: |
@@ -659,8 +674,8 @@ done: | |||
659 | struct sockaddr_in6 *psin6; | 674 | struct sockaddr_in6 *psin6; |
660 | 675 | ||
661 | psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; | 676 | psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; |
662 | retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, | 677 | retv = __ipv6_sock_mc_join(sk, greqs.gsr_interface, |
663 | &psin6->sin6_addr); | 678 | &psin6->sin6_addr); |
664 | /* prior join w/ different source is ok */ | 679 | /* prior join w/ different source is ok */ |
665 | if (retv && retv != -EADDRINUSE) | 680 | if (retv && retv != -EADDRINUSE) |
666 | break; | 681 | break; |
@@ -837,11 +852,15 @@ pref_skip_coa: | |||
837 | } | 852 | } |
838 | 853 | ||
839 | release_sock(sk); | 854 | release_sock(sk); |
855 | if (needs_rtnl) | ||
856 | rtnl_unlock(); | ||
840 | 857 | ||
841 | return retv; | 858 | return retv; |
842 | 859 | ||
843 | e_inval: | 860 | e_inval: |
844 | release_sock(sk); | 861 | release_sock(sk); |
862 | if (needs_rtnl) | ||
863 | rtnl_unlock(); | ||
845 | return -EINVAL; | 864 | return -EINVAL; |
846 | } | 865 | } |
847 | 866 | ||