--- linux.org/net/xfrm/xfrm_user.c 2004-10-18 23:54:32.000000000 +0200 +++ linux/net/xfrm/xfrm_user.c 2004-10-21 16:27:59.000000000 +0200 @@ -240,6 +240,12 @@ if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) goto error; + if(xfrma[XFRMA_REPLAY-1]) { + struct xfrm_replay_state *replay; + replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]); + x->replay = *replay; + } + err = -ENOENT; x->type = xfrm_get_type(x->id.proto, x->props.family); if (x->type == NULL) @@ -368,6 +375,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++; @@ -852,6 +861,27 @@ return 0; } +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; + + 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]) { + replay = RTA_DATA(xfrma[XFRMA_REPLAY - 1]); + x->replay = *replay; + } + else return -EINVAL; + + return 0; +} + static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = { NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* NEW SA */ NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* DEL SA */ @@ -867,6 +897,7 @@ NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */ NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)), /* FLUSH SA */ NLMSG_LENGTH(0), /* FLUSH POLICY */ + NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),/* UPD SEQ */ }; static struct xfrm_link { @@ -893,6 +924,7 @@ {}, { .doit = xfrm_flush_sa }, { .doit = xfrm_flush_policy }, + { .doit = xfrm_update_seq }, }; static int xfrm_done(struct netlink_callback *cb) @@ -1050,6 +1082,33 @@ return -1; } +static int build_replay(struct sk_buff *skb, struct xfrm_state *x, int event) +{ + struct xfrm_usersa_id *id; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + + nlh = NLMSG_PUT(skb, 0, 0, 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_state_notify(struct xfrm_state *x, int hard) { struct sk_buff *skb; @@ -1218,12 +1277,28 @@ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); } +static int xfrm_send_replay_notify(struct xfrm_state *x, int event) { + 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, event) < 0) + BUG(); + + NETLINK_CB(skb).dst_groups = XFRMGRP_REPLAY; + + return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_REPLAY, GFP_ATOMIC); +} + static struct xfrm_mgr netlink_mgr = { .id = "netlink", .notify = xfrm_send_state_notify, .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)