@@ -26,6 +26,8 @@ struct nf_conntrack_expect {
/* Function to call after setup and insertion */
void (*expectfn)(struct nf_conn *new,
struct nf_conntrack_expect *this);
+ /* The module which expectfn belongs to */
+ struct module *nat_module;
/* Helper to assign to new connection */
struct nf_conntrack_helper *helper;
@@ -113,6 +113,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, unsigned int protoff,
struct nf_ct_nat_helper {
struct list_head head;
+ struct module *me;
const char *name;
void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
};
@@ -569,11 +569,13 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
static struct nf_ct_nat_helper q931_nat = {
.name = "Q.931",
+ .me = THIS_MODULE,
.expectfn = ip_nat_q931_expect,
};
static struct nf_ct_nat_helper callforwarding_nat = {
.name = "callforwarding",
+ .me = THIS_MODULE,
.expectfn = ip_nat_callforwarding_expect,
};
@@ -66,6 +66,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
exp->mask.src.u.udp.port = htons(0xFFFF);
exp->expectfn = NULL;
+ exp->nat_module = NULL;
exp->flags = NF_CT_EXPECT_PERMANENT;
exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
exp->helper = NULL;
@@ -296,6 +296,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
exp->flags = 0;
exp->class = class;
exp->expectfn = NULL;
+ exp->nat_module = NULL;
exp->helper = NULL;
exp->tuple.src.l3num = family;
exp->tuple.dst.protonum = proto;
@@ -130,6 +130,42 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
return NULL;
}
+static void
+nf_ct_flush_expect(const struct module *me)
+{
+ struct nf_conntrack_expect *exp;
+ const struct hlist_node *next;
+ u32 i;
+
+ if (!me)
+ return;
+
+ /* Make sure no one is still using the module unless
+ * its a connection in the hash.
+ */
+ synchronize_rcu();
+
+ /* Get rid of expectations */
+ spin_lock_bh(&nf_conntrack_expect_lock);
+ for (i = 0; i < nf_ct_expect_hsize; i++) {
+ hlist_for_each_entry_safe(exp, next,
+ &nf_ct_expect_hash[i], hnode) {
+ struct nf_conn_help *master_help = nfct_help(exp->master);
+
+ if ((master_help->helper && master_help->helper->me == me) ||
+ (exp->helper && exp->helper->me == me) ||
+ exp->nat_module == me) {
+ /* This expect belongs to the dying module */
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
+ }
+ }
+ }
+ spin_unlock_bh(&nf_conntrack_expect_lock);
+}
+
struct nf_conntrack_helper *
__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
{
@@ -308,6 +344,8 @@ void nf_ct_nat_helper_unregister(struct nf_ct_nat_helper *n)
spin_lock_bh(&nf_conntrack_expect_lock);
list_del_rcu(&n->head);
spin_unlock_bh(&nf_conntrack_expect_lock);
+
+ nf_ct_flush_expect(n->me);
}
EXPORT_SYMBOL_GPL(nf_ct_nat_helper_unregister);
@@ -421,8 +459,6 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{
struct nf_conntrack_tuple_hash *h;
- struct nf_conntrack_expect *exp;
- const struct hlist_node *next;
const struct hlist_nulls_node *nn;
unsigned int last_hsize;
spinlock_t *lock;
@@ -434,28 +470,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
nf_ct_helper_count--;
mutex_unlock(&nf_ct_helper_mutex);
- /* Make sure every nothing is still using the helper unless its a
- * connection in the hash.
- */
- synchronize_rcu();
-
- /* Get rid of expectations */
- spin_lock_bh(&nf_conntrack_expect_lock);
- for (i = 0; i < nf_ct_expect_hsize; i++) {
- hlist_for_each_entry_safe(exp, next,
- &nf_ct_expect_hash[i], hnode) {
- struct nf_conn_help *help = nfct_help(exp->master);
- if ((rcu_dereference_protected(
- help->helper,
- lockdep_is_held(&nf_conntrack_expect_lock)
- ) == me || exp->helper == me) &&
- del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_ct_expect_put(exp);
- }
- }
- }
- spin_unlock_bh(&nf_conntrack_expect_lock);
+ nf_ct_flush_expect(me->me);
rtnl_lock();
for_each_net(net)
@@ -3078,8 +3078,11 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
goto err_out;
}
exp->expectfn = nat_helper->expectfn;
- } else
+ exp->nat_module = nat_helper->me;
+ } else {
exp->expectfn = NULL;
+ exp->nat_module = NULL;
+ }
exp->class = class;
exp->master = ct;
@@ -850,6 +850,7 @@ static void __net_exit nf_nat_net_exit(struct net *net)
static struct nf_ct_nat_helper follow_master_nat = {
.name = "nat-follow-master",
+ .me = THIS_MODULE,
.expectfn = nf_nat_follow_master,
};
@@ -620,6 +620,7 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
static struct nf_ct_nat_helper sip_nat = {
.name = "sip",
+ .me = THIS_MODULE,
.expectfn = nf_nat_sip_expected,
};