Work on the radix code, added support to compile on OpenWRT,
[ipfw.git] / dummynet / ip_fw2.c
index 50e8701..4e46566 100644 (file)
@@ -104,6 +104,10 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 
 #include <machine/in_cksum.h>  /* XXX for in_cksum */
 
+#ifdef IPFW_HASHTABLES
+#include "hashtable.h"
+#endif
+
 #ifdef MAC
 #include <security/mac/mac_framework.h>
 #endif
@@ -135,21 +139,6 @@ static int default_to_accept;
 #endif
 static uma_zone_t ipfw_dyn_rule_zone;
 
-struct ip_fw *ip_fw_default_rule;
-
-/*
- * Data structure to cache our ucred related
- * information. This structure only gets used if
- * the user specified UID/GID based constraints in
- * a firewall rule.
- */
-struct ip_fw_ugid {
-       gid_t           fw_groups[NGROUPS];
-       int             fw_ngroups;
-       uid_t           fw_uid;
-       int             fw_prid;
-};
-
 /*
  * list of rules for layer 3
  */
@@ -194,12 +183,18 @@ SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose,
 SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,
     CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,
     "Set upper limit of matches of ipfw rules logged");
+static unsigned int dummy_default_rule = IPFW_DEFAULT_RULE;
 SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
-    NULL, IPFW_DEFAULT_RULE,
+    &dummy_default_rule, IPFW_DEFAULT_RULE,
     "The default/max possible rule number.");
+static unsigned int dummy_tables_max = IPFW_TABLES_MAX;
 SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
-    NULL, IPFW_TABLES_MAX,
+    &dummy_tables_max, IPFW_TABLES_MAX,
     "The maximum number of tables.");
+static unsigned int skipto_entries = 256;
+SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, skipto_entries,
+    CTLFLAG_RW, &skipto_entries, 0,
+    "Number of entries in the skipto cache");
 SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
     &default_to_accept, 0,
     "Make the default rule accept all packets.");
@@ -218,9 +213,6 @@ SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
 
 #endif /* SYSCTL_NODE */
 
-#ifndef IPFW_NEWTABLES_MAX
-#define IPFW_NEWTABLES_MAX     256
-#endif
 /*
  * Description of dynamic rules.
  *
@@ -1894,6 +1886,61 @@ send_reject(struct ip_fw_args *args, int code, int ip_len, struct ip *ip)
        args->m = NULL;
 }
 
+static void
+set_skipto_table(struct ip_fw_chain *ch)
+{
+       int i, n, sh;
+       struct ip_fw *f, **t, **oldt;
+
+       for (sh = 15; sh > 0; sh--)
+               if (skipto_entries > 1<<sh)
+                       break;
+       sh++;
+       skipto_entries = 1<< (16 - sh) ;
+       /* XXX unsafe and too long */
+       t = malloc(skipto_entries * sizeof(*t), M_IPFW_TBL, M_WAITOK | M_ZERO);
+       if (t == NULL)
+               return;
+       IPFW_RLOCK(ch);
+       /* Store pointers in the table. In the loop i is the next
+        * free slot, n is the slot where the current rule goes.
+        */
+       for (i = 0, f = ch->rules; f; f = f->next) {
+               n = f->rulenum >> sh ;
+               while (i <= n)
+                       t[i++] = f;
+       }
+       V_layer3_chain.skipto_shift = sh;
+       V_layer3_chain.skipto_size = skipto_entries;
+       oldt = V_layer3_chain.skipto_ptrs;
+       V_layer3_chain.skipto_ptrs = t;
+       IPFW_RUNLOCK(ch);
+       if (oldt) {
+               IPFW_WLOCK(ch);
+               IPFW_WUNLOCK(ch);
+               /* now can free oldt */
+               free(oldt, M_IPFW_TBL);
+       }
+}
+#if 0
+/*
+ * Map a rule number to a rule pointer, using the skipto table.
+ * First lookup the slot, then follow the chain until we find a
+ * non-null entry with rulenum >= num. Return default_rule on error.
+ */
+static struct ip_fw *
+rule2ptr(struct ip_fw_chain *ch, int num)
+{
+       struct ip_fw *r = NULL;
+       int ix = (num & 0xffff) >> ch->skipto_shift;
+
+       while (ix < ch->skipto_size && (r = ch->skipto_ptrs[ix]) == NULL)
+               ix++;
+       while (r && num < r->rulenum)
+               r = r->next;
+       return (r ? r : ch->default_rule);
+}
+#endif
 /**
  *
  * Given an ip_fw *, lookup_next_rule will return a pointer
@@ -1910,12 +1957,11 @@ send_reject(struct ip_fw_args *args, int code, int ip_len, struct ip *ip)
  */
 
 static struct ip_fw *
-lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
+lookup_next_rule(struct ip_fw_chain *ch, struct ip_fw *me, uint32_t tablearg)
 {
        struct ip_fw *rule = NULL;
        ipfw_insn *cmd;
-       u_int16_t       rulenum;
-printf("%s called\n", __FUNCTION__);
+
        /* look for action, in case it is a skipto */
        cmd = ACTION_PTR(me);
        if (cmd->opcode == O_LOG)
@@ -1924,56 +1970,22 @@ printf("%s called\n", __FUNCTION__);
                cmd += F_LEN(cmd);
        if (cmd->opcode == O_TAG)
                cmd += F_LEN(cmd);
-       if (cmd->opcode == O_SKIPTO ) {
-               if (tablearg != 0) {
-                       rulenum = (u_int16_t)tablearg;
-               } else {
-                       rulenum = cmd->arg1;
-               }
+       if (cmd->opcode != O_SKIPTO ) {
+               rule = me->next;
+       } else {
+               tablearg = tablearg ? tablearg : cmd->arg1;
                for (rule = me->next; rule ; rule = rule->next) {
-                       if (rule->rulenum >= rulenum) {
+                       if (rule->rulenum >= tablearg) {
                                break;
                        }
                }
-       }
-       if (rule == NULL)                       /* failure or not a skipto */
-               rule = me->next;
-       me->next_rule = rule;
-       return rule;
-}
-
-#ifdef IPFW_HAVE_SKIPTO_TABLE
-struct ip_fw *lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num);
 
-struct ip_fw *
-lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num)
-{
-       struct ip_fw *f;
-
-       printf("--%s called\n", __FUNCTION__);
-       if (1)
-               return NULL;
-       if (chain->skipto_pointers[num].id == chain->id) {
-               printf("-- %s pointer ok, return it\n", __FUNCTION__);
-               return chain->skipto_pointers[num].rule;
+//             rule = rule2ptr(ch, tablearg ? tablearg : cmd->arg1);
        }
-       printf("-- %s search pointer\n", __FUNCTION__);
-
-       for (f = chain->rules; f ; f = f->next) {
-               if (f->rulenum == num) {
-                       chain->skipto_pointers[num].id = chain->id;
-                       chain->skipto_pointers[num].rule = f;
-                       printf("-- %s found, set and return\n", __FUNCTION__);
-                       return f;
-               }
-       }
-       printf("-- %s NOT found return NULL\n", __FUNCTION__);
-
-       return NULL;
+       me->next_rule = rule; /* XXX perhaps unnecessary ? */
+       return rule;
 }
-#endif /* IPFW_HAVE_SKIPTO_TABLE */
 
-#ifdef radix
 static int
 add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
     uint8_t mlen, uint32_t value)
@@ -1982,6 +1994,11 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        struct table_entry *ent;
        struct radix_node *rn;
 
+#ifdef IPFW_HASHTABLES
+       if (tbl >= 2*IPFW_TABLES_MAX)
+               return EINVAL;
+       return EINVAL; // XXX to be completed
+#endif
        if (tbl >= IPFW_TABLES_MAX)
                return (EINVAL);
        rnh = ch->tables[tbl];
@@ -1989,7 +2006,16 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        if (ent == NULL)
                return (ENOMEM);
        ent->value = value;
+#ifdef linux
+       /* there is no sin_len on linux, and the code assumes the first
+        * byte in the sockaddr to contain the length in bits.
+        * So we just dump the number right there
+        */
+       *((uint8_t *)&(ent->addr)) = 8;
+       *((uint8_t *)&(ent->mask)) = 8;
+#else
        ent->addr.sin_len = ent->mask.sin_len = 8;
+#endif
        ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
        ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
        IPFW_WLOCK(ch);
@@ -2011,10 +2037,21 @@ del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        struct table_entry *ent;
        struct sockaddr_in sa, mask;
 
+#ifdef IPFW_HASHTABLES
+       if (tbl >= 2*IPFW_TABLES_MAX)
+               return EINVAL;
+       return EINVAL; // XXX to be completed
+#endif
        if (tbl >= IPFW_TABLES_MAX)
                return (EINVAL);
        rnh = ch->tables[tbl];
+#ifdef linux
+       /* there is no sin_len on linux, see above */
+       *((uint8_t *)&sa) = 8;
+       *((uint8_t *)&mask) = 8;
+#else
        sa.sin_len = mask.sin_len = 8;
+#endif
        mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
        sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
        IPFW_WLOCK(ch);
@@ -2048,6 +2085,11 @@ flush_table(struct ip_fw_chain *ch, uint16_t tbl)
 
        IPFW_WLOCK_ASSERT(ch);
 
+#ifdef IPFW_HASHTABLES
+       if (tbl >= 2*IPFW_TABLES_MAX)
+               return EINVAL;
+       return EINVAL; // XXX to be completed
+#endif
        if (tbl >= IPFW_TABLES_MAX)
                return (EINVAL);
        rnh = ch->tables[tbl];
@@ -2055,18 +2097,6 @@ flush_table(struct ip_fw_chain *ch, uint16_t tbl)
        rnh->rnh_walktree(rnh, flush_table_entry, rnh);
        return (0);
 }
-#else
-extern int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
-    in_addr_t addr, uint8_t mlen, uint32_t value);
-extern int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
-    in_addr_t addr, uint8_t mlen);
-extern int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
-extern int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
-extern int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
-extern int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
-    uint32_t *val);
-extern int init_tables(struct ip_fw_chain *ch);
-#endif
 
 static void
 flush_tables(struct ip_fw_chain *ch)
@@ -2075,11 +2105,14 @@ flush_tables(struct ip_fw_chain *ch)
 
        IPFW_WLOCK_ASSERT(ch);
 
-       for (tbl = IPFW_TABLES_MAX -1; tbl < IPFW_NEWTABLES_MAX; tbl++)
+       for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
                flush_table(ch, tbl);
+#ifdef IPFW_HASHTABLES
+       for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
+               ch->hashtab[tbl] = ipfw_ht_destroy(ch->hashtab[tbl]);
+#endif
 }
 
-#ifdef radix
 static int
 init_tables(struct ip_fw_chain *ch)
 { 
@@ -2094,6 +2127,10 @@ init_tables(struct ip_fw_chain *ch)
                        return (ENOMEM);
                }
        }
+#ifdef IPFW_HASHTABLES
+        for (i = 0; i < IPFW_TABLES_MAX; i++)
+               ch->hashtab[i] = ipfw_ht_destroy(ch->hashtab[i]);
+#endif
        return (0);
 }
 
@@ -2108,7 +2145,12 @@ lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        if (tbl >= IPFW_TABLES_MAX)
                return (0);
        rnh = ch->tables[tbl];
+#ifdef linux
+       /* there is no sin_len on linux, see above */
+       *((uint8_t *)&sa) = 8;
+#else
        sa.sin_len = 8;
+#endif
        sa.sin_addr.s_addr = addr;
        ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh));
        if (ent != NULL) {
@@ -2117,9 +2159,7 @@ lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        }
        return (0);
 }
-#endif
 
