Merge commit 'jwb/next' into next
[linux-drm-fsl-dcu.git] / net / netlink / af_netlink.c
index 6464a1972a69dc649099fbd05a7ca5d56708b790..a2eb965207d339682728b5dd5a52104a8d4f848b 100644 (file)
@@ -978,6 +978,8 @@ struct netlink_broadcast_data {
        int delivered;
        gfp_t allocation;
        struct sk_buff *skb, *skb2;
+       int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data);
+       void *tx_data;
 };
 
 static inline int do_one_broadcast(struct sock *sk,
@@ -1020,6 +1022,9 @@ static inline int do_one_broadcast(struct sock *sk,
                p->failure = 1;
                if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
                        p->delivery_failure = 1;
+       } else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) {
+               kfree_skb(p->skb2);
+               p->skb2 = NULL;
        } else if (sk_filter(sk, p->skb2)) {
                kfree_skb(p->skb2);
                p->skb2 = NULL;
@@ -1038,8 +1043,10 @@ out:
        return 0;
 }
 
-int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
-                     u32 group, gfp_t allocation)
+int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid,
+       u32 group, gfp_t allocation,
+       int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
+       void *filter_data)
 {
        struct net *net = sock_net(ssk);
        struct netlink_broadcast_data info;
@@ -1059,6 +1066,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
        info.allocation = allocation;
        info.skb = skb;
        info.skb2 = NULL;
+       info.tx_filter = filter;
+       info.tx_data = filter_data;
 
        /* While we sleep in clone, do not allow to change socket list */
 
@@ -1083,6 +1092,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
        }
        return -ESRCH;
 }
+EXPORT_SYMBOL(netlink_broadcast_filtered);
+
+int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
+                     u32 group, gfp_t allocation)
+{
+       return netlink_broadcast_filtered(ssk, skb, pid, group, allocation,
+               NULL, NULL);
+}
 EXPORT_SYMBOL(netlink_broadcast);
 
 struct netlink_set_err_data {