Index: conf/files
===================================================================
RCS file: /home/ncvs/src/sys/conf/files,v
retrieving revision 1.942
diff -u -p -r1.942 files
--- conf/files	17 Aug 2004 00:14:30 -0000	1.942
+++ conf/files	17 Aug 2004 18:23:34 -0000
@@ -1484,6 +1484,7 @@ netinet/ip_encap.c	optional inet
 netinet/ip_encap.c	optional inet6
 netinet/ip_fastfwd.c	optional inet
 netinet/ip_fw2.c	optional ipfirewall
+netinet/ip_fw_pfil.c	optional ipfirewall
 netinet/ip_icmp.c	optional inet
 netinet/ip_input.c	optional inet
 netinet/ip_mroute.c	optional mrouting
Index: conf/options
===================================================================
RCS file: /home/ncvs/src/sys/conf/options,v
retrieving revision 1.474
diff -u -p -r1.474 options
--- conf/options	16 Aug 2004 06:36:20 -0000	1.474
+++ conf/options	17 Aug 2004 18:23:34 -0000
@@ -347,6 +347,7 @@ IPFIREWALL		opt_ipfw.h
 IPFIREWALL_VERBOSE	opt_ipfw.h
 IPFIREWALL_VERBOSE_LIMIT	opt_ipfw.h
 IPFIREWALL_DEFAULT_TO_ACCEPT	opt_ipfw.h
+IPFIREWALL_FORWARD	opt_ipfw.h
 IPV6FIREWALL		opt_ip6fw.h
 IPV6FIREWALL_VERBOSE	opt_ip6fw.h
 IPV6FIREWALL_VERBOSE_LIMIT	opt_ip6fw.h
Index: i386/conf/GENERIC
===================================================================
RCS file: /home/ncvs/src/sys/i386/conf/GENERIC,v
retrieving revision 1.413
diff -u -p -r1.413 GENERIC
--- i386/conf/GENERIC	11 Aug 2004 01:34:18 -0000	1.413
+++ i386/conf/GENERIC	17 Aug 2004 18:23:35 -0000
@@ -31,6 +31,12 @@ makeoptions	DEBUG=-g		# Build kernel wit
 
 options 	SCHED_ULE		# ULE scheduler
 options 	INET			# InterNETworking
+
+options		IPFIREWALL
+options		IPFIREWALL_FORWARD
+options		IPDIVERT
+options		DUMMYNET
+
 options 	INET6			# IPv6 communications protocols
 options 	FFS			# Berkeley Fast Filesystem
 options 	SOFTUPDATES		# Enable FFS soft updates support
Index: modules/ipfw/Makefile
===================================================================
RCS file: /home/ncvs/src/sys/modules/ipfw/Makefile,v
retrieving revision 1.16
diff -u -p -r1.16 Makefile
--- modules/ipfw/Makefile	28 Jun 2002 08:10:07 -0000	1.16
+++ modules/ipfw/Makefile	17 Aug 2004 18:23:36 -0000
@@ -3,7 +3,7 @@
 .PATH: ${.CURDIR}/../../netinet
 
 KMOD=	ipfw
-SRCS=	ip_fw2.c
+SRCS=	ip_fw2.c ip_fw_pfil.c
 
 CFLAGS+= -DIPFIREWALL
 #
Index: netgraph/ng_bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/netgraph/ng_bridge.c,v
retrieving revision 1.27
diff -u -p -r1.27 ng_bridge.c
--- netgraph/ng_bridge.c	20 Jul 2004 17:15:37 -0000	1.27
+++ netgraph/ng_bridge.c	17 Aug 2004 18:23:36 -0000
@@ -629,9 +629,11 @@ ng_bridge_rcvdata(hook_p hook, item_p it
 	}
 
 	/* Run packet through ipfw processing, if enabled */
+#if 0
 	if (priv->conf.ipfw[linkNum] && fw_enable && ip_fw_chk_ptr != NULL) {
 		/* XXX not implemented yet */
 	}
+#endif
 
 	/*
 	 * If unicast and destination host known, deliver to host's link,
Index: netinet/ip_divert.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_divert.c,v
retrieving revision 1.97
diff -u -p -r1.97 ip_divert.c
--- netinet/ip_divert.c	11 Aug 2004 20:30:08 -0000	1.97
+++ netinet/ip_divert.c	17 Aug 2004 18:23:36 -0000
@@ -373,27 +373,6 @@ cantsend:
 	return error;
 }
 
-/*
- * Return a copy of the specified packet, but without
- * the divert tag.  This is used when packets are ``tee'd''
- * and we want the cloned copy to not have divert processing.
- */
-struct mbuf *
-divert_clone(struct mbuf *m)
-{
-	struct mbuf *clone;
-	struct m_tag *mtag;
-
-	clone = m_dup(m, M_DONTWAIT);
-	if (clone != NULL) {
-		/* strip divert tag from copy */
-		mtag = m_tag_find(clone, PACKET_TAG_DIVERT, NULL);
-		if (mtag != NULL)
-			m_tag_delete(clone, mtag);
-	}
-	return clone;
-}
-
 static int
 div_attach(struct socket *so, int proto, struct thread *td)
 {
Index: netinet/ip_dummynet.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.c,v
retrieving revision 1.82
diff -u -p -r1.82 ip_dummynet.c
--- netinet/ip_dummynet.c	15 Jul 2004 08:26:07 -0000	1.82
+++ netinet/ip_dummynet.c	17 Aug 2004 18:23:36 -0000
@@ -179,7 +179,6 @@ static struct mtx dummynet_mtx;
 static int config_pipe(struct dn_pipe *p);
 static int ip_dn_ctl(struct sockopt *sopt);
 
-static void rt_unref(struct rtentry *, const char *);
 static void dummynet(void *);
 static void dummynet_flush(void);
 void dummynet_drain(void);
@@ -188,19 +187,6 @@ static void dn_rule_delete(void *);
 
 int if_tx_rdy(struct ifnet *ifp);
 
-static void
-rt_unref(struct rtentry *rt, const char *where)
-{
-    if (rt == NULL)
-	return ;
-    RT_LOCK(rt);
-    if (rt->rt_refcnt <= 0) {
-	printf("dummynet: warning, refcnt now %ld, decreasing (%s)\n",
-	    rt->rt_refcnt, where);
-    }
-    RTFREE_LOCKED(rt);
-}
-
 /*
  * Heap management functions.
  *
@@ -446,6 +432,7 @@ transmit_event(struct dn_pipe *pipe)
 {
     struct mbuf *m ;
     struct dn_pkt_tag *pkt ;
+    struct ip *ip;
 
     DUMMYNET_LOCK_ASSERT();
 
@@ -468,6 +455,9 @@ transmit_event(struct dn_pipe *pipe)
 	    break ;
 
 	case DN_TO_IP_IN :
+	    ip = mtod(m, struct ip *);
+	    ip->ip_len = htons(ip->ip_len);
+	    ip->ip_off = htons(ip->ip_off);
 	    ip_input(m) ;
 	    break ;
 
@@ -1127,8 +1117,6 @@ locate_flowset(int pipe_nr, struct ip_fw
  * ifp		the 'ifp' parameter from the caller.
  *		NULL in ip_input, destination interface in ip_output,
  *		real_dst in bdg_forward
- * ro		route parameter (only used in ip_output, NULL otherwise)
- * dst		destination address, only used by ip_output
  * rule		matching rule, in case of multiple passes
  * flags	flags from the caller, only used in ip_output
  *
@@ -1214,23 +1202,8 @@ dummynet_io(struct mbuf *m, int pipe_nr,
     pkt->dn_dir = dir ;
 
     pkt->ifp = fwa->oif;
-    if (dir == DN_TO_IP_OUT) {
-	/*
-	 * We need to copy *ro because for ICMP pkts (and maybe others)
-	 * the caller passed a pointer into the stack; dst might also be
-	 * a pointer into *ro so it needs to be updated.
-	 */
-	pkt->ro = *(fwa->ro);
-	if (pkt->ro.ro_rt) {
-	    RT_LOCK(pkt->ro.ro_rt);
-	    RT_ADDREF(pkt->ro.ro_rt) ;
-	    RT_UNLOCK(pkt->ro.ro_rt);
-	}
-	if (fwa->dst == (struct sockaddr_in *)&fwa->ro->ro_dst) /* dst points into ro */
-	    fwa->dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
-	pkt->dn_dst = fwa->dst;
+    if (dir == DN_TO_IP_OUT)
 	pkt->flags = fwa->flags;
-    }
     if (q->head == NULL)
 	q->head = m;
     else
@@ -1327,7 +1300,6 @@ dropit:
  * Doing this would probably save us the initial bzero of dn_pkt
  */
 #define	DN_FREE_PKT(_m) do {				\
-	rt_unref(dn_tag_get(_m)->ro.ro_rt, __func__);	\
 	m_freem(_m);					\
 } while (0)
 
