-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi all,

IPSec uses sequence numbers to protect against replay attacks.
So far there is no way to get or set these sequence numbers in the kernel.
The attached patches will remedy these issues. Any comments are
welcome! :)

I would be pleased if at least 2.6.13-rc3_ipsec_pfkey_seqnr.diff and
2.6.13-rc3_ipsec_xfrm_seqnr.diff find there way in the vanilla kernel.

Best regards
 Ulrich


2.6.13-rc3_ipsec_pfkey_seqnr.diff:
Get sequence numbers over the pf_key interface. Command "setkey -D".
Credits go to Hiroyuki YAMAMORI
(http://www.linux-ipv6.org/ml/usagi-users/msg02909.html)


2.6.13-rc3_ipsec_xfrm_seqnr.diff:
Get sequence numbers over the XFRM/Netlink interface. Therefore a new
XFRM attribute
(XFRMA_REPLAY) is added every SA dump. Please see
iproute2-2.6.11-050330_XFRMA_REPLAY.diff
to use with "ip -s xfrm state".


2.6.13-rc3_ipsec_set_xfrm_seqnr.diff:
For IPSec HA solutions it is necessary to be informed about sequence
number changes
and to set the sequence number counter of installed SAs. Therefore a
new XFRM group
(XFRMGRP_REPLAY) was added with a new XFRM message type XFRM_MSG_UPDSEQ.
These XFRM_MSG_UPDSEQ messages can be used to inform in intervals
about changed
sequence numbers (an inbound and outbound interval is used, set via
sysctl) and
to set sequence numbers of installed SAs. In addition, it is possible
to install SAs with
an given XFRMA_REPLAY attribute as initial sequence number value.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFC23uH22t2oTuElzoRAvUyAKCkGSwFnqOjs6RnAI9IoZyd9Zk0mgCdGbuB
iIvA8vPtWJ0htDiaIxJ6mls=
=4f66
-----END PGP SIGNATURE-----

diff -Nru linux-2.6.13-rc3.org/net/key/af_key.c linux-2.6.13-rc3/net/key/af_key.c
--- linux-2.6.13-rc3.org/net/key/af_key.c	2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/key/af_key.c	2005-07-18 10:47:15.000000000 +0200
@@ -868,7 +868,7 @@
 	sa2->sadb_x_sa2_mode = x->props.mode + 1;
 	sa2->sadb_x_sa2_reserved1 = 0;
 	sa2->sadb_x_sa2_reserved2 = 0;
-	sa2->sadb_x_sa2_sequence = 0;
+	sa2->sadb_x_sa2_sequence = x->replay.seq ? x->replay.seq : x->replay.oseq;
 	sa2->sadb_x_sa2_reqid = x->props.reqid;
 
 	if (natt && natt->encap_type) {
diff -Nru linux-2.6.13-rc3.org/include/linux/sysctl.h linux-2.6.13-rc3/include/linux/sysctl.h
--- linux-2.6.13-rc3.org/include/linux/sysctl.h	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/include/linux/sysctl.h	2005-07-18 10:49:54.000000000 +0200
@@ -253,6 +253,8 @@
 	NET_CORE_DEV_WEIGHT=17,
 	NET_CORE_SOMAXCONN=18,
 	NET_CORE_BUDGET=19,
+	NET_CORE_XFRM_SEQDIFF_IN=20,
+	NET_CORE_XFRM_SEQDIFF_OUT=21,
 };
 
 /* /proc/sys/net/ethernet */
diff -Nru linux-2.6.13-rc3.org/include/linux/xfrm.h linux-2.6.13-rc3/include/linux/xfrm.h
--- linux-2.6.13-rc3.org/include/linux/xfrm.h	2005-07-18 10:49:43.000000000 +0200
+++ linux-2.6.13-rc3/include/linux/xfrm.h	2005-07-18 10:49:54.000000000 +0200
@@ -140,6 +140,9 @@
 	XFRM_MSG_FLUSHPOLICY,
 #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
 
+	XFRM_MSG_UPDSEQ,
+#define XFRM_MSG_UPDSEQ XFRM_MSG_UPDSEQ
+ 
 	__XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -263,5 +266,6 @@
 #define XFRMGRP_EXPIRE		2
 #define XFRMGRP_SA		4
 #define XFRMGRP_POLICY		8
+#define XFRMGRP_REPLAY		16
 
 #endif /* _LINUX_XFRM_H */
diff -Nru linux-2.6.13-rc3.org/include/net/xfrm.h linux-2.6.13-rc3/include/net/xfrm.h
--- linux-2.6.13-rc3.org/include/net/xfrm.h	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/include/net/xfrm.h	2005-07-18 10:49:54.000000000 +0200
@@ -134,6 +134,9 @@
 	/* State for replay detection */
 	struct xfrm_replay_state replay;
 
+	/* Replay detection state at the time we sent the last notification */
+	struct xfrm_replay_state preplay;
+
 	/* Statistics */
 	struct xfrm_stats	stats;
 
@@ -301,6 +304,11 @@
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+/* which seqno */
+#define XFRM_REPLAY_INBOUND	1
+#define XFRM_REPLAY_OUTBOUND	2
+#define XFRM_REPLAY_BOUND_MASK	3
+
 #define XFRM_KM_TIMEOUT		30
 
 struct xfrm_mgr
@@ -312,6 +320,7 @@
 	struct xfrm_policy	*(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
 	int			(*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
 	int			(*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
+	int			(*notify_seq)(struct xfrm_state *x, u32, u32);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -838,6 +847,8 @@
 extern void xfrm_state_flush(u8 proto);
 extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
+extern void xfrm_replay_notify(struct xfrm_state *x, int event);
+extern void xfrm_state_replay_update(struct xfrm_state *x, struct xfrm_replay_state *replay);
 extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
 extern int xfrm_init_state(struct xfrm_state *x);
@@ -888,6 +899,7 @@
 struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 
 				  xfrm_address_t *daddr, xfrm_address_t *saddr, 
 				  int create, unsigned short family);
+void km_replay_notify(struct xfrm_state *);
 extern void xfrm_policy_flush(void);
 extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
 extern int xfrm_flush_bundles(void);
diff -Nru linux-2.6.13-rc3.org/net/core/sysctl_net_core.c linux-2.6.13-rc3/net/core/sysctl_net_core.c
--- linux-2.6.13-rc3.org/net/core/sysctl_net_core.c	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/net/core/sysctl_net_core.c	2005-07-18 10:49:54.000000000 +0200
@@ -31,6 +31,11 @@
 extern char sysctl_divert_version[];
 #endif /* CONFIG_NET_DIVERT */
 
+#ifdef CONFIG_XFRM
+extern u32 sysctl_xfrm_seqdiff_in;
+extern u32 sysctl_xfrm_seqdiff_out;
+#endif /* CONFIG_XFRM */
+
 ctl_table core_table[] = {
 #ifdef CONFIG_NET
 	{
@@ -116,6 +121,24 @@
 		.proc_handler	= &proc_dostring
 	},
 #endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_XFRM
+	{
+		.ctl_name	= NET_CORE_XFRM_SEQDIFF_IN,
+		.procname	= "xfrm_seqdiff_in",
+		.data		= &sysctl_xfrm_seqdiff_in,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_CORE_XFRM_SEQDIFF_OUT,
+		.procname	= "xfrm_seqdiff_out",
+		.data		= &sysctl_xfrm_seqdiff_out,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif /* CONFIG_XFRM */
 #endif /* CONFIG_NET */
 	{
 		.ctl_name	= NET_CORE_SOMAXCONN,
diff -Nru linux-2.6.13-rc3.org/net/ipv4/ah4.c linux-2.6.13-rc3/net/ipv4/ah4.c
--- linux-2.6.13-rc3.org/net/ipv4/ah4.c	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv4/ah4.c	2005-07-18 10:49:54.000000000 +0200
@@ -96,6 +96,8 @@
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
+	xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
 	ahp->icv(ahp, skb, ah->auth_data);
 
 	top_iph->tos = iph->tos;
diff -Nru linux-2.6.13-rc3.org/net/ipv4/esp4.c linux-2.6.13-rc3/net/ipv4/esp4.c
--- linux-2.6.13-rc3.org/net/ipv4/esp4.c	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv4/esp4.c	2005-07-18 10:49:54.000000000 +0200
@@ -96,6 +96,8 @@
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(++x->replay.oseq);
 
+	xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
 	if (esp->conf.ivlen)
 		crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
 
diff -Nru linux-2.6.13-rc3.org/net/ipv6/ah6.c linux-2.6.13-rc3/net/ipv6/ah6.c
--- linux-2.6.13-rc3.org/net/ipv6/ah6.c	2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv6/ah6.c	2005-07-18 10:49:54.000000000 +0200
@@ -212,6 +212,8 @@
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
+	xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+
 	ahp->icv(ahp, skb, ah->auth_data);
 
 	err = 0;
diff -Nru linux-2.6.13-rc3.org/net/ipv6/esp6.c linux-2.6.13-rc3/net/ipv6/esp6.c
--- linux-2.6.13-rc3.org/net/ipv6/esp6.c	2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/ipv6/esp6.c	2005-07-18 10:49:54.000000000 +0200
@@ -93,6 +93,8 @@
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(++x->replay.oseq);
 
+	xfrm_replay_notify(x, XFRM_REPLAY_OUTBOUND);
+	
 	if (esp->conf.ivlen)
 		crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
 
diff -Nru linux-2.6.13-rc3.org/net/key/af_key.c linux-2.6.13-rc3/net/key/af_key.c
--- linux-2.6.13-rc3.org/net/key/af_key.c	2005-07-18 10:49:41.000000000 +0200
+++ linux-2.6.13-rc3/net/key/af_key.c	2005-07-18 10:49:54.000000000 +0200
@@ -2860,6 +2860,12 @@
 	return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
 }
 
+static int pfkey_send_replay_notify(struct xfrm_state *x, u32 pid, u32 seq)
+{
+	/* FIXME: To be done*/
+	return 0;
+}
+
 static int pfkey_sendmsg(struct kiocb *kiocb,
 			 struct socket *sock, struct msghdr *msg, size_t len)
 {
@@ -3029,6 +3035,7 @@
 	.compile_policy	= pfkey_compile_policy,
 	.new_mapping	= pfkey_send_new_mapping,
 	.notify_policy	= pfkey_send_policy_notify,
+	.notify_seq	= pfkey_send_replay_notify,
 };
 
 static void __exit ipsec_pfkey_exit(void)
diff -Nru linux-2.6.13-rc3.org/net/xfrm/xfrm_state.c linux-2.6.13-rc3/net/xfrm/xfrm_state.c
--- linux-2.6.13-rc3.org/net/xfrm/xfrm_state.c	2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/xfrm/xfrm_state.c	2005-07-18 10:49:54.000000000 +0200
@@ -20,6 +20,9 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
+u32 sysctl_xfrm_seqdiff_in = 0;
+u32 sysctl_xfrm_seqdiff_out = 0;
+
 /* Each xfrm_state may be linked to two tables:
 
    1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
@@ -758,6 +761,29 @@
 }
 EXPORT_SYMBOL(xfrm_state_walk);
 
+void xfrm_replay_notify(struct xfrm_state *x, int event)
+{
+	switch (event & XFRM_REPLAY_BOUND_MASK) {
+	case XFRM_REPLAY_INBOUND:
+		if (!sysctl_xfrm_seqdiff_in ||
+		    (x->replay.seq - x->preplay.seq < sysctl_xfrm_seqdiff_in))
+			return;
+
+		break;
+
+	case XFRM_REPLAY_OUTBOUND:
+		if (!sysctl_xfrm_seqdiff_out ||
+		    (x->replay.oseq - x->preplay.oseq < sysctl_xfrm_seqdiff_out))
+			return;
+
+		break;
+	}
+
+	memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
+	km_replay_notify(x);
+}
+EXPORT_SYMBOL(xfrm_replay_notify);
+
 int xfrm_replay_check(struct xfrm_state *x, u32 seq)
 {
 	u32 diff;
@@ -801,9 +827,20 @@
 		diff = x->replay.seq - seq;
 		x->replay.bitmap |= (1U << diff);
 	}
+
+	xfrm_replay_notify(x, XFRM_REPLAY_INBOUND);
 }
 EXPORT_SYMBOL(xfrm_replay_advance);
 
+void xfrm_state_replay_update(struct xfrm_state *x, struct xfrm_replay_state *replay)
+{
+	spin_lock(&x->lock);
+	memcpy(&x->replay, replay, sizeof(*replay));
+	memcpy(&x->preplay, replay, sizeof(*replay));
+	spin_unlock(&x->lock);
+}
+EXPORT_SYMBOL(xfrm_state_replay_update);
+
 static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
 static DEFINE_RWLOCK(xfrm_km_lock);
 
@@ -891,6 +928,17 @@
 		wake_up(&km_waitq);
 }
 
+void km_replay_notify(struct xfrm_state *x)
+{
+	struct xfrm_mgr *km;
+
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list)
+		if (km->notify_seq)
+			km->notify_seq(x, 0, 0);
+	read_unlock(&xfrm_km_lock);
+}
+
 int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
 {
 	int err;
@@ -1104,3 +1152,7 @@
 	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
 }
 
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(sysctl_xfrm_seqdiff_in);
+EXPORT_SYMBOL(sysctl_xfrm_seqdiff_out);
+#endif
diff -Nru linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c linux-2.6.13-rc3/net/xfrm/xfrm_user.c
--- linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c	2005-07-18 10:49:43.000000000 +0200
+++ linux-2.6.13-rc3/net/xfrm/xfrm_user.c	2005-07-18 10:49:54.000000000 +0200
@@ -917,6 +917,76 @@
 	return 0;
 }
 
+static int build_replay(struct sk_buff *skb, struct xfrm_state *x, __u32 pid, __u32 seq)
+{
+	struct xfrm_usersa_id *id;
+	struct nlmsghdr *nlh;
+	unsigned char *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, pid, seq, XFRM_MSG_UPDSEQ, sizeof(*id));
+	id = NLMSG_DATA(nlh);
+	nlh->nlmsg_flags = 0;
+
+	id->daddr = x->id.daddr;
+	id->spi = x->id.spi;
+	id->family = x->props.family;
+	id->proto = x->id.proto;
+
+	RTA_PUT(skb, XFRMA_REPLAY, sizeof(x->replay), &x->replay);
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+rtattr_failure:
+nlmsg_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static int xfrm_send_replay_notify(struct xfrm_state *x, __u32 pid,__u32 seq) {
+	struct sk_buff *skb;
+
+	skb = alloc_skb(sizeof(struct xfrm_usersa_id) + sizeof(struct xfrm_replay_state) + 16, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	if (build_replay(skb, x, pid, seq) < 0)
+		BUG();
+
+	if(pid == 0)
+	{
+		NETLINK_CB(skb).dst_groups = XFRMGRP_REPLAY;
+		return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_REPLAY, GFP_ATOMIC);
+	}
+	else
+		return netlink_unicast(xfrm_nl, skb, pid, MSG_DONTWAIT);
+}
+
+static int xfrm_update_seq(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+	struct xfrm_state *x;
+	struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
+	struct xfrm_replay_state *replay;
+	struct rtattr *rt = xfrma[XFRMA_REPLAY-1];
+ 
+	x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
+	if (x == NULL) {
+		printk(KERN_INFO "Found no xfrm state for sa seq update\n");
+		return -ESRCH;
+	}
+
+	if( xfrma[XFRMA_REPLAY-1] != NULL && (rt->rta_len == (sizeof(struct xfrm_replay_state) + sizeof(struct rtattr)))) {
+		replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
+		xfrm_state_replay_update(x, replay);
+		xfrm_state_put(x);
+	}
+	else {
+		xfrm_send_replay_notify(x, nlh->nlmsg_pid, nlh->nlmsg_seq);
+	}
+
+	return 0;
+} 
+
 #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
 
 static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
@@ -934,6 +1004,7 @@
 	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
 	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
+	[XFRM_MSG_UPDSEQ      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
 };
 
 #undef XMSGSIZE
@@ -955,6 +1026,7 @@
 	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
 	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
 	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
+	[XFRM_MSG_UPDSEQ      - XFRM_MSG_BASE] = { .doit = xfrm_update_seq    },
 };
 
 static int xfrm_done(struct netlink_callback *cb)
@@ -1519,6 +1591,7 @@
 	.acquire	= xfrm_send_acquire,
 	.compile_policy	= xfrm_compile_policy,
 	.notify_policy	= xfrm_send_policy_notify,
+	.notify_seq	= xfrm_send_replay_notify,
 };
 
 static int __init xfrm_user_init(void)
diff -Nru linux-2.6.13-rc3.org/include/linux/xfrm.h linux-2.6.13-rc3/include/linux/xfrm.h
--- linux-2.6.13-rc3.org/include/linux/xfrm.h	2005-07-18 10:24:11.000000000 +0200
+++ linux-2.6.13-rc3/include/linux/xfrm.h	2005-07-18 10:48:32.000000000 +0200
@@ -176,6 +176,7 @@
 	XFRMA_TMPL,		/* 1 or more struct xfrm_user_tmpl */
 	XFRMA_SA,
 	XFRMA_POLICY,
+	XFRMA_REPLAY,		/* struct xfrm_replay_state */
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
diff -Nru linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c linux-2.6.13-rc3/net/xfrm/xfrm_user.c
--- linux-2.6.13-rc3.org/net/xfrm/xfrm_user.c	2005-07-18 10:24:12.000000000 +0200
+++ linux-2.6.13-rc3/net/xfrm/xfrm_user.c	2005-07-18 10:48:32.000000000 +0200
@@ -227,6 +227,7 @@
 					       int *errp)
 {
 	struct xfrm_state *x = xfrm_state_alloc();
+	struct rtattr *rt = xfrma[XFRMA_REPLAY-1];
 	int err = -ENOMEM;
 
 	if (!x)
@@ -249,6 +250,12 @@
 	if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1])))
 		goto error;
 
+	if( xfrma[XFRMA_REPLAY-1] && (rt->rta_len == (sizeof(struct xfrm_replay_state) + sizeof(struct rtattr)))) {
+		struct xfrm_replay_state *replay;
+		replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
+		x->replay = *replay;
+	}
+
 	err = xfrm_init_state(x);
 	if (err)
 		goto error;
@@ -390,6 +397,8 @@
 	if (x->encap)
 		RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
 
+	RTA_PUT(skb, XFRMA_REPLAY, sizeof(x->replay), &x->replay);
+
 	nlh->nlmsg_len = skb->tail - b;
 out:
 	sp->this_idx++;
diff -Nru iproute2-2.6.11-050330.org/include/linux/xfrm.h iproute2-2.6.11-050330/include/linux/xfrm.h
--- iproute2-2.6.11-050330.org/include/linux/xfrm.h	2005-07-11 15:43:01.000000000 +0200
+++ iproute2-2.6.11-050330/include/linux/xfrm.h	2005-07-12 10:21:40.000000000 +0200
@@ -171,6 +171,9 @@
 	XFRMA_ALG_COMP,		/* struct xfrm_algo */
 	XFRMA_ENCAP,		/* struct xfrm_algo + struct xfrm_encap_tmpl */
 	XFRMA_TMPL,		/* 1 or more struct xfrm_user_tmpl */
+	XFRMA_SA,
+	XFRMA_POLICY,
+	XFRMA_REPLAY,		/* struct xfrm_replay_state */
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
diff -Nru iproute2-2.6.11-050330.org/ip/ipxfrm.c iproute2-2.6.11-050330/ip/ipxfrm.c
--- iproute2-2.6.11-050330.org/ip/ipxfrm.c	2005-07-11 15:43:01.000000000 +0200
+++ iproute2-2.6.11-050330/ip/ipxfrm.c	2005-07-12 10:18:18.000000000 +0200
@@ -669,7 +669,17 @@
 	fprintf(fp, buf);
 	fprintf(fp, "replay-window %u ", xsinfo->replay_window);
 	if (show_stats > 0)
-		fprintf(fp, "seq 0x%08u ", xsinfo->seq);
+	{
+		__u32 sa_seq = 0;
+
+		if(tb[XFRMA_REPLAY] != NULL)
+		{
+			struct xfrm_replay_state replay;
+			memcpy(&replay, RTA_DATA(tb[XFRMA_REPLAY]), sizeof(replay));
+			sa_seq = replay.seq ? replay.seq : replay.oseq;
+		}
+		fprintf(fp, "sa_seq 0x%08x seq 0x%08u ", sa_seq, xsinfo->seq);
+	}
 	if (show_stats > 0 || xsinfo->flags) {
 		__u8 flags = xsinfo->flags;
 

Reply via email to