Commit 03292745 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by David S. Miller

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: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a31f2d17
...@@ -179,6 +179,7 @@ struct netlink_kernel_cfg { ...@@ -179,6 +179,7 @@ struct netlink_kernel_cfg {
unsigned int groups; unsigned int groups;
void (*input)(struct sk_buff *skb); void (*input)(struct sk_buff *skb);
struct mutex *cb_mutex; struct mutex *cb_mutex;
void (*bind)(int group);
}; };
extern struct sock *netlink_kernel_create(struct net *net, int unit, extern struct sock *netlink_kernel_create(struct net *net, int unit,
......
...@@ -39,6 +39,15 @@ static char __initdata nfversion[] = "0.30"; ...@@ -39,6 +39,15 @@ static char __initdata nfversion[] = "0.30";
static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT]; static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT];
static DEFINE_MUTEX(nfnl_mutex); static DEFINE_MUTEX(nfnl_mutex);
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
[NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK,
[NFNLGRP_CONNTRACK_UPDATE] = NFNL_SUBSYS_CTNETLINK,
[NFNLGRP_CONNTRACK_DESTROY] = NFNL_SUBSYS_CTNETLINK,
[NFNLGRP_CONNTRACK_EXP_NEW] = NFNL_SUBSYS_CTNETLINK_EXP,
[NFNLGRP_CONNTRACK_EXP_UPDATE] = NFNL_SUBSYS_CTNETLINK_EXP,
[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
};
void nfnl_lock(void) void nfnl_lock(void)
{ {
mutex_lock(&nfnl_mutex); mutex_lock(&nfnl_mutex);
...@@ -200,12 +209,32 @@ static void nfnetlink_rcv(struct sk_buff *skb) ...@@ -200,12 +209,32 @@ static void nfnetlink_rcv(struct sk_buff *skb)
netlink_rcv_skb(skb, &nfnetlink_rcv_msg); netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
} }
#ifdef CONFIG_MODULES
static void nfnetlink_bind(int group)
{
const struct nfnetlink_subsystem *ss;
int type = nfnl_group2type[group];
rcu_read_lock();
ss = nfnetlink_get_subsys(type);
if (!ss) {
rcu_read_unlock();
request_module("nfnetlink-subsys-%d", type);
return;
}
rcu_read_unlock();
}
#endif
static int __net_init nfnetlink_net_init(struct net *net) static int __net_init nfnetlink_net_init(struct net *net)
{ {
struct sock *nfnl; struct sock *nfnl;
struct netlink_kernel_cfg cfg = { struct netlink_kernel_cfg cfg = {
.groups = NFNLGRP_MAX, .groups = NFNLGRP_MAX,
.input = nfnetlink_rcv, .input = nfnetlink_rcv,
#ifdef CONFIG_MODULES
.bind = nfnetlink_bind,
#endif
}; };
nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, THIS_MODULE, &cfg); nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, THIS_MODULE, &cfg);
......
...@@ -80,6 +80,7 @@ struct netlink_sock { ...@@ -80,6 +80,7 @@ struct netlink_sock {
struct mutex *cb_mutex; struct mutex *cb_mutex;
struct mutex cb_def_mutex; struct mutex cb_def_mutex;
void (*netlink_rcv)(struct sk_buff *skb); void (*netlink_rcv)(struct sk_buff *skb);
void (*netlink_bind)(int group);
struct module *module; struct module *module;
}; };
...@@ -124,6 +125,7 @@ struct netlink_table { ...@@ -124,6 +125,7 @@ struct netlink_table {
unsigned int groups; unsigned int groups;
struct mutex *cb_mutex; struct mutex *cb_mutex;
struct module *module; struct module *module;
void (*bind)(int group);
int registered; int registered;
}; };
...@@ -444,6 +446,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, ...@@ -444,6 +446,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
struct module *module = NULL; struct module *module = NULL;
struct mutex *cb_mutex; struct mutex *cb_mutex;
struct netlink_sock *nlk; struct netlink_sock *nlk;
void (*bind)(int group);
int err = 0; int err = 0;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
...@@ -468,6 +471,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, ...@@ -468,6 +471,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
else else
err = -EPROTONOSUPPORT; err = -EPROTONOSUPPORT;
cb_mutex = nl_table[protocol].cb_mutex; cb_mutex = nl_table[protocol].cb_mutex;
bind = nl_table[protocol].bind;
netlink_unlock_table(); netlink_unlock_table();
if (err < 0) if (err < 0)
...@@ -483,6 +487,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, ...@@ -483,6 +487,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
nlk = nlk_sk(sock->sk); nlk = nlk_sk(sock->sk);
nlk->module = module; nlk->module = module;
nlk->netlink_bind = bind;
out: out:
return err; return err;
...@@ -683,6 +688,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, ...@@ -683,6 +688,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
netlink_update_listeners(sk); netlink_update_listeners(sk);
netlink_table_ungrab(); netlink_table_ungrab();
if (nlk->netlink_bind && nlk->groups[0]) {
int i;
for (i=0; i<nlk->ngroups; i++) {
if (test_bit(i, nlk->groups))
nlk->netlink_bind(i);
}
}
return 0; return 0;
} }
...@@ -1239,6 +1253,10 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, ...@@ -1239,6 +1253,10 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
netlink_update_socket_mc(nlk, val, netlink_update_socket_mc(nlk, val,
optname == NETLINK_ADD_MEMBERSHIP); optname == NETLINK_ADD_MEMBERSHIP);
netlink_table_ungrab(); netlink_table_ungrab();
if (nlk->netlink_bind)
nlk->netlink_bind(val);
err = 0; err = 0;
break; break;
} }
...@@ -1559,6 +1577,7 @@ netlink_kernel_create(struct net *net, int unit, ...@@ -1559,6 +1577,7 @@ netlink_kernel_create(struct net *net, int unit,
rcu_assign_pointer(nl_table[unit].listeners, listeners); rcu_assign_pointer(nl_table[unit].listeners, listeners);
nl_table[unit].cb_mutex = cb_mutex; nl_table[unit].cb_mutex = cb_mutex;
nl_table[unit].module = module; nl_table[unit].module = module;
nl_table[unit].bind = cfg ? cfg->bind : NULL;
nl_table[unit].registered = 1; nl_table[unit].registered = 1;
} else { } else {
kfree(listeners); kfree(listeners);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment