vserver 1.9.3
[linux-2.6.git] / net / netlink / af_netlink.c
index 4c90113..4aa0503 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
+#include <linux/vs_base.h>
+#include <linux/vs_context.h>
+#include <linux/vs_network.h>
+#include <linux/vs_limit.h>
 #include <net/sock.h>
 #include <net/scm.h>
 
@@ -176,7 +180,7 @@ found:
        return sk;
 }
 
-extern struct proto_ops netlink_ops;
+static struct proto_ops netlink_ops;
 
 static int netlink_insert(struct sock *sk, u32 pid)
 {
@@ -242,6 +246,12 @@ static int netlink_create(struct socket *sock, int protocol)
        sk->sk_destruct = netlink_sock_destruct;
        atomic_inc(&netlink_sock_nr);
 
+       set_vx_info(&sk->sk_vx_info, current->vx_info);
+       sk->sk_xid = vx_current_xid();
+       vx_sock_inc(sk);
+       set_nx_info(&sk->sk_nx_info, current->nx_info);
+       sk->sk_nid = nx_current_nid();
+
        sk->sk_protocol = protocol;
        return 0;
 }
@@ -283,6 +293,12 @@ static int netlink_release(struct socket *sock)
                notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
        }       
        
+       vx_sock_dec(sk);
+       clr_vx_info(&sk->sk_vx_info);
+       sk->sk_xid = -1;
+       clr_nx_info(&sk->sk_nx_info);
+       sk->sk_nid = -1;
+
        sock_put(sk);
        return 0;
 }
@@ -365,6 +381,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        struct sockaddr_nl *nladdr=(struct sockaddr_nl*)addr;
 
        if (addr->sa_family == AF_UNSPEC) {
+               sk->sk_state    = NETLINK_UNCONNECTED;
                nlk->dst_pid    = 0;
                nlk->dst_groups = 0;
                return 0;
@@ -380,11 +397,12 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
                err = netlink_autobind(sock);
 
        if (err == 0) {
+               sk->sk_state    = NETLINK_CONNECTED;
                nlk->dst_pid    = nladdr->nl_pid;
                nlk->dst_groups = nladdr->nl_groups;
        }
 
-       return 0;
+       return err;
 }
 
 static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
@@ -427,7 +445,9 @@ struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid)
 
        /* Don't bother queuing skb if kernel socket has no input function */
        nlk = nlk_sk(sock);
-       if (nlk->pid == 0 && !nlk->data_ready) {
+       if ((nlk->pid == 0 && !nlk->data_ready) ||
+           (sock->sk_state == NETLINK_CONNECTED &&
+            nlk->dst_pid != nlk_sk(ssk)->pid)) {
                sock_put(sock);
                return ERR_PTR(-ECONNREFUSED);
        }
@@ -532,12 +552,31 @@ void netlink_detachskb(struct sock *sk, struct sk_buff *skb)
        sock_put(sk);
 }
 
+static inline void netlink_trim(struct sk_buff *skb, int allocation)
+{
+       int delta = skb->end - skb->tail;
+
+       /* If the packet is charged to a socket, the modification
+        * of truesize below is illegal and will corrupt socket
+        * buffer accounting state.
+        */
+       BUG_ON(skb->list != NULL);
+
+       if (delta * 2 < skb->truesize)
+               return;
+       if (pskb_expand_head(skb, 0, -delta, allocation))
+               return;
+       skb->truesize -= delta;
+}
+
 int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
 {
        struct sock *sk;
        int err;
        long timeo;
 
+       netlink_trim(skb, gfp_any());
+
        timeo = sock_sndtimeo(ssk, nonblock);
 retry:
        sk = netlink_getsockbypid(ssk, pid);
@@ -584,6 +623,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
        int protocol = ssk->sk_protocol;
        int failure = 0, delivered = 0;
 
+       netlink_trim(skb, allocation);
+
        /* While we sleep in clone, do not allow to change socket list */
 
        netlink_lock_table();
@@ -728,14 +769,14 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
           to corresponding kernel module.   --ANK (980802)
         */
 
-       err = security_netlink_send(skb);
-       if (err) {
+       err = -EFAULT;
+       if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {
                kfree_skb(skb);
                goto out;
        }
 
-       err = -EFAULT;
-       if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {
+       err = security_netlink_send(sk, skb);
+       if (err) {
                kfree_skb(skb);
                goto out;
        }
@@ -1216,7 +1257,6 @@ MODULE_ALIAS_NETPROTO(PF_NETLINK);
 
 EXPORT_SYMBOL(netlink_ack);
 EXPORT_SYMBOL(netlink_broadcast);
-EXPORT_SYMBOL(netlink_broadcast_deliver);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_kernel_create);
 EXPORT_SYMBOL(netlink_register_notifier);