}
 }
 
+typedef struct sk_buff *(*udp_gro_receive_t)(struct sock *sk,
+                                            struct list_head *head,
+                                            struct sk_buff *skb);
+
 static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
                                       struct sock *sk)
 {
 #ifdef CONFIG_XFRM
+       udp_gro_receive_t new_gro_receive;
+
        if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
-               if (family == AF_INET)
-                       WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
-               else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
-                       WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
+               if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
+                       new_gro_receive = ipv6_stub->xfrm6_gro_udp_encap_rcv;
+               else
+                       new_gro_receive = xfrm4_gro_udp_encap_rcv;
+
+               if (udp_sk(sk)->gro_receive != new_gro_receive) {
+                       /*
+                        * With IPV6_ADDRFORM the gro callback could change
+                        * after being set, unregister the old one, if valid.
+                        */
+                       if (udp_sk(sk)->gro_receive)
+                               udp_tunnel_update_gro_rcv(sk, false);
+
+                       WRITE_ONCE(udp_sk(sk)->gro_receive, new_gro_receive);
+                       udp_tunnel_update_gro_rcv(sk, true);
+               }
        }
 #endif
 }
                break;
 
        case UDP_ENCAP:
+               sockopt_lock_sock(sk);
                switch (val) {
                case 0:
 #ifdef CONFIG_XFRM
                        err = -ENOPROTOOPT;
                        break;
                }
+               sockopt_release_sock(sk);
                break;
 
        case UDP_NO_CHECK6_TX:
                break;
 
        case UDP_GRO:
-
+               sockopt_lock_sock(sk);
                /* when enabling GRO, accept the related GSO packet type */
                if (valbool)
                        udp_tunnel_encap_enable(sk);
                udp_assign_bit(GRO_ENABLED, sk, valbool);
                udp_assign_bit(ACCEPT_L4, sk, valbool);
                set_xfrm_gro_udp_encap_rcv(up->encap_type, sk->sk_family, sk);
+               sockopt_release_sock(sk);
                break;
 
        /*