[ALSA] Added model for ASUS M2NPV-VM mobo
[safe/jmp/linux-2.6] / net / xfrm / xfrm_user.c
index 2dc1e69..fa79ddc 100644 (file)
@@ -10,6 +10,7 @@
  *
  */
 
+#include <linux/crypto.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -28,8 +29,6 @@
 #include <net/netlink.h>
 #include <asm/uaccess.h>
 
-struct sock *xfrm_nl;
-
 static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
 {
        struct rtattr *rt = xfrma[type - 1];
@@ -103,9 +102,6 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma)
 
        uctx = RTA_DATA(rt);
 
-       if (uctx->ctx_len > PAGE_SIZE)
-               return -EINVAL;
-
        len += sizeof(struct xfrm_user_sec_ctx);
        len += uctx->ctx_len;
 
@@ -217,6 +213,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
                return -ENOMEM;
 
        memcpy(p, ualg, len);
+       strcpy(p->alg_name, algo->name);
        *algpp = p;
        return 0;
 }
@@ -432,23 +429,25 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
        if (x == NULL)
                return -ESRCH;
 
+       if ((err = security_xfrm_state_delete(x)) != 0)
+               goto out;
+
        if (xfrm_state_kern(x)) {
-               xfrm_state_put(x);
-               return -EPERM;
+               err = -EPERM;
+               goto out;
        }
 
        err = xfrm_state_delete(x);
-       if (err < 0) {
-               xfrm_state_put(x);
-               return err;
-       }
+       if (err < 0)
+               goto out;
 
        c.seq = nlh->nlmsg_seq;
        c.pid = nlh->nlmsg_pid;
        c.event = nlh->nlmsg_type;
        km_state_notify(x, &c);
-       xfrm_state_put(x);
 
+out:
+       xfrm_state_put(x);
        return err;
 }
 
@@ -1060,6 +1059,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
                                              MSG_DONTWAIT);
                }
        } else {
+               if ((err = security_xfrm_policy_delete(xp)) != 0)
+                       goto out;
                c.data.byid = p->index;
                c.event = nlh->nlmsg_type;
                c.seq = nlh->nlmsg_seq;
@@ -1069,6 +1070,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
 
        xfrm_pol_put(xp);
 
+out:
        return err;
 }
 
@@ -1222,7 +1224,7 @@ out:
 
 static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
 {
-       struct km_event c;
+struct km_event c;
 
        xfrm_policy_flush();
        c.event = nlh->nlmsg_type;
@@ -1232,6 +1234,58 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x
        return 0;
 }
 
+static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_policy *xp;
+       struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
+       struct xfrm_userpolicy_info *p = &up->pol;
+       int err = -ENOENT;
+
+       if (p->index)
+               xp = xfrm_policy_byid(p->dir, p->index, 0);
+       else {
+               struct rtattr **rtattrs = (struct rtattr **)xfrma;
+               struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+               struct xfrm_policy tmp;
+
+               err = verify_sec_ctx_len(rtattrs);
+               if (err)
+                       return err;
+
+               memset(&tmp, 0, sizeof(struct xfrm_policy));
+               if (rt) {
+                       struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
+
+                       if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
+                               return err;
+               }
+               xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0);
+               security_xfrm_policy_free(&tmp);
+       }
+
+       if (xp == NULL)
+               return err;
+                                                                                       read_lock(&xp->lock);
+       if (xp->dead) {
+               read_unlock(&xp->lock);
+               goto out;
+       }
+
+       read_unlock(&xp->lock);
+       err = 0;
+       if (up->hard) {
+               xfrm_policy_delete(xp, p->dir);
+       } else {
+               // reset the timers here?
+               printk("Dont know what to do with soft policy expire\n");
+       }
+       km_policy_expired(xp, p->dir, up->hard, current->pid);
+
+out:
+       xfrm_pol_put(xp);
+       return err;
+}
+
 static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
 {
        struct xfrm_state *x;
@@ -1327,6 +1381,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
        [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_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_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
@@ -1352,6 +1407,7 @@ static struct xfrm_link {
        [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_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
        [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
        [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
        [XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
@@ -1381,7 +1437,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
        link = &xfrm_dispatch[type];
 
        /* All operations require privileges, even GET */
-       if (security_netlink_recv(skb)) {
+       if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
                *errp = -EPERM;
                return -1;
        }
@@ -1437,9 +1493,9 @@ static void xfrm_netlink_rcv(struct sock *sk, int len)
        unsigned int qlen = 0;
 
        do {
-               down(&xfrm_cfg_sem);
+               mutex_lock(&xfrm_cfg_mutex);
                netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg);
-               up(&xfrm_cfg_sem);
+               mutex_unlock(&xfrm_cfg_mutex);
 
        } while (qlen);
 }
@@ -1898,12 +1954,15 @@ static struct xfrm_mgr netlink_mgr = {
 
 static int __init xfrm_user_init(void)
 {
+       struct sock *nlsk;
+
        printk(KERN_INFO "Initializing IPsec netlink socket\n");
 
-       xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
-                                       xfrm_netlink_rcv, THIS_MODULE);
-       if (xfrm_nl == NULL)
+       nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
+                                    xfrm_netlink_rcv, THIS_MODULE);
+       if (nlsk == NULL)
                return -ENOMEM;
+       rcu_assign_pointer(xfrm_nl, nlsk);
 
        xfrm_register_km(&netlink_mgr);
 
@@ -1912,13 +1971,16 @@ static int __init xfrm_user_init(void)
 
 static void __exit xfrm_user_exit(void)
 {
+       struct sock *nlsk = xfrm_nl;
+
        xfrm_unregister_km(&netlink_mgr);
-       sock_release(xfrm_nl->sk_socket);
+       rcu_assign_pointer(xfrm_nl, NULL);
+       synchronize_rcu();
+       sock_release(nlsk->sk_socket);
 }
 
 module_init(xfrm_user_init);
 module_exit(xfrm_user_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
-EXPORT_SYMBOL(xfrm_nl);