]> err.no Git - linux-2.6/blobdiff - net/netlink/af_netlink.c
Merge /spare/repo/linux-2.6/
[linux-2.6] / net / netlink / af_netlink.c
index 29a5fd231eac9a97bb247162e8a8fc20a8163cea..70bcd4744d9370e44f0389f28754df5aaaa3bee6 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/bitops.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/audit.h>
+
 #include <net/sock.h>
 #include <net/scm.h>
 
@@ -373,7 +375,6 @@ static int netlink_release(struct socket *sock)
                nlk->cb->done(nlk->cb);
                netlink_destroy_callback(nlk->cb);
                nlk->cb = NULL;
-               __sock_put(sk);
        }
        spin_unlock(&nlk->cb_lock);
 
@@ -734,11 +735,15 @@ static inline int do_one_broadcast(struct sock *sk,
 
        sock_hold(sk);
        if (p->skb2 == NULL) {
-               if (atomic_read(&p->skb->users) != 1) {
+               if (skb_shared(p->skb)) {
                        p->skb2 = skb_clone(p->skb, p->allocation);
                } else {
-                       p->skb2 = p->skb;
-                       atomic_inc(&p->skb->users);
+                       p->skb2 = skb_get(p->skb);
+                       /*
+                        * skb ownership may have been set when
+                        * delivered to a previous socket.
+                        */
+                       skb_orphan(p->skb2);
                }
        }
        if (p->skb2 == NULL) {
@@ -784,11 +789,12 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
        sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
                do_one_broadcast(sk, &info);
 
+       kfree_skb(skb);
+
        netlink_unlock_table();
 
        if (info.skb2)
                kfree_skb(info.skb2);
-       kfree_skb(skb);
 
        if (info.delivered) {
                if (info.congested && (allocation & __GFP_WAIT))
@@ -905,6 +911,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        NETLINK_CB(skb).groups  = nlk->groups;
        NETLINK_CB(skb).dst_pid = dst_pid;
        NETLINK_CB(skb).dst_groups = dst_groups;
+       NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
        memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
        /* What can I do? Netlink is asynchronous, so that
@@ -1088,8 +1095,7 @@ static int netlink_dump(struct sock *sk)
                return 0;
        }
 
-       nlh = __nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLMSG_DONE, sizeof(int));
-       nlh->nlmsg_flags |= NLM_F_MULTI;
+       nlh = NLMSG_NEW_ANSWER(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
        memcpy(NLMSG_DATA(nlh), &len, sizeof(len));
        skb_queue_tail(&sk->sk_receive_queue, skb);
        sk->sk_data_ready(sk, skb->len);
@@ -1099,8 +1105,10 @@ static int netlink_dump(struct sock *sk)
        spin_unlock(&nlk->cb_lock);
 
        netlink_destroy_callback(cb);
-       __sock_put(sk);
        return 0;
+
+nlmsg_failure:
+       return -ENOBUFS;
 }
 
 int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
@@ -1138,7 +1146,6 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
                return -EBUSY;
        }
        nlk->cb = cb;
-       sock_hold(sk);
        spin_unlock(&nlk->cb_lock);
 
        netlink_dump(sk);
@@ -1173,7 +1180,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
        }
 
        rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
-                         NLMSG_ERROR, sizeof(struct nlmsgerr));
+                         NLMSG_ERROR, sizeof(struct nlmsgerr), 0);
        errmsg = NLMSG_DATA(rep);
        errmsg->error = err;
        memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr));