aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c86
1 files changed, 73 insertions, 13 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 33f60fca7aa..bd43f0152c2 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -114,9 +114,9 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
114 } 114 }
115 opt = xchg(&inet6_sk(sk)->opt, opt); 115 opt = xchg(&inet6_sk(sk)->opt, opt);
116 } else { 116 } else {
117 write_lock(&sk->sk_dst_lock); 117 spin_lock(&sk->sk_dst_lock);
118 opt = xchg(&inet6_sk(sk)->opt, opt); 118 opt = xchg(&inet6_sk(sk)->opt, opt);
119 write_unlock(&sk->sk_dst_lock); 119 spin_unlock(&sk->sk_dst_lock);
120 } 120 }
121 sk_dst_reset(sk); 121 sk_dst_reset(sk);
122 122
@@ -337,6 +337,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
337 retv = 0; 337 retv = 0;
338 break; 338 break;
339 339
340 case IPV6_RECVPATHMTU:
341 if (optlen < sizeof(int))
342 goto e_inval;
343 np->rxopt.bits.rxpmtu = valbool;
344 retv = 0;
345 break;
346
340 case IPV6_HOPOPTS: 347 case IPV6_HOPOPTS:
341 case IPV6_RTHDRDSTOPTS: 348 case IPV6_RTHDRDSTOPTS:
342 case IPV6_RTHDR: 349 case IPV6_RTHDR:
@@ -451,7 +458,8 @@ sticky_done:
451 msg.msg_controllen = optlen; 458 msg.msg_controllen = optlen;
452 msg.msg_control = (void*)(opt+1); 459 msg.msg_control = (void*)(opt+1);
453 460
454 retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk); 461 retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk,
462 &junk);
455 if (retv) 463 if (retv)
456 goto done; 464 goto done;
457update: 465update:
@@ -767,6 +775,17 @@ pref_skip_coa:
767 775
768 break; 776 break;
769 } 777 }
778 case IPV6_MINHOPCOUNT:
779 if (optlen < sizeof(int))
780 goto e_inval;
781 if (val < 0 || val > 255)
782 goto e_inval;
783 np->min_hopcount = val;
784 break;
785 case IPV6_DONTFRAG:
786 np->dontfrag = valbool;
787 retv = 0;
788 break;
770 } 789 }
771 790
772 release_sock(sk); 791 release_sock(sk);
@@ -971,14 +990,13 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
971 case IPV6_MTU: 990 case IPV6_MTU:
972 { 991 {
973 struct dst_entry *dst; 992 struct dst_entry *dst;
993
974 val = 0; 994 val = 0;
975 lock_sock(sk); 995 rcu_read_lock();
976 dst = sk_dst_get(sk); 996 dst = __sk_dst_get(sk);
977 if (dst) { 997 if (dst)
978 val = dst_mtu(dst); 998 val = dst_mtu(dst);
979 dst_release(dst); 999 rcu_read_unlock();
980 }
981 release_sock(sk);
982 if (!val) 1000 if (!val)
983 return -ENOTCONN; 1001 return -ENOTCONN;
984 break; 1002 break;
@@ -1056,6 +1074,38 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1056 val = np->rxopt.bits.rxflow; 1074 val = np->rxopt.bits.rxflow;
1057 break; 1075 break;
1058 1076
1077 case IPV6_RECVPATHMTU:
1078 val = np->rxopt.bits.rxpmtu;
1079 break;
1080
1081 case IPV6_PATHMTU:
1082 {
1083 struct dst_entry *dst;
1084 struct ip6_mtuinfo mtuinfo;
1085
1086 if (len < sizeof(mtuinfo))
1087 return -EINVAL;
1088
1089 len = sizeof(mtuinfo);
1090 memset(&mtuinfo, 0, sizeof(mtuinfo));
1091
1092 rcu_read_lock();
1093 dst = __sk_dst_get(sk);
1094 if (dst)
1095 mtuinfo.ip6m_mtu = dst_mtu(dst);
1096 rcu_read_unlock();
1097 if (!mtuinfo.ip6m_mtu)
1098 return -ENOTCONN;
1099
1100 if (put_user(len, optlen))
1101 return -EFAULT;
1102 if (copy_to_user(optval, &mtuinfo, len))
1103 return -EFAULT;
1104
1105 return 0;
1106 break;
1107 }
1108
1059 case IPV6_UNICAST_HOPS: 1109 case IPV6_UNICAST_HOPS:
1060 case IPV6_MULTICAST_HOPS: 1110 case IPV6_MULTICAST_HOPS:
1061 { 1111 {
@@ -1066,12 +1116,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1066 else 1116 else
1067 val = np->mcast_hops; 1117 val = np->mcast_hops;
1068 1118
1069 dst = sk_dst_get(sk); 1119 if (val < 0) {
1070 if (dst) { 1120 rcu_read_lock();
1071 if (val < 0) 1121 dst = __sk_dst_get(sk);
1122 if (dst)
1072 val = ip6_dst_hoplimit(dst); 1123 val = ip6_dst_hoplimit(dst);
1073 dst_release(dst); 1124 rcu_read_unlock();
1074 } 1125 }
1126
1075 if (val < 0) 1127 if (val < 0)
1076 val = sock_net(sk)->ipv6.devconf_all->hop_limit; 1128 val = sock_net(sk)->ipv6.devconf_all->hop_limit;
1077 break; 1129 break;
@@ -1115,6 +1167,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1115 val |= IPV6_PREFER_SRC_HOME; 1167 val |= IPV6_PREFER_SRC_HOME;
1116 break; 1168 break;
1117 1169
1170 case IPV6_MINHOPCOUNT:
1171 val = np->min_hopcount;
1172 break;
1173
1174 case IPV6_DONTFRAG:
1175 val = np->dontfrag;
1176 break;
1177
1118 default: 1178 default:
1119 return -ENOPROTOOPT; 1179 return -ENOPROTOOPT;
1120 } 1180 }