diff options
author | Patrick McHardy <kaber@trash.net> | 2005-03-31 05:20:06 -0800 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-03-31 05:20:06 -0800 |
commit | 384b4336e40d686e7a617adc1af032f2915f9733 (patch) | |
tree | 4151be53d2e415d11d67b24819dc444afa189e6e | |
parent | 0038bccf6b28af630e05c75cc1ef516ecd7e92f9 (diff) | |
download | history-384b4336e40d686e7a617adc1af032f2915f9733.tar.gz |
[IPSEC]: Check if SPI exists before creating acquire state.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/xfrm/xfrm_state.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index d96218fc01c06f..1db59f11f37d68 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -304,10 +304,17 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family) { unsigned h = xfrm_dst_hash(daddr, family); - struct xfrm_state *x; + struct xfrm_state *x, *x0; int acquire_in_progress = 0; int error = 0; struct xfrm_state *best = NULL; + struct xfrm_state_afinfo *afinfo; + + afinfo = xfrm_state_get_afinfo(family); + if (afinfo == NULL) { + *err = -EAFNOSUPPORT; + return NULL; + } spin_lock_bh(&xfrm_state_lock); list_for_each_entry(x, xfrm_state_bydst+h, bydst) { @@ -343,14 +350,24 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, } else if (x->km.state == XFRM_STATE_ERROR || x->km.state == XFRM_STATE_EXPIRED) { if (xfrm_selector_match(&x->sel, fl, family)) - error = 1; + error = -ESRCH; } } } x = best; - if (!x && !error && !acquire_in_progress && - ((x = xfrm_state_alloc()) != NULL)) { + if (!x && !error && !acquire_in_progress) { + x0 = afinfo->state_lookup(&tmpl->id.daddr, tmpl->id.spi, tmpl->id.proto); + if (x0 != NULL) { + xfrm_state_put(x0); + error = -EEXIST; + goto out; + } + x = xfrm_state_alloc(); + if (x == NULL) { + error = -ENOMEM; + goto out; + } /* Initialize temporary selector matching only * to current session. */ xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); @@ -372,15 +389,16 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, x->km.state = XFRM_STATE_DEAD; xfrm_state_put(x); x = NULL; - error = 1; + error = -ESRCH; } } +out: if (x) xfrm_state_hold(x); else - *err = acquire_in_progress ? -EAGAIN : - (error ? -ESRCH : -ENOMEM); + *err = acquire_in_progress ? -EAGAIN : error; spin_unlock_bh(&xfrm_state_lock); + xfrm_state_put_afinfo(afinfo); return x; } |