aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ip_sockglue.c31
-rw-r--r--net/ipv6/ipv6_sockglue.c35
2 files changed, 52 insertions, 14 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 5cd99271d3a6..5171709199f4 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -536,12 +536,25 @@ out:
536 * Socket option code for IP. This is the end of the line after any 536 * Socket option code for IP. This is the end of the line after any
537 * TCP,UDP etc options on an IP socket. 537 * TCP,UDP etc options on an IP socket.
538 */ 538 */
539static bool setsockopt_needs_rtnl(int optname)
540{
541 switch (optname) {
542 case IP_ADD_MEMBERSHIP:
543 case IP_ADD_SOURCE_MEMBERSHIP:
544 case IP_DROP_MEMBERSHIP:
545 case MCAST_JOIN_GROUP:
546 case MCAST_LEAVE_GROUP:
547 return true;
548 }
549 return false;
550}
539 551
540static int do_ip_setsockopt(struct sock *sk, int level, 552static int do_ip_setsockopt(struct sock *sk, int level,
541 int optname, char __user *optval, unsigned int optlen) 553 int optname, char __user *optval, unsigned int optlen)
542{ 554{
543 struct inet_sock *inet = inet_sk(sk); 555 struct inet_sock *inet = inet_sk(sk);
544 int val = 0, err; 556 int val = 0, err;
557 bool needs_rtnl = setsockopt_needs_rtnl(optname);
545 558
546 switch (optname) { 559 switch (optname) {
547 case IP_PKTINFO: 560 case IP_PKTINFO:
@@ -584,6 +597,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
584 return ip_mroute_setsockopt(sk, optname, optval, optlen); 597 return ip_mroute_setsockopt(sk, optname, optval, optlen);
585 598
586 err = 0; 599 err = 0;
600 if (needs_rtnl)
601 rtnl_lock();
587 lock_sock(sk); 602 lock_sock(sk);
588 603
589 switch (optname) { 604 switch (optname) {
@@ -846,9 +861,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
846 } 861 }
847 862
848 if (optname == IP_ADD_MEMBERSHIP) 863 if (optname == IP_ADD_MEMBERSHIP)
849 err = ip_mc_join_group(sk, &mreq); 864 err = __ip_mc_join_group(sk, &mreq);
850 else 865 else
851 err = ip_mc_leave_group(sk, &mreq); 866 err = __ip_mc_leave_group(sk, &mreq);
852 break; 867 break;
853 } 868 }
854 case IP_MSFILTER: 869 case IP_MSFILTER:
@@ -913,7 +928,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
913 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr; 928 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
914 mreq.imr_address.s_addr = mreqs.imr_interface; 929 mreq.imr_address.s_addr = mreqs.imr_interface;
915 mreq.imr_ifindex = 0; 930 mreq.imr_ifindex = 0;
916 err = ip_mc_join_group(sk, &mreq); 931 err = __ip_mc_join_group(sk, &mreq);
917 if (err && err != -EADDRINUSE) 932 if (err && err != -EADDRINUSE)
918 break; 933 break;
919 omode = MCAST_INCLUDE; 934 omode = MCAST_INCLUDE;
@@ -945,9 +960,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
945 mreq.imr_ifindex = greq.gr_interface; 960 mreq.imr_ifindex = greq.gr_interface;
946 961
947 if (optname == MCAST_JOIN_GROUP) 962 if (optname == MCAST_JOIN_GROUP)
948 err = ip_mc_join_group(sk, &mreq); 963 err = __ip_mc_join_group(sk, &mreq);
949 else 964 else
950 err = ip_mc_leave_group(sk, &mreq); 965 err = __ip_mc_leave_group(sk, &mreq);
951 break; 966 break;
952 } 967 }
953 case MCAST_JOIN_SOURCE_GROUP: 968 case MCAST_JOIN_SOURCE_GROUP:
@@ -990,7 +1005,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
990 mreq.imr_multiaddr = psin->sin_addr; 1005 mreq.imr_multiaddr = psin->sin_addr;
991 mreq.imr_address.s_addr = 0; 1006 mreq.imr_address.s_addr = 0;
992 mreq.imr_ifindex = greqs.gsr_interface; 1007 mreq.imr_ifindex = greqs.gsr_interface;
993 err = ip_mc_join_group(sk, &mreq); 1008 err = __ip_mc_join_group(sk, &mreq);
994 if (err && err != -EADDRINUSE) 1009 if (err && err != -EADDRINUSE)
995 break; 1010 break;
996 greqs.gsr_interface = mreq.imr_ifindex; 1011 greqs.gsr_interface = mreq.imr_ifindex;
@@ -1118,10 +1133,14 @@ mc_msf_out:
1118 break; 1133 break;
1119 } 1134 }
1120 release_sock(sk); 1135 release_sock(sk);
1136 if (needs_rtnl)
1137 rtnl_unlock();
1121 return err; 1138 return err;
1122 1139
1123e_inval: 1140e_inval:
1124 release_sock(sk); 1141 release_sock(sk);
1142 if (needs_rtnl)
1143 rtnl_unlock();
1125 return -EINVAL; 1144 return -EINVAL;
1126} 1145}
1127 1146
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
120static 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
120static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, 132static 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
843e_inval: 860e_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