Re: [IPSEC] xfrm_state_replace fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Jun 29, 2003 at 10:47:45PM +1000, herbert wrote:
> On Sun, Jun 29, 2003 at 10:42:54PM +1000, James Morris wrote:
> > 
> > The logic in this function is starting to look pretty tortured.
> 
> Indeed, perhaps we should split it into add and replace.

Here is the patch to do that.  I've tweaked the logic slightly so
that SADB_UPDATE will fail on a larval state that hasn't undergone
SADB_GETSPI.  This is what RFC2367 calls for and it simplifies the
code in that we don't have to call find_acq for SADB_UPDATE.

This doesn't affect any of the three KMs as they either don't use
SADB_UPDATE or call SADB_GETSPI before doing an update.

Cheers,
-- 
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/include/net/xfrm.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/xfrm.h,v
retrieving revision 1.6
diff -u -r1.6 xfrm.h
--- kernel-source-2.5/include/net/xfrm.h	28 Jun 2003 00:28:01 -0000	1.6
+++ kernel-source-2.5/include/net/xfrm.h	29 Jun 2003 12:57:53 -0000
@@ -767,7 +767,8 @@
 					  unsigned short family);
 extern int xfrm_state_check_expire(struct xfrm_state *x);
 extern void xfrm_state_insert(struct xfrm_state *x);
-extern int xfrm_state_replace(struct xfrm_state *x, int excl);
+extern int xfrm_state_add(struct xfrm_state *x);
+extern int xfrm_state_update(struct xfrm_state *x);
 extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb);
 extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
 extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
Index: kernel-source-2.5/net/netsyms.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/netsyms.c,v
retrieving revision 1.4
diff -u -r1.4 netsyms.c
--- kernel-source-2.5/net/netsyms.c	28 Jun 2003 00:31:10 -0000	1.4
+++ kernel-source-2.5/net/netsyms.c	29 Jun 2003 12:58:10 -0000
@@ -306,7 +306,8 @@
 EXPORT_SYMBOL(__xfrm_state_destroy);
 EXPORT_SYMBOL(xfrm_state_find);
 EXPORT_SYMBOL(xfrm_state_insert);
-EXPORT_SYMBOL(xfrm_state_replace);
+EXPORT_SYMBOL(xfrm_state_add);
+EXPORT_SYMBOL(xfrm_state_update);
 EXPORT_SYMBOL(xfrm_state_check_expire);
 EXPORT_SYMBOL(xfrm_state_check_space);
 EXPORT_SYMBOL(xfrm_state_lookup);
Index: kernel-source-2.5/net/key/af_key.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/key/af_key.c,v
retrieving revision 1.7
diff -u -r1.7 af_key.c
--- kernel-source-2.5/net/key/af_key.c	28 Jun 2003 00:28:01 -0000	1.7
+++ kernel-source-2.5/net/key/af_key.c	29 Jun 2003 12:58:52 -0000
@@ -1223,7 +1223,11 @@
 	if (IS_ERR(x))
 		return PTR_ERR(x);
 
-	err = xfrm_state_replace(x, hdr->sadb_msg_type == SADB_ADD);
+	if (hdr->sadb_msg_type == SADB_ADD)
+		err = xfrm_state_add(x);
+	else
+		err = xfrm_state_update(x);
+
 	if (err < 0) {
 		x->km.state = XFRM_STATE_DEAD;
 		xfrm_state_put(x);
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 13:14:48 -0000
@@ -395,49 +395,110 @@
 	spin_unlock_bh(&xfrm_state_lock);
 }
 
-int xfrm_state_replace(struct xfrm_state *x, int excl)
+int xfrm_state_add(struct xfrm_state *x)
 {
 	struct xfrm_state_afinfo *afinfo;
 	struct xfrm_state *x1;
 	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;
 		}
 	}
 
+	if (x1 && x1->id.spi) {
+		xfrm_state_put(x1);
+		x1 = NULL;
+		err = -EEXIST;
+		goto out;
+	}
+
 	__xfrm_state_insert(x);
 	err = 0;
 
 out:
 	spin_unlock_bh(&xfrm_state_lock);
+	xfrm_state_put_afinfo(afinfo);
 
 	if (x1) {
 		xfrm_state_delete(x1);
 		xfrm_state_put(x1);
 	}
 
+	return err;
+}
+
+int xfrm_state_update(struct xfrm_state *x)
+{
+	struct xfrm_state_afinfo *afinfo;
+	struct xfrm_state *x1;
+	int err;
+
+	afinfo = xfrm_state_get_afinfo(x->props.family);
+	if (unlikely(afinfo == NULL))
+		return -EAFNOSUPPORT;
+
+	spin_lock_bh(&xfrm_state_lock);
+	x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
+
+	err = -ESRCH;
+	if (!x1)
+		goto out;
+
+	if (xfrm_state_kern(x1)) {
+		xfrm_state_put(x1);
+		err = -EEXIST;
+		goto out;
+	}
+
+	if (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);
+
+	if (err)
+		return err;
+
+	if (!x) {
+		xfrm_state_delete(x1);
+		xfrm_state_put(x1);
+		return 0;
+	}
+
+	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);
+
+	xfrm_state_put(x1);
+
 	return err;
 }
 
Index: kernel-source-2.5/net/xfrm/xfrm_user.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_user.c,v
retrieving revision 1.6
diff -u -r1.6 xfrm_user.c
--- kernel-source-2.5/net/xfrm/xfrm_user.c	28 Jun 2003 00:28:01 -0000	1.6
+++ kernel-source-2.5/net/xfrm/xfrm_user.c	29 Jun 2003 12:59:17 -0000
@@ -260,7 +260,11 @@
 	if (!x)
 		return err;
 
-	err = xfrm_state_replace(x, nlh->nlmsg_type == XFRM_MSG_NEWSA);
+	if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+		err = xfrm_state_add(x);
+	else
+		err = xfrm_state_update(x);
+
 	if (err < 0) {
 		x->km.state = XFRM_STATE_DEAD;
 		xfrm_state_put(x);

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux