Grab the lock before reading uid/gid related structure, this will
marta [Wed, 9 Dec 2009 11:24:41 +0000 (11:24 +0000)]
fix a panic present on the previous versions while matching users.

Start to commit the work on ipfw tables, some little changes on
include files generation (removed empty files, removed common
includes between kernel and user space).

66 files changed:
README
dummynet/Makefile
dummynet/hashtable.c [new file with mode: 0644]
dummynet/hashtable.h [new file with mode: 0644]
dummynet/include/netgraph/ng_ipfw.h
dummynet/include/netinet/ip_dummynet.h
dummynet/include/netinet/ip_fw.h
dummynet/ip_dummynet.c
dummynet/ip_fw2.c
dummynet/ip_fw_pfil.c
dummynet/ipfw2_mod.c
dummynet/missing.h
dummynet/new_glue.c [new file with mode: 0644]
glue.h
include_e/altq/if_altq.h [deleted file]
include_e/arpa/inet.h [deleted file]
include_e/machine/in_cksum.h [deleted file]
include_e/net/ethernet.h [deleted file]
include_e/net/netisr.h [deleted file]
include_e/net/pf_mtag.h [deleted file]
include_e/net/radix.h [deleted file]
include_e/netinet/ether.h [deleted file]
include_e/netinet/icmp6.h [deleted file]
include_e/netinet/if_ether.h [deleted file]
include_e/netinet/in.h [deleted file]
include_e/netinet/in_pcb.h [deleted file]
include_e/netinet/in_var.h [deleted file]
include_e/netinet/ip_carp.h [deleted file]
include_e/netinet/ip_var.h [deleted file]
include_e/netinet/pim.h [deleted file]
include_e/netinet/sctp.h [deleted file]
include_e/netinet/tcp_timer.h [deleted file]
include_e/netinet/tcpip.h [deleted file]
include_e/netinet/udp_var.h [deleted file]
include_e/netinet6/ip6_var.h [deleted file]
include_e/opt_inet6.h [deleted file]
include_e/opt_ipfw.h [deleted file]
include_e/opt_ipsec.h [deleted file]
include_e/opt_mac.h [deleted file]
include_e/opt_mbuf_stress_test.h [deleted file]
include_e/opt_param.h [deleted file]
include_e/sys/_lock.h [deleted file]
include_e/sys/_mutex.h [deleted file]
include_e/sys/jail.h [deleted file]
include_e/sys/limits.h [deleted file]
include_e/sys/lock.h [deleted file]
include_e/sys/mutex.h [deleted file]
include_e/sys/priv.h [deleted file]
include_e/sys/proc.h [deleted file]
include_e/sys/rwlock.h [deleted file]
include_e/sys/socket.h [deleted file]
include_e/sys/socketvar.h [deleted file]
include_e/sys/sysctl.h [deleted file]
include_e/sys/time.h [deleted file]
include_e/sys/ucred.h [deleted file]
ipfw.spec
ipfw/Makefile
ipfw/dummynet.c
ipfw/expand_number.c [new file with mode: 0644]
ipfw/glue.c
ipfw/humanize_number.c [new file with mode: 0644]
ipfw/include/netinet/ip_dummynet.h [deleted file]
ipfw/include/netinet/ip_fw.h [deleted file]
ipfw/include/netinet/tcp.h [deleted file]
ipfw/ipfw2.c
ipfw/ipfw2.h

diff --git a/README b/README
index fe5c578..bfd3289 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 #
-# $Id$
+# $Id: README 4363 2009-12-08 16:06:54Z marta $
 #
 
 This directory contains a port of ipfw and dummynet to Linux and OpenWrt
@@ -10,7 +10,7 @@ Building the code produces:
        a userland program,     /sbin/ipfw
 
 The source code here comes straight from FreeBSD (roughly the
-version in RELENG_7 and HEAD as of June 2009), plus some glue code
+version in RELENG_7 and HEAD as of December 2009), plus some glue code
 and headers written from scratch.
 Unless specified otherwise, all the code here is under a BSD license.
 
index 7cbddca..e732601 100644 (file)
@@ -135,7 +135,7 @@ ipfw_mod-y = $(IPFW_SRCS:%.c=%.o)
 IPFW_SRCS = ip_fw2.c ip_dummynet.c ip_fw_pfil.c in_cksum.c
 
 # Module glue and functions missing in linux
-IPFW_SRCS += ipfw2_mod.c bsd_compat.c
+IPFW_SRCS += ipfw2_mod.c bsd_compat.c hashtable.c new_glue.c
 
 # additional $(CC) flags
 ccflags-y += $(WARN)
@@ -166,6 +166,7 @@ EFILES += altq/if_altq.h
 EFILES += arpa/inet.h
 EFILES += machine/in_cksum.h
 EFILES += net/ethernet.h net/netisr.h net/pf_mtag.h net/radix.h
+EFILES += net/vnet.h
 
 EFILES += netinet/ether.h netinet/icmp6.h netinet/if_ether.h
 EFILES += netinet/in.h netinet/in_pcb.h netinet/in_var.h
diff --git a/dummynet/hashtable.c b/dummynet/hashtable.c
new file mode 100644 (file)
index 0000000..517cec6
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * XXX Copyright
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include "hashtable.h" // XXX fix path later
+
+struct new_obj {
+       struct new_obj *next;   /* Next object in the list */
+       char obj[0];            /* actually bigger */
+};
+
+/* Hash table */
+struct new_hash_table {
+       int table_size;         /* Size of the table (buckets) */
+       int table_obj;          /* number of object in the table */
+       int obj_size;           /* size of object (key + value) */
+       /* Hash function for this table */
+       uint32_t (*hash)(const void *key, uint32_t size);
+       int (*cmp)(const void *obj1, const void *obj2);
+       int hash_arg;           /* hash function parameter */
+       struct malloc_type *mtype;
+       struct new_obj **table_ptr;     /* Pointer to the table */
+};
+
+/*
+ * initialize an hash table
+ * - size:     size of table (number of buckets)
+ * - obj_size: size of the object to store in the table (key + value)
+ * - hf:       pointer to the hash function for this table
+ * - compare:  function to compare two objects
+ *
+ * Return value: pointer to the hash table, NULL if error occurs
+ */
+struct new_hash_table *
+new_table_init (int size, int obj_size,
+       uint32_t (hf)(const void *, uint32_t size),
+       int (compare)(const void *, const void *),
+       struct malloc_type *mtype)
+{
+       struct new_hash_table *h;
+
+       printf("%s called\n", __FUNCTION__);
+
+       h = malloc(sizeof(struct new_hash_table), mtype, M_NOWAIT | M_ZERO);
+       if (h == NULL)
+               return NULL;
+
+       h->table_ptr = malloc(size * sizeof(struct new_obj*), mtype,
+                              M_NOWAIT | M_ZERO);
+       if (h->table_ptr == NULL) { /* no memory */
+               free (h, mtype);
+               return 0;
+       }
+       h->table_size = size;
+       h->hash = hf;
+       h->cmp = compare;
+       h->mtype = mtype;
+       h->obj_size = obj_size;
+
+       return h;
+}
+
+int
+new_table_insert_obj (struct new_hash_table *h, const void *obj)
+{
+       int i; /* array index */
+       struct new_obj *o, *ot;
+       
+       i = h->hash(obj, h->table_size);
+       
+       /* same key not allowed */
+       for (ot = h->table_ptr[i]; ot; ot = ot->next) {
+               if (h->cmp(obj, ot->obj) == 0)
+                       return 1; /* error */
+       }
+       /* allocate a single chunk of memory */
+       o = malloc(sizeof(*o) + h->obj_size, h->mtype, M_NOWAIT);
+       if (o == NULL)
+               return 1;
+       bcopy(obj, o->obj, h->obj_size);
+
+       /* put at the head */
+       o->next = h->table_ptr[i];
+       h->table_ptr[i] = o;
+
+       h->table_obj++;
+
+       return 0;
+}
+
+int
+new_table_delete_obj(struct new_hash_table *h, const void *obj)
+{
+       int i;
+       struct new_obj *obj1, *prev;
+
+       i = h->hash(obj, h->table_size);
+
+       for (prev = NULL, obj1 = h->table_ptr[i]; obj1; obj1 = obj1->next) {
+               if (h->cmp(obj, (void *)obj1->obj) != 0)
+                       continue;
+               /* Object found, delete */
+               if (prev != NULL)
+                       prev->next = obj1->next;
+               else
+                       h->table_ptr[i] = obj1->next;
+               free(obj1, h->mtype);
+               h->table_obj--;
+               return 0;
+       }
+       return 1; /* Not found */
+}
+
+const void *
+new_table_extract_obj(struct new_hash_table *h, const void *obj)
+{
+       struct new_obj *o;
+       int i;
+       if (h == NULL || h->table_obj == 0)
+               return NULL;
+
+       i = h->hash(obj, h->table_size);
+       for (o =  h->table_ptr[i]; o; o = o->next) {
+               if (h->cmp(o->obj, obj) == 0)
+                       return obj;
+       }
+       return NULL;
+}
+
+void *
+new_table_destroy(struct new_hash_table *h)
+{
+       int i;
+       struct new_obj *cur, *next;
+
+       if (!h || !h->table_ptr)
+               return NULL;
+       for (i = 0; i < h->table_size; i++)  {
+               for (cur = h->table_ptr[i]; cur; cur = next) {
+                       next = cur->next;
+                       free(cur, h->mtype);
+               }
+       }
+       free (h->table_ptr, h->mtype);
+       free (h, h->mtype);
+
+       return NULL;
+}
+
+/* returns the number of elements in the table */
+int
+new_table_get_element(const struct new_hash_table *h)
+{
+       return h ? h->table_obj : 0;
+}
+
+const void * 
+table_next(struct new_hash_table *h, const void *o)
+{
+       int i;
+       struct new_obj *obj;
+
+       printf("%s called\n", __FUNCTION__);
+       if (h == NULL || h->table_obj == 0)
+               return NULL;
+       if (o == NULL) {
+               for (i = 0; i < h->table_size; i++)
+                       if (h->table_ptr[i])
+                               return h->table_ptr[i]->obj;
+               return NULL; /* XXX should not happen */
+       }
+
+       /* here we can optimize if we can map o to the bucket,
+        * otherwise locate o and find the next one.
+        */
+       i = h->hash(o, h->table_size);
+       for (obj = h->table_ptr[i]; obj; obj = obj->next) {
+               if (h->cmp(obj->obj, o) == 0)
+                       break;
+       }
+       if (obj && obj->next != NULL)
+               return obj->next->obj;
+       /* take the first of the next bucket */
+       for (i++; i < h->table_size; i++) {
+               if (h->table_ptr[i])
+                       return h->table_ptr[i]->obj;
+       }
+       return NULL;
+}
diff --git a/dummynet/hashtable.h b/dummynet/hashtable.h
new file mode 100644 (file)
index 0000000..a20b7b4
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __HASHTABLE_H_
+#define __HASHTABLE_H_
+
+/*
+ * new_table_init creates a table with the specified
+ *     number of buckets (size).
+ * obj_size is the size of individual objects (key+value),
+ * the first function is the hash function (called with the
+ *     size and the payload pointer)
+ * the second function is the compare function, to tell if two
+ *     objects are the same (XXX we could spare this if we also
+ *     pass a key_size and use a bcmp for comparisons)
+ * Not extensible at the moment.
+ * max_el and max_ratio currently unused.
+ */
+struct malloc_type;
+struct new_hash_table * new_table_init (int size, int obj_size,
+    uint32_t (hash_fn)(const void *, uint32_t size),
+    int (cmp_fn)(const void*, const void*),
+    struct malloc_type *mtype);
+
+/* add a new object to the table, return success/failure */
+int new_table_insert_obj (struct new_hash_table *h, const void *obj);
+
+/*
+ * returns a pointer to the matching object or NULL if not found.
+ * No refcounts.
+ */
+const void *new_table_extract_obj(struct new_hash_table *h, const void *key);
+
+/* remove an object from the table */
+int new_table_delete_obj(struct new_hash_table *h, const void *key);
+void *new_table_destroy(struct new_hash_table *h);
+
+/* return the number of elements in the table */
+int new_table_get_element(const struct new_hash_table *h);
+
+/* returns the first or next element. Works by hashing the
+ * current object and then finds the next one.
+ * If obj == NULL returns the first object in the table
+ */
+const void *table_next(struct new_hash_table *h, const void *obj);
+
+#endif
index a6b6ea9..9b28374 100644 (file)
@@ -42,6 +42,8 @@ extern        ng_ipfw_input_t *ng_ipfw_input_p;
 struct ng_ipfw_tag {
        struct m_tag    mt;             /* tag header */
        struct ip_fw    *rule;          /* matching rule */
+       uint32_t        rule_id;        /* matching rule id */
+       uint32_t        chain_id;       /* ruleset id */
        struct ifnet    *ifp;           /* interface, for ip_output */
        int             dir;
 #define        NG_IPFW_OUT     0
index c6a6575..4f8291f 100644 (file)
@@ -113,6 +113,8 @@ struct dn_heap {
  */
 struct dn_pkt_tag {
     struct ip_fw *rule;                /* matching rule */
+    uint32_t rule_id;          /* matching rule id */
+    uint32_t chain_id;         /* ruleset id */
     int dn_dir;                        /* action when packet comes out. */
 #define DN_TO_IP_OUT   1
 #define DN_TO_IP_IN    2
@@ -339,8 +341,10 @@ struct dn_pipe {           /* a pipe */
 
     /* Same as in dn_flow_queue, numbytes can become large */
     int64_t numbytes;          /* bits I can transmit (more or less). */
+    uint64_t burst;            /* burst size, scaled: bits * hz */
 
     dn_key sched_time ;                /* time pipe was scheduled in ready_heap */
+    dn_key idle_time;          /* start of pipe idle time */
 
     /*
      * When the tx clock come from an interface (if_name[0] != '\0'), its name
@@ -379,7 +383,6 @@ typedef     int ip_dn_io_t(struct mbuf **m, int dir, struct ip_fw_args *fwa);
 extern ip_dn_ctl_t *ip_dn_ctl_ptr;
 extern ip_dn_ruledel_t *ip_dn_ruledel_ptr;
 extern ip_dn_io_t *ip_dn_io_ptr;
-#define        DUMMYNET_LOADED (ip_dn_io_ptr != NULL)
 
 /*
  * Return the IPFW rule associated with the dummynet tag; if any.
index bd4d3f9..a19a6df 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
+ * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #define        IPFW_DEFAULT_RULE       65535
 
 /*
+ * The number of ipfw tables.  The maximum allowed table number is the
+ * (IPFW_TABLES_MAX - 1).
+ */
+#define        IPFW_TABLES_MAX         128
+
+/*
+ * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit
+ * argument between 1 and 65534. The value 0 is unused, the value
+ * 65535 (IP_FW_TABLEARG) is used to represent 'tablearg', i.e. the
+ * can be 1..65534, or 65535 to indicate the use of a 'tablearg'
+ * result of the most recent table() lookup.
+ * Note that 16bit is only a historical limit, resulting from
+ * the use of a 16-bit fields for that value. In reality, we can have
+ * 2^32 pipes, queues, tag values and so on, and use 0 as a tablearg.
+ */
+#define        IPFW_ARG_MIN            1
+#define        IPFW_ARG_MAX            65534
+#define        IP_FW_TABLEARG          65535   /* XXX should use 0 */
+
+/*
  * The kernel representation of ipfw rules is made of a list of
  * 'instructions' (for all practical purposes equivalent to BPF
  * instructions), which specify which fields of the packet
@@ -217,7 +237,7 @@ enum ipfw_opcodes {         /* arguments (4 byte each)      */
  *
  */
 typedef struct _ipfw_insn {    /* template for instructions */
-       enum ipfw_opcodes       opcode:8;
+       u_int8_t        opcode;
        u_int8_t        len;    /* number of 32-bit words */
 #define        F_NOT           0x80
 #define        F_OR            0x40
@@ -233,8 +253,6 @@ typedef struct      _ipfw_insn {    /* template for instructions */
  */
 #define        F_INSN_SIZE(t)  ((sizeof (t))/sizeof(u_int32_t))
 
-#define MTAG_IPFW      1148380143      /* IPFW-tagged cookie */
-
 /*
  * This is used to store an array of 16-bit entries (ports etc.)
  */
@@ -447,17 +465,18 @@ struct ip_fw {
        struct ip_fw    *next_rule;     /* ptr to next [skipto] rule    */
        /* 'next_rule' is used to pass up 'set_disable' status          */
 
-       u_int16_t       act_ofs;        /* offset of action in 32-bit units */
-       u_int16_t       cmd_len;        /* # of 32-bit words in cmd     */
-       u_int16_t       rulenum;        /* rule number                  */
-       u_int8_t        set;            /* rule set (0..31)             */
+       uint16_t        act_ofs;        /* offset of action in 32-bit units */
+       uint16_t        cmd_len;        /* # of 32-bit words in cmd     */
+       uint16_t        rulenum;        /* rule number                  */
+       uint8_t         set;            /* rule set (0..31)             */
 #define        RESVD_SET       31      /* set for default and persistent rules */
-       u_int8_t        _pad;           /* padding                      */
+       uint8_t         _pad;           /* padding                      */
+       uint32_t        id;             /* rule id */
 
        /* These fields are present in all rules.                       */
-       u_int64_t       pcnt;           /* Packet counter               */
-       u_int64_t       bcnt;           /* Byte counter                 */
-       u_int32_t       timestamp;      /* tv_sec of last match         */
+       uint64_t        pcnt;           /* Packet counter               */
+       uint64_t        bcnt;           /* Byte counter                 */
+       uint32_t        timestamp;      /* tv_sec of last match         */
 
        ipfw_insn       cmd[1];         /* storage for commands         */
 };
@@ -552,13 +571,13 @@ typedef struct    _ipfw_table {
        ipfw_table_entry ent[0];        /* entries                      */
 } ipfw_table;
 
-#define IP_FW_TABLEARG 65535
-
 /*
  * Main firewall chains definitions and global var's definitions.
  */
 #ifdef _KERNEL
 
+#define MTAG_IPFW      1148380143      /* IPFW-tagged cookie */
+
 /* Return values from ipfw_chk() */
 enum {
        IP_FW_PASS = 0,
@@ -601,10 +620,12 @@ struct ip_fw_args {
        struct ifnet    *oif;           /* output interface             */
        struct sockaddr_in *next_hop;   /* forward address              */
        struct ip_fw    *rule;          /* matching rule                */
+       uint32_t        rule_id;                /* matching rule id */
+       uint32_t        chain_id;       /* ruleset id */
        struct ether_header *eh;        /* for bridged packets          */
 
        struct ipfw_flow_id f_id;       /* grabbed from IP header       */
-       u_int32_t       cookie;         /* a cookie depending on rule action */
+       uint32_t        cookie;         /* a cookie depending on rule action */
        struct inpcb    *inp;
 
        struct _ip6dn_args      dummypar; /* dummynet->ip6_output */
@@ -638,11 +659,9 @@ extern int fw6_enable;
 /* For kernel ipfw_ether and ipfw_bridge. */
 typedef        int ip_fw_chk_t(struct ip_fw_args *args);
 extern ip_fw_chk_t     *ip_fw_chk_ptr;
-#define        IPFW_LOADED     (ip_fw_chk_ptr != NULL)
 
 #ifdef IPFW_INTERNAL
 
-#define        IPFW_TABLES_MAX         128
 struct ip_fw_chain {
        struct ip_fw    *rules;         /* list of rules */
        struct ip_fw    *reap;          /* list of rules to reap */
@@ -653,6 +672,7 @@ struct ip_fw_chain {
 #else
        struct rwlock   rwmtx;
 #endif /* !__linux__ */
+       uint32_t        id;             /* ruleset id */
 };
 #define        IPFW_LOCK_INIT(_chain) \
        rw_init(&(_chain)->rwmtx, "IPFW static rules")
index 836d1e1..473a761 100644 (file)
@@ -72,7 +72,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1
 #include <sys/time.h>
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
-#include <net/if.h>    /* IFNAMSIZ, struct ifaddr, ifq head */
+#include <net/if.h>    /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
 #include <net/netisr.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>                /* ip_len, ip_off */
@@ -697,13 +697,17 @@ ready_event_wfq(struct dn_pipe *p, struct mbuf **head, struct mbuf **tail)
        struct dn_heap *neh = &(p->not_eligible_heap);
        int64_t p_numbytes = p->numbytes;
 
+       /*
+        * p->numbytes is only 32bits in FBSD7, but we might need 64 bits.
+        * Use a local variable for the computations, and write back the
+        * results when done, saturating if needed.
+        * The local variable has no impact on performance and helps
+        * reducing diffs between the various branches.
+        */
+
        DUMMYNET_LOCK_ASSERT();
 
        if (p->if_name[0] == 0)         /* tx clock is simulated */
-               /*
-                * Since result may not fit into p->numbytes (32bit) we
-                * are using 64bit var here.
-                */
                p_numbytes += (curr_time - p->sched_time) * p->bandwidth;
        else {  /*
                 * tx clock is for real,
@@ -814,13 +818,8 @@ ready_event_wfq(struct dn_pipe *p, struct mbuf **head, struct mbuf **tail)
                 */
        }
 
-       /* Fit (adjust if necessary) 64bit result into 32bit variable. */
-       if (p_numbytes > INT_MAX)
-               p->numbytes = INT_MAX;
-       else if (p_numbytes < INT_MIN)
-               p->numbytes = INT_MIN;
-       else
-               p->numbytes = p_numbytes;
+       /* Write back p_numbytes (adjust 64->32bit if necessary). */
+       p->numbytes = p_numbytes;
 
        /*
         * If the delay line was empty call transmit_event() now.
@@ -1423,6 +1422,8 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
         * Build and enqueue packet + parameters.
         */
        pkt->rule = fwa->rule;
+       pkt->rule_id = fwa->rule_id;
+       pkt->chain_id = fwa->chain_id;
        pkt->dn_dir = dir;
 
        pkt->ifp = fwa->oif;
@@ -1477,7 +1478,7 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)
                        heap_extract(&(pipe->idle_heap), q);
                        q->S = MAX64(q->F, pipe->V);
                }
-               q->F = div64(q->S + (len << MY_M), fs->weight);
+               q->F = q->S + div64(len << MY_M, fs->weight);
 
                if (pipe->not_eligible_heap.elements == 0 &&
                    pipe->scheduler_heap.elements == 0)
@@ -1836,6 +1837,8 @@ config_pipe(struct dn_pipe *p)
         * qsize = slots/bytes
         */
        p->delay = (p->delay * hz) / 1000;
+       /* Scale burst size: bytes -> bits * hz */
+       p->burst *= 8 * hz;
        /* We need either a pipe number or a flow_set number. */
        if (p->pipe_nr == 0 && pfs->fs_nr == 0)
                return (EINVAL);
@@ -2212,6 +2215,7 @@ dummynet_get(struct sockopt *sopt)
                 */
                bcopy(pipe, bp, sizeof(*pipe));
                pipe_bp->delay = (pipe_bp->delay * 1000) / hz;
+               pipe_bp->burst = div64(pipe_bp->burst, 8 * hz);
                /*
                 * XXX the following is a hack based on ->next being the
                 * first field in dn_pipe and dn_flow_set. The correct
@@ -2301,8 +2305,8 @@ ip_dn_ctl(struct sockopt *sopt)
        break ;
 
     case IP_DUMMYNET_DEL :     /* remove a pipe or queue */
-       p = malloc(sizeof(struct dn_pipe_max), M_TEMP, M_WAITOK);
-       error = sooptcopyin(sopt, p, sizeof *p, sizeof *p);
+       p = malloc(sizeof(struct dn_pipe), M_TEMP, M_WAITOK);
+       error = sooptcopyin(sopt, p, sizeof (struct dn_pipe), sizeof *p);
        if (error)
            break ;
 
index d05fa74..19d4d94 100644 (file)
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <net/radix.h>
 #include <net/route.h>
 #include <net/pf_mtag.h>
+#include <net/vnet.h>
 
 #define        IPFW_INTERNAL   /* Access to protected data structures in ip_fw.h. */
 
@@ -84,6 +85,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
 #include <netinet/sctp.h>
+
 #include <netgraph/ng_ipfw.h>
 
 #include <netinet/ip6.h>
@@ -98,8 +100,16 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <security/mac/mac_framework.h>
 #endif
 
+#ifdef linux
+//#include <linux/netdevice.h>    /* XXX dev_net() is used in linux 2.6.30.5 */
+#define INP_LOCK_ASSERT                /* define before missing.h otherwise ? */
 #include "missing.h"
+#define _IPV6_H                /* prevent ipv6 inclusion from hashtables and udp.h */
+#include <net/sock.h>  /* linux - struct sock and sock_put() */
+#endif
 
+static VNET_DEFINE(int, ipfw_vnet_ready) = 0;
+#define        V_ipfw_vnet_ready       VNET(ipfw_vnet_ready)
 /*
  * set_disable contains one bit per set value (0..31).
  * If the bit is set, all rules with the corresponding set
@@ -108,13 +118,25 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
  * and CANNOT be disabled.
  * Rules in set RESVD_SET can only be deleted explicitly.
  */
-static u_int32_t set_disable;
-static int fw_verbose;
-static struct callout ipfw_timeout;
-static int verbose_limit;
+static VNET_DEFINE(u_int32_t, set_disable);
+static VNET_DEFINE(int, fw_verbose);
+static VNET_DEFINE(struct callout, ipfw_timeout);
+static VNET_DEFINE(int, verbose_limit);
 
+#define        V_set_disable           VNET(set_disable)
+#define        V_fw_verbose            VNET(fw_verbose)
+#define        V_ipfw_timeout          VNET(ipfw_timeout)
+#define        V_verbose_limit         VNET(verbose_limit)
+
+#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
+static int default_to_accept = 1;
+#else
+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
@@ -131,7 +153,7 @@ struct ip_fw_ugid {
 /*
  * list of rules for layer 3
  */
-struct ip_fw_chain layer3_chain;
+VNET_DEFINE(struct ip_fw_chain, layer3_chain);
 
 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
 MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
@@ -148,30 +170,52 @@ struct table_entry {
        u_int32_t               value;
 };
 
-static int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */
+static VNET_DEFINE(int, autoinc_step);
+#define        V_autoinc_step                  VNET(autoinc_step)
+static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
+#define        V_fw_deny_unknown_exthdrs       VNET(fw_deny_unknown_exthdrs)
 
 extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
 
 #ifdef SYSCTL_NODE
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, enable,
-    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &fw_enable, 0,
+SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0,
     ipfw_chg_hook, "I", "Enable ipfw");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, CTLFLAG_RW,
-    &autoinc_step, 0, "Rule number autincrement step");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
-    CTLFLAG_RW | CTLFLAG_SECURE3,
-    &fw_one_pass, 0,
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
+    CTLFLAG_RW,  &VNET_NAME(autoinc_step), 0,
+    "Rule number auto-increment step");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
+    CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
     "Only do a single pass through ipfw when using dummynet(4)");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose,
-    CTLFLAG_RW | CTLFLAG_SECURE3,
-    &fw_verbose, 0, "Log matches to ipfw rules");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW,
-    &verbose_limit, 0, "Set upper limit of matches of ipfw rules logged");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose,
+    CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0,
+    "Log matches to ipfw rules");
+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");
 SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
-    NULL, IPFW_DEFAULT_RULE, "The default/max possible rule number.");
+    NULL, IPFW_DEFAULT_RULE,
+    "The default/max possible rule number.");
 SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