Index: netinet/ip_dummynet.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.h,v
retrieving revision 1.31
diff -u -p -r1.31 ip_dummynet.h
--- netinet/ip_dummynet.h	25 Feb 2004 19:55:28 -0000	1.31
+++ netinet/ip_dummynet.h	17 Aug 2004 18:23:36 -0000
@@ -127,8 +127,6 @@ struct dn_pkt_tag {
 
     dn_key output_time;		/* when the pkt is due for delivery	*/
     struct ifnet *ifp;		/* interface, for ip_output		*/
-    struct sockaddr_in *dn_dst ;
-    struct route ro;		/* route, for ip_output. MUST COPY	*/
     int flags ;			/* flags, for ip_output (IPv6 ?)	*/
 };
 #endif /* _KERNEL */
Index: netinet/ip_fastfwd.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fastfwd.c,v
retrieving revision 1.16
diff -u -p -r1.16 ip_fastfwd.c
--- netinet/ip_fastfwd.c	11 Aug 2004 12:32:10 -0000	1.16
+++ netinet/ip_fastfwd.c	17 Aug 2004 18:23:36 -0000
@@ -76,9 +76,6 @@
  */
 
 #include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
 #include "opt_ipstealth.h"
 #include "opt_pfil_hooks.h"
 
@@ -107,10 +104,6 @@
 
 #include <machine/in_cksum.h>
 
-#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
-#include <netinet/ip_dummynet.h>
-
 static int ipfastforward_active = 0;
 SYSCTL_INT(_net_inet_ip, OID_AUTO, fastforwarding, CTLFLAG_RW,
     &ipfastforward_active, 0, "Enable fast IP forwarding");
@@ -163,20 +156,15 @@ ip_fastforward(struct mbuf *m)
 {
 	struct ip *ip;
 	struct mbuf *m0 = NULL;
-#ifdef IPDIVERT
-	struct ip *tip;
-	struct mbuf *clone = NULL;
-#endif
 	struct route ro;
 	struct sockaddr_in *dst = NULL;
 	struct in_ifaddr *ia = NULL;
 	struct ifaddr *ifa = NULL;
 	struct ifnet *ifp;
-	struct ip_fw_args args;
 	struct in_addr odest, dest;
 	u_short sum, ip_len;
 	int error = 0;
-	int hlen, ipfw, mtu;
+	int hlen, mtu;
 
 	/*
 	 * Are we active and forwarding packets?
@@ -375,92 +363,6 @@ ip_fastforward(struct mbuf *m)
 
 	ip = mtod(m, struct ip *);	/* m may have changed by pfil hook */
 	dest.s_addr = ip->ip_dst.s_addr;
-#endif
-
-	/*
-	 * Run through ipfw for input packets
-	 */
-	if (fw_enable && IPFW_LOADED) {
-		bzero(&args, sizeof(args));
-		args.m = m;
-
-		ipfw = ip_fw_chk_ptr(&args);
-		m = args.m;
-
-		M_ASSERTVALID(m);
-		M_ASSERTPKTHDR(m);
-
-		/*
-		 * Packet denied, drop it
-		 */
-		if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
-			goto drop;
-		/*
-		 * Send packet to the appropriate pipe
-		 */
-		if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
-			ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_IN, &args);
-			return 1;
-		}
-#ifdef IPDIVERT
-		/*
-		 * Divert packet
-		 */
-		if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
-			/*
-			 * See if this is a fragment
-			 */
-			if (ip->ip_off & (IP_MF | IP_OFFMASK))
-				goto droptoours;
-			/*
-			 * Tee packet
-			 */
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
-				clone = divert_clone(m);
-			else
-				clone = m;
-			if (clone == NULL)
-				goto passin;
-
-			/*
-			 * Delayed checksums are not compatible
-			 */
-			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
-				in_delayed_cksum(m);
-				m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
-			}
-			/*
-			 * Restore packet header fields to original values
-			 */
-			tip = mtod(m, struct ip *);
-			tip->ip_len = htons(tip->ip_len);
-			tip->ip_off = htons(tip->ip_off);
-			/*
-			 * Deliver packet to divert input routine
-			 */
-			divert_packet(m, 0);
-			/*
-			 * If this was not tee, we are done
-			 */
-			m = clone;
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0)
-				return 1;
-			/* Continue if it was tee */
-			goto passin;
-		}
-#endif
-		if (ipfw == 0 && args.next_hop != NULL) {
-			dest.s_addr = args.next_hop->sin_addr.s_addr;
-			goto passin;
-		}
-		/*
-		 * Let through or not?
-		 */
-		if (ipfw != 0)
-			goto drop;
-	}
-passin:
-	ip = mtod(m, struct ip *);	/* if m changed during fw processing */
 
 	/*
 	 * Destination address changed?
@@ -475,6 +377,7 @@ passin:
 		 * Go on with new destination address
 		 */
 	}
+#endif
 
 	/*
 	 * Step 4: decrement TTL and look up route
@@ -528,89 +431,6 @@ passin:
 
 	ip = mtod(m, struct ip *);
 	dest.s_addr = ip->ip_dst.s_addr;
-#endif
-	if (fw_enable && IPFW_LOADED && !args.next_hop) {
-		bzero(&args, sizeof(args));
-		args.m = m;
-		args.oif = ifp;
-
-		ipfw = ip_fw_chk_ptr(&args);
-		m = args.m;
-
-		M_ASSERTVALID(m);
-		M_ASSERTPKTHDR(m);
-
-		if ((ipfw & IP_FW_PORT_DENY_FLAG) || m == NULL)
-			goto drop;
-
-		if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/*
-			 * XXX note: if the ifp or rt entry are deleted
-			 * while a pkt is in dummynet, we are in trouble!
-			 */
-			args.ro = &ro;		/* dummynet does not save it */
-			args.dst = dst;
-
-			ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_OUT, &args);
-			goto consumed;
-		}
-#ifdef IPDIVERT
-		if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
-			/*
-			 * See if this is a fragment
-			 */
-			if (ip->ip_off & (IP_MF | IP_OFFMASK))
-				goto droptoours;
-			/*
-			 * Tee packet
-			 */
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
-				clone = divert_clone(m);
-			else
-				clone = m;
-			if (clone == NULL)
-				goto passout;
-
-			/*
-			 * Delayed checksums are not compatible with divert
-			 */
-			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
-				in_delayed_cksum(m);
-				m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
-			}
-			/*
-			 * Restore packet header fields to original values
-			 */
-			tip = mtod(m, struct ip *);
-			tip->ip_len = htons(tip->ip_len);
-			tip->ip_off = htons(tip->ip_off);
-			/*
-			 * Deliver packet to divert input routine
-			 */
-			divert_packet(m, 0);
-			/*
-			 * If this was not tee, we are done
-			 */
-			m = clone;
-			if ((ipfw & IP_FW_PORT_TEE_FLAG) == 0) {
-				goto consumed;
-			}
-			/* Continue if it was tee */
-			goto passout;
-		}
-#endif
-		if (ipfw == 0 && args.next_hop != NULL) {
-			dest.s_addr = args.next_hop->sin_addr.s_addr;
-			goto passout;
-		}
-		/*
-		 * Let through or not?
-		 */
-		if (ipfw != 0)
-			goto drop;
-	}
-passout:
-	ip = mtod(m, struct ip *);
 
 	/*
 	 * Destination address changed?
@@ -621,30 +441,11 @@ passout:
 		 */
 		if (in_localip(dest)) {
 forwardlocal:
-			if (args.next_hop) {
-				struct m_tag *mtag = m_tag_get(
-				    PACKET_TAG_IPFORWARD,
-				    sizeof(struct sockaddr_in *),
-				    M_NOWAIT);
-				if (mtag == NULL) {
-					goto drop;
-				}
-				*(struct sockaddr_in **)(mtag+1) =
-				    args.next_hop;
-				m_tag_prepend(m, mtag);
-			}
-#ifdef IPDIVERT
-droptoours:	/* Used for DIVERT */
-#endif
 			/* for ip_input */
 			m->m_flags |= M_FASTFWD_OURS;
 
-			/* ip still points to the real packet */
-			ip->ip_len = htons(ip->ip_len);
-			ip->ip_off = htons(ip->ip_off);
-
 			/*
-			 * Return packet for processing by ip_input
+			 * Return packet for processing by ip_input()
 			 */
 			if (ro.ro_rt)
 				RTFREE(ro.ro_rt);
@@ -658,6 +459,7 @@ droptoours:	/* Used for DIVERT */
 			return 1;	/* icmp unreach already sent */
 		ifp = ro.ro_rt->rt_ifp;
 	}
+#endif
 
 	/*
 	 * Step 6: send off the packet
Index: netinet/ip_fw.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.88
diff -u -p -r1.88 ip_fw.h
--- netinet/ip_fw.h	16 Aug 2004 12:05:19 -0000	1.88
+++ netinet/ip_fw.h	17 Aug 2004 18:23:37 -0000
@@ -28,6 +28,7 @@
 #ifndef _IPFW2_H
 #define _IPFW2_H
 #define IPFW2  1
+
 /*
  * The kernel representation of ipfw rules is made of a list of
  * 'instructions' (for all practical purposes equivalent to BPF
@@ -420,8 +421,6 @@ struct ip_fw_args {
 	struct ip_fw	*rule;		/* matching rule		*/
 	struct ether_header *eh;	/* for bridged packets		*/
 
