Index: conf/files
===================================================================
RCS file: /home/ncvs/src/sys/conf/files,v
retrieving revision 1.893
diff -u -p -r1.893 files
--- conf/files	3 May 2004 21:18:56 -0000	1.893
+++ conf/files	10 May 2004 20:17:04 -0000
@@ -1436,9 +1436,11 @@ 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
+netinet/ip_options.c	optional inet
 netinet/ip_output.c	optional inet
 netinet/raw_ip.c	optional inet
 netinet/tcp_debug.c	optional tcpdebug
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	10 May 2004 20:17:11 -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: net/bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/net/bridge.c,v
retrieving revision 1.77
diff -u -p -r1.77 bridge.c
--- net/bridge.c	24 Apr 2004 22:11:13 -0000	1.77
+++ net/bridge.c	10 May 2004 20:17:14 -0000
@@ -961,16 +961,14 @@ bdg_forward(struct mbuf *m0, struct ifne
      * Additional restrictions may apply e.g. non-IP, short packets,
      * and pkts already gone through a pipe.
      */
-    if (src != NULL && (
+    if ((src != NULL) &&
 #ifdef PFIL_HOOKS
 	(inet_pfil_hook.ph_busy_count >= 0 && bdg_ipf != 0) ||
 #endif
-	(IPFW_LOADED && bdg_ipfw != 0))) {
+	(1 == 0)) {
 
 	int i;
 
-	if (args.rule != NULL && fw_one_pass)
-	    goto forward; /* packet already partially processed */
 	/*
 	 * i need some amt of data to be contiguous, and in case others need
 	 * the packet (shared==1) also better be in the first mbuf.
@@ -985,7 +983,6 @@ bdg_forward(struct mbuf *m0, struct ifne
 	    }
 	    eh = mtod(m0, struct ether_header *);
 	}
-
 	/*
 	 * Processing below expects the Ethernet header is stripped.
 	 * Furthermore, the mbuf chain might be replaced at various
@@ -1029,54 +1026,6 @@ bdg_forward(struct mbuf *m0, struct ifne
 #endif /* PFIL_HOOKS */
 
 	/*
-	 * Prepare arguments and call the firewall.
-	 */
-	if (!IPFW_LOADED || bdg_ipfw == 0) {
-	    EH_RESTORE(m0);	/* restore Ethernet header */
-	    goto forward;	/* not using ipfw, accept the packet */
-	}
-
-	/*
-	 * XXX The following code is very similar to the one in
-	 * if_ethersubr.c:ether_ipfw_chk()
-	 */
-
-	args.m = m0;		/* the packet we are looking at		*/
-	args.oif = NULL;	/* this is an input packet		*/
-	args.next_hop = NULL;	/* we do not support forward yet	*/
-	args.eh = &save_eh;	/* MAC header for bridged/MAC packets	*/
-	i = ip_fw_chk_ptr(&args);
-	m0 = args.m;		/* in case the firewall used the mbuf	*/
-
-	if (m0 != NULL)
-		EH_RESTORE(m0);	/* restore Ethernet header */
-
-	if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */
-	    return m0;
-
-	if (i == 0) /* a PASS rule.  */
-	    goto forward;
-	if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) {
-	    /*
-	     * Pass the pkt to dummynet, which consumes it.
-	     * If shared, make a copy and keep the original.
-	     */
-	    if (shared) {
-		m = m_copypacket(m0, M_DONTWAIT);
-		if (m == NULL) {	/* copy failed, give up */
-		    bdg_dropped++;
-		    return NULL;
-		}
-	    } else {
-		m = m0 ; /* pass the original to dummynet */
-		m0 = NULL ; /* and nothing back to the caller */
-	    }
-
-	    args.oif = real_dst;
-	    ip_dn_io_ptr(m, (i & 0xffff),DN_TO_BDG_FWD, &args);
-	    return m0;
-	}
-	/*
 	 * XXX at some point, add support for divert/forward actions.
 	 * If none of the above matches, we have to drop the packet.
 	 */
@@ -1084,6 +1033,7 @@ bdg_forward(struct mbuf *m0, struct ifne
 	return m0;
     }
 forward:
+
     /*
      * Again, bring up the headers in case of shared bufs to avoid
      * corruptions in the future.
Index: net/if_ethersubr.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.169
diff -u -p -r1.169 if_ethersubr.c
--- net/if_ethersubr.c	25 Apr 2004 09:24:51 -0000	1.169
+++ net/if_ethersubr.c	10 May 2004 20:17:14 -0000
@@ -349,15 +349,8 @@ ether_output_frame(struct ifnet *ifp, st
 			m_freem(m);
 		return (0);
 	}
-	if (IPFW_LOADED && ether_ipfw != 0) {
-		if (ether_ipfw_chk(&m, ifp, &rule, 0) == 0) {
-			if (m) {
-				m_freem(m);
-				return EACCES;	/* pkt dropped */
-			} else
-				return 0;	/* consumed e.g. in a pipe */
-		}
-	}
+
+	/* XXY: ipfw check was here. */
 
 	/*
 	 * Queue message on interface, update output statistics if
@@ -367,100 +360,6 @@ ether_output_frame(struct ifnet *ifp, st
 }
 
 /*
- * ipfw processing for ethernet packets (in and out).
- * The second parameter is NULL from ether_demux, and ifp from
- * ether_output_frame. This section of code could be used from
- * bridge.c as well as long as we use some extra info
- * to distinguish that case from ether_output_frame();
- */
-int
-ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
-	struct ip_fw **rule, int shared)
-{
-	struct ether_header *eh;
-	struct ether_header save_eh;
-	struct mbuf *m;
-	int i;
-	struct ip_fw_args args;
-
-	if (*rule != NULL && fw_one_pass)
-		return 1; /* dummynet packet, already partially processed */
-
-	/*
-	 * I need some amt of data to be contiguous, and in case others need
-	 * the packet (shared==1) also better be in the first mbuf.
-	 */
-	m = *m0;
-	i = min( m->m_pkthdr.len, max_protohdr);
-	if ( shared || m->m_len < i) {
-		m = m_pullup(m, i);
-		if (m == NULL) {
-			*m0 = m;
-			return 0;
-		}
-	}
-	eh = mtod(m, struct ether_header *);
-	save_eh = *eh;			/* save copy for restore below */
-	m_adj(m, ETHER_HDR_LEN);	/* strip ethernet header */
-
-	args.m = m;		/* the packet we are looking at		*/
-	args.oif = dst;		/* destination, if any			*/
-	args.rule = *rule;	/* matching rule to restart		*/
-	args.next_hop = NULL;	/* we do not support forward yet	*/
-	args.eh = &save_eh;	/* MAC header for bridged/MAC packets	*/
-	i = ip_fw_chk_ptr(&args);
-	m = args.m;
-	if (m != NULL) {
-		/*
-		 * Restore Ethernet header, as needed, in case the
-		 * mbuf chain was replaced by ipfw.
-		 */
-		M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
-		if (m == NULL) {
-			*m0 = m;
-			return 0;
-		}
-		if (eh != mtod(m, struct ether_header *))
-			bcopy(&save_eh, mtod(m, struct ether_header *),
-				ETHER_HDR_LEN);
-	}
-	*m0 = m;
-	*rule = args.rule;
-
-	if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) /* drop */
-		return 0;
-
-	if (i == 0) /* a PASS rule.  */
-		return 1;
-
-	if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) {
-		/*
-		 * Pass the pkt to dummynet, which consumes it.
-		 * If shared, make a copy and keep the original.
-		 */
-		if (shared) {
-			m = m_copypacket(m, M_DONTWAIT);
-			if (m == NULL)
-				return 0;
-		} else {
-			/*
-			 * Pass the original to dummynet and
-			 * nothing back to the caller
-			 */
-			*m0 = NULL ;
-		}
-		ip_dn_io_ptr(m, (i & 0xffff),
-			dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args);
-		return 0;
-	}
-	/*
-	 * XXX at some point add support for divert/forward actions.
-	 * If none of the above matches, we have to drop the pkt.
-	 */
-	return 0;
-}
-
-/*
  * Process a received Ethernet packet; the packet is in the
  * mbuf chain m with the ethernet header at the front.
  */