-    NULL, IPFW_TABLES_MAX, "The maximum number of tables.");
+    NULL, IPFW_TABLES_MAX,
+    "The maximum number of tables.");
+SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
+    &default_to_accept, 0,
+    "Make the default rule accept all packets.");
+TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
+
+#ifdef INET6
+SYSCTL_DECL(_net_inet6_ip6);
+SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
+SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0,
+    ipfw_chg_hook, "I", "Enable ipfw+6");
+SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
+    CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,
+    "Deny packets with unknown IPv6 Extension Headers");
+#endif /* INET6 */
+
 #endif /* SYSCTL_NODE */
 
 /*
@@ -210,9 +254,13 @@ SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
  * obey the 'randomized match', and we do not do multiple
  * passes through the firewall. XXX check the latter!!!
  */
-static ipfw_dyn_rule **ipfw_dyn_v = NULL;
-static u_int32_t dyn_buckets = 256; /* must be power of 2 */
-static u_int32_t curr_dyn_buckets = 256; /* must be power of 2 */
+static VNET_DEFINE(ipfw_dyn_rule **, ipfw_dyn_v);
+static VNET_DEFINE(u_int32_t, dyn_buckets);
+static VNET_DEFINE(u_int32_t, curr_dyn_buckets);
+
+#define        V_ipfw_dyn_v                    VNET(ipfw_dyn_v)
+#define        V_dyn_buckets                   VNET(dyn_buckets)
+#define        V_curr_dyn_buckets              VNET(curr_dyn_buckets)
 
 #if defined( __linux__ ) || defined( _WIN32 )
 DEFINE_SPINLOCK(ipfw_dyn_mtx);
@@ -226,15 +274,26 @@ static struct mtx ipfw_dyn_mtx;           /* mutex guarding dynamic rules */
 #define        IPFW_DYN_UNLOCK()       mtx_unlock(&ipfw_dyn_mtx)
 #define        IPFW_DYN_LOCK_ASSERT()  mtx_assert(&ipfw_dyn_mtx, MA_OWNED)
 
+static struct mbuf *send_pkt(struct mbuf *, struct ipfw_flow_id *,
+    u_int32_t, u_int32_t, int);
+
+
 /*
  * Timeouts for various events in handing dynamic rules.
  */
-static u_int32_t dyn_ack_lifetime = 300;
-static u_int32_t dyn_syn_lifetime = 20;
-static u_int32_t dyn_fin_lifetime = 1;
-static u_int32_t dyn_rst_lifetime = 1;
-static u_int32_t dyn_udp_lifetime = 10;
-static u_int32_t dyn_short_lifetime = 5;
+static VNET_DEFINE(u_int32_t, dyn_ack_lifetime);
+static VNET_DEFINE(u_int32_t, dyn_syn_lifetime);
+static VNET_DEFINE(u_int32_t, dyn_fin_lifetime);
+static VNET_DEFINE(u_int32_t, dyn_rst_lifetime);
+static VNET_DEFINE(u_int32_t, dyn_udp_lifetime);
+static VNET_DEFINE(u_int32_t, dyn_short_lifetime);
+    
+#define        V_dyn_ack_lifetime              VNET(dyn_ack_lifetime)
+#define        V_dyn_syn_lifetime              VNET(dyn_syn_lifetime)
+#define        V_dyn_fin_lifetime              VNET(dyn_fin_lifetime)
+#define        V_dyn_rst_lifetime              VNET(dyn_rst_lifetime)
+#define        V_dyn_udp_lifetime              VNET(dyn_udp_lifetime)
+#define        V_dyn_short_lifetime            VNET(dyn_short_lifetime)
 
 /*
  * Keepalives are sent if dyn_keepalive is set. They are sent every
@@ -244,57 +303,63 @@ static u_int32_t dyn_short_lifetime = 5;
  * than dyn_keepalive_period.
  */
 
-static u_int32_t dyn_keepalive_interval = 20;
-static u_int32_t dyn_keepalive_period = 5;
-static u_int32_t dyn_keepalive = 1;    /* do send keepalives */
+static VNET_DEFINE(u_int32_t, dyn_keepalive_interval);
+static VNET_DEFINE(u_int32_t, dyn_keepalive_period);
+static VNET_DEFINE(u_int32_t, dyn_keepalive);
 
-static u_int32_t static_count; /* # of static rules */
-static u_int32_t static_len;   /* size in bytes of static rules */
-static u_int32_t dyn_count;            /* # of dynamic rules */
-static u_int32_t dyn_max = 4096;       /* max # of dynamic rules */
+#define        V_dyn_keepalive_interval        VNET(dyn_keepalive_interval)
+#define        V_dyn_keepalive_period          VNET(dyn_keepalive_period)
+#define        V_dyn_keepalive                 VNET(dyn_keepalive)
 
-#ifdef SYSCTL_NODE
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, CTLFLAG_RW,
-    &dyn_buckets, 0, "Number of dyn. buckets");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD,
-    &curr_dyn_buckets, 0, "Current Number of dyn. buckets");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, CTLFLAG_RD,
-    &dyn_count, 0, "Number of dyn. rules");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, CTLFLAG_RW,
-    &dyn_max, 0, "Max number of dyn. rules");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, static_count, CTLFLAG_RD,
-    &static_count, 0, "Number of static rules");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW,
-    &dyn_ack_lifetime, 0, "Lifetime of dyn. rules for acks");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime, CTLFLAG_RW,
-    &dyn_syn_lifetime, 0, "Lifetime of dyn. rules for syn");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime, CTLFLAG_RW,
-    &dyn_fin_lifetime, 0, "Lifetime of dyn. rules for fin");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime, CTLFLAG_RW,
-    &dyn_rst_lifetime, 0, "Lifetime of dyn. rules for rst");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime, CTLFLAG_RW,
-    &dyn_udp_lifetime, 0, "Lifetime of dyn. rules for UDP");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW,
-    &dyn_short_lifetime, 0, "Lifetime of dyn. rules for other situations");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW,
-    &dyn_keepalive, 0, "Enable keepalives for dyn. rules");
-#endif /* SYSCTL_NODE */
+static VNET_DEFINE(u_int32_t, static_count);   /* # of static rules */
+static VNET_DEFINE(u_int32_t, static_len);     /* bytes of static rules */
+static VNET_DEFINE(u_int32_t, dyn_count);      /* # of dynamic rules */
+static VNET_DEFINE(u_int32_t, dyn_max);                /* max # of dynamic rules */
+
+#define        V_static_count          VNET(static_count)
+#define        V_static_len            VNET(static_len)
+#define        V_dyn_count             VNET(dyn_count)
+#define        V_dyn_max               VNET(dyn_max)
 
-#ifdef INET6
-/*
- * IPv6 specific variables
- */
 #ifdef SYSCTL_NODE
-SYSCTL_DECL(_net_inet6_ip6);
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets,
+    CTLFLAG_RW, &VNET_NAME(dyn_buckets), 0,
+    "Number of dyn. buckets");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets,
+    CTLFLAG_RD, &VNET_NAME(curr_dyn_buckets), 0,
+    "Current Number of dyn. buckets");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_count,
+    CTLFLAG_RD, &VNET_NAME(dyn_count), 0,
+    "Number of dyn. rules");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_max,
+    CTLFLAG_RW, &VNET_NAME(dyn_max), 0,
+    "Max number of dyn. rules");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
+    CTLFLAG_RD, &VNET_NAME(static_count), 0,
+    "Number of static rules");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_ack_lifetime), 0,
+    "Lifetime of dyn. rules for acks");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_syn_lifetime), 0,
+    "Lifetime of dyn. rules for syn");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_fin_lifetime), 0,
+    "Lifetime of dyn. rules for fin");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_rst_lifetime), 0,
+    "Lifetime of dyn. rules for rst");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_udp_lifetime), 0,
+    "Lifetime of dyn. rules for UDP");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime,
+    CTLFLAG_RW, &VNET_NAME(dyn_short_lifetime), 0,
+    "Lifetime of dyn. rules for other situations");
+SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive,
+    CTLFLAG_RW, &VNET_NAME(dyn_keepalive), 0,
+    "Enable keepalives for dyn. rules");
 #endif /* SYSCTL_NODE */
 
-static struct sysctl_ctx_list ip6_fw_sysctl_ctx;
-static struct sysctl_oid *ip6_fw_sysctl_tree;
-#endif /* INET6 */
-
-static int fw_deny_unknown_exthdrs = 1;
-
-
 /*
  * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
  * Other macros just cast void * into the appropriate type
@@ -461,14 +526,17 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
 #if !defined( __linux__ ) && !defined( _WIN32 )
                struct ifaddr *ia;
 
-               /* XXX lock? */
+               if_addr_rlock(ifp);
                TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) {
                        if (ia->ifa_addr->sa_family != AF_INET)
                                continue;
                        if (cmd->p.ip.s_addr == ((struct sockaddr_in *)
-                           (ia->ifa_addr))->sin_addr.s_addr)
+                           (ia->ifa_addr))->sin_addr.s_addr) {
+                               if_addr_runlock(ifp);
                                return(1);      /* match */
+                       }
                }
+               if_addr_runlock(ifp);
 #endif
        }
        return(0);      /* no match, fail ... */
@@ -507,7 +575,7 @@ verify_path(struct in_addr src, struct ifnet *ifp, u_int fib)
        dst->sin_family = AF_INET;
        dst->sin_len = sizeof(*dst);
        dst->sin_addr = src;
-       in_rtalloc_ign(&ro, RTF_CLONING, fib);
+       in_rtalloc_ign(&ro, 0, fib);
 
        if (ro.ro_rt == NULL)
                return 0;
@@ -572,17 +640,22 @@ search_ip6_addr_net (struct in6_addr * ip6_addr)
        struct in6_ifaddr *fdm;
        struct in6_addr copia;
 
-       TAILQ_FOREACH(mdc, &ifnet, if_link)
-               TAILQ_FOREACH(mdc2, &mdc->if_addrlist, ifa_list) {
+       TAILQ_FOREACH(mdc, &V_ifnet, if_link) {
+               if_addr_rlock(mdc);
+               TAILQ_FOREACH(mdc2, &mdc->if_addrhead, ifa_link) {
                        if (mdc2->ifa_addr->sa_family == AF_INET6) {
                                fdm = (struct in6_ifaddr *)mdc2;
                                copia = fdm->ia_addr.sin6_addr;
                                /* need for leaving scope_id in the sock_addr */
                                in6_clearscope(&copia);
-                               if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia))
+                               if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia)) {
+                                       if_addr_runlock(mdc);
                                        return 1;
+                               }
                        }
                }
+               if_addr_runlock(mdc);
+       }
        return 0;
 }
 
@@ -599,7 +672,7 @@ verify_path6(struct in6_addr *src, struct ifnet *ifp)
        dst->sin6_len = sizeof(*dst);
        dst->sin6_addr = *src;
        /* XXX MRT 0 for ipv6 at this time */
-       rtalloc_ign((struct route *)&ro, RTF_CLONING);
+       rtalloc_ign((struct route *)&ro, 0);
 
        if (ro.ro_rt == NULL)
                return 0;
@@ -668,60 +741,18 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
        m = args->m;
        if (code == ICMP6_UNREACH_RST && args->f_id.proto == IPPROTO_TCP) {
                struct tcphdr *tcp;
-               tcp_seq ack, seq;
-               int flags;
-               struct {
-                       struct ip6_hdr ip6;
-                       struct tcphdr th;
-               } ti;
                tcp = (struct tcphdr *)((char *)ip6 + hlen);
 
-               if ((tcp->th_flags & TH_RST) != 0) {
-                       m_freem(m);
-                       args->m = NULL;
-                       return;
-               }
-
-               ti.ip6 = *ip6;
-               ti.th = *tcp;
-               ti.th.th_seq = ntohl(ti.th.th_seq);
-               ti.th.th_ack = ntohl(ti.th.th_ack);
-               ti.ip6.ip6_nxt = IPPROTO_TCP;
-
-               if (ti.th.th_flags & TH_ACK) {
-                       ack = 0;
-                       seq = ti.th.th_ack;
-                       flags = TH_RST;
-               } else {
-                       ack = ti.th.th_seq;
-                       if ((m->m_flags & M_PKTHDR) != 0) {
-                               /*
-                                * total new data to ACK is:
-                                * total packet length,
-                                * minus the header length,
-                                * minus the tcp header length.
-                                */
-                               ack += m->m_pkthdr.len - hlen
-                                       - (ti.th.th_off << 2);
-                       } else if (ip6->ip6_plen) {
-                               ack += ntohs(ip6->ip6_plen) + sizeof(*ip6) -
-                                   hlen - (ti.th.th_off << 2);
-                       } else {
-                               m_freem(m);
-                               return;
-                       }
-                       if (tcp->th_flags & TH_SYN)
-                               ack++;
-                       seq = 0;
-                       flags = TH_RST|TH_ACK;
+               if ((tcp->th_flags & TH_RST) == 0) {
+                       struct mbuf *m0;
+                       m0 = send_pkt(args->m, &(args->f_id),
+                           ntohl(tcp->th_seq), ntohl(tcp->th_ack),
+                           tcp->th_flags | TH_RST);
+                       if (m0 != NULL)
+                               ip6_output(m0, NULL, NULL, 0, NULL, NULL,
+                                   NULL);
                }
-               bcopy(&ti, ip6, sizeof(ti));
-               /*
-                * m is only used to recycle the mbuf
-                * The data in it is never read so we don't need
-                * to correct the offsets or anything
-                */
-               tcp_respond(NULL, ip6, tcp, m, ack, seq, flags);
+               m_freem(m);
        } else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
 #if 0
                /*
@@ -744,7 +775,9 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
 
 #endif /* INET6 */
 
-static u_int64_t norule_counter;       /* counter for ipfw_log(NULL...) */
+/* counter for ipfw_log(NULL...) */
+static VNET_DEFINE(u_int64_t, norule_counter);
+#define        V_norule_counter                VNET(norule_counter)
 
 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
 #define SNP(buf) buf, sizeof(buf)
@@ -767,11 +800,11 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
        proto[0] = '\0';
 
        if (f == NULL) {        /* bogus pkt */
-               if (verbose_limit != 0 && norule_counter >= verbose_limit)
+               if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit)
                        return;
-               norule_counter++;
-               if (norule_counter == verbose_limit)
-                       limit_reached = verbose_limit;
+               V_norule_counter++;
+               if (V_norule_counter == V_verbose_limit)
+                       limit_reached = V_verbose_limit;
                action = "Refuse";
        } else {        /* O_LOG is the first action, find the real one */
                ipfw_insn *cmd = ACTION_PTR(f);
@@ -878,6 +911,9 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
                case O_NAT:
                        action = "Nat";
                        break;
+               case O_REASS:
+                       action = "Reass";
+                       break;
                default:
                        action = "UNKNOWN";
                        break;
@@ -889,7 +925,11 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
 
        } else {
                int len;
-               char src[48], dst[48];
+#ifdef INET6
+               char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2];
+#else
+               char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
+#endif
                struct icmphdr *icmp;
                struct tcphdr *tcp;
                struct udphdr *udp;
@@ -1036,10 +1076,36 @@ hash_packet(struct ipfw_flow_id *id)
        else
 #endif /* INET6 */
        i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
-       i &= (curr_dyn_buckets - 1);
+       i &= (V_curr_dyn_buckets - 1);
        return i;
 }
 
+static __inline void
+unlink_dyn_rule_print(struct ipfw_flow_id *id)
+{
+       struct in_addr da;
+#ifdef INET6
+       char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
+#else
+       char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
+#endif
+
+#ifdef INET6
+       if (IS_IP6_FLOW_ID(id)) {
+               ip6_sprintf(src, &id->src_ip6);
+               ip6_sprintf(dst, &id->dst_ip6);
+       } else
+#endif
+       {
+               da.s_addr = htonl(id->src_ip);
+               inet_ntoa_r(da, src);
+               da.s_addr = htonl(id->dst_ip);
+               inet_ntoa_r(da, dst);
+       }
+       printf("ipfw: unlink entry %s %d -> %s %d, %d left\n",
+           src, id->src_port, dst, id->dst_port, V_dyn_count - 1);
+}
+
 /**
  * unlink a dynamic rule from a chain. prev is a pointer to
  * the previous one, q is a pointer to the rule to delete,
@@ -1052,14 +1118,12 @@ hash_packet(struct ipfw_flow_id *id)
        /* remove a refcount to the parent */                           \
        if (q->dyn_type == O_LIMIT)                                     \
                q->parent->count--;                                     \
-       DEB(printf("ipfw: unlink entry 0x%08x %d -> 0x%08x %d, %d left\n",\
-               (q->id.src_ip), (q->id.src_port),                       \
-               (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); )      \
+       DEB(unlink_dyn_rule_print(&q->id);)                             \
        if (prev != NULL)                                               \
                prev->next = q = q->next;                               \
        else                                                            \
                head = q = q->next;                                     \
-       dyn_count--;                                                    \
+       V_dyn_count--;                                                  \
        uma_zfree(ipfw_dyn_rule_zone, old_q); }
 
 #define TIME_LEQ(a,b)       ((int)((a)-(b)) <= 0)
@@ -1088,7 +1152,7 @@ remove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me)
 
        IPFW_DYN_LOCK_ASSERT();
 
-       if (ipfw_dyn_v == NULL || dyn_count == 0)
+       if (V_ipfw_dyn_v == NULL || V_dyn_count == 0)
                return;
        /* do not expire more than once per second, it is useless */
        if (!FORCE && last_remove == time_uptime)
@@ -1101,8 +1165,8 @@ remove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me)
         * them in a second pass.
         */
 next_pass:
-       for (i = 0 ; i < curr_dyn_buckets ; i++) {
-               for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) {
+       for (i = 0 ; i < V_curr_dyn_buckets ; i++) {
+               for (prev=NULL, q = V_ipfw_dyn_v[i] ; q ; ) {
                        /*
                         * Logic can become complex here, so we split tests.
                         */
@@ -1129,7 +1193,7 @@ next_pass:
                                        goto next;
                        }
              if (q->dyn_type != O_LIMIT_PARENT || !q->count) {
-                     UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
+                     UNLINK_DYN_RULE(prev, V_ipfw_dyn_v[i], q);
                      continue;
              }
 next:
@@ -1162,14 +1226,14 @@ lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction,
 
        IPFW_DYN_LOCK_ASSERT();
 
-       if (ipfw_dyn_v == NULL)
+       if (V_ipfw_dyn_v == NULL)
                goto done;      /* not found */
        i = hash_packet( pkt );
-       for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
+       for (prev=NULL, q = V_ipfw_dyn_v[i] ; q != NULL ; ) {
                if (q->dyn_type == O_LIMIT_PARENT && q->count)
                        goto next;
                if (TIME_LEQ( q->expire, time_uptime)) { /* expire entry */
-                       UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
+                       UNLINK_DYN_RULE(prev, V_ipfw_dyn_v[i], q);
                        continue;
                }
                if (pkt->proto == q->id.proto &&
@@ -1219,8 +1283,8 @@ next:
 
        if ( prev != NULL) { /* found and not in front */
                prev->next = q->next;
-               q->next = ipfw_dyn_v[i];
-               ipfw_dyn_v[i] = q;
+               q->next = V_ipfw_dyn_v[i];
+               V_ipfw_dyn_v[i] = q;
        }
        if (pkt->proto == IPPROTO_TCP) { /* update state according to flags */
                u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST);
@@ -1230,7 +1294,7 @@ next:
                q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8);
                switch (q->state) {
                case TH_SYN:                            /* opening */
-                       q->expire = time_uptime + dyn_syn_lifetime;
+                       q->expire = time_uptime + V_dyn_syn_lifetime;
                        break;
 
                case BOTH_SYN:                  /* move to established */
@@ -1253,13 +1317,13 @@ next:
                                }
                            }
                        }
-                       q->expire = time_uptime + dyn_ack_lifetime;
+                       q->expire = time_uptime + V_dyn_ack_lifetime;
                        break;
 
                case BOTH_SYN | BOTH_FIN:       /* both sides closed */
-                       if (dyn_fin_lifetime >= dyn_keepalive_period)
-                               dyn_fin_lifetime = dyn_keepalive_period - 1;
-                       q->expire = time_uptime + dyn_fin_lifetime;
+                       if (V_dyn_fin_lifetime >= V_dyn_keepalive_period)
+                               V_dyn_fin_lifetime = V_dyn_keepalive_period - 1;
+                       q->expire = time_uptime + V_dyn_fin_lifetime;
                        break;
 
                default:
@@ -1271,16 +1335,16 @@ next:
                        if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0)
                                printf("invalid state: 0x%x\n", q->state);
 #endif