-	struct route	*ro;		/* for dummynet			*/
-	struct sockaddr_in *dst;	/* for dummynet			*/
 	int flags;			/* for dummynet			*/
 
 	struct ipfw_flow_id f_id;	/* grabbed from IP header	*/
@@ -436,15 +435,24 @@ struct ip_fw_args {
 struct sockopt;
 struct dn_flow_set;
 
+int ipfw_check_in(void *, struct mbuf **, struct ifnet *, int);
+int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int);
+
+int ipfw_chk(struct ip_fw_args *);
+
+int ipfw_init(void);
+void ipfw_destroy(void);
+
 void flush_pipe_ptrs(struct dn_flow_set *match); /* used by dummynet */
 
-typedef int ip_fw_chk_t (struct ip_fw_args *args);
-typedef int ip_fw_ctl_t (struct sockopt *);
-extern ip_fw_chk_t *ip_fw_chk_ptr;
+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;
+
+/* 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)
-#endif /* _KERNEL */
 
+#endif /* _KERNEL */
 #endif /* _IPFW2_H */
Index: netinet/ip_fw2.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.69
diff -u -p -r1.69 ip_fw2.c
--- netinet/ip_fw2.c	12 Aug 2004 22:05:47 -0000	1.69
+++ netinet/ip_fw2.c	17 Aug 2004 18:23:37 -0000
@@ -156,9 +156,6 @@ static int autoinc_step = 100; /* bounde
 
 #ifdef SYSCTL_NODE
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");
-SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, enable,
-    CTLFLAG_RW | CTLFLAG_SECURE3,
-    &fw_enable, 0, "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,
@@ -276,10 +273,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dy
 #endif /* SYSCTL_NODE */
 
 
-static ip_fw_chk_t	ipfw_chk;
-
-ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;	/* hook into dummynet */
-
 /*
  * This macro maps an ip pointer into a layer3 header pointer of type T
  */
@@ -1653,7 +1646,7 @@ check_uidgid(ipfw_insn_u32 *insn,
  *		  16 bits as a dummynet pipe number instead of diverting
  */
 
-static int
+int
 ipfw_chk(struct ip_fw_args *args)
 {
 	/*
@@ -3348,7 +3341,7 @@ done:
 	callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL);
 }
 
-static int
+int
 ipfw_init(void)
 {
 	struct ip_fw default_rule;
@@ -3384,7 +3377,13 @@ ipfw_init(void)
 
 	ip_fw_default_rule = layer3_chain.rules;
 	printf("ipfw2 initialized, divert %s, "
-		"rule-based forwarding enabled, default to %s, logging ",
+		"rule-based forwarding "
+#ifdef IPFIREWALL_FORWARD
+		"enabled, "
+#else
+		"disabled, "
+#endif
+		"default to %s, logging ",
 #ifdef IPDIVERT
 		"enabled",
 #else
@@ -3406,22 +3405,23 @@ ipfw_init(void)
 		printf("limited to %d packets/entry by default\n",
 		    verbose_limit);
 
-	ip_fw_chk_ptr = ipfw_chk;
+	init_tables();
 	ip_fw_ctl_ptr = ipfw_ctl;
+	ip_fw_chk_ptr = ipfw_chk;
 	callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);
 
 	return (0);
 }
 
-static void
+void
 ipfw_destroy(void)
 {
 	struct ip_fw *reap;
 
-	IPFW_LOCK(&layer3_chain);
-	callout_stop(&ipfw_timeout);
 	ip_fw_chk_ptr = NULL;
 	ip_fw_ctl_ptr = NULL;
+	IPFW_LOCK(&layer3_chain);
+	callout_stop(&ipfw_timeout);
 	layer3_chain.reap = NULL;
 	free_chain(&layer3_chain, 1 /* kill default rule */);
 	reap = layer3_chain.reap, layer3_chain.reap = NULL;
@@ -3433,42 +3433,5 @@ ipfw_destroy(void)
 	IPFW_LOCK_DESTROY(&layer3_chain);
 	printf("IP firewall unloaded\n");
 }
-
-static int
-ipfw_modevent(module_t mod, int type, void *unused)
-{
-	int err = 0;
-
-	switch (type) {
-	case MOD_LOAD:
-		if (IPFW_LOADED) {
-			printf("IP firewall already loaded\n");
-			err = EEXIST;
-		} else {
-			err = ipfw_init();
-		}
-		break;
-
-	case MOD_UNLOAD:
-		ipfw_destroy();
-		err = 0;
-		break;
-	default:
-		return EOPNOTSUPP;
-		break;
-	}
-	return err;
-}
-
-static moduledata_t ipfwmod = {
-	"ipfw",
-	ipfw_modevent,
-	0
-};
-DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
-MODULE_VERSION(ipfw, 1);
-
-/* Must be run after route_init(). */
-SYSINIT(ipfw, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, init_tables, 0)
 
 #endif /* IPFW2 */
Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.282
diff -u -p -r1.282 ip_input.c
--- netinet/ip_input.c	14 Aug 2004 15:32:19 -0000	1.282
+++ netinet/ip_input.c	17 Aug 2004 18:23:37 -0000
@@ -32,9 +32,6 @@
 
 #include "opt_bootp.h"
 #include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
 #include "opt_ipstealth.h"
 #include "opt_ipsec.h"
 #include "opt_mac.h"
@@ -72,8 +69,8 @@
 
 #include <sys/socketvar.h>
 
+/* XXX: Temporary until ipfw_ether and ipfw_bridge are converted. */
 #include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
 #include <netinet/ip_dummynet.h>
 
 #ifdef IPSEC
@@ -208,15 +205,14 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, steal
     &ipstealth, 0, "");
 #endif
 
-
-/* Firewall hooks */
-ip_fw_chk_t *ip_fw_chk_ptr;
-int fw_enable = 1 ;
+/*
+ * ipfw_ether and ipfw_bridge hooks.
+ * XXX: Temporary until those are converted to pfil_hooks as well.
+ */
+ip_fw_chk_t *ip_fw_chk_ptr = NULL;
+ip_dn_io_t *ip_dn_io_ptr = NULL;
 int fw_one_pass = 1;
 
-/* Dummynet hooks */
-ip_dn_io_t *ip_dn_io_ptr;
-
 /*
  * XXX this is ugly -- the following two global variables are
  * used to store packet state while it travels through the stack.
@@ -240,12 +236,9 @@ static	struct ip_srcrt {
 } ip_srcrt;
 
 static void	save_rte(u_char *, struct in_addr);
-static int	ip_dooptions(struct mbuf *m, int,
-			struct sockaddr_in *next_hop);
-static void	ip_forward(struct mbuf *m, int srcrt,
-			struct sockaddr_in *next_hop);
+static int	ip_dooptions(struct mbuf *m, int);
+static void	ip_forward(struct mbuf *m, int srcrt);
 static void	ip_freef(struct ipqhead *, struct ipq *);
-static struct	mbuf *ip_reass(struct mbuf *);
 
 /*
  * IP initialization: fill in IP protocol switch table.
@@ -301,13 +294,8 @@ ip_input(struct mbuf *m)
 	struct ip *ip = NULL;
 	struct in_ifaddr *ia = NULL;
 	struct ifaddr *ifa;
-	int    i, checkif, hlen = 0;
+	int    checkif, hlen = 0;
 	u_short sum;
-	struct in_addr pkt_dst;
-#ifdef IPDIVERT
-	u_int32_t divert_info;			/* packet divert/tee info */
-#endif
-	struct ip_fw_args args;
 	int dchg = 0;				/* dest changed after fw */
 #ifdef PFIL_HOOKS
 	struct in_addr odst;			/* original dst address */
@@ -319,26 +307,20 @@ ip_input(struct mbuf *m)
 	int s, error;
 #endif /* FAST_IPSEC */
 
-	args.eh = NULL;
-	args.oif = NULL;
-
   	M_ASSERTPKTHDR(m);
   	
-	args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
-	args.rule = ip_dn_claim_rule(m);
-  
 	if (m->m_flags & M_FASTFWD_OURS) {
-		/* ip_fastforward firewall changed dest to local */
+		/*
+		 * ip_fastforward firewall changed dest to local.
+		 * We expect ip_len and ip_off in host byte order.
+		 */
 		m->m_flags &= ~M_FASTFWD_OURS;	/* for reflected mbufs */
+		/* Set up some basic stuff */
+		ip = mtod(m, struct ip *);
+		hlen = ip->ip_hl << 2;
   		goto ours;
   	}
 
-  	if (args.rule) {	/* dummynet already filtered us */
-  		ip = mtod(m, struct ip *);
-  		hlen = ip->ip_hl << 2;
-		goto iphack ;
-	}
-
 	ipstat.ips_total++;
 
 	if (m->m_pkthdr.len < sizeof(struct ip))
