/* Timer function; deletes the expectation. */
        struct timer_list timeout;
 
+       /* Usage count. */
+       atomic_t use;
+
 #ifdef CONFIG_IP_NF_NAT_NEEDED
        /* This is the original per-proto part, used to map the
         * expected connection the way the recipient expects. */
 
 extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
 
 /* Allocate space for an expectation: this is mandatory before calling 
-   ip_conntrack_expect_related. */
-extern struct ip_conntrack_expect *ip_conntrack_expect_alloc(void);
-extern void ip_conntrack_expect_free(struct ip_conntrack_expect *exp);
+   ip_conntrack_expect_related.  You will have to call put afterwards. */
+extern struct ip_conntrack_expect *
+ip_conntrack_expect_alloc(struct ip_conntrack *master);
+extern void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
 
 /* Add an expected connection: can have more than one per connection */
 extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp);
 
                if (port == 0 || len > 5)
                        break;
 
-               exp = ip_conntrack_expect_alloc();
+               exp = ip_conntrack_expect_alloc(ct);
                if (exp == NULL) {
                        ret = NF_DROP;
                        goto out;
                }
 
                exp->expectfn = NULL;
-               exp->master = ct;
 
                exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
                exp->tuple.src.u.tcp.port = 0;
                        ret = ip_nat_amanda_hook(pskb, ctinfo,
                                                 tmp - amanda_buffer,
                                                 len, exp);
-               else if (ip_conntrack_expect_related(exp) != 0) {
-                       ip_conntrack_expect_free(exp);
+               else if (ip_conntrack_expect_related(exp) != 0)
                        ret = NF_DROP;
-               }
+               ip_conntrack_expect_put(exp);
        }
 
 out:
 
 
 
 /* ip_conntrack_expect helper functions */
-static void destroy_expect(struct ip_conntrack_expect *exp)
-{
-       ip_conntrack_put(exp->master);
-       IP_NF_ASSERT(!timer_pending(&exp->timeout));
-       kmem_cache_free(ip_conntrack_expect_cachep, exp);
-       CONNTRACK_STAT_INC(expect_delete);
-}
-
 static void unlink_expect(struct ip_conntrack_expect *exp)
 {
        ASSERT_WRITE_LOCK(&ip_conntrack_lock);
+       IP_NF_ASSERT(!timer_pending(&exp->timeout));
        list_del(&exp->list);
-       /* Logically in destroy_expect, but we hold the lock here. */
+       CONNTRACK_STAT_INC(expect_delete);
        exp->master->expecting--;
 }
 
        write_lock_bh(&ip_conntrack_lock);
        unlink_expect(exp);
        write_unlock_bh(&ip_conntrack_lock);
-       destroy_expect(exp);
+       ip_conntrack_expect_put(exp);
 }
 
 /* If an expectation for this connection is found, it gets delete from
        list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
                if (i->master == ct && del_timer(&i->timeout)) {
                        unlink_expect(i);
-                       destroy_expect(i);
+                       ip_conntrack_expect_put(i);
                }
        }
 }
        if (exp) {
                if (exp->expectfn)
                        exp->expectfn(conntrack, exp);
-               destroy_expect(exp);
+               ip_conntrack_expect_put(exp);
        }
 
        return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
                if (expect_matches(i, exp) && del_timer(&i->timeout)) {
                        unlink_expect(i);
                        write_unlock_bh(&ip_conntrack_lock);
-                       destroy_expect(i);
+                       ip_conntrack_expect_put(i);
                        return;
                }
        }
        write_unlock_bh(&ip_conntrack_lock);
 }
 
-struct ip_conntrack_expect *ip_conntrack_expect_alloc(void)
+struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
 {
        struct ip_conntrack_expect *new;
 
                DEBUGP("expect_related: OOM allocating expect\n");
                return NULL;
        }
-       new->master = NULL;
+       new->master = me;
+       atomic_inc(&new->master->ct_general.use);
+       atomic_set(&new->use, 1);
        return new;
 }
 
-void ip_conntrack_expect_free(struct ip_conntrack_expect *expect)
+void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
 {
-       kmem_cache_free(ip_conntrack_expect_cachep, expect);
+       if (atomic_dec_and_test(&exp->use)) {
+               ip_conntrack_put(exp->master);
+               kmem_cache_free(ip_conntrack_expect_cachep, exp);
+       }
 }
 
 static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
 {
-       atomic_inc(&exp->master->ct_general.use);
+       atomic_inc(&exp->use);
        exp->master->expecting++;
        list_add(&exp->list, &ip_conntrack_expect_list);
 
                if (i->master == master) {
                        if (del_timer(&i->timeout)) {
                                unlink_expect(i);
-                               destroy_expect(i);
+                               ip_conntrack_expect_put(i);
                        }
                        break;
                }
                        /* Refresh timer: if it's dying, ignore.. */
                        if (refresh_timer(i)) {
                                ret = 0;
-                               /* We don't need the one they've given us. */
-                               ip_conntrack_expect_free(expect);
                                goto out;
                        }
                } else if (expect_clash(i, expect)) {
        list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
                if (exp->master->helper == me && del_timer(&exp->timeout)) {
                        unlink_expect(exp);
-                       destroy_expect(exp);
+                       ip_conntrack_expect_put(exp);
                }
        }
        /* Get rid of expecteds, set helpers to NULL. */
 
               fb_ptr + matchoff, matchlen, ntohl(th->seq) + matchoff);
                         
        /* Allocate expectation which will be inserted */