-                       if (dyn_rst_lifetime >= dyn_keepalive_period)
-                               dyn_rst_lifetime = dyn_keepalive_period - 1;
-                       q->expire = time_uptime + dyn_rst_lifetime;
+                       if (V_dyn_rst_lifetime >= V_dyn_keepalive_period)
+                               V_dyn_rst_lifetime = V_dyn_keepalive_period - 1;
+                       q->expire = time_uptime + V_dyn_rst_lifetime;
                        break;
                }
        } else if (pkt->proto == IPPROTO_UDP) {
-               q->expire = time_uptime + dyn_udp_lifetime;
+               q->expire = time_uptime + V_dyn_udp_lifetime;
        } else {
                /* other protocols */
-               q->expire = time_uptime + dyn_short_lifetime;
+               q->expire = time_uptime + V_dyn_short_lifetime;
        }
 done:
        if (match_direction)
@@ -1313,21 +1377,21 @@ realloc_dynamic_table(void)
         * default to 1024.
         */
 
-       if (dyn_buckets > 65536)
-               dyn_buckets = 1024;
-       if ((dyn_buckets & (dyn_buckets-1)) != 0) { /* not a power of 2 */
-               dyn_buckets = curr_dyn_buckets; /* reset */
+       if (V_dyn_buckets > 65536)
+               V_dyn_buckets = 1024;
+       if ((V_dyn_buckets & (V_dyn_buckets-1)) != 0) { /* not a power of 2 */
+               V_dyn_buckets = V_curr_dyn_buckets; /* reset */
                return;
        }
-       curr_dyn_buckets = dyn_buckets;
-       if (ipfw_dyn_v != NULL)
-               free(ipfw_dyn_v, M_IPFW);
+       V_curr_dyn_buckets = V_dyn_buckets;
+       if (V_ipfw_dyn_v != NULL)
+               free(V_ipfw_dyn_v, M_IPFW);
        for (;;) {
-               ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof(ipfw_dyn_rule *),
+               V_ipfw_dyn_v = malloc(V_curr_dyn_buckets * sizeof(ipfw_dyn_rule *),
                       M_IPFW, M_NOWAIT | M_ZERO);
-               if (ipfw_dyn_v != NULL || curr_dyn_buckets <= 2)
+               if (V_ipfw_dyn_v != NULL || V_curr_dyn_buckets <= 2)
                        break;
-               curr_dyn_buckets /= 2;
+               V_curr_dyn_buckets /= 2;
        }
 }
 
@@ -1349,10 +1413,10 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
 
        IPFW_DYN_LOCK_ASSERT();
 
-       if (ipfw_dyn_v == NULL ||
-           (dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) {
+       if (V_ipfw_dyn_v == NULL ||
+           (V_dyn_count == 0 && V_dyn_buckets != V_curr_dyn_buckets)) {
                realloc_dynamic_table();
-               if (ipfw_dyn_v == NULL)
+               if (V_ipfw_dyn_v == NULL)
                        return NULL; /* failed ! */
        }
        i = hash_packet(id);
@@ -1374,21 +1438,42 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
        }
 
        r->id = *id;
-       r->expire = time_uptime + dyn_syn_lifetime;
+       r->expire = time_uptime + V_dyn_syn_lifetime;
        r->rule = rule;
        r->dyn_type = dyn_type;
        r->pcnt = r->bcnt = 0;
        r->count = 0;
 
        r->bucket = i;
-       r->next = ipfw_dyn_v[i];
-       ipfw_dyn_v[i] = r;
-       dyn_count++;
-       DEB(printf("ipfw: add dyn entry ty %d 0x%08x %d -> 0x%08x %d, total %d\n",
-          dyn_type,
-          (r->id.src_ip), (r->id.src_port),
-          (r->id.dst_ip), (r->id.dst_port),
-          dyn_count ); )
+       r->next = V_ipfw_dyn_v[i];
+       V_ipfw_dyn_v[i] = r;
+       V_dyn_count++;
+       DEB({
+               struct in_addr da;
+#ifdef INET6
+               char src[INET6_ADDRSTRLEN];
+               char dst[INET6_ADDRSTRLEN];
+#else
+               char src[INET_ADDRSTRLEN];
+               char dst[INET_ADDRSTRLEN];
+#endif
+
+#ifdef INET6
+               if (IS_IP6_FLOW_ID(&(r->id))) {
+                       ip6_sprintf(src, &r->id.src_ip6);
+                       ip6_sprintf(dst, &r->id.dst_ip6);
+               } else
+#endif
+               {
+                       da.s_addr = htonl(r->id.src_ip);
+                       inet_ntoa_r(da, src);
+                       da.s_addr = htonl(r->id.dst_ip);
+                       inet_ntoa_r(da, dst);
+               }
+               printf("ipfw: add dyn entry ty %d %s %d -> %s %d, total %d\n",
+                   dyn_type, src, r->id.src_port, dst, r->id.dst_port,
+                   V_dyn_count);
+       })
        return r;
 }
 
@@ -1404,10 +1489,10 @@ lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
 
        IPFW_DYN_LOCK_ASSERT();
 
-       if (ipfw_dyn_v) {
+       if (V_ipfw_dyn_v) {
                int is_v6 = IS_IP6_FLOW_ID(pkt);
                i = hash_packet( pkt );
-               for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
+               for (q = V_ipfw_dyn_v[i] ; q != NULL ; q=q->next)
                        if (q->dyn_type == O_LIMIT_PARENT &&
                            rule== q->rule &&
                            pkt->proto == q->id.proto &&
@@ -1424,7 +1509,7 @@ lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
                                 pkt->dst_ip == q->id.dst_ip)
                            )
                        ) {
-                               q->expire = time_uptime + dyn_short_lifetime;
+                               q->expire = time_uptime + V_dyn_short_lifetime;
                                DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);)
                                return q;
                        }
@@ -1445,20 +1530,37 @@ install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
        static int last_log;
        ipfw_dyn_rule *q;
        struct in_addr da;
-       char src[48], dst[48];
+#ifdef INET6
+       char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2];
+#else
+       char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];
+#endif
 
        src[0] = '\0';
        dst[0] = '\0';
 
+       IPFW_DYN_LOCK();
+
        DEB(
-       printf("ipfw: %s: type %d 0x%08x %u -> 0x%08x %u\n",
-           __func__, cmd->o.opcode,
-           (args->f_id.src_ip), (args->f_id.src_port),
-           (args->f_id.dst_ip), (args->f_id.dst_port));
+#ifdef INET6
+       if (IS_IP6_FLOW_ID(&(args->f_id))) {
+               ip6_sprintf(src, &args->f_id.src_ip6);
+               ip6_sprintf(dst, &args->f_id.dst_ip6);
+       } else
+#endif
+       {
+               da.s_addr = htonl(args->f_id.src_ip);
+               inet_ntoa_r(da, src);
+               da.s_addr = htonl(args->f_id.dst_ip);
+               inet_ntoa_r(da, dst);
+       }
+       printf("ipfw: %s: type %d %s %u -> %s %u\n",
+           __func__, cmd->o.opcode, src, args->f_id.src_port,
+           dst, args->f_id.dst_port);
+       src[0] = '\0';
+       dst[0] = '\0';
        )
 
-       IPFW_DYN_LOCK();
-
        q = lookup_dyn_rule_locked(&args->f_id, NULL, NULL);
 
        if (q != NULL) {        /* should never occur */
@@ -1471,11 +1573,11 @@ install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
                return (0);
        }
 
-       if (dyn_count >= dyn_max)
+       if (V_dyn_count >= V_dyn_max)
                /* Run out of slots, try to remove any expired rule. */
                remove_dyn_rule(NULL, (ipfw_dyn_rule *)1);
 
