Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 22178
b: refs/heads/master
c: 4277a08
h: refs/heads/master
v: v3
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Mar 21, 2006
1 parent 4d6ced6 commit 75f4d8f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a24276924875802853b5bdc12c56d29f1c1bbc79
refs/heads/master: 4277a083ecd2c8771058641132bcecea04ca6608
1 change: 1 addition & 0 deletions trunk/include/linux/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct netlink_skb_parms

extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
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);
Expand Down
52 changes: 48 additions & 4 deletions trunk/net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct nl_pid_hash {
struct netlink_table {
struct nl_pid_hash hash;
struct hlist_head mc_list;
unsigned long *listeners;
unsigned int nl_nonroot;
unsigned int groups;
struct module *module;
Expand Down Expand Up @@ -296,6 +297,24 @@ static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len)

static const struct proto_ops netlink_ops;

static void
netlink_update_listeners(struct sock *sk)
{
struct netlink_table *tbl = &nl_table[sk->sk_protocol];
struct hlist_node *node;
unsigned long mask;
unsigned int i;

for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
mask = 0;
sk_for_each_bound(sk, node, &tbl->mc_list)
mask |= nlk_sk(sk)->groups[i];
tbl->listeners[i] = mask;
}
/* this function is only called with the netlink table "grabbed", which
* makes sure updates are visible before bind or setsockopt return. */
}

static int netlink_insert(struct sock *sk, u32 pid)
{
struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash;
Expand Down Expand Up @@ -456,12 +475,14 @@ static int netlink_release(struct socket *sock)
if (nlk->module)
module_put(nlk->module);

netlink_table_grab();
if (nlk->flags & NETLINK_KERNEL_SOCKET) {
netlink_table_grab();
kfree(nl_table[sk->sk_protocol].listeners);
nl_table[sk->sk_protocol].module = NULL;
nl_table[sk->sk_protocol].registered = 0;
netlink_table_ungrab();
}
} else if (nlk->subscriptions)
netlink_update_listeners(sk);
netlink_table_ungrab();

kfree(nlk->groups);
nlk->groups = NULL;
Expand Down Expand Up @@ -589,6 +610,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
hweight32(nladdr->nl_groups) -
hweight32(nlk->groups[0]));
nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups;
netlink_update_listeners(sk);
netlink_table_ungrab();

return 0;
Expand Down Expand Up @@ -807,6 +829,17 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock
return netlink_sendskb(sk, skb, ssk->sk_protocol);
}

int netlink_has_listeners(struct sock *sk, unsigned int group)
{
int res = 0;

BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
if (group - 1 < nl_table[sk->sk_protocol].groups)
res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
return res;
}
EXPORT_SYMBOL_GPL(netlink_has_listeners);

static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
{
struct netlink_sock *nlk = nlk_sk(sk);
Expand Down Expand Up @@ -1011,6 +1044,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
else
__clear_bit(val - 1, nlk->groups);
netlink_update_subscriptions(sk, subscriptions);
netlink_update_listeners(sk);
netlink_table_ungrab();
err = 0;
break;
Expand Down Expand Up @@ -1237,6 +1271,7 @@ netlink_kernel_create(int unit, unsigned int groups,
struct socket *sock;
struct sock *sk;
struct netlink_sock *nlk;
unsigned long *listeners = NULL;

if (!nl_table)
return NULL;
Expand All @@ -1250,6 +1285,13 @@ netlink_kernel_create(int unit, unsigned int groups,
if (__netlink_create(sock, unit) < 0)
goto out_sock_release;

if (groups < 32)
groups = 32;

listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
if (!listeners)
goto out_sock_release;

sk = sock->sk;
sk->sk_data_ready = netlink_data_ready;
if (input)
Expand All @@ -1262,14 +1304,16 @@ netlink_kernel_create(int unit, unsigned int groups,
nlk->flags |= NETLINK_KERNEL_SOCKET;

netlink_table_grab();
nl_table[unit].groups = groups < 32 ? 32 : groups;
nl_table[unit].groups = groups;
nl_table[unit].listeners = listeners;
nl_table[unit].module = module;
nl_table[unit].registered = 1;
netlink_table_ungrab();

return sk;

out_sock_release:
kfree(listeners);
sock_release(sock);
return NULL;
}
Expand Down

0 comments on commit 75f4d8f

Please sign in to comment.