vserver 1.9.3
[linux-2.6.git] / net / xfrm / xfrm_user.c
index 15bf2fd..db2087c 100644 (file)
@@ -155,15 +155,24 @@ out:
        return err;
 }
 
-static int attach_one_algo(struct xfrm_algo **algpp, struct rtattr *u_arg)
+static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
+                          struct xfrm_algo_desc *(*get_byname)(char *),
+                          struct rtattr *u_arg)
 {
        struct rtattr *rta = u_arg;
        struct xfrm_algo *p, *ualg;
+       struct xfrm_algo_desc *algo;
 
        if (!rta)
                return 0;
 
        ualg = RTA_DATA(rta);
+
+       algo = get_byname(ualg->alg_name);
+       if (!algo)
+               return -ENOSYS;
+       *props = algo->desc.sadb_alg_id;
+
        p = kmalloc(sizeof(*ualg) + ualg->alg_key_len, GFP_KERNEL);
        if (!p)
                return -ENOMEM;
@@ -216,11 +225,17 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
 
        copy_from_user_state(x, p);
 
-       if ((err = attach_one_algo(&x->aalg, xfrma[XFRMA_ALG_AUTH-1])))
+       if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
+                                  xfrm_aalg_get_byname,
+                                  xfrma[XFRMA_ALG_AUTH-1])))
                goto error;
-       if ((err = attach_one_algo(&x->ealg, xfrma[XFRMA_ALG_CRYPT-1])))
+       if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
+                                  xfrm_ealg_get_byname,
+                                  xfrma[XFRMA_ALG_CRYPT-1])))
                goto error;
-       if ((err = attach_one_algo(&x->calg, xfrma[XFRMA_ALG_COMP-1])))
+       if ((err = attach_one_algo(&x->calg, &x->props.calgo,
+                                  xfrm_calg_get_byname,
+                                  xfrma[XFRMA_ALG_COMP-1])))
                goto error;
        if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1])))
                goto error;
@@ -258,6 +273,8 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
        if (err)
                return err;
 
+       xfrm_probe_algs();
+
        x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err);
        if (!x)
                return err;
@@ -453,16 +470,32 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **
        struct xfrm_state *x;
        struct xfrm_userspi_info *p;
        struct sk_buff *resp_skb;
+       xfrm_address_t *daddr;
+       int family;
        int err;
 
        p = NLMSG_DATA(nlh);
        err = verify_userspi_info(p);
        if (err)
                goto out_noput;
-       x = xfrm_find_acq(p->info.mode, p->info.reqid, p->info.id.proto,
-                         &p->info.id.daddr,
-                         &p->info.saddr, 1,
-                         p->info.family);
+
+       family = p->info.family;
+       daddr = &p->info.id.daddr;
+
+       x = NULL;
+       if (p->info.seq) {
+               x = xfrm_find_acq_byseq(p->info.seq);
+               if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
+                       xfrm_state_put(x);
+                       x = NULL;
+               }
+       }
+
+       if (!x)
+               x = xfrm_find_acq(p->info.mode, p->info.reqid,
+                                 p->info.id.proto, daddr,
+                                 &p->info.saddr, 1,
+                                 family);
        err = -ENOENT;
        if (x == NULL)
                goto out_noput;
@@ -805,6 +838,20 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
        return err;
 }
 
+static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
+
+       xfrm_state_flush(p->proto);
+       return 0;
+}
+
+static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       xfrm_policy_flush();
+       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 */
@@ -817,6 +864,9 @@ static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = {
        NLMSG_LENGTH(sizeof(struct xfrm_user_expire)),  /* EXPIRE */
        NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */
        NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),  /* UPD SA */
+       NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */
+       NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)), /* FLUSH SA */
+       NLMSG_LENGTH(0),                                /* FLUSH POLICY */
 };
 
 static struct xfrm_link {
@@ -840,6 +890,9 @@ static struct xfrm_link {
        {},
        {       .doit   =       xfrm_add_policy         },
        {       .doit   =       xfrm_add_sa,            },
+       {},
+       {       .doit   =       xfrm_flush_sa           },
+       {       .doit   =       xfrm_flush_policy       },
 };
 
 static int xfrm_done(struct netlink_callback *cb)