diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 33f60fca7aa7..bd43f0152c21 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; |
| 457 | update: | 465 | update: |
| @@ -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 | } |