@@ -441,20 +423,6 @@ tooshort:
 		goto pass;
 #endif
 
-	/*
-	 * IpHack's section.
-	 * Right now when no processing on packet has done
-	 * and it is still fresh out of network we do our black
-	 * deals with it.
-	 * - Firewall: deny/allow/divert
-	 * - Xlate: translate packet's addr/port (NAT).
-	 * - Pipe: pass pkt through dummynet.
-	 * - Wrap: fake packet's addr/port <unimpl.>
-	 * - Encapsulate: put it in another IP and send out. <unimp.>
- 	 */
-
-iphack:
-
 #ifdef PFIL_HOOKS
 	/*
 	 * Run through list of hooks for input packets.
@@ -469,50 +437,23 @@ iphack:
 		return;
 	if (m == NULL)			/* consumed by filter */
 		return;
+
 	ip = mtod(m, struct ip *);
 	dchg = (odst.s_addr != ip->ip_dst.s_addr);
-#endif /* PFIL_HOOKS */
 
-	if (fw_enable && IPFW_LOADED) {
-		/*
-		 * If we've been forwarded from the output side, then
-		 * skip the firewall a second time
-		 */
-		if (args.next_hop)
-			goto ours;
+#ifdef IPFIREWALL_FORWARD
+	if (m->m_flags & M_FASTFWD_OURS) {
+		m->m_flags &= ~M_FASTFWD_OURS;
+		goto ours;
+	}
+	dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL);
+#endif /* IPFIREWALL_FORWARD */
 
-		args.m = m;
-		i = ip_fw_chk_ptr(&args);
-		m = args.m;
+#endif /* PFIL_HOOKS */
 
-		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
-			if (m)
-				m_freem(m);
-			return;
-		}
-		ip = mtod(m, struct ip *); /* just in case m changed */
-		if (i == 0 && args.next_hop == NULL)	/* common case */
-			goto pass;
-                if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/* Send packet to the appropriate pipe */
-			ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
-			return;
-		}
-#ifdef IPDIVERT
-		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
-			/* Divert or tee packet */
-			goto ours;
-		}
-#endif
-		if (i == 0 && args.next_hop != NULL)
-			goto pass;
-		/*
-		 * if we get here, the packet must be dropped
-		 */
-		m_freem(m);
-		return;
-	}
+#if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF)
 pass:
+#endif
 
 	/*
 	 * Process options and, if not destined for us,
@@ -520,8 +461,7 @@ pass:
 	 * error was detected (causing an icmp message
 	 * to be sent and the original packet to be freed).
 	 */
-	ip_nhops = 0;		/* for source routed packets */
-	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
+	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0))
 		return;
 
         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
@@ -544,12 +484,6 @@ pass:
 		goto ours;
 
 	/*
-	 * Cache the destination address of the packet; this may be
-	 * changed by use of 'ipfw fwd'.
-	 */
-	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
-
-	/*
 	 * Enable a consistency check between the destination address
 	 * and the arrival interface for a unicast packet (the RFC 1122
 	 * strong ES model) if IP forwarding is disabled and the packet
@@ -566,18 +500,18 @@ pass:
 	checkif = ip_checkinterface && (ipforwarding == 0) && 
 	    m->m_pkthdr.rcvif != NULL &&
 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
-	    (args.next_hop == NULL) && (dchg == 0);
+	    (dchg == 0);
 
 	/*
 	 * Check for exact addresses in the hash bucket.
 	 */
-	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
+	LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
 		/*
 		 * If the address matches, verify that the packet
 		 * arrived via the correct interface if checking is
 		 * enabled.
 		 */
-		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 
+		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr && 
 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
 			goto ours;
 	}
@@ -596,9 +530,9 @@ pass:
 				continue;
 			ia = ifatoia(ifa);
 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
-			    pkt_dst.s_addr)
+			    ip->ip_dst.s_addr)
 				goto ours;
-			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
+			if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr)
 				goto ours;
 #ifdef BOOTP_COMPAT
 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
@@ -706,7 +640,7 @@ pass:
 			goto bad;
 		}
 #endif /* FAST_IPSEC */
-		ip_forward(m, dchg, args.next_hop);
+		ip_forward(m, dchg);
 	}
 	return;
 
@@ -717,7 +651,7 @@ ours:
 	 * if the packet is destined for us.
 	 */
 	if (ipstealth && hlen > sizeof (struct ip) &&
-	    ip_dooptions(m, 1, args.next_hop))
+	    ip_dooptions(m, 1))
 		return;
 #endif /* IPSTEALTH */
 
@@ -738,20 +672,6 @@ ours:
 		ip = mtod(m, struct ip *);
 		/* Get the header length of the reassembled packet */
 		hlen = ip->ip_hl << 2;
-#ifdef IPDIVERT
-		/* Restore original checksum before diverting packet */
-		if (divert_find_info(m) != 0) {
-			ip->ip_len = htons(ip->ip_len);
-			ip->ip_off = htons(ip->ip_off);
-			ip->ip_sum = 0;
-			if (hlen == sizeof(struct ip))
-				ip->ip_sum = in_cksum_hdr(ip);
-			else
-				ip->ip_sum = in_cksum(m, hlen);
-			ip->ip_off = ntohs(ip->ip_off);
-			ip->ip_len = ntohs(ip->ip_len);
-		}
-#endif
 	}
 
 	/*
@@ -760,46 +680,6 @@ ours:
 	 */
 	ip->ip_len -= hlen;
 
-#ifdef IPDIVERT
-	/*
-	 * Divert or tee packet to the divert protocol if required.
-	 */
-	divert_info = divert_find_info(m);
-	if (divert_info != 0) {
-		struct mbuf *clone;
-
-		/* Clone packet if we're doing a 'tee' */
-		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
-			clone = divert_clone(m);
-		else
-			clone = NULL;
-
-		/* Restore packet header fields to original values */
-		ip->ip_len += hlen;
-		ip->ip_len = htons(ip->ip_len);
-		ip->ip_off = htons(ip->ip_off);
-
-		/* Deliver packet to divert input routine */
-		divert_packet(m, 1);
-		ipstat.ips_delivered++;
-
-		/* If 'tee', continue with original packet */
-		if (clone == NULL)
-			return;
-		m = clone;
-		ip = mtod(m, struct ip *);
-		ip->ip_len += hlen;
-		/*
-		 * Jump backwards to complete processing of the
-		 * packet.  We do not need to clear args.next_hop
-		 * as that will not be used again and the cloned packet
-		 * doesn't contain a divert packet tag so we won't
-		 * re-entry this block.
-		 */
-		goto pass;
-	}
-#endif
-
 #ifdef IPSEC
 	/*
 	 * enforce IPsec policy checking if we are seeing last header.
@@ -856,15 +736,7 @@ DPRINTF(("ip_input: no SP, packet discar
 	 * Switch out to protocol's input routine.
 	 */
 	ipstat.ips_delivered++;
-	if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
-		/* attach next hop info for TCP */
-		struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
-		    sizeof(struct sockaddr_in *), M_NOWAIT);
-		if (mtag == NULL)
-			goto bad;
-		*(struct sockaddr_in **)(mtag+1) = args.next_hop;
-		m_tag_prepend(m, mtag);
-	}
+
 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
 	return;
 bad:
@@ -1092,18 +964,6 @@ found:
 
 inserted:
 
-#ifdef IPDIVERT
-	if (ip->ip_off != 0) {
-		/*
-		 * Strip any divert information; only the info
-		 * on the first fragment is used/kept.
-		 */
-		struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
-		if (mtag)
-			m_tag_delete(m, mtag);
-	}
-#endif
-
 	/*
 	 * Check for complete reassembly and perform frag per packet
 	 * limiting.
@@ -1298,7 +1158,7 @@ ip_drain()
  * 0 if the packet should be processed further.
  */
 static int
-ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
+ip_dooptions(struct mbuf *m, int pass)
 {
 	struct ip *ip = mtod(m, struct ip *);
 	u_char *cp;
@@ -1557,7 +1417,7 @@ dropit:
 		}
 	}
 	if (forward && ipforwarding) {
-		ip_forward(m, 1, next_hop);
+		ip_forward(m, 1);
 		return (1);
 	}
 	return (0);