-       if (dyn_count >= dyn_max) {
+       if (V_dyn_count >= V_dyn_max) {
                if (last_log != time_uptime) {
                        last_log = time_uptime;
                        printf("ipfw: %s: Too many dynamic rules\n", __func__);
@@ -1537,7 +1639,7 @@ install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
                        /* See if we can remove some expired rule. */
                        remove_dyn_rule(rule, parent);
                        if (parent->count >= conn_limit) {
-                               if (fw_verbose && last_log != time_uptime) {
+                               if (V_fw_verbose && last_log != time_uptime) {
                                        last_log = time_uptime;
 #ifdef INET6
                                        /*
@@ -1607,85 +1709,141 @@ send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,
        return NULL;
 #else
        struct mbuf *m;
-       struct ip *ip;
-       struct tcphdr *tcp;
+       int len, dir;
+       struct ip *h = NULL;            /* stupid compiler */
+#ifdef INET6
+       struct ip6_hdr *h6 = NULL;
+#endif
+       struct tcphdr *th = NULL;
 
        MGETHDR(m, M_DONTWAIT, MT_DATA);
-       if (m == 0)
+       if (m == NULL)
                return (NULL);
-       m->m_pkthdr.rcvif = (struct ifnet *)0;
 
        M_SETFIB(m, id->fib);
 #ifdef MAC
        if (replyto != NULL)
-               mac_create_mbuf_netlayer(replyto, m);
+               mac_netinet_firewall_reply(replyto, m);
        else
-               mac_create_mbuf_from_firewall(m);
+               mac_netinet_firewall_send(m);
 #else
        (void)replyto;          /* don't warn about unused arg */
 #endif
 
-       m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr);
+       switch (id->addr_type) {
+       case 4:
+               len = sizeof(struct ip) + sizeof(struct tcphdr);
+               break;
+#ifdef INET6
+       case 6:
+               len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
+               break;
+#endif
+       default:
+               /* XXX: log me?!? */
+               m_freem(m);
+               return (NULL);
+       }
+       dir = ((flags & (TH_SYN | TH_RST)) == TH_SYN);
+
        m->m_data += max_linkhdr;
+       m->m_flags |= M_SKIP_FIREWALL;
+       m->m_pkthdr.len = m->m_len = len;
+       m->m_pkthdr.rcvif = NULL;
+       bzero(m->m_data, len);
+
+       switch (id->addr_type) {
+       case 4:
+               h = mtod(m, struct ip *);
+
+               /* prepare for checksum */
+               h->ip_p = IPPROTO_TCP;
+               h->ip_len = htons(sizeof(struct tcphdr));
+               if (dir) {
+                       h->ip_src.s_addr = htonl(id->src_ip);
+                       h->ip_dst.s_addr = htonl(id->dst_ip);
+               } else {
+                       h->ip_src.s_addr = htonl(id->dst_ip);
+                       h->ip_dst.s_addr = htonl(id->src_ip);
+               }
 
-       ip = mtod(m, struct ip *);
-       bzero(ip, m->m_len);
-       tcp = (struct tcphdr *)(ip + 1); /* no IP options */
-       ip->ip_p = IPPROTO_TCP;
-       tcp->th_off = 5;
-       /*
-        * Assume we are sending a RST (or a keepalive in the reverse
-        * direction), swap src and destination addresses and ports.
-        */
-       ip->ip_src.s_addr = htonl(id->dst_ip);
-       ip->ip_dst.s_addr = htonl(id->src_ip);
-       tcp->th_sport = htons(id->dst_port);
-       tcp->th_dport = htons(id->src_port);
-       if (flags & TH_RST) {   /* we are sending a RST */
+               th = (struct tcphdr *)(h + 1);
+               break;
+#ifdef INET6
+       case 6:
+               h6 = mtod(m, struct ip6_hdr *);
+
+               /* prepare for checksum */
+               h6->ip6_nxt = IPPROTO_TCP;
+               h6->ip6_plen = htons(sizeof(struct tcphdr));
+               if (dir) {
+                       h6->ip6_src = id->src_ip6;
+                       h6->ip6_dst = id->dst_ip6;
+               } else {
+                       h6->ip6_src = id->dst_ip6;
+                       h6->ip6_dst = id->src_ip6;
+               }
+
+               th = (struct tcphdr *)(h6 + 1);
+               break;
+#endif
+       }
+
+       if (dir) {
+               th->th_sport = htons(id->src_port);
+               th->th_dport = htons(id->dst_port);
+       } else {
+               th->th_sport = htons(id->dst_port);
+               th->th_dport = htons(id->src_port);
+       }
+       th->th_off = sizeof(struct tcphdr) >> 2;
+
+       if (flags & TH_RST) {
                if (flags & TH_ACK) {
-                       tcp->th_seq = htonl(ack);
-                       tcp->th_ack = htonl(0);
-                       tcp->th_flags = TH_RST;
+                       th->th_seq = htonl(ack);
+                       // XXX th->th_ack = htonl(0);
+                       th->th_flags = TH_RST;
                } else {
                        if (flags & TH_SYN)
                                seq++;
-                       tcp->th_seq = htonl(0);
-                       tcp->th_ack = htonl(seq);
-                       tcp->th_flags = TH_RST | TH_ACK;
+                       // XXX th->th_seq = htonl(0);
+                       th->th_ack = htonl(seq);
+                       th->th_flags = TH_RST | TH_ACK;
                }
        } else {
                /*
-                * We are sending a keepalive. flags & TH_SYN determines
-                * the direction, forward if set, reverse if clear.
-                * NOTE: seq and ack are always assumed to be correct
-                * as set by the caller. This may be confusing...
+                * Keepalive - use caller provided sequence numbers
                 */
-               if (flags & TH_SYN) {
-                       /*
-                        * we have to rewrite the correct addresses!
-                        */
-                       ip->ip_dst.s_addr = htonl(id->dst_ip);
-                       ip->ip_src.s_addr = htonl(id->src_ip);
-                       tcp->th_dport = htons(id->dst_port);
-                       tcp->th_sport = htons(id->src_port);
-               }
-               tcp->th_seq = htonl(seq);
-               tcp->th_ack = htonl(ack);
-               tcp->th_flags = TH_ACK;
+               th->th_seq = htonl(seq);
+               th->th_ack = htonl(ack);
+               th->th_flags = TH_ACK;
        }
-       /*
-        * set ip_len to the payload size so we can compute
-        * the tcp checksum on the pseudoheader
-        * XXX check this, could save a couple of words ?
-        */
-       ip->ip_len = htons(sizeof(struct tcphdr));
-       tcp->th_sum = in_cksum(m, m->m_pkthdr.len);
-       /*
-        * now fill fields left out earlier
-        */
-       ip->ip_ttl = ip_defttl;
-       ip->ip_len = m->m_pkthdr.len;
-       m->m_flags |= M_SKIP_FIREWALL;
+
+       switch (id->addr_type) {
+       case 4:
+               th->th_sum = in_cksum(m, len);
+
+               /* finish the ip header */
+               h->ip_v = 4;
+               h->ip_hl = sizeof(*h) >> 2;
+               h->ip_tos = IPTOS_LOWDELAY;
+               h->ip_off = 0;
+               h->ip_len = len;
+               h->ip_ttl = V_ip_defttl;
+               h->ip_sum = 0;
+               break;
+#ifdef INET6
+       case 6:
+               th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(*h6),
+                   sizeof(struct tcphdr));
+
+               /* finish the ip6 header */
+               h6->ip6_vfc |= IPV6_VERSION;
+               h6->ip6_hlim = IPV6_DEFHLIM;
+               break;
+#endif
+       }
+
        return (m);
 #endif /* !__linux__ */
 }
@@ -1863,19 +2021,25 @@ 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);
 #endif
 
 static void
 flush_tables(struct ip_fw_chain *ch)
 {
-#ifdef radix
        uint16_t tbl;
 
        IPFW_WLOCK_ASSERT(ch);
 
        for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
                flush_table(ch, tbl);
-#endif
 }
 
 static int
@@ -2005,7 +2169,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
        if (*ugid_lookupp == 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
+                * if sk != NULL then we also have a reference 
                 */
                *ugid_lookupp = linux_lookup(proto,
                        src_ip.s_addr, htons(src_port),
@@ -2025,7 +2189,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
 
        return match;
 
-#else /* FreeBSD */
+#else  /* FreeBSD */
 
        struct inpcbinfo *pi;
        int wildcard;
@@ -2055,10 +2219,10 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
                return (0);
        if (proto == IPPROTO_TCP) {
                wildcard = 0;
-               pi = &tcbinfo;
+               pi = &V_tcbinfo;
        } else if (proto == IPPROTO_UDP) {
                wildcard = INPLOOKUP_WILDCARD;
-               pi = &udbinfo;
+               pi = &V_udbinfo;
        } else
                return 0;
        match = 0;
@@ -2141,6 +2305,7 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
 int
 ipfw_chk(struct ip_fw_args *args)
 {
+
        /*
         * Local variables holding state during the processing of a packet:
         *
@@ -2243,7 +2408,7 @@ ipfw_chk(struct ip_fw_args *args)
         */
        int dyn_dir = MATCH_UNKNOWN;
        ipfw_dyn_rule *q = NULL;
-       struct ip_fw_chain *chain = &layer3_chain;
+       struct ip_fw_chain *chain = &V_layer3_chain;
        struct m_tag *mtag;
 
        /*
@@ -2259,9 +2424,9 @@ ipfw_chk(struct ip_fw_args *args)
        /* end of ipv6 variables */
        int is_ipv4 = 0;
 
-       int done = 0;           /* flag for actions match */
+       int done = 0;           /* flag to exit the outer loop */
 
-       if (m->m_flags & M_SKIP_FIREWALL)
+       if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready))
                return (IP_FW_PASS);    /* accept */
 
        dst_ip.s_addr = 0;      /* make sure it is initialized */
@@ -2283,7 +2448,7 @@ do {                                                                      \
        if ((m)->m_len < x) {                                           \
                        goto pullup_failed;                             \
        }                                                               \
-       p = (mtod(m, char *) + (_len));                         \
+       p = (mtod(m, char *) + (_len));                                 \
 } while (0)
 
        /*
@@ -2349,7 +2514,7 @@ do {                                                                      \
                                        printf("IPFW2: IPV6 - Unknown Routing "
                                            "Header type(%d)\n",
                                            ((struct ip6_rthdr *)ulp)->ip6r_type);
-                                       if (fw_deny_unknown_exthdrs)
+                                       if (V_fw_deny_unknown_exthdrs)
                                            return (IP_FW_DENY);
                                        break;
                                }
@@ -2373,7 +2538,7 @@ do {                                                                      \
                                if (offset == 0) {
                                        printf("IPFW2: IPV6 - Invalid Fragment "
                                            "Header\n");
-                                       if (fw_deny_unknown_exthdrs)
+                                       if (V_fw_deny_unknown_exthdrs)
                                            return (IP_FW_DENY);
                                        break;
                                }
@@ -2445,7 +2610,7 @@ do {                                                                      \
                        default:
                                printf("IPFW2: IPV6 - Unknown Extension "
                                    "Header(%d), ext_hd=%x\n", proto, ext_hd);
-                               if (fw_deny_unknown_exthdrs)
+                               if (V_fw_deny_unknown_exthdrs)
                                    return (IP_FW_DENY);
                                PULLUP_TO(hlen, ulp, struct ip6_ext);
                                break;
@@ -2517,22 +2682,27 @@ do {                                                                    \
        }
 
        IPFW_RLOCK(chain);
+       if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */
+               IPFW_RUNLOCK(chain);
+               return (IP_FW_PASS);    /* accept */
+       }
        mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
        if (args->rule) {
                /*
                 * Packet has already been tagged. Look for the next rule
-                * to restart processing.
-                *
+                * to restart processing. Make sure that args->rule still
+                * exists and not changed.
                 * If fw_one_pass != 0 then just accept it.
                 * XXX should not happen here, but optimized out in
                 * the caller.
                 */
-               if (fw_one_pass) {
+               if (V_fw_one_pass) {
                        IPFW_RUNLOCK(chain);
                        return (IP_FW_PASS);
                }
 
                f = args->rule->next_rule;
+
                if (f == NULL)
                        f = lookup_next_rule(args->rule, 0);
        } else {
@@ -2565,6 +2735,21 @@ do {                                                                     \
 
        /*
         * Now scan the rules, and parse microinstructions for each rule.
+        * We have two nested loops and an inner switch. Sometimes we
+        * need to break out of one or both loops, or re-enter one of
+        * the loops with updated variables. Loop variables are:
+        *
+        *      f (outer loop) points to the current rule.
+        *              On output it points to the matching rule.
+        *      done (outer loop) is used as a flag to break the loop.
+        *      l (inner loop)  residual length of current rule.
+        *      cmd points to the current microinstruction.
+        *
+        * We break the inner loop by setting l=0 and possibly
+        * cmdlen=0 if we don't want to advance cmd.
+        * We break the outer loop by setting done=1
+        * We can restart the inner loop by setting l>0 and f, cmd
+        * as needed.
         */
        for (; f; f = f->next) {
                ipfw_insn *cmd;
@@ -2572,7 +2757,7 @@ do {                                                                      \
                int l, cmdlen, skip_or; /* skip rest of OR block */
 
 /* again: */
-               if (set_disable & (1 << f->set) )
+               if (V_set_disable & (1 << f->set) )
                        continue;
 
                skip_or = 0;
@@ -2958,7 +3143,7 @@ do {                                                                      \
                        }
 
                        case O_LOG:
-                               if (fw_verbose)
+                               if (V_fw_verbose)
                                        ipfw_log(f, hlen, args, m,
                                            oif, offset, tablearg, ip);
                                match = 1;
@@ -3161,14 +3346,13 @@ do {                                                                    \
                         *
                         * In general, here we set retval and terminate the
                         * outer loop (would be a 'break 3' in some language,
-                        * but we need to do a 'goto done').
+                        * but we need to set l=0, done=1)
                         *
                         * Exceptions:
                         * O_COUNT and O_SKIPTO actions:
                         *   instead of terminating, we jump to the next rule
-                        *   ('break' after setting match and l)
-                        *   or to the SKIPTO target ('break' after
-                        *   having set f, cmd and l), respectively.
+                        *   (setting l=0), or to the SKIPTO target (by
+                        *   setting f, cmd and l as needed), respectively.
                         *
                         * O_TAG, O_LOG and O_ALTQ action parameters:
                         *   perform some action and set match = 1;
@@ -3179,30 +3363,28 @@ do {                                                                    \
                         *   These opcodes try to install an entry in the
                         *   state tables; if successful, we continue with
                         *   the next opcode (match=1; break;), otherwise
-                        *   the packet *   must be dropped
-                        *   ('goto done' after setting retval);
+                        *   the packet must be dropped (set retval,
+                        *   break loops with l=0, done=1)
                         *
                         * O_PROBE_STATE and O_CHECK_STATE: these opcodes
                         *   cause a lookup of the state table, and a jump
                         *   to the 'action' part of the parent rule
                         *   if an entry is found, or
                         *   (CHECK_STATE only) a jump to the next rule if
-                        *   the entry is not found ('goto next_rule').
-                        *   The result of the lookup is cached to make
-                        *   further instances of these opcodes are
-                        *   effectively NOPs.
-                        *   The jump to the next rule is done by a break
-                        *   after zeroing the cmdlen value and setting
-                        *   match.
+                        *   the entry is not found.
+                        *   The result of the lookup is cached so that
+                        *   further instances of these opcodes become NOPs.
+                        *   The jump to the next rule is done by setting
+                        *   l=0, cmdlen=0.
                         */
                        case O_LIMIT:
                        case O_KEEP_STATE:
                                if (install_state(f,
                                    (ipfw_insn_limit *)cmd, args, tablearg)) {
+                                       /* error or limit violation */
                                        retval = IP_FW_DENY;
-                                       /* was goto done; */ /* error/limit violation */
-                                       l = 0;          /* break the inner loop */
-                                       done = 1;       /* break the external loop */
+                                       l = 0;  /* exit inner loop */
+                                       done = 1; /* exit outer loop */
                                }
                                match = 1;
                                break;
@@ -3226,7 +3408,8 @@ do {                                                                      \
                                        /*
                                         * Found dynamic entry, update stats
                                         * and jump to the 'action' part of
-                                        * the parent rule.
+                                        * the parent rule by setting
+                                        * f, cmd, l and clearing cmdlen.
                                         */
                                        q->pcnt++;
                                        q->bcnt += pktlen;
@@ -3234,9 +3417,8 @@ do {                                                                      \
                                        cmd = ACTION_PTR(f);
                                        l = f->cmd_len - f->act_ofs;
                                        IPFW_DYN_UNLOCK();
-                                       /* previously was goto check_body; */
-                                       cmdlen = 0;     /* make null for() changes */
-                                       match = 1;      /* do not break to the external loop */
+                                       cmdlen = 0;
+                                       match = 1;
                                        break;
                                }
                                /*
@@ -3245,60 +3427,56 @@ do {                                                                    \
                                 * ignore and continue with next opcode.
                                 */
                                if (cmd->opcode == O_CHECK_STATE)
-                                       l = 0; /* was goto next_rule; */
+                                       l = 0; /* exit inner loop */
                                match = 1;
                                break;
 
                        case O_ACCEPT:
                                retval = 0;     /* accept */
-                               /* was goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                break;
 
                        case O_PIPE:
                        case O_QUEUE:
                                args->rule = f; /* report matching rule */
+                               args->rule_id = f->id;
+                               args->chain_id = chain->id;
                                if (cmd->arg1 == IP_FW_TABLEARG)
                                        args->cookie = tablearg;
                                else
                                        args->cookie = cmd->arg1;
                                retval = IP_FW_DUMMYNET;
-                               /* was goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                break;
 
 #if 0
                        case O_DIVERT:
-                       case O_TEE: {
-                               struct divert_tag *dt;
-
+                       case O_TEE:
                                if (args->eh) /* not on layer 2 */
                                        break;
+                               /* otherwise this is terminal */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                mtag = m_tag_get(PACKET_TAG_DIVERT,
-                                               sizeof(struct divert_tag),
-                                               M_NOWAIT);
+                                       sizeof(struct divert_tag),
+                                       M_NOWAIT);
                                if (mtag == NULL) {
-                                       /* XXX statistic */
-                                       /* drop packet */
-                                       IPFW_RUNLOCK(chain);
-                                       return (IP_FW_DENY);
-                               }
-                               dt = (struct divert_tag *)(mtag+1);
-                               dt->cookie = f->rulenum;
-                               if (cmd->arg1 == IP_FW_TABLEARG)
+                                   retval = IP_FW_DENY;
+                               } else {
+                                   struct divert_tag *dt;
+                                   dt = (struct divert_tag *)(mtag+1);
+                                   dt->cookie = f->rulenum;
+                                   if (cmd->arg1 == IP_FW_TABLEARG)
                                        dt->info = tablearg;
-                               else
+                                   else
                                        dt->info = cmd->arg1;
-                               m_tag_prepend(m, mtag);
-                               retval = (cmd->opcode == O_DIVERT) ?
-                                   IP_FW_DIVERT : IP_FW_TEE;
-                               /* was goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                                   m_tag_prepend(m, mtag);
+                                   retval = (cmd->opcode == O_DIVERT) ?
+                                       IP_FW_DIVERT : IP_FW_TEE;
+                               }
                                break;
-                       }
 #endif
 
                        case O_COUNT:
@@ -3307,9 +3485,7 @@ do {                                                                      \
                                f->bcnt += pktlen;
                                f->timestamp = time_uptime;
                                if (cmd->opcode == O_COUNT) {
-                                       /* was goto next_rule; */
-                                       l = 0;          /* exit the inner loop */
-                                       match = 1;      /* do not break the loop */
+                                       l = 0;  /* exit inner loop */
                                        break;
                                }
                                /* handle skipto */
@@ -3320,25 +3496,23 @@ do {                                                                    \
                                                lookup_next_rule(f, 0);
                                        f = f->next_rule;
                                }
-                               /* previously was "goto again;"
-                                * We emulate by re-entering the inner loop
+                               /*
+                                * Skip disabled rules, and
+                                * re-enter the inner loop
                                 * with the correct f, l and cmd.
-                                * First, skip over disabled rules.
-                                * Should at least match the default rule,
-                                * but try to be robust.
+                                * Also clear cmdlen and skip_or
                                 */
-                               while (f && (set_disable & (1 << f->set)))
+                               while (f && (V_set_disable & (1 << f->set)))
                                        f = f->next;
-                               /* prepare to re-enter the inner loop. */
-                               if (f) {        /* better safe than sorry */
+                               if (f) { /* found a valid rule */
                                        l = f->cmd_len;
                                        cmd = f->cmd;
                                } else {
-                                       l = 0;  /* this will break the inner loop */
+                                       l = 0;  /* exit inner loop */
                                }
-                               cmdlen = 0;     /* reset loop condition */
+                               match = 1;
+                               cmdlen = 0;
                                skip_or = 0;
-                               match = 1;      /* do not break the loop */
                                break;
 
                        case O_REJECT:
@@ -3373,47 +3547,44 @@ do {                                                                    \
 #endif
                        case O_DENY:
                                retval = IP_FW_DENY;
-                               /* goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                break;
 
-                       case O_FORWARD_IP: {
-                               struct sockaddr_in *sa;
-                               sa = &(((ipfw_insn_sa *)cmd)->sa);
+                       case O_FORWARD_IP:
                                if (args->eh)   /* not valid on layer2 pkts */
                                        break;
                                if (!q || dyn_dir == MATCH_FORWARD) {
-                                       if (sa->sin_addr.s_addr == INADDR_ANY) {
-                                               bcopy(sa, &args->hopstore,
-                                                       sizeof(*sa));
-                                               args->hopstore.sin_addr.s_addr =
-                                                   htonl(tablearg);
-                                               args->next_hop =
-                                                   &args->hopstore;
-                                       } else {
-                                               args->next_hop = sa;
-                                       }
+                                   struct sockaddr_in *sa;
+                                   sa = &(((ipfw_insn_sa *)cmd)->sa);
+                                   if (sa->sin_addr.s_addr == INADDR_ANY) {
+                                       bcopy(sa, &args->hopstore,
+                                               sizeof(*sa));
+                                       args->hopstore.sin_addr.s_addr =
+                                               htonl(tablearg);
+                                       args->next_hop = &args->hopstore;
+                                   } else {
+                                       args->next_hop = sa;
+                                   }
                                }
                                retval = IP_FW_PASS;
-                       }
-                               /* goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                break;
 
                        case O_NETGRAPH:
                        case O_NGTEE:
                                args->rule = f; /* report matching rule */
+                               args->rule_id = f->id;
+                               args->chain_id = chain->id;
                                if (cmd->arg1 == IP_FW_TABLEARG)
                                        args->cookie = tablearg;
                                else
                                        args->cookie = cmd->arg1;
                                retval = (cmd->opcode == O_NETGRAPH) ?
                                    IP_FW_NETGRAPH : IP_FW_NGTEE;
-                               /* goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
                                break;
 
 #if 0
@@ -3423,38 +3594,89 @@ do {                                                                    \
                                f->timestamp = time_uptime;
                                M_SETFIB(m, cmd->arg1);
                                args->f_id.fib = cmd->arg1;
-                               /* was goto next_rule; */
-                               l = 0;
-                               match = 1;
+                               l = 0;          /* exit inner loop */
                                break;
 
-                       case O_NAT: {
-                               struct cfg_nat *t;
-                               int nat_id;
-
-                               if (IPFW_NAT_LOADED) {
-                                       args->rule = f; /* Report matching rule. */
-                                       t = ((ipfw_insn_nat *)cmd)->nat;
+                       case O_NAT:
+                               if (!IPFW_NAT_LOADED) {
+                                   retval = IP_FW_DENY;
+                               } else {
+                                   struct cfg_nat *t;
+                                   int nat_id;
+
+                                   args->rule = f; /* Report matching rule. */
+                                   args->rule_id = f->id;
+                                   args->chain_id = chain->id;
+                                   t = ((ipfw_insn_nat *)cmd)->nat;
+                                   if (t == NULL) {
+                                       nat_id = (cmd->arg1 == IP_FW_TABLEARG) ?
+                                               tablearg : cmd->arg1;
+                                       LOOKUP_NAT(V_layer3_chain, nat_id, t);
                                        if (t == NULL) {
-                                               nat_id = (cmd->arg1 == IP_FW_TABLEARG) ?
-                                                   tablearg : cmd->arg1;
-                                               LOOKUP_NAT(layer3_chain, nat_id, t);
-                                               if (t == NULL) {
-                                                       retval = IP_FW_DENY;
-                                                       /* goto done; */
-                                                       l = 0;          /* break the inner loop */
-                                                       done = 1;       /* break the external loop */
-                                                       break;
-                                               }
-                                               if (cmd->arg1 != IP_FW_TABLEARG)
-                                                       ((ipfw_insn_nat *)cmd)->nat = t;
+                                           retval = IP_FW_DENY;
+                                           l = 0;      /* exit inner loop */
+                                           done = 1;   /* exit outer loop */
+                                           break;
                                        }
-                                       retval = ipfw_nat_ptr(args, t, m);
-                               } else
-                                       retval = IP_FW_DENY;
-                               /* goto done; */
-                               l = 0;          /* break the inner loop */
-                               done = 1;       /* break the external loop */
+                                       if (cmd->arg1 != IP_FW_TABLEARG)
+                                           ((ipfw_insn_nat *)cmd)->nat = t;
+                                   }
+                                   retval = ipfw_nat_ptr(args, t, m);
+                               }
+                               l = 0;          /* exit inner loop */
+                               done = 1;       /* exit outer loop */
+                               break;
+
+                       case O_REASS: {
+                               int ip_off;
+
+                               f->pcnt++;
+                               f->bcnt += pktlen;
+                               l = 0;  /* in any case exit inner loop */
+
+                               ip_off = (args->eh != NULL) ?
+                               ntohs(ip->ip_off) : ip->ip_off;
+                               /* if not fragmented, go to next rule */
+                               if ((ip_off & (IP_MF | IP_OFFMASK)) == 0)
+                                   break;
+                               /*
+                                * ip_reass() expects len & off in host
+                                * byte order: fix them in case we come
+                                * from layer2.
+                                */
+                               if (args->eh != NULL) {
+                                   ip->ip_len = ntohs(ip->ip_len);
+                                   ip->ip_off = ntohs(ip->ip_off);
+                               }
+
+                               args->m = m = ip_reass(m);
+
+                               /*
+                                * IP header checksum fixup after
+                                * reassembly and leave header
+                                * in network byte order.
+                               */
+                               if (m == NULL) { /* fragment got swallowed */
+                                   retval = IP_FW_DENY;
+                               } else { /* good, packet complete */
+                                   int hlen;
+
+                                   ip = mtod(m, struct ip *);
+                                   hlen = ip->ip_hl << 2;
+                                   /* revert len & off for layer2 pkts */
+                                   if (args->eh != NULL)
+                                   ip->ip_len = htons(ip->ip_len);
+                                   ip->ip_sum = 0;
+                                   if (hlen == sizeof(struct ip))
+                                   ip->ip_sum = in_cksum_hdr(ip);
+                                   else
+                                   ip->ip_sum = in_cksum(m, hlen);
+                                   retval = IP_FW_REASS;
+                                   args->rule = f;
+                                   args->rule_id = f->id;
+                                   args->chain_id = chain->id;
+                               }
+                               done = 1;       /* exit outer loop */
                                break;
                        }
 #endif
@@ -3463,6 +3685,9 @@ do {                                                                      \
                                break; // XXX we disabled some
                                panic("-- unknown opcode %d\n", cmd->opcode);
                        } /* end of switch() on opcodes */
+                       /*
+                        * if we get here with l=0, then match is irrelevant.
+                        */
 
                        if (cmd->len & F_NOT)
                                match = !match;
@@ -3475,12 +3700,13 @@ do {                                                                    \
                                        break;          /* try next rule    */
                        }
 
-               }       /* end of inner for, scan opcodes */
+               }       /* end of inner loop, scan opcodes */
 
                if (done)
                        break;
 
-/* next_rule:; */      /* try next rule */
+/* next_rule:;*/               /* try next rule                */
+
        }               /* end of outer for, scan rules */
 
        if (done) {
@@ -3488,16 +3714,15 @@ do {                                                                    \
                f->pcnt++;
                f->bcnt += pktlen;
                f->timestamp = time_uptime;
-               IPFW_RUNLOCK(chain);
-               return (retval);
+       } else {
+               retval = IP_FW_DENY;
+               printf("ipfw: ouch!, skip past end of rules, denying packet\n");
        }
-
-       printf("ipfw: ouch!, skip past end of rules, denying packet\n");
        IPFW_RUNLOCK(chain);
-       return (IP_FW_DENY);
+       return (retval);
 
 pullup_failed:
-       if (fw_verbose)
+       if (V_fw_verbose)
                printf("ipfw: pullup failed\n");
        return (IP_FW_DENY);
 }
@@ -3513,6 +3738,8 @@ flush_rule_ptrs(struct ip_fw_chain *chain)
 
        IPFW_WLOCK_ASSERT(chain);
 
+       chain->id++;
+
        for (rule = chain->rules; rule; rule = rule->next)
                rule->next_rule = NULL;
 }
@@ -3548,6 +3775,7 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
 
        if (chain->rules == NULL) {     /* default rule */
                chain->rules = rule;
+               rule->id = ++chain->id;
                goto done;
         }
 
@@ -3555,10 +3783,10 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
         * If rulenum is 0, find highest numbered rule before the
         * default rule, and add autoinc_step
         */
-       if (autoinc_step < 1)
-               autoinc_step = 1;
-       else if (autoinc_step > 1000)
-               autoinc_step = 1000;
+       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
@@ -3568,8 +3796,8 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
                                break;
                        rule->rulenum = f->rulenum;
                }
-               if (rule->rulenum < IPFW_DEFAULT_RULE - autoinc_step)
-                       rule->rulenum += autoinc_step;
+               if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
+                       rule->rulenum += V_autoinc_step;
                input_rule->rulenum = rule->rulenum;
        }
 
@@ -3589,12 +3817,14 @@ add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
                }
        }
        flush_rule_ptrs(chain);
+       /* chain->id incremented inside flush_rule_ptrs() */
+       rule->id = chain->id;
 done:
-       static_count++;
-       static_len += l;
+       V_static_count++;
+       V_static_len += l;
        IPFW_WUNLOCK(chain);
        DEB(printf("ipfw: installed rule %d, static count now %d\n",
-               rule->rulenum, static_count);)
+               rule->rulenum, V_static_count);)
        return (0);
 }
 
@@ -3623,8 +3853,8 @@ remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
                chain->rules = n;
        else
                prev->next = n;
-       static_count--;
-       static_len -= l;
+       V_static_count--;
+       V_static_len -= l;
 
        rule->next = chain->reap;
        chain->reap = rule;
@@ -3714,8 +3944,8 @@ del_entry(struct ip_fw_chain *chain, u_int32_t arg)
        }
 
        IPFW_WLOCK(chain);
-       rule = chain->rules;
-       chain->reap = NULL;
+       rule = chain->rules;    /* common starting point */
+       chain->reap = NULL;     /* prepare for deletions */
        switch (cmd) {
        case 0: /* delete rules with given number */
                /*
@@ -3739,18 +3969,17 @@ del_entry(struct ip_fw_chain *chain, u_int32_t arg)
 
        case 1: /* delete all rules with given set number */
                flush_rule_ptrs(chain);
-               rule = chain->rules;
-               while (rule->rulenum < IPFW_DEFAULT_RULE)
+               while (rule->rulenum < IPFW_DEFAULT_RULE) {
                        if (rule->set == rulenum)
                                rule = remove_rule(chain, rule, prev);
                        else {
                                prev = rule;
                                rule = rule->next;
                        }
+               }
                break;
 
        case 2: /* move rules with given number to new set */
-               rule = chain->rules;
                for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next)
                        if (rule->rulenum == rulenum)
                                rule->set = new_set;
@@ -3769,6 +3998,7 @@ del_entry(struct ip_fw_chain *chain, u_int32_t arg)
                        else if (rule->set == new_set)
                                rule->set = rulenum;
                break;
+
        case 5: /* delete rules with given number and with given set number.
                 * rulenum - given rule number;
                 * new_set - given set number.
@@ -3845,7 +4075,7 @@ zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
 
        IPFW_WLOCK(chain);
        if (rulenum == 0) {
-               norule_counter = 0;
+               V_norule_counter = 0;
                for (rule = chain->rules; rule; rule = rule->next) {
                        /* Skip rules from another set. */
                        if (cmd == 1 && rule->set != set)
@@ -3878,7 +4108,7 @@ zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
        }
        IPFW_WUNLOCK(chain);
 
-       if (fw_verbose) {
+       if (V_fw_verbose) {
 #define lev LOG_SECURITY | LOG_NOTICE
 
                if (rulenum)
@@ -4117,6 +4347,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
                case O_UNREACH6:
 #endif
                case O_SKIPTO:
+               case O_REASS:
 check_size:
                        if (cmdlen != F_INSN_SIZE(ipfw_insn))
                                goto bad_size;
@@ -4209,8 +4440,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) {
@@ -4224,19 +4454,19 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
                if (bp + i <= ep) {
                        bcopy(rule, bp, i);
                        /*
-                        * XXX HACK. Store the disable mask in the "next" pointer
-                        * in a wild attempt to keep the ABI the same.
+                        * XXX HACK. Store the disable mask in the "next"
+                        * pointer in a wild attempt to keep the ABI the same.
                         * Why do we do this on EVERY rule?
                         */
-                       bcopy(&set_disable, &(((struct ip_fw *)bp)->next_rule),
-                           sizeof(set_disable));
+                       bcopy(&V_set_disable,
+                           &(((struct ip_fw *)bp)->next_rule),
+                           sizeof(V_set_disable));
                        if (((struct ip_fw *)bp)->timestamp)
                                ((struct ip_fw *)bp)->timestamp += boot_seconds;
                        bp += i;
                }
        }
        IPFW_RUNLOCK(chain);
-
        return (bp - (char *)buf);
 }
 
@@ -4255,14 +4485,14 @@ ipfw_getdynrules(struct ip_fw_chain *chain, void *buf, size_t space)
        time_t  boot_seconds;
 
        printf("dynrules requested\n");
-       boot_seconds = boottime.tv_sec;
+        boot_seconds = boottime.tv_sec;
 
-       if (ipfw_dyn_v) {
+       if (V_ipfw_dyn_v) {
                ipfw_dyn_rule *p, *last = NULL;
 
                IPFW_DYN_LOCK();
-               for (i = 0 ; i < curr_dyn_buckets; i++)
-                       for (p = ipfw_dyn_v[i] ; p != NULL; p = p->next) {
+               for (i = 0 ; i < V_curr_dyn_buckets; i++)
+                       for (p = V_ipfw_dyn_v[i] ; p != NULL; p = p->next) {
                                if (bp + sizeof *p <= ep) {
                                        ipfw_dyn_rule *dst =
                                                (ipfw_dyn_rule *)bp;
@@ -4291,7 +4521,7 @@ ipfw_getdynrules(struct ip_fw_chain *chain, void *buf, size_t space)
                                        bp += sizeof(ipfw_dyn_rule);
                                } else {
                                        p = NULL;       /* break the loop */
-                                       i = curr_dyn_buckets;
+                                       i = V_curr_dyn_buckets;
                                }
                        }
                IPFW_DYN_UNLOCK();
@@ -4343,7 +4573,7 @@ ipfw_ctl(struct sockopt *sopt)
                 * change between calculating the size and returning the
                 * data in which case we'll just return what fits.
                 */
-               size = static_len;      /* size of static rules */
+               size = V_static_len;    /* size of static rules */
 
                /*
                 * XXX todo: if the user passes a short length just to know
@@ -4352,7 +4582,7 @@ ipfw_ctl(struct sockopt *sopt)
                 */
                buf = malloc(size, M_TEMP, M_WAITOK);
                error = sooptcopyout(sopt, buf,
-                               ipfw_getrules(&layer3_chain, buf, size));
+                               ipfw_getrules(&V_layer3_chain, buf, size));
                free(buf, M_TEMP);
                break;
 
@@ -4361,12 +4591,12 @@ ipfw_ctl(struct sockopt *sopt)
                 * pass up a copy of the current dynamic rules.
                 * The last dynamic rule has NULL in the "next" field.
                 */
-               /* if (!ipfw_dyn_v) XXX check for empty set ? */
-               size = (dyn_count * sizeof(ipfw_dyn_rule)); /* size of dyn. rules */
+               /* if (!V_ipfw_dyn_v) XXX check for empty set ? */
+               size = (V_dyn_count * sizeof(ipfw_dyn_rule)); /* size of dyn. rules */
 
                buf = malloc(size, M_TEMP, M_WAITOK);
                error = sooptcopyout(sopt, buf,
-                               ipfw_getdynrules(&layer3_chain, buf, size));
+                               ipfw_getdynrules(&V_layer3_chain, buf, size));
                free(buf, M_TEMP);
                break;
 
@@ -4384,12 +4614,12 @@ ipfw_ctl(struct sockopt *sopt)
                 * the old list without the need for a lock.
                 */
 
-               IPFW_WLOCK(&layer3_chain);
-               layer3_chain.reap = NULL;
-               free_chain(&layer3_chain, 0 /* keep default rule */);
-               rule = layer3_chain.reap;
-               layer3_chain.reap = NULL;
-               IPFW_WUNLOCK(&layer3_chain);
+               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);
                break;
@@ -4401,7 +4631,7 @@ ipfw_ctl(struct sockopt *sopt)
                if (error == 0)
                        error = check_ipfw_struct(rule, sopt->sopt_valsize);
                if (error == 0) {
-                       error = add_rule(&layer3_chain, rule);
+                       error = add_rule(&V_layer3_chain, rule);
                        size = RULESIZE(rule);
                        if (!error && sopt->sopt_dir == SOPT_GET)
                                error = sooptcopyout(sopt, rule, size);
@@ -4428,10 +4658,10 @@ ipfw_ctl(struct sockopt *sopt)
                        break;
                size = sopt->sopt_valsize;
                if (size == sizeof(u_int32_t))  /* delete or reassign */
-                       error = del_entry(&layer3_chain, rulenum[0]);
+                       error = del_entry(&V_layer3_chain, rulenum[0]);
                else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */
-                       set_disable =
-                           (set_disable | rulenum[0]) & ~rulenum[1] &
+                       V_set_disable =
+                           (V_set_disable | rulenum[0]) & ~rulenum[1] &
                            ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
                else
                        error = EINVAL;
@@ -4446,11 +4676,10 @@ ipfw_ctl(struct sockopt *sopt)
                    if (error)
                        break;
                }
