X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fnetlink%2Faf_netlink.c;h=70bcd4744d9370e44f0389f28754df5aaaa3bee6;hb=aef7b83c92dd0b7e994805440655d1d64147287b;hp=733bf52cef3e72c663a9f4bc7f90cecab421c706;hpb=bfd4bda097f8758d28e632ff2035e25577f6b060;p=linux-2.6 diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 733bf52cef..70bcd4744d 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));