@@ -1737,35 +1597,25 @@ u_char inetctlerrmap[PRC_NCMDS] = {
  * The srcrt parameter indicates whether the packet is being forwarded
  * via a source route.
  */
-static void
-ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
+void
+ip_forward(struct mbuf *m, int srcrt)
 {
 	struct ip *ip = mtod(m, struct ip *);
-	struct in_ifaddr *ia;
+	struct in_ifaddr *ia = NULL;
 	int error, type = 0, code = 0;
 	struct mbuf *mcopy;
-	n_long dest;
-	struct in_addr pkt_dst;
-	struct ifnet *destifp;
-#if defined(IPSEC) || defined(FAST_IPSEC)
-	struct ifnet dummyifp;
-#endif
-
-	/*
-	 * Cache the destination address of the packet; this may be
-	 * changed by use of 'ipfw fwd'.
-	 */
-	pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
+	struct in_addr dest;
+	struct ifnet *destifp, dummyifp;
 
 #ifdef DIAGNOSTIC
 	if (ipprintfs)
 		printf("forward: src %lx dst %lx ttl %x\n",
-		    (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
+		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
 		    ip->ip_ttl);
 #endif
 
 
-	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
+	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
 		ipstat.ips_cantforward++;
 		m_freem(m);
 		return;
@@ -1782,7 +1632,7 @@ ip_forward(struct mbuf *m, int srcrt, st
 	}
 #endif
 
-	if ((ia = ip_rtaddr(pkt_dst)) == NULL) {
+	if (!srcrt && (ia = ip_rtaddr(ip->ip_dst)) == NULL) {
 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
 		return;
 	}
@@ -1837,8 +1687,8 @@ ip_forward(struct mbuf *m, int srcrt, st
 	 * Also, don't send redirect if forwarding using a default route
 	 * or a route modified by a redirect.
 	 */
-	dest = 0;
-	if (ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
+	dest.s_addr = 0;
+	if (!srcrt && ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
 		struct sockaddr_in *sin;
 		struct route ro;
 		struct rtentry *rt;
@@ -1847,29 +1697,28 @@ ip_forward(struct mbuf *m, int srcrt, st
 		sin = (struct sockaddr_in *)&ro.ro_dst;
 		sin->sin_family = AF_INET;
 		sin->sin_len = sizeof(*sin);
-		sin->sin_addr = pkt_dst;
+		sin->sin_addr = ip->ip_dst;
 		rtalloc_ign(&ro, RTF_CLONING);
 
 		rt = ro.ro_rt;
 
 		if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
-		    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
-		    ipsendredirects && !srcrt && !next_hop) {
+		    satosin(rt_key(rt))->sin_addr.s_addr != 0) {
 #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
 			u_long src = ntohl(ip->ip_src.s_addr);
 
 			if (RTA(rt) &&
 			    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
 				if (rt->rt_flags & RTF_GATEWAY)
-					dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
+					dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
 				else
-					dest = pkt_dst.s_addr;
+					dest.s_addr = ip->ip_dst.s_addr;
 				/* Router requirements says to only send host redirects */
 				type = ICMP_REDIRECT;
 				code = ICMP_REDIRECT_HOST;
 #ifdef DIAGNOSTIC
 				if (ipprintfs)
-					printf("redirect (%d) to %lx\n", code, (u_long)dest);
+					printf("redirect (%d) to %lx\n", code, (u_long)dest.s_addr);
 #endif
 			}
 		}
@@ -1877,16 +1726,6 @@ ip_forward(struct mbuf *m, int srcrt, st
 			RTFREE(rt);
 	}
 
-	if (next_hop) {
-		struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD,
-		    sizeof(struct sockaddr_in *), M_NOWAIT);
-		if (mtag == NULL) {
-			m_freem(m);
-			return;
-		}
-		*(struct sockaddr_in **)(mtag+1) = next_hop;
-		m_tag_prepend(m, mtag);
-	}
 	error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL);
 	if (error)
 		ipstat.ips_cantforward++;
@@ -1985,7 +1824,16 @@ ip_forward(struct mbuf *m, int srcrt, st
 				break;
 			} else 
 #endif /*IPSEC || FAST_IPSEC*/
-		destifp = ia->ia_ifp;
+		/*
+		 * When doing source routing 'ia' can be NULL.  Fall back
+		 * to the minimum guaranteed routeable packet size and use
+		 * the same hack as IPSEC to setup a dummyifp for icmp.
+		 */
+		if (ia == NULL) {
+			dummyifp.if_mtu = IP_MSS;
+			destifp = &dummyifp;
+		} else
+			destifp = ia->ia_ifp;
 #if defined(IPSEC) || defined(FAST_IPSEC)
 		}
 #endif /*IPSEC || FAST_IPSEC*/
@@ -2014,7 +1862,7 @@ ip_forward(struct mbuf *m, int srcrt, st
 		m_freem(mcopy);
 		return;
 	}
-	icmp_error(mcopy, type, code, dest, destifp);
+	icmp_error(mcopy, type, code, dest.s_addr, destifp);
 }
 
 void
Index: netinet/ip_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.224
diff -u -p -r1.224 ip_output.c
--- netinet/ip_output.c	14 Aug 2004 15:32:19 -0000	1.224
+++ netinet/ip_output.c	17 Aug 2004 18:23:37 -0000
@@ -31,9 +31,6 @@
  */
 
 #include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#include "opt_ipdivert.h"
-#include "opt_ipfilter.h"
 #include "opt_ipsec.h"
 #include "opt_mac.h"
 #include "opt_pfil_hooks.h"
@@ -51,6 +48,7 @@
 #include <sys/sysctl.h>
 
 #include <net/if.h>
+#include <net/netisr.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -84,10 +82,6 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_mopt
 #include <netipsec/key.h>
 #endif /*FAST_IPSEC*/
 
-#include <netinet/ip_fw.h>
-#include <netinet/ip_divert.h>
-#include <netinet/ip_dummynet.h>
-
 #define print_ip(x, a, y)	 printf("%s %d.%d.%d.%d%s",\
 				x, (ntohl(a.s_addr)>>24)&0xFF,\
 				  (ntohl(a.s_addr)>>16)&0xFF,\
@@ -133,49 +127,27 @@ ip_output(struct mbuf *m, struct mbuf *o
 	struct ifnet *ifp = NULL;	/* keep compiler happy */
 	struct mbuf *m0;
 	int hlen = sizeof (struct ip);
-	int len, off, error = 0;
+	int len, error = 0;
 	struct sockaddr_in *dst = NULL;	/* keep compiler happy */
 	struct in_ifaddr *ia = NULL;
 	int isbroadcast, sw_csum;
-	struct in_addr pkt_dst;
 	struct route iproute;
-	struct m_tag *mtag, *dummytag;
+	struct in_addr odst;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag = NULL;
+#endif
 #ifdef IPSEC
 	struct secpolicy *sp = NULL;
 #endif
 #ifdef FAST_IPSEC
 	struct secpolicy *sp = NULL;
 	struct tdb_ident *tdbi;
+	struct m_tag *mtag;
 	int s;
 #endif /* FAST_IPSEC */
-	struct ip_fw_args args;
-	int src_was_INADDR_ANY = 0;	/* as the name says... */
-
-	args.eh = NULL;
-	args.rule = NULL;
 
 	M_ASSERTPKTHDR(m);
 	
-	args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
-	dummytag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
-	if (dummytag != NULL) {
-		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
-		/*
-		 * Prevent lower layers from finding the tag
-		 * Cleanup and free is done below
-		 */
-		m_tag_unlink(m, dummytag);
-		/*
-		 * the packet was already tagged, so part of the
-		 * processing was already done, and we need to go down.
-		 * Get parameters from the header.
-		 */
-		args.rule = dt->rule;
-		ro = &(dt->ro);
-		dst = dt->dn_dst;
-		ifp = dt->ifp;
-	}
-
 	if (ro == NULL) {
 		ro = &iproute;
 		bzero(ro, sizeof (*ro));
@@ -184,14 +156,6 @@ ip_output(struct mbuf *m, struct mbuf *o
 	if (inp != NULL)
 		INP_LOCK_ASSERT(inp);
 
-	if (args.rule != NULL) {	/* dummynet already saw us */
-		ip = mtod(m, struct ip *);
-		hlen = ip->ip_hl << 2 ;
-		if (ro->ro_rt)
-			ia = ifatoia(ro->ro_rt->rt_ifa);
-		goto sendit;
-	}
-
 	if (opt) {
 		len = 0;
 		m = ip_insertoptions(m, opt, &len);
@@ -199,7 +163,6 @@ ip_output(struct mbuf *m, struct mbuf *o
 			hlen = len;
 	}
 	ip = mtod(m, struct ip *);
-	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
 
 	/*
 	 * Fill in IP header.  If we are not allowing fragmentation,
@@ -222,6 +185,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 	}
 
 	dst = (struct sockaddr_in *)&ro->ro_dst;
+again:
 	/*
 	 * If there is a cached route,
 	 * check that it is to the same destination
@@ -231,15 +195,19 @@ ip_output(struct mbuf *m, struct mbuf *o
 	 */
 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
 			  dst->sin_family != AF_INET ||
-			  dst->sin_addr.s_addr != pkt_dst.s_addr)) {
+			  dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
 		RTFREE(ro->ro_rt);
 		ro->ro_rt = (struct rtentry *)0;
 	}
+#ifdef IPFIREWALL_FORWARD
+	if (ro->ro_rt == NULL && fwd_tag == NULL) {
+#else
 	if (ro->ro_rt == NULL) {
+#endif
 		bzero(dst, sizeof(*dst));
 		dst->sin_family = AF_INET;
 		dst->sin_len = sizeof(*dst);
-		dst->sin_addr = pkt_dst;
+		dst->sin_addr = ip->ip_dst;
 	}
 	/*
 	 * If routing to interface only,
@@ -287,7 +255,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 		else
 			isbroadcast = in_broadcast(dst->sin_addr, ifp);
 	}
-	if (IN_MULTICAST(ntohl(pkt_dst.s_addr))) {
+	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
 		struct in_multi *inm;
 
 		m->m_flags |= M_MCAST;
@@ -329,7 +297,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 				ip->ip_src = IA_SIN(ia)->sin_addr;
 		}
 
-		IN_LOOKUP_MULTI(pkt_dst, ifp, inm);
+		IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
 		if (inm != NULL &&
 		   (imo == NULL || imo->imo_multicast_loop)) {
 			/*
@@ -395,7 +363,6 @@ ip_output(struct mbuf *m, struct mbuf *o
 		/* Interface may have no addresses. */
 		if (ia != NULL) {
 			ip->ip_src = IA_SIN(ia)->sin_addr;
-			src_was_INADDR_ANY = 1;
 		}
 	}
 #endif /* notdef */
@@ -693,250 +660,75 @@ skip_ipsec:
 spd_done:
 #endif /* FAST_IPSEC */
 
-	/*
-	 * IpHack's section.
-	 * - Xlate: translate packet's addr/port (NAT).
-	 * - Firewall: deny/allow/etc.
-	 * - Wrap: fake packet's addr/port <unimpl.>
-	 * - Encapsulate: put it in another IP and send out. <unimp.>
-	 */ 
 #ifdef PFIL_HOOKS
 	/*
 	 * Run through list of hooks for output packets.
 	 */
+	odst.s_addr = ip->ip_dst.s_addr;
 	error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT);
 	if (error != 0 || m == NULL)
 		goto done;
+
 	ip = mtod(m, struct ip *);
-#endif /* PFIL_HOOKS */
 
-	/*
-	 * Check with the firewall...
-	 * but not if we are already being fwd'd from a firewall.
-	 */
-	if (fw_enable && IPFW_LOADED && !args.next_hop) {
-		struct sockaddr_in *old = dst;
+	/* See if destination IP address was changed by packet filter. */
+	if (odst.s_addr != ip->ip_dst.s_addr) {
+		m->m_flags |= M_SKIP_FIREWALL;
+		if (in_localip(ip->ip_dst)) {
+			m->m_flags |= M_FASTFWD_OURS;
+			if (m->m_pkthdr.rcvif == NULL)
+				m->m_pkthdr.rcvif = ifunit("lo0");
+			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+				m->m_pkthdr.csum_flags |=
+				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+				m->m_pkthdr.csum_data = 0xffff;
+			}
+			m->m_pkthdr.csum_flags |=
+			    CSUM_IP_CHECKED | CSUM_IP_VALID;
 
-		args.m = m;
-		args.next_hop = dst;
-		args.oif = ifp;
-		off = ip_fw_chk_ptr(&args);
-		m = args.m;
-		dst = args.next_hop;
-
-                /*
-		 * On return we must do the following:
-		 * m == NULL	-> drop the pkt (old interface, deprecated)
-		 * (off & IP_FW_PORT_DENY_FLAG)	-> drop the pkt (new interface)
-		 * 1<=off<= 0xffff		-> DIVERT
-		 * (off & IP_FW_PORT_DYNT_FLAG)	-> send to a DUMMYNET pipe
-		 * (off & IP_FW_PORT_TEE_FLAG)	-> TEE the packet
-		 * dst != old			-> IPFIREWALL_FORWARD
-		 * off==0, dst==old		-> accept
-		 * If some of the above modules are not compiled in, then
-		 * we should't have to check the corresponding condition
-		 * (because the ipfw control socket should not accept
-		 * unsupported rules), but better play safe and drop
-		 * packets in case of doubt.
-		 */
-		if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
-			if (m)
-				m_freem(m);
-			error = EACCES;
+			error = netisr_queue(NETISR_IP, m);
 			goto done;
-		}
-		ip = mtod(m, struct ip *);
-		if (off == 0 && dst == old)		/* common case */
-			goto pass;
-                if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {
-			/*
-			 * pass the pkt to dummynet. Need to include
-			 * pipe number, m, ifp, ro, dst because these are
-			 * not recomputed in the next pass.
-			 * All other parameters have been already used and
-			 * so they are not needed anymore. 
-			 * XXX note: if the ifp or ro entry are deleted
-			 * while a pkt is in dummynet, we are in trouble!
-			 */ 
-			args.ro = ro;
-			args.dst = dst;
-			args.flags = flags;
+		} else
+			goto again;
+	}
 
-			error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
-				&args);
-			goto done;
+#ifdef IPFIREWALL_FORWARD
+	/* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */
+	if (m->m_flags & M_FASTFWD_OURS) {
+		if (m->m_pkthdr.rcvif == NULL)
+			m->m_pkthdr.rcvif = ifunit("lo0");
+		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+			m->m_pkthdr.csum_flags |=
+			    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+			m->m_pkthdr.csum_data = 0xffff;
 		}
-#ifdef IPDIVERT
-		if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
-			struct mbuf *clone;
-
-			/* Clone packet if we're doing a 'tee' */
-			if ((off & IP_FW_PORT_TEE_FLAG) != 0)
-				clone = divert_clone(m);
-			else
-				clone = NULL;
-
-			/* Restore packet header fields to original values */
-			ip->ip_len = htons(ip->ip_len);
-			ip->ip_off = htons(ip->ip_off);
-
-			/* Deliver packet to divert input routine */
-			divert_packet(m, 0);
-
-			/* If 'tee', continue with original packet */
-			if (clone != NULL) {
-				m = clone;
-				ip = mtod(m, struct ip *);
-				goto pass;
-			}
-			goto done;
+		m->m_pkthdr.csum_flags |=
+			    CSUM_IP_CHECKED | CSUM_IP_VALID;
+
+		error = netisr_queue(NETISR_IP, m);
+		goto done;
+	}
+	/* Or forward to some other address? */
+	fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+	if (fwd_tag) {
+		if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst)) {
+			dst = (struct sockaddr_in *)&ro->ro_dst;
+			bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
+			m->m_flags |= M_SKIP_FIREWALL;
+			m_tag_delete(m, fwd_tag);
+			goto again;
+		} else {
+			m_tag_delete(m, fwd_tag);
+			/* Continue. */
 		}
+	}
 #endif
 