@@ -660,13 +559,6 @@ ether_demux(struct ifnet *ifp, struct mb
 		ifp->if_imcasts++;
 
 post_stats:
-	if (IPFW_LOADED && ether_ipfw != 0) {
-		if (ether_ipfw_chk(&m, NULL, &rule, 0) == 0) {
-			if (m)
-				m_freem(m);
-			return;
-		}
-	}
 
 	/*
 	 * If VLANs are configured on the interface, check to
Index: netgraph/ng_bridge.c
===================================================================
RCS file: /home/ncvs/src/sys/netgraph/ng_bridge.c,v
retrieving revision 1.23
diff -u -p -r1.23 ng_bridge.c
--- netgraph/ng_bridge.c	26 Jan 2004 14:05:31 -0000	1.23
+++ netgraph/ng_bridge.c	10 May 2004 20:17:14 -0000
@@ -632,10 +632,12 @@ ng_bridge_rcvdata(hook_p hook, item_p it
 		}
 	}
 
+#if 0
 	/* Run packet through ipfw processing, if enabled */
 	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/igmp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/igmp.c,v
retrieving revision 1.45
diff -u -p -r1.45 igmp.c
--- netinet/igmp.c	7 Apr 2004 20:46:13 -0000	1.45
+++ netinet/igmp.c	10 May 2004 20:17:14 -0000
@@ -65,6 +65,7 @@
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #include <netinet/igmp.h>
 #include <netinet/igmp_var.h>
 
Index: netinet/ip_fastfwd.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fastfwd.c,v
retrieving revision 1.11
diff -u -p -r1.11 ip_fastfwd.c
--- netinet/ip_fastfwd.c	6 May 2004 18:46:03 -0000	1.11
+++ netinet/ip_fastfwd.c	10 May 2004 20:17:14 -0000
@@ -105,6 +105,7 @@
 #include <netinet/in_var.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #include <netinet/ip_icmp.h>
 
 #include <machine/in_cksum.h>
@@ -178,7 +179,8 @@ ip_fastforward(struct mbuf *m)
 	in_addr_t odest, dest;
 	u_short sum, ip_len;
 	int error = 0;
-	int hlen, ipfw, mtu;
+	int hlen, mtu;
+	/* int ipfw; */
 
 	/*
 	 * Are we active and forwarding packets?
@@ -373,91 +375,6 @@ ip_fastforward(struct mbuf *m)
 #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 = 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?
 	 */
 	if (odest != dest) {
@@ -526,88 +443,6 @@ passin:
 	ip = mtod(m, struct ip *);
 	dest = 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 = 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?
@@ -631,9 +466,6 @@ forwardlocal:
 					    args.next_hop;
 					m_tag_prepend(m, mtag);
 				}
-#ifdef IPDIVERT
-droptoours:	/* Used for DIVERT */
-#endif
 				/* for ip_input */
 				m->m_flags |= M_FASTFWD_OURS;
 
Index: netinet/ip_fw.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.84
diff -u -p -r1.84 ip_fw.h
--- netinet/ip_fw.h	23 Apr 2004 14:27:27 -0000	1.84
+++ netinet/ip_fw.h	10 May 2004 20:17:14 -0000
@@ -412,15 +412,19 @@ struct ip_fw_args {
 struct sockopt;
 struct dn_flow_set;
 
+int hook_ipfw(void);
+void unhook_ipfw(void);
+
+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 *);
+
 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;
 extern ip_fw_ctl_t *ip_fw_ctl_ptr;
 extern int fw_one_pass;
-extern int fw_enable;
-#define	IPFW_LOADED	(ip_fw_chk_ptr != NULL)
 #endif /* _KERNEL */
 
 #endif /* _IPFW2_H */
Index: netinet/ip_fw2.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.57
diff -u -p -r1.57 ip_fw2.c
--- netinet/ip_fw2.c	23 Apr 2004 14:27:27 -0000	1.57
+++ netinet/ip_fw2.c	10 May 2004 20:17:15 -0000
@@ -136,9 +136,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,
@@ -256,8 +253,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 */
 
 /*
@@ -1401,7 +1396,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)
 {
 	/*
@@ -3016,7 +3011,6 @@ ipfw_init(void)
 		printf("limited to %d packets/entry by default\n",
 		    verbose_limit);
 
-	ip_fw_chk_ptr = ipfw_chk;
 	ip_fw_ctl_ptr = ipfw_ctl;
 	callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);
 
@@ -3030,7 +3024,6 @@ ipfw_destroy(void)
 
 	IPFW_LOCK(&layer3_chain);
 	callout_stop(&ipfw_timeout);
-	ip_fw_chk_ptr = NULL;
 	ip_fw_ctl_ptr = NULL;
 	layer3_chain.reap = NULL;
 	free_chain(&layer3_chain, 1 /* kill default rule */);
@@ -3051,7 +3044,7 @@ ipfw_modevent(module_t mod, int type, vo
 
 	switch (type) {
 	case MOD_LOAD:
-		if (IPFW_LOADED) {
+		if (hook_ipfw()) {
 			printf("IP firewall already loaded\n");
 			err = EEXIST;
 		} else {
@@ -3060,6 +3053,7 @@ ipfw_modevent(module_t mod, int type, vo
 		break;
 
 	case MOD_UNLOAD:
+		unhook_ipfw();
 		ipfw_destroy();
 		err = 0;
 		break;
Index: netinet/ip_icmp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.92
diff -u -p -r1.92 ip_icmp.c
--- netinet/ip_icmp.c	7 May 2004 01:24:53 -0000	1.92
+++ netinet/ip_icmp.c	10 May 2004 20:17:15 -0000
@@ -54,6 +54,7 @@
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcpip.h>
Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.271
diff -u -p -r1.271 ip_input.c
--- netinet/ip_input.c	6 May 2004 18:46:02 -0000	1.271
+++ netinet/ip_input.c	10 May 2004 20:17:15 -0000
@@ -68,6 +68,7 @@
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #include <netinet/ip_icmp.h>
 #include <machine/in_cksum.h>
 
@@ -101,19 +102,6 @@ int	ip_defttl = IPDEFTTL;
 SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
     &ip_defttl, 0, "Maximum TTL on IP packets");
 
-static int	ip_dosourceroute = 0;
-SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
-    &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
-
-static int	ip_acceptsourceroute = 0;
-SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 
-    CTLFLAG_RW, &ip_acceptsourceroute, 0, 
-    "Enable accepting source routed IP packets");
-
-int		ip_doopts = 1;	/* 0 = ignore, 1 = process, 2 = reject */
-SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW,
-    &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)");
-
 static int	ip_keepfaith = 0;
 SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
 	&ip_keepfaith,	0,
@@ -204,43 +192,8 @@ 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 ;
-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.
- * Note that the code even makes assumptions on the size and
- * alignment of fields inside struct ip_srcrt so e.g. adding some
- * fields will break the code. This needs to be fixed.
- *
- * We need to save the IP options in case a protocol wants to respond
- * to an incoming packet over the same route if the packet got here
- * using IP source routing.  This allows connection establishment and
- * maintenance when the remote end is on a network that is not known
- * to us.
- */
-static int	ip_nhops = 0;
-static	struct ip_srcrt {
-	struct	in_addr dst;			/* final destination */
-	char	nop;				/* one NOP to align */
-	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
-	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
-} 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 void	ip_freef(struct ipqhead *, struct ipq *);
-static struct	mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *);
+
 
 /*
  * IP initialization: fill in IP protocol switch table.
@@ -296,16 +249,11 @@ void
 ip_input(struct mbuf *m)
 {
 	struct ip *ip = NULL;
-	struct ipq *fp;
 	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 */
@@ -317,26 +265,14 @@ 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 */
 		m->m_flags &= ~M_FASTFWD_OURS;	/* for reflected mbufs */
   		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))
@@ -433,20 +369,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.
@@ -456,55 +378,18 @@ iphack:
 	 *     ip_forward to do the right thing.
 	 */
 	odst = ip->ip_dst;
-	if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
-	    PFIL_IN) != 0)
+	if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN) != 0)
 		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;
-
-		args.m = m;
-		i = ip_fw_chk_ptr(&args);
-		m = args.m;
-
-		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,
@@ -512,8 +397,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, NULL))
 		return;
 
         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
@@ -539,7 +423,7 @@ pass:
 	 * 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;
+	pkt_dst = ip->ip_dst;
 
 	/*
 	 * Enable a consistency check between the destination address
@@ -558,7 +442,7 @@ 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.
@@ -697,7 +581,7 @@ pass:
 			goto bad;
 		}
 #endif /* FAST_IPSEC */
-		ip_forward(m, dchg, args.next_hop);
+		ip_forward(m, dchg, NULL);
 	}
 	return;
 
@@ -719,158 +603,19 @@ ours:
 	}
 
 	/*
-	 * If offset or IP_MF are set, must reassemble.
-	 * Otherwise, nothing need be done.
-	 * (We could look in the reassembly queue to see
-	 * if the packet was previously fragmented,
-	 * but it's not worth the time; just let them time out.)
+	 * Attempt reassembly; if it succeeds, proceed.
+	 * ip_reass() will return a different mbuf.
 	 */
 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
-
-		/* If maxnipq is 0, never accept fragments. */
-		if (maxnipq == 0) {
-                	ipstat.ips_fragments++;
-			ipstat.ips_fragdropped++;
-			goto bad;
-		}
-
-		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
-		IPQ_LOCK();
-		/*
-		 * Look for queue of fragments
-		 * of this datagram.
-		 */
-		TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
-			if (ip->ip_id == fp->ipq_id &&
-			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
-			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
-#ifdef MAC
-			    mac_fragment_match(m, fp) &&
-#endif
-			    ip->ip_p == fp->ipq_p)
-				goto found;
-
-		fp = NULL;
-
-		/*
-		 * Enforce upper bound on number of fragmented packets
-		 * for which we attempt reassembly;
-		 * If maxnipq is -1, accept all fragments without limitation.
-		 */
-		if ((nipq > maxnipq) && (maxnipq > 0)) {
-		    /*
-		     * drop something from the tail of the current queue
-		     * before proceeding further
-		     */
-		    struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
-		    if (q == NULL) {   /* gak */
-			for (i = 0; i < IPREASS_NHASH; i++) {
-			    struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
-			    if (r) {
-				ipstat.ips_fragtimeout += r->ipq_nfrags;
-				ip_freef(&ipq[i], r);
-				break;
-			    }
-			}
-		    } else {
-			ipstat.ips_fragtimeout += q->ipq_nfrags;
-			ip_freef(&ipq[sum], q);
-		    }
-		}
-found:
-		/*
-		 * Adjust ip_len to not reflect header,
-		 * convert offset of this to bytes.
-		 */
-		ip->ip_len -= hlen;
-		if (ip->ip_off & IP_MF) {
-		        /*
-		         * Make sure that fragments have a data length
-			 * that's a non-zero multiple of 8 bytes.
-		         */
-			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
-				IPQ_UNLOCK();
-				ipstat.ips_toosmall++; /* XXX */
-				goto bad;
-			}
-			m->m_flags |= M_FRAG;
-		} else
-			m->m_flags &= ~M_FRAG;
-		ip->ip_off <<= 3;
-
-		/*
-		 * Attempt reassembly; if it succeeds, proceed.
-		 * ip_reass() will return a different mbuf.
-		 */
-		ipstat.ips_fragments++;
-		m->m_pkthdr.header = ip;
-		m = ip_reass(m, &ipq[sum], fp);
-		IPQ_UNLOCK();
-		if (m == 0)
+		m = ip_reass(m);
+		if (m == NULL)
 			return;
