diff options
-rw-r--r-- | include/net/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 20 | ||||
-rw-r--r-- | net/ipv6/route.c | 12 |
3 files changed, 24 insertions, 9 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index d0aeb97..fd02e90 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -959,6 +959,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr, int addr_len); +int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr); int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 669585e..59e01f27 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -64,7 +64,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6, struct sock *sk) security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); } -static int ip6_datagram_dst_update(struct sock *sk) +int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr) { struct ip6_flowlabel *flowlabel = NULL; struct in6_addr *final_p, final; @@ -93,14 +93,16 @@ static int ip6_datagram_dst_update(struct sock *sk) goto out; } - if (ipv6_addr_any(&np->saddr)) - np->saddr = fl6.saddr; + if (fix_sk_saddr) { + if (ipv6_addr_any(&np->saddr)) + np->saddr = fl6.saddr; - if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - sk->sk_v6_rcv_saddr = fl6.saddr; - inet->inet_rcv_saddr = LOOPBACK4_IPV6; - if (sk->sk_prot->rehash) - sk->sk_prot->rehash(sk); + if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { + sk->sk_v6_rcv_saddr = fl6.saddr; + inet->inet_rcv_saddr = LOOPBACK4_IPV6; + if (sk->sk_prot->rehash) + sk->sk_prot->rehash(sk); + } } ip6_dst_store(sk, dst, @@ -221,7 +223,7 @@ ipv4_connected: * destination cache for it. */ - err = ip6_datagram_dst_update(sk); + err = ip6_datagram_dst_update(sk, true); if (err) goto out; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1d8871a..d916d6a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1418,8 +1418,20 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu); void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) { + struct dst_entry *dst; + ip6_update_pmtu(skb, sock_net(sk), mtu, sk->sk_bound_dev_if, sk->sk_mark); + + dst = __sk_dst_get(sk); + if (!dst || !dst->obsolete || + dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) + return; + + bh_lock_sock(sk); + if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) + ip6_datagram_dst_update(sk, false); + bh_unlock_sock(sk); } EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu); |