-		/* IPFIREWALL_FORWARD */
-		/*
-		 * Check dst to make sure it is directly reachable on the
-		 * interface we previously thought it was.
-		 * If it isn't (which may be likely in some situations) we have
-		 * to re-route it (ie, find a route for the next-hop and the
-		 * associated interface) and set them here. This is nested
-		 * forwarding which in most cases is undesirable, except where
-		 * such control is nigh impossible. So we do it here.
-		 * And I'm babbling.
-		 */
-		if (off == 0 && old != dst) { /* FORWARD, dst has changed */
-#if 0
-			/*
-			 * XXX To improve readability, this block should be
-			 * changed into a function call as below:
-			 */
-			error = ip_ipforward(&m, &dst, &ifp);
-			if (error)
-				goto bad;
-			if (m == NULL) /* ip_input consumed the mbuf */
-				goto done;
-#else
-			struct in_ifaddr *ia;
-
-			/*
-			 * XXX sro_fwd below is static, and a pointer
-			 * to it gets passed to routines downstream.
-			 * This could have surprisingly bad results in
-			 * practice, because its content is overwritten
-			 * by subsequent packets.
-			 * XXX: Breaks on SMP and possibly preemption!
-			 */
-			/* There must be a better way to do this next line... */
-			static struct route sro_fwd;
-			struct route *ro_fwd = &sro_fwd;
+#endif /* PFIL_HOOKS */
 
 #if 0
-			print_ip("IPFIREWALL_FORWARD: New dst ip: ",
-			    dst->sin_addr, "\n");
-#endif
-
-			/*
-			 * We need to figure out if we have been forwarded
-			 * to a local socket. If so, then we should somehow 
-			 * "loop back" to ip_input, and get directed to the
-			 * PCB as if we had received this packet. This is
-			 * because it may be dificult to identify the packets
-			 * you want to forward until they are being output
-			 * and have selected an interface. (e.g. locally
-			 * initiated packets) If we used the loopback inteface,
-			 * we would not be able to control what happens 
-			 * as the packet runs through ip_input() as
-			 * it is done through an ISR.
-			 */
-			LIST_FOREACH(ia,
-			    INADDR_HASH(dst->sin_addr.s_addr), ia_hash) {
-				/*
-				 * If the addr to forward to is one
-				 * of ours, we pretend to
-				 * be the destination for this packet.
-				 */
-				if (IA_SIN(ia)->sin_addr.s_addr ==
-						 dst->sin_addr.s_addr)
-					break;
-			}
-			if (ia) {	/* tell ip_input "dont filter" */
-				mtag = m_tag_get(
-				    PACKET_TAG_IPFORWARD,
-				    sizeof(struct sockaddr_in *), M_NOWAIT);
-				if (mtag == NULL) {
-					error = ENOBUFS;
-					goto bad;
-				}
-				*(struct sockaddr_in **)(mtag+1) =
-				    args.next_hop;
-				m_tag_prepend(m, mtag);
-
-				if (m->m_pkthdr.rcvif == NULL)
-					m->m_pkthdr.rcvif = ifunit("lo0");
-				if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
-					m->m_pkthdr.csum_flags |=
-					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-					m->m_pkthdr.csum_data = 0xffff;
-				}
-				m->m_pkthdr.csum_flags |=
-				    CSUM_IP_CHECKED | CSUM_IP_VALID;
-				ip->ip_len = htons(ip->ip_len);
-				ip->ip_off = htons(ip->ip_off);
-				ip_input(m);
-				goto done;
-			}
-			/*
-			 * Some of the logic for this was
-			 * nicked from above.
-			 */
-			bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
-
-			ro_fwd->ro_rt = 0;
-			rtalloc_ign(ro_fwd, RTF_CLONING);
-
-			if (ro_fwd->ro_rt == NULL) {
-				ipstat.ips_noroute++;
-				error = EHOSTUNREACH;
-				goto bad;
-			}
-
-			ia = ifatoia(ro_fwd->ro_rt->rt_ifa);
-			ifp = ro_fwd->ro_rt->rt_ifp;
-			ro_fwd->ro_rt->rt_rmx.rmx_pksent++;
-			if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
-				dst = (struct sockaddr_in *)
-					ro_fwd->ro_rt->rt_gateway;
-			if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
-				isbroadcast =
-				    (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
-			else
-				isbroadcast = in_broadcast(dst->sin_addr, ifp);
-			if (ro->ro_rt)
-				RTFREE(ro->ro_rt);
-			ro->ro_rt = ro_fwd->ro_rt;
-			dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
-
-#endif	/* ... block to be put into a function */
-			/*
-			 * If we added a default src ip earlier,
-			 * which would have been gotten from the-then
-			 * interface, do it again, from the new one.
-			 */
-			if (src_was_INADDR_ANY)
-				ip->ip_src = IA_SIN(ia)->sin_addr;
-			goto pass ;
-		}
-
-                /*
-                 * if we get here, none of the above matches, and 
-                 * we have to drop the pkt
-                 */
-		m_freem(m);
-                error = EACCES; /* not sure this is the right error msg */
-                goto done;
-	}
-
 pass:
