]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/xfrm/xfrm_state.c
xfrm: clone missing x->lastused in xfrm_do_migrate
[mirror_ubuntu-jammy-kernel.git] / net / xfrm / xfrm_state.c
index a2f4001221d160266a71423a89ccf965630e8dcf..15132b080614cd19a2a1f2a18a23e914b18cb845 100644 (file)
@@ -1578,9 +1578,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        memcpy(&x->mark, &orig->mark, sizeof(x->mark));
        memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
 
-       if (xfrm_init_state(x) < 0)
-               goto error;
-
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
@@ -1593,6 +1590,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        x->km.seq = orig->km.seq;
        x->replay = orig->replay;
        x->preplay = orig->preplay;
+       x->mapping_maxage = orig->mapping_maxage;
+       x->lastused = orig->lastused;
+       x->new_mapping = 0;
+       x->new_mapping_sport = 0;
 
        return x;
 
@@ -1602,7 +1603,8 @@ out:
        return NULL;
 }
 
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
+                                               u32 if_id)
 {
        unsigned int h;
        struct xfrm_state *x = NULL;
@@ -1618,6 +1620,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                continue;
                        if (m->reqid && x->props.reqid != m->reqid)
                                continue;
+                       if (if_id != 0 && x->if_id != if_id)
+                               continue;
                        if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
                                             m->old_family) ||
                            !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
@@ -1633,6 +1637,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                        if (x->props.mode != m->mode ||
                            x->id.proto != m->proto)
                                continue;
+                       if (if_id != 0 && x->if_id != if_id)
+                               continue;
                        if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
                                             m->old_family) ||
                            !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
@@ -1659,6 +1665,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
        if (!xc)
                return NULL;
 
+       xc->props.family = m->new_family;
+
+       if (xfrm_init_state(xc) < 0)
+               goto error;
+
        memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
        memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
 
@@ -2242,7 +2253,7 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
 }
 EXPORT_SYMBOL(km_query);
 
-int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
+static int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
 {
        int err = -EINVAL;
        struct xfrm_mgr *km;
@@ -2257,6 +2268,24 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
        rcu_read_unlock();
        return err;
 }
+
+int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
+{
+       int ret = 0;
+
+       if (x->mapping_maxage) {
+               if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage ||
+                   x->new_mapping_sport != sport) {
+                       x->new_mapping_sport = sport;
+                       x->new_mapping = jiffies / HZ;
+                       ret = __km_new_mapping(x, ipaddr, sport);
+               }
+       } else {
+               ret = __km_new_mapping(x, ipaddr, sport);
+       }
+
+       return ret;
+}
 EXPORT_SYMBOL(km_new_mapping);
 
 void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
@@ -2550,7 +2579,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x)
 }
 EXPORT_SYMBOL(xfrm_state_delete_tunnel);
 
-u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu)
+u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
 {
        const struct xfrm_type *type = READ_ONCE(x->type);
        struct crypto_aead *aead;
@@ -2581,17 +2610,7 @@ u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu)
        return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
                 net_adj) & ~(blksize - 1)) + net_adj - 2;
 }
-EXPORT_SYMBOL_GPL(__xfrm_state_mtu);
-
-u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
-{
-       mtu = __xfrm_state_mtu(x, mtu);
-
-       if (x->props.family == AF_INET6 && mtu < IPV6_MIN_MTU)
-               return IPV6_MIN_MTU;
-
-       return mtu;
-}
+EXPORT_SYMBOL_GPL(xfrm_state_mtu);
 
 int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
 {
@@ -2601,7 +2620,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
        int err;
 
        if (family == AF_INET &&
-           xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)
+           READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc))
                x->props.flags |= XFRM_STATE_NOPMTUDISC;
 
        err = -EPROTONOSUPPORT;