-#ifdef radix
 static int
 count_table_entry(struct radix_node *rn, void *arg)
 {
@@ -2175,52 +2215,37 @@ dump_table(struct ip_fw_chain *ch, ipfw_table *tbl)
        rnh->rnh_walktree(rnh, dump_table_entry, tbl);
        return (0);
 }
-#endif
-
-#ifndef linux /* FreeBSD */
-static void
-fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp)
-{
-       struct ucred *cr;
-
-       cr = inp->inp_cred;
-       ugp->fw_prid = jailed(cr) ? cr->cr_prison->pr_id : -1;
-       ugp->fw_uid = cr->cr_uid;
-       ugp->fw_ngroups = cr->cr_ngroups;
-       bcopy(cr->cr_groups, ugp->fw_groups, sizeof(ugp->fw_groups));
-}
-#endif
 
 static int
 check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
-    u_int16_t src_port, struct ip_fw_ugid *ugp, int *ugid_lookupp,
+    u_int16_t src_port, struct ucred **uc, int *ugid_lookup,
     struct inpcb *inp)
 {
 #ifdef linux
        int match = 0;
        struct sk_buff *skb = ((struct mbuf *)inp)->m_skb;
+       struct bsd_ucred *u = (struct bsd_ucred *)uc;
 
-       if (*ugid_lookupp == 0) {       /* actively lookup and copy in cache */
-
+       if (*ugid_lookup == 0) {        /* actively lookup and copy in cache */
                /* returns null if any element of the chain up to file is null.
                 * if sk != NULL then we also have a reference 
                 */
-               *ugid_lookupp = linux_lookup(proto,
+               *ugid_lookup = linux_lookup(proto,
                        src_ip.s_addr, htons(src_port),
                        dst_ip.s_addr, htons(dst_port),
-                       skb, oif ? 1 : 0, ugp);
+                       skb, oif ? 1 : 0, u);
 
        }
-       if (*ugid_lookupp < 0)
+       if (*ugid_lookup < 0)
                return 0;
 
        if (insn->o.opcode == O_UID)
-               match = (ugp->fw_uid == (uid_t)insn->d[0]);
+               match = (u->uid == (uid_t)insn->d[0]);
        else if (insn->o.opcode == O_JAIL)
-               match = (ugp->fw_groups[1] == (uid_t)insn->d[0]);
+               match = (u->xid == (uid_t)insn->d[0]);
        else if (insn->o.opcode == O_GID)
-               match = (ugp->fw_groups[0] == (uid_t)insn->d[0]);
+               match = (u->gid == (uid_t)insn->d[0]);
 
        return match;
 
@@ -2230,7 +2255,6 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
        int wildcard;
        struct inpcb *pcb;
        int match;
-       gid_t *gp;
 
        /*
         * Check to see if the UDP or TCP stack supplied us with
@@ -2240,7 +2264,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
        if (inp && *ugid_lookupp == 0) {
                INP_LOCK_ASSERT(inp);
                if (inp->inp_socket != NULL) {
-                       fill_ugid_cache(inp, ugp);
+                       *uc = crhold(inp->inp_cred);
                        *ugid_lookupp = 1;
                } else
                        *ugid_lookupp = -1;
@@ -2273,7 +2297,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
                                dst_ip, htons(dst_port),
                                wildcard, NULL);
                if (pcb != NULL) {
-                       fill_ugid_cache(pcb, ugp);
+                       *uc = crhold(pcb->inp_cred);
                        *ugid_lookupp = 1;
                }
                INP_INFO_RUNLOCK(pi);
@@ -2289,16 +2313,11 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
                }
        } 
        if (insn->o.opcode == O_UID)
-               match = (ugp->fw_uid == (uid_t)insn->d[0]);
-       else if (insn->o.opcode == O_GID) {
-               for (gp = ugp->fw_groups;
-                       gp < &ugp->fw_groups[ugp->fw_ngroups]; gp++)
-                       if (*gp == (gid_t)insn->d[0]) {
-                               match = 1;
-                               break;
-                       }
-       } else if (insn->o.opcode == O_JAIL)
-               match = (ugp->fw_prid == (int)insn->d[0]);
+               match = ((*uc)->cr_uid == (uid_t)insn->d[0]);
+       else if (insn->o.opcode == O_GID)
+               match = groupmember((gid_t)insn->d[0], *uc);
+       else if (insn->o.opcode == O_JAIL)
+               match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
        return match;
 #endif
 }
@@ -2375,8 +2394,8 @@ ipfw_chk(struct ip_fw_args *args)
         * these types of constraints, as well as decrease contention
         * on pcb related locks.
         */
-       struct ip_fw_ugid fw_ugid_cache;
-       int ugid_lookup = 0;
+       struct bsd_ucred ucred_cache;
+       int ucred_lookup = 0;
 
        /*
         * divinput_flags       If non-zero, set to the IP_FW_DIVERT_*_FLAG
@@ -2735,11 +2754,20 @@ do {                                                                    \
                        IPFW_RUNLOCK(chain);
                        return (IP_FW_PASS);
                }
+               if (chain->id != args->chain_id) {
+                       for (f = chain->rules; f != NULL; f = f->next)
+                               if (f == args->rule && f->id == args->rule_id)
+                                       break;
 
-               f = args->rule->next_rule;
+                       if (f != NULL)
+                               f = f->next_rule;
+                       else
+                               f = chain->default_rule;
+               } else
+                       f = args->rule->next_rule;
 
                if (f == NULL)
-                       f = lookup_next_rule(args->rule, 0);
+                       f = lookup_next_rule(chain, args->rule, 0);
        } else {
                /*
                 * Find the starting rule. It can be either the first
@@ -2753,12 +2781,9 @@ do {                                                                     \
                                IPFW_RUNLOCK(chain);
                                return (IP_FW_DENY); /* invalid */
                        }
+//                     f = rule2ptr(chain, skipto+1);
                        while (f && f->rulenum <= skipto)
                                f = f->next;
-                       if (f == NULL) {        /* drop packet */
-                               IPFW_RUNLOCK(chain);
-                               return (IP_FW_DENY);
-                       }
                }
        }
        /* reset divert rule to avoid confusion later */