+#endif
 	/* 127/8 must not appear on wire - RFC1122. */
 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
@@ -1037,13 +829,6 @@ pass:
 done:
 	if (ro == &iproute && ro->ro_rt) {
 		RTFREE(ro->ro_rt);
-		ro->ro_rt = NULL;
-	}
-	if (dummytag) {
-		struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
-		if (dt->ro.ro_rt)
-			RTFREE(dt->ro.ro_rt);
-		m_tag_free(dummytag);
 	}
 #ifdef IPSEC
 	if (sp != NULL) {
Index: netinet/ip_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.88
diff -u -p -r1.88 ip_var.h
--- netinet/ip_var.h	14 Aug 2004 15:32:19 -0000	1.88
+++ netinet/ip_var.h	17 Aug 2004 18:23:37 -0000
@@ -168,6 +168,8 @@ extern int	 (*ip_mforward)(struct ip *, 
 int	 ip_output(struct mbuf *,
 	    struct mbuf *, struct route *, int, struct ip_moptions *,
 	    struct inpcb *);
+struct mbuf *
+	 ip_reass(struct mbuf *);
 struct in_ifaddr *
 	 ip_rtaddr(struct in_addr);
 void	 ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
Index: netinet/raw_ip.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.141
diff -u -p -r1.141 raw_ip.c
--- netinet/raw_ip.c	16 Aug 2004 18:32:07 -0000	1.141
+++ netinet/raw_ip.c	17 Aug 2004 18:23:37 -0000
@@ -78,8 +78,8 @@ struct	inpcbhead ripcb;
 struct	inpcbinfo ripcbinfo;
 
 /* control hooks for ipfw and dummynet */
-ip_fw_ctl_t *ip_fw_ctl_ptr;
-ip_dn_ctl_t *ip_dn_ctl_ptr;
+ip_fw_ctl_t *ip_fw_ctl_ptr = NULL;
+ip_dn_ctl_t *ip_dn_ctl_ptr = NULL;
 
 /*
  * hooks for multicast routing. They all default to NULL,
@@ -358,14 +358,14 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_FW_GET:
 		case IP_FW_TABLE_GETSIZE:
 		case IP_FW_TABLE_LIST:
-			if (IPFW_LOADED)
+			if (ip_fw_ctl_ptr != NULL)
 				error = ip_fw_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
 			break;
 
 		case IP_DUMMYNET_GET:
-			if (DUMMYNET_LOADED)
+			if (ip_dn_ctl_ptr != NULL)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
@@ -414,7 +414,7 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_FW_TABLE_ADD:
 		case IP_FW_TABLE_DEL:
 		case IP_FW_TABLE_FLUSH:
-			if (IPFW_LOADED)
+			if (ip_fw_ctl_ptr != NULL)
 				error = ip_fw_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
@@ -423,7 +423,7 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_DUMMYNET_CONFIGURE:
 		case IP_DUMMYNET_DEL:
 		case IP_DUMMYNET_FLUSH:
-			if (DUMMYNET_LOADED)
+			if (ip_dn_ctl_ptr != NULL)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT ;
Index: netinet/tcp_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.251
diff -u -p -r1.251 tcp_input.c
--- netinet/tcp_input.c	16 Aug 2004 18:32:07 -0000	1.251
+++ netinet/tcp_input.c	17 Aug 2004 18:23:38 -0000
@@ -429,7 +429,9 @@ tcp_input(m, off0)
 	struct tcpopt to;		/* options in this segment */
 	struct rmxp_tao tao;		/* our TAO cache entry */
 	int headlocked = 0;
-	struct sockaddr_in *next_hop = NULL;
+#ifdef IPFIREWALL_FORWARD
+	struct m_tag *fwd_tag;
+#endif
 	int rstreason; /* For badport_bandlim accounting purposes */
 
 	struct ip6_hdr *ip6 = NULL;
@@ -449,8 +451,6 @@ tcp_input(m, off0)
 	short ostate = 0;
 #endif
 
-	/* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
-	next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD);
 #ifdef INET6
 	isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
 #endif
@@ -611,17 +611,24 @@ tcp_input(m, off0)
 	INP_INFO_WLOCK(&tcbinfo);
 	headlocked = 1;
 findpcb:
-	/* IPFIREWALL_FORWARD section */
-	if (next_hop != NULL && isipv6 == 0) {	/* IPv6 support is not yet */
+#ifdef IPFIREWALL_FORWARD
+	/* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
+	fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+
+	if (fwd_tag != NULL && isipv6 == 0) {	/* IPv6 support is not yet */
+		struct sockaddr_in *next_hop;
+
+		next_hop = (struct sockaddr_in *)(fwd_tag+1);
 		/*
 		 * Transparently forwarded. Pretend to be the destination.
 		 * already got one like this?
 		 */
-		inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
+		inp = in_pcblookup_hash(&tcbinfo,
+					ip->ip_src, th->th_sport,
 					ip->ip_dst, th->th_dport,
 					0, m->m_pkthdr.rcvif);
 		if (!inp) {
-			/* It's new.  Try find the ambushing socket. */
+			/* It's new.  Try to find the ambushing socket. */
 			inp = in_pcblookup_hash(&tcbinfo,
 						ip->ip_src, th->th_sport,
 						next_hop->sin_addr,
@@ -630,7 +637,10 @@ findpcb:
 						    th->th_dport,
 						1, m->m_pkthdr.rcvif);
 		}
+		/* Remove the tag from the packet.  We don't need it anymore. */
+		m_tag_delete(m, fwd_tag);
 	} else {
+#endif /* IPFIREWALL_FORWARD */
 		if (isipv6) {
 #ifdef INET6
 			inp = in6_pcblookup_hash(&tcbinfo,
@@ -643,7 +653,9 @@ findpcb:
 						ip->ip_src, th->th_sport,
 						ip->ip_dst, th->th_dport,
 						1, m->m_pkthdr.rcvif);
+#ifdef IPFIREWALL_FORWARD
 	}
+#endif /* IPFIREWALL_FORWARD */
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
 #ifdef INET6
Index: netinet/tcp_sack.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_sack.c,v
retrieving revision 1.2
diff -u -p -r1.2 tcp_sack.c
--- netinet/tcp_sack.c	16 Aug 2004 18:32:07 -0000	1.2
+++ netinet/tcp_sack.c	17 Aug 2004 18:23:38 -0000
@@ -96,7 +96,6 @@
  * official policies, either expressed or implied, of the US Naval
  * Research Laboratory (NRL).
  */
-#include "opt_ipfw.h"		/* for ipfw_fwd		*/
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
Index: sys/mbuf.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/mbuf.h,v
retrieving revision 1.156
diff -u -p -r1.156 mbuf.h
--- sys/mbuf.h	2 Aug 2004 00:18:35 -0000	1.156
+++ sys/mbuf.h	17 Aug 2004 18:23:38 -0000
@@ -737,21 +737,6 @@ m_tag_find(struct mbuf *m, int type, str
 	    NULL : m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
 }
 
-/*
- * Obtain next_hop information associated with the mbuf, if any.
- * If a tag is present devalidate it also.
- */
-static __inline struct sockaddr_in *
-m_claim_next(struct mbuf *m, int type)
-{
-	struct m_tag *mtag = m_tag_find(m, type, NULL);
-	if (mtag) {
-		struct sockaddr_in *sin = *(struct sockaddr_in **)(mtag + 1);
-		mtag->m_tag_id = PACKET_TAG_NONE;
-		return (sin);
-	}
-	return (NULL);
-}
 #endif /* _KERNEL */
 
 #endif /* !_SYS_MBUF_H_ */
/*
 * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
 * 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: $
 */

#if !defined(KLD_MODULE)
#include "opt_ipfw.h"
#include "opt_ipdn.h"
#include "opt_ipdivert.h"
#include "opt_inet.h"
#ifndef INET
#error IPFIREWALL requires INET.
#endif /* INET */
#endif

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/ucred.h>

#include <net/if.h>
#include <net/route.h>
#include <net/pfil.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_fw.h>
#include <netinet/ip_divert.h>
#include <netinet/ip_dummynet.h>

#include <machine/in_cksum.h>

static	int ipfw_pfil_hooked = 0;

/* Dummynet hooks. */
ip_dn_ruledel_t	*ip_dn_ruledel_ptr = NULL;

#define	DIV_DIR_IN	1
#define	DIV_DIR_OUT	0

static int	ipfw_divert(struct mbuf **, int, int);

int
ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
{
	struct ip_fw_args args;
	struct m_tag *dn_tag;
	int ipfw = 0;
	int divert;
#ifdef IPFIREWALL_FORWARD
	struct m_tag *fwd_tag;
#endif

	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));

	bzero(&args, sizeof(args));

	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
	if (dn_tag != NULL){
		struct dn_pkt_tag *dt;

		dt = (struct dn_pkt_tag *)(dn_tag+1);
		args.rule = dt->rule;

		m_tag_delete(*m0, dn_tag);
	}

	args.m = *m0;
	ipfw = ipfw_chk(&args);
	*m0 = args.m;

	if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
		goto drop;

	if (ipfw == 0 && args.next_hop == NULL)
		goto pass;

	if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
		ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
		*m0 = NULL;
		return 0;		/* packet consumed */
	}

	if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
		if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
			divert = ipfw_divert(m0, DIV_DIR_IN, 1);
		else
			divert = ipfw_divert(m0, DIV_DIR_IN, 0);

		/* tee should continue again with the firewall. */
		if (divert) {
			*m0 = NULL;
			return 0;	/* packet consumed */
		} else
			goto pass;	/* continue with packet */
	}

