aboutsummaryrefslogtreecommitdiff
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 733bf52cef3..70bcd4744d9 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -735,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) {
@@ -785,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))
@@ -1090,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);
@@ -1102,6 +1106,9 @@ static int netlink_dump(struct sock *sk)
netlink_destroy_callback(cb);
return 0;
+
+nlmsg_failure:
+ return -ENOBUFS;
}
int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
@@ -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));