On Sun, Jun 29, 2003 at 01:55:18PM +1000, herbert wrote: > > This patch fixes a number of problems with xfrm_state_replace: > > 1. Only update update lifetime and encap options if the state is valid. > 2. Disallow updates to states that do not exist. > 3. Bail if afinfo cannot be found. > > This brings SADB_UPDATE in line with what is required by RFC2367. > It is also needed by SFS NAT-T support as it needs to update valid > states when the encap ports move. Oops, I forgot the patch. -- Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ ) Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/net/xfrm/xfrm_state.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_state.c,v retrieving revision 1.2 diff -u -r1.2 xfrm_state.c --- kernel-source-2.5/net/xfrm/xfrm_state.c 28 Jun 2003 00:28:01 -0000 1.2 +++ kernel-source-2.5/net/xfrm/xfrm_state.c 29 Jun 2003 03:39:38 -0000 @@ -402,42 +402,64 @@ int err; afinfo = xfrm_state_get_afinfo(x->props.family); - x1 = NULL; + if (unlikely(afinfo == NULL)) + return -EAFNOSUPPORT; spin_lock_bh(&xfrm_state_lock); - if (afinfo) { - x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); - 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 && (excl ? x1->id.spi : xfrm_state_kern(x1))) { + x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); + 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; - err = -EEXIST; - goto out; } } - __xfrm_state_insert(x); - err = 0; + if (x1 && (excl ? x1->id.spi : xfrm_state_kern(x1))) { + xfrm_state_put(x1); + x = NULL; + x1 = NULL; + err = -EEXIST; + } else if (excl || (x1 && x1->km.state == XFRM_STATE_ACQ)) { + __xfrm_state_insert(x); + x = NULL; + err = 0; + } -out: spin_unlock_bh(&xfrm_state_lock); + xfrm_state_put_afinfo(afinfo); + + err = -ESRCH; + if (!x) { + if (x1) { + xfrm_state_delete(x1); + xfrm_state_put(x1); + } + err = 0; + } else if (x1) { + err = -EINVAL; + spin_lock_bh(&x1->lock); + + if (likely(x1->km.state == XFRM_STATE_VALID)) { + memcpy(x1->encap, x->encap, sizeof(*x1->encap)); + memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); + x1->km.dying = 0; + err = 0; + } + + spin_unlock_bh(&x1->lock); + + if (!mod_timer(&x1->timer, jiffies + HZ)) + xfrm_state_hold(x1); + if (x1->curlft.use_time) + xfrm_state_check_expire(x1); - if (x1) { - xfrm_state_delete(x1); xfrm_state_put(x1); } - xfrm_state_put_afinfo(afinfo); return err; }