+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