-		ipstat.ips_reassembled++;
 		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 += hlen;
-			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);
-			ip->ip_len -= hlen;
-		}
-#endif
 	} else
 		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.
@@ -927,6 +672,7 @@ DPRINTF(("ip_input: no SP, packet discar
 	 * Switch out to protocol's input routine.
 	 */
 	ipstat.ips_delivered++;
+#if 0
 	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,
@@ -936,6 +682,7 @@ DPRINTF(("ip_input: no SP, packet discar
 		*(struct sockaddr_in **)(mtag+1) = args.next_hop;
 		m_tag_prepend(m, mtag);
 	}
+#endif
 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
 	return;
 bad:
@@ -946,26 +693,106 @@ bad:
  * Take incoming datagram fragment and try to reassemble it into
  * whole datagram.  If a chain for reassembly of this datagram already
  * exists, then it is given as fp; otherwise have to make a chain.
- *
- * When IPDIVERT enabled, keep additional state with each packet that
- * tells us if we need to divert or tee the packet we're building.
- * In particular, *divinfo includes the port and TEE flag,
- * *divert_rule is the number of the matching rule.
  */
 
-static struct mbuf *
-ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp)
+struct mbuf *
+ip_reass(struct mbuf *m)
 {
-	struct ip *ip = mtod(m, struct ip *);
-	register struct mbuf *p, *q, *nq;
-	struct mbuf *t;
-	int hlen = ip->ip_hl << 2;
-	int i, next;
+	struct ip *ip;
+	struct mbuf *p, *q, *nq, *t;
+	struct ipq *fp = NULL;
+	struct ipqhead *head;
+	int i, hlen, next;
 	u_int8_t ecn, ecn0;
+	u_short hash;
 
-	IPQ_LOCK_ASSERT();
+	/* If maxnipq is 0, never accept fragments. */
+	if (maxnipq == 0) {
+		ipstat.ips_fragments++;
+		ipstat.ips_fragdropped++;
+		goto dropfrag;
+	}
+
+	ip = mtod(m, struct ip *);
+	hlen = ip->ip_hl << 2;
+
+	hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
+	head = &ipq[hash];
+	IPQ_LOCK();
 
 	/*
+	 * Look for queue of fragments
+	 * of this datagram.
+	 */
+	TAILQ_FOREACH(fp, head, ipq_list)
+		if (ip->ip_id == fp->ipq_id &&
+		    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+		    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+#ifdef MAC
+		    mac_fragment_match(m, fp) &&
+#endif
+		    ip->ip_p == fp->ipq_p)
+			goto found;
+
+	fp = NULL;
+
+	/*
+	 * Enforce upper bound on number of fragmented packets
+	 * for which we attempt reassembly;
+	 * If maxnipq is -1, accept all fragments without limitation.
+	 */
+	if ((nipq > maxnipq) && (maxnipq > 0)) {
+		/*
+		 * drop something from the tail of the current queue
+		 * before proceeding further
+		 */
+		struct ipq *q = TAILQ_LAST(head, ipqhead);
+		if (q == NULL) {   /* gak */
+			for (i = 0; i < IPREASS_NHASH; i++) {
+				struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
+				if (r) {
+					ipstat.ips_fragtimeout += r->ipq_nfrags;
+					ip_freef(&ipq[i], r);
+					break;
+				}
+			}
+		} else {
+			ipstat.ips_fragtimeout += q->ipq_nfrags;
+			ip_freef(head, q);
+		}
+	}
+
+found:
+	/*
+	 * Adjust ip_len to not reflect header,
+	 * convert offset of this to bytes.
+	 */
+	ip->ip_len -= hlen;
+	if (ip->ip_off & IP_MF) {
+		/*
+		 * Make sure that fragments have a data length
+		 * that's a non-zero multiple of 8 bytes.
+		 */
+		if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
+			IPQ_UNLOCK();
+			ipstat.ips_toosmall++; /* XXX */
+			goto dropfrag;
+		}
+		m->m_flags |= M_FRAG;
+	} else
+		m->m_flags &= ~M_FRAG;
+	ip->ip_off <<= 3;
+
+
+	/*
+	 * Attempt reassembly; if it succeeds, proceed.
+	 * ip_reass() will return a different mbuf.
+	 */
+	ipstat.ips_fragments++;
+	m->m_pkthdr.header = ip;
+
+	/* OLD CODE */
+	/*
 	 * Presence of header sizes in mbufs
 	 * would confuse code below.
 	 */
@@ -1078,18 +905,6 @@ ip_reass(struct mbuf *m, struct ipqhead 
 
 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.
@@ -1107,7 +922,7 @@ inserted:
 				ipstat.ips_fragdropped += fp->ipq_nfrags;
 				ip_freef(head, fp);
 			}
-			return (0);
+			goto done;
 		}
 		next += GETIP(q)->ip_len;
 	}
@@ -1117,7 +932,7 @@ inserted:
 			ipstat.ips_fragdropped += fp->ipq_nfrags;
 			ip_freef(head, fp);
 		}
-		return (0);
+		goto done;
 	}
 
 	/*
@@ -1129,7 +944,7 @@ inserted:
 		ipstat.ips_toolong++;
 		ipstat.ips_fragdropped += fp->ipq_nfrags;
 		ip_freef(head, fp);
-		return (0);
+		goto done;
 	}
 
 	/*
@@ -1170,6 +985,8 @@ inserted:
 	/* some debugging cruft by sklower, below, will go away soon */
 	if (m->m_flags & M_PKTHDR)	/* XXX this should be done elsewhere */
 		m_fixhdr(m);
+	ipstat.ips_reassembled++;
+	IPQ_UNLOCK();
 	return (m);
 
 dropfrag:
@@ -1177,7 +994,9 @@ dropfrag:
 	if (fp != NULL)
 		fp->ipq_nfrags--;
 	m_freem(m);
-	return (0);
+done:
+	IPQ_UNLOCK();
+	return (NULL);
 
 #undef GETIP
 }
