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

Hi All,

thanks for revising Patrick! Attached is the updated patch.
Sorry had no time yet to remove the sysctl variables.
It will follow in a few weeks if I have more time :)

Best regards
 Ulrich

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

iD8DBQFC8fRi22t2oTuElzoRAkPIAJ40Ej2cs+1DX2IYiVcpr/OF8dUKJgCeJj6T
o639zBMfTeeEwY1OgxRcsw0=
=ggAG
-----END PGP SIGNATURE-----

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-19 10:10:22.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-19 10:10:22.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-08-04 12:28:36.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,10 @@
        struct xfrm_tmpl        xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+/* which seqno */
+#define XFRM_REPLAY_INBOUND    1
+#define XFRM_REPLAY_OUTBOUND   2
+
 #define XFRM_KM_TIMEOUT                30
 
 struct xfrm_mgr
@@ -312,6 +319,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 pid, 
u32 seq);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -838,6 +846,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 +898,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);
+extern 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-19 10:10:22.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-19 10:10:22.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-19 10:10:22.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-19 10:10:22.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-19 10:10:22.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-19 10:10:22.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-08-04 12:29:41.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) {
+       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,19 @@
                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_bh(&x->lock);
+       memcpy(&x->replay, replay, sizeof(*replay));
+       memcpy(&x->preplay, replay, sizeof(*replay));
+       spin_unlock_bh(&x->lock);
+}
+
 static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
 static DEFINE_RWLOCK(xfrm_km_lock);
 
@@ -891,6 +927,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 +1151,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-08-04 12:44:53.000000000 
+0200
@@ -250,7 +250,8 @@
        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)))) {
+       if (xfrma[XFRMA_REPLAY-1] &&
+           (rt->rta_len == RTA_LENGTH(sizeof(struct xfrm_replay_state)))) {
                struct xfrm_replay_state *replay;
                replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
                x->replay = *replay;
@@ -917,6 +918,75 @@
        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) {
+               return -ESRCH;
+       }
+
+       if (xfrma[XFRMA_REPLAY-1] != NULL &&
+           (rt->rta_len == RTA_LENGTH(sizeof(struct xfrm_replay_state)))) {
+               replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]);
+               xfrm_state_replay_update(x, replay);
+       }
+       else {
+               xfrm_send_replay_notify(x, nlh->nlmsg_pid, nlh->nlmsg_seq);
+       }
+       xfrm_state_put(x);
+
+       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)

Reply via email to