aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 59dc7d140600..2a233ffcf618 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;
@@ -122,7 +123,7 @@ static void netlink_destroy_callback(struct netlink_callback *cb);
122static DEFINE_RWLOCK(nl_table_lock); 123static DEFINE_RWLOCK(nl_table_lock);
123static atomic_t nl_table_users = ATOMIC_INIT(0); 124static atomic_t nl_table_users = ATOMIC_INIT(0);
124 125
125static struct notifier_block *netlink_chain; 126static ATOMIC_NOTIFIER_HEAD(netlink_chain);
126 127
127static u32 netlink_group_mask(u32 group) 128static u32 netlink_group_mask(u32 group)
128{ 129{
@@ -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;
@@ -450,18 +469,21 @@ static int netlink_release(struct socket *sock)
450 .protocol = sk->sk_protocol, 469 .protocol = sk->sk_protocol,
451 .pid = nlk->pid, 470 .pid = nlk->pid,
452 }; 471 };
453 notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); 472 atomic_notifier_call_chain(&netlink_chain,
473 NETLINK_URELEASE, &n);
454 } 474 }
455 475
456 if (nlk->module) 476 if (nlk->module)
457 module_put(nlk->module); 477 module_put(nlk->module);
458 478
479 netlink_table_grab();
459 if (nlk->flags & NETLINK_KERNEL_SOCKET) { 480 if (nlk->flags & NETLINK_KERNEL_SOCKET) {
460 netlink_table_grab(); 481 kfree(nl_table[sk->sk_protocol].listeners);
461 nl_table[sk->sk_protocol].module = NULL; 482 nl_table[sk->sk_protocol].module = NULL;
462 nl_table[sk->sk_protocol].registered = 0; 483 nl_table[sk->sk_protocol].registered = 0;
463 netlink_table_ungrab(); 484 } else if (nlk->subscriptions)
464 } 485 netlink_update_listeners(sk);
486 netlink_table_ungrab();
465 487
466 kfree(nlk->groups); 488 kfree(nlk->groups);
467 nlk->groups = NULL; 489 nlk->groups = NULL;
@@ -589,6 +611,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
589 hweight32(nladdr->nl_groups) - 611 hweight32(nladdr->nl_groups) -
590 hweight32(nlk->groups[0])); 612 hweight32(nlk->groups[0]));
591 nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; 613 nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups;
614 netlink_update_listeners(sk);
592 netlink_table_ungrab(); 615 netlink_table_ungrab();
593 616
594 return 0; 617 return 0;
@@ -807,6 +830,17 @@ retry:
807 return netlink_sendskb(sk, skb, ssk->sk_protocol); 830 return netlink_sendskb(sk, skb, ssk->sk_protocol);
808} 831}
809 832
833int netlink_has_listeners(struct sock *sk, unsigned int group)
834{
835 int res = 0;
836
837 BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
838 if (group - 1 < nl_table[sk->sk_protocol].groups)
839 res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
840 return res;
841}
842EXPORT_SYMBOL_GPL(netlink_has_listeners);
843
810static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) 844static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
811{ 845{
812 struct netlink_sock *nlk = nlk_sk(sk); 846 struct netlink_sock *nlk = nlk_sk(sk);
@@ -1011,6 +1045,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1011 else 1045 else
1012 __clear_bit(val - 1, nlk->groups); 1046 __clear_bit(val - 1, nlk->groups);
1013 netlink_update_subscriptions(sk, subscriptions); 1047 netlink_update_subscriptions(sk, subscriptions);
1048 netlink_update_listeners(sk);
1014 netlink_table_ungrab(); 1049 netlink_table_ungrab();
1015 err = 0; 1050 err = 0;
1016 break; 1051 break;
@@ -1237,6 +1272,7 @@ netlink_kernel_create(int unit, unsigned int groups,
1237 struct socket *sock; 1272 struct socket *sock;
1238 struct sock *sk; 1273 struct sock *sk;
1239 struct netlink_sock *nlk; 1274 struct netlink_sock *nlk;
1275 unsigned long *listeners = NULL;
1240 1276
1241 if (!nl_table) 1277 if (!nl_table)
1242 return NULL; 1278 return NULL;
@@ -1250,6 +1286,13 @@ netlink_kernel_create(int unit, unsigned int groups,
1250 if (__netlink_create(sock, unit) < 0) 1286 if (__netlink_create(sock, unit) < 0)
1251 goto out_sock_release; 1287 goto out_sock_release;
1252 1288
1289 if (groups < 32)
1290 groups = 32;
1291
1292 listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
1293 if (!listeners)
1294 goto out_sock_release;
1295
1253 sk = sock->sk; 1296 sk = sock->sk;
1254 sk->sk_data_ready = netlink_data_ready; 1297 sk->sk_data_ready = netlink_data_ready;
1255 if (input) 1298 if (input)
@@ -1262,7 +1305,8 @@ netlink_kernel_create(int unit, unsigned int groups,
1262 nlk->flags |= NETLINK_KERNEL_SOCKET; 1305 nlk->flags |= NETLINK_KERNEL_SOCKET;
1263 1306
1264 netlink_table_grab(); 1307 netlink_table_grab();
1265 nl_table[unit].groups = groups < 32 ? 32 : groups; 1308 nl_table[unit].groups = groups;
1309 nl_table[unit].listeners = listeners;
1266 nl_table[unit].module = module; 1310 nl_table[unit].module = module;
1267 nl_table[unit].registered = 1; 1311 nl_table[unit].registered = 1;
1268 netlink_table_ungrab(); 1312 netlink_table_ungrab();
@@ -1270,6 +1314,7 @@ netlink_kernel_create(int unit, unsigned int groups,
1270 return sk; 1314 return sk;
1271 1315
1272out_sock_release: 1316out_sock_release:
1317 kfree(listeners);
1273 sock_release(sock); 1318 sock_release(sock);
1274 return NULL; 1319 return NULL;
1275} 1320}
@@ -1651,12 +1696,12 @@ static struct file_operations netlink_seq_fops = {
1651 1696
1652int netlink_register_notifier(struct notifier_block *nb) 1697int netlink_register_notifier(struct notifier_block *nb)
1653{ 1698{
1654 return notifier_chain_register(&netlink_chain, nb); 1699 return atomic_notifier_chain_register(&netlink_chain, nb);
1655} 1700}
1656 1701
1657int netlink_unregister_notifier(struct notifier_block *nb) 1702int netlink_unregister_notifier(struct notifier_block *nb)
1658{ 1703{
1659 return notifier_chain_unregister(&netlink_chain, nb); 1704 return atomic_notifier_chain_unregister(&netlink_chain, nb);
1660} 1705}
1661 1706
1662static const struct proto_ops netlink_ops = { 1707static const struct proto_ops netlink_ops = {