Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / udp.c
index 599e1ba6d1ceaa6766d53eda020a69a0aa234e5b..da6019b63730fcf81f4af2a41bb2b30a8fcde3b1 100644 (file)
@@ -450,15 +450,16 @@ try_again:
                sin6->sin6_family = AF_INET6;
                sin6->sin6_port = udp_hdr(skb)->source;
                sin6->sin6_flowinfo = 0;
-               sin6->sin6_scope_id = 0;
 
-               if (is_udp4)
+               if (is_udp4) {
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin6->sin6_addr);
-               else {
+                       sin6->sin6_scope_id = 0;
+               } else {
                        sin6->sin6_addr = ipv6_hdr(skb)->saddr;
-                       if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-                               sin6->sin6_scope_id = IP6CB(skb)->iif;
+                       sin6->sin6_scope_id =
+                               ipv6_iface_scope_id(&sin6->sin6_addr,
+                                                   IP6CB(skb)->iif);
                }
 
        }
@@ -1118,7 +1119,7 @@ do_udp_sendmsg:
 
                if (addr_len >= sizeof(struct sockaddr_in6) &&
                    sin6->sin6_scope_id &&
-                   ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+                   __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
                        fl6.flowi6_oif = sin6->sin6_scope_id;
        } else {
                if (sk->sk_state != TCP_ESTABLISHED)
@@ -1285,10 +1286,18 @@ do_confirm:
 
 void udpv6_destroy_sock(struct sock *sk)
 {
+       struct udp_sock *up = udp_sk(sk);
        lock_sock(sk);
        udp_v6_flush_pending_frames(sk);
        release_sock(sk);
 
+       if (static_key_false(&udpv6_encap_needed) && up->encap_type) {
+               void (*encap_destroy)(struct sock *sk);
+               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               if (encap_destroy)
+                       encap_destroy(sk);
+       }
+
        inet6_destroy_sock(sk);
 }