@@ -1269,288 +1088,6 @@ ip_drain()
 }
 
 /*
- * Do option processing on a datagram,
- * possibly discarding it if bad options are encountered,
- * or forwarding it if source-routed.
- * The pass argument is used when operating in the IPSTEALTH
- * mode to tell what options to process:
- * [LS]SRR (pass 0) or the others (pass 1).
- * The reason for as many as two passes is that when doing IPSTEALTH,
- * non-routing options should be processed only if the packet is for us.
- * Returns 1 if packet has been forwarded/freed,
- * 0 if the packet should be processed further.
- */
-static int
-ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
-{
-	struct ip *ip = mtod(m, struct ip *);
-	u_char *cp;
-	struct in_ifaddr *ia;
-	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
-	struct in_addr *sin, dst;
-	n_time ntime;
-	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
-
-	/* ignore or reject packets with IP options */
-	if (ip_doopts == 0)
-		return 0;
-	else if (ip_doopts == 2) {
-		type = ICMP_UNREACH;
-		code = ICMP_UNREACH_FILTER_PROHIB;
-		goto bad;
-	}
-
-	dst = ip->ip_dst;
-	cp = (u_char *)(ip + 1);
-	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
-	for (; cnt > 0; cnt -= optlen, cp += optlen) {
-		opt = cp[IPOPT_OPTVAL];
-		if (opt == IPOPT_EOL)
-			break;
-		if (opt == IPOPT_NOP)
-			optlen = 1;
-		else {
-			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
-				code = &cp[IPOPT_OLEN] - (u_char *)ip;
-				goto bad;
-			}
-			optlen = cp[IPOPT_OLEN];
-			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
-				code = &cp[IPOPT_OLEN] - (u_char *)ip;
-				goto bad;
-			}
-		}
-		switch (opt) {
-
-		default:
-			break;
-
-		/*
-		 * Source routing with record.
-		 * Find interface with current destination address.
-		 * If none on this machine then drop if strictly routed,
-		 * or do nothing if loosely routed.
-		 * Record interface address and bring up next address
-		 * component.  If strictly routed make sure next
-		 * address is on directly accessible net.
-		 */
-		case IPOPT_LSRR:
-		case IPOPT_SSRR:
-#ifdef IPSTEALTH
-			if (ipstealth && pass > 0)
-				break;
-#endif
-			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
-				code = &cp[IPOPT_OLEN] - (u_char *)ip;
-				goto bad;
-			}
-			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
-				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-				goto bad;
-			}
-			ipaddr.sin_addr = ip->ip_dst;
-			ia = (struct in_ifaddr *)
-				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
-			if (ia == 0) {
-				if (opt == IPOPT_SSRR) {
-					type = ICMP_UNREACH;
-					code = ICMP_UNREACH_SRCFAIL;
-					goto bad;
-				}
-				if (!ip_dosourceroute)
-					goto nosourcerouting;
-				/*
-				 * Loose routing, and not at next destination
-				 * yet; nothing to do except forward.
-				 */
-				break;
-			}
-			off--;			/* 0 origin */
-			if (off > optlen - (int)sizeof(struct in_addr)) {
-				/*
-				 * End of source route.  Should be for us.
-				 */
-				if (!ip_acceptsourceroute)
-					goto nosourcerouting;
-				save_rte(cp, ip->ip_src);
-				break;
-			}
-#ifdef IPSTEALTH
-			if (ipstealth)
-				goto dropit;
-#endif
-			if (!ip_dosourceroute) {
-				if (ipforwarding) {
-					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
-					/*
-					 * Acting as a router, so generate ICMP
-					 */
-nosourcerouting:
-					strcpy(buf, inet_ntoa(ip->ip_dst));
-					log(LOG_WARNING, 
-					    "attempted source route from %s to %s\n",
-					    inet_ntoa(ip->ip_src), buf);
-					type = ICMP_UNREACH;
-					code = ICMP_UNREACH_SRCFAIL;
-					goto bad;
-				} else {
-					/*
-					 * Not acting as a router, so silently drop.
-					 */
-#ifdef IPSTEALTH
-dropit:
-#endif
-					ipstat.ips_cantforward++;
-					m_freem(m);
-					return (1);
-				}
-			}
-
-			/*
-			 * locate outgoing interface
-			 */
-			(void)memcpy(&ipaddr.sin_addr, cp + off,
-			    sizeof(ipaddr.sin_addr));
-
-			if (opt == IPOPT_SSRR) {
-#define	INA	struct in_ifaddr *
-#define	SA	struct sockaddr *
-			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
-				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
-			} else
-				ia = ip_rtaddr(ipaddr.sin_addr);
-			if (ia == 0) {
-				type = ICMP_UNREACH;
-				code = ICMP_UNREACH_SRCFAIL;
-				goto bad;
-			}
-			ip->ip_dst = ipaddr.sin_addr;
-			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
-			    sizeof(struct in_addr));
-			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
-			/*
-			 * Let ip_intr's mcast routing check handle mcast pkts
-			 */
-			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
-			break;
-
-		case IPOPT_RR:
-#ifdef IPSTEALTH
-			if (ipstealth && pass == 0)
-				break;
-#endif
-			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
-				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-				goto bad;
-			}
-			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
-				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-				goto bad;
-			}
-			/*
-			 * If no space remains, ignore.
-			 */
-			off--;			/* 0 origin */
-			if (off > optlen - (int)sizeof(struct in_addr))
-				break;
-			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
-			    sizeof(ipaddr.sin_addr));
-			/*
-			 * locate outgoing interface; if we're the destination,
-			 * use the incoming interface (should be same).
-			 */
-			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
-			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
-				type = ICMP_UNREACH;
-				code = ICMP_UNREACH_HOST;
-				goto bad;
-			}
-			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
-			    sizeof(struct in_addr));
-			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
-			break;
-
-		case IPOPT_TS:
-#ifdef IPSTEALTH
-			if (ipstealth && pass == 0)
-				break;
-#endif
-			code = cp - (u_char *)ip;
-			if (optlen < 4 || optlen > 40) {
-				code = &cp[IPOPT_OLEN] - (u_char *)ip;
-				goto bad;
-			}
-			if ((off = cp[IPOPT_OFFSET]) < 5) {
-				code = &cp[IPOPT_OLEN] - (u_char *)ip;
-				goto bad;
-			}
-			if (off > optlen - (int)sizeof(int32_t)) {
-				cp[IPOPT_OFFSET + 1] += (1 << 4);
-				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
-					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-					goto bad;
-				}
-				break;
-			}
-			off--;				/* 0 origin */
-			sin = (struct in_addr *)(cp + off);
-			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
-
-			case IPOPT_TS_TSONLY:
-				break;
-
-			case IPOPT_TS_TSANDADDR:
-				if (off + sizeof(n_time) +
-				    sizeof(struct in_addr) > optlen) {
-					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-					goto bad;
-				}
-				ipaddr.sin_addr = dst;
-				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
-							    m->m_pkthdr.rcvif);
-				if (ia == 0)
-					continue;
-				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
-				    sizeof(struct in_addr));
-				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
-				off += sizeof(struct in_addr);
-				break;
-
-			case IPOPT_TS_PRESPEC:
-				if (off + sizeof(n_time) +
-				    sizeof(struct in_addr) > optlen) {
-					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
-					goto bad;
-				}
-				(void)memcpy(&ipaddr.sin_addr, sin,
-				    sizeof(struct in_addr));
-				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
-					continue;
-				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
-				off += sizeof(struct in_addr);
-				break;
-
-			default:
-				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
-				goto bad;
-			}
-			ntime = iptime();
-			(void)memcpy(cp + off, &ntime, sizeof(n_time));
-			cp[IPOPT_OFFSET] += sizeof(n_time);
-		}
-	}
-	if (forward && ipforwarding) {
-		ip_forward(m, 1, next_hop);
-		return (1);
-	}
-	return (0);
-bad:
-	icmp_error(m, type, code, 0, 0);
-	ipstat.ips_badoptions++;
-	return (1);
-}
-
-/*
  * Given address of next destination (final or next hop),
  * return internet address info of interface to be used to get there.
  */
@@ -1577,126 +1114,6 @@ ip_rtaddr(dst)
 	return ifa;
 }
 
-/*
- * Save incoming source route for use in replies,
- * to be picked up later by ip_srcroute if the receiver is interested.
- */
-static void
-save_rte(option, dst)
-	u_char *option;
-	struct in_addr dst;
-{
-	unsigned olen;
-
-	olen = option[IPOPT_OLEN];
-#ifdef DIAGNOSTIC
-	if (ipprintfs)
-		printf("save_rte: olen %d\n", olen);
-#endif
-	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
-		return;
-	bcopy(option, ip_srcrt.srcopt, olen);
-	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
-	ip_srcrt.dst = dst;
-}
-
-/*
- * Retrieve incoming source route for use in replies,
- * in the same form used by setsockopt.
- * The first hop is placed before the options, will be removed later.
- */
-struct mbuf *
-ip_srcroute()
-{
-	register struct in_addr *p, *q;
-	register struct mbuf *m;
-
-	if (ip_nhops == 0)
-		return ((struct mbuf *)0);
-	m = m_get(M_DONTWAIT, MT_HEADER);
-	if (m == 0)
-		return ((struct mbuf *)0);
-
-#define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
-
-	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
-	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
-	    OPTSIZ;
-#ifdef DIAGNOSTIC
-	if (ipprintfs)
-		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
-#endif
-
-	/*
-	 * First save first hop for return route
-	 */
-	p = &ip_srcrt.route[ip_nhops - 1];
-	*(mtod(m, struct in_addr *)) = *p--;
-#ifdef DIAGNOSTIC
-	if (ipprintfs)
-		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
-#endif
-
-	/*
-	 * Copy option fields and padding (nop) to mbuf.
-	 */
-	ip_srcrt.nop = IPOPT_NOP;
-	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
-	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
-	    &ip_srcrt.nop, OPTSIZ);
-	q = (struct in_addr *)(mtod(m, caddr_t) +
-	    sizeof(struct in_addr) + OPTSIZ);
-#undef OPTSIZ
-	/*
-	 * Record return path as an IP source route,
-	 * reversing the path (pointers are now aligned).
-	 */
-	while (p >= ip_srcrt.route) {
-#ifdef DIAGNOSTIC
-		if (ipprintfs)
-			printf(" %lx", (u_long)ntohl(q->s_addr));
-#endif
-		*q++ = *p--;
-	}
-	/*
-	 * Last hop goes to final destination.
-	 */
-	*q = ip_srcrt.dst;
-#ifdef DIAGNOSTIC
-	if (ipprintfs)
-		printf(" %lx\n", (u_long)ntohl(q->s_addr));
-#endif
-	return (m);
-}
-
-/*
- * Strip out IP options, at higher
- * level protocol in the kernel.
- * Second argument is buffer to which options
- * will be moved, and return value is their length.
- * XXX should be deleted; last arg currently ignored.
- */
-void
-ip_stripoptions(m, mopt)
-	register struct mbuf *m;
-	struct mbuf *mopt;
-{
-	register int i;
-	struct ip *ip = mtod(m, struct ip *);
-	register caddr_t opts;
-	int olen;
-
-	olen = (ip->ip_hl << 2) - sizeof (struct ip);
-	opts = (caddr_t)(ip + 1);
-	i = m->m_len - (sizeof (struct ip) + olen);
-	bcopy(opts + olen, opts, (unsigned)i);
-	m->m_len -= olen;
-	if (m->m_flags & M_PKTHDR)
-		m->m_pkthdr.len -= olen;
-	ip->ip_v = IPVERSION;
-	ip->ip_hl = sizeof(struct ip) >> 2;
-}
-
 u_char inetctlerrmap[PRC_NCMDS] = {
 	0,		0,		0,		0,
 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
@@ -1720,7 +1137,7 @@ u_char inetctlerrmap[PRC_NCMDS] = {
  * The srcrt parameter indicates whether the packet is being forwarded
  * via a source route.
  */
-static void
+void
 ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
 {
 	struct ip *ip = mtod(m, struct ip *);
Index: netinet/ip_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.217
diff -u -p -r1.217 ip_output.c
--- netinet/ip_output.c	2 May 2004 15:10:16 -0000	1.217
+++ netinet/ip_output.c	10 May 2004 20:17:15 -0000
@@ -60,6 +60,7 @@
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 
 #ifdef PFIL_HOOKS
 #include <net/pfil.h>
@@ -103,18 +104,14 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_
 	&mbuf_frag_size, 0, "Fragment outgoing mbufs to this size");
 #endif
 
-static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
 static struct ifnet *ip_multicast_if(struct in_addr *, int *);
 static void	ip_mloopback
 	(struct ifnet *, struct mbuf *, struct sockaddr_in *, int);
 static int	ip_getmoptions
 	(struct sockopt *, struct ip_moptions *);
-static int	ip_pcbopts(int, struct mbuf **, struct mbuf *);
 static int	ip_setmoptions
 	(struct sockopt *, struct ip_moptions **);
 
-int	ip_optcopy(struct ip *, struct ip *);
-
 
 extern	struct protosw inetsw[];
 
@@ -134,13 +131,13 @@ 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 m_tag *mtag, *dummytag; */
 #ifdef IPSEC
 	struct secpolicy *sp = NULL;
 #endif
@@ -149,34 +146,9 @@ ip_output(struct mbuf *m, struct mbuf *o
 	struct tdb_ident *tdbi;
 	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));
@@ -185,14 +157,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);
@@ -200,7 +164,7 @@ 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;
+	pkt_dst = ip->ip_dst;
 
 	/*
 	 * Fill in IP header.  If we are not allowing fragmentation,
@@ -389,7 +353,7 @@ ip_output(struct mbuf *m, struct mbuf *o
 
 		goto sendit;
 	}
-#ifndef notdef
+
 	/*
 	 * If the source address is not specified yet, use the address
 	 * of the outoing interface. In case, keep note we did that, so
@@ -400,10 +364,9 @@ 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 */
+
 	/*
 	 * Verify that we have any chance at all of being able to queue
 	 *      the packet or packet fragments
@@ -691,13 +654,6 @@ 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.
@@ -705,245 +661,13 @@ spd_done:
 	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;
-
-		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;
-			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;
-
-			error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
-				&args);
-			goto done;
-		}
-#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;
-
-			/*
-			 * XXX
-			 * delayed checksums are not currently compatible
-			 * with divert sockets.
-			 */
-			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 */
-			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;
-		}
-#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.
-			 */
-			/* There must be a better way to do this next line... */
-			static struct route sro_fwd;
-			struct route *ro_fwd = &sro_fwd;
-
 #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 == 0) {
