--- 2.4.0-zc/net/netlink/af_netlink.c Mon Jan 15 11:02:14 2001 +++ 2.4.0-vlan/net/netlink/af_netlink.c Tue Jan 16 17:22:21 2001 @@ -456,6 +456,10 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) { +struct sk_buff *skb2; +unsigned long flags; +unsigned int len = skb->len; + #ifdef NL_EMULATE_DEV if (sk->protinfo.af_netlink->handler) { skb_orphan(skb); @@ -463,15 +467,48 @@ return 0; } else #endif - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf && - !test_bit(0, &sk->protinfo.af_netlink->state)) { - skb_orphan(skb); + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + test_bit(0, &sk->protinfo.af_netlink->state)) + return -1; + + skb_orphan(skb); + spin_lock_irqsave(&(sk->receive_queue.lock), flags); + skb2 = skb_peek_tail (&sk->receive_queue); + + if (skb2 == NULL) { +notailroom: skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, skb->len); - return 0; + __skb_queue_tail(&sk->receive_queue, skb); + spin_unlock_irqrestore(&(sk->receive_queue.lock), flags); + } else { + struct nlmsghdr *h = (struct nlmsghdr *)skb->data, + *h2 = (struct nlmsghdr *)skb2->data, *nlh; + unsigned int tailroomreq = len; + + if ( !(h2->nlmsg_flags & NLM_F_MULTI) ) + tailroomreq += NLMSG_ALIGN(NLMSG_LENGTH(sizeof(int))); + + if (skb_tailroom (skb2) < tailroomreq) + goto notailroom; + + if ( h2->nlmsg_flags & NLM_F_MULTI ) + skb_trim (skb2, skb2->len - + NLMSG_ALIGN(NLMSG_LENGTH(sizeof(int)))); + + h2->nlmsg_flags |= NLM_F_MULTI; + h->nlmsg_flags |= NLM_F_MULTI; + + memcpy(skb_put(skb2, skb->len), skb->data, skb->len); + nlh = __nlmsg_put(skb2, NETLINK_CB(skb).pid, + h2->nlmsg_seq, NLMSG_DONE, sizeof (int)); + nlh->nlmsg_flags |= NLM_F_MULTI; + memcpy(NLMSG_DATA(nlh), &(skb2->len), sizeof(int)); + + spin_unlock_irqrestore(&(sk->receive_queue.lock), flags); + kfree_skb (skb); } - return -1; + sk->data_ready(sk, len); + return 0; } void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,