-       exp = ip_conntrack_expect_alloc();
+       exp = ip_conntrack_expect_alloc(ct);
        if (exp == NULL) {
                ret = NF_DROP;
                goto out;
                   networks, or the packet filter itself). */
                if (!loose) {
                        ret = NF_ACCEPT;
-                       ip_conntrack_expect_free(exp);
-                       goto out_update_nl;
+                       goto out_put_expect;
                }
                exp->tuple.dst.ip = htonl((array[0] << 24) | (array[1] << 16)
                                         | (array[2] << 8) | array[3]);
                  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
 
        exp->expectfn = NULL;
-       exp->master = ct;
 
        /* Now, NAT might want to mangle the packet, and register the
         * (possibly changed) expectation itself. */
                                      matchoff, matchlen, exp, &seq);
        else {
                /* Can't expect this?  Best to drop packet now. */
-               if (ip_conntrack_expect_related(exp) != 0) {
-                       ip_conntrack_expect_free(exp);
+               if (ip_conntrack_expect_related(exp) != 0)
                        ret = NF_DROP;
-               } else
+               else
                        ret = NF_ACCEPT;
        }
 
+out_put_expect:
+       ip_conntrack_expect_put(exp);
+
 out_update_nl:
        /* Now if this ends in \n, update ftp info.  Seq may have been
         * adjusted by NAT code. */
 
                                continue;
                        }
 
-                       exp = ip_conntrack_expect_alloc();
+                       exp = ip_conntrack_expect_alloc(ct);
                        if (exp == NULL) {
                                ret = NF_DROP;
                                goto out;
                                { { 0, { 0 } },
                                  { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
                        exp->expectfn = NULL;
-                       exp->master = ct;
                        if (ip_nat_irc_hook)
                                ret = ip_nat_irc_hook(pskb, ctinfo, 
                                                      addr_beg_p - ib_ptr,
                                                      addr_end_p - addr_beg_p,
                                                      exp);
-                       else if (ip_conntrack_expect_related(exp) != 0) {
-                               ip_conntrack_expect_free(exp);
+                       else if (ip_conntrack_expect_related(exp) != 0)
                                ret = NF_DROP;
-                       }
+                       ip_conntrack_expect_put(exp);
                        goto out;
                } /* for .. NUM_DCCPROTO */
        } /* while data < ... */
 
 EXPORT_SYMBOL(ip_ct_protos);
 EXPORT_SYMBOL(ip_ct_find_proto);
 EXPORT_SYMBOL(ip_conntrack_expect_alloc);
-EXPORT_SYMBOL(ip_conntrack_expect_free);
+EXPORT_SYMBOL(ip_conntrack_expect_put);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 
                DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
                DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-               exp = ip_conntrack_expect_alloc();
+               exp = ip_conntrack_expect_alloc(ct);
                if (exp == NULL)
                        return NF_DROP;
 
                exp->mask.dst.u.udp.port = 0xffff;
                exp->mask.dst.protonum = 0xff;
                exp->expectfn = NULL;
-               exp->master = ct;
 
                DEBUGP("expect: ");
                DUMP_TUPLE(&exp->tuple);
                DUMP_TUPLE(&exp->mask);
                if (ip_nat_tftp_hook)
                        ret = ip_nat_tftp_hook(pskb, ctinfo, exp);
-               else if (ip_conntrack_expect_related(exp) != 0) {
-                       ip_conntrack_expect_free(exp);
+               else if (ip_conntrack_expect_related(exp) != 0)
                        ret = NF_DROP;
-               }
+               ip_conntrack_expect_put(exp);
                break;
        case TFTP_OPCODE_DATA:
        case TFTP_OPCODE_ACK:
 
                        break;
        }
 
-       if (port == 0) {
-               ip_conntrack_expect_free(exp);
+       if (port == 0)
                return NF_DROP;
-       }
 
        sprintf(buffer, "%u", port);
        ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
 
                        break;
        }
 
-       if (port == 0) {
-               ip_conntrack_expect_free(exp);
+       if (port == 0)
                return NF_DROP;
-       }
 
        if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
                          seq)) {
 
                        break;
        }
 
-       if (port == 0) {
-               ip_conntrack_expect_free(exp);
+       if (port == 0)
                return NF_DROP;
-       }
 
        /*      strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
         *      strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
 
        exp->saved_proto.udp.port = exp->tuple.dst.u.tcp.port;
        exp->dir = IP_CT_DIR_REPLY;
        exp->expectfn = ip_nat_follow_master;
-       if (ip_conntrack_expect_related(exp) != 0) {
-               ip_conntrack_expect_free(exp);
+       if (ip_conntrack_expect_related(exp) != 0)
                return NF_DROP;
-       }
        return NF_ACCEPT;
 }