-				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) {
@@ -1046,12 +770,14 @@ done:
 		RTFREE(ro->ro_rt);
 		ro->ro_rt = NULL;
 	}
+#if 0
 	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);
 	}
+#endif
 #ifdef IPSEC
 	if (sp != NULL) {
 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -1265,108 +991,6 @@ in_delayed_cksum(struct mbuf *m)
 }
 
 /*
- * Insert IP options into preformed packet.
- * Adjust IP destination as required for IP source routing,
- * as indicated by a non-zero in_addr at the start of the options.
- *
- * XXX This routine assumes that the packet has no options in place.
- */
-static struct mbuf *
-ip_insertoptions(m, opt, phlen)
-	register struct mbuf *m;
-	struct mbuf *opt;
-	int *phlen;
-{
-	register struct ipoption *p = mtod(opt, struct ipoption *);
-	struct mbuf *n;
-	register struct ip *ip = mtod(m, struct ip *);
-	unsigned optlen;
-
-	optlen = opt->m_len - sizeof(p->ipopt_dst);
-	if (optlen + ip->ip_len > IP_MAXPACKET) {
-		*phlen = 0;
-		return (m);		/* XXX should fail */
-	}
-	if (p->ipopt_dst.s_addr)
-		ip->ip_dst = p->ipopt_dst;
-	if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
-		MGETHDR(n, M_DONTWAIT, MT_HEADER);
-		if (n == 0) {
-			*phlen = 0;
-			return (m);
-		}
-		n->m_pkthdr.rcvif = (struct ifnet *)0;
-#ifdef MAC
-		mac_create_mbuf_from_mbuf(m, n);
-#endif
-		n->m_pkthdr.len = m->m_pkthdr.len + optlen;
-		m->m_len -= sizeof(struct ip);
-		m->m_data += sizeof(struct ip);
-		n->m_next = m;
-		m = n;
-		m->m_len = optlen + sizeof(struct ip);
-		m->m_data += max_linkhdr;
-		bcopy(ip, mtod(m, void *), sizeof(struct ip));
-	} else {
-		m->m_data -= optlen;
-		m->m_len += optlen;
-		m->m_pkthdr.len += optlen;
-		bcopy(ip, mtod(m, void *), sizeof(struct ip));
-	}
-	ip = mtod(m, struct ip *);
-	bcopy(p->ipopt_list, ip + 1, optlen);
-	*phlen = sizeof(struct ip) + optlen;
-	ip->ip_v = IPVERSION;
-	ip->ip_hl = *phlen >> 2;
-	ip->ip_len += optlen;
-	return (m);
-}
-
-/*
- * Copy options from ip to jp,
- * omitting those not copied during fragmentation.
- */
-int
-ip_optcopy(ip, jp)
-	struct ip *ip, *jp;
-{
-	register u_char *cp, *dp;
-	int opt, optlen, cnt;
-
-	cp = (u_char *)(ip + 1);
-	dp = (u_char *)(jp + 1);
-	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
-	for (; cnt > 0; cnt -= optlen, cp += optlen) {
-		opt = cp[0];
-		if (opt == IPOPT_EOL)
-			break;
-		if (opt == IPOPT_NOP) {
-			/* Preserve for IP mcast tunnel's LSRR alignment. */
-			*dp++ = IPOPT_NOP;
-			optlen = 1;
-			continue;
-		}
-
-		KASSERT(cnt >= IPOPT_OLEN + sizeof(*cp),
-		    ("ip_optcopy: malformed ipv4 option"));
-		optlen = cp[IPOPT_OLEN];
-		KASSERT(optlen >= IPOPT_OLEN + sizeof(*cp) && optlen <= cnt,
-		    ("ip_optcopy: malformed ipv4 option"));
-
-		/* bogus lengths should have been caught by ip_dooptions */
-		if (optlen > cnt)
-			optlen = cnt;
-		if (IPOPT_COPIED(opt)) {
-			bcopy(cp, dp, optlen);
-			dp += optlen;
-		}
-	}
-	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
-		*dp++ = IPOPT_EOL;
-	return (optlen);
-}
-
-/*
  * IP socket option processing.
  */
 int
@@ -1645,108 +1269,6 @@ ip_ctloutput(so, sopt)
 		break;
 	}
 	return (error);
-}
-
-/*
- * Set up IP options in pcb for insertion in output packets.
- * Store in mbuf with pointer in pcbopt, adding pseudo-option
- * with destination address if source routed.
- */
-static int
-ip_pcbopts(optname, pcbopt, m)
-	int optname;
-	struct mbuf **pcbopt;
-	register struct mbuf *m;
-{
-	register int cnt, optlen;
-	register u_char *cp;
-	u_char opt;
-
-	/* turn off any old options */
-	if (*pcbopt)
-		(void)m_free(*pcbopt);
-	*pcbopt = 0;
-	if (m == (struct mbuf *)0 || m->m_len == 0) {
-		/*
-		 * Only turning off any previous options.
-		 */
-		if (m)
-			(void)m_free(m);
-		return (0);
-	}
-
-	if (m->m_len % sizeof(int32_t))
-		goto bad;
-	/*
-	 * IP first-hop destination address will be stored before
-	 * actual options; move other options back
-	 * and clear it when none present.
-	 */
-	if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
-		goto bad;
-	cnt = m->m_len;
-	m->m_len += sizeof(struct in_addr);
-	cp = mtod(m, u_char *) + sizeof(struct in_addr);
-	bcopy(mtod(m, void *), cp, (unsigned)cnt);
-	bzero(mtod(m, void *), sizeof(struct in_addr));
-
-	for (; cnt > 0; cnt -= optlen, cp += optlen) {
-		opt = cp[IPOPT_OPTVAL];
-		if (opt == IPOPT_EOL)
-			break;
-		if (opt == IPOPT_NOP)
-			optlen = 1;
-		else {
-			if (cnt < IPOPT_OLEN + sizeof(*cp))
-				goto bad;
-			optlen = cp[IPOPT_OLEN];
-			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
-				goto bad;
-		}
-		switch (opt) {
-
-		default:
-			break;
-
-		case IPOPT_LSRR:
-		case IPOPT_SSRR:
-			/*
-			 * user process specifies route as:
-			 *	->A->B->C->D
-			 * D must be our final destination (but we can't
-			 * check that since we may not have connected yet).
-			 * A is first hop destination, which doesn't appear in
-			 * actual IP option, but is stored before the options.
-			 */
-			if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
-				goto bad;
-			m->m_len -= sizeof(struct in_addr);
-			cnt -= sizeof(struct in_addr);
-			optlen -= sizeof(struct in_addr);
-			cp[IPOPT_OLEN] = optlen;
-			/*
-			 * Move first hop before start of options.
-			 */
-			bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
-			    sizeof(struct in_addr));
-			/*
-			 * Then copy rest of options back
-			 * to close up the deleted entry.
-			 */
-			bcopy((&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)),
-			    &cp[IPOPT_OFFSET+1],
-			    (unsigned)cnt + sizeof(struct in_addr));
-			break;
-		}
-	}
-	if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
-		goto bad;
-	*pcbopt = m;
-	return (0);
-
-bad:
-	(void)m_free(m);
-	return (EINVAL);
 }
 
 /*
Index: netinet/ip_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.87
diff -u -p -r1.87 ip_var.h
--- netinet/ip_var.h	6 May 2004 18:46:03 -0000	1.87
+++ netinet/ip_var.h	10 May 2004 20:17:15 -0000
@@ -66,19 +66,6 @@ struct ipq {
 #endif /* _KERNEL */
 
 /*
- * Structure stored in mbuf in inpcb.ip_options
- * and passed to ip_output when ip options are in use.
- * The actual length of the options (including ipopt_dst)
- * is in m_len.
- */
-#define MAX_IPOPTLEN	40
-
-struct ipoption {
-	struct	in_addr ipopt_dst;	/* first-hop dst if source routed */
-	char	ipopt_list[MAX_IPOPTLEN];	/* options proper */
-};
-
-/*
  * Structure attached to inpcb.ip_moptions and
  * passed to ip_output when IP multicast options are in use.
  */
