Commit e73d5fb7 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipv6-data-races'

Eric Dumazet says:

====================
ipv6: round of data-races fixes

This series is inspired by one related syzbot report.

Many inet6_sk(sk) fields reads or writes are racy.

Move 1-bit fields to inet->inet_flags to provide
atomic safety. inet6_{test|set|clear|assign}_bit() helpers
could be changed later if we need to make room in inet_flags.

Also add missing READ_ONCE()/WRITE_ONCE() when
lockless readers need access to specific fields.

np->srcprefs will be handled separately to avoid merge conflicts
because a prior patch was posted for net tree.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f2fa1c81 859f8b26
...@@ -213,28 +213,9 @@ struct ipv6_pinfo { ...@@ -213,28 +213,9 @@ struct ipv6_pinfo {
__be32 flow_label; __be32 flow_label;
__u32 frag_size; __u32 frag_size;
/* s16 hop_limit;
* Packed in 16bits. u8 mcast_hops;
* Omit one shift by putting the signed field at MSB.
*/
#if defined(__BIG_ENDIAN_BITFIELD)
__s16 hop_limit:9;
__u16 __unused_1:7;
#else
__u16 __unused_1:7;
__s16 hop_limit:9;
#endif
#if defined(__BIG_ENDIAN_BITFIELD)
/* Packed in 16bits. */
__s16 mcast_hops:9;
__u16 __unused_2:6,
mc_loop:1;
#else
__u16 mc_loop:1,
__unused_2:6;
__s16 mcast_hops:9;
#endif
int ucast_oif; int ucast_oif;
int mcast_oif; int mcast_oif;
...@@ -262,21 +243,11 @@ struct ipv6_pinfo { ...@@ -262,21 +243,11 @@ struct ipv6_pinfo {
} rxopt; } rxopt;
/* sockopt flags */ /* sockopt flags */
__u16 recverr:1, __u8 srcprefs:3; /* 001: prefer temporary address
sndflow:1,
repflow:1,
pmtudisc:3,
padding:1, /* 1 bit hole */
srcprefs:3, /* 001: prefer temporary address
* 010: prefer public address * 010: prefer public address
* 100: prefer care-of address * 100: prefer care-of address
*/ */
dontfrag:1, __u8 pmtudisc;
autoflowlabel:1,
autoflowlabel_set:1,
mc_all:1,
recverr_rfc4884:1,
rtalert_isolate:1;
__u8 min_hopcount; __u8 min_hopcount;
__u8 tclass; __u8 tclass;
__be32 rcv_flowinfo; __be32 rcv_flowinfo;
...@@ -293,6 +264,18 @@ struct ipv6_pinfo { ...@@ -293,6 +264,18 @@ struct ipv6_pinfo {
struct inet6_cork cork; struct inet6_cork cork;
}; };
/* We currently use available bits from inet_sk(sk)->inet_flags,
* this could change in the future.
*/
#define inet6_test_bit(nr, sk) \
test_bit(INET_FLAGS_##nr, &inet_sk(sk)->inet_flags)
#define inet6_set_bit(nr, sk) \
set_bit(INET_FLAGS_##nr, &inet_sk(sk)->inet_flags)
#define inet6_clear_bit(nr, sk) \
clear_bit(INET_FLAGS_##nr, &inet_sk(sk)->inet_flags)
#define inet6_assign_bit(nr, sk, val) \
assign_bit(INET_FLAGS_##nr, &inet_sk(sk)->inet_flags, val)
/* WARNING: don't change the layout of the members in {raw,udp,tcp}6_sock! */ /* WARNING: don't change the layout of the members in {raw,udp,tcp}6_sock! */
struct raw6_sock { struct raw6_sock {
/* inet_sock has to be the first member of raw6_sock */ /* inet_sock has to be the first member of raw6_sock */
......
...@@ -268,6 +268,16 @@ enum { ...@@ -268,6 +268,16 @@ enum {
INET_FLAGS_NODEFRAG = 17, INET_FLAGS_NODEFRAG = 17,
INET_FLAGS_BIND_ADDRESS_NO_PORT = 18, INET_FLAGS_BIND_ADDRESS_NO_PORT = 18,
INET_FLAGS_DEFER_CONNECT = 19, INET_FLAGS_DEFER_CONNECT = 19,
INET_FLAGS_MC6_LOOP = 20,
INET_FLAGS_RECVERR6_RFC4884 = 21,
INET_FLAGS_MC6_ALL = 22,
INET_FLAGS_AUTOFLOWLABEL_SET = 23,
INET_FLAGS_AUTOFLOWLABEL = 24,
INET_FLAGS_DONTFRAG = 25,
INET_FLAGS_RECVERR6 = 26,
INET_FLAGS_REPFLOW = 27,
INET_FLAGS_RTALERT_ISOLATE = 28,
INET_FLAGS_SNDFLOW = 29,
}; };
/* cmsg flags for inet */ /* cmsg flags for inet */
......
...@@ -266,7 +266,7 @@ static inline unsigned int ip6_skb_dst_mtu(const struct sk_buff *skb) ...@@ -266,7 +266,7 @@ static inline unsigned int ip6_skb_dst_mtu(const struct sk_buff *skb)
const struct dst_entry *dst = skb_dst(skb); const struct dst_entry *dst = skb_dst(skb);
unsigned int mtu; unsigned int mtu;
if (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) { if (np && READ_ONCE(np->pmtudisc) >= IPV6_PMTUDISC_PROBE) {
mtu = READ_ONCE(dst->dev->mtu); mtu = READ_ONCE(dst->dev->mtu);
mtu -= lwtunnel_headroom(dst->lwtstate, mtu); mtu -= lwtunnel_headroom(dst->lwtstate, mtu);
} else { } else {
...@@ -277,14 +277,18 @@ static inline unsigned int ip6_skb_dst_mtu(const struct sk_buff *skb) ...@@ -277,14 +277,18 @@ static inline unsigned int ip6_skb_dst_mtu(const struct sk_buff *skb)
static inline bool ip6_sk_accept_pmtu(const struct sock *sk) static inline bool ip6_sk_accept_pmtu(const struct sock *sk)
{ {
return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE && u8 pmtudisc = READ_ONCE(inet6_sk(sk)->pmtudisc);
inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT;
return pmtudisc != IPV6_PMTUDISC_INTERFACE &&
pmtudisc != IPV6_PMTUDISC_OMIT;
} }
static inline bool ip6_sk_ignore_df(const struct sock *sk) static inline bool ip6_sk_ignore_df(const struct sock *sk)
{ {
return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO || u8 pmtudisc = READ_ONCE(inet6_sk(sk)->pmtudisc);
inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
return pmtudisc < IPV6_PMTUDISC_DO ||
pmtudisc == IPV6_PMTUDISC_OMIT;
} }
static inline const struct in6_addr *rt6_nexthop(const struct rt6_info *rt, static inline const struct in6_addr *rt6_nexthop(const struct rt6_info *rt,
......
...@@ -373,12 +373,12 @@ static inline void ipcm6_init(struct ipcm6_cookie *ipc6) ...@@ -373,12 +373,12 @@ static inline void ipcm6_init(struct ipcm6_cookie *ipc6)
} }
static inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6, static inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6,
const struct ipv6_pinfo *np) const struct sock *sk)
{ {
*ipc6 = (struct ipcm6_cookie) { *ipc6 = (struct ipcm6_cookie) {
.hlimit = -1, .hlimit = -1,
.tclass = np->tclass, .tclass = inet6_sk(sk)->tclass,
.dontfrag = np->dontfrag, .dontfrag = inet6_test_bit(DONTFRAG, sk),
}; };
} }
...@@ -428,7 +428,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, ...@@ -428,7 +428,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
int flags); int flags);
int ip6_flowlabel_init(void); int ip6_flowlabel_init(void);
void ip6_flowlabel_cleanup(void); void ip6_flowlabel_cleanup(void);
bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np); bool ip6_autoflowlabel(struct net *net, const struct sock *sk);
static inline void fl6_sock_release(struct ip6_flowlabel *fl) static inline void fl6_sock_release(struct ip6_flowlabel *fl)
{ {
...@@ -914,9 +914,9 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, ...@@ -914,9 +914,9 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
int hlimit; int hlimit;
if (ipv6_addr_is_multicast(&fl6->daddr)) if (ipv6_addr_is_multicast(&fl6->daddr))
hlimit = np->mcast_hops; hlimit = READ_ONCE(np->mcast_hops);
else else
hlimit = np->hop_limit; hlimit = READ_ONCE(np->hop_limit);
if (hlimit < 0) if (hlimit < 0)
hlimit = ip6_dst_hoplimit(dst); hlimit = ip6_dst_hoplimit(dst);
return hlimit; return hlimit;
...@@ -1303,9 +1303,7 @@ static inline int ip6_sock_set_v6only(struct sock *sk) ...@@ -1303,9 +1303,7 @@ static inline int ip6_sock_set_v6only(struct sock *sk)
static inline void ip6_sock_set_recverr(struct sock *sk) static inline void ip6_sock_set_recverr(struct sock *sk)
{ {
lock_sock(sk); inet6_set_bit(RECVERR6, sk);
inet6_sk(sk)->recverr = true;
release_sock(sk);
} }
static inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val) static inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val)
......
...@@ -2238,7 +2238,7 @@ static inline void sock_confirm_neigh(struct sk_buff *skb, struct neighbour *n) ...@@ -2238,7 +2238,7 @@ static inline void sock_confirm_neigh(struct sk_buff *skb, struct neighbour *n)
} }
} }
bool sk_mc_loop(struct sock *sk); bool sk_mc_loop(const struct sock *sk);
static inline bool sk_can_gso(const struct sock *sk) static inline bool sk_can_gso(const struct sock *sk)
{ {
......
...@@ -2166,7 +2166,7 @@ static inline bool xfrm6_local_dontfrag(const struct sock *sk) ...@@ -2166,7 +2166,7 @@ static inline bool xfrm6_local_dontfrag(const struct sock *sk)
proto = sk->sk_protocol; proto = sk->sk_protocol;
if (proto == IPPROTO_UDP || proto == IPPROTO_RAW) if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
return inet6_sk(sk)->dontfrag; return inet6_test_bit(DONTFRAG, sk);
return false; return false;
} }
......
...@@ -759,7 +759,7 @@ static int sock_getbindtodevice(struct sock *sk, sockptr_t optval, ...@@ -759,7 +759,7 @@ static int sock_getbindtodevice(struct sock *sk, sockptr_t optval,
return ret; return ret;
} }
bool sk_mc_loop(struct sock *sk) bool sk_mc_loop(const struct sock *sk)
{ {
if (dev_recursion_level()) if (dev_recursion_level())
return false; return false;
...@@ -771,7 +771,7 @@ bool sk_mc_loop(struct sock *sk) ...@@ -771,7 +771,7 @@ bool sk_mc_loop(struct sock *sk)
return inet_test_bit(MC_LOOP, sk); return inet_test_bit(MC_LOOP, sk);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case AF_INET6: case AF_INET6:
return inet6_sk(sk)->mc_loop; return inet6_test_bit(MC6_LOOP, sk);
#endif #endif
} }
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
......
...@@ -185,7 +185,7 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -185,7 +185,7 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out; goto out;
} }
if (!sock_owned_by_user(sk) && np->recverr) { if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) {
sk->sk_err = err; sk->sk_err = err;
sk_error_report(sk); sk_error_report(sk);
} else { } else {
...@@ -676,10 +676,10 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -676,10 +676,10 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
np->mcast_oif = inet6_iif(opt_skb); np->mcast_oif = inet6_iif(opt_skb);
if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 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) if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
if (np->repflow) if (inet6_test_bit(REPFLOW, sk))
np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
if (ipv6_opt_accepted(sk, opt_skb, if (ipv6_opt_accepted(sk, opt_skb,
&DCCP_SKB_CB(opt_skb)->header.h6)) { &DCCP_SKB_CB(opt_skb)->header.h6)) {
...@@ -844,7 +844,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -844,7 +844,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
memset(&fl6, 0, sizeof(fl6)); memset(&fl6, 0, sizeof(fl6));
if (np->sndflow) { if (inet6_test_bit(SNDFLOW, sk)) {
fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
IP6_ECN_flow_init(fl6.flowlabel); IP6_ECN_flow_init(fl6.flowlabel);
if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) { if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
......
...@@ -581,7 +581,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info) ...@@ -581,7 +581,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
* 4.1.3.3. * 4.1.3.3.
*/ */
if ((family == AF_INET && !inet_test_bit(RECVERR, sk)) || if ((family == AF_INET && !inet_test_bit(RECVERR, sk)) ||
(family == AF_INET6 && !inet6_sk(sk)->recverr)) { (family == AF_INET6 && !inet6_test_bit(RECVERR6, sk))) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED) if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out; goto out;
} else { } else {
...@@ -899,7 +899,6 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, ...@@ -899,7 +899,6 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
} else if (family == AF_INET6) { } else if (family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6hdr *ip6 = ipv6_hdr(skb); struct ipv6hdr *ip6 = ipv6_hdr(skb);
DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
...@@ -908,7 +907,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, ...@@ -908,7 +907,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
sin6->sin6_port = 0; sin6->sin6_port = 0;
sin6->sin6_addr = ip6->saddr; sin6->sin6_addr = ip6->saddr;
sin6->sin6_flowinfo = 0; sin6->sin6_flowinfo = 0;
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
sin6->sin6_flowinfo = ip6_flowinfo(ip6); sin6->sin6_flowinfo = ip6_flowinfo(ip6);
sin6->sin6_scope_id = sin6->sin6_scope_id =
ipv6_iface_scope_id(&sin6->sin6_addr, ipv6_iface_scope_id(&sin6->sin6_addr,
......
...@@ -217,10 +217,11 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, ...@@ -217,10 +217,11 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk);
np->hop_limit = -1; np->hop_limit = -1;
np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
np->mc_loop = 1; inet6_set_bit(MC6_LOOP, sk);
np->mc_all = 1; inet6_set_bit(MC6_ALL, sk);
np->pmtudisc = IPV6_PMTUDISC_WANT; np->pmtudisc = IPV6_PMTUDISC_WANT;
np->repflow = net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ESTABLISHED; inet6_assign_bit(REPFLOW, sk, net->ipv6.sysctl.flowlabel_reflect &
FLOWLABEL_REFLECT_ESTABLISHED);
sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash); sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash);
...@@ -536,7 +537,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -536,7 +537,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
} }
sin->sin6_port = inet->inet_dport; sin->sin6_port = inet->inet_dport;
sin->sin6_addr = sk->sk_v6_daddr; sin->sin6_addr = sk->sk_v6_daddr;
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
sin->sin6_flowinfo = np->flow_label; sin->sin6_flowinfo = np->flow_label;
BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin, BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
CGROUP_INET6_GETPEERNAME); CGROUP_INET6_GETPEERNAME);
......
...@@ -80,7 +80,8 @@ int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr) ...@@ -80,7 +80,8 @@ int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr)
struct flowi6 fl6; struct flowi6 fl6;
int err = 0; int err = 0;
if (np->sndflow && (np->flow_label & IPV6_FLOWLABEL_MASK)) { if (inet6_test_bit(SNDFLOW, sk) &&
(np->flow_label & IPV6_FLOWLABEL_MASK)) {
flowlabel = fl6_sock_lookup(sk, np->flow_label); flowlabel = fl6_sock_lookup(sk, np->flow_label);
if (IS_ERR(flowlabel)) if (IS_ERR(flowlabel))
return -EINVAL; return -EINVAL;
...@@ -163,7 +164,7 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -163,7 +164,7 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
if (usin->sin6_family != AF_INET6) if (usin->sin6_family != AF_INET6)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
if (ipv6_addr_any(&usin->sin6_addr)) { if (ipv6_addr_any(&usin->sin6_addr)) {
...@@ -305,11 +306,10 @@ static void ipv6_icmp_error_rfc4884(const struct sk_buff *skb, ...@@ -305,11 +306,10 @@ static void ipv6_icmp_error_rfc4884(const struct sk_buff *skb,
void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
__be16 port, u32 info, u8 *payload) __be16 port, u32 info, u8 *payload)
{ {
struct ipv6_pinfo *np = inet6_sk(sk);
struct icmp6hdr *icmph = icmp6_hdr(skb); struct icmp6hdr *icmph = icmp6_hdr(skb);
struct sock_exterr_skb *serr; struct sock_exterr_skb *serr;
if (!np->recverr) if (!inet6_test_bit(RECVERR6, sk))
return; return;
skb = skb_clone(skb, GFP_ATOMIC); skb = skb_clone(skb, GFP_ATOMIC);
...@@ -332,7 +332,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, ...@@ -332,7 +332,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
__skb_pull(skb, payload - skb->data); __skb_pull(skb, payload - skb->data);
if (inet6_sk(sk)->recverr_rfc4884) if (inet6_test_bit(RECVERR6_RFC4884, sk))
ipv6_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884); ipv6_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884);
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
...@@ -344,12 +344,11 @@ EXPORT_SYMBOL_GPL(ipv6_icmp_error); ...@@ -344,12 +344,11 @@ EXPORT_SYMBOL_GPL(ipv6_icmp_error);
void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info)
{ {
const struct ipv6_pinfo *np = inet6_sk(sk);
struct sock_exterr_skb *serr; struct sock_exterr_skb *serr;
struct ipv6hdr *iph; struct ipv6hdr *iph;
struct sk_buff *skb; struct sk_buff *skb;
if (!np->recverr) if (!inet6_test_bit(RECVERR6, sk))
return; return;
skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
...@@ -493,7 +492,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) ...@@ -493,7 +492,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset), const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
struct ipv6hdr, daddr); struct ipv6hdr, daddr);
sin->sin6_addr = ip6h->daddr; sin->sin6_addr = ip6h->daddr;
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
sin->sin6_flowinfo = ip6_flowinfo(ip6h); sin->sin6_flowinfo = ip6_flowinfo(ip6h);
sin->sin6_scope_id = sin->sin6_scope_id =
ipv6_iface_scope_id(&sin->sin6_addr, ipv6_iface_scope_id(&sin->sin6_addr,
......
...@@ -588,7 +588,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, ...@@ -588,7 +588,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
else if (!fl6.flowi6_oif) else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif; fl6.flowi6_oif = np->ucast_oif;
ipcm6_init_sk(&ipc6, np); ipcm6_init_sk(&ipc6, sk);
ipc6.sockc.mark = mark; ipc6.sockc.mark = mark;
fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
...@@ -791,7 +791,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb) ...@@ -791,7 +791,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
msg.offset = 0; msg.offset = 0;
msg.type = type; msg.type = type;
ipcm6_init_sk(&ipc6, np); ipcm6_init_sk(&ipc6, sk);
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb)); ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
ipc6.sockc.mark = mark; ipc6.sockc.mark = mark;
......
...@@ -513,7 +513,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, ...@@ -513,7 +513,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
return 0; return 0;
} }
if (np->repflow) { if (inet6_test_bit(REPFLOW, sk)) {
freq->flr_label = np->flow_label; freq->flr_label = np->flow_label;
return 0; return 0;
} }
...@@ -551,10 +551,10 @@ static int ipv6_flowlabel_put(struct sock *sk, struct in6_flowlabel_req *freq) ...@@ -551,10 +551,10 @@ static int ipv6_flowlabel_put(struct sock *sk, struct in6_flowlabel_req *freq)
if (freq->flr_flags & IPV6_FL_F_REFLECT) { if (freq->flr_flags & IPV6_FL_F_REFLECT) {
if (sk->sk_protocol != IPPROTO_TCP) if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT; return -ENOPROTOOPT;
if (!np->repflow) if (!inet6_test_bit(REPFLOW, sk))
return -ESRCH; return -ESRCH;
np->flow_label = 0; np->flow_label = 0;
np->repflow = 0; inet6_clear_bit(REPFLOW, sk);
return 0; return 0;
} }
...@@ -626,7 +626,7 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq, ...@@ -626,7 +626,7 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
if (sk->sk_protocol != IPPROTO_TCP) if (sk->sk_protocol != IPPROTO_TCP)
return -ENOPROTOOPT; return -ENOPROTOOPT;
np->repflow = 1; inet6_set_bit(REPFLOW, sk);
return 0; return 0;
} }
......
...@@ -232,12 +232,11 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -232,12 +232,11 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
} }
EXPORT_SYMBOL(ip6_output); EXPORT_SYMBOL(ip6_output);
bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np) bool ip6_autoflowlabel(struct net *net, const struct sock *sk)
{ {
if (!np->autoflowlabel_set) if (!inet6_test_bit(AUTOFLOWLABEL_SET, sk))
return ip6_default_np_autolabel(net); return ip6_default_np_autolabel(net);
else return inet6_test_bit(AUTOFLOWLABEL, sk);
return np->autoflowlabel;
} }
/* /*
...@@ -309,12 +308,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, ...@@ -309,12 +308,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
* Fill in the IPv6 header * Fill in the IPv6 header
*/ */
if (np) if (np)
hlimit = np->hop_limit; hlimit = READ_ONCE(np->hop_limit);
if (hlimit < 0) if (hlimit < 0)
hlimit = ip6_dst_hoplimit(dst); hlimit = ip6_dst_hoplimit(dst);
ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
ip6_autoflowlabel(net, np), fl6)); ip6_autoflowlabel(net, sk), fl6));
hdr->payload_len = htons(seg_len); hdr->payload_len = htons(seg_len);
hdr->nexthdr = proto; hdr->nexthdr = proto;
...@@ -369,9 +368,8 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel) ...@@ -369,9 +368,8 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
if (sk && ra->sel == sel && if (sk && ra->sel == sel &&
(!sk->sk_bound_dev_if || (!sk->sk_bound_dev_if ||
sk->sk_bound_dev_if == skb->dev->ifindex)) { sk->sk_bound_dev_if == skb->dev->ifindex)) {
struct ipv6_pinfo *np = inet6_sk(sk);
if (np && np->rtalert_isolate && if (inet6_test_bit(RTALERT_ISOLATE, sk) &&
!net_eq(sock_net(sk), dev_net(skb->dev))) { !net_eq(sock_net(sk), dev_net(skb->dev))) {
continue; continue;
} }
...@@ -881,9 +879,11 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, ...@@ -881,9 +879,11 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
mtu = IPV6_MIN_MTU; mtu = IPV6_MIN_MTU;
} }
if (np && np->frag_size < mtu) { if (np) {
if (np->frag_size) u32 frag_size = READ_ONCE(np->frag_size);
mtu = np->frag_size;
if (frag_size && frag_size < mtu)
mtu = frag_size;
} }
if (mtu < hlen + sizeof(struct frag_hdr) + 8) if (mtu < hlen + sizeof(struct frag_hdr) + 8)
goto fail_toobig; goto fail_toobig;
...@@ -1392,7 +1392,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, ...@@ -1392,7 +1392,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
struct rt6_info *rt) struct rt6_info *rt)
{ {
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
unsigned int mtu; unsigned int mtu, frag_size;
struct ipv6_txoptions *nopt, *opt = ipc6->opt; struct ipv6_txoptions *nopt, *opt = ipc6->opt;
/* callers pass dst together with a reference, set it first so /* callers pass dst together with a reference, set it first so
...@@ -1436,15 +1436,16 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, ...@@ -1436,15 +1436,16 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
v6_cork->hop_limit = ipc6->hlimit; v6_cork->hop_limit = ipc6->hlimit;
v6_cork->tclass = ipc6->tclass; v6_cork->tclass = ipc6->tclass;
if (rt->dst.flags & DST_XFRM_TUNNEL) if (rt->dst.flags & DST_XFRM_TUNNEL)
mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? mtu = READ_ONCE(np->pmtudisc) >= IPV6_PMTUDISC_PROBE ?
READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst); READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
else else
mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? mtu = READ_ONCE(np->pmtudisc) >= IPV6_PMTUDISC_PROBE ?
READ_ONCE(rt->dst.dev->mtu) : dst_mtu(xfrm_dst_path(&rt->dst)); READ_ONCE(rt->dst.dev->mtu) : dst_mtu(xfrm_dst_path(&rt->dst));
if (np->frag_size < mtu) {
if (np->frag_size) frag_size = READ_ONCE(np->frag_size);
mtu = np->frag_size; if (frag_size && frag_size < mtu)
} mtu = frag_size;
cork->base.fragsize = mtu; cork->base.fragsize = mtu;
cork->base.gso_size = ipc6->gso_size; cork->base.gso_size = ipc6->gso_size;
cork->base.tx_flags = 0; cork->base.tx_flags = 0;
...@@ -1935,7 +1936,6 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, ...@@ -1935,7 +1936,6 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
struct sk_buff *skb, *tmp_skb; struct sk_buff *skb, *tmp_skb;
struct sk_buff **tail_skb; struct sk_buff **tail_skb;
struct in6_addr *final_dst; struct in6_addr *final_dst;
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
struct ipv6_txoptions *opt = v6_cork->opt; struct ipv6_txoptions *opt = v6_cork->opt;
...@@ -1978,7 +1978,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, ...@@ -1978,7 +1978,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
ip6_flow_hdr(hdr, v6_cork->tclass, ip6_flow_hdr(hdr, v6_cork->tclass,
ip6_make_flowlabel(net, skb, fl6->flowlabel, ip6_make_flowlabel(net, skb, fl6->flowlabel,
ip6_autoflowlabel(net, np), fl6)); ip6_autoflowlabel(net, sk), fl6));
hdr->hop_limit = v6_cork->hop_limit; hdr->hop_limit = v6_cork->hop_limit;
hdr->nexthdr = proto; hdr->nexthdr = proto;
hdr->saddr = fl6->saddr; hdr->saddr = fl6->saddr;
...@@ -2091,7 +2091,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk, ...@@ -2091,7 +2091,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
return ERR_PTR(err); return ERR_PTR(err);
} }
if (ipc6->dontfrag < 0) if (ipc6->dontfrag < 0)
ipc6->dontfrag = inet6_sk(sk)->dontfrag; ipc6->dontfrag = inet6_test_bit(DONTFRAG, sk);
err = __ip6_append_data(sk, &queue, cork, &v6_cork, err = __ip6_append_data(sk, &queue, cork, &v6_cork,
&current->task_frag, getfrag, from, &current->task_frag, getfrag, from,
......
...@@ -415,6 +415,97 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -415,6 +415,97 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (ip6_mroute_opt(optname)) if (ip6_mroute_opt(optname))
return ip6_mroute_setsockopt(sk, optname, optval, optlen); return ip6_mroute_setsockopt(sk, optname, optval, optlen);
/* Handle options that can be set without locking the socket. */
switch (optname) {
case IPV6_UNICAST_HOPS:
if (optlen < sizeof(int))
return -EINVAL;
if (val > 255 || val < -1)
return -EINVAL;
WRITE_ONCE(np->hop_limit, val);
return 0;
case IPV6_MULTICAST_LOOP:
if (optlen < sizeof(int))
return -EINVAL;
if (val != valbool)
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;
case IPV6_MTU:
if (optlen < sizeof(int))
return -EINVAL;
if (val && val < IPV6_MIN_MTU)
return -EINVAL;
WRITE_ONCE(np->frag_size, val);
return 0;
case IPV6_MINHOPCOUNT:
if (optlen < sizeof(int))
return -EINVAL;
if (val < 0 || val > 255)
return -EINVAL;
if (val)
static_branch_enable(&ip6_min_hopcount);
/* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount
* while we are changing it.
*/
WRITE_ONCE(np->min_hopcount, val);
return 0;
case IPV6_RECVERR_RFC4884:
if (optlen < sizeof(int))
return -EINVAL;
if (val < 0 || val > 1)
return -EINVAL;
inet6_assign_bit(RECVERR6_RFC4884, sk, valbool);
return 0;
case IPV6_MULTICAST_ALL:
if (optlen < sizeof(int))
return -EINVAL;
inet6_assign_bit(MC6_ALL, sk, valbool);
return 0;
case IPV6_AUTOFLOWLABEL:
inet6_assign_bit(AUTOFLOWLABEL, sk, valbool);
inet6_set_bit(AUTOFLOWLABEL_SET, sk);
return 0;
case IPV6_DONTFRAG:
inet6_assign_bit(DONTFRAG, sk, valbool);
return 0;
case IPV6_RECVERR:
if (optlen < sizeof(int))
return -EINVAL;
inet6_assign_bit(RECVERR6, sk, valbool);
if (!val)
skb_errqueue_purge(&sk->sk_error_queue);
return 0;
case IPV6_ROUTER_ALERT_ISOLATE:
if (optlen < sizeof(int))
return -EINVAL;
inet6_assign_bit(RTALERT_ISOLATE, sk, valbool);
return 0;
case IPV6_MTU_DISCOVER:
if (optlen < sizeof(int))
return -EINVAL;
if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
return -EINVAL;
WRITE_ONCE(np->pmtudisc, val);
return 0;
case IPV6_FLOWINFO_SEND:
if (optlen < sizeof(int))
return -EINVAL;
inet6_assign_bit(SNDFLOW, sk, valbool);
return 0;
}
if (needs_rtnl) if (needs_rtnl)
rtnl_lock(); rtnl_lock();
sockopt_lock_sock(sk); sockopt_lock_sock(sk);
...@@ -733,34 +824,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -733,34 +824,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
} }
break; break;
} }
case IPV6_UNICAST_HOPS:
if (optlen < sizeof(int))
goto e_inval;
if (val > 255 || val < -1)
goto e_inval;
np->hop_limit = val;
retv = 0;
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_MULTICAST_LOOP:
if (optlen < sizeof(int))
goto e_inval;
if (val != valbool)
goto e_inval;
np->mc_loop = valbool;
retv = 0;
break;
case IPV6_UNICAST_IF: case IPV6_UNICAST_IF:
{ {
...@@ -862,13 +926,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -862,13 +926,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
break; break;
} }
case IPV6_MULTICAST_ALL:
if (optlen < sizeof(int))
goto e_inval;
np->mc_all = valbool;
retv = 0;
break;
case MCAST_JOIN_GROUP: case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP: case MCAST_LEAVE_GROUP:
if (in_compat_syscall()) if (in_compat_syscall())
...@@ -896,42 +953,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -896,42 +953,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
goto e_inval; goto e_inval;
retv = ip6_ra_control(sk, val); retv = ip6_ra_control(sk, val);
break; break;
case IPV6_ROUTER_ALERT_ISOLATE:
if (optlen < sizeof(int))
goto e_inval;
np->rtalert_isolate = valbool;
retv = 0;
break;
case IPV6_MTU_DISCOVER:
if (optlen < sizeof(int))
goto e_inval;
if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
goto e_inval;
np->pmtudisc = val;
retv = 0;
break;
case IPV6_MTU:
if (optlen < sizeof(int))
goto e_inval;
if (val && val < IPV6_MIN_MTU)
goto e_inval;
np->frag_size = val;
retv = 0;
break;
case IPV6_RECVERR:
if (optlen < sizeof(int))
goto e_inval;
np->recverr = valbool;
if (!val)
skb_errqueue_purge(&sk->sk_error_queue);
retv = 0;
break;
case IPV6_FLOWINFO_SEND:
if (optlen < sizeof(int))
goto e_inval;
np->sndflow = valbool;
retv = 0;
break;
case IPV6_FLOWLABEL_MGR: case IPV6_FLOWLABEL_MGR:
retv = ipv6_flowlabel_opt(sk, optval, optlen); retv = ipv6_flowlabel_opt(sk, optval, optlen);
break; break;
...@@ -948,42 +969,10 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -948,42 +969,10 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
goto e_inval; goto e_inval;
retv = __ip6_sock_set_addr_preferences(sk, val); retv = __ip6_sock_set_addr_preferences(sk, val);
break; break;
case IPV6_MINHOPCOUNT:
if (optlen < sizeof(int))
goto e_inval;
if (val < 0 || val > 255)
goto e_inval;
if (val)
static_branch_enable(&ip6_min_hopcount);
/* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount
* while we are changing it.
*/
WRITE_ONCE(np->min_hopcount, val);
retv = 0;
break;
case IPV6_DONTFRAG:
np->dontfrag = valbool;
retv = 0;
break;
case IPV6_AUTOFLOWLABEL:
np->autoflowlabel = valbool;
np->autoflowlabel_set = 1;
retv = 0;
break;
case IPV6_RECVFRAGSIZE: case IPV6_RECVFRAGSIZE:
np->rxopt.bits.recvfragsize = valbool; np->rxopt.bits.recvfragsize = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVERR_RFC4884:
if (optlen < sizeof(int))
goto e_inval;
if (val < 0 || val > 1)
goto e_inval;
np->recverr_rfc4884 = valbool;
retv = 0;
break;
} }
unlock: unlock:
...@@ -1180,7 +1169,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1180,7 +1169,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
} }
if (np->rxopt.bits.rxhlim) { 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); put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
} }
if (np->rxopt.bits.rxtclass) { if (np->rxopt.bits.rxtclass) {
...@@ -1197,7 +1187,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1197,7 +1187,8 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
} }
if (np->rxopt.bits.rxohlim) { 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); put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
} }
if (np->rxopt.bits.rxflow) { if (np->rxopt.bits.rxflow) {
...@@ -1347,9 +1338,9 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1347,9 +1338,9 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
struct dst_entry *dst; struct dst_entry *dst;
if (optname == IPV6_UNICAST_HOPS) if (optname == IPV6_UNICAST_HOPS)
val = np->hop_limit; val = READ_ONCE(np->hop_limit);
else else
val = np->mcast_hops; val = READ_ONCE(np->mcast_hops);
if (val < 0) { if (val < 0) {
rcu_read_lock(); rcu_read_lock();
...@@ -1365,7 +1356,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1365,7 +1356,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
} }
case IPV6_MULTICAST_LOOP: case IPV6_MULTICAST_LOOP:
val = np->mc_loop; val = inet6_test_bit(MC6_LOOP, sk);
break; break;
case IPV6_MULTICAST_IF: case IPV6_MULTICAST_IF:
...@@ -1373,7 +1364,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1373,7 +1364,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_MULTICAST_ALL: case IPV6_MULTICAST_ALL:
val = np->mc_all; val = inet6_test_bit(MC6_ALL, sk);
break; break;
case IPV6_UNICAST_IF: case IPV6_UNICAST_IF:
...@@ -1381,15 +1372,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1381,15 +1372,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_MTU_DISCOVER: case IPV6_MTU_DISCOVER:
val = np->pmtudisc; val = READ_ONCE(np->pmtudisc);
break; break;
case IPV6_RECVERR: case IPV6_RECVERR:
val = np->recverr; val = inet6_test_bit(RECVERR6, sk);
break; break;
case IPV6_FLOWINFO_SEND: case IPV6_FLOWINFO_SEND:
val = np->sndflow; val = inet6_test_bit(SNDFLOW, sk);
break; break;
case IPV6_FLOWLABEL_MGR: case IPV6_FLOWLABEL_MGR:
...@@ -1442,15 +1433,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1442,15 +1433,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_MINHOPCOUNT: case IPV6_MINHOPCOUNT:
val = np->min_hopcount; val = READ_ONCE(np->min_hopcount);
break; break;
case IPV6_DONTFRAG: case IPV6_DONTFRAG:
val = np->dontfrag; val = inet6_test_bit(DONTFRAG, sk);
break; break;
case IPV6_AUTOFLOWLABEL: case IPV6_AUTOFLOWLABEL:
val = ip6_autoflowlabel(sock_net(sk), np); val = ip6_autoflowlabel(sock_net(sk), sk);
break; break;
case IPV6_RECVFRAGSIZE: case IPV6_RECVFRAGSIZE:
...@@ -1458,11 +1449,11 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -1458,11 +1449,11 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_ROUTER_ALERT_ISOLATE: case IPV6_ROUTER_ALERT_ISOLATE:
val = np->rtalert_isolate; val = inet6_test_bit(RTALERT_ISOLATE, sk);
break; break;
case IPV6_RECVERR_RFC4884: case IPV6_RECVERR_RFC4884:
val = np->recverr_rfc4884; val = inet6_test_bit(RECVERR6_RFC4884, sk);
break; break;
default: default:
......
...@@ -642,7 +642,7 @@ bool inet6_mc_check(const struct sock *sk, const struct in6_addr *mc_addr, ...@@ -642,7 +642,7 @@ bool inet6_mc_check(const struct sock *sk, const struct in6_addr *mc_addr,
} }
if (!mc) { if (!mc) {
rcu_read_unlock(); rcu_read_unlock();
return np->mc_all; return inet6_test_bit(MC6_ALL, sk);
} }
psl = rcu_dereference(mc->sflist); psl = rcu_dereference(mc->sflist);
if (!psl) { if (!psl) {
...@@ -1716,7 +1716,7 @@ static void ip6_mc_hdr(const struct sock *sk, struct sk_buff *skb, ...@@ -1716,7 +1716,7 @@ static void ip6_mc_hdr(const struct sock *sk, struct sk_buff *skb,
hdr->payload_len = htons(len); hdr->payload_len = htons(len);
hdr->nexthdr = proto; hdr->nexthdr = proto;
hdr->hop_limit = inet6_sk(sk)->hop_limit; hdr->hop_limit = READ_ONCE(inet6_sk(sk)->hop_limit);
hdr->saddr = *saddr; hdr->saddr = *saddr;
hdr->daddr = *daddr; hdr->daddr = *daddr;
......
...@@ -500,7 +500,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, ...@@ -500,7 +500,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
csum_partial(icmp6h, csum_partial(icmp6h,
skb->len, 0)); skb->len, 0));
ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); ip6_nd_hdr(skb, saddr, daddr, READ_ONCE(inet6_sk(sk)->hop_limit), skb->len);
rcu_read_lock(); rcu_read_lock();
idev = __in6_dev_get(dst->dev); idev = __in6_dev_get(dst->dev);
...@@ -1996,7 +1996,7 @@ static int __net_init ndisc_net_init(struct net *net) ...@@ -1996,7 +1996,7 @@ static int __net_init ndisc_net_init(struct net *net)
np = inet6_sk(sk); np = inet6_sk(sk);
np->hop_limit = 255; np->hop_limit = 255;
/* Do not loopback ndisc messages */ /* Do not loopback ndisc messages */
np->mc_loop = 0; inet6_clear_bit(MC6_LOOP, sk);
return 0; return 0;
} }
......
...@@ -89,7 +89,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -89,7 +89,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
} }
daddr = &(u->sin6_addr); daddr = &(u->sin6_addr);
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
fl6.flowlabel = u->sin6_flowinfo & IPV6_FLOWINFO_MASK; fl6.flowlabel = u->sin6_flowinfo & IPV6_FLOWINFO_MASK;
if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr))) if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr)))
oif = u->sin6_scope_id; oif = u->sin6_scope_id;
...@@ -118,7 +118,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -118,7 +118,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
l3mdev_master_ifindex_by_index(sock_net(sk), oif) != sk->sk_bound_dev_if)) l3mdev_master_ifindex_by_index(sock_net(sk), oif) != sk->sk_bound_dev_if))
return -EINVAL; return -EINVAL;
ipcm6_init_sk(&ipc6, np); ipcm6_init_sk(&ipc6, sk);
ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags); ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
ipc6.sockc.mark = READ_ONCE(sk->sk_mark); ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
......
...@@ -291,6 +291,7 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, ...@@ -291,6 +291,7 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
struct inet6_skb_parm *opt, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info) u8 type, u8 code, int offset, __be32 info)
{ {
bool recverr = inet6_test_bit(RECVERR6, sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
int err; int err;
int harderr; int harderr;
...@@ -300,26 +301,26 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, ...@@ -300,26 +301,26 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
2. Socket is connected (otherwise the error indication 2. Socket is connected (otherwise the error indication
is useless without recverr and error is hard. is useless without recverr and error is hard.
*/ */
if (!np->recverr && sk->sk_state != TCP_ESTABLISHED) if (!recverr && sk->sk_state != TCP_ESTABLISHED)
return; return;
harderr = icmpv6_err_convert(type, code, &err); harderr = icmpv6_err_convert(type, code, &err);
if (type == ICMPV6_PKT_TOOBIG) { if (type == ICMPV6_PKT_TOOBIG) {
ip6_sk_update_pmtu(skb, sk, info); ip6_sk_update_pmtu(skb, sk, info);
harderr = (np->pmtudisc == IPV6_PMTUDISC_DO); harderr = (READ_ONCE(np->pmtudisc) == IPV6_PMTUDISC_DO);
} }
if (type == NDISC_REDIRECT) { if (type == NDISC_REDIRECT) {
ip6_sk_redirect(skb, sk); ip6_sk_redirect(skb, sk);
return; return;
} }
if (np->recverr) { if (recverr) {
u8 *payload = skb->data; u8 *payload = skb->data;
if (!inet_test_bit(HDRINCL, sk)) if (!inet_test_bit(HDRINCL, sk))
payload += offset; payload += offset;
ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload); ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
} }
if (np->recverr || harderr) { if (recverr || harderr) {
sk->sk_err = err; sk->sk_err = err;
sk_error_report(sk); sk_error_report(sk);
} }
...@@ -587,7 +588,6 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, ...@@ -587,7 +588,6 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
struct flowi6 *fl6, struct dst_entry **dstp, struct flowi6 *fl6, struct dst_entry **dstp,
unsigned int flags, const struct sockcm_cookie *sockc) unsigned int flags, const struct sockcm_cookie *sockc)
{ {
struct ipv6_pinfo *np = inet6_sk(sk);
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct ipv6hdr *iph; struct ipv6hdr *iph;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -668,7 +668,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, ...@@ -668,7 +668,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
error: error:
IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
error_check: error_check:
if (err == -ENOBUFS && !np->recverr) if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk))
err = 0; err = 0;
return err; return err;
} }
...@@ -795,7 +795,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -795,7 +795,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return -EINVAL; return -EINVAL;
daddr = &sin6->sin6_addr; daddr = &sin6->sin6_addr;
if (np->sndflow) { if (inet6_test_bit(SNDFLOW, sk)) {
fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
...@@ -898,7 +898,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -898,7 +898,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
if (ipc6.dontfrag < 0) if (ipc6.dontfrag < 0)
ipc6.dontfrag = np->dontfrag; ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
if (msg->msg_flags&MSG_CONFIRM) if (msg->msg_flags&MSG_CONFIRM)
goto do_confirm; goto do_confirm;
......
...@@ -163,7 +163,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -163,7 +163,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
memset(&fl6, 0, sizeof(fl6)); memset(&fl6, 0, sizeof(fl6));
if (np->sndflow) { if (inet6_test_bit(SNDFLOW, sk)) {
fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
IP6_ECN_flow_init(fl6.flowlabel); IP6_ECN_flow_init(fl6.flowlabel);
if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
...@@ -508,7 +508,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -508,7 +508,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
tcp_ld_RTO_revert(sk, seq); tcp_ld_RTO_revert(sk, seq);
} }
if (!sock_owned_by_user(sk) && np->recverr) { if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) {
WRITE_ONCE(sk->sk_err, err); WRITE_ONCE(sk->sk_err, err);
sk_error_report(sk); sk_error_report(sk);
} else { } else {
...@@ -548,7 +548,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, ...@@ -548,7 +548,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
&ireq->ir_v6_rmt_addr); &ireq->ir_v6_rmt_addr);
fl6->daddr = ireq->ir_v6_rmt_addr; fl6->daddr = ireq->ir_v6_rmt_addr;
if (np->repflow && ireq->pktopts) if (inet6_test_bit(REPFLOW, sk) && ireq->pktopts)
fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
tclass = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos) ? tclass = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos) ?
...@@ -797,7 +797,7 @@ static void tcp_v6_init_req(struct request_sock *req, ...@@ -797,7 +797,7 @@ static void tcp_v6_init_req(struct request_sock *req,
(ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) || (ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxinfo ||
np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
np->rxopt.bits.rxohlim || np->repflow)) { np->rxopt.bits.rxohlim || inet6_test_bit(REPFLOW, sk_listener))) {
refcount_inc(&skb->users); refcount_inc(&skb->users);
ireq->pktopts = skb; ireq->pktopts = skb;
} }
...@@ -1055,10 +1055,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ...@@ -1055,10 +1055,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
if (sk) { if (sk) {
oif = sk->sk_bound_dev_if; oif = sk->sk_bound_dev_if;
if (sk_fullsock(sk)) { if (sk_fullsock(sk)) {
const struct ipv6_pinfo *np = tcp_inet6_sk(sk);
trace_tcp_send_reset(sk, skb); trace_tcp_send_reset(sk, skb);
if (np->repflow) if (inet6_test_bit(REPFLOW, sk))
label = ip6_flowlabel(ipv6h); label = ip6_flowlabel(ipv6h);
priority = sk->sk_priority; priority = sk->sk_priority;
txhash = sk->sk_txhash; txhash = sk->sk_txhash;
...@@ -1247,7 +1245,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * ...@@ -1247,7 +1245,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
newnp->mcast_oif = inet_iif(skb); newnp->mcast_oif = inet_iif(skb);
newnp->mcast_hops = ip_hdr(skb)->ttl; newnp->mcast_hops = ip_hdr(skb)->ttl;
newnp->rcv_flowinfo = 0; newnp->rcv_flowinfo = 0;
if (np->repflow) if (inet6_test_bit(REPFLOW, sk))
newnp->flow_label = 0; newnp->flow_label = 0;
/* /*
...@@ -1320,7 +1318,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * ...@@ -1320,7 +1318,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
newnp->mcast_oif = tcp_v6_iif(skb); newnp->mcast_oif = tcp_v6_iif(skb);
newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
if (np->repflow) if (inet6_test_bit(REPFLOW, sk))
newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));
/* Set ToS of the new socket based upon the value of incoming SYN. /* Set ToS of the new socket based upon the value of incoming SYN.
...@@ -1542,10 +1540,11 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1542,10 +1540,11 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
np->mcast_oif = tcp_v6_iif(opt_skb); np->mcast_oif = tcp_v6_iif(opt_skb);
if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 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) if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
if (np->repflow) if (inet6_test_bit(REPFLOW, sk))
np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) { if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) {
tcp_v6_restore_cb(opt_skb); tcp_v6_restore_cb(opt_skb);
......
...@@ -598,7 +598,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -598,7 +598,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!ip6_sk_accept_pmtu(sk)) if (!ip6_sk_accept_pmtu(sk))
goto out; goto out;
ip6_sk_update_pmtu(skb, sk, info); ip6_sk_update_pmtu(skb, sk, info);
if (np->pmtudisc != IPV6_PMTUDISC_DONT) if (READ_ONCE(np->pmtudisc) != IPV6_PMTUDISC_DONT)
harderr = 1; harderr = 1;
} }
if (type == NDISC_REDIRECT) { if (type == NDISC_REDIRECT) {
...@@ -619,7 +619,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -619,7 +619,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out; goto out;
} }
if (!np->recverr) { if (!inet6_test_bit(RECVERR6, sk)) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED) if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out; goto out;
} else { } else {
...@@ -1283,7 +1283,7 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, ...@@ -1283,7 +1283,7 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
send: send:
err = ip6_send_skb(skb); err = ip6_send_skb(skb);
if (err) { if (err) {
if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk)) {
UDP6_INC_STATS(sock_net(sk), UDP6_INC_STATS(sock_net(sk),
UDP_MIB_SNDBUFERRORS, is_udplite); UDP_MIB_SNDBUFERRORS, is_udplite);
err = 0; err = 0;
...@@ -1429,7 +1429,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1429,7 +1429,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
fl6->fl6_dport = sin6->sin6_port; fl6->fl6_dport = sin6->sin6_port;
daddr = &sin6->sin6_addr; daddr = &sin6->sin6_addr;
if (np->sndflow) { if (inet6_test_bit(SNDFLOW, sk)) {
fl6->flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; fl6->flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
if (fl6->flowlabel & IPV6_FLOWLABEL_MASK) { if (fl6->flowlabel & IPV6_FLOWLABEL_MASK) {
flowlabel = fl6_sock_lookup(sk, fl6->flowlabel); flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
...@@ -1595,7 +1595,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1595,7 +1595,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
do_append_data: do_append_data:
if (ipc6.dontfrag < 0) if (ipc6.dontfrag < 0)
ipc6.dontfrag = np->dontfrag; ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
up->len += ulen; up->len += ulen;
err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr), err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
&ipc6, fl6, (struct rt6_info *)dst, &ipc6, fl6, (struct rt6_info *)dst,
...@@ -1608,7 +1608,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1608,7 +1608,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
up->pending = 0; up->pending = 0;
if (err > 0) if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0; err = inet6_test_bit(RECVERR6, sk) ? net_xmit_errno(err) : 0;
release_sock(sk); release_sock(sk);
out: out:
......
...@@ -431,7 +431,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -431,7 +431,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
return -ENOTCONN; return -ENOTCONN;
lsa->l2tp_conn_id = lsk->peer_conn_id; lsa->l2tp_conn_id = lsk->peer_conn_id;
lsa->l2tp_addr = sk->sk_v6_daddr; lsa->l2tp_addr = sk->sk_v6_daddr;
if (np->sndflow) if (inet6_test_bit(SNDFLOW, sk))
lsa->l2tp_flowinfo = np->flow_label; lsa->l2tp_flowinfo = np->flow_label;
} else { } else {
if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) if (ipv6_addr_any(&sk->sk_v6_rcv_saddr))
...@@ -529,7 +529,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -529,7 +529,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
daddr = &lsa->l2tp_addr; daddr = &lsa->l2tp_addr;
if (np->sndflow) { if (inet6_test_bit(SNDFLOW, sk)) {
fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK; fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK;
if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) { if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
...@@ -621,7 +621,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -621,7 +621,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
if (ipc6.dontfrag < 0) if (ipc6.dontfrag < 0)
ipc6.dontfrag = np->dontfrag; ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
if (msg->msg_flags & MSG_CONFIRM) if (msg->msg_flags & MSG_CONFIRM)
goto do_confirm; goto do_confirm;
......
...@@ -1298,17 +1298,13 @@ static void set_sock_size(struct sock *sk, int mode, int val) ...@@ -1298,17 +1298,13 @@ static void set_sock_size(struct sock *sk, int mode, int val)
static void set_mcast_loop(struct sock *sk, u_char loop) static void set_mcast_loop(struct sock *sk, u_char loop)
{ {
/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */ /* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
lock_sock(sk);
inet_assign_bit(MC_LOOP, sk, loop); inet_assign_bit(MC_LOOP, sk, loop);
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (sk->sk_family == AF_INET6) { if (READ_ONCE(sk->sk_family) == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
/* IPV6_MULTICAST_LOOP */ /* IPV6_MULTICAST_LOOP */
np->mc_loop = loop ? 1 : 0; inet6_assign_bit(MC6_LOOP, sk, loop);
} }
#endif #endif
release_sock(sk);
} }
/* /*
...@@ -1326,7 +1322,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl) ...@@ -1326,7 +1322,7 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl)
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
/* IPV6_MULTICAST_HOPS */ /* IPV6_MULTICAST_HOPS */
np->mcast_hops = ttl; WRITE_ONCE(np->mcast_hops, ttl);
} }
#endif #endif
release_sock(sk); release_sock(sk);
...@@ -1345,7 +1341,7 @@ static void set_mcast_pmtudisc(struct sock *sk, int val) ...@@ -1345,7 +1341,7 @@ static void set_mcast_pmtudisc(struct sock *sk, int val)
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
/* IPV6_MTU_DISCOVER */ /* IPV6_MTU_DISCOVER */
np->pmtudisc = val; WRITE_ONCE(np->pmtudisc, val);
} }
#endif #endif
release_sock(sk); release_sock(sk);
......
...@@ -128,7 +128,6 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb, ...@@ -128,7 +128,6 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
{ {
struct sctp_association *asoc = t->asoc; struct sctp_association *asoc = t->asoc;
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct ipv6_pinfo *np;
int err = 0; int err = 0;
switch (type) { switch (type) {
...@@ -149,9 +148,8 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb, ...@@ -149,9 +148,8 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
break; break;
} }
np = inet6_sk(sk);
icmpv6_err_convert(type, code, &err); icmpv6_err_convert(type, code, &err);
if (!sock_owned_by_user(sk) && np->recverr) { if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) {
sk->sk_err = err; sk->sk_err = err;
sk_error_report(sk); sk_error_report(sk);
} else { } else {
...@@ -298,7 +296,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, ...@@ -298,7 +296,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK) if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK)
fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK); fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK);
if (np->sndflow && (fl6->flowlabel & IPV6_FLOWLABEL_MASK)) { if (inet6_test_bit(SNDFLOW, sk) &&
(fl6->flowlabel & IPV6_FLOWLABEL_MASK)) {
struct ip6_flowlabel *flowlabel; struct ip6_flowlabel *flowlabel;
flowlabel = fl6_sock_lookup(sk, fl6->flowlabel); flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment