aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2005-03-31 05:20:06 -0800
committerDavid S. Miller <davem@sunset.davemloft.net>2005-03-31 05:20:06 -0800
commit384b4336e40d686e7a617adc1af032f2915f9733 (patch)
tree4151be53d2e415d11d67b24819dc444afa189e6e
parent0038bccf6b28af630e05c75cc1ef516ecd7e92f9 (diff)
downloadhistory-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.c32
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;
}