diff options
| -rw-r--r-- | include/linux/netlink.h | 3 | ||||
| -rw-r--r-- | net/netfilter/nfnetlink.c | 3 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 68 | ||||
| -rw-r--r-- | net/netlink/af_netlink.h | 6 |
4 files changed, 56 insertions, 24 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index aad8eeaf416d..5146ce066498 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
| @@ -45,7 +45,8 @@ struct netlink_kernel_cfg { | |||
| 45 | unsigned int flags; | 45 | unsigned int flags; |
| 46 | void (*input)(struct sk_buff *skb); | 46 | void (*input)(struct sk_buff *skb); |
| 47 | struct mutex *cb_mutex; | 47 | struct mutex *cb_mutex; |
| 48 | void (*bind)(int group); | 48 | int (*bind)(int group); |
| 49 | void (*unbind)(int group); | ||
| 49 | bool (*compare)(struct net *net, struct sock *sk); | 50 | bool (*compare)(struct net *net, struct sock *sk); |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 0df800a454ec..6e42dcfad40a 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
| @@ -400,7 +400,7 @@ static void nfnetlink_rcv(struct sk_buff *skb) | |||
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | #ifdef CONFIG_MODULES | 402 | #ifdef CONFIG_MODULES |
| 403 | static void nfnetlink_bind(int group) | 403 | static int nfnetlink_bind(int group) |
| 404 | { | 404 | { |
| 405 | const struct nfnetlink_subsystem *ss; | 405 | const struct nfnetlink_subsystem *ss; |
| 406 | int type = nfnl_group2type[group]; | 406 | int type = nfnl_group2type[group]; |
| @@ -410,6 +410,7 @@ static void nfnetlink_bind(int group) | |||
| 410 | rcu_read_unlock(); | 410 | rcu_read_unlock(); |
| 411 | if (!ss) | 411 | if (!ss) |
| 412 | request_module("nfnetlink-subsys-%d", type); | 412 | request_module("nfnetlink-subsys-%d", type); |
| 413 | return 0; | ||
| 413 | } | 414 | } |
| 414 | #endif | 415 | #endif |
| 415 | 416 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 894cda0206bb..7e8d229bc010 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -1206,7 +1206,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
| 1206 | struct module *module = NULL; | 1206 | struct module *module = NULL; |
| 1207 | struct mutex *cb_mutex; | 1207 | struct mutex *cb_mutex; |
| 1208 | struct netlink_sock *nlk; | 1208 | struct netlink_sock *nlk; |
| 1209 | void (*bind)(int group); | 1209 | int (*bind)(int group); |
| 1210 | void (*unbind)(int group); | ||
| 1210 | int err = 0; | 1211 | int err = 0; |
| 1211 | 1212 | ||
| 1212 | sock->state = SS_UNCONNECTED; | 1213 | sock->state = SS_UNCONNECTED; |
| @@ -1232,6 +1233,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
| 1232 | err = -EPROTONOSUPPORT; | 1233 | err = -EPROTONOSUPPORT; |
| 1233 | cb_mutex = nl_table[protocol].cb_mutex; | 1234 | cb_mutex = nl_table[protocol].cb_mutex; |
| 1234 | bind = nl_table[protocol].bind; | 1235 | bind = nl_table[protocol].bind; |
| 1236 | unbind = nl_table[protocol].unbind; | ||
| 1235 | netlink_unlock_table(); | 1237 | netlink_unlock_table(); |
| 1236 | 1238 | ||
| 1237 | if (err < 0) | 1239 | if (err < 0) |
| @@ -1248,6 +1250,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
| 1248 | nlk = nlk_sk(sock->sk); | 1250 | nlk = nlk_sk(sock->sk); |
| 1249 | nlk->module = module; | 1251 | nlk->module = module; |
| 1250 | nlk->netlink_bind = bind; | 1252 | nlk->netlink_bind = bind; |
| 1253 | nlk->netlink_unbind = unbind; | ||
| 1251 | out: | 1254 | out: |
| 1252 | return err; | 1255 | return err; |
| 1253 | 1256 | ||
| @@ -1301,6 +1304,7 @@ static int netlink_release(struct socket *sock) | |||
| 1301 | kfree_rcu(old, rcu); | 1304 | kfree_rcu(old, rcu); |
| 1302 | nl_table[sk->sk_protocol].module = NULL; | 1305 | nl_table[sk->sk_protocol].module = NULL; |
| 1303 | nl_table[sk->sk_protocol].bind = NULL; | 1306 | nl_table[sk->sk_protocol].bind = NULL; |
| 1307 | nl_table[sk->sk_protocol].unbind = NULL; | ||
| 1304 | nl_table[sk->sk_protocol].flags = 0; | 1308 | nl_table[sk->sk_protocol].flags = 0; |
| 1305 | nl_table[sk->sk_protocol].registered = 0; | 1309 | nl_table[sk->sk_protocol].registered = 0; |
| 1306 | } | 1310 | } |
| @@ -1411,6 +1415,19 @@ static int netlink_realloc_groups(struct sock *sk) | |||
| 1411 | return err; | 1415 | return err; |
| 1412 | } | 1416 | } |
| 1413 | 1417 | ||
| 1418 | static void netlink_unbind(int group, long unsigned int groups, | ||
| 1419 | struct netlink_sock *nlk) | ||
| 1420 | { | ||
| 1421 | int undo; | ||
| 1422 | |||
| 1423 | if (!nlk->netlink_unbind) | ||
| 1424 | return; | ||
| 1425 | |||
| 1426 | for (undo = 0; undo < group; undo++) | ||
| 1427 | if (test_bit(group, &groups)) | ||
| 1428 | nlk->netlink_unbind(undo); | ||
| 1429 | } | ||
| 1430 | |||
| 1414 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, | 1431 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, |
| 1415 | int addr_len) | 1432 | int addr_len) |
| 1416 | { | 1433 | { |
| @@ -1419,6 +1436,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1419 | struct netlink_sock *nlk = nlk_sk(sk); | 1436 | struct netlink_sock *nlk = nlk_sk(sk); |
| 1420 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 1437 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
| 1421 | int err; | 1438 | int err; |
| 1439 | long unsigned int groups = nladdr->nl_groups; | ||
| 1422 | 1440 | ||
| 1423 | if (addr_len < sizeof(struct sockaddr_nl)) | 1441 | if (addr_len < sizeof(struct sockaddr_nl)) |
| 1424 | return -EINVAL; | 1442 | return -EINVAL; |
| @@ -1427,7 +1445,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1427 | return -EINVAL; | 1445 | return -EINVAL; |
| 1428 | 1446 | ||
| 1429 | /* Only superuser is allowed to listen multicasts */ | 1447 | /* Only superuser is allowed to listen multicasts */ |
| 1430 | if (nladdr->nl_groups) { | 1448 | if (groups) { |
| 1431 | if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) | 1449 | if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) |
| 1432 | return -EPERM; | 1450 | return -EPERM; |
| 1433 | err = netlink_realloc_groups(sk); | 1451 | err = netlink_realloc_groups(sk); |
| @@ -1435,37 +1453,45 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
| 1435 | return err; | 1453 | return err; |
| 1436 | } | 1454 | } |
| 1437 | 1455 | ||
| 1438 | if (nlk->portid) { | 1456 | if (nlk->portid) |
| 1439 | if (nladdr->nl_pid != nlk->portid) | 1457 | if (nladdr->nl_pid != nlk->portid) |
| 1440 | return -EINVAL; | 1458 | return -EINVAL; |
| 1441 | } else { | 1459 | |
| 1460 | if (nlk->netlink_bind && groups) { | ||
| 1461 | int group; | ||
| 1462 | |||
| 1463 | for (group = 0; group < nlk->ngroups; group++) { | ||
| 1464 | if (!test_bit(group, &groups)) | ||
| 1465 | continue; | ||
| 1466 | err = nlk->netlink_bind(group); | ||
| 1467 | if (!err) | ||
| 1468 | continue; | ||
| 1469 | netlink_unbind(group, groups, nlk); | ||
| 1470 | return err; | ||
| 1471 | } | ||
| 1472 | } | ||
| 1473 | |||
| 1474 | if (!nlk->portid) { | ||
| 1442 | err = nladdr->nl_pid ? | 1475 | err = nladdr->nl_pid ? |
| 1443 | netlink_insert(sk, net, nladdr->nl_pid) : | 1476 | netlink_insert(sk, net, nladdr->nl_pid) : |
| 1444 | netlink_autobind(sock); | 1477 | netlink_autobind(sock); |
| 1445 | if (err) | 1478 | if (err) { |
| 1479 | netlink_unbind(nlk->ngroups - 1, groups, nlk); | ||
| 1446 | return err; | 1480 | return err; |
| 1481 | } | ||
| 1447 | } | 1482 | } |
| 1448 | 1483 | ||
| 1449 | if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) | 1484 | if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) |
| 1450 | return 0; | 1485 | return 0; |
| 1451 | 1486 | ||
| 1452 | netlink_table_grab(); | 1487 | netlink_table_grab(); |
| 1453 | netlink_update_subscriptions(sk, nlk->subscriptions + | 1488 | netlink_update_subscriptions(sk, nlk->subscriptions + |
| 1454 | hweight32(nladdr->nl_groups) - | 1489 | hweight32(groups) - |
| 1455 | hweight32(nlk->groups[0])); | 1490 | hweight32(nlk->groups[0])); |
| 1456 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; | 1491 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups; |
| 1457 | netlink_update_listeners(sk); | 1492 | netlink_update_listeners(sk); |
| 1458 | netlink_table_ungrab(); | 1493 | netlink_table_ungrab(); |
| 1459 | 1494 | ||
| 1460 | if (nlk->netlink_bind && nlk->groups[0]) { | ||
| 1461 | int i; | ||
| 1462 | |||
| 1463 | for (i = 0; i < nlk->ngroups; i++) { | ||
| 1464 | if (test_bit(i, nlk->groups)) | ||
| 1465 | nlk->netlink_bind(i); | ||
| 1466 | } | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | return 0; | 1495 | return 0; |
| 1470 | } | 1496 | } |
| 1471 | 1497 | ||
| @@ -2103,14 +2129,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
| 2103 | return err; | 2129 | return err; |
| 2104 | if (!val || val - 1 >= nlk->ngroups) | 2130 | if (!val || val - 1 >= nlk->ngroups) |
| 2105 | return -EINVAL; | 2131 | return -EINVAL; |
| 2132 | if (nlk->netlink_bind) { | ||
| 2133 | err = nlk->netlink_bind(val); | ||
| 2134 | if (err) | ||
| 2135 | return err; | ||
| 2136 | } | ||
| 2106 | netlink_table_grab(); | 2137 | netlink_table_grab(); |
| 2107 | netlink_update_socket_mc(nlk, val, | 2138 | netlink_update_socket_mc(nlk, val, |
| 2108 | optname == NETLINK_ADD_MEMBERSHIP); | 2139 | optname == NETLINK_ADD_MEMBERSHIP); |
| 2109 | netlink_table_ungrab(); | 2140 | netlink_table_ungrab(); |
| 2110 | 2141 | ||
| 2111 | if (nlk->netlink_bind) | ||
| 2112 | nlk->netlink_bind(val); | ||
| 2113 | |||
| 2114 | err = 0; | 2142 | err = 0; |
| 2115 | break; | 2143 | break; |
| 2116 | } | 2144 | } |
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index ed13a790b00e..0b59d441f5b6 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
| @@ -38,7 +38,8 @@ struct netlink_sock { | |||
| 38 | struct mutex *cb_mutex; | 38 | struct mutex *cb_mutex; |
| 39 | struct mutex cb_def_mutex; | 39 | struct mutex cb_def_mutex; |
| 40 | void (*netlink_rcv)(struct sk_buff *skb); | 40 | void (*netlink_rcv)(struct sk_buff *skb); |
| 41 | void (*netlink_bind)(int group); | 41 | int (*netlink_bind)(int group); |
| 42 | void (*netlink_unbind)(int group); | ||
| 42 | struct module *module; | 43 | struct module *module; |
| 43 | #ifdef CONFIG_NETLINK_MMAP | 44 | #ifdef CONFIG_NETLINK_MMAP |
| 44 | struct mutex pg_vec_lock; | 45 | struct mutex pg_vec_lock; |
| @@ -74,7 +75,8 @@ struct netlink_table { | |||
| 74 | unsigned int groups; | 75 | unsigned int groups; |
| 75 | struct mutex *cb_mutex; | 76 | struct mutex *cb_mutex; |
| 76 | struct module *module; | 77 | struct module *module; |
| 77 | void (*bind)(int group); | 78 | int (*bind)(int group); |
| 79 | void (*unbind)(int group); | ||
| 78 | bool (*compare)(struct net *net, struct sock *sock); | 80 | bool (*compare)(struct net *net, struct sock *sock); |
| 79 | int registered; | 81 | int registered; |
| 80 | }; | 82 | }; |
