aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netlink.h1
-rw-r--r--net/netlink/af_netlink.c52
2 files changed, 49 insertions, 4 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index c256ebe2a7b4..f8f3d1c927f8 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -151,6 +151,7 @@ struct netlink_skb_parms
151 151
152extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module); 152extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
153extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); 153extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
154extern int netlink_has_listeners(struct sock *sk, unsigned int group);
154extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); 155extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
155extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, 156extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
156 __u32 group, gfp_t allocation); 157 __u32 group, gfp_t allocation);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 59dc7d140600..d00a9034cb5f 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -106,6 +106,7 @@ struct nl_pid_hash {
106struct netlink_table { 106struct netlink_table {
107 struct nl_pid_hash hash; 107 struct nl_pid_hash hash;
108 struct hlist_head mc_list; 108 struct hlist_head mc_list;
109 unsigned long *listeners;
109 unsigned int nl_nonroot; 110 unsigned int nl_nonroot;
110 unsigned int groups; 111 unsigned int groups;
111 struct module *module; 112 struct module *module;
@@ -296,6 +297,24 @@ static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len)
296 297
297static const struct proto_ops netlink_ops; 298static const struct proto_ops netlink_ops;
298 299
300static void
301netlink_update_listeners(struct sock *sk)
302{
303 struct netlink_table *tbl = &nl_table[sk->sk_protocol];
304 struct hlist_node *node;
305 unsigned long mask;
306 unsigned int i;
307
308 for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
309 mask = 0;
310 sk_for_each_bound(sk, node, &tbl->mc_list)
311 mask |= nlk_sk(sk)->groups[i];
312 tbl->listeners[i] = mask;
313 }
314 /* this function is only called with the netlink table "grabbed", which
315 * makes sure updates are visible before bind or setsockopt return. */
316}
317
299static int netlink_insert(struct sock *sk, u32 pid) 318static int netlink_insert(struct sock *sk, u32 pid)
300{ 319{
301 struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; 320 struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash;
@@ -456,12 +475,14 @@ static int netlink_release(struct socket *sock)
456 if (nlk->module) 475 if (nlk->module)
457 module_put(nlk->module); 476 module_put(nlk->module);
458 477
478 netlink_table_grab();
459 if (nlk->flags & NETLINK_KERNEL_SOCKET) { 479 if (nlk->flags & NETLINK_KERNEL_SOCKET) {
460 netlink_table_grab(); 480 kfree(nl_table[sk->sk_protocol].listeners);
461 nl_table[sk->sk_protocol].module = NULL; 481 nl_table[sk->sk_protocol].module = NULL;
462 nl_table[sk->sk_protocol].registered = 0; 482 nl_table[sk->sk_protocol].registered = 0;
463 netlink_table_ungrab(); 483 } else if (nlk->subscriptions)
464 } 484 netlink_update_listeners(sk);
485 netlink_table_ungrab();
465 486
466 kfree(nlk->groups); 487 kfree(nlk->groups);
467 nlk->groups = NULL; 488 nlk->groups = NULL;
@@ -589,6 +610,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
589 hweight32(nladdr->nl_groups) - 610 hweight32(nladdr->nl_groups) -
590 hweight32(nlk->groups[0])); 611 hweight32(nlk->groups[0]));
591 nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; 612 nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups;
613 netlink_update_listeners(sk);
592 netlink_table_ungrab(); 614 netlink_table_ungrab();
593 615
594 return 0; 616 return 0;
@@ -807,6 +829,17 @@ retry:
807 return netlink_sendskb(sk, skb, ssk->sk_protocol); 829 return netlink_sendskb(sk, skb, ssk->sk_protocol);
808} 830}
809 831
832int netlink_has_listeners(struct sock *sk, unsigned int group)
833{
834 int res = 0;
835
836 BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
837 if (group - 1 < nl_table[sk->sk_protocol].groups)
838 res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
839 return res;
840}
841EXPORT_SYMBOL_GPL(netlink_has_listeners);
842
810static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) 843static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
811{ 844{
812 struct netlink_sock *nlk = nlk_sk(sk); 845 struct netlink_sock *nlk = nlk_sk(sk);
@@ -1011,6 +1044,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1011 else 1044 else
1012 __clear_bit(val - 1, nlk->groups); 1045 __clear_bit(val - 1, nlk->groups);
1013 netlink_update_subscriptions(sk, subscriptions); 1046 netlink_update_subscriptions(sk, subscriptions);
1047 netlink_update_listeners(sk);
1014 netlink_table_ungrab(); 1048 netlink_table_ungrab();
1015 err = 0; 1049 err = 0;
1016 break; 1050 break;
@@ -1237,6 +1271,7 @@ netlink_kernel_create(int unit, unsigned int groups,
1237 struct socket *sock; 1271 struct socket *sock;
1238 struct sock *sk; 1272 struct sock *sk;
1239 struct netlink_sock *nlk; 1273 struct netlink_sock *nlk;
1274 unsigned long *listeners = NULL;
1240 1275
1241 if (!nl_table) 1276 if (!nl_table)
1242 return NULL; 1277 return NULL;
@@ -1250,6 +1285,13 @@ netlink_kernel_create(int unit, unsigned int groups,
1250 if (__netlink_create(sock, unit) < 0) 1285 if (__netlink_create(sock, unit) < 0)
1251 goto out_sock_release; 1286 goto out_sock_release;
1252 1287
1288 if (groups < 32)
1289 groups = 32;
1290
1291 listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
1292 if (!listeners)
1293 goto out_sock_release;
1294
1253 sk = sock->sk; 1295 sk = sock->sk;
1254 sk->sk_data_ready = netlink_data_ready; 1296 sk->sk_data_ready = netlink_data_ready;
1255 if (input) 1297 if (input)
@@ -1262,7 +1304,8 @@ netlink_kernel_create(int unit, unsigned int groups,
1262 nlk->flags |= NETLINK_KERNEL_SOCKET; 1304 nlk->flags |= NETLINK_KERNEL_SOCKET;
1263 1305
1264 netlink_table_grab(); 1306 netlink_table_grab();
1265 nl_table[unit].groups = groups < 32 ? 32 : groups; 1307 nl_table[unit].groups = groups;
1308 nl_table[unit].listeners = listeners;
1266 nl_table[unit].module = module; 1309 nl_table[unit].module = module;
1267 nl_table[unit].registered = 1; 1310 nl_table[unit].registered = 1;
1268 netlink_table_ungrab(); 1311 netlink_table_ungrab();
@@ -1270,6 +1313,7 @@ netlink_kernel_create(int unit, unsigned int groups,
1270 return sk; 1313 return sk;
1271 1314
1272out_sock_release: 1315out_sock_release:
1316 kfree(listeners);
1273 sock_release(sock); 1317 sock_release(sock);
1274 return NULL; 1318 return NULL;
1275} 1319}