-               error = zero_entry(&layer3_chain, rulenum[0],
+               error = zero_entry(&V_layer3_chain, rulenum[0],
                        sopt->sopt_name == IP_FW_RESETLOG);
                break;
 
-#ifdef radix
        case IP_FW_TABLE_ADD:
                {
                        ipfw_table_entry ent;
@@ -4459,7 +4688,7 @@ ipfw_ctl(struct sockopt *sopt)
                            sizeof(ent), sizeof(ent));
                        if (error)
                                break;
-                       error = add_table_entry(&layer3_chain, ent.tbl,
+                       error = add_table_entry(&V_layer3_chain, ent.tbl,
                            ent.addr, ent.masklen, ent.value);
                }
                break;
@@ -4472,7 +4701,7 @@ ipfw_ctl(struct sockopt *sopt)
                            sizeof(ent), sizeof(ent));
                        if (error)
                                break;
-                       error = del_table_entry(&layer3_chain, ent.tbl,
+                       error = del_table_entry(&V_layer3_chain, ent.tbl,
                            ent.addr, ent.masklen);
                }
                break;
@@ -4485,9 +4714,9 @@ ipfw_ctl(struct sockopt *sopt)
                            sizeof(tbl), sizeof(tbl));
                        if (error)
                                break;
-                       IPFW_WLOCK(&layer3_chain);
-                       error = flush_table(&layer3_chain, tbl);
-                       IPFW_WUNLOCK(&layer3_chain);
+                       IPFW_WLOCK(&V_layer3_chain);
+                       error = flush_table(&V_layer3_chain, tbl);
+                       IPFW_WUNLOCK(&V_layer3_chain);
                }
                break;
 
@@ -4498,9 +4727,9 @@ ipfw_ctl(struct sockopt *sopt)
                        if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
                            sizeof(tbl))))
                                break;
-                       IPFW_RLOCK(&layer3_chain);
-                       error = count_table(&layer3_chain, tbl, &cnt);
-                       IPFW_RUNLOCK(&layer3_chain);
+                       IPFW_RLOCK(&V_layer3_chain);
+                       error = count_table(&V_layer3_chain, tbl, &cnt);
+                       IPFW_RUNLOCK(&V_layer3_chain);
                        if (error)
                                break;
                        error = sooptcopyout(sopt, &cnt, sizeof(cnt));
@@ -4524,9 +4753,9 @@ ipfw_ctl(struct sockopt *sopt)
                        }
                        tbl->size = (size - sizeof(*tbl)) /
                            sizeof(ipfw_table_entry);
-                       IPFW_RLOCK(&layer3_chain);
-                       error = dump_table(&layer3_chain, tbl);
-                       IPFW_RUNLOCK(&layer3_chain);
+                       IPFW_RLOCK(&V_layer3_chain);
+                       error = dump_table(&V_layer3_chain, tbl);
+                       IPFW_RUNLOCK(&V_layer3_chain);
                        if (error) {
                                free(tbl, M_TEMP);
                                break;
@@ -4536,8 +4765,6 @@ ipfw_ctl(struct sockopt *sopt)
                }
                break;
 
-#endif /* radix */
-
        case IP_FW_NAT_CFG:
                if (IPFW_NAT_LOADED)
                        error = ipfw_nat_cfg_ptr(sopt);
@@ -4601,13 +4828,20 @@ struct ip_fw *ip_fw_default_rule;
  * every dyn_keepalive_period
  */
 static void
-ipfw_tick(void * __unused unused)
+ipfw_tick(void * vnetx)
 {
        struct mbuf *m0, *m, *mnext, **mtailp;
+#ifdef INET6
+       struct mbuf *m6, **m6_tailp;
+#endif
        int i;
        ipfw_dyn_rule *q;
+#ifdef VIMAGE
+       struct vnet *vp = vnetx;
+#endif
 
-       if (dyn_keepalive == 0 || ipfw_dyn_v == NULL || dyn_count == 0)
+       CURVNET_SET(vp);
+       if (V_dyn_keepalive == 0 || V_ipfw_dyn_v == NULL || V_dyn_count == 0)
                goto done;
 
        /*
@@ -4618,29 +4852,56 @@ ipfw_tick(void * __unused unused)
         */
        m0 = NULL;
        mtailp = &m0;
+#ifdef INET6
+       m6 = NULL;
+       m6_tailp = &m6;
+#endif
        IPFW_DYN_LOCK();
-       for (i = 0 ; i < curr_dyn_buckets ; i++) {
-               for (q = ipfw_dyn_v[i] ; q ; q = q->next ) {
+       for (i = 0 ; i < V_curr_dyn_buckets ; i++) {
+               for (q = V_ipfw_dyn_v[i] ; q ; q = q->next ) {
                        if (q->dyn_type == O_LIMIT_PARENT)
                                continue;
                        if (q->id.proto != IPPROTO_TCP)
                                continue;
                        if ( (q->state & BOTH_SYN) != BOTH_SYN)
                                continue;
-                       if (TIME_LEQ( time_uptime+dyn_keepalive_interval,
+                       if (TIME_LEQ( time_uptime+V_dyn_keepalive_interval,
                            q->expire))
                                continue;       /* too early */
                        if (TIME_LEQ(q->expire, time_uptime))
                                continue;       /* too late, rule expired */
 
-                       *mtailp = send_pkt(NULL, &(q->id), q->ack_rev - 1,
+                       m = send_pkt(NULL, &(q->id), q->ack_rev - 1,
                                q->ack_fwd, TH_SYN);
-                       if (*mtailp != NULL)
-                               mtailp = &(*mtailp)->m_nextpkt;
-                       *mtailp = send_pkt(NULL, &(q->id), q->ack_fwd - 1,
+                       mnext = send_pkt(NULL, &(q->id), q->ack_fwd - 1,
                                q->ack_rev, 0);
-                       if (*mtailp != NULL)
-                               mtailp = &(*mtailp)->m_nextpkt;
+
+                       switch (q->id.addr_type) {
+                       case 4:
+                               if (m != NULL) {
+                                       *mtailp = m;
+                                       mtailp = &(*mtailp)->m_nextpkt;
+                               }
+                               if (mnext != NULL) {
+                                       *mtailp = mnext;
+                                       mtailp = &(*mtailp)->m_nextpkt;
+                               }
+                               break;
+#ifdef INET6
+                       case 6:
+                               if (m != NULL) {
+                                       *m6_tailp = m;
+                                       m6_tailp = &(*m6_tailp)->m_nextpkt;
+                               }
+                               if (mnext != NULL) {
+                                       *m6_tailp = mnext;
+                                       m6_tailp = &(*m6_tailp)->m_nextpkt;
+                               }
+                               break;
+#endif
+                       }
+
+                       m = mnext = NULL;
                }
        }
        IPFW_DYN_UNLOCK();
@@ -4649,64 +4910,43 @@ ipfw_tick(void * __unused unused)
                m->m_nextpkt = NULL;
                ip_output(m, NULL, NULL, 0, NULL, NULL);
        }
+#ifdef INET6
+       for (m = mnext = m6; m != NULL; m = mnext) {
+               mnext = m->m_nextpkt;
+               m->m_nextpkt = NULL;
+               ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+       }
+#endif
 done:
-       callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL);
+       callout_reset(&V_ipfw_timeout, V_dyn_keepalive_period*hz,
+               ipfw_tick, NULL);
+       CURVNET_RESTORE();
 }
 
+static int vnet_ipfw_init(const void *);
+
 int
 ipfw_init(void)
 {
-       struct ip_fw default_rule;
-       int error;
-
-#ifdef INET6
-       /* Setup IPv6 fw sysctl tree. */
-       sysctl_ctx_init(&ip6_fw_sysctl_ctx);
-       ip6_fw_sysctl_tree = SYSCTL_ADD_NODE(&ip6_fw_sysctl_ctx,
-           SYSCTL_STATIC_CHILDREN(_net_inet6_ip6), OID_AUTO, "fw",
-           CTLFLAG_RW | CTLFLAG_SECURE, 0, "Firewall");
-       SYSCTL_ADD_PROC(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree),
-           OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3,
-           &fw6_enable, 0, ipfw_chg_hook, "I", "Enable ipfw+6");
-       SYSCTL_ADD_INT(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree),
-           OID_AUTO, "deny_unknown_exthdrs", CTLFLAG_RW | CTLFLAG_SECURE,
-           &fw_deny_unknown_exthdrs, 0,
-           "Deny packets with unknown IPv6 Extension Headers");
-#endif
+       int error = 0;
 
-       layer3_chain.rules = NULL;
-       IPFW_LOCK_INIT(&layer3_chain);
        ipfw_dyn_rule_zone = uma_zcreate("IPFW dynamic rule",
            sizeof(ipfw_dyn_rule), NULL, NULL, NULL, NULL,
            UMA_ALIGN_PTR, 0);
-       IPFW_DYN_LOCK_INIT();
-       callout_init(&ipfw_timeout, CALLOUT_MPSAFE);
-
-       bzero(&default_rule, sizeof default_rule);
-
-       default_rule.act_ofs = 0;
-       default_rule.rulenum = IPFW_DEFAULT_RULE;
-       default_rule.cmd_len = 1;
-       default_rule.set = RESVD_SET;
-
-       default_rule.cmd[0].len = 1;
-       default_rule.cmd[0].opcode =
-#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
-                               1 ? O_ACCEPT :
-#endif
-                               O_DENY;
 
-       error = add_rule(&layer3_chain, &default_rule);
-       if (error != 0) {
-               printf("ipfw2: error %u initializing default rule "
-                       "(support disabled)\n", error);
+       IPFW_DYN_LOCK_INIT();
+       error = vnet_ipfw_init(NULL);
+       if (error) {
                IPFW_DYN_LOCK_DESTROY();
-               IPFW_LOCK_DESTROY(&layer3_chain);
+               IPFW_LOCK_DESTROY(&V_layer3_chain);
                uma_zdestroy(ipfw_dyn_rule_zone);
                return (error);
        }
 
-       ip_fw_default_rule = layer3_chain.rules;
+       /*
+        * Only print out this stuff the first time around,
+        * when called from the sysinit code.
+        */
        printf("ipfw2 "
 #ifdef INET6
                "(+ipv6) "
@@ -4729,35 +4969,24 @@ ipfw_init(void)
 #else
                "loadable",
 #endif
+               default_to_accept ? "accept" : "deny");
 
-               default_rule.cmd[0].opcode == O_ACCEPT ? "accept" : "deny");
-
-#ifdef IPFIREWALL_VERBOSE
-       fw_verbose = 1;
-#endif
-#ifdef IPFIREWALL_VERBOSE_LIMIT
-       verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
-#endif
-       if (fw_verbose == 0)
+       /*
+        * Note: V_xxx variables can be accessed here but the vnet specific
+        * initializer may not have been called yet for the VIMAGE case.
+        * Tuneables will have been processed. We will print out values for
+        * the default vnet.
+        * XXX This should all be rationalized AFTER 8.0
+        */
+       if (V_fw_verbose == 0)
                printf("disabled\n");
-       else if (verbose_limit == 0)
+       else if (V_verbose_limit == 0)
                printf("unlimited\n");
        else
                printf("limited to %d packets/entry by default\n",
-                   verbose_limit);
+                   V_verbose_limit);
 
-       error = init_tables(&layer3_chain);
-       if (error) {
-               IPFW_DYN_LOCK_DESTROY();
-               IPFW_LOCK_DESTROY(&layer3_chain);
-               uma_zdestroy(ipfw_dyn_rule_zone);
-               return (error);
-       }
-       ip_fw_ctl_ptr = ipfw_ctl;
-       ip_fw_chk_ptr = ipfw_chk;
-       callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);      
-       LIST_INIT(&layer3_chain.nat);
-       return (0);
+       return (error);
 }
 
 void
@@ -4768,19 +4997,19 @@ ipfw_destroy(void)
        ip_fw_chk_ptr = NULL;
        ip_fw_ctl_ptr = NULL;
        callout_drain(&ipfw_timeout);
-       IPFW_WLOCK(&layer3_chain);
-       flush_tables(&layer3_chain);
-       layer3_chain.reap = NULL;
-       free_chain(&layer3_chain, 1 /* kill default rule */);
-       reap = layer3_chain.reap, layer3_chain.reap = NULL;
-       IPFW_WUNLOCK(&layer3_chain);
+       IPFW_WLOCK(&V_layer3_chain);
+       flush_tables(&V_layer3_chain);
+       V_layer3_chain.reap = NULL;
+       free_chain(&V_layer3_chain, 1 /* kill default rule */);
+       reap = V_layer3_chain.reap, V_layer3_chain.reap = NULL;
+       IPFW_WUNLOCK(&V_layer3_chain);
        if (reap != NULL)
                reap_rules(reap);
        IPFW_DYN_LOCK_DESTROY();
        uma_zdestroy(ipfw_dyn_rule_zone);
-       if (ipfw_dyn_v != NULL)
-               free(ipfw_dyn_v, M_IPFW);
-       IPFW_LOCK_DESTROY(&layer3_chain);
+       if (V_ipfw_dyn_v != NULL)
+               free(V_ipfw_dyn_v, M_IPFW);
+       IPFW_LOCK_DESTROY(&V_layer3_chain);
 
 #ifdef INET6
        /* Free IPv6 fw sysctl tree. */
@@ -4789,3 +5018,110 @@ ipfw_destroy(void)
 
        printf("IP firewall unloaded\n");
 }
+
+/****************
+ * Stuff that must be initialized for every instance
+ * (including the first of course).
+ */
+static int
+vnet_ipfw_init(const void *unused)
+{
+       int error;
+       struct ip_fw default_rule;
+
+       /* First set up some values that are compile time options */
+#ifdef IPFIREWALL_VERBOSE
+       V_fw_verbose = 1;
+#endif
+#ifdef IPFIREWALL_VERBOSE_LIMIT
+       V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
+#endif
+
+       error = init_tables(&V_layer3_chain);
+       if (error) {
+               panic("init_tables"); /* XXX Marko fix this ! */
+       }
+#ifdef IPFIREWALL_NAT
+       LIST_INIT(&V_layer3_chain.nat);
+#endif
+
+       V_autoinc_step = 100;   /* bounded to 1..1000 in add_rule() */
+
+       V_ipfw_dyn_v = NULL;
+       V_dyn_buckets = 256;    /* must be power of 2 */
+       V_curr_dyn_buckets = 256; /* must be power of 2 */
+
+       V_dyn_ack_lifetime = 300;
+       V_dyn_syn_lifetime = 20;
+       V_dyn_fin_lifetime = 1;
+       V_dyn_rst_lifetime = 1;
+       V_dyn_udp_lifetime = 10;
+       V_dyn_short_lifetime = 5;
+       
+       V_dyn_keepalive_interval = 20;
+       V_dyn_keepalive_period = 5;
+       V_dyn_keepalive = 1;    /* do send keepalives */
+
+       V_dyn_max = 4096;       /* max # of dynamic rules */
+
+       V_fw_deny_unknown_exthdrs = 1;
+
+       V_layer3_chain.rules = NULL;
+       IPFW_LOCK_INIT(&V_layer3_chain);
+       callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);
+
+       bzero(&default_rule, sizeof default_rule);
+       default_rule.act_ofs = 0;
+       default_rule.rulenum = IPFW_DEFAULT_RULE;
+       default_rule.cmd_len = 1;
+       default_rule.set = RESVD_SET;
+       default_rule.cmd[0].len = 1;
+       default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
+       error = add_rule(&V_layer3_chain, &default_rule);
+
+       if (error != 0) {
+               printf("ipfw2: error %u initializing default rule "
+                       "(support disabled)\n", error);
+               IPFW_LOCK_DESTROY(&V_layer3_chain);
+               printf("leaving ipfw_iattach (1) with error %d\n", error);
+               return (error);
+       }
+
+       ip_fw_default_rule = V_layer3_chain.rules;
+
+       /* curvnet is NULL in the !VIMAGE case */
+       callout_reset(&V_ipfw_timeout, hz, ipfw_tick, curvnet);
+
+       /* First set up some values that are compile time options */
+       V_ipfw_vnet_ready = 1;          /* Open for business */
+
+       /*
+        * Hook the sockopt handler, and the layer2 (V_ip_fw_chk_ptr)
+        * and pfil hooks for ipv4 and ipv6. Even if the latter two fail
+        * we still keep the module alive because the sockopt and
+        * layer2 paths are still useful.
+        * ipfw[6]_hook return 0 on success, ENOENT on failure,
+        * so we can ignore the exact return value and just set a flag.
+        *
+        * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
+        * changes in the underlying (per-vnet) variables trigger
+        * immediate hook()/unhook() calls.
+        * In layer2 we have the same behaviour, except that V_ether_ipfw
+        * is checked on each packet because there are no pfil hooks.
+         */
+       V_ip_fw_ctl_ptr = ipfw_ctl;
+       V_ip_fw_chk_ptr = ipfw_chk;
+#ifndef linux
+       if (V_fw_enable && ipfw_hook() != 0) {
+               error = ENOENT; /* see ip_fw_pfil.c::ipfw_hook() */
+               printf("ipfw_hook() error\n");
+       }
+#ifdef INET6
+       if (V_fw6_enable && ipfw6_hook() != 0) {
+               error = ENOENT;
+               printf("ipfw6_hook() error\n");
+       }
+#endif
+#endif /* !linux */
+       return (error);
+}
index bc1f011..4e3568a 100644 (file)
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw_pfil.c,v 1.25.2.2 2008/04/25 10:26:30
 
 #include <net/if.h>
 #include <net/pfil.h>
+#include <net/vnet.h>
 
 #include <netinet/in.h>
 #include <netinet/ip.h>
@@ -105,6 +106,8 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
                KASSERT(ng_tag->dir == NG_IPFW_IN,
                    ("ng_ipfw tag with wrong direction"));
                args.rule = ng_tag->rule;
+               args.rule_id = ng_tag->rule_id;
+               args.chain_id = ng_tag->chain_id;
                m_tag_delete(*m0, (struct m_tag *)ng_tag);
        }
 
@@ -115,6 +118,8 @@ again:
 
                dt = (struct dn_pkt_tag *)(dn_tag+1);
                args.rule = dt->rule;
+               args.rule_id = dt->rule_id;
+               args.chain_id = dt->chain_id;
 
                m_tag_delete(*m0, dn_tag);
        }
@@ -231,6 +236,8 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
                KASSERT(ng_tag->dir == NG_IPFW_OUT,
                    ("ng_ipfw tag with wrong direction"));
                args.rule = ng_tag->rule;
+               args.rule_id = ng_tag->rule_id;
+               args.chain_id = ng_tag->chain_id;
                m_tag_delete(*m0, (struct m_tag *)ng_tag);
        }
 
@@ -241,6 +248,8 @@ again:
 
                dt = (struct dn_pkt_tag *)(dn_tag+1);
                args.rule = dt->rule;
+               args.rule_id = dt->rule_id;
+               args.chain_id = dt->chain_id;
 
                m_tag_delete(*m0, dn_tag);
        }
@@ -432,8 +441,10 @@ ipfw_hook(void)
        if (pfh_inet == NULL)
                return ENOENT;
 
-       pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
-       pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+       (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+               pfh_inet);
+       (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+               pfh_inet);
 
        return 0;
 }
@@ -447,8 +458,10 @@ ipfw_unhook(void)
        if (pfh_inet == NULL)
                return ENOENT;
 
-       pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
-       pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+       (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+               pfh_inet);
+       (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+               pfh_inet);
 
        return 0;
 }
@@ -463,8 +476,10 @@ ipfw6_hook(void)
        if (pfh_inet6 == NULL)
                return ENOENT;
 
-       pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
-       pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
+       (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+               pfh_inet6);
+       (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+               pfh_inet6);
 
        return 0;
 }
@@ -478,8 +493,10 @@ ipfw6_unhook(void)
        if (pfh_inet6 == NULL)
                return ENOENT;
 
-       pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
-       pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
+       (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+               pfh_inet6);
+       (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+               pfh_inet6);
 
        return 0;
 }
index 0765718..ee4eeba 100644 (file)
@@ -490,10 +490,9 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
 {
        struct sock *sk;
        int ret = -1;   /* default return value */
-       int uid = -1;   /* user id */
        int st = -1;    /* state */
 
-       if (proto != IPPROTO_TCP)
+       if (proto != IPPROTO_TCP)       /* XXX extend for UDP */
                return -1;
 
        if ((dir ? (void *)skb->dst : (void *)skb->dev) == NULL) {
@@ -501,11 +500,17 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
                return -1;
        }
 
-       /*
-        * inet_lookup above 2.6.24 has an additional 'net' parameter
-        * so we use a macro to conditionally supply it.
-        * Also we need to switch dst and src depending on the direction.
-        */
+       if (skb->sk) {
+               sk = skb->sk;
+       } else {
+               /*
+                * Try a lookup. On a match, sk has a refcount that we must
+                * release on exit (we know it because skb->sk = NULL).
+                *
+                * inet_lookup above 2.6.24 has an additional 'net' parameter
+                * so we use a macro to conditionally supply it.
+                * swap dst and src depending on the direction.
+                */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
 #define _OPT_NET_ARG
 #else
@@ -516,35 +521,34 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
 #define _OPT_NET_ARG dev_net(skb->dev),
 #endif
 #endif
-
-       if (0 && skb->sk) {
-               sk=skb->sk;
-       } else {
-       sk =  (dir) ?
-               inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
-                       daddr, dport, saddr, sport,     // matches outgoing for server sockets
+               sk =  (dir) ? /* dir != 0 on output */
+                   inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
+                       daddr, dport, saddr, sport,     // match outgoing
                        inet_iif(skb)) :
-               inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
-                       saddr, sport, daddr, dport,     // matches incoming for server sockets
+                   inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
+                       saddr, sport, daddr, dport,     // match incoming
                        skb->dev->ifindex);
-       }
-
 #undef _OPT_NET_ARG
-       /* no match, nothing to be done */
-       if (sk == NULL)
-               return -1;
 
+               if (sk == NULL) /* no match, nothing to be done */
+                       return -1;
+       }
+       ret = 1;        /* retrying won't make things better */
+       st = sk->sk_state;
+#ifdef CONFIG_VSERVER
+       ugp->fw_groups[1] = sk->sk_xid;
+       ugp->fw_groups[2] = sk->sk_nid;
+#else
+       ugp->fw_groups[1] = ugp->fw_groups[2] = 0;
+#endif
        /*
-        * On a match, sk is returned with a refcount.
-        * In tcp some states reference a valid struct sock
-        * which is what we want, otherwise the struct sock
-        * referenced can be invalid, as in the case of the
-        * TCP_TIME_WAIT state, when it references a
-        * struct inet_timewait_sock which does not point to credentials.
-        * To be safe we exclude TCP_CLOSE and TCP_LAST_ACK states too.
+        * Exclude tcp states where sk points to a inet_timewait_sock which
+        * has no sk_socket field (surely TCP_TIME_WAIT, perhaps more).
+        * To be safe, use a whitelist and not a blacklist.
+        * Before dereferencing sk_socket grab a lock on sk_callback_lock.
         *
         * Once again we need conditional code because the UID and GID
-        * location changes between the two kernels.
+        * location changes between kernels.
         */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
 /* use the current's real uid/gid */
@@ -555,24 +559,37 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
 #define _CURR_UID f_cred->fsuid
 #define _CURR_GID f_cred->fsgid
 #endif
