netdev_state_change(t->dev);
 }
 
-static void ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
+                          bool strict)
 {
-       /* for default tnl0 device allow to change only the proto */
+       /* For the default ip6tnl0 device, allow changing only the protocol
+        * (the IP6_TNL_F_CAP_PER_PACKET flag is set on ip6tnl0, and all other
+        * parameters are 0).
+        */
+       if (strict &&
+           (!ipv6_addr_any(&p->laddr) || !ipv6_addr_any(&p->raddr) ||
+            p->flags != t->parms.flags || p->hop_limit || p->encap_limit ||
+            p->flowinfo || p->link || p->fwmark || p->collect_md))
+               return -EINVAL;
+
        t->parms.proto = p->proto;
        netdev_state_change(t->dev);
+       return 0;
 }
 
 static void
                        } else
                                t = netdev_priv(dev);
                        if (dev == ip6n->fb_tnl_dev)
-                               ip6_tnl0_update(t, &p1);
+                               ip6_tnl0_update(t, &p1, false);
                        else
                                ip6_tnl_update(t, &p1);
                }
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
        struct ip_tunnel_encap ipencap;
 
-       if (dev == ip6n->fb_tnl_dev)
-               return -EINVAL;
+       if (dev == ip6n->fb_tnl_dev) {
+               if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
+                       /* iproute2 always sets TUNNEL_ENCAP_FLAG_CSUM6, so
+                        * let's ignore this flag.
+                        */
+                       ipencap.flags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
+                       if (memchr_inv(&ipencap, 0, sizeof(ipencap))) {
+                               NL_SET_ERR_MSG(extack,
+                                              "Only protocol can be changed for fallback tunnel, not encap params");
+                               return -EINVAL;
+                       }
+               }
+
+               ip6_tnl_netlink_parms(data, &p);
+               if (ip6_tnl0_update(t, &p, true) < 0) {
+                       NL_SET_ERR_MSG(extack,
+                                      "Only protocol can be changed for fallback tunnel");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
 
        if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
                int err = ip6_tnl_encap_setup(t, &ipencap);