struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        struct nf_conn_help *help;
+       struct nf_conntrack_helper *helper;
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(*pskb, &ctinfo);
                return NF_ACCEPT;
 
        help = nfct_help(ct);
-       if (!help || !help->helper)
+       if (!help)
                return NF_ACCEPT;
-
-       return help->helper->help(pskb,
-                                 skb_network_offset(*pskb) + ip_hdrlen(*pskb),
-                                 ct, ctinfo);
+       /* rcu_read_lock()ed by nf_hook_slow */
+       helper = rcu_dereference(help->helper);
+       if (!helper)
+               return NF_ACCEPT;
+       return helper->help(pskb, skb_network_offset(*pskb) + ip_hdrlen(*pskb),
+                           ct, ctinfo);
 }
 
 static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
 
 {
        struct nf_conn *ct;
        struct nf_conn_help *help;
+       struct nf_conntrack_helper *helper;
        enum ip_conntrack_info ctinfo;
        unsigned int ret, protoff;
        unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
                goto out;
 
        help = nfct_help(ct);
-       if (!help || !help->helper)
+       if (!help)
+               goto out;
+       /* rcu_read_lock()ed by nf_hook_slow */
+       helper = rcu_dereference(help->helper);
+       if (!helper)
                goto out;
 
        protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
                return NF_ACCEPT;
        }
 
-       ret = help->helper->help(pskb, protoff, ct, ctinfo);
+       ret = helper->help(pskb, protoff, ct, ctinfo);
        if (ret != NF_ACCEPT)
                return ret;
 out:
 
 {
        struct nf_conn *ct = (void *)ul_conntrack;
        struct nf_conn_help *help = nfct_help(ct);
+       struct nf_conntrack_helper *helper;
 
-       if (help && help->helper && help->helper->destroy)
-               help->helper->destroy(ct);
+       if (help) {
+               rcu_read_lock();
+               helper = rcu_dereference(help->helper);
+               if (helper && helper->destroy)
+                       helper->destroy(ct);
+               rcu_read_unlock();
+       }
 
        write_lock_bh(&nf_conntrack_lock);
        /* Inside lock so preempt is disabled on module removal path.
               unsigned int dataoff)
 {
        struct nf_conn *conntrack;
+       struct nf_conn_help *help;
        struct nf_conntrack_tuple repl_tuple;
        struct nf_conntrack_expect *exp;
        u_int32_t features = 0;
        write_lock_bh(&nf_conntrack_lock);
        exp = find_expectation(tuple);
 
+       help = nfct_help(conntrack);
        if (exp) {
                DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
                        conntrack, exp);
                __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
                conntrack->master = exp->master;
                if (exp->helper)
-                       nfct_help(conntrack)->helper = exp->helper;
+                       rcu_assign_pointer(help->helper, exp->helper);
 #ifdef CONFIG_NF_CONNTRACK_MARK
                conntrack->mark = exp->master->mark;
 #endif
                nf_conntrack_get(&conntrack->master->ct_general);
                NF_CT_STAT_INC(expect_new);
        } else {
-               struct nf_conn_help *help = nfct_help(conntrack);
-
-               if (help)
-                       help->helper = __nf_ct_helper_find(&repl_tuple);
+               if (help) {
+                       /* not in hash table yet, so not strictly necessary */
+                       rcu_assign_pointer(help->helper,
+                                          __nf_ct_helper_find(&repl_tuple));
+               }
                NF_CT_STAT_INC(new);
        }
 
                helper = __nf_ct_helper_find(newreply);
                if (helper)
                        memset(&help->help, 0, sizeof(help->help));
-               help->helper = helper;
+               /* not in hash table yet, so not strictly necessary */
+               rcu_assign_pointer(help->helper, helper);
        }
        write_unlock_bh(&nf_conntrack_lock);
 }
 
        NF_CT_ASSERT(master_help);
 
        write_lock_bh(&nf_conntrack_lock);
+       if (!master_help->helper) {
+               ret = -ESHUTDOWN;
+               goto out;
+       }
        list_for_each_entry(i, &nf_conntrack_expect_list, list) {
                if (expect_matches(i, expect)) {
                        /* Refresh timer: if it's dying, ignore.. */
 
 
        if (help && help->helper == me) {
                nf_conntrack_event(IPCT_HELPER, ct);
-               help->helper = NULL;
+               rcu_assign_pointer(help->helper, NULL);
        }
        return 0;
 }
 
 {
        struct nfattr *nest_helper;
        const struct nf_conn_help *help = nfct_help(ct);
+       struct nf_conntrack_helper *helper;
 
-       if (!help || !help->helper)
+       if (!help)
                return 0;
 
+       rcu_read_lock();
+       helper = rcu_dereference(help->helper);
+       if (!helper)
+               goto out;
+
        nest_helper = NFA_NEST(skb, CTA_HELP);
-       NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name);
+       NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name);
 
-       if (help->helper->to_nfattr)
-               help->helper->to_nfattr(skb, ct);
+       if (helper->to_nfattr)
+               helper->to_nfattr(skb, ct);
 
        NFA_NEST_END(skb, nest_helper);
-
+out:
+       rcu_read_unlock();
        return 0;
 
 nfattr_failure:
+       rcu_read_unlock();
        return -1;
 }
 
                if (help && help->helper) {
                        /* we had a helper before ... */
                        nf_ct_remove_expectations(ct);
-                       help->helper = NULL;
+                       rcu_assign_pointer(help->helper, NULL);
                }
 
                return 0;
 
        /* need to zero data of old helper */
        memset(&help->help, 0, sizeof(help->help));
-       help->helper = helper;
+       rcu_assign_pointer(help->helper, helper);
 
        return 0;
 }
        struct nf_conn *ct;
        int err = -EINVAL;
        struct nf_conn_help *help;
+       struct nf_conntrack_helper *helper = NULL;
 
        ct = nf_conntrack_alloc(otuple, rtuple);
        if (ct == NULL || IS_ERR(ct))
 #endif
 
        help = nfct_help(ct);
-       if (help)
-               help->helper = nf_ct_helper_find_get(rtuple);
+       if (help) {
+               helper = nf_ct_helper_find_get(rtuple);
+               /* not in hash table yet so not strictly necessary */
+               rcu_assign_pointer(help->helper, helper);
+       }
 
        add_timer(&ct->timeout);
        nf_conntrack_hash_insert(ct);
 
-       if (help && help->helper)
-               nf_ct_helper_put(help->helper);
+       if (helper)
+               nf_ct_helper_put(helper);
 
        return 0;
 
 
        struct nf_conn_help *help = nfct_help(ct);
        struct nf_ct_gre_keymap **kmp, *km;
 
-       BUG_ON(strcmp(help->helper->name, "pptp"));
        kmp = &help->help.ct_pptp_info.keymap[dir];
        if (*kmp) {
                /* check whether it's a retransmission */
        enum ip_conntrack_dir dir;
 
        DEBUGP("entering for ct %p\n", ct);
-       BUG_ON(strcmp(help->helper->name, "pptp"));
 
        write_lock_bh(&nf_ct_gre_lock);
        for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {