diff options
| -rw-r--r-- | include/linux/netlink.h | 4 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 21 | 
2 files changed, 23 insertions, 2 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 6eaca5e1e8c..59d066936ab 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -188,6 +188,10 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group);  extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);  extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,  			     __u32 group, gfp_t allocation); +extern 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);  extern int netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);  extern int netlink_register_notifier(struct notifier_block *nb);  extern int netlink_unregister_notifier(struct notifier_block *nb); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 6464a1972a6..a2eb965207d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -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 {  |