Skip to content

Commit

Permalink
netlink: Implment netlink_broadcast_filtered
Browse files Browse the repository at this point in the history
When netlink sockets are used to convey data that is in a namespace
we need a way to select a subset of the listening sockets to deliver
the packet to.  For the network namespace we have been doing this
by only transmitting packets in the correct network namespace.

For data belonging to other namespaces netlink_bradcast_filtered
provides a mechanism that allows us to examine the destination
socket and to decide if we should transmit the specified packet
to it.

Signed-off-by: Eric W. Biederman <[email protected]>
Acked-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
ebiederm authored and gregkh committed May 21, 2010
1 parent d6523dd commit 910a7e9
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
4 changes: 4 additions & 0 deletions include/linux/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 19 additions & 2 deletions net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -1038,8 +1043,10 @@ static inline int do_one_broadcast(struct sock *sk,
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;
Expand All @@ -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 */

Expand All @@ -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 {
Expand Down

0 comments on commit 910a7e9

Please sign in to comment.