@@ -2857,8 +2882,8 @@ do {                                                                      \
                                                    (ipfw_insn_u32 *)cmd,
                                                    proto, oif,
                                                    dst_ip, dst_port,
-                                                   src_ip, src_port, &fw_ugid_cache,
-                                                   &ugid_lookup, (struct inpcb *)args->m);
+                                                   src_ip, src_port, (struct ucred **)&ucred_cache,
+                                                   &ucred_lookup, (struct inpcb *)args->m);
                                break;
 
                        case O_RECV:
@@ -2964,14 +2989,23 @@ do {                                                                    \
                                                    (ipfw_insn_u32 *)cmd,
                                                    proto, oif,
                                                    dst_ip, dst_port,
-                                                   src_ip, src_port, &fw_ugid_cache,
-                                                   &ugid_lookup, (struct inpcb *)args->m);
+                                                   src_ip, src_port, (struct ucred **)&ucred_cache,
+                                                   &ucred_lookup, (struct inpcb *)args->m);
+#ifdef linux
+                                           if (v ==4 /* O_UID */)
+                                               a = ucred_cache.uid;
+                                           else if (v == 5 /* O_GID */)
+                                               a = ucred_cache.gid;
+                                           else if (v == 6 /* O_JAIL */)
+                                               a = ucred_cache.xid;
+#else
                                            if (v ==4 /* O_UID */)
-                                               a = fw_ugid_cache.fw_uid;
+                                               a = (*uc)->cr_uid;
                                            else if (v == 5 /* O_GID */)
-                                               a = fw_ugid_cache.fw_groups[0];
+                                               ; // a = groupmember((gid_t)insn->d[0], *uc);
                                            else if (v == 6 /* O_JAIL */)
-                                               a = fw_ugid_cache.fw_groups[1];
+                                               a = (*uc)->cr_prison->pr_id;
+#endif
                                        } else
                                            break;
                                    }