-       st = sk->sk_state;
-       if (st != TCP_TIME_WAIT && st != TCP_CLOSE && st != TCP_LAST_ACK &&
-                       sk->sk_socket && sk->sk_socket->file) {
-               ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
-               uid = ugp->fw_uid;
-               ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID;
+
 #ifdef CONFIG_VSERVER
-               ugp->fw_groups[1] = sk->sk_xid;
-               ugp->fw_groups[2] = sk->sk_nid;
+       ugp->fw_groups[1] = sk->sk_xid;
+       ugp->fw_groups[2] = sk->sk_nid;
+#else
+       ugp->fw_groups[1] =
+       ugp->fw_groups[2] = 0;
 #endif
-               ret = 1;
+       ret = 1;
+
+#define GOOD_STATES (  \
+       (1<<TCP_LISTEN) | (1<<TCP_SYN_RECV)   | (1<<TCP_SYN_SENT)   | \
+       (1<<TCP_ESTABLISHED)  | (1<<TCP_FIN_WAIT1) | (1<<TCP_FIN_WAIT2) )
+       // surely exclude TCP_CLOSE, TCP_TIME_WAIT, TCP_LAST_ACK
+       // uncertain TCP_CLOSE_WAIT and TCP_CLOSING
+
+       if ((1<<st) & GOOD_STATES) {
+               read_lock_bh(&sk->sk_callback_lock);
+                       if (sk->sk_socket && sk->sk_socket->file) {
+                               ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
+                               ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID;
+                       }
+               read_unlock_bh(&sk->sk_callback_lock);
+       } else {
+               ugp->fw_uid = ugp->fw_groups[0] = 0;
        }
-       if (1 || !skb->sk) /* the reference came from the lookup */
+       if (!skb->sk) /* return the reference that came from the lookup */
                sock_put(sk);
+#undef GOOD_STATES
 #undef _CURR_UID
 #undef _CURR_GID
-
-       //printf("%s dir %d sb>dst %p sb>dev %p ret %d id %d st%d\n", __FUNCTION__, dir, skb->dst, skb->dev, ret, uid, st);
        return ret;
 }
 
index b15d84a..c6bb4f3 100644 (file)
@@ -346,8 +346,10 @@ struct sysctl_req;
  * sysctl are mapped into /sys/module/ipfw_mod parameters
  */
 #define CTLFLAG_RD             1
+#define CTLFLAG_RDTUN          1
 #define CTLFLAG_RW             2
 #define CTLFLAG_SECURE3                0 // unsupported
+#define CTLFLAG_VNET    0      /* unsupported */
 
 #ifdef _WIN32
 #define module_param_named(_name, _var, _ty, _perm)
@@ -359,6 +361,7 @@ struct sysctl_req;
 #endif /* __linux__ */
 
 #define SYSCTL_DECL(_1)
+#define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8)
 #define SYSCTL_NODE(_1, _2, _3, _4, _5, _6)
 #define _SYSCTL_BASE(_name, _var, _ty, _perm)          \
        module_param_named(_name, *(_var), _ty,         \
@@ -382,6 +385,8 @@ struct sysctl_req;
 int sysctl_handle_int(SYSCTL_HANDLER_ARGS);
 int sysctl_handle_long(SYSCTL_HANDLER_ARGS); 
 
+#define TUNABLE_INT(_name, _ptr)
+
 void ether_demux(struct ifnet *ifp, struct mbuf *m);
 
 int ether_output_frame(struct ifnet *ifp, struct mbuf *m);
@@ -422,4 +427,36 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
        const __be32 daddr, const __be16 dport,
        struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp);
 
+/* vnet wrappers, in vnet.h and ip_var.h */
+#define curvnet                 NULL
+#define        CURVNET_SET(_v)
+#define        CURVNET_RESTORE()
+#define VNET_ASSERT(condition)
+
+#define VNET_NAME(n)            n
+#define VNET_DECLARE(t, n)      extern t n
+#define VNET_DEFINE(t, n)       t n
+#define _VNET_PTR(b, n)         &VNET_NAME(n)
+/*
+ * Virtualized global variable accessor macros.
+ */
+#define VNET_VNET_PTR(vnet, n)          (&(n))
+#define VNET_VNET(vnet, n)              (n)
+
+#define VNET_PTR(n)             (&(n))
+#define VNET(n)                 (n)
+
+VNET_DECLARE(struct ip_fw_chain, layer3_chain);
+
+#define        V_fw_enable             VNET(fw_enable)
+#define        V_fw_one_pass           VNET(fw_one_pass)
+#define V_ip_fw_chk_ptr         VNET(ip_fw_chk_ptr)
+#define V_ip_fw_ctl_ptr         VNET(ip_fw_ctl_ptr)
+#define V_layer3_chain         VNET(layer3_chain)
+#define        V_tcbinfo               VNET(tcbinfo)
+#define        V_udbinfo               VNET(udbinfo)
+
+#define SYSCTL_VNET_PROC       SYSCTL_PROC
+#define SYSCTL_VNET_INT                SYSCTL_INT
+
 #endif /* !_MISSING_H_ */
diff --git a/dummynet/new_glue.c b/dummynet/new_glue.c
new file mode 100644 (file)
index 0000000..52a1a7f
--- /dev/null
@@ -0,0 +1,263 @@
+#include "missing.h"
+//#include <sys/param.h>
+//#include <sys/systm.h>
+//#include <sys/malloc.h>
+// #include <sys/mbuf.h>
+//#include <sys/kernel.h>
+//#include <sys/lock.h>
+//#include <sys/jail.h>
+//#include <sys/module.h>
+//#include <sys/priv.h>
+//#include <sys/proc.h>
+//#include <sys/socket.h>
+//#include <sys/socketvar.h>
+//#include <sys/sysctl.h>
+//#include <sys/syslog.h>
+//#include <sys/ucred.h>
+//#include <net/ethernet.h> /* for ETHERTYPE_IP */
+//#include <net/if.h>
+//#include <net/radix.h>
+//#include <net/route.h>
+//#include <net/pf_mtag.h>
+
+#define IPFW_INTERNAL
+#include <netinet/ip_fw.h>
+
+#include "hashtable.h"
+#define IPFW_NEWTABLES_MAX     256
+
+struct t_o {
+       /* Object stored in the hash table */
+       uint32_t addr;
+       uint32_t value;
+       uint8_t mask;
+};
+
+MALLOC_DEFINE(M_IPFW_HTBL, "ipfw_tbl", "IpFw tables");
+
+static struct new_hash_table *global_tables[128];
+int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+                       uint8_t mlen, uint32_t value);
+int new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr);
+int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+                    uint8_t mlen);
+int new_flush_table(uint16_t tbl);
+int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
+int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 
+                uint32_t *val);
+int new_count_table_entry(uint32_t tbl, uint32_t *cnt);
+int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
+int new_dump_table_entry(ipfw_table *tbl);
+int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
+int init_tables(struct ip_fw_chain *ch);
+
+/* hash and compare functions for 32-bit entries */
+static uint32_t
+simple_hash32(const void *key, uint32_t size)
+{
+       uint32_t ret = *(const uint32_t *)key % size;
+       printf("%s called\n", __FUNCTION__);
+       printf("Hash returns %d\n", ret);
+
+       return ret;
+}
+
+static int
+cmp_func32(const void *key1, const void *key2)
+{
+       int k1 = *(const int *)key1;
+       int k2 = *(const int *)key2;
+       int ret;
+       printf("(%s) k1=%d, k2=%d\n", __FUNCTION__, k1, k2);
+       if (k1 < k2)
+               ret = -1;
+       else if (k1 > k2)
+               ret = 1;
+       else
+               ret = 0;
+
+       printf("compare returns %d\n", ret);
+
+       return ret;
+}
+
+int
+add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+    uint8_t mlen, uint32_t value)
+{
+       /* TODO:
+        * - Search the correct hash table (tbl - IPFW_TABLES_MAX)
+        * - Search if the entry already exists
+        * - Insert the new entry in the table
+        * - Possibly reallocate the table if it is too small
+        */
+
+       struct t_o obj;
+       int ret;
+       int i = tbl - IPFW_TABLES_MAX;
+       int size = 128;
+       int obj_size = sizeof(struct t_o);
+
+       printf("%s called\n", __FUNCTION__);
+       if (i < 0 || i > size-1) /* wrong table number */
+               return 1;
+       if (global_tables[i] == NULL) {
+               printf("Creating table n %d\n", tbl);
+               global_tables[i] = new_table_init(size, obj_size,
+                               simple_hash32, cmp_func32, M_IPFW_HTBL);
+       }
+
+       obj.addr = addr;
+       obj.value = value;
+       obj.mask = mlen;
+
+       /* Insert the object in the table */
+       ret = new_table_insert_obj(global_tables[i], &obj);
+       return ret;
+}
+
+int
+new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr)
+{
+       int ret;
+       int nr = tbl - IPFW_TABLES_MAX;
+
+       printf("%s called\n", __FUNCTION__);
+
+       ret = new_table_delete_obj(global_tables[nr], &addr);
+
+       return ret;
+}
+
+int
+del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+    uint8_t mlen)
+{
+       printf("%s called\n", __FUNCTION__);
+       if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
+               new_del_table_entry(ch, tbl, addr);
+               return 0;
+       }
+       return (EINVAL);
+}
+
+int
+new_flush_table(uint16_t tbl)
+{
+       printf("%s called\n", __FUNCTION__);
+       new_table_destroy(global_tables[tbl - IPFW_TABLES_MAX]);
+       return 0;
+}
+
+int
+flush_table(struct ip_fw_chain *ch, uint16_t tbl)
+{
+       printf("%s called\n", __FUNCTION__);
+       if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX)
+               return new_flush_table(tbl);
+       
+       return (EINVAL);
+}
+
+int
+lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+    uint32_t *val)
+{
+       printf("%s called\n", __FUNCTION__);
+       if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
+               struct new_hash_table *h;
+               struct t_o *obj;
+
+               h = global_tables[tbl - IPFW_NEWTABLES_MAX];
+               printf("Search %d in table number %d\n", addr, tbl);
+
+               obj = (struct t_o *)new_table_extract_obj(h, (void *)&addr);
+               if (obj == NULL)
+                       return 0;
+
+               *val = obj->value;
+
+               return 1;
+       }
+
+       return 1;
+}
+
+int
+new_count_table_entry(uint32_t tbl, uint32_t *cnt)
+{
+       printf("%s called\n", __FUNCTION__);
+       *cnt = new_table_get_element(global_tables[tbl - IPFW_TABLES_MAX]);
+       return 0;
+}
+
+int
+count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
+{
+       printf("%s called\n", __FUNCTION__);
+       if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
+               new_count_table_entry(tbl, cnt);
+               return (0);
+       }
+       return (EINVAL);
+}
+
+int
+new_dump_table_entry(ipfw_table *tbl)
+{
+       /* fill the tbl with all entryes */
+       ipfw_table_entry *ent;
+       const struct t_o *obj;
+       int i;
+       int n_el;
+       int nr = tbl->tbl - IPFW_TABLES_MAX;
+       struct new_hash_table *t = global_tables[nr];
+
+       printf("%s called\n", __FUNCTION__);
+
+       i = 0;
+       tbl->cnt = 0;
+
+       /* XXX determine tbl->size */
+       n_el = new_table_get_element(t);
+       obj = NULL;
+       for (; n_el > 0; n_el--) {
+               obj = table_next(t, obj);
+               if (obj == NULL)
+                       break;
+               printf("Found \n");
+               ent = &tbl->ent[tbl->cnt];
+
+               ent->addr = obj->addr;
+               ent->value = obj->value;
+               ent->masklen = obj->mask;
+               tbl->cnt++;
+       }
+       printf("\n");
+       return 0;
+}
+
+int
+dump_table(struct ip_fw_chain *ch, ipfw_table *tbl)
+{
+       printf("%s called\n", __FUNCTION__);
+       if (tbl->tbl >= IPFW_TABLES_MAX && tbl->tbl < IPFW_NEWTABLES_MAX) {
+               new_dump_table_entry(tbl);
+               return (0);
+       }
+       return (EINVAL);
+}
+
+int
+init_tables(struct ip_fw_chain *ch)
+{
+
+       int i;
+       printf("%s called\n", __FUNCTION__);
+       /* Initialize new tables XXXMPD */
+       for (i = 0; i < IPFW_NEWTABLES_MAX - IPFW_TABLES_MAX; i++) {
+               memset(&global_tables[i], sizeof(struct new_hash_table*), 0);
+       }
+
+       return (0);
+}
diff --git a/glue.h b/glue.h
index a3548bd..bf7043d 100644 (file)
--- a/glue.h
+++ b/glue.h
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  */
 /*
- * $Id$
+ * $Id: glue.h 4363 2009-12-08 16:06:54Z marta $
  *
  * glue code to adapt the FreeBSD version to linux and windows,
  * userland and kernel.
@@ -55,6 +55,7 @@ enum sopt_dir { SOPT_GET, SOPT_SET };
 #include <sys/types.h>         /* for size_t */
 #include <sys/ioctl.h>
 #include <time.h>
+#include <errno.h>
 
 #include <netinet/ether.h>
 
@@ -213,6 +214,20 @@ void
 qsort_r(void *a, size_t n, size_t es, void *thunk,
        int cmp_t(void *, const void *, const void *));
 
+/* prototypes from libutil */
+/* humanize_number(3) */
+#define HN_DECIMAL              0x01
+#define HN_NOSPACE              0x02
+#define HN_B                    0x04
+#define HN_DIVISOR_1000         0x08
+
+#define HN_GETSCALE             0x10
+#define HN_AUTOSCALE            0x20
+
+int     humanize_number(char *_buf, size_t _len, int64_t _number,
+            const char *_suffix, int _scale, int _flags);
+int     expand_number(const char *_buf, int64_t *_num);
+
 #define setprogname(x) /* not present in linux */
 
 extern int optreset;   /* not present in linux */
@@ -241,6 +256,10 @@ struct route_in6 { };
 
 #endif /* KERNEL_MODULE */
 
+/* missing in netinet/in.h */
+
+#define INET_ADDRSTRLEN                16
+
 /*
  * List of values used for set/getsockopt options.
  * The base value on FreeBSD is defined as a macro,
@@ -255,13 +274,17 @@ enum ipfw_msg_type {
        IP_FW_TABLE_FLUSH,
        IP_FW_TABLE_GETSIZE,
        IP_FW_TABLE_LIST,
+       IP_FW_DYN_GET,          /* new addition */
+
+       /* IP_FW3 and IP_DUMMYNET3 are the new API */
+       IP_FW3                  = _IPFW_SOCKOPT_BASE + 8,
+       IP_DUMMYNET3,
 
        IP_FW_ADD               = _IPFW_SOCKOPT_BASE + 10,
        IP_FW_DEL,
        IP_FW_FLUSH,
        IP_FW_ZERO,
        IP_FW_GET,
-       IP_FW_DYN_GET,
        IP_FW_RESETLOG,
 
        IP_FW_NAT_CFG,
diff --git a/include_e/altq/if_altq.h b/include_e/altq/if_altq.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/arpa/inet.h b/include_e/arpa/inet.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/machine/in_cksum.h b/include_e/machine/in_cksum.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/net/ethernet.h b/include_e/net/ethernet.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/net/netisr.h b/include_e/net/netisr.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/net/pf_mtag.h b/include_e/net/pf_mtag.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/net/radix.h b/include_e/net/radix.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/ether.h b/include_e/netinet/ether.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/icmp6.h b/include_e/netinet/icmp6.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/if_ether.h b/include_e/netinet/if_ether.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/in.h b/include_e/netinet/in.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/in_pcb.h b/include_e/netinet/in_pcb.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/in_var.h b/include_e/netinet/in_var.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/ip_carp.h b/include_e/netinet/ip_carp.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/ip_var.h b/include_e/netinet/ip_var.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/pim.h b/include_e/netinet/pim.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/sctp.h b/include_e/netinet/sctp.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/tcp_timer.h b/include_e/netinet/tcp_timer.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/tcpip.h b/include_e/netinet/tcpip.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet/udp_var.h b/include_e/netinet/udp_var.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/netinet6/ip6_var.h b/include_e/netinet6/ip6_var.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_inet6.h b/include_e/opt_inet6.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_ipfw.h b/include_e/opt_ipfw.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_ipsec.h b/include_e/opt_ipsec.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_mac.h b/include_e/opt_mac.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_mbuf_stress_test.h b/include_e/opt_mbuf_stress_test.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/opt_param.h b/include_e/opt_param.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/_lock.h b/include_e/sys/_lock.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/_mutex.h b/include_e/sys/_mutex.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/jail.h b/include_e/sys/jail.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/limits.h b/include_e/sys/limits.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/lock.h b/include_e/sys/lock.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/mutex.h b/include_e/sys/mutex.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/priv.h b/include_e/sys/priv.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/proc.h b/include_e/sys/proc.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/rwlock.h b/include_e/sys/rwlock.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/socket.h b/include_e/sys/socket.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/socketvar.h b/include_e/sys/socketvar.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/sysctl.h b/include_e/sys/sysctl.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/time.h b/include_e/sys/time.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include_e/sys/ucred.h b/include_e/sys/ucred.h
deleted file mode 100644 (file)
index e69de29..0000000
index a3869f1..1b20e61 100644 (file)
--- a/ipfw.spec
+++ b/ipfw.spec
@@ -47,7 +47,6 @@ ipfw is the Linux port of the FreeBSD ipfw and dummynet packages
 
 %build
 # clean the rpm build directory
-
 rm -rf $RPM_BUILD_ROOT
 
 # with the new build, we use the kernel-devel rpm for building
@@ -74,6 +73,10 @@ rm -rf $RPM_BUILD_ROOT
 /usr/bin/ipfw-cleanup
 %{_sysconfdir}/cron.d/ipfw.cron
 
+%postun
+# unload the module if present
+LOADED=`cat /proc/modules | grep ^ipfw_mod`; if [ -n "$LOADED" ] ; then rmmod ipfw_mod; fi
+
 %changelog
 * Sun Nov 29 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-7
 - added missing qsort.c - tag 0.9-6 was broken
@@ -96,5 +99,6 @@ rm -rf $RPM_BUILD_ROOT
 
 * Thu Jun 25 2009 Marta Carbone <marta.carbone@iet.unipi.it>
 - post installation removed for deployment, moved manpages to the slice package
+
 * Fri Apr 17 2009 Marta Carbone <marta.carbone@iet.unipi.it>
 - Initial release
index bcaed9c..2a5e08e 100644 (file)
@@ -8,7 +8,7 @@
 $(warning Building userland ipfw for $(VER))
 EXTRA_CFLAGS += -O1
 # comment this on planetlab
-# EXTRA_CFLAGS += -Wall -Werror
+#EXTRA_CFLAGS += -Wall -Werror
 EXTRA_CFLAGS += -include ../glue.h
 EXTRA_CFLAGS += -I ./include
 
@@ -29,6 +29,7 @@ CFLAGS += -I$(USRDIR)/include
 LDFLAGS += -L$(USRDIR)/lib
 
 OBJS = ipfw2.o dummynet.o main.o ipv6.o altq.o qsort_r.o
+OBJS += expand_number.o humanize_number.o
 ifneq ($(HAVE_NAT),)
     OBJS += nat.o
     EXTRA_CFLAGS += -DHAVE_NAT
@@ -41,7 +42,14 @@ all: ipfw
 ipfw: $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $^
 
-$(OBJS) : ipfw2.h ../glue.h
+$(OBJS) : ipfw2.h ../glue.h include/netinet
+
+include/netinet:
+       -@rm -rf include/netinet
+       -@mkdir -p include/netinet
+       -(cd include/netinet; \
+               for i in ip_fw.h ip_dummynet.h tcp.h; do \
+               ln -s ../../../dummynet/include/netinet/$$i; done; )
 
 clean distclean:
        -rm -f $(OBJS) ipfw
index e2c5ff1..12625fe 100644 (file)
@@ -70,11 +70,12 @@ static struct _s_x dummynet_params[] = {
        { "src-ipv6",           TOK_SRCIP6},
        { "src-ip6",            TOK_SRCIP6},
        { "profile",            TOK_PIPE_PROFILE},
+       { "burst",              TOK_BURST},
        { "dummynet-params",    TOK_NULL },
        { NULL, 0 }     /* terminator */
 };
 
-/*
+/* 
  * XXX to be updated to the new version,
  * without the global struct command_opts variable
  */
@@ -254,7 +255,7 @@ print_flowset_parms(struct dn_flow_set *fs, char *prefix)
 }
 
 static void
-print_extra_delay_parms(struct dn_pipe *p, char *prefix)
+print_extra_delay_parms(struct dn_pipe *p)
 {
        double loss;
        if (p->samples_no <= 0)
@@ -262,8 +263,8 @@ print_extra_delay_parms(struct dn_pipe *p, char *prefix)
 
        loss = p->loss_level;
        loss /= p->samples_no;
-       printf("%s profile: name \"%s\" loss %f samples %d\n",
-               prefix, p->name, loss, p->samples_no);
+       printf("\t profile: name \"%s\" loss %f samples %d\n",
+               p->name, loss, p->samples_no);
 }
 
 void
@@ -284,6 +285,7 @@ ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[])
                double b = p->bandwidth;
                char buf[30];
                char prefix[80];
+               char burst[5 + 7];
 
                if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE)
                        break;  /* done with pipes, now queues */
@@ -315,10 +317,16 @@ ipfw_list_pipes(void *data, uint nbytes, int ac, char *av[])
                sprintf(prefix, "%05d: %s %4d ms ",
                    p->pipe_nr, buf, p->delay);
 
-               print_extra_delay_parms(p, prefix);
-
                print_flowset_parms(&(p->fs), prefix);
 
+               if (humanize_number(burst, sizeof(burst), p->burst,
+                   "Byte", HN_AUTOSCALE, 0) < 0 || co.verbose)
+                       printf("\t burst: %ju Byte\n", p->burst);
+               else
+                       printf("\t burst: %s\n", burst);
+
+               print_extra_delay_parms(p);
+
                q = (struct dn_flow_queue *)(p+1);
                list_queues(&(p->fs), q);
        }
@@ -645,6 +653,8 @@ load_extra_delays(const char *filename, struct dn_pipe *p)
                }
        }
 
+       fclose (f);
+
        if (samples == -1) {
            warnx("'%s' not found, assuming 100", ED_TOK_SAMPLES);
            samples = 100;
@@ -938,6 +948,21 @@ end_mask:
                        --ac; ++av;
                        break;
 
+               case TOK_BURST:
+                       if (co.do_pipe != 1)
+                               errx(EX_DATAERR, "burst only valid for pipes");
+                       NEED1("burst needs argument\n");
+                       errno = 0;
+                       if (expand_number(av[0], (int64_t *)&p.burst) < 0)
+                               if (errno != ERANGE)
+                                       errx(EX_DATAERR,
+                                               "burst: invalid argument");
+                       if (errno || p.burst > (1ULL << 48) - 1)
+                               errx(EX_DATAERR,
+                                       "burst: out of range (0..2^48-1)");
+                       ac--; av++;
+                       break;
+
                default:
                        errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
                }
diff --git a/ipfw/expand_number.c b/ipfw/expand_number.c
new file mode 100644 (file)
index 0000000..d557111
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
+ * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// #include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libutil/expand_number.c,v 1.2.4.2 2009/06/10 14:52:34 des Exp $");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+//#include <libutil.h>
+#include <stdint.h>
+
+/*
+ * Convert an expression of the following forms to a int64_t.
+ *     1) A positive decimal number.
+ *     2) A positive decimal number followed by a 'b' or 'B' (mult by 1).
+ *     3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
+ *     4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
+ *     5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
+ *     6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40).
+ *     7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50).
+ *     8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).
+ */
+int
+expand_number(const char *buf, int64_t *num)
+{
+       static const char unit[] = "bkmgtpe";
+       char *endptr, s;
+       int64_t number;
+       int i;
+
+       number = strtoimax(buf, &endptr, 0);
+
+       if (endptr == buf) {
+               /* No valid digits. */
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*endptr == '\0') {
+               /* No unit. */
+               *num = number;
+               return (0);
+       }
+
+       s = tolower(*endptr);
+       switch (s) {
+       case 'b':
+       case 'k':
+       case 'm':
+       case 'g':
+       case 't':
+       case 'p':
+       case 'e':
+               break;
+       default:
+               /* Unrecognized unit. */
+               errno = EINVAL;
+               return (-1);
+       }
+
+       for (i = 0; unit[i] != '\0'; i++) {
+               if (s == unit[i])
+                       break;
+               if ((number < 0 && (number << 10) > number) ||
+                   (number >= 0 && (number << 10) < number)) {
+                       errno = ERANGE;
+                       return (-1);
+               }
+               number <<= 10;
+       }
+
+       *num = number;
+       return (0);
+}
index c70cd18..db90c60 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * $Id$
+ * $Id: glue.c 4051 2009-11-16 11:30:05Z luigi $
  *
  * Userland functions missing in linux
  */
