aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2005-08-15 15:29:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 19:01:02 -0400
commitf7fa9b10edbb9391bdd4ec8e8b3d621d0664b198 (patch)
tree5b4b3a6b96b0ede7030915996e63f3858ed72a7b
parentab33a1711cf60bfb562b1ab89ac9f23d1425e8b1 (diff)
[NETLINK]: Support dynamic number of multicast groups per netlink family
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/netlink/af_netlink.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 444ed223ee43..58d4ca42ac32 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -60,21 +60,24 @@
60#include <net/scm.h> 60#include <net/scm.h>
61 61
62#define Nprintk(a...) 62#define Nprintk(a...)
63#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
63 64
64struct netlink_sock { 65struct netlink_sock {
65 /* struct sock has to be the first member of netlink_sock */ 66 /* struct sock has to be the first member of netlink_sock */
66 struct sock sk; 67 struct sock sk;
67 u32 pid; 68 u32 pid;
68 unsigned int groups;
69 u32 dst_pid; 69 u32 dst_pid;
70 u32 dst_group; 70 u32 dst_group;
71 u32 flags;
72 u32 subscriptions;
73 u32 ngroups;
74 unsigned long *groups;
71 unsigned long state; 75 unsigned long state;
72 wait_queue_head_t wait; 76 wait_queue_head_t wait;
73 struct netlink_callback *cb; 77 struct netlink_callback *cb;
74 spinlock_t cb_lock; 78 spinlock_t cb_lock;
75 void (*data_ready)(struct sock *sk, int bytes); 79 void (*data_ready)(struct sock *sk, int bytes);
76 struct module *module; 80 struct module *module;
77 u32 flags;
78}; 81};
79 82
80#define NETLINK_KERNEL_SOCKET 0x1 83#define NETLINK_KERNEL_SOCKET 0x1
@@ -101,6 +104,7 @@ struct netlink_table {
101 struct nl_pid_hash hash; 104 struct nl_pid_hash hash;
102 struct hlist_head mc_list; 105 struct hlist_head mc_list;
103 unsigned int nl_nonroot; 106 unsigned int nl_nonroot;
107 unsigned int groups;
104 struct module *module; 108 struct module *module;
105 int registered; 109 int registered;
106}; 110};
@@ -138,6 +142,7 @@ static void netlink_sock_destruct(struct sock *sk)
138 BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); 142 BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
139 BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); 143 BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
140 BUG_TRAP(!nlk_sk(sk)->cb); 144 BUG_TRAP(!nlk_sk(sk)->cb);
145 BUG_TRAP(!nlk_sk(sk)->groups);
141} 146}
142 147
143/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. 148/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP.
@@ -333,7 +338,7 @@ static void netlink_remove(struct sock *sk)
333 netlink_table_grab(); 338 netlink_table_grab();
334 if (sk_del_node_init(sk)) 339 if (sk_del_node_init(sk))
335 nl_table[sk->sk_protocol].hash.entries--; 340 nl_table[sk->sk_protocol].hash.entries--;
336 if (nlk_sk(sk)->groups) 341 if (nlk_sk(sk)->subscriptions)
337 __sk_del_bind_node(sk); 342 __sk_del_bind_node(sk);
338 netlink_table_ungrab(); 343 netlink_table_ungrab();
339} 344}
@@ -369,6 +374,8 @@ static int __netlink_create(struct socket *sock, int protocol)
369static int netlink_create(struct socket *sock, int protocol) 374static int netlink_create(struct socket *sock, int protocol)
370{ 375{
371 struct module *module = NULL; 376 struct module *module = NULL;
377 struct netlink_sock *nlk;
378 unsigned int groups;
372 int err = 0; 379 int err = 0;
373 380
374 sock->state = SS_UNCONNECTED; 381 sock->state = SS_UNCONNECTED;
@@ -392,15 +399,23 @@ static int netlink_create(struct socket *sock, int protocol)
392 module = nl_table[protocol].module; 399 module = nl_table[protocol].module;
393 else 400 else
394 err = -EPROTONOSUPPORT; 401 err = -EPROTONOSUPPORT;
402 groups = nl_table[protocol].groups;
395 netlink_unlock_table(); 403 netlink_unlock_table();
396 404
397 if (err) 405 if (err || (err = __netlink_create(sock, protocol) < 0))
398 goto out; 406 goto out_module;
407
408 nlk = nlk_sk(sock->sk);
399 409
400 if ((err = __netlink_create(sock, protocol) < 0)) 410 nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL);
411 if (nlk->groups == NULL) {
412 err = -ENOMEM;
401 goto out_module; 413 goto out_module;
414 }
415 memset(nlk->groups, 0, NLGRPSZ(groups));
416 nlk->ngroups = groups;
402 417
403 nlk_sk(sock->sk)->module = module; 418 nlk->module = module;
404out: 419out:
405 return err; 420 return err;
406 421
@@ -437,7 +452,7 @@ static int netlink_release(struct socket *sock)
437 452
438 skb_queue_purge(&sk->sk_write_queue); 453 skb_queue_purge(&sk->sk_write_queue);
439 454
440 if (nlk->pid && !nlk->groups) { 455 if (nlk->pid && !nlk->subscriptions) {
441 struct netlink_notify n = { 456 struct netlink_notify n = {
442 .protocol = sk->sk_protocol, 457 .protocol = sk->sk_protocol,
443 .pid = nlk->pid, 458 .pid = nlk->pid,
@@ -455,6 +470,9 @@ static int netlink_release(struct socket *sock)
455 netlink_table_ungrab(); 470 netlink_table_ungrab();
456 } 471 }
457 472
473 kfree(nlk->groups);
474 nlk->groups = NULL;
475
458 sock_put(sk); 476 sock_put(sk);
459 return 0; 477 return 0;
460} 478}
@@ -503,6 +521,18 @@ static inline int netlink_capable(struct socket *sock, unsigned int flag)
503 capable(CAP_NET_ADMIN); 521 capable(CAP_NET_ADMIN);
504} 522}
505 523
524static void
525netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
526{
527 struct netlink_sock *nlk = nlk_sk(sk);
528
529 if (nlk->subscriptions && !subscriptions)
530 __sk_del_bind_node(sk);
531 else if (!nlk->subscriptions && subscriptions)
532 sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list);
533 nlk->subscriptions = subscriptions;
534}
535
506static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 536static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
507{ 537{
508 struct sock *sk = sock->sk; 538 struct sock *sk = sock->sk;
@@ -528,15 +558,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
528 return err; 558 return err;
529 } 559 }
530 560
531 if (!nladdr->nl_groups && !nlk->groups) 561 if (!nladdr->nl_groups && !(u32)nlk->groups[0])
532 return 0; 562 return 0;
533 563
534 netlink_table_grab(); 564 netlink_table_grab();
535 if (nlk->groups && !nladdr->nl_groups) 565 netlink_update_subscriptions(sk, nlk->subscriptions +
536 __sk_del_bind_node(sk); 566 hweight32(nladdr->nl_groups) -
537 else if (!nlk->groups && nladdr->nl_groups) 567 hweight32(nlk->groups[0]));
538 sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); 568 nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups;
539 nlk->groups = nladdr->nl_groups;
540 netlink_table_ungrab(); 569 netlink_table_ungrab();
541 570
542 return 0; 571 return 0;
@@ -590,7 +619,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr
590 nladdr->nl_groups = netlink_group_mask(nlk->dst_group); 619 nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
591 } else { 620 } else {
592 nladdr->nl_pid = nlk->pid; 621 nladdr->nl_pid = nlk->pid;
593 nladdr->nl_groups = nlk->groups; 622 nladdr->nl_groups = nlk->groups[0];
594 } 623 }
595 return 0; 624 return 0;
596} 625}
@@ -791,7 +820,8 @@ static inline int do_one_broadcast(struct sock *sk,
791 if (p->exclude_sk == sk) 820 if (p->exclude_sk == sk)
792 goto out; 821 goto out;
793 822
794 if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) 823 if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||
824 !test_bit(p->group - 1, nlk->groups))
795 goto out; 825 goto out;
796 826
797 if (p->failure) { 827 if (p->failure) {
@@ -887,7 +917,8 @@ static inline int do_one_set_err(struct sock *sk,
887 if (sk == p->exclude_sk) 917 if (sk == p->exclude_sk)
888 goto out; 918 goto out;
889 919
890 if (nlk->pid == p->pid || !(nlk->groups & netlink_group_mask(p->group))) 920 if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||
921 !test_bit(p->group - 1, nlk->groups))
891 goto out; 922 goto out;
892 923
893 sk->sk_err = p->code; 924 sk->sk_err = p->code;
@@ -1112,6 +1143,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct
1112 nlk->flags |= NETLINK_KERNEL_SOCKET; 1143 nlk->flags |= NETLINK_KERNEL_SOCKET;
1113 1144
1114 netlink_table_grab(); 1145 netlink_table_grab();
1146 nl_table[unit].groups = 32;
1115 nl_table[unit].module = module; 1147 nl_table[unit].module = module;
1116 nl_table[unit].registered = 1; 1148 nl_table[unit].registered = 1;
1117 netlink_table_ungrab(); 1149 netlink_table_ungrab();
@@ -1358,7 +1390,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
1358 s, 1390 s,
1359 s->sk_protocol, 1391 s->sk_protocol,
1360 nlk->pid, 1392 nlk->pid,
1361 nlk->groups, 1393 nlk->flags & NETLINK_KERNEL_SOCKET ?
1394 0 : (unsigned int)nlk->groups[0],
1362 atomic_read(&s->sk_rmem_alloc), 1395 atomic_read(&s->sk_rmem_alloc),
1363 atomic_read(&s->sk_wmem_alloc), 1396 atomic_read(&s->sk_wmem_alloc),
1364 nlk->cb, 1397 nlk->cb,