aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netlink.h3
-rw-r--r--net/netfilter/nfnetlink.c3
-rw-r--r--net/netlink/af_netlink.c68
-rw-r--r--net/netlink/af_netlink.h6
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
403static void nfnetlink_bind(int group) 403static 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;
1251out: 1254out:
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
1418static 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
1414static int netlink_bind(struct socket *sock, struct sockaddr *addr, 1431static 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};