Commit f7fa9b10edbb9391bdd4ec8e8b3d621d0664b198
Committed by
David S. Miller
1 parent
ab33a1711c
Exists in
master
and in
7 other branches
[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>
Showing 1 changed file with 51 additions and 18 deletions Side-by-side Diff
net/netlink/af_netlink.c
... | ... | @@ -60,21 +60,24 @@ |
60 | 60 | #include <net/scm.h> |
61 | 61 | |
62 | 62 | #define Nprintk(a...) |
63 | +#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | |
63 | 64 | |
64 | 65 | struct netlink_sock { |
65 | 66 | /* struct sock has to be the first member of netlink_sock */ |
66 | 67 | struct sock sk; |
67 | 68 | u32 pid; |
68 | - unsigned int groups; | |
69 | 69 | u32 dst_pid; |
70 | 70 | u32 dst_group; |
71 | + u32 flags; | |
72 | + u32 subscriptions; | |
73 | + u32 ngroups; | |
74 | + unsigned long *groups; | |
71 | 75 | unsigned long state; |
72 | 76 | wait_queue_head_t wait; |
73 | 77 | struct netlink_callback *cb; |
74 | 78 | spinlock_t cb_lock; |
75 | 79 | void (*data_ready)(struct sock *sk, int bytes); |
76 | 80 | struct module *module; |
77 | - u32 flags; | |
78 | 81 | }; |
79 | 82 | |
80 | 83 | #define NETLINK_KERNEL_SOCKET 0x1 |
... | ... | @@ -101,6 +104,7 @@ |
101 | 104 | struct nl_pid_hash hash; |
102 | 105 | struct hlist_head mc_list; |
103 | 106 | unsigned int nl_nonroot; |
107 | + unsigned int groups; | |
104 | 108 | struct module *module; |
105 | 109 | int registered; |
106 | 110 | }; |
... | ... | @@ -138,6 +142,7 @@ |
138 | 142 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); |
139 | 143 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); |
140 | 144 | BUG_TRAP(!nlk_sk(sk)->cb); |
145 | + BUG_TRAP(!nlk_sk(sk)->groups); | |
141 | 146 | } |
142 | 147 | |
143 | 148 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. |
... | ... | @@ -333,7 +338,7 @@ |
333 | 338 | netlink_table_grab(); |
334 | 339 | if (sk_del_node_init(sk)) |
335 | 340 | nl_table[sk->sk_protocol].hash.entries--; |
336 | - if (nlk_sk(sk)->groups) | |
341 | + if (nlk_sk(sk)->subscriptions) | |
337 | 342 | __sk_del_bind_node(sk); |
338 | 343 | netlink_table_ungrab(); |
339 | 344 | } |
... | ... | @@ -369,6 +374,8 @@ |
369 | 374 | static int netlink_create(struct socket *sock, int protocol) |
370 | 375 | { |
371 | 376 | struct module *module = NULL; |
377 | + struct netlink_sock *nlk; | |
378 | + unsigned int groups; | |
372 | 379 | int err = 0; |
373 | 380 | |
374 | 381 | sock->state = SS_UNCONNECTED; |
375 | 382 | |
376 | 383 | |
377 | 384 | |
378 | 385 | |
... | ... | @@ -392,15 +399,23 @@ |
392 | 399 | module = nl_table[protocol].module; |
393 | 400 | else |
394 | 401 | err = -EPROTONOSUPPORT; |
402 | + groups = nl_table[protocol].groups; | |
395 | 403 | netlink_unlock_table(); |
396 | 404 | |
397 | - if (err) | |
398 | - goto out; | |
405 | + if (err || (err = __netlink_create(sock, protocol) < 0)) | |
406 | + goto out_module; | |
399 | 407 | |
400 | - if ((err = __netlink_create(sock, protocol) < 0)) | |
408 | + nlk = nlk_sk(sock->sk); | |
409 | + | |
410 | + nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | |
411 | + if (nlk->groups == NULL) { | |
412 | + err = -ENOMEM; | |
401 | 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; | |
404 | 419 | out: |
405 | 420 | return err; |
406 | 421 | |
... | ... | @@ -437,7 +452,7 @@ |
437 | 452 | |
438 | 453 | skb_queue_purge(&sk->sk_write_queue); |
439 | 454 | |
440 | - if (nlk->pid && !nlk->groups) { | |
455 | + if (nlk->pid && !nlk->subscriptions) { | |
441 | 456 | struct netlink_notify n = { |
442 | 457 | .protocol = sk->sk_protocol, |
443 | 458 | .pid = nlk->pid, |
... | ... | @@ -455,6 +470,9 @@ |
455 | 470 | netlink_table_ungrab(); |
456 | 471 | } |
457 | 472 | |
473 | + kfree(nlk->groups); | |
474 | + nlk->groups = NULL; | |
475 | + | |
458 | 476 | sock_put(sk); |
459 | 477 | return 0; |
460 | 478 | } |
... | ... | @@ -503,6 +521,18 @@ |
503 | 521 | capable(CAP_NET_ADMIN); |
504 | 522 | } |
505 | 523 | |
524 | +static void | |
525 | +netlink_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 | + | |
506 | 536 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
507 | 537 | { |
508 | 538 | struct sock *sk = sock->sk; |
509 | 539 | |
... | ... | @@ -528,15 +558,14 @@ |
528 | 558 | return err; |
529 | 559 | } |
530 | 560 | |
531 | - if (!nladdr->nl_groups && !nlk->groups) | |
561 | + if (!nladdr->nl_groups && !(u32)nlk->groups[0]) | |
532 | 562 | return 0; |
533 | 563 | |
534 | 564 | netlink_table_grab(); |
535 | - if (nlk->groups && !nladdr->nl_groups) | |
536 | - __sk_del_bind_node(sk); | |
537 | - else if (!nlk->groups && nladdr->nl_groups) | |
538 | - sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | |
539 | - nlk->groups = nladdr->nl_groups; | |
565 | + netlink_update_subscriptions(sk, nlk->subscriptions + | |
566 | + hweight32(nladdr->nl_groups) - | |
567 | + hweight32(nlk->groups[0])); | |
568 | + nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; | |
540 | 569 | netlink_table_ungrab(); |
541 | 570 | |
542 | 571 | return 0; |
... | ... | @@ -590,7 +619,7 @@ |
590 | 619 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
591 | 620 | } else { |
592 | 621 | nladdr->nl_pid = nlk->pid; |
593 | - nladdr->nl_groups = nlk->groups; | |
622 | + nladdr->nl_groups = nlk->groups[0]; | |
594 | 623 | } |
595 | 624 | return 0; |
596 | 625 | } |
... | ... | @@ -791,7 +820,8 @@ |
791 | 820 | if (p->exclude_sk == sk) |
792 | 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 | 825 | goto out; |
796 | 826 | |
797 | 827 | if (p->failure) { |
... | ... | @@ -887,7 +917,8 @@ |
887 | 917 | if (sk == p->exclude_sk) |
888 | 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 | 922 | goto out; |
892 | 923 | |
893 | 924 | sk->sk_err = p->code; |
... | ... | @@ -1112,6 +1143,7 @@ |
1112 | 1143 | nlk->flags |= NETLINK_KERNEL_SOCKET; |
1113 | 1144 | |
1114 | 1145 | netlink_table_grab(); |
1146 | + nl_table[unit].groups = 32; | |
1115 | 1147 | nl_table[unit].module = module; |
1116 | 1148 | nl_table[unit].registered = 1; |
1117 | 1149 | netlink_table_ungrab(); |
... | ... | @@ -1358,7 +1390,8 @@ |
1358 | 1390 | s, |
1359 | 1391 | s->sk_protocol, |
1360 | 1392 | nlk->pid, |
1361 | - nlk->groups, | |
1393 | + nlk->flags & NETLINK_KERNEL_SOCKET ? | |
1394 | + 0 : (unsigned int)nlk->groups[0], | |
1362 | 1395 | atomic_read(&s->sk_rmem_alloc), |
1363 | 1396 | atomic_read(&s->sk_wmem_alloc), |
1364 | 1397 | nlk->cb, |