#ifdef IPFIREWALL_FORWARD
	if (ipfw == 0 && args.next_hop != NULL) {
		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
				sizeof(struct sockaddr_in), M_NOWAIT);
		if (fwd_tag == NULL)
			goto drop;
		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
		m_tag_prepend(*m0, fwd_tag);

		if (in_localip(args.next_hop->sin_addr))
			(*m0)->m_flags |= M_FASTFWD_OURS;
		goto pass;
	}
#endif

drop:
	if (*m0)
		m_freem(*m0);
	*m0 = NULL;
	return (EACCES);
pass:
	return 0;	/* not filtered */
}

int
ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
{
	struct ip_fw_args args;
	struct m_tag *dn_tag;
	int ipfw = 0;
	int divert;
#ifdef IPFIREWALL_FORWARD
	struct m_tag *fwd_tag;
#endif

	KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));

	bzero(&args, sizeof(args));

	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
	if (dn_tag != NULL) {
		struct dn_pkt_tag *dt;

		dt = (struct dn_pkt_tag *)(dn_tag+1);
		args.rule = dt->rule;

		m_tag_delete(*m0, dn_tag);
	}

	args.m = *m0;
	args.oif = ifp;
	ipfw = ipfw_chk(&args);
	*m0 = args.m;

	if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
		goto drop;

	if (ipfw == 0 && args.next_hop == NULL)
		goto pass;

	if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
		ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args);
		*m0 = NULL;
		return 0;		/* packet consumed */
	}

	if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
		if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
			divert = ipfw_divert(m0, DIV_DIR_OUT, 1);
		else
			divert = ipfw_divert(m0, DIV_DIR_OUT, 0);

		if (divert) {
			*m0 = NULL;
			return 0;	/* packet consumed */
		} else
			goto pass;	/* continue with packet */
        }

#ifdef IPFIREWALL_FORWARD
	if (ipfw == 0 && args.next_hop != NULL) {
		/* Overwrite existing tag. */
		fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
		if (fwd_tag == NULL)
			fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
				sizeof(struct sockaddr_in), M_NOWAIT);
		if (fwd_tag == NULL)
			goto drop;
		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
		m_tag_prepend(*m0, fwd_tag);

		if (in_localip(args.next_hop->sin_addr))
			(*m0)->m_flags |= M_FASTFWD_OURS;
		goto pass;
	}
#endif

drop:
	if (*m0)
		m_freem(*m0);
	*m0 = NULL;
	return (EACCES);
pass:
	return 0;	/* not filtered */
}

static int
ipfw_divert(struct mbuf **m, int incoming, int tee)
{
	/*
	 * ipfw_chk() has already tagged the packet with the divert
	 * tag.  For tee we need to remove the tag.
	 * If tee is set, copy packet and return original.
	 * If not tee, consume packet and send it to divert socket.
	 */
#ifdef IPDIVERT
	struct mbuf *clone, *reass;
	struct m_tag *mtag;
	struct ip *ip;
	int hlen;

	reass = NULL;

	/* Cloning needed for tee? */
	if (tee)
		clone = m_dup(*m, M_DONTWAIT);
	else
		clone = *m;

	/* In case m_dup was unable to allocate mbufs. */
	if (clone == NULL)
		goto teeout;

	/*
	 * Divert listeners can only handle non-fragmented packets.
	 * However when tee is set we will *not* de-fragment the packets;
	 * Doing do would put the reassembly into double-jeopardy.  On top
	 * of that someone doing a tee will probably want to get the packet
	 * in its original form.
	 */
	ip = mtod(clone, struct ip *);
	if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {

		/* Reassemble packet. */
		reass = ip_reass(clone);

		/*
		 * IP header checksum fixup after reassembly and leave header
		 * in network byte order.
		 */
		if (reass != NULL) {
			ip = mtod(reass, struct ip *);
			hlen = ip->ip_hl << 2;
			ip->ip_len = htons(ip->ip_len);
			ip->ip_off = htons(ip->ip_off);
			ip->ip_sum = 0;
			if (hlen == sizeof(struct ip))
				ip->ip_sum = in_cksum_hdr(ip);
			else
				ip->ip_sum = in_cksum(reass, hlen);
			clone = reass;
		} else
			clone = NULL;
	} else {
		/* Convert header to network byte order. */
		ip->ip_len = htons(ip->ip_len);
		ip->ip_off = htons(ip->ip_off);
	}

	/* Do the dirty job... */
	if (clone)
		divert_packet(clone, incoming);

teeout:
	if (tee) {
		mtag = m_tag_find(*m, PACKET_TAG_DIVERT, NULL);
		if (mtag != NULL)
			m_tag_delete(*m, mtag);
		return 0;	/* continue with original packet. */
	}

	/* Packet diverted and consumed */
	return 1;
#else
	m_freem(*m);
	return 1;
#endif	/* ipdivert */
}

static int
ipfw_hook(void)
{
	struct pfil_head *pfh_inet;

	if (ipfw_pfil_hooked)
		return EEXIST;

	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
	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);

	return 0;
}

static int
ipfw_unhook(void)
{
	struct pfil_head *pfh_inet;

	if (!ipfw_pfil_hooked)
		return ENOENT;

	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
	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);

	return 0;
}

static int
ipfw_modevent(module_t mod, int type, void *unused)
{
	int err = 0;

	switch (type) {
	case MOD_LOAD:
		if (ipfw_pfil_hooked) {
			printf("IP firewall already loaded\n");
			err = EEXIST;
		} else {
			if ((err = ipfw_init()) != 0) {
				printf("ipfw_init() error\n");
				break;
			}
			if ((err = ipfw_hook()) != 0) {
				printf("ipfw_hook() error\n");
				break;
			}
			ipfw_pfil_hooked = 1;
		}
		break;

	case MOD_UNLOAD:
		if (ipfw_pfil_hooked) {
			if ((err = ipfw_unhook()) > 0);
				break;
			ipfw_destroy();
			ipfw_pfil_hooked = 0;
		} else {
			printf("IP firewall already unloaded\n");
		}
		break;

	default:
		return EOPNOTSUPP;
		break;
	}
	return err;
}

static moduledata_t ipfwmod = {
	"ipfw",
	ipfw_modevent,
	0
};
DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
MODULE_VERSION(ipfw, 2);
