diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-29 02:15:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-29 19:46:06 -0400 |
commit | 03292745b02d1166e2a215504407e096b8427be5 (patch) | |
tree | 2251b4bed9969a6c8a02a322927a74621b29155c /net | |
parent | a31f2d17b331db970259e875b7223d3aba7e3821 (diff) |
netlink: add nlk->netlink_bind hook for module auto-loading
This patch adds a hook in the binding path of netlink.
This is used by ctnetlink to allow module autoloading for the case
in which one user executes:
conntrack -E
So far, this resulted in nfnetlink loaded, but not
nf_conntrack_netlink.
I have received in the past many complains on this behaviour.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nfnetlink.c | 29 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 19 |
2 files changed, 48 insertions, 0 deletions
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 700e4616a098..5a2132b97fe9 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -39,6 +39,15 @@ static char __initdata nfversion[] = "0.30"; | |||
39 | static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT]; | 39 | static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT]; |
40 | static DEFINE_MUTEX(nfnl_mutex); | 40 | static DEFINE_MUTEX(nfnl_mutex); |
41 | 41 | ||
42 | static const int nfnl_group2type[NFNLGRP_MAX+1] = { | ||
43 | [NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK, | ||
44 | [NFNLGRP_CONNTRACK_UPDATE] = NFNL_SUBSYS_CTNETLINK, | ||
45 | [NFNLGRP_CONNTRACK_DESTROY] = NFNL_SUBSYS_CTNETLINK, | ||
46 | [NFNLGRP_CONNTRACK_EXP_NEW] = NFNL_SUBSYS_CTNETLINK_EXP, | ||
47 | [NFNLGRP_CONNTRACK_EXP_UPDATE] = NFNL_SUBSYS_CTNETLINK_EXP, | ||
48 | [NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP, | ||
49 | }; | ||
50 | |||
42 | void nfnl_lock(void) | 51 | void nfnl_lock(void) |
43 | { | 52 | { |
44 | mutex_lock(&nfnl_mutex); | 53 | mutex_lock(&nfnl_mutex); |
@@ -200,12 +209,32 @@ static void nfnetlink_rcv(struct sk_buff *skb) | |||
200 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); | 209 | netlink_rcv_skb(skb, &nfnetlink_rcv_msg); |
201 | } | 210 | } |
202 | 211 | ||
212 | #ifdef CONFIG_MODULES | ||
213 | static void nfnetlink_bind(int group) | ||
214 | { | ||
215 | const struct nfnetlink_subsystem *ss; | ||
216 | int type = nfnl_group2type[group]; | ||
217 | |||
218 | rcu_read_lock(); | ||
219 | ss = nfnetlink_get_subsys(type); | ||
220 | if (!ss) { | ||
221 | rcu_read_unlock(); | ||
222 | request_module("nfnetlink-subsys-%d", type); | ||
223 | return; | ||
224 | } | ||
225 | rcu_read_unlock(); | ||
226 | } | ||
227 | #endif | ||
228 | |||
203 | static int __net_init nfnetlink_net_init(struct net *net) | 229 | static int __net_init nfnetlink_net_init(struct net *net) |
204 | { | 230 | { |
205 | struct sock *nfnl; | 231 | struct sock *nfnl; |
206 | struct netlink_kernel_cfg cfg = { | 232 | struct netlink_kernel_cfg cfg = { |
207 | .groups = NFNLGRP_MAX, | 233 | .groups = NFNLGRP_MAX, |
208 | .input = nfnetlink_rcv, | 234 | .input = nfnetlink_rcv, |
235 | #ifdef CONFIG_MODULES | ||
236 | .bind = nfnetlink_bind, | ||
237 | #endif | ||
209 | }; | 238 | }; |
210 | 239 | ||
211 | nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, THIS_MODULE, &cfg); | 240 | nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, THIS_MODULE, &cfg); |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 43a124feaad8..5463969da45b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -80,6 +80,7 @@ struct netlink_sock { | |||
80 | struct mutex *cb_mutex; | 80 | struct mutex *cb_mutex; |
81 | struct mutex cb_def_mutex; | 81 | struct mutex cb_def_mutex; |
82 | void (*netlink_rcv)(struct sk_buff *skb); | 82 | void (*netlink_rcv)(struct sk_buff *skb); |
83 | void (*netlink_bind)(int group); | ||
83 | struct module *module; | 84 | struct module *module; |
84 | }; | 85 | }; |
85 | 86 | ||
@@ -124,6 +125,7 @@ struct netlink_table { | |||
124 | unsigned int groups; | 125 | unsigned int groups; |
125 | struct mutex *cb_mutex; | 126 | struct mutex *cb_mutex; |
126 | struct module *module; | 127 | struct module *module; |
128 | void (*bind)(int group); | ||
127 | int registered; | 129 | int registered; |
128 | }; | 130 | }; |
129 | 131 | ||
@@ -444,6 +446,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
444 | struct module *module = NULL; | 446 | struct module *module = NULL; |
445 | struct mutex *cb_mutex; | 447 | struct mutex *cb_mutex; |
446 | struct netlink_sock *nlk; | 448 | struct netlink_sock *nlk; |
449 | void (*bind)(int group); | ||
447 | int err = 0; | 450 | int err = 0; |
448 | 451 | ||
449 | sock->state = SS_UNCONNECTED; | 452 | sock->state = SS_UNCONNECTED; |
@@ -468,6 +471,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
468 | else | 471 | else |
469 | err = -EPROTONOSUPPORT; | 472 | err = -EPROTONOSUPPORT; |
470 | cb_mutex = nl_table[protocol].cb_mutex; | 473 | cb_mutex = nl_table[protocol].cb_mutex; |
474 | bind = nl_table[protocol].bind; | ||
471 | netlink_unlock_table(); | 475 | netlink_unlock_table(); |
472 | 476 | ||
473 | if (err < 0) | 477 | if (err < 0) |
@@ -483,6 +487,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, | |||
483 | 487 | ||
484 | nlk = nlk_sk(sock->sk); | 488 | nlk = nlk_sk(sock->sk); |
485 | nlk->module = module; | 489 | nlk->module = module; |
490 | nlk->netlink_bind = bind; | ||
486 | out: | 491 | out: |
487 | return err; | 492 | return err; |
488 | 493 | ||
@@ -683,6 +688,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, | |||
683 | netlink_update_listeners(sk); | 688 | netlink_update_listeners(sk); |
684 | netlink_table_ungrab(); | 689 | netlink_table_ungrab(); |
685 | 690 | ||
691 | if (nlk->netlink_bind && nlk->groups[0]) { | ||
692 | int i; | ||
693 | |||
694 | for (i=0; i<nlk->ngroups; i++) { | ||
695 | if (test_bit(i, nlk->groups)) | ||
696 | nlk->netlink_bind(i); | ||
697 | } | ||
698 | } | ||
699 | |||
686 | return 0; | 700 | return 0; |
687 | } | 701 | } |
688 | 702 | ||
@@ -1239,6 +1253,10 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
1239 | netlink_update_socket_mc(nlk, val, | 1253 | netlink_update_socket_mc(nlk, val, |
1240 | optname == NETLINK_ADD_MEMBERSHIP); | 1254 | optname == NETLINK_ADD_MEMBERSHIP); |
1241 | netlink_table_ungrab(); | 1255 | netlink_table_ungrab(); |
1256 | |||
1257 | if (nlk->netlink_bind) | ||
1258 | nlk->netlink_bind(val); | ||
1259 | |||
1242 | err = 0; | 1260 | err = 0; |
1243 | break; | 1261 | break; |
1244 | } | 1262 | } |
@@ -1559,6 +1577,7 @@ netlink_kernel_create(struct net *net, int unit, | |||
1559 | rcu_assign_pointer(nl_table[unit].listeners, listeners); | 1577 | rcu_assign_pointer(nl_table[unit].listeners, listeners); |
1560 | nl_table[unit].cb_mutex = cb_mutex; | 1578 | nl_table[unit].cb_mutex = cb_mutex; |
1561 | nl_table[unit].module = module; | 1579 | nl_table[unit].module = module; |
1580 | nl_table[unit].bind = cfg ? cfg->bind : NULL; | ||
1562 | nl_table[unit].registered = 1; | 1581 | nl_table[unit].registered = 1; |
1563 | } else { | 1582 | } else { |
1564 | kfree(listeners); | 1583 | kfree(listeners); |