@@ -3555,37 +3589,13 @@ do {                                                                    \
                                        break;
                                }
                                /* handle skipto */
-#ifdef IPFW_HAVE_SKIPTO_TABLE
-                               /* NOTE: lookup_skipto_table can return NULL
-                                *       if the rule isn't found, so the
-                                *       standard lookup function must be
-                                *       called XXX
-                                */
-                               if (cmd->arg1 == IP_FW_TABLEARG) {
-                                       f = lookup_skipto_table(chain,
-                                                                tablearg);
-                                       if (f == NULL)
-                                               f = lookup_next_rule(f, tablearg);
-                               }
-                                else {
-                                       f = lookup_skipto_table(chain,
-                                                                cmd->arg1);
-                                       if (f == NULL) {
-                                               if (f->next_rule == NULL)
-                                                       lookup_next_rule(f, 0);
-                                               f = f->next_rule;
-                                       }
-                                }
-
-#else
                                if (cmd->arg1 == IP_FW_TABLEARG) {
-                                       f = lookup_next_rule(f, tablearg);
+                                       f = lookup_next_rule(chain, f, tablearg);
                                } else {
                                        if (f->next_rule == NULL)
-                                               lookup_next_rule(f, 0);
+                                               lookup_next_rule(chain, f, 0);
                                        f = f->next_rule;
                                }
-#endif
                                /*
                                 * Skip disabled rules, and
                                 * re-enter the inner loop
@@ -3809,6 +3819,10 @@ do {                                                                     \
                printf("ipfw: ouch!, skip past end of rules, denying packet\n");
        }
        IPFW_RUNLOCK(chain);
+#ifdef __FreeBSD__
+       if (ucred_cache != NULL)
+               crfree(ucred_cache);
+#endif
        return (retval);
 
 pullup_failed:
@@ -3869,17 +3883,15 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
                goto done;
         }
 
-       /*
-        * If rulenum is 0, find highest numbered rule before the
-        * default rule, and add autoinc_step
-        */
        if (V_autoinc_step < 1)
                V_autoinc_step = 1;
        else if (V_autoinc_step > 1000)
                V_autoinc_step = 1000;
        if (rule->rulenum == 0) {
                /*
-                * locate the highest numbered rule before default
+                * If rulenum is 0, use highest numbered rule before
+                * the default, adding autoinc_step if room.
+                * Also set the number in the caller.
                 */
                for (f = chain->rules; f; f = f->next) {
                        if (f->rulenum == IPFW_DEFAULT_RULE)
@@ -3893,6 +3905,7 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
 
        /*
         * Now insert the new rule in the right place in the sorted list.
+        * XXX TODO also put in the skipto table.
         */
        for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) {
                if (f->rulenum > rule->rulenum) { /* found the location */
@@ -3945,6 +3958,7 @@ remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
                prev->next = n;
        V_static_count--;
        V_static_len -= l;
+       // XXX remove from the skipto table
 
        rule->next = chain->reap;
        chain->reap = rule;
@@ -3953,12 +3967,6 @@ remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
 }
 
 /*
- * Hook for cleaning up dummynet when an ipfw rule is deleted.
- * Set/cleared when dummynet module is loaded/unloaded.
- */
-void   (*ip_dn_ruledel_ptr)(void *) = NULL;
-
-/**
  * Reclaim storage associated with a list of rules.  This is
  * typically the list created using remove_rule.
  * A NULL pointer on input is handled correctly.
@@ -3970,8 +3978,6 @@ reap_rules(struct ip_fw *head)
 
        while ((rule = head) != NULL) {
                head = head->next;
-               if (ip_dn_ruledel_ptr)
-                       ip_dn_ruledel_ptr(rule);
                free(rule, M_IPFW);
        }
 }
@@ -3988,6 +3994,7 @@ free_chain(struct ip_fw_chain *chain, int kill_default)
 
        IPFW_WLOCK_ASSERT(chain);
 
+       chain->reap = NULL;
        flush_rule_ptrs(chain); /* more efficient to do outside the loop */
        for (prev = NULL, rule = chain->rules; rule ; )
                if (kill_default || rule->set != RESVD_SET)
@@ -4115,10 +4122,8 @@ del_entry(struct ip_fw_chain *chain, u_int32_t arg)
         * avoid a LOR with dummynet.
         */
        rule = chain->reap;
-       chain->reap = NULL;
        IPFW_WUNLOCK(chain);
-       if (rule)
-               reap_rules(rule);
+       reap_rules(rule);
        return 0;
 }
 
@@ -4531,7 +4536,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
        int i;
        time_t  boot_seconds;
 
-        boot_seconds = boottime.tv_sec;
+       boot_seconds = boottime.tv_sec;
        /* XXX this can take a long time and locking will block packet flow */
        IPFW_RLOCK(chain);
        for (rule = chain->rules; rule ; rule = rule->next) {
@@ -4619,7 +4624,6 @@ ipfw_getdynrules(struct ip_fw_chain *chain, void *buf, size_t space)
                if (last != NULL) /* mark last dynamic rule */
                        bzero(&last->next, sizeof(last));
        }
-
        return (bp - (char *)buf);
 }
 
