}
 EXPORT_SYMBOL(xfrm_state_lookup_byspi);
 
+static struct xfrm_state *xfrm_state_lookup_spi_proto(struct net *net, __be32 spi, u8 proto)
+{
+       struct xfrm_state *x;
+       unsigned int i;
+
+       rcu_read_lock();
+       for (i = 0; i <= net->xfrm.state_hmask; i++) {
+               hlist_for_each_entry_rcu(x, &net->xfrm.state_byspi[i], byspi) {
+                       if (x->id.spi == spi && x->id.proto == proto) {
+                               if (!xfrm_state_hold_rcu(x))
+                                       continue;
+                               rcu_read_unlock();
+                               return x;
+                       }
+               }
+       }
+       rcu_read_unlock();
+       return NULL;
+}
+
 static void __xfrm_state_insert(struct xfrm_state *x)
 {
        struct net *net = xs_net(x);
        unsigned int h;
        struct xfrm_state *x0;
        int err = -ENOENT;
-       __be32 minspi = htonl(low);
-       __be32 maxspi = htonl(high);
+       u32 range = high - low + 1;
        __be32 newspi = 0;
-       u32 mark = x->mark.v & x->mark.m;
 
        spin_lock_bh(&x->lock);
        if (x->km.state == XFRM_STATE_DEAD) {
 
        err = -ENOENT;
 
-       if (minspi == maxspi) {
-               x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family);
-               if (x0) {
-                       NL_SET_ERR_MSG(extack, "Requested SPI is already in use");
-                       xfrm_state_put(x0);
+       for (h = 0; h < range; h++) {
+               u32 spi = (low == high) ? low : get_random_u32_inclusive(low, high);
+               newspi = htonl(spi);
+
+               spin_lock_bh(&net->xfrm.xfrm_state_lock);
+               x0 = xfrm_state_lookup_spi_proto(net, newspi, x->id.proto);
+               if (!x0) {
+                       x->id.spi = newspi;
+                       h = xfrm_spi_hash(net, &x->id.daddr, newspi, x->id.proto, x->props.family);
+                       XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h, x->xso.type);
+                       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+                       err = 0;
                        goto unlock;
                }
-               newspi = minspi;
-       } else {
-               u32 spi = 0;
-               for (h = 0; h < high-low+1; h++) {
-                       spi = get_random_u32_inclusive(low, high);
-                       x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
-                       if (x0 == NULL) {
-                               newspi = htonl(spi);
-                               break;
-                       }
-                       xfrm_state_put(x0);
+               xfrm_state_put(x0);
+               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+               if (signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       goto unlock;
                }
+
+               if (low == high)
+                       break;
        }
-       if (newspi) {
-               spin_lock_bh(&net->xfrm.xfrm_state_lock);
-               x->id.spi = newspi;
-               h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
-               XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h,
-                                 x->xso.type);
-               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
 
-               err = 0;
-       } else {
+       if (err)
                NL_SET_ERR_MSG(extack, "No SPI available in the requested range");
-       }
 
 unlock:
        spin_unlock_bh(&x->lock);