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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e73d5fb75d
@ -213,28 +213,9 @@ struct ipv6_pinfo {
|
||||
__be32 flow_label;
|
||||
__u32 frag_size;
|
||||
|
||||
/*
|
||||
* Packed in 16bits.
|
||||
* 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
|
||||
s16 hop_limit;
|
||||
u8 mcast_hops;
|
||||
|
||||
#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 mcast_oif;
|
||||
|
||||
@ -262,21 +243,11 @@ struct ipv6_pinfo {
|
||||
} rxopt;
|
||||
|
||||
/* sockopt flags */
|
||||
__u16 recverr:1,
|
||||
sndflow:1,
|
||||
repflow:1,
|
||||
pmtudisc:3,
|
||||
padding:1, /* 1 bit hole */
|
||||
srcprefs:3, /* 001: prefer temporary address
|
||||
__u8 srcprefs:3; /* 001: prefer temporary address
|
||||
* 010: prefer public address
|
||||
* 100: prefer care-of address
|
||||
*/
|
||||
dontfrag:1,
|
||||
autoflowlabel:1,
|
||||
autoflowlabel_set:1,
|
||||
mc_all:1,
|
||||
recverr_rfc4884:1,
|
||||
rtalert_isolate:1;
|
||||
__u8 pmtudisc;
|
||||
__u8 min_hopcount;
|
||||
__u8 tclass;
|
||||
__be32 rcv_flowinfo;
|
||||
@ -293,6 +264,18 @@ struct ipv6_pinfo {
|
||||
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! */
|
||||
struct raw6_sock {
|
||||
/* inet_sock has to be the first member of raw6_sock */
|
||||
|
@ -268,6 +268,16 @@ enum {
|
||||
INET_FLAGS_NODEFRAG = 17,
|
||||
INET_FLAGS_BIND_ADDRESS_NO_PORT = 18,
|
||||
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 */
|
||||
|
@ -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);
|
||||
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 -= lwtunnel_headroom(dst->lwtstate, mtu);
|
||||
} else {
|
||||
@ -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)
|
||||
{
|
||||
return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE &&
|
||||
inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT;
|
||||
u8 pmtudisc = READ_ONCE(inet6_sk(sk)->pmtudisc);
|
||||
|
||||
return pmtudisc != IPV6_PMTUDISC_INTERFACE &&
|
||||
pmtudisc != IPV6_PMTUDISC_OMIT;
|
||||
}
|
||||
|
||||
static inline bool ip6_sk_ignore_df(const struct sock *sk)
|
||||
{
|
||||
return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO ||
|
||||
inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
|
||||
u8 pmtudisc = READ_ONCE(inet6_sk(sk)->pmtudisc);
|
||||
|
||||
return pmtudisc < IPV6_PMTUDISC_DO ||
|
||||
pmtudisc == IPV6_PMTUDISC_OMIT;
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
static inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6,
|
||||
const struct ipv6_pinfo *np)
|
||||
const struct sock *sk)
|
||||
{
|
||||
*ipc6 = (struct ipcm6_cookie) {
|
||||
.hlimit = -1,
|
||||
.tclass = np->tclass,
|
||||
.dontfrag = np->dontfrag,
|
||||
.tclass = inet6_sk(sk)->tclass,
|
||||
.dontfrag = inet6_test_bit(DONTFRAG, sk),
|
||||
};
|
||||
}
|
||||
|
||||
@ -428,7 +428,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
|
||||
int flags);
|
||||
int ip6_flowlabel_init(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)
|
||||
{
|
||||
@ -914,9 +914,9 @@ 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 = np->hop_limit;
|
||||
hlimit = READ_ONCE(np->hop_limit);
|
||||
if (hlimit < 0)
|
||||
hlimit = ip6_dst_hoplimit(dst);
|
||||
return hlimit;
|
||||
@ -1303,9 +1303,7 @@ static inline int ip6_sock_set_v6only(struct sock *sk)
|
||||
|
||||
static inline void ip6_sock_set_recverr(struct sock *sk)
|
||||
{
|
||||
lock_sock(sk);
|
||||
inet6_sk(sk)->recverr = true;
|
||||
release_sock(sk);
|
||||
inet6_set_bit(RECVERR6, sk);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -2166,7 +2166,7 @@ static inline bool xfrm6_local_dontfrag(const struct sock *sk)
|
||||
|
||||
proto = sk->sk_protocol;
|
||||
if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
|
||||
return inet6_sk(sk)->dontfrag;
|
||||
return inet6_test_bit(DONTFRAG, sk);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -759,7 +759,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool sk_mc_loop(struct sock *sk)
|
||||
bool sk_mc_loop(const struct sock *sk)
|
||||
{
|
||||
if (dev_recursion_level())
|
||||
return false;
|
||||
@ -771,7 +771,7 @@ bool sk_mc_loop(struct sock *sk)
|
||||
return inet_test_bit(MC_LOOP, sk);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
return inet6_sk(sk)->mc_loop;
|
||||
return inet6_test_bit(MC6_LOOP, sk);
|
||||
#endif
|
||||
}
|
||||
WARN_ON_ONCE(1);
|
||||
|
@ -185,7 +185,7 @@ static int dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
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_error_report(sk);
|
||||
} else {
|
||||
@ -676,10 +676,10 @@ 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)
|
||||
if (inet6_test_bit(REPFLOW, sk))
|
||||
np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
|
||||
if (ipv6_opt_accepted(sk, opt_skb,
|
||||
&DCCP_SKB_CB(opt_skb)->header.h6)) {
|
||||
@ -844,7 +844,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
|
||||
if (np->sndflow) {
|
||||
if (inet6_test_bit(SNDFLOW, sk)) {
|
||||
fl6.flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
||||
IP6_ECN_flow_init(fl6.flowlabel);
|
||||
if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
|
||||
|
@ -581,7 +581,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
|
||||
* 4.1.3.3.
|
||||
*/
|
||||
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)
|
||||
goto out;
|
||||
} else {
|
||||
@ -899,7 +899,6 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else if (family == AF_INET6) {
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct ipv6hdr *ip6 = ipv6_hdr(skb);
|
||||
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,
|
||||
sin6->sin6_port = 0;
|
||||
sin6->sin6_addr = ip6->saddr;
|
||||
sin6->sin6_flowinfo = 0;
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
sin6->sin6_flowinfo = ip6_flowinfo(ip6);
|
||||
sin6->sin6_scope_id =
|
||||
ipv6_iface_scope_id(&sin6->sin6_addr,
|
||||
|
@ -217,10 +217,11 @@ lookup_protocol:
|
||||
inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk);
|
||||
np->hop_limit = -1;
|
||||
np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
|
||||
np->mc_loop = 1;
|
||||
np->mc_all = 1;
|
||||
inet6_set_bit(MC6_LOOP, sk);
|
||||
inet6_set_bit(MC6_ALL, sk);
|
||||
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_txrehash = READ_ONCE(net->core.sysctl_txrehash);
|
||||
|
||||
@ -536,7 +537,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
|
||||
}
|
||||
sin->sin6_port = inet->inet_dport;
|
||||
sin->sin6_addr = sk->sk_v6_daddr;
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
sin->sin6_flowinfo = np->flow_label;
|
||||
BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin,
|
||||
CGROUP_INET6_GETPEERNAME);
|
||||
|
@ -80,7 +80,8 @@ int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr)
|
||||
struct flowi6 fl6;
|
||||
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);
|
||||
if (IS_ERR(flowlabel))
|
||||
return -EINVAL;
|
||||
@ -163,7 +164,7 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
if (usin->sin6_family != AF_INET6)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
||||
|
||||
if (ipv6_addr_any(&usin->sin6_addr)) {
|
||||
@ -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,
|
||||
__be16 port, u32 info, u8 *payload)
|
||||
{
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct icmp6hdr *icmph = icmp6_hdr(skb);
|
||||
struct sock_exterr_skb *serr;
|
||||
|
||||
if (!np->recverr)
|
||||
if (!inet6_test_bit(RECVERR6, sk))
|
||||
return;
|
||||
|
||||
skb = skb_clone(skb, GFP_ATOMIC);
|
||||
@ -332,7 +332,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
|
||||
|
||||
__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);
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
@ -344,12 +344,11 @@ EXPORT_SYMBOL_GPL(ipv6_icmp_error);
|
||||
|
||||
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 ipv6hdr *iph;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!np->recverr)
|
||||
if (!inet6_test_bit(RECVERR6, sk))
|
||||
return;
|
||||
|
||||
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)
|
||||
const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
|
||||
struct ipv6hdr, daddr);
|
||||
sin->sin6_addr = ip6h->daddr;
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
sin->sin6_flowinfo = ip6_flowinfo(ip6h);
|
||||
sin->sin6_scope_id =
|
||||
ipv6_iface_scope_id(&sin->sin6_addr,
|
||||
|
@ -588,7 +588,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
|
||||
ipcm6_init_sk(&ipc6, np);
|
||||
ipcm6_init_sk(&ipc6, sk);
|
||||
ipc6.sockc.mark = mark;
|
||||
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)
|
||||
msg.offset = 0;
|
||||
msg.type = type;
|
||||
|
||||
ipcm6_init_sk(&ipc6, np);
|
||||
ipcm6_init_sk(&ipc6, sk);
|
||||
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
|
||||
ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
|
||||
ipc6.sockc.mark = mark;
|
||||
|
@ -513,7 +513,7 @@ int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (np->repflow) {
|
||||
if (inet6_test_bit(REPFLOW, sk)) {
|
||||
freq->flr_label = np->flow_label;
|
||||
return 0;
|
||||
}
|
||||
@ -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 (sk->sk_protocol != IPPROTO_TCP)
|
||||
return -ENOPROTOOPT;
|
||||
if (!np->repflow)
|
||||
if (!inet6_test_bit(REPFLOW, sk))
|
||||
return -ESRCH;
|
||||
np->flow_label = 0;
|
||||
np->repflow = 0;
|
||||
inet6_clear_bit(REPFLOW, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -626,7 +626,7 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
|
||||
|
||||
if (sk->sk_protocol != IPPROTO_TCP)
|
||||
return -ENOPROTOOPT;
|
||||
np->repflow = 1;
|
||||
inet6_set_bit(REPFLOW, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -232,12 +232,11 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
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);
|
||||
else
|
||||
return np->autoflowlabel;
|
||||
return inet6_test_bit(AUTOFLOWLABEL, sk);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -309,12 +308,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
|
||||
* Fill in the IPv6 header
|
||||
*/
|
||||
if (np)
|
||||
hlimit = np->hop_limit;
|
||||
hlimit = READ_ONCE(np->hop_limit);
|
||||
if (hlimit < 0)
|
||||
hlimit = ip6_dst_hoplimit(dst);
|
||||
|
||||
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->nexthdr = proto;
|
||||
@ -369,9 +368,8 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
|
||||
if (sk && ra->sel == sel &&
|
||||
(!sk->sk_bound_dev_if ||
|
||||
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))) {
|
||||
continue;
|
||||
}
|
||||
@ -881,9 +879,11 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
mtu = IPV6_MIN_MTU;
|
||||
}
|
||||
|
||||
if (np && np->frag_size < mtu) {
|
||||
if (np->frag_size)
|
||||
mtu = np->frag_size;
|
||||
if (np) {
|
||||
u32 frag_size = READ_ONCE(np->frag_size);
|
||||
|
||||
if (frag_size && frag_size < mtu)
|
||||
mtu = frag_size;
|
||||
}
|
||||
if (mtu < hlen + sizeof(struct frag_hdr) + 8)
|
||||
goto fail_toobig;
|
||||
@ -1392,7 +1392,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
|
||||
struct rt6_info *rt)
|
||||
{
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
unsigned int mtu;
|
||||
unsigned int mtu, frag_size;
|
||||
struct ipv6_txoptions *nopt, *opt = ipc6->opt;
|
||||
|
||||
/* 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,
|
||||
v6_cork->hop_limit = ipc6->hlimit;
|
||||
v6_cork->tclass = ipc6->tclass;
|
||||
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);
|
||||
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));
|
||||
if (np->frag_size < mtu) {
|
||||
if (np->frag_size)
|
||||
mtu = np->frag_size;
|
||||
}
|
||||
|
||||
frag_size = READ_ONCE(np->frag_size);
|
||||
if (frag_size && frag_size < mtu)
|
||||
mtu = frag_size;
|
||||
|
||||
cork->base.fragsize = mtu;
|
||||
cork->base.gso_size = ipc6->gso_size;
|
||||
cork->base.tx_flags = 0;
|
||||
@ -1935,7 +1936,6 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
|
||||
struct sk_buff *skb, *tmp_skb;
|
||||
struct sk_buff **tail_skb;
|
||||
struct in6_addr *final_dst;
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct net *net = sock_net(sk);
|
||||
struct ipv6hdr *hdr;
|
||||
struct ipv6_txoptions *opt = v6_cork->opt;
|
||||
@ -1978,7 +1978,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
|
||||
|
||||
ip6_flow_hdr(hdr, v6_cork->tclass,
|
||||
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->nexthdr = proto;
|
||||
hdr->saddr = fl6->saddr;
|
||||
@ -2091,7 +2091,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
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,
|
||||
¤t->task_frag, getfrag, from,
|
||||
|
@ -415,6 +415,97 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||
if (ip6_mroute_opt(optname))
|
||||
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)
|
||||
rtnl_lock();
|
||||
sockopt_lock_sock(sk);
|
||||
@ -733,34 +824,7 @@ done:
|
||||
}
|
||||
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:
|
||||
{
|
||||
@ -862,13 +926,6 @@ done:
|
||||
retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
||||
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_LEAVE_GROUP:
|
||||
if (in_compat_syscall())
|
||||
@ -896,42 +953,6 @@ done:
|
||||
goto e_inval;
|
||||
retv = ip6_ra_control(sk, val);
|
||||
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:
|
||||
retv = ipv6_flowlabel_opt(sk, optval, optlen);
|
||||
break;
|
||||
@ -948,42 +969,10 @@ done:
|
||||
goto e_inval;
|
||||
retv = __ip6_sock_set_addr_preferences(sk, val);
|
||||
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:
|
||||
np->rxopt.bits.recvfragsize = valbool;
|
||||
retv = 0;
|
||||
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:
|
||||
@ -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);
|
||||
}
|
||||
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 +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);
|
||||
}
|
||||
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) {
|
||||
@ -1347,9 +1338,9 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
struct dst_entry *dst;
|
||||
|
||||
if (optname == IPV6_UNICAST_HOPS)
|
||||
val = np->hop_limit;
|
||||
val = READ_ONCE(np->hop_limit);
|
||||
else
|
||||
val = np->mcast_hops;
|
||||
val = READ_ONCE(np->mcast_hops);
|
||||
|
||||
if (val < 0) {
|
||||
rcu_read_lock();
|
||||
@ -1365,7 +1356,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
}
|
||||
|
||||
case IPV6_MULTICAST_LOOP:
|
||||
val = np->mc_loop;
|
||||
val = inet6_test_bit(MC6_LOOP, sk);
|
||||
break;
|
||||
|
||||
case IPV6_MULTICAST_IF:
|
||||
@ -1373,7 +1364,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case IPV6_MULTICAST_ALL:
|
||||
val = np->mc_all;
|
||||
val = inet6_test_bit(MC6_ALL, sk);
|
||||
break;
|
||||
|
||||
case IPV6_UNICAST_IF:
|
||||
@ -1381,15 +1372,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case IPV6_MTU_DISCOVER:
|
||||
val = np->pmtudisc;
|
||||
val = READ_ONCE(np->pmtudisc);
|
||||
break;
|
||||
|
||||
case IPV6_RECVERR:
|
||||
val = np->recverr;
|
||||
val = inet6_test_bit(RECVERR6, sk);
|
||||
break;
|
||||
|
||||
case IPV6_FLOWINFO_SEND:
|
||||
val = np->sndflow;
|
||||
val = inet6_test_bit(SNDFLOW, sk);
|
||||
break;
|
||||
|
||||
case IPV6_FLOWLABEL_MGR:
|
||||
@ -1442,15 +1433,15 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case IPV6_MINHOPCOUNT:
|
||||
val = np->min_hopcount;
|
||||
val = READ_ONCE(np->min_hopcount);
|
||||
break;
|
||||
|
||||
case IPV6_DONTFRAG:
|
||||
val = np->dontfrag;
|
||||
val = inet6_test_bit(DONTFRAG, sk);
|
||||
break;
|
||||
|
||||
case IPV6_AUTOFLOWLABEL:
|
||||
val = ip6_autoflowlabel(sock_net(sk), np);
|
||||
val = ip6_autoflowlabel(sock_net(sk), sk);
|
||||
break;
|
||||
|
||||
case IPV6_RECVFRAGSIZE:
|
||||
@ -1458,11 +1449,11 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case IPV6_ROUTER_ALERT_ISOLATE:
|
||||
val = np->rtalert_isolate;
|
||||
val = inet6_test_bit(RTALERT_ISOLATE, sk);
|
||||
break;
|
||||
|
||||
case IPV6_RECVERR_RFC4884:
|
||||
val = np->recverr_rfc4884;
|
||||
val = inet6_test_bit(RECVERR6_RFC4884, sk);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -642,7 +642,7 @@ bool inet6_mc_check(const struct sock *sk, const struct in6_addr *mc_addr,
|
||||
}
|
||||
if (!mc) {
|
||||
rcu_read_unlock();
|
||||
return np->mc_all;
|
||||
return inet6_test_bit(MC6_ALL, sk);
|
||||
}
|
||||
psl = rcu_dereference(mc->sflist);
|
||||
if (!psl) {
|
||||
@ -1716,7 +1716,7 @@ static void ip6_mc_hdr(const struct sock *sk, struct sk_buff *skb,
|
||||
|
||||
hdr->payload_len = htons(len);
|
||||
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->daddr = *daddr;
|
||||
|
@ -500,7 +500,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
|
||||
csum_partial(icmp6h,
|
||||
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();
|
||||
idev = __in6_dev_get(dst->dev);
|
||||
@ -1996,7 +1996,7 @@ static int __net_init ndisc_net_init(struct net *net)
|
||||
np = inet6_sk(sk);
|
||||
np->hop_limit = 255;
|
||||
/* Do not loopback ndisc messages */
|
||||
np->mc_loop = 0;
|
||||
inet6_clear_bit(MC6_LOOP, sk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
daddr = &(u->sin6_addr);
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
fl6.flowlabel = u->sin6_flowinfo & IPV6_FLOWINFO_MASK;
|
||||
if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr)))
|
||||
oif = u->sin6_scope_id;
|
||||
@ -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))
|
||||
return -EINVAL;
|
||||
|
||||
ipcm6_init_sk(&ipc6, np);
|
||||
ipcm6_init_sk(&ipc6, sk);
|
||||
ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
|
||||
ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
|
||||
|
||||
|
@ -291,6 +291,7 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
|
||||
struct inet6_skb_parm *opt,
|
||||
u8 type, u8 code, int offset, __be32 info)
|
||||
{
|
||||
bool recverr = inet6_test_bit(RECVERR6, sk);
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
int err;
|
||||
int harderr;
|
||||
@ -300,26 +301,26 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
|
||||
2. Socket is connected (otherwise the error indication
|
||||
is useless without recverr and error is hard.
|
||||
*/
|
||||
if (!np->recverr && sk->sk_state != TCP_ESTABLISHED)
|
||||
if (!recverr && sk->sk_state != TCP_ESTABLISHED)
|
||||
return;
|
||||
|
||||
harderr = icmpv6_err_convert(type, code, &err);
|
||||
if (type == ICMPV6_PKT_TOOBIG) {
|
||||
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) {
|
||||
ip6_sk_redirect(skb, sk);
|
||||
return;
|
||||
}
|
||||
if (np->recverr) {
|
||||
if (recverr) {
|
||||
u8 *payload = skb->data;
|
||||
if (!inet_test_bit(HDRINCL, sk))
|
||||
payload += offset;
|
||||
ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
|
||||
}
|
||||
|
||||
if (np->recverr || harderr) {
|
||||
if (recverr || harderr) {
|
||||
sk->sk_err = err;
|
||||
sk_error_report(sk);
|
||||
}
|
||||
@ -587,7 +588,6 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
|
||||
struct flowi6 *fl6, struct dst_entry **dstp,
|
||||
unsigned int flags, const struct sockcm_cookie *sockc)
|
||||
{
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct net *net = sock_net(sk);
|
||||
struct ipv6hdr *iph;
|
||||
struct sk_buff *skb;
|
||||
@ -668,7 +668,7 @@ out:
|
||||
error:
|
||||
IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
|
||||
error_check:
|
||||
if (err == -ENOBUFS && !np->recverr)
|
||||
if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk))
|
||||
err = 0;
|
||||
return err;
|
||||
}
|
||||
@ -795,7 +795,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
return -EINVAL;
|
||||
|
||||
daddr = &sin6->sin6_addr;
|
||||
if (np->sndflow) {
|
||||
if (inet6_test_bit(SNDFLOW, sk)) {
|
||||
fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
|
||||
if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
|
||||
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
|
||||
@ -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);
|
||||
|
||||
if (ipc6.dontfrag < 0)
|
||||
ipc6.dontfrag = np->dontfrag;
|
||||
ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
|
||||
|
||||
if (msg->msg_flags&MSG_CONFIRM)
|
||||
goto do_confirm;
|
||||
|
@ -163,7 +163,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
|
||||
if (np->sndflow) {
|
||||
if (inet6_test_bit(SNDFLOW, sk)) {
|
||||
fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
|
||||
IP6_ECN_flow_init(fl6.flowlabel);
|
||||
if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
|
||||
@ -508,7 +508,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
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);
|
||||
sk_error_report(sk);
|
||||
} else {
|
||||
@ -548,7 +548,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
|
||||
&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));
|
||||
|
||||
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,
|
||||
(ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) ||
|
||||
np->rxopt.bits.rxinfo ||
|
||||
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);
|
||||
ireq->pktopts = skb;
|
||||
}
|
||||
@ -1055,10 +1055,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
|
||||
if (sk) {
|
||||
oif = sk->sk_bound_dev_if;
|
||||
if (sk_fullsock(sk)) {
|
||||
const struct ipv6_pinfo *np = tcp_inet6_sk(sk);
|
||||
|
||||
trace_tcp_send_reset(sk, skb);
|
||||
if (np->repflow)
|
||||
if (inet6_test_bit(REPFLOW, sk))
|
||||
label = ip6_flowlabel(ipv6h);
|
||||
priority = sk->sk_priority;
|
||||
txhash = sk->sk_txhash;
|
||||
@ -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_hops = ip_hdr(skb)->ttl;
|
||||
newnp->rcv_flowinfo = 0;
|
||||
if (np->repflow)
|
||||
if (inet6_test_bit(REPFLOW, sk))
|
||||
newnp->flow_label = 0;
|
||||
|
||||
/*
|
||||
@ -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_hops = ipv6_hdr(skb)->hop_limit;
|
||||
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));
|
||||
|
||||
/* Set ToS of the new socket based upon the value of incoming SYN.
|
||||
@ -1542,10 +1540,11 @@ 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)
|
||||
if (inet6_test_bit(REPFLOW, sk))
|
||||
np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
|
||||
if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) {
|
||||
tcp_v6_restore_cb(opt_skb);
|
||||
|
@ -598,7 +598,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
if (!ip6_sk_accept_pmtu(sk))
|
||||
goto out;
|
||||
ip6_sk_update_pmtu(skb, sk, info);
|
||||
if (np->pmtudisc != IPV6_PMTUDISC_DONT)
|
||||
if (READ_ONCE(np->pmtudisc) != IPV6_PMTUDISC_DONT)
|
||||
harderr = 1;
|
||||
}
|
||||
if (type == NDISC_REDIRECT) {
|
||||
@ -619,7 +619,7 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!np->recverr) {
|
||||
if (!inet6_test_bit(RECVERR6, sk)) {
|
||||
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
|
||||
goto out;
|
||||
} else {
|
||||
@ -1283,7 +1283,7 @@ csum_partial:
|
||||
send:
|
||||
err = ip6_send_skb(skb);
|
||||
if (err) {
|
||||
if (err == -ENOBUFS && !inet6_sk(sk)->recverr) {
|
||||
if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk)) {
|
||||
UDP6_INC_STATS(sock_net(sk),
|
||||
UDP_MIB_SNDBUFERRORS, is_udplite);
|
||||
err = 0;
|
||||
@ -1429,7 +1429,7 @@ do_udp_sendmsg:
|
||||
fl6->fl6_dport = sin6->sin6_port;
|
||||
daddr = &sin6->sin6_addr;
|
||||
|
||||
if (np->sndflow) {
|
||||
if (inet6_test_bit(SNDFLOW, sk)) {
|
||||
fl6->flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
|
||||
if (fl6->flowlabel & IPV6_FLOWLABEL_MASK) {
|
||||
flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
|
||||
@ -1595,7 +1595,7 @@ back_from_confirm:
|
||||
|
||||
do_append_data:
|
||||
if (ipc6.dontfrag < 0)
|
||||
ipc6.dontfrag = np->dontfrag;
|
||||
ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
|
||||
up->len += ulen;
|
||||
err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
|
||||
&ipc6, fl6, (struct rt6_info *)dst,
|
||||
@ -1608,7 +1608,7 @@ do_append_data:
|
||||
up->pending = 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);
|
||||
|
||||
out:
|
||||
|
@ -431,7 +431,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
|
||||
return -ENOTCONN;
|
||||
lsa->l2tp_conn_id = lsk->peer_conn_id;
|
||||
lsa->l2tp_addr = sk->sk_v6_daddr;
|
||||
if (np->sndflow)
|
||||
if (inet6_test_bit(SNDFLOW, sk))
|
||||
lsa->l2tp_flowinfo = np->flow_label;
|
||||
} else {
|
||||
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)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
daddr = &lsa->l2tp_addr;
|
||||
if (np->sndflow) {
|
||||
if (inet6_test_bit(SNDFLOW, sk)) {
|
||||
fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK;
|
||||
if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
|
||||
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)
|
||||
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
|
||||
|
||||
if (ipc6.dontfrag < 0)
|
||||
ipc6.dontfrag = np->dontfrag;
|
||||
ipc6.dontfrag = inet6_test_bit(DONTFRAG, sk);
|
||||
|
||||
if (msg->msg_flags & MSG_CONFIRM)
|
||||
goto do_confirm;
|
||||
|
@ -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)
|
||||
{
|
||||
/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
|
||||
lock_sock(sk);
|
||||
inet_assign_bit(MC_LOOP, sk, loop);
|
||||
#ifdef CONFIG_IP_VS_IPV6
|
||||
if (sk->sk_family == AF_INET6) {
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
|
||||
if (READ_ONCE(sk->sk_family) == AF_INET6) {
|
||||
/* IPV6_MULTICAST_LOOP */
|
||||
np->mc_loop = loop ? 1 : 0;
|
||||
inet6_assign_bit(MC6_LOOP, sk, loop);
|
||||
}
|
||||
#endif
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1326,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);
|
||||
@ -1345,7 +1341,7 @@ static void set_mcast_pmtudisc(struct sock *sk, int val)
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
|
||||
/* IPV6_MTU_DISCOVER */
|
||||
np->pmtudisc = val;
|
||||
WRITE_ONCE(np->pmtudisc, val);
|
||||
}
|
||||
#endif
|
||||
release_sock(sk);
|
||||
|
@ -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 sock *sk = asoc->base.sk;
|
||||
struct ipv6_pinfo *np;
|
||||
int err = 0;
|
||||
|
||||
switch (type) {
|
||||
@ -149,9 +148,8 @@ static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
|
||||
break;
|
||||
}
|
||||
|
||||
np = inet6_sk(sk);
|
||||
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_error_report(sk);
|
||||
} else {
|
||||
@ -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)
|
||||
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;
|
||||
|
||||
flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
|
||||
|
Loading…
x
Reference in New Issue
Block a user