@@ -4706,13 +4710,10 @@ ipfw_ctl(struct sockopt *sopt)
                 */
 
                IPFW_WLOCK(&V_layer3_chain);
-               V_layer3_chain.reap = NULL;
                free_chain(&V_layer3_chain, 0 /* keep default rule */);
                rule = V_layer3_chain.reap;
-               V_layer3_chain.reap = NULL;
                IPFW_WUNLOCK(&V_layer3_chain);
-               if (rule != NULL)
-                       reap_rules(rule);
+               reap_rules(rule);
                break;
 
        case IP_FW_ADD:
@@ -4905,14 +4906,6 @@ ipfw_ctl(struct sockopt *sopt)
 #undef RULE_MAXSIZE
 }
 
-/**
- * dummynet needs a reference to the default rule, because rules can be
- * deleted while packets hold a reference to them. When this happens,
- * dummynet changes the reference to the default rule (it could well be a
- * NULL pointer, but this way we do not need to check for the special
- * case, plus here he have info on the default behaviour).
- */
-//struct ip_fw *ip_fw_default_rule;
 
 /*
  * This procedure is only used to handle keepalives. It is invoked
@@ -5010,7 +5003,7 @@ ipfw_tick(void * vnetx)
 #endif
 done:
        callout_reset(&V_ipfw_timeout, V_dyn_keepalive_period*hz,
-               ipfw_tick, NULL);
+               ipfw_tick, vnetx);
        CURVNET_RESTORE();
 }
 
@@ -5132,12 +5125,6 @@ vnet_ipfw_init(const void *unused)
        if (error) {
                panic("init_tables"); /* XXX Marko fix this ! */
        }
-
-#ifdef IPFW_HAVE_SKIPTO_TABLE
-//     for (error = 0; error < 64*1024; error++)
-//             V_layer3_chain.skipto_pointers[error].id = -1;
-#endif /* IPFW_HAVE_SKIPTO_TABLE */
-
 #ifdef IPFIREWALL_NAT
        LIST_INIT(&V_layer3_chain.nat);
 #endif
@@ -5167,6 +5154,8 @@ vnet_ipfw_init(const void *unused)
        IPFW_LOCK_INIT(&V_layer3_chain);
        callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);
 
+       set_skipto_table(&V_layer3_chain);
+
        bzero(&default_rule, sizeof default_rule);
        default_rule.act_ofs = 0;
        default_rule.rulenum = IPFW_DEFAULT_RULE;
@@ -5184,7 +5173,7 @@ vnet_ipfw_init(const void *unused)
                return (error);
        }
 
-       ip_fw_default_rule = V_layer3_chain.rules;
+       V_layer3_chain.default_rule = V_layer3_chain.rules;
 
        /* curvnet is NULL in the !VIMAGE case */
        callout_reset(&V_ipfw_timeout, hz, ipfw_tick, curvnet);