diff --git a/ipfw/humanize_number.c b/ipfw/humanize_number.c
new file mode 100644 (file)
index 0000000..90aa18b
--- /dev/null
@@ -0,0 +1,153 @@
+/*     $NetBSD: humanize_number.c,v 1.13 2007/12/14 17:26:19 christos Exp $    */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the NetBSD
+ *      Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// #include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libutil/humanize_number.c,v 1.2.10.1 2008/04/20 16:29:01 antoine Exp $");
+
+#include <sys/types.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+// #include <locale.h>
+//#include <libutil.h>
+
+int
+humanize_number(char *buf, size_t len, int64_t bytes,
+    const char *suffix, int scale, int flags)
+{
+       const char *prefixes, *sep;
+       int     b, i, r, maxscale, s1, s2, sign;
+       int64_t divisor, max;
+       size_t  baselen;
+
+       assert(buf != NULL);
+       assert(suffix != NULL);
+       assert(scale >= 0);
+
+       if (flags & HN_DIVISOR_1000) {
+               /* SI for decimal multiplies */
+               divisor = 1000;
+               if (flags & HN_B)
+                       prefixes = "B\0k\0M\0G\0T\0P\0E";
+               else
+                       prefixes = "\0\0k\0M\0G\0T\0P\0E";
+       } else {
+               /*
+                * binary multiplies
+                * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+                */
+               divisor = 1024;
+               if (flags & HN_B)
+                       prefixes = "B\0K\0M\0G\0T\0P\0E";
+               else
+                       prefixes = "\0\0K\0M\0G\0T\0P\0E";
+       }
+
+#define        SCALE2PREFIX(scale)     (&prefixes[(scale) << 1])
+       maxscale = 7;
+
+       if (scale >= maxscale &&
+           (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+               return (-1);
+
+       if (buf == NULL || suffix == NULL)
+               return (-1);
+
+       if (len > 0)
+               buf[0] = '\0';
+       if (bytes < 0) {
+               sign = -1;
+               bytes *= -100;
+               baselen = 3;            /* sign, digit, prefix */
+       } else {
+               sign = 1;
+               bytes *= 100;
+               baselen = 2;            /* digit, prefix */
+       }
+       if (flags & HN_NOSPACE)
+               sep = "";
+       else {
+               sep = " ";
+               baselen++;
+       }
+       baselen += strlen(suffix);
+
+       /* Check if enough room for `x y' + suffix + `\0' */
+       if (len < baselen + 1)
+               return (-1);
+
+       if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+               /* See if there is additional columns can be used. */
+               for (max = 100, i = len - baselen; i-- > 0;)
+                       max *= 10;
+
+               /*
+                * Divide the number until it fits the given column.
+                * If there will be an overflow by the rounding below,
+                * divide once more.
+                */
+               for (i = 0; bytes >= max - 50 && i < maxscale; i++)
+                       bytes /= divisor;
+
+               if (scale & HN_GETSCALE)
+                       return (i);
+       } else
+               for (i = 0; i < scale && i < maxscale; i++)
+                       bytes /= divisor;
+
+       /* If a value <= 9.9 after rounding and ... */
+       if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+               /* baselen + \0 + .N */
+               if (len < baselen + 1 + 2)
+                       return (-1);
+               b = ((int)bytes + 5) / 10;
+               s1 = b / 10;
+               s2 = b % 10;
+               r = snprintf(buf, len, "%d%s%d%s%s%s",
+                   sign * s1, ".", s2,
+                   sep, SCALE2PREFIX(i), suffix);
+       } else
+               r = snprintf(buf, len, "%" PRId64 "%s%s%s",
+                   sign * ((bytes + 50) / 100),
+                   sep, SCALE2PREFIX(i), suffix);
+
+       return (r);
+}
diff --git a/ipfw/include/netinet/ip_dummynet.h b/ipfw/include/netinet/ip_dummynet.h
deleted file mode 100644 (file)
index c6a6575..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*-
- * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa
- * Portions Copyright (c) 2000 Akamba Corp.
- * All rights reserved
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/netinet/ip_dummynet.h,v 1.40.2.1 2008/04/25 10:26:30 oleg Exp $
- */
-
-#ifndef _IP_DUMMYNET_H
-#define _IP_DUMMYNET_H
-
-/*
- * Definition of dummynet data structures. In the structures, I decided
- * not to use the macros in <sys/queue.h> in the hope of making the code
- * easier to port to other architectures. The type of lists and queue we
- * use here is pretty simple anyways.
- */
-
-/*
- * We start with a heap, which is used in the scheduler to decide when
- * to transmit packets etc.
- *
- * The key for the heap is used for two different values:
- *
- * 1. timer ticks- max 10K/second, so 32 bits are enough;
- *
- * 2. virtual times. These increase in steps of len/x, where len is the
- *    packet length, and x is either the weight of the flow, or the
- *    sum of all weights.
- *    If we limit to max 1000 flows and a max weight of 100, then
- *    x needs 17 bits. The packet size is 16 bits, so we can easily
- *    overflow if we do not allow errors.
- * So we use a key "dn_key" which is 64 bits. Some macros are used to
- * compare key values and handle wraparounds.
- * MAX64 returns the largest of two key values.
- * MY_M is used as a shift count when doing fixed point arithmetic
- * (a better name would be useful...).
- */
-typedef u_int64_t dn_key ;      /* sorting key */
-#define DN_KEY_LT(a,b)     ((int64_t)((a)-(b)) < 0)
-#define DN_KEY_LEQ(a,b)    ((int64_t)((a)-(b)) <= 0)
-#define DN_KEY_GT(a,b)     ((int64_t)((a)-(b)) > 0)
-#define DN_KEY_GEQ(a,b)    ((int64_t)((a)-(b)) >= 0)
-#define MAX64(x,y)  (( (int64_t) ( (y)-(x) )) > 0 ) ? (y) : (x)
-#define MY_M   16 /* number of left shift to obtain a larger precision */
-
-/*
- * XXX With this scaling, max 1000 flows, max weight 100, 1Gbit/s, the
- * virtual time wraps every 15 days.
- */
-
-
-/*
- * The maximum hash table size for queues.  This value must be a power
- * of 2.
- */
-#define DN_MAX_HASH_SIZE 65536
-
-/*
- * A heap entry is made of a key and a pointer to the actual
- * object stored in the heap.
- * The heap is an array of dn_heap_entry entries, dynamically allocated.
- * Current size is "size", with "elements" actually in use.
- * The heap normally supports only ordered insert and extract from the top.
- * If we want to extract an object from the middle of the heap, we
- * have to know where the object itself is located in the heap (or we
- * need to scan the whole array). To this purpose, an object has a
- * field (int) which contains the index of the object itself into the
- * heap. When the object is moved, the field must also be updated.
- * The offset of the index in the object is stored in the 'offset'
- * field in the heap descriptor. The assumption is that this offset
- * is non-zero if we want to support extract from the middle.
- */
-struct dn_heap_entry {
-    dn_key key ;       /* sorting key. Topmost element is smallest one */
-    void *object ;     /* object pointer */
-} ;
-
-struct dn_heap {
-    int size ;
-    int elements ;
-    int offset ; /* XXX if > 0 this is the offset of direct ptr to obj */
-    struct dn_heap_entry *p ;  /* really an array of "size" entries */
-} ;
-
-#ifdef _KERNEL
-/*
- * Packets processed by dummynet have an mbuf tag associated with
- * them that carries their dummynet state.  This is used within
- * the dummynet code as well as outside when checking for special
- * processing requirements.
- */
-struct dn_pkt_tag {
-    struct ip_fw *rule;                /* matching rule */
-    int dn_dir;                        /* action when packet comes out. */
-#define DN_TO_IP_OUT   1
-#define DN_TO_IP_IN    2
-/* Obsolete: #define DN_TO_BDG_FWD     3 */
-#define DN_TO_ETH_DEMUX        4
-#define DN_TO_ETH_OUT  5
-#define DN_TO_IP6_IN   6
-#define DN_TO_IP6_OUT  7
-#define DN_TO_IFB_FWD  8
-
-    dn_key output_time;                /* when the pkt is due for delivery     */
-    struct ifnet *ifp;         /* interface, for ip_output             */
-    struct _ip6dn_args ip6opt; /* XXX ipv6 options                     */
-};
-#endif /* _KERNEL */
-
-/*
- * Overall structure of dummynet (with WF2Q+):
-
-In dummynet, packets are selected with the firewall rules, and passed
-to two different objects: PIPE or QUEUE.
-
-A QUEUE is just a queue with configurable size and queue management
-policy. It is also associated with a mask (to discriminate among
-different flows), a weight (used to give different shares of the
-bandwidth to different flows) and a "pipe", which essentially
-supplies the transmit clock for all queues associated with that
-pipe.
-
-A PIPE emulates a fixed-bandwidth link, whose bandwidth is
-configurable.  The "clock" for a pipe can come from either an
-internal timer, or from the transmit interrupt of an interface.
-A pipe is also associated with one (or more, if masks are used)
-queue, where all packets for that pipe are stored.
-
-The bandwidth available on the pipe is shared by the queues
-associated with that pipe (only one in case the packet is sent
-to a PIPE) according to the WF2Q+ scheduling algorithm and the
-configured weights.
-
-In general, incoming packets are stored in the appropriate queue,
-which is then placed into one of a few heaps managed by a scheduler
-to decide when the packet should be extracted.
-The scheduler (a function called dummynet()) is run at every timer
-tick, and grabs queues from the head of the heaps when they are
-ready for processing.
-
-There are three data structures definining a pipe and associated queues:
-
- + dn_pipe, which contains the main configuration parameters related
-   to delay and bandwidth;
- + dn_flow_set, which contains WF2Q+ configuration, flow
-   masks, plr and RED configuration;
- + dn_flow_queue, which is the per-flow queue (containing the packets)
-
-Multiple dn_flow_set can be linked to the same pipe, and multiple
-dn_flow_queue can be linked to the same dn_flow_set.
-All data structures are linked in a linear list which is used for
-housekeeping purposes.
-
-During configuration, we create and initialize the dn_flow_set
-and dn_pipe structures (a dn_pipe also contains a dn_flow_set).
-
-At runtime: packets are sent to the appropriate dn_flow_set (either
-WFQ ones, or the one embedded in the dn_pipe for fixed-rate flows),
-which in turn dispatches them to the appropriate dn_flow_queue
-(created dynamically according to the masks).
-
-The transmit clock for fixed rate flows (ready_event()) selects the
-dn_flow_queue to be used to transmit the next packet. For WF2Q,
-wfq_ready_event() extract a pipe which in turn selects the right
-flow using a number of heaps defined into the pipe itself.
-
- *
- */
-
-/*
- * per flow queue. This contains the flow identifier, the queue
- * of packets, counters, and parameters used to support both RED and
- * WF2Q+.
- *
- * A dn_flow_queue is created and initialized whenever a packet for
- * a new flow arrives.
- */
-struct dn_flow_queue {
-    struct dn_flow_queue *next ;
-    struct ipfw_flow_id id ;
-
-    struct mbuf *head, *tail ; /* queue of packets */
-    u_int len ;
-    u_int len_bytes ;
-
-    /*
-     * When we emulate MAC overheads, or channel unavailability due
-     * to other traffic on a shared medium, we augment the packet at
-     * the head of the queue with an 'extra_bits' field representsing
-     * the additional delay the packet will be subject to:
-     *         extra_bits = bw*unavailable_time.
-     * With large bandwidth and large delays, extra_bits (and also numbytes)
-     * can become very large, so better play safe and use 64 bit
-     */
-    uint64_t numbytes ;                /* credit for transmission (dynamic queues) */
-    int64_t extra_bits;                /* extra bits simulating unavailable channel */
-
-    u_int64_t tot_pkts ;       /* statistics counters  */
-    u_int64_t tot_bytes ;
-    u_int32_t drops ;
-
-    int hash_slot ;            /* debugging/diagnostic */
-
-    /* RED parameters */
-    int avg ;                   /* average queue length est. (scaled) */
-    int count ;                 /* arrivals since last RED drop */
-    int random ;                /* random value (scaled) */
-    dn_key q_time;             /* start of queue idle time */
-
-    /* WF2Q+ support */
-    struct dn_flow_set *fs ;   /* parent flow set */
-    int heap_pos ;             /* position (index) of struct in heap */
-    dn_key sched_time ;                /* current time when queue enters ready_heap */
-
-    dn_key S,F ;               /* start time, finish time */
-    /*
-     * Setting F < S means the timestamp is invalid. We only need
-     * to test this when the queue is empty.
-     */
-} ;
-
-/*
- * flow_set descriptor. Contains the "template" parameters for the
- * queue configuration, and pointers to the hash table of dn_flow_queue's.
- *
- * The hash table is an array of lists -- we identify the slot by
- * hashing the flow-id, then scan the list looking for a match.
- * The size of the hash table (buckets) is configurable on a per-queue
- * basis.
- *
- * A dn_flow_set is created whenever a new queue or pipe is created (in the
- * latter case, the structure is located inside the struct dn_pipe).
- */
-struct dn_flow_set {
-    SLIST_ENTRY(dn_flow_set)   next;   /* linked list in a hash slot */
-
-    u_short fs_nr ;             /* flow_set number       */
-    u_short flags_fs;
-#define DN_HAVE_FLOW_MASK      0x0001
-#define DN_IS_RED              0x0002
-#define DN_IS_GENTLE_RED       0x0004
-#define DN_QSIZE_IS_BYTES      0x0008  /* queue size is measured in bytes */
-#define DN_NOERROR             0x0010  /* do not report ENOBUFS on drops  */
-#define        DN_HAS_PROFILE          0x0020  /* the pipe has a delay profile. */
-#define DN_IS_PIPE             0x4000
-#define DN_IS_QUEUE            0x8000
-
-    struct dn_pipe *pipe ;     /* pointer to parent pipe */
-    u_short parent_nr ;                /* parent pipe#, 0 if local to a pipe */
-
-    int weight ;               /* WFQ queue weight */
-    int qsize ;                        /* queue size in slots or bytes */
-    int plr ;                  /* pkt loss rate (2^31-1 means 100%) */
-
-    struct ipfw_flow_id flow_mask ;
-
-    /* hash table of queues onto this flow_set */
-    int rq_size ;              /* number of slots */
-    int rq_elements ;          /* active elements */
-    struct dn_flow_queue **rq; /* array of rq_size entries */
-
-    u_int32_t last_expired ;   /* do not expire too frequently */
-    int backlogged ;           /* #active queues for this flowset */
-
-        /* RED parameters */
-#define SCALE_RED               16
-#define SCALE(x)                ( (x) << SCALE_RED )
-#define SCALE_VAL(x)            ( (x) >> SCALE_RED )
-#define SCALE_MUL(x,y)          ( ( (x) * (y) ) >> SCALE_RED )
-    int w_q ;                  /* queue weight (scaled) */
-    int max_th ;               /* maximum threshold for queue (scaled) */
-    int min_th ;               /* minimum threshold for queue (scaled) */
-    int max_p ;                        /* maximum value for p_b (scaled) */
-    u_int c_1 ;                        /* max_p/(max_th-min_th) (scaled) */
-    u_int c_2 ;                        /* max_p*min_th/(max_th-min_th) (scaled) */
-    u_int c_3 ;                        /* for GRED, (1-max_p)/max_th (scaled) */
-    u_int c_4 ;                        /* for GRED, 1 - 2*max_p (scaled) */
-    u_int * w_q_lookup ;       /* lookup table for computing (1-w_q)^t */
-    u_int lookup_depth ;       /* depth of lookup table */
-    int lookup_step ;          /* granularity inside the lookup table */
-    int lookup_weight ;                /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
-    int avg_pkt_size ;         /* medium packet size */
-    int max_pkt_size ;         /* max packet size */
-};
-SLIST_HEAD(dn_flow_set_head, dn_flow_set);
-
-/*
- * Pipe descriptor. Contains global parameters, delay-line queue,
- * and the flow_set used for fixed-rate queues.
- *
- * For WF2Q+ support it also has 3 heaps holding dn_flow_queue:
- *   not_eligible_heap, for queues whose start time is higher
- *     than the virtual time. Sorted by start time.
- *   scheduler_heap, for queues eligible for scheduling. Sorted by
- *     finish time.
- *   idle_heap, all flows that are idle and can be removed. We
- *     do that on each tick so we do not slow down too much
- *     operations during forwarding.
- *
- */
-struct dn_pipe {               /* a pipe */
-    SLIST_ENTRY(dn_pipe)       next;   /* linked list in a hash slot */
-
-    int        pipe_nr ;               /* number       */
-    int bandwidth;             /* really, bytes/tick.  */
-    int        delay ;                 /* really, ticks        */
-
-    struct     mbuf *head, *tail ;     /* packets in delay line */
-
-    /* WF2Q+ */
-    struct dn_heap scheduler_heap ; /* top extract - key Finish time*/
-    struct dn_heap not_eligible_heap; /* top extract- key Start time */
-    struct dn_heap idle_heap ; /* random extract - key Start=Finish time */
-
-    dn_key V ;                 /* virtual time */
-    int sum;                   /* sum of weights of all active sessions */
-
-    /* Same as in dn_flow_queue, numbytes can become large */
-    int64_t numbytes;          /* bits I can transmit (more or less). */
-
-    dn_key sched_time ;                /* time pipe was scheduled in ready_heap */
-
-    /*
-     * When the tx clock come from an interface (if_name[0] != '\0'), its name
-     * is stored below, whereas the ifp is filled when the rule is configured.
-     */
-    char if_name[IFNAMSIZ];
-    struct ifnet *ifp ;
-    int ready ; /* set if ifp != NULL and we got a signal from it */
-
-    struct dn_flow_set fs ; /* used with fixed-rate flows */
-
-    /* fields to simulate a delay profile */
-
-#define ED_MAX_NAME_LEN                32
-    char name[ED_MAX_NAME_LEN];
-    int loss_level;
-    int samples_no;
-    int *samples;
-};
-
-/* dn_pipe_max is used to pass pipe configuration from userland onto
- * kernel space and back
- */
-#define ED_MAX_SAMPLES_NO      1024
-struct dn_pipe_max {
-       struct dn_pipe pipe;
-       int samples[ED_MAX_SAMPLES_NO];
-};
-
-SLIST_HEAD(dn_pipe_head, dn_pipe);
-
-#ifdef _KERNEL
-typedef        int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
-typedef        void ip_dn_ruledel_t(void *); /* ip_fw.c */
-typedef        int ip_dn_io_t(struct mbuf **m, int dir, struct ip_fw_args *fwa);
-extern ip_dn_ctl_t *ip_dn_ctl_ptr;
-extern ip_dn_ruledel_t *ip_dn_ruledel_ptr;
-extern ip_dn_io_t *ip_dn_io_ptr;
-#define        DUMMYNET_LOADED (ip_dn_io_ptr != NULL)
-
-/*
- * Return the IPFW rule associated with the dummynet tag; if any.
- * Make sure that the dummynet tag is not reused by lower layers.
- */
-static __inline struct ip_fw *
-ip_dn_claim_rule(struct mbuf *m)
-{
-       struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
-       if (mtag != NULL) {
-               mtag->m_tag_id = PACKET_TAG_NONE;
-               return (((struct dn_pkt_tag *)(mtag+1))->rule);
-       } else
-               return (NULL);
-}
-#endif
-#endif /* _IP_DUMMYNET_H */
diff --git a/ipfw/include/netinet/ip_fw.h b/ipfw/include/netinet/ip_fw.h
deleted file mode 100644 (file)
index 62617f5..0000000
+++ /dev/null
@@ -1,676 +0,0 @@
-/*-
- * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/netinet/ip_fw.h,v 1.110.2.6 2008/10/14 08:03:58 rwatson Exp $
- */
-
-#ifndef _IPFW2_H
-#define _IPFW2_H
-
-/*
- * The default rule number.  By the design of ip_fw, the default rule
- * is the last one, so its number can also serve as the highest number
- * allowed for a rule.  The ip_fw code relies on both meanings of this
- * constant. 
- */
-#define        IPFW_DEFAULT_RULE       65535
-
-/*
- * The kernel representation of ipfw rules is made of a list of
- * 'instructions' (for all practical purposes equivalent to BPF
- * instructions), which specify which fields of the packet
- * (or its metadata) should be analysed.
- *
- * Each instruction is stored in a structure which begins with
- * "ipfw_insn", and can contain extra fields depending on the
- * instruction type (listed below).
- * Note that the code is written so that individual instructions
- * have a size which is a multiple of 32 bits. This means that, if
- * such structures contain pointers or other 64-bit entities,
- * (there is just one instance now) they may end up unaligned on
- * 64-bit architectures, so the must be handled with care.
- *
- * "enum ipfw_opcodes" are the opcodes supported. We can have up
- * to 256 different opcodes. When adding new opcodes, they should
- * be appended to the end of the opcode list before O_LAST_OPCODE,
- * this will prevent the ABI from being broken, otherwise users
- * will have to recompile ipfw(8) when they update the kernel.
- */
-
-enum ipfw_opcodes {            /* arguments (4 byte each)      */
-       O_NOP,
-
-       O_IP_SRC,               /* u32 = IP                     */
-       O_IP_SRC_MASK,          /* ip = IP/mask                 */
-       O_IP_SRC_ME,            /* none                         */
-       O_IP_SRC_SET,           /* u32=base, arg1=len, bitmap   */
-
-       O_IP_DST,               /* u32 = IP                     */
-       O_IP_DST_MASK,          /* ip = IP/mask                 */
-       O_IP_DST_ME,            /* none                         */
-       O_IP_DST_SET,           /* u32=base, arg1=len, bitmap   */
-
-       O_IP_SRCPORT,           /* (n)port list:mask 4 byte ea  */
-       O_IP_DSTPORT,           /* (n)port list:mask 4 byte ea  */
-       O_PROTO,                /* arg1=protocol                */
-
-       O_MACADDR2,             /* 2 mac addr:mask              */
-       O_MAC_TYPE,             /* same as srcport              */
-
-       O_LAYER2,               /* none                         */
-       O_IN,                   /* none                         */
-       O_FRAG,                 /* none                         */
-
-       O_RECV,                 /* none                         */
-       O_XMIT,                 /* none                         */
-       O_VIA,                  /* none                         */
-
-       O_IPOPT,                /* arg1 = 2*u8 bitmap           */
-       O_IPLEN,                /* arg1 = len                   */
-       O_IPID,                 /* arg1 = id                    */
-
-       O_IPTOS,                /* arg1 = id                    */
-       O_IPPRECEDENCE,         /* arg1 = precedence << 5       */
-       O_IPTTL,                /* arg1 = TTL                   */
-
-       O_IPVER,                /* arg1 = version               */
-       O_UID,                  /* u32 = id                     */
-       O_GID,                  /* u32 = id                     */
-       O_ESTAB,                /* none (tcp established)       */
-       O_TCPFLAGS,             /* arg1 = 2*u8 bitmap           */
-       O_TCPWIN,               /* arg1 = desired win           */
-       O_TCPSEQ,               /* u32 = desired seq.           */
-       O_TCPACK,               /* u32 = desired seq.           */
-       O_ICMPTYPE,             /* u32 = icmp bitmap            */
-       O_TCPOPTS,              /* arg1 = 2*u8 bitmap           */
-
-       O_VERREVPATH,           /* none                         */
-       O_VERSRCREACH,          /* none                         */
-
-       O_PROBE_STATE,          /* none                         */
-       O_KEEP_STATE,           /* none                         */
-       O_LIMIT,                /* ipfw_insn_limit              */
-       O_LIMIT_PARENT,         /* dyn_type, not an opcode.     */
-
-       /*
-        * These are really 'actions'.
-        */
-
-       O_LOG,                  /* ipfw_insn_log                */
-       O_PROB,                 /* u32 = match probability      */
-
-       O_CHECK_STATE,          /* none                         */
-       O_ACCEPT,               /* none                         */
-       O_DENY,                 /* none                         */
-       O_REJECT,               /* arg1=icmp arg (same as deny) */
-       O_COUNT,                /* none                         */
-       O_SKIPTO,               /* arg1=next rule number        */
-       O_PIPE,                 /* arg1=pipe number             */
-       O_QUEUE,                /* arg1=queue number            */
-       O_DIVERT,               /* arg1=port number             */
-       O_TEE,                  /* arg1=port number             */
-       O_FORWARD_IP,           /* fwd sockaddr                 */
-       O_FORWARD_MAC,          /* fwd mac                      */
-       O_NAT,                  /* nope                         */
-       O_REASS,                /* none                         */
-
-       /*
-        * More opcodes.
-        */
-       O_IPSEC,                /* has ipsec history            */
-       O_IP_SRC_LOOKUP,        /* arg1=table number, u32=value */
-       O_IP_DST_LOOKUP,        /* arg1=table number, u32=value */
-       O_ANTISPOOF,            /* none                         */
-       O_JAIL,                 /* u32 = id                     */
-       O_ALTQ,                 /* u32 = altq classif. qid      */
-       O_DIVERTED,             /* arg1=bitmap (1:loop, 2:out)  */
-       O_TCPDATALEN,           /* arg1 = tcp data len          */
-       O_IP6_SRC,              /* address without mask         */
-       O_IP6_SRC_ME,           /* my addresses                 */
-       O_IP6_SRC_MASK,         /* address with the mask        */
-       O_IP6_DST,
-       O_IP6_DST_ME,
-       O_IP6_DST_MASK,
-       O_FLOW6ID,              /* for flow id tag in the ipv6 pkt */
-       O_ICMP6TYPE,            /* icmp6 packet type filtering  */
-       O_EXT_HDR,              /* filtering for ipv6 extension header */
-       O_IP6,
-
-       /*
-        * actions for ng_ipfw
-        */
-       O_NETGRAPH,             /* send to ng_ipfw              */
-       O_NGTEE,                /* copy to ng_ipfw              */
-
-       O_IP4,
-
-       O_UNREACH6,             /* arg1=icmpv6 code arg (deny)  */
-
-       O_TAG,                  /* arg1=tag number */
-       O_TAGGED,               /* arg1=tag number */
-
-       O_SETFIB,               /* arg1=FIB number */
-       O_FIB,                  /* arg1=FIB desired fib number */
-
-       O_LAST_OPCODE           /* not an opcode!               */
-};
-
-/*
- * The extension header are filtered only for presence using a bit
- * vector with a flag for each header.
- */
-#define EXT_FRAGMENT   0x1
-#define EXT_HOPOPTS    0x2
-#define EXT_ROUTING    0x4
-#define EXT_AH         0x8
-#define EXT_ESP                0x10
-#define EXT_DSTOPTS    0x20
-#define EXT_RTHDR0             0x40
-#define EXT_RTHDR2             0x80
-
-/*
- * Template for instructions.
- *
- * ipfw_insn is used for all instructions which require no operands,
- * a single 16-bit value (arg1), or a couple of 8-bit values.
- *
- * For other instructions which require different/larger arguments
- * we have derived structures, ipfw_insn_*.
- *
- * The size of the instruction (in 32-bit words) is in the low
- * 6 bits of "len". The 2 remaining bits are used to implement
- * NOT and OR on individual instructions. Given a type, you can
- * compute the length to be put in "len" using F_INSN_SIZE(t)
- *
- * F_NOT       negates the match result of the instruction.
- *
- * F_OR                is used to build or blocks. By default, instructions
- *             are evaluated as part of a logical AND. An "or" block
- *             { X or Y or Z } contains F_OR set in all but the last
- *             instruction of the block. A match will cause the code
- *             to skip past the last instruction of the block.
- *
- * NOTA BENE: in a couple of places we assume that
- *     sizeof(ipfw_insn) == sizeof(u_int32_t)
- * this needs to be fixed.
- *
- */
-typedef struct _ipfw_insn {    /* template for instructions */
-       enum ipfw_opcodes       opcode:8;
-       u_int8_t        len;    /* number of 32-bit words */
-#define        F_NOT           0x80
-#define        F_OR            0x40
-#define        F_LEN_MASK      0x3f
-#define        F_LEN(cmd)      ((cmd)->len & F_LEN_MASK)
-
-       u_int16_t       arg1;
-} ipfw_insn;
-
-/*
- * The F_INSN_SIZE(type) computes the size, in 4-byte words, of
- * a given type.
- */
-#define        F_INSN_SIZE(t)  ((sizeof (t))/sizeof(u_int32_t))
-
-#define MTAG_IPFW      1148380143      /* IPFW-tagged cookie */
-
-/*
- * This is used to store an array of 16-bit entries (ports etc.)
- */
-typedef struct _ipfw_insn_u16 {
-       ipfw_insn o;
-       u_int16_t ports[2];     /* there may be more */
-} ipfw_insn_u16;
-
-/*
- * This is used to store an array of 32-bit entries
- * (uid, single IPv4 addresses etc.)
- */
-typedef struct _ipfw_insn_u32 {
-       ipfw_insn o;
-       u_int32_t d[1]; /* one or more */
-} ipfw_insn_u32;
-
-/*
- * This is used to store IP addr-mask pairs.
- */
-typedef struct _ipfw_insn_ip {
-       ipfw_insn o;
-       struct in_addr  addr;
-       struct in_addr  mask;
-} ipfw_insn_ip;
-
-/*
- * This is used to forward to a given address (ip).
- */
-typedef struct  _ipfw_insn_sa {
-       ipfw_insn o;
-       struct sockaddr_in sa;
-} ipfw_insn_sa;
-
-/*
- * This is used for MAC addr-mask pairs.
- */
-typedef struct _ipfw_insn_mac {
-       ipfw_insn o;
-       u_char addr[12];        /* dst[6] + src[6] */
-       u_char mask[12];        /* dst[6] + src[6] */
-} ipfw_insn_mac;
-
-/*
- * This is used for interface match rules (recv xx, xmit xx).
- */
-typedef struct _ipfw_insn_if {
-       ipfw_insn o;
-       union {
-               struct in_addr ip;
-               int glob;
-       } p;
-       char name[IFNAMSIZ];
-} ipfw_insn_if;
-
-/*
- * This is used for storing an altq queue id number.
- */
-typedef struct _ipfw_insn_altq {
-       ipfw_insn       o;
-       u_int32_t       qid;
-} ipfw_insn_altq;
-
-/*
- * This is used for limit rules.
- */
-typedef struct _ipfw_insn_limit {
-       ipfw_insn o;
-       u_int8_t _pad;
-       u_int8_t limit_mask;    /* combination of DYN_* below   */
-#define        DYN_SRC_ADDR    0x1
-#define        DYN_SRC_PORT    0x2
-#define        DYN_DST_ADDR    0x4
-#define        DYN_DST_PORT    0x8
-
-       u_int16_t conn_limit;
-} ipfw_insn_limit;
-
-/*
- * This is used for log instructions.
- */
-typedef struct  _ipfw_insn_log {
-        ipfw_insn o;
-       u_int32_t max_log;      /* how many do we log -- 0 = all */
-       u_int32_t log_left;     /* how many left to log         */
-} ipfw_insn_log;
-
-/*
- * Data structures required by both ipfw(8) and ipfw(4) but not part of the
- * management API are protected by IPFW_INTERNAL.
- */
-#ifdef IPFW_INTERNAL
-/* Server pool support (LSNAT). */
-struct cfg_spool {
-       LIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */
-       struct in_addr          addr;
-       u_short                 port;
-};
-#endif
-
-/* Redirect modes id. */
-#define REDIR_ADDR      0x01
-#define REDIR_PORT      0x02
-#define REDIR_PROTO     0x04
-
-#ifdef IPFW_INTERNAL
-/* Nat redirect configuration. */
-struct cfg_redir {
-       LIST_ENTRY(cfg_redir)   _next;          /* chain of redir instances */
-       u_int16_t               mode;           /* type of redirect mode */
-       struct in_addr          laddr;          /* local ip address */
-       struct in_addr          paddr;          /* public ip address */
-       struct in_addr          raddr;          /* remote ip address */
-       u_short                 lport;          /* local port */
-       u_short                 pport;          /* public port */
-       u_short                 rport;          /* remote port  */
-       u_short                 pport_cnt;      /* number of public ports */
-       u_short                 rport_cnt;      /* number of remote ports */
-       int                     proto;          /* protocol: tcp/udp */
-       struct alias_link       **alink;        
-       /* num of entry in spool chain */
-       u_int16_t               spool_cnt;      
-       /* chain of spool instances */
-       LIST_HEAD(spool_chain, cfg_spool) spool_chain;
-};
-#endif
-
-#define NAT_BUF_LEN     1024
-
-#ifdef IPFW_INTERNAL
-/* Nat configuration data struct. */
-struct cfg_nat {
-       /* chain of nat instances */
-       LIST_ENTRY(cfg_nat)     _next;
-       int                     id;                     /* nat id */
-       struct in_addr          ip;                     /* nat ip address */
-       char                    if_name[IF_NAMESIZE];   /* interface name */
-       int                     mode;                   /* aliasing mode */
-       struct libalias         *lib;                   /* libalias instance */
-       /* number of entry in spool chain */
-       int                     redir_cnt;              
-       /* chain of redir instances */
-       LIST_HEAD(redir_chain, cfg_redir) redir_chain;  
-};
-#endif
-
-#define SOF_NAT         sizeof(struct cfg_nat)
-#define SOF_REDIR       sizeof(struct cfg_redir)
-#define SOF_SPOOL       sizeof(struct cfg_spool)
-
-/* Nat command. */
-typedef struct _ipfw_insn_nat {
-       ipfw_insn       o;
-       struct cfg_nat *nat;    
-} ipfw_insn_nat;
-
-/* Apply ipv6 mask on ipv6 addr */
-#define APPLY_MASK(addr,mask)                          \
-    (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \
-    (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \
-    (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \
-    (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3];
-
-/* Structure for ipv6 */
-typedef struct _ipfw_insn_ip6 {
-       ipfw_insn o;
-       struct in6_addr addr6;
-       struct in6_addr mask6;
-} ipfw_insn_ip6;
-
-/* Used to support icmp6 types */
-typedef struct _ipfw_insn_icmp6 {
-       ipfw_insn o;
-       uint32_t d[7]; /* XXX This number si related to the netinet/icmp6.h
-                       *     define ICMP6_MAXTYPE
-                       *     as follows: n = ICMP6_MAXTYPE/32 + 1
-                        *     Actually is 203 
-                       */
-} ipfw_insn_icmp6;
-
-/*
- * Here we have the structure representing an ipfw rule.
- *
- * It starts with a general area (with link fields and counters)
- * followed by an array of one or more instructions, which the code
- * accesses as an array of 32-bit values.
- *
- * Given a rule pointer  r:
- *
- *  r->cmd             is the start of the first instruction.
- *  ACTION_PTR(r)      is the start of the first action (things to do
- *                     once a rule matched).
- *
- * When assembling instruction, remember the following:
- *
- *  + if a rule has a "keep-state" (or "limit") option, then the
- *     first instruction (at r->cmd) MUST BE an O_PROBE_STATE
- *  + if a rule has a "log" option, then the first action
- *     (at ACTION_PTR(r)) MUST be O_LOG
- *  + if a rule has an "altq" option, it comes after "log"
- *  + if a rule has an O_TAG option, it comes after "log" and "altq"
- *
- * NOTE: we use a simple linked list of rules because we never need
- *     to delete a rule without scanning the list. We do not use
- *     queue(3) macros for portability and readability.
- */
-
-struct ip_fw {
-       struct ip_fw    *next;          /* linked list of rules         */
-       struct ip_fw    *next_rule;     /* ptr to next [skipto] rule    */
-       /* 'next_rule' is used to pass up 'set_disable' status          */
-
-       u_int16_t       act_ofs;        /* offset of action in 32-bit units */
-       u_int16_t       cmd_len;        /* # of 32-bit words in cmd     */
-       u_int16_t       rulenum;        /* rule number                  */
-       u_int8_t        set;            /* rule set (0..31)             */
-#define        RESVD_SET       31      /* set for default and persistent rules */
-       u_int8_t        _pad;           /* padding                      */
-
-       /* These fields are present in all rules.                       */
-       u_int64_t       pcnt;           /* Packet counter               */
-       u_int64_t       bcnt;           /* Byte counter                 */
-       u_int32_t       timestamp;      /* tv_sec of last match         */
-
-       ipfw_insn       cmd[1];         /* storage for commands         */
-};
-
-#define ACTION_PTR(rule)                               \
-       (ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )
-
-#define RULESIZE(rule)  (sizeof(struct ip_fw) + \
-       ((struct ip_fw *)(rule))->cmd_len * 4 - 4)
-
-/*
- * This structure is used as a flow mask and a flow id for various
- * parts of the code.
- */
-struct ipfw_flow_id {
-       u_int32_t       dst_ip;
-       u_int32_t       src_ip;
-       u_int16_t       dst_port;
-       u_int16_t       src_port;
-       u_int8_t        fib;
-       u_int8_t        proto;
-       u_int8_t        flags;  /* protocol-specific flags */
-       uint8_t         addr_type; /* 4 = ipv4, 6 = ipv6, 1=ether ? */
-       struct in6_addr dst_ip6;        /* could also store MAC addr! */
-       struct in6_addr src_ip6;
-       u_int32_t       flow_id6;
-       u_int32_t       frag_id6;
-};
-
-#define IS_IP6_FLOW_ID(id)     ((id)->addr_type == 6)
-
-/*
- * Dynamic ipfw rule.
- */
-typedef struct _ipfw_dyn_rule ipfw_dyn_rule;
-
-struct _ipfw_dyn_rule {
-       ipfw_dyn_rule   *next;          /* linked list of rules.        */
-       struct ip_fw *rule;             /* pointer to rule              */
-       /* 'rule' is used to pass up the rule number (from the parent)  */
-
-       ipfw_dyn_rule *parent;          /* pointer to parent rule       */
-       u_int64_t       pcnt;           /* packet match counter         */
-       u_int64_t       bcnt;           /* byte match counter           */
-       struct ipfw_flow_id id;         /* (masked) flow id             */
-       u_int32_t       expire;         /* expire time                  */
-       u_int32_t       bucket;         /* which bucket in hash table   */
-       u_int32_t       state;          /* state of this rule (typically a
-                                        * combination of TCP flags)
-                                        */
-       u_int32_t       ack_fwd;        /* most recent ACKs in forward  */
-       u_int32_t       ack_rev;        /* and reverse directions (used */
-                                       /* to generate keepalives)      */
-       u_int16_t       dyn_type;       /* rule type                    */
-       u_int16_t       count;          /* refcount                     */
-};
-
-/*
- * Definitions for IP option names.
- */
-#define        IP_FW_IPOPT_LSRR        0x01
-#define        IP_FW_IPOPT_SSRR        0x02
-#define        IP_FW_IPOPT_RR          0x04
-#define        IP_FW_IPOPT_TS          0x08
-
-/*
- * Definitions for TCP option names.
- */
-#define        IP_FW_TCPOPT_MSS        0x01
-#define        IP_FW_TCPOPT_WINDOW     0x02
-#define        IP_FW_TCPOPT_SACK       0x04
-#define        IP_FW_TCPOPT_TS         0x08
-#define        IP_FW_TCPOPT_CC         0x10
-
-#define        ICMP_REJECT_RST         0x100   /* fake ICMP code (send a TCP RST) */
-#define        ICMP6_UNREACH_RST       0x100   /* fake ICMPv6 code (send a TCP RST) */
-
-/*
- * These are used for lookup tables.
- */
-typedef struct _ipfw_table_entry {
-       in_addr_t       addr;           /* network address              */
-       u_int32_t       value;          /* value                        */
-       u_int16_t       tbl;            /* table number                 */
-       u_int8_t        masklen;        /* mask length                  */
-} ipfw_table_entry;
-
-typedef struct _ipfw_table {
-       u_int32_t       size;           /* size of entries in bytes     */
-       u_int32_t       cnt;            /* # of entries                 */
-       u_int16_t       tbl;            /* table number                 */
-       ipfw_table_entry ent[0];        /* entries                      */
-} ipfw_table;
-
-#define IP_FW_TABLEARG 65535
-
-/*
- * Main firewall chains definitions and global var's definitions.
- */
-#ifdef _KERNEL
-
-/* Return values from ipfw_chk() */
-enum {
-       IP_FW_PASS = 0,
-       IP_FW_DENY,
-       IP_FW_DIVERT,
-       IP_FW_TEE,
-       IP_FW_DUMMYNET,
-       IP_FW_NETGRAPH,
-       IP_FW_NGTEE,
-       IP_FW_NAT,
-       IP_FW_REASS,
-};
-
-/* flags for divert mtag */
-#define        IP_FW_DIVERT_LOOPBACK_FLAG      0x00080000
-#define        IP_FW_DIVERT_OUTPUT_FLAG        0x00100000
-
-/*
- * Structure for collecting parameters to dummynet for ip6_output forwarding
- */
-struct _ip6dn_args {
-       struct ip6_pktopts *opt_or;
-       struct route_in6 ro_or;
-       int flags_or;
-       struct ip6_moptions *im6o_or;
-       struct ifnet *origifp_or;
-       struct ifnet *ifp_or;
-       struct sockaddr_in6 dst_or;
-       u_long mtu_or;
-       struct route_in6 ro_pmtu_or;
-};
-
-/*
- * Arguments for calling ipfw_chk() and dummynet_io(). We put them
- * all into a structure because this way it is easier and more
- * efficient to pass variables around and extend the interface.
- */
-struct ip_fw_args {
-       struct mbuf     *m;             /* the mbuf chain               */
-       struct ifnet    *oif;           /* output interface             */
-       struct sockaddr_in *next_hop;   /* forward address              */
-       struct ip_fw    *rule;          /* matching rule                */
-       struct ether_header *eh;        /* for bridged packets          */
-
-       struct ipfw_flow_id f_id;       /* grabbed from IP header       */
-       u_int32_t       cookie;         /* a cookie depending on rule action */
-       struct inpcb    *inp;
-
-       struct _ip6dn_args      dummypar; /* dummynet->ip6_output */
-       struct sockaddr_in hopstore;    /* store here if cannot use a pointer */
-};
-
-/*
- * Function definitions.
- */
-
-/* Firewall hooks */
-struct sockopt;
-struct dn_flow_set;
-
-int ipfw_check_in(void *, struct mbuf **, struct ifnet *, int, struct inpcb *inp);
-int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int, struct inpcb *inp);
-
-int ipfw_chk(struct ip_fw_args *);
-
-int ipfw_init(void);
-void ipfw_destroy(void);
-
-typedef int ip_fw_ctl_t(struct sockopt *);
-extern ip_fw_ctl_t *ip_fw_ctl_ptr;
-extern int fw_one_pass;
-extern int fw_enable;
-#ifdef INET6
-extern int fw6_enable;
-#endif
-
-/* For kernel ipfw_ether and ipfw_bridge. */
-typedef        int ip_fw_chk_t(struct ip_fw_args *args);
-extern ip_fw_chk_t     *ip_fw_chk_ptr;
-#define        IPFW_LOADED     (ip_fw_chk_ptr != NULL)
-
-#ifdef IPFW_INTERNAL
-
-#define        IPFW_TABLES_MAX         128
-struct ip_fw_chain {
-       struct ip_fw    *rules;         /* list of rules */
-       struct ip_fw    *reap;          /* list of rules to reap */
-       LIST_HEAD(, cfg_nat) nat;       /* list of nat entries */
-       struct radix_node_head *tables[IPFW_TABLES_MAX];
-       struct rwlock   rwmtx;
-};
-#define        IPFW_LOCK_INIT(_chain) \
-       rw_init(&(_chain)->rwmtx, "IPFW static rules")
-#define        IPFW_LOCK_DESTROY(_chain)       rw_destroy(&(_chain)->rwmtx)
-#define        IPFW_WLOCK_ASSERT(_chain)       rw_assert(&(_chain)->rwmtx, RA_WLOCKED)
-
-#define IPFW_RLOCK(p) rw_rlock(&(p)->rwmtx)
-#define IPFW_RUNLOCK(p) rw_runlock(&(p)->rwmtx)
-#define IPFW_WLOCK(p) rw_wlock(&(p)->rwmtx)
-#define IPFW_WUNLOCK(p) rw_wunlock(&(p)->rwmtx)
-
-#define LOOKUP_NAT(l, i, p) do {                                       \
-               LIST_FOREACH((p), &(l.nat), _next) {                    \
-                       if ((p)->id == (i)) {                           \
-                               break;                                  \
-                       }                                               \
-               }                                                       \
-       } while (0)
-
-typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
-typedef int ipfw_nat_cfg_t(struct sockopt *);
-#endif
-
-#endif /* _KERNEL */
-#endif /* _IPFW2_H */
diff --git a/ipfw/include/netinet/tcp.h b/ipfw/include/netinet/tcp.h
deleted file mode 100644 (file)
index 37992e2..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * a subset of FreeBSD's netinet/tcp.h
- */
-#ifndef _NETINET_TCP_H_
-#define _NETINET_TCP_H_
-
-#define        TH_FIN  0x01
-#define        TH_SYN  0x02
-#define        TH_RST  0x04
-#define        TH_PUSH 0x08
-#define        TH_ACK  0x10
-#define        TH_URG  0x20
-
-#endif /* _NETINET_TCP_H_ */
index 8d6ed87..e9b3fb3 100644 (file)
@@ -1816,7 +1816,6 @@ ipfw_list(int ac, char *av[], int show_counters)
                                bcwidth = width;
                }
        }
-
        if (co.do_dynamic && ndyn) {
                for (n = 0, d = dynrules; n < ndyn; n++, d++) {
                        if (co.use_set) {
@@ -1837,7 +1836,6 @@ ipfw_list(int ac, char *av[], int show_counters)
                                bcwidth = width;
                }
        }
-
        /* if no rule numbers were specified, list all rules */
        if (ac == 0) {
                for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
index 1de0f3c..bd80cff 100644 (file)
@@ -154,6 +154,7 @@ enum tokens {
        TOK_BW,
        TOK_DELAY,
        TOK_PIPE_PROFILE,
+       TOK_BURST,
        TOK_RED,
        TOK_GRED,
        TOK_DROPTAIL,