@@ -147,7 +134,6 @@ extern u_short	ip_id;				/* ip packet ct
 #endif
 extern int	ip_defttl;			/* default IP ttl */
 extern int	ipforwarding;			/* ip forwarding */
-extern int	ip_doopts;			/* process or ignore IP options */
 #ifdef IPSTEALTH
 extern int	ipstealth;			/* stealth forwarding */
 #endif
@@ -164,20 +150,20 @@ void	 ip_drain(void);
 int	 ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
 	    u_long if_hwassist_flags, int sw_csum);
 void	 ip_freemoptions(struct ip_moptions *);
+void	 ip_forward(struct mbuf *, int, struct sockaddr_in *);
 void	 ip_init(void);
 extern int	 (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
 			  struct ip_moptions *);
 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 *,
 		struct mbuf *);
 void	 ip_slowtimo(void);
-struct mbuf *
-	 ip_srcroute(void);
-void	 ip_stripoptions(struct mbuf *, struct mbuf *);
 #ifdef RANDOM_IP_ID
 u_int16_t	
 	 ip_randomid(void);
Index: netinet/raw_ip.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.132
diff -u -p -r1.132 raw_ip.c
--- netinet/raw_ip.c	4 May 2004 02:11:47 -0000	1.132
+++ netinet/raw_ip.c	10 May 2004 20:17:15 -0000
@@ -80,7 +80,7 @@ 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_dn_ctl_t *ip_dn_ctl_ptr; */
 
 /*
  * hooks for multicast routing. They all default to NULL,
@@ -351,17 +351,19 @@ rip_ctloutput(struct socket *so, struct 
 
 		case IP_FW_ADD:	/* ADD actually returns the body... */
 		case IP_FW_GET:
-			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)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
+*/
 			break ;
 
 		case MRT_INIT:
@@ -404,7 +406,7 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_FW_FLUSH:
 		case IP_FW_ZERO:
 		case IP_FW_RESETLOG:
-			if (IPFW_LOADED)
+			if (ip_fw_ctl_ptr != NULL)
 				error = ip_fw_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT;
