struct xfrm_tmpl;
 extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
+extern int __xfrm_state_delete(struct xfrm_state *x);
+
 struct xfrm_state_afinfo {
        unsigned short          family;
        rwlock_t                lock;
 
 
 static int xfrm_state_gc_flush_bundles;
 
-static int __xfrm_state_delete(struct xfrm_state *x);
+int __xfrm_state_delete(struct xfrm_state *x);
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
 int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
-static void km_state_expired(struct xfrm_state *x, int hard);
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
 
        x->km.dying = warn;
        if (warn)
-               km_state_expired(x, 0);
+               km_state_expired(x, 0, 0);
 resched:
        if (next != LONG_MAX &&
            !mod_timer(&x->timer, jiffies + make_jiffies(next)))
                goto resched;
        }
        if (!__xfrm_state_delete(x) && x->id.spi)
-               km_state_expired(x, 1);
+               km_state_expired(x, 1, 0);
 
 out:
        spin_unlock(&x->lock);
 }
 EXPORT_SYMBOL(__xfrm_state_destroy);
 
-static int __xfrm_state_delete(struct xfrm_state *x)
+int __xfrm_state_delete(struct xfrm_state *x)
 {
        int err = -ESRCH;
 
 
        return err;
 }
+EXPORT_SYMBOL(__xfrm_state_delete);
 
 int xfrm_state_delete(struct xfrm_state *x)
 {
            (x->curlft.bytes >= x->lft.soft_byte_limit ||
             x->curlft.packets >= x->lft.soft_packet_limit)) {
                x->km.dying = 1;
-               km_state_expired(x, 0);
+               km_state_expired(x, 0, 0);
        }
        return 0;
 }
 EXPORT_SYMBOL(km_policy_notify);
 EXPORT_SYMBOL(km_state_notify);
 
-void km_state_expired(struct xfrm_state *x, int hard)
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
 {
        struct km_event c;
 
        c.data.hard = hard;
+       c.pid = pid;
        c.event = XFRM_MSG_EXPIRE;
        km_state_notify(x, &c);
 
                wake_up(&km_waitq);
 }
 
+EXPORT_SYMBOL(km_state_expired);
 /*
  * We send to all registered managers regardless of failure
  * We are happy with one success
 
        return 0;
 }
 
+static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_state *x;
+       int err;
+       struct xfrm_user_expire *ue = NLMSG_DATA(nlh);
+       struct xfrm_usersa_info *p = &ue->state;
+
+       x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family);
+               err = -ENOENT;
+
+       if (x == NULL)
+               return err;
+
+       err = -EINVAL;
+
+       spin_lock_bh(&x->lock);
+       if (x->km.state != XFRM_STATE_VALID)
+               goto out;
+       km_state_expired(x, ue->hard, current->pid);
+
+       if (ue->hard)
+               __xfrm_state_delete(x);
+out:
+       spin_unlock_bh(&x->lock);
+       xfrm_state_put(x);
+       return err;
+}
+
 static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
 {
        struct xfrm_policy *xp;
        [XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
        [XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info),
        [XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
+       [XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
        [XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
        [XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
        [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
                                                   .dump = xfrm_dump_policy   },
        [XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
        [XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
+       [XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
        [XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
        [XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
        [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },