mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
ipv6: lockless IPV6_MULTICAST_HOPS implementation
This fixes data-races around np->mcast_hops, and make IPV6_MULTICAST_HOPS lockless. Note that np->mcast_hops is never negative, thus can fit an u8 field instead of s16. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d986f52124
commit
2da23eb07c
@ -214,15 +214,8 @@ struct ipv6_pinfo {
|
||||
__u32 frag_size;
|
||||
|
||||
s16 hop_limit;
|
||||
u8 mcast_hops;
|
||||
|
||||
#if defined(__BIG_ENDIAN_BITFIELD)
|
||||
/* Packed in 16bits. */
|
||||
__s16 mcast_hops:9;
|
||||
__u16 __unused_2:7,
|
||||
#else
|
||||
__u16 __unused_2:7;
|
||||
__s16 mcast_hops:9;
|
||||
#endif
|
||||
int ucast_oif;
|
||||
int mcast_oif;
|
||||
|
||||
|
@ -914,7 +914,7 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
|
||||
int hlimit;
|
||||
|
||||
if (ipv6_addr_is_multicast(&fl6->daddr))
|
||||
hlimit = np->mcast_hops;
|
||||
hlimit = READ_ONCE(np->mcast_hops);
|
||||
else
|
||||
hlimit = READ_ONCE(np->hop_limit);
|
||||
if (hlimit < 0)
|
||||
|
@ -676,7 +676,7 @@ ipv6_pktoptions:
|
||||
if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
|
||||
np->mcast_oif = inet6_iif(opt_skb);
|
||||
if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
|
||||
np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
|
||||
WRITE_ONCE(np->mcast_hops, ipv6_hdr(opt_skb)->hop_limit);
|
||||
if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
|
||||
np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
|
||||
if (np->repflow)
|
||||
|
@ -431,6 +431,16 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||
return -EINVAL;
|
||||
inet6_assign_bit(MC6_LOOP, sk, valbool);
|
||||
return 0;
|
||||
case IPV6_MULTICAST_HOPS:
|
||||
if (sk->sk_type == SOCK_STREAM)
|
||||
return retv;
|
||||
if (optlen < sizeof(int))
|
||||
return -EINVAL;
|
||||
if (val > 255 || val < -1)
|
||||
return -EINVAL;
|
||||
WRITE_ONCE(np->mcast_hops,
|
||||
val == -1 ? IPV6_DEFAULT_MCASTHOPS : val);
|
||||
return 0;
|
||||
}
|
||||
if (needs_rtnl)
|
||||
rtnl_lock();
|
||||
@ -751,16 +761,6 @@ done:
|
||||
break;
|
||||
}
|
||||
|
||||
case IPV6_MULTICAST_HOPS:
|
||||
if (sk->sk_type == SOCK_STREAM)
|
||||
break;
|
||||
if (optlen < sizeof(int))
|
||||
goto e_inval;
|
||||
if (val > 255 || val < -1)
|
||||
goto e_inval;
|
||||
np->mcast_hops = (val == -1 ? IPV6_DEFAULT_MCASTHOPS : val);
|
||||
retv = 0;
|
||||
break;
|
||||
|
||||
case IPV6_UNICAST_IF:
|
||||
{
|
||||
@ -1180,7 +1180,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
|
||||
}
|
||||
if (np->rxopt.bits.rxhlim) {
|
||||
int hlim = np->mcast_hops;
|
||||
int hlim = READ_ONCE(np->mcast_hops);
|
||||
|
||||
put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
||||
}
|
||||
if (np->rxopt.bits.rxtclass) {
|
||||
@ -1197,7 +1198,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
|
||||
}
|
||||
if (np->rxopt.bits.rxohlim) {
|
||||
int hlim = np->mcast_hops;
|
||||
int hlim = READ_ONCE(np->mcast_hops);
|
||||
|
||||
put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
|
||||
}
|
||||
if (np->rxopt.bits.rxflow) {
|
||||
@ -1349,7 +1351,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
if (optname == IPV6_UNICAST_HOPS)
|
||||
val = READ_ONCE(np->hop_limit);
|
||||
else
|
||||
val = np->mcast_hops;
|
||||
val = READ_ONCE(np->mcast_hops);
|
||||
|
||||
if (val < 0) {
|
||||
rcu_read_lock();
|
||||
|
@ -1542,7 +1542,8 @@ ipv6_pktoptions:
|
||||
if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
|
||||
np->mcast_oif = tcp_v6_iif(opt_skb);
|
||||
if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
|
||||
np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
|
||||
WRITE_ONCE(np->mcast_hops,
|
||||
ipv6_hdr(opt_skb)->hop_limit);
|
||||
if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
|
||||
np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
|
||||
if (np->repflow)
|
||||
|
@ -1322,7 +1322,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl)
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
|
||||
/* IPV6_MULTICAST_HOPS */
|
||||
np->mcast_hops = ttl;
|
||||
WRITE_ONCE(np->mcast_hops, ttl);
|
||||
}
|
||||
#endif
|
||||
release_sock(sk);
|
||||
|
Loading…
Reference in New Issue
Block a user