X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fxfrm%2Fxfrm_state.c;h=2317ae179be965eab5d3d604cb0fc230b64c4100;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=f45fa55c2c6c57f429bed827540c7a4a07c6d593;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f45fa55c2..2317ae179 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -387,13 +387,17 @@ void xfrm_state_insert(struct xfrm_state *x) spin_unlock_bh(&xfrm_state_lock); } +static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); + int xfrm_state_add(struct xfrm_state *x) { struct xfrm_state_afinfo *afinfo; struct xfrm_state *x1; + int family; int err; - afinfo = xfrm_state_get_afinfo(x->props.family); + family = x->props.family; + afinfo = xfrm_state_get_afinfo(family); if (unlikely(afinfo == NULL)) return -EAFNOSUPPORT; @@ -407,9 +411,18 @@ int xfrm_state_add(struct xfrm_state *x) goto out; } - x1 = afinfo->find_acq( - x->props.mode, x->props.reqid, x->id.proto, - &x->id.daddr, &x->props.saddr, 0); + if (x->km.seq) { + x1 = __xfrm_find_acq_byseq(x->km.seq); + if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { + xfrm_state_put(x1); + x1 = NULL; + } + } + + if (!x1) + 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; @@ -570,24 +583,31 @@ xfrm_find_acq(u8 mode, u32 reqid, u8 proto, /* Silly enough, but I'm lazy to build resolution list */ -struct xfrm_state * xfrm_find_acq_byseq(u32 seq) +static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) { int i; struct xfrm_state *x; - spin_lock_bh(&xfrm_state_lock); for (i = 0; i < XFRM_DST_HSIZE; i++) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) { if (x->km.seq == seq) { xfrm_state_hold(x); - spin_unlock_bh(&xfrm_state_lock); return x; } } } - spin_unlock_bh(&xfrm_state_lock); return NULL; } + +struct xfrm_state *xfrm_find_acq_byseq(u32 seq) +{ + struct xfrm_state *x; + + spin_lock_bh(&xfrm_state_lock); + x = __xfrm_find_acq_byseq(seq); + spin_unlock_bh(&xfrm_state_lock); + return x; +} u32 xfrm_get_acqseq(void) {