This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / xfrm / xfrm_state.c
index f45fa55..160bb61 100644 (file)
@@ -65,6 +65,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
                xfrm_put_type(x->type);
        }
        kfree(x);
+       wake_up(&km_waitq);
 }
 
 static void xfrm_state_gc_task(void *data)
@@ -81,7 +82,6 @@ static void xfrm_state_gc_task(void *data)
                x = list_entry(entry, struct xfrm_state, bydst);
                xfrm_state_gc_destroy(x);
        }
-       wake_up(&km_waitq);
 }
 
 static inline unsigned long make_jiffies(long secs)
@@ -400,17 +400,23 @@ int xfrm_state_add(struct xfrm_state *x)
        spin_lock_bh(&xfrm_state_lock);
 
        x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
-       if (x1) {
+       if (!x1) {
+               x1 = afinfo->find_acq(
+                       x->props.mode, x->props.reqid, x->id.proto,
+                       &x->id.daddr, &x->props.saddr, 0);
+               if (x1 && x1->id.spi != x->id.spi && x1->id.spi) {
+                       xfrm_state_put(x1);
+                       x1 = NULL;
+               }
+       }
+
+       if (x1 && x1->id.spi) {
                xfrm_state_put(x1);
                x1 = NULL;
                err = -EEXIST;
                goto out;
        }
 
-       x1 = afinfo->find_acq(
-               x->props.mode, x->props.reqid, x->id.proto,
-               &x->id.daddr, &x->props.saddr, 0);
-
        __xfrm_state_insert(x);
        err = 0;
 
@@ -624,12 +630,11 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
                for (h=0; h<maxspi-minspi+1; h++) {
                        spi = minspi + net_random()%(maxspi-minspi+1);
                        x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
-                       if (x0 == NULL) {
-                               x->id.spi = htonl(spi);
+                       if (x0 == NULL)
                                break;
-                       }
                        xfrm_state_put(x0);
                }
+               x->id.spi = htonl(spi);
        }
        if (x->id.spi) {
                spin_lock_bh(&xfrm_state_lock);