aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-07-18 18:47:05 -0400
committerDavid S. Miller <davem@davemloft.net>2007-07-18 18:47:05 -0400
commit84659eb529b33572bb3f8c94e0978bd5d084bc7e (patch)
tree3eddcba4b7e4779a51480c3cc24384ff2046b287 /net/netlink/af_netlink.c
parentb4ff4f0419ae5db83553fab79d03a89c10d540a8 (diff)
[NETLIKN]: Allow removing multicast groups.
Allow kicking listeners out of a multicast group when necessary (for example if that group is going to be removed.) Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Patrick McHardy <kaber@trash.net> Acked-by: Jamal Hadi Salim <hadi@cyberus.ca> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index c386eaf6ad5b..5681ce3aebca 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1027,6 +1027,23 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
1027 read_unlock(&nl_table_lock); 1027 read_unlock(&nl_table_lock);
1028} 1028}
1029 1029
1030/* must be called with netlink table grabbed */
1031static void netlink_update_socket_mc(struct netlink_sock *nlk,
1032 unsigned int group,
1033 int is_new)
1034{
1035 int old, new = !!is_new, subscriptions;
1036
1037 old = test_bit(group - 1, nlk->groups);
1038 subscriptions = nlk->subscriptions - old + new;
1039 if (new)
1040 __set_bit(group - 1, nlk->groups);
1041 else
1042 __clear_bit(group - 1, nlk->groups);
1043 netlink_update_subscriptions(&nlk->sk, subscriptions);
1044 netlink_update_listeners(&nlk->sk);
1045}
1046
1030static int netlink_setsockopt(struct socket *sock, int level, int optname, 1047static int netlink_setsockopt(struct socket *sock, int level, int optname,
1031 char __user *optval, int optlen) 1048 char __user *optval, int optlen)
1032{ 1049{
@@ -1052,9 +1069,6 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1052 break; 1069 break;
1053 case NETLINK_ADD_MEMBERSHIP: 1070 case NETLINK_ADD_MEMBERSHIP:
1054 case NETLINK_DROP_MEMBERSHIP: { 1071 case NETLINK_DROP_MEMBERSHIP: {
1055 unsigned int subscriptions;
1056 int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0;
1057
1058 if (!netlink_capable(sock, NL_NONROOT_RECV)) 1072 if (!netlink_capable(sock, NL_NONROOT_RECV))
1059 return -EPERM; 1073 return -EPERM;
1060 err = netlink_realloc_groups(sk); 1074 err = netlink_realloc_groups(sk);
@@ -1063,14 +1077,8 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1063 if (!val || val - 1 >= nlk->ngroups) 1077 if (!val || val - 1 >= nlk->ngroups)
1064 return -EINVAL; 1078 return -EINVAL;
1065 netlink_table_grab(); 1079 netlink_table_grab();
1066 old = test_bit(val - 1, nlk->groups); 1080 netlink_update_socket_mc(nlk, val,
1067 subscriptions = nlk->subscriptions - old + new; 1081 optname == NETLINK_ADD_MEMBERSHIP);
1068 if (new)
1069 __set_bit(val - 1, nlk->groups);
1070 else
1071 __clear_bit(val - 1, nlk->groups);
1072 netlink_update_subscriptions(sk, subscriptions);
1073 netlink_update_listeners(sk);
1074 netlink_table_ungrab(); 1082 netlink_table_ungrab();
1075 err = 0; 1083 err = 0;
1076 break; 1084 break;
@@ -1351,7 +1359,9 @@ out_sock_release:
1351 * 1359 *
1352 * This changes the number of multicast groups that are available 1360 * This changes the number of multicast groups that are available
1353 * on a certain netlink family. Note that it is not possible to 1361 * on a certain netlink family. Note that it is not possible to
1354 * change the number of groups to below 32. 1362 * change the number of groups to below 32. Also note that it does
1363 * not implicitly call netlink_clear_multicast_users() when the
1364 * number of groups is reduced.
1355 * 1365 *
1356 * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). 1366 * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
1357 * @groups: The new number of groups. 1367 * @groups: The new number of groups.
@@ -1386,6 +1396,29 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups)
1386} 1396}
1387EXPORT_SYMBOL(netlink_change_ngroups); 1397EXPORT_SYMBOL(netlink_change_ngroups);
1388 1398
1399/**
1400 * netlink_clear_multicast_users - kick off multicast listeners
1401 *
1402 * This function removes all listeners from the given group.
1403 * @ksk: The kernel netlink socket, as returned by
1404 * netlink_kernel_create().
1405 * @group: The multicast group to clear.
1406 */
1407void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
1408{
1409 struct sock *sk;
1410 struct hlist_node *node;
1411 struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
1412
1413 netlink_table_grab();
1414
1415 sk_for_each_bound(sk, node, &tbl->mc_list)
1416 netlink_update_socket_mc(nlk_sk(sk), group, 0);
1417
1418 netlink_table_ungrab();
1419}
1420EXPORT_SYMBOL(netlink_clear_multicast_users);
1421
1389void netlink_set_nonroot(int protocol, unsigned int flags) 1422void netlink_set_nonroot(int protocol, unsigned int flags)
1390{ 1423{
1391 if ((unsigned int)protocol < MAX_LINKS) 1424 if ((unsigned int)protocol < MAX_LINKS)