@@ -413,10 +415,12 @@ rip_ctloutput(struct socket *so, struct 
 		case IP_DUMMYNET_CONFIGURE:
 		case IP_DUMMYNET_DEL:
 		case IP_DUMMYNET_FLUSH:
+/*
 			if (DUMMYNET_LOADED)
 				error = ip_dn_ctl_ptr(sopt);
 			else
 				error = ENOPROTOOPT ;
+*/
 			break ;
 
 		case IP_RSVP_ON:
Index: netinet/tcp_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.237
diff -u -p -r1.237 tcp_input.c
--- netinet/tcp_input.c	2 May 2004 15:10:17 -0000	1.237
+++ netinet/tcp_input.c	10 May 2004 20:17:15 -0000
@@ -67,6 +67,7 @@
 #include <netinet/ip_icmp.h>	/* for ICMP_BANDLIM		*/
 #include <netinet/icmp_var.h>	/* for ICMP_BANDLIM		*/
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 #include <netinet6/in6_pcb.h>
Index: netinet/tcp_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_output.c,v
retrieving revision 1.91
diff -u -p -r1.91 tcp_output.c
--- netinet/tcp_output.c	4 May 2004 02:11:47 -0000	1.91
+++ netinet/tcp_output.c	10 May 2004 20:17:15 -0000
@@ -56,6 +56,7 @@
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #ifdef INET6
 #include <netinet6/in6_pcb.h>
 #include <netinet/ip6.h>
Index: netinet/tcp_syncache.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_syncache.c,v
retrieving revision 1.57
diff -u -p -r1.57 tcp_syncache.c
--- netinet/tcp_syncache.c	4 May 2004 02:11:47 -0000	1.57
+++ netinet/tcp_syncache.c	10 May 2004 20:17:15 -0000
@@ -62,6 +62,7 @@
 #include <netinet/in_var.h>
 #include <netinet/in_pcb.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #ifdef INET6
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.153
diff -u -p -r1.153 udp_usrreq.c
--- netinet/udp_usrreq.c	4 May 2004 02:11:47 -0000	1.153
+++ netinet/udp_usrreq.c	10 May 2004 20:17:15 -0000
@@ -68,6 +68,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp_var.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
 #ifdef INET6
 #include <netinet6/ip6_var.h>
 #endif
--- netinet/null	Mon May 10 22:17:30 2004
+++ netinet/ip_fw_pfil.c	Mon May 10 20:56:02 2004
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
+ * 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"
+#include "opt_ipsec.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/kernel.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/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/in_pcb.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_fw.h>
+#include <netinet/ip_divert.h>
+#include <netinet/ip_dummynet.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcpip.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif
+
+#include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */
+
+#include <machine/in_cksum.h>   /* XXX for in_cksum */
+
+static	int ipfw_pfil_hooked = 0;
+
+/* Dummynet hooks */
+ip_dn_io_t *ip_dn_io_ptr;
+
+#define	DIV_DIR_IN	1
+#define	DIV_DIR_OUT	0
+
+int fw_one_pass = 1;
+
+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;
+	int ipfw = 0;
+	int divert;
+
+	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
+
+	bzero(&args, sizeof(args));
+
+	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(m, ipfw & 0xffff, DN_TO_IP_IN, &args);
+		m = NULL;
+		return 0;
+	}
+	*/
+
+	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);
+
+		if (divert) {
+			*m0 = NULL;
+			return 0;	/* packet consumed */
+		} else
+			goto pass;	/* continue with packet */
+	}
+
+	/*
+	if (ipfw == 0 && args.next_hop != NULL) {
+
+	}
+	*/
+
+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;
+	int ipfw = 0;
+	int divert;
+
+	KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
+
+	bzero(&args, sizeof(args));
+	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) {
+		args.ro = &ro;
+		args.dst = dst;
+
+		ip_dn_io_ptr(m, ipfw & 0xffff, DN_TO_IP_IN, &args);
+		return 1;
+	}
+	*/
+
+	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 */
+        }
+
+	/*
+	if (ipfw == 0 && args.next_hop == NULL) {
+
+	}
+	*/
+
+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;
+	struct ip *ip;
+
+	ip = mtod(m, struct ip *);
+
+	if (tee)
+		clone = divert_clone(m);
+	else
+		clone = NULL;
+
+	if (ip->ip_off & (IP_MF | IP_OFFMASK))
+		m = ip_reass(m);
+
+	if (m) {
+		/*
+		 * delayed checksums are not currently compatible
+		 * with divert sockets.
+		 */
+		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+			in_delayed_cksum(m);
+			m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+		}
+
+		ip->ip_len = htons(ip->ip_len);
+		ip->ip_off = htons(ip->ip_off);
+
+		/* This function will give up on *m!?? */
+		divert_packet(m, incoming);
+	}
+
+	if (tee && clone) {
+		m = clone;
+		return 0;	/* continue with packet */
+	}
+
+#endif	/* ipdivert */
+	return 1;		/* packet diverted and consumed */
+}
+
+int
+hook_ipfw(void)
+{
+	struct pfil_head *pfh_inet;
+
+	if (ipfw_pfil_hooked)
+		return 1;
+
+	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+	if (pfh_inet == NULL)
+		return 1;
+
+	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);
+
+	ipfw_pfil_hooked = 1;
+	return 0;
+}
+
+void
+unhook_ipfw(void)
+{
+	struct pfil_head *pfh_inet;
+
+	if (!ipfw_pfil_hooked)
+		return;
+
+	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+	if (pfh_inet == NULL)
+		return;
+
+	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);
+
+	ipfw_pfil_hooked = 0;
+	return;
+}
+
--- netinet/null	Mon May 10 22:17:30 2004
+++ netinet/ip_options.h	Sat May  8 01:07:29 2004
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2004
+ *	Andre Oppermann, Internet Business Solutions AG.  All right 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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: $
+ */
+
+#ifndef _NETINET_IP_OPTIONS_H_
+#define	_NETINET_IP_OPTIONS_H_
+
+/*
+ * Structure stored in mbuf in inpcb.ip_options
+ * and passed to ip_output when ip options are in use.
+ * The actual length of the options (including ipopt_dst)
+ * is in m_len.
+ */
+#define MAX_IPOPTLEN    40
+
+struct ipoption {
+	struct	in_addr ipopt_dst;	/* first-hop dst if source routed */
+	char	ipopt_list[MAX_IPOPTLEN];	/* options proper */
+};
+
+extern	int	ip_doopts;		/* process or ignore IP options */
+
+int	ip_dooptions(struct mbuf *, int, struct sockaddr_in *);
+struct mbuf *
+	ip_insertoptions(struct mbuf *, struct mbuf *, int *);
+int	ip_optcopy(struct ip *, struct ip *);
+int	ip_pcbopts(int, struct mbuf **, struct mbuf *);
+void	ip_stripoptions(struct mbuf *, struct mbuf *);
+struct mbuf *
+	ip_srcroute(void);
+
+#endif /* !_NETINET_IP_OPTIONS_H_ */
--- netinet/null	Mon May 10 22:17:30 2004
+++ netinet/ip_options.c	Sat May  8 01:06:48 2004
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2004
+ *	Andre Oppermann, Internet Business Solutions AG.  All right 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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: $
+ */
+
+#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"
+#include "opt_pfil_hooks.h"
+#include "opt_random_ip_id.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mac.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <net/pfil.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
+#include <netinet/ip_icmp.h>
+#include <machine/in_cksum.h>
+
+#include <sys/socketvar.h>
+
+#include <netinet/ip_fw.h>
+#include <netinet/ip_divert.h>
+#include <netinet/ip_dummynet.h>
+
+
+static int	ip_dosourceroute = 0;
+SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
+	&ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
+
+static int	ip_acceptsourceroute = 0;
+SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
+	CTLFLAG_RW, &ip_acceptsourceroute, 0,
+	"Enable accepting source routed IP packets");
+
+int	ip_doopts = 1;	/* 0 = ignore, 1 = process, 2 = reject */
+SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW,
+	&ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)");
+
+static void	save_rte(u_char *, struct in_addr);
+
+
+/*
+ * XXX this is ugly -- the following two global variables are
+ * used to store packet state while it travels through the stack.
+ * Note that the code even makes assumptions on the size and
+ * alignment of fields inside struct ip_srcrt so e.g. adding some
+ * fields will break the code. This needs to be fixed.
+ *
+ * We need to save the IP options in case a protocol wants to respond
+ * to an incoming packet over the same route if the packet got here
+ * using IP source routing.  This allows connection establishment and
+ * maintenance when the remote end is on a network that is not known
+ * to us.
+ */
+static int	ip_nhops = 0;
+static	struct ip_srcrt {
+	struct	in_addr dst;			/* final destination */
+	char	nop;				/* one NOP to align */
+	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
+	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
+} ip_srcrt;
+
+
+/*
+ * Do option processing on a datagram,
+ * possibly discarding it if bad options are encountered,
+ * or forwarding it if source-routed.
+ * The pass argument is used when operating in the IPSTEALTH
+ * mode to tell what options to process:
+ * [LS]SRR (pass 0) or the others (pass 1).
+ * The reason for as many as two passes is that when doing IPSTEALTH,
+ * non-routing options should be processed only if the packet is for us.
+ * Returns 1 if packet has been forwarded/freed,
+ * 0 if the packet should be processed further.
+ */
+int
+ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
+{
+	struct ip *ip = mtod(m, struct ip *);
+	u_char *cp;
+	struct in_ifaddr *ia;
+	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
+	struct in_addr *sin, dst;
+	n_time ntime;
+	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
+
+	/* ignore or reject packets with IP options */
+	if (ip_doopts == 0)
+		return 0;
+	else if (ip_doopts == 2) {
+		type = ICMP_UNREACH;
+		code = ICMP_UNREACH_FILTER_PROHIB;
+		goto bad;
+	}
+
+	dst = ip->ip_dst;
+	cp = (u_char *)(ip + 1);
+	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[IPOPT_OPTVAL];
+		if (opt == IPOPT_EOL)
+			break;
+		if (opt == IPOPT_NOP)
+			optlen = 1;
+		else {
+			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+			optlen = cp[IPOPT_OLEN];
+			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+		}
+		switch (opt) {
+
+		default:
+			break;
+
+		/*
+		 * Source routing with record.
+		 * Find interface with current destination address.
+		 * If none on this machine then drop if strictly routed,
+		 * or do nothing if loosely routed.
+		 * Record interface address and bring up next address
+		 * component.  If strictly routed make sure next
+		 * address is on directly accessible net.
+		 */
+		case IPOPT_LSRR:
+		case IPOPT_SSRR:
+#ifdef IPSTEALTH
+			if (ipstealth && pass > 0)
+				break;
+#endif
+			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+				goto bad;
+			}
+			ipaddr.sin_addr = ip->ip_dst;
+			ia = (struct in_ifaddr *)
+				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
+			if (ia == 0) {
+				if (opt == IPOPT_SSRR) {
+					type = ICMP_UNREACH;
+					code = ICMP_UNREACH_SRCFAIL;
+					goto bad;
+				}
+				if (!ip_dosourceroute)
+					goto nosourcerouting;
+				/*
+				 * Loose routing, and not at next destination
+				 * yet; nothing to do except forward.
+				 */
+				break;
+			}
+			off--;			/* 0 origin */
+			if (off > optlen - (int)sizeof(struct in_addr)) {
+				/*
+				 * End of source route.  Should be for us.
+				 */
+				if (!ip_acceptsourceroute)
+					goto nosourcerouting;
+				save_rte(cp, ip->ip_src);
+				break;
+			}
+#ifdef IPSTEALTH
+			if (ipstealth)
+				goto dropit;
+#endif
+			if (!ip_dosourceroute) {
+				if (ipforwarding) {
+					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
+					/*
+					 * Acting as a router, so generate ICMP
+					 */
+nosourcerouting:
+					strcpy(buf, inet_ntoa(ip->ip_dst));
+					log(LOG_WARNING, 
+					    "attempted source route from %s to %s\n",
+					    inet_ntoa(ip->ip_src), buf);
+					type = ICMP_UNREACH;
+					code = ICMP_UNREACH_SRCFAIL;
+					goto bad;
+				} else {
+					/*
+					 * Not acting as a router, so silently drop.
+					 */
+#ifdef IPSTEALTH
+dropit:
+#endif
+					ipstat.ips_cantforward++;
+					m_freem(m);
+					return (1);
+				}
+			}
+
+			/*
+			 * locate outgoing interface
+			 */
+			(void)memcpy(&ipaddr.sin_addr, cp + off,
+			    sizeof(ipaddr.sin_addr));
+
+			if (opt == IPOPT_SSRR) {
+#define	INA	struct in_ifaddr *
+#define	SA	struct sockaddr *
+			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
+				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
+			} else
+				ia = ip_rtaddr(ipaddr.sin_addr);
+			if (ia == 0) {
+				type = ICMP_UNREACH;
+				code = ICMP_UNREACH_SRCFAIL;
+				goto bad;
+			}
+			ip->ip_dst = ipaddr.sin_addr;
+			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
+			    sizeof(struct in_addr));
+			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+			/*
+			 * Let ip_intr's mcast routing check handle mcast pkts
+			 */
+			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
+			break;
+
+		case IPOPT_RR:
+#ifdef IPSTEALTH
+			if (ipstealth && pass == 0)
+				break;
+#endif
+			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
+				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+				goto bad;
+			}
+			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
+				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+				goto bad;
+			}
+			/*
+			 * If no space remains, ignore.
+			 */
+			off--;			/* 0 origin */
+			if (off > optlen - (int)sizeof(struct in_addr))
+				break;
+			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
+			    sizeof(ipaddr.sin_addr));
+			/*
+			 * locate outgoing interface; if we're the destination,
+			 * use the incoming interface (should be same).
+			 */
+			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
+			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
+				type = ICMP_UNREACH;
+				code = ICMP_UNREACH_HOST;
+				goto bad;
+			}
+			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
+			    sizeof(struct in_addr));
+			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+			break;
+
+		case IPOPT_TS:
+#ifdef IPSTEALTH
+			if (ipstealth && pass == 0)
+				break;
+#endif
+			code = cp - (u_char *)ip;
+			if (optlen < 4 || optlen > 40) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+			if ((off = cp[IPOPT_OFFSET]) < 5) {
+				code = &cp[IPOPT_OLEN] - (u_char *)ip;
+				goto bad;
+			}
+			if (off > optlen - (int)sizeof(int32_t)) {
+				cp[IPOPT_OFFSET + 1] += (1 << 4);
+				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
+					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+					goto bad;
+				}
+				break;
+			}
+			off--;				/* 0 origin */
+			sin = (struct in_addr *)(cp + off);
+			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
+
+			case IPOPT_TS_TSONLY:
+				break;
+
+			case IPOPT_TS_TSANDADDR:
+				if (off + sizeof(n_time) +
+				    sizeof(struct in_addr) > optlen) {
+					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+					goto bad;
+				}
+				ipaddr.sin_addr = dst;
+				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
+							    m->m_pkthdr.rcvif);
+				if (ia == 0)
+					continue;
+				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
+				    sizeof(struct in_addr));
+				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+				off += sizeof(struct in_addr);
+				break;
+
+			case IPOPT_TS_PRESPEC:
+				if (off + sizeof(n_time) +
+				    sizeof(struct in_addr) > optlen) {
+					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
+					goto bad;
+				}
+				(void)memcpy(&ipaddr.sin_addr, sin,
+				    sizeof(struct in_addr));
+				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
+					continue;
+				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+				off += sizeof(struct in_addr);
+				break;
+
+			default:
+				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
+				goto bad;
+			}
+			ntime = iptime();
+			(void)memcpy(cp + off, &ntime, sizeof(n_time));
+			cp[IPOPT_OFFSET] += sizeof(n_time);
+		}
+	}
+	if (forward && ipforwarding) {
+		ip_forward(m, 1, next_hop);
+		return (1);
+	}
+	return (0);
+bad:
+	icmp_error(m, type, code, 0, 0);
+	ipstat.ips_badoptions++;
+	return (1);
+}
+
+
+
+/*
+ * Save incoming source route for use in replies,
+ * to be picked up later by ip_srcroute if the receiver is interested.
+ */
+static void
+save_rte(option, dst)
+	u_char *option;
+	struct in_addr dst;
+{
+	unsigned olen;
+
+	olen = option[IPOPT_OLEN];
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf("save_rte: olen %d\n", olen);
+#endif
+	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
+		return;
+	bcopy(option, ip_srcrt.srcopt, olen);
+	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
+	ip_srcrt.dst = dst;
+}
+
+/*
+ * Retrieve incoming source route for use in replies,
+ * in the same form used by setsockopt.
+ * The first hop is placed before the options, will be removed later.
+ */
+struct mbuf *
+ip_srcroute()
+{
+	register struct in_addr *p, *q;
+	register struct mbuf *m;
+
+	if (ip_nhops == 0)
+		return ((struct mbuf *)0);
+	m = m_get(M_DONTWAIT, MT_HEADER);
+	if (m == 0)
+		return ((struct mbuf *)0);
+
+#define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
+
+	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
+	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
+	    OPTSIZ;
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
+#endif
+
+	/*
+	 * First save first hop for return route
+	 */
+	p = &ip_srcrt.route[ip_nhops - 1];
+	*(mtod(m, struct in_addr *)) = *p--;
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
+#endif
+
+	/*
+	 * Copy option fields and padding (nop) to mbuf.
+	 */
+	ip_srcrt.nop = IPOPT_NOP;
+	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
+	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
+	    &ip_srcrt.nop, OPTSIZ);
+	q = (struct in_addr *)(mtod(m, caddr_t) +
+	    sizeof(struct in_addr) + OPTSIZ);
+#undef OPTSIZ
+	/*
+	 * Record return path as an IP source route,
+	 * reversing the path (pointers are now aligned).
+	 */
+	while (p >= ip_srcrt.route) {
+#ifdef DIAGNOSTIC
+		if (ipprintfs)
+			printf(" %lx", (u_long)ntohl(q->s_addr));
+#endif
+		*q++ = *p--;
+	}
+	/*
+	 * Last hop goes to final destination.
+	 */
+	*q = ip_srcrt.dst;
+#ifdef DIAGNOSTIC
+	if (ipprintfs)
+		printf(" %lx\n", (u_long)ntohl(q->s_addr));
+#endif
+	return (m);
+}
+
+/*
+ * Strip out IP options, at higher
+ * level protocol in the kernel.
+ * Second argument is buffer to which options
+ * will be moved, and return value is their length.
+ * XXX should be deleted; last arg currently ignored.
+ */
+void
+ip_stripoptions(m, mopt)
+	register struct mbuf *m;
+	struct mbuf *mopt;
+{
+	register int i;
+	struct ip *ip = mtod(m, struct ip *);
+	register caddr_t opts;
+	int olen;
+
+	olen = (ip->ip_hl << 2) - sizeof (struct ip);
+	opts = (caddr_t)(ip + 1);
+	i = m->m_len - (sizeof (struct ip) + olen);
+	bcopy(opts + olen, opts, (unsigned)i);
+	m->m_len -= olen;
+	if (m->m_flags & M_PKTHDR)
+		m->m_pkthdr.len -= olen;
+	ip->ip_v = IPVERSION;
+	ip->ip_hl = sizeof(struct ip) >> 2;
+}
+
+/*
+ * Insert IP options into preformed packet.
+ * Adjust IP destination as required for IP source routing,
+ * as indicated by a non-zero in_addr at the start of the options.
+ *
+ * XXX This routine assumes that the packet has no options in place.
+ */
+struct mbuf *
+ip_insertoptions(m, opt, phlen)
+	register struct mbuf *m;
+	struct mbuf *opt;
+	int *phlen;
+{
+	register struct ipoption *p = mtod(opt, struct ipoption *);
+	struct mbuf *n;
+	register struct ip *ip = mtod(m, struct ip *);
+	unsigned optlen;
+
+	optlen = opt->m_len - sizeof(p->ipopt_dst);
+	if (optlen + ip->ip_len > IP_MAXPACKET) {
+		*phlen = 0;
+		return (m);		/* XXX should fail */
+	}
+	if (p->ipopt_dst.s_addr)
+		ip->ip_dst = p->ipopt_dst;
+	if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
+		MGETHDR(n, M_DONTWAIT, MT_HEADER);
+		if (n == 0) {
+			*phlen = 0;
+			return (m);
+		}
+		n->m_pkthdr.rcvif = (struct ifnet *)0;
+#ifdef MAC
+		mac_create_mbuf_from_mbuf(m, n);
+#endif
+		n->m_pkthdr.len = m->m_pkthdr.len + optlen;
+		m->m_len -= sizeof(struct ip);
+		m->m_data += sizeof(struct ip);
+		n->m_next = m;
+		m = n;
+		m->m_len = optlen + sizeof(struct ip);
+		m->m_data += max_linkhdr;
+		bcopy(ip, mtod(m, void *), sizeof(struct ip));
+	} else {
+		m->m_data -= optlen;
+		m->m_len += optlen;
+		m->m_pkthdr.len += optlen;
+		bcopy(ip, mtod(m, void *), sizeof(struct ip));
+	}
+	ip = mtod(m, struct ip *);
+	bcopy(p->ipopt_list, ip + 1, optlen);
+	*phlen = sizeof(struct ip) + optlen;
+	ip->ip_v = IPVERSION;
+	ip->ip_hl = *phlen >> 2;
+	ip->ip_len += optlen;
+	return (m);
+}
+
+/*
+ * Copy options from ip to jp,
+ * omitting those not copied during fragmentation.
+ */
+int
+ip_optcopy(ip, jp)
+	struct ip *ip, *jp;
+{
+	register u_char *cp, *dp;
+	int opt, optlen, cnt;
+
+	cp = (u_char *)(ip + 1);
+	dp = (u_char *)(jp + 1);
+	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[0];
+		if (opt == IPOPT_EOL)
+			break;
+		if (opt == IPOPT_NOP) {
+			/* Preserve for IP mcast tunnel's LSRR alignment. */
+			*dp++ = IPOPT_NOP;
+			optlen = 1;
+			continue;
+		}
+
+		KASSERT(cnt >= IPOPT_OLEN + sizeof(*cp),
+		    ("ip_optcopy: malformed ipv4 option"));
+		optlen = cp[IPOPT_OLEN];
+		KASSERT(optlen >= IPOPT_OLEN + sizeof(*cp) && optlen <= cnt,
+		    ("ip_optcopy: malformed ipv4 option"));
+
+		/* bogus lengths should have been caught by ip_dooptions */
+		if (optlen > cnt)
+			optlen = cnt;
+		if (IPOPT_COPIED(opt)) {
+			bcopy(cp, dp, optlen);
+			dp += optlen;
+		}
+	}
+	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
+		*dp++ = IPOPT_EOL;
+	return (optlen);
+}
+
+/*
+ * Set up IP options in pcb for insertion in output packets.
+ * Store in mbuf with pointer in pcbopt, adding pseudo-option
+ * with destination address if source routed.
+ */
+int
+ip_pcbopts(optname, pcbopt, m)
+	int optname;
+	struct mbuf **pcbopt;
+	register struct mbuf *m;
+{
+	register int cnt, optlen;
+	register u_char *cp;
+	u_char opt;
+
+	/* turn off any old options */
+	if (*pcbopt)
+		(void)m_free(*pcbopt);
+	*pcbopt = 0;
+	if (m == (struct mbuf *)0 || m->m_len == 0) {
+		/*
+		 * Only turning off any previous options.
+		 */
+		if (m)
+			(void)m_free(m);
+		return (0);
+	}
+
+	if (m->m_len % sizeof(int32_t))
+		goto bad;
+	/*
+	 * IP first-hop destination address will be stored before
+	 * actual options; move other options back
+	 * and clear it when none present.
+	 */
+	if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
+		goto bad;
+	cnt = m->m_len;
+	m->m_len += sizeof(struct in_addr);
+	cp = mtod(m, u_char *) + sizeof(struct in_addr);
+	bcopy(mtod(m, void *), cp, (unsigned)cnt);
+	bzero(mtod(m, void *), sizeof(struct in_addr));
+
+	for (; cnt > 0; cnt -= optlen, cp += optlen) {
+		opt = cp[IPOPT_OPTVAL];
+		if (opt == IPOPT_EOL)
+			break;
+		if (opt == IPOPT_NOP)
+			optlen = 1;
+		else {
+			if (cnt < IPOPT_OLEN + sizeof(*cp))
+				goto bad;
+			optlen = cp[IPOPT_OLEN];
+			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
+				goto bad;
+		}
+		switch (opt) {
+
+		default:
+			break;
+
+		case IPOPT_LSRR:
+		case IPOPT_SSRR:
+			/*
+			 * user process specifies route as:
+			 *	->A->B->C->D
+			 * D must be our final destination (but we can't
+			 * check that since we may not have connected yet).
+			 * A is first hop destination, which doesn't appear in
+			 * actual IP option, but is stored before the options.
+			 */
+			if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
+				goto bad;
+			m->m_len -= sizeof(struct in_addr);
+			cnt -= sizeof(struct in_addr);
+			optlen -= sizeof(struct in_addr);
+			cp[IPOPT_OLEN] = optlen;
+			/*
+			 * Move first hop before start of options.
+			 */
+			bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
+			    sizeof(struct in_addr));
+			/*
+			 * Then copy rest of options back
+			 * to close up the deleted entry.
+			 */
+			bcopy((&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)),
+			    &cp[IPOPT_OFFSET+1],
+			    (unsigned)cnt + sizeof(struct in_addr));
+			break;
+		}
+	}
+	if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
+		goto bad;
+	*pcbopt = m;
+	return (0);
+
+bad:
+	(void)m_free(m);